Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Antheas Kapenekakis and committed by
Ilpo Järvinen
7525566a d3133cca

+54 -5
+41 -5
drivers/platform/x86/asus-wmi.c
··· 1720 1720 } 1721 1721 1722 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 + 1760 + /* 1723 1761 * These functions actually update the LED's, and are called from a 1724 1762 * workqueue. By doing this as separate work rather than when the LED 1725 1763 * subsystem asks, we avoid messing with the Asus ACPI stuff during a ··· 1839 1801 { 1840 1802 struct asus_hid_listener *listener; 1841 1803 struct asus_wmi *asus; 1842 - int max_level; 1843 1804 1844 1805 asus = container_of(led_cdev, struct asus_wmi, kbd_led); 1845 - max_level = asus->kbd_led.max_brightness; 1846 1806 1847 1807 scoped_guard(spinlock_irqsave, &asus_ref.lock) 1848 - asus->kbd_led_wk = clamp_val(value, 0, max_level); 1808 + asus->kbd_led_wk = clamp_val(value, 0, ASUS_EV_MAX_BRIGHTNESS); 1849 1809 1850 1810 if (asus->kbd_led_avail) 1851 1811 kbd_led_update(asus); ··· 2047 2011 asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED; 2048 2012 asus->kbd_led.brightness_set_blocking = kbd_led_set; 2049 2013 asus->kbd_led.brightness_get = kbd_led_get; 2050 - asus->kbd_led.max_brightness = 3; 2014 + asus->kbd_led.max_brightness = ASUS_EV_MAX_BRIGHTNESS; 2051 2015 asus->kbd_led_avail = !kbd_led_read(asus, &led_val, NULL); 2052 2016 INIT_WORK(&asus->kbd_led_work, kbd_led_update_all); 2053 2017 ··· 4566 4530 return; 4567 4531 } 4568 4532 if (code == NOTIFY_KBD_BRTTOGGLE) { 4569 - if (led_value >= asus->kbd_led.max_brightness) 4533 + if (led_value >= ASUS_EV_MAX_BRIGHTNESS) 4570 4534 kbd_led_set_by_kbd(asus, 0); 4571 4535 else 4572 4536 kbd_led_set_by_kbd(asus, led_value + 1);
+13
include/linux/platform_data/x86/asus-wmi.h
··· 178 178 void (*brightness_set)(struct asus_hid_listener *listener, int brightness); 179 179 }; 180 180 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 + 181 189 #if IS_REACHABLE(CONFIG_ASUS_WMI) 182 190 void set_ally_mcu_hack(enum asus_ally_mcu_hack status); 183 191 void set_ally_mcu_powersave(bool enabled); ··· 194 186 int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval); 195 187 int asus_hid_register_listener(struct asus_hid_listener *cdev); 196 188 void asus_hid_unregister_listener(struct asus_hid_listener *cdev); 189 + int asus_hid_event(enum asus_hid_event event); 197 190 #else 198 191 static inline void set_ally_mcu_hack(enum asus_ally_mcu_hack status) 199 192 { ··· 221 212 } 222 213 static inline void asus_hid_unregister_listener(struct asus_hid_listener *bdev) 223 214 { 215 + } 216 + static inline int asus_hid_event(enum asus_hid_event event) 217 + { 218 + return -ENODEV; 224 219 } 225 220 #endif 226 221