* [RFC PATCH] platform/x86: acer-wmi: Add 4-zone RGB keyboard support for Acer Nitro AN515-58
@ 2026-05-03 6:19 Dirga Yuza
2026-05-10 11:59 ` kernel test robot
0 siblings, 1 reply; 2+ messages in thread
From: Dirga Yuza @ 2026-05-03 6:19 UTC (permalink / raw)
To: hansg, ilpo.jarvinen, jlee; +Cc: platform-driver-x86, linux-kernel, Dirga Yuza
This RFC adds support for the 4-zone RGB keyboard on Acer Nitro AN515-58.
The current acer-wmi driver does not provide support for keyboard
backlighting. This patch introduces support for the multicolor LED class
to expose the four zones to userspace.
The implementation is based on prior reverse engineering efforts of WMI
method ID 6, particularly from Linuwu-sense and
JafarAkhondali's acer-predator-turbo-and-rgb-keyboard-linux-module.
I do not have access to a Windows environment to capture traces myself.
This has been tested on AN515-58 under regular usage, including
suspend/resume cycles.
I would appreciate feedback on the following points:
1. acer-wmi currently relies heavily on global state. This patch follows
the same approach for consistency. However, given that this introduces
new structures, would it be preferable to group them into a private
per-device structure, or is continuing with global data acceptable
for this driver?
2. The current implementation registers four independent
led_classdev_mc instances (acer-wmi::kbd_backlight_N). In testing with
KDE Plasma, color updates propagate correctly across all zones, but
brightness control appears to affect only the last registered zone.
Is independent registration the preferred approach, or would a
single aggregate device controlling all zones be more appropriate?
3. The patch currently hardcodes four zones via a model-specific quirk.
Is this the preferred approach, or is there a more scalable way to handle
varying zone counts across devices?
4. Kconfig is updated to add `imply LEDS_CLASS_MULTICOLOR` for acer-wmi
and the code is wrapped with IS_REACHABLE() to handle optional dependency
on LEDS_CLASS. Is this correct approach for optional multicolor
LED support?
On this hardware, brightness keys (Fn+F9/F10) generate KEY_KBDILLUMUP/DOWN
input events. In my testing, these events do not appear to generate
corresponding release events, unlike other keys
(e.g., touchpad toggle or rfkill), which emit proper press/release pairs.
In KDE Plasma, this is interpreted as a held key, causing continuous
brightness changes.
Synthesizing press/release events would result in both the EC and
userspace adjusting their own brightness, causing duplicate changes.
The current behavior (no release events) also leads to incorrect
interpretation as a held key in KDE Plasma.
Therefore it is unclear whether these events should be ignored
entirely or handled in some other way. Guidance on the preferred approach
would be appreciated.
This is my first contribution in the kernel, so any feedback on design,
coding style, or submission process would be appreciated.
Signed-off-by: Dirga Yuza <dirgayuza123@gmail.com>
---
drivers/platform/x86/Kconfig | 1 +
drivers/platform/x86/acer-wmi.c | 141 ++++++++++++++++++++++++++++++++
2 files changed, 142 insertions(+)
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 2ffa4ecf6..c7eb3a587 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -179,6 +179,7 @@ config ACER_WMI
select INPUT_SPARSEKMAP
select LEDS_CLASS
select NEW_LEDS
+ imply LEDS_CLASS_MULTICOLOR
select ACPI_PLATFORM_PROFILE
help
This is a driver for newer Acer (and Wistron) laptops. It adds
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index e0eaaefb1..b7c3d6c28 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -36,6 +36,7 @@
#include <linux/unaligned.h>
#include <linux/bitfield.h>
#include <linux/bitmap.h>
+#include <linux/led-class-multicolor.h>
MODULE_AUTHOR("Carlos Corbacho");
MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
@@ -76,10 +77,16 @@ MODULE_LICENSE("GPL");
#define ACER_WMID_GET_GAMING_FAN_SPEED_METHODID 17
#define ACER_WMID_SET_GAMING_MISC_SETTING_METHODID 22
#define ACER_WMID_GET_GAMING_MISC_SETTING_METHODID 23
+#define ACER_WMID_SET_GAMING_STATIC_LED_METHODID 6
+
+#define ACER_GAMING_KBL_ZONES 4
#define ACER_GAMING_FAN_BEHAVIOR_CPU BIT(0)
#define ACER_GAMING_FAN_BEHAVIOR_GPU BIT(3)
+/* Bit 3 enables keyboard backlight update */
+#define ACER_GAMING_KBL_SET_ON BIT(3)
+
#define ACER_GAMING_FAN_BEHAVIOR_STATUS_MASK GENMASK_ULL(7, 0)
#define ACER_GAMING_FAN_BEHAVIOR_ID_MASK GENMASK_ULL(15, 0)
#define ACER_GAMING_FAN_BEHAVIOR_SET_CPU_MODE_MASK GENMASK(17, 16)
@@ -91,6 +98,9 @@ MODULE_LICENSE("GPL");
#define ACER_GAMING_FAN_SPEED_ID_MASK GENMASK_ULL(7, 0)
#define ACER_GAMING_FAN_SPEED_VALUE_MASK GENMASK_ULL(15, 8)
+/* Bits [43:40] selects target zones, setting all bits targets all zones*/
+#define ACER_GAMING_KBL_SET_ALL_ZONES GENMASK(43, 40)
+
#define ACER_GAMING_MISC_SETTING_STATUS_MASK GENMASK_ULL(7, 0)
#define ACER_GAMING_MISC_SETTING_INDEX_MASK GENMASK_ULL(7, 0)
#define ACER_GAMING_MISC_SETTING_VALUE_MASK GENMASK_ULL(15, 8)
@@ -310,6 +320,7 @@ struct hotkey_function_type_aa {
#define ACER_CAP_PLATFORM_PROFILE BIT(10)
#define ACER_CAP_HWMON BIT(11)
#define ACER_CAP_PWM BIT(12)
+#define ACER_CAP_KBL_FOUR_ZONE_RGB BIT(13)
/*
* Interface type flags
@@ -405,6 +416,7 @@ struct quirk_entry {
u8 gpu_fans;
u8 predator_v4;
u8 pwm;
+ u8 kbl_four_zone_rgb;
};
static struct quirk_entry *quirks;
@@ -427,6 +439,9 @@ static void __init set_quirks(void)
if (quirks->pwm)
interface->capability |= ACER_CAP_PWM;
+
+ if (quirks->kbl_four_zone_rgb)
+ interface->capability |= ACER_CAP_KBL_FOUR_ZONE_RGB;
}
static int __init dmi_matched(const struct dmi_system_id *dmi)
@@ -458,6 +473,7 @@ static struct quirk_entry quirk_acer_travelmate_2490 = {
static struct quirk_entry quirk_acer_nitro_an515_58 = {
.predator_v4 = 1,
.pwm = 1,
+ .kbl_four_zone_rgb = 1,
};
static struct quirk_entry quirk_acer_predator_ph315_53 = {
@@ -2762,6 +2778,118 @@ static u32 get_wmid_devices(void)
static int acer_wmi_hwmon_init(void);
+#if IS_REACHABLE(CONFIG_LEDS_CLASS_MULTICOLOR)
+
+static int acer_wmi_poll_and_enable_zones(void)
+{
+ acpi_status status;
+
+ status = WMI_gaming_execute_u64(ACER_WMID_GET_GAMING_SYS_INFO_METHODID,
+ 0, NULL);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+ status = WMI_gaming_execute_u64(ACER_WMID_GET_GAMING_LED_METHODID,
+ ACER_GAMING_KBL_SET_ON |
+ ACER_GAMING_KBL_SET_ALL_ZONES,
+ NULL);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ return 0;
+}
+
+struct acer_wmi_led_zone {
+ struct led_classdev_mc mc_cdev;
+ struct mc_subled subled_info[3];
+ u8 zone_id;
+};
+
+struct led_four_zone_set_param {
+ u8 zone;
+ u8 red;
+ u8 green;
+ u8 blue;
+} __packed;
+
+static struct acer_wmi_led_zone kbl_zones[ACER_GAMING_KBL_ZONES];
+
+static int acer_wmi_mc_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ int err;
+ struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(led_cdev);
+ struct acer_wmi_led_zone *zone = container_of(mc_cdev,
+ struct acer_wmi_led_zone, mc_cdev);
+ struct led_four_zone_set_param params;
+ struct acpi_buffer input;
+ acpi_status status;
+
+ err = led_mc_calc_color_components(mc_cdev, brightness);
+ if (err)
+ return err;
+
+ led_cdev->brightness = brightness;
+
+ params.zone = zone->zone_id;
+ params.red = mc_cdev->subled_info[0].brightness;
+ params.green = mc_cdev->subled_info[1].brightness;
+ params.blue = mc_cdev->subled_info[2].brightness;
+
+ input.length = sizeof(params);
+ input.pointer = ¶ms;
+
+ status = wmi_evaluate_method(WMID_GUID4, 0,
+ ACER_WMID_SET_GAMING_STATIC_LED_METHODID, &input, NULL);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ return 0;
+}
+
+static enum led_brightness
+acer_wmi_mc_brightness_get(struct led_classdev *led_cdev)
+{
+ return led_cdev->brightness;
+}
+
+static int acer_wmi_register_four_zone_leds(struct device *dev)
+{
+ int i, ret;
+
+ for (i = 0; i < ACER_GAMING_KBL_ZONES; i++) {
+ struct acer_wmi_led_zone *zone = &kbl_zones[i];
+
+ memset(zone, 0, sizeof(*zone));
+
+ zone->subled_info[0].color_index = LED_COLOR_ID_RED;
+ zone->subled_info[1].color_index = LED_COLOR_ID_GREEN;
+ zone->subled_info[2].color_index = LED_COLOR_ID_BLUE;
+
+ zone->mc_cdev.subled_info = zone->subled_info;
+ zone->mc_cdev.num_colors = 3;
+
+ /* WMI uses a bitmask as for zones. BIT(i) selects zone i */
+ zone->zone_id = BIT(i);
+
+ zone->mc_cdev.led_cdev.name = devm_kasprintf(dev, GFP_KERNEL,
+ "acer-wmi::kbd_backlight_%d", i + 1);
+ zone->mc_cdev.led_cdev.dev = dev;
+ zone->mc_cdev.led_cdev.brightness_set_blocking =
+ acer_wmi_mc_brightness_set;
+ zone->mc_cdev.led_cdev.brightness_get =
+ acer_wmi_mc_brightness_get;
+ zone->mc_cdev.led_cdev.max_brightness = 255;
+
+ ret = devm_led_classdev_multicolor_register(dev,
+ &zone->mc_cdev);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+#endif /* IS_REACHABLE(CONFIG_LEDS_CLASS_MULTICOLOR) */
+
/*
* Platform device
*/
@@ -2797,8 +2925,21 @@ static int acer_platform_probe(struct platform_device *device)
goto error_hwmon;
}
+ if (has_cap(ACER_CAP_KBL_FOUR_ZONE_RGB)) {
+#if IS_REACHABLE(CONFIG_LEDS_CLASS_MULTICOLOR)
+ err = acer_wmi_poll_and_enable_zones();
+ if (err)
+ goto error_kbl_four_zone_rgb;
+
+ err = acer_wmi_register_four_zone_leds(&device->dev);
+ if (err)
+ goto error_kbl_four_zone_rgb;
+#endif /* IS_REACHABLE(CONFIG_LEDS_CLASS_MULTICOLOR) */
+ }
+
return 0;
+error_kbl_four_zone_rgb:
error_hwmon:
error_platform_profile:
acer_rfkill_exit();
--
2.54.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [RFC PATCH] platform/x86: acer-wmi: Add 4-zone RGB keyboard support for Acer Nitro AN515-58
2026-05-03 6:19 [RFC PATCH] platform/x86: acer-wmi: Add 4-zone RGB keyboard support for Acer Nitro AN515-58 Dirga Yuza
@ 2026-05-10 11:59 ` kernel test robot
0 siblings, 0 replies; 2+ messages in thread
From: kernel test robot @ 2026-05-10 11:59 UTC (permalink / raw)
To: Dirga Yuza; +Cc: oe-kbuild-all
Hi Dirga,
[This is a private test report for your RFC patch.]
kernel test robot noticed the following build warnings:
[auto build test WARNING on linus/master]
[also build test WARNING on v7.1-rc2 next-20260508]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Dirga-Yuza/platform-x86-acer-wmi-Add-4-zone-RGB-keyboard-support-for-Acer-Nitro-AN515-58/20260510-030340
base: linus/master
patch link: https://lore.kernel.org/r/20260503062131.158944-1-dirgayuza123%40gmail.com
patch subject: [RFC PATCH] platform/x86: acer-wmi: Add 4-zone RGB keyboard support for Acer Nitro AN515-58
config: i386-allmodconfig (https://download.01.org/0day-ci/archive/20260510/202605101956.GFGLqih0-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260510/202605101956.GFGLqih0-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202605101956.GFGLqih0-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from include/linux/bitops.h:6,
from include/linux/kernel.h:23,
from drivers/platform/x86/acer-wmi.c:14:
drivers/platform/x86/acer-wmi.c: In function 'acer_wmi_poll_and_enable_zones':
include/linux/bits.h:48:27: warning: left shift count >= width of type [-Wshift-count-overflow]
48 | (type_max(t) << (l) & \
| ^~
include/linux/bits.h:51:33: note: in expansion of macro 'GENMASK_TYPE'
51 | #define GENMASK(h, l) GENMASK_TYPE(unsigned long, h, l)
| ^~~~~~~~~~~~
drivers/platform/x86/acer-wmi.c:102:39: note: in expansion of macro 'GENMASK'
102 | #define ACER_GAMING_KBL_SET_ALL_ZONES GENMASK(43, 40)
| ^~~~~~~
drivers/platform/x86/acer-wmi.c:2793:17: note: in expansion of macro 'ACER_GAMING_KBL_SET_ALL_ZONES'
2793 | ACER_GAMING_KBL_SET_ALL_ZONES,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> include/linux/bits.h:49:27: warning: right shift count >= width of type [-Wshift-count-overflow]
49 | type_max(t) >> (BITS_PER_TYPE(t) - 1 - (h)))))
| ^~
include/linux/bits.h:51:33: note: in expansion of macro 'GENMASK_TYPE'
51 | #define GENMASK(h, l) GENMASK_TYPE(unsigned long, h, l)
| ^~~~~~~~~~~~
drivers/platform/x86/acer-wmi.c:102:39: note: in expansion of macro 'GENMASK'
102 | #define ACER_GAMING_KBL_SET_ALL_ZONES GENMASK(43, 40)
| ^~~~~~~
drivers/platform/x86/acer-wmi.c:2793:17: note: in expansion of macro 'ACER_GAMING_KBL_SET_ALL_ZONES'
2793 | ACER_GAMING_KBL_SET_ALL_ZONES,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
In file included from include/linux/bitops.h:6,
from include/linux/kernel.h:23,
from acer-wmi.c:14:
acer-wmi.c: In function 'acer_wmi_poll_and_enable_zones':
include/linux/bits.h:48:27: warning: left shift count >= width of type [-Wshift-count-overflow]
48 | (type_max(t) << (l) & \
| ^~
include/linux/bits.h:51:33: note: in expansion of macro 'GENMASK_TYPE'
51 | #define GENMASK(h, l) GENMASK_TYPE(unsigned long, h, l)
| ^~~~~~~~~~~~
acer-wmi.c:102:39: note: in expansion of macro 'GENMASK'
102 | #define ACER_GAMING_KBL_SET_ALL_ZONES GENMASK(43, 40)
| ^~~~~~~
acer-wmi.c:2793:17: note: in expansion of macro 'ACER_GAMING_KBL_SET_ALL_ZONES'
2793 | ACER_GAMING_KBL_SET_ALL_ZONES,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> include/linux/bits.h:49:27: warning: right shift count >= width of type [-Wshift-count-overflow]
49 | type_max(t) >> (BITS_PER_TYPE(t) - 1 - (h)))))
| ^~
include/linux/bits.h:51:33: note: in expansion of macro 'GENMASK_TYPE'
51 | #define GENMASK(h, l) GENMASK_TYPE(unsigned long, h, l)
| ^~~~~~~~~~~~
acer-wmi.c:102:39: note: in expansion of macro 'GENMASK'
102 | #define ACER_GAMING_KBL_SET_ALL_ZONES GENMASK(43, 40)
| ^~~~~~~
acer-wmi.c:2793:17: note: in expansion of macro 'ACER_GAMING_KBL_SET_ALL_ZONES'
2793 | ACER_GAMING_KBL_SET_ALL_ZONES,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
vim +49 include/linux/bits.h
31299a5e0211241 Vincent Mailhol 2025-03-26 35
19408200c094858 Vincent Mailhol 2025-03-26 36 /*
19408200c094858 Vincent Mailhol 2025-03-26 37 * Generate a mask for the specified type @t. Additional checks are made to
19408200c094858 Vincent Mailhol 2025-03-26 38 * guarantee the value returned fits in that type, relying on
19408200c094858 Vincent Mailhol 2025-03-26 39 * -Wshift-count-overflow compiler check to detect incompatible arguments.
19408200c094858 Vincent Mailhol 2025-03-26 40 * For example, all these create build errors or warnings:
19408200c094858 Vincent Mailhol 2025-03-26 41 *
19408200c094858 Vincent Mailhol 2025-03-26 42 * - GENMASK(15, 20): wrong argument order
19408200c094858 Vincent Mailhol 2025-03-26 43 * - GENMASK(72, 15): doesn't fit unsigned long
19408200c094858 Vincent Mailhol 2025-03-26 44 * - GENMASK_U32(33, 15): doesn't fit in a u32
19408200c094858 Vincent Mailhol 2025-03-26 45 */
19408200c094858 Vincent Mailhol 2025-03-26 46 #define GENMASK_TYPE(t, h, l) \
19408200c094858 Vincent Mailhol 2025-03-26 47 ((t)(GENMASK_INPUT_CHECK(h, l) + \
19408200c094858 Vincent Mailhol 2025-03-26 48 (type_max(t) << (l) & \
19408200c094858 Vincent Mailhol 2025-03-26 @49 type_max(t) >> (BITS_PER_TYPE(t) - 1 - (h)))))
19408200c094858 Vincent Mailhol 2025-03-26 50
104ea1c84b91c9f Vincent Mailhol 2025-06-09 @51 #define GENMASK(h, l) GENMASK_TYPE(unsigned long, h, l)
104ea1c84b91c9f Vincent Mailhol 2025-06-09 52 #define GENMASK_ULL(h, l) GENMASK_TYPE(unsigned long long, h, l)
104ea1c84b91c9f Vincent Mailhol 2025-06-09 53
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-05-10 11:59 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-03 6:19 [RFC PATCH] platform/x86: acer-wmi: Add 4-zone RGB keyboard support for Acer Nitro AN515-58 Dirga Yuza
2026-05-10 11:59 ` kernel test robot
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.