Skip to content

Commit 9ee3e06

Browse files
brotfessorJiri Kosina
authored andcommitted
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: 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> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
1 parent dc4e05d commit 9ee3e06

File tree

4 files changed

+439
-20
lines changed

4 files changed

+439
-20
lines changed

drivers/hid/i2c-hid/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@
33
#
44

55
obj-$(CONFIG_I2C_HID) += i2c-hid.o
6+
7+
i2c-hid-objs = i2c-hid-core.o
8+
i2c-hid-$(CONFIG_DMI) += i2c-hid-dmi-quirks.o

drivers/hid/i2c-hid/i2c-hid.c renamed to drivers/hid/i2c-hid/i2c-hid-core.c

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include <linux/platform_data/i2c-hid.h>
4444

4545
#include "../hid-ids.h"
46+
#include "i2c-hid.h"
4647

4748
/* quirks to control the device */
4849
#define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0)
@@ -669,6 +670,7 @@ static int i2c_hid_parse(struct hid_device *hid)
669670
char *rdesc;
670671
int ret;
671672
int tries = 3;
673+
char *use_override;
672674

673675
i2c_hid_dbg(ihid, "entering %s\n", __func__);
674676

@@ -687,26 +689,37 @@ static int i2c_hid_parse(struct hid_device *hid)
687689
if (ret)
688690
return ret;
689691

690-
rdesc = kzalloc(rsize, GFP_KERNEL);
692+
use_override = i2c_hid_get_dmi_hid_report_desc_override(client->name,
693+
&rsize);
691694

692-
if (!rdesc) {
693-
dbg_hid("couldn't allocate rdesc memory\n");
694-
return -ENOMEM;
695-
}
696-
697-
i2c_hid_dbg(ihid, "asking HID report descriptor\n");
698-
699-
ret = i2c_hid_command(client, &hid_report_descr_cmd, rdesc, rsize);
700-
if (ret) {
701-
hid_err(hid, "reading report descriptor failed\n");
702-
kfree(rdesc);
703-
return -EIO;
695+
if (use_override) {
696+
rdesc = use_override;
697+
i2c_hid_dbg(ihid, "Using a HID report descriptor override\n");
698+
} else {
699+
rdesc = kzalloc(rsize, GFP_KERNEL);
700+
701+
if (!rdesc) {
702+
dbg_hid("couldn't allocate rdesc memory\n");
703+
return -ENOMEM;
704+
}
705+
706+
i2c_hid_dbg(ihid, "asking HID report descriptor\n");
707+
708+
ret = i2c_hid_command(client, &hid_report_descr_cmd,
709+
rdesc, rsize);
710+
if (ret) {
711+
hid_err(hid, "reading report descriptor failed\n");
712+
kfree(rdesc);
713+
return -EIO;
714+
}
704715
}
705716

706717
i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc);
707718

708719
ret = hid_parse_report(hid, rdesc, rsize);
709-
kfree(rdesc);
720+
if (!use_override)
721+
kfree(rdesc);
722+
710723
if (ret) {
711724
dbg_hid("parsing report descriptor failed\n");
712725
return ret;
@@ -833,12 +846,19 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
833846
int ret;
834847

835848
/* i2c hid fetch using a fixed descriptor size (30 bytes) */
836-
i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
837-
ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer,
838-
sizeof(struct i2c_hid_desc));
839-
if (ret) {
840-
dev_err(&client->dev, "hid_descr_cmd failed\n");
841-
return -ENODEV;
849+
if (i2c_hid_get_dmi_i2c_hid_desc_override(client->name)) {
850+
i2c_hid_dbg(ihid, "Using a HID descriptor override\n");
851+
ihid->hdesc =
852+
*i2c_hid_get_dmi_i2c_hid_desc_override(client->name);
853+
} else {
854+
i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
855+
ret = i2c_hid_command(client, &hid_descr_cmd,
856+
ihid->hdesc_buffer,
857+
sizeof(struct i2c_hid_desc));
858+
if (ret) {
859+
dev_err(&client->dev, "hid_descr_cmd failed\n");
860+
return -ENODEV;
861+
}
842862
}
843863

844864
/* Validate the length of HID descriptor, the 4 first bytes:

0 commit comments

Comments
 (0)