All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>
To: Antheas Kapenekakis <lkml@antheas.dev>
Cc: platform-driver-x86@vger.kernel.org, linux-input@vger.kernel.org,
	 LKML <linux-kernel@vger.kernel.org>,
	Jiri Kosina <jikos@kernel.org>,
	 Benjamin Tissoires <bentiss@kernel.org>,
	 Corentin Chary <corentin.chary@gmail.com>,
	 "Luke D . Jones" <luke@ljones.dev>,
	Hans de Goede <hdegoede@redhat.com>,
	 Denis Benato <benato.denis96@gmail.com>
Subject: Re: [PATCH v6 3/7] platform/x86: asus-wmi: Add support for multiple kbd RGB handlers
Date: Wed, 15 Oct 2025 14:59:33 +0300 (EEST)	[thread overview]
Message-ID: <cf0ca840-6e0d-2d99-cb23-eabf0ac5263b@linux.intel.com> (raw)
In-Reply-To: <20251013201535.6737-4-lkml@antheas.dev>

On Mon, 13 Oct 2025, Antheas Kapenekakis wrote:

> Some devices, such as the Z13 have multiple AURA devices connected
> to them by USB. In addition, they might have a WMI interface for
> RGB. In Windows, Armoury Crate exposes a unified brightness slider
> for all of them, with 3 brightness levels.
> 
> Therefore, to be synergistic in Linux, and support existing tooling
> such as UPower, allow adding listeners to the RGB device of the WMI
> interface. If WMI does not exist, lazy initialize the interface.
> 
> Reviewed-by: Luke D. Jones <luke@ljones.dev>
> Tested-by: Luke D. Jones <luke@ljones.dev>
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> ---
>  drivers/platform/x86/asus-wmi.c            | 118 ++++++++++++++++++---
>  include/linux/platform_data/x86/asus-wmi.h |  16 +++
>  2 files changed, 121 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
> index e72a2b5d158e..a2a7cd61fd59 100644
> --- a/drivers/platform/x86/asus-wmi.c
> +++ b/drivers/platform/x86/asus-wmi.c
> @@ -258,6 +258,8 @@ struct asus_wmi {
>  	int tpd_led_wk;
>  	struct led_classdev kbd_led;
>  	int kbd_led_wk;
> +	bool kbd_led_avail;
> +	bool kbd_led_registered;
>  	struct led_classdev lightbar_led;
>  	int lightbar_led_wk;
>  	struct led_classdev micmute_led;
> @@ -1530,6 +1532,53 @@ static void asus_wmi_battery_exit(struct asus_wmi *asus)
>  
>  /* LEDs ***********************************************************************/
>  
> +struct asus_hid_ref {
> +	struct list_head listeners;
> +	struct asus_wmi *asus;
> +	spinlock_t lock;

Please always document what a lock protects.

I started wonder why it needs to be spinlock?

It would seem rwsem is more natural for it as write is only needed at 
probe/remove time (if there's no good reason for using a spinlock).

You're also missing include.

> +};
> +
> +struct asus_hid_ref asus_ref = {

Should be static ?

> +	.listeners = LIST_HEAD_INIT(asus_ref.listeners),
> +	.asus = NULL,
> +	.lock = __SPIN_LOCK_UNLOCKED(asus_ref.lock),
> +};
> +
> +int asus_hid_register_listener(struct asus_hid_listener *bdev)
> +{
> +	unsigned long flags;
> +	int ret = 0;
> +
> +	spin_lock_irqsave(&asus_ref.lock, flags);
> +	list_add_tail(&bdev->list, &asus_ref.listeners);
> +	if (asus_ref.asus) {
> +		if (asus_ref.asus->kbd_led_registered && asus_ref.asus->kbd_led_wk >= 0)
> +			bdev->brightness_set(bdev, asus_ref.asus->kbd_led_wk);
> +
> +		if (!asus_ref.asus->kbd_led_registered) {
> +			ret = led_classdev_register(
> +				&asus_ref.asus->platform_device->dev,
> +				&asus_ref.asus->kbd_led);
> +			if (!ret)
> +				asus_ref.asus->kbd_led_registered = true;

I suggest you use guard() for the spinlock and return early where possible.

With guard() in use, you can do normal error handling here with return ret
immediately.

Please also add a local var for asus_ref.asus.

> +		}
> +	}
> +	spin_unlock_irqrestore(&asus_ref.lock, flags);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(asus_hid_register_listener);
> +
> +void asus_hid_unregister_listener(struct asus_hid_listener *bdev)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&asus_ref.lock, flags);
> +	list_del(&bdev->list);
> +	spin_unlock_irqrestore(&asus_ref.lock, flags);
> +}
> +EXPORT_SYMBOL_GPL(asus_hid_unregister_listener);
> +
>  /*
>   * These functions actually update the LED's, and are called from a
>   * workqueue. By doing this as separate work rather than when the LED
> @@ -1609,6 +1658,7 @@ static int kbd_led_read(struct asus_wmi *asus, int *level, int *env)
>  
>  static void do_kbd_led_set(struct led_classdev *led_cdev, int value)
>  {
> +	struct asus_hid_listener *listener;
>  	struct asus_wmi *asus;
>  	int max_level;
>  
> @@ -1616,25 +1666,39 @@ static void do_kbd_led_set(struct led_classdev *led_cdev, int value)
>  	max_level = asus->kbd_led.max_brightness;
>  
>  	asus->kbd_led_wk = clamp_val(value, 0, max_level);
> -	kbd_led_update(asus);
> +
> +	if (asus->kbd_led_avail)
> +		kbd_led_update(asus);
> +
> +	list_for_each_entry(listener, &asus_ref.listeners, list)
> +		listener->brightness_set(listener, asus->kbd_led_wk);
>  }
>  
>  static void kbd_led_set(struct led_classdev *led_cdev,
>  			enum led_brightness value)
>  {
> +	unsigned long flags;
> +
>  	/* Prevent disabling keyboard backlight on module unregister */
>  	if (led_cdev->flags & LED_UNREGISTERING)
>  		return;
>
> +	spin_lock_irqsave(&asus_ref.lock, flags);
>  	do_kbd_led_set(led_cdev, value);
> +	spin_unlock_irqrestore(&asus_ref.lock, flags);
>  }
>  
>  static void kbd_led_set_by_kbd(struct asus_wmi *asus, enum led_brightness value)
>  {
> -	struct led_classdev *led_cdev = &asus->kbd_led;
> +	struct led_classdev *led_cdev;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&asus_ref.lock, flags);
> +	led_cdev = &asus->kbd_led;
>  

