diff mbox

[v3] hid/i2c-hid: override HID descriptors for certain devices

Message ID 20180715101507.644-1-jsbc@gmx.de (mailing list archive)
State New, archived
Headers show

Commit Message

Julian Sax July 15, 2018, 10:15 a.m. UTC
A particular touchpad (SIPODEV SP1064) refuses to supply the HID
descriptors. This patch provides the framework for overriding these
descriptors based on DMI data. It also includes the descriptors for
said touchpad, which were extracted by listening to the traffic of the
windows filter driver, as well as the DMI data for the laptops known
to use this device.

Relevant Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1526312

Cc: Hans de Goede <hdegoede@redhat.com>
Reported-and-tested-by: ahormann@gmx.net
Reported-and-tested-by: Bruno Jesus <bruno.fl.jesus@gmail.com>
Reported-and-tested-by: Dietrich <enaut.w@googlemail.com>
Reported-and-tested-by: kloxdami@yahoo.com
Signed-off-by: Julian Sax <jsbc@gmx.de>
---
Changes in v3:
* added additional check for the ACPI ID of the device
* added Direkt-Tek DTLAPY116-2 to the override list

Changes in v2:
* added documentation about the source of the descriptors
* added documentation inside the descriptors

 drivers/hid/i2c-hid/Makefile                  |   3 +
 .../hid/i2c-hid/{i2c-hid.c => i2c-hid-core.c} |  60 ++-
 drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c      | 369 ++++++++++++++++++
 drivers/hid/i2c-hid/i2c-hid.h                 |  20 +
 4 files changed, 432 insertions(+), 20 deletions(-)
 rename drivers/hid/i2c-hid/{i2c-hid.c => i2c-hid-core.c} (96%)
 create mode 100644 drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
 create mode 100644 drivers/hid/i2c-hid/i2c-hid.h

Comments

Hans de Goede Sept. 17, 2018, 3:31 p.m. UTC | #1
Hi,

On 15-07-18 12:15, Julian Sax wrote:
> A particular touchpad (SIPODEV SP1064) refuses to supply the HID
> descriptors. This patch provides the framework for overriding these
> descriptors based on DMI data. It also includes the descriptors for
> said touchpad, which were extracted by listening to the traffic of the
> windows filter driver, as well as the DMI data for the laptops known
> to use this device.
> 
> Relevant Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1526312
> 
> Cc: Hans de Goede <hdegoede@redhat.com>
> Reported-and-tested-by: ahormann@gmx.net
> Reported-and-tested-by: Bruno Jesus <bruno.fl.jesus@gmail.com>
> Reported-and-tested-by: Dietrich <enaut.w@googlemail.com>
> Reported-and-tested-by: kloxdami@yahoo.com
> Signed-off-by: Julian Sax <jsbc@gmx.de>

Jiri, what is the status of this patch? I thought we agreed that although
ugly, this was the best fix we could do and that the plan was to merge
this patch ?

Regards,

Hans


