Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9ee3e066 authored by Julian Sax's avatar Julian Sax Committed by Jiri Kosina
Browse files

HID: i2c-hid: override HID descriptors for certain devices

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: default avatar <ahormann@gmx.net>
Reported-and-tested-by: default avatarBruno Jesus <bruno.fl.jesus@gmail.com>
Reported-and-tested-by: default avatarDietrich <enaut.w@googlemail.com>
Reported-and-tested-by: default avatar <kloxdami@yahoo.com>
Signed-off-by: default avatarJulian Sax <jsbc@gmx.de>
Reviewed-by: default avatarBenjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent dc4e05d0
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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
+40 −20
Original line number Diff line number Diff line
@@ -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)
@@ -669,6 +670,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__);

@@ -687,6 +689,13 @@ static int i2c_hid_parse(struct hid_device *hid)
	if (ret)
		return ret;

	use_override = i2c_hid_get_dmi_hid_report_desc_override(client->name,
								&rsize);

	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) {
@@ -696,17 +705,21 @@ static int i2c_hid_parse(struct hid_device *hid)

		i2c_hid_dbg(ihid, "asking HID report descriptor\n");

	ret = i2c_hid_command(client, &hid_report_descr_cmd, rdesc, rsize);
		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);
	if (!use_override)
		kfree(rdesc);

	if (ret) {
		dbg_hid("parsing report descriptor failed\n");
		return ret;
@@ -833,13 +846,20 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
	int ret;

	/* i2c hid fetch using a fixed descriptor size (30 bytes) */
	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,
		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:
	 * bytes 0-1 -> length
+376 −0

File added.

Preview size limit exceeded, changes collapsed.

+20 −0
Original line number Diff line number Diff line
/* 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