495 lines · c
1// SPDX-License-Identifier: GPL-2.0+2 3/*4 * Quirks for I2C-HID devices that do not supply proper descriptors5 *6 * Copyright (c) 2018 Julian Sax <jsbc@gmx.de>7 *8 */9 10#include <linux/types.h>11#include <linux/dmi.h>12#include <linux/mod_devicetable.h>13#include <linux/hid.h>14 15#include "i2c-hid.h"16#include "../hid-ids.h"17 18 19struct i2c_hid_desc_override {20 union {21 struct i2c_hid_desc *i2c_hid_desc;22 uint8_t *i2c_hid_desc_buffer;23 };24 uint8_t *hid_report_desc;25 unsigned int hid_report_desc_size;26 uint8_t *i2c_name;27};28 29 30/*31 * descriptors for the SIPODEV SP1064 touchpad32 *33 * This device does not supply any descriptors and on windows a filter34 * driver operates between the i2c-hid layer and the device and injects35 * these descriptors when the device is prompted. The descriptors were36 * extracted by listening to the i2c-hid traffic that occurs between the37 * windows filter driver and the windows i2c-hid driver.38 */39 40static const struct i2c_hid_desc_override sipodev_desc = {41 .i2c_hid_desc_buffer = (uint8_t [])42 {0x1e, 0x00, /* Length of descriptor */43 0x00, 0x01, /* Version of descriptor */44 0xdb, 0x01, /* Length of report descriptor */45 0x21, 0x00, /* Location of report descriptor */46 0x24, 0x00, /* Location of input report */47 0x1b, 0x00, /* Max input report length */48 0x25, 0x00, /* Location of output report */49 0x11, 0x00, /* Max output report length */50 0x22, 0x00, /* Location of command register */51 0x23, 0x00, /* Location of data register */52 0x11, 0x09, /* Vendor ID */53 0x88, 0x52, /* Product ID */54 0x06, 0x00, /* Version ID */55 0x00, 0x00, 0x00, 0x00 /* Reserved */56 },57 58 .hid_report_desc = (uint8_t [])59 {0x05, 0x01, /* Usage Page (Desktop), */60 0x09, 0x02, /* Usage (Mouse), */61 0xA1, 0x01, /* Collection (Application), */62 0x85, 0x01, /* Report ID (1), */63 0x09, 0x01, /* Usage (Pointer), */64 0xA1, 0x00, /* Collection (Physical), */65 0x05, 0x09, /* Usage Page (Button), */66 0x19, 0x01, /* Usage Minimum (01h), */67 0x29, 0x02, /* Usage Maximum (02h), */68 0x25, 0x01, /* Logical Maximum (1), */69 0x75, 0x01, /* Report Size (1), */70 0x95, 0x02, /* Report Count (2), */71 0x81, 0x02, /* Input (Variable), */72 0x95, 0x06, /* Report Count (6), */73 0x81, 0x01, /* Input (Constant), */74 0x05, 0x01, /* Usage Page (Desktop), */75 0x09, 0x30, /* Usage (X), */76 0x09, 0x31, /* Usage (Y), */77 0x15, 0x81, /* Logical Minimum (-127), */78 0x25, 0x7F, /* Logical Maximum (127), */79 0x75, 0x08, /* Report Size (8), */80 0x95, 0x02, /* Report Count (2), */81 0x81, 0x06, /* Input (Variable, Relative), */82 0xC0, /* End Collection, */83 0xC0, /* End Collection, */84 0x05, 0x0D, /* Usage Page (Digitizer), */85 0x09, 0x05, /* Usage (Touchpad), */86 0xA1, 0x01, /* Collection (Application), */87 0x85, 0x04, /* Report ID (4), */88 0x05, 0x0D, /* Usage Page (Digitizer), */89 0x09, 0x22, /* Usage (Finger), */90 0xA1, 0x02, /* Collection (Logical), */91 0x15, 0x00, /* Logical Minimum (0), */92 0x25, 0x01, /* Logical Maximum (1), */93 0x09, 0x47, /* Usage (Touch Valid), */94 0x09, 0x42, /* Usage (Tip Switch), */95 0x95, 0x02, /* Report Count (2), */96 0x75, 0x01, /* Report Size (1), */97 0x81, 0x02, /* Input (Variable), */98 0x95, 0x01, /* Report Count (1), */99 0x75, 0x03, /* Report Size (3), */100 0x25, 0x05, /* Logical Maximum (5), */101 0x09, 0x51, /* Usage (Contact Identifier), */102 0x81, 0x02, /* Input (Variable), */103 0x75, 0x01, /* Report Size (1), */104 0x95, 0x03, /* Report Count (3), */105 0x81, 0x03, /* Input (Constant, Variable), */106 0x05, 0x01, /* Usage Page (Desktop), */107 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */108 0x75, 0x10, /* Report Size (16), */109 0x55, 0x0E, /* Unit Exponent (14), */110 0x65, 0x11, /* Unit (Centimeter), */111 0x09, 0x30, /* Usage (X), */112 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */113 0x95, 0x01, /* Report Count (1), */114 0x81, 0x02, /* Input (Variable), */115 0x46, 0xBC, 0x02, /* Physical Maximum (700), */116 0x26, 0x34, 0x05, /* Logical Maximum (1332), */117 0x09, 0x31, /* Usage (Y), */118 0x81, 0x02, /* Input (Variable), */119 0xC0, /* End Collection, */120 0x05, 0x0D, /* Usage Page (Digitizer), */121 0x09, 0x22, /* Usage (Finger), */122 0xA1, 0x02, /* Collection (Logical), */123 0x25, 0x01, /* Logical Maximum (1), */124 0x09, 0x47, /* Usage (Touch Valid), */125 0x09, 0x42, /* Usage (Tip Switch), */126 0x95, 0x02, /* Report Count (2), */127 0x75, 0x01, /* Report Size (1), */128 0x81, 0x02, /* Input (Variable), */129 0x95, 0x01, /* Report Count (1), */130 0x75, 0x03, /* Report Size (3), */131 0x25, 0x05, /* Logical Maximum (5), */132 0x09, 0x51, /* Usage (Contact Identifier), */133 0x81, 0x02, /* Input (Variable), */134 0x75, 0x01, /* Report Size (1), */135 0x95, 0x03, /* Report Count (3), */136 0x81, 0x03, /* Input (Constant, Variable), */137 0x05, 0x01, /* Usage Page (Desktop), */138 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */139 0x75, 0x10, /* Report Size (16), */140 0x09, 0x30, /* Usage (X), */141 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */142 0x95, 0x01, /* Report Count (1), */143 0x81, 0x02, /* Input (Variable), */144 0x46, 0xBC, 0x02, /* Physical Maximum (700), */145 0x26, 0x34, 0x05, /* Logical Maximum (1332), */146 0x09, 0x31, /* Usage (Y), */147 0x81, 0x02, /* Input (Variable), */148 0xC0, /* End Collection, */149 0x05, 0x0D, /* Usage Page (Digitizer), */150 0x09, 0x22, /* Usage (Finger), */151 0xA1, 0x02, /* Collection (Logical), */152 0x25, 0x01, /* Logical Maximum (1), */153 0x09, 0x47, /* Usage (Touch Valid), */154 0x09, 0x42, /* Usage (Tip Switch), */155 0x95, 0x02, /* Report Count (2), */156 0x75, 0x01, /* Report Size (1), */157 0x81, 0x02, /* Input (Variable), */158 0x95, 0x01, /* Report Count (1), */159 0x75, 0x03, /* Report Size (3), */160 0x25, 0x05, /* Logical Maximum (5), */161 0x09, 0x51, /* Usage (Contact Identifier), */162 0x81, 0x02, /* Input (Variable), */163 0x75, 0x01, /* Report Size (1), */164 0x95, 0x03, /* Report Count (3), */165 0x81, 0x03, /* Input (Constant, Variable), */166 0x05, 0x01, /* Usage Page (Desktop), */167 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */168 0x75, 0x10, /* Report Size (16), */169 0x09, 0x30, /* Usage (X), */170 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */171 0x95, 0x01, /* Report Count (1), */172 0x81, 0x02, /* Input (Variable), */173 0x46, 0xBC, 0x02, /* Physical Maximum (700), */174 0x26, 0x34, 0x05, /* Logical Maximum (1332), */175 0x09, 0x31, /* Usage (Y), */176 0x81, 0x02, /* Input (Variable), */177 0xC0, /* End Collection, */178 0x05, 0x0D, /* Usage Page (Digitizer), */179 0x09, 0x22, /* Usage (Finger), */180 0xA1, 0x02, /* Collection (Logical), */181 0x25, 0x01, /* Logical Maximum (1), */182 0x09, 0x47, /* Usage (Touch Valid), */183 0x09, 0x42, /* Usage (Tip Switch), */184 0x95, 0x02, /* Report Count (2), */185 0x75, 0x01, /* Report Size (1), */186 0x81, 0x02, /* Input (Variable), */187 0x95, 0x01, /* Report Count (1), */188 0x75, 0x03, /* Report Size (3), */189 0x25, 0x05, /* Logical Maximum (5), */190 0x09, 0x51, /* Usage (Contact Identifier), */191 0x81, 0x02, /* Input (Variable), */192 0x75, 0x01, /* Report Size (1), */193 0x95, 0x03, /* Report Count (3), */194 0x81, 0x03, /* Input (Constant, Variable), */195 0x05, 0x01, /* Usage Page (Desktop), */196 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */197 0x75, 0x10, /* Report Size (16), */198 0x09, 0x30, /* Usage (X), */199 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */200 0x95, 0x01, /* Report Count (1), */201 0x81, 0x02, /* Input (Variable), */202 0x46, 0xBC, 0x02, /* Physical Maximum (700), */203 0x26, 0x34, 0x05, /* Logical Maximum (1332), */204 0x09, 0x31, /* Usage (Y), */205 0x81, 0x02, /* Input (Variable), */206 0xC0, /* End Collection, */207 0x05, 0x0D, /* Usage Page (Digitizer), */208 0x55, 0x0C, /* Unit Exponent (12), */209 0x66, 0x01, 0x10, /* Unit (Seconds), */210 0x47, 0xFF, 0xFF, 0x00, 0x00,/* Physical Maximum (65535), */211 0x27, 0xFF, 0xFF, 0x00, 0x00,/* Logical Maximum (65535), */212 0x75, 0x10, /* Report Size (16), */213 0x95, 0x01, /* Report Count (1), */214 0x09, 0x56, /* Usage (Scan Time), */215 0x81, 0x02, /* Input (Variable), */216 0x09, 0x54, /* Usage (Contact Count), */217 0x25, 0x7F, /* Logical Maximum (127), */218 0x75, 0x08, /* Report Size (8), */219 0x81, 0x02, /* Input (Variable), */220 0x05, 0x09, /* Usage Page (Button), */221 0x09, 0x01, /* Usage (01h), */222 0x25, 0x01, /* Logical Maximum (1), */223 0x75, 0x01, /* Report Size (1), */224 0x95, 0x01, /* Report Count (1), */225 0x81, 0x02, /* Input (Variable), */226 0x95, 0x07, /* Report Count (7), */227 0x81, 0x03, /* Input (Constant, Variable), */228 0x05, 0x0D, /* Usage Page (Digitizer), */229 0x85, 0x02, /* Report ID (2), */230 0x09, 0x55, /* Usage (Contact Count Maximum), */231 0x09, 0x59, /* Usage (59h), */232 0x75, 0x04, /* Report Size (4), */233 0x95, 0x02, /* Report Count (2), */234 0x25, 0x0F, /* Logical Maximum (15), */235 0xB1, 0x02, /* Feature (Variable), */236 0x05, 0x0D, /* Usage Page (Digitizer), */237 0x85, 0x07, /* Report ID (7), */238 0x09, 0x60, /* Usage (60h), */239 0x75, 0x01, /* Report Size (1), */240 0x95, 0x01, /* Report Count (1), */241 0x25, 0x01, /* Logical Maximum (1), */242 0xB1, 0x02, /* Feature (Variable), */243 0x95, 0x07, /* Report Count (7), */244 0xB1, 0x03, /* Feature (Constant, Variable), */245 0x85, 0x06, /* Report ID (6), */246 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */247 0x09, 0xC5, /* Usage (C5h), */248 0x26, 0xFF, 0x00, /* Logical Maximum (255), */249 0x75, 0x08, /* Report Size (8), */250 0x96, 0x00, 0x01, /* Report Count (256), */251 0xB1, 0x02, /* Feature (Variable), */252 0xC0, /* End Collection, */253 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */254 0x09, 0x01, /* Usage (01h), */255 0xA1, 0x01, /* Collection (Application), */256 0x85, 0x0D, /* Report ID (13), */257 0x26, 0xFF, 0x00, /* Logical Maximum (255), */258 0x19, 0x01, /* Usage Minimum (01h), */259 0x29, 0x02, /* Usage Maximum (02h), */260 0x75, 0x08, /* Report Size (8), */261 0x95, 0x02, /* Report Count (2), */262 0xB1, 0x02, /* Feature (Variable), */263 0xC0, /* End Collection, */264 0x05, 0x0D, /* Usage Page (Digitizer), */265 0x09, 0x0E, /* Usage (Configuration), */266 0xA1, 0x01, /* Collection (Application), */267 0x85, 0x03, /* Report ID (3), */268 0x09, 0x22, /* Usage (Finger), */269 0xA1, 0x02, /* Collection (Logical), */270 0x09, 0x52, /* Usage (Device Mode), */271 0x25, 0x0A, /* Logical Maximum (10), */272 0x95, 0x01, /* Report Count (1), */273 0xB1, 0x02, /* Feature (Variable), */274 0xC0, /* End Collection, */275 0x09, 0x22, /* Usage (Finger), */276 0xA1, 0x00, /* Collection (Physical), */277 0x85, 0x05, /* Report ID (5), */278 0x09, 0x57, /* Usage (57h), */279 0x09, 0x58, /* Usage (58h), */280 0x75, 0x01, /* Report Size (1), */281 0x95, 0x02, /* Report Count (2), */282 0x25, 0x01, /* Logical Maximum (1), */283 0xB1, 0x02, /* Feature (Variable), */284 0x95, 0x06, /* Report Count (6), */285 0xB1, 0x03, /* Feature (Constant, Variable),*/286 0xC0, /* End Collection, */287 0xC0 /* End Collection */288 },289 .hid_report_desc_size = 475,290 .i2c_name = "SYNA3602:00"291};292 293 294static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {295 {296 .ident = "Teclast F6 Pro",297 .matches = {298 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"),299 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F6 Pro"),300 },301 .driver_data = (void *)&sipodev_desc302 },303 {304 .ident = "Teclast F7",305 .matches = {306 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"),307 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F7"),308 },309 .driver_data = (void *)&sipodev_desc310 },311 {312 .ident = "Trekstor Primebook C13",313 .matches = {314 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),315 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C13"),316 },317 .driver_data = (void *)&sipodev_desc318 },319 {320 .ident = "Trekstor Primebook C11",321 .matches = {322 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),323 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C11"),324 },325 .driver_data = (void *)&sipodev_desc326 },327 {328 /*329 * There are at least 2 Primebook C11B versions, the older330 * version has a product-name of "Primebook C11B", and a331 * bios version / release / firmware revision of:332 * V2.1.2 / 05/03/2018 / 18.2333 * The new version has "PRIMEBOOK C11B" as product-name and a334 * bios version / release / firmware revision of:335 * CFALKSW05_BIOS_V1.1.2 / 11/19/2018 / 19.2336 * Only the older version needs this quirk, note the newer337 * version will not match as it has a different product-name.338 */339 .ident = "Trekstor Primebook C11B",340 .matches = {341 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),342 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C11B"),343 },344 .driver_data = (void *)&sipodev_desc345 },346 {347 .ident = "Trekstor SURFBOOK E11B",348 .matches = {349 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),350 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SURFBOOK E11B"),351 },352 .driver_data = (void *)&sipodev_desc353 },354 {355 .ident = "Direkt-Tek DTLAPY116-2",356 .matches = {357 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Direkt-Tek"),358 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "DTLAPY116-2"),359 },360 .driver_data = (void *)&sipodev_desc361 },362 {363 .ident = "Direkt-Tek DTLAPY133-1",364 .matches = {365 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Direkt-Tek"),366 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "DTLAPY133-1"),367 },368 .driver_data = (void *)&sipodev_desc369 },370 {371 .ident = "Mediacom Flexbook Edge 11",372 .matches = {373 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MEDIACOM"),374 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "FlexBook edge11 - M-FBE11"),375 },376 .driver_data = (void *)&sipodev_desc377 },378 {379 .ident = "Mediacom FlexBook edge 13",380 .matches = {381 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MEDIACOM"),382 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "FlexBook_edge13-M-FBE13"),383 },384 .driver_data = (void *)&sipodev_desc385 },386 {387 .ident = "Odys Winbook 13",388 .matches = {389 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AXDIA International GmbH"),390 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "WINBOOK 13"),391 },392 .driver_data = (void *)&sipodev_desc393 },394 {395 .ident = "iBall Aer3",396 .matches = {397 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "iBall"),398 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Aer3"),399 },400 .driver_data = (void *)&sipodev_desc401 },402 {403 .ident = "Schneider SCL142ALM",404 .matches = {405 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SCHNEIDER"),406 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SCL142ALM"),407 },408 .driver_data = (void *)&sipodev_desc409 },410 {411 .ident = "Vero K147",412 .matches = {413 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "VERO"),414 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "K147"),415 },416 .driver_data = (void *)&sipodev_desc417 },418 { } /* Terminate list */419};420 421static const struct hid_device_id i2c_hid_elan_flipped_quirks = {422 HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, USB_VENDOR_ID_ELAN, 0x2dcd),423 HID_QUIRK_X_INVERT | HID_QUIRK_Y_INVERT424};425 426/*427 * This list contains devices which have specific issues based on the system428 * they're on and not just the device itself. The driver_data will have a429 * specific hid device to match against.430 */431static const struct dmi_system_id i2c_hid_dmi_quirk_table[] = {432 {433 .ident = "DynaBook K50/FR",434 .matches = {435 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dynabook Inc."),436 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "dynabook K50/FR"),437 },438 .driver_data = (void *)&i2c_hid_elan_flipped_quirks,439 },440 { } /* Terminate list */441};442 443 444struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name)445{446 struct i2c_hid_desc_override *override;447 const struct dmi_system_id *system_id;448 449 system_id = dmi_first_match(i2c_hid_dmi_desc_override_table);450 if (!system_id)451 return NULL;452 453 override = system_id->driver_data;454 if (strcmp(override->i2c_name, i2c_name))455 return NULL;456 457 return override->i2c_hid_desc;458}459 460char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,461 unsigned int *size)462{463 struct i2c_hid_desc_override *override;464 const struct dmi_system_id *system_id;465 466 system_id = dmi_first_match(i2c_hid_dmi_desc_override_table);467 if (!system_id)468 return NULL;469 470 override = system_id->driver_data;471 if (strcmp(override->i2c_name, i2c_name))472 return NULL;473 474 *size = override->hid_report_desc_size;475 return override->hid_report_desc;476}477 478u32 i2c_hid_get_dmi_quirks(const u16 vendor, const u16 product)479{480 u32 quirks = 0;481 const struct dmi_system_id *system_id =482 dmi_first_match(i2c_hid_dmi_quirk_table);483 484 if (system_id) {485 const struct hid_device_id *device_id =486 (struct hid_device_id *)(system_id->driver_data);487 488 if (device_id && device_id->vendor == vendor &&489 device_id->product == product)490 quirks = device_id->driver_data;491 }492 493 return quirks;494}495