> ---
> Changes in v3:
> * added additional check for the ACPI ID of the device
> * added Direkt-Tek DTLAPY116-2 to the override list
> 
> Changes in v2:
> * added documentation about the source of the descriptors
> * added documentation inside the descriptors
> 
>   drivers/hid/i2c-hid/Makefile                  |   3 +
>   .../hid/i2c-hid/{i2c-hid.c => i2c-hid-core.c} |  60 ++-
>   drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c      | 369 ++++++++++++++++++
>   drivers/hid/i2c-hid/i2c-hid.h                 |  20 +
>   4 files changed, 432 insertions(+), 20 deletions(-)
>   rename drivers/hid/i2c-hid/{i2c-hid.c => i2c-hid-core.c} (96%)
>   create mode 100644 drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
>   create mode 100644 drivers/hid/i2c-hid/i2c-hid.h
> 
> diff --git a/drivers/hid/i2c-hid/Makefile b/drivers/hid/i2c-hid/Makefile
> index 832d8f9aa..099e1ce2f 100644
> --- a/drivers/hid/i2c-hid/Makefile
> +++ b/drivers/hid/i2c-hid/Makefile
> @@ -3,3 +3,6 @@
>   #
>   
>   obj-$(CONFIG_I2C_HID)				+= i2c-hid.o
> +
> +i2c-hid-objs					=  i2c-hid-core.o
> +i2c-hid-$(CONFIG_DMI)				+= i2c-hid-dmi-quirks.o
> diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid-core.c
> similarity index 96%
> rename from drivers/hid/i2c-hid/i2c-hid.c
> rename to drivers/hid/i2c-hid/i2c-hid-core.c
> index c1652bb7b..d4917e306 100644
> --- a/drivers/hid/i2c-hid/i2c-hid.c
> +++ b/drivers/hid/i2c-hid/i2c-hid-core.c
> @@ -43,6 +43,7 @@
>   #include <linux/platform_data/i2c-hid.h>
>   
>   #include "../hid-ids.h"
> +#include "i2c-hid.h"
>   
>   /* quirks to control the device */
>   #define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV	BIT(0)
> @@ -671,6 +672,7 @@ static int i2c_hid_parse(struct hid_device *hid)
>   	char *rdesc;
>   	int ret;
>   	int tries = 3;
> +	char *use_override;
>   
>   	i2c_hid_dbg(ihid, "entering %s\n", __func__);
>   
> @@ -689,26 +691,37 @@ static int i2c_hid_parse(struct hid_device *hid)
>   	if (ret)
>   		return ret;
>   
> -	rdesc = kzalloc(rsize, GFP_KERNEL);
> +	use_override = i2c_hid_get_dmi_hid_report_desc_override(client->name,
> +								&rsize);
>   
> -	if (!rdesc) {
> -		dbg_hid("couldn't allocate rdesc memory\n");
> -		return -ENOMEM;
> -	}
> -
> -	i2c_hid_dbg(ihid, "asking HID report descriptor\n");
> -
> -	ret = i2c_hid_command(client, &hid_report_descr_cmd, rdesc, rsize);
> -	if (ret) {
> -		hid_err(hid, "reading report descriptor failed\n");
> -		kfree(rdesc);
> -		return -EIO;
> +	if (use_override) {
> +		rdesc = use_override;
> +		i2c_hid_dbg(ihid, "Using a HID report descriptor override\n");
> +	} else {
> +		rdesc = kzalloc(rsize, GFP_KERNEL);
> +
> +		if (!rdesc) {
> +			dbg_hid("couldn't allocate rdesc memory\n");
> +			return -ENOMEM;
> +		}
> +
> +		i2c_hid_dbg(ihid, "asking HID report descriptor\n");
> +
> +		ret = i2c_hid_command(client, &hid_report_descr_cmd,
> +				      rdesc, rsize);
> +		if (ret) {
> +			hid_err(hid, "reading report descriptor failed\n");
> +			kfree(rdesc);
> +			return -EIO;
> +		}
>   	}
>   
>   	i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc);
>   
>   	ret = hid_parse_report(hid, rdesc, rsize);
> -	kfree(rdesc);
> +	if (!use_override)
> +		kfree(rdesc);
> +
>   	if (ret) {
>   		dbg_hid("parsing report descriptor failed\n");
>   		return ret;
> @@ -835,12 +848,19 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
>   	int ret;
>   
>   	/* i2c hid fetch using a fixed descriptor size (30 bytes) */
> -	i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
> -	ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer,
> -				sizeof(struct i2c_hid_desc));
> -	if (ret) {
> -		dev_err(&client->dev, "hid_descr_cmd failed\n");
> -		return -ENODEV;
> +	if (i2c_hid_get_dmi_i2c_hid_desc_override(client->name)) {
> +		i2c_hid_dbg(ihid, "Using a HID descriptor override\n");
> +		ihid->hdesc =
> +			*i2c_hid_get_dmi_i2c_hid_desc_override(client->name);
> +	} else {
> +		i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
> +		ret = i2c_hid_command(client, &hid_descr_cmd,
> +				      ihid->hdesc_buffer,
> +				      sizeof(struct i2c_hid_desc));
> +		if (ret) {
> +			dev_err(&client->dev, "hid_descr_cmd failed\n");
> +			return -ENODEV;
> +		}
>   	}
>   
>   	/* Validate the length of HID descriptor, the 4 first bytes:
> diff --git a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
> new file mode 100644
> index 000000000..b923d2372
> --- /dev/null
> +++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
> @@ -0,0 +1,369 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +/*
> + * Quirks for I2C-HID devices that do not supply proper descriptors
> + *
> + * Copyright (c) 2018 Julian Sax <jsbc@gmx.de>
> + *
> + */
> +
> +#include <linux/types.h>
> +#include <linux/dmi.h>
> +#include <linux/mod_devicetable.h>
> +
> +#include "i2c-hid.h"
> +
> +
> +struct i2c_hid_desc_override {
> +	union {
> +		struct i2c_hid_desc *i2c_hid_desc;
> +		uint8_t             *i2c_hid_desc_buffer;
> +	};
> +	uint8_t              *hid_report_desc;
> +	unsigned int          hid_report_desc_size;
> +	uint8_t              *i2c_name;
> +};
> +
> +
> +/*
> + * descriptors for the SIPODEV SP1064 touchpad
> + *
> + * This device does not supply any descriptors and on windows a filter
> + * driver operates between the i2c-hid layer and the device and injects
> + * these descriptors when the device is prompted. The descriptors were
> + * extracted by listening to the i2c-hid traffic that occurs between the
> + * windows filter driver and the windows i2c-hid driver.
> + */
> +
> +static const struct i2c_hid_desc_override sipodev_desc = {
> +	.i2c_hid_desc_buffer = (uint8_t [])
> +	{0x1e, 0x00,                  /* Length of descriptor                 */
> +	 0x00, 0x01,                  /* Version of descriptor                */
> +	 0xdb, 0x01,                  /* Length of report descriptor          */
> +	 0x21, 0x00,                  /* Location of report descriptor        */
> +	 0x24, 0x00,                  /* Location of input report             */
> +	 0x1b, 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 (Desktop),                */
> +	 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 (01h),         */
> +	 0x29, 0x02,                  /*         Usage Maximum (02h),         */
> +	 0x25, 0x01,                  /*         Logical Maximum (1),         */
> +	 0x75, 0x01,                  /*         Report Size (1),             */
> +	 0x95, 0x02,                  /*         Report Count (2),            */
> +	 0x81, 0x02,                  /*         Input (Variable),            */
> +	 0x95, 0x06,                  /*         Report Count (6),            */
> +	 0x81, 0x01,                  /*         Input (Constant),            */
> +	 0x05, 0x01,                  /*         Usage Page (Desktop),        */
> +	 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 (Variable, Relative),  */
> +	 0xC0,                        /*     End Collection,                  */
> +	 0xC0,                        /* End Collection,                      */
> +	 0x05, 0x0D,                  /* Usage Page (Digitizer),              */
> +	 0x09, 0x05,                  /* Usage (Touchpad),                    */
> +	 0xA1, 0x01,                  /* Collection (Application),            */
> +	 0x85, 0x04,                  /*     Report ID (4),                   */
> +	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
> +	 0x09, 0x22,                  /*     Usage (Finger),                  */
> +	 0xA1, 0x02,                  /*     Collection (Logical),            */
> +	 0x15, 0x00,                  /*         Logical Minimum (0),         */
> +	 0x25, 0x01,                  /*         Logical Maximum (1),         */
> +	 0x09, 0x47,                  /*         Usage (Touch Valid),         */
> +	 0x09, 0x42,                  /*         Usage (Tip Switch),          */
> +	 0x95, 0x02,                  /*         Report Count (2),            */
> +	 0x75, 0x01,                  /*         Report Size (1),             */
> +	 0x81, 0x02,                  /*         Input (Variable),            */
> +	 0x95, 0x01,                  /*         Report Count (1),            */
> +	 0x75, 0x03,                  /*         Report Size (3),             */
> +	 0x25, 0x05,                  /*         Logical Maximum (5),         */
> +	 0x09, 0x51,                  /*         Usage (Contact Identifier),  */
> +	 0x81, 0x02,                  /*         Input (Variable),            */
> +	 0x75, 0x01,                  /*         Report Size (1),             */
> +	 0x95, 0x03,                  /*         Report Count (3),            */
> +	 0x81, 0x03,                  /*         Input (Constant, Variable),  */
> +	 0x05, 0x01,                  /*         Usage Page (Desktop),        */
> +	 0x26, 0x44, 0x0A,            /*         Logical Maximum (2628),      */
> +	 0x75, 0x10,                  /*         Report Size (16),            */
> +	 0x55, 0x0E,                  /*         Unit Exponent (14),          */
> +	 0x65, 0x11,                  /*         Unit (Centimeter),           */
> +	 0x09, 0x30,                  /*         Usage (X),                   */
> +	 0x46, 0x1A, 0x04,            /*         Physical Maximum (1050),     */
> +	 0x95, 0x01,                  /*         Report Count (1),            */
> +	 0x81, 0x02,                  /*         Input (Variable),            */
> +	 0x46, 0xBC, 0x02,            /*         Physical Maximum (700),      */
> +	 0x26, 0x34, 0x05,            /*         Logical Maximum (1332),      */
> +	 0x09, 0x31,                  /*         Usage (Y),                   */
> +	 0x81, 0x02,                  /*         Input (Variable),            */
> +	 0xC0,                        /*     End Collection,                  */
> +	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
> +	 0x09, 0x22,                  /*     Usage (Finger),                  */
> +	 0xA1, 0x02,                  /*     Collection (Logical),            */
> +	 0x25, 0x01,                  /*         Logical Maximum (1),         */
> +	 0x09, 0x47,                  /*         Usage (Touch Valid),         */
> +	 0x09, 0x42,                  /*         Usage (Tip Switch),          */
> +	 0x95, 0x02,                  /*         Report Count (2),            */
> +	 0x75, 0x01,                  /*         Report Size (1),             */
> +	 0x81, 0x02,                  /*         Input (Variable),            */
> +	 0x95, 0x01,                  /*         Report Count (1),            */
> +	 0x75, 0x03,                  /*         Report Size (3),             */
> +	 0x25, 0x05,                  /*         Logical Maximum (5),         */
> +	 0x09, 0x51,                  /*         Usage (Contact Identifier),  */
> +	 0x81, 0x02,                  /*         Input (Variable),            */
> +	 0x75, 0x01,                  /*         Report Size (1),             */
> +	 0x95, 0x03,                  /*         Report Count (3),            */
> +	 0x81, 0x03,                  /*         Input (Constant, Variable),  */
> +	 0x05, 0x01,                  /*         Usage Page (Desktop),        */
> +	 0x26, 0x44, 0x0A,            /*         Logical Maximum (2628),      */
> +	 0x75, 0x10,                  /*         Report Size (16),            */
> +	 0x09, 0x30,                  /*         Usage (X),                   */
> +	 0x46, 0x1A, 0x04,            /*         Physical Maximum (1050),     */
> +	 0x95, 0x01,                  /*         Report Count (1),            */
> +	 0x81, 0x02,                  /*         Input (Variable),            */
> +	 0x46, 0xBC, 0x02,            /*         Physical Maximum (700),      */
> +	 0x26, 0x34, 0x05,            /*         Logical Maximum (1332),      */
> +	 0x09, 0x31,                  /*         Usage (Y),                   */
> +	 0x81, 0x02,                  /*         Input (Variable),            */
> +	 0xC0,                        /*     End Collection,                  */
> +	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
> +	 0x09, 0x22,                  /*     Usage (Finger),                  */
> +	 0xA1, 0x02,                  /*     Collection (Logical),            */
> +	 0x25, 0x01,                  /*         Logical Maximum (1),         */
> +	 0x09, 0x47,                  /*         Usage (Touch Valid),         */
> +	 0x09, 0x42,                  /*         Usage (Tip Switch),          */
> +	 0x95, 0x02,                  /*         Report Count (2),            */
> +	 0x75, 0x01,                  /*         Report Size (1),             */
> +	 0x81, 0x02,                  /*         Input (Variable),            */
> +	 0x95, 0x01,                  /*         Report Count (1),            */
> +	 0x75, 0x03,                  /*         Report Size (3),             */
> +	 0x25, 0x05,                  /*         Logical Maximum (5),         */
> +	 0x09, 0x51,                  /*         Usage (Contact Identifier),  */
> +	 0x81, 0x02,                  /*         Input (Variable),            */
> +	 0x75, 0x01,                  /*         Report Size (1),             */
> +	 0x95, 0x03,                  /*         Report Count (3),            */
> +	 0x81, 0x03,                  /*         Input (Constant, Variable),  */
> +	 0x05, 0x01,                  /*         Usage Page (Desktop),        */
> +	 0x26, 0x44, 0x0A,            /*         Logical Maximum (2628),      */
> +	 0x75, 0x10,                  /*         Report Size (16),            */
> +	 0x09, 0x30,                  /*         Usage (X),                   */
> +	 0x46, 0x1A, 0x04,            /*         Physical Maximum (1050),     */
> +	 0x95, 0x01,                  /*         Report Count (1),            */
> +	 0x81, 0x02,                  /*         Input (Variable),            */
> +	 0x46, 0xBC, 0x02,            /*         Physical Maximum (700),      */
> +	 0x26, 0x34, 0x05,            /*         Logical Maximum (1332),      */
> +	 0x09, 0x31,                  /*         Usage (Y),                   */
> +	 0x81, 0x02,                  /*         Input (Variable),            */
> +	 0xC0,                        /*     End Collection,                  */
> +	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
> +	 0x09, 0x22,                  /*     Usage (Finger),                  */
> +	 0xA1, 0x02,                  /*     Collection (Logical),            */
> +	 0x25, 0x01,                  /*         Logical Maximum (1),         */
> +	 0x09, 0x47,                  /*         Usage (Touch Valid),         */
> +	 0x09, 0x42,                  /*         Usage (Tip Switch),          */
> +	 0x95, 0x02,                  /*         Report Count (2),            */
> +	 0x75, 0x01,                  /*         Report Size (1),             */
> +	 0x81, 0x02,                  /*         Input (Variable),            */
> +	 0x95, 0x01,                  /*         Report Count (1),            */
> +	 0x75, 0x03,                  /*         Report Size (3),             */
> +	 0x25, 0x05,                  /*         Logical Maximum (5),         */
> +	 0x09, 0x51,                  /*         Usage (Contact Identifier),  */
> +	 0x81, 0x02,                  /*         Input (Variable),            */
> +	 0x75, 0x01,                  /*         Report Size (1),             */
> +	 0x95, 0x03,                  /*         Report Count (3),            */
> +	 0x81, 0x03,                  /*         Input (Constant, Variable),  */
> +	 0x05, 0x01,                  /*         Usage Page (Desktop),        */
> +	 0x26, 0x44, 0x0A,            /*         Logical Maximum (2628),      */
> +	 0x75, 0x10,                  /*         Report Size (16),            */
> +	 0x09, 0x30,                  /*         Usage (X),                   */
> +	 0x46, 0x1A, 0x04,            /*         Physical Maximum (1050),     */
> +	 0x95, 0x01,                  /*         Report Count (1),            */
> +	 0x81, 0x02,                  /*         Input (Variable),            */
> +	 0x46, 0xBC, 0x02,            /*         Physical Maximum (700),      */
> +	 0x26, 0x34, 0x05,            /*         Logical Maximum (1332),      */
> +	 0x09, 0x31,                  /*         Usage (Y),                   */
> +	 0x81, 0x02,                  /*         Input (Variable),            */
> +	 0xC0,                        /*     End Collection,                  */
> +	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
> +	 0x55, 0x0C,                  /*     Unit Exponent (12),              */
> +	 0x66, 0x01, 0x10,            /*     Unit (Seconds),                  */
> +	 0x47, 0xFF, 0xFF, 0x00, 0x00,/*     Physical Maximum (65535),        */
> +	 0x27, 0xFF, 0xFF, 0x00, 0x00,/*     Logical Maximum (65535),         */
> +	 0x75, 0x10,                  /*     Report Size (16),                */
> +	 0x95, 0x01,                  /*     Report Count (1),                */
> +	 0x09, 0x56,                  /*     Usage (Scan Time),               */
> +	 0x81, 0x02,                  /*     Input (Variable),                */
> +	 0x09, 0x54,                  /*     Usage (Contact Count),           */
> +	 0x25, 0x7F,                  /*     Logical Maximum (127),           */
> +	 0x75, 0x08,                  /*     Report Size (8),                 */
> +	 0x81, 0x02,                  /*     Input (Variable),                */
> +	 0x05, 0x09,                  /*     Usage Page (Button),             */
> +	 0x09, 0x01,                  /*     Usage (01h),                     */
> +	 0x25, 0x01,                  /*     Logical Maximum (1),             */
> +	 0x75, 0x01,                  /*     Report Size (1),                 */
> +	 0x95, 0x01,                  /*     Report Count (1),                */
> +	 0x81, 0x02,                  /*     Input (Variable),                */
> +	 0x95, 0x07,                  /*     Report Count (7),                */
> +	 0x81, 0x03,                  /*     Input (Constant, Variable),      */
> +	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
> +	 0x85, 0x02,                  /*     Report ID (2),                   */
> +	 0x09, 0x55,                  /*     Usage (Contact Count Maximum),   */
> +	 0x09, 0x59,                  /*     Usage (59h),                     */
> +	 0x75, 0x04,                  /*     Report Size (4),                 */
> +	 0x95, 0x02,                  /*     Report Count (2),                */
> +	 0x25, 0x0F,                  /*     Logical Maximum (15),            */
> +	 0xB1, 0x02,                  /*     Feature (Variable),              */
> +	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
> +	 0x85, 0x07,                  /*     Report ID (7),                   */
> +	 0x09, 0x60,                  /*     Usage (60h),                     */
> +	 0x75, 0x01,                  /*     Report Size (1),                 */
> +	 0x95, 0x01,                  /*     Report Count (1),                */
> +	 0x25, 0x01,                  /*     Logical Maximum (1),             */
> +	 0xB1, 0x02,                  /*     Feature (Variable),              */
> +	 0x95, 0x07,                  /*     Report Count (7),                */
> +	 0xB1, 0x03,                  /*     Feature (Constant, Variable),    */
> +	 0x85, 0x06,                  /*     Report ID (6),                   */
> +	 0x06, 0x00, 0xFF,            /*     Usage Page (FF00h),              */
> +	 0x09, 0xC5,                  /*     Usage (C5h),                     */
> +	 0x26, 0xFF, 0x00,            /*     Logical Maximum (255),           */
> +	 0x75, 0x08,                  /*     Report Size (8),                 */
> +	 0x96, 0x00, 0x01,            /*     Report Count (256),              */
> +	 0xB1, 0x02,                  /*     Feature (Variable),              */
> +	 0xC0,                        /* End Collection,                      */
> +	 0x06, 0x00, 0xFF,            /* Usage Page (FF00h),                  */
> +	 0x09, 0x01,                  /* Usage (01h),                         */
> +	 0xA1, 0x01,                  /* Collection (Application),            */
> +	 0x85, 0x0D,                  /*     Report ID (13),                  */
> +	 0x26, 0xFF, 0x00,            /*     Logical Maximum (255),           */
> +	 0x19, 0x01,                  /*     Usage Minimum (01h),             */
> +	 0x29, 0x02,                  /*     Usage Maximum (02h),             */
> +	 0x75, 0x08,                  /*     Report Size (8),                 */
> +	 0x95, 0x02,                  /*     Report Count (2),                */
> +	 0xB1, 0x02,                  /*     Feature (Variable),              */
> +	 0xC0,                        /* End Collection,                      */
> +	 0x05, 0x0D,                  /* Usage Page (Digitizer),              */
> +	 0x09, 0x0E,                  /* Usage (Configuration),               */
> +	 0xA1, 0x01,                  /* Collection (Application),            */
> +	 0x85, 0x03,                  /*     Report ID (3),                   */
> +	 0x09, 0x22,                  /*     Usage (Finger),                  */
> +	 0xA1, 0x02,                  /*     Collection (Logical),            */
> +	 0x09, 0x52,                  /*         Usage (Device Mode),         */
> +	 0x25, 0x0A,                  /*         Logical Maximum (10),        */
> +	 0x95, 0x01,                  /*         Report Count (1),            */
> +	 0xB1, 0x02,                  /*         Feature (Variable),          */
> +	 0xC0,                        /*     End Collection,                  */
> +	 0x09, 0x22,                  /*     Usage (Finger),                  */
> +	 0xA1, 0x00,                  /*     Collection (Physical),           */
> +	 0x85, 0x05,                  /*         Report ID (5),               */
> +	 0x09, 0x57,                  /*         Usage (57h),                 */
> +	 0x09, 0x58,                  /*         Usage (58h),                 */
> +	 0x75, 0x01,                  /*         Report Size (1),             */
> +	 0x95, 0x02,                  /*         Report Count (2),            */
> +	 0x25, 0x01,                  /*         Logical Maximum (1),         */
> +	 0xB1, 0x02,                  /*         Feature (Variable),          */
> +	 0x95, 0x06,                  /*         Report Count (6),            */
> +	 0xB1, 0x03,                  /*         Feature (Constant, Variable),*/
> +	 0xC0,                        /*     End Collection,                  */
> +	 0xC0                         /* End Collection                       */
> +	},
> +	.hid_report_desc_size = 475,
> +	.i2c_name = "SYNA3602:00"
> +};
> +
> +
> +static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
> +	{
> +		.ident = "Teclast F6 Pro",
> +		.matches = {
> +			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"),
> +			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F6 Pro"),
> +		},
> +		.driver_data = (void *)&sipodev_desc
> +	},
> +	{
> +		.ident = "Teclast F7",
> +		.matches = {
> +			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"),
> +			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F7"),
> +		},
> +		.driver_data = (void *)&sipodev_desc
> +	},
> +	{
> +		.ident = "Trekstor Primebook C13",
> +		.matches = {
> +			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
> +			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C13"),
> +		},
> +		.driver_data = (void *)&sipodev_desc
> +	},
> +	{
> +		.ident = "Trekstor Primebook C11",
> +		.matches = {
> +			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
> +			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C11"),
> +		},
> +		.driver_data = (void *)&sipodev_desc
> +	},
> +	{
> +		.ident = "Direkt-Tek DTLAPY116-2",
> +		.matches = {
> +			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Direkt-Tek"),
> +			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "DTLAPY116-2"),
> +		},
> +		.driver_data = (void *)&sipodev_desc
> +	}
> +};
> +
> +
> +struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name)
> +{
> +	struct i2c_hid_desc_override *override;
> +	const struct dmi_system_id *system_id;
> +
> +	system_id = dmi_first_match(i2c_hid_dmi_desc_override_table);
> +	if (!system_id)
> +		return NULL;
> +
> +	override = system_id->driver_data;
> +	if (strcmp(override->i2c_name, i2c_name))
> +		return NULL;
> +
> +	return override->i2c_hid_desc;
> +}
> +
> +char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
> +					       unsigned int *size)
> +{
> +	struct i2c_hid_desc_override *override;
> +	const struct dmi_system_id *system_id;
> +
> +	system_id = dmi_first_match(i2c_hid_dmi_desc_override_table);
> +	if (!system_id)
> +		return NULL;
> +
> +	override = system_id->driver_data;
> +	if (strcmp(override->i2c_name, i2c_name))
> +		return NULL;
> +
> +	*size = override->hid_report_desc_size;
> +	return override->hid_report_desc;
> +}
> +
> diff --git a/drivers/hid/i2c-hid/i2c-hid.h b/drivers/hid/i2c-hid/i2c-hid.h
> new file mode 100644
> index 000000000..a8c19aef5
> --- /dev/null
> +++ b/drivers/hid/i2c-hid/i2c-hid.h
> @@ -0,0 +1,20 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +
> +#ifndef I2C_HID_H
> +#define I2C_HID_H
> +
> +
> +#ifdef CONFIG_DMI
> +struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name);
> +char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
> +					       unsigned int *size);
> +#else
> +static inline struct i2c_hid_desc
> +		   *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name)
> +{ return NULL; }
> +static inline char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
> +							     unsigned int *size)
> +{ return NULL; }
> +#endif
> +
> +#endif
>
diff mbox

