e336be
From 9ee3e06610fdb8a601cde59c92089fb6c1deb4aa Mon Sep 17 00:00:00 2001
e336be
From: Julian Sax <jsbc@gmx.de>
e336be
Date: Wed, 19 Sep 2018 11:46:23 +0200
e336be
Subject: [PATCH] HID: i2c-hid: override HID descriptors for certain devices
e336be
e336be
A particular touchpad (SIPODEV SP1064) refuses to supply the HID
e336be
descriptors. This patch provides the framework for overriding these
e336be
descriptors based on DMI data. It also includes the descriptors for
e336be
said touchpad, which were extracted by listening to the traffic of the
e336be
windows filter driver, as well as the DMI data for the laptops known
e336be
to use this device.
e336be
e336be
Relevant Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1526312
e336be
e336be
Cc: Hans de Goede <hdegoede@redhat.com>
e336be
Reported-and-tested-by: ahormann@gmx.net
e336be
Reported-and-tested-by: Bruno Jesus <bruno.fl.jesus@gmail.com>
e336be
Reported-and-tested-by: Dietrich <enaut.w@googlemail.com>
e336be
Reported-and-tested-by: kloxdami@yahoo.com
e336be
Signed-off-by: Julian Sax <jsbc@gmx.de>
e336be
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
e336be
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
e336be
---
e336be
 drivers/hid/i2c-hid/Makefile                  |   3 +
e336be
 .../hid/i2c-hid/{i2c-hid.c => i2c-hid-core.c} |  60 ++-
e336be
 drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c      | 376 ++++++++++++++++++
e336be
 drivers/hid/i2c-hid/i2c-hid.h                 |  20 +
e336be
 4 files changed, 439 insertions(+), 20 deletions(-)
e336be
 rename drivers/hid/i2c-hid/{i2c-hid.c => i2c-hid-core.c} (96%)
e336be
 create mode 100644 drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
e336be
 create mode 100644 drivers/hid/i2c-hid/i2c-hid.h
e336be
e336be
diff --git a/drivers/hid/i2c-hid/Makefile b/drivers/hid/i2c-hid/Makefile
e336be
index 832d8f9aaba2..099e1ce2f234 100644
e336be
--- a/drivers/hid/i2c-hid/Makefile
e336be
+++ b/drivers/hid/i2c-hid/Makefile
e336be
@@ -3,3 +3,6 @@
e336be
 #
e336be
 
e336be
 obj-$(CONFIG_I2C_HID)				+= i2c-hid.o
e336be
+
e336be
+i2c-hid-objs					=  i2c-hid-core.o
e336be
+i2c-hid-$(CONFIG_DMI)				+= i2c-hid-dmi-quirks.o
e336be
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid-core.c
e336be
similarity index 96%
e336be
rename from drivers/hid/i2c-hid/i2c-hid.c
e336be
rename to drivers/hid/i2c-hid/i2c-hid-core.c
e336be
index f3076659361a..823c63ad08b1 100644
e336be
--- a/drivers/hid/i2c-hid/i2c-hid.c
e336be
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
e336be
@@ -43,6 +43,7 @@
e336be
 #include <linux/platform_data/i2c-hid.h>
e336be
 
e336be
 #include "../hid-ids.h"
e336be
+#include "i2c-hid.h"
e336be
 
e336be
 /* quirks to control the device */
e336be
 #define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV	BIT(0)
e336be
@@ -669,6 +670,7 @@ static int i2c_hid_parse(struct hid_device *hid)
e336be
 	char *rdesc;
e336be
 	int ret;
e336be
 	int tries = 3;
e336be
+	char *use_override;
e336be
 
e336be
 	i2c_hid_dbg(ihid, "entering %s\n", __func__);
e336be
 
e336be
@@ -687,26 +689,37 @@ static int i2c_hid_parse(struct hid_device *hid)
e336be
 	if (ret)
e336be
 		return ret;
e336be
 
e336be
-	rdesc = kzalloc(rsize, GFP_KERNEL);
e336be
+	use_override = i2c_hid_get_dmi_hid_report_desc_override(client->name,
e336be
+								&rsize);
e336be
 
