1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * HID driver for Asus notebook built-in keyboard. |
4 | * Fixes small logical maximum to match usage maximum. |
5 | * |
6 | * Currently supported devices are: |
7 | * EeeBook X205TA |
8 | * VivoBook E200HA |
9 | * |
10 | * Copyright (c) 2016 Yusuke Fujimaki <usk.fujimaki@gmail.com> |
11 | * |
12 | * This module based on hid-ortek by |
13 | * Copyright (c) 2010 Johnathon Harris <jmharris@gmail.com> |
14 | * Copyright (c) 2011 Jiri Kosina |
15 | * |
16 | * This module has been updated to add support for Asus i2c touchpad. |
17 | * |
18 | * Copyright (c) 2016 Brendan McGrath <redmcg@redmandi.dyndns.org> |
19 | * Copyright (c) 2016 Victor Vlasenko <victor.vlasenko@sysgears.com> |
20 | * Copyright (c) 2016 Frederik Wenigwieser <frederik.wenigwieser@gmail.com> |
21 | */ |
22 | |
23 | /* |
24 | */ |
25 | |
26 | #include <linux/dmi.h> |
27 | #include <linux/hid.h> |
28 | #include <linux/module.h> |
29 | #include <linux/platform_data/x86/asus-wmi.h> |
30 | #include <linux/input/mt.h> |
31 | #include <linux/usb.h> /* For to_usb_interface for T100 touchpad intf check */ |
32 | #include <linux/power_supply.h> |
33 | #include <linux/leds.h> |
34 | |
35 | #include "hid-ids.h" |
36 | |
37 | MODULE_AUTHOR("Yusuke Fujimaki <usk.fujimaki@gmail.com>" ); |
38 | MODULE_AUTHOR("Brendan McGrath <redmcg@redmandi.dyndns.org>" ); |
39 | MODULE_AUTHOR("Victor Vlasenko <victor.vlasenko@sysgears.com>" ); |
40 | MODULE_AUTHOR("Frederik Wenigwieser <frederik.wenigwieser@gmail.com>" ); |
41 | MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad" ); |
42 | |
43 | #define T100_TPAD_INTF 2 |
44 | #define MEDION_E1239T_TPAD_INTF 1 |
45 | |
46 | #define E1239T_TP_TOGGLE_REPORT_ID 0x05 |
47 | #define T100CHI_MOUSE_REPORT_ID 0x06 |
48 | #define FEATURE_REPORT_ID 0x0d |
49 | #define INPUT_REPORT_ID 0x5d |
50 | #define FEATURE_KBD_REPORT_ID 0x5a |
51 | #define FEATURE_KBD_REPORT_SIZE 16 |
52 | #define FEATURE_KBD_LED_REPORT_ID1 0x5d |
53 | #define FEATURE_KBD_LED_REPORT_ID2 0x5e |
54 | |
55 | #define SUPPORT_KBD_BACKLIGHT BIT(0) |
56 | |
57 | #define MAX_TOUCH_MAJOR 8 |
58 | #define MAX_PRESSURE 128 |
59 | |
60 | #define BTN_LEFT_MASK 0x01 |
61 | #define CONTACT_TOOL_TYPE_MASK 0x80 |
62 | #define CONTACT_X_MSB_MASK 0xf0 |
63 | #define CONTACT_Y_MSB_MASK 0x0f |
64 | #define CONTACT_TOUCH_MAJOR_MASK 0x07 |
65 | #define CONTACT_PRESSURE_MASK 0x7f |
66 | |
67 | #define BATTERY_REPORT_ID (0x03) |
68 | #define BATTERY_REPORT_SIZE (1 + 8) |
69 | #define BATTERY_LEVEL_MAX ((u8)255) |
70 | #define BATTERY_STAT_DISCONNECT (0) |
71 | #define BATTERY_STAT_CHARGING (1) |
72 | #define BATTERY_STAT_FULL (2) |
73 | |
74 | #define QUIRK_FIX_NOTEBOOK_REPORT BIT(0) |
75 | #define QUIRK_NO_INIT_REPORTS BIT(1) |
76 | #define QUIRK_SKIP_INPUT_MAPPING BIT(2) |
77 | #define QUIRK_IS_MULTITOUCH BIT(3) |
78 | #define QUIRK_NO_CONSUMER_USAGES BIT(4) |
79 | #define QUIRK_USE_KBD_BACKLIGHT BIT(5) |
80 | #define QUIRK_T100_KEYBOARD BIT(6) |
81 | #define QUIRK_T100CHI BIT(7) |
82 | #define QUIRK_G752_KEYBOARD BIT(8) |
83 | #define QUIRK_T90CHI BIT(9) |
84 | #define QUIRK_MEDION_E1239T BIT(10) |
85 | #define QUIRK_ROG_NKEY_KEYBOARD BIT(11) |
86 | #define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12) |
87 | |
88 | #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ |
89 | QUIRK_NO_INIT_REPORTS | \ |
90 | QUIRK_NO_CONSUMER_USAGES) |
91 | #define I2C_TOUCHPAD_QUIRKS (QUIRK_NO_INIT_REPORTS | \ |
92 | QUIRK_SKIP_INPUT_MAPPING | \ |
93 | QUIRK_IS_MULTITOUCH) |
94 | |
95 | #define TRKID_SGN ((TRKID_MAX + 1) >> 1) |
96 | |
97 | struct asus_kbd_leds { |
98 | struct led_classdev cdev; |
99 | struct hid_device *hdev; |
100 | struct work_struct work; |
101 | unsigned int brightness; |
102 | spinlock_t lock; |
103 | bool removed; |
104 | }; |
105 | |
106 | struct asus_touchpad_info { |
107 | int max_x; |
108 | int max_y; |
109 | int res_x; |
110 | int res_y; |
111 | int contact_size; |
112 | int max_contacts; |
113 | int report_size; |
114 | }; |
115 | |
116 | struct asus_drvdata { |
117 | unsigned long quirks; |
118 | struct hid_device *hdev; |
119 | struct input_dev *input; |
120 | struct input_dev *tp_kbd_input; |
121 | struct asus_kbd_leds *kbd_backlight; |
122 | const struct asus_touchpad_info *tp; |
123 | bool enable_backlight; |
124 | struct power_supply *battery; |
125 | struct power_supply_desc battery_desc; |
126 | int battery_capacity; |
127 | int battery_stat; |
128 | bool battery_in_query; |
129 | unsigned long battery_next_query; |
130 | }; |
131 | |
132 | static int asus_report_battery(struct asus_drvdata *, u8 *, int); |
133 | |
134 | static const struct asus_touchpad_info asus_i2c_tp = { |
135 | .max_x = 2794, |
136 | .max_y = 1758, |
137 | .contact_size = 5, |
138 | .max_contacts = 5, |
139 | .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */, |
140 | }; |
141 | |
142 | static const struct asus_touchpad_info asus_t100ta_tp = { |
143 | .max_x = 2240, |
144 | .max_y = 1120, |
145 | .res_x = 30, /* units/mm */ |
146 | .res_y = 27, /* units/mm */ |
147 | .contact_size = 5, |
148 | .max_contacts = 5, |
149 | .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */, |
150 | }; |
151 | |
152 | static const struct asus_touchpad_info asus_t100ha_tp = { |
153 | .max_x = 2640, |
154 | .max_y = 1320, |
155 | .res_x = 30, /* units/mm */ |
156 | .res_y = 29, /* units/mm */ |
157 | .contact_size = 5, |
158 | .max_contacts = 5, |
159 | .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */, |
160 | }; |
161 | |
162 | static const struct asus_touchpad_info asus_t200ta_tp = { |
163 | .max_x = 3120, |
164 | .max_y = 1716, |
165 | .res_x = 30, /* units/mm */ |
166 | .res_y = 28, /* units/mm */ |
167 | .contact_size = 5, |
168 | .max_contacts = 5, |
169 | .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */, |
170 | }; |
171 | |
172 | static const struct asus_touchpad_info asus_t100chi_tp = { |
173 | .max_x = 2640, |
174 | .max_y = 1320, |
175 | .res_x = 31, /* units/mm */ |
176 | .res_y = 29, /* units/mm */ |
177 | .contact_size = 3, |
178 | .max_contacts = 4, |
179 | .report_size = 15 /* 2 byte header + 3 * 4 + 1 byte footer */, |
180 | }; |
181 | |
182 | static const struct asus_touchpad_info medion_e1239t_tp = { |
183 | .max_x = 2640, |
184 | .max_y = 1380, |
185 | .res_x = 29, /* units/mm */ |
186 | .res_y = 28, /* units/mm */ |
187 | .contact_size = 5, |
188 | .max_contacts = 5, |
189 | .report_size = 32 /* 2 byte header + 5 * 5 + 5 byte footer */, |
190 | }; |
191 | |
192 | static void asus_report_contact_down(struct asus_drvdata *drvdat, |
193 | int toolType, u8 *data) |
194 | { |
195 | struct input_dev *input = drvdat->input; |
196 | int touch_major, pressure, x, y; |
197 | |
198 | x = (data[0] & CONTACT_X_MSB_MASK) << 4 | data[1]; |
199 | y = drvdat->tp->max_y - ((data[0] & CONTACT_Y_MSB_MASK) << 8 | data[2]); |
200 | |
201 | input_report_abs(dev: input, ABS_MT_POSITION_X, value: x); |
202 | input_report_abs(dev: input, ABS_MT_POSITION_Y, value: y); |
203 | |
204 | if (drvdat->tp->contact_size < 5) |
205 | return; |
206 | |
207 | if (toolType == MT_TOOL_PALM) { |
208 | touch_major = MAX_TOUCH_MAJOR; |
209 | pressure = MAX_PRESSURE; |
210 | } else { |
211 | touch_major = (data[3] >> 4) & CONTACT_TOUCH_MAJOR_MASK; |
212 | pressure = data[4] & CONTACT_PRESSURE_MASK; |
213 | } |
214 | |
215 | input_report_abs(dev: input, ABS_MT_TOUCH_MAJOR, value: touch_major); |
216 | input_report_abs(dev: input, ABS_MT_PRESSURE, value: pressure); |
217 | } |
218 | |
219 | /* Required for Synaptics Palm Detection */ |
220 | static void asus_report_tool_width(struct asus_drvdata *drvdat) |
221 | { |
222 | struct input_mt *mt = drvdat->input->mt; |
223 | struct input_mt_slot *oldest; |
224 | int oldid, i; |
225 | |
226 | if (drvdat->tp->contact_size < 5) |
227 | return; |
228 | |
229 | oldest = NULL; |
230 | oldid = mt->trkid; |
231 | |
232 | for (i = 0; i < mt->num_slots; ++i) { |
233 | struct input_mt_slot *ps = &mt->slots[i]; |
234 | int id = input_mt_get_value(slot: ps, ABS_MT_TRACKING_ID); |
235 | |
236 | if (id < 0) |
237 | continue; |
238 | if ((id - oldid) & TRKID_SGN) { |
239 | oldest = ps; |
240 | oldid = id; |
241 | } |
242 | } |
243 | |
244 | if (oldest) { |
245 | input_report_abs(dev: drvdat->input, ABS_TOOL_WIDTH, |
246 | value: input_mt_get_value(slot: oldest, ABS_MT_TOUCH_MAJOR)); |
247 | } |
248 | } |
249 | |
250 | static int asus_report_input(struct asus_drvdata *drvdat, u8 *data, int size) |
251 | { |
252 | int i, toolType = MT_TOOL_FINGER; |
253 | u8 *contactData = data + 2; |
254 | |
255 | if (size != drvdat->tp->report_size) |
256 | return 0; |
257 | |
258 | for (i = 0; i < drvdat->tp->max_contacts; i++) { |
259 | bool down = !!(data[1] & BIT(i+3)); |
260 | |
261 | if (drvdat->tp->contact_size >= 5) |
262 | toolType = contactData[3] & CONTACT_TOOL_TYPE_MASK ? |
263 | MT_TOOL_PALM : MT_TOOL_FINGER; |
264 | |
265 | input_mt_slot(dev: drvdat->input, slot: i); |
266 | input_mt_report_slot_state(dev: drvdat->input, tool_type: toolType, active: down); |
267 | |
268 | if (down) { |
269 | asus_report_contact_down(drvdat, toolType, data: contactData); |
270 | contactData += drvdat->tp->contact_size; |
271 | } |
272 | } |
273 | |
274 | input_report_key(dev: drvdat->input, BTN_LEFT, value: data[1] & BTN_LEFT_MASK); |
275 | asus_report_tool_width(drvdat); |
276 | |
277 | input_mt_sync_frame(dev: drvdat->input); |
278 | input_sync(dev: drvdat->input); |
279 | |
280 | return 1; |
281 | } |
282 | |
283 | static int asus_e1239t_event(struct asus_drvdata *drvdat, u8 *data, int size) |
284 | { |
285 | if (size != 3) |
286 | return 0; |
287 | |
288 | /* Handle broken mute key which only sends press events */ |
289 | if (!drvdat->tp && |
290 | data[0] == 0x02 && data[1] == 0xe2 && data[2] == 0x00) { |
291 | input_report_key(dev: drvdat->input, KEY_MUTE, value: 1); |
292 | input_sync(dev: drvdat->input); |
293 | input_report_key(dev: drvdat->input, KEY_MUTE, value: 0); |
294 | input_sync(dev: drvdat->input); |
295 | return 1; |
296 | } |
297 | |
298 | /* Handle custom touchpad toggle key which only sends press events */ |
299 | if (drvdat->tp_kbd_input && |
300 | data[0] == 0x05 && data[1] == 0x02 && data[2] == 0x28) { |
301 | input_report_key(dev: drvdat->tp_kbd_input, KEY_F21, value: 1); |
302 | input_sync(dev: drvdat->tp_kbd_input); |
303 | input_report_key(dev: drvdat->tp_kbd_input, KEY_F21, value: 0); |
304 | input_sync(dev: drvdat->tp_kbd_input); |
305 | return 1; |
306 | } |
307 | |
308 | return 0; |
309 | } |
310 | |
311 | static int asus_event(struct hid_device *hdev, struct hid_field *field, |
312 | struct hid_usage *usage, __s32 value) |
313 | { |
314 | if ((usage->hid & HID_USAGE_PAGE) == 0xff310000 && |
315 | (usage->hid & HID_USAGE) != 0x00 && |
316 | (usage->hid & HID_USAGE) != 0xff && !usage->type) { |
317 | hid_warn(hdev, "Unmapped Asus vendor usagepage code 0x%02x\n" , |
318 | usage->hid & HID_USAGE); |
319 | } |
320 | |
321 | return 0; |
322 | } |
323 | |
324 | static int asus_raw_event(struct hid_device *hdev, |
325 | struct hid_report *report, u8 *data, int size) |
326 | { |
327 | struct asus_drvdata *drvdata = hid_get_drvdata(hdev); |
328 | |
329 | if (drvdata->battery && data[0] == BATTERY_REPORT_ID) |
330 | return asus_report_battery(drvdata, data, size); |
331 | |
332 | if (drvdata->tp && data[0] == INPUT_REPORT_ID) |
333 | return asus_report_input(drvdat: drvdata, data, size); |
334 | |
335 | if (drvdata->quirks & QUIRK_MEDION_E1239T) |
336 | return asus_e1239t_event(drvdat: drvdata, data, size); |
337 | |
338 | if (drvdata->quirks & QUIRK_USE_KBD_BACKLIGHT) { |
339 | /* |
340 | * Skip these report ID, the device emits a continuous stream associated |
341 | * with the AURA mode it is in which looks like an 'echo'. |
342 | */ |
343 | if (report->id == FEATURE_KBD_LED_REPORT_ID1 || |
344 | report->id == FEATURE_KBD_LED_REPORT_ID2) { |
345 | return -1; |
346 | /* Additional report filtering */ |
347 | } else if (report->id == FEATURE_KBD_REPORT_ID) { |
348 | /* |
349 | * G14 and G15 send these codes on some keypresses with no |
350 | * discernable reason for doing so. We'll filter them out to avoid |
351 | * unmapped warning messages later. |
352 | */ |
353 | if (data[1] == 0xea || data[1] == 0xec || data[1] == 0x02 || |
354 | data[1] == 0x8a || data[1] == 0x9e) { |
355 | return -1; |
356 | } |
357 | } |
358 | if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) { |
359 | /* |
360 | * G713 and G733 send these codes on some keypresses, depending on |
361 | * the key pressed it can trigger a shutdown event if not caught. |
362 | */ |
363 | if(data[0] == 0x02 && data[1] == 0x30) { |
364 | return -1; |
365 | } |
366 | } |
367 | |
368 | } |
369 | |
370 | if (drvdata->quirks & QUIRK_ROG_CLAYMORE_II_KEYBOARD) { |
371 | /* |
372 | * CLAYMORE II keyboard sends this packet when it goes to sleep |
373 | * this causes the whole system to go into suspend. |
374 | */ |
375 | |
376 | if(size == 2 && data[0] == 0x02 && data[1] == 0x00) { |
377 | return -1; |
378 | } |
379 | } |
380 | |
381 | return 0; |
382 | } |
383 | |
384 | static int asus_kbd_set_report(struct hid_device *hdev, u8 *buf, size_t buf_size) |
385 | { |
386 | unsigned char *dmabuf; |
387 | int ret; |
388 | |
389 | dmabuf = kmemdup(p: buf, size: buf_size, GFP_KERNEL); |
390 | if (!dmabuf) |
391 | return -ENOMEM; |
392 | |
393 | /* |
394 | * The report ID should be set from the incoming buffer due to LED and key |
395 | * interfaces having different pages |
396 | */ |
397 | ret = hid_hw_raw_request(hdev, reportnum: buf[0], buf: dmabuf, |
398 | len: buf_size, rtype: HID_FEATURE_REPORT, |
399 | reqtype: HID_REQ_SET_REPORT); |
400 | kfree(objp: dmabuf); |
401 | |
402 | return ret; |
403 | } |
404 | |
405 | static int asus_kbd_init(struct hid_device *hdev) |
406 | { |
407 | u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x41, 0x53, 0x55, 0x53, 0x20, 0x54, |
408 | 0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 }; |
409 | int ret; |
410 | |
411 | ret = asus_kbd_set_report(hdev, buf, buf_size: sizeof(buf)); |
412 | if (ret < 0) |
413 | hid_err(hdev, "Asus failed to send init command: %d\n" , ret); |
414 | |
415 | return ret; |
416 | } |
417 | |
418 | static int asus_kbd_get_functions(struct hid_device *hdev, |
419 | unsigned char *kbd_func) |
420 | { |
421 | u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x05, 0x20, 0x31, 0x00, 0x08 }; |
422 | u8 *readbuf; |
423 | int ret; |
424 | |
425 | ret = asus_kbd_set_report(hdev, buf, buf_size: sizeof(buf)); |
426 | if (ret < 0) { |
427 | hid_err(hdev, "Asus failed to send configuration command: %d\n" , ret); |
428 | return ret; |
429 | } |
430 | |
431 | readbuf = kzalloc(FEATURE_KBD_REPORT_SIZE, GFP_KERNEL); |
432 | if (!readbuf) |
433 | return -ENOMEM; |
434 | |
435 | ret = hid_hw_raw_request(hdev, FEATURE_KBD_REPORT_ID, buf: readbuf, |
436 | FEATURE_KBD_REPORT_SIZE, rtype: HID_FEATURE_REPORT, |
437 | reqtype: HID_REQ_GET_REPORT); |
438 | if (ret < 0) { |
439 | hid_err(hdev, "Asus failed to request functions: %d\n" , ret); |
440 | kfree(objp: readbuf); |
441 | return ret; |
442 | } |
443 | |
444 | *kbd_func = readbuf[6]; |
445 | |
446 | kfree(objp: readbuf); |
447 | return ret; |
448 | } |
449 | |
450 | static int rog_nkey_led_init(struct hid_device *hdev) |
451 | { |
452 | u8 buf_init_start[] = { FEATURE_KBD_LED_REPORT_ID1, 0xB9 }; |
453 | u8 buf_init2[] = { FEATURE_KBD_LED_REPORT_ID1, 0x41, 0x53, 0x55, 0x53, 0x20, |
454 | 0x54, 0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 }; |
455 | u8 buf_init3[] = { FEATURE_KBD_LED_REPORT_ID1, |
456 | 0x05, 0x20, 0x31, 0x00, 0x08 }; |
457 | int ret; |
458 | |
459 | hid_info(hdev, "Asus initialise N-KEY Device" ); |
460 | /* The first message is an init start */ |
461 | ret = asus_kbd_set_report(hdev, buf: buf_init_start, buf_size: sizeof(buf_init_start)); |
462 | if (ret < 0) { |
463 | hid_warn(hdev, "Asus failed to send init start command: %d\n" , ret); |
464 | return ret; |
465 | } |
466 | /* Followed by a string */ |
467 | ret = asus_kbd_set_report(hdev, buf: buf_init2, buf_size: sizeof(buf_init2)); |
468 | if (ret < 0) { |
469 | hid_warn(hdev, "Asus failed to send init command 1.0: %d\n" , ret); |
470 | return ret; |
471 | } |
472 | /* Followed by a string */ |
473 | ret = asus_kbd_set_report(hdev, buf: buf_init3, buf_size: sizeof(buf_init3)); |
474 | if (ret < 0) { |
475 | hid_warn(hdev, "Asus failed to send init command 1.1: %d\n" , ret); |
476 | return ret; |
477 | } |
478 | |
479 | /* begin second report ID with same data */ |
480 | buf_init2[0] = FEATURE_KBD_LED_REPORT_ID2; |
481 | buf_init3[0] = FEATURE_KBD_LED_REPORT_ID2; |
482 | |
483 | ret = asus_kbd_set_report(hdev, buf: buf_init2, buf_size: sizeof(buf_init2)); |
484 | if (ret < 0) { |
485 | hid_warn(hdev, "Asus failed to send init command 2.0: %d\n" , ret); |
486 | return ret; |
487 | } |
488 | ret = asus_kbd_set_report(hdev, buf: buf_init3, buf_size: sizeof(buf_init3)); |
489 | if (ret < 0) |
490 | hid_warn(hdev, "Asus failed to send init command 2.1: %d\n" , ret); |
491 | |
492 | return ret; |
493 | } |
494 | |
495 | static void asus_schedule_work(struct asus_kbd_leds *led) |
496 | { |
497 | unsigned long flags; |
498 | |
499 | spin_lock_irqsave(&led->lock, flags); |
500 | if (!led->removed) |
501 | schedule_work(work: &led->work); |
502 | spin_unlock_irqrestore(lock: &led->lock, flags); |
503 | } |
504 | |
505 | static void asus_kbd_backlight_set(struct led_classdev *led_cdev, |
506 | enum led_brightness brightness) |
507 | { |
508 | struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds, |
509 | cdev); |
510 | unsigned long flags; |
511 | |
512 | spin_lock_irqsave(&led->lock, flags); |
513 | led->brightness = brightness; |
514 | spin_unlock_irqrestore(lock: &led->lock, flags); |
515 | |
516 | asus_schedule_work(led); |
517 | } |
518 | |
519 | static enum led_brightness asus_kbd_backlight_get(struct led_classdev *led_cdev) |
520 | { |
521 | struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds, |
522 | cdev); |
523 | enum led_brightness brightness; |
524 | unsigned long flags; |
525 | |
526 | spin_lock_irqsave(&led->lock, flags); |
527 | brightness = led->brightness; |
528 | spin_unlock_irqrestore(lock: &led->lock, flags); |
529 | |
530 | return brightness; |
531 | } |
532 | |
533 | static void asus_kbd_backlight_work(struct work_struct *work) |
534 | { |
535 | struct asus_kbd_leds *led = container_of(work, struct asus_kbd_leds, work); |
536 | u8 buf[] = { FEATURE_KBD_REPORT_ID, 0xba, 0xc5, 0xc4, 0x00 }; |
537 | int ret; |
538 | unsigned long flags; |
539 | |
540 | spin_lock_irqsave(&led->lock, flags); |
541 | buf[4] = led->brightness; |
542 | spin_unlock_irqrestore(lock: &led->lock, flags); |
543 | |
544 | ret = asus_kbd_set_report(hdev: led->hdev, buf, buf_size: sizeof(buf)); |
545 | if (ret < 0) |
546 | hid_err(led->hdev, "Asus failed to set keyboard backlight: %d\n" , ret); |
547 | } |
548 | |
549 | /* WMI-based keyboard backlight LED control (via asus-wmi driver) takes |
550 | * precedence. We only activate HID-based backlight control when the |
551 | * WMI control is not available. |
552 | */ |
553 | static bool asus_kbd_wmi_led_control_present(struct hid_device *hdev) |
554 | { |
555 | u32 value; |
556 | int ret; |
557 | |
558 | if (!IS_ENABLED(CONFIG_ASUS_WMI)) |
559 | return false; |
560 | |
561 | ret = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, |
562 | ASUS_WMI_DEVID_KBD_BACKLIGHT, arg1: 0, retval: &value); |
563 | hid_dbg(hdev, "WMI backlight check: rc %d value %x" , ret, value); |
564 | if (ret) |
565 | return false; |
566 | |
567 | return !!(value & ASUS_WMI_DSTS_PRESENCE_BIT); |
568 | } |
569 | |
570 | static int asus_kbd_register_leds(struct hid_device *hdev) |
571 | { |
572 | struct asus_drvdata *drvdata = hid_get_drvdata(hdev); |
573 | unsigned char kbd_func; |
574 | int ret; |
575 | |
576 | if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) { |
577 | ret = rog_nkey_led_init(hdev); |
578 | if (ret < 0) |
579 | return ret; |
580 | } else { |
581 | /* Initialize keyboard */ |
582 | ret = asus_kbd_init(hdev); |
583 | if (ret < 0) |
584 | return ret; |
585 | |
586 | /* Get keyboard functions */ |
587 | ret = asus_kbd_get_functions(hdev, kbd_func: &kbd_func); |
588 | if (ret < 0) |
589 | return ret; |
590 | |
591 | /* Check for backlight support */ |
592 | if (!(kbd_func & SUPPORT_KBD_BACKLIGHT)) |
593 | return -ENODEV; |
594 | } |
595 | |
596 | drvdata->kbd_backlight = devm_kzalloc(dev: &hdev->dev, |
597 | size: sizeof(struct asus_kbd_leds), |
598 | GFP_KERNEL); |
599 | if (!drvdata->kbd_backlight) |
600 | return -ENOMEM; |
601 | |
602 | drvdata->kbd_backlight->removed = false; |
603 | drvdata->kbd_backlight->brightness = 0; |
604 | drvdata->kbd_backlight->hdev = hdev; |
605 | drvdata->kbd_backlight->cdev.name = "asus::kbd_backlight" ; |
606 | drvdata->kbd_backlight->cdev.max_brightness = 3; |
607 | drvdata->kbd_backlight->cdev.brightness_set = asus_kbd_backlight_set; |
608 | drvdata->kbd_backlight->cdev.brightness_get = asus_kbd_backlight_get; |
609 | INIT_WORK(&drvdata->kbd_backlight->work, asus_kbd_backlight_work); |
610 | spin_lock_init(&drvdata->kbd_backlight->lock); |
611 | |
612 | ret = devm_led_classdev_register(parent: &hdev->dev, led_cdev: &drvdata->kbd_backlight->cdev); |
613 | if (ret < 0) { |
614 | /* No need to have this still around */ |
615 | devm_kfree(dev: &hdev->dev, p: drvdata->kbd_backlight); |
616 | } |
617 | |
618 | return ret; |
619 | } |
620 | |
621 | /* |
622 | * [0] REPORT_ID (same value defined in report descriptor) |
623 | * [1] rest battery level. range [0..255] |
624 | * [2]..[7] Bluetooth hardware address (MAC address) |
625 | * [8] charging status |
626 | * = 0 : AC offline / discharging |
627 | * = 1 : AC online / charging |
628 | * = 2 : AC online / fully charged |
629 | */ |
630 | static int asus_parse_battery(struct asus_drvdata *drvdata, u8 *data, int size) |
631 | { |
632 | u8 sts; |
633 | u8 lvl; |
634 | int val; |
635 | |
636 | lvl = data[1]; |
637 | sts = data[8]; |
638 | |
639 | drvdata->battery_capacity = ((int)lvl * 100) / (int)BATTERY_LEVEL_MAX; |
640 | |
641 | switch (sts) { |
642 | case BATTERY_STAT_CHARGING: |
643 | val = POWER_SUPPLY_STATUS_CHARGING; |
644 | break; |
645 | case BATTERY_STAT_FULL: |
646 | val = POWER_SUPPLY_STATUS_FULL; |
647 | break; |
648 | case BATTERY_STAT_DISCONNECT: |
649 | default: |
650 | val = POWER_SUPPLY_STATUS_DISCHARGING; |
651 | break; |
652 | } |
653 | drvdata->battery_stat = val; |
654 | |
655 | return 0; |
656 | } |
657 | |
658 | static int asus_report_battery(struct asus_drvdata *drvdata, u8 *data, int size) |
659 | { |
660 | /* notify only the autonomous event by device */ |
661 | if ((drvdata->battery_in_query == false) && |
662 | (size == BATTERY_REPORT_SIZE)) |
663 | power_supply_changed(psy: drvdata->battery); |
664 | |
665 | return 0; |
666 | } |
667 | |
668 | static int asus_battery_query(struct asus_drvdata *drvdata) |
669 | { |
670 | u8 *buf; |
671 | int ret = 0; |
672 | |
673 | buf = kmalloc(BATTERY_REPORT_SIZE, GFP_KERNEL); |
674 | if (!buf) |
675 | return -ENOMEM; |
676 | |
677 | drvdata->battery_in_query = true; |
678 | ret = hid_hw_raw_request(hdev: drvdata->hdev, BATTERY_REPORT_ID, |
679 | buf, BATTERY_REPORT_SIZE, |
680 | rtype: HID_INPUT_REPORT, reqtype: HID_REQ_GET_REPORT); |
681 | drvdata->battery_in_query = false; |
682 | if (ret == BATTERY_REPORT_SIZE) |
683 | ret = asus_parse_battery(drvdata, data: buf, BATTERY_REPORT_SIZE); |
684 | else |
685 | ret = -ENODATA; |
686 | |
687 | kfree(objp: buf); |
688 | |
689 | return ret; |
690 | } |
691 | |
692 | static enum power_supply_property asus_battery_props[] = { |
693 | POWER_SUPPLY_PROP_STATUS, |
694 | POWER_SUPPLY_PROP_PRESENT, |
695 | POWER_SUPPLY_PROP_CAPACITY, |
696 | POWER_SUPPLY_PROP_SCOPE, |
697 | POWER_SUPPLY_PROP_MODEL_NAME, |
698 | }; |
699 | |
700 | #define QUERY_MIN_INTERVAL (60 * HZ) /* 60[sec] */ |
701 | |
702 | static int asus_battery_get_property(struct power_supply *psy, |
703 | enum power_supply_property psp, |
704 | union power_supply_propval *val) |
705 | { |
706 | struct asus_drvdata *drvdata = power_supply_get_drvdata(psy); |
707 | int ret = 0; |
708 | |
709 | switch (psp) { |
710 | case POWER_SUPPLY_PROP_STATUS: |
711 | case POWER_SUPPLY_PROP_CAPACITY: |
712 | if (time_before(drvdata->battery_next_query, jiffies)) { |
713 | drvdata->battery_next_query = |
714 | jiffies + QUERY_MIN_INTERVAL; |
715 | ret = asus_battery_query(drvdata); |
716 | if (ret) |
717 | return ret; |
718 | } |
719 | if (psp == POWER_SUPPLY_PROP_STATUS) |
720 | val->intval = drvdata->battery_stat; |
721 | else |
722 | val->intval = drvdata->battery_capacity; |
723 | break; |
724 | case POWER_SUPPLY_PROP_PRESENT: |
725 | val->intval = 1; |
726 | break; |
727 | case POWER_SUPPLY_PROP_SCOPE: |
728 | val->intval = POWER_SUPPLY_SCOPE_DEVICE; |
729 | break; |
730 | case POWER_SUPPLY_PROP_MODEL_NAME: |
731 | val->strval = drvdata->hdev->name; |
732 | break; |
733 | default: |
734 | ret = -EINVAL; |
735 | break; |
736 | } |
737 | |
738 | return ret; |
739 | } |
740 | |
741 | static int asus_battery_probe(struct hid_device *hdev) |
742 | { |
743 | struct asus_drvdata *drvdata = hid_get_drvdata(hdev); |
744 | struct power_supply_config pscfg = { .drv_data = drvdata }; |
745 | int ret = 0; |
746 | |
747 | drvdata->battery_capacity = 0; |
748 | drvdata->battery_stat = POWER_SUPPLY_STATUS_UNKNOWN; |
749 | drvdata->battery_in_query = false; |
750 | |
751 | drvdata->battery_desc.properties = asus_battery_props; |
752 | drvdata->battery_desc.num_properties = ARRAY_SIZE(asus_battery_props); |
753 | drvdata->battery_desc.get_property = asus_battery_get_property; |
754 | drvdata->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY; |
755 | drvdata->battery_desc.use_for_apm = 0; |
756 | drvdata->battery_desc.name = devm_kasprintf(dev: &hdev->dev, GFP_KERNEL, |
757 | fmt: "asus-keyboard-%s-battery" , |
758 | strlen(hdev->uniq) ? |
759 | hdev->uniq : dev_name(dev: &hdev->dev)); |
760 | if (!drvdata->battery_desc.name) |
761 | return -ENOMEM; |
762 | |
763 | drvdata->battery_next_query = jiffies; |
764 | |
765 | drvdata->battery = devm_power_supply_register(parent: &hdev->dev, |
766 | desc: &(drvdata->battery_desc), cfg: &pscfg); |
767 | if (IS_ERR(ptr: drvdata->battery)) { |
768 | ret = PTR_ERR(ptr: drvdata->battery); |
769 | drvdata->battery = NULL; |
770 | hid_err(hdev, "Unable to register battery device\n" ); |
771 | return ret; |
772 | } |
773 | |
774 | power_supply_powers(psy: drvdata->battery, dev: &hdev->dev); |
775 | |
776 | return ret; |
777 | } |
778 | |
779 | static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) |
780 | { |
781 | struct input_dev *input = hi->input; |
782 | struct asus_drvdata *drvdata = hid_get_drvdata(hdev); |
783 | |
784 | /* T100CHI uses MULTI_INPUT, bind the touchpad to the mouse hid_input */ |
785 | if (drvdata->quirks & QUIRK_T100CHI && |
786 | hi->report->id != T100CHI_MOUSE_REPORT_ID) |
787 | return 0; |
788 | |
789 | /* Handle MULTI_INPUT on E1239T mouse/touchpad USB interface */ |
790 | if (drvdata->tp && (drvdata->quirks & QUIRK_MEDION_E1239T)) { |
791 | switch (hi->report->id) { |
792 | case E1239T_TP_TOGGLE_REPORT_ID: |
793 | input_set_capability(dev: input, EV_KEY, KEY_F21); |
794 | input->name = "Asus Touchpad Keys" ; |
795 | drvdata->tp_kbd_input = input; |
796 | return 0; |
797 | case INPUT_REPORT_ID: |
798 | break; /* Touchpad report, handled below */ |
799 | default: |
800 | return 0; /* Ignore other reports */ |
801 | } |
802 | } |
803 | |
804 | if (drvdata->tp) { |
805 | int ret; |
806 | |
807 | input_set_abs_params(dev: input, ABS_MT_POSITION_X, min: 0, |
808 | max: drvdata->tp->max_x, fuzz: 0, flat: 0); |
809 | input_set_abs_params(dev: input, ABS_MT_POSITION_Y, min: 0, |
810 | max: drvdata->tp->max_y, fuzz: 0, flat: 0); |
811 | input_abs_set_res(dev: input, ABS_MT_POSITION_X, val: drvdata->tp->res_x); |
812 | input_abs_set_res(dev: input, ABS_MT_POSITION_Y, val: drvdata->tp->res_y); |
813 | |
814 | if (drvdata->tp->contact_size >= 5) { |
815 | input_set_abs_params(dev: input, ABS_TOOL_WIDTH, min: 0, |
816 | MAX_TOUCH_MAJOR, fuzz: 0, flat: 0); |
817 | input_set_abs_params(dev: input, ABS_MT_TOUCH_MAJOR, min: 0, |
818 | MAX_TOUCH_MAJOR, fuzz: 0, flat: 0); |
819 | input_set_abs_params(dev: input, ABS_MT_PRESSURE, min: 0, |
820 | MAX_PRESSURE, fuzz: 0, flat: 0); |
821 | } |
822 | |
823 | __set_bit(BTN_LEFT, input->keybit); |
824 | __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); |
825 | |
826 | ret = input_mt_init_slots(dev: input, num_slots: drvdata->tp->max_contacts, |
827 | INPUT_MT_POINTER); |
828 | |
829 | if (ret) { |
830 | hid_err(hdev, "Asus input mt init slots failed: %d\n" , ret); |
831 | return ret; |
832 | } |
833 | } |
834 | |
835 | drvdata->input = input; |
836 | |
837 | if (drvdata->enable_backlight && |
838 | !asus_kbd_wmi_led_control_present(hdev) && |
839 | asus_kbd_register_leds(hdev)) |
840 | hid_warn(hdev, "Failed to initialize backlight.\n" ); |
841 | |
842 | return 0; |
843 | } |
844 | |
845 | #define asus_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, \ |
846 | max, EV_KEY, (c)) |
847 | static int asus_input_mapping(struct hid_device *hdev, |
848 | struct hid_input *hi, struct hid_field *field, |
849 | struct hid_usage *usage, unsigned long **bit, |
850 | int *max) |
851 | { |
852 | struct asus_drvdata *drvdata = hid_get_drvdata(hdev); |
853 | |
854 | if (drvdata->quirks & QUIRK_SKIP_INPUT_MAPPING) { |
855 | /* Don't map anything from the HID report. |
856 | * We do it all manually in asus_input_configured |
857 | */ |
858 | return -1; |
859 | } |
860 | |
861 | /* |
862 | * Ignore a bunch of bogus collections in the T100CHI descriptor. |
863 | * This avoids a bunch of non-functional hid_input devices getting |
864 | * created because of the T100CHI using HID_QUIRK_MULTI_INPUT. |
865 | */ |
866 | if ((drvdata->quirks & (QUIRK_T100CHI | QUIRK_T90CHI)) && |
867 | (field->application == (HID_UP_GENDESK | 0x0080) || |
868 | field->application == HID_GD_MOUSE || |
869 | usage->hid == (HID_UP_GENDEVCTRLS | 0x0024) || |
870 | usage->hid == (HID_UP_GENDEVCTRLS | 0x0025) || |
871 | usage->hid == (HID_UP_GENDEVCTRLS | 0x0026))) |
872 | return -1; |
873 | |
874 | /* ASUS-specific keyboard hotkeys and led backlight */ |
875 | if ((usage->hid & HID_USAGE_PAGE) == HID_UP_ASUSVENDOR) { |
876 | switch (usage->hid & HID_USAGE) { |
877 | case 0x10: asus_map_key_clear(KEY_BRIGHTNESSDOWN); break; |
878 | case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP); break; |
879 | case 0x35: asus_map_key_clear(KEY_DISPLAY_OFF); break; |
880 | case 0x6c: asus_map_key_clear(KEY_SLEEP); break; |
881 | case 0x7c: asus_map_key_clear(KEY_MICMUTE); break; |
882 | case 0x82: asus_map_key_clear(KEY_CAMERA); break; |
883 | case 0x88: asus_map_key_clear(KEY_RFKILL); break; |
884 | case 0xb5: asus_map_key_clear(KEY_CALC); break; |
885 | case 0xc4: asus_map_key_clear(KEY_KBDILLUMUP); break; |
886 | case 0xc5: asus_map_key_clear(KEY_KBDILLUMDOWN); break; |
887 | case 0xc7: asus_map_key_clear(KEY_KBDILLUMTOGGLE); break; |
888 | |
889 | case 0x6b: asus_map_key_clear(KEY_F21); break; /* ASUS touchpad toggle */ |
890 | case 0x38: asus_map_key_clear(KEY_PROG1); break; /* ROG key */ |
891 | case 0xba: asus_map_key_clear(KEY_PROG2); break; /* Fn+C ASUS Splendid */ |
892 | case 0x5c: asus_map_key_clear(KEY_PROG3); break; /* Fn+Space Power4Gear */ |
893 | case 0x99: asus_map_key_clear(KEY_PROG4); break; /* Fn+F5 "fan" symbol */ |
894 | case 0xae: asus_map_key_clear(KEY_PROG4); break; /* Fn+F5 "fan" symbol */ |
895 | case 0x92: asus_map_key_clear(KEY_CALC); break; /* Fn+Ret "Calc" symbol */ |
896 | case 0xb2: asus_map_key_clear(KEY_PROG2); break; /* Fn+Left previous aura */ |
897 | case 0xb3: asus_map_key_clear(KEY_PROG3); break; /* Fn+Left next aura */ |
898 | case 0x6a: asus_map_key_clear(KEY_F13); break; /* Screenpad toggle */ |
899 | case 0x4b: asus_map_key_clear(KEY_F14); break; /* Arrows/Pg-Up/Dn toggle */ |
900 | |
901 | |
902 | default: |
903 | /* ASUS lazily declares 256 usages, ignore the rest, |
904 | * as some make the keyboard appear as a pointer device. */ |
905 | return -1; |
906 | } |
907 | |
908 | /* |
909 | * Check and enable backlight only on devices with UsagePage == |
910 | * 0xff31 to avoid initializing the keyboard firmware multiple |
911 | * times on devices with multiple HID descriptors but same |
912 | * PID/VID. |
913 | */ |
914 | if (drvdata->quirks & QUIRK_USE_KBD_BACKLIGHT) |
915 | drvdata->enable_backlight = true; |
916 | |
917 | set_bit(EV_REP, addr: hi->input->evbit); |
918 | return 1; |
919 | } |
920 | |
921 | if ((usage->hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR) { |
922 | switch (usage->hid & HID_USAGE) { |
923 | case 0xff01: asus_map_key_clear(BTN_1); break; |
924 | case 0xff02: asus_map_key_clear(BTN_2); break; |
925 | case 0xff03: asus_map_key_clear(BTN_3); break; |
926 | case 0xff04: asus_map_key_clear(BTN_4); break; |
927 | case 0xff05: asus_map_key_clear(BTN_5); break; |
928 | case 0xff06: asus_map_key_clear(BTN_6); break; |
929 | case 0xff07: asus_map_key_clear(BTN_7); break; |
930 | case 0xff08: asus_map_key_clear(BTN_8); break; |
931 | case 0xff09: asus_map_key_clear(BTN_9); break; |
932 | case 0xff0a: asus_map_key_clear(BTN_A); break; |
933 | case 0xff0b: asus_map_key_clear(BTN_B); break; |
934 | case 0x00f1: asus_map_key_clear(KEY_WLAN); break; |
935 | case 0x00f2: asus_map_key_clear(KEY_BRIGHTNESSDOWN); break; |
936 | case 0x00f3: asus_map_key_clear(KEY_BRIGHTNESSUP); break; |
937 | case 0x00f4: asus_map_key_clear(KEY_DISPLAY_OFF); break; |
938 | case 0x00f7: asus_map_key_clear(KEY_CAMERA); break; |
939 | case 0x00f8: asus_map_key_clear(KEY_PROG1); break; |
940 | default: |
941 | return 0; |
942 | } |
943 | |
944 | set_bit(EV_REP, addr: hi->input->evbit); |
945 | return 1; |
946 | } |
947 | |
948 | if (drvdata->quirks & QUIRK_NO_CONSUMER_USAGES && |
949 | (usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) { |
950 | switch (usage->hid & HID_USAGE) { |
951 | case 0xe2: /* Mute */ |
952 | case 0xe9: /* Volume up */ |
953 | case 0xea: /* Volume down */ |
954 | return 0; |
955 | default: |
956 | /* Ignore dummy Consumer usages which make the |
957 | * keyboard incorrectly appear as a pointer device. |
958 | */ |
959 | return -1; |
960 | } |
961 | } |
962 | |
963 | /* |
964 | * The mute button is broken and only sends press events, we |
965 | * deal with this in our raw_event handler, so do not map it. |
966 | */ |
967 | if ((drvdata->quirks & QUIRK_MEDION_E1239T) && |
968 | usage->hid == (HID_UP_CONSUMER | 0xe2)) { |
969 | input_set_capability(dev: hi->input, EV_KEY, KEY_MUTE); |
970 | return -1; |
971 | } |
972 | |
973 | return 0; |
974 | } |
975 | |
976 | static int asus_start_multitouch(struct hid_device *hdev) |
977 | { |
978 | int ret; |
979 | static const unsigned char buf[] = { |
980 | FEATURE_REPORT_ID, 0x00, 0x03, 0x01, 0x00 |
981 | }; |
982 | unsigned char *dmabuf = kmemdup(p: buf, size: sizeof(buf), GFP_KERNEL); |
983 | |
984 | if (!dmabuf) { |
985 | ret = -ENOMEM; |
986 | hid_err(hdev, "Asus failed to alloc dma buf: %d\n" , ret); |
987 | return ret; |
988 | } |
989 | |
990 | ret = hid_hw_raw_request(hdev, reportnum: dmabuf[0], buf: dmabuf, len: sizeof(buf), |
991 | rtype: HID_FEATURE_REPORT, reqtype: HID_REQ_SET_REPORT); |
992 | |
993 | kfree(objp: dmabuf); |
994 | |
995 | if (ret != sizeof(buf)) { |
996 | hid_err(hdev, "Asus failed to start multitouch: %d\n" , ret); |
997 | return ret; |
998 | } |
999 | |
1000 | return 0; |
1001 | } |
1002 | |
1003 | static int __maybe_unused asus_reset_resume(struct hid_device *hdev) |
1004 | { |
1005 | struct asus_drvdata *drvdata = hid_get_drvdata(hdev); |
1006 | |
1007 | if (drvdata->tp) |
1008 | return asus_start_multitouch(hdev); |
1009 | |
1010 | return 0; |
1011 | } |
1012 | |
1013 | static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) |
1014 | { |
1015 | int ret; |
1016 | struct asus_drvdata *drvdata; |
1017 | |
1018 | drvdata = devm_kzalloc(dev: &hdev->dev, size: sizeof(*drvdata), GFP_KERNEL); |
1019 | if (drvdata == NULL) { |
1020 | hid_err(hdev, "Can't alloc Asus descriptor\n" ); |
1021 | return -ENOMEM; |
1022 | } |
1023 | |
1024 | hid_set_drvdata(hdev, data: drvdata); |
1025 | |
1026 | drvdata->quirks = id->driver_data; |
1027 | |
1028 | /* |
1029 | * T90CHI's keyboard dock returns same ID values as T100CHI's dock. |
1030 | * Thus, identify T90CHI dock with product name string. |
1031 | */ |
1032 | if (strstr(hdev->name, "T90CHI" )) { |
1033 | drvdata->quirks &= ~QUIRK_T100CHI; |
1034 | drvdata->quirks |= QUIRK_T90CHI; |
1035 | } |
1036 | |
1037 | if (drvdata->quirks & QUIRK_IS_MULTITOUCH) |
1038 | drvdata->tp = &asus_i2c_tp; |
1039 | |
1040 | if ((drvdata->quirks & QUIRK_T100_KEYBOARD) && hid_is_usb(hdev)) { |
1041 | struct usb_interface *intf = to_usb_interface(hdev->dev.parent); |
1042 | |
1043 | if (intf->altsetting->desc.bInterfaceNumber == T100_TPAD_INTF) { |
1044 | drvdata->quirks = QUIRK_SKIP_INPUT_MAPPING; |
1045 | /* |
1046 | * The T100HA uses the same USB-ids as the T100TAF and |
1047 | * the T200TA uses the same USB-ids as the T100TA, while |
1048 | * both have different max x/y values as the T100TA[F]. |
1049 | */ |
1050 | if (dmi_match(f: DMI_PRODUCT_NAME, str: "T100HAN" )) |
1051 | drvdata->tp = &asus_t100ha_tp; |
1052 | else if (dmi_match(f: DMI_PRODUCT_NAME, str: "T200TA" )) |
1053 | drvdata->tp = &asus_t200ta_tp; |
1054 | else |
1055 | drvdata->tp = &asus_t100ta_tp; |
1056 | } |
1057 | } |
1058 | |
1059 | if (drvdata->quirks & QUIRK_T100CHI) { |
1060 | /* |
1061 | * All functionality is on a single HID interface and for |
1062 | * userspace the touchpad must be a separate input_dev. |
1063 | */ |
1064 | hdev->quirks |= HID_QUIRK_MULTI_INPUT; |
1065 | drvdata->tp = &asus_t100chi_tp; |
1066 | } |
1067 | |
1068 | if ((drvdata->quirks & QUIRK_MEDION_E1239T) && hid_is_usb(hdev)) { |
1069 | struct usb_host_interface *alt = |
1070 | to_usb_interface(hdev->dev.parent)->altsetting; |
1071 | |
1072 | if (alt->desc.bInterfaceNumber == MEDION_E1239T_TPAD_INTF) { |
1073 | /* For separate input-devs for tp and tp toggle key */ |
1074 | hdev->quirks |= HID_QUIRK_MULTI_INPUT; |
1075 | drvdata->quirks |= QUIRK_SKIP_INPUT_MAPPING; |
1076 | drvdata->tp = &medion_e1239t_tp; |
1077 | } |
1078 | } |
1079 | |
1080 | if (drvdata->quirks & QUIRK_NO_INIT_REPORTS) |
1081 | hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; |
1082 | |
1083 | drvdata->hdev = hdev; |
1084 | |
1085 | if (drvdata->quirks & (QUIRK_T100CHI | QUIRK_T90CHI)) { |
1086 | ret = asus_battery_probe(hdev); |
1087 | if (ret) { |
1088 | hid_err(hdev, |
1089 | "Asus hid battery_probe failed: %d\n" , ret); |
1090 | return ret; |
1091 | } |
1092 | } |
1093 | |
1094 | ret = hid_parse(hdev); |
1095 | if (ret) { |
1096 | hid_err(hdev, "Asus hid parse failed: %d\n" , ret); |
1097 | return ret; |
1098 | } |
1099 | |
1100 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); |
1101 | if (ret) { |
1102 | hid_err(hdev, "Asus hw start failed: %d\n" , ret); |
1103 | return ret; |
1104 | } |
1105 | |
1106 | if (!drvdata->input) { |
1107 | hid_err(hdev, "Asus input not registered\n" ); |
1108 | ret = -ENOMEM; |
1109 | goto err_stop_hw; |
1110 | } |
1111 | |
1112 | if (drvdata->tp) { |
1113 | drvdata->input->name = "Asus TouchPad" ; |
1114 | } else { |
1115 | drvdata->input->name = "Asus Keyboard" ; |
1116 | } |
1117 | |
1118 | if (drvdata->tp) { |
1119 | ret = asus_start_multitouch(hdev); |
1120 | if (ret) |
1121 | goto err_stop_hw; |
1122 | } |
1123 | |
1124 | return 0; |
1125 | err_stop_hw: |
1126 | hid_hw_stop(hdev); |
1127 | return ret; |
1128 | } |
1129 | |
1130 | static void asus_remove(struct hid_device *hdev) |
1131 | { |
1132 | struct asus_drvdata *drvdata = hid_get_drvdata(hdev); |
1133 | unsigned long flags; |
1134 | |
1135 | if (drvdata->kbd_backlight) { |
1136 | spin_lock_irqsave(&drvdata->kbd_backlight->lock, flags); |
1137 | drvdata->kbd_backlight->removed = true; |
1138 | spin_unlock_irqrestore(lock: &drvdata->kbd_backlight->lock, flags); |
1139 | |
1140 | cancel_work_sync(work: &drvdata->kbd_backlight->work); |
1141 | } |
1142 | |
1143 | hid_hw_stop(hdev); |
1144 | } |
1145 | |
1146 | static const __u8 asus_g752_fixed_rdesc[] = { |
1147 | 0x19, 0x00, /* Usage Minimum (0x00) */ |
1148 | 0x2A, 0xFF, 0x00, /* Usage Maximum (0xFF) */ |
1149 | }; |
1150 | |
1151 | static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc, |
1152 | unsigned int *rsize) |
1153 | { |
1154 | struct asus_drvdata *drvdata = hid_get_drvdata(hdev); |
1155 | |
1156 | if (drvdata->quirks & QUIRK_FIX_NOTEBOOK_REPORT && |
1157 | *rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x65) { |
1158 | hid_info(hdev, "Fixing up Asus notebook report descriptor\n" ); |
1159 | rdesc[55] = 0xdd; |
1160 | } |
1161 | /* For the T100TA/T200TA keyboard dock */ |
1162 | if (drvdata->quirks & QUIRK_T100_KEYBOARD && |
1163 | (*rsize == 76 || *rsize == 101) && |
1164 | rdesc[73] == 0x81 && rdesc[74] == 0x01) { |
1165 | hid_info(hdev, "Fixing up Asus T100 keyb report descriptor\n" ); |
1166 | rdesc[74] &= ~HID_MAIN_ITEM_CONSTANT; |
1167 | } |
1168 | /* For the T100CHI/T90CHI keyboard dock */ |
1169 | if (drvdata->quirks & (QUIRK_T100CHI | QUIRK_T90CHI)) { |
1170 | int rsize_orig; |
1171 | int offs; |
1172 | |
1173 | if (drvdata->quirks & QUIRK_T100CHI) { |
1174 | rsize_orig = 403; |
1175 | offs = 388; |
1176 | } else { |
1177 | rsize_orig = 306; |
1178 | offs = 291; |
1179 | } |
1180 | |
1181 | /* |
1182 | * Change Usage (76h) to Usage Minimum (00h), Usage Maximum |
1183 | * (FFh) and clear the flags in the Input() byte. |
1184 | * Note the descriptor has a bogus 0 byte at the end so we |
1185 | * only need 1 extra byte. |
1186 | */ |
1187 | if (*rsize == rsize_orig && |
1188 | rdesc[offs] == 0x09 && rdesc[offs + 1] == 0x76) { |
1189 | *rsize = rsize_orig + 1; |
1190 | rdesc = kmemdup(p: rdesc, size: *rsize, GFP_KERNEL); |
1191 | if (!rdesc) |
1192 | return NULL; |
1193 | |
1194 | hid_info(hdev, "Fixing up %s keyb report descriptor\n" , |
1195 | drvdata->quirks & QUIRK_T100CHI ? |
1196 | "T100CHI" : "T90CHI" ); |
1197 | memmove(rdesc + offs + 4, rdesc + offs + 2, 12); |
1198 | rdesc[offs] = 0x19; |
1199 | rdesc[offs + 1] = 0x00; |
1200 | rdesc[offs + 2] = 0x29; |
1201 | rdesc[offs + 3] = 0xff; |
1202 | rdesc[offs + 14] = 0x00; |
1203 | } |
1204 | } |
1205 | |
1206 | if (drvdata->quirks & QUIRK_G752_KEYBOARD && |
1207 | *rsize == 75 && rdesc[61] == 0x15 && rdesc[62] == 0x00) { |
1208 | /* report is missing usage mninum and maximum */ |
1209 | __u8 *new_rdesc; |
1210 | size_t new_size = *rsize + sizeof(asus_g752_fixed_rdesc); |
1211 | |
1212 | new_rdesc = devm_kzalloc(dev: &hdev->dev, size: new_size, GFP_KERNEL); |
1213 | if (new_rdesc == NULL) |
1214 | return rdesc; |
1215 | |
1216 | hid_info(hdev, "Fixing up Asus G752 keyb report descriptor\n" ); |
1217 | /* copy the valid part */ |
1218 | memcpy(new_rdesc, rdesc, 61); |
1219 | /* insert missing part */ |
1220 | memcpy(new_rdesc + 61, asus_g752_fixed_rdesc, sizeof(asus_g752_fixed_rdesc)); |
1221 | /* copy remaining data */ |
1222 | memcpy(new_rdesc + 61 + sizeof(asus_g752_fixed_rdesc), rdesc + 61, *rsize - 61); |
1223 | |
1224 | *rsize = new_size; |
1225 | rdesc = new_rdesc; |
1226 | } |
1227 | |
1228 | if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD && |
1229 | *rsize == 331 && rdesc[190] == 0x85 && rdesc[191] == 0x5a && |
1230 | rdesc[204] == 0x95 && rdesc[205] == 0x05) { |
1231 | hid_info(hdev, "Fixing up Asus N-KEY keyb report descriptor\n" ); |
1232 | rdesc[205] = 0x01; |
1233 | } |
1234 | |
1235 | return rdesc; |
1236 | } |
1237 | |
1238 | static const struct hid_device_id asus_devices[] = { |
1239 | { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, |
1240 | USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD), I2C_KEYBOARD_QUIRKS}, |
1241 | { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, |
1242 | USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD), I2C_TOUCHPAD_QUIRKS }, |
1243 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, |
1244 | USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1), QUIRK_USE_KBD_BACKLIGHT }, |
1245 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, |
1246 | USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2), QUIRK_USE_KBD_BACKLIGHT }, |
1247 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, |
1248 | USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3), QUIRK_G752_KEYBOARD }, |
1249 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, |
1250 | USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD), |
1251 | QUIRK_USE_KBD_BACKLIGHT }, |
1252 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, |
1253 | USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD), |
1254 | QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, |
1255 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, |
1256 | USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2), |
1257 | QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, |
1258 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, |
1259 | USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD3), |
1260 | QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, |
1261 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, |
1262 | USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD), |
1263 | QUIRK_ROG_CLAYMORE_II_KEYBOARD }, |
1264 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, |
1265 | USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD), |
1266 | QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES }, |
1267 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, |
1268 | USB_DEVICE_ID_ASUSTEK_T100TAF_KEYBOARD), |
1269 | QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES }, |
1270 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_ASUS_AK1D) }, |
1271 | { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_ASUS_MD_5110) }, |
1272 | { HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_ASUS_MD_5112) }, |
1273 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK, |
1274 | USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD), QUIRK_T100CHI }, |
1275 | { HID_USB_DEVICE(USB_VENDOR_ID_ITE, USB_DEVICE_ID_ITE_MEDION_E1239T), |
1276 | QUIRK_MEDION_E1239T }, |
1277 | /* |
1278 | * Note bind to the HID_GROUP_GENERIC group, so that we only bind to the keyboard |
1279 | * part, while letting hid-multitouch.c handle the touchpad. |
1280 | */ |
1281 | { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, |
1282 | USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T101HA_KEYBOARD) }, |
1283 | { } |
1284 | }; |
1285 | MODULE_DEVICE_TABLE(hid, asus_devices); |
1286 | |
1287 | static struct hid_driver asus_driver = { |
1288 | .name = "asus" , |
1289 | .id_table = asus_devices, |
1290 | .report_fixup = asus_report_fixup, |
1291 | .probe = asus_probe, |
1292 | .remove = asus_remove, |
1293 | .input_mapping = asus_input_mapping, |
1294 | .input_configured = asus_input_configured, |
1295 | #ifdef CONFIG_PM |
1296 | .reset_resume = asus_reset_resume, |
1297 | #endif |
1298 | .event = asus_event, |
1299 | .raw_event = asus_raw_event |
1300 | }; |
1301 | module_hid_driver(asus_driver); |
1302 | |
1303 | MODULE_LICENSE("GPL" ); |