This is my first patch, so hopefully I'm doing this right. I noticed when trying to use `ledtrig-timer` on the Joycon LEDS that it at times would hang for a while (I assume the firmware isn't a fan of frequent LED subcommands, or something), and I've tested with this patch and it blinks consistently with carefree abandon. Separately, I was also thinking about exposing the LEDs as evdev codes, but it doesn't seem like there's any good options of the `LED_*` constants to represent them. Signed-off-by: Noa <coolreader18@xxxxxxxxx> --- drivers/hid/hid-nintendo.c | 45 ++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c index 11ac246176ae..83dff0c4f7e1 100644 --- a/drivers/hid/hid-nintendo.c +++ b/drivers/hid/hid-nintendo.c @@ -2183,14 +2183,13 @@ static int joycon_input_create(struct joycon_ctlr *ctlr) return 0; } -/* Because the subcommand sets all the leds at once, the brightness argument is ignored */ -static int joycon_player_led_brightness_set(struct led_classdev *led, - enum led_brightness brightness) +/* Update the on/flash status of the leds according to their led_classdev fields */ +static int joycon_update_player_leds(struct device *dev) { - struct device *dev = led->dev->parent; struct hid_device *hdev = to_hid_device(dev); struct joycon_ctlr *ctlr; int val = 0; + int flash = 0; int i; int ret; @@ -2200,16 +2199,47 @@ static int joycon_player_led_brightness_set(struct led_classdev *led, return -ENODEV; } - for (i = 0; i < JC_NUM_LEDS; i++) - val |= ctlr->leds[i].brightness << i; + for (i = 0; i < JC_NUM_LEDS; i++) { + if (ctlr->leds[i].blink_delay_on || ctlr->leds[i].blink_delay_off) + flash |= 1 << i; + else if (ctlr->leds[i].brightness) + val |= 1 << i; + } mutex_lock(&ctlr->output_mutex); - ret = joycon_set_player_leds(ctlr, 0, val); + ret = joycon_set_player_leds(ctlr, flash, val); mutex_unlock(&ctlr->output_mutex); return ret; } +static int joycon_player_led_brightness_set(struct led_classdev *led, + enum led_brightness brightness) +{ + led->brightness = brightness; + + if (!brightness) + led->blink_delay_on = led->blink_delay_off = 0; + + return joycon_update_player_leds(led->dev->parent); +} + +/* the blink period of the leds can't be changed, and is always these values */ +static const JC_LED_BLINK_DELAY_ON = 500; +static const JC_LED_BLINK_DELAY_OFF = 200; +/* the different leds on a joycon can't actually be set to hw blink independently + * of each other, since they all use the same one subcommand, so this function + * actually resets the cycle of all the leds */ +static int joycon_player_led_blink_set(struct led_classdev *led, + unsigned long *delay_on, + unsigned long *delay_off) +{ + led->blink_delay_on = *delay_on = JC_LED_BLINK_DELAY_ON; + led->blink_delay_off = *delay_off = JC_LED_BLINK_DELAY_OFF; + + return joycon_update_player_leds(led->dev->parent); +} + static int joycon_home_led_brightness_set(struct led_classdev *led, enum led_brightness brightness) { @@ -2268,6 +2298,7 @@ static int joycon_leds_create(struct joycon_ctlr *ctlr) led->max_brightness = 1; led->brightness_set_blocking = joycon_player_led_brightness_set; + led->blink_set = joycon_player_led_blink_set; led->flags = LED_CORE_SUSPENDRESUME | LED_HW_PLUGGABLE; led_val |= joycon_player_led_patterns[player_led_pattern][i] << i; -- 2.48.1