diff mbox series

[v2,RESEND] HID: nintendo: cleanup LED code

Message ID 20230906102831.16734-2-tinozzo123@gmail.com (mailing list archive)
State Superseded
Delegated to: Jiri Kosina
Headers show
Series [v2,RESEND] HID: nintendo: cleanup LED code | expand

Commit Message

Martino Fontana Sept. 6, 2023, 10:26 a.m. UTC
- Only turn on the nth LED, instead of all the LEDs up to n. This better
  matches Nintendo consoles' behaviour, as they never turn on more than
  one LED.
  (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.

Changes for v2:

Applied suggestions, commit message explains more stuff, restored `return ret`
when `devm_led_classdev_register` fails (since all other hid drivers do this).
If setting LED fails, `hid_warn` now explicitly says "skipping registration".

Signed-off-by: Martino Fontana <tinozzo123@gmail.com>
---
 drivers/hid/hid-nintendo.c | 117 ++++++++++++++++++-------------------
 1 file changed, 57 insertions(+), 60 deletions(-)

Comments

kernel test robot Sept. 6, 2023, 1:48 p.m. UTC | #1
Hi Martino,

kernel test robot noticed the following build errors:

[auto build test ERROR on hid/for-next]
[also build test ERROR on linus/master v6.5 next-20230906]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Martino-Fontana/HID-nintendo-cleanup-LED-code/20230906-183111
base:   https://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git for-next
patch link:    https://lore.kernel.org/r/20230906102831.16734-2-tinozzo123%40gmail.com
patch subject: [PATCH v2 RESEND] HID: nintendo: cleanup LED code
config: parisc-randconfig-r011-20230906 (https://download.01.org/0day-ci/archive/20230906/202309062140.CiSKWeEO-lkp@intel.com/config)
compiler: hppa-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20230906/202309062140.CiSKWeEO-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202309062140.CiSKWeEO-lkp@intel.com/

All error/warnings (new ones prefixed by >>):

   drivers/hid/hid-nintendo.c: In function 'joycon_leds_create':
>> drivers/hid/hid-nintendo.c:1954:17: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
    1954 |                 if (ret)
         |                 ^~
   drivers/hid/hid-nintendo.c:1956:25: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
    1956 |                         return ret;
         |                         ^~~~~~
   drivers/hid/hid-nintendo.c:1986:17: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
    1986 |                 if (ret)
         |                 ^~
   drivers/hid/hid-nintendo.c:1988:25: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
    1988 |                         return ret
         |                         ^~~~~~
>> drivers/hid/hid-nintendo.c:1988:35: error: expected ';' before '}' token
    1988 |                         return ret
         |                                   ^
         |                                   ;
    1989 |         }
         |         ~                          


vim +1988 drivers/hid/hid-nintendo.c

  1906	
  1907	static DEFINE_SPINLOCK(joycon_input_num_spinlock);
  1908	static int joycon_leds_create(struct joycon_ctlr *ctlr)
  1909	{
  1910		struct hid_device *hdev = ctlr->hdev;
  1911		struct device *dev = &hdev->dev;
  1912		const char *d_name = dev_name(dev);
  1913		struct led_classdev *led;
  1914		char *name;
  1915		int ret;
  1916		int i;
  1917		unsigned long flags;
  1918		int player_led_number;
  1919		static int input_num;
  1920	
  1921		/* Set the player leds based on controller number */
  1922		spin_lock_irqsave(&joycon_input_num_spinlock, flags);
  1923		player_led_number = input_num++ % JC_NUM_LEDS;
  1924		spin_unlock_irqrestore(&joycon_input_num_spinlock, flags);
  1925	
  1926		/* configure the player LEDs */
  1927		for (i = 0; i < JC_NUM_LEDS; i++) {
  1928			name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s:%s",
  1929					      d_name,
  1930					      "green",
  1931					      joycon_player_led_names[i]);
  1932			if (!name)
  1933				return -ENOMEM;
  1934	
  1935			led = &ctlr->leds[i];
  1936			led->name = name;
  1937			led->brightness = (i == player_led_number) ? 1 : 0;
  1938			led->max_brightness = 1;
  1939			led->brightness_set_blocking =
  1940						joycon_player_led_brightness_set;
  1941			led->flags = LED_CORE_SUSPENDRESUME | LED_HW_PLUGGABLE;
  1942		}
  1943		mutex_lock(&ctlr->output_mutex);
  1944		ret = joycon_set_player_leds(ctlr, 0, 0x1 << player_led_number);
  1945		mutex_unlock(&ctlr->output_mutex);
  1946		if (ret) {
  1947			hid_warn(hdev, "Failed to set players LEDs, skipping registration; ret=%d\n", ret);
  1948			goto home_led;
  1949		}
  1950	
  1951		for (i = 0; i < JC_NUM_LEDS; i++) {
  1952			led = &ctlr->leds[i];
  1953			ret = devm_led_classdev_register(&hdev->dev, led);
> 1954			if (ret)
  1955				hid_err(hdev, "Failed to register player %d LED; ret=%d\n", i + 1, ret);
> 1956				return ret;
  1957		}
  1958	
  1959	home_led:
  1960		/* configure the home LED */
  1961		if (jc_type_has_right(ctlr)) {
  1962			name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s:%s",
  1963					      d_name,
  1964					      "blue",
  1965					      LED_FUNCTION_PLAYER5);
  1966			if (!name)
  1967				return -ENOMEM;
  1968	
  1969			led = &ctlr->home_led;
  1970			led->name = name;
  1971			led->brightness = 0;
  1972			led->max_brightness = 0xF;
  1973			led->brightness_set_blocking = joycon_home_led_brightness_set;
  1974			led->flags = LED_CORE_SUSPENDRESUME | LED_HW_PLUGGABLE;
  1975	
  1976			/* Set the home LED to 0 as default state */
  1977			mutex_lock(&ctlr->output_mutex);
  1978			ret = joycon_set_home_led(ctlr, 0);
  1979			mutex_unlock(&ctlr->output_mutex);
  1980			if (ret) {
  1981				hid_warn(hdev, "Failed to set home LED, skipping registration; ret=%d\n", ret);
  1982				return 0;
  1983			}
  1984	
  1985			ret = devm_led_classdev_register(&hdev->dev, led);
  1986			if (ret)
  1987				hid_err(hdev, "Failed to register home LED; ret=%d\n", ret);
> 1988				return ret
  1989		}
  1990	
  1991		return 0;
  1992	}
  1993