e336be
-	if (!rdesc) {
e336be
-		dbg_hid("couldn't allocate rdesc memory\n");
e336be
-		return -ENOMEM;
e336be
-	}
e336be
-
e336be
-	i2c_hid_dbg(ihid, "asking HID report descriptor\n");
e336be
-
e336be
-	ret = i2c_hid_command(client, &hid_report_descr_cmd, rdesc, rsize);
e336be
-	if (ret) {
e336be
-		hid_err(hid, "reading report descriptor failed\n");
e336be
-		kfree(rdesc);
e336be
-		return -EIO;
e336be
+	if (use_override) {
e336be
+		rdesc = use_override;
e336be
+		i2c_hid_dbg(ihid, "Using a HID report descriptor override\n");
e336be
+	} else {
e336be
+		rdesc = kzalloc(rsize, GFP_KERNEL);
e336be
+
e336be
+		if (!rdesc) {
e336be
+			dbg_hid("couldn't allocate rdesc memory\n");
e336be
+			return -ENOMEM;
e336be
+		}
e336be
+
e336be
+		i2c_hid_dbg(ihid, "asking HID report descriptor\n");
e336be
+
e336be
+		ret = i2c_hid_command(client, &hid_report_descr_cmd,
e336be
+				      rdesc, rsize);
e336be
+		if (ret) {
e336be
+			hid_err(hid, "reading report descriptor failed\n");
e336be
+			kfree(rdesc);
e336be
+			return -EIO;
e336be
+		}
e336be
 	}
e336be
 
e336be
 	i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc);
e336be
 
e336be
 	ret = hid_parse_report(hid, rdesc, rsize);
