* [PATCH v4 1/4] Input: snvs_pwrkey - make use of dev_err_probe()
From: joy.zou @ 2026-06-18 7:31 UTC (permalink / raw)
To: Dmitry Torokhov, Frank Li, Bough Chen, Peng Fan, Jacky Bai, Ye Li
Cc: Joy Zou, imx, linux-input, linux-kernel, Joy Zou
In-Reply-To: <20260618-b4-pwrkey-v4-0-4bfda105bdf3@oss.nxp.com>
From: Joy Zou <joy.zou@nxp.com>
Add dev_err_probe() at return path of probe() to support users to
identify issues easier.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Joy Zou <joy.zou@nxp.com>
---
Changes in v4:
1. Use dev_err_probe() for devm_input_allocate_device() to simplify
error handling.
Changes in v2:
1. Drop dev_err_probe() change for platform_get_irq() per AI review comments.
2. Add Reviewed-by tag.
---
drivers/input/keyboard/snvs_pwrkey.c | 44 +++++++++++++-----------------------
1 file changed, 16 insertions(+), 28 deletions(-)
diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c
index 954055aaf6e2..8cc6863d26ed 100644
--- a/drivers/input/keyboard/snvs_pwrkey.c
+++ b/drivers/input/keyboard/snvs_pwrkey.c
@@ -124,17 +124,15 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
/* Get SNVS register Page */
np = pdev->dev.of_node;
if (!np)
- return -ENODEV;
+ return dev_err_probe(&pdev->dev, -ENODEV, "Device tree node not found\n");
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
pdata->snvs = syscon_regmap_lookup_by_phandle(np, "regmap");
- if (IS_ERR(pdata->snvs)) {
- dev_err(&pdev->dev, "Can't get snvs syscon\n");
- return PTR_ERR(pdata->snvs);
- }
+ if (IS_ERR(pdata->snvs))
+ return dev_err_probe(&pdev->dev, PTR_ERR(pdata->snvs), "Can't get snvs syscon\n");
if (of_property_read_u32(np, "linux,keycode", &pdata->keycode)) {
pdata->keycode = KEY_POWER;
@@ -142,10 +140,9 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
}
clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
- if (IS_ERR(clk)) {
- dev_err(&pdev->dev, "Failed to get snvs clock (%pe)\n", clk);
- return PTR_ERR(clk);
- }
+ if (IS_ERR(clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(clk),
+ "Failed to get snvs clock (%pe)\n", clk);
pdata->wakeup = of_property_read_bool(np, "wakeup-source");
@@ -165,9 +162,8 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
bpt = (val / 5) - 1;
break;
default:
- dev_err(&pdev->dev,
- "power-off-time-sec %d out of range\n", val);
- return -EINVAL;
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "power-off-time-sec %d out of range\n", val);
}
regmap_update_bits(pdata->snvs, SNVS_LPCR_REG, SNVS_LPCR_BPT_MASK,
@@ -185,10 +181,8 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
timer_setup(&pdata->check_timer, imx_imx_snvs_check_for_events, 0);
input = devm_input_allocate_device(&pdev->dev);
- if (!input) {
- dev_err(&pdev->dev, "failed to allocate the input device\n");
- return -ENOMEM;
- }
+ if (!input)
+ return dev_err_probe(&pdev->dev, -ENOMEM, "failed to allocate the input device\n");
input->name = pdev->name;
input->phys = "snvs-pwrkey/input0";
@@ -198,10 +192,8 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
/* input customer action to cancel release timer */
error = devm_add_action(&pdev->dev, imx_snvs_pwrkey_act, pdata);
- if (error) {
- dev_err(&pdev->dev, "failed to register remove action\n");
- return error;
- }
+ if (error)
+ return dev_err_probe(&pdev->dev, error, "failed to register remove action\n");
pdata->input = input;
platform_set_drvdata(pdev, pdata);
@@ -209,16 +201,12 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
error = devm_request_irq(&pdev->dev, pdata->irq,
imx_snvs_pwrkey_interrupt,
0, pdev->name, pdev);
- if (error) {
- dev_err(&pdev->dev, "interrupt not available.\n");
- return error;
- }
+ if (error)
+ return dev_err_probe(&pdev->dev, error, "interrupt not available.\n");
error = input_register_device(input);
- if (error < 0) {
- dev_err(&pdev->dev, "failed to register input device\n");
- return error;
- }
+ if (error < 0)
+ return dev_err_probe(&pdev->dev, error, "failed to register input device\n");
device_init_wakeup(&pdev->dev, pdata->wakeup);
error = dev_pm_set_wake_irq(&pdev->dev, pdata->irq);
--
2.34.1
^ permalink raw reply related
* [PATCH v4 0/4] snvs_pwrkey - code improvements and add report event
From: joy.zou @ 2026-06-18 7:31 UTC (permalink / raw)
To: Dmitry Torokhov, Frank Li, Bough Chen, Peng Fan, Jacky Bai, Ye Li
Cc: Joy Zou, imx, linux-input, linux-kernel, Joy Zou
This patch series improves the snvs_pwrkey driver with better code quality
and add report press event.
The main improvements include:
1. Clean up the code by using local device pointers and dev_err_probe() for
better readability and easier debugging.
2. Fix potential event loss during system suspend by reporting key press events
directly in the interrupt handler.
Signed-off-by: Joy Zou <joy.zou@oss.nxp.com>
---
Changes in v4:
- Use dev_err_probe() for devm_input_allocate_device() to simplify error handling
for patch #1.
- Add Reviewed-by tag for patch #2 and #3.
- Modify the subject description for patch #2.
- Link to v3: https://patch.msgid.link/20260615-b4-pwrkey-v3-0-9510b1173f6e@oss.nxp.com
Changes in v3:
- Add spinlock for pdata->keystate and pdata->suspended per AI review comments.
- Replace hardcode value 1 with local variable keystate in input_report_key()
under suspended.
- Link to v2: https://lore.kernel.org/r/20260604-pwrkey-cleanup-v2-0-59fa0ddf0d7c@nxp.com
Changes in v2:
- Drop dev_err_probe() change for platform_get_irq() per AI review comments.
- Add new patch #2 replace hardcoding -EINVAL with original error code per
AI review comments.
- Use dev instead of &pdev->dev for devm_input_allocate_device(), which was
missed in patch v1 per AI review comments.
- Add a boolean variable suspended and PM callback functions to replace
the use of the is_suspended field per AI review comments.
- Move event report handle to else branch in suspended state, since the
pdata->minor_rev == 0 branch has no debounce detection per AI review
comments.
- Modify patch #3 and #4 commit message.
- Add Reviewed-by tag for patch #1.
- Link to v1: https://lore.kernel.org/r/20260326-pwrkey-cleanup-v1-0-d85d7c0bf275@nxp.com
To: Dmitry Torokhov <dmitry.torokhov@gmail.com>
To: Frank Li <Frank.Li@nxp.com>
To: Bough Chen <haibo.chen@nxp.com>
To: Peng Fan <peng.fan@nxp.com>
To: Jacky Bai <ping.bai@nxp.com>
To: Ye Li <ye.li@nxp.com>
Cc: imx@lists.linux.dev
Cc: linux-input@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
Joy Zou (4):
Input: snvs_pwrkey - make use of dev_err_probe()
Input: snvs_pwrkey - propagate error code of platform_get_irq()
Input: snvs_pwrkey - use local device pointer to simple code
Input: snvs_pwrkey - report press event in interrupt handler
drivers/input/keyboard/snvs_pwrkey.c | 131 +++++++++++++++++++++++------------
1 file changed, 87 insertions(+), 44 deletions(-)
---
base-commit: f7af91adc230aa99e23330ecf85bc9badd9780ad
change-id: 20260615-b4-pwrkey-a60b2043cd29
Best regards,
--
Joy Zou <joy.zou@oss.nxp.com>
^ permalink raw reply
* [PATCH] HID: lg-g15: cancel pending work on remove to fix a use-after-free
From: Maoyi Xie @ 2026-06-18 7:06 UTC (permalink / raw)
To: Hans de Goede, Jiri Kosina, Benjamin Tissoires; +Cc: linux-input, linux-kernel
lg_g15_data is allocated with devm and holds a work item. The report
handlers schedule that work straight from device input.
lg_g15_event() and lg_g15_v2_event() do it on the backlight cycle key,
and lg_g510_leds_event() does it too. The worker dereferences the
lg_g15_data back through container_of.
The driver had no remove callback and never cancelled the work. So if a
report scheduled the work and the keyboard was then unplugged, devres
freed lg_g15_data while the work was still pending or running, and the
worker touched freed memory. This is a use-after-free. It is reachable
as a race on device unplug.
Add a remove callback that cancels the work before devres frees the
state. g15->work is only initialized for the models that schedule it
(G15, G15 v2, G510). The G13 and Z-10 leave it zeroed, so guard the
cancel on g15->work.func to avoid cancelling a work that was never set
up. The g15 NULL test mirrors the one already in lg_g15_raw_event().
Fixes: 97b741aba918 ("HID: lg-g15: Add keyboard and LCD backlight control")
Cc: stable@vger.kernel.org
Suggested-by: Hans de Goede <hansg@kernel.org>
Signed-off-by: Maoyi Xie <maoyixie.tju@gmail.com>
---
drivers/hid/hid-lg-g15.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/hid/hid-lg-g15.c b/drivers/hid/hid-lg-g15.c
index 1a88bc44ada4..02ef3e2094b4 100644
--- a/drivers/hid/hid-lg-g15.c
+++ b/drivers/hid/hid-lg-g15.c
@@ -1374,11 +1374,27 @@ static const struct hid_device_id lg_g15_devices[] = {
};
MODULE_DEVICE_TABLE(hid, lg_g15_devices);
+static void lg_g15_remove(struct hid_device *hdev)
+{
+ struct lg_g15_data *g15 = hid_get_drvdata(hdev);
+
+ /*
+ * g15->work is only initialized for the models that schedule it
+ * (G15, G15 v2, G510). The G13 and Z-10 leave it zeroed, so only
+ * cancel it when it was set up.
+ */
+ if (g15 && g15->work.func)
+ cancel_work_sync(&g15->work);
+
+ hid_hw_stop(hdev);
+}
+
static struct hid_driver lg_g15_driver = {
.name = "lg-g15",
.id_table = lg_g15_devices,
.raw_event = lg_g15_raw_event,
.probe = lg_g15_probe,
+ .remove = lg_g15_remove,
};
module_hid_driver(lg_g15_driver);
--
2.34.1
^ permalink raw reply related
* [PATCH] HID: logitech-dj: Fix maxfield check in DJ short report validation
From: HyeongJun An @ 2026-06-18 6:37 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina
Cc: Filipe Laíns, Lee Jones, linux-input, linux-kernel,
HyeongJun An, stable
Commit b6a57912854e ("HID: logitech-dj: Prevent REPORT_ID_DJ_SHORT
related user initiated OOB write") added validation for the DJ short
output report, but the error path dereferences rep->field[0] even when
rep->maxfield is zero.
Commit 8b9a097eb2fc ("HID: logitech-dj: fix wrong detection of bad
DJ_SHORT output report") made the check conditional on rep being present,
but a crafted descriptor can still create report ID 0x20 with only padding
output items. hid-core registers the report, ignores the padding field,
and leaves rep->maxfield as zero.
In that case the validation enters the rep->maxfield < 1 branch and then
dereferences rep->field[0]->report_count while printing the error message,
causing a NULL pointer dereference during probe. This is reproducible with
uhid by emulating a Logitech receiver with a padding-only DJ short output
report:
BUG: KASAN: null-ptr-deref in logi_dj_probe+0xb1/0x754 [hid_logitech_dj]
Read of size 4 at addr 0000000000000028 by task kworker/4:1/129
...
Call Trace:
logi_dj_probe+0xb1/0x754 [hid_logitech_dj]
hid_device_probe+0x329/0x3f0 [hid]
really_probe+0x162/0x570
__device_attach+0x137/0x2c0
bus_probe_device+0x38/0xc0
device_add+0xa56/0xce0
hid_add_device+0x19c/0x280 [hid]
uhid_device_add_worker+0x2c/0xb0 [uhid]
Reject the zero-field report before printing the field report_count.
Fixes: b6a57912854e ("HID: logitech-dj: Prevent REPORT_ID_DJ_SHORT related user initiated OOB write")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: HyeongJun An <sammiee5311@gmail.com>
---
drivers/hid/hid-logitech-dj.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index 381e4dc5aba7..9c574ab8b60b 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -1907,8 +1907,13 @@ static int logi_dj_probe(struct hid_device *hdev,
output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT];
rep = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT];
- if (rep && (rep->maxfield < 1 ||
- rep->field[0]->report_count != DJREPORT_SHORT_LENGTH - 1)) {
+ if (rep && rep->maxfield < 1) {
+ hid_err(hdev, "Expected size of DJ short report is %d, but got 0",
+ DJREPORT_SHORT_LENGTH - 1);
+ return -EINVAL;
+ }
+
+ if (rep && rep->field[0]->report_count != DJREPORT_SHORT_LENGTH - 1) {
hid_err(hdev, "Expected size of DJ short report is %d, but got %d",
DJREPORT_SHORT_LENGTH - 1, rep->field[0]->report_count);
return -EINVAL;
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 1/2] HID: roccat: bound device-supplied profile index
From: sashiko-bot @ 2026-06-18 3:18 UTC (permalink / raw)
To: Michael Bommarito; +Cc: dmitry.torokhov, linux-input
In-Reply-To: <20260618030036.1880139-2-michael.bommarito@gmail.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Closing a stale roccat character device file descriptor after device removal causes a memory leak, state corruption and Use-After-Free.
- [High] `kone_get_profile()` uses an embedded, unaligned struct field (`&kone->profiles[i]`) as a DMA buffer for inbound USB control messages, leading to cache-line sharing corruption.
--
commit cda04d8cb7b50c97cbcee76f405a2121b1b4c56d
Author: Michael Bommarito <michael.bommarito@gmail.com>
HID: roccat: bound device-supplied profile index
kone_keep_values_up_to_date() and kone_profile_activated() use an
8-bit, device-supplied profile value as an index into the 5-element
kone->profiles[] array without a range check. A malicious USB device
claiming the Roccat Kone id can send a switch-profile event (or a
startup_profile read at probe) with an out-of-range value and make the
driver read out of bounds; the result is exposed via the actual_dpi
sysfs attribute.
> diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
> index 58654cf78f0df..17495fcc8b7da 100644
> --- a/drivers/hid/hid-roccat-kone.c
> +++ b/drivers/hid/hid-roccat-kone.c
[ ... ]
> @@ -793,8 +795,10 @@ static void kone_keep_values_up_to_date(struct kone_device *kone,
> {
> switch (event->event) {
> case kone_mouse_event_switch_profile:
> - kone->actual_dpi = kone->profiles[event->value - 1].
> - startup_dpi;
> + if (event->value >= 1 &&
> + event->value <= ARRAY_SIZE(kone->profiles))
> + kone->actual_dpi =
> + kone->profiles[event->value - 1].startup_dpi;
> fallthrough;
> case kone_mouse_event_osd_profile:
> kone->actual_profile = event->value;
[Severity: High]
This is a pre-existing issue, but does kone_get_profile() use an embedded,
unaligned array element as a DMA buffer?
In kone_init_kone_device_struct(), we call kone_get_profile() passing a
pointer to the embedded array element:
drivers/hid/hid-roccat-kone.c:kone_init_kone_device_struct() {
...
retval = kone_get_profile(usb_dev, &kone->profiles[i], i + 1);
...
}
Which then passes the unaligned buffer directly to usb_control_msg() for a
USB_DIR_IN transfer:
drivers/hid/hid-roccat-kone.c:kone_get_profile() {
...
len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
USB_REQ_CLEAR_FEATURE,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
kone_command_profile, number, buf,
sizeof(struct kone_profile), USB_CTRL_SET_TIMEOUT);
...
}
Since sizeof(struct kone_profile) is 975 bytes, the array elements are not
cache-line aligned and share cache lines with other struct kone_device
members. Because hid_hw_start() is called earlier, the device can generate
interrupts and concurrent writes to these shared fields may occur.
On architectures with non-coherent DMA caches, won't the cache invalidation
required for the inbound USB DMA wipe out these concurrent CPU writes,
leading to state corruption?
[Severity: High]
This is a pre-existing issue, but can roccat_release() cause a memory leak,
list corruption, and Use-After-Free if a stale file descriptor is closed
after device removal?
When closing the file descriptor, roccat_release() retrieves the device from
the global array instead of using the local reader->device:
drivers/hid/hid-roccat.c:roccat_release() {
...
device = devices[minor];
if (!device) {
mutex_unlock(&devices_lock);
pr_emerg("roccat device with minor %d doesn't exist\n", minor);
return -ENODEV;
}
...
}
If the original device was disconnected, devices[minor] is cleared, causing
roccat_release() to return -ENODEV and permanently leak the roccat_reader
allocation and the original roccat_device.
If a new device is plugged in before the stale file descriptor is closed,
devices[minor] resolves to the new device. roccat_release() then operates on
the new device, locking its readers_lock while modifying the old device's
list:
drivers/hid/hid-roccat.c:roccat_release() {
...
list_del(&reader->node);
...
if (!--device->open) {
...
}
Could this lead to list corruption and incorrectly decrement the new device's
open count, causing premature shutdown and a Use-After-Free of the new device
when legitimate users close their descriptors?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260618030036.1880139-1-michael.bommarito@gmail.com?part=1
^ permalink raw reply
* Re: [PATCH 2/2] HID: roccat: add KUnit test for kone profile-index bounds
From: sashiko-bot @ 2026-06-18 3:14 UTC (permalink / raw)
To: Michael Bommarito; +Cc: linux-input, dmitry.torokhov
In-Reply-To: <20260618030036.1880139-3-michael.bommarito@gmail.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] A Use-After-Free vulnerability occurs because the `kone_device` structure is freed while hardware interrupts are still active, leaving a dangling pointer in `hid_drvdata`.
- [High] Uninitialized kernel memory is copied to the persistent `kone->settings` structure on a failed USB control message, leading to a heap information leak via sysfs.
--
commit e8aee21a8be54aaf776b4d76c32eeaefd255b5aa
Author: Michael Bommarito <michael.bommarito@gmail.com>
HID: roccat: add KUnit test for kone profile-index bounds
This commit adds a KUnit test for the Roccat Kone driver to verify bounds
checking on profile indices. It simulates a crafted switch-profile event to
ensure the driver does not read out-of-bounds.
> diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> index ff2f580b660ba..3c6bc918aeb54 100644
> --- a/drivers/hid/Kconfig
> +++ b/drivers/hid/Kconfig
> @@ -1057,6 +1057,15 @@ config HID_ROCCAT
> Say Y here if you have a Roccat mouse or keyboard and want
> support for its special functionalities.
>
> +config HID_ROCCAT_KONE_KUNIT_TEST
> + bool "KUnit tests for the Roccat Kone driver" if !KUNIT_ALL_TESTS
> + depends on HID_ROCCAT=y && KUNIT=y
> + default KUNIT_ALL_TESTS
> + help
> + Enable the KUnit regression tests for the Roccat Kone driver,
> + covering bounds checking of device-supplied profile indices.
> + If unsure, say N.
> +
> config HID_SAITEK
> tristate "Saitek (Mad Catz) non-fully HID-compliant devices"
> help
> diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
> index 17495fcc8b7da..3dae9eaa0b6f4 100644
> --- a/drivers/hid/hid-roccat-kone.c
> +++ b/drivers/hid/hid-roccat-kone.c
[ ... ]
> @@ -919,3 +919,60 @@ module_exit(kone_exit);
> MODULE_AUTHOR("Stefan Achatz");
> MODULE_DESCRIPTION("USB Roccat Kone driver");
> MODULE_LICENSE("GPL v2");
> +
> +#if IS_ENABLED(CONFIG_HID_ROCCAT_KONE_KUNIT_TEST)
> +#include <kunit/test.h>
> +
> +/*
> + * Regression test for the out-of-bounds read in
> + * kone_keep_values_up_to_date(): a malicious USB device sends a
> + * "switch profile" HID event (event == kone_mouse_event_switch_profile)
> + * with an attacker-chosen value in 0..255, which is used unbounded as
> + * profiles[value - 1]. On an unpatched kernel the attack case triggers a
> + * KASAN slab-out-of-bounds read; the fix must leave actual_dpi unchanged.
> + */
> +static void kone_profile_index_oob_test(struct kunit *test)
> +{
> + struct kone_device *kone;
> + struct kone_mouse_event ev = {};
[ ... ]
> + /* attack: value == ARRAY_SIZE(profiles) + 1 reads profiles[5], one
> + * element past the array end -> KASAN slab-out-of-bounds read on an
> + * unpatched kernel. The fix must reject it (actual_dpi unchanged).
> + */
> + ev.value = ARRAY_SIZE(kone->profiles) + 1;
> + kone_keep_values_up_to_date(kone, &ev);
> + KUNIT_EXPECT_EQ(test, kone->actual_dpi, 0x42);
> +}
> +
> +static struct kunit_case kone_test_cases[] = {
> + KUNIT_CASE(kone_profile_index_oob_test),
> + {}
> +};
> +
> +static struct kunit_suite kone_test_suite = {
> + .name = "hid-roccat-kone",
> + .test_cases = kone_test_cases,
> +};
> +kunit_test_suite(kone_test_suite);
> +#endif /* CONFIG_HID_ROCCAT_KONE_KUNIT_TEST */
[Severity: High]
This isn't a bug introduced by this patch, but while reviewing I noticed a
potential use-after-free vulnerability in the driver initialization and
teardown paths.
In kone_probe(), hid_hw_start() is called before kone_init_specials(),
starting the hardware and enabling USB interrupts. If initialization fails,
the error path frees the driver data but does not clear the pointer:
drivers/hid/hid-roccat-kone.c:kone_init_specials() {
...
exit_free:
kfree(kone);
return retval;
}
Between kfree() and hid_hw_stop(), an incoming USB interrupt will trigger
kone_raw_event(), which dereferences the dangling pointer:
drivers/hid/hid-roccat-kone.c:kone_raw_event() {
...
struct kone_device *kone = hid_get_drvdata(hdev);
...
}
The same window exists in the teardown path, where the driver state is freed
before stopping the hardware:
drivers/hid/hid-roccat-kone.c:kone_remove() {
...
kone_remove_specials(hdev);
hid_hw_stop(hdev);
}
Is it possible for an attacker to trigger this use-after-free by
disconnecting the device or simulating a device error while hardware
interrupts are active?
[Severity: High]
This is a pre-existing issue, but there appears to be a potential heap
information leak when copying uninitialized memory after a failed USB
transfer.
In kone_receive(), a bounce buffer is allocated with kmalloc() and
unconditionally copied to the target even if the USB transfer fails:
drivers/hid/hid-roccat-kone.c:kone_receive() {
buf = kmalloc(size, GFP_KERNEL);
...
retval = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), ...
...
memcpy(data, buf, size);
kfree(buf);
return retval;
}
When called via kone_get_settings(), the uninitialized kernel heap memory
is copied to the persistent settings structure. If this occurs during a
sysfs operation where the error is handled, the corrupted structure remains
intact:
drivers/hid/hid-roccat-kone.c:kone_sysfs_set_tcu() {
...
retval = kone_get_settings(usb_dev, &kone->settings);
if (retval)
goto exit_no_settings;
...
}
A subsequent read of the settings sysfs attribute exposes this memory
directly to userspace:
drivers/hid/hid-roccat-kone.c:kone_sysfs_read_settings() {
...
memcpy(buf, ((char const *)&kone->settings) + off, count);
...
}
Could a malicious USB device intentionally fail the transfer to exploit
this leak? Should we check the return value of usb_control_msg() before
calling memcpy() in kone_receive()?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260618030036.1880139-1-michael.bommarito@gmail.com?part=2
^ permalink raw reply
* [PATCH 2/2] HID: roccat: add KUnit test for kone profile-index bounds
From: Michael Bommarito @ 2026-06-18 3:00 UTC (permalink / raw)
To: Stefan Achatz, Jiri Kosina, Benjamin Tissoires; +Cc: linux-input, linux-kernel
In-Reply-To: <20260618030036.1880139-1-michael.bommarito@gmail.com>
Drive kone_keep_values_up_to_date() with a crafted switch-profile event;
an out-of-range value reads past profiles[] (KASAN slab-out-of-bounds on
an unpatched tree). A benign control with an in-range value exercises the
same path. The test object is sized to end at profiles[] so the over-read
lands in the KASAN redzone.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
drivers/hid/Kconfig | 9 ++++++
drivers/hid/hid-roccat-kone.c | 57 +++++++++++++++++++++++++++++++++++
2 files changed, 66 insertions(+)
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index ff2f580b660ba..3c6bc918aeb54 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -1057,6 +1057,15 @@ config HID_ROCCAT
Say Y here if you have a Roccat mouse or keyboard and want
support for its special functionalities.
+config HID_ROCCAT_KONE_KUNIT_TEST
+ bool "KUnit tests for the Roccat Kone driver" if !KUNIT_ALL_TESTS
+ depends on HID_ROCCAT=y && KUNIT=y
+ default KUNIT_ALL_TESTS
+ help
+ Enable the KUnit regression tests for the Roccat Kone driver,
+ covering bounds checking of device-supplied profile indices.
+ If unsure, say N.
+
config HID_SAITEK
tristate "Saitek (Mad Catz) non-fully HID-compliant devices"
help
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index 17495fcc8b7da..3dae9eaa0b6f4 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c
@@ -919,3 +919,60 @@ module_exit(kone_exit);
MODULE_AUTHOR("Stefan Achatz");
MODULE_DESCRIPTION("USB Roccat Kone driver");
MODULE_LICENSE("GPL v2");
+
+#if IS_ENABLED(CONFIG_HID_ROCCAT_KONE_KUNIT_TEST)
+#include <kunit/test.h>
+
+/*
+ * Regression test for the out-of-bounds read in
+ * kone_keep_values_up_to_date(): a malicious USB device sends a
+ * "switch profile" HID event (event == kone_mouse_event_switch_profile)
+ * with an attacker-chosen value in 0..255, which is used unbounded as
+ * profiles[value - 1]. On an unpatched kernel the attack case triggers a
+ * KASAN slab-out-of-bounds read; the fix must leave actual_dpi unchanged.
+ */
+static void kone_profile_index_oob_test(struct kunit *test)
+{
+ struct kone_device *kone;
+ struct kone_mouse_event ev = {};
+ /*
+ * Allocate only up to the end of profiles[] so that any index past
+ * the 5-element array is IMMEDIATELY out of bounds and lands in the
+ * KASAN redzone (a far over-read would hit unrelated valid memory and
+ * escape KASAN).
+ */
+ size_t sz = offsetof(struct kone_device, profiles) +
+ sizeof(kone->profiles);
+
+ kone = kunit_kzalloc(test, sz, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, kone);
+ kone->profiles[0].startup_dpi = 0x42;
+
+ /* benign control: a valid in-range value drives the SAME path and
+ * must succeed (proves the trigger reaches the real code).
+ */
+ ev.event = kone_mouse_event_switch_profile;
+ ev.value = 1;
+ kone_keep_values_up_to_date(kone, &ev);
+ KUNIT_EXPECT_EQ(test, kone->actual_dpi, 0x42);
+
+ /* attack: value == ARRAY_SIZE(profiles) + 1 reads profiles[5], one
+ * element past the array end -> KASAN slab-out-of-bounds read on an
+ * unpatched kernel. The fix must reject it (actual_dpi unchanged).
+ */
+ ev.value = ARRAY_SIZE(kone->profiles) + 1;
+ kone_keep_values_up_to_date(kone, &ev);
+ KUNIT_EXPECT_EQ(test, kone->actual_dpi, 0x42);
+}
+
+static struct kunit_case kone_test_cases[] = {
+ KUNIT_CASE(kone_profile_index_oob_test),
+ {}
+};
+
+static struct kunit_suite kone_test_suite = {
+ .name = "hid-roccat-kone",
+ .test_cases = kone_test_cases,
+};
+kunit_test_suite(kone_test_suite);
+#endif /* CONFIG_HID_ROCCAT_KONE_KUNIT_TEST */
--
2.53.0
^ permalink raw reply related
* [PATCH 1/2] HID: roccat: bound device-supplied profile index
From: Michael Bommarito @ 2026-06-18 3:00 UTC (permalink / raw)
To: Stefan Achatz, Jiri Kosina, Benjamin Tissoires; +Cc: linux-input, linux-kernel
In-Reply-To: <20260618030036.1880139-1-michael.bommarito@gmail.com>
kone_keep_values_up_to_date() and kone_profile_activated() use an
8-bit, device-supplied profile value as an index into the 5-element
kone->profiles[] array without a range check. A malicious USB device
claiming the Roccat Kone id can send a switch-profile event (or a
startup_profile read at probe) with an out-of-range value and make the
driver read out of bounds; the result is exposed via the actual_dpi
sysfs attribute.
Reject out-of-range indices in both paths.
This was found with static analysis and confirmed with the KUnit test
added in the following patch (KASAN: slab-out-of-bounds).
Fixes: 14bf62cde7942 ("HID: add driver for Roccat Kone gaming mouse")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
drivers/hid/hid-roccat-kone.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index 58654cf78f0df..17495fcc8b7da 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c
@@ -36,6 +36,8 @@ static uint profile_numbers[5] = {0, 1, 2, 3, 4};
static void kone_profile_activated(struct kone_device *kone, uint new_profile)
{
+ if (new_profile < 1 || new_profile > ARRAY_SIZE(kone->profiles))
+ new_profile = 1;
kone->actual_profile = new_profile;
kone->actual_dpi = kone->profiles[new_profile - 1].startup_dpi;
}
@@ -793,8 +795,10 @@ static void kone_keep_values_up_to_date(struct kone_device *kone,
{
switch (event->event) {
case kone_mouse_event_switch_profile:
- kone->actual_dpi = kone->profiles[event->value - 1].
- startup_dpi;
+ if (event->value >= 1 &&
+ event->value <= ARRAY_SIZE(kone->profiles))
+ kone->actual_dpi =
+ kone->profiles[event->value - 1].startup_dpi;
fallthrough;
case kone_mouse_event_osd_profile:
kone->actual_profile = event->value;
--
2.53.0
^ permalink raw reply related
* [PATCH 0/2] HID: roccat: bound device-supplied profile index
From: Michael Bommarito @ 2026-06-18 3:00 UTC (permalink / raw)
To: Stefan Achatz, Jiri Kosina, Benjamin Tissoires; +Cc: linux-input, linux-kernel
The Roccat Kone driver uses an 8-bit value taken straight from a USB HID
interrupt report as an index into a fixed 5-element profiles[] array,
without any range check. A malicious or counterfeit device that claims
the Roccat Kone VID/PID can send a "switch profile" report with an
out-of-range value and make the driver read out of bounds; the same
unbounded index is also reachable at probe time from a device-supplied
startup_profile field. The read result is stored in actual_dpi and
exposed to user space through the actual_dpi sysfs attribute.
Michael Bommarito (2):
HID: roccat: bound device-supplied profile index
HID: roccat: add KUnit test for kone profile-index bounds
drivers/hid/Kconfig | 9 +++++
drivers/hid/hid-roccat-kone.c | 65 +++++++++++++++++++++++++++++++++--
2 files changed, 72 insertions(+), 2 deletions(-)
--
2.53.0
^ permalink raw reply
* Re: [PATCH 1/2] HID: logitech-hidpp: add HID++ 2.0 reprogrammable button support
From: Elliot Douglas @ 2026-06-18 1:16 UTC (permalink / raw)
To: Bastien Nocera; +Cc: linux-input, lains, jikos, bentiss, linux-kernel
In-Reply-To: <f741bafd41f7fc31fe0019020e14ad4f99fd193e.camel@hadess.net>
Thanks, that makes sense.
For Solaar, this is not continuously forced. The kernel only programs
temporary diversion when the device connects. Solaar can still issue HID++
commands through hidraw, so if Solaar changes reporting for the same controls
afterwards, the last writer wins.
If Solaar takes over those controls for custom actions, the kernel would stop
receiving the diverted button notifications for normal evdev reporting until
the kernel diverts the controls again, for example after reconnect. While the
controls remain diverted, hidraw clients should still receive the raw HID++
reports.
I have addressed the inline comments locally for v2:
- replaced the profile/count wrapper with NULL-terminated mapping arrays
- cached the selected mapping pointer in struct hidpp_device
I'll wait for Benjamin's input to send Patch v2.
On Wed, Jun 17, 2026 at 3:28 AM Bastien Nocera <hadess@hadess.net> wrote:
>
> On Sat, 2026-06-13 at 10:51 -0700, Elliot Douglas wrote:
> > Some Logitech HID++ 2.0 mice can report diverted reprogrammable
> > controls through HID++ feature 0x1b04, SpecialKeysMseButtons /
> > REPROG_CONTROLS_V4, instead of the normal HID mouse report.
> >
> > Add a quirk-gated event path for those controls. The handler temporarily
> > diverts verified per-product controls, parses divertedButtonsEvent as the
> > current pressed-control list, and reports the corresponding evdev key state
> > for every mapped control.
> >
> > Keep the control mappings in per-product profiles so adding support for
> > another mouse does not change the evdev capabilities advertised by
> > already-supported devices.
>
> How does this forced setting work/clash with the programmable buttons
> in Solaar?
>
> I've added some inline comments below.
>
> >
> > Documentation for feature 0x1b04 describes divertedButtonsEvent as a list
> > of currently pressed diverted buttons, which is the event format handled
> > here.
> >
> > Link: https://lekensteyn.nl/files/logitech/x1b04_specialkeysmsebuttons.html
> >
> > Signed-off-by: Elliot Douglas <edouglas7358@gmail.com>
> > ---
> > drivers/hid/hid-logitech-hidpp.c | 215 +++++++++++++++++++++++++++++++
> > 1 file changed, 215 insertions(+)
> >
> > diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
> > index 70ba1a5e40d8..24c9cfaa4f37 100644
> > --- a/drivers/hid/hid-logitech-hidpp.c
> > +++ b/drivers/hid/hid-logitech-hidpp.c
> > @@ -76,6 +76,7 @@ MODULE_PARM_DESC(disable_tap_to_click,
> > #define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(28)
> > #define HIDPP_QUIRK_WIRELESS_STATUS BIT(29)
> > #define HIDPP_QUIRK_RESET_HI_RES_SCROLL BIT(30)
> > +#define HIDPP_QUIRK_HIDPP_REPROG_CONTROLS_BTNS BIT(31)
> >
> > /* These are just aliases for now */
> > #define HIDPP_QUIRK_KBD_SCROLL_WHEEL HIDPP_QUIRK_HIDPP_WHEELS
> > @@ -205,6 +206,7 @@ struct hidpp_device {
> > struct hidpp_scroll_counter vertical_wheel_counter;
> >
> > u8 wireless_feature_index;
> > + u8 reprog_controls_feature_index;
> >
> > int hires_wheel_multiplier;
> > u8 hires_wheel_feature_index;
> > @@ -3601,6 +3603,209 @@ static int hidpp10_extra_mouse_buttons_raw_event(struct hidpp_device *hidpp,
> > return 1;
> > }
> >
> > +/* -------------------------------------------------------------------------- */
> > +/* HID++2.0 reprogrammable controls */
> > +/* -------------------------------------------------------------------------- */
> > +
> > +#define HIDPP_PAGE_REPROG_CONTROLS_V4 0x1b04
> > +
> > +#define HIDPP_REPROG_CONTROLS_GET_COUNT 0x00
> > +#define HIDPP_REPROG_CONTROLS_GET_CID_INFO 0x10
> > +#define HIDPP_REPROG_CONTROLS_SET_CONTROL_REPORTING 0x30
> > +
> > +#define HIDPP_REPROG_CONTROLS_FLAG_MOUSE BIT(0)
> > +#define HIDPP_REPROG_CONTROLS_FLAG_DIVERT BIT(5)
> > +
> > +#define HIDPP_REPROG_CONTROLS_TEMPORARY_DIVERTED BIT(0)
> > +#define HIDPP_REPROG_CONTROLS_CHANGE_TEMPORARY_DIVERT BIT(1)
> > +
> > +#define HIDPP_REPROG_CONTROLS_EVENT_DIVERTED 0x00
> > +
> > +struct hidpp_reprog_control_mapping {
> > + u16 control;
> > + u16 code;
> > +};
> > +
> > +struct hidpp_reprog_controls_profile {
> > + const struct hidpp_reprog_control_mapping *mappings;
>
> probably needs a __counted_by(), or maybe as it's static, it might be
> better to not require an intermediate struct, and return a NULL-
> terminated array instead.
>
> > + unsigned int mapping_count;
> > +};
> > +
> > +static const struct hidpp_reprog_controls_profile *
> > +hidpp20_reprog_controls_get_profile(struct hidpp_device *hidpp)
> > +{
> > + return NULL;
> > +}
> > +
> > +static int hidpp20_reprog_controls_get_count(struct hidpp_device *hidpp)
> > +{
> > + struct hidpp_report response;
> > + u8 feature_index = hidpp->reprog_controls_feature_index;
> > + u8 cmd = HIDPP_REPROG_CONTROLS_GET_COUNT;
> > + int ret;
> > +
> > + ret = hidpp_send_fap_command_sync(hidpp, feature_index, cmd, NULL, 0,
> > + &response);
> > + if (ret > 0)
> > + return -EPROTO;
> > + if (ret)
> > + return ret;
> > +
> > + return response.fap.params[0];
> > +}
> > +
> > +static int hidpp20_reprog_controls_get_cid_info(struct hidpp_device *hidpp,
> > + u8 index, u16 *control,
> > + u8 *flags)
> > +{
> > + struct hidpp_report response;
> > + u8 feature_index = hidpp->reprog_controls_feature_index;
> > + u8 cmd = HIDPP_REPROG_CONTROLS_GET_CID_INFO;
> > + int ret;
> > +
> > + ret = hidpp_send_fap_command_sync(hidpp, feature_index, cmd, &index,
> > + sizeof(index), &response);
> > + if (ret > 0)
> > + return -EPROTO;
> > + if (ret)
> > + return ret;
> > +
> > + *control = get_unaligned_be16(&response.fap.params[0]);
> > + *flags = response.fap.params[4];
> > +
> > + return 0;
> > +}
> > +
> > +static bool hidpp20_reprog_controls_find_control(struct hidpp_device *hidpp,
> > + u16 control)
> > +{
> > + int count, ret;
> > + u16 cid;
> > + u8 flags;
> > + int i;
> > +
> > + count = hidpp20_reprog_controls_get_count(hidpp);
> > + if (count < 0)
> > + return false;
> > +
> > + for (i = 0; i < count; i++) {
> > + ret = hidpp20_reprog_controls_get_cid_info(hidpp, i, &cid,
> > + &flags);
> > + if (ret)
> > + return false;
> > +
> > + if (cid == control)
> > + return (flags & HIDPP_REPROG_CONTROLS_FLAG_MOUSE) &&
> > + (flags & HIDPP_REPROG_CONTROLS_FLAG_DIVERT);
> > + }
> > +
> > + return false;
> > +}
> > +
> > +static int hidpp20_reprog_controls_set_control_reporting(struct hidpp_device *hidpp,
> > + u16 control, u8 flags)
> > +{
> > + struct hidpp_report response;
> > + u8 params[5];
> > +
> > + put_unaligned_be16(control, ¶ms[0]);
> > + params[2] = flags;
> > + put_unaligned_be16(control, ¶ms[3]);
> > +
> > + return hidpp_send_fap_command_sync(hidpp,
> > + hidpp->reprog_controls_feature_index,
> > + HIDPP_REPROG_CONTROLS_SET_CONTROL_REPORTING,
> > + params, sizeof(params), &response);
> > +}
> > +
> > +static void hidpp20_reprog_controls_connect(struct hidpp_device *hidpp)
> > +{
> > + const struct hidpp_reprog_controls_profile *profile;
> > + u8 flags = HIDPP_REPROG_CONTROLS_TEMPORARY_DIVERTED |
> > + HIDPP_REPROG_CONTROLS_CHANGE_TEMPORARY_DIVERT;
> > + unsigned int i;
> > +
> > + if (!(hidpp->quirks & HIDPP_QUIRK_HIDPP_REPROG_CONTROLS_BTNS))
> > + return;
> > +
> > + profile = hidpp20_reprog_controls_get_profile(hidpp);
>
> Could the profile be cached in the hidpp_device struct?
>
> > + if (!profile)
> > + return;
> > +
> > + if (hidpp_root_get_feature(hidpp, HIDPP_PAGE_REPROG_CONTROLS_V4,
> > + &hidpp->reprog_controls_feature_index))
> > + return;
> > +
> > + for (i = 0; i < profile->mapping_count; i++) {
> > + u16 control = profile->mappings[i].control;
> > +
> > + if (!hidpp20_reprog_controls_find_control(hidpp, control))
> > + continue;
> > +
> > + hidpp20_reprog_controls_set_control_reporting(hidpp, control, flags);
> > + }
> > +}
> > +
> > +static int hidpp20_reprog_controls_raw_event(struct hidpp_device *hidpp,
> > + u8 *data, int size)
> > +{
> > + const struct hidpp_reprog_controls_profile *profile;
> > + const struct hidpp_reprog_control_mapping *mapping;
> > + struct hidpp_report *report = (struct hidpp_report *)data;
> > + u16 controls[4];
> > + bool pressed;
> > + unsigned int i, j;
> > +
> > + if (!(hidpp->quirks & HIDPP_QUIRK_HIDPP_REPROG_CONTROLS_BTNS) ||
> > + !hidpp->input ||
> > + hidpp->reprog_controls_feature_index == 0xff)
> > + return 0;
> > +
> > + profile = hidpp20_reprog_controls_get_profile(hidpp);
> > + if (!profile)
> > + return 0;
> > +
> > + if (size < HIDPP_REPORT_LONG_LENGTH ||
> > + report->fap.feature_index != hidpp->reprog_controls_feature_index ||
> > + report->fap.funcindex_clientid != HIDPP_REPROG_CONTROLS_EVENT_DIVERTED)
> > + return 0;
> > +
> > + for (i = 0; i < ARRAY_SIZE(controls); i++)
> > + controls[i] = get_unaligned_be16(&report->fap.params[i * 2]);
> > +
> > + for (i = 0; i < profile->mapping_count; i++) {
> > + mapping = &profile->mappings[i];
> > + pressed = false;
> > +
> > + for (j = 0; j < ARRAY_SIZE(controls); j++) {
> > + if (controls[j] == mapping->control) {
> > + pressed = true;
> > + break;
> > + }
> > + }
> > +
> > + input_report_key(hidpp->input, mapping->code, pressed);
> > + }
> > +
> > + input_sync(hidpp->input);
> > +
> > + return 1;
> > +}
> > +
> > +static void hidpp20_reprog_controls_populate_input(struct hidpp_device *hidpp,
> > + struct input_dev *input_dev)
> > +{
> > + const struct hidpp_reprog_controls_profile *profile;
> > + unsigned int i;
> > +
> > + profile = hidpp20_reprog_controls_get_profile(hidpp);
> > + if (!profile)
> > + return;
> > +
> > + for (i = 0; i < profile->mapping_count; i++)
> > + input_set_capability(input_dev, EV_KEY, profile->mappings[i].code);
> > +}
> > +
> > static void hidpp10_extra_mouse_buttons_populate_input(
> > struct hidpp_device *hidpp, struct input_dev *input_dev)
> > {
> > @@ -3859,6 +4064,9 @@ static void hidpp_populate_input(struct hidpp_device *hidpp,
> >
> > if (hidpp->quirks & HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS)
> > hidpp10_extra_mouse_buttons_populate_input(hidpp, input);
> > +
> > + if (hidpp->quirks & HIDPP_QUIRK_HIDPP_REPROG_CONTROLS_BTNS)
> > + hidpp20_reprog_controls_populate_input(hidpp, input);
> > }
> >
> > static int hidpp_input_configured(struct hid_device *hdev,
> > @@ -3971,6 +4179,10 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
> > return ret;
> > }
> >
> > + ret = hidpp20_reprog_controls_raw_event(hidpp, data, size);
> > + if (ret != 0)
> > + return ret;
> > +
> > if (hidpp->quirks & HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS) {
> > ret = hidpp10_consumer_keys_raw_event(hidpp, data, size);
> > if (ret != 0)
> > @@ -4264,6 +4476,8 @@ static void hidpp_connect_event(struct work_struct *work)
> > return;
> > }
> >
> > + hidpp20_reprog_controls_connect(hidpp);
> > +
> > if (hidpp->quirks & HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS) {
> > ret = hidpp10_consumer_keys_connect(hidpp);
> > if (ret)
> > @@ -4436,6 +4650,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
> > hidpp->hid_dev = hdev;
> > hidpp->name = hdev->name;
> > hidpp->quirks = id->driver_data;
> > + hidpp->reprog_controls_feature_index = 0xff;
> > hid_set_drvdata(hdev, hidpp);
> >
> > ret = hid_parse(hdev);
^ permalink raw reply
* Re: [PATCH v4 10/10] Input: cap11xx - add support for CAP1114
From: sashiko-bot @ 2026-06-17 21:25 UTC (permalink / raw)
To: Jun Yan; +Cc: dmitry.torokhov, devicetree, linux-input, conor+dt, robh
In-Reply-To: <20260617150318.753148-11-jerrysteve1101@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Out-of-bounds write in `cap11xx_i2c_probe` due to unvalidated Device Tree keycodes.
--
commit 42cef688f767435c4da8af0dd519be20d4164735
Author: Jun Yan <jerrysteve1101@gmail.com>
CAP1114 is a 14-channel capacitive touch sensor with 11 LED outputs
and hardware reset support.
This commit adds support for the CAP1114 touch sensor, updating the driver
to handle up to 14 channels and 11 LED outputs. It introduces logic to
read from a secondary status register to support the expanded channel count
and configures grouped sensors as independent inputs.
> diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
> index 275eb79a7193..865c58533eb9 100644
> --- a/drivers/input/keyboard/cap11xx.c
> +++ b/drivers/input/keyboard/cap11xx.c
[ ... ]
> @@ -292,6 +307,17 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv)
> of_property_read_u32_array(node, "linux,keycodes",
> priv->keycodes, priv->model->num_channels);
[Severity: High]
This is a pre-existing issue, but I noticed that these keycodes are read
directly from the Device Tree into the priv->keycodes array without any
bounds validation.
Later during initialization in cap11xx_i2c_probe(), the driver loops over
these keycodes and sets bits using an unchecked macro:
__set_bit(priv->keycodes[i], priv->idev->keybit);
If an exceptionally large keycode (greater than KEY_MAX) is provided via a
Device Tree overlay, could this cause an out-of-bounds write on the
priv->idev->keybit array and corrupt adjacent heap memory? Should we verify
that each keycode read from the Device Tree is less than or equal to KEY_MAX?
> +
> + /*
> + * CAP1114 needs dedicated configuration to split
> + * grouped sensors into independent inputs.
> + */
> + if (priv->model->has_grouped_sensors) {
> + error = regmap_set_bits(priv->regmap, CAP1114_REG_CONFIG2,
> + CAP1114_REG_CONFIG2_VOL_UP_DOWN);
> + if (error)
> + return error;
> + }
> +
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260617150318.753148-1-jerrysteve1101@gmail.com?part=10
^ permalink raw reply
* Re: [PATCH v4 09/10] dt-bindings: input: microchip,cap11xx: Add CAP1114 support
From: sashiko-bot @ 2026-06-17 21:15 UTC (permalink / raw)
To: Jun Yan; +Cc: conor+dt, devicetree, robh, linux-input, dmitry.torokhov
In-Reply-To: <20260617150318.753148-10-jerrysteve1101@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Schema Validation Regression (Incomplete Constraints Update)
--
commit 74e08f50d786114a66be01956a59aeb6b7083fbc
Author: Jun Yan <jerrysteve1101@gmail.com>
dt-bindings: input: cap11xx: Add CAP1114 support
CAP1114 is a 14-channel capacitive touch sensor with 11 LED outputs
and hardware reset support. Add the compatible string for CAP1114, add
its datasheet URL, update the maximum of LED channel reg, and add
constraint for linux,keycodes.
> diff --git a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
> index b97e5b2735f1..2a37ac252c37 100644
> --- a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
> +++ b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
[ ... ]
> @@ -140,7 +144,7 @@ properties:
> The number of entries must correspond to the number of channels.
>
> patternProperties:
> - "^led@[0-7]$":
> + "^led@[0-9a]$":
[Severity: Medium]
Does this global regex update also require an update to the disablement block
for hardware variants without LEDs?
The allOf block that disables LEDs for specific variants (like CAP1106,
CAP1203, etc.) still uses "^led@[0-7]$": false.
Because of this new global regex, wouldn't nodes like led@8, led@9,
and led@a now bypass the false constraint and be silently permitted on
devices that are supposed to have zero LEDs?
> type: object
> description: CAP11xx LEDs
> $ref: /schemas/leds/common.yaml#
> @@ -149,7 +153,7 @@ patternProperties:
> reg:
> description: LED channel number
> minimum: 0
> - maximum: 7
> + maximum: 10
>
> label: true
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260617150318.753148-1-jerrysteve1101@gmail.com?part=9
^ permalink raw reply
* Re: [PATCH v4 07/10] Input: cap11xx - refactor code for better CAP1114 support.
From: sashiko-bot @ 2026-06-17 20:57 UTC (permalink / raw)
To: Jun Yan; +Cc: conor+dt, devicetree, dmitry.torokhov, linux-input, robh
In-Reply-To: <20260617150318.753148-8-jerrysteve1101@gmail.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] Bitmask truncation in `cap11xx_led_set` causing silent failure for LEDs >= 8.
- [High] Regmap cache staleness due to missing volatile register definition for the dynamic `sensor_input_reg_base`.
Pre-existing issues:
- [High] Buffer overflow and Fortify Source panic when reading `calib_sensitivities` for devices with more than 8 channels.
--
commit 837f207153012dfc0860b6d46ad5d3ae4f7b3004
Author: Jun Yan <jerrysteve1101@gmail.com>
Extend cap11xx_hw_model structure to support CAP1114
This patch extends the cap11xx_hw_model structure to support CAP1114
with different register offsets and hardware characteristics.
> diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
> index 1db4a9090705..0f19ee036e78 100644
> --- a/drivers/input/keyboard/cap11xx.c
> +++ b/drivers/input/keyboard/cap11xx.c
[ ... ]
> @@ -211,8 +215,8 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv)
> }
>
> if (!of_property_read_u32_array(node, "microchip,input-threshold",
> - priv->thresholds, priv->model->num_channels)) {
> + priv->thresholds, priv->model->num_sensor_thresholds)) {
> - for (i = 0; i < priv->model->num_channels; i++) {
> + for (i = 0; i < priv->model->num_sensor_thresholds; i++) {
> if (priv->thresholds[i] > 127) {
> dev_err(dev, "Invalid input-threshold value %u\n",
> priv->thresholds[i]);
[Severity: High]
This is a pre-existing issue, but looking at cap11xx_init_keys(), could
reading "microchip,calib-sensitivity" overflow the calib_sensitivities array
for devices with more than 8 channels?
In cap11xx_init_keys():
} else if (!of_property_read_u32_array(node, "microchip,calib-sensitivity",
priv->calib_sensitivities,
priv->model->num_channels)) {
The calib_sensitivities array is statically allocated to 8 elements in
struct cap11xx_priv. For models with more than 8 channels (like the CAP1114
which has 14), could this cause a buffer overflow into the keycodes array
and trigger a kernel panic if FORTIFY_SOURCE is enabled?
[ ... ]
> @@ -308,7 +314,7 @@ static irqreturn_t cap11xx_thread_func(int irq_num, void *data)
> if (ret < 0)
> goto out;
>
> - ret = regmap_read(priv->regmap, CAP11XX_REG_SENSOR_INPUT, &status);
> + ret = regmap_read(priv->regmap, priv->model->sensor_input_reg_base, &status);
> if (ret < 0)
> goto out;
[Severity: High]
Will this result in reading stale cached values instead of the actual
hardware state?
The interrupt handler now dynamically reads from sensor_input_reg_base.
However, cap11xx_volatile_reg() still hardcodes CAP11XX_REG_SENSOR_INPUT as
a volatile register.
Since the new dynamic base register (and the subsequent register for devices
with more than 8 channels) is no longer marked volatile, will the regmap
cache return stale data and break input events for these models?
[ ... ]
> @@ -362,7 +368,7 @@ static int cap11xx_led_set(struct led_classdev *cdev,
> * 0 (OFF) and 1 (ON).
> */
> return regmap_update_bits(priv->regmap,
> - CAP11XX_REG_LED_OUTPUT_CONTROL,
> + priv->model->led_output_control_reg_base,
> BIT(led->reg),
> value ? BIT(led->reg) : 0);
> }
[Severity: High]
Will this bitmask be truncated for LEDs with an index of 8 or higher?
The bitmask passed to regmap_update_bits() is BIT(led->reg). Since models
like CAP1114 support more than 8 LEDs, and the register operations are 8-bit,
BIT(led->reg) will exceed 8 bits for higher-index LEDs.
The initialization code in cap11xx_init_leds() caps the LED clearance mask to
8 bits:
GENMASK(min(num_leds, 8) - 1, 0)
Does cap11xx_led_set() also need an update to handle devices with more than
8 LEDs to avoid silently failing?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260617150318.753148-1-jerrysteve1101@gmail.com?part=7
^ permalink raw reply
* Re: [PATCH v4 03/10] dt-bindings: input: microchip,cap11xx: Update datasheet URL and LED reg range
From: sashiko-bot @ 2026-06-17 20:31 UTC (permalink / raw)
To: Jun Yan; +Cc: devicetree, linux-input, robh, dmitry.torokhov, conor+dt
In-Reply-To: <20260617150318.753148-4-jerrysteve1101@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Incomplete Refactoring / Code and Commit Message Mismatch
--
commit e8499e0ca62db6a2ee6dc0986e7c04ea1337f6c7
Author: Jun Yan <jerrysteve1101@gmail.com>
Add datasheet links for all supported CAP11xx variants.
Update LED node regex and replace enum constraints with minimum/maximum
for LED reg ranges in preparation for CAP1114 support. Drop unnecessary
led unit-address pattern.
> diff --git a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
> index 7ade03f1b32b..eabf06a1163e 100644
> --- a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
> +++ b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
[ ... ]
> @@ -131,7 +140,9 @@ patternProperties:
>
> properties:
> reg:
> - enum: [0, 1, 2, 3, 4, 5, 6, 7]
> + description: LED channel number
> + minimum: 0
> + maximum: 7
[Severity: Medium]
Does this fully prepare the schema for CAP1114 support as mentioned in the
commit message?
While the constraints on the reg property were updated here, the main
patternProperties definition for the LED node just above this still uses
"^led@[0-7]$".
Since CAP1114 has 11 LED channels, wouldn't the schema fail validation for
nodes like led@8 and led@9 because the top-level pattern wasn't also updated?
[ ... ]
> @@ -158,7 +169,7 @@ allOf:
> - microchip,cap1298
> then:
> patternProperties:
> - "^led@[0-7]$": false
> + "^led@": false
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260617150318.753148-1-jerrysteve1101@gmail.com?part=3
^ permalink raw reply
* Re: [PATCH v4 02/10] Input: cap11xx - remove unused register macros
From: sashiko-bot @ 2026-06-17 20:21 UTC (permalink / raw)
To: Jun Yan; +Cc: linux-input, dmitry.torokhov, robh, devicetree, conor+dt
In-Reply-To: <20260617150318.753148-3-jerrysteve1101@gmail.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [Medium] The patch fails to remove unused definitions in `cap11xx_volatile_reg` despite the commit message claiming otherwise.
Pre-existing issues:
- [High] The threaded interrupt handler unconditionally returns IRQ_HANDLED even when I2C operations fail to clear the hardware interrupt source, risking an IRQ storm.
--
commit 8aa29f5d8b4eefa859454cdb0496fecf07ff5aa8
Author: Jun Yan <jerrysteve1101@gmail.com>
Remove unused register address macros and unused definitions in
the cap11xx_reg_defaults array and cap11xx_volatile_reg.
This cleanup reduces code clutter and makes the driver easier to
maintain without affecting functionality.
> Remove unused register address macros and unused definitions in
> the cap11xx_reg_defaults array and cap11xx_volatile_reg.
[Severity: Medium]
Will this patch actually remove the unused definitions in
cap11xx_volatile_reg?
The commit message states they are removed, but the patch doesn't modify
that function.
> diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
> index 485d8ba97723..fae26f035186 100644
> --- a/drivers/input/keyboard/cap11xx.c
> +++ b/drivers/input/keyboard/cap11xx.c
> @@ -20,53 +20,24 @@
> #define CAP11XX_REG_MAIN_CONTROL_GAIN_SHIFT (6)
> #define CAP11XX_REG_MAIN_CONTROL_GAIN_MASK (0xc0)
> #define CAP11XX_REG_MAIN_CONTROL_DLSEEP BIT(4)
> -#define CAP11XX_REG_GENERAL_STATUS 0x02
> #define CAP11XX_REG_SENSOR_INPUT 0x03
> -#define CAP11XX_REG_NOISE_FLAG_STATUS 0x0a
> #define CAP11XX_REG_SENOR_DELTA(X) (0x10 + (X))
[Severity: Medium]
Should this macro also have been removed?
Because cap11xx_volatile_reg() was not updated, this macro and its
corresponding case entries:
case CAP11XX_REG_SENOR_DELTA(0):
case CAP11XX_REG_SENOR_DELTA(1):
were left in the file.
[ ... ]
> static bool cap11xx_volatile_reg(struct device *dev, unsigned int reg)
[Severity: High]
This isn't a bug introduced by this patch, but could the error handling
in cap11xx_thread_func() risk an IRQ storm?
If an I2C communication error occurs during the interrupt handler:
cap11xx_thread_func() {
...
if (ret < 0)
goto out;
...
out:
return IRQ_HANDLED;
}
Because this uses IRQF_ONESHOT, returning IRQ_HANDLED instructs the IRQ
subsystem to unmask the interrupt. Since the device's interrupt status
was never cleared due to the I2C failure, the interrupt line will remain
asserted.
Will this cause the interrupt to immediately fire again when unmasked,
creating an infinite loop?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260617150318.753148-1-jerrysteve1101@gmail.com?part=2
^ permalink raw reply
* Re: [PATCH 2/9] iio: orientation: hid-sensor-incl-3d: Fix race between callback registration and device exposure
From: Pandruvada, Srinivas @ 2026-06-17 19:50 UTC (permalink / raw)
To: jic23@kernel.org, sanjayembeddedse@gmail.com
Cc: dlechner@baylibre.com, archana.patni@linux.intel.com,
hongyan.song@intel.com, linux-iio@vger.kernel.org,
nuno.sa@analog.com, linux-kernel@vger.kernel.org,
jikos@kernel.org, andy@kernel.org, linux-input@vger.kernel.org
In-Reply-To: <3FED088A-651B-4E8B-840B-1B92CB4DF6F4@gmail.com>
On Thu, 2026-06-18 at 00:07 +0530, Sanjay Chitroda wrote:
>
>
> On 15 June 2026 7:06:43 pm IST, "Pandruvada, Srinivas"
> <srinivas.pandruvada@intel.com> wrote:
> > On Sun, 2026-06-14 at 19:24 +0100, Jonathan Cameron wrote:
> > > On Mon, 8 Jun 2026 15:34:05 +0000
> > > "Pandruvada, Srinivas" <srinivas.pandruvada@intel.com> wrote:
> > >
> > > > On Sat, 2026-06-06 at 17:07 +0530, Sanjay Chitroda wrote:
> > > > > From: Sanjay Chitroda <sanjayembeddedse@gmail.com>
> > > > >
> > > > > The driver registers the IIO device before completing sensor
> > > > > hub
> > > > > callback registration and unregisters callbacks while the IIO
> > > > > device
> > > > > is still exposed during teardown.
> > > > >
> > > > > This creates race windows in both probe and remove paths,
> > > > > which
> > > > > can
> > > > > lead to NULL pointer dereferences or use-after-free.
> > > >
> > > > Reordering is fine, but can you show how this use after free is
> > > > possible?
> > > Agreed - I'm not seeing a definite issue so more info needed.
> > > For now I'm going to mark this changes-requested in patchwork.
> > >
> > > It might be a touch slow if someone manages to get buffered
> > > capture
> > > up before the callbacks are available, but I think that just
> > > means
> > > dropping a few samples?
> >
> >
> > Correct.
> >
> > Thanks,
> > Srinivas
>
> Hi Jonathan and Srinivas,
>
Hi Sanjay,
> Thanks for the review and for pointing this out.
>
> After analyzing and investigating the interaction between callback
> registration and iio_device_register().
>
> Found that read_raw() (on-demand access) and buffered IIO (streaming)
> operate via different paths. The primary impact is loss/stable
> samples rather than data corruption or system instability.
>
> Given this, I believe the change does not strictly qualify as a "fix"
> for a user-visible regression, but rather as an improvement to
> tighten ordering and avoid a potential race window.
>
> Treating this as a improvement patch rather than a bug fix with
> potential following commit message in v2.
>
> .............
>
> iio: orientation: hid-sensor-incl-3d: Avoid race between callback
> setup and device exposure
>
> The driver currently exposes the IIO device to userspace before
> completing sensor hub callback registration, and similarly removes
> callbacks while the device can still be accessed during teardown.
>
> This creates a timing window where userspace may enable the buffer
> before callbacks are available. In such cases:
> - samples can be dropped,
> - buffered reads may observe stale or no data.
>
> Reorder probe and remove paths to ensure callbacks are active before
> device exposure and are removed after device is no longer accessible.
>
> This avoids a race window leading to data loss.
>
Looks good.
Thanks,
Srinivas
> .............
>
> Welcome your feedback and valuable input for v2.
>
> Thanks, Sanjay
>
> >
> > >
> > > Jonathan
> > >
> > > >
> > > > Thanks,
> > > > Srinivas
> > >
^ permalink raw reply
* Re: [PATCH 00/11] HID: iio: warning clean up and prefer kernel coding style
From: Sanjay Chitroda @ 2026-06-17 19:03 UTC (permalink / raw)
To: Maxwell Doose
Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Jiri Kosina, Srinivas Pandruvada, linux-iio, linux-kernel,
linux-input, Zhang Lixu
In-Reply-To: <CAKqfh0GEeyQ3UMuMupevgPfCon+zccAv302sV5YKCETWMua-xA@mail.gmail.com>
On 17 June 2026 1:00:37 pm IST, Maxwell Doose <m32285159@gmail.com> wrote:
>On Tue, Jun 16, 2026 at 5:26 AM Sanjay Chitroda
><sanjayembeddedse@gmail.com> wrote:
>>
>> Hi all,
>>
>> This series updates HID IIO drivers to resolve checkpatch and
>> kernel coding style issue.
>>
>> This improves readability and follow standard kernel coding style
>> No functional changes are introduced.
>>
>> Testing:
>> - Compiled with W=1 for each patch in the series
>>
>> ---
>> Sanjay Chitroda (11):
>> iio: hid-sensors: add missing blank line after declarations
>> iio: humidity: hid-sensor-humidity: align parenthesis for readability
>> iio: gyro: hid-sensor-gyro-3d: align parenthesis for readability
>> iio: magnetometer: hid-sensor-magn-3d: align parenthesis for readability
>> iio: humidity: hid-sensor-humidity: use common device for devres
>> iio: position: hid-sensor-custom-intel-hinge: use common device for devres
>> iio: temperature: hid-sensor-temperature: use common device for devres
>> iio: hid-sensor-magn-3d: use ! instead of explicit NULL check
>> iio: hid-sensor-rotation: use ! instead of explicit NULL check
>> iio: hid-sensor-incl-3d: use ! instead of explicit NULL check
>> iio: hid-sensor-accel-3d: use ! instead of explicit NULL check
>>
>> drivers/iio/accel/hid-sensor-accel-3d.c | 2 +-
>> .../iio/common/hid-sensors/hid-sensor-trigger.c | 3 +
>> drivers/iio/gyro/hid-sensor-gyro-3d.c | 58 ++++++++--------
>> drivers/iio/humidity/hid-sensor-humidity.c | 48 ++++++-------
>> drivers/iio/magnetometer/hid-sensor-magn-3d.c | 80 +++++++++++-----------
>> drivers/iio/orientation/hid-sensor-incl-3d.c | 2 +-
>> drivers/iio/orientation/hid-sensor-rotation.c | 2 +-
>> .../iio/position/hid-sensor-custom-intel-hinge.c | 2 +-
>> drivers/iio/temperature/hid-sensor-temperature.c | 4 +-
>> 9 files changed, 102 insertions(+), 99 deletions(-)
>
>Firstly, for all of the style patches (1-4, 8-11):
>
>Reviewed-by: Maxwell Doose <m32285159@gmail.com>
>
Hi Maxwell,
Thank you for the review.
>with Andy's comments.
>
>Secondly, the style fixes are all churn. It would honestly be much
>much better if you were to squash those (even despite the
>one-logical-change-per-patch rule).
I agree with squashing 1-4, common HID drivers-specific changes which cover all HID IIO drivers.
However, this series updates 4 HID drivers, while several other HID IIO drivers needs coding style cleanup.
I'd like to ask Jonathan for his opinion on whether all alignment coding style should be handled in single change, individual change or some logic specific HIO IIO drivers split.
Additionally, 5-7 haven't received any comment/tag. I can consider all changes in v2 and also rebase on latest iio/testing tree to incorporate u32 usage_id change.
Thanks, Sanjay
>
^ permalink raw reply
* Re: [PATCH 2/9] iio: orientation: hid-sensor-incl-3d: Fix race between callback registration and device exposure
From: Sanjay Chitroda @ 2026-06-17 18:37 UTC (permalink / raw)
To: Pandruvada, Srinivas, jic23@kernel.org
Cc: dlechner@baylibre.com, archana.patni@linux.intel.com,
hongyan.song@intel.com, linux-iio@vger.kernel.org,
nuno.sa@analog.com, linux-kernel@vger.kernel.org,
jikos@kernel.org, andy@kernel.org, linux-input@vger.kernel.org
In-Reply-To: <50ce20dec63080dde13336c6af41c0bf4de43426.camel@intel.com>
On 15 June 2026 7:06:43 pm IST, "Pandruvada, Srinivas" <srinivas.pandruvada@intel.com> wrote:
>On Sun, 2026-06-14 at 19:24 +0100, Jonathan Cameron wrote:
>> On Mon, 8 Jun 2026 15:34:05 +0000
>> "Pandruvada, Srinivas" <srinivas.pandruvada@intel.com> wrote:
>>
>> > On Sat, 2026-06-06 at 17:07 +0530, Sanjay Chitroda wrote:
>> > > From: Sanjay Chitroda <sanjayembeddedse@gmail.com>
>> > >
>> > > The driver registers the IIO device before completing sensor hub
>> > > callback registration and unregisters callbacks while the IIO
>> > > device
>> > > is still exposed during teardown.
>> > >
>> > > This creates race windows in both probe and remove paths, which
>> > > can
>> > > lead to NULL pointer dereferences or use-after-free.
>> >
>> > Reordering is fine, but can you show how this use after free is
>> > possible?
>> Agreed - I'm not seeing a definite issue so more info needed.
>> For now I'm going to mark this changes-requested in patchwork.
>>
>> It might be a touch slow if someone manages to get buffered capture
>> up before the callbacks are available, but I think that just means
>> dropping a few samples?
>
>
>Correct.
>
>Thanks,
>Srinivas
Hi Jonathan and Srinivas,
Thanks for the review and for pointing this out.
After analyzing and investigating the interaction between callback registration and iio_device_register().
Found that read_raw() (on-demand access) and buffered IIO (streaming) operate via different paths. The primary impact is loss/stable samples rather than data corruption or system instability.
Given this, I believe the change does not strictly qualify as a "fix" for a user-visible regression, but rather as an improvement to tighten ordering and avoid a potential race window.
Treating this as a improvement patch rather than a bug fix with potential following commit message in v2.
.............
iio: orientation: hid-sensor-incl-3d: Avoid race between callback setup and device exposure
The driver currently exposes the IIO device to userspace before completing sensor hub callback registration, and similarly removes callbacks while the device can still be accessed during teardown.
This creates a timing window where userspace may enable the buffer before callbacks are available. In such cases:
- samples can be dropped,
- buffered reads may observe stale or no data.
Reorder probe and remove paths to ensure callbacks are active before device exposure and are removed after device is no longer accessible.
This avoids a race window leading to data loss.
.............
Welcome your feedback and valuable input for v2.
Thanks, Sanjay
>
>>
>> Jonathan
>>
>> >
>> > Thanks,
>> > Srinivas
>>
^ permalink raw reply
* Re: [PATCH v2] HID: wacom: avoid copying Bluetooth input reports
From: Jason Gerecke @ 2026-06-17 16:55 UTC (permalink / raw)
To: Ruoyu Wang
Cc: Ping Cheng, Jason Gerecke, Jiri Kosina, Benjamin Tissoires,
linux-input, linux-kernel
In-Reply-To: <20260617072035.3373487-1-ruoyuw560@gmail.com>
On Wed, Jun 17, 2026 at 12:21 AM Ruoyu Wang <ruoyuw560@gmail.com> wrote:
>
> wacom_intuos_bt_irq() duplicates the received Bluetooth report with
> kmemdup() so that it can pass 10-byte input report payloads to the
> common Intuos parser. The helper then copies each payload back into
> wacom->data before calling wacom_intuos_irq().
>
> Avoid the allocation and copy by temporarily pointing wacom->data at the
> current 10-byte payload while the common parser runs, then restoring the
> original report pointer. The Bluetooth report parser keeps using the
> original report buffer for dispatch and battery parsing, while the common
> parser sees the same payload bytes as before.
>
> This also removes the unchecked kmemdup() result from the Bluetooth IRQ
> path.
>
> Suggested-by: Jason Gerecke <jason.gerecke@wacom.com>
> Signed-off-by: Ruoyu Wang <ruoyuw560@gmail.com>
Thanks for the update! The sashiko warnings reveal an existing issue
with this function triggering unaligned memory accesses. I don't think
the warnings should block this particular patch, but instead remind us
that some kind of dedicated alignment cleanup patch would be a good
idea.
Reviewed-by: Jason Gerecke <jason.gerecke@wacom.com>
Jason (she/they)
---
Now instead of four in the eights place /
you’ve got three, ‘Cause you added one /
(That is to say, eight) to the two, /
But you can’t take seven from three, /
So you look at the sixty-fours....
> ---
> Changes in v2:
> - Replace the kmemdup()/memcpy() path with temporary wacom->data pointer
> substitution, as suggested by Jason.
>
> drivers/hid/wacom_wac.c | 8 +++++---
> 1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
> index da1f0ea85625d..a29bf051ada7c 100644
> --- a/drivers/hid/wacom_wac.c
> +++ b/drivers/hid/wacom_wac.c
> @@ -1192,8 +1192,11 @@ static int int_dist(int x1, int y1, int x2, int y2)
> static void wacom_intuos_bt_process_data(struct wacom_wac *wacom,
> unsigned char *data)
> {
> - memcpy(wacom->data, data, 10);
> + u8 *saved_data = wacom->data;
> +
> + wacom->data = data;
> wacom_intuos_irq(wacom);
> + wacom->data = saved_data;
>
> input_sync(wacom->pen_input);
> if (wacom->pad_input)
> @@ -1202,7 +1205,7 @@ static void wacom_intuos_bt_process_data(struct wacom_wac *wacom,
>
> static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
> {
> - u8 *data = kmemdup(wacom->data, len, GFP_KERNEL);
> + u8 *data = wacom->data;
> int i = 1;
> unsigned power_raw, battery_capacity, bat_charging, ps_connected;
>
> @@ -1242,7 +1245,6 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
> break;
> }
>
> - kfree(data);
> return 0;
> }
>
> --
> 2.51.0
>
^ permalink raw reply
* Re: hid-lg-g15: possible use-after-free of devm data via work scheduled from a report
From: Hans de Goede @ 2026-06-17 16:24 UTC (permalink / raw)
To: Maoyi Xie, Jiri Kosina, Benjamin Tissoires; +Cc: linux-input, linux-kernel
In-Reply-To: <178169820506.2930960.12219303668828186338@maoyixie.com>
Hi,
On 17-Jun-26 14:10, Maoyi Xie wrote:
> Hi all,
>
> I think the lg-g15 driver can read freed memory on disconnect. I would
> appreciate it if you could check my reading before I send a patch.
>
> The per device state is allocated with devm in lg_g15_probe().
>
> g15 = devm_kzalloc(&hdev->dev, sizeof(*g15), GFP_KERNEL);
>
> That struct contains a work item, and the report handlers schedule it
> straight from device input. For example in lg_g15_event().
>
> /* Backlight cycle button pressed? */
> if (data[1] & 0x80)
> schedule_work(&g15->work);
>
> The same schedule_work(&g15->work) call also runs in lg_g15_v2_event() and
> lg_g510_leds_event(). The worker lg_g15_leds_changed_work() does a
> container_of() back to g15 and dereferences g15->mutex and g15->leds.
>
> The driver has a probe but no remove callback, and there is no
> cancel_work_sync() anywhere in the file. So if a report schedules the work
> and the keyboard is then removed, devm frees g15 while the work is still
> pending or running, and the worker touches the freed object.
>
> The attacker model is a Logitech G15 class keyboard that sends one report
> with the backlight cycle bit set and then disconnects. That can be a
> malicious device or an unlucky unplug.
>
> I reproduced the freed while pending pattern under KASAN on 7.1-rc7. The
> workqueue picked up the orphaned work after the object was freed, and KASAN
> reported a slab-use-after-free read.
>
> The fix I tried is a small remove callback that cancels the work before the
> devm teardown frees g15.
>
> static void lg_g15_remove(struct hid_device *hdev)
> {
> struct lg_g15_data *g15 = hid_get_drvdata(hdev);
>
> if (g15)
> cancel_work_sync(&g15->work);
>
> hid_hw_stop(hdev);
> }
>
> and wiring it up with .remove = lg_g15_remove. The g15 NULL guard mirrors the
> existing check in lg_g15_raw_event().
>
> Does this look like a real issue to you, and is the remove plus
> cancel_work_sync the approach you would want? If so I am happy to send a
> proper patch with a Fixes tag against 97b741aba918.
Thank you for reporting this. Yes this looks like a real issue (possible race
on device unplug).
As for your suggested solution, that looks good but g15->work is not always
initialized. For example in the g15->model == G13 case lg_g15_probe() does
not initialize it.
I don't think you should cancel an uninitialized work. Trying to queue it
will cause a WARN() backtrace to trigger, not sure if cancel also enforces
this.
So you should add a test for `g15->work.func != NULL` or just `g15->work.func`
before cancelling.
With that fixed, a proper patch fixing this would be much appreciated.
Regards,
Hans
^ permalink raw reply
* Re: [PATCH 0/4] HID: wacom: add report length validation in irq handlers
From: Jason Gerecke @ 2026-06-17 15:55 UTC (permalink / raw)
To: Jiri Kosina
Cc: Jinmo Yang, linux-input, benjamin.tissoires, linux-kernel, stable,
Ping Cheng, Jason Gerecke
In-Reply-To: <9o1psn77-q665-0rp6-pnnq-9179802p2nsp@xreary.bet>
On Wed, Jun 10, 2026 at 9:19 AM Jiri Kosina <jikos@kernel.org> wrote:
>
> On Sun, 17 May 2026, Jinmo Yang wrote:
>
> > Several wacom IRQ handler sub-functions access fixed offsets in the raw
> > HID report buffer without validating the buffer length. wacom_wac_irq()
> > receives the length from wacom_raw_event() but does not validate it
> > before dispatching to the sub-functions, which do not receive the length
> > parameter.
> >
> > A malicious USB device can declare a small HID report in its descriptor
> > and send a matching short report that passes the HID core size check
> > (csize >= rsize), but the driver assumes a full-size hardware report
> > layout, leading to slab-out-of-bounds reads.
> >
> > Note: this is not mitigated by the recent HID core bounds checking
> > series which validates actual_size >= declared_size. An attacker
> > controls both the descriptor (declared size) and the sent data (actual
> > size), so the core check passes. Driver-level validation against the
> > expected hardware report layout is still necessary.
> >
> > Tested with KASAN on Linux 7.1-rc3 (slab-out-of-bounds confirmed) and
> > verified kernel panic on a production device via uhid.
> >
> > Jinmo Yang (4):
> > HID: wacom: validate report length for PL and PTU handlers
> > HID: wacom: validate report length for DTU handler
> > HID: wacom: validate report length for DTUS handler
> > HID: wacom: validate report length for 24HDT and 27QHDT handlers
> >
Two main comments:
1) I would prefer each of these commits to pass 'len' as a value into
the sub-functions and perform the checks there. We already do this
with several of the sub-functions, and it would be good to be
consistent in where the checks are performed.
2) Please define new WACOM_PKGLEN_* values in drivers/hid/wacom_wac.h
and use these definitions rather than magic numbers. E.g. `#define
WACOM_PKGLEN_PL 8` to cover the PL case.
Jason (she/they)
---
Now instead of four in the eights place /
you’ve got three, ‘Cause you added one /
(That is to say, eight) to the two, /
But you can’t take seven from three, /
So you look at the sixty-fours....
> > drivers/hid/wacom_wac.c | 15 +++++++++++++++
> > 1 file changed, 15 insertions(+)
>
> CCing Ping and Jason for their review. Thanks in advance,
>
> --
> Jiri Kosina
> SUSE Labs
>
>
^ permalink raw reply
* Re: [PATCH 0/3] HID: iio: callback API signature match for usage_id
From: Andy Shevchenko @ 2026-06-17 15:52 UTC (permalink / raw)
To: Sanjay Chitroda
Cc: Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada, David Lechner,
Nuno Sá, Andy Shevchenko, linux-input, linux-iio,
linux-kernel
In-Reply-To: <20260616-16-jun-hid-iio-u32-api-type-v1-0-952c74195f46@gmail.com>
On Tue, Jun 16, 2026 at 06:55:19PM +0530, Sanjay Chitroda wrote:
>
> Most of HID IIO driver has correct 'u32' type of usage_id with
> https://lore.kernel.org/all/20260610-6-june-hid-iio-correct-usage-id-v2-0-c3c5f0720493@gmail.com/
> series which is applied on iio/testing branch.
>
> On top of the same, this series updates remaining HID IIO drivers
> to use 'u32' for the usage_id parameter.
>
> Pending list of HID IIO drivers are extracted with command line:
> find drivers/iio/ -type f -name "*hid*" | xargs grep -A 5 static | \
> grep -E -A 5 "_proc_event\(|_capture_sample\(|_parse_report\(" --color | \
> grep usage_id
I recommend to get used with `git grep ...` which is more powerful and much
faster (on a Git index).
git grep -lw 'u[^3].* usage_id' -- drivers/iio/
for the list of files, and
git grep -np -w 'u[^3].* usage_id' -- drivers/iio/
for a better view.
(It gives one false positive, though :-)
> This matches expected callback API type as HID usage IDs are
> defined as 32-bit values.
>
> No functional changes are introduced.
>
> Testing:
> - Compiled with W=1 for each patch in the series
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Jonathan, it seems the missing part of the initial unification. Please, apply
to your testing branch.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* [PATCH v4 01/10] Input: cap11xx - clean up duplicate log and add probe error logs
From: Jun Yan @ 2026-06-17 15:02 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, linux-input, devicetree, linux-kernel
In-Reply-To: <20260617150318.753148-1-jerrysteve1101@gmail.com>
Duplicated device detection log exists at line 537 and line 542,
which brings redundant kernel print messages. Drop one redundant
log entry to clean up dmesg output.
Meanwhile add missing error logs when I2C communication fails
during driver probe(), helping debug.
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
---
drivers/input/keyboard/cap11xx.c | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index 2447c1ae2166..485d8ba97723 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -512,7 +512,7 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
error = regmap_read(priv->regmap, CAP11XX_REG_PRODUCT_ID, &val);
if (error)
- return error;
+ return dev_err_probe(dev, error, "Failed to read product ID\n");
if (val != cap->product_id) {
dev_err(dev, "Product ID: Got 0x%02x, expected 0x%02x\n",
@@ -522,7 +522,7 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
error = regmap_read(priv->regmap, CAP11XX_REG_MANUFACTURER_ID, &val);
if (error)
- return error;
+ return dev_err_probe(dev, error, "Failed to read manufacturer ID\n");
if (val != CAP11XX_MANUFACTURER_ID) {
dev_err(dev, "Manufacturer ID: Got 0x%02x, expected 0x%02x\n",
@@ -531,11 +531,8 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
}
error = regmap_read(priv->regmap, CAP11XX_REG_REVISION, &rev);
- if (error < 0)
- return error;
-
- dev_info(dev, "CAP11XX detected, model %s, revision 0x%02x\n",
- id->name, rev);
+ if (error)
+ return dev_err_probe(dev, error, "Failed to read revision\n");
priv->model = cap;
--
2.54.0
^ permalink raw reply related
* [PATCH v4 10/10] Input: cap11xx - add support for CAP1114
From: Jun Yan @ 2026-06-17 15:02 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, linux-input, devicetree, linux-kernel
In-Reply-To: <20260617150318.753148-1-jerrysteve1101@gmail.com>
CAP1114 is a 14-channel capacitive touch sensor with 11 LED outputs
and hardware reset support.
The CAP1114 uses two control registers for LED output management and
requires two button status registers for touch input state reporting.
By default, channels CS8~CS14 operate as a single grouped block.
Set the corresponding register enable bit to enable these channels as
independent touch inputs. Note these channels share the input threshold
of the eighth entry, causing num_sensor_thresholds to differ from
num_channels.
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
---
drivers/input/keyboard/cap11xx.c | 73 ++++++++++++++++++++++++++++++--
1 file changed, 69 insertions(+), 4 deletions(-)
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index 275eb79a7193..865c58533eb9 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -18,6 +18,12 @@
#include <linux/gpio/consumer.h>
#include <linux/bitfield.h>
+#define CAP1114_REG_BUTTON_STATUS1 0x03
+#define CAP1114_REG_BUTTON_STATUS2 0x04
+#define CAP1114_REG_CONFIG2 0x40
+#define CAP1114_REG_CONFIG2_VOL_UP_DOWN BIT(1)
+#define CAP1114_REG_LED_OUTPUT_CONTROL1 0x73
+
#define CAP11XX_REG_MAIN_CONTROL 0x00
#define CAP11XX_REG_MAIN_CONTROL_GAIN_SHIFT (6)
#define CAP11XX_REG_MAIN_CONTROL_GAIN_MASK (0xc0)
@@ -83,6 +89,7 @@ struct cap11xx_hw_model {
unsigned int num_leds;
unsigned int num_sensor_thresholds;
bool has_gain;
+ bool has_grouped_sensors;
bool has_irq_config;
bool has_repeat_en;
bool has_sensitivity_control;
@@ -99,6 +106,8 @@ static const struct reg_default cap11xx_reg_defaults[] = {
{ CAP11XX_REG_SENSOR_THRESH(3), 0x40 },
{ CAP11XX_REG_SENSOR_THRESH(4), 0x40 },
{ CAP11XX_REG_SENSOR_THRESH(5), 0x40 },
+ { CAP11XX_REG_SENSOR_THRESH(6), 0x40 },
+ { CAP11XX_REG_SENSOR_THRESH(7), 0x40 },
{ CAP11XX_REG_CONFIG2, 0x40 },
};
@@ -107,6 +116,12 @@ static bool cap11xx_volatile_reg(struct device *dev, unsigned int reg)
switch (reg) {
case CAP11XX_REG_MAIN_CONTROL:
case CAP11XX_REG_SENSOR_INPUT:
+ /*
+ * CAP1114_REG_BUTTON_STATUS1 (CAP11XX_REG_SENSOR_INPUT) and
+ * CAP1114_REG_BUTTON_STATUS2 is volatile for the CAP1114,
+ * which supports more than 8 touch channels.
+ */
+ case CAP1114_REG_BUTTON_STATUS2:
case CAP11XX_REG_SENOR_DELTA(0):
case CAP11XX_REG_SENOR_DELTA(1):
case CAP11XX_REG_SENOR_DELTA(2):
@@ -292,6 +307,17 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv)
of_property_read_u32_array(node, "linux,keycodes",
priv->keycodes, priv->model->num_channels);
+ /*
+ * CAP1114 needs dedicated configuration to split
+ * grouped sensors into independent inputs.
+ */
+ if (priv->model->has_grouped_sensors) {
+ error = regmap_set_bits(priv->regmap, CAP1114_REG_CONFIG2,
+ CAP1114_REG_CONFIG2_VOL_UP_DOWN);
+ if (error)
+ return error;
+ }
+
if (priv->model->has_repeat_en) {
/* Disable autorepeat. The Linux input system has its own handling. */
error = regmap_write(priv->regmap, CAP11XX_REG_REPEAT_RATE, 0);
@@ -320,6 +346,21 @@ static irqreturn_t cap11xx_thread_func(int irq_num, void *data)
if (ret < 0)
goto out;
+ if (priv->model->num_channels > 8) {
+ unsigned int status2;
+
+ ret = regmap_read(priv->regmap, priv->model->sensor_input_reg_base + 1, &status2);
+ if (ret < 0)
+ goto out;
+
+ /*
+ * CAP1114 STATUS1 register only contains data for the first 6 channels.
+ * the remaining channels is stored in STATUS2.
+ */
+ status &= GENMASK(5, 0);
+ status |= FIELD_PREP(GENMASK(13, 6), status2);
+ }
+
for (i = 0; i < priv->idev->keycodemax; i++)
input_report_key(priv->idev, priv->keycodes[i],
status & (1 << i));
@@ -369,10 +410,16 @@ static int cap11xx_led_set(struct led_classdev *cdev,
* limitation. Brightness levels per LED are either
* 0 (OFF) and 1 (ON).
*/
- return regmap_update_bits(priv->regmap,
- priv->model->led_output_control_reg_base,
- BIT(led->reg),
- value ? BIT(led->reg) : 0);
+ if (led->reg >= 8)
+ return regmap_update_bits(priv->regmap,
+ priv->model->led_output_control_reg_base + 1,
+ BIT(led->reg - 8),
+ value ? BIT(led->reg - 8) : 0);
+ else
+ return regmap_update_bits(priv->regmap,
+ priv->model->led_output_control_reg_base,
+ BIT(led->reg),
+ value ? BIT(led->reg) : 0);
}
static int cap11xx_init_leds(struct device *dev,
@@ -403,6 +450,14 @@ static int cap11xx_init_leds(struct device *dev,
if (error)
return error;
+ if (num_leds > 8) {
+ error = regmap_update_bits(priv->regmap,
+ priv->model->led_output_control_reg_base + 1,
+ GENMASK(num_leds - 8 - 1, 0), 0);
+ if (error)
+ return error;
+ }
+
duty_val = FIELD_PREP(CAP11XX_REG_LED_DUTY_MAX_MASK,
CAP11XX_REG_LED_DUTY_MAX_VALUE);
@@ -581,6 +636,14 @@ static const struct cap11xx_hw_model cap1106_model = {
.has_repeat_en = true,
};
+static const struct cap11xx_hw_model cap1114_model = {
+ .product_id = 0x3a,
+ .num_channels = 14, .num_leds = 11, .num_sensor_thresholds = 8,
+ .led_output_control_reg_base = CAP1114_REG_LED_OUTPUT_CONTROL1,
+ .sensor_input_reg_base = CAP1114_REG_BUTTON_STATUS1,
+ .has_grouped_sensors = true,
+};
+
static const struct cap11xx_hw_model cap1126_model = {
.product_id = 0x53,
.num_channels = 6, .num_leds = 2, .num_sensor_thresholds = 6,
@@ -637,6 +700,7 @@ static const struct cap11xx_hw_model cap1298_model = {
static const struct of_device_id cap11xx_dt_ids[] = {
{ .compatible = "microchip,cap1106", .data = &cap1106_model },
+ { .compatible = "microchip,cap1114", .data = &cap1114_model },
{ .compatible = "microchip,cap1126", .data = &cap1126_model },
{ .compatible = "microchip,cap1188", .data = &cap1188_model },
{ .compatible = "microchip,cap1203", .data = &cap1203_model },
@@ -649,6 +713,7 @@ MODULE_DEVICE_TABLE(of, cap11xx_dt_ids);
static const struct i2c_device_id cap11xx_i2c_ids[] = {
{ .name = "cap1106", .driver_data = (kernel_ulong_t)&cap1106_model },
+ { .name = "cap1114", .driver_data = (kernel_ulong_t)&cap1114_model },
{ .name = "cap1126", .driver_data = (kernel_ulong_t)&cap1126_model },
{ .name = "cap1188", .driver_data = (kernel_ulong_t)&cap1188_model },
{ .name = "cap1203", .driver_data = (kernel_ulong_t)&cap1203_model },
--
2.54.0
^ permalink raw reply related
* [PATCH v4 09/10] dt-bindings: input: microchip,cap11xx: Add CAP1114 support
From: Jun Yan @ 2026-06-17 15:02 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, Conor Dooley, linux-input, devicetree, linux-kernel
In-Reply-To: <20260617150318.753148-1-jerrysteve1101@gmail.com>
CAP1114 is a 14-channel capacitive touch sensor with 11 LED outputs
and hardware reset support.
Add the compatible string for CAP1114, add its datasheet URL,
update the maximum of LED channel reg, and add constraint for
linux,keycodes.
Previously, the LED reg property had a default maximum of 7 for CAP1188.
With the addition of CAP1114, the default maximum is now 11.
An if-then constraint is added to limit the LED count for CAP1188.
Update description for microchip,input-threshold: CAP1114 only provides
eight threshold entries, which does not match its total channel count.
CAP1114 does not support microchip,signal-guard and
microchip,calib-sensitivity.
Add CAP1114 to the unsupported enum list.
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
---
.../bindings/input/microchip,cap11xx.yaml | 39 +++++++++++++++++--
1 file changed, 36 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
index b97e5b2735f1..2a37ac252c37 100644
--- a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
+++ b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
@@ -12,6 +12,7 @@ description: |
For more product information please see the links below:
CAP1106: https://ww1.microchip.com/downloads/en/DeviceDoc/00001624B.pdf
+ CAP1114: https://ww1.microchip.com/downloads/en/DeviceDoc/00002444A.pdf
CAP1126: https://ww1.microchip.com/downloads/en/DeviceDoc/00001623B.pdf
CAP1188: https://ww1.microchip.com/downloads/en/DeviceDoc/00001620C.pdf
CAP1203: https://ww1.microchip.com/downloads/en/DeviceDoc/00001572B.pdf
@@ -26,6 +27,7 @@ properties:
compatible:
enum:
- microchip,cap1106
+ - microchip,cap1114
- microchip,cap1126
- microchip,cap1188
- microchip,cap1203
@@ -62,7 +64,7 @@ properties:
linux,keycodes:
minItems: 3
- maxItems: 8
+ maxItems: 14
description: |
Specifies an array of numeric keycode values to
be used for the channels. If this property is
@@ -122,6 +124,8 @@ properties:
is required for a touch to be registered, making the touch sensor less
sensitive.
The number of entries must correspond to the number of channels.
+ CAP1114 is an exception where channels 8~14 reuse the eighth entry's
+ threshold, so counts differ.
microchip,calib-sensitivity:
$ref: /schemas/types.yaml#/definitions/uint32-array
@@ -140,7 +144,7 @@ properties:
The number of entries must correspond to the number of channels.
patternProperties:
- "^led@[0-7]$":
+ "^led@[0-9a]$":
type: object
description: CAP11xx LEDs
$ref: /schemas/leds/common.yaml#
@@ -149,7 +153,7 @@ patternProperties:
reg:
description: LED channel number
minimum: 0
- maximum: 7
+ maximum: 10
label: true
@@ -178,6 +182,21 @@ allOf:
properties:
reset-gpios: false
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - microchip,cap1114
+ then:
+ properties:
+ linux,keycodes:
+ minItems: 14
+ else:
+ properties:
+ linux,keycodes:
+ maxItems: 8
+
- if:
properties:
compatible:
@@ -205,12 +224,26 @@ allOf:
reg:
maximum: 1
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - microchip,cap1188
+ then:
+ patternProperties:
+ "^led@":
+ properties:
+ reg:
+ maximum: 7
+
- if:
properties:
compatible:
contains:
enum:
- microchip,cap1106
+ - microchip,cap1114
- microchip,cap1126
- microchip,cap1188
- microchip,cap1203
--
2.54.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox