From patchwork Tue May 22 19:54:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Sax X-Patchwork-Id: 10419541 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id E20F06032A for ; Tue, 22 May 2018 19:55:27 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CDFDC28E64 for ; Tue, 22 May 2018 19:55:27 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BF5FA28E97; Tue, 22 May 2018 19:55:27 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,FREEMAIL_FROM, MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C2E1628E64 for ; Tue, 22 May 2018 19:55:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752163AbeEVTz0 (ORCPT ); Tue, 22 May 2018 15:55:26 -0400 Received: from mout.gmx.net ([212.227.17.22]:58861 "EHLO mout.gmx.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752161AbeEVTzZ (ORCPT ); Tue, 22 May 2018 15:55:25 -0400 Received: from chef.lew.wohnheim ([131.188.23.42]) by mail.gmx.com (mrgmx102 [212.227.17.168]) with ESMTPSA (Nemesis) id 0MEtba-1fb7g93oZG-00G4o7; Tue, 22 May 2018 21:55:16 +0200 From: Julian Sax To: linux-input@vger.kernel.org Cc: Jiri Kosina , Benjamin Tissoires , Julian Sax , Hans de Goede Subject: [PATCH] hid/i2c-hid: override HID descriptors for certain devices Date: Tue, 22 May 2018 21:54:27 +0200 Message-Id: <20180522195427.25853-1-jsbc@gmx.de> X-Mailer: git-send-email 2.17.0 X-Provags-ID: V03:K1:c1U5iU6rps7em0DKxEuZQnskfaEWGcXvJ+40e9A7O+nzWVmZtHX +Egp0Szax8TxMeRZb8MPzozv/dz4PSCkEenJIITcNfymxpRsxNe5jZkmmri4mv8kP6UGjOY org/D5SqGk/DtUOh3RcvQ5sowCirBWJ/AOJhBzCcoZ0V9beyLtFdt2V4IIZuwm5BbxuXkdv AXyIkuQ32frLBj5e6N3UA== X-UI-Out-Filterresults: notjunk:1; V01:K0:JvklO+2XZ9Q=:HEHUV43QmtSv5qauQ8Gckn +x2fFP0+Qd0CGvc3gIw/MAcwvlzCmuFcmbSv5Td+YBC+BXr8K8XOksf8ZS7gcZL4PDeARw2BL KlUiydcE2loEM+UgwEX0OyqNAO1Jv0ln0wlT0j+8aIksli8S7y2LHQBbBShAMs7US8wda/fqQ og2+AAj0feNl/Uau6hUKqJSum/YgQx0W7TrL2w5Fm74ZdcpH0S+5aZza6XDNFhBE46+ntfuMT qpz7C4915o2yHw/c2m92/jZwMSsT22e+GOxUhY7btijDjOIkzcMUzuMnGkRgZrTfCYdi4a22o Jn+MyWT8pu6yqia5Wxf5mxvwoNKBRfq9h7yqb3AykU2vaXAqeznac66F/5t6V3bc+teD+V4ZF FGvHtpBLnb1jh/qGF6/7wK+IgBhcdG1QV2ZDO2Qq6oPy+hto4v7UgLNt8Ge2c+T+aaJ8ZOJFF dJhmX0O3rldkfb5UVgpXuxCagzfgKFYPdYEYZtjoPFM8hU7WcGGKKBGSu0v7JYD6LCqFKFgAk Mj+giMmvh9gpJZ6A5qWiooDr8wB7RHEPK4rXNWSfGjzFSLOIg86T/h+7ONLCtDysidnGSyoX1 OaFF9NVKfd2pKNw8K2H4uY7O63ACiI8tz/srzE3nTSBhQ9ZGzuoUJ8F0Bw/hcIFbGS32AVPuR BaQQT3VdKXJxaXVNJGtwL1iV4FqqLD+3QSPViOheAxXipYi+b40+aAlkNQm8Wz0uSVTvZc1ou AlRTWwJ1BVA+W31vO9JNJ2arYqYa46NyIhBsNLnoJ8lrhgc9AyzGOGEgCYY= Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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, as well as the DMI data for the 4 laptops known to use this device. Relevant Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1526312 Cc: Hans de Goede Reported-and-tested-by: ahormann@gmx.net Reported-and-tested-by: Bruno Jesus Reported-and-tested-by: Dietrich Reported-and-tested-by: kloxdami@yahoo.com Signed-off-by: Julian Sax Reviewed-by: Hans de Goede Acked-By: Benjamin Tissoires --- drivers/hid/i2c-hid/Makefile | 3 + .../hid/i2c-hid/{i2c-hid.c => i2c-hid-core.c} | 54 ++++--- drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c | 149 ++++++++++++++++++ drivers/hid/i2c-hid/i2c-hid.h | 17 ++ 4 files changed, 205 insertions(+), 18 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 832d8f9aaba2..099e1ce2f234 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 cc33622253aa..3cdd1e1aeb95 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -43,6 +43,7 @@ #include #include "../hid-ids.h" +#include "i2c-hid.h" /* quirks to control the device */ #define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0) @@ -673,6 +674,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__); @@ -691,26 +693,36 @@ 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(&rsize); - if (!rdesc) { - dbg_hid("couldn't allocate rdesc memory\n"); - return -ENOMEM; - } + if (use_override) { + rdesc = use_override; + i2c_hid_dbg(ihid, "Using a HID report descriptor override\n"); + } else { + rdesc = kzalloc(rsize, GFP_KERNEL); - i2c_hid_dbg(ihid, "asking HID report descriptor\n"); + if (!rdesc) { + dbg_hid("couldn't allocate rdesc memory\n"); + return -ENOMEM; + } - 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, "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; @@ -837,12 +849,18 @@ 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()) { + i2c_hid_dbg(ihid, "Using a HID descriptor override\n"); + ihid->hdesc = *i2c_hid_get_dmi_i2c_hid_desc_override(); + } 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 000000000000..400f076c6be3 --- /dev/null +++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * Quirks for I2C-HID devices that do not supply proper descriptors + * + * Copyright (c) 2018 Julian Sax + * + */ + +#include +#include +#include + +#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; +}; + + +/* descriptors for the SIPODEV SP1064 touchpad */ +static const struct i2c_hid_desc_override sipodev_desc = { + .i2c_hid_desc_buffer = (uint8_t []) + {0x1e, 0x00, 0x00, 0x01, 0xdb, 0x01, 0x21, 0x00, 0x24, 0x00, + 0x1b, 0x00, 0x25, 0x00, 0x11, 0x00, 0x22, 0x00, 0x23, 0x00, + 0x11, 0x09, 0x88, 0x52, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, + + .hid_report_desc = (uint8_t []) + {0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x85, 0x01, 0x09, 0x01, + 0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x02, 0x25, 0x01, + 0x75, 0x01, 0x95, 0x02, 0x81, 0x02, 0x95, 0x06, 0x81, 0x01, + 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81, 0x25, 0x7f, + 0x75, 0x08, 0x95, 0x02, 0x81, 0x06, 0xc0, 0xc0, 0x05, 0x0d, + 0x09, 0x05, 0xa1, 0x01, 0x85, 0x04, 0x05, 0x0d, 0x09, 0x22, + 0xa1, 0x02, 0x15, 0x00, 0x25, 0x01, 0x09, 0x47, 0x09, 0x42, + 0x95, 0x02, 0x75, 0x01, 0x81, 0x02, 0x95, 0x01, 0x75, 0x03, + 0x25, 0x05, 0x09, 0x51, 0x81, 0x02, 0x75, 0x01, 0x95, 0x03, + 0x81, 0x03, 0x05, 0x01, 0x26, 0x44, 0x0a, 0x75, 0x10, 0x55, + 0x0e, 0x65, 0x11, 0x09, 0x30, 0x46, 0x1a, 0x04, 0x95, 0x01, + 0x81, 0x02, 0x46, 0xbc, 0x02, 0x26, 0x34, 0x05, 0x09, 0x31, + 0x81, 0x02, 0xc0, 0x05, 0x0d, 0x09, 0x22, 0xa1, 0x02, 0x25, + 0x01, 0x09, 0x47, 0x09, 0x42, 0x95, 0x02, 0x75, 0x01, 0x81, + 0x02, 0x95, 0x01, 0x75, 0x03, 0x25, 0x05, 0x09, 0x51, 0x81, + 0x02, 0x75, 0x01, 0x95, 0x03, 0x81, 0x03, 0x05, 0x01, 0x26, + 0x44, 0x0a, 0x75, 0x10, 0x09, 0x30, 0x46, 0x1a, 0x04, 0x95, + 0x01, 0x81, 0x02, 0x46, 0xbc, 0x02, 0x26, 0x34, 0x05, 0x09, + 0x31, 0x81, 0x02, 0xc0, 0x05, 0x0d, 0x09, 0x22, 0xa1, 0x02, + 0x25, 0x01, 0x09, 0x47, 0x09, 0x42, 0x95, 0x02, 0x75, 0x01, + 0x81, 0x02, 0x95, 0x01, 0x75, 0x03, 0x25, 0x05, 0x09, 0x51, + 0x81, 0x02, 0x75, 0x01, 0x95, 0x03, 0x81, 0x03, 0x05, 0x01, + 0x26, 0x44, 0x0a, 0x75, 0x10, 0x09, 0x30, 0x46, 0x1a, 0x04, + 0x95, 0x01, 0x81, 0x02, 0x46, 0xbc, 0x02, 0x26, 0x34, 0x05, + 0x09, 0x31, 0x81, 0x02, 0xc0, 0x05, 0x0d, 0x09, 0x22, 0xa1, + 0x02, 0x25, 0x01, 0x09, 0x47, 0x09, 0x42, 0x95, 0x02, 0x75, + 0x01, 0x81, 0x02, 0x95, 0x01, 0x75, 0x03, 0x25, 0x05, 0x09, + 0x51, 0x81, 0x02, 0x75, 0x01, 0x95, 0x03, 0x81, 0x03, 0x05, + 0x01, 0x26, 0x44, 0x0a, 0x75, 0x10, 0x09, 0x30, 0x46, 0x1a, + 0x04, 0x95, 0x01, 0x81, 0x02, 0x46, 0xbc, 0x02, 0x26, 0x34, + 0x05, 0x09, 0x31, 0x81, 0x02, 0xc0, 0x05, 0x0d, 0x55, 0x0c, + 0x66, 0x01, 0x10, 0x47, 0xff, 0xff, 0x00, 0x00, 0x27, 0xff, + 0xff, 0x00, 0x00, 0x75, 0x10, 0x95, 0x01, 0x09, 0x56, 0x81, + 0x02, 0x09, 0x54, 0x25, 0x7f, 0x75, 0x08, 0x81, 0x02, 0x05, + 0x09, 0x09, 0x01, 0x25, 0x01, 0x75, 0x01, 0x95, 0x01, 0x81, + 0x02, 0x95, 0x07, 0x81, 0x03, 0x05, 0x0d, 0x85, 0x02, 0x09, + 0x55, 0x09, 0x59, 0x75, 0x04, 0x95, 0x02, 0x25, 0x0f, 0xb1, + 0x02, 0x05, 0x0d, 0x85, 0x07, 0x09, 0x60, 0x75, 0x01, 0x95, + 0x01, 0x25, 0x01, 0xb1, 0x02, 0x95, 0x07, 0xb1, 0x03, 0x85, + 0x06, 0x06, 0x00, 0xff, 0x09, 0xc5, 0x26, 0xff, 0x00, 0x75, + 0x08, 0x96, 0x00, 0x01, 0xb1, 0x02, 0xc0, 0x06, 0x00, 0xff, + 0x09, 0x01, 0xa1, 0x01, 0x85, 0x0d, 0x26, 0xff, 0x00, 0x19, + 0x01, 0x29, 0x02, 0x75, 0x08, 0x95, 0x02, 0xb1, 0x02, 0xc0, + 0x05, 0x0d, 0x09, 0x0e, 0xa1, 0x01, 0x85, 0x03, 0x09, 0x22, + 0xa1, 0x02, 0x09, 0x52, 0x25, 0x0a, 0x95, 0x01, 0xb1, 0x02, + 0xc0, 0x09, 0x22, 0xa1, 0x00, 0x85, 0x05, 0x09, 0x57, 0x09, + 0x58, 0x75, 0x01, 0x95, 0x02, 0x25, 0x01, 0xb1, 0x02, 0x95, + 0x06, 0xb1, 0x03, 0xc0, 0xc0 }, + .hid_report_desc_size = 475 +}; + + +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 + } +}; + + +struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(void) +{ + 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; + return override->i2c_hid_desc; +} + +char *i2c_hid_get_dmi_hid_report_desc_override(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; + *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 000000000000..c543bb5ef1c1 --- /dev/null +++ b/drivers/hid/i2c-hid/i2c-hid.h @@ -0,0 +1,17 @@ +/* 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(void); +char *i2c_hid_get_dmi_hid_report_desc_override(unsigned int *size); +#else +static inline struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(void) +{ return NULL; } +static inline char *i2c_hid_get_dmi_hid_report_desc_override(unsigned int *size) +{ return NULL; } +#endif + +#endif