Skip to content

Commit 9282760

Browse files
SuperSamusJiri Kosina
authored andcommitted
HID: nintendo: cleanup LED code
- Support player LED patterns up to 8 players. (Note that the behavior still consinsts in increasing the player number every time a controller is connected, never decreasing it. It should be as is described in https://bugzilla.kernel.org/show_bug.cgi?id=216225. However, any implementation here would stop making sense as soon as a non-Nintendo controller is connected, which is why I'm not bothering.) - Split part of `joycon_home_led_brightness_set` (which is called by hid) into `joycon_set_home_led` (which is what actually sets the LEDs), for consistency with player LEDs. - `joycon_player_led_brightness_set` won't try it to "determine which player led this is" anymore: it's already looking at every LED brightness value. - Instead of first registering the `led_classdev`, then attempting to set the LED and unregistering the `led_classdev` if it fails, first attempt to set the LED, then register the `led_classdev` only if it succeeds (the class is still filled up in either case). - If setting the player LEDs fails, still attempt setting the home LED. (I don't know there's a third party controller where this may actually happen, but who knows...) - Use `JC_NUM_LEDS` where appropriate instead of 4. - Print return codes in more places. - Use spinlock instead of mutex for `input_num`. Copy its value to a local variable, so that it can be unlocked immediately. - `input_num` starts counting from 0 - Less holding of mutexes in general. Signed-off-by: Martino Fontana <[email protected]> Reviewed-by: Daniel J. Ogorchock <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 29aa98d commit 9282760

File tree

1 file changed

+76
-57
lines changed

1 file changed

+76
-57
lines changed

drivers/hid/hid-nintendo.c

Lines changed: 76 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,18 @@ static const char * const joycon_player_led_names[] = {
410410
LED_FUNCTION_PLAYER4,
411411
};
412412
#define JC_NUM_LEDS ARRAY_SIZE(joycon_player_led_names)
413+
#define JC_NUM_LED_PATTERNS 8
414+
/* Taken from https://www.nintendo.com/my/support/qa/detail/33822 */
415+
static const enum led_brightness joycon_player_led_patterns[JC_NUM_LED_PATTERNS][JC_NUM_LEDS] = {
416+
{ 1, 0, 0, 0 },
417+
{ 1, 1, 0, 0 },
418+
{ 1, 1, 1, 0 },
419+
{ 1, 1, 1, 1 },
420+
{ 1, 0, 0, 1 },
421+
{ 1, 0, 1, 0 },
422+
{ 1, 0, 1, 1 },
423+
{ 0, 1, 1, 0 },
424+
};
413425

414426
/* Each physical controller is associated with a joycon_ctlr struct */
415427
struct joycon_ctlr {
@@ -699,6 +711,25 @@ static int joycon_set_player_leds(struct joycon_ctlr *ctlr, u8 flash, u8 on)
699711
return joycon_send_subcmd(ctlr, req, 1, HZ/4);
700712
}
701713

714+
static int joycon_set_home_led(struct joycon_ctlr *ctlr, enum led_brightness brightness)
715+
{
716+
struct joycon_subcmd_request *req;
717+
u8 buffer[sizeof(*req) + 5] = { 0 };
718+
u8 *data;
719+
720+
req = (struct joycon_subcmd_request *)buffer;
721+
req->subcmd_id = JC_SUBCMD_SET_HOME_LIGHT;
722+
data = req->data;
723+
data[0] = 0x01;
724+
data[1] = brightness << 4;
725+
data[2] = brightness | (brightness << 4);
726+
data[3] = 0x11;
727+
data[4] = 0x11;
728+
729+
hid_dbg(ctlr->hdev, "setting home led brightness\n");
730+
return joycon_send_subcmd(ctlr, req, 5, HZ/4);
731+
}
732+
702733
static int joycon_request_spi_flash_read(struct joycon_ctlr *ctlr,
703734
u32 start_addr, u8 size, u8 **reply)
704735
{
@@ -1840,6 +1871,7 @@ static int joycon_input_create(struct joycon_ctlr *ctlr)
18401871
return 0;
18411872
}
18421873

1874+
/* Because the subcommand sets all the leds at once, the brightness argument is ignored */
18431875
static int joycon_player_led_brightness_set(struct led_classdev *led,
18441876
enum led_brightness brightness)
18451877
{
@@ -1849,29 +1881,17 @@ static int joycon_player_led_brightness_set(struct led_classdev *led,
18491881
int val = 0;
18501882
int i;
18511883
int ret;
1852-
int num;
18531884

18541885
ctlr = hid_get_drvdata(hdev);
18551886
if (!ctlr) {
18561887
hid_err(hdev, "No controller data\n");
18571888
return -ENODEV;
18581889
}
18591890

1860-
/* determine which player led this is */
1861-
for (num = 0; num < JC_NUM_LEDS; num++) {
1862-
if (&ctlr->leds[num] == led)
1863-
break;
1864-
}
1865-
if (num >= JC_NUM_LEDS)
1866-
return -EINVAL;
1891+
for (i = 0; i < JC_NUM_LEDS; i++)
1892+
val |= ctlr->leds[i].brightness << i;
18671893

18681894
mutex_lock(&ctlr->output_mutex);
1869-
for (i = 0; i < JC_NUM_LEDS; i++) {
1870-
if (i == num)
1871-
val |= brightness << i;
1872-
else
1873-
val |= ctlr->leds[i].brightness << i;
1874-
}
18751895
ret = joycon_set_player_leds(ctlr, 0, val);
18761896
mutex_unlock(&ctlr->output_mutex);
18771897

@@ -1884,85 +1904,80 @@ static int joycon_home_led_brightness_set(struct led_classdev *led,
18841904
struct device *dev = led->dev->parent;
18851905
struct hid_device *hdev = to_hid_device(dev);
18861906
struct joycon_ctlr *ctlr;
1887-
struct joycon_subcmd_request *req;
1888-
u8 buffer[sizeof(*req) + 5] = { 0 };
1889-
u8 *data;
18901907
int ret;
18911908

18921909
ctlr = hid_get_drvdata(hdev);
18931910
if (!ctlr) {
18941911
hid_err(hdev, "No controller data\n");
18951912
return -ENODEV;
18961913
}
1897-
1898-
req = (struct joycon_subcmd_request *)buffer;
1899-
req->subcmd_id = JC_SUBCMD_SET_HOME_LIGHT;
1900-
data = req->data;
1901-
data[0] = 0x01;
1902-
data[1] = brightness << 4;
1903-
data[2] = brightness | (brightness << 4);
1904-
data[3] = 0x11;
1905-
data[4] = 0x11;
1906-
1907-
hid_dbg(hdev, "setting home led brightness\n");
19081914
mutex_lock(&ctlr->output_mutex);
1909-
ret = joycon_send_subcmd(ctlr, req, 5, HZ/4);
1915+
ret = joycon_set_home_led(ctlr, brightness);
19101916
mutex_unlock(&ctlr->output_mutex);
1911-
19121917
return ret;
19131918
}
19141919

1915-
static DEFINE_MUTEX(joycon_input_num_mutex);
1920+
static DEFINE_SPINLOCK(joycon_input_num_spinlock);
19161921
static int joycon_leds_create(struct joycon_ctlr *ctlr)
19171922
{
19181923
struct hid_device *hdev = ctlr->hdev;
19191924
struct device *dev = &hdev->dev;
19201925
const char *d_name = dev_name(dev);
19211926
struct led_classdev *led;
1927+
int led_val = 0;
19221928
char *name;
1923-
int ret = 0;
1929+
int ret;
19241930
int i;
1925-
static int input_num = 1;
1931+
unsigned long flags;
1932+
int player_led_pattern;
1933+
static int input_num;
19261934

1927-
/* Set the default controller player leds based on controller number */
1928-
mutex_lock(&joycon_input_num_mutex);
1929-
mutex_lock(&ctlr->output_mutex);
1930-
ret = joycon_set_player_leds(ctlr, 0, 0xF >> (4 - input_num));
1931-
if (ret)
1932-
hid_warn(ctlr->hdev, "Failed to set leds; ret=%d\n", ret);
1933-
mutex_unlock(&ctlr->output_mutex);
1935+
/*
1936+
* Set the player leds based on controller number
1937+
* Because there is no standard concept of "player number", the pattern
1938+
* number will simply increase by 1 every time a controller is connected.
1939+
*/
1940+
spin_lock_irqsave(&joycon_input_num_spinlock, flags);
1941+
player_led_pattern = input_num++ % JC_NUM_LED_PATTERNS;
1942+
spin_unlock_irqrestore(&joycon_input_num_spinlock, flags);
19341943

19351944
/* configure the player LEDs */
19361945
for (i = 0; i < JC_NUM_LEDS; i++) {
19371946
name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s:%s",
19381947
d_name,
19391948
"green",
19401949
joycon_player_led_names[i]);
1941-
if (!name) {
1942-
mutex_unlock(&joycon_input_num_mutex);
1950+
if (!name)
19431951
return -ENOMEM;
1944-
}
19451952

19461953
led = &ctlr->leds[i];
19471954
led->name = name;
1948-
led->brightness = ((i + 1) <= input_num) ? 1 : 0;
1955+
led->brightness = joycon_player_led_patterns[player_led_pattern][i];
19491956
led->max_brightness = 1;
19501957
led->brightness_set_blocking =
19511958
joycon_player_led_brightness_set;
19521959
led->flags = LED_CORE_SUSPENDRESUME | LED_HW_PLUGGABLE;
19531960

1961+
led_val |= joycon_player_led_patterns[player_led_pattern][i] << i;
1962+
}
1963+
mutex_lock(&ctlr->output_mutex);
1964+
ret = joycon_set_player_leds(ctlr, 0, led_val);
1965+
mutex_unlock(&ctlr->output_mutex);
1966+
if (ret) {
1967+
hid_warn(hdev, "Failed to set players LEDs, skipping registration; ret=%d\n", ret);
1968+
goto home_led;
1969+
}
1970+
1971+
for (i = 0; i < JC_NUM_LEDS; i++) {
1972+
led = &ctlr->leds[i];
19541973
ret = devm_led_classdev_register(&hdev->dev, led);
19551974
if (ret) {
1956-
hid_err(hdev, "Failed registering %s LED\n", led->name);
1957-
mutex_unlock(&joycon_input_num_mutex);
1975+
hid_err(hdev, "Failed to register player %d LED; ret=%d\n", i + 1, ret);
19581976
return ret;
19591977
}
19601978
}
19611979

1962-
if (++input_num > 4)
1963-
input_num = 1;
1964-
mutex_unlock(&joycon_input_num_mutex);
1965-
1980+
home_led:
19661981
/* configure the home LED */
19671982
if (jc_type_has_right(ctlr)) {
19681983
name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s:%s",
@@ -1978,16 +1993,20 @@ static int joycon_leds_create(struct joycon_ctlr *ctlr)
19781993
led->max_brightness = 0xF;
19791994
led->brightness_set_blocking = joycon_home_led_brightness_set;
19801995
led->flags = LED_CORE_SUSPENDRESUME | LED_HW_PLUGGABLE;
1981-
ret = devm_led_classdev_register(&hdev->dev, led);
1996+
1997+
/* Set the home LED to 0 as default state */
1998+
mutex_lock(&ctlr->output_mutex);
1999+
ret = joycon_set_home_led(ctlr, 0);
2000+
mutex_unlock(&ctlr->output_mutex);
19822001
if (ret) {
1983-
hid_err(hdev, "Failed registering home led\n");
1984-
return ret;
2002+
hid_warn(hdev, "Failed to set home LED, skipping registration; ret=%d\n", ret);
2003+
return 0;
19852004
}
1986-
/* Set the home LED to 0 as default state */
1987-
ret = joycon_home_led_brightness_set(led, 0);
2005+
2006+
ret = devm_led_classdev_register(&hdev->dev, led);
19882007
if (ret) {
1989-
hid_warn(hdev, "Failed to set home LED default, unregistering home LED");
1990-
devm_led_classdev_unregister(&hdev->dev, led);
2008+
hid_err(hdev, "Failed to register home LED; ret=%d\n", ret);
2009+
return ret;
19912010
}
19922011
}
19932012

0 commit comments

Comments
 (0)