drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c | 262 +++++++++++++++++++++++ 1 file changed, 262 insertions(+)
On some Samsung laptops (750XFG) with Haptick 5288 touchpads over
designware i2c bus, the supplied HID descriptors and report descriptors
can become partially corrupted under some circumstances.
In particular, this can happen if the touchpad attempts to generate
input reports while we try to retrieve the HID descriptors or the Report
descriptor. This can be reproduced by repeatedly reloading the relevant
kernel modules (i2c_hid_acpi and i2c_hid) and attempting to use the
touchpad at the same time. The usage of a script is suggested for the
reproduction of the issue.
Since it is a race condition, one of the symptom of the issue is that it
will eventually resolve itself after repeated rebooting.
There is currently no way of handling malformed HID descriptors and
report descriptors and per the I2C HID spec, it is not necessary for the
HOST to re-retrieve a report descriptor under such circumstances.
Instead of having a system to deal with malformed HID descriptors and
report descriptors, we simply hard-code them.
A related issues on another samsung laptop (750XED) have been reported
on the archlinux forum.
Links: https://bbs.archlinux.org/viewtopic.php?id=289627
Signed-off-by: Kwok Kin Ming <kenkinming2002@gmail.com>
---
Other fixes were attempted at the issue but none of them work. In
summary, they included:
1: Remove I2C_HID_QUIRK_NO_IRQ_AFTER_RESET quirk.
2: Do not send power on command to the device before reset.
3: Detect if any interrupts have fired when we are reading HID
descriptors and report descriptors in a racy manner.
Other suggestions are welcomed.
The patch triggers style check warnings due to long line but it should
sitll be readable. The comments could be removed if necessary.
Other samsung laptops affected by the issue could also be added if it
can be confirmed.
drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c | 262 +++++++++++++++++++++++
1 file changed, 262 insertions(+)
diff --git a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
index 210f17c3a0be..befec7a0c2fd 100644
--- a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
+++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
@@ -290,6 +290,260 @@ static const struct i2c_hid_desc_override sipodev_desc = {
.i2c_name = "SYNA3602:00"
};
+static const struct i2c_hid_desc_override hantick5288_desc = {
+ .i2c_hid_desc_buffer = (uint8_t [])
+ {0x1e, 0x00, /* Length of descriptor */
+ 0x00, 0x01, /* Version of descriptor */
+ 0xe2, 0x01, /* Length of report descriptor */
+ 0x21, 0x00, /* Location of report descriptor */
+ 0x24, 0x00, /* Location of input report */
+ 0x1f, 0x00, /* Max input report length */
+ 0x25, 0x00, /* Location of output report */
+ 0x11, 0x00, /* Max output report length */
+ 0x22, 0x00, /* Location of command register */
+ 0x23, 0x00, /* Location of data register */
+ 0x11, 0x09, /* Vendor ID */
+ 0x88, 0x52, /* Product ID */
+ 0x06, 0x00, /* Version ID */
+ 0x00, 0x00, 0x00, 0x00, /* Reserved */
+ },
+ .hid_report_desc = (uint8_t [])
+ {0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
+ 0x09, 0x02, /* Usage (Mouse) */
+ 0xA1, 0x01, /* Collection (Application) */
+ 0x85, 0x01, /* Report ID (1) */
+ 0x09, 0x01, /* Usage (Pointer) */
+ 0xA1, 0x00, /* Collection (Physical) */
+ 0x05, 0x09, /* Usage Page (Button) */
+ 0x19, 0x01, /* Usage Minimum (0x01) */
+ 0x29, 0x02, /* Usage Maximum (0x02) */
+ 0x25, 0x01, /* Logical Maximum (1) */
+ 0x75, 0x01, /* Report Size (1) */
+ 0x95, 0x02, /* Report Count (2) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x95, 0x06, /* Report Count (6) */
+ 0x81, 0x01, /* Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
+ 0x09, 0x30, /* Usage (X) */
+ 0x09, 0x31, /* Usage (Y) */
+ 0x15, 0x81, /* Logical Minimum (-127) */
+ 0x25, 0x7F, /* Logical Maximum (127) */
+ 0x75, 0x08, /* Report Size (8) */
+ 0x95, 0x02, /* Report Count (2) */
+ 0x81, 0x06, /* Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) */
+ 0xC0, /* End Collection */
+ 0xC0, /* End Collection */
+ 0x05, 0x0D, /* Usage Page (Digitizer) */
+ 0x09, 0x05, /* Usage (Touch Pad) */
+ 0xA1, 0x01, /* Collection (Application) */
+ 0x95, 0x01, /* Report Count (1) */
+ 0x55, 0x0E, /* Unit Exponent (-2) */
+ 0x65, 0x11, /* Unit (System: SI Linear, Length: Centimeter) */
+ 0x15, 0x00, /* Logical Minimum (0) */
+ 0x85, 0x04, /* Report ID (4) */
+ 0x05, 0x0D, /* Usage Page (Digitizer) */
+ 0x09, 0x22, /* Usage (Finger) */
+ 0xA1, 0x02, /* Collection (Logical) */
+ 0x25, 0x01, /* Logical Maximum (1) */
+ 0x75, 0x01, /* Report Size (1) */
+ 0x09, 0x47, /* Usage (0x47) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x09, 0x42, /* Usage (Tip Switch) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x75, 0x06, /* Report Size (6) */
+ 0x25, 0x05, /* Logical Maximum (5) */
+ 0x09, 0x51, /* Usage (0x51) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
+ 0x75, 0x10, /* Report Size (16) */
+ 0x26, 0x44, 0x0A, /* Logical Maximum (2628) */
+ 0x46, 0xB0, 0x04, /* Physical Maximum (1200) */
+ 0x09, 0x30, /* Usage (X) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x26, 0x34, 0x05, /* Logical Maximum (1332) */
+ 0x46, 0x38, 0x03, /* Physical Maximum (824) */
+ 0x09, 0x31, /* Usage (Y) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0xC0, /* End Collection */
+ 0x05, 0x0D, /* Usage Page (Digitizer) */
+ 0x09, 0x22, /* Usage (Finger) */
+ 0xA1, 0x02, /* Collection (Logical) */
+ 0x25, 0x01, /* Logical Maximum (1) */
+ 0x75, 0x01, /* Report Size (1) */
+ 0x09, 0x47, /* Usage (0x47) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x09, 0x42, /* Usage (Tip Switch) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x75, 0x06, /* Report Size (6) */
+ 0x25, 0x05, /* Logical Maximum (5) */
+ 0x09, 0x51, /* Usage (0x51) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
+ 0x75, 0x10, /* Report Size (16) */
+ 0x26, 0x44, 0x0A, /* Logical Maximum (2628) */
+ 0x46, 0xB0, 0x04, /* Physical Maximum (1200) */
+ 0x09, 0x30, /* Usage (X) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x26, 0x34, 0x05, /* Logical Maximum (1332) */
+ 0x46, 0x38, 0x03, /* Physical Maximum (824) */
+ 0x09, 0x31, /* Usage (Y) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0xC0, /* End Collection */
+ 0x05, 0x0D, /* Usage Page (Digitizer) */
+ 0x09, 0x22, /* Usage (Finger) */
+ 0xA1, 0x02, /* Collection (Logical) */
+ 0x25, 0x01, /* Logical Maximum (1) */
+ 0x75, 0x01, /* Report Size (1) */
+ 0x09, 0x47, /* Usage (0x47) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x09, 0x42, /* Usage (Tip Switch) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x75, 0x06, /* Report Size (6) */
+ 0x25, 0x05, /* Logical Maximum (5) */
+ 0x09, 0x51, /* Usage (0x51) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
+ 0x75, 0x10, /* Report Size (16) */
+ 0x26, 0x44, 0x0A, /* Logical Maximum (2628) */
+ 0x46, 0xB0, 0x04, /* Physical Maximum (1200) */
+ 0x09, 0x30, /* Usage (X) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x26, 0x34, 0x05, /* Logical Maximum (1332) */
+ 0x46, 0x38, 0x03, /* Physical Maximum (824) */
+ 0x09, 0x31, /* Usage (Y) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0xC0, /* End Collection */
+ 0x05, 0x0D, /* Usage Page (Digitizer) */
+ 0x09, 0x22, /* Usage (Finger) */
+ 0xA1, 0x02, /* Collection (Logical) */
+ 0x25, 0x01, /* Logical Maximum (1) */
+ 0x75, 0x01, /* Report Size (1) */
+ 0x09, 0x47, /* Usage (0x47) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x09, 0x42, /* Usage (Tip Switch) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x75, 0x06, /* Report Size (6) */
+ 0x25, 0x05, /* Logical Maximum (5) */
+ 0x09, 0x51, /* Usage (0x51) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
+ 0x75, 0x10, /* Report Size (16) */
+ 0x26, 0x44, 0x0A, /* Logical Maximum (2628) */
+ 0x46, 0xB0, 0x04, /* Physical Maximum (1200) */
+ 0x09, 0x30, /* Usage (X) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x26, 0x34, 0x05, /* Logical Maximum (1332) */
+ 0x46, 0x38, 0x03, /* Physical Maximum (824) */
+ 0x09, 0x31, /* Usage (Y) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0xC0, /* End Collection */
+ 0x05, 0x0D, /* Usage Page (Digitizer) */
+ 0x55, 0x0C, /* Unit Exponent (-4) */
+ 0x66, 0x01, 0x10, /* Unit (System: SI Linear, Time: Seconds) */
+ 0x47, 0xFF, 0xFF, 0x00, 0x00, /* Physical Maximum (65534) */
+ 0x27, 0xFF, 0xFF, 0x00, 0x00, /* Logical Maximum (65534) */
+ 0x09, 0x56, /* Usage (0x56) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x25, 0x05, /* Logical Maximum (5) */
+ 0x09, 0x54, /* Usage (0x54) */
+ 0x75, 0x04, /* Report Size (4) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x05, 0x09, /* Usage Page (Button) */
+ 0x09, 0x01, /* Usage (0x01) */
+ 0x25, 0x01, /* Logical Maximum (1) */
+ 0x25, 0x01, /* Logical Maximum (1) */
+ 0x75, 0x01, /* Report Size (1) */
+ 0x95, 0x01, /* Report Count (1) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x06, 0x01, 0xFF, /* Usage Page (Vendor Defined 0xFF01) */
+ 0x95, 0x01, /* Report Count (1) */
+ 0x75, 0x03, /* Report Size (3) */
+ 0x09, 0x41, /* Usage (0x41) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x09, 0x42, /* Usage (0x42) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x75, 0x01, /* Report Size (1) */
+ 0x09, 0x40, /* Usage (0x40) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x75, 0x24, /* Report Size (36) */
+ 0x81, 0x03, /* Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x05, 0x0D, /* Usage Page (Digitizer) */
+ 0x85, 0x02, /* Report ID (2) */
+ 0x25, 0x0F, /* Logical Maximum (15) */
+ 0x75, 0x04, /* Report Size (4) */
+ 0x09, 0x55, /* Usage (0x55) */
+ 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
+ 0x09, 0x59, /* Usage (0x59) */
+ 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
+ 0x85, 0x06, /* Report ID (6) */
+ 0x06, 0x00, 0xFF, /* Usage Page (Vendor Defined 0xFF00) */
+ 0x09, 0xC5, /* Usage (0xC5) */
+ 0x26, 0xFF, 0x00, /* Logical Maximum (255) */
+ 0x75, 0x08, /* Report Size (8) */
+ 0x96, 0x00, 0x01, /* Report Count (256) */
+ 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
+ 0xC0, /* End Collection */
+ 0x05, 0x0D, /* Usage Page (Digitizer) */
+ 0x09, 0x0E, /* Usage (0x0E) */
+ 0xA1, 0x01, /* Collection (Application) */
+ 0x85, 0x03, /* Report ID (3) */
+ 0x09, 0x22, /* Usage (Finger) */
+ 0xA1, 0x02, /* Collection (Logical) */
+ 0x09, 0x52, /* Usage (0x52) */
+ 0x25, 0x0A, /* Logical Maximum (10) */
+ 0x95, 0x01, /* Report Count (1) */
+ 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
+ 0xC0, /* End Collection */
+ 0x09, 0x22, /* Usage (Finger) */
+ 0xA1, 0x00, /* Collection (Physical) */
+ 0x85, 0x05, /* Report ID (5) */
+ 0x25, 0x01, /* Logical Maximum (1) */
+ 0x75, 0x01, /* Report Size (1) */
+ 0x09, 0x57, /* Usage (0x57) */
+ 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
+ 0x09, 0x58, /* Usage (0x58) */
+ 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
+ 0x75, 0x06, /* Report Size (6) */
+ 0xB1, 0x03, /* Feature (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
+ 0xC0, /* End Collection */
+ 0xC0, /* End Collection */
+ 0x06, 0x01, 0xFF, /* Usage Page (Vendor Defined 0xFF01) */
+ 0x09, 0x02, /* Usage (0x02) */
+ 0xA1, 0x01, /* Collection (Application) */
+ 0x75, 0x08, /* Report Size (8) */
+ 0x85, 0x0D, /* Report ID (13) */
+ 0x09, 0xD5, /* Usage (0xD5) */
+ 0x95, 0x18, /* Report Count (24) */
+ 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
+ 0x85, 0x0C, /* Report ID (12) */
+ 0x09, 0xD6, /* Usage (0xD6) */
+ 0x96, 0x91, 0x00, /* Report Count (145) */
+ 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
+ 0x09, 0x30, /* Usage (0x30) */
+ 0x85, 0x07, /* Report ID (7) */
+ 0x95, 0x07, /* Report Count (7) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x09, 0x70, /* Usage (0x70) */
+ 0x85, 0x0E, /* Report ID (14) */
+ 0x95, 0xC9, /* Report Count (-55) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x09, 0x71, /* Usage (0x71) */
+ 0x85, 0x08, /* Report ID (8) */
+ 0x95, 0x97, /* Report Count (-105) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x09, 0x72, /* Usage (0x72) */
+ 0x85, 0x09, /* Report ID (9) */
+ 0x95, 0xFD, /* Report Count (-3) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x09, 0x73, /* Usage (0x73) */
+ 0x85, 0x0A, /* Report ID (10) */
+ 0x95, 0x20, /* Report Count (32) */
+ 0x91, 0x02, /* Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
+ 0xC0, /* End Collection */
+ },
+ .hid_report_desc_size = 482,
+ .i2c_name = "SPPT2600:00"
+};
static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
{
@@ -415,6 +669,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
},
.driver_data = (void *)&sipodev_desc
},
+ {
+ .ident = "Samsung 750XFG",
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "750XFG"),
+ },
+ .driver_data = (void *)&hantick5288_desc
+ },
{ } /* Terminate list */
};
--
2.52.0
On Dec 26 2025, Kwok Kin Ming wrote:
> On some Samsung laptops (750XFG) with Haptick 5288 touchpads over
> designware i2c bus, the supplied HID descriptors and report descriptors
> can become partially corrupted under some circumstances.
>
> In particular, this can happen if the touchpad attempts to generate
> input reports while we try to retrieve the HID descriptors or the Report
> descriptor. This can be reproduced by repeatedly reloading the relevant
> kernel modules (i2c_hid_acpi and i2c_hid) and attempting to use the
> touchpad at the same time. The usage of a script is suggested for the
> reproduction of the issue.
>
> Since it is a race condition, one of the symptom of the issue is that it
> will eventually resolve itself after repeated rebooting.
>
> There is currently no way of handling malformed HID descriptors and
> report descriptors and per the I2C HID spec, it is not necessary for the
> HOST to re-retrieve a report descriptor under such circumstances.
> Instead of having a system to deal with malformed HID descriptors and
> report descriptors, we simply hard-code them.
>
> A related issues on another samsung laptop (750XED) have been reported
> on the archlinux forum.
>
> Links: https://bbs.archlinux.org/viewtopic.php?id=289627
> Signed-off-by: Kwok Kin Ming <kenkinming2002@gmail.com>
> ---
> Other fixes were attempted at the issue but none of them work. In
> summary, they included:
>
> 1: Remove I2C_HID_QUIRK_NO_IRQ_AFTER_RESET quirk.
> 2: Do not send power on command to the device before reset.
> 3: Detect if any interrupts have fired when we are reading HID
> descriptors and report descriptors in a racy manner.
>
> Other suggestions are welcomed.
I'm really not found of this patch. AFAICT, from the archlinux bug, the
device is presenting itself to HID, and we "just" have a truncated
report descriptor. I'm not sure if you can trigger that bug at the HID
descriptor level, without scripting it (so in real case scenarios).
The simplest "solution" following what you are doing is making a HID-BPF
fixup which checks whether the device properly sent the report
descriptor and if not puts the one here. The HID-BPF has the advantage
of being compatible with hid-multitouch so you won't get into troubles
with a separate module.
The proper solution should be to detect those situations. But you
mentioned above that the detection of the interrupts wasn't working.
Could you tell us more?
I'd very much not have a report descriptor written in stone in the
kernel when the device returns a correct one. Especially not at the
i2c-hid level (I would be happier with a HID module, but this might
break mutltiouch functionality).
Cheers,
Benjamin
>
> The patch triggers style check warnings due to long line but it should
> sitll be readable. The comments could be removed if necessary.
>
> Other samsung laptops affected by the issue could also be added if it
> can be confirmed.
>
> drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c | 262 +++++++++++++++++++++++
> 1 file changed, 262 insertions(+)
>
> diff --git a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
> index 210f17c3a0be..befec7a0c2fd 100644
> --- a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
> +++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
> @@ -290,6 +290,260 @@ static const struct i2c_hid_desc_override sipodev_desc = {
> .i2c_name = "SYNA3602:00"
> };
>
> +static const struct i2c_hid_desc_override hantick5288_desc = {
> + .i2c_hid_desc_buffer = (uint8_t [])
> + {0x1e, 0x00, /* Length of descriptor */
> + 0x00, 0x01, /* Version of descriptor */
> + 0xe2, 0x01, /* Length of report descriptor */
> + 0x21, 0x00, /* Location of report descriptor */
> + 0x24, 0x00, /* Location of input report */
> + 0x1f, 0x00, /* Max input report length */
> + 0x25, 0x00, /* Location of output report */
> + 0x11, 0x00, /* Max output report length */
> + 0x22, 0x00, /* Location of command register */
> + 0x23, 0x00, /* Location of data register */
> + 0x11, 0x09, /* Vendor ID */
> + 0x88, 0x52, /* Product ID */
> + 0x06, 0x00, /* Version ID */
> + 0x00, 0x00, 0x00, 0x00, /* Reserved */
> + },
> + .hid_report_desc = (uint8_t [])
> + {0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
> + 0x09, 0x02, /* Usage (Mouse) */
> + 0xA1, 0x01, /* Collection (Application) */
> + 0x85, 0x01, /* Report ID (1) */
> + 0x09, 0x01, /* Usage (Pointer) */
> + 0xA1, 0x00, /* Collection (Physical) */
> + 0x05, 0x09, /* Usage Page (Button) */
> + 0x19, 0x01, /* Usage Minimum (0x01) */
> + 0x29, 0x02, /* Usage Maximum (0x02) */
> + 0x25, 0x01, /* Logical Maximum (1) */
> + 0x75, 0x01, /* Report Size (1) */
> + 0x95, 0x02, /* Report Count (2) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x95, 0x06, /* Report Count (6) */
> + 0x81, 0x01, /* Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
> + 0x09, 0x30, /* Usage (X) */
> + 0x09, 0x31, /* Usage (Y) */
> + 0x15, 0x81, /* Logical Minimum (-127) */
> + 0x25, 0x7F, /* Logical Maximum (127) */
> + 0x75, 0x08, /* Report Size (8) */
> + 0x95, 0x02, /* Report Count (2) */
> + 0x81, 0x06, /* Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) */
> + 0xC0, /* End Collection */
> + 0xC0, /* End Collection */
> + 0x05, 0x0D, /* Usage Page (Digitizer) */
> + 0x09, 0x05, /* Usage (Touch Pad) */
> + 0xA1, 0x01, /* Collection (Application) */
> + 0x95, 0x01, /* Report Count (1) */
> + 0x55, 0x0E, /* Unit Exponent (-2) */
> + 0x65, 0x11, /* Unit (System: SI Linear, Length: Centimeter) */
> + 0x15, 0x00, /* Logical Minimum (0) */
> + 0x85, 0x04, /* Report ID (4) */
> + 0x05, 0x0D, /* Usage Page (Digitizer) */
> + 0x09, 0x22, /* Usage (Finger) */
> + 0xA1, 0x02, /* Collection (Logical) */
> + 0x25, 0x01, /* Logical Maximum (1) */
> + 0x75, 0x01, /* Report Size (1) */
> + 0x09, 0x47, /* Usage (0x47) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x09, 0x42, /* Usage (Tip Switch) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x75, 0x06, /* Report Size (6) */
> + 0x25, 0x05, /* Logical Maximum (5) */
> + 0x09, 0x51, /* Usage (0x51) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
> + 0x75, 0x10, /* Report Size (16) */
> + 0x26, 0x44, 0x0A, /* Logical Maximum (2628) */
> + 0x46, 0xB0, 0x04, /* Physical Maximum (1200) */
> + 0x09, 0x30, /* Usage (X) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x26, 0x34, 0x05, /* Logical Maximum (1332) */
> + 0x46, 0x38, 0x03, /* Physical Maximum (824) */
> + 0x09, 0x31, /* Usage (Y) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0xC0, /* End Collection */
> + 0x05, 0x0D, /* Usage Page (Digitizer) */
> + 0x09, 0x22, /* Usage (Finger) */
> + 0xA1, 0x02, /* Collection (Logical) */
> + 0x25, 0x01, /* Logical Maximum (1) */
> + 0x75, 0x01, /* Report Size (1) */
> + 0x09, 0x47, /* Usage (0x47) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x09, 0x42, /* Usage (Tip Switch) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x75, 0x06, /* Report Size (6) */
> + 0x25, 0x05, /* Logical Maximum (5) */
> + 0x09, 0x51, /* Usage (0x51) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
> + 0x75, 0x10, /* Report Size (16) */
> + 0x26, 0x44, 0x0A, /* Logical Maximum (2628) */
> + 0x46, 0xB0, 0x04, /* Physical Maximum (1200) */
> + 0x09, 0x30, /* Usage (X) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x26, 0x34, 0x05, /* Logical Maximum (1332) */
> + 0x46, 0x38, 0x03, /* Physical Maximum (824) */
> + 0x09, 0x31, /* Usage (Y) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0xC0, /* End Collection */
> + 0x05, 0x0D, /* Usage Page (Digitizer) */
> + 0x09, 0x22, /* Usage (Finger) */
> + 0xA1, 0x02, /* Collection (Logical) */
> + 0x25, 0x01, /* Logical Maximum (1) */
> + 0x75, 0x01, /* Report Size (1) */
> + 0x09, 0x47, /* Usage (0x47) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x09, 0x42, /* Usage (Tip Switch) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x75, 0x06, /* Report Size (6) */
> + 0x25, 0x05, /* Logical Maximum (5) */
> + 0x09, 0x51, /* Usage (0x51) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
> + 0x75, 0x10, /* Report Size (16) */
> + 0x26, 0x44, 0x0A, /* Logical Maximum (2628) */
> + 0x46, 0xB0, 0x04, /* Physical Maximum (1200) */
> + 0x09, 0x30, /* Usage (X) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x26, 0x34, 0x05, /* Logical Maximum (1332) */
> + 0x46, 0x38, 0x03, /* Physical Maximum (824) */
> + 0x09, 0x31, /* Usage (Y) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0xC0, /* End Collection */
> + 0x05, 0x0D, /* Usage Page (Digitizer) */
> + 0x09, 0x22, /* Usage (Finger) */
> + 0xA1, 0x02, /* Collection (Logical) */
> + 0x25, 0x01, /* Logical Maximum (1) */
> + 0x75, 0x01, /* Report Size (1) */
> + 0x09, 0x47, /* Usage (0x47) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x09, 0x42, /* Usage (Tip Switch) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x75, 0x06, /* Report Size (6) */
> + 0x25, 0x05, /* Logical Maximum (5) */
> + 0x09, 0x51, /* Usage (0x51) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
> + 0x75, 0x10, /* Report Size (16) */
> + 0x26, 0x44, 0x0A, /* Logical Maximum (2628) */
> + 0x46, 0xB0, 0x04, /* Physical Maximum (1200) */
> + 0x09, 0x30, /* Usage (X) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x26, 0x34, 0x05, /* Logical Maximum (1332) */
> + 0x46, 0x38, 0x03, /* Physical Maximum (824) */
> + 0x09, 0x31, /* Usage (Y) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0xC0, /* End Collection */
> + 0x05, 0x0D, /* Usage Page (Digitizer) */
> + 0x55, 0x0C, /* Unit Exponent (-4) */
> + 0x66, 0x01, 0x10, /* Unit (System: SI Linear, Time: Seconds) */
> + 0x47, 0xFF, 0xFF, 0x00, 0x00, /* Physical Maximum (65534) */
> + 0x27, 0xFF, 0xFF, 0x00, 0x00, /* Logical Maximum (65534) */
> + 0x09, 0x56, /* Usage (0x56) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x25, 0x05, /* Logical Maximum (5) */
> + 0x09, 0x54, /* Usage (0x54) */
> + 0x75, 0x04, /* Report Size (4) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x05, 0x09, /* Usage Page (Button) */
> + 0x09, 0x01, /* Usage (0x01) */
> + 0x25, 0x01, /* Logical Maximum (1) */
> + 0x25, 0x01, /* Logical Maximum (1) */
> + 0x75, 0x01, /* Report Size (1) */
> + 0x95, 0x01, /* Report Count (1) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x06, 0x01, 0xFF, /* Usage Page (Vendor Defined 0xFF01) */
> + 0x95, 0x01, /* Report Count (1) */
> + 0x75, 0x03, /* Report Size (3) */
> + 0x09, 0x41, /* Usage (0x41) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x09, 0x42, /* Usage (0x42) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x75, 0x01, /* Report Size (1) */
> + 0x09, 0x40, /* Usage (0x40) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x75, 0x24, /* Report Size (36) */
> + 0x81, 0x03, /* Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x05, 0x0D, /* Usage Page (Digitizer) */
> + 0x85, 0x02, /* Report ID (2) */
> + 0x25, 0x0F, /* Logical Maximum (15) */
> + 0x75, 0x04, /* Report Size (4) */
> + 0x09, 0x55, /* Usage (0x55) */
> + 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
> + 0x09, 0x59, /* Usage (0x59) */
> + 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
> + 0x85, 0x06, /* Report ID (6) */
> + 0x06, 0x00, 0xFF, /* Usage Page (Vendor Defined 0xFF00) */
> + 0x09, 0xC5, /* Usage (0xC5) */
> + 0x26, 0xFF, 0x00, /* Logical Maximum (255) */
> + 0x75, 0x08, /* Report Size (8) */
> + 0x96, 0x00, 0x01, /* Report Count (256) */
> + 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
> + 0xC0, /* End Collection */
> + 0x05, 0x0D, /* Usage Page (Digitizer) */
> + 0x09, 0x0E, /* Usage (0x0E) */
> + 0xA1, 0x01, /* Collection (Application) */
> + 0x85, 0x03, /* Report ID (3) */
> + 0x09, 0x22, /* Usage (Finger) */
> + 0xA1, 0x02, /* Collection (Logical) */
> + 0x09, 0x52, /* Usage (0x52) */
> + 0x25, 0x0A, /* Logical Maximum (10) */
> + 0x95, 0x01, /* Report Count (1) */
> + 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
> + 0xC0, /* End Collection */
> + 0x09, 0x22, /* Usage (Finger) */
> + 0xA1, 0x00, /* Collection (Physical) */
> + 0x85, 0x05, /* Report ID (5) */
> + 0x25, 0x01, /* Logical Maximum (1) */
> + 0x75, 0x01, /* Report Size (1) */
> + 0x09, 0x57, /* Usage (0x57) */
> + 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
> + 0x09, 0x58, /* Usage (0x58) */
> + 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
> + 0x75, 0x06, /* Report Size (6) */
> + 0xB1, 0x03, /* Feature (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
> + 0xC0, /* End Collection */
> + 0xC0, /* End Collection */
> + 0x06, 0x01, 0xFF, /* Usage Page (Vendor Defined 0xFF01) */
> + 0x09, 0x02, /* Usage (0x02) */
> + 0xA1, 0x01, /* Collection (Application) */
> + 0x75, 0x08, /* Report Size (8) */
> + 0x85, 0x0D, /* Report ID (13) */
> + 0x09, 0xD5, /* Usage (0xD5) */
> + 0x95, 0x18, /* Report Count (24) */
> + 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
> + 0x85, 0x0C, /* Report ID (12) */
> + 0x09, 0xD6, /* Usage (0xD6) */
> + 0x96, 0x91, 0x00, /* Report Count (145) */
> + 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
> + 0x09, 0x30, /* Usage (0x30) */
> + 0x85, 0x07, /* Report ID (7) */
> + 0x95, 0x07, /* Report Count (7) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x09, 0x70, /* Usage (0x70) */
> + 0x85, 0x0E, /* Report ID (14) */
> + 0x95, 0xC9, /* Report Count (-55) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x09, 0x71, /* Usage (0x71) */
> + 0x85, 0x08, /* Report ID (8) */
> + 0x95, 0x97, /* Report Count (-105) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x09, 0x72, /* Usage (0x72) */
> + 0x85, 0x09, /* Report ID (9) */
> + 0x95, 0xFD, /* Report Count (-3) */
> + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
> + 0x09, 0x73, /* Usage (0x73) */
> + 0x85, 0x0A, /* Report ID (10) */
> + 0x95, 0x20, /* Report Count (32) */
> + 0x91, 0x02, /* Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
> + 0xC0, /* End Collection */
> + },
> + .hid_report_desc_size = 482,
> + .i2c_name = "SPPT2600:00"
> +};
>
> static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
> {
> @@ -415,6 +669,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
> },
> .driver_data = (void *)&sipodev_desc
> },
> + {
> + .ident = "Samsung 750XFG",
> + .matches = {
> + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
> + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "750XFG"),
> + },
> + .driver_data = (void *)&hantick5288_desc
> + },
> { } /* Terminate list */
> };
>
> --
> 2.52.0
>
On Wed, Jan 07, 2026 at 06:45:45PM +0100, Benjamin Tissoires wrote:
> I'm really not found of this patch.
Me neither and would be happy with a cleaner solution.
> I'm really not found of this patch. AFAICT, from the archlinux bug, the
> device is presenting itself to HID, and we "just" have a truncated
> report descriptor. I'm not sure if you can trigger that bug at the HID
> descriptor level, without scripting it (so in real case scenarios).
At least I can trigger it, because I have an full disk encryption setup
and my theory is that I might unintentionally touch the trackpad while
typing the password. That would explain how I come across the bug.
> The simplest "solution" following what you are doing is making a HID-BPF
> fixup which checks whether the device properly sent the report
> descriptor and if not puts the one here. The HID-BPF has the advantage
> of being compatible with hid-multitouch so you won't get into troubles
> with a separate module.
This might be a solution but would that not only fix it just for me? I
would have to look into how to do HID-BPF fixup.
> The proper solution should be to detect those situations. But you
> mentioned above that the detection of the interrupts wasn't working.
> Could you tell us more?
This is the diff that is lying in my filesystem. I do not see a nice way
to do it without any race. The call to msleep(1) is just a best effort
to make sure any interrupt that have fired would be seen but there is no
guarantee. Now that I think about it, there might be some memory
visiblity issue with multicore but I am not sure.
diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
index f9b9dd0d9bb8..161eb8301763 100644
--- a/drivers/hid/i2c-hid/i2c-hid-core.c
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -66,6 +66,7 @@
/* flags */
#define I2C_HID_STARTED 0
#define I2C_HID_RESET_PENDING 1
+#define I2C_HID_IRQ_HANDLED 2
#define I2C_HID_PWR_ON 0x00
#define I2C_HID_PWR_SLEEP 0x01
@@ -219,7 +220,25 @@ static int i2c_hid_xfer(struct i2c_hid *ihid,
n++;
}
+ // On some devices, what we received will may become corrupted if we
+ // are also supposed to receive input reports asynchronously at the
+ // same time, persumably because the hardware buffer in the device is
+ // shared.
+ clear_bit(I2C_HID_IRQ_HANDLED, &ihid->flags);
ret = i2c_transfer(client->adapter, msgs, n);
+ if(recv_len != 0)
+ while(ret == n)
+ {
+ msleep(1);
+ if(!test_and_clear_bit(I2C_HID_IRQ_HANDLED, &ihid->flags))
+ break;
+
+ i2c_hid_dbg(ihid, "%s: interrupted transfer: res=%*ph\n",
+ __func__, recv_len, recv_buf);
+
+ clear_bit(I2C_HID_IRQ_HANDLED, &ihid->flags);
+ ret = i2c_transfer(client->adapter, msgs, n);
+ }
if (ret != n)
return ret < 0 ? ret : -EIO;
@@ -585,6 +604,7 @@ static irqreturn_t i2c_hid_irq(int irq, void *dev_id)
{
struct i2c_hid *ihid = dev_id;
+ set_bit(I2C_HID_IRQ_HANDLED, &ihid->flags);
i2c_hid_get_input(ihid);
return IRQ_HANDLED;
Simply disable and enabling interrupt would not work since we would be
just masking the interrupt on the cpu side. In fact, that is another fix
that I have attempted:
diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
index 63f46a2e5..28ba480e4 100644
--- a/drivers/hid/i2c-hid/i2c-hid-core.c
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -219,7 +219,9 @@ static int i2c_hid_xfer(struct i2c_hid *ihid,
n++;
}
+ disable_irq(client->irq);
ret = i2c_transfer(client->adapter, msgs, n);
+ enable_irq(client->irq);
if (ret != n)
return ret < 0 ? ret : -EIO;
> I'd very much not have a report descriptor written in stone in the
> kernel when the device returns a correct one. Especially not at the
> i2c-hid level (I would be happier with a HID module, but this might
> break mutltiouch functionality).
Same, which is why I am asking for suggestion to alternative fixes.
Yours sincerly,
Ken Kwok
On Thu, Jan 08, 2026 at 02:14:29AM +0800, kenkinming2002@gmail.com wrote: > > The simplest "solution" following what you are doing is making a HID-BPF > > fixup which checks whether the device properly sent the report > > descriptor and if not puts the one here. The HID-BPF has the advantage > > of being compatible with hid-multitouch so you won't get into troubles > > with a separate module. > This might be a solution but would that not only fix it just for me? I > would have to look into how to do HID-BPF fixup. An update, I have looked into HID-BPF but it seems to me that we can only fix up the HID report descriptor and not the HID descriptor (this descriptor is specific to i2c-hid device) but from my testing both descriptor can be corrupted. Specifically, I see messages such as: i2c_hid_acpi i2c-SPPT2600:00: unexpected HID descriptor bcdVersion (0x0209) i2c_hid_acpi i2c-SPPT2600:00: Failed to fetch the HID Descriptor appearing in my log. For now, I am just going to just apply the patch locally for myself till a better solution come up. I have finally clean up the pile of garbage I have while investigating the problem and put up a proper git repository with relevant script and logs at https://github.com/kenkinming2002/samsung-i2c-hid-bug-repro.git. Huge thanks to Benjamin and anyway who might have stumbled across this patch for your time. Yours sincerly, Ken Kwok
On Jan 13 2026, kenkinming2002@gmail.com wrote: > On Thu, Jan 08, 2026 at 02:14:29AM +0800, kenkinming2002@gmail.com wrote: > > > The simplest "solution" following what you are doing is making a HID-BPF > > > fixup which checks whether the device properly sent the report > > > descriptor and if not puts the one here. The HID-BPF has the advantage > > > of being compatible with hid-multitouch so you won't get into troubles > > > with a separate module. > > This might be a solution but would that not only fix it just for me? I > > would have to look into how to do HID-BPF fixup. > An update, I have looked into HID-BPF but it seems to me that we can > only fix up the HID report descriptor and not the HID descriptor (this > descriptor is specific to i2c-hid device) but from my testing both > descriptor can be corrupted. Specifically, I see messages such as: > > i2c_hid_acpi i2c-SPPT2600:00: unexpected HID descriptor bcdVersion (0x0209) > i2c_hid_acpi i2c-SPPT2600:00: Failed to fetch the HID Descriptor > > appearing in my log. > > For now, I am just going to just apply the patch locally for myself till > a better solution come up. On second thoughts, maybe we can have the HID descriptor dmi quirk in the kernel only. This way, the device should be presented to HID-BPF and the HID stack, and if there is something wrong in the descriptor, this shouldn't fail dramatically. The HID descriptor is something specific to i2c-hid, so it's fine "fixing" it there. The report descriptor can be fixed later on I think. Cheers, Benjamin > > I have finally clean up the pile of garbage I have while investigating > the problem and put up a proper git repository with relevant script and > logs at https://github.com/kenkinming2002/samsung-i2c-hid-bug-repro.git. > > Huge thanks to Benjamin and anyway who might have stumbled across this > patch for your time. > > Yours sincerly, > Ken Kwok
On Tue, Jan 13, 2026 at 04:00:35PM +0100, Benjamin Tissoires wrote: > On second thoughts, maybe we can have the HID descriptor dmi quirk in > the kernel only. This way, the device should be presented to HID-BPF and > the HID stack, and if there is something wrong in the descriptor, this > shouldn't fail dramatically. Unfortunately, this fail even more badly. The logs are consistent and short enough that I will include one of them verbatim here but they are also available on same github repository under logs https://github.com/kenkinming2002/samsung-i2c-hid-bug-repro. > [ 1976.296726] i2c_hid:i2c_hid_core_probe: i2c-hid-core.c: HID probe called for i2c 0x2c > [ 1976.296960] i2c_hid:i2c_hid_fetch_hid_descriptor: i2c_hid_acpi i2c-SPPT2600:00: Using a HID descriptor override > [ 1976.296965] i2c_hid:i2c_hid_fetch_hid_descriptor: i2c_hid_acpi i2c-SPPT2600:00: HID Descriptor: 1e 00 00 01 e2 01 21 00 24 00 1f 00 25 00 11 00 22 00 23 00 11 09 88 52 06 00 00 00 00 00 > [ 1976.296969] i2c_hid:i2c_hid_init_irq: i2c_hid_acpi i2c-SPPT2600:00: Requesting IRQ: 152 > [ 1976.297217] i2c_hid:i2c_hid_parse: i2c_hid_acpi i2c-SPPT2600:00: entering i2c_hid_parse > [ 1976.297220] i2c_hid:i2c_hid_start_hwreset: i2c_hid_acpi i2c-SPPT2600:00: i2c_hid_start_hwreset > [ 1976.297222] i2c_hid:i2c_hid_set_power: i2c_hid_acpi i2c-SPPT2600:00: i2c_hid_set_power > [ 1976.297224] i2c_hid:i2c_hid_xfer: i2c_hid_acpi i2c-SPPT2600:00: i2c_hid_xfer: cmd=22 00 00 08 > [ 1976.357910] i2c_hid:i2c_hid_xfer: i2c_hid_acpi i2c-SPPT2600:00: i2c_hid_xfer: cmd=22 00 00 01 > [ 1976.358600] i2c_hid:i2c_hid_finish_hwreset: i2c_hid_acpi i2c-SPPT2600:00: i2c_hid_finish_hwreset: waiting... > [ 1976.461915] i2c_hid:i2c_hid_finish_hwreset: i2c_hid_acpi i2c-SPPT2600:00: i2c_hid_finish_hwreset: finished. > [ 1976.461925] i2c_hid:i2c_hid_set_power: i2c_hid_acpi i2c-SPPT2600:00: i2c_hid_set_power > [ 1976.461929] i2c_hid:i2c_hid_xfer: i2c_hid_acpi i2c-SPPT2600:00: i2c_hid_xfer: cmd=22 00 00 08 > [ 1976.523047] i2c_hid:i2c_hid_parse: i2c_hid_acpi i2c-SPPT2600:00: asking HID report descriptor > [ 1976.523057] i2c_hid:i2c_hid_xfer: i2c_hid_acpi i2c-SPPT2600:00: i2c_hid_xfer: cmd=21 00 > [ 1976.523723] i2c_hid:i2c_hid_parse: i2c_hid_acpi i2c-SPPT2600:00: Report Descriptor: > [ 1976.523954] hid-generic 0018:0911:5288.00FC: item fetching failed at offset 0/0 > [ 1976.523970] hid-generic 0018:0911:5288.00FC: probe with driver hid-generic failed with error -22 It seems that the touchpad really does not like us only retrieving the hid descriptor and not the report descriptor and end up returning an empty report descriptor. We know that this is the device returning an empty report descriptor and not me botching up my hid-bpf driver by looking at the third line from the bottom which comes from the i2c-hid driver: > [ 1976.523723] i2c_hid:i2c_hid_parse: i2c_hid_acpi i2c-SPPT2600:00: Report Descriptor: This would imply that for an user who do not have hid-bpf report descriptor fix, he would change from having a touchpad that works most of the time to never which is a horrible regression to have. Judging by the fact that I seem to be the only person affected that is on this mailing list and my full disk encryption setup which kinda triggered this issue might not be the most common, I am okay with keeping this as a local patch for myself. On a side note, I have written and compiled a hid-bpf driver but not yet figure out how to it to load even after installing it with udev-hid-bpf. There is probably something blatantly obvious I overlooked. That is besides the point anyway since there is no point in a hid-bpf driver if the above issue is not fixed. I also do not know how to fill the vid and pid field for HID_DEVICE from HID_BPF_CONFIG but that seems to me to be only for some introspection purposes that is not used in runtime. Thanks. Yours sincerely, Ken Kwok
© 2016 - 2026 Red Hat, Inc.