Patch

diff --git a/drivers/hid/i2c-hid/Makefile b/drivers/hid/i2c-hid/Makefile
index 832d8f9aa..099e1ce2f 100644
--- a/drivers/hid/i2c-hid/Makefile
+++ b/drivers/hid/i2c-hid/Makefile
@@ -3,3 +3,6 @@ 
 #
 
 obj-$(CONFIG_I2C_HID)				+= i2c-hid.o
+
+i2c-hid-objs					=  i2c-hid-core.o
+i2c-hid-$(CONFIG_DMI)				+= i2c-hid-dmi-quirks.o
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid-core.c
similarity index 96%
rename from drivers/hid/i2c-hid/i2c-hid.c
rename to drivers/hid/i2c-hid/i2c-hid-core.c
index c1652bb7b..d4917e306 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -43,6 +43,7 @@ 
 #include <linux/platform_data/i2c-hid.h>
 
 #include "../hid-ids.h"
+#include "i2c-hid.h"
 
 /* quirks to control the device */
 #define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV	BIT(0)
@@ -671,6 +672,7 @@  static int i2c_hid_parse(struct hid_device *hid)
 	char *rdesc;
 	int ret;
 	int tries = 3;
+	char *use_override;
 
 	i2c_hid_dbg(ihid, "entering %s\n", __func__);
 
