* [PATCH] HID: add quirk for IBM SK-8845 keyboard
From: TheDragonWhoAte @ 2026-06-10 4:09 UTC (permalink / raw)
To: linux-input@vger.kernel.org
Cc: Jiri Kosina, Benjamin Tissoires, linux-kernel@vger.kernel.org
[-- Attachment #1: Type: text/plain, Size: 792 bytes --]
HID: add quirk for IBM SK-8845 keyboard
The TrackPoint on the IBM SK-8845 (Synaptics 06cb:0009) sends corrupted
input events when bound to the synaptics_usb driver. Moving the stick
generates random BTN_LEFT/BTN_RIGHT/BTN_MIDDLE events instead of
REL_X/REL_Y movement.
Force the device to bind to hid-generic instead by setting
HID_QUIRK_IGNORE_SPECIAL_DRIVER.
Link: https://bugzilla.kernel.org/show_bug.cgi?id=221624
Note: This quirk disables two-finger scrolling on the touchpad. That's a trade-off, but without it the TrackPoint is completely unusable. The real fix would be to make synaptics_usb handle this device properly, so both the touchpad gestures and the TrackPoint work. That's beyond this patch.
Signed-off-by: TheDragonWhoAte <TheDragonWhoAte@protonmail.com>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-HID-add-quirk-for-IBM-SK-8845-keyboard.patch --]
[-- Type: text/x-patch; name=0001-HID-add-quirk-for-IBM-SK-8845-keyboard.patch, Size: 2037 bytes --]
From 0bc38d7fac65dc07f48e074130329924adf5744b Mon Sep 17 00:00:00 2001
From: thedragonwhoate <thedragonwhoate@protonmail.com>
Date: Wed, 10 Jun 2026 06:38:03 +0300
Subject: [PATCH] HID: add quirk for IBM SK-8845 keyboard
To: linux-input@vger.kernel.org
The TrackPoint on the IBM SK-8845 (Synaptics 06cb:0009) sends corrupted
input events when bound to the synaptics_usb driver. Moving the stick
generates random BTN_LEFT/BTN_RIGHT/BTN_MIDDLE events instead of
REL_X/REL_Y movement.
Force the device to bind to hid-generic instead by setting
HID_QUIRK_IGNORE_SPECIAL_DRIVER.
Link: https://bugzilla.kernel.org/show_bug.cgi?id=221624
Note: This quirk disables two-finger scrolling on the touchpad. That's a trade-off, but without it the TrackPoint is completely unusable. The real fix would be to make synaptics_usb handle this device properly, so both the touchpad gestures and the TrackPoint work. That's beyond this patch.
Signed-off-by: thedragonwhoate <thedragonwhoate@protonmail.com>
---
drivers/hid/hid-quirks.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 57d8efdd9..c8394b896 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -203,6 +203,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP_V103), HID_QUIRK_NO_INIT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DELL_K12A), HID_QUIRK_NO_INIT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DELL_K15A), HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_COMP_TP), HID_QUIRK_IGNORE_SPECIAL_DRIVER },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD), HID_QUIRK_BADPAD },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8882), HID_QUIRK_NOGET },
--
2.54.0
^ permalink raw reply related
* [PATCH] Input: ipaq-micro-keys - fix potential deadlock
From: Dmitry Torokhov @ 2026-06-10 6:05 UTC (permalink / raw)
To: linux-input; +Cc: linux-kernel
The driver acquires the micro->lock spinlock in process context (in
micro_key_start() and micro_key_stop()) without disabling interrupts.
However, this lock is also acquired in hardirq context by the MFD core
rx handler (micro_rx_msg()) which is called from the serial ISR.
This can lead to a lock inversion deadlock if the interrupt fires on the
same CPU while the process context holds the lock.
Fix this by using guard(spinlock_irq) instead of guard(spinlock) in
micro_key_start() and micro_key_stop() to disable interrupts while
holding the lock.
Reported-by: sashiko-bot@kernel.org
Assisted-by: Antigravity:gemini-3.5-flash
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/keyboard/ipaq-micro-keys.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/input/keyboard/ipaq-micro-keys.c b/drivers/input/keyboard/ipaq-micro-keys.c
index ca7ec054b1ce..63d589253e46 100644
--- a/drivers/input/keyboard/ipaq-micro-keys.c
+++ b/drivers/input/keyboard/ipaq-micro-keys.c
@@ -54,7 +54,7 @@ static void micro_key_receive(void *data, int len, unsigned char *msg)
static void micro_key_start(struct ipaq_micro_keys *keys)
{
- guard(spinlock)(&keys->micro->lock);
+ guard(spinlock_irq)(&keys->micro->lock);
keys->micro->key = micro_key_receive;
keys->micro->key_data = keys;
@@ -62,7 +62,7 @@ static void micro_key_start(struct ipaq_micro_keys *keys)
static void micro_key_stop(struct ipaq_micro_keys *keys)
{
- guard(spinlock)(&keys->micro->lock);
+ guard(spinlock_irq)(&keys->micro->lock);
keys->micro->key = NULL;
keys->micro->key_data = NULL;
--
2.54.0.1099.g489fc7bff1-goog
--
Dmitry
^ permalink raw reply related
* Re: [PATCHv2] input: ipaq-micro-keys: simplify allocation
From: Dmitry Torokhov @ 2026-06-10 6:08 UTC (permalink / raw)
To: Rosen Penev; +Cc: linux-input, open list
In-Reply-To: <20260609213532.25181-1-rosenp@gmail.com>
On Tue, Jun 09, 2026 at 02:35:32PM -0700, Rosen Penev wrote:
> Embed the keycode array in the struct to have a single allocation.
>
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
Applied, thank you.
--
Dmitry
^ permalink raw reply
* Re: [PATCH v1] Input: Drop unused assignments from pnp_device_id arrays
From: Dmitry Torokhov @ 2026-06-10 6:12 UTC (permalink / raw)
To: Uwe Kleine-König (The Capable Hub)
Cc: Kees Cook, Werner Sembach, Christoffer Sandberg, feng, gongqi,
linux-input, linux-kernel
In-Reply-To: <f987c14dea1d3236d3889e5cf96c01eef6a2445d.1781016727.git.u.kleine-koenig@baylibre.com>
Hi Uwe,
On Tue, Jun 09, 2026 at 04:53:25PM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> Explicitly assigning .driver_data in drivers that don't use this member
> is silly and a bit irritating. Drop these. Also simplify the list
> terminator entry to be just empty to match what most other device_id
> tables do.
>
> There is no changed semantic, not even a change in the compiled result.
>
> Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>
> ---
> drivers/input/gameport/ns558.c | 46 +++++++++++-----------
> drivers/input/serio/i8042-acpipnpio.h | 56 +++++++++++++--------------
> 2 files changed, 51 insertions(+), 51 deletions(-)
>
> diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
> index fdece6ec1df3..f70a96c4f1fd 100644
> --- a/drivers/input/gameport/ns558.c
> +++ b/drivers/input/gameport/ns558.c
> @@ -148,29 +148,29 @@ static int ns558_isa_probe(int io)
> #ifdef CONFIG_PNP
>
> static const struct pnp_device_id pnp_devids[] = {
> - { .id = "@P@0001", .driver_data = 0 }, /* ALS 100 */
> - { .id = "@P@0020", .driver_data = 0 }, /* ALS 200 */
> - { .id = "@P@1001", .driver_data = 0 }, /* ALS 100+ */
> - { .id = "@P@2001", .driver_data = 0 }, /* ALS 120 */
> - { .id = "ASB16fd", .driver_data = 0 }, /* AdLib NSC16 */
> - { .id = "AZT3001", .driver_data = 0 }, /* AZT1008 */
> - { .id = "CDC0001", .driver_data = 0 }, /* Opl3-SAx */
> - { .id = "CSC0001", .driver_data = 0 }, /* CS4232 */
> - { .id = "CSC000f", .driver_data = 0 }, /* CS4236 */
> - { .id = "CSC0101", .driver_data = 0 }, /* CS4327 */
> - { .id = "CTL7001", .driver_data = 0 }, /* SB16 */
> - { .id = "CTL7002", .driver_data = 0 }, /* AWE64 */
> - { .id = "CTL7005", .driver_data = 0 }, /* Vibra16 */
> - { .id = "ENS2020", .driver_data = 0 }, /* SoundscapeVIVO */
> - { .id = "ESS0001", .driver_data = 0 }, /* ES1869 */
> - { .id = "ESS0005", .driver_data = 0 }, /* ES1878 */
> - { .id = "ESS6880", .driver_data = 0 }, /* ES688 */
> - { .id = "IBM0012", .driver_data = 0 }, /* CS4232 */
> - { .id = "OPT0001", .driver_data = 0 }, /* OPTi Audio16 */
> - { .id = "YMH0006", .driver_data = 0 }, /* Opl3-SA */
> - { .id = "YMH0022", .driver_data = 0 }, /* Opl3-SAx */
> - { .id = "PNPb02f", .driver_data = 0 }, /* Generic */
> - { .id = "", },
> + { .id = "@P@0001" }, /* ALS 100 */
> + { .id = "@P@0020" }, /* ALS 200 */
> + { .id = "@P@1001" }, /* ALS 100+ */
> + { .id = "@P@2001" }, /* ALS 120 */
> + { .id = "ASB16fd" }, /* AdLib NSC16 */
> + { .id = "AZT3001" }, /* AZT1008 */
> + { .id = "CDC0001" }, /* Opl3-SAx */
> + { .id = "CSC0001" }, /* CS4232 */
> + { .id = "CSC000f" }, /* CS4236 */
> + { .id = "CSC0101" }, /* CS4327 */
> + { .id = "CTL7001" }, /* SB16 */
> + { .id = "CTL7002" }, /* AWE64 */
> + { .id = "CTL7005" }, /* Vibra16 */
> + { .id = "ENS2020" }, /* SoundscapeVIVO */
> + { .id = "ESS0001" }, /* ES1869 */
> + { .id = "ESS0005" }, /* ES1878 */
> + { .id = "ESS6880" }, /* ES688 */
> + { .id = "IBM0012" }, /* CS4232 */
> + { .id = "OPT0001" }, /* OPTi Audio16 */
> + { .id = "YMH0006" }, /* Opl3-SA */
> + { .id = "YMH0022" }, /* Opl3-SAx */
> + { .id = "PNPb02f" }, /* Generic */
> + { }
This goes BOOOM! You have to keep empty .id string as terminator.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH] Input: ipaq-micro-keys - fix potential deadlock
From: sashiko-bot @ 2026-06-10 6:16 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: dmitry.torokhov, linux-input
In-Reply-To: <aij-pfaKK-Nna7wf@google.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [High] ipaq_micro_str() fails to null-terminate a stack-allocated string before passing it to kstrdup().
- [Medium] micro_key_receive() accesses the message payload without checking if the length is greater than zero.
- [Medium] Potential off-by-one error in keycode array indexing.
--
commit cc960c88f9bd89346f2cb6d8461bbe44bd01c18b
Author: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Input: ipaq-micro-keys - fix potential deadlock
This commit fixes a lock inversion deadlock in the ipaq-micro-keys driver.
It updates micro_key_start() and micro_key_stop() to use guard(spinlock_irq)
instead of guard(spinlock), ensuring interrupts are disabled while the lock
is held in process context.
> diff --git a/drivers/input/keyboard/ipaq-micro-keys.c b/drivers/input/keyboard/ipaq-micro-keys.c
> index ca7ec054b1cef..63d589253e465 100644
> --- a/drivers/input/keyboard/ipaq-micro-keys.c
> +++ b/drivers/input/keyboard/ipaq-micro-keys.c
[ ... ]
> @@ -54,7 +54,7 @@ static void micro_key_receive(void *data, int len, unsigned char *msg)
[Severity: Medium]
This isn't a bug introduced by this patch, but could this code read
uninitialized or stale memory if len is zero?
In micro_key_receive():
down = 0x80 & msg[0];
key = 0x7f & msg[0];
The parent MFD driver parses serial messages and can validly produce a
payload with a length of 0. When this happens, micro_process_char() skips
writing to the buffer, leaving it with stale data.
Since micro_key_receive() reads msg[0] without checking if len > 0, does
this cause the driver to report phantom key events based on old hardware
traffic?
[Severity: Medium]
This is a pre-existing issue, but does this array indexing have an
off-by-one error?
In micro_key_receive():
if (key < ARRAY_SIZE(micro_keycodes)) {
input_report_key(keys->input, keys->codes[key], down);
input_sync(keys->input);
}
If the hardware sends 1-based codes (for example, 1 for Record and 9
for Down), using the hardware key value directly as a zero-based index means
a value of 1 maps to index 1 instead of 0.
Furthermore, if the hardware sends 9 for the Down button, the event would be
dropped entirely since 9 < 9 evaluates to false. Should the index be
decremented before lookup if the device uses 1-based indexing?
>
> static void micro_key_start(struct ipaq_micro_keys *keys)
> {
> - guard(spinlock)(&keys->micro->lock);
> + guard(spinlock_irq)(&keys->micro->lock);
>
> keys->micro->key = micro_key_receive;
> keys->micro->key_data = keys;
> @@ -62,7 +62,7 @@ static void micro_key_start(struct ipaq_micro_keys *keys)
>
> static void micro_key_stop(struct ipaq_micro_keys *keys)
> {
> - guard(spinlock)(&keys->micro->lock);
> + guard(spinlock_irq)(&keys->micro->lock);
>
> keys->micro->key = NULL;
> keys->micro->key_data = NULL;
[Severity: High]
This is also a pre-existing issue in a related file, but does this code
cause an out-of-bounds stack read?
In drivers/mfd/ipaq-micro.c:ipaq_micro_str():
for (i = 0; i < len / 2; i++)
retstr[i] = wchar[i * 2];
return kstrdup(retstr, GFP_KERNEL);
The array retstr is filled without an explicit null terminator. When
kstrdup() is called, it relies on strlen(), which will read past the valid
copied characters into uninitialized stack memory until it hits a random null
byte.
Could this leak kernel stack contents when the string is later printed?
--
Sashiko AI review · https://sashiko.dev/#/patchset/aij-pfaKK-Nna7wf@google.com?part=1
^ permalink raw reply
* [PATCH] Input: synaptics-rmi4 - unregister function handlers on physical driver registration failure
From: Haoxiang Li @ 2026-06-10 6:46 UTC (permalink / raw)
To: dmitry.torokhov, git, Marge.Yang, kees, jiapeng.chong
Cc: linux-input, linux-kernel, Haoxiang Li, stable
If rmi_register_physical_driver() fails, the current error path
unregisters only the RMI bus. The function handlers registered
earlier remain registered with the driver core.
Add a separate error path to unregister the function handlers
before unregistering the bus in this failure case.
Fixes: d6e680837ec5 ("Input: synaptics-rmi4 - fix function name in kerneldoc")
Cc: stable@vger.kernel.org
Signed-off-by: Haoxiang Li <haoxiang_li2024@163.com>
---
drivers/input/rmi4/rmi_bus.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c
index 687cb987bc13..ade57e2a7201 100644
--- a/drivers/input/rmi4/rmi_bus.c
+++ b/drivers/input/rmi4/rmi_bus.c
@@ -455,11 +455,13 @@ static int __init rmi_bus_init(void)
if (error) {
pr_err("%s: error registering the RMI physical driver: %d\n",
__func__, error);
- goto err_unregister_bus;
+ goto err_unregister_function_handlers;
}
return 0;
+err_unregister_function_handlers:
+ rmi_unregister_function_handlers();
err_unregister_bus:
bus_unregister(&rmi_bus_type);
return error;
--
2.25.1
^ permalink raw reply related
* [PATCH 0/2] HID: iio: Fix stale or zero quaternion reads with multi-byte read helper
From: Zhang Lixu @ 2026-06-10 8:29 UTC (permalink / raw)
To: Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada,
Benjamin Tissoires
Cc: David Lechner, Nuno Sá, Andy Shevchenko, linux-input,
linux-iio, linux-kernel, lixu.zhang
When reading in_rot_quaternion_raw from hid-sensor-rotation, the driver
returns either all zeros (if the sensor was never enabled) or stale data
(if previously enabled), because it reads from an internal buffer without
requesting a fresh sample from the device.
This series fixes the issue in two steps:
1. Add sensor_hub_input_attr_read_values() to the HID sensor hub core.
Unlike sensor_hub_input_attr_get_raw_value(), which is limited to a
single 32-bit value, the new helper accepts a caller-provided buffer
and accumulates incoming input report data until the buffer is full.
The two code paths are distinguished in sensor_hub_raw_event() by
pending.max_raw_size being non-zero, preserving backward compatibility.
2. Switch hid-sensor-rotation to use the new helper for raw quaternion
reads. It now powers up the sensor, issues a synchronous GET_REPORT,
and receives all four quaternion components directly into a local
buffer before decoding them, eliminating stale or zero output.
Srinivas Pandruvada (1):
HID: sensor-hub: Add sensor_hub_input_attr_read_values() for
multi-byte reads
Zhang Lixu (1):
iio: hid-sensor-rotation: Fix stale or zero output when reading raw
values
drivers/hid/hid-sensor-hub.c | 77 +++++++++++++++++--
drivers/iio/orientation/hid-sensor-rotation.c | 40 +++++++++-
include/linux/hid-sensor-hub.h | 25 ++++++
3 files changed, 134 insertions(+), 8 deletions(-)
base-commit: 49e02880ec0a8c378e811bc9d85da188d7c6204c
--
2.43.0
^ permalink raw reply
* [PATCH 1/2] HID: sensor-hub: Add sensor_hub_input_attr_read_values() for multi-byte reads
From: Zhang Lixu @ 2026-06-10 8:29 UTC (permalink / raw)
To: Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada,
Benjamin Tissoires
Cc: David Lechner, Nuno Sá, Andy Shevchenko, linux-input,
linux-iio, linux-kernel, lixu.zhang
In-Reply-To: <20260610082911.157232-1-lixu.zhang@intel.com>
From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
sensor_hub_input_attr_get_raw_value() is limited to returning a single
32-bit value, which is insufficient for sensors that report data larger
than 32 bits, such as a quaternion with four s16 elements.
Add sensor_hub_input_attr_read_values() that accepts a caller-provided
buffer and accumulates incoming data until the buffer is full. The two
paths are distinguished in sensor_hub_raw_event() by pending.max_raw_size
being non-zero, preserving backward compatibility.
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Co-developed-by: Zhang Lixu <lixu.zhang@intel.com>
Signed-off-by: Zhang Lixu <lixu.zhang@intel.com>
---
drivers/hid/hid-sensor-hub.c | 77 +++++++++++++++++++++++++++++++---
include/linux/hid-sensor-hub.h | 25 +++++++++++
2 files changed, 96 insertions(+), 6 deletions(-)
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index 90666ff629def..34f710c465b80 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -286,6 +286,54 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
}
EXPORT_SYMBOL_GPL(sensor_hub_get_feature);
+int sensor_hub_input_attr_read_values(struct hid_sensor_hub_device *hsdev,
+ u32 usage_id, u32 attr_usage_id,
+ u32 report_id,
+ enum sensor_hub_read_flags flag,
+ u32 buffer_size, u8 *buffer)
+{
+ struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
+ struct hid_report *report;
+ unsigned long flags;
+ long cycles;
+ int ret;
+
+ report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT);
+ if (!report)
+ return -EINVAL;
+
+ mutex_lock(hsdev->mutex_ptr);
+ if (flag == SENSOR_HUB_SYNC) {
+ memset(&hsdev->pending, 0, sizeof(hsdev->pending));
+ init_completion(&hsdev->pending.ready);
+ hsdev->pending.usage_id = usage_id;
+ hsdev->pending.attr_usage_id = attr_usage_id;
+ hsdev->pending.max_raw_size = buffer_size;
+ hsdev->pending.raw_data = buffer;
+
+ spin_lock_irqsave(&data->lock, flags);
+ hsdev->pending.status = true;
+ spin_unlock_irqrestore(&data->lock, flags);
+ }
+ mutex_lock(&data->mutex);
+ hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
+ mutex_unlock(&data->mutex);
+ ret = 0;
+ if (flag == SENSOR_HUB_SYNC) {
+ cycles = wait_for_completion_interruptible_timeout(&hsdev->pending.ready,
+ HZ * 5);
+ if (cycles == 0)
+ ret = -ETIMEDOUT;
+ else if (cycles < 0)
+ ret = cycles;
+
+ hsdev->pending.status = false;
+ }
+ mutex_unlock(hsdev->mutex_ptr);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_input_attr_read_values);
int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
u32 usage_id,
@@ -478,6 +526,8 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
struct hid_collection *collection = NULL;
void *priv = NULL;
struct hid_sensor_hub_device *hsdev = NULL;
+ u32 copy_size;
+ u32 avail;
hid_dbg(hdev, "sensor_hub_raw_event report id:0x%x size:%d type:%d\n",
report->id, size, report->type);
@@ -518,12 +568,27 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
hsdev->pending.attr_usage_id ==
report->field[i]->logical)) {
hid_dbg(hdev, "data was pending ...\n");
- hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC);
- if (hsdev->pending.raw_data)
- hsdev->pending.raw_size = sz;
- else
- hsdev->pending.raw_size = 0;
- complete(&hsdev->pending.ready);
+ if (hsdev->pending.max_raw_size) {
+ if (hsdev->pending.index < hsdev->pending.max_raw_size) {
+ avail = hsdev->pending.max_raw_size - hsdev->pending.index;
+ copy_size = clamp(sz, 0U, avail);
+
+ memcpy(hsdev->pending.raw_data + hsdev->pending.index,
+ ptr, copy_size);
+ hsdev->pending.index += copy_size;
+ if (hsdev->pending.index >= hsdev->pending.max_raw_size) {
+ hsdev->pending.raw_size = hsdev->pending.index;
+ complete(&hsdev->pending.ready);
+ }
+ }
+ } else {
+ hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC);
+ if (hsdev->pending.raw_data)
+ hsdev->pending.raw_size = sz;
+ else
+ hsdev->pending.raw_size = 0;
+ complete(&hsdev->pending.ready);
+ }
}
if (callback->capture_sample) {
if (report->field[i]->logical)
diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h
index e710565531085..ab5cc8db3fbb3 100644
--- a/include/linux/hid-sensor-hub.h
+++ b/include/linux/hid-sensor-hub.h
@@ -43,6 +43,8 @@ struct hid_sensor_hub_attribute_info {
* @attr_usage_id: Usage Id of a field, e.g. X-axis for a gyro.
* @raw_size: Response size for a read request.
* @raw_data: Place holder for received response.
+ * @index: Current write index into raw_data for multi-byte reads.
+ * @max_raw_size: Total buffer size for multi-byte reads; 0 for single-value reads.
*/
struct sensor_hub_pending {
bool status;
@@ -51,6 +53,8 @@ struct sensor_hub_pending {
u32 attr_usage_id;
int raw_size;
u8 *raw_data;
+ u32 index;
+ u32 max_raw_size;
};
/**
@@ -183,6 +187,27 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
bool is_signed
);
+/**
+ * sensor_hub_input_attr_read_values() - Synchronous multi-byte read request
+ * @hsdev: Hub device instance.
+ * @usage_id: Attribute usage id of parent physical device as per spec
+ * @attr_usage_id: Attribute usage id as per spec
+ * @report_id: Report id to look for
+ * @flag: Synchronous or asynchronous read
+ * @buffer_size: Size of the buffer in bytes
+ * @buffer: Buffer to store the read data
+ *
+ * Issues a synchronous or asynchronous read request for an input attribute,
+ * accumulating data into the provided buffer until it is full.
+ * Return: 0 on success, -ETIMEDOUT if the device did not respond, or a
+ * negative error code.
+ */
+int sensor_hub_input_attr_read_values(struct hid_sensor_hub_device *hsdev,
+ u32 usage_id, u32 attr_usage_id,
+ u32 report_id,
+ enum sensor_hub_read_flags flag,
+ u32 buffer_size, u8 *buffer);
+
/**
* sensor_hub_set_feature() - Feature set request
* @hsdev: Hub device instance.
--
2.43.0
^ permalink raw reply related
* [PATCH 2/2] iio: hid-sensor-rotation: Fix stale or zero output when reading raw values
From: Zhang Lixu @ 2026-06-10 8:29 UTC (permalink / raw)
To: Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada,
Benjamin Tissoires
Cc: David Lechner, Nuno Sá, Andy Shevchenko, linux-input,
linux-iio, linux-kernel, lixu.zhang
In-Reply-To: <20260610082911.157232-1-lixu.zhang@intel.com>
When reading the raw quaternion attribute (in_rot_quaternion_raw), the
driver currently returns either all zeros (if the sensor was never enabled)
or stale data (if the sensor was previously enabled) because it reads from
the internal buffer without explicitly requesting a new sample from the
sensor.
To fix this, power up the sensor, call sensor_hub_input_attr_read_values()
to issue a synchronous GET_REPORT and receive the full quaternion data
directly into a local buffer, then decode the four components.
Signed-off-by: Zhang Lixu <lixu.zhang@intel.com>
---
drivers/iio/orientation/hid-sensor-rotation.c | 40 ++++++++++++++++++-
1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c
index 4a11e45550991..1c6f02374f3ce 100644
--- a/drivers/iio/orientation/hid-sensor-rotation.c
+++ b/drivers/iio/orientation/hid-sensor-rotation.c
@@ -86,6 +86,13 @@ static int dev_rot_read_raw(struct iio_dev *indio_dev,
long mask)
{
struct dev_rot_state *rot_state = iio_priv(indio_dev);
+ struct hid_sensor_hub_device *hsdev = rot_state->common_attributes.hsdev;
+ struct hid_sensor_hub_attribute_info *info = &rot_state->quaternion;
+ u32 usage_id = HID_USAGE_SENSOR_ORIENT_QUATERNION;
+ union {
+ s16 val16[4];
+ s32 val32[4];
+ } raw_buf;
int ret_type;
int i;
@@ -95,8 +102,37 @@ static int dev_rot_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (size >= 4) {
- for (i = 0; i < 4; ++i)
- vals[i] = rot_state->scan.sampled_vals[i];
+ if (info->size <= 0 || info->size > sizeof(raw_buf))
+ return -EINVAL;
+
+ hid_sensor_power_state(&rot_state->common_attributes, true);
+
+ ret_type = sensor_hub_input_attr_read_values(hsdev,
+ hsdev->usage,
+ usage_id,
+ info->report_id,
+ SENSOR_HUB_SYNC,
+ info->size,
+ (u8 *)&raw_buf);
+
+ hid_sensor_power_state(&rot_state->common_attributes, false);
+
+ if (ret_type < 0)
+ return ret_type;
+
+ switch (info->size) {
+ case sizeof(raw_buf.val16):
+ for (i = 0; i < ARRAY_SIZE(raw_buf.val16); i++)
+ vals[i] = raw_buf.val16[i];
+ break;
+ case sizeof(raw_buf.val32):
+ for (i = 0; i < ARRAY_SIZE(raw_buf.val32); i++)
+ vals[i] = raw_buf.val32[i];
+ break;
+ default:
+ return -EINVAL;
+ }
+
ret_type = IIO_VAL_INT_MULTIPLE;
*val_len = 4;
} else
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 1/2] HID: sensor-hub: Add sensor_hub_input_attr_read_values() for multi-byte reads
From: sashiko-bot @ 2026-06-10 8:38 UTC (permalink / raw)
To: Zhang Lixu; +Cc: linux-input, dmitry.torokhov
In-Reply-To: <20260610082911.157232-2-lixu.zhang@intel.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [Critical] Missing spinlock acquisition in the timeout/abort path of `sensor_hub_input_attr_read_values` leads to race conditions, use-after-free, and stack memory corruption.
Pre-existing issues:
- [High] Reading past the end of short HID reports exposes uninitialized kernel heap memory.
- [High] Repeated field matches in `sensor_hub_raw_event()` cause uncontrolled `kmemdup()` allocations, leaking memory.
--
commit b3186306e6632f94df0275d5e172210ae3044b54
Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
HID: sensor-hub: Add sensor_hub_input_attr_read_values() for multi-byte reads
This commit introduces sensor_hub_input_attr_read_values() to allow
multi-byte reads for sensors reporting data larger than 32 bits. It
uses a caller-provided buffer to accumulate incoming data in
sensor_hub_raw_event() until the buffer is full.
> diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
> --- a/drivers/hid/hid-sensor-hub.c
> +++ b/drivers/hid/hid-sensor-hub.c
[ ... ]
> + if (flag == SENSOR_HUB_SYNC) {
> + cycles = wait_for_completion_interruptible_timeout(&hsdev->pending.ready,
> + HZ * 5);
> + if (cycles == 0)
> + ret = -ETIMEDOUT;
> + else if (cycles < 0)
> + ret = cycles;
> +
> + hsdev->pending.status = false;
[Severity: Critical]
Does setting this status flag without acquiring the data->lock introduce a
race condition?
If wait_for_completion_interruptible_timeout() times out or is interrupted,
this locklessly sets hsdev->pending.status = false and returns. Concurrently,
the interrupt handler sensor_hub_raw_event() might have already observed
status as true and could be mid-copy into the caller-provided buffer.
Returning early would invalidate the caller-provided buffer, and the
interrupt handler might subsequently overwrite the destroyed stack frame.
> + }
> + mutex_unlock(hsdev->mutex_ptr);
> +
> + return ret;
> +}
[ ... ]
> @@ -518,12 +568,27 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
> hsdev->pending.attr_usage_id ==
> report->field[i]->logical)) {
> hid_dbg(hdev, "data was pending ...\n");
> - hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC);
> - if (hsdev->pending.raw_data)
> - hsdev->pending.raw_size = sz;
> - else
> - hsdev->pending.raw_size = 0;
> - complete(&hsdev->pending.ready);
> + if (hsdev->pending.max_raw_size) {
> + if (hsdev->pending.index < hsdev->pending.max_raw_size) {
> + avail = hsdev->pending.max_raw_size - hsdev->pending.index;
> + copy_size = clamp(sz, 0U, avail);
> +
> + memcpy(hsdev->pending.raw_data + hsdev->pending.index,
> + ptr, copy_size);
[Severity: Critical]
As mentioned above, if sensor_hub_input_attr_read_values() aborts early,
could this memcpy() write into an invalidated stack buffer?
> + hsdev->pending.index += copy_size;
> + if (hsdev->pending.index >= hsdev->pending.max_raw_size) {
> + hsdev->pending.raw_size = hsdev->pending.index;
> + complete(&hsdev->pending.ready);
> + }
> + }
> + } else {
> + hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC);
[Severity: High]
This is a pre-existing issue, but does this allocation leak memory if a
crafted HID report contains multiple duplicate fields matching the
requested usage?
If the device rapidly spams events while a reader is waiting, each match
could trigger a new kmemdup, overwriting the hsdev->pending.raw_data
pointer and permanently leaking the previously allocated blocks.
> + if (hsdev->pending.raw_data)
> + hsdev->pending.raw_size = sz;
> + else
> + hsdev->pending.raw_size = 0;
> + complete(&hsdev->pending.ready);
> + }
> }
> if (callback->capture_sample) {
> if (report->field[i]->logical)
[Severity: High]
This is a pre-existing issue, but does the loop advancing ptr expose
uninitialized heap memory on short reports?
Looking at the loop in sensor_hub_raw_event():
for (i = 0; i < report->maxfield; ++i) {
...
sz = (report->field[i]->report_size *
report->field[i]->report_count)/8;
...
ptr += sz;
}
The pointer is unconditionally advanced by the expected sizes defined in
the report descriptor. Since sensor_hub_raw_event() ignores the actual
size argument representing the received packet length, a maliciously
short packet could cause the driver to read past the initialized packet
bounds.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260610082911.157232-1-lixu.zhang@intel.com?part=1
^ permalink raw reply
* Re: [PATCH 2/2] iio: hid-sensor-rotation: Fix stale or zero output when reading raw values
From: sashiko-bot @ 2026-06-10 8:40 UTC (permalink / raw)
To: Zhang Lixu; +Cc: dmitry.torokhov, linux-input
In-Reply-To: <20260610082911.157232-3-lixu.zhang@intel.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] Stack Use-After-Free / Memory Corruption via synchronous HID read
- [High] PM Runtime Usage Counter Underflow due to missing error check
--
commit 4651e39f1dd649401d6eaaef3b3ae792bc120ba0
Author: Zhang Lixu <lixu.zhang@intel.com>
iio: hid-sensor-rotation: Fix stale or zero output when reading raw values
This commit fixes stale or zero output in dev_rot_read_raw by explicitly
powering up the sensor and issuing a synchronous GET_REPORT to receive
the full quaternion data into a local buffer.
> diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c
> index 4a11e45550991..1c6f02374f3ce 100644
> --- a/drivers/iio/orientation/hid-sensor-rotation.c
> +++ b/drivers/iio/orientation/hid-sensor-rotation.c
> @@ -86,6 +86,13 @@ static int dev_rot_read_raw(struct iio_dev *indio_dev,
> long mask)
> {
> struct dev_rot_state *rot_state = iio_priv(indio_dev);
> + struct hid_sensor_hub_device *hsdev = rot_state->common_attributes.hsdev;
> + struct hid_sensor_hub_attribute_info *info = &rot_state->quaternion;
> + u32 usage_id = HID_USAGE_SENSOR_ORIENT_QUATERNION;
> + union {
> + s16 val16[4];
> + s32 val32[4];
> + } raw_buf;
> int ret_type;
> int i;
>
> @@ -95,8 +102,37 @@ static int dev_rot_read_raw(struct iio_dev *indio_dev,
> switch (mask) {
> case IIO_CHAN_INFO_RAW:
> if (size >= 4) {
> - for (i = 0; i < 4; ++i)
> - vals[i] = rot_state->scan.sampled_vals[i];
> + if (info->size <= 0 || info->size > sizeof(raw_buf))
> + return -EINVAL;
> +
> + hid_sensor_power_state(&rot_state->common_attributes, true);
[Severity: High]
Should the return value of this power-on call be checked?
If hid_sensor_power_state fails, pm_runtime_resume_and_get cleans up its
PM usage count increment, leaving the net usage count unchanged.
Because this error is ignored, the code unconditionally calls
hid_sensor_power_state false later on, which invokes
pm_runtime_put_autosuspend and drops the usage counter by 1.
Does this cause the PM usage counter to underflow when power-on fails?
> +
> + ret_type = sensor_hub_input_attr_read_values(hsdev,
> + hsdev->usage,
> + usage_id,
> + info->report_id,
> + SENSOR_HUB_SYNC,
> + info->size,
> + (u8 *)&raw_buf);
[Severity: Critical]
Can this corrupt the stack if the synchronous read is interrupted?
By passing a pointer to the stack-allocated raw_buf into
sensor_hub_input_attr_read_values, the driver relies on the wait
completing successfully.
If the wait is interrupted by a signal sent to the userspace process,
or if it times out:
drivers/hid/hid-sensor-hub.c:sensor_hub_input_attr_read_values() {
...
cycles = wait_for_completion_interruptible_timeout(&hsdev->pending.ready,
HZ * 5);
if (cycles == 0)
ret = -ETIMEDOUT;
else if (cycles < 0)
ret = cycles;
hsdev->pending.status = false;
...
}
The function locklessly clears hsdev->pending.status and returns, destroying
the raw_buf stack frame.
However, the concurrent HID interrupt handler sensor_hub_raw_event might
have already evaluated hsdev->pending.status as true under the lock, and
could proceed to memcpy into the now-freed stack pointer.
> +
> + hid_sensor_power_state(&rot_state->common_attributes, false);
> +
> + if (ret_type < 0)
> + return ret_type;
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260610082911.157232-1-lixu.zhang@intel.com?part=2
^ permalink raw reply
* Re: [PATCH 1/2] HID: sensor-hub: Add sensor_hub_input_attr_read_values() for multi-byte reads
From: Andy Shevchenko @ 2026-06-10 10:52 UTC (permalink / raw)
To: Zhang Lixu
Cc: Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada,
Benjamin Tissoires, David Lechner, Nuno Sá, Andy Shevchenko,
linux-input, linux-iio, linux-kernel
In-Reply-To: <20260610082911.157232-2-lixu.zhang@intel.com>
On Wed, Jun 10, 2026 at 04:29:09PM +0800, Zhang Lixu wrote:
> sensor_hub_input_attr_get_raw_value() is limited to returning a single
> 32-bit value, which is insufficient for sensors that report data larger
> than 32 bits, such as a quaternion with four s16 elements.
>
> Add sensor_hub_input_attr_read_values() that accepts a caller-provided
> buffer and accumulates incoming data until the buffer is full. The two
> paths are distinguished in sensor_hub_raw_event() by pending.max_raw_size
> being non-zero, preserving backward compatibility.
I have reviewed that internally and checked public version which LGTM,
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH 2/2] iio: hid-sensor-rotation: Fix stale or zero output when reading raw values
From: Andy Shevchenko @ 2026-06-10 10:53 UTC (permalink / raw)
To: Zhang Lixu
Cc: Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada,
Benjamin Tissoires, David Lechner, Nuno Sá, Andy Shevchenko,
linux-input, linux-iio, linux-kernel
In-Reply-To: <20260610082911.157232-3-lixu.zhang@intel.com>
On Wed, Jun 10, 2026 at 04:29:10PM +0800, Zhang Lixu wrote:
> When reading the raw quaternion attribute (in_rot_quaternion_raw), the
> driver currently returns either all zeros (if the sensor was never enabled)
> or stale data (if the sensor was previously enabled) because it reads from
> the internal buffer without explicitly requesting a new sample from the
> sensor.
>
> To fix this, power up the sensor, call sensor_hub_input_attr_read_values()
> to issue a synchronous GET_REPORT and receive the full quaternion data
> directly into a local buffer, then decode the four components.
I have reviewed that internally and checked public version which LGTM,
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v3 1/4] HID: wacom: Fix Use-After-Free in wacom_intuos_pad
From: Lee Jones @ 2026-06-10 10:55 UTC (permalink / raw)
To: Ping Cheng, Jason Gerecke, Jiri Kosina, Benjamin Tissoires,
Peter Hutterer, Dmitry Torokhov, linux-input, linux-kernel
In-Reply-To: <20260609121353.3743782-1-lee@kernel.org>
Note that all of the issues raised by Sashiko are pre-existing.
--
Lee Jones
^ permalink raw reply
* Re: [PATCH v1] Input: Drop unused assignments from pnp_device_id arrays
From: Uwe Kleine-König (The Capable Hub) @ 2026-06-10 11:58 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Kees Cook, Werner Sembach, Christoffer Sandberg, feng, gongqi,
linux-input, linux-kernel
In-Reply-To: <aij_gj5W1dylcbrX@google.com>
[-- Attachment #1: Type: text/plain, Size: 1517 bytes --]
Hello Dmitry,
On Tue, Jun 09, 2026 at 11:12:49PM -0700, Dmitry Torokhov wrote:
> On Tue, Jun 09, 2026 at 04:53:25PM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> > Explicitly assigning .driver_data in drivers that don't use this member
> > is silly and a bit irritating. Drop these. Also simplify the list
> > terminator entry to be just empty to match what most other device_id
> > tables do.
> >
> > There is no changed semantic, not even a change in the compiled result.
> >
> > Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>
> > ---
> > drivers/input/gameport/ns558.c | 46 +++++++++++-----------
> > drivers/input/serio/i8042-acpipnpio.h | 56 +++++++++++++--------------
> > 2 files changed, 51 insertions(+), 51 deletions(-)
> >
> > diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
> > index fdece6ec1df3..f70a96c4f1fd 100644
> > --- a/drivers/input/gameport/ns558.c
> > +++ b/drivers/input/gameport/ns558.c
> > @@ -148,29 +148,29 @@ static int ns558_isa_probe(int io)
> > #ifdef CONFIG_PNP
> >
> > static const struct pnp_device_id pnp_devids[] = {
> > - [...]
> > - { .id = "", },
> > + [...]
> > + { }
>
> This goes BOOOM! You have to keep empty .id string as terminator.
How so? Given that my patch doesn't modify the resulting ns558.o I doubt
that. If .id was a char *, I'd agree, but it's a char[], so there should
be no difference (and the compiler agrees).
Best regards
Uwe
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* [PATCH] HID: hid-steam: fix uninit-value access in steam_get_serial
From: Pei Xiao @ 2026-06-10 12:01 UTC (permalink / raw)
To: jikos, bentiss, linux-input, linux-kernel,
syzbot+75f3f9bff8c510602d36
Cc: syzkaller-bugs, Pei Xiao
In-Reply-To: <6a27d055.39669fcc.33b062.008d.GAE@google.com>
The reply buffer in steam_get_serial() is allocated on the stack without
initialization. In cases where steam_recv_report() returns a short read or
an error, not all bytes of the buffer are written, leading to subsequent
access of uninitialized memory when checking reply[0], reply[1], reply[2].
Zero-initialize the reply array to prevent KMSAN uninit-value warnings.
Logs:
hid-steam 0003:28DE:1102.0007: unknown main item tag 0x0
hid-steam 0003:28DE:1102.0007: unknown main item tag 0x0
hid-steam 0003:28DE:1102.0007: :
USB HID v7f.fd Device [HID 28de:1102] on usb-dummy_hcd.1-1/input0
=====================================================
BUG: KMSAN: uninit-value in steam_get_serial drivers/hid/hid-steam.c:457 [inline]
BUG: KMSAN: uninit-value in steam_register+0xd83/0x10e0 drivers/hid/hid-steam.c:965
steam_get_serial drivers/hid/hid-steam.c:457 [inline]
steam_register+0xd83/0x10e0 drivers/hid/hid-steam.c:965
steam_probe+0x6f1/0x19b0 drivers/hid/hid-steam.c:1273
__hid_device_probe drivers/hid/hid-core.c:2822 [inline]
hid_device_probe+0x60d/0xb90 drivers/hid/hid-core.c:2859
call_driver_probe drivers/base/dd.c:-1 [inline]
really_probe+0x4d5/0xe40 drivers/base/dd.c:709
...
Local variable reply.i created at:
steam_get_serial drivers/hid/hid-steam.c:448 [inline]
steam_register+0x180/0x10e0 drivers/hid/hid-steam.c:965
steam_probe+0x6f1/0x19b0 drivers/hid/hid-steam.c:1273
Reported-by: syzbot+75f3f9bff8c510602d36@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/lkml/6a27d055.39669fcc.33b062.008d.GAE@google.com/
Fixes: c164d6abf384 ("HID: add driver for Valve Steam Controller")
Signed-off-by: Pei Xiao <xiaopei01@kylinos.cn>
---
drivers/hid/hid-steam.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c
index 197126d6e081..f65ad1a21c01 100644
--- a/drivers/hid/hid-steam.c
+++ b/drivers/hid/hid-steam.c
@@ -445,7 +445,7 @@ static int steam_get_serial(struct steam_device *steam)
*/
int ret = 0;
u8 cmd[] = {ID_GET_STRING_ATTRIBUTE, sizeof(steam->serial_no), ATTRIB_STR_UNIT_SERIAL};
- u8 reply[3 + STEAM_SERIAL_LEN + 1];
+ u8 reply[3 + STEAM_SERIAL_LEN + 1] = { 0 };
mutex_lock(&steam->report_mutex);
ret = steam_send_report(steam, cmd, sizeof(cmd));
--
2.25.1
^ permalink raw reply related
* Re: [PATCH] HID: hid-steam: fix uninit-value access in steam_get_serial
From: sashiko-bot @ 2026-06-10 12:17 UTC (permalink / raw)
To: Pei Xiao; +Cc: dmitry.torokhov, linux-input
In-Reply-To: <0c5f5bcd3d01776615a97d7f23b5c1bff6a2acce.1781092734.git.xiaopei01@kylinos.cn>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing payload length validation in `steam_get_serial()` allows a short report to produce an empty serial number, leading to list corruption (Use-After-Free) during device unregistration.
- [High] Probe error path leaves a freed object in the global `steam_devices` list, causing a Use-After-Free.
- [Medium] Incorrect size argument passed to `strscpy()` causes truncation of the last character of the device's serial number.
--
commit ecebdbfdb0a084297c080f3d3ad65a720d3b9ec6
Author: Pei Xiao <xiaopei01@kylinos.cn>
HID: hid-steam: fix uninit-value access in steam_get_serial
The reply buffer in steam_get_serial() is zero-initialized to prevent KMSAN
uninit-value warnings. These warnings occur when steam_recv_report()
returns a short read or an error.
Reported-by: syzbot+75f3f9bff8c510602d36@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/lkml/6a27d055.39669fcc.33b062.008d.GAE@google.com/
Fixes: c164d6abf384 ("HID: add driver for Valve Steam Controller")
Signed-off-by: Pei Xiao <xiaopei01@kylinos.cn>
> diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c
> index 197126d6e0810..f65ad1a21c018 100644
> --- a/drivers/hid/hid-steam.c
> +++ b/drivers/hid/hid-steam.c
> @@ -445,7 +445,7 @@ static int steam_get_serial(struct steam_device *steam)
> */
> int ret = 0;
> u8 cmd[] = {ID_GET_STRING_ATTRIBUTE, sizeof(steam->serial_no), ATTRIB_STR_UNIT_SERIAL};
> - u8 reply[3 + STEAM_SERIAL_LEN + 1];
> + u8 reply[3 + STEAM_SERIAL_LEN + 1] = { 0 };
>
> mutex_lock(&steam->report_mutex);
> ret = steam_send_report(steam, cmd, sizeof(cmd));
[Severity: High]
This is a pre-existing issue, but does steam_get_serial() properly validate
the payload length before copying the serial number?
If a device returns a short report (e.g., 4 bytes), steam_recv_report()
returns 4. The buffer validation checks reply[0] through reply[2], and if
they match, execution reaches the copy:
drivers/hid/hid-steam.c:steam_get_serial() {
...
strscpy(steam->serial_no, reply + 3, reply[1]);
...
}
If reply[1] is 1, strscpy() will copy 0 characters and write a null
terminator at steam->serial_no[0]. steam_get_serial() then returns 4
(success), bypassing the fallback assignment in steam_register().
Later, during device unregistration:
drivers/hid/hid-steam.c:steam_unregister() {
if (steam->serial_no[0]) {
...
list_del_init(&steam->list);
...
}
}
Could this skip list removal because steam->serial_no[0] is null, leaving a
freed object on the global steam_devices list and causing a use-after-free?
[Severity: Medium]
This isn't a bug introduced by this patch, but does the strscpy() call inside
steam_get_serial() pass the correct size argument?
drivers/hid/hid-steam.c:steam_get_serial() {
...
strscpy(steam->serial_no, reply + 3, reply[1]);
...
}
Since strscpy() reserves one byte for the null terminator, passing the exact
string length (reply[1]) as the size will cause it to copy only reply[1] - 1
characters. Will this truncate the last character of a valid serial number if
the device specifies its exact length in reply[1]?
[Severity: High]
This is a pre-existing issue, but does steam_register() properly clean up
the global steam_devices list on failure?
During registration, the device is added to the global list:
drivers/hid/hid-steam.c:steam_register() {
...
mutex_lock(&steam_devices_lock);
if (list_empty(&steam->list))
list_add(&steam->list, &steam_devices);
mutex_unlock(&steam_devices_lock);
...
ret = steam_input_register(steam);
if (ret != 0)
goto steam_register_input_fail;
...
steam_register_input_fail:
return ret;
}
If steam_input_register() fails, steam_register() returns an error without
removing the object from the steam_devices list.
In the probe function:
drivers/hid/hid-steam.c:steam_probe() {
...
ret = steam_register(steam);
if (ret) {
hid_err(hdev,
"%s:steam_register failed with error %d\n",
__func__, ret);
goto err_hw_close;
}
...
}
If steam_register() fails, the driver core will free the devres-managed
steam_device struct. Could this leave a dangling pointer in the global
steam_devices list and lead to a use-after-free upon later list traversal?
--
Sashiko AI review · https://sashiko.dev/#/patchset/0c5f5bcd3d01776615a97d7f23b5c1bff6a2acce.1781092734.git.xiaopei01@kylinos.cn?part=1
^ permalink raw reply
* Re: [PATCH 7/8] dt-bindings: input: microchip,cap11xx: Add CAP1114 support
From: Jun Yan @ 2026-06-10 13:34 UTC (permalink / raw)
To: conor
Cc: conor+dt, devicetree, dmitry.torokhov, jerrysteve1101, krzk+dt,
linux-input, linux-kernel, robh
In-Reply-To: <20260609-ebook-tantrum-4846384c02d5@spud>
> On Tue, Jun 09, 2026 at 10:08:27PM +0800, Jun Yan wrote:
> > > On Sat, Jun 06, 2026 at 11:04:00PM +0800, Jun Yan wrote:
> > > > CAP1114 is a 14-channel capacitive touch sensor with 11 LED outputs
> > > > and hardware reset support.
> > > >=3D20
> > > > Add the compatible string for CAP1114, include its datasheet URL,
> > > > and update the maximum count of LED channels and linux,keycodes entri=
> es.
> > > >=3D20
> > > > Add description for microchip,input-threshold: CAP1114 only provides =
> eight
> > > > threshold entries, which does not match its total channel count.
> > > >=3D20
> > > > Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
> > > > ---
> > > > .../bindings/input/microchip,cap11xx.yaml | 21 +++++++++++++++++=
> --
> > > > 1 file changed, 19 insertions(+), 2 deletions(-)
> > > >=3D20
> > > > diff --git a/Documentation/devicetree/bindings/input/microchip,cap11x=
> x.ya=3D
> > > ml b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
> > > > index e307628350c2..08233386a433 100644
> > > > --- a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
> > > > +++ b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
> > > > @@ -12,6 +12,7 @@ description: |
> > > > =3D20
> > > > For more product information please see the links below:
> > > > CAP1106: https://ww1.microchip.com/downloads/en/DeviceDoc/000016=
> 24B.=3D
> > > pdf
> > > > + CAP1114: https://ww1.microchip.com/downloads/en/DeviceDoc/000024=
> 44A.=3D
> > > pdf
> > > > CAP1126: https://ww1.microchip.com/downloads/en/DeviceDoc/000016=
> 23B.=3D
> > > pdf
> > > > CAP1188: https://ww1.microchip.com/downloads/en/DeviceDoc/000016=
> 20C.=3D
> > > pdf
> > > > CAP1203: https://ww1.microchip.com/downloads/en/DeviceDoc/000015=
> 72B.=3D
> > > pdf
> > > > @@ -26,6 +27,7 @@ properties:
> > > > compatible:
> > > > enum:
> > > > - microchip,cap1106
> > > > + - microchip,cap1114
> > > > - microchip,cap1126
> > > > - microchip,cap1188
> > > > - microchip,cap1203
> > > > @@ -62,7 +64,7 @@ properties:
> > > > =3D20
> > > > 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 sen=
> sor =3D
> > > less
> > > > sensitive.
> > > > The number of entries must correspond to the number of channel=
> s.
> > > > + CAP1114 is an exception where channels 8~14 reuse the eighth e=
> ntry=3D
> > > 's
> > > > + threshold, so counts differ.
> > > > =3D20
> > > > microchip,calib-sensitivity:
> > > > $ref: /schemas/types.yaml#/definitions/uint32-array
> > > > @@ -149,7 +153,7 @@ patternProperties:
> > > > reg:
> > > > description: LED channel number
> > > > minimum: 0
> > > > - maximum: 7
> > > > + maximum: 10
> > > > =3D20
> > > > required:
> > > > - reg
> > > > @@ -199,6 +203,19 @@ allOf:
> > > > reg:
> > > > maximum: 1
> > > > =3D20
> > > > + - if:
> > > > + properties:
> > > > + compatible:
> > > > + contains:
> > > > + enum:
> > > > + - microchip,cap1188
> > >=20
> > > I don't understand this restriction, shouldn't this be
> > > if: properties: compatible: not: contains: microchip,cap1114
> > > so that the constraints before your change are retained?
> > >=20
> >=20
> > Previously, the LED reg property had a default maximum of 7 for CAP1188.=
> =20
> > With the addition of CAP1114, the default maximum is now 11.=20
> > An if-then constraint is added to limit the LED count for CAP1188.
>
> Ah, is this because cap1188 is the only existing device in the binding
> that actually has LEDs?
- CAP1126: max 2 LED channels (0-1)
- CAP1188: max 8 LED channels (0-7)
- CAP1106, CAP12xx: no LED support
The LED reg property constraints for CAP1126 were added in Patch 3 [1].
[1] https://lore.kernel.org/linux-input/20260606150458.250606-4-jerrysteve1101@gmail.com/
^ permalink raw reply
* [PATCH] HID: ft260: fix SMBus block read protocol handling
From: Raman Varabets @ 2026-06-10 13:41 UTC (permalink / raw)
To: michael.zaidman
Cc: jikos, bentiss, linux-i2c, linux-input, linux-kernel,
Raman Varabets
For I2C_SMBUS_BLOCK_DATA reads, ft260_smbus_xfer() passed
data->block[0] + 1 as the read length. But on a block read the byte
count is supplied by the slave as the first byte of the response;
data->block[0] is not initialized by the caller, so the transfer
length was taken from stale buffer contents, and the count byte the
slave did return was stored without any validation.
Implement the SMBus 2.0 block read protocol properly: read the count
byte first with a repeated START and no STOP, validate it against
I2C_SMBUS_BLOCK_MAX (resetting the bus and returning -EPROTO on a
bogus count), then read exactly that many data bytes and finish the
transaction with STOP. This keeps the whole sequence within a single
I2C transaction:
S Addr+Wr A Reg A Sr Addr+Rd A Count A Data... P
To support issuing the two reads as one transaction, teach
ft260_i2c_read() to honor the caller's flags instead of always
forcing a START and unconditionally appending STOP to the last
chunk: START is only emitted if requested, and STOP is appended to
the final chunk only when the caller asked for it.
Signed-off-by: Raman Varabets <kernel-linux-20260610-80b7ab08@raman.v1.sg>
---
drivers/hid/hid-ft260.c | 45 ++++++++++++++++++++++++++++++++++++-----
1 file changed, 40 insertions(+), 5 deletions(-)
diff --git a/drivers/hid/hid-ft260.c b/drivers/hid/hid-ft260.c
index 70e2eedb4..946ed0c6f 100644
--- a/drivers/hid/hid-ft260.c
+++ b/drivers/hid/hid-ft260.c
@@ -502,15 +502,23 @@ static int ft260_i2c_read(struct ft260_device *dev, u8 addr, u8 *data,
struct ft260_i2c_read_request_report rep;
struct hid_device *hdev = dev->hdev;
u8 bus_busy = 0;
+ /*
+ * STOP terminates the last chunk; clear means hold the bus so a
+ * follow-up call continues the same I2C transaction.
+ */
+ bool want_stop = !!(flag & FT260_FLAG_STOP);
if ((flag & FT260_FLAG_START_REPEATED) == FT260_FLAG_START_REPEATED)
flag = FT260_FLAG_START_REPEATED;
- else
+ else if (flag & FT260_FLAG_START)
flag = FT260_FLAG_START;
+ else
+ flag = 0; /* no fresh START - continue current transaction */
do {
if (len <= rd_data_max) {
rd_len = len;
- flag |= FT260_FLAG_STOP;
+ if (want_stop)
+ flag |= FT260_FLAG_STOP;
} else {
rd_len = rd_data_max;
}
@@ -708,14 +716,41 @@ static int ft260_smbus_xfer(struct i2c_adapter *adapter, u16 addr, u16 flags,
break;
case I2C_SMBUS_BLOCK_DATA:
if (read_write == I2C_SMBUS_READ) {
+ u8 count = 0;
+
+ /*
+ * SMBus 2.0 section 6.5.7 block read in one I2C
+ * transaction:
+ *
+ * S Addr+Wr A Reg A Sr Addr+Rd A Count A Data... P
+ *
+ * The count is read separately and validated
+ * before sizing the data read so a misbehaving
+ * slave cannot drive a write past data->block[].
+ */
ret = ft260_smbus_write(dev, addr, cmd, NULL, 0,
FT260_FLAG_START);
if (ret)
goto smbus_exit;
- ret = ft260_i2c_read(dev, addr, data->block,
- data->block[0] + 1,
- FT260_FLAG_START_STOP_REPEATED);
+ ret = ft260_i2c_read(dev, addr, &count, 1,
+ FT260_FLAG_START_REPEATED);
+ if (ret)
+ goto smbus_exit;
+
+ if (count == 0 || count > I2C_SMBUS_BLOCK_MAX) {
+ hid_warn(hdev,
+ "smbus block read: invalid count %u from slave 0x%02x\n",
+ count, addr);
+ ft260_i2c_reset(hdev);
+ ret = -EPROTO;
+ goto smbus_exit;
+ }
+
+ data->block[0] = count;
+
+ ret = ft260_i2c_read(dev, addr, data->block + 1,
+ count, FT260_FLAG_STOP);
} else {
ret = ft260_smbus_write(dev, addr, cmd, data->block,
data->block[0] + 1,
base-commit: ab5fce87a778cb780a05984a2ca448f2b41aafbf
--
2.54.0
^ permalink raw reply related
* Re: [PATCH] HID: ft260: fix SMBus block read protocol handling
From: sashiko-bot @ 2026-06-10 14:08 UTC (permalink / raw)
To: Raman Varabets; +Cc: linux-input, dmitry.torokhov
In-Reply-To: <20260610134119.3313484-1-kernel-linux-20260610-80b7ab08@raman.v1.sg>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [Critical] A Time-of-Check to Time-of-Use (TOCTOU) race condition in the I2C read timeout handling allows a malicious USB device to execute a Use-After-Free write on the kernel stack. This problem wasn't introduced by this patch, but it is a critical pre-existing flaw. `ft260_i2c_read` sets `dev->read_buf` to point to a stack variable and waits for completion. If the device delays the response causing a timeout, the function clears `dev->read_buf` to NULL and returns, popping the stack frame. Concurrently, `ft260_raw_event` checks `dev->read_buf != NULL` without locking and then performs a `memcpy`. A properly timed malicious device response can pass the NULL check before the timeout clears it, resulting in the `memcpy` writing device-controlled payload data into freed kernel stack memory, potentially hijacking control flow.
--
commit b044839cc37c642e14b8d9de071b491bae721de9
Author: Raman Varabets <kernel-linux-20260610-80b7ab08@raman.v1.sg>
HID: ft260: fix SMBus block read protocol handling
For I2C_SMBUS_BLOCK_DATA reads, ft260_smbus_xfer() passed
data->block[0] + 1 as the read length. But on a block read the byte
count is supplied by the slave as the first byte of the response;
data->block[0] is not initialized by the caller, so the transfer
length was taken from stale buffer contents, and the count byte the
slave did return was stored without any validation.
> diff --git a/drivers/hid/hid-ft260.c b/drivers/hid/hid-ft260.c
> index 70e2eedb465af..946ed0c6fc39f 100644
> --- a/drivers/hid/hid-ft260.c
> +++ b/drivers/hid/hid-ft260.c
> @@ -502,15 +502,23 @@ static int ft260_i2c_read(struct ft260_device *dev, u8 addr, u8 *data,
> struct ft260_i2c_read_request_report rep;
> struct hid_device *hdev = dev->hdev;
> u8 bus_busy = 0;
> + /*
> + * STOP terminates the last chunk; clear means hold the bus so a
> + * follow-up call continues the same I2C transaction.
> + */
> + bool want_stop = !!(flag & FT260_FLAG_STOP);
[Severity: Critical]
This is a pre-existing issue, but is there a TOCTOU race condition in the I2C
read timeout handling that allows a malicious USB device to execute a
use-after-free write on the kernel stack?
Looking at ft260_i2c_read(), it sets dev->read_buf to point to the provided
data pointer and waits for completion. If the device delays the response
causing a timeout, the function clears dev->read_buf to NULL and returns,
popping the stack frame:
drivers/hid/hid-ft260.c:ft260_i2c_read() {
...
if (!wait_for_completion_timeout(&dev->wait, timeout)) {
ret = -ETIMEDOUT;
ft260_i2c_reset(hdev);
goto ft260_i2c_read_exit;
}
...
ft260_i2c_read_exit:
dev->read_buf = NULL;
return ret;
}
Concurrently, ft260_raw_event() checks dev->read_buf != NULL without taking
any locks and then performs a memcpy():
drivers/hid/hid-ft260.c:ft260_raw_event() {
...
if ((dev->read_buf == NULL) ||
(xfer->length > dev->read_len - dev->read_idx)) {
...
}
memcpy(&dev->read_buf[dev->read_idx], &xfer->data,
xfer->length);
...
}
Could a properly timed malicious device response pass the NULL check before the
timeout clears it, resulting in the memcpy() writing device-controlled payload
data into freed kernel stack memory?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260610134119.3313484-1-kernel-linux-20260610-80b7ab08@raman.v1.sg?part=1
^ permalink raw reply
* [PATCH] HID: ft260: fix stack-use-after-return write in I2C read race
From: Raman Varabets @ 2026-06-10 14:29 UTC (permalink / raw)
To: michael.zaidman
Cc: jikos, bentiss, linux-i2c, linux-input, linux-kernel,
Raman Varabets, stable
ft260_i2c_read() points dev->read_buf at a caller-supplied buffer
(often an on-stack variable), arms a completion and waits up to five
seconds for the device to return the data. The HID input callback
ft260_raw_event() runs in the input/IRQ path, independent of the
dev->lock mutex held by the read path, and copies the device-supplied
payload into dev->read_buf after a plain NULL check.
These two paths share read_buf, read_idx and read_len with no
serialization. If the device delays its response until the read
times out, ft260_i2c_read() resets the controller, clears read_buf
and returns, unwinding the stack frame the buffer lived in. A
response that arrives at that moment lets ft260_raw_event() pass the
NULL check and then memcpy() the device-controlled payload into the
now-freed stack location, a bounded but attacker-influenced
stack-use-after-return write triggerable by malicious or
malfunctioning hardware.
Add a dedicated spinlock that serializes every access to read_buf,
read_idx and read_len. ft260_raw_event() now holds it across the
NULL check, the memcpy and the index update, while the read path
takes it when arming and when clearing the buffer, so the teardown
can no longer slip between the check and the copy.
Fixes: 6a82582d9fa4 ("HID: ft260: add usb hid to i2c host bridge driver")
Cc: stable@vger.kernel.org
Signed-off-by: Raman Varabets <kernel-linux-20260610-80b7ab08@raman.v1.sg>
---
drivers/hid/hid-ft260.c | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/hid-ft260.c b/drivers/hid/hid-ft260.c
index 70e2eedb4..f47945954 100644
--- a/drivers/hid/hid-ft260.c
+++ b/drivers/hid/hid-ft260.c
@@ -240,6 +240,8 @@ struct ft260_device {
struct mutex lock;
u8 write_buf[FT260_REPORT_MAX_LENGTH];
unsigned long need_wakeup_at;
+ /* Protects read_buf, read_idx and read_len against ft260_raw_event() */
+ spinlock_t read_lock;
u8 *read_buf;
u16 read_idx;
u16 read_len;
@@ -501,6 +503,7 @@ static int ft260_i2c_read(struct ft260_device *dev, u8 addr, u8 *data,
int timeout, ret = 0;
struct ft260_i2c_read_request_report rep;
struct hid_device *hdev = dev->hdev;
+ unsigned long irqflags;
u8 bus_busy = 0;
if ((flag & FT260_FLAG_START_REPEATED) == FT260_FLAG_START_REPEATED)
@@ -526,9 +529,11 @@ static int ft260_i2c_read(struct ft260_device *dev, u8 addr, u8 *data,
reinit_completion(&dev->wait);
+ spin_lock_irqsave(&dev->read_lock, irqflags);
dev->read_idx = 0;
dev->read_buf = data;
dev->read_len = rd_len;
+ spin_unlock_irqrestore(&dev->read_lock, irqflags);
ret = ft260_hid_output_report(hdev, (u8 *)&rep, sizeof(rep));
if (ret < 0) {
@@ -543,7 +548,9 @@ static int ft260_i2c_read(struct ft260_device *dev, u8 addr, u8 *data,
goto ft260_i2c_read_exit;
}
+ spin_lock_irqsave(&dev->read_lock, irqflags);
dev->read_buf = NULL;
+ spin_unlock_irqrestore(&dev->read_lock, irqflags);
if (flag & FT260_FLAG_STOP)
bus_busy = FT260_I2C_STATUS_BUS_BUSY;
@@ -562,7 +569,9 @@ static int ft260_i2c_read(struct ft260_device *dev, u8 addr, u8 *data,
} while (len > 0);
ft260_i2c_read_exit:
+ spin_lock_irqsave(&dev->read_lock, irqflags);
dev->read_buf = NULL;
+ spin_unlock_irqrestore(&dev->read_lock, irqflags);
return ret;
}
@@ -1018,6 +1027,7 @@ static int ft260_probe(struct hid_device *hdev, const struct hid_device_id *id)
"FT260 usb-i2c bridge");
mutex_init(&dev->lock);
+ spin_lock_init(&dev->read_lock);
init_completion(&dev->wait);
ret = ft260_xfer_status(dev, FT260_I2C_STATUS_BUS_BUSY);
@@ -1067,6 +1077,7 @@ static int ft260_raw_event(struct hid_device *hdev, struct hid_report *report,
{
struct ft260_device *dev = hid_get_drvdata(hdev);
struct ft260_i2c_input_report *xfer = (void *)data;
+ unsigned long irqflags;
if (size < offsetof(struct ft260_i2c_input_report, data)) {
hid_err(hdev, "short report %d\n", size);
@@ -1075,6 +1086,8 @@ static int ft260_raw_event(struct hid_device *hdev, struct hid_report *report,
if (xfer->report >= FT260_I2C_REPORT_MIN &&
xfer->report <= FT260_I2C_REPORT_MAX) {
+ bool complete_read;
+
ft260_dbg("i2c resp: rep %#02x len %d size %d\n",
xfer->report, xfer->length, size);
@@ -1085,8 +1098,15 @@ static int ft260_raw_event(struct hid_device *hdev, struct hid_report *report,
return -1;
}
+ /*
+ * Hold read_lock so a timed-out ft260_i2c_read() cannot
+ * clear read_buf between the NULL check and the memcpy.
+ */
+ spin_lock_irqsave(&dev->read_lock, irqflags);
+
if ((dev->read_buf == NULL) ||
(xfer->length > dev->read_len - dev->read_idx)) {
+ spin_unlock_irqrestore(&dev->read_lock, irqflags);
hid_err(hdev, "unexpected report %#02x, length %d\n",
xfer->report, xfer->length);
return -1;
@@ -1095,8 +1115,11 @@ static int ft260_raw_event(struct hid_device *hdev, struct hid_report *report,
memcpy(&dev->read_buf[dev->read_idx], &xfer->data,
xfer->length);
dev->read_idx += xfer->length;
+ complete_read = dev->read_idx == dev->read_len;
+
+ spin_unlock_irqrestore(&dev->read_lock, irqflags);
- if (dev->read_idx == dev->read_len)
+ if (complete_read)
complete(&dev->wait);
} else {
--
2.54.0
^ permalink raw reply related
* Re: [PATCH] HID: ft260: fix stack-use-after-return write in I2C read race
From: sashiko-bot @ 2026-06-10 14:42 UTC (permalink / raw)
To: Raman Varabets; +Cc: dmitry.torokhov, linux-input
In-Reply-To: <20260610142952.3335586-1-kernel-linux-20260610-80b7ab08@raman.v1.sg>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [High] The driver calls `hid_hw_open()` and `hid_hw_start()` before fully initializing driver data and locks, allowing an early interrupt to cause a NULL pointer dereference or uninitialized spinlock access.
- [High] Calling `complete(&dev->wait)` outside the `read_lock` creates a race condition where a delayed completion signal can spuriously wake up a subsequent I2C read, resulting in the exposure of uninitialized memory.
- [High] A delayed I2C response from a timed-out read can erroneously fulfill a newly issued I2C read request, silently corrupting the read payload.
--
commit f93912f569da4f226a3bdb7379cc9b9a98ba1eb9
Author: Raman Varabets <kernel-linux-20260610-80b7ab08@raman.v1.sg>
HID: ft260: fix stack-use-after-return write in I2C read race
This commit fixes a race condition where a delayed I2C response could write
into a freed stack buffer after a timeout in ft260_i2c_read. It adds a
dedicated spinlock to serialize accesses to the read buffer, index, and length
between the read path and the raw event handler.
> diff --git a/drivers/hid/hid-ft260.c b/drivers/hid/hid-ft260.c
> index 70e2eedb465af..f479459544aee 100644
> --- a/drivers/hid/hid-ft260.c
> +++ b/drivers/hid/hid-ft260.c
[ ... ]
> @@ -543,7 +548,9 @@ static int ft260_i2c_read(struct ft260_device *dev, u8 addr, u8 *data,
> goto ft260_i2c_read_exit;
> }
>
> + spin_lock_irqsave(&dev->read_lock, irqflags);
> dev->read_buf = NULL;
> + spin_unlock_irqrestore(&dev->read_lock, irqflags);
[Severity: High]
This is a pre-existing issue, but does the timeout path leave stale USB input
reports pending?
If an I2C read times out, ft260_i2c_read() resets the controller but does not
flush the HID/USB receive queues. When a new I2C read begins, dev->read_buf
is updated to point to the new buffer.
Could a delayed USB report containing the response for the previous timed-out
read arrive, pass the NULL check in ft260_raw_event(), and blindly copy stale
data into the new buffer? This would silently corrupt the payload and
desynchronize the bus state.
[ ... ]
> @@ -1018,6 +1027,7 @@ static int ft260_probe(struct hid_device *hdev, const struct hid_device_id *id)
> "FT260 usb-i2c bridge");
>
> mutex_init(&dev->lock);
> + spin_lock_init(&dev->read_lock);
> init_completion(&dev->wait);
>
> ret = ft260_xfer_status(dev, FT260_I2C_STATUS_BUS_BUSY);
[Severity: High]
This isn't a bug introduced by this patch, but does hid_hw_open() allow events
to trigger before the driver data and locks are fully initialized?
In ft260_probe(), hid_hw_open() is called before hid_set_drvdata() and before
spin_lock_init(&dev->read_lock). Because hid_hw_open() submits USB interrupt
IN URBs, the hardware can start sending events immediately.
If ft260_raw_event() triggers early, hid_get_drvdata() would return NULL.
Could this lead to a NULL pointer dereference when ft260_raw_event() attempts
to acquire dev->read_lock?
[ ... ]
> @@ -1095,8 +1115,11 @@ static int ft260_raw_event(struct hid_device *hdev, struct hid_report *report,
> memcpy(&dev->read_buf[dev->read_idx], &xfer->data,
> xfer->length);
> dev->read_idx += xfer->length;
> + complete_read = dev->read_idx == dev->read_len;
> +
> + spin_unlock_irqrestore(&dev->read_lock, irqflags);
>
> - if (dev->read_idx == dev->read_len)
> + if (complete_read)
> complete(&dev->wait);
>
> } else {
[Severity: High]
This is a pre-existing issue, but does calling complete() outside the
read_lock create a race condition with the teardown path?
If an I2C read times out, ft260_i2c_read() wakes up and clears dev->read_buf.
A new I2C read request could then be issued, which calls
reinit_completion(&dev->wait).
If the softirq executing ft260_raw_event() is preempted between dropping the
lock and calling complete(&dev->wait), could it resume and signal the
completion after the new request has already reinitialized it? This would
cause the new wait to instantly succeed, returning success without writing any
data to the caller's buffer.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260610142952.3335586-1-kernel-linux-20260610-80b7ab08@raman.v1.sg?part=1
^ permalink raw reply
* [PATCH v2 00/12] HID: storing pointers in 'hid_device_id::driver_data'
From: Pawel Zalewski (The Capable Hub) @ 2026-06-10 15:11 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Ping Cheng, Jason Gerecke
Cc: linux-kernel, linux-input, Pawel Zalewski (The Capable Hub)
The <linux/mod_devicetable.h> has multiple structs that follow
the pattern of having either 'driver_data' or 'driver_info'
fields which are of the 'kernel_ulong_t' type. Then how to
interpret that field is user defined, some users will treat
the value as an actual integer, others as a valid pointer to
dereference.
One of instances of the above is the 'hid_device_id::driver_data'
field, for the most part it is used for setting HID quirks and
treated as an integer value for storing metadata in the subsystem
drivers. But in a few instances it is used as a valid pointer to
dereference, namely in:
- hid-tmff
- wacom
Additionally this field can be set from the userspace via the
'hid_core::new_id_store' function - which is not memory safe and
could lead to OOB memory access in the above two cases.
This series is addressing the issue by making the usage of the field
consistent, all drives treat the value as an integer and if the
driver has a need for dereferencing a pointer - it stores and
index to a table of pointers. The index is bounded by a named enum
and checked at runtime at the module level to avoid developer bugs.
Furthermore a user-input sanitizer was added in the 'hid_core' module
that restricts injecting arbitrary values for 'hid_device_id::driver_data'
that are not defined and matched within the driver already.
It was found that some modules that use the field do not use a named
initializers for the field - which is inconsistent with rest of the
modules within the HID subsystem. This is also addressed in the series
as part of the pre-clean up to increase clarity in patches 1-4.
It was found that some modules use a bit of a type-unsafe way of storing
integers in the 'void *driver_data' pointer of the 'struct hid_device'
- this required a cast during storage via 'hid_set_drvdata' and a cast
during retrieval when using 'hid_get_drvdata'. I can see why this was
done - as we potentially save on an allocation - but really code is
more readable and better quality without resorting to this. This issue
is also addressed in this patch series in patches 5-8 as part of the
pre-clean up.
The actual implementation of the table of pointers approach
can be found in patches 9-11. In case of wacom driver the sad thing
about it is that it requires a bit of macro magic for sanity.
However, in doing so it was discovered that in the wacom driver
there is a 1:1 mapping between the 'driver_data' field and the
product id - therefore patch 12 shows that the lookup can be
simplified as there is no need for using 'driver_data' at all
(it also does not require macro magic) - but it was left in a
separate patch to show the working - happy to squash in v3 if
this would be accepted.
The change also makes the code more portable on architecture
like CHERI [1], where a pointer is replaced with a new primitive
(called the capability) at the architecture level and is twice as
wide as the greatest representable address, ie. for 64 bit address
space capabilities are 128 bits wide (the other 64 bits are used to
store meta-data relating to the 64 bit address). So you can not store
valid pointers inside 'unsigned long' as effectively a different set of
instructions is being generated by the compiler based on the data-type
that was used in C (ie. capabilities have their own set of load/store
that also copy over the meta-data which are orthogonal to the load/store
instructions used for plain integers that would invalidate the meta-data).
There is slightly more detail to this, but the above is enough to
explain the motivation - the proposed changes make the code a bit
better even without considering CHERI at all - as it is more readable
and type-safe.
The series was built and tested under QEMU (boots with relevant
configs set to Y) on arm64. Additionally the operation of the input
sanitizer was tested via the following:
```
modprobe wacom
echo "0x0003 0x056a 0x0001 0x00000" > /sys/bus/hid/drivers/wacom/new_id
echo "0x0003 0x056a 0x0000 0x000A1" > /sys/bus/hid/drivers/wacom/new_id
echo "0x0003 0x056a 0x0000 0x000A2" > /sys/bus/hid/drivers/wacom/new_id
-sh: echo: write error: Invalid argument
modprobe wacom
echo "0x0003 0x056a 0x0001 0x00000" > /sys/bus/hid/drivers/wacom/new_id
echo "0x0003 0x056a 0x0001 0x00001" > /sys/bus/hid/drivers/wacom/new_id
-sh: echo: write error: Invalid argument
echo "0x0003 0x056a 0x0001 0x00010" > /sys/bus/hid/drivers/wacom/new_id
-sh: echo: write error: Invalid argument
```
The 'hid-tmff' and other randomly picked modules were also tested as
above. Furthermore the './hid-wacom.sh' test was run from the user space
and all tests (except the expected to-do's) passed as required.
This series is part of a larger effort led by Uwe [2]
[1] https://cheri-alliance.org/discover-cheri/
[2] https://lore.kernel.org/all/cover.1776429984.git.u.kleine-koenig@baylibre.com/
---
Changes in v2:
- Patches 1-4: No change
- Patches 5-8: Additional signed-off-by as patches were applied.
- Patches 9-12: Rewritten and new.
- Link to v1: https://patch.msgid.link/20260518-mod-devicetable-hid_device_id-v1-0-a08e3989c283@thegoodpenguin.co.uk
To: Jiri Kosina <jikos@kernel.org>
To: Benjamin Tissoires <bentiss@kernel.org>
To: Ping Cheng <ping.cheng@wacom.com>
To: Jason Gerecke <jason.gerecke@wacom.com>
Cc: linux-input@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
Pawel Zalewski (The Capable Hub) (12):
HID: hid-input: use named initializer for 'hid_battery_quirks[]'
HID: hid-quirks: use named initializer in 'hid_quirks[]'
HID: hid-asus: use named initializer for 'asus_devices[]'
HID: i2c-hid-dmi-quirks: use named initializer for 'i2c_hid_elan_flipped_quirks[]'
HID: hid-belkin: clean up usage of 'driver_data'
HID: hid-cypress: clean up usage of 'driver_data'
HID: hid-gfrm: clean up usage of 'driver_data'
HID: hid-ite: clean up usage of 'driver_data'
HID: hid-tmff: clean up usage of 'driver_data'
HID: wacom: cleanup usage of 'driver_data'
HID: hid-core: sanitize user input in 'new_id_store'
HID: wacom: do not use 'driver_data'
drivers/hid/hid-asus.c | 46 ++-
drivers/hid/hid-belkin.c | 5 +-
drivers/hid/hid-core.c | 18 +
drivers/hid/hid-cypress.c | 32 +-
drivers/hid/hid-gfrm.c | 8 +-
drivers/hid/hid-input.c | 38 +-
drivers/hid/hid-ite.c | 9 +-
drivers/hid/hid-quirks.c | 578 ++++++++++++++++++++-----------
drivers/hid/hid-tmff.c | 48 ++-
drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c | 2 +-
drivers/hid/wacom.h | 1 +
drivers/hid/wacom_sys.c | 25 +-
drivers/hid/wacom_wac.c | 194 ++++++++++-
drivers/hid/wacom_wac.h | 5 +
14 files changed, 731 insertions(+), 278 deletions(-)
---
base-commit: c1f7d1aa16a4f3b5d9476bf3716ca6bb8271c910
change-id: 20260427-mod-devicetable-hid_device_id-7f30d877387c
Best regards,
--
Pawel Zalewski (The Capable Hub) <pzalewski@thegoodpenguin.co.uk>
^ permalink raw reply
* [PATCH v2 01/12] HID: hid-input: use named initializer for 'hid_battery_quirks[]'
From: Pawel Zalewski (The Capable Hub) @ 2026-06-10 15:11 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Ping Cheng, Jason Gerecke
Cc: linux-kernel, linux-input, Pawel Zalewski (The Capable Hub)
In-Reply-To: <20260610-mod-devicetable-hid_device_id-v2-0-a1d7473ccd9c@thegoodpenguin.co.uk>
This makes the code a little bit more readable and consistent
with other drivers in the HID subsystem that assign the
'driver_data' field in the 'hid_device_id' struct explicitly.
While touching the 'hid_battery_quirks[]', align the list
terminator entry to use a space between the curly braces for
better matching the layout of the other entries.
It was confirmed that hid-input.o pre/post the patch are equal
using diffscope.
Signed-off-by: Pawel Zalewski (The Capable Hub) <pzalewski@thegoodpenguin.co.uk>
---
drivers/hid/hid-input.c | 38 ++++++++++++++++++++------------------
1 file changed, 20 insertions(+), 18 deletions(-)
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index d73cfa2e73d3..50ee03508806 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -359,49 +359,51 @@ static enum power_supply_property hidinput_battery_props[] = {
static const struct hid_device_id hid_battery_quirks[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
- HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
+ .driver_data = HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
- HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
+ .driver_data = HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
- HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
+ .driver_data = HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
- USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO),
- HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
+ USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO),
+ .driver_data = HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI),
- HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
+ .driver_data = HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_MAGICTRACKPAD),
- HID_BATTERY_QUIRK_IGNORE },
+ .driver_data = HID_BATTERY_QUIRK_IGNORE },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM,
USB_DEVICE_ID_ELECOM_BM084),
- HID_BATTERY_QUIRK_IGNORE },
+ .driver_data = HID_BATTERY_QUIRK_IGNORE },
{ HID_USB_DEVICE(USB_VENDOR_ID_SYMBOL,
USB_DEVICE_ID_SYMBOL_SCANNER_3),
- HID_BATTERY_QUIRK_IGNORE },
+ .driver_data = HID_BATTERY_QUIRK_IGNORE },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD),
- HID_BATTERY_QUIRK_IGNORE },
+ .driver_data = HID_BATTERY_QUIRK_IGNORE },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD),
- HID_BATTERY_QUIRK_IGNORE },
+ .driver_data = HID_BATTERY_QUIRK_IGNORE },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L),
- HID_BATTERY_QUIRK_AVOID_QUERY },
+ .driver_data = HID_BATTERY_QUIRK_AVOID_QUERY },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW),
- HID_BATTERY_QUIRK_AVOID_QUERY },
+ .driver_data = HID_BATTERY_QUIRK_AVOID_QUERY },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW),
- HID_BATTERY_QUIRK_AVOID_QUERY },
+ .driver_data = HID_BATTERY_QUIRK_AVOID_QUERY },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_CHROMEBOOK_TROGDOR_POMPOM),
- HID_BATTERY_QUIRK_AVOID_QUERY },
+ .driver_data = HID_BATTERY_QUIRK_AVOID_QUERY },
/*
* Elan HID touchscreens seem to all report a non present battery,
* set HID_BATTERY_QUIRK_IGNORE for all Elan I2C and USB HID devices.
*/
- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_BATTERY_QUIRK_DYNAMIC },
- { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_BATTERY_QUIRK_DYNAMIC },
- {}
+ { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID),
+ .driver_data = HID_BATTERY_QUIRK_DYNAMIC },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID),
+ .driver_data = HID_BATTERY_QUIRK_DYNAMIC },
+ { }
};
static unsigned find_battery_quirk(struct hid_device *hdev)
--
2.43.0
^ permalink raw reply related
* [PATCH v2 02/12] HID: hid-quirks: use named initializer in 'hid_quirks[]'
From: Pawel Zalewski (The Capable Hub) @ 2026-06-10 15:11 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Ping Cheng, Jason Gerecke
Cc: linux-kernel, linux-input, Pawel Zalewski (The Capable Hub)
In-Reply-To: <20260610-mod-devicetable-hid_device_id-v2-0-a1d7473ccd9c@thegoodpenguin.co.uk>
This makes the code a little bit more readable and consistent
with other drivers in the HID subsystem that assign the
'driver_data' field in the 'hid_device_id' struct explicitly.
While touching the 'hid_quirks[]', modify the terminator entry to use
a space between the curly braces as opposed to a 0 for consistency.
It was confirmed that hid-quirks.o pre/post the patch are equal
using diffscope.
Signed-off-by: Pawel Zalewski (The Capable Hub) <pzalewski@thegoodpenguin.co.uk>
---
drivers/hid/hid-quirks.c | 578 +++++++++++++++++++++++++++++++----------------
1 file changed, 384 insertions(+), 194 deletions(-)
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 57d8efdd9b89..71efca6a03ed 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -25,202 +25,392 @@
*/
static const struct hid_device_id hid_quirks[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_8BITDO, USB_DEVICE_ID_8BITDO_PRO_3), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD), HID_QUIRK_BADPAD },
- { HID_USB_DEVICE(USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR), HID_QUIRK_BADPAD },
- { HID_USB_DEVICE(USB_VENDOR_ID_ADATA_XPG, USB_VENDOR_ID_ADATA_XPG_WL_GAMING_MOUSE), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_ADATA_XPG, USB_VENDOR_ID_ADATA_XPG_WL_GAMING_MOUSE_DONGLE), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016), HID_QUIRK_FULLSPEED_INTERVAL },
- { HID_USB_DEVICE(USB_VENDOR_ID_AIREN, USB_DEVICE_ID_AIREN_SLIMPLUS), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_AKAI_09E8, USB_DEVICE_ID_AKAI_09E8_MIDIMIX), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_AKAI, USB_DEVICE_ID_AKAI_MPKMINI2), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD), HID_QUIRK_BADPAD },
- { HID_USB_DEVICE(USB_VENDOR_ID_AMI, USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS1758), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS682), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS692), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD), HID_QUIRK_BADPAD },
- { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_COMBATSTICK), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FIGHTERSTICK), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_ECLIPSE_YOKE), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_PEDALS), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_THROTTLE), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_COOLER_MASTER, USB_DEVICE_ID_COOLER_MASTER_MICE_DONGLE), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB_RAPIDFIRE), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70RGB), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70RGB_RAPIDFIRE), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70R), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K95RGB), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_M65RGB), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_GLAIVE_RGB), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_STRAFE), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_PRO_WIRELESS_KM5221W), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_2NES2SNES), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_4NES4SNES), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_REDRAGON_SEYMUR2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
- { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER), HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_EDIFIER, USB_DEVICE_ID_EDIFIER_QR30), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH_2968), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_FUTABA, USB_DEVICE_ID_LED_DISPLAY), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_SAT_ADAPTOR), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD), HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_8BITDO, USB_DEVICE_ID_8BITDO_PRO_3),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD),
+ .driver_data = HID_QUIRK_BADPAD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR),
+ .driver_data = HID_QUIRK_BADPAD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ADATA_XPG, USB_VENDOR_ID_ADATA_XPG_WL_GAMING_MOUSE),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ADATA_XPG, USB_VENDOR_ID_ADATA_XPG_WL_GAMING_MOUSE_DONGLE),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016),
+ .driver_data = HID_QUIRK_FULLSPEED_INTERVAL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AIREN, USB_DEVICE_ID_AIREN_SLIMPLUS),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AKAI_09E8, USB_DEVICE_ID_AKAI_09E8_MIDIMIX),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AKAI, USB_DEVICE_ID_AKAI_MPKMINI2),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD),
+ .driver_data = HID_QUIRK_BADPAD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AMI, USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS1758),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS682),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS692),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD),
+ .driver_data = HID_QUIRK_BADPAD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_COMBATSTICK),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FIGHTERSTICK),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_ECLIPSE_YOKE),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_PEDALS),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_THROTTLE),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_COOLER_MASTER, USB_DEVICE_ID_COOLER_MASTER_MICE_DONGLE),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB_RAPIDFIRE),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70RGB),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70RGB_RAPIDFIRE),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70R),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K95RGB),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_M65RGB),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_GLAIVE_RGB),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_STRAFE),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_PIXART_USB_OPTICAL_MOUSE),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_PRO_WIRELESS_KM5221W),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_2NES2SNES),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_4NES4SNES),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_REDRAGON_SEYMUR2),
+ .driver_data = HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER),
+ .driver_data = HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_EDIFIER, USB_DEVICE_ID_EDIFIER_QR30),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH_2968),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_FUTABA, USB_DEVICE_ID_LED_DISPLAY),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_SAT_ADAPTOR),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_GAMEVICE, USB_DEVICE_ID_GAMEVICE_GV186),
- HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+ .driver_data = HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
{ HID_USB_DEVICE(USB_VENDOR_ID_GAMEVICE, USB_DEVICE_ID_GAMEVICE_KISHI),
- HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
- { HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING), HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING), HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING), HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A293), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A), HID_QUIRK_ALWAYS_POLL },
- { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_ELITE_PRESENTER_MOUSE_464A), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0941), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_1f4a), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE_ID2), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M406), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M506), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M406W), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_340), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_M912), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_M508WX), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_M508X), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M406XE), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_T609A), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_ODDOR_HANDBRAKE), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_LEGION_GO_DUAL_DINPUT), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_LEGION_GO2_DUAL_DINPUT), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C01A), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_MCS, USB_DEVICE_ID_MCS_GAMEPADBLOCK), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_MOUSE_0783), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PIXART_MOUSE), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE3_COVER), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_MULTIPLE_1781, USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_NATSU, USB_DEVICE_ID_NATSU_GAMEPAD), HID_QUIRK_BADPAD },
- { HID_USB_DEVICE(USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD), HID_QUIRK_BADPAD },
- { HID_USB_DEVICE(USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_NEXTWINDOW, USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN), HID_QUIRK_MULTI_INPUT},
- { HID_USB_DEVICE(USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_DUOSENSE), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK), HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_1610), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_1640), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_PI_ENGINEERING, USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL), HID_QUIRK_HIDINPUT_FORCE },
- { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_MOUSE_4D22), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_MOUSE_4E2A), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D65), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4E22), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3003), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_REALTEK, USB_DEVICE_ID_REALTEK_READER), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_RETROUSB, USB_DEVICE_ID_RETROUSB_SNES_RETROPAD), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
- { HID_USB_DEVICE(USB_VENDOR_ID_RETROUSB, USB_DEVICE_ID_RETROUSB_SNES_RETROPORT), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
- { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD), HID_QUIRK_BADPAD },
- { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
- { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
- { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_PRO), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
- { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X65), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
- { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD2), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_USB_MOUSE), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS1030_TOUCH), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS817_TOUCH), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS9200_TOUCH), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS_TS), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_HD), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS1), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS2), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_QUAD_HD), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP_V103), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DELL_K12A), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DELL_K15A), HID_QUIRK_NO_INIT_REPORTS },
- { HID_USB_DEVICE(USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD), HID_QUIRK_BADPAD },
- { HID_USB_DEVICE(USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8882), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8883), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWA60), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_WP5540), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_VRS, USB_DEVICE_ID_VRS_R295), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_GROUP_AUDIO), HID_QUIRK_NOGET },
-
- { 0 }
+ .driver_data = HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING),
+ .driver_data = HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING),
+ .driver_data = HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING),
+ .driver_data = HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A293),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_ELITE_PRESENTER_MOUSE_464A),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0941),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_1f4a),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE_ID2),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M406),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M506),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M406W),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_340),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_M912),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_M508WX),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_M508X),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M406XE),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_T609A),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_ODDOR_HANDBRAKE),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_LEGION_GO_DUAL_DINPUT),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_LEGION_GO2_DUAL_DINPUT),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C01A),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MCS, USB_DEVICE_ID_MCS_GAMEPADBLOCK),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_MOUSE_0783),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PIXART_MOUSE),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE3_COVER),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MULTIPLE_1781, USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NATSU, USB_DEVICE_ID_NATSU_GAMEPAD),
+ .driver_data = HID_QUIRK_BADPAD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD),
+ .driver_data = HID_QUIRK_BADPAD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NEXTWINDOW, USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN),
+ .driver_data = HID_QUIRK_MULTI_INPUT},
+ { HID_USB_DEVICE(USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_DUOSENSE),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK),
+ .driver_data = HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_1610),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_1640),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PI_ENGINEERING,
+ USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL),
+ .driver_data = HID_QUIRK_HIDINPUT_FORCE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_MOUSE_4D22),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_MOUSE_4E2A),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D65),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4E22),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3003),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_REALTEK, USB_DEVICE_ID_REALTEK_READER),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_RETROUSB, USB_DEVICE_ID_RETROUSB_SNES_RETROPAD),
+ .driver_data = HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_RETROUSB, USB_DEVICE_ID_RETROUSB_SNES_RETROPORT),
+ .driver_data = HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD),
+ .driver_data = HID_QUIRK_BADPAD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52),
+ .driver_data = HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_2),
+ .driver_data = HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_PRO),
+ .driver_data = HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X65),
+ .driver_data = HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD2),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_USB_MOUSE),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS1030_TOUCH),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS817_TOUCH),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS9200_TOUCH),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS_TS),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_HD),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS1),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS2),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_QUAD_HD),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP_V103),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DELL_K12A),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DELL_K15A),
+ .driver_data = HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD),
+ .driver_data = HID_QUIRK_BADPAD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8882),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8883),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD),
+ .driver_data = HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWA60),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_WP5540),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_VRS, USB_DEVICE_ID_VRS_R295),
+ .driver_data = HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS),
+ .driver_data = HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD),
+ .driver_data = HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_GROUP_AUDIO),
+ .driver_data = HID_QUIRK_NOGET },
+ { }
};
/*
--
2.43.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