I'd remove the empty line from the critical section.

I think you should mention the locking in the changelog too as it clearly 
impacts not only the new code.

>  	do_kbd_led_set(led_cdev, value);
>  	led_classdev_notify_brightness_hw_changed(led_cdev, asus->kbd_led_wk);
> +	spin_unlock_irqrestore(&asus_ref.lock, flags);
>  }
>  
>  static enum led_brightness kbd_led_get(struct led_classdev *led_cdev)
> @@ -1644,6 +1708,9 @@ static enum led_brightness kbd_led_get(struct led_classdev *led_cdev)
>  
>  	asus = container_of(led_cdev, struct asus_wmi, kbd_led);
>  
> +	if (!asus->kbd_led_avail)
> +		return asus->kbd_led_wk;
> +
>  	retval = kbd_led_read(asus, &value, NULL);
>  	if (retval < 0)
>  		return retval;
> @@ -1759,7 +1826,15 @@ static int camera_led_set(struct led_classdev *led_cdev,
>  
>  static void asus_wmi_led_exit(struct asus_wmi *asus)
>  {
> -	led_classdev_unregister(&asus->kbd_led);
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&asus_ref.lock, flags);
> +	asus_ref.asus = NULL;
> +	spin_unlock_irqrestore(&asus_ref.lock, flags);
> +
> +	if (asus->kbd_led_registered)
> +		led_classdev_unregister(&asus->kbd_led);
> +
>  	led_classdev_unregister(&asus->tpd_led);
>  	led_classdev_unregister(&asus->wlan_led);
>  	led_classdev_unregister(&asus->lightbar_led);
> @@ -1773,6 +1848,8 @@ static void asus_wmi_led_exit(struct asus_wmi *asus)
>  static int asus_wmi_led_init(struct asus_wmi *asus)
>  {
>  	int rv = 0, num_rgb_groups = 0, led_val;
> +	struct asus_hid_listener *listener;
> +	unsigned long flags;
>  
>  	if (asus->kbd_rgb_dev)
>  		kbd_rgb_mode_groups[num_rgb_groups++] = &kbd_rgb_mode_group;
> @@ -1797,23 +1874,38 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
>  			goto error;
>  	}
>  
> -	if (!kbd_led_read(asus, &led_val, NULL) && !dmi_check_system(asus_use_hid_led_dmi_ids)) {
> -		pr_info("using asus-wmi for asus::kbd_backlight\n");
> +	asus->kbd_led.name = "asus::kbd_backlight";
> +	asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED;
> +	asus->kbd_led.brightness_set = kbd_led_set;
> +	asus->kbd_led.brightness_get = kbd_led_get;
> +	asus->kbd_led.max_brightness = 3;
> +	asus->kbd_led_avail = !kbd_led_read(asus, &led_val, NULL);
> +
> +	if (asus->kbd_led_avail)
>  		asus->kbd_led_wk = led_val;
> -		asus->kbd_led.name = "asus::kbd_backlight";
> -		asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED;
> -		asus->kbd_led.brightness_set = kbd_led_set;
> -		asus->kbd_led.brightness_get = kbd_led_get;
> -		asus->kbd_led.max_brightness = 3;
> +	else
> +		asus->kbd_led_wk = -1;
>  
> -		if (num_rgb_groups != 0)
> -			asus->kbd_led.groups = kbd_rgb_mode_groups;
> +	if (asus->kbd_led_avail && num_rgb_groups != 0)
> +		asus->kbd_led.groups = kbd_rgb_mode_groups;

Can't this be placed into the block above?

>  
> +	spin_lock_irqsave(&asus_ref.lock, flags);
> +	if (asus->kbd_led_avail || !list_empty(&asus_ref.listeners)) {
>  		rv = led_classdev_register(&asus->platform_device->dev,
>  					   &asus->kbd_led);
> -		if (rv)
> +		if (rv) {
> +			spin_unlock_irqrestore(&asus_ref.lock, flags);

Please use scoped_guard() so you don't need to call unlock yourself.

Unrelated to this patch, I'd also simplify error label by adding return 0 
before it so the code after the label doesn't need if (rv) check.

>  			goto error;
> +		}
> +		asus->kbd_led_registered = true;
> +
> +		if (asus->kbd_led_wk >= 0) {
> +			list_for_each_entry(listener, &asus_ref.listeners, list)
> +				listener->brightness_set(listener, asus->kbd_led_wk);
> +		}
>  	}
> +	asus_ref.asus = asus;
> +	spin_unlock_irqrestore(&asus_ref.lock, flags);
>  
>  	if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_WIRELESS_LED)
>  			&& (asus->driver->quirks->wapf > 0)) {
> diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
> index 8a515179113d..f13a701f47a8 100644
> --- a/include/linux/platform_data/x86/asus-wmi.h
> +++ b/include/linux/platform_data/x86/asus-wmi.h
> @@ -163,11 +163,19 @@ enum asus_ally_mcu_hack {
>  	ASUS_WMI_ALLY_MCU_HACK_DISABLED,
>  };
>  
> +struct asus_hid_listener {
> +	struct list_head list;
> +	void (*brightness_set)(struct asus_hid_listener *listener, int brightness);
> +};

Please add kerneldoc to this struct and the exported functions.

> +
>  #if IS_REACHABLE(CONFIG_ASUS_WMI)
>  void set_ally_mcu_hack(enum asus_ally_mcu_hack status);
>  void set_ally_mcu_powersave(bool enabled);
>  int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval);
>  int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval);
> +
> +int asus_hid_register_listener(struct asus_hid_listener *cdev);
> +void asus_hid_unregister_listener(struct asus_hid_listener *cdev);
>  #else
>  static inline void set_ally_mcu_hack(enum asus_ally_mcu_hack status)
>  {
> @@ -184,6 +192,14 @@ static inline int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1,
>  {
>  	return -ENODEV;
>  }
> +
> +static inline int asus_hid_register_listener(struct asus_hid_listener *bdev)
> +{
> +	return -ENODEV;
> +}
> +static inline void asus_hid_unregister_listener(struct asus_hid_listener *bdev)
> +{
> +}
>  #endif
>  
>  /* To be used by both hid-asus and asus-wmi to determine which controls kbd_brightness */
> 

-- 
 i.


  reply	other threads:[~2025-10-15 11:59 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-13 20:15 [PATCH v6 0/7] HID: asus: Fix ASUS ROG Laptop's Keyboard backlight handling Antheas Kapenekakis
2025-10-13 20:15 ` [PATCH v6 1/7] HID: asus: refactor init sequence per spec Antheas Kapenekakis
2025-10-15 10:53   ` Ilpo Järvinen
2025-10-15 11:18     ` Antheas Kapenekakis
2025-10-15 11:30       ` Ilpo Järvinen
2025-10-13 20:15 ` [PATCH v6 2/7] HID: asus: prevent binding to all HID devices on ROG Antheas Kapenekakis
2025-10-15 10:59   ` Ilpo Järvinen
2025-10-13 20:15 ` [PATCH v6 3/7] platform/x86: asus-wmi: Add support for multiple kbd RGB handlers Antheas Kapenekakis
2025-10-15 11:59   ` Ilpo Järvinen [this message]
2025-10-15 15:45     ` Antheas Kapenekakis
2025-10-16 10:18       ` Ilpo Järvinen
2025-10-16 10:23         ` Antheas Kapenekakis
2025-10-16 10:38           ` Ilpo Järvinen
2025-10-13 20:15 ` [PATCH v6 4/7] HID: asus: listen to the asus-wmi brightness device instead of creating one Antheas Kapenekakis
2025-10-13 21:44   ` Denis Benato
2025-10-13 21:57     ` Antheas Kapenekakis
2025-10-13 22:06       ` Denis Benato
2025-10-13 22:18         ` Antheas Kapenekakis
2025-10-13 22:50           ` Denis Benato
2025-10-13 20:15 ` [PATCH v6 5/7] platform/x86: asus-wmi: remove unused keyboard backlight quirk Antheas Kapenekakis
2025-10-13 20:15 ` [PATCH v6 6/7] platform/x86: asus-wmi: add keyboard brightness event handler Antheas Kapenekakis
2025-10-15 12:18   ` Ilpo Järvinen
2025-10-15 15:38     ` Antheas Kapenekakis
2025-10-13 20:15 ` [PATCH v6 7/7] HID: asus: add support for the asus-wmi brightness handler Antheas Kapenekakis
2025-10-13 21:37   ` Denis Benato
2025-10-13 21:36 ` [PATCH v6 0/7] HID: asus: Fix ASUS ROG Laptop's Keyboard backlight handling Denis Benato
2025-10-13 21:45   ` Antheas Kapenekakis
2025-10-16 11:57 ` Denis Benato
2025-10-16 12:14   ` Antheas Kapenekakis
2025-10-16 12:19     ` Denis Benato
2025-10-16 12:28       ` Antheas Kapenekakis
2025-10-16 12:46         ` Denis Benato
2025-10-16 12:51           ` Antheas Kapenekakis
2025-10-16 14:32             ` Denis Benato
2025-10-16 14:44               ` Antheas Kapenekakis
2025-10-16 14:44                 ` Antheas Kapenekakis
2025-10-16 15:16                 ` Denis Benato
2025-10-16 15:08     ` Ilpo Järvinen
2025-10-16 16:16       ` Antheas Kapenekakis
2025-10-17  7:54         ` Antheas Kapenekakis
2025-10-17 11:00           ` Denis Benato
2025-10-17 11:21             ` Antheas Kapenekakis
2025-10-20 17:13           ` Ilpo Järvinen
2025-10-20 18:54             ` Antheas Kapenekakis
2025-10-17 10:36         ` Ilpo Järvinen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=cf0ca840-6e0d-2d99-cb23-eabf0ac5263b@linux.intel.com \
    --to=ilpo.jarvinen@linux.intel.com \
    --cc=benato.denis96@gmail.com \
    --cc=bentiss@kernel.org \
    --cc=corentin.chary@gmail.com \
    --cc=hdegoede@redhat.com \
    --cc=jikos@kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lkml@antheas.dev \
    --cc=luke@ljones.dev \
    --cc=platform-driver-x86@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.