]>
Commit | Line | Data |
---|---|---|
5ddacef6 SLM |
1 | From 33c620b67b7660349ac1b62746b101499e68445c Mon Sep 17 00:00:00 2001 |
2 | From: Julian Sax <jsbc@gmx.de> | |
3 | Date: Wed, 19 Sep 2018 11:46:23 +0200 | |
4 | Subject: HID: i2c-hid: override HID descriptors for certain devices | |
5 | ||
6 | [ Upstream commit 9ee3e06610fdb8a601cde59c92089fb6c1deb4aa ] | |
7 | ||
8 | A particular touchpad (SIPODEV SP1064) refuses to supply the HID | |
9 | descriptors. This patch provides the framework for overriding these | |
10 | descriptors based on DMI data. It also includes the descriptors for | |
11 | said touchpad, which were extracted by listening to the traffic of the | |
12 | windows filter driver, as well as the DMI data for the laptops known | |
13 | to use this device. | |
14 | ||
15 | Relevant Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1526312 | |
16 | ||
17 | Cc: Hans de Goede <hdegoede@redhat.com> | |
18 | Reported-and-tested-by: ahormann@gmx.net | |
19 | Reported-and-tested-by: Bruno Jesus <bruno.fl.jesus@gmail.com> | |
20 | Reported-and-tested-by: Dietrich <enaut.w@googlemail.com> | |
21 | Reported-and-tested-by: kloxdami@yahoo.com | |
22 | Signed-off-by: Julian Sax <jsbc@gmx.de> | |
23 | Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> | |
24 | Signed-off-by: Jiri Kosina <jkosina@suse.cz> | |
25 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
26 | --- | |
27 | drivers/hid/i2c-hid/Makefile | 3 + | |
28 | .../hid/i2c-hid/{i2c-hid.c => i2c-hid-core.c} | 56 ++- | |
29 | drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c | 376 ++++++++++++++++++ | |
30 | drivers/hid/i2c-hid/i2c-hid.h | 20 + | |
31 | 4 files changed, 437 insertions(+), 18 deletions(-) | |
32 | rename drivers/hid/i2c-hid/{i2c-hid.c => i2c-hid-core.c} (96%) | |
33 | create mode 100644 drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c | |
34 | create mode 100644 drivers/hid/i2c-hid/i2c-hid.h | |
35 | ||
36 | diff --git a/drivers/hid/i2c-hid/Makefile b/drivers/hid/i2c-hid/Makefile | |
37 | index 832d8f9aaba2..099e1ce2f234 100644 | |
38 | --- a/drivers/hid/i2c-hid/Makefile | |
39 | +++ b/drivers/hid/i2c-hid/Makefile | |
40 | @@ -3,3 +3,6 @@ | |
41 | # | |
42 | ||
43 | obj-$(CONFIG_I2C_HID) += i2c-hid.o | |
44 | + | |
45 | +i2c-hid-objs = i2c-hid-core.o | |
46 | +i2c-hid-$(CONFIG_DMI) += i2c-hid-dmi-quirks.o | |
47 | diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid-core.c | |
48 | similarity index 96% | |
49 | rename from drivers/hid/i2c-hid/i2c-hid.c | |
50 | rename to drivers/hid/i2c-hid/i2c-hid-core.c | |
51 | index ce2b80009c19..850527d5fab1 100644 | |
52 | --- a/drivers/hid/i2c-hid/i2c-hid.c | |
53 | +++ b/drivers/hid/i2c-hid/i2c-hid-core.c | |
54 | @@ -42,6 +42,7 @@ | |
55 | #include <linux/i2c/i2c-hid.h> | |
56 | ||
57 | #include "../hid-ids.h" | |
58 | +#include "i2c-hid.h" | |
59 | ||
60 | /* quirks to control the device */ | |
61 | #define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0) | |
62 | @@ -724,6 +725,7 @@ static int i2c_hid_parse(struct hid_device *hid) | |
63 | char *rdesc; | |
64 | int ret; | |
65 | int tries = 3; | |
66 | + char *use_override; | |
67 | ||
68 | i2c_hid_dbg(ihid, "entering %s\n", __func__); | |
69 | ||
70 | @@ -742,26 +744,37 @@ static int i2c_hid_parse(struct hid_device *hid) | |
71 | if (ret) | |
72 | return ret; | |
73 | ||
74 | - rdesc = kzalloc(rsize, GFP_KERNEL); | |
75 | + use_override = i2c_hid_get_dmi_hid_report_desc_override(client->name, | |
76 | + &rsize); | |
77 | ||
78 | - if (!rdesc) { | |
79 | - dbg_hid("couldn't allocate rdesc memory\n"); | |
80 | - return -ENOMEM; | |
81 | - } | |
82 | + if (use_override) { | |
83 | + rdesc = use_override; | |
84 | + i2c_hid_dbg(ihid, "Using a HID report descriptor override\n"); | |
85 | + } else { | |
86 | + rdesc = kzalloc(rsize, GFP_KERNEL); | |
87 | ||
88 | - i2c_hid_dbg(ihid, "asking HID report descriptor\n"); | |
89 | + if (!rdesc) { | |
90 | + dbg_hid("couldn't allocate rdesc memory\n"); | |
91 | + return -ENOMEM; | |
92 | + } | |
93 | ||
94 | - ret = i2c_hid_command(client, &hid_report_descr_cmd, rdesc, rsize); | |
95 | - if (ret) { | |
96 | - hid_err(hid, "reading report descriptor failed\n"); | |
97 | - kfree(rdesc); | |
98 | - return -EIO; | |
99 | + i2c_hid_dbg(ihid, "asking HID report descriptor\n"); | |
100 | + | |
101 | + ret = i2c_hid_command(client, &hid_report_descr_cmd, | |
102 | + rdesc, rsize); | |
103 | + if (ret) { | |
104 | + hid_err(hid, "reading report descriptor failed\n"); | |
105 | + kfree(rdesc); | |
106 | + return -EIO; | |
107 | + } | |
108 | } | |
109 | ||
110 | i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc); | |
111 | ||
112 | ret = hid_parse_report(hid, rdesc, rsize); | |
113 | - kfree(rdesc); | |
114 | + if (!use_override) | |
115 | + kfree(rdesc); | |
116 | + | |
117 | if (ret) { | |
118 | dbg_hid("parsing report descriptor failed\n"); | |
119 | return ret; | |
120 | @@ -899,12 +912,19 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid) | |
121 | int ret; | |
122 | ||
123 | /* i2c hid fetch using a fixed descriptor size (30 bytes) */ | |
124 | - i2c_hid_dbg(ihid, "Fetching the HID descriptor\n"); | |
125 | - ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer, | |
126 | - sizeof(struct i2c_hid_desc)); | |
127 | - if (ret) { | |
128 | - dev_err(&client->dev, "hid_descr_cmd failed\n"); | |
129 | - return -ENODEV; | |
130 | + if (i2c_hid_get_dmi_i2c_hid_desc_override(client->name)) { | |
131 | + i2c_hid_dbg(ihid, "Using a HID descriptor override\n"); | |
132 | + ihid->hdesc = | |
133 | + *i2c_hid_get_dmi_i2c_hid_desc_override(client->name); | |
134 | + } else { | |
135 | + i2c_hid_dbg(ihid, "Fetching the HID descriptor\n"); | |
136 | + ret = i2c_hid_command(client, &hid_descr_cmd, | |
137 | + ihid->hdesc_buffer, | |
138 | + sizeof(struct i2c_hid_desc)); | |
139 | + if (ret) { | |
140 | + dev_err(&client->dev, "hid_descr_cmd failed\n"); | |
141 | + return -ENODEV; | |
142 | + } | |
143 | } | |
144 | ||
145 | /* Validate the length of HID descriptor, the 4 first bytes: | |
146 | diff --git a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c | |
147 | new file mode 100644 | |
148 | index 000000000000..1d645c9ab417 | |
149 | --- /dev/null | |
150 | +++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c | |
151 | @@ -0,0 +1,376 @@ | |
152 | +// SPDX-License-Identifier: GPL-2.0+ | |
153 | + | |
154 | +/* | |
155 | + * Quirks for I2C-HID devices that do not supply proper descriptors | |
156 | + * | |
157 | + * Copyright (c) 2018 Julian Sax <jsbc@gmx.de> | |
158 | + * | |
159 | + */ | |
160 | + | |
161 | +#include <linux/types.h> | |
162 | +#include <linux/dmi.h> | |
163 | +#include <linux/mod_devicetable.h> | |
164 | + | |
165 | +#include "i2c-hid.h" | |
166 | + | |
167 | + | |
168 | +struct i2c_hid_desc_override { | |
169 | + union { | |
170 | + struct i2c_hid_desc *i2c_hid_desc; | |
171 | + uint8_t *i2c_hid_desc_buffer; | |
172 | + }; | |
173 | + uint8_t *hid_report_desc; | |
174 | + unsigned int hid_report_desc_size; | |
175 | + uint8_t *i2c_name; | |
176 | +}; | |
177 | + | |
178 | + | |
179 | +/* | |
180 | + * descriptors for the SIPODEV SP1064 touchpad | |
181 | + * | |
182 | + * This device does not supply any descriptors and on windows a filter | |
183 | + * driver operates between the i2c-hid layer and the device and injects | |
184 | + * these descriptors when the device is prompted. The descriptors were | |
185 | + * extracted by listening to the i2c-hid traffic that occurs between the | |
186 | + * windows filter driver and the windows i2c-hid driver. | |
187 | + */ | |
188 | + | |
189 | +static const struct i2c_hid_desc_override sipodev_desc = { | |
190 | + .i2c_hid_desc_buffer = (uint8_t []) | |
191 | + {0x1e, 0x00, /* Length of descriptor */ | |
192 | + 0x00, 0x01, /* Version of descriptor */ | |
193 | + 0xdb, 0x01, /* Length of report descriptor */ | |
194 | + 0x21, 0x00, /* Location of report descriptor */ | |
195 | + 0x24, 0x00, /* Location of input report */ | |
196 | + 0x1b, 0x00, /* Max input report length */ | |
197 | + 0x25, 0x00, /* Location of output report */ | |
198 | + 0x11, 0x00, /* Max output report length */ | |
199 | + 0x22, 0x00, /* Location of command register */ | |
200 | + 0x23, 0x00, /* Location of data register */ | |
201 | + 0x11, 0x09, /* Vendor ID */ | |
202 | + 0x88, 0x52, /* Product ID */ | |
203 | + 0x06, 0x00, /* Version ID */ | |
204 | + 0x00, 0x00, 0x00, 0x00 /* Reserved */ | |
205 | + }, | |
206 | + | |
207 | + .hid_report_desc = (uint8_t []) | |
208 | + {0x05, 0x01, /* Usage Page (Desktop), */ | |
209 | + 0x09, 0x02, /* Usage (Mouse), */ | |
210 | + 0xA1, 0x01, /* Collection (Application), */ | |
211 | + 0x85, 0x01, /* Report ID (1), */ | |
212 | + 0x09, 0x01, /* Usage (Pointer), */ | |
213 | + 0xA1, 0x00, /* Collection (Physical), */ | |
214 | + 0x05, 0x09, /* Usage Page (Button), */ | |
215 | + 0x19, 0x01, /* Usage Minimum (01h), */ | |
216 | + 0x29, 0x02, /* Usage Maximum (02h), */ | |
217 | + 0x25, 0x01, /* Logical Maximum (1), */ | |
218 | + 0x75, 0x01, /* Report Size (1), */ | |
219 | + 0x95, 0x02, /* Report Count (2), */ | |
220 | + 0x81, 0x02, /* Input (Variable), */ | |
221 | + 0x95, 0x06, /* Report Count (6), */ | |
222 | + 0x81, 0x01, /* Input (Constant), */ | |
223 | + 0x05, 0x01, /* Usage Page (Desktop), */ | |
224 | + 0x09, 0x30, /* Usage (X), */ | |
225 | + 0x09, 0x31, /* Usage (Y), */ | |
226 | + 0x15, 0x81, /* Logical Minimum (-127), */ | |
227 | + 0x25, 0x7F, /* Logical Maximum (127), */ | |
228 | + 0x75, 0x08, /* Report Size (8), */ | |
229 | + 0x95, 0x02, /* Report Count (2), */ | |
230 | + 0x81, 0x06, /* Input (Variable, Relative), */ | |
231 | + 0xC0, /* End Collection, */ | |
232 | + 0xC0, /* End Collection, */ | |
233 | + 0x05, 0x0D, /* Usage Page (Digitizer), */ | |
234 | + 0x09, 0x05, /* Usage (Touchpad), */ | |
235 | + 0xA1, 0x01, /* Collection (Application), */ | |
236 | + 0x85, 0x04, /* Report ID (4), */ | |
237 | + 0x05, 0x0D, /* Usage Page (Digitizer), */ | |
238 | + 0x09, 0x22, /* Usage (Finger), */ | |
239 | + 0xA1, 0x02, /* Collection (Logical), */ | |
240 | + 0x15, 0x00, /* Logical Minimum (0), */ | |
241 | + 0x25, 0x01, /* Logical Maximum (1), */ | |
242 | + 0x09, 0x47, /* Usage (Touch Valid), */ | |
243 | + 0x09, 0x42, /* Usage (Tip Switch), */ | |
244 | + 0x95, 0x02, /* Report Count (2), */ | |
245 | + 0x75, 0x01, /* Report Size (1), */ | |
246 | + 0x81, 0x02, /* Input (Variable), */ | |
247 | + 0x95, 0x01, /* Report Count (1), */ | |
248 | + 0x75, 0x03, /* Report Size (3), */ | |
249 | + 0x25, 0x05, /* Logical Maximum (5), */ | |
250 | + 0x09, 0x51, /* Usage (Contact Identifier), */ | |
251 | + 0x81, 0x02, /* Input (Variable), */ | |
252 | + 0x75, 0x01, /* Report Size (1), */ | |
253 | + 0x95, 0x03, /* Report Count (3), */ | |
254 | + 0x81, 0x03, /* Input (Constant, Variable), */ | |
255 | + 0x05, 0x01, /* Usage Page (Desktop), */ | |
256 | + 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */ | |
257 | + 0x75, 0x10, /* Report Size (16), */ | |
258 | + 0x55, 0x0E, /* Unit Exponent (14), */ | |
259 | + 0x65, 0x11, /* Unit (Centimeter), */ | |
260 | + 0x09, 0x30, /* Usage (X), */ | |
261 | + 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */ | |
262 | + 0x95, 0x01, /* Report Count (1), */ | |
263 | + 0x81, 0x02, /* Input (Variable), */ | |
264 | + 0x46, 0xBC, 0x02, /* Physical Maximum (700), */ | |
265 | + 0x26, 0x34, 0x05, /* Logical Maximum (1332), */ | |
266 | + 0x09, 0x31, /* Usage (Y), */ | |
267 | + 0x81, 0x02, /* Input (Variable), */ | |
268 | + 0xC0, /* End Collection, */ | |
269 | + 0x05, 0x0D, /* Usage Page (Digitizer), */ | |
270 | + 0x09, 0x22, /* Usage (Finger), */ | |
271 | + 0xA1, 0x02, /* Collection (Logical), */ | |
272 | + 0x25, 0x01, /* Logical Maximum (1), */ | |
273 | + 0x09, 0x47, /* Usage (Touch Valid), */ | |
274 | + 0x09, 0x42, /* Usage (Tip Switch), */ | |
275 | + 0x95, 0x02, /* Report Count (2), */ | |
276 | + 0x75, 0x01, /* Report Size (1), */ | |
277 | + 0x81, 0x02, /* Input (Variable), */ | |
278 | + 0x95, 0x01, /* Report Count (1), */ | |
279 | + 0x75, 0x03, /* Report Size (3), */ | |
280 | + 0x25, 0x05, /* Logical Maximum (5), */ | |
281 | + 0x09, 0x51, /* Usage (Contact Identifier), */ | |
282 | + 0x81, 0x02, /* Input (Variable), */ | |
283 | + 0x75, 0x01, /* Report Size (1), */ | |
284 | + 0x95, 0x03, /* Report Count (3), */ | |
285 | + 0x81, 0x03, /* Input (Constant, Variable), */ | |
286 | + 0x05, 0x01, /* Usage Page (Desktop), */ | |
287 | + 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */ | |
288 | + 0x75, 0x10, /* Report Size (16), */ | |
289 | + 0x09, 0x30, /* Usage (X), */ | |
290 | + 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */ | |
291 | + 0x95, 0x01, /* Report Count (1), */ | |
292 | + 0x81, 0x02, /* Input (Variable), */ | |
293 | + 0x46, 0xBC, 0x02, /* Physical Maximum (700), */ | |
294 | + 0x26, 0x34, 0x05, /* Logical Maximum (1332), */ | |
295 | + 0x09, 0x31, /* Usage (Y), */ | |
296 | + 0x81, 0x02, /* Input (Variable), */ | |
297 | + 0xC0, /* End Collection, */ | |
298 | + 0x05, 0x0D, /* Usage Page (Digitizer), */ | |
299 | + 0x09, 0x22, /* Usage (Finger), */ | |
300 | + 0xA1, 0x02, /* Collection (Logical), */ | |
301 | + 0x25, 0x01, /* Logical Maximum (1), */ | |
302 | + 0x09, 0x47, /* Usage (Touch Valid), */ | |
303 | + 0x09, 0x42, /* Usage (Tip Switch), */ | |
304 | + 0x95, 0x02, /* Report Count (2), */ | |
305 | + 0x75, 0x01, /* Report Size (1), */ | |
306 | + 0x81, 0x02, /* Input (Variable), */ | |
307 | + 0x95, 0x01, /* Report Count (1), */ | |
308 | + 0x75, 0x03, /* Report Size (3), */ | |
309 | + 0x25, 0x05, /* Logical Maximum (5), */ | |
310 | + 0x09, 0x51, /* Usage (Contact Identifier), */ | |
311 | + 0x81, 0x02, /* Input (Variable), */ | |
312 | + 0x75, 0x01, /* Report Size (1), */ | |
313 | + 0x95, 0x03, /* Report Count (3), */ | |
314 | + 0x81, 0x03, /* Input (Constant, Variable), */ | |
315 | + 0x05, 0x01, /* Usage Page (Desktop), */ | |
316 | + 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */ | |
317 | + 0x75, 0x10, /* Report Size (16), */ | |
318 | + 0x09, 0x30, /* Usage (X), */ | |
319 | + 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */ | |
320 | + 0x95, 0x01, /* Report Count (1), */ | |
321 | + 0x81, 0x02, /* Input (Variable), */ | |
322 | + 0x46, 0xBC, 0x02, /* Physical Maximum (700), */ | |
323 | + 0x26, 0x34, 0x05, /* Logical Maximum (1332), */ | |
324 | + 0x09, 0x31, /* Usage (Y), */ | |
325 | + 0x81, 0x02, /* Input (Variable), */ | |
326 | + 0xC0, /* End Collection, */ | |
327 | + 0x05, 0x0D, /* Usage Page (Digitizer), */ | |
328 | + 0x09, 0x22, /* Usage (Finger), */ | |
329 | + 0xA1, 0x02, /* Collection (Logical), */ | |
330 | + 0x25, 0x01, /* Logical Maximum (1), */ | |
331 | + 0x09, 0x47, /* Usage (Touch Valid), */ | |
332 | + 0x09, 0x42, /* Usage (Tip Switch), */ | |
333 | + 0x95, 0x02, /* Report Count (2), */ | |
334 | + 0x75, 0x01, /* Report Size (1), */ | |
335 | + 0x81, 0x02, /* Input (Variable), */ | |
336 | + 0x95, 0x01, /* Report Count (1), */ | |
337 | + 0x75, 0x03, /* Report Size (3), */ | |
338 | + 0x25, 0x05, /* Logical Maximum (5), */ | |
339 | + 0x09, 0x51, /* Usage (Contact Identifier), */ | |
340 | + 0x81, 0x02, /* Input (Variable), */ | |
341 | + 0x75, 0x01, /* Report Size (1), */ | |
342 | + 0x95, 0x03, /* Report Count (3), */ | |
343 | + 0x81, 0x03, /* Input (Constant, Variable), */ | |
344 | + 0x05, 0x01, /* Usage Page (Desktop), */ | |
345 | + 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */ | |
346 | + 0x75, 0x10, /* Report Size (16), */ | |
347 | + 0x09, 0x30, /* Usage (X), */ | |
348 | + 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */ | |
349 | + 0x95, 0x01, /* Report Count (1), */ | |
350 | + 0x81, 0x02, /* Input (Variable), */ | |
351 | + 0x46, 0xBC, 0x02, /* Physical Maximum (700), */ | |
352 | + 0x26, 0x34, 0x05, /* Logical Maximum (1332), */ | |
353 | + 0x09, 0x31, /* Usage (Y), */ | |
354 | + 0x81, 0x02, /* Input (Variable), */ | |
355 | + 0xC0, /* End Collection, */ | |
356 | + 0x05, 0x0D, /* Usage Page (Digitizer), */ | |
357 | + 0x55, 0x0C, /* Unit Exponent (12), */ | |
358 | + 0x66, 0x01, 0x10, /* Unit (Seconds), */ | |
359 | + 0x47, 0xFF, 0xFF, 0x00, 0x00,/* Physical Maximum (65535), */ | |
360 | + 0x27, 0xFF, 0xFF, 0x00, 0x00,/* Logical Maximum (65535), */ | |
361 | + 0x75, 0x10, /* Report Size (16), */ | |
362 | + 0x95, 0x01, /* Report Count (1), */ | |
363 | + 0x09, 0x56, /* Usage (Scan Time), */ | |
364 | + 0x81, 0x02, /* Input (Variable), */ | |
365 | + 0x09, 0x54, /* Usage (Contact Count), */ | |
366 | + 0x25, 0x7F, /* Logical Maximum (127), */ | |
367 | + 0x75, 0x08, /* Report Size (8), */ | |
368 | + 0x81, 0x02, /* Input (Variable), */ | |
369 | + 0x05, 0x09, /* Usage Page (Button), */ | |
370 | + 0x09, 0x01, /* Usage (01h), */ | |
371 | + 0x25, 0x01, /* Logical Maximum (1), */ | |
372 | + 0x75, 0x01, /* Report Size (1), */ | |
373 | + 0x95, 0x01, /* Report Count (1), */ | |
374 | + 0x81, 0x02, /* Input (Variable), */ | |
375 | + 0x95, 0x07, /* Report Count (7), */ | |
376 | + 0x81, 0x03, /* Input (Constant, Variable), */ | |
377 | + 0x05, 0x0D, /* Usage Page (Digitizer), */ | |
378 | + 0x85, 0x02, /* Report ID (2), */ | |
379 | + 0x09, 0x55, /* Usage (Contact Count Maximum), */ | |
380 | + 0x09, 0x59, /* Usage (59h), */ | |
381 | + 0x75, 0x04, /* Report Size (4), */ | |
382 | + 0x95, 0x02, /* Report Count (2), */ | |
383 | + 0x25, 0x0F, /* Logical Maximum (15), */ | |
384 | + 0xB1, 0x02, /* Feature (Variable), */ | |
385 | + 0x05, 0x0D, /* Usage Page (Digitizer), */ | |
386 | + 0x85, 0x07, /* Report ID (7), */ | |
387 | + 0x09, 0x60, /* Usage (60h), */ | |
388 | + 0x75, 0x01, /* Report Size (1), */ | |
389 | + 0x95, 0x01, /* Report Count (1), */ | |
390 | + 0x25, 0x01, /* Logical Maximum (1), */ | |
391 | + 0xB1, 0x02, /* Feature (Variable), */ | |
392 | + 0x95, 0x07, /* Report Count (7), */ | |
393 | + 0xB1, 0x03, /* Feature (Constant, Variable), */ | |
394 | + 0x85, 0x06, /* Report ID (6), */ | |
395 | + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ | |
396 | + 0x09, 0xC5, /* Usage (C5h), */ | |
397 | + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ | |
398 | + 0x75, 0x08, /* Report Size (8), */ | |
399 | + 0x96, 0x00, 0x01, /* Report Count (256), */ | |
400 | + 0xB1, 0x02, /* Feature (Variable), */ | |
401 | + 0xC0, /* End Collection, */ | |
402 | + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ | |
403 | + 0x09, 0x01, /* Usage (01h), */ | |
404 | + 0xA1, 0x01, /* Collection (Application), */ | |
405 | + 0x85, 0x0D, /* Report ID (13), */ | |
406 | + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ | |
407 | + 0x19, 0x01, /* Usage Minimum (01h), */ | |
408 | + 0x29, 0x02, /* Usage Maximum (02h), */ | |
409 | + 0x75, 0x08, /* Report Size (8), */ | |
410 | + 0x95, 0x02, /* Report Count (2), */ | |
411 | + 0xB1, 0x02, /* Feature (Variable), */ | |
412 | + 0xC0, /* End Collection, */ | |
413 | + 0x05, 0x0D, /* Usage Page (Digitizer), */ | |
414 | + 0x09, 0x0E, /* Usage (Configuration), */ | |
415 | + 0xA1, 0x01, /* Collection (Application), */ | |
416 | + 0x85, 0x03, /* Report ID (3), */ | |
417 | + 0x09, 0x22, /* Usage (Finger), */ | |
418 | + 0xA1, 0x02, /* Collection (Logical), */ | |
419 | + 0x09, 0x52, /* Usage (Device Mode), */ | |
420 | + 0x25, 0x0A, /* Logical Maximum (10), */ | |
421 | + 0x95, 0x01, /* Report Count (1), */ | |
422 | + 0xB1, 0x02, /* Feature (Variable), */ | |
423 | + 0xC0, /* End Collection, */ | |
424 | + 0x09, 0x22, /* Usage (Finger), */ | |
425 | + 0xA1, 0x00, /* Collection (Physical), */ | |
426 | + 0x85, 0x05, /* Report ID (5), */ | |
427 | + 0x09, 0x57, /* Usage (57h), */ | |
428 | + 0x09, 0x58, /* Usage (58h), */ | |
429 | + 0x75, 0x01, /* Report Size (1), */ | |
430 | + 0x95, 0x02, /* Report Count (2), */ | |
431 | + 0x25, 0x01, /* Logical Maximum (1), */ | |
432 | + 0xB1, 0x02, /* Feature (Variable), */ | |
433 | + 0x95, 0x06, /* Report Count (6), */ | |
434 | + 0xB1, 0x03, /* Feature (Constant, Variable),*/ | |
435 | + 0xC0, /* End Collection, */ | |
436 | + 0xC0 /* End Collection */ | |
437 | + }, | |
438 | + .hid_report_desc_size = 475, | |
439 | + .i2c_name = "SYNA3602:00" | |
440 | +}; | |
441 | + | |
442 | + | |
443 | +static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = { | |
444 | + { | |
445 | + .ident = "Teclast F6 Pro", | |
446 | + .matches = { | |
447 | + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"), | |
448 | + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F6 Pro"), | |
449 | + }, | |
450 | + .driver_data = (void *)&sipodev_desc | |
451 | + }, | |
452 | + { | |
453 | + .ident = "Teclast F7", | |
454 | + .matches = { | |
455 | + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"), | |
456 | + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F7"), | |
457 | + }, | |
458 | + .driver_data = (void *)&sipodev_desc | |
459 | + }, | |
460 | + { | |
461 | + .ident = "Trekstor Primebook C13", | |
462 | + .matches = { | |
463 | + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"), | |
464 | + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C13"), | |
465 | + }, | |
466 | + .driver_data = (void *)&sipodev_desc | |
467 | + }, | |
468 | + { | |
469 | + .ident = "Trekstor Primebook C11", | |
470 | + .matches = { | |
471 | + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"), | |
472 | + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C11"), | |
473 | + }, | |
474 | + .driver_data = (void *)&sipodev_desc | |
475 | + }, | |
476 | + { | |
477 | + .ident = "Direkt-Tek DTLAPY116-2", | |
478 | + .matches = { | |
479 | + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Direkt-Tek"), | |
480 | + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "DTLAPY116-2"), | |
481 | + }, | |
482 | + .driver_data = (void *)&sipodev_desc | |
483 | + }, | |
484 | + { | |
485 | + .ident = "Mediacom Flexbook Edge 11", | |
486 | + .matches = { | |
487 | + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MEDIACOM"), | |
488 | + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "FlexBook edge11 - M-FBE11"), | |
489 | + }, | |
490 | + .driver_data = (void *)&sipodev_desc | |
491 | + } | |
492 | +}; | |
493 | + | |
494 | + | |
495 | +struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name) | |
496 | +{ | |
497 | + struct i2c_hid_desc_override *override; | |
498 | + const struct dmi_system_id *system_id; | |
499 | + | |
500 | + system_id = dmi_first_match(i2c_hid_dmi_desc_override_table); | |
501 | + if (!system_id) | |
502 | + return NULL; | |
503 | + | |
504 | + override = system_id->driver_data; | |
505 | + if (strcmp(override->i2c_name, i2c_name)) | |
506 | + return NULL; | |
507 | + | |
508 | + return override->i2c_hid_desc; | |
509 | +} | |
510 | + | |
511 | +char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name, | |
512 | + unsigned int *size) | |
513 | +{ | |
514 | + struct i2c_hid_desc_override *override; | |
515 | + const struct dmi_system_id *system_id; | |
516 | + | |
517 | + system_id = dmi_first_match(i2c_hid_dmi_desc_override_table); | |
518 | + if (!system_id) | |
519 | + return NULL; | |
520 | + | |
521 | + override = system_id->driver_data; | |
522 | + if (strcmp(override->i2c_name, i2c_name)) | |
523 | + return NULL; | |
524 | + | |
525 | + *size = override->hid_report_desc_size; | |
526 | + return override->hid_report_desc; | |
527 | +} | |
528 | diff --git a/drivers/hid/i2c-hid/i2c-hid.h b/drivers/hid/i2c-hid/i2c-hid.h | |
529 | new file mode 100644 | |
530 | index 000000000000..a8c19aef5824 | |
531 | --- /dev/null | |
532 | +++ b/drivers/hid/i2c-hid/i2c-hid.h | |
533 | @@ -0,0 +1,20 @@ | |
534 | +/* SPDX-License-Identifier: GPL-2.0+ */ | |
535 | + | |
536 | +#ifndef I2C_HID_H | |
537 | +#define I2C_HID_H | |
538 | + | |
539 | + | |
540 | +#ifdef CONFIG_DMI | |
541 | +struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name); | |
542 | +char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name, | |
543 | + unsigned int *size); | |
544 | +#else | |
545 | +static inline struct i2c_hid_desc | |
546 | + *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name) | |
547 | +{ return NULL; } | |
548 | +static inline char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name, | |
549 | + unsigned int *size) | |
550 | +{ return NULL; } | |
551 | +#endif | |
552 | + | |
553 | +#endif | |
554 | -- | |
555 | 2.19.1 | |
556 |