Skip to content

Commit

Permalink
HID: i2c-hid: override HID descriptors for certain devices
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Julian Sax authored and Jiri Kosina committed Sep 29, 2018
1 parent dc4e05d commit 9ee3e06
Show file tree
Hide file tree
Showing 4 changed files with 439 additions and 20 deletions.
3 changes: 3 additions & 0 deletions drivers/hid/i2c-hid/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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__);

Expand All @@ -687,26 +689,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;
Expand Down Expand Up @@ -833,12 +846,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:
Expand Down
Loading

0 comments on commit 9ee3e06

Please sign in to comment.