Message ID | 20250324210151.6042-8-lkml@antheas.dev (mailing list archive) |
---|---|
State | Changes Requested, archived |
Headers | show |
Series | HID: asus: Add RGB Support to Asus Z13, Ally, unify backlight asus-wmi, and Z13 QOL | expand |
On Mon, 24 Mar 2025, Antheas Kapenekakis wrote: > Currenlty, the keyboard brightness control of Asus WMI keyboards is > handled in the kernel, which leads to the shortcut going from > brightness 0, to 1, to 2, and 3. > > However, for HID keyboards it is exposed as a key and handled by the > user's desktop environment. For the toggle button, this means that > brightness control becomes on/off. In addition, in the absence of a > DE, the keyboard brightness does not work. > > Therefore, expose an event handler for the keyboard brightness control > which can then be used by hid-asus. > > 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 | 39 ++++++++++++++++++++++ > include/linux/platform_data/x86/asus-wmi.h | 11 ++++++ > 2 files changed, 50 insertions(+) > > diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c > index ff1d7ccb3982f..27468d67dba09 100644 > --- a/drivers/platform/x86/asus-wmi.c > +++ b/drivers/platform/x86/asus-wmi.c > @@ -1536,6 +1536,45 @@ void asus_hid_unregister_listener(struct asus_hid_listener *bdev) > } > EXPORT_SYMBOL_GPL(asus_hid_unregister_listener); > > +static void do_kbd_led_set(struct led_classdev *led_cdev, int value); > + > +int asus_hid_event(enum asus_hid_event event) > +{ > + unsigned long flags; > + int brightness; > + > + spin_lock_irqsave(&asus_ref.lock, flags); > + if (!asus_ref.asus || !asus_ref.asus->kbd_led_registered) { > + spin_unlock_irqrestore(&asus_ref.lock, flags); > + return -EBUSY; > + } > + brightness = asus_ref.asus->kbd_led_wk; > + > + switch (event) { > + case ASUS_EV_BRTUP: > + brightness += 1; > + break; > + case ASUS_EV_BRTDOWN: > + brightness -= 1; > + break; > + case ASUS_EV_BRTTOGGLE: > + if (brightness >= 3) Add ASUS_EV_MAX_BRIGHTNESS instead of a literal? > + brightness = 0; > + else > + brightness += 1; > + break; > + } > + > + do_kbd_led_set(&asus_ref.asus->kbd_led, brightness); > + led_classdev_notify_brightness_hw_changed(&asus_ref.asus->kbd_led, > + asus_ref.asus->kbd_led_wk); > + > + spin_unlock_irqrestore(&asus_ref.lock, flags); > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(asus_hid_event); > + > /* > * These functions actually update the LED's, and are called from a > * workqueue. By doing this as separate work rather than when the LED > diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h > index c513b5a732323..9adbe8abef090 100644 > --- a/include/linux/platform_data/x86/asus-wmi.h > +++ b/include/linux/platform_data/x86/asus-wmi.h > @@ -162,11 +162,18 @@ struct asus_hid_listener { > void (*brightness_set)(struct asus_hid_listener *listener, int brightness); > }; > > +enum asus_hid_event { > + ASUS_EV_BRTUP, > + ASUS_EV_BRTDOWN, > + ASUS_EV_BRTTOGGLE, > +}; > + > #if IS_REACHABLE(CONFIG_ASUS_WMI) > 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); > +int asus_hid_event(enum asus_hid_event event); > #else > static inline int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, > u32 *retval) > @@ -181,6 +188,10 @@ static inline int asus_hid_register_listener(struct asus_hid_listener *bdev) > static inline void asus_hid_unregister_listener(struct asus_hid_listener *bdev) > { > } > +static inline int asus_hid_event(enum asus_hid_event event) > +{ > + return -ENODEV; > +} > #endif > > #endif /* __PLATFORM_DATA_X86_ASUS_WMI_H */ >
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index ff1d7ccb3982f..27468d67dba09 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1536,6 +1536,45 @@ void asus_hid_unregister_listener(struct asus_hid_listener *bdev) } EXPORT_SYMBOL_GPL(asus_hid_unregister_listener); +static void do_kbd_led_set(struct led_classdev *led_cdev, int value); + +int asus_hid_event(enum asus_hid_event event) +{ + unsigned long flags; + int brightness; + + spin_lock_irqsave(&asus_ref.lock, flags); + if (!asus_ref.asus || !asus_ref.asus->kbd_led_registered) { + spin_unlock_irqrestore(&asus_ref.lock, flags); + return -EBUSY; + } + brightness = asus_ref.asus->kbd_led_wk; + + switch (event) { + case ASUS_EV_BRTUP: + brightness += 1; + break; + case ASUS_EV_BRTDOWN: + brightness -= 1; + break; + case ASUS_EV_BRTTOGGLE: + if (brightness >= 3) + brightness = 0; + else + brightness += 1; + break; + } + + do_kbd_led_set(&asus_ref.asus->kbd_led, brightness); + led_classdev_notify_brightness_hw_changed(&asus_ref.asus->kbd_led, + asus_ref.asus->kbd_led_wk); + + spin_unlock_irqrestore(&asus_ref.lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(asus_hid_event); + /* * These functions actually update the LED's, and are called from a * workqueue. By doing this as separate work rather than when the LED diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index c513b5a732323..9adbe8abef090 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -162,11 +162,18 @@ struct asus_hid_listener { void (*brightness_set)(struct asus_hid_listener *listener, int brightness); }; +enum asus_hid_event { + ASUS_EV_BRTUP, + ASUS_EV_BRTDOWN, + ASUS_EV_BRTTOGGLE, +}; + #if IS_REACHABLE(CONFIG_ASUS_WMI) 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); +int asus_hid_event(enum asus_hid_event event); #else static inline int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval) @@ -181,6 +188,10 @@ static inline int asus_hid_register_listener(struct asus_hid_listener *bdev) static inline void asus_hid_unregister_listener(struct asus_hid_listener *bdev) { } +static inline int asus_hid_event(enum asus_hid_event event) +{ + return -ENODEV; +} #endif #endif /* __PLATFORM_DATA_X86_ASUS_WMI_H */