@@ -689,26 +691,37 @@  static int i2c_hid_parse(struct hid_device *hid)
 	if (ret)
 		return ret;
 
-	rdesc = kzalloc(rsize, GFP_KERNEL);
+	use_override = i2c_hid_get_dmi_hid_report_desc_override(client->name,
+								&rsize);
 
-	if (!rdesc) {
-		dbg_hid("couldn't allocate rdesc memory\n");
-		return -ENOMEM;
-	}
-
-	i2c_hid_dbg(ihid, "asking HID report descriptor\n");
-
-	ret = i2c_hid_command(client, &hid_report_descr_cmd, rdesc, rsize);
-	if (ret) {
-		hid_err(hid, "reading report descriptor failed\n");
-		kfree(rdesc);
-		return -EIO;
+	if (use_override) {
+		rdesc = use_override;
+		i2c_hid_dbg(ihid, "Using a HID report descriptor override\n");
+	} else {
+		rdesc = kzalloc(rsize, GFP_KERNEL);
+
+		if (!rdesc) {
+			dbg_hid("couldn't allocate rdesc memory\n");
+			return -ENOMEM;
+		}
+
+		i2c_hid_dbg(ihid, "asking HID report descriptor\n");
+
+		ret = i2c_hid_command(client, &hid_report_descr_cmd,
+				      rdesc, rsize);
+		if (ret) {
+			hid_err(hid, "reading report descriptor failed\n");
+			kfree(rdesc);
+			return -EIO;
+		}
 	}
 
 	i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc);
 
 	ret = hid_parse_report(hid, rdesc, rsize);
