Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

HID: asus: Add T100CHI bluetooth keyboard dock touchpad support

Put the touchpad in native (absolute coordinate mode) and export it to
userspace as a touchpad rather then as a mouse.

Note this requires HID_QUIRK_MULTI_INPUT as the T100CHI keyboard dock
has all functionality on a single HID interface and userspace expects
touchpads to be on a separate input_dev. Without MULTI_INPUT userspace
will ignore the keyboard part of the keyboard/touchpad combo.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>

authored by

Hans de Goede and committed by
Jiri Kosina
73c75d39 5703e52c

+67 -7
+67 -7
drivers/hid/hid-asus.c
··· 41 41 42 42 #define T100_TPAD_INTF 2 43 43 44 + #define T100CHI_MOUSE_REPORT_ID 0x06 44 45 #define FEATURE_REPORT_ID 0x0d 45 46 #define INPUT_REPORT_ID 0x5d 46 47 #define FEATURE_KBD_REPORT_ID 0x5a ··· 118 117 .max_contacts = 5, 119 118 }; 120 119 120 + static const struct asus_touchpad_info asus_t100chi_tp = { 121 + .max_x = 2640, 122 + .max_y = 1320, 123 + .res_x = 31, /* units/mm */ 124 + .res_y = 29, /* units/mm */ 125 + .contact_size = 3, 126 + .max_contacts = 4, 127 + }; 128 + 121 129 static void asus_report_contact_down(struct asus_drvdata *drvdat, 122 130 int toolType, u8 *data) 123 131 { ··· 136 126 x = (data[0] & CONTACT_X_MSB_MASK) << 4 | data[1]; 137 127 y = drvdat->tp->max_y - ((data[0] & CONTACT_Y_MSB_MASK) << 8 | data[2]); 138 128 129 + input_report_abs(input, ABS_MT_POSITION_X, x); 130 + input_report_abs(input, ABS_MT_POSITION_Y, y); 131 + 132 + if (drvdat->tp->contact_size < 5) 133 + return; 134 + 139 135 if (toolType == MT_TOOL_PALM) { 140 136 touch_major = MAX_TOUCH_MAJOR; 141 137 pressure = MAX_PRESSURE; ··· 150 134 pressure = data[4] & CONTACT_PRESSURE_MASK; 151 135 } 152 136 153 - input_report_abs(input, ABS_MT_POSITION_X, x); 154 - input_report_abs(input, ABS_MT_POSITION_Y, y); 155 137 input_report_abs(input, ABS_MT_TOUCH_MAJOR, touch_major); 156 138 input_report_abs(input, ABS_MT_PRESSURE, pressure); 157 139 } ··· 160 146 struct input_mt *mt = drvdat->input->mt; 161 147 struct input_mt_slot *oldest; 162 148 int oldid, count, i; 149 + 150 + if (drvdat->tp->contact_size < 5) 151 + return; 163 152 164 153 oldest = NULL; 165 154 oldid = mt->trkid; ··· 189 172 190 173 static int asus_report_input(struct asus_drvdata *drvdat, u8 *data, int size) 191 174 { 192 - int i; 175 + int i, toolType = MT_TOOL_FINGER; 193 176 u8 *contactData = data + 2; 194 177 195 178 if (size != 3 + drvdat->tp->contact_size * drvdat->tp->max_contacts) ··· 197 180 198 181 for (i = 0; i < drvdat->tp->max_contacts; i++) { 199 182 bool down = !!(data[1] & BIT(i+3)); 200 - int toolType = contactData[3] & CONTACT_TOOL_TYPE_MASK ? 183 + 184 + if (drvdat->tp->contact_size >= 5) 185 + toolType = contactData[3] & CONTACT_TOOL_TYPE_MASK ? 201 186 MT_TOOL_PALM : MT_TOOL_FINGER; 202 187 203 188 input_mt_slot(drvdat->input, i); ··· 378 359 struct input_dev *input = hi->input; 379 360 struct asus_drvdata *drvdata = hid_get_drvdata(hdev); 380 361 362 + /* T100CHI uses MULTI_INPUT, bind the touchpad to the mouse hid_input */ 363 + if (drvdata->quirks & QUIRK_T100CHI && 364 + hi->report->id != T100CHI_MOUSE_REPORT_ID) 365 + return 0; 366 + 381 367 if (drvdata->tp) { 382 368 int ret; 383 369 ··· 392 368 drvdata->tp->max_y, 0, 0); 393 369 input_abs_set_res(input, ABS_MT_POSITION_X, drvdata->tp->res_x); 394 370 input_abs_set_res(input, ABS_MT_POSITION_Y, drvdata->tp->res_y); 395 - input_set_abs_params(input, ABS_TOOL_WIDTH, 0, MAX_TOUCH_MAJOR, 0, 0); 396 - input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, MAX_TOUCH_MAJOR, 0, 0); 397 - input_set_abs_params(input, ABS_MT_PRESSURE, 0, MAX_PRESSURE, 0, 0); 371 + 372 + if (drvdata->tp->contact_size >= 5) { 373 + input_set_abs_params(input, ABS_TOOL_WIDTH, 0, 374 + MAX_TOUCH_MAJOR, 0, 0); 375 + input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 376 + MAX_TOUCH_MAJOR, 0, 0); 377 + input_set_abs_params(input, ABS_MT_PRESSURE, 0, 378 + MAX_PRESSURE, 0, 0); 379 + } 398 380 399 381 __set_bit(BTN_LEFT, input->keybit); 400 382 __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); ··· 436 406 * We do it all manually in asus_input_configured 437 407 */ 438 408 return -1; 409 + } 410 + 411 + /* 412 + * Ignore a bunch of bogus collections in the T100CHI descriptor. 413 + * This avoids a bunch of non-functional hid_input devices getting 414 + * created because of the T100CHI using HID_QUIRK_MULTI_INPUT. 415 + */ 416 + if (drvdata->quirks & QUIRK_T100CHI) { 417 + if (field->application == (HID_UP_GENDESK | 0x0080) || 418 + usage->hid == (HID_UP_GENDEVCTRLS | 0x0024) || 419 + usage->hid == (HID_UP_GENDEVCTRLS | 0x0025) || 420 + usage->hid == (HID_UP_GENDEVCTRLS | 0x0026)) 421 + return -1; 422 + /* 423 + * We use the hid_input for the mouse report for the touchpad, 424 + * keep the left button, to avoid the core removing it. 425 + */ 426 + if (field->application == HID_GD_MOUSE && 427 + usage->hid != (HID_UP_BUTTON | 1)) 428 + return -1; 439 429 } 440 430 441 431 /* ASUS-specific keyboard hotkeys */ ··· 607 557 drvdata->quirks = QUIRK_SKIP_INPUT_MAPPING; 608 558 drvdata->tp = &asus_t100ta_tp; 609 559 } 560 + } 561 + 562 + if (drvdata->quirks & QUIRK_T100CHI) { 563 + /* 564 + * All functionality is on a single HID interface and for 565 + * userspace the touchpad must be a separate input_dev. 566 + */ 567 + hdev->quirks |= HID_QUIRK_MULTI_INPUT | 568 + HID_QUIRK_NO_EMPTY_INPUT; 569 + drvdata->tp = &asus_t100chi_tp; 610 570 } 611 571 612 572 if (drvdata->quirks & QUIRK_NO_INIT_REPORTS)