.../ABI/testing/sysfs-driver-hid-lamparray | 16 + drivers/hid/Kconfig | 18 + drivers/hid/Makefile | 2 + drivers/hid/hid-generic.c | 38 + drivers/hid/hid-lamparray.c | 812 ++++++++++++++++++ include/linux/hid-lamparray.h | 88 ++ 6 files changed, 974 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-lamparray create mode 100644 drivers/hid/hid-lamparray.c create mode 100644 include/linux/hid-lamparray.h
Add a new hid-lamparray helper module and integrate it with the hid-generic driver. While more complex lamparray handling should be done in userspace via hidraw, providing a small module to add basic lamparray support makes it possible for userspace software to interact with lamparrays by simply using well-known APIs of the LED subsystem. One use-case would be to enable desktop environments to support keyboard backlight control out of the box for HID lamparray devices without having to implement the whole HID protocol themselves. This patch is based on previous discussions: https://lore.kernel.org/all/1fb08a74-62c7-4d0c-ba5d-648e23082dcb@tuxedocomputers.com/ The helper provides basic support for devices exposing a Lighting/LampArray application collection (usage page 0x59) and registers a single-zone RGB LED representation via the LED subsystem. hid-generic now checks for LampArray support after hid_parse() and optionally registers a lamparray instance. Failures in the helper do not abort device probe to keep the driver logic otherwise unchanged. LampArray resources are released on driver remove. This commit was successfully tested on the Microsoft MacroPad reference implementation (https://github.com/microsoft/RP2040MacropadHidSample 1d6c3ad) and in combination with the tuxedo_nb04_wmi driver, albeit only fully functional with a recent fix posted to the LKML (https://lore.kernel.org/all/20260826081149.235487-2-aer@tuxedocomputers.com). v5: - Proper hardware detection (no quirks necessary anymore) - Add documentation for new sysfs knob - Pass limits of the device to sysfs (intesities & brightness) - More flexible Kconfig (use tristate) - Improved locking - Several memory leak and (de-)initialization fixes - Don't read current color values from hardware (the HID spec does not offer this option) - Remove redundant report dump functionality v4: - Restrict CONFIG_HID_LAMPARRAY to built-in configurations only to fix additional randconfig build errors v3: - Squash V1 and V2 into one patch v2: - Fix Kconfig to avoid build errors when LEDS_CLASS_MULTICOLOR is disabled Aaron Erhardt (2): HID: lamparray: add new LampArray helper module HID: generic: add LampArray support via hid-lamparray helper .../ABI/testing/sysfs-driver-hid-lamparray | 16 + drivers/hid/Kconfig | 18 + drivers/hid/Makefile | 2 + drivers/hid/hid-generic.c | 38 + drivers/hid/hid-lamparray.c | 812 ++++++++++++++++++ include/linux/hid-lamparray.h | 88 ++ 6 files changed, 974 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-lamparray create mode 100644 drivers/hid/hid-lamparray.c create mode 100644 include/linux/hid-lamparray.h -- 2.43.0
Am 03.09.26 um 09:35 schrieb Aaron Erhardt: > Add a new hid-lamparray helper module and integrate it with the > hid-generic driver. > > While more complex lamparray handling should be done in userspace via > hidraw, providing a small module to add basic lamparray support makes it > possible for userspace software to interact with lamparrays by simply > using well-known APIs of the LED subsystem. One use-case would be to > enable desktop environments to support keyboard backlight control out of > the box for HID lamparray devices without having to implement the whole > HID protocol themselves. > > This patch is based on previous discussions: > https://lore.kernel.org/all/1fb08a74-62c7-4d0c-ba5d-648e23082dcb@tuxedocomputers.com/ > > The helper provides basic support for devices exposing a > Lighting/LampArray application collection (usage page 0x59) and > registers a single-zone RGB LED representation via the LED > subsystem. > > hid-generic now checks for LampArray support after hid_parse() and > optionally registers a lamparray instance. Failures in the helper > do not abort device probe to keep the driver logic otherwise unchanged. Another question that came to my mind while doing some tests on what will soon be posted as v6 is the following: Should we really set everything to zero as a default? Up to v4, the LEDs were set to full brightness by default which would be quite annoying in dark environments or when the LEDs of the device are really bright. Turning everything off like the current implementation on the other side makes things look like they don't work until a userspace program takes over control. So I was wondering whether it would be better to just leave everything in autonomous mode until userspace starts writing to the LED. I'm not sure yet what the best solution is, so I would like to have some feedback on that design if possible. > > LampArray resources are released on driver remove. > > This commit was successfully tested on the Microsoft MacroPad reference > implementation (https://github.com/microsoft/RP2040MacropadHidSample > 1d6c3ad) and in combination with the tuxedo_nb04_wmi driver, albeit > only fully functional with a recent fix posted to the LKML > (https://lore.kernel.org/all/20260826081149.235487-2-aer@tuxedocomputers.com). > > v5: > - Proper hardware detection (no quirks necessary anymore) > - Add documentation for new sysfs knob > - Pass limits of the device to sysfs (intesities & brightness) > - More flexible Kconfig (use tristate) > - Improved locking > - Several memory leak and (de-)initialization fixes > - Don't read current color values from hardware (the HID spec does not > offer this option) > - Remove redundant report dump functionality > v4: > - Restrict CONFIG_HID_LAMPARRAY to built-in configurations only to fix > additional randconfig build errors > v3: > - Squash V1 and V2 into one patch > v2: > - Fix Kconfig to avoid build errors when LEDS_CLASS_MULTICOLOR is > disabled > > Aaron Erhardt (2): > HID: lamparray: add new LampArray helper module > HID: generic: add LampArray support via hid-lamparray helper > > .../ABI/testing/sysfs-driver-hid-lamparray | 16 + > drivers/hid/Kconfig | 18 + > drivers/hid/Makefile | 2 + > drivers/hid/hid-generic.c | 38 + > drivers/hid/hid-lamparray.c | 812 ++++++++++++++++++ > include/linux/hid-lamparray.h | 88 ++ > 6 files changed, 974 insertions(+) > create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-lamparray > create mode 100644 drivers/hid/hid-lamparray.c > create mode 100644 include/linux/hid-lamparray.h >
Am 03.09.26 um 09:35 schrieb Aaron Erhardt: > Add a new hid-lamparray helper module and integrate it with the > hid-generic driver. > > While more complex lamparray handling should be done in userspace via > hidraw, providing a small module to add basic lamparray support makes it > possible for userspace software to interact with lamparrays by simply > using well-known APIs of the LED subsystem. One use-case would be to > enable desktop environments to support keyboard backlight control out of > the box for HID lamparray devices without having to implement the whole > HID protocol themselves. > > This patch is based on previous discussions: > https://lore.kernel.org/all/1fb08a74-62c7-4d0c-ba5d-648e23082dcb@tuxedocomputers.com/ > > The helper provides basic support for devices exposing a > Lighting/LampArray application collection (usage page 0x59) and > registers a single-zone RGB LED representation via the LED > subsystem. > > hid-generic now checks for LampArray support after hid_parse() and > optionally registers a lamparray instance. Failures in the helper > do not abort device probe to keep the driver logic otherwise unchanged. > > LampArray resources are released on driver remove. > > This commit was successfully tested on the Microsoft MacroPad reference > implementation (https://github.com/microsoft/RP2040MacropadHidSample > 1d6c3ad) and in combination with the tuxedo_nb04_wmi driver, albeit > only fully functional with a recent fix posted to the LKML > (https://lore.kernel.org/all/20260826081149.235487-2-aer@tuxedocomputers.com). Nice work, it works on my ASUS Prime B650-Plus. However the behavior of the brightness attribute is a bit strange: - manually setting "brightness" does not change anything (max. is 1) - setting RGB to "0 0 0" causes "brightness" to become 0 - setting RGB to a non-zero value causes "brightness" to become 1 Any idea why this happens? I can check if the same problems also exists under Windows, if requested. Thanks, Armin Wolf > v5: > - Proper hardware detection (no quirks necessary anymore) > - Add documentation for new sysfs knob > - Pass limits of the device to sysfs (intesities & brightness) > - More flexible Kconfig (use tristate) > - Improved locking > - Several memory leak and (de-)initialization fixes > - Don't read current color values from hardware (the HID spec does not > offer this option) > - Remove redundant report dump functionality > v4: > - Restrict CONFIG_HID_LAMPARRAY to built-in configurations only to fix > additional randconfig build errors > v3: > - Squash V1 and V2 into one patch > v2: > - Fix Kconfig to avoid build errors when LEDS_CLASS_MULTICOLOR is > disabled > > Aaron Erhardt (2): > HID: lamparray: add new LampArray helper module > HID: generic: add LampArray support via hid-lamparray helper > > .../ABI/testing/sysfs-driver-hid-lamparray | 16 + > drivers/hid/Kconfig | 18 + > drivers/hid/Makefile | 2 + > drivers/hid/hid-generic.c | 38 + > drivers/hid/hid-lamparray.c | 812 ++++++++++++++++++ > include/linux/hid-lamparray.h | 88 ++ > 6 files changed, 974 insertions(+) > create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-lamparray > create mode 100644 drivers/hid/hid-lamparray.c > create mode 100644 include/linux/hid-lamparray.h >
Am 04.09.26 um 22:49 schrieb Armin Wolf: > Am 03.09.26 um 09:35 schrieb Aaron Erhardt: > >> Add a new hid-lamparray helper module and integrate it with the >> hid-generic driver. >> >> While more complex lamparray handling should be done in userspace via >> hidraw, providing a small module to add basic lamparray support makes it >> possible for userspace software to interact with lamparrays by simply >> using well-known APIs of the LED subsystem. One use-case would be to >> enable desktop environments to support keyboard backlight control out of >> the box for HID lamparray devices without having to implement the whole >> HID protocol themselves. >> >> This patch is based on previous discussions: >> https://lore.kernel.org/all/1fb08a74-62c7-4d0c-ba5d-648e23082dcb@tuxedocomputers.com/ >> >> The helper provides basic support for devices exposing a >> Lighting/LampArray application collection (usage page 0x59) and >> registers a single-zone RGB LED representation via the LED >> subsystem. >> >> hid-generic now checks for LampArray support after hid_parse() and >> optionally registers a lamparray instance. Failures in the helper >> do not abort device probe to keep the driver logic otherwise unchanged. >> >> LampArray resources are released on driver remove. >> >> This commit was successfully tested on the Microsoft MacroPad reference >> implementation (https://github.com/microsoft/RP2040MacropadHidSample >> 1d6c3ad) and in combination with the tuxedo_nb04_wmi driver, albeit >> only fully functional with a recent fix posted to the LKML >> (https://lore.kernel.org/all/20260826081149.235487-2-aer@tuxedocomputers.com). > > Nice work, it works on my ASUS Prime B650-Plus. However the behavior of the brightness > attribute is a bit strange: > > - manually setting "brightness" does not change anything (max. is 1) > - setting RGB to "0 0 0" causes "brightness" to become 0 > - setting RGB to a non-zero value causes "brightness" to become 1 > > Any idea why this happens? I can check if the same problems also exists under Windows, > if requested. > > Thanks, > Armin Wolf > It is completely normal for LampArray devices to only offer two brightness values (1 and 0) for turning the whole LED on and off. Since a lot of userspace software seems to never use brightness (it is more convenient to adjust the RGB channels directly), this was not even properly implemented in the MacropadHidSample until recently: https://github.com/microsoft/RP2040MacropadHidSample/commit/cfc29120a3910c5772976da29ecd57392dfd44d6 Thus, I think it is likely, that the implementation is broken and simply ignores brightness. The driver just forwards this to the device. However, the RGB values (aka. multi_intensity) should not interfere with the brightness. Yet, I wasn't able to reproduce this on the Macropad. Capping the brightness to 1 is normal on the other hand, at least if that's the maxIntensity reported by your device. So the only really odd thing for me would be the RGB values influencing the brightness. Please provide more detailed feedback if you can since I can't reproduce this on the hardware available to me. If you want to investigate the LampArray capabilities of your device, you're probably better off with userspace tooling like my lampctl fork: https://github.com/tuxedo-aer/lampctl You can adjust the hardcoded brightness here to see whether your device honors the brightness value or not: https://github.com/tuxedo-aer/lampctl/blob/main/crates/lamparray/src/hid.rs#L36 >> v5: >> - Proper hardware detection (no quirks necessary anymore) >> - Add documentation for new sysfs knob >> - Pass limits of the device to sysfs (intesities & brightness) >> - More flexible Kconfig (use tristate) >> - Improved locking >> - Several memory leak and (de-)initialization fixes >> - Don't read current color values from hardware (the HID spec does not >> offer this option) >> - Remove redundant report dump functionality >> v4: >> - Restrict CONFIG_HID_LAMPARRAY to built-in configurations only to fix >> additional randconfig build errors >> v3: >> - Squash V1 and V2 into one patch >> v2: >> - Fix Kconfig to avoid build errors when LEDS_CLASS_MULTICOLOR is >> disabled >> >> Aaron Erhardt (2): >> HID: lamparray: add new LampArray helper module >> HID: generic: add LampArray support via hid-lamparray helper >> >> .../ABI/testing/sysfs-driver-hid-lamparray | 16 + >> drivers/hid/Kconfig | 18 + >> drivers/hid/Makefile | 2 + >> drivers/hid/hid-generic.c | 38 + >> drivers/hid/hid-lamparray.c | 812 ++++++++++++++++++ >> include/linux/hid-lamparray.h | 88 ++ >> 6 files changed, 974 insertions(+) >> create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-lamparray >> create mode 100644 drivers/hid/hid-lamparray.c >> create mode 100644 include/linux/hid-lamparray.h >> >
These are four fixes on top of the v5 series, posted 2026-09-03: https://lore.kernel.org/linux-input/20260903073602.3815258-1-aer@tuxedocomputers.com/ Tested on an Acer Predator PT14-52T, which has two LampArray devices: a USB keyboard (05AF:767A) and an I2C ENE controller (0CF2:5130). With v5 as posted, the keyboard does not probe. LampCount reads back 0, and once that is fixed the level counts read back 0 as well, which divides by zero in led_mc_calc_color_components() during probe and takes the USB hub worker down with it. Patches 1 and 2 cover the reads and the validation; this is the same problem Aaron and Werner discussed in this thread, with a backtrace from hardware that hits it. Patch 3 makes use_leds_uapi transfer control in both directions. Autonomous mode is currently only set at probe, so writing 1 re-registers the LED class device without taking the hardware back, and updates sent afterwards are ignored. Patch 4 blanks the lamps across suspend. On this machine, the lighting accounts for 9.21W of the 12.35W s2idle power draw against 3.14W with the lamps blanked from this driver, so this is most of the suspend power on a laptop with RGB. This was also tested with one of the 2 lights on the ENE controller still on; this patch does not control both zones. Please treat these as input for v6 rather than a separate series; squashing them in is fine by me, and I will rebase and retest against v6 when it arrives. Two things I have not fixed: - The ENE controller exposes two LampArrayAttributesReport collections. lamparray_parse_update_report() has no first-match guard, so the second overwrites the first and only one zone is claimed; the other stays in firmware control. This is the multi-zone question from Werner's reply. I really believe that multi-zone support should exist, but I have not included it because I haven't started it; uni is taking away a lot of my time currently. - hid_device_io_start() in lamparray_register() may no longer be needed: hid_hw_raw_request() is synchronous and does not go through hid_input_report(), so it does not need driver_input_lock released. That would also address the second [High] item from the Sashiko review. Cristian Mazzotta (4): HID: lamparray: read attribute reports synchronously HID: lamparray: raise log level of fatal probe errors HID: lamparray: transfer control when use_leds_uapi changes HID: lamparray: blank lamps across suspend and restore on resume drivers/hid/hid-generic.c | 27 ++++++ drivers/hid/hid-lamparray.c | 162 +++++++++++++++++++++++++++++----- include/linux/hid-lamparray.h | 35 ++++++++ 3 files changed, 200 insertions(+), 24 deletions(-) base-commit: 9b298109e37e5caf4b6800198c4907a5a6bf00ae -- 2.55.0
Am 09.09.26 um 18:52 schrieb Cristian Mazzotta: > These are four fixes on top of the v5 series, posted 2026-09-03: > https://lore.kernel.org/linux-input/20260903073602.3815258-1-aer@tuxedocomputers.com/ > > Tested on an Acer Predator PT14-52T, which has two LampArray devices: a > USB keyboard (05AF:767A) and an I2C ENE controller (0CF2:5130). > > With v5 as posted, the keyboard does not probe. LampCount reads back 0, > and once that is fixed the level counts read back 0 as well, which > divides by zero in led_mc_calc_color_components() during probe and takes > the USB hub worker down with it. Patches 1 and 2 cover the reads and the > validation; this is the same problem Aaron and Werner discussed in this > thread, with a backtrace from hardware that hits it. > > Patch 3 makes use_leds_uapi transfer control in both directions. > Autonomous mode is currently only set at probe, so writing 1 re-registers > the LED class device without taking the hardware back, and updates sent > afterwards are ignored. > > Patch 4 blanks the lamps across suspend. On this machine, the lighting > accounts for 9.21W of the 12.35W s2idle power draw against 3.14W with > the lamps blanked from this driver, so this is most of the suspend power > on a laptop with RGB. This was also tested with one of the 2 lights on > the ENE controller still on; this patch does not control both zones. > > Please treat these as input for v6 rather than a separate series; > squashing them in is fine by me, and I will rebase and retest against v6 > when it arrives. Thanks for your patches! I have reviewed and tested them and the only thing I noticed is that wrapping the resume/suspend methods with pm_ptr is missing in the final patch. Otherwise everything LGTM. I will follow up with v6 soon, adding you with "Co-developed-by" on the relevant commits. Best regards Aaron > > Two things I have not fixed: > > - The ENE controller exposes two LampArrayAttributesReport collections. > lamparray_parse_update_report() has no first-match guard, so the second > overwrites the first and only one zone is claimed; the other stays in > firmware control. This is the multi-zone question from Werner's reply. > I really believe that multi-zone support should exist, but I have not > included it because I haven't started it; uni is taking away a lot of > my time currently. Ack. I think this is better suited for a separate patch series, unless it is trivial to add. > > - hid_device_io_start() in lamparray_register() may no longer be needed: > hid_hw_raw_request() is synchronous and does not go through > hid_input_report(), so it does not need driver_input_lock released. > That would also address the second [High] item from the Sashiko review. Ack. I will look into this for v6. > > Cristian Mazzotta (4): > HID: lamparray: read attribute reports synchronously > HID: lamparray: raise log level of fatal probe errors > HID: lamparray: transfer control when use_leds_uapi changes > HID: lamparray: blank lamps across suspend and restore on resume > > drivers/hid/hid-generic.c | 27 ++++++ > drivers/hid/hid-lamparray.c | 162 +++++++++++++++++++++++++++++----- > include/linux/hid-lamparray.h | 35 ++++++++ > 3 files changed, 200 insertions(+), 24 deletions(-) > > > base-commit: 9b298109e37e5caf4b6800198c4907a5a6bf00ae
lamparray_read_attributes_report() and lamparray_get_lamp_attributes()
use hid_hw_request(HID_REQ_GET_REPORT) followed by hid_hw_wait(), then
read the results out of field->value[]. hid_hw_request() is asynchronous
and hid_hw_wait() only clears the output queue, so the values are still
read before the transfer has completed.
On an Acer Predator PT14-52T (USB keyboard 05AF:767A), this returns zero
for LampCount, and then zero for red, green, blue, and intensity counts.
The last one is evil: max_brightness is passed to
led_mc_calc_color_components() as a divisor during
lamparray_register_led(), resulting in a divide by zero during probe:
Oops: divide error: 0000 [#1] SMP NOPTI
RIP: 0010:led_mc_calc_color_components+0x58/0x70
Call Trace:
lamparray_register_led+0x119/0x1e0
lamparray_register+0x502/0x820
hid_generic_probe+0x5e/0xc0
The fault kills the kworker running hub_event() while it holds the USB
and HID device locks, which stalls further probing on that bus.
Use hid_hw_raw_request() with a hid_report_len()-sized buffer and hand
the result to hid_report_raw_event() so the HID core parses it into
field->value[] before the values are read.
Validate the level counts after reading them and fail with -EINVAL if
any is zero, so a device reporting no levels cannot reach
led_mc_calc_color_components() at all. The four level fields are also
required to share one report, since a single GET_REPORT is used to
fetch them.
Signed-off-by: Cristian Mazzotta <cmmazzo@icloud.com>
---
drivers/hid/hid-lamparray.c | 73 ++++++++++++++++++++++++++++++-------
1 file changed, 59 insertions(+), 14 deletions(-)
diff --git a/drivers/hid/hid-lamparray.c b/drivers/hid/hid-lamparray.c
index 9a438aa2d305..f169929aecd6 100644
--- a/drivers/hid/hid-lamparray.c
+++ b/drivers/hid/hid-lamparray.c
@@ -164,6 +164,9 @@ static int lamparray_read_attributes_report(struct lamparray_device *ldev)
{
struct hid_device *hdev = ldev->hdev;
struct hid_report *report;
+ int ret;
+ u8 *buf;
+ size_t len;
if (!ldev->lamp_count.field) {
hid_dbg(hdev, "No LampCount field found\n");
@@ -182,25 +185,37 @@ static int lamparray_read_attributes_report(struct lamparray_device *ldev)
return -ENODEV;
}
+ len = hid_report_len(report);
+ buf = kmalloc(len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
mutex_lock(&ldev->dev_lock);
/* Update values */
- hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
- hid_hw_wait(hdev);
+ ret = hid_hw_raw_request(hdev, report->id, buf, len,
+ HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
+ if (ret < 0) {
+ hid_dbg(hdev, "Failed to get LampCount value from device: %d\n", ret);
+ goto out;
+ }
- ldev->lamp_count_value = get_field_value(&ldev->lamp_count);
+ hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf, len, ret, 0);
- if (ldev->lamp_count_value == 0) {
- mutex_unlock(&ldev->dev_lock);
- hid_dbg(hdev, "LampCount is %d (invalid)\n", ldev->lamp_count_value);
- return -EINVAL;
+ ldev->lamp_count_value = get_field_value(&ldev->lamp_count);
+ if (!ldev->lamp_count_value) {
+ hid_dbg(hdev, "LampCount is 0 (invalid)\n");
+ ret = -EINVAL;
+ goto out;
}
ldev->lamparray_kind_value = get_field_value(&ldev->lamparray_kind);
+ ret = 0;
+out:
mutex_unlock(&ldev->dev_lock);
-
- return 0;
+ kfree(buf);
+ return ret;
}
static int lamparray_parse_update_report(struct lamparray_device *ldev)
@@ -371,28 +386,58 @@ static int lamparray_get_lamp_attributes(struct lamparray_device *ldev)
{
struct hid_device *hdev = ldev->hdev;
struct hid_report *report;
+ int ret;
+ u8 *buf;
+ size_t len;
if (!lamparray_color_fields_is_complete(&ldev->color_levels))
return -ENODEV;
/*
- * Get value of any lamp.
+ * All four fields must share the same report since the
+ * attributes are fetched with a single GET_REPORT below.
*/
report = ldev->color_levels.red.field->report;
+ if (!report ||
+ ldev->color_levels.green.field->report != report ||
+ ldev->color_levels.blue.field->report != report ||
+ ldev->color_levels.intensity.field->report != report)
+ return -ENODEV;
+
+ len = hid_report_len(report);
+ buf = kmalloc(len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
mutex_lock(&ldev->dev_lock);
- hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
- hid_hw_wait(hdev);
+ /* Update values */
+ ret = hid_hw_raw_request(hdev, report->id, buf, len,
+ HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
+ if (ret < 0) {
+ hid_dbg(hdev, "Failed to read LampAttributesResponseReport: %d\n", ret);
+ goto out;
+ }
+
+ hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf, len, ret, 0);
ldev->max_r = get_field_value_as_u8(&ldev->color_levels.red);
ldev->max_g = get_field_value_as_u8(&ldev->color_levels.green);
ldev->max_b = get_field_value_as_u8(&ldev->color_levels.blue);
ldev->max_brightness = get_field_value_as_u8(&ldev->color_levels.intensity);
- mutex_unlock(&ldev->dev_lock);
+ if (!ldev->max_r || !ldev->max_g || !ldev->max_b || !ldev->max_brightness) {
+ hid_dbg(hdev, "LampArray device has no color levels\n");
+ ret = -EINVAL;
+ goto out;
+ }
- return 0;
+ ret = 0;
+
+out:
+ mutex_unlock(&ldev->dev_lock);
+ kfree(buf);
+ return ret;
}
/* Helper functions */
--
2.55.0
The failure paths in lamparray_read_attributes_report() and
lamparray_get_lamp_attributes() use hid_dbg(), so on a device that
cannot be driven the driver declines to register with no output unless
dynamic debug is enabled for the module.
Use hid_warn() for these, since they leave the device without LED
support and the reason is useful to anyone diagnosing why a LampArray
device did not appear under /sys/class/leds.
Signed-off-by: Cristian Mazzotta <cmmazzo@icloud.com>
---
drivers/hid/hid-lamparray.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/hid/hid-lamparray.c b/drivers/hid/hid-lamparray.c
index f169929aecd6..70c596f292a2 100644
--- a/drivers/hid/hid-lamparray.c
+++ b/drivers/hid/hid-lamparray.c
@@ -169,19 +169,19 @@ static int lamparray_read_attributes_report(struct lamparray_device *ldev)
size_t len;
if (!ldev->lamp_count.field) {
- hid_dbg(hdev, "No LampCount field found\n");
+ hid_warn(hdev, "No LampCount field found\n");
return -ENODEV;
}
if (!ldev->lamparray_kind.field) {
- hid_dbg(hdev, "No LampArrayKind field found\n");
+ hid_warn(hdev, "No LampArrayKind field found\n");
return -ENODEV;
}
report = ldev->lamp_count.field->report;
if (!report) {
- hid_dbg(hdev, "LampCount field has no report\n");
+ hid_warn(hdev, "LampCount field has no report\n");
return -ENODEV;
}
@@ -196,7 +196,7 @@ static int lamparray_read_attributes_report(struct lamparray_device *ldev)
ret = hid_hw_raw_request(hdev, report->id, buf, len,
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
if (ret < 0) {
- hid_dbg(hdev, "Failed to get LampCount value from device: %d\n", ret);
+ hid_warn(hdev, "Failed to get LampCount value from device: %d\n", ret);
goto out;
}
@@ -204,7 +204,7 @@ static int lamparray_read_attributes_report(struct lamparray_device *ldev)
ldev->lamp_count_value = get_field_value(&ldev->lamp_count);
if (!ldev->lamp_count_value) {
- hid_dbg(hdev, "LampCount is 0 (invalid)\n");
+ hid_warn(hdev, "LampCount is 0 (invalid)\n");
ret = -EINVAL;
goto out;
}
@@ -415,7 +415,7 @@ static int lamparray_get_lamp_attributes(struct lamparray_device *ldev)
ret = hid_hw_raw_request(hdev, report->id, buf, len,
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
if (ret < 0) {
- hid_dbg(hdev, "Failed to read LampAttributesResponseReport: %d\n", ret);
+ hid_warn(hdev, "Failed to read LampAttributesResponseReport: %d\n", ret);
goto out;
}
@@ -427,7 +427,7 @@ static int lamparray_get_lamp_attributes(struct lamparray_device *ldev)
ldev->max_brightness = get_field_value_as_u8(&ldev->color_levels.intensity);
if (!ldev->max_r || !ldev->max_g || !ldev->max_b || !ldev->max_brightness) {
- hid_dbg(hdev, "LampArray device has no color levels\n");
+ hid_warn(hdev, "LampArray device has no color levels\n");
ret = -EINVAL;
goto out;
}
--
2.55.0
Autonomous mode is disabled once in lamparray_register() and never
changed again. Writing 0 to use_leds_uapi unregisters the LED class
device but leaves the device under host control, and writing 1
re-registers the class device without taking the device back, so lamp
updates sent afterwards are ignored.
On an Acer Predator PT14-52T (USB keyboard 05AF:767A) the device stays
with whatever last drove it: after writing 0, running a userspace tool
that sets a hardware effect, then writing 1, the LED class device
reports the cached values despite the hardware still running an effect.
Reading AutonomousMode back returns the last value written by the host
rather than the state the device is actually in, so the driver cannot
detect this.
Disable autonomous mode before registering the LED class device and
re-enable it after unregistering, so control is handed over in both
directions. Unregister the class device before handing the hardware
back, so userspace cannot write lamp updates to a device that is no
longer accepting them.
Failure to re-enable autonomous mode on the disable path is logged but
not propagated since the class device is already gone and the write
has otherwise succeeded. The restore failure path drops back to
hid_warn() for the same reason: it is recoverable, and the attribute
reverts to its previous value.
Signed-off-by: Cristian Mazzotta <cmmazzo@icloud.com>
---
drivers/hid/hid-lamparray.c | 32 +++++++++++++++++++++++++-------
1 file changed, 25 insertions(+), 7 deletions(-)
diff --git a/drivers/hid/hid-lamparray.c b/drivers/hid/hid-lamparray.c
index 70c596f292a2..bbde006d119b 100644
--- a/drivers/hid/hid-lamparray.c
+++ b/drivers/hid/hid-lamparray.c
@@ -659,25 +659,43 @@ static ssize_t use_leds_uapi_store(struct device *dev,
ldev->use_leds_uapi = val;
mutex_unlock(&ldev->dev_lock);
+ /*
+ * Take the device out of autonomous mode before exposing the LED
+ * class device, and hand it back afterwards, so that control is
+ * transferred in both directions rather than only at probe.
+ */
if (val == 1) {
+ ret = lamparray_hw_set_autonomous(ldev, false);
+ if (ret)
+ goto err_revert;
ret = lamparray_register_led(ldev);
if (ret) {
- mutex_lock(&ldev->dev_lock);
- ldev->use_leds_uapi = old_val;
- mutex_unlock(&ldev->dev_lock);
- return ret;
+ lamparray_hw_set_autonomous(ldev, true);
+ goto err_revert;
}
ret = lamparray_restore_state(ldev);
if (ret) {
- hid_err(ldev->hdev, "Could not restore state: %d\n", ret);
- return ret;
+ hid_warn(ldev->hdev, "Could not restore state: %d\n", ret);
+ lamparray_unregister_led(ldev);
+ lamparray_hw_set_autonomous(ldev, true);
+ goto err_revert;
}
-
} else {
lamparray_unregister_led(ldev);
+ ret = lamparray_hw_set_autonomous(ldev, true);
+ if (ret) {
+ hid_warn(ldev->hdev, "Could not enable autonomous mode: %d\n", ret);
+ return count;
+ }
}
return count;
+
+err_revert:
+ mutex_lock(&ldev->dev_lock);
+ ldev->use_leds_uapi = old_val;
+ mutex_unlock(&ldev->dev_lock);
+ return ret;
}
static DEVICE_ATTR_RW(use_leds_uapi);
--
2.55.0
The helper installs no PM callbacks, so lamps keep their last state
across suspend. Firmware is not required to turn them off in low power
states, and on devices where it does not, they stay lit for the whole
suspend.
On an Acer Predator PT14-52T, system power draw during s2idle is 12.35W
with the lamps lit and 3.14W with them blanked, measured at the charger.
Add lamparray_suspend(), which writes zeroes to the color channels
while leaving the cached RGB and brightness untouched, and
lamparray_resume(), which restores that cache. Both return early when
use_leds_uapi is 0 so a userspace driver keeps full control. hid-generic
gains suspend and resume callbacks to drive them, and calls
lamparray_resume() from reset_resume as well.
Some devices return to firmware control across a hibernate transition
while still reporting AutonomousMode = 0, and ignore host lamp updates
until the value genuinely transitions. Force a 1 -> 0 on resume
before restoring state.
Signed-off-by: Cristian Mazzotta <cmmazzo@icloud.com>
---
drivers/hid/hid-generic.c | 27 +++++++++++++++++++
drivers/hid/hid-lamparray.c | 51 +++++++++++++++++++++++++++++++++++
include/linux/hid-lamparray.h | 35 ++++++++++++++++++++++++
3 files changed, 113 insertions(+)
diff --git a/drivers/hid/hid-generic.c b/drivers/hid/hid-generic.c
index c3d2283198e8..dc1cca45d599 100644
--- a/drivers/hid/hid-generic.c
+++ b/drivers/hid/hid-generic.c
@@ -99,9 +99,34 @@ static int hid_generic_probe(struct hid_device *hdev,
static int hid_generic_reset_resume(struct hid_device *hdev)
{
+ struct lamparray *la = hid_get_drvdata(hdev);
+
if (hdev->claimed & HID_CLAIMED_INPUT)
hidinput_reset_resume(hdev);
+ if (IS_ENABLED(CONFIG_HID_LAMPARRAY) && la)
+ lamparray_resume(la);
+
+ return 0;
+}
+
+static int hid_generic_suspend(struct hid_device *hdev, pm_message_t message)
+{
+ struct lamparray *la = hid_get_drvdata(hdev);
+
+ if (IS_ENABLED(CONFIG_HID_LAMPARRAY) && la)
+ lamparray_suspend(la);
+
+ return 0;
+}
+
+static int hid_generic_resume(struct hid_device *hdev)
+{
+ struct lamparray *la = hid_get_drvdata(hdev);
+
+ if (IS_ENABLED(CONFIG_HID_LAMPARRAY) && la)
+ lamparray_resume(la);
+
return 0;
}
@@ -127,6 +152,8 @@ static struct hid_driver hid_generic = {
.match = hid_generic_match,
.probe = hid_generic_probe,
.reset_resume = hid_generic_reset_resume,
+ .suspend = hid_generic_suspend,
+ .resume = hid_generic_resume,
.remove = hid_generic_remove,
};
module_hid_driver(hid_generic);
diff --git a/drivers/hid/hid-lamparray.c b/drivers/hid/hid-lamparray.c
index bbde006d119b..dec9d7883887 100644
--- a/drivers/hid/hid-lamparray.c
+++ b/drivers/hid/hid-lamparray.c
@@ -869,6 +869,57 @@ void lamparray_unregister(struct lamparray *la)
}
EXPORT_SYMBOL_GPL(lamparray_unregister);
+/*
+ * Blank all lamps on suspend rather than handing control back to the firmware,
+ * which may not turn them off in low power states. On an Acer Predator PT14-52T,
+ * system power draw during s2idle was ~12.35W with lamps lit, and ~2.84W with
+ * them blanked; the lighting accounted for ~77% of the power draw during suspend.
+ * Since writing zeroes is well defined on all lamparray devices, always do it.
+ * This is ignored if use_leds_uapi is 0; let userspace keep full control.
+ *
+ * Lamps are written to without holding the lock because PM will freeze userspace
+ * first, which makes concurrent writes impossible.
+ */
+int lamparray_suspend(struct lamparray *la)
+{
+ if (!la)
+ return 0;
+
+ struct lamparray_device *ldev = &la->ldev;
+
+ if (!ldev->use_leds_uapi)
+ return 0;
+
+ lamparray_hw_set_state(ldev, 0, 0, 0, ldev->last_brightness);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(lamparray_suspend);
+
+int lamparray_resume(struct lamparray *la)
+{
+ if (!la)
+ return 0;
+
+ struct lamparray_device *ldev = &la->ldev;
+
+ if (!ldev->use_leds_uapi)
+ return 0;
+
+ /*
+ * After a S4 transition, some devices report
+ * AutonomousMode = 0 while still ignoring host lamp updates.
+ * Writing 0 again does nothing; forcing a 1 -> 0
+ * will guarantee the device will update.
+ */
+ lamparray_hw_set_autonomous(ldev, true);
+ lamparray_hw_set_autonomous(ldev, false);
+ lamparray_restore_state(ldev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(lamparray_resume);
+
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Tim Guttzeit <tgu@tuxedocomputers.com>");
MODULE_AUTHOR("Aaron Erhardt <aer@tuxedocomputers.com>");
diff --git a/include/linux/hid-lamparray.h b/include/linux/hid-lamparray.h
index a77869728d12..a9f827743baa 100644
--- a/include/linux/hid-lamparray.h
+++ b/include/linux/hid-lamparray.h
@@ -65,6 +65,31 @@ struct lamparray *lamparray_register(struct hid_device *hdev,
*/
void lamparray_unregister(struct lamparray *la);
+/**
+ * lamparray_suspend() - blank all lamps ahead of sleep transition
+ * @la: LampArray handle returned by lamparray_register()
+ *
+ * Writes zeroes to the rgb values only, keeping the brightness, unless the
+ * use_leds_uapi sysfs attribute is 0, in which case, it will return early
+ * before writing anything. The cached state is left untouched so
+ * lamparray_resume() can restore it.
+ *
+ * Return: 0
+ */
+int lamparray_suspend(struct lamparray *la);
+
+/**
+ * lamparray_resume() - restore host control and LampArray state
+ * @la: LampArray handle returned by lamparray_register()
+ *
+ * Disables autonomous mode (in case device returns to firmware control after suspend)
+ * and restores the cached state of the device. If the use_leds_uapi attribute is 0,
+ * it will return early and prevent any unwanted writing.
+ *
+ * Return: 0
+ */
+int lamparray_resume(struct lamparray *la);
+
#else /* !CONFIG_HID_LAMPARRAY */
static inline bool lamparray_is_supported_device(struct hid_device *hdev)
@@ -83,6 +108,16 @@ static inline void lamparray_unregister(struct lamparray *la)
{
}
+static inline int lamparray_suspend(struct lamparray *la)
+{
+ return 0;
+}
+
+static inline int lamparray_resume(struct lamparray *la)
+{
+ return 0;
+}
+
#endif /* CONFIG_HID_LAMPARRAY */
#endif /* _HID_LAMPARRAY_H */
--
2.55.0
Am 07.09.26 um 18:30 schrieb Aaron Erhardt: > Am 04.09.26 um 22:49 schrieb Armin Wolf: >> Am 03.09.26 um 09:35 schrieb Aaron Erhardt: >> >>> Add a new hid-lamparray helper module and integrate it with the >>> hid-generic driver. >>> >>> While more complex lamparray handling should be done in userspace via >>> hidraw, providing a small module to add basic lamparray support makes it >>> possible for userspace software to interact with lamparrays by simply >>> using well-known APIs of the LED subsystem. One use-case would be to >>> enable desktop environments to support keyboard backlight control out of >>> the box for HID lamparray devices without having to implement the whole >>> HID protocol themselves. >>> >>> This patch is based on previous discussions: >>> https://lore.kernel.org/all/1fb08a74-62c7-4d0c-ba5d-648e23082dcb@tuxedocomputers.com/ >>> >>> The helper provides basic support for devices exposing a >>> Lighting/LampArray application collection (usage page 0x59) and >>> registers a single-zone RGB LED representation via the LED >>> subsystem. >>> >>> hid-generic now checks for LampArray support after hid_parse() and >>> optionally registers a lamparray instance. Failures in the helper >>> do not abort device probe to keep the driver logic otherwise unchanged. >>> >>> LampArray resources are released on driver remove. >>> >>> This commit was successfully tested on the Microsoft MacroPad reference >>> implementation (https://github.com/microsoft/RP2040MacropadHidSample >>> 1d6c3ad) and in combination with the tuxedo_nb04_wmi driver, albeit >>> only fully functional with a recent fix posted to the LKML >>> (https://lore.kernel.org/all/20260826081149.235487-2-aer@tuxedocomputers.com). >> Nice work, it works on my ASUS Prime B650-Plus. However the behavior of the brightness >> attribute is a bit strange: >> >> - manually setting "brightness" does not change anything (max. is 1) >> - setting RGB to "0 0 0" causes "brightness" to become 0 >> - setting RGB to a non-zero value causes "brightness" to become 1 >> >> Any idea why this happens? I can check if the same problems also exists under Windows, >> if requested. >> >> Thanks, >> Armin Wolf >> > It is completely normal for LampArray devices to only offer two brightness > values (1 and 0) for turning the whole LED on and off. Since a lot of > userspace software seems to never use brightness (it is more convenient to > adjust the RGB channels directly), this was not even properly implemented in > the MacropadHidSample until recently: > https://github.com/microsoft/RP2040MacropadHidSample/commit/cfc29120a3910c5772976da29ecd57392dfd44d6 > > Thus, I think it is likely, that the implementation is broken and simply > ignores brightness. The driver just forwards this to the device. > > However, the RGB values (aka. multi_intensity) should not interfere with the > brightness. Yet, I wasn't able to reproduce this on the Macropad. Capping the > brightness to 1 is normal on the other hand, at least if that's the > maxIntensity reported by your device. > > So the only really odd thing for me would be the RGB values influencing the > brightness. Please provide more detailed feedback if you can since I can't > reproduce this on the hardware available to me. I did some further tests, and it turned out that the RGB values indeed do not influence the brightness value. It seems that i confused myself during testing xd. So it seems that Asus copied the buggy Macropad code. Would it be possible to send RGB = (0, 0, 0) when the user has selected brightness 0 to work around this firmware bug? Thanks, Armin Wolf > If you want to investigate the LampArray capabilities of your device, you're > probably better off with userspace tooling like my lampctl fork: > https://github.com/tuxedo-aer/lampctl > > You can adjust the hardcoded brightness here to see whether your device honors > the brightness value or not: > https://github.com/tuxedo-aer/lampctl/blob/main/crates/lamparray/src/hid.rs#L36 > >>> v5: >>> - Proper hardware detection (no quirks necessary anymore) >>> - Add documentation for new sysfs knob >>> - Pass limits of the device to sysfs (intesities & brightness) >>> - More flexible Kconfig (use tristate) >>> - Improved locking >>> - Several memory leak and (de-)initialization fixes >>> - Don't read current color values from hardware (the HID spec does not >>> offer this option) >>> - Remove redundant report dump functionality >>> v4: >>> - Restrict CONFIG_HID_LAMPARRAY to built-in configurations only to fix >>> additional randconfig build errors >>> v3: >>> - Squash V1 and V2 into one patch >>> v2: >>> - Fix Kconfig to avoid build errors when LEDS_CLASS_MULTICOLOR is >>> disabled >>> >>> Aaron Erhardt (2): >>> HID: lamparray: add new LampArray helper module >>> HID: generic: add LampArray support via hid-lamparray helper >>> >>> .../ABI/testing/sysfs-driver-hid-lamparray | 16 + >>> drivers/hid/Kconfig | 18 + >>> drivers/hid/Makefile | 2 + >>> drivers/hid/hid-generic.c | 38 + >>> drivers/hid/hid-lamparray.c | 812 ++++++++++++++++++ >>> include/linux/hid-lamparray.h | 88 ++ >>> 6 files changed, 974 insertions(+) >>> create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-lamparray >>> create mode 100644 drivers/hid/hid-lamparray.c >>> create mode 100644 include/linux/hid-lamparray.h >>>
Am 10.09.26 um 00:36 schrieb Armin Wolf: > > Am 07.09.26 um 18:30 schrieb Aaron Erhardt: >> Am 04.09.26 um 22:49 schrieb Armin Wolf: >>> Am 03.09.26 um 09:35 schrieb Aaron Erhardt: >>> >>>> Add a new hid-lamparray helper module and integrate it with the >>>> hid-generic driver. >>>> >>>> While more complex lamparray handling should be done in userspace via >>>> hidraw, providing a small module to add basic lamparray support makes it >>>> possible for userspace software to interact with lamparrays by simply >>>> using well-known APIs of the LED subsystem. One use-case would be to >>>> enable desktop environments to support keyboard backlight control out of >>>> the box for HID lamparray devices without having to implement the whole >>>> HID protocol themselves. >>>> >>>> This patch is based on previous discussions: >>>> https://lore.kernel.org/all/1fb08a74-62c7-4d0c-ba5d-648e23082dcb@tuxedocomputers.com/ >>>> >>>> The helper provides basic support for devices exposing a >>>> Lighting/LampArray application collection (usage page 0x59) and >>>> registers a single-zone RGB LED representation via the LED >>>> subsystem. >>>> >>>> hid-generic now checks for LampArray support after hid_parse() and >>>> optionally registers a lamparray instance. Failures in the helper >>>> do not abort device probe to keep the driver logic otherwise unchanged. >>>> >>>> LampArray resources are released on driver remove. >>>> >>>> This commit was successfully tested on the Microsoft MacroPad reference >>>> implementation (https://github.com/microsoft/RP2040MacropadHidSample >>>> 1d6c3ad) and in combination with the tuxedo_nb04_wmi driver, albeit >>>> only fully functional with a recent fix posted to the LKML >>>> (https://lore.kernel.org/all/20260826081149.235487-2-aer@tuxedocomputers.com). >>> Nice work, it works on my ASUS Prime B650-Plus. However the behavior of the brightness >>> attribute is a bit strange: >>> >>> - manually setting "brightness" does not change anything (max. is 1) >>> - setting RGB to "0 0 0" causes "brightness" to become 0 >>> - setting RGB to a non-zero value causes "brightness" to become 1 >>> >>> Any idea why this happens? I can check if the same problems also exists under Windows, >>> if requested. >>> >>> Thanks, >>> Armin Wolf >>> >> It is completely normal for LampArray devices to only offer two brightness >> values (1 and 0) for turning the whole LED on and off. Since a lot of >> userspace software seems to never use brightness (it is more convenient to >> adjust the RGB channels directly), this was not even properly implemented in >> the MacropadHidSample until recently: >> https://github.com/microsoft/RP2040MacropadHidSample/commit/cfc29120a3910c5772976da29ecd57392dfd44d6 >> >> Thus, I think it is likely, that the implementation is broken and simply >> ignores brightness. The driver just forwards this to the device. >> >> However, the RGB values (aka. multi_intensity) should not interfere with the >> brightness. Yet, I wasn't able to reproduce this on the Macropad. Capping the >> brightness to 1 is normal on the other hand, at least if that's the >> maxIntensity reported by your device. >> >> So the only really odd thing for me would be the RGB values influencing the >> brightness. Please provide more detailed feedback if you can since I can't >> reproduce this on the hardware available to me. > > I did some further tests, and it turned out that the RGB values indeed do not > influence the brightness value. It seems that i confused myself during testing xd. > > So it seems that Asus copied the buggy Macropad code. Would it be possible to > send RGB = (0, 0, 0) when the user has selected brightness 0 to work around this > firmware bug? Yes, I think that would be a reasonably small quirk that could be useful for a wide range of devices. I will add this in the next iteration. > > Thanks, > Armin Wolf > >> If you want to investigate the LampArray capabilities of your device, you're >> probably better off with userspace tooling like my lampctl fork: >> https://github.com/tuxedo-aer/lampctl >> >> You can adjust the hardcoded brightness here to see whether your device honors >> the brightness value or not: >> https://github.com/tuxedo-aer/lampctl/blob/main/crates/lamparray/src/hid.rs#L36 >> >>>> v5: >>>> - Proper hardware detection (no quirks necessary anymore) >>>> - Add documentation for new sysfs knob >>>> - Pass limits of the device to sysfs (intesities & brightness) >>>> - More flexible Kconfig (use tristate) >>>> - Improved locking >>>> - Several memory leak and (de-)initialization fixes >>>> - Don't read current color values from hardware (the HID spec does not >>>> offer this option) >>>> - Remove redundant report dump functionality >>>> v4: >>>> - Restrict CONFIG_HID_LAMPARRAY to built-in configurations only to fix >>>> additional randconfig build errors >>>> v3: >>>> - Squash V1 and V2 into one patch >>>> v2: >>>> - Fix Kconfig to avoid build errors when LEDS_CLASS_MULTICOLOR is >>>> disabled >>>> >>>> Aaron Erhardt (2): >>>> HID: lamparray: add new LampArray helper module >>>> HID: generic: add LampArray support via hid-lamparray helper >>>> >>>> .../ABI/testing/sysfs-driver-hid-lamparray | 16 + >>>> drivers/hid/Kconfig | 18 + >>>> drivers/hid/Makefile | 2 + >>>> drivers/hid/hid-generic.c | 38 + >>>> drivers/hid/hid-lamparray.c | 812 ++++++++++++++++++ >>>> include/linux/hid-lamparray.h | 88 ++ >>>> 6 files changed, 974 insertions(+) >>>> create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-lamparray >>>> create mode 100644 drivers/hid/hid-lamparray.c >>>> create mode 100644 include/linux/hid-lamparray.h >>>> >
© 2016 - 2026 Red Hat, Inc.