Skip to content

Commit 7525566

Browse files
antheasij-intel
authored andcommitted
platform/x86: asus-wmi: add keyboard brightness event handler
The keyboard brightness control of Asus WMI keyboards is handled in 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. Since this handler is called from an interrupt context, defer the actual work to a workqueue. In the process, introduce ASUS_EV_MAX_BRIGHTNESS to hold the constant for maximum brightness since it is shared between hid-asus/asus-wmi. Reviewed-by: Luke D. Jones <luke@ljones.dev> Tested-by: Luke D. Jones <luke@ljones.dev> Acked-by: Benjamin Tissoires <bentiss@kernel.org> Reviewed-by: Denis Benato <benato.denis96@gmail.com> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev> Link: https://patch.msgid.link/20260122075044.5070-11-lkml@antheas.dev Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
1 parent d3133cc commit 7525566

2 files changed

Lines changed: 54 additions & 5 deletions

File tree

drivers/platform/x86/asus-wmi.c

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1719,6 +1719,44 @@ static void kbd_led_update_all(struct work_struct *work)
17191719
}
17201720
}
17211721

1722+
/*
1723+
* This function is called from hid-asus to inform asus-wmi of brightness
1724+
* changes initiated by the keyboard backlight keys.
1725+
*/
1726+
int asus_hid_event(enum asus_hid_event event)
1727+
{
1728+
struct asus_wmi *asus;
1729+
int brightness;
1730+
1731+
guard(spinlock_irqsave)(&asus_ref.lock);
1732+
asus = asus_ref.asus;
1733+
if (!asus || !asus->kbd_led_registered)
1734+
return -EBUSY;
1735+
1736+
brightness = asus->kbd_led_wk;
1737+
1738+
switch (event) {
1739+
case ASUS_EV_BRTUP:
1740+
brightness += 1;
1741+
break;
1742+
case ASUS_EV_BRTDOWN:
1743+
brightness -= 1;
1744+
break;
1745+
case ASUS_EV_BRTTOGGLE:
1746+
if (brightness >= ASUS_EV_MAX_BRIGHTNESS)
1747+
brightness = 0;
1748+
else
1749+
brightness += 1;
1750+
break;
1751+
}
1752+
1753+
asus->kbd_led_wk = clamp_val(brightness, 0, ASUS_EV_MAX_BRIGHTNESS);
1754+
asus->kbd_led_notify = true;
1755+
queue_work(asus->led_workqueue, &asus->kbd_led_work);
1756+
return 0;
1757+
}
1758+
EXPORT_SYMBOL_GPL(asus_hid_event);
1759+
17221760
/*
17231761
* These functions actually update the LED's, and are called from a
17241762
* workqueue. By doing this as separate work rather than when the LED
@@ -1801,13 +1839,11 @@ static void do_kbd_led_set(struct led_classdev *led_cdev, int value)
18011839
{
18021840
struct asus_hid_listener *listener;
18031841
struct asus_wmi *asus;
1804-
int max_level;
18051842

18061843
asus = container_of(led_cdev, struct asus_wmi, kbd_led);
1807-
max_level = asus->kbd_led.max_brightness;
18081844

18091845
scoped_guard(spinlock_irqsave, &asus_ref.lock)
1810-
asus->kbd_led_wk = clamp_val(value, 0, max_level);
1846+
asus->kbd_led_wk = clamp_val(value, 0, ASUS_EV_MAX_BRIGHTNESS);
18111847

18121848
if (asus->kbd_led_avail)
18131849
kbd_led_update(asus);
@@ -2011,7 +2047,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
20112047
asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED;
20122048
asus->kbd_led.brightness_set_blocking = kbd_led_set;
20132049
asus->kbd_led.brightness_get = kbd_led_get;
2014-
asus->kbd_led.max_brightness = 3;
2050+
asus->kbd_led.max_brightness = ASUS_EV_MAX_BRIGHTNESS;
20152051
asus->kbd_led_avail = !kbd_led_read(asus, &led_val, NULL);
20162052
INIT_WORK(&asus->kbd_led_work, kbd_led_update_all);
20172053

@@ -4530,7 +4566,7 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
45304566
return;
45314567
}
45324568
if (code == NOTIFY_KBD_BRTTOGGLE) {
4533-
if (led_value >= asus->kbd_led.max_brightness)
4569+
if (led_value >= ASUS_EV_MAX_BRIGHTNESS)
45344570
kbd_led_set_by_kbd(asus, 0);
45354571
else
45364572
kbd_led_set_by_kbd(asus, led_value + 1);

include/linux/platform_data/x86/asus-wmi.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,14 @@ struct asus_hid_listener {
178178
void (*brightness_set)(struct asus_hid_listener *listener, int brightness);
179179
};
180180

181+
enum asus_hid_event {
182+
ASUS_EV_BRTUP,
183+
ASUS_EV_BRTDOWN,
184+
ASUS_EV_BRTTOGGLE,
185+
};
186+
187+
#define ASUS_EV_MAX_BRIGHTNESS 3
188+
181189
#if IS_REACHABLE(CONFIG_ASUS_WMI)
182190
void set_ally_mcu_hack(enum asus_ally_mcu_hack status);
183191
void set_ally_mcu_powersave(bool enabled);
@@ -186,6 +194,7 @@ int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval);
186194
int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval);
187195
int asus_hid_register_listener(struct asus_hid_listener *cdev);
188196
void asus_hid_unregister_listener(struct asus_hid_listener *cdev);
197+
int asus_hid_event(enum asus_hid_event event);
189198
#else
190199
static inline void set_ally_mcu_hack(enum asus_ally_mcu_hack status)
191200
{
@@ -213,6 +222,10 @@ static inline int asus_hid_register_listener(struct asus_hid_listener *bdev)
213222
static inline void asus_hid_unregister_listener(struct asus_hid_listener *bdev)
214223
{
215224
}
225+
static inline int asus_hid_event(enum asus_hid_event event)
226+
{
227+
return -ENODEV;
228+
}
216229
#endif
217230

218231
#endif /* __PLATFORM_DATA_X86_ASUS_WMI_H */

0 commit comments

Comments
 (0)