]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/hid/hid-asus.c
HID: hiddev: avoid opening a disconnected device
[mirror_ubuntu-bionic-kernel.git] / drivers / hid / hid-asus.c
CommitLineData
eeb01a57 1/*
b94f7d5d 2 * HID driver for Asus notebook built-in keyboard.
eeb01a57
YF
3 * Fixes small logical maximum to match usage maximum.
4 *
b94f7d5d
YF
5 * Currently supported devices are:
6 * EeeBook X205TA
7 * VivoBook E200HA
8 *
eeb01a57
YF
9 * Copyright (c) 2016 Yusuke Fujimaki <usk.fujimaki@gmail.com>
10 *
11 * This module based on hid-ortek by
12 * Copyright (c) 2010 Johnathon Harris <jmharris@gmail.com>
13 * Copyright (c) 2011 Jiri Kosina
9ce12d8b
BM
14 *
15 * This module has been updated to add support for Asus i2c touchpad.
16 *
17 * Copyright (c) 2016 Brendan McGrath <redmcg@redmandi.dyndns.org>
18 * Copyright (c) 2016 Victor Vlasenko <victor.vlasenko@sysgears.com>
19 * Copyright (c) 2016 Frederik Wenigwieser <frederik.wenigwieser@gmail.com>
eeb01a57
YF
20 */
21
22/*
23 * This program is free software; you can redistribute it and/or modify it
24 * under the terms of the GNU General Public License as published by the Free
25 * Software Foundation; either version 2 of the License, or (at your option)
26 * any later version.
27 */
28
eeb01a57
YF
29#include <linux/hid.h>
30#include <linux/module.h>
9ce12d8b 31#include <linux/input/mt.h>
57573c54 32#include <linux/usb.h> /* For to_usb_interface for T100 touchpad intf check */
eeb01a57
YF
33
34#include "hid-ids.h"
35
9ce12d8b
BM
36MODULE_AUTHOR("Yusuke Fujimaki <usk.fujimaki@gmail.com>");
37MODULE_AUTHOR("Brendan McGrath <redmcg@redmandi.dyndns.org>");
38MODULE_AUTHOR("Victor Vlasenko <victor.vlasenko@sysgears.com>");
39MODULE_AUTHOR("Frederik Wenigwieser <frederik.wenigwieser@gmail.com>");
40MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
41
57573c54
HG
42#define T100_TPAD_INTF 2
43
73c75d39 44#define T100CHI_MOUSE_REPORT_ID 0x06
9ce12d8b
BM
45#define FEATURE_REPORT_ID 0x0d
46#define INPUT_REPORT_ID 0x5d
af22a610 47#define FEATURE_KBD_REPORT_ID 0x5a
af22a610
CC
48#define FEATURE_KBD_REPORT_SIZE 16
49
50#define SUPPORT_KBD_BACKLIGHT BIT(0)
9ce12d8b 51
9ce12d8b
BM
52#define MAX_TOUCH_MAJOR 8
53#define MAX_PRESSURE 128
54
9ce12d8b
BM
55#define BTN_LEFT_MASK 0x01
56#define CONTACT_TOOL_TYPE_MASK 0x80
57#define CONTACT_X_MSB_MASK 0xf0
58#define CONTACT_Y_MSB_MASK 0x0f
59#define CONTACT_TOUCH_MAJOR_MASK 0x07
60#define CONTACT_PRESSURE_MASK 0x7f
61
62#define QUIRK_FIX_NOTEBOOK_REPORT BIT(0)
63#define QUIRK_NO_INIT_REPORTS BIT(1)
64#define QUIRK_SKIP_INPUT_MAPPING BIT(2)
65#define QUIRK_IS_MULTITOUCH BIT(3)
0485b1ec 66#define QUIRK_NO_CONSUMER_USAGES BIT(4)
af22a610 67#define QUIRK_USE_KBD_BACKLIGHT BIT(5)
76dd1fbe 68#define QUIRK_T100_KEYBOARD BIT(6)
5703e52c 69#define QUIRK_T100CHI BIT(7)
832e1eee 70#define QUIRK_G752_KEYBOARD BIT(8)
9ce12d8b 71
a93913e1 72#define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
0485b1ec
MH
73 QUIRK_NO_INIT_REPORTS | \
74 QUIRK_NO_CONSUMER_USAGES)
c81760b9 75#define I2C_TOUCHPAD_QUIRKS (QUIRK_NO_INIT_REPORTS | \
9ce12d8b
BM
76 QUIRK_SKIP_INPUT_MAPPING | \
77 QUIRK_IS_MULTITOUCH)
78
79#define TRKID_SGN ((TRKID_MAX + 1) >> 1)
80
af22a610
CC
81struct asus_kbd_leds {
82 struct led_classdev cdev;
83 struct hid_device *hdev;
84 struct work_struct work;
85 unsigned int brightness;
86 bool removed;
87};
88
c81760b9
HG
89struct asus_touchpad_info {
90 int max_x;
91 int max_y;
b61d43e6
HG
92 int res_x;
93 int res_y;
c81760b9
HG
94 int contact_size;
95 int max_contacts;
96};
97
9ce12d8b
BM
98struct asus_drvdata {
99 unsigned long quirks;
100 struct input_dev *input;
af22a610 101 struct asus_kbd_leds *kbd_backlight;
c81760b9 102 const struct asus_touchpad_info *tp;
af22a610 103 bool enable_backlight;
9ce12d8b
BM
104};
105
c81760b9
HG
106static const struct asus_touchpad_info asus_i2c_tp = {
107 .max_x = 2794,
108 .max_y = 1758,
109 .contact_size = 5,
110 .max_contacts = 5,
111};
112
113static const struct asus_touchpad_info asus_t100ta_tp = {
114 .max_x = 2240,
25cc2611 115 .max_y = 1120,
b61d43e6
HG
116 .res_x = 30, /* units/mm */
117 .res_y = 27, /* units/mm */
c81760b9
HG
118 .contact_size = 5,
119 .max_contacts = 5,
120};
121
73c75d39
HG
122static const struct asus_touchpad_info asus_t100chi_tp = {
123 .max_x = 2640,
124 .max_y = 1320,
125 .res_x = 31, /* units/mm */
126 .res_y = 29, /* units/mm */
127 .contact_size = 3,
128 .max_contacts = 4,
129};
130
c81760b9 131static void asus_report_contact_down(struct asus_drvdata *drvdat,
9ce12d8b
BM
132 int toolType, u8 *data)
133{
c81760b9
HG
134 struct input_dev *input = drvdat->input;
135 int touch_major, pressure, x, y;
136
137 x = (data[0] & CONTACT_X_MSB_MASK) << 4 | data[1];
138 y = drvdat->tp->max_y - ((data[0] & CONTACT_Y_MSB_MASK) << 8 | data[2]);
9ce12d8b 139
73c75d39
HG
140 input_report_abs(input, ABS_MT_POSITION_X, x);
141 input_report_abs(input, ABS_MT_POSITION_Y, y);
142
143 if (drvdat->tp->contact_size < 5)
144 return;
145
9ce12d8b
BM
146 if (toolType == MT_TOOL_PALM) {
147 touch_major = MAX_TOUCH_MAJOR;
148 pressure = MAX_PRESSURE;
149 } else {
150 touch_major = (data[3] >> 4) & CONTACT_TOUCH_MAJOR_MASK;
151 pressure = data[4] & CONTACT_PRESSURE_MASK;
152 }
153
9ce12d8b
BM
154 input_report_abs(input, ABS_MT_TOUCH_MAJOR, touch_major);
155 input_report_abs(input, ABS_MT_PRESSURE, pressure);
156}
157
158/* Required for Synaptics Palm Detection */
c81760b9 159static void asus_report_tool_width(struct asus_drvdata *drvdat)
9ce12d8b 160{
c81760b9 161 struct input_mt *mt = drvdat->input->mt;
9ce12d8b
BM
162 struct input_mt_slot *oldest;
163 int oldid, count, i;
164
73c75d39
HG
165 if (drvdat->tp->contact_size < 5)
166 return;
167
9ce12d8b
BM
168 oldest = NULL;
169 oldid = mt->trkid;
170 count = 0;
171
172 for (i = 0; i < mt->num_slots; ++i) {
173 struct input_mt_slot *ps = &mt->slots[i];
174 int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
175
176 if (id < 0)
177 continue;
178 if ((id - oldid) & TRKID_SGN) {
179 oldest = ps;
180 oldid = id;
181 }
182 count++;
183 }
184
185 if (oldest) {
c81760b9 186 input_report_abs(drvdat->input, ABS_TOOL_WIDTH,
9ce12d8b
BM
187 input_mt_get_value(oldest, ABS_MT_TOUCH_MAJOR));
188 }
189}
190
c81760b9 191static int asus_report_input(struct asus_drvdata *drvdat, u8 *data, int size)
9ce12d8b 192{
73c75d39 193 int i, toolType = MT_TOOL_FINGER;
9ce12d8b
BM
194 u8 *contactData = data + 2;
195
c81760b9
HG
196 if (size != 3 + drvdat->tp->contact_size * drvdat->tp->max_contacts)
197 return 0;
198
199 for (i = 0; i < drvdat->tp->max_contacts; i++) {
9ce12d8b 200 bool down = !!(data[1] & BIT(i+3));
73c75d39
HG
201
202 if (drvdat->tp->contact_size >= 5)
203 toolType = contactData[3] & CONTACT_TOOL_TYPE_MASK ?
9ce12d8b
BM
204 MT_TOOL_PALM : MT_TOOL_FINGER;
205
c81760b9
HG
206 input_mt_slot(drvdat->input, i);
207 input_mt_report_slot_state(drvdat->input, toolType, down);
9ce12d8b
BM
208
209 if (down) {
c81760b9
HG
210 asus_report_contact_down(drvdat, toolType, contactData);
211 contactData += drvdat->tp->contact_size;
9ce12d8b
BM
212 }
213 }
214
c81760b9
HG
215 input_report_key(drvdat->input, BTN_LEFT, data[1] & BTN_LEFT_MASK);
216 asus_report_tool_width(drvdat);
217
218 input_mt_sync_frame(drvdat->input);
219 input_sync(drvdat->input);
9ce12d8b 220
c81760b9 221 return 1;
9ce12d8b
BM
222}
223
224static int asus_raw_event(struct hid_device *hdev,
225 struct hid_report *report, u8 *data, int size)
226{
227 struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
228
c81760b9
HG
229 if (drvdata->tp && data[0] == INPUT_REPORT_ID)
230 return asus_report_input(drvdata, data, size);
9ce12d8b
BM
231
232 return 0;
233}
234
af22a610
CC
235static int asus_kbd_set_report(struct hid_device *hdev, u8 *buf, size_t buf_size)
236{
237 unsigned char *dmabuf;
238 int ret;
239
240 dmabuf = kmemdup(buf, buf_size, GFP_KERNEL);
241 if (!dmabuf)
242 return -ENOMEM;
243
244 ret = hid_hw_raw_request(hdev, FEATURE_KBD_REPORT_ID, dmabuf,
245 buf_size, HID_FEATURE_REPORT,
246 HID_REQ_SET_REPORT);
247 kfree(dmabuf);
248
249 return ret;
250}
251
252static int asus_kbd_init(struct hid_device *hdev)
253{
254 u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x41, 0x53, 0x55, 0x53, 0x20, 0x54,
255 0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 };
256 int ret;
257
258 ret = asus_kbd_set_report(hdev, buf, sizeof(buf));
259 if (ret < 0)
260 hid_err(hdev, "Asus failed to send init command: %d\n", ret);
261
262 return ret;
263}
264
265static int asus_kbd_get_functions(struct hid_device *hdev,
266 unsigned char *kbd_func)
267{
268 u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x05, 0x20, 0x31, 0x00, 0x08 };
269 u8 *readbuf;
270 int ret;
271
272 ret = asus_kbd_set_report(hdev, buf, sizeof(buf));
273 if (ret < 0) {
274 hid_err(hdev, "Asus failed to send configuration command: %d\n", ret);
275 return ret;
276 }
277
278 readbuf = kzalloc(FEATURE_KBD_REPORT_SIZE, GFP_KERNEL);
279 if (!readbuf)
280 return -ENOMEM;
281
282 ret = hid_hw_raw_request(hdev, FEATURE_KBD_REPORT_ID, readbuf,
283 FEATURE_KBD_REPORT_SIZE, HID_FEATURE_REPORT,
284 HID_REQ_GET_REPORT);
285 if (ret < 0) {
286 hid_err(hdev, "Asus failed to request functions: %d\n", ret);
287 kfree(readbuf);
288 return ret;
289 }
290
291 *kbd_func = readbuf[6];
292
293 kfree(readbuf);
294 return ret;
295}
296
297static void asus_kbd_backlight_set(struct led_classdev *led_cdev,
298 enum led_brightness brightness)
299{
300 struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds,
301 cdev);
302 if (led->brightness == brightness)
303 return;
304
305 led->brightness = brightness;
306 schedule_work(&led->work);
307}
308
309static enum led_brightness asus_kbd_backlight_get(struct led_classdev *led_cdev)
310{
311 struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds,
312 cdev);
313
314 return led->brightness;
315}
316
317static void asus_kbd_backlight_work(struct work_struct *work)
318{
319 struct asus_kbd_leds *led = container_of(work, struct asus_kbd_leds, work);
320 u8 buf[] = { FEATURE_KBD_REPORT_ID, 0xba, 0xc5, 0xc4, 0x00 };
321 int ret;
322
323 if (led->removed)
324 return;
325
326 buf[4] = led->brightness;
327
328 ret = asus_kbd_set_report(led->hdev, buf, sizeof(buf));
329 if (ret < 0)
330 hid_err(led->hdev, "Asus failed to set keyboard backlight: %d\n", ret);
331}
332
333static int asus_kbd_register_leds(struct hid_device *hdev)
334{
335 struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
336 unsigned char kbd_func;
337 int ret;
338
339 /* Initialize keyboard */
340 ret = asus_kbd_init(hdev);
341 if (ret < 0)
342 return ret;
343
344 /* Get keyboard functions */
345 ret = asus_kbd_get_functions(hdev, &kbd_func);
346 if (ret < 0)
347 return ret;
348
349 /* Check for backlight support */
350 if (!(kbd_func & SUPPORT_KBD_BACKLIGHT))
351 return -ENODEV;
352
353 drvdata->kbd_backlight = devm_kzalloc(&hdev->dev,
354 sizeof(struct asus_kbd_leds),
355 GFP_KERNEL);
356 if (!drvdata->kbd_backlight)
357 return -ENOMEM;
358
359 drvdata->kbd_backlight->removed = false;
360 drvdata->kbd_backlight->brightness = 0;
361 drvdata->kbd_backlight->hdev = hdev;
362 drvdata->kbd_backlight->cdev.name = "asus::kbd_backlight";
363 drvdata->kbd_backlight->cdev.max_brightness = 3;
364 drvdata->kbd_backlight->cdev.brightness_set = asus_kbd_backlight_set;
365 drvdata->kbd_backlight->cdev.brightness_get = asus_kbd_backlight_get;
366 INIT_WORK(&drvdata->kbd_backlight->work, asus_kbd_backlight_work);
367
368 ret = devm_led_classdev_register(&hdev->dev, &drvdata->kbd_backlight->cdev);
369 if (ret < 0) {
370 /* No need to have this still around */
371 devm_kfree(&hdev->dev, drvdata->kbd_backlight);
372 }
373
374 return ret;
375}
376
9ce12d8b
BM
377static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi)
378{
c8b1b3dd 379 struct input_dev *input = hi->input;
9ce12d8b
BM
380 struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
381
73c75d39
HG
382 /* T100CHI uses MULTI_INPUT, bind the touchpad to the mouse hid_input */
383 if (drvdata->quirks & QUIRK_T100CHI &&
384 hi->report->id != T100CHI_MOUSE_REPORT_ID)
385 return 0;
386
c81760b9 387 if (drvdata->tp) {
9ce12d8b 388 int ret;
9ce12d8b 389
c81760b9
HG
390 input_set_abs_params(input, ABS_MT_POSITION_X, 0,
391 drvdata->tp->max_x, 0, 0);
392 input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
393 drvdata->tp->max_y, 0, 0);
b61d43e6
HG
394 input_abs_set_res(input, ABS_MT_POSITION_X, drvdata->tp->res_x);
395 input_abs_set_res(input, ABS_MT_POSITION_Y, drvdata->tp->res_y);
73c75d39
HG
396
397 if (drvdata->tp->contact_size >= 5) {
398 input_set_abs_params(input, ABS_TOOL_WIDTH, 0,
399 MAX_TOUCH_MAJOR, 0, 0);
400 input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0,
401 MAX_TOUCH_MAJOR, 0, 0);
402 input_set_abs_params(input, ABS_MT_PRESSURE, 0,
403 MAX_PRESSURE, 0, 0);
404 }
9ce12d8b
BM
405
406 __set_bit(BTN_LEFT, input->keybit);
407 __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
408
c81760b9
HG
409 ret = input_mt_init_slots(input, drvdata->tp->max_contacts,
410 INPUT_MT_POINTER);
9ce12d8b
BM
411
412 if (ret) {
413 hid_err(hdev, "Asus input mt init slots failed: %d\n", ret);
414 return ret;
415 }
9ce12d8b
BM
416 }
417
c8b1b3dd
BM
418 drvdata->input = input;
419
af22a610
CC
420 if (drvdata->enable_backlight && asus_kbd_register_leds(hdev))
421 hid_warn(hdev, "Failed to initialize backlight.\n");
422
9ce12d8b
BM
423 return 0;
424}
425
a93913e1 426#define asus_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, \
1caccc25 427 max, EV_KEY, (c))
9ce12d8b
BM
428static int asus_input_mapping(struct hid_device *hdev,
429 struct hid_input *hi, struct hid_field *field,
430 struct hid_usage *usage, unsigned long **bit,
431 int *max)
432{
433 struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
434
435 if (drvdata->quirks & QUIRK_SKIP_INPUT_MAPPING) {
436 /* Don't map anything from the HID report.
437 * We do it all manually in asus_input_configured
438 */
439 return -1;
440 }
441
73c75d39
HG
442 /*
443 * Ignore a bunch of bogus collections in the T100CHI descriptor.
444 * This avoids a bunch of non-functional hid_input devices getting
445 * created because of the T100CHI using HID_QUIRK_MULTI_INPUT.
446 */
447 if (drvdata->quirks & QUIRK_T100CHI) {
448 if (field->application == (HID_UP_GENDESK | 0x0080) ||
449 usage->hid == (HID_UP_GENDEVCTRLS | 0x0024) ||
450 usage->hid == (HID_UP_GENDEVCTRLS | 0x0025) ||
451 usage->hid == (HID_UP_GENDEVCTRLS | 0x0026))
452 return -1;
453 /*
454 * We use the hid_input for the mouse report for the touchpad,
455 * keep the left button, to avoid the core removing it.
456 */
457 if (field->application == HID_GD_MOUSE &&
458 usage->hid != (HID_UP_BUTTON | 1))
459 return -1;
460 }
461
a93913e1 462 /* ASUS-specific keyboard hotkeys */
1caccc25
CC
463 if ((usage->hid & HID_USAGE_PAGE) == 0xff310000) {
464 set_bit(EV_REP, hi->input->evbit);
465 switch (usage->hid & HID_USAGE) {
a93913e1
MH
466 case 0x10: asus_map_key_clear(KEY_BRIGHTNESSDOWN); break;
467 case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP); break;
468 case 0x35: asus_map_key_clear(KEY_DISPLAY_OFF); break;
469 case 0x6c: asus_map_key_clear(KEY_SLEEP); break;
470 case 0x82: asus_map_key_clear(KEY_CAMERA); break;
802b24b4 471 case 0x88: asus_map_key_clear(KEY_RFKILL); break;
a93913e1
MH
472 case 0xb5: asus_map_key_clear(KEY_CALC); break;
473 case 0xc4: asus_map_key_clear(KEY_KBDILLUMUP); break;
474 case 0xc5: asus_map_key_clear(KEY_KBDILLUMDOWN); break;
1caccc25
CC
475
476 /* ASUS touchpad toggle */
a93913e1 477 case 0x6b: asus_map_key_clear(KEY_F21); break;
1caccc25
CC
478
479 /* ROG key */
a93913e1 480 case 0x38: asus_map_key_clear(KEY_PROG1); break;
1caccc25
CC
481
482 /* Fn+C ASUS Splendid */
a93913e1 483 case 0xba: asus_map_key_clear(KEY_PROG2); break;
1caccc25
CC
484
485 /* Fn+Space Power4Gear Hybrid */
a93913e1 486 case 0x5c: asus_map_key_clear(KEY_PROG3); break;
1caccc25
CC
487
488 default:
0485b1ec
MH
489 /* ASUS lazily declares 256 usages, ignore the rest,
490 * as some make the keyboard appear as a pointer device. */
491 return -1;
1caccc25 492 }
af22a610
CC
493
494 /*
495 * Check and enable backlight only on devices with UsagePage ==
496 * 0xff31 to avoid initializing the keyboard firmware multiple
497 * times on devices with multiple HID descriptors but same
498 * PID/VID.
499 */
500 if (drvdata->quirks & QUIRK_USE_KBD_BACKLIGHT)
501 drvdata->enable_backlight = true;
502
1caccc25
CC
503 return 1;
504 }
505
5be91803
DD
506 if ((usage->hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR) {
507 set_bit(EV_REP, hi->input->evbit);
508 switch (usage->hid & HID_USAGE) {
509 case 0xff01: asus_map_key_clear(BTN_1); break;
510 case 0xff02: asus_map_key_clear(BTN_2); break;
511 case 0xff03: asus_map_key_clear(BTN_3); break;
512 case 0xff04: asus_map_key_clear(BTN_4); break;
513 case 0xff05: asus_map_key_clear(BTN_5); break;
514 case 0xff06: asus_map_key_clear(BTN_6); break;
515 case 0xff07: asus_map_key_clear(BTN_7); break;
516 case 0xff08: asus_map_key_clear(BTN_8); break;
517 case 0xff09: asus_map_key_clear(BTN_9); break;
518 case 0xff0a: asus_map_key_clear(BTN_A); break;
519 case 0xff0b: asus_map_key_clear(BTN_B); break;
520 case 0x00f1: asus_map_key_clear(KEY_WLAN); break;
521 case 0x00f2: asus_map_key_clear(KEY_BRIGHTNESSDOWN); break;
522 case 0x00f3: asus_map_key_clear(KEY_BRIGHTNESSUP); break;
523 case 0x00f4: asus_map_key_clear(KEY_DISPLAY_OFF); break;
524 case 0x00f7: asus_map_key_clear(KEY_CAMERA); break;
525 case 0x00f8: asus_map_key_clear(KEY_PROG1); break;
526 default:
527 return 0;
528 }
529
530 return 1;
531 }
532
0485b1ec
MH
533 if (drvdata->quirks & QUIRK_NO_CONSUMER_USAGES &&
534 (usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) {
535 switch (usage->hid & HID_USAGE) {
536 case 0xe2: /* Mute */
537 case 0xe9: /* Volume up */
538 case 0xea: /* Volume down */
539 return 0;
540 default:
541 /* Ignore dummy Consumer usages which make the
542 * keyboard incorrectly appear as a pointer device.
543 */
544 return -1;
545 }
546 }
547
9ce12d8b
BM
548 return 0;
549}
550
551static int asus_start_multitouch(struct hid_device *hdev)
552{
553 int ret;
554 const unsigned char buf[] = { FEATURE_REPORT_ID, 0x00, 0x03, 0x01, 0x00 };
555 unsigned char *dmabuf = kmemdup(buf, sizeof(buf), GFP_KERNEL);
556
557 if (!dmabuf) {
558 ret = -ENOMEM;
559 hid_err(hdev, "Asus failed to alloc dma buf: %d\n", ret);
560 return ret;
561 }
562
563 ret = hid_hw_raw_request(hdev, dmabuf[0], dmabuf, sizeof(buf),
564 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
565
566 kfree(dmabuf);
567
568 if (ret != sizeof(buf)) {
569 hid_err(hdev, "Asus failed to start multitouch: %d\n", ret);
570 return ret;
571 }
572
573 return 0;
574}
575
576static int __maybe_unused asus_reset_resume(struct hid_device *hdev)
577{
578 struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
579
c81760b9 580 if (drvdata->tp)
9ce12d8b
BM
581 return asus_start_multitouch(hdev);
582
583 return 0;
584}
585
586static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
587{
588 int ret;
589 struct asus_drvdata *drvdata;
590
591 drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
592 if (drvdata == NULL) {
593 hid_err(hdev, "Can't alloc Asus descriptor\n");
594 return -ENOMEM;
595 }
596
597 hid_set_drvdata(hdev, drvdata);
598
599 drvdata->quirks = id->driver_data;
600
c81760b9
HG
601 if (drvdata->quirks & QUIRK_IS_MULTITOUCH)
602 drvdata->tp = &asus_i2c_tp;
603
57573c54
HG
604 if (drvdata->quirks & QUIRK_T100_KEYBOARD) {
605 struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
606
c81760b9
HG
607 if (intf->altsetting->desc.bInterfaceNumber == T100_TPAD_INTF) {
608 drvdata->quirks = QUIRK_SKIP_INPUT_MAPPING;
609 drvdata->tp = &asus_t100ta_tp;
610 }
57573c54
HG
611 }
612
73c75d39
HG
613 if (drvdata->quirks & QUIRK_T100CHI) {
614 /*
615 * All functionality is on a single HID interface and for
616 * userspace the touchpad must be a separate input_dev.
617 */
618 hdev->quirks |= HID_QUIRK_MULTI_INPUT |
619 HID_QUIRK_NO_EMPTY_INPUT;
620 drvdata->tp = &asus_t100chi_tp;
621 }
622
9ce12d8b
BM
623 if (drvdata->quirks & QUIRK_NO_INIT_REPORTS)
624 hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
625
626 ret = hid_parse(hdev);
627 if (ret) {
628 hid_err(hdev, "Asus hid parse failed: %d\n", ret);
629 return ret;
630 }
631
632 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
633 if (ret) {
634 hid_err(hdev, "Asus hw start failed: %d\n", ret);
635 return ret;
636 }
637
638 if (!drvdata->input) {
639 hid_err(hdev, "Asus input not registered\n");
640 ret = -ENOMEM;
641 goto err_stop_hw;
642 }
643
c81760b9 644 if (drvdata->tp) {
c8b1b3dd
BM
645 drvdata->input->name = "Asus TouchPad";
646 } else {
647 drvdata->input->name = "Asus Keyboard";
648 }
9ce12d8b 649
c81760b9 650 if (drvdata->tp) {
9ce12d8b
BM
651 ret = asus_start_multitouch(hdev);
652 if (ret)
653 goto err_stop_hw;
654 }
655
656 return 0;
657err_stop_hw:
658 hid_hw_stop(hdev);
659 return ret;
660}
661
af22a610
CC
662static void asus_remove(struct hid_device *hdev)
663{
664 struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
665
666 if (drvdata->kbd_backlight) {
667 drvdata->kbd_backlight->removed = true;
668 cancel_work_sync(&drvdata->kbd_backlight->work);
669 }
715e944f
CC
670
671 hid_hw_stop(hdev);
af22a610
CC
672}
673
832e1eee
MB
674static const __u8 asus_g752_fixed_rdesc[] = {
675 0x19, 0x00, /* Usage Minimum (0x00) */
676 0x2A, 0xFF, 0x00, /* Usage Maximum (0xFF) */
677};
678
eeb01a57
YF
679static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc,
680 unsigned int *rsize)
681{
9ce12d8b
BM
682 struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
683
684 if (drvdata->quirks & QUIRK_FIX_NOTEBOOK_REPORT &&
685 *rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x65) {
b94f7d5d 686 hid_info(hdev, "Fixing up Asus notebook report descriptor\n");
eeb01a57
YF
687 rdesc[55] = 0xdd;
688 }
5703e52c 689 /* For the T100TA keyboard dock */
76dd1fbe
HG
690 if (drvdata->quirks & QUIRK_T100_KEYBOARD &&
691 *rsize == 76 && rdesc[73] == 0x81 && rdesc[74] == 0x01) {
692 hid_info(hdev, "Fixing up Asus T100 keyb report descriptor\n");
693 rdesc[74] &= ~HID_MAIN_ITEM_CONSTANT;
694 }
5703e52c
HG
695 /* For the T100CHI keyboard dock */
696 if (drvdata->quirks & QUIRK_T100CHI &&
697 *rsize == 403 && rdesc[388] == 0x09 && rdesc[389] == 0x76) {
698 /*
699 * Change Usage (76h) to Usage Minimum (00h), Usage Maximum
700 * (FFh) and clear the flags in the Input() byte.
701 * Note the descriptor has a bogus 0 byte at the end so we
702 * only need 1 extra byte.
703 */
704 *rsize = 404;
705 rdesc = kmemdup(rdesc, *rsize, GFP_KERNEL);
706 if (!rdesc)
707 return NULL;
708
709 hid_info(hdev, "Fixing up T100CHI keyb report descriptor\n");
710 memmove(rdesc + 392, rdesc + 390, 12);
711 rdesc[388] = 0x19;
712 rdesc[389] = 0x00;
713 rdesc[390] = 0x29;
714 rdesc[391] = 0xff;
715 rdesc[402] = 0x00;
716 }
832e1eee
MB
717 if (drvdata->quirks & QUIRK_G752_KEYBOARD &&
718 *rsize == 75 && rdesc[61] == 0x15 && rdesc[62] == 0x00) {
719 /* report is missing usage mninum and maximum */
720 __u8 *new_rdesc;
721 size_t new_size = *rsize + sizeof(asus_g752_fixed_rdesc);
722
723 new_rdesc = devm_kzalloc(&hdev->dev, new_size, GFP_KERNEL);
724 if (new_rdesc == NULL)
725 return rdesc;
726
727 hid_info(hdev, "Fixing up Asus G752 keyb report descriptor\n");
728 /* copy the valid part */
729 memcpy(new_rdesc, rdesc, 61);
730 /* insert missing part */
731 memcpy(new_rdesc + 61, asus_g752_fixed_rdesc, sizeof(asus_g752_fixed_rdesc));
732 /* copy remaining data */
733 memcpy(new_rdesc + 61 + sizeof(asus_g752_fixed_rdesc), rdesc + 61, *rsize - 61);
734
735 *rsize = new_size;
736 rdesc = new_rdesc;
737 }
76dd1fbe 738
eeb01a57
YF
739 return rdesc;
740}
741
742static const struct hid_device_id asus_devices[] = {
9ce12d8b 743 { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK,
a93913e1 744 USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD), I2C_KEYBOARD_QUIRKS},
9ce12d8b 745 { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK,
c81760b9 746 USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD), I2C_TOUCHPAD_QUIRKS },
1caccc25 747 { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
339ee3fc 748 USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1), QUIRK_USE_KBD_BACKLIGHT },
1caccc25 749 { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
af22a610 750 USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2), QUIRK_USE_KBD_BACKLIGHT },
832e1eee
MB
751 { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
752 USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3), QUIRK_G752_KEYBOARD },
76dd1fbe
HG
753 { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
754 USB_DEVICE_ID_ASUSTEK_T100_KEYBOARD),
755 QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES },
5be91803 756 { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_ASUS_AK1D) },
38b2d78c 757 { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_ASUS_MD_5110) },
5be91803 758 { HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_ASUS_MD_5112) },
5703e52c
HG
759 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK,
760 USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD), QUIRK_T100CHI },
761
eeb01a57
YF
762 { }
763};
764MODULE_DEVICE_TABLE(hid, asus_devices);
765
766static struct hid_driver asus_driver = {
9ce12d8b
BM
767 .name = "asus",
768 .id_table = asus_devices,
769 .report_fixup = asus_report_fixup,
770 .probe = asus_probe,
af22a610 771 .remove = asus_remove,
9ce12d8b
BM
772 .input_mapping = asus_input_mapping,
773 .input_configured = asus_input_configured,
774#ifdef CONFIG_PM
775 .reset_resume = asus_reset_resume,
776#endif
777 .raw_event = asus_raw_event
eeb01a57
YF
778};
779module_hid_driver(asus_driver);
780
781MODULE_LICENSE("GPL");