e336be
-	kfree(rdesc);
e336be
+	if (!use_override)
e336be
+		kfree(rdesc);
e336be
+
e336be
 	if (ret) {
e336be
 		dbg_hid("parsing report descriptor failed\n");
e336be
 		return ret;
e336be
@@ -833,12 +846,19 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
e336be
 	int ret;
e336be
 
e336be
 	/* i2c hid fetch using a fixed descriptor size (30 bytes) */
e336be
-	i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
e336be
-	ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer,
e336be
-				sizeof(struct i2c_hid_desc));
e336be
-	if (ret) {
e336be
-		dev_err(&client->dev, "hid_descr_cmd failed\n");
e336be
-		return -ENODEV;
e336be
+	if (i2c_hid_get_dmi_i2c_hid_desc_override(client->name)) {
e336be
+		i2c_hid_dbg(ihid, "Using a HID descriptor override\n");
e336be
+		ihid->hdesc =
e336be
+			*i2c_hid_get_dmi_i2c_hid_desc_override(client->name);
e336be
+	} else {
e336be
+		i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
e336be
+		ret = i2c_hid_command(client, &hid_descr_cmd,
e336be
+				      ihid->hdesc_buffer,
e336be
+				      sizeof(struct i2c_hid_desc));
e336be
+		if (ret) {
e336be
+			dev_err(&client->dev, "hid_descr_cmd failed\n");
e336be
+			return -ENODEV;
e336be
+		}
e336be
 	}
e336be
 
e336be
 	/* Validate the length of HID descriptor, the 4 first bytes:
e336be
diff --git a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
e336be
new file mode 100644
e336be
index 000000000000..1d645c9ab417
e336be
--- /dev/null
e336be
+++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
e336be
@@ -0,0 +1,385 @@
e336be
+// SPDX-License-Identifier: GPL-2.0+
e336be
+
e336be
+/*
e336be
+ * Quirks for I2C-HID devices that do not supply proper descriptors
e336be
+ *
e336be
+ * Copyright (c) 2018 Julian Sax <jsbc@gmx.de>
e336be
+ *
e336be
+ */
e336be
+
e336be
+#include <linux/types.h>
e336be
+#include <linux/dmi.h>
e336be
+#include <linux/mod_devicetable.h>
e336be
+
e336be
+#include "i2c-hid.h"
e336be
+
e336be
+
e336be
+struct i2c_hid_desc_override {
e336be
+	union {
e336be
+		struct i2c_hid_desc *i2c_hid_desc;
e336be
+		uint8_t             *i2c_hid_desc_buffer;
e336be
+	};
e336be
+	uint8_t              *hid_report_desc;
e336be
+	unsigned int          hid_report_desc_size;
e336be
+	uint8_t              *i2c_name;
e336be
+};
e336be
+
e336be
+
e336be
+/*
e336be
+ * descriptors for the SIPODEV SP1064 touchpad
e336be
+ *
e336be
+ * This device does not supply any descriptors and on windows a filter
e336be
+ * driver operates between the i2c-hid layer and the device and injects
e336be
+ * these descriptors when the device is prompted. The descriptors were
e336be
+ * extracted by listening to the i2c-hid traffic that occurs between the
e336be
+ * windows filter driver and the windows i2c-hid driver.
e336be
+ */
e336be
+
e336be
+static const struct i2c_hid_desc_override sipodev_desc = {
e336be
+	.i2c_hid_desc_buffer = (uint8_t [])
e336be
+	{0x1e, 0x00,                  /* Length of descriptor                 */
e336be
+	 0x00, 0x01,                  /* Version of descriptor                */
e336be
+	 0xdb, 0x01,                  /* Length of report descriptor          */
e336be
+	 0x21, 0x00,                  /* Location of report descriptor        */
e336be
+	 0x24, 0x00,                  /* Location of input report             */
e336be
+	 0x1b, 0x00,                  /* Max input report length              */
e336be
+	 0x25, 0x00,                  /* Location of output report            */
e336be
+	 0x11, 0x00,                  /* Max output report length             */
e336be
+	 0x22, 0x00,                  /* Location of command register         */
e336be
+	 0x23, 0x00,                  /* Location of data register            */
e336be
+	 0x11, 0x09,                  /* Vendor ID                            */
e336be
+	 0x88, 0x52,                  /* Product ID                           */
e336be
+	 0x06, 0x00,                  /* Version ID                           */
e336be
+	 0x00, 0x00, 0x00, 0x00       /* Reserved                             */
e336be
+	},
e336be
+
e336be
+	.hid_report_desc = (uint8_t [])
e336be
+	{0x05, 0x01,                  /* Usage Page (Desktop),                */
e336be
+	 0x09, 0x02,                  /* Usage (Mouse),                       */
e336be
+	 0xA1, 0x01,                  /* Collection (Application),            */
e336be
+	 0x85, 0x01,                  /*     Report ID (1),                   */
e336be
+	 0x09, 0x01,                  /*     Usage (Pointer),                 */
e336be
+	 0xA1, 0x00,                  /*     Collection (Physical),           */
e336be
+	 0x05, 0x09,                  /*         Usage Page (Button),         */
e336be
+	 0x19, 0x01,                  /*         Usage Minimum (01h),         */
e336be
+	 0x29, 0x02,                  /*         Usage Maximum (02h),         */
e336be
+	 0x25, 0x01,                  /*         Logical Maximum (1),         */
e336be
+	 0x75, 0x01,                  /*         Report Size (1),             */
e336be
+	 0x95, 0x02,                  /*         Report Count (2),            */
e336be
+	 0x81, 0x02,                  /*         Input (Variable),            */
e336be
+	 0x95, 0x06,                  /*         Report Count (6),            */
e336be
+	 0x81, 0x01,                  /*         Input (Constant),            */
e336be
+	 0x05, 0x01,                  /*         Usage Page (Desktop),        */
e336be
+	 0x09, 0x30,                  /*         Usage (X),                   */
e336be
+	 0x09, 0x31,                  /*         Usage (Y),                   */
e336be
+	 0x15, 0x81,                  /*         Logical Minimum (-127),      */
e336be
+	 0x25, 0x7F,                  /*         Logical Maximum (127),       */
e336be
+	 0x75, 0x08,                  /*         Report Size (8),             */
e336be
+	 0x95, 0x02,                  /*         Report Count (2),            */
e336be
+	 0x81, 0x06,                  /*         Input (Variable, Relative),  */
e336be
+	 0xC0,                        /*     End Collection,                  */
e336be
+	 0xC0,                        /* End Collection,                      */
e336be
+	 0x05, 0x0D,                  /* Usage Page (Digitizer),              */
e336be
+	 0x09, 0x05,                  /* Usage (Touchpad),                    */
e336be
+	 0xA1, 0x01,                  /* Collection (Application),            */
e336be
+	 0x85, 0x04,                  /*     Report ID (4),                   */
e336be
+	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
e336be
+	 0x09, 0x22,                  /*     Usage (Finger),                  */
e336be
+	 0xA1, 0x02,                  /*     Collection (Logical),            */
e336be
+	 0x15, 0x00,                  /*         Logical Minimum (0),         */
e336be
+	 0x25, 0x01,                  /*         Logical Maximum (1),         */
e336be
+	 0x09, 0x47,                  /*         Usage (Touch Valid),         */
e336be
+	 0x09, 0x42,                  /*         Usage (Tip Switch),          */
e336be
+	 0x95, 0x02,                  /*         Report Count (2),            */
e336be
+	 0x75, 0x01,                  /*         Report Size (1),             */
e336be
+	 0x81, 0x02,                  /*         Input (Variable),            */
e336be
+	 0x95, 0x01,                  /*         Report Count (1),            */
e336be
+	 0x75, 0x03,                  /*         Report Size (3),             */
e336be
+	 0x25, 0x05,                  /*         Logical Maximum (5),         */
e336be
+	 0x09, 0x51,                  /*         Usage (Contact Identifier),  */
e336be
+	 0x81, 0x02,                  /*         Input (Variable),            */
e336be
+	 0x75, 0x01,                  /*         Report Size (1),             */
e336be
+	 0x95, 0x03,                  /*         Report Count (3),            */
e336be
+	 0x81, 0x03,                  /*         Input (Constant, Variable),  */
e336be
+	 0x05, 0x01,                  /*         Usage Page (Desktop),        */
e336be
+	 0x26, 0x44, 0x0A,            /*         Logical Maximum (2628),      */
e336be
+	 0x75, 0x10,                  /*         Report Size (16),            */
e336be
+	 0x55, 0x0E,                  /*         Unit Exponent (14),          */
e336be
+	 0x65, 0x11,                  /*         Unit (Centimeter),           */
e336be
+	 0x09, 0x30,                  /*         Usage (X),                   */
e336be
+	 0x46, 0x1A, 0x04,            /*         Physical Maximum (1050),     */
e336be
+	 0x95, 0x01,                  /*         Report Count (1),            */
e336be
+	 0x81, 0x02,                  /*         Input (Variable),            */
e336be
+	 0x46, 0xBC, 0x02,            /*         Physical Maximum (700),      */
e336be
+	 0x26, 0x34, 0x05,            /*         Logical Maximum (1332),      */
e336be
+	 0x09, 0x31,                  /*         Usage (Y),                   */
e336be
+	 0x81, 0x02,                  /*         Input (Variable),            */
e336be
+	 0xC0,                        /*     End Collection,                  */
e336be
+	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
e336be
+	 0x09, 0x22,                  /*     Usage (Finger),                  */
e336be
+	 0xA1, 0x02,                  /*     Collection (Logical),            */
e336be
+	 0x25, 0x01,                  /*         Logical Maximum (1),         */
e336be
+	 0x09, 0x47,                  /*         Usage (Touch Valid),         */
e336be
+	 0x09, 0x42,                  /*         Usage (Tip Switch),          */
e336be
+	 0x95, 0x02,                  /*         Report Count (2),            */
e336be
+	 0x75, 0x01,                  /*         Report Size (1),             */
e336be
+	 0x81, 0x02,                  /*         Input (Variable),            */
e336be
+	 0x95, 0x01,                  /*         Report Count (1),            */
e336be
+	 0x75, 0x03,                  /*         Report Size (3),             */
e336be
+	 0x25, 0x05,                  /*         Logical Maximum (5),         */
e336be
+	 0x09, 0x51,                  /*         Usage (Contact Identifier),  */
e336be
+	 0x81, 0x02,                  /*         Input (Variable),            */
e336be
+	 0x75, 0x01,                  /*         Report Size (1),             */
e336be
+	 0x95, 0x03,                  /*         Report Count (3),            */
e336be
+	 0x81, 0x03,                  /*         Input (Constant, Variable),  */
e336be
+	 0x05, 0x01,                  /*         Usage Page (Desktop),        */
e336be
+	 0x26, 0x44, 0x0A,            /*         Logical Maximum (2628),      */
e336be
+	 0x75, 0x10,                  /*         Report Size (16),            */
e336be
+	 0x09, 0x30,                  /*         Usage (X),                   */
e336be
+	 0x46, 0x1A, 0x04,            /*         Physical Maximum (1050),     */
e336be
+	 0x95, 0x01,                  /*         Report Count (1),            */
e336be
+	 0x81, 0x02,                  /*         Input (Variable),            */
e336be
+	 0x46, 0xBC, 0x02,            /*         Physical Maximum (700),      */
e336be
+	 0x26, 0x34, 0x05,            /*         Logical Maximum (1332),      */
e336be
+	 0x09, 0x31,                  /*         Usage (Y),                   */
e336be
+	 0x81, 0x02,                  /*         Input (Variable),            */
e336be
+	 0xC0,                        /*     End Collection,                  */
e336be
+	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
e336be
+	 0x09, 0x22,                  /*     Usage (Finger),                  */
e336be
+	 0xA1, 0x02,                  /*     Collection (Logical),            */
e336be
+	 0x25, 0x01,                  /*         Logical Maximum (1),         */
e336be
+	 0x09, 0x47,                  /*         Usage (Touch Valid),         */
e336be
+	 0x09, 0x42,                  /*         Usage (Tip Switch),          */
e336be
+	 0x95, 0x02,                  /*         Report Count (2),            */
e336be
+	 0x75, 0x01,                  /*         Report Size (1),             */
e336be
+	 0x81, 0x02,                  /*         Input (Variable),            */
e336be
+	 0x95, 0x01,                  /*         Report Count (1),            */
e336be
+	 0x75, 0x03,                  /*         Report Size (3),             */
e336be
+	 0x25, 0x05,                  /*         Logical Maximum (5),         */
e336be
+	 0x09, 0x51,                  /*         Usage (Contact Identifier),  */
e336be
+	 0x81, 0x02,                  /*         Input (Variable),            */
e336be
+	 0x75, 0x01,                  /*         Report Size (1),             */
e336be
+	 0x95, 0x03,                  /*         Report Count (3),            */
e336be
+	 0x81, 0x03,                  /*         Input (Constant, Variable),  */
e336be
+	 0x05, 0x01,                  /*         Usage Page (Desktop),        */
e336be
+	 0x26, 0x44, 0x0A,            /*         Logical Maximum (2628),      */
e336be
+	 0x75, 0x10,                  /*         Report Size (16),            */
e336be
+	 0x09, 0x30,                  /*         Usage (X),                   */
e336be
+	 0x46, 0x1A, 0x04,            /*         Physical Maximum (1050),     */
e336be
+	 0x95, 0x01,                  /*         Report Count (1),            */
e336be
+	 0x81, 0x02,                  /*         Input (Variable),            */
e336be
+	 0x46, 0xBC, 0x02,            /*         Physical Maximum (700),      */
e336be
+	 0x26, 0x34, 0x05,            /*         Logical Maximum (1332),      */
e336be
+	 0x09, 0x31,                  /*         Usage (Y),                   */
e336be
+	 0x81, 0x02,                  /*         Input (Variable),            */
e336be
+	 0xC0,                        /*     End Collection,                  */
e336be
+	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
e336be
+	 0x09, 0x22,                  /*     Usage (Finger),                  */
e336be
+	 0xA1, 0x02,                  /*     Collection (Logical),            */
e336be
+	 0x25, 0x01,                  /*         Logical Maximum (1),         */
e336be
+	 0x09, 0x47,                  /*         Usage (Touch Valid),         */
e336be
+	 0x09, 0x42,                  /*         Usage (Tip Switch),          */
e336be
+	 0x95, 0x02,                  /*         Report Count (2),            */
e336be
+	 0x75, 0x01,                  /*         Report Size (1),             */
e336be
+	 0x81, 0x02,                  /*         Input (Variable),            */
e336be
+	 0x95, 0x01,                  /*         Report Count (1),            */
e336be
+	 0x75, 0x03,                  /*         Report Size (3),             */
e336be
+	 0x25, 0x05,                  /*         Logical Maximum (5),         */
e336be
+	 0x09, 0x51,                  /*         Usage (Contact Identifier),  */
e336be
+	 0x81, 0x02,                  /*         Input (Variable),            */
e336be
+	 0x75, 0x01,                  /*         Report Size (1),             */
e336be
+	 0x95, 0x03,                  /*         Report Count (3),            */
e336be
+	 0x81, 0x03,                  /*         Input (Constant, Variable),  */
e336be
+	 0x05, 0x01,                  /*         Usage Page (Desktop),        */
e336be
+	 0x26, 0x44, 0x0A,            /*         Logical Maximum (2628),      */
e336be
+	 0x75, 0x10,                  /*         Report Size (16),            */
e336be
+	 0x09, 0x30,                  /*         Usage (X),                   */
e336be
+	 0x46, 0x1A, 0x04,            /*         Physical Maximum (1050),     */
e336be
+	 0x95, 0x01,                  /*         Report Count (1),            */
e336be
+	 0x81, 0x02,                  /*         Input (Variable),            */
e336be
+	 0x46, 0xBC, 0x02,            /*         Physical Maximum (700),      */
e336be
+	 0x26, 0x34, 0x05,            /*         Logical Maximum (1332),      */
e336be
+	 0x09, 0x31,                  /*         Usage (Y),                   */
e336be
+	 0x81, 0x02,                  /*         Input (Variable),            */
e336be
+	 0xC0,                        /*     End Collection,                  */
e336be
+	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
e336be
+	 0x55, 0x0C,                  /*     Unit Exponent (12),              */
e336be
+	 0x66, 0x01, 0x10,            /*     Unit (Seconds),                  */
e336be
+	 0x47, 0xFF, 0xFF, 0x00, 0x00,/*     Physical Maximum (65535),        */
e336be
+	 0x27, 0xFF, 0xFF, 0x00, 0x00,/*     Logical Maximum (65535),         */
e336be
+	 0x75, 0x10,                  /*     Report Size (16),                */
e336be
+	 0x95, 0x01,                  /*     Report Count (1),                */
e336be
+	 0x09, 0x56,                  /*     Usage (Scan Time),               */
e336be
+	 0x81, 0x02,                  /*     Input (Variable),                */
e336be
+	 0x09, 0x54,                  /*     Usage (Contact Count),           */
e336be
+	 0x25, 0x7F,                  /*     Logical Maximum (127),           */
e336be
+	 0x75, 0x08,                  /*     Report Size (8),                 */
e336be
+	 0x81, 0x02,                  /*     Input (Variable),                */
e336be
+	 0x05, 0x09,                  /*     Usage Page (Button),             */
e336be
+	 0x09, 0x01,                  /*     Usage (01h),                     */
e336be
+	 0x25, 0x01,                  /*     Logical Maximum (1),             */
e336be
+	 0x75, 0x01,                  /*     Report Size (1),                 */
e336be
+	 0x95, 0x01,                  /*     Report Count (1),                */
e336be
+	 0x81, 0x02,                  /*     Input (Variable),                */
e336be
+	 0x95, 0x07,                  /*     Report Count (7),                */
e336be
+	 0x81, 0x03,                  /*     Input (Constant, Variable),      */
e336be
+	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
e336be
+	 0x85, 0x02,                  /*     Report ID (2),                   */
e336be
+	 0x09, 0x55,                  /*     Usage (Contact Count Maximum),   */
e336be
+	 0x09, 0x59,                  /*     Usage (59h),                     */
e336be
+	 0x75, 0x04,                  /*     Report Size (4),                 */
e336be
+	 0x95, 0x02,                  /*     Report Count (2),                */
e336be
+	 0x25, 0x0F,                  /*     Logical Maximum (15),            */
e336be
+	 0xB1, 0x02,                  /*     Feature (Variable),              */
e336be
+	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
e336be
+	 0x85, 0x07,                  /*     Report ID (7),                   */
e336be
+	 0x09, 0x60,                  /*     Usage (60h),                     */
e336be
+	 0x75, 0x01,                  /*     Report Size (1),                 */
e336be
+	 0x95, 0x01,                  /*     Report Count (1),                */
e336be
+	 0x25, 0x01,                  /*     Logical Maximum (1),             */
e336be
+	 0xB1, 0x02,                  /*     Feature (Variable),              */
e336be
+	 0x95, 0x07,                  /*     Report Count (7),                */
e336be
+	 0xB1, 0x03,                  /*     Feature (Constant, Variable),    */
e336be
+	 0x85, 0x06,                  /*     Report ID (6),                   */
e336be
+	 0x06, 0x00, 0xFF,            /*     Usage Page (FF00h),              */
e336be
+	 0x09, 0xC5,                  /*     Usage (C5h),                     */
e336be
+	 0x26, 0xFF, 0x00,            /*     Logical Maximum (255),           */
e336be
+	 0x75, 0x08,                  /*     Report Size (8),                 */
e336be
+	 0x96, 0x00, 0x01,            /*     Report Count (256),              */
e336be
+	 0xB1, 0x02,                  /*     Feature (Variable),              */
e336be
+	 0xC0,                        /* End Collection,                      */
e336be
+	 0x06, 0x00, 0xFF,            /* Usage Page (FF00h),                  */
e336be
+	 0x09, 0x01,                  /* Usage (01h),                         */
e336be
+	 0xA1, 0x01,                  /* Collection (Application),            */
e336be
+	 0x85, 0x0D,                  /*     Report ID (13),                  */
e336be
+	 0x26, 0xFF, 0x00,            /*     Logical Maximum (255),           */
e336be
+	 0x19, 0x01,                  /*     Usage Minimum (01h),             */
e336be
+	 0x29, 0x02,                  /*     Usage Maximum (02h),             */
e336be
+	 0x75, 0x08,                  /*     Report Size (8),                 */
e336be
+	 0x95, 0x02,                  /*     Report Count (2),                */
e336be
+	 0xB1, 0x02,                  /*     Feature (Variable),              */
e336be
+	 0xC0,                        /* End Collection,                      */
e336be
+	 0x05, 0x0D,                  /* Usage Page (Digitizer),              */
e336be
+	 0x09, 0x0E,                  /* Usage (Configuration),               */
e336be
+	 0xA1, 0x01,                  /* Collection (Application),            */
e336be
+	 0x85, 0x03,                  /*     Report ID (3),                   */
e336be
+	 0x09, 0x22,                  /*     Usage (Finger),                  */
e336be
+	 0xA1, 0x02,                  /*     Collection (Logical),            */
e336be
+	 0x09, 0x52,                  /*         Usage (Device Mode),         */
e336be
+	 0x25, 0x0A,                  /*         Logical Maximum (10),        */
e336be
+	 0x95, 0x01,                  /*         Report Count (1),            */
e336be
+	 0xB1, 0x02,                  /*         Feature (Variable),          */
e336be
+	 0xC0,                        /*     End Collection,                  */
e336be
+	 0x09, 0x22,                  /*     Usage (Finger),                  */
e336be
+	 0xA1, 0x00,                  /*     Collection (Physical),           */
e336be
+	 0x85, 0x05,                  /*         Report ID (5),               */
e336be
+	 0x09, 0x57,                  /*         Usage (57h),                 */
e336be
+	 0x09, 0x58,                  /*         Usage (58h),                 */
e336be
+	 0x75, 0x01,                  /*         Report Size (1),             */
e336be
+	 0x95, 0x02,                  /*         Report Count (2),            */
e336be
+	 0x25, 0x01,                  /*         Logical Maximum (1),         */
e336be
+	 0xB1, 0x02,                  /*         Feature (Variable),          */
e336be
+	 0x95, 0x06,                  /*         Report Count (6),            */
e336be
+	 0xB1, 0x03,                  /*         Feature (Constant, Variable),*/
e336be
+	 0xC0,                        /*     End Collection,                  */
e336be
+	 0xC0                         /* End Collection                       */
e336be
+	},
e336be
+	.hid_report_desc_size = 475,
e336be
+	.i2c_name = "SYNA3602:00"
e336be
+};
e336be
+
e336be
+
e336be
+static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
e336be
+	{
e336be
+		.ident = "Teclast F6 Pro",
e336be
+		.matches = {
e336be
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"),
e336be
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F6 Pro"),
e336be
+		},
e336be
+		.driver_data = (void *)&sipodev_desc
e336be
+	},
e336be
+	{
e336be
+		.ident = "Teclast F7",
e336be
+		.matches = {
e336be
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"),
e336be
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F7"),
e336be
+		},
e336be
+		.driver_data = (void *)&sipodev_desc
e336be
+	},
e336be
+	{
e336be
+		.ident = "Trekstor Primebook C13",
e336be
+		.matches = {
e336be
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
e336be
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C13"),
e336be
+		},
e336be
+		.driver_data = (void *)&sipodev_desc
e336be
+	},
e336be
+	{
e336be
+		.ident = "Trekstor Primebook C11",
e336be
+		.matches = {
e336be
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
e336be
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C11"),
e336be
+		},
e336be
+		.driver_data = (void *)&sipodev_desc
e336be
+	},
e336be
+	{
e336be
+		.ident = "Direkt-Tek DTLAPY116-2",
e336be
+		.matches = {
e336be
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Direkt-Tek"),
e336be
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "DTLAPY116-2"),
e336be
+		},
e336be
+		.driver_data = (void *)&sipodev_desc
e336be
+	},
e336be
+	{
e336be
+		.ident = "Direkt-Tek DTLAPY133-1",
e336be
+		.matches = {
e336be
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Direkt-Tek"),
e336be
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "DTLAPY133-1"),
e336be
+		},
e336be
+		.driver_data = (void *)&sipodev_desc
e336be
+	},
e336be
+	{
e336be
+		.ident = "Mediacom Flexbook Edge 11",
e336be
+		.matches = {
e336be
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MEDIACOM"),
e336be
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "FlexBook edge11 - M-FBE11"),
e336be
+		},
e336be
+		.driver_data = (void *)&sipodev_desc
e336be
+	},
e336be
+	{ }	/* Terminate list */
e336be
+};
e336be
+
e336be
+
e336be
+struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name)
e336be
+{
e336be
+	struct i2c_hid_desc_override *override;
e336be
+	const struct dmi_system_id *system_id;
e336be
+
e336be
+	system_id = dmi_first_match(i2c_hid_dmi_desc_override_table);
e336be
+	if (!system_id)
e336be
+		return NULL;
e336be
+
e336be
+	override = system_id->driver_data;
e336be
+	if (strcmp(override->i2c_name, i2c_name))
e336be
+		return NULL;
e336be
+
e336be
+	return override->i2c_hid_desc;
e336be
+}
e336be
+
e336be
+char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
e336be
+					       unsigned int *size)
e336be
+{
e336be
+	struct i2c_hid_desc_override *override;
e336be
+	const struct dmi_system_id *system_id;
e336be
+
e336be
+	system_id = dmi_first_match(i2c_hid_dmi_desc_override_table);
e336be
+	if (!system_id)
e336be
+		return NULL;
e336be
+
e336be
+	override = system_id->driver_data;
e336be
+	if (strcmp(override->i2c_name, i2c_name))
e336be
+		return NULL;
e336be
+
e336be
+	*size = override->hid_report_desc_size;
e336be
+	return override->hid_report_desc;
e336be
+}
e336be
diff --git a/drivers/hid/i2c-hid/i2c-hid.h b/drivers/hid/i2c-hid/i2c-hid.h
e336be
new file mode 100644
e336be
index 000000000000..a8c19aef5824
e336be
--- /dev/null
e336be
+++ b/drivers/hid/i2c-hid/i2c-hid.h
e336be
@@ -0,0 +1,20 @@
e336be
+/* SPDX-License-Identifier: GPL-2.0+ */
e336be
+
e336be
+#ifndef I2C_HID_H
e336be
+#define I2C_HID_H
e336be
+
e336be
+
e336be
+#ifdef CONFIG_DMI
e336be
+struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name);
e336be
+char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
e336be
+					       unsigned int *size);
e336be
+#else
e336be
+static inline struct i2c_hid_desc
e336be
+		   *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name)
e336be
+{ return NULL; }
e336be
+static inline char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
e336be
+							     unsigned int *size)
e336be
+{ return NULL; }
e336be
+#endif
e336be
+
e336be
+#endif
e336be
-- 
e336be
2.19.1
e336be