[PATCH] HID: multitouch: ignore unstable pen serial on ELAN 04f3:2dd2

Lucas Martins via B4 Relay posted 1 patch 4 weeks ago
drivers/hid/hid-multitouch.c | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
[PATCH] HID: multitouch: ignore unstable pen serial on ELAN 04f3:2dd2
Posted by Lucas Martins via B4 Relay 4 weeks ago
From: Lucas Martins <snowniak@gmail.com>

The ELAN 04f3:2dd2 touchscreen declares its stylus serial number as a
64-bit field. It initially sends zero and populates the field roughly
200 ms after tip-down while the stroke remains active.

The generic HID input path truncates fields wider than 32 bits. On this
device the delayed update is exposed as an MSC_SERIAL change from 1 to
255. Tablet consumers interpret that as a tool replacement, terminate
the current stroke, and leave subsequent motion visible only as hover.

Replace the serial field in this device's report descriptor with two
32-bit constant fields. This preserves the 64-bit report layout while
preventing both the mid-stroke MSC_SERIAL update and the
hid_field_extract() width warning.

Tested on an ASUS CX5400FM (Google Copano). Before the fix, a raw HID
serial change occurred during every stroke and evdev emitted MSC_SERIAL
values 1 and 255. After the fix, evdev emitted no MSC_SERIAL events while
X, Y, pressure, tip, hover, and touchscreen input continued to work.

Signed-off-by: Lucas Martins <snowniak@gmail.com>
---
 drivers/hid/hid-multitouch.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 2c41bacab..874d74085 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -1718,6 +1718,48 @@ static void mt_yogabook9_fixup(struct hid_device *hdev, __u8 *rdesc,
 static const __u8 *mt_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 			     unsigned int *size)
 {
+	/*
+	 * ELAN 04f3:2dd2 delays populating its 64-bit Transducer Serial
+	 * Number until after tip-down. The generic HID input path can only
+	 * extract 32-bit values and exports the resulting mid-contact change
+	 * through MSC_SERIAL, causing userspace to switch tablet tools while a
+	 * stroke is active.
+	 *
+	 * Keep the field's full 64 bits in the report layout, but describe them
+	 * as two 32-bit constant values. This prevents both MSC_SERIAL events
+	 * and hid_field_extract(..., 64), without moving any later fields.
+	 */
+	if (hdev->vendor == USB_VENDOR_ID_ELAN && hdev->product == 0x2dd2) {
+		static const u8 elan_bad_serial[] = {
+			0x09, 0x5b,       /* Usage (Transducer Serial Number) */
+			0x25, 0xff,       /* Logical Maximum (255) */
+			0x75, 0x40,       /* Report Size (64) */
+			0x81, 0x02,       /* Input (Data,Var,Abs) */
+		};
+		static const u8 elan_ignored_serial[] = {
+			0x09, 0x00,       /* Usage (Undefined) */
+			0x75, 0x20,       /* Report Size (32) */
+			0x95, 0x02,       /* Report Count (2) */
+			0x81, 0x03,       /* Input (Const,Var,Abs) */
+		};
+		unsigned int i;
+
+		for (i = 0; i + sizeof(elan_bad_serial) <= *size; i++) {
+			if (!memcmp(&rdesc[i], elan_bad_serial,
+				    sizeof(elan_bad_serial))) {
+				memcpy(&rdesc[i], elan_ignored_serial,
+				       sizeof(elan_ignored_serial));
+				hid_info(hdev,
+					 "ignoring unstable 64-bit pen serial number\n");
+				break;
+			}
+		}
+
+		if (i + sizeof(elan_bad_serial) > *size)
+			hid_warn(hdev,
+				 "expected pen serial descriptor pattern not found\n");
+	}
+
 	if (hdev->vendor == I2C_VENDOR_ID_GOODIX &&
 	    (hdev->product == I2C_DEVICE_ID_GOODIX_01E8 ||
 	     hdev->product == I2C_DEVICE_ID_GOODIX_01E9)) {

---
base-commit: a93f3bf4e1d60777b1659b812c9e818cfc53b449
change-id: 20260829-elan-2dd2-pen-serial-fix-149fb47a993e

Best regards,
--  
Lucas Martins <snowniak@gmail.com>