1 // SPDX-License-Identifier: GPL-2.0+
4 * Quirks for I2C-HID devices that do not supply proper descriptors
6 * Copyright (c) 2018 Julian Sax <jsbc@gmx.de>
10 #include <linux/types.h>
11 #include <linux/dmi.h>
12 #include <linux/mod_devicetable.h>
17 struct i2c_hid_desc_override
{
19 struct i2c_hid_desc
*i2c_hid_desc
;
20 uint8_t *i2c_hid_desc_buffer
;
22 uint8_t *hid_report_desc
;
23 unsigned int hid_report_desc_size
;
29 * descriptors for the SIPODEV SP1064 touchpad
31 * This device does not supply any descriptors and on windows a filter
32 * driver operates between the i2c-hid layer and the device and injects
33 * these descriptors when the device is prompted. The descriptors were
34 * extracted by listening to the i2c-hid traffic that occurs between the
35 * windows filter driver and the windows i2c-hid driver.
38 static const struct i2c_hid_desc_override sipodev_desc
= {
39 .i2c_hid_desc_buffer
= (uint8_t [])
40 {0x1e, 0x00, /* Length of descriptor */
41 0x00, 0x01, /* Version of descriptor */
42 0xdb, 0x01, /* Length of report descriptor */
43 0x21, 0x00, /* Location of report descriptor */
44 0x24, 0x00, /* Location of input report */
45 0x1b, 0x00, /* Max input report length */
46 0x25, 0x00, /* Location of output report */
47 0x11, 0x00, /* Max output report length */
48 0x22, 0x00, /* Location of command register */
49 0x23, 0x00, /* Location of data register */
50 0x11, 0x09, /* Vendor ID */
51 0x88, 0x52, /* Product ID */
52 0x06, 0x00, /* Version ID */
53 0x00, 0x00, 0x00, 0x00 /* Reserved */
56 .hid_report_desc
= (uint8_t [])
57 {0x05, 0x01, /* Usage Page (Desktop), */
58 0x09, 0x02, /* Usage (Mouse), */
59 0xA1, 0x01, /* Collection (Application), */
60 0x85, 0x01, /* Report ID (1), */
61 0x09, 0x01, /* Usage (Pointer), */
62 0xA1, 0x00, /* Collection (Physical), */
63 0x05, 0x09, /* Usage Page (Button), */
64 0x19, 0x01, /* Usage Minimum (01h), */
65 0x29, 0x02, /* Usage Maximum (02h), */
66 0x25, 0x01, /* Logical Maximum (1), */
67 0x75, 0x01, /* Report Size (1), */
68 0x95, 0x02, /* Report Count (2), */
69 0x81, 0x02, /* Input (Variable), */
70 0x95, 0x06, /* Report Count (6), */
71 0x81, 0x01, /* Input (Constant), */
72 0x05, 0x01, /* Usage Page (Desktop), */
73 0x09, 0x30, /* Usage (X), */
74 0x09, 0x31, /* Usage (Y), */
75 0x15, 0x81, /* Logical Minimum (-127), */
76 0x25, 0x7F, /* Logical Maximum (127), */
77 0x75, 0x08, /* Report Size (8), */
78 0x95, 0x02, /* Report Count (2), */
79 0x81, 0x06, /* Input (Variable, Relative), */
80 0xC0, /* End Collection, */
81 0xC0, /* End Collection, */
82 0x05, 0x0D, /* Usage Page (Digitizer), */
83 0x09, 0x05, /* Usage (Touchpad), */
84 0xA1, 0x01, /* Collection (Application), */
85 0x85, 0x04, /* Report ID (4), */
86 0x05, 0x0D, /* Usage Page (Digitizer), */
87 0x09, 0x22, /* Usage (Finger), */
88 0xA1, 0x02, /* Collection (Logical), */
89 0x15, 0x00, /* Logical Minimum (0), */
90 0x25, 0x01, /* Logical Maximum (1), */
91 0x09, 0x47, /* Usage (Touch Valid), */
92 0x09, 0x42, /* Usage (Tip Switch), */
93 0x95, 0x02, /* Report Count (2), */
94 0x75, 0x01, /* Report Size (1), */
95 0x81, 0x02, /* Input (Variable), */
96 0x95, 0x01, /* Report Count (1), */
97 0x75, 0x03, /* Report Size (3), */
98 0x25, 0x05, /* Logical Maximum (5), */
99 0x09, 0x51, /* Usage (Contact Identifier), */
100 0x81, 0x02, /* Input (Variable), */
101 0x75, 0x01, /* Report Size (1), */
102 0x95, 0x03, /* Report Count (3), */
103 0x81, 0x03, /* Input (Constant, Variable), */
104 0x05, 0x01, /* Usage Page (Desktop), */
105 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */
106 0x75, 0x10, /* Report Size (16), */
107 0x55, 0x0E, /* Unit Exponent (14), */
108 0x65, 0x11, /* Unit (Centimeter), */
109 0x09, 0x30, /* Usage (X), */
110 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */
111 0x95, 0x01, /* Report Count (1), */
112 0x81, 0x02, /* Input (Variable), */
113 0x46, 0xBC, 0x02, /* Physical Maximum (700), */
114 0x26, 0x34, 0x05, /* Logical Maximum (1332), */
115 0x09, 0x31, /* Usage (Y), */
116 0x81, 0x02, /* Input (Variable), */
117 0xC0, /* End Collection, */
118 0x05, 0x0D, /* Usage Page (Digitizer), */
119 0x09, 0x22, /* Usage (Finger), */
120 0xA1, 0x02, /* Collection (Logical), */
121 0x25, 0x01, /* Logical Maximum (1), */
122 0x09, 0x47, /* Usage (Touch Valid), */
123 0x09, 0x42, /* Usage (Tip Switch), */
124 0x95, 0x02, /* Report Count (2), */
125 0x75, 0x01, /* Report Size (1), */
126 0x81, 0x02, /* Input (Variable), */
127 0x95, 0x01, /* Report Count (1), */
128 0x75, 0x03, /* Report Size (3), */
129 0x25, 0x05, /* Logical Maximum (5), */
130 0x09, 0x51, /* Usage (Contact Identifier), */
131 0x81, 0x02, /* Input (Variable), */
132 0x75, 0x01, /* Report Size (1), */
133 0x95, 0x03, /* Report Count (3), */
134 0x81, 0x03, /* Input (Constant, Variable), */
135 0x05, 0x01, /* Usage Page (Desktop), */
136 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */
137 0x75, 0x10, /* Report Size (16), */
138 0x09, 0x30, /* Usage (X), */
139 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */
140 0x95, 0x01, /* Report Count (1), */
141 0x81, 0x02, /* Input (Variable), */
142 0x46, 0xBC, 0x02, /* Physical Maximum (700), */
143 0x26, 0x34, 0x05, /* Logical Maximum (1332), */
144 0x09, 0x31, /* Usage (Y), */
145 0x81, 0x02, /* Input (Variable), */
146 0xC0, /* End Collection, */
147 0x05, 0x0D, /* Usage Page (Digitizer), */
148 0x09, 0x22, /* Usage (Finger), */
149 0xA1, 0x02, /* Collection (Logical), */
150 0x25, 0x01, /* Logical Maximum (1), */
151 0x09, 0x47, /* Usage (Touch Valid), */
152 0x09, 0x42, /* Usage (Tip Switch), */
153 0x95, 0x02, /* Report Count (2), */
154 0x75, 0x01, /* Report Size (1), */
155 0x81, 0x02, /* Input (Variable), */
156 0x95, 0x01, /* Report Count (1), */
157 0x75, 0x03, /* Report Size (3), */
158 0x25, 0x05, /* Logical Maximum (5), */
159 0x09, 0x51, /* Usage (Contact Identifier), */
160 0x81, 0x02, /* Input (Variable), */
161 0x75, 0x01, /* Report Size (1), */
162 0x95, 0x03, /* Report Count (3), */
163 0x81, 0x03, /* Input (Constant, Variable), */
164 0x05, 0x01, /* Usage Page (Desktop), */
165 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */
166 0x75, 0x10, /* Report Size (16), */
167 0x09, 0x30, /* Usage (X), */
168 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */
169 0x95, 0x01, /* Report Count (1), */
170 0x81, 0x02, /* Input (Variable), */
171 0x46, 0xBC, 0x02, /* Physical Maximum (700), */
172 0x26, 0x34, 0x05, /* Logical Maximum (1332), */
173 0x09, 0x31, /* Usage (Y), */
174 0x81, 0x02, /* Input (Variable), */
175 0xC0, /* End Collection, */
176 0x05, 0x0D, /* Usage Page (Digitizer), */
177 0x09, 0x22, /* Usage (Finger), */
178 0xA1, 0x02, /* Collection (Logical), */
179 0x25, 0x01, /* Logical Maximum (1), */
180 0x09, 0x47, /* Usage (Touch Valid), */
181 0x09, 0x42, /* Usage (Tip Switch), */
182 0x95, 0x02, /* Report Count (2), */
183 0x75, 0x01, /* Report Size (1), */
184 0x81, 0x02, /* Input (Variable), */
185 0x95, 0x01, /* Report Count (1), */
186 0x75, 0x03, /* Report Size (3), */
187 0x25, 0x05, /* Logical Maximum (5), */
188 0x09, 0x51, /* Usage (Contact Identifier), */
189 0x81, 0x02, /* Input (Variable), */
190 0x75, 0x01, /* Report Size (1), */
191 0x95, 0x03, /* Report Count (3), */
192 0x81, 0x03, /* Input (Constant, Variable), */
193 0x05, 0x01, /* Usage Page (Desktop), */
194 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */
195 0x75, 0x10, /* Report Size (16), */
196 0x09, 0x30, /* Usage (X), */
197 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */
198 0x95, 0x01, /* Report Count (1), */
199 0x81, 0x02, /* Input (Variable), */
200 0x46, 0xBC, 0x02, /* Physical Maximum (700), */
201 0x26, 0x34, 0x05, /* Logical Maximum (1332), */
202 0x09, 0x31, /* Usage (Y), */
203 0x81, 0x02, /* Input (Variable), */
204 0xC0, /* End Collection, */
205 0x05, 0x0D, /* Usage Page (Digitizer), */
206 0x55, 0x0C, /* Unit Exponent (12), */
207 0x66, 0x01, 0x10, /* Unit (Seconds), */
208 0x47, 0xFF, 0xFF, 0x00, 0x00,/* Physical Maximum (65535), */
209 0x27, 0xFF, 0xFF, 0x00, 0x00,/* Logical Maximum (65535), */
210 0x75, 0x10, /* Report Size (16), */
211 0x95, 0x01, /* Report Count (1), */
212 0x09, 0x56, /* Usage (Scan Time), */
213 0x81, 0x02, /* Input (Variable), */
214 0x09, 0x54, /* Usage (Contact Count), */
215 0x25, 0x7F, /* Logical Maximum (127), */
216 0x75, 0x08, /* Report Size (8), */
217 0x81, 0x02, /* Input (Variable), */
218 0x05, 0x09, /* Usage Page (Button), */
219 0x09, 0x01, /* Usage (01h), */
220 0x25, 0x01, /* Logical Maximum (1), */
221 0x75, 0x01, /* Report Size (1), */
222 0x95, 0x01, /* Report Count (1), */
223 0x81, 0x02, /* Input (Variable), */
224 0x95, 0x07, /* Report Count (7), */
225 0x81, 0x03, /* Input (Constant, Variable), */
226 0x05, 0x0D, /* Usage Page (Digitizer), */
227 0x85, 0x02, /* Report ID (2), */
228 0x09, 0x55, /* Usage (Contact Count Maximum), */
229 0x09, 0x59, /* Usage (59h), */
230 0x75, 0x04, /* Report Size (4), */
231 0x95, 0x02, /* Report Count (2), */
232 0x25, 0x0F, /* Logical Maximum (15), */
233 0xB1, 0x02, /* Feature (Variable), */
234 0x05, 0x0D, /* Usage Page (Digitizer), */
235 0x85, 0x07, /* Report ID (7), */
236 0x09, 0x60, /* Usage (60h), */
237 0x75, 0x01, /* Report Size (1), */
238 0x95, 0x01, /* Report Count (1), */
239 0x25, 0x01, /* Logical Maximum (1), */
240 0xB1, 0x02, /* Feature (Variable), */
241 0x95, 0x07, /* Report Count (7), */
242 0xB1, 0x03, /* Feature (Constant, Variable), */
243 0x85, 0x06, /* Report ID (6), */
244 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
245 0x09, 0xC5, /* Usage (C5h), */
246 0x26, 0xFF, 0x00, /* Logical Maximum (255), */
247 0x75, 0x08, /* Report Size (8), */
248 0x96, 0x00, 0x01, /* Report Count (256), */
249 0xB1, 0x02, /* Feature (Variable), */
250 0xC0, /* End Collection, */
251 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
252 0x09, 0x01, /* Usage (01h), */
253 0xA1, 0x01, /* Collection (Application), */
254 0x85, 0x0D, /* Report ID (13), */
255 0x26, 0xFF, 0x00, /* Logical Maximum (255), */
256 0x19, 0x01, /* Usage Minimum (01h), */
257 0x29, 0x02, /* Usage Maximum (02h), */
258 0x75, 0x08, /* Report Size (8), */
259 0x95, 0x02, /* Report Count (2), */
260 0xB1, 0x02, /* Feature (Variable), */
261 0xC0, /* End Collection, */
262 0x05, 0x0D, /* Usage Page (Digitizer), */
263 0x09, 0x0E, /* Usage (Configuration), */
264 0xA1, 0x01, /* Collection (Application), */
265 0x85, 0x03, /* Report ID (3), */
266 0x09, 0x22, /* Usage (Finger), */
267 0xA1, 0x02, /* Collection (Logical), */
268 0x09, 0x52, /* Usage (Device Mode), */
269 0x25, 0x0A, /* Logical Maximum (10), */
270 0x95, 0x01, /* Report Count (1), */
271 0xB1, 0x02, /* Feature (Variable), */
272 0xC0, /* End Collection, */
273 0x09, 0x22, /* Usage (Finger), */
274 0xA1, 0x00, /* Collection (Physical), */
275 0x85, 0x05, /* Report ID (5), */
276 0x09, 0x57, /* Usage (57h), */
277 0x09, 0x58, /* Usage (58h), */
278 0x75, 0x01, /* Report Size (1), */
279 0x95, 0x02, /* Report Count (2), */
280 0x25, 0x01, /* Logical Maximum (1), */
281 0xB1, 0x02, /* Feature (Variable), */
282 0x95, 0x06, /* Report Count (6), */
283 0xB1, 0x03, /* Feature (Constant, Variable),*/
284 0xC0, /* End Collection, */
285 0xC0 /* End Collection */
287 .hid_report_desc_size
= 475,
288 .i2c_name
= "SYNA3602:00"
292 static const struct dmi_system_id i2c_hid_dmi_desc_override_table
[] = {
294 .ident
= "Teclast F6 Pro",
296 DMI_EXACT_MATCH(DMI_SYS_VENDOR
, "TECLAST"),
297 DMI_EXACT_MATCH(DMI_PRODUCT_NAME
, "F6 Pro"),
299 .driver_data
= (void *)&sipodev_desc
302 .ident
= "Teclast F7",
304 DMI_EXACT_MATCH(DMI_SYS_VENDOR
, "TECLAST"),
305 DMI_EXACT_MATCH(DMI_PRODUCT_NAME
, "F7"),
307 .driver_data
= (void *)&sipodev_desc
310 .ident
= "Trekstor Primebook C13",
312 DMI_EXACT_MATCH(DMI_SYS_VENDOR
, "TREKSTOR"),
313 DMI_EXACT_MATCH(DMI_PRODUCT_NAME
, "Primebook C13"),
315 .driver_data
= (void *)&sipodev_desc
318 .ident
= "Trekstor Primebook C11",
320 DMI_EXACT_MATCH(DMI_SYS_VENDOR
, "TREKSTOR"),
321 DMI_EXACT_MATCH(DMI_PRODUCT_NAME
, "Primebook C11"),
323 .driver_data
= (void *)&sipodev_desc
327 * There are at least 2 Primebook C11B versions, the older
328 * version has a product-name of "Primebook C11B", and a
329 * bios version / release / firmware revision of:
330 * V2.1.2 / 05/03/2018 / 18.2
331 * The new version has "PRIMEBOOK C11B" as product-name and a
332 * bios version / release / firmware revision of:
333 * CFALKSW05_BIOS_V1.1.2 / 11/19/2018 / 19.2
334 * Only the older version needs this quirk, note the newer
335 * version will not match as it has a different product-name.
337 .ident
= "Trekstor Primebook C11B",
339 DMI_EXACT_MATCH(DMI_SYS_VENDOR
, "TREKSTOR"),
340 DMI_EXACT_MATCH(DMI_PRODUCT_NAME
, "Primebook C11B"),
342 .driver_data
= (void *)&sipodev_desc
345 .ident
= "Trekstor SURFBOOK E11B",
347 DMI_EXACT_MATCH(DMI_SYS_VENDOR
, "TREKSTOR"),
348 DMI_EXACT_MATCH(DMI_PRODUCT_NAME
, "SURFBOOK E11B"),
350 .driver_data
= (void *)&sipodev_desc
353 .ident
= "Direkt-Tek DTLAPY116-2",
355 DMI_EXACT_MATCH(DMI_SYS_VENDOR
, "Direkt-Tek"),
356 DMI_EXACT_MATCH(DMI_PRODUCT_NAME
, "DTLAPY116-2"),
358 .driver_data
= (void *)&sipodev_desc
361 .ident
= "Direkt-Tek DTLAPY133-1",
363 DMI_EXACT_MATCH(DMI_SYS_VENDOR
, "Direkt-Tek"),
364 DMI_EXACT_MATCH(DMI_PRODUCT_NAME
, "DTLAPY133-1"),
366 .driver_data
= (void *)&sipodev_desc
369 .ident
= "Mediacom Flexbook Edge 11",
371 DMI_EXACT_MATCH(DMI_SYS_VENDOR
, "MEDIACOM"),
372 DMI_EXACT_MATCH(DMI_PRODUCT_NAME
, "FlexBook edge11 - M-FBE11"),
374 .driver_data
= (void *)&sipodev_desc
377 .ident
= "Mediacom FlexBook edge 13",
379 DMI_EXACT_MATCH(DMI_SYS_VENDOR
, "MEDIACOM"),
380 DMI_EXACT_MATCH(DMI_PRODUCT_NAME
, "FlexBook_edge13-M-FBE13"),
382 .driver_data
= (void *)&sipodev_desc
385 .ident
= "Odys Winbook 13",
387 DMI_EXACT_MATCH(DMI_SYS_VENDOR
, "AXDIA International GmbH"),
388 DMI_EXACT_MATCH(DMI_PRODUCT_NAME
, "WINBOOK 13"),
390 .driver_data
= (void *)&sipodev_desc
393 .ident
= "iBall Aer3",
395 DMI_EXACT_MATCH(DMI_SYS_VENDOR
, "iBall"),
396 DMI_EXACT_MATCH(DMI_PRODUCT_NAME
, "Aer3"),
398 .driver_data
= (void *)&sipodev_desc
401 .ident
= "Schneider SCL142ALM",
403 DMI_EXACT_MATCH(DMI_SYS_VENDOR
, "SCHNEIDER"),
404 DMI_EXACT_MATCH(DMI_PRODUCT_NAME
, "SCL142ALM"),
406 .driver_data
= (void *)&sipodev_desc
408 { } /* Terminate list */
412 struct i2c_hid_desc
*i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name
)
414 struct i2c_hid_desc_override
*override
;
415 const struct dmi_system_id
*system_id
;
417 system_id
= dmi_first_match(i2c_hid_dmi_desc_override_table
);
421 override
= system_id
->driver_data
;
422 if (strcmp(override
->i2c_name
, i2c_name
))
425 return override
->i2c_hid_desc
;
428 char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name
,
431 struct i2c_hid_desc_override
*override
;
432 const struct dmi_system_id
*system_id
;
434 system_id
= dmi_first_match(i2c_hid_dmi_desc_override_table
);
438 override
= system_id
->driver_data
;
439 if (strcmp(override
->i2c_name
, i2c_name
))
442 *size
= override
->hid_report_desc_size
;
443 return override
->hid_report_desc
;