-	kfree(rdesc);
+	if (!use_override)
+		kfree(rdesc);
+
 	if (ret) {
 		dbg_hid("parsing report descriptor failed\n");
 		return ret;
@@ -835,12 +848,19 @@  static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
 	int ret;
 
 	/* i2c hid fetch using a fixed descriptor size (30 bytes) */
-	i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
-	ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer,
-				sizeof(struct i2c_hid_desc));
-	if (ret) {
-		dev_err(&client->dev, "hid_descr_cmd failed\n");
-		return -ENODEV;
+	if (i2c_hid_get_dmi_i2c_hid_desc_override(client->name)) {
+		i2c_hid_dbg(ihid, "Using a HID descriptor override\n");
+		ihid->hdesc =
+			*i2c_hid_get_dmi_i2c_hid_desc_override(client->name);
+	} else {
+		i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
+		ret = i2c_hid_command(client, &hid_descr_cmd,
+				      ihid->hdesc_buffer,
+				      sizeof(struct i2c_hid_desc));
+		if (ret) {
+			dev_err(&client->dev, "hid_descr_cmd failed\n");
+			return -ENODEV;
+		}
 	}
 
 	/* Validate the length of HID descriptor, the 4 first bytes:
diff --git a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
new file mode 100644
index 000000000..b923d2372
--- /dev/null
+++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
@@ -0,0 +1,369 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * Quirks for I2C-HID devices that do not supply proper descriptors
+ *
+ * Copyright (c) 2018 Julian Sax <jsbc@gmx.de>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/dmi.h>
+#include <linux/mod_devicetable.h>
+
+#include "i2c-hid.h"
+
+
+struct i2c_hid_desc_override {
+	union {
+		struct i2c_hid_desc *i2c_hid_desc;
+		uint8_t             *i2c_hid_desc_buffer;
+	};
+	uint8_t              *hid_report_desc;
+	unsigned int          hid_report_desc_size;
+	uint8_t              *i2c_name;
+};
+
+
+/*
+ * descriptors for the SIPODEV SP1064 touchpad
+ *
+ * This device does not supply any descriptors and on windows a filter
+ * driver operates between the i2c-hid layer and the device and injects
+ * these descriptors when the device is prompted. The descriptors were
+ * extracted by listening to the i2c-hid traffic that occurs between the
+ * windows filter driver and the windows i2c-hid driver.
+ */
+
+static const struct i2c_hid_desc_override sipodev_desc = {
+	.i2c_hid_desc_buffer = (uint8_t [])
+	{0x1e, 0x00,                  /* Length of descriptor                 */
+	 0x00, 0x01,                  /* Version of descriptor                */
+	 0xdb, 0x01,                  /* Length of report descriptor          */
+	 0x21, 0x00,                  /* Location of report descriptor        */
+	 0x24, 0x00,                  /* Location of input report             */
+	 0x1b, 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 (Desktop),                */
+	 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 (01h),         */
+	 0x29, 0x02,                  /*         Usage Maximum (02h),         */
+	 0x25, 0x01,                  /*         Logical Maximum (1),         */
+	 0x75, 0x01,                  /*         Report Size (1),             */
+	 0x95, 0x02,                  /*         Report Count (2),            */
+	 0x81, 0x02,                  /*         Input (Variable),            */
+	 0x95, 0x06,                  /*         Report Count (6),            */
+	 0x81, 0x01,                  /*         Input (Constant),            */
+	 0x05, 0x01,                  /*         Usage Page (Desktop),        */
+	 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 (Variable, Relative),  */
+	 0xC0,                        /*     End Collection,                  */
+	 0xC0,                        /* End Collection,                      */
+	 0x05, 0x0D,                  /* Usage Page (Digitizer),              */
+	 0x09, 0x05,                  /* Usage (Touchpad),                    */
+	 0xA1, 0x01,                  /* Collection (Application),            */
+	 0x85, 0x04,                  /*     Report ID (4),                   */
+	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
+	 0x09, 0x22,                  /*     Usage (Finger),                  */
+	 0xA1, 0x02,                  /*     Collection (Logical),            */
+	 0x15, 0x00,                  /*         Logical Minimum (0),         */
+	 0x25, 0x01,                  /*         Logical Maximum (1),         */
+	 0x09, 0x47,                  /*         Usage (Touch Valid),         */
+	 0x09, 0x42,                  /*         Usage (Tip Switch),          */
+	 0x95, 0x02,                  /*         Report Count (2),            */
+	 0x75, 0x01,                  /*         Report Size (1),             */
+	 0x81, 0x02,                  /*         Input (Variable),            */
+	 0x95, 0x01,                  /*         Report Count (1),            */
+	 0x75, 0x03,                  /*         Report Size (3),             */
+	 0x25, 0x05,                  /*         Logical Maximum (5),         */
+	 0x09, 0x51,                  /*         Usage (Contact Identifier),  */
+	 0x81, 0x02,                  /*         Input (Variable),            */
+	 0x75, 0x01,                  /*         Report Size (1),             */
+	 0x95, 0x03,                  /*         Report Count (3),            */
+	 0x81, 0x03,                  /*         Input (Constant, Variable),  */
+	 0x05, 0x01,                  /*         Usage Page (Desktop),        */
+	 0x26, 0x44, 0x0A,            /*         Logical Maximum (2628),      */
+	 0x75, 0x10,                  /*         Report Size (16),            */
+	 0x55, 0x0E,                  /*         Unit Exponent (14),          */
+	 0x65, 0x11,                  /*         Unit (Centimeter),           */
+	 0x09, 0x30,                  /*         Usage (X),                   */
+	 0x46, 0x1A, 0x04,            /*         Physical Maximum (1050),     */
+	 0x95, 0x01,                  /*         Report Count (1),            */
+	 0x81, 0x02,                  /*         Input (Variable),            */
+	 0x46, 0xBC, 0x02,            /*         Physical Maximum (700),      */
+	 0x26, 0x34, 0x05,            /*         Logical Maximum (1332),      */
+	 0x09, 0x31,                  /*         Usage (Y),                   */
+	 0x81, 0x02,                  /*         Input (Variable),            */
+	 0xC0,                        /*     End Collection,                  */
+	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
+	 0x09, 0x22,                  /*     Usage (Finger),                  */
+	 0xA1, 0x02,                  /*     Collection (Logical),            */
+	 0x25, 0x01,                  /*         Logical Maximum (1),         */
+	 0x09, 0x47,                  /*         Usage (Touch Valid),         */
+	 0x09, 0x42,                  /*         Usage (Tip Switch),          */
+	 0x95, 0x02,                  /*         Report Count (2),            */
+	 0x75, 0x01,                  /*         Report Size (1),             */
+	 0x81, 0x02,                  /*         Input (Variable),            */
+	 0x95, 0x01,                  /*         Report Count (1),            */
+	 0x75, 0x03,                  /*         Report Size (3),             */
+	 0x25, 0x05,                  /*         Logical Maximum (5),         */
+	 0x09, 0x51,                  /*         Usage (Contact Identifier),  */
+	 0x81, 0x02,                  /*         Input (Variable),            */
+	 0x75, 0x01,                  /*         Report Size (1),             */
+	 0x95, 0x03,                  /*         Report Count (3),            */
+	 0x81, 0x03,                  /*         Input (Constant, Variable),  */
+	 0x05, 0x01,                  /*         Usage Page (Desktop),        */
+	 0x26, 0x44, 0x0A,            /*         Logical Maximum (2628),      */
+	 0x75, 0x10,                  /*         Report Size (16),            */
+	 0x09, 0x30,                  /*         Usage (X),                   */
+	 0x46, 0x1A, 0x04,            /*         Physical Maximum (1050),     */
+	 0x95, 0x01,                  /*         Report Count (1),            */
+	 0x81, 0x02,                  /*         Input (Variable),            */
+	 0x46, 0xBC, 0x02,            /*         Physical Maximum (700),      */
+	 0x26, 0x34, 0x05,            /*         Logical Maximum (1332),      */
+	 0x09, 0x31,                  /*         Usage (Y),                   */
+	 0x81, 0x02,                  /*         Input (Variable),            */
+	 0xC0,                        /*     End Collection,                  */
+	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
+	 0x09, 0x22,                  /*     Usage (Finger),                  */
+	 0xA1, 0x02,                  /*     Collection (Logical),            */
+	 0x25, 0x01,                  /*         Logical Maximum (1),         */
+	 0x09, 0x47,                  /*         Usage (Touch Valid),         */
+	 0x09, 0x42,                  /*         Usage (Tip Switch),          */
+	 0x95, 0x02,                  /*         Report Count (2),            */
+	 0x75, 0x01,                  /*         Report Size (1),             */
+	 0x81, 0x02,                  /*         Input (Variable),            */
+	 0x95, 0x01,                  /*         Report Count (1),            */
+	 0x75, 0x03,                  /*         Report Size (3),             */
+	 0x25, 0x05,                  /*         Logical Maximum (5),         */
+	 0x09, 0x51,                  /*         Usage (Contact Identifier),  */
+	 0x81, 0x02,                  /*         Input (Variable),            */
+	 0x75, 0x01,                  /*         Report Size (1),             */
+	 0x95, 0x03,                  /*         Report Count (3),            */
+	 0x81, 0x03,                  /*         Input (Constant, Variable),  */
+	 0x05, 0x01,                  /*         Usage Page (Desktop),        */
+	 0x26, 0x44, 0x0A,            /*         Logical Maximum (2628),      */
+	 0x75, 0x10,                  /*         Report Size (16),            */
+	 0x09, 0x30,                  /*         Usage (X),                   */
+	 0x46, 0x1A, 0x04,            /*         Physical Maximum (1050),     */
+	 0x95, 0x01,                  /*         Report Count (1),            */
+	 0x81, 0x02,                  /*         Input (Variable),            */
+	 0x46, 0xBC, 0x02,            /*         Physical Maximum (700),      */
+	 0x26, 0x34, 0x05,            /*         Logical Maximum (1332),      */
+	 0x09, 0x31,                  /*         Usage (Y),                   */
+	 0x81, 0x02,                  /*         Input (Variable),            */
+	 0xC0,                        /*     End Collection,                  */
+	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
+	 0x09, 0x22,                  /*     Usage (Finger),                  */
+	 0xA1, 0x02,                  /*     Collection (Logical),            */
+	 0x25, 0x01,                  /*         Logical Maximum (1),         */
+	 0x09, 0x47,                  /*         Usage (Touch Valid),         */
+	 0x09, 0x42,                  /*         Usage (Tip Switch),          */
+	 0x95, 0x02,                  /*         Report Count (2),            */
+	 0x75, 0x01,                  /*         Report Size (1),             */
+	 0x81, 0x02,                  /*         Input (Variable),            */
+	 0x95, 0x01,                  /*         Report Count (1),            */
+	 0x75, 0x03,                  /*         Report Size (3),             */
+	 0x25, 0x05,                  /*         Logical Maximum (5),         */
+	 0x09, 0x51,                  /*         Usage (Contact Identifier),  */
+	 0x81, 0x02,                  /*         Input (Variable),            */
+	 0x75, 0x01,                  /*         Report Size (1),             */
+	 0x95, 0x03,                  /*         Report Count (3),            */
+	 0x81, 0x03,                  /*         Input (Constant, Variable),  */
+	 0x05, 0x01,                  /*         Usage Page (Desktop),        */
+	 0x26, 0x44, 0x0A,            /*         Logical Maximum (2628),      */
+	 0x75, 0x10,                  /*         Report Size (16),            */
+	 0x09, 0x30,                  /*         Usage (X),                   */
+	 0x46, 0x1A, 0x04,            /*         Physical Maximum (1050),     */
+	 0x95, 0x01,                  /*         Report Count (1),            */
+	 0x81, 0x02,                  /*         Input (Variable),            */
+	 0x46, 0xBC, 0x02,            /*         Physical Maximum (700),      */
+	 0x26, 0x34, 0x05,            /*         Logical Maximum (1332),      */
+	 0x09, 0x31,                  /*         Usage (Y),                   */
+	 0x81, 0x02,                  /*         Input (Variable),            */
+	 0xC0,                        /*     End Collection,                  */
+	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
+	 0x55, 0x0C,                  /*     Unit Exponent (12),              */
+	 0x66, 0x01, 0x10,            /*     Unit (Seconds),                  */
+	 0x47, 0xFF, 0xFF, 0x00, 0x00,/*     Physical Maximum (65535),        */
+	 0x27, 0xFF, 0xFF, 0x00, 0x00,/*     Logical Maximum (65535),         */
+	 0x75, 0x10,                  /*     Report Size (16),                */
+	 0x95, 0x01,                  /*     Report Count (1),                */
+	 0x09, 0x56,                  /*     Usage (Scan Time),               */
+	 0x81, 0x02,                  /*     Input (Variable),                */
+	 0x09, 0x54,                  /*     Usage (Contact Count),           */
+	 0x25, 0x7F,                  /*     Logical Maximum (127),           */
+	 0x75, 0x08,                  /*     Report Size (8),                 */
+	 0x81, 0x02,                  /*     Input (Variable),                */
+	 0x05, 0x09,                  /*     Usage Page (Button),             */
+	 0x09, 0x01,                  /*     Usage (01h),                     */
+	 0x25, 0x01,                  /*     Logical Maximum (1),             */
+	 0x75, 0x01,                  /*     Report Size (1),                 */
+	 0x95, 0x01,                  /*     Report Count (1),                */
+	 0x81, 0x02,                  /*     Input (Variable),                */
+	 0x95, 0x07,                  /*     Report Count (7),                */
+	 0x81, 0x03,                  /*     Input (Constant, Variable),      */
+	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
+	 0x85, 0x02,                  /*     Report ID (2),                   */
+	 0x09, 0x55,                  /*     Usage (Contact Count Maximum),   */
+	 0x09, 0x59,                  /*     Usage (59h),                     */
+	 0x75, 0x04,                  /*     Report Size (4),                 */
+	 0x95, 0x02,                  /*     Report Count (2),                */
+	 0x25, 0x0F,                  /*     Logical Maximum (15),            */
+	 0xB1, 0x02,                  /*     Feature (Variable),              */
+	 0x05, 0x0D,                  /*     Usage Page (Digitizer),          */
+	 0x85, 0x07,                  /*     Report ID (7),                   */
+	 0x09, 0x60,                  /*     Usage (60h),                     */
+	 0x75, 0x01,                  /*     Report Size (1),                 */
+	 0x95, 0x01,                  /*     Report Count (1),                */
+	 0x25, 0x01,                  /*     Logical Maximum (1),             */
+	 0xB1, 0x02,                  /*     Feature (Variable),              */
+	 0x95, 0x07,                  /*     Report Count (7),                */
+	 0xB1, 0x03,                  /*     Feature (Constant, Variable),    */
+	 0x85, 0x06,                  /*     Report ID (6),                   */
+	 0x06, 0x00, 0xFF,            /*     Usage Page (FF00h),              */
+	 0x09, 0xC5,                  /*     Usage (C5h),                     */
+	 0x26, 0xFF, 0x00,            /*     Logical Maximum (255),           */
+	 0x75, 0x08,                  /*     Report Size (8),                 */
+	 0x96, 0x00, 0x01,            /*     Report Count (256),              */
+	 0xB1, 0x02,                  /*     Feature (Variable),              */
+	 0xC0,                        /* End Collection,                      */
+	 0x06, 0x00, 0xFF,            /* Usage Page (FF00h),                  */
+	 0x09, 0x01,                  /* Usage (01h),                         */
+	 0xA1, 0x01,                  /* Collection (Application),            */
+	 0x85, 0x0D,                  /*     Report ID (13),                  */
+	 0x26, 0xFF, 0x00,            /*     Logical Maximum (255),           */
+	 0x19, 0x01,                  /*     Usage Minimum (01h),             */
+	 0x29, 0x02,                  /*     Usage Maximum (02h),             */
+	 0x75, 0x08,                  /*     Report Size (8),                 */
+	 0x95, 0x02,                  /*     Report Count (2),                */
+	 0xB1, 0x02,                  /*     Feature (Variable),              */
+	 0xC0,                        /* End Collection,                      */
+	 0x05, 0x0D,                  /* Usage Page (Digitizer),              */
+	 0x09, 0x0E,                  /* Usage (Configuration),               */
+	 0xA1, 0x01,                  /* Collection (Application),            */
+	 0x85, 0x03,                  /*     Report ID (3),                   */
+	 0x09, 0x22,                  /*     Usage (Finger),                  */
+	 0xA1, 0x02,                  /*     Collection (Logical),            */
+	 0x09, 0x52,                  /*         Usage (Device Mode),         */
+	 0x25, 0x0A,                  /*         Logical Maximum (10),        */
+	 0x95, 0x01,                  /*         Report Count (1),            */
+	 0xB1, 0x02,                  /*         Feature (Variable),          */
+	 0xC0,                        /*     End Collection,                  */
+	 0x09, 0x22,                  /*     Usage (Finger),                  */
+	 0xA1, 0x00,                  /*     Collection (Physical),           */
+	 0x85, 0x05,                  /*         Report ID (5),               */
+	 0x09, 0x57,                  /*         Usage (57h),                 */
+	 0x09, 0x58,                  /*         Usage (58h),                 */
+	 0x75, 0x01,                  /*         Report Size (1),             */
+	 0x95, 0x02,                  /*         Report Count (2),            */
+	 0x25, 0x01,                  /*         Logical Maximum (1),         */
+	 0xB1, 0x02,                  /*         Feature (Variable),          */
+	 0x95, 0x06,                  /*         Report Count (6),            */
+	 0xB1, 0x03,                  /*         Feature (Constant, Variable),*/
+	 0xC0,                        /*     End Collection,                  */
+	 0xC0                         /* End Collection                       */
+	},
+	.hid_report_desc_size = 475,
+	.i2c_name = "SYNA3602:00"
+};
+
+
+static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
+	{
+		.ident = "Teclast F6 Pro",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F6 Pro"),
+		},
+		.driver_data = (void *)&sipodev_desc
+	},
+	{
+		.ident = "Teclast F7",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F7"),
+		},
+		.driver_data = (void *)&sipodev_desc
+	},
+	{
+		.ident = "Trekstor Primebook C13",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C13"),
+		},
+		.driver_data = (void *)&sipodev_desc
+	},
+	{
+		.ident = "Trekstor Primebook C11",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C11"),
+		},
+		.driver_data = (void *)&sipodev_desc
+	},
+	{
+		.ident = "Direkt-Tek DTLAPY116-2",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Direkt-Tek"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "DTLAPY116-2"),
+		},
+		.driver_data = (void *)&sipodev_desc
+	}
+};
+
+
+struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name)
+{
+	struct i2c_hid_desc_override *override;
+	const struct dmi_system_id *system_id;
+
+	system_id = dmi_first_match(i2c_hid_dmi_desc_override_table);
+	if (!system_id)
+		return NULL;
+
+	override = system_id->driver_data;
+	if (strcmp(override->i2c_name, i2c_name))
+		return NULL;
+
+	return override->i2c_hid_desc;
+}
+
+char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
+					       unsigned int *size)
+{
+	struct i2c_hid_desc_override *override;
+	const struct dmi_system_id *system_id;
+
+	system_id = dmi_first_match(i2c_hid_dmi_desc_override_table);
+	if (!system_id)
+		return NULL;
+
+	override = system_id->driver_data;
+	if (strcmp(override->i2c_name, i2c_name))
+		return NULL;
+
+	*size = override->hid_report_desc_size;
+	return override->hid_report_desc;
+}
+
diff --git a/drivers/hid/i2c-hid/i2c-hid.h b/drivers/hid/i2c-hid/i2c-hid.h
new file mode 100644
index 000000000..a8c19aef5
--- /dev/null
+++ b/drivers/hid/i2c-hid/i2c-hid.h
@@ -0,0 +1,20 @@ 
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef I2C_HID_H
+#define I2C_HID_H
+
+
+#ifdef CONFIG_DMI
+struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name);
+char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
+					       unsigned int *size);
+#else
+static inline struct i2c_hid_desc
+		   *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name)
+{ return NULL; }
+static inline char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
+							     unsigned int *size)
+{ return NULL; }
+#endif
+
+#endif