diff mbox series

Patch

diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c
index a5ebe857a..dd7c7fce3 100644
--- a/drivers/hid/hid-nintendo.c
+++ b/drivers/hid/hid-nintendo.c
@@ -699,6 +699,25 @@  static int joycon_set_player_leds(struct joycon_ctlr *ctlr, u8 flash, u8 on)
 	return joycon_send_subcmd(ctlr, req, 1, HZ/4);
 }
 
+static int joycon_set_home_led(struct joycon_ctlr *ctlr, enum led_brightness brightness)
+{
+	struct joycon_subcmd_request *req;
+	u8 buffer[sizeof(*req) + 5] = { 0 };
+	u8 *data;
+
+	req = (struct joycon_subcmd_request *)buffer;
+	req->subcmd_id = JC_SUBCMD_SET_HOME_LIGHT;
+	data = req->data;
+	data[0] = 0x01;
+	data[1] = brightness << 4;
+	data[2] = brightness | (brightness << 4);
+	data[3] = 0x11;
+	data[4] = 0x11;
+
+	hid_dbg(ctlr->hdev, "setting home led brightness\n");
+	return joycon_send_subcmd(ctlr, req, 5, HZ/4);
+}
+
 static int joycon_request_spi_flash_read(struct joycon_ctlr *ctlr,
 					 u32 start_addr, u8 size, u8 **reply)
 {
@@ -1849,7 +1868,6 @@  static int joycon_player_led_brightness_set(struct led_classdev *led,
 	int val = 0;
 	int i;
 	int ret;
-	int num;
 
 	ctlr = hid_get_drvdata(hdev);
 	if (!ctlr) {
@@ -1857,21 +1875,10 @@  static int joycon_player_led_brightness_set(struct led_classdev *led,
 		return -ENODEV;
 	}
 
-	/* determine which player led this is */
-	for (num = 0; num < JC_NUM_LEDS; num++) {
-		if (&ctlr->leds[num] == led)
-			break;
-	}
-	if (num >= JC_NUM_LEDS)
-		return -EINVAL;
+	for (i = 0; i < JC_NUM_LEDS; i++)
+		val |= ctlr->leds[i].brightness << i;
 
 	mutex_lock(&ctlr->output_mutex);
-	for (i = 0; i < JC_NUM_LEDS; i++) {
-		if (i == num)
-			val |= brightness << i;
-		else
-			val |= ctlr->leds[i].brightness << i;
-	}
 	ret = joycon_set_player_leds(ctlr, 0, val);
 	mutex_unlock(&ctlr->output_mutex);
 
@@ -1884,9 +1891,6 @@  static int joycon_home_led_brightness_set(struct led_classdev *led,
 	struct device *dev = led->dev->parent;
 	struct hid_device *hdev = to_hid_device(dev);
 	struct joycon_ctlr *ctlr;
-	struct joycon_subcmd_request *req;
-	u8 buffer[sizeof(*req) + 5] = { 0 };
-	u8 *data;
 	int ret;
 
 	ctlr = hid_get_drvdata(hdev);
@@ -1894,25 +1898,13 @@  static int joycon_home_led_brightness_set(struct led_classdev *led,
 		hid_err(hdev, "No controller data\n");
 		return -ENODEV;
 	}
-
-	req = (struct joycon_subcmd_request *)buffer;
-	req->subcmd_id = JC_SUBCMD_SET_HOME_LIGHT;
-	data = req->data;
-	data[0] = 0x01;
-	data[1] = brightness << 4;
-	data[2] = brightness | (brightness << 4);
-	data[3] = 0x11;
-	data[4] = 0x11;
-
-	hid_dbg(hdev, "setting home led brightness\n");
 	mutex_lock(&ctlr->output_mutex);
-	ret = joycon_send_subcmd(ctlr, req, 5, HZ/4);
+	ret = joycon_set_home_led(ctlr, brightness);
 	mutex_unlock(&ctlr->output_mutex);
-
 	return ret;
 }
 
-static DEFINE_MUTEX(joycon_input_num_mutex);
+static DEFINE_SPINLOCK(joycon_input_num_spinlock);
 static int joycon_leds_create(struct joycon_ctlr *ctlr)
 {
 	struct hid_device *hdev = ctlr->hdev;
@@ -1920,17 +1912,16 @@  static int joycon_leds_create(struct joycon_ctlr *ctlr)
 	const char *d_name = dev_name(dev);
 	struct led_classdev *led;
 	char *name;
-	int ret = 0;
+	int ret;
 	int i;
-	static int input_num = 1;
+	unsigned long flags;
+	int player_led_number;
+	static int input_num;
 
-	/* Set the default controller player leds based on controller number */
-	mutex_lock(&joycon_input_num_mutex);
-	mutex_lock(&ctlr->output_mutex);
-	ret = joycon_set_player_leds(ctlr, 0, 0xF >> (4 - input_num));
-	if (ret)
-		hid_warn(ctlr->hdev, "Failed to set leds; ret=%d\n", ret);
-	mutex_unlock(&ctlr->output_mutex);
+	/* Set the player leds based on controller number */
+	spin_lock_irqsave(&joycon_input_num_spinlock, flags);
+	player_led_number = input_num++ % JC_NUM_LEDS;
+	spin_unlock_irqrestore(&joycon_input_num_spinlock, flags);
 
 	/* configure the player LEDs */
 	for (i = 0; i < JC_NUM_LEDS; i++) {
@@ -1938,31 +1929,34 @@  static int joycon_leds_create(struct joycon_ctlr *ctlr)
 				      d_name,
 				      "green",
 				      joycon_player_led_names[i]);
-		if (!name) {
-			mutex_unlock(&joycon_input_num_mutex);
+		if (!name)
 			return -ENOMEM;
-		}
 
 		led = &ctlr->leds[i];
 		led->name = name;
-		led->brightness = ((i + 1) <= input_num) ? 1 : 0;
+		led->brightness = (i == player_led_number) ? 1 : 0;
 		led->max_brightness = 1;
 		led->brightness_set_blocking =
 					joycon_player_led_brightness_set;
 		led->flags = LED_CORE_SUSPENDRESUME | LED_HW_PLUGGABLE;
+	}
+	mutex_lock(&ctlr->output_mutex);
+	ret = joycon_set_player_leds(ctlr, 0, 0x1 << player_led_number);
+	mutex_unlock(&ctlr->output_mutex);
+	if (ret) {
+		hid_warn(hdev, "Failed to set players LEDs, skipping registration; ret=%d\n", ret);
+		goto home_led;
+	}
 
+	for (i = 0; i < JC_NUM_LEDS; i++) {
+		led = &ctlr->leds[i];
 		ret = devm_led_classdev_register(&hdev->dev, led);
-		if (ret) {
-			hid_err(hdev, "Failed registering %s LED\n", led->name);
-			mutex_unlock(&joycon_input_num_mutex);
+		if (ret)
+			hid_err(hdev, "Failed to register player %d LED; ret=%d\n", i + 1, ret);
 			return ret;
-		}
 	}
 
-	if (++input_num > 4)
-		input_num = 1;
-	mutex_unlock(&joycon_input_num_mutex);
-
+home_led:
 	/* configure the home LED */
 	if (jc_type_has_right(ctlr)) {
 		name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s:%s",
@@ -1978,17 +1972,20 @@  static int joycon_leds_create(struct joycon_ctlr *ctlr)
 		led->max_brightness = 0xF;
 		led->brightness_set_blocking = joycon_home_led_brightness_set;
 		led->flags = LED_CORE_SUSPENDRESUME | LED_HW_PLUGGABLE;
-		ret = devm_led_classdev_register(&hdev->dev, led);
-		if (ret) {
-			hid_err(hdev, "Failed registering home led\n");
-			return ret;
-		}
+
 		/* Set the home LED to 0 as default state */
-		ret = joycon_home_led_brightness_set(led, 0);
+		mutex_lock(&ctlr->output_mutex);
+		ret = joycon_set_home_led(ctlr, 0);
+		mutex_unlock(&ctlr->output_mutex);
 		if (ret) {
-			hid_warn(hdev, "Failed to set home LED default, unregistering home LED");
-			devm_led_classdev_unregister(&hdev->dev, led);
+			hid_warn(hdev, "Failed to set home LED, skipping registration; ret=%d\n", ret);
+			return 0;
 		}
+
+		ret = devm_led_classdev_register(&hdev->dev, led);
+		if (ret)
+			hid_err(hdev, "Failed to register home LED; ret=%d\n", ret);
+			return ret
 	}
 
 	return 0;