2 * HID driver for Asus notebook built-in keyboard.
3 * Fixes small logical maximum to match usage maximum.
5 * Currently supported devices are:
9 * Copyright (c) 2016 Yusuke Fujimaki <usk.fujimaki@gmail.com>
11 * This module based on hid-ortek by
12 * Copyright (c) 2010 Johnathon Harris <jmharris@gmail.com>
13 * Copyright (c) 2011 Jiri Kosina
15 * This module has been updated to add support for Asus i2c touchpad.
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>
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)
29 #include <linux/hid.h>
30 #include <linux/module.h>
31 #include <linux/input/mt.h>
35 MODULE_AUTHOR("Yusuke Fujimaki <usk.fujimaki@gmail.com>");
36 MODULE_AUTHOR("Brendan McGrath <redmcg@redmandi.dyndns.org>");
37 MODULE_AUTHOR("Victor Vlasenko <victor.vlasenko@sysgears.com>");
38 MODULE_AUTHOR("Frederik Wenigwieser <frederik.wenigwieser@gmail.com>");
39 MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
41 #define FEATURE_REPORT_ID 0x0d
42 #define INPUT_REPORT_ID 0x5d
44 #define INPUT_REPORT_SIZE 28
46 #define MAX_CONTACTS 5
50 #define MAX_TOUCH_MAJOR 8
51 #define MAX_PRESSURE 128
53 #define CONTACT_DATA_SIZE 5
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
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)
67 #define KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
68 QUIRK_NO_INIT_REPORTS)
69 #define TOUCHPAD_QUIRKS (QUIRK_NO_INIT_REPORTS | \
70 QUIRK_SKIP_INPUT_MAPPING | \
73 #define TRKID_SGN ((TRKID_MAX + 1) >> 1)
77 struct input_dev
*input
;
80 static void asus_report_contact_down(struct input_dev
*input
,
81 int toolType
, u8
*data
)
83 int touch_major
, pressure
;
84 int x
= (data
[0] & CONTACT_X_MSB_MASK
) << 4 | data
[1];
85 int y
= MAX_Y
- ((data
[0] & CONTACT_Y_MSB_MASK
) << 8 | data
[2]);
87 if (toolType
== MT_TOOL_PALM
) {
88 touch_major
= MAX_TOUCH_MAJOR
;
89 pressure
= MAX_PRESSURE
;
91 touch_major
= (data
[3] >> 4) & CONTACT_TOUCH_MAJOR_MASK
;
92 pressure
= data
[4] & CONTACT_PRESSURE_MASK
;
95 input_report_abs(input
, ABS_MT_POSITION_X
, x
);
96 input_report_abs(input
, ABS_MT_POSITION_Y
, y
);
97 input_report_abs(input
, ABS_MT_TOUCH_MAJOR
, touch_major
);
98 input_report_abs(input
, ABS_MT_PRESSURE
, pressure
);
101 /* Required for Synaptics Palm Detection */
102 static void asus_report_tool_width(struct input_dev
*input
)
104 struct input_mt
*mt
= input
->mt
;
105 struct input_mt_slot
*oldest
;
112 for (i
= 0; i
< mt
->num_slots
; ++i
) {
113 struct input_mt_slot
*ps
= &mt
->slots
[i
];
114 int id
= input_mt_get_value(ps
, ABS_MT_TRACKING_ID
);
118 if ((id
- oldid
) & TRKID_SGN
) {
126 input_report_abs(input
, ABS_TOOL_WIDTH
,
127 input_mt_get_value(oldest
, ABS_MT_TOUCH_MAJOR
));
131 static void asus_report_input(struct input_dev
*input
, u8
*data
)
134 u8
*contactData
= data
+ 2;
136 for (i
= 0; i
< MAX_CONTACTS
; i
++) {
137 bool down
= !!(data
[1] & BIT(i
+3));
138 int toolType
= contactData
[3] & CONTACT_TOOL_TYPE_MASK
?
139 MT_TOOL_PALM
: MT_TOOL_FINGER
;
141 input_mt_slot(input
, i
);
142 input_mt_report_slot_state(input
, toolType
, down
);
145 asus_report_contact_down(input
, toolType
, contactData
);
146 contactData
+= CONTACT_DATA_SIZE
;
150 input_report_key(input
, BTN_LEFT
, data
[1] & BTN_LEFT_MASK
);
151 asus_report_tool_width(input
);
153 input_mt_sync_frame(input
);
157 static int asus_raw_event(struct hid_device
*hdev
,
158 struct hid_report
*report
, u8
*data
, int size
)
160 struct asus_drvdata
*drvdata
= hid_get_drvdata(hdev
);
162 if (drvdata
->quirks
& QUIRK_IS_MULTITOUCH
&&
163 data
[0] == INPUT_REPORT_ID
&&
164 size
== INPUT_REPORT_SIZE
) {
165 asus_report_input(drvdata
->input
, data
);
172 static int asus_input_configured(struct hid_device
*hdev
, struct hid_input
*hi
)
174 struct input_dev
*input
= hi
->input
;
175 struct asus_drvdata
*drvdata
= hid_get_drvdata(hdev
);
177 if (drvdata
->quirks
& QUIRK_IS_MULTITOUCH
) {
180 input_set_abs_params(input
, ABS_MT_POSITION_X
, 0, MAX_X
, 0, 0);
181 input_set_abs_params(input
, ABS_MT_POSITION_Y
, 0, MAX_Y
, 0, 0);
182 input_set_abs_params(input
, ABS_TOOL_WIDTH
, 0, MAX_TOUCH_MAJOR
, 0, 0);
183 input_set_abs_params(input
, ABS_MT_TOUCH_MAJOR
, 0, MAX_TOUCH_MAJOR
, 0, 0);
184 input_set_abs_params(input
, ABS_MT_PRESSURE
, 0, MAX_PRESSURE
, 0, 0);
186 __set_bit(BTN_LEFT
, input
->keybit
);
187 __set_bit(INPUT_PROP_BUTTONPAD
, input
->propbit
);
189 ret
= input_mt_init_slots(input
, MAX_CONTACTS
, INPUT_MT_POINTER
);
192 hid_err(hdev
, "Asus input mt init slots failed: %d\n", ret
);
197 drvdata
->input
= input
;
202 static int asus_input_mapping(struct hid_device
*hdev
,
203 struct hid_input
*hi
, struct hid_field
*field
,
204 struct hid_usage
*usage
, unsigned long **bit
,
207 struct asus_drvdata
*drvdata
= hid_get_drvdata(hdev
);
209 if (drvdata
->quirks
& QUIRK_SKIP_INPUT_MAPPING
) {
210 /* Don't map anything from the HID report.
211 * We do it all manually in asus_input_configured
219 static int asus_start_multitouch(struct hid_device
*hdev
)
222 const unsigned char buf
[] = { FEATURE_REPORT_ID
, 0x00, 0x03, 0x01, 0x00 };
223 unsigned char *dmabuf
= kmemdup(buf
, sizeof(buf
), GFP_KERNEL
);
227 hid_err(hdev
, "Asus failed to alloc dma buf: %d\n", ret
);
231 ret
= hid_hw_raw_request(hdev
, dmabuf
[0], dmabuf
, sizeof(buf
),
232 HID_FEATURE_REPORT
, HID_REQ_SET_REPORT
);
236 if (ret
!= sizeof(buf
)) {
237 hid_err(hdev
, "Asus failed to start multitouch: %d\n", ret
);
244 static int __maybe_unused
asus_reset_resume(struct hid_device
*hdev
)
246 struct asus_drvdata
*drvdata
= hid_get_drvdata(hdev
);
248 if (drvdata
->quirks
& QUIRK_IS_MULTITOUCH
)
249 return asus_start_multitouch(hdev
);
254 static int asus_probe(struct hid_device
*hdev
, const struct hid_device_id
*id
)
257 struct asus_drvdata
*drvdata
;
259 drvdata
= devm_kzalloc(&hdev
->dev
, sizeof(*drvdata
), GFP_KERNEL
);
260 if (drvdata
== NULL
) {
261 hid_err(hdev
, "Can't alloc Asus descriptor\n");
265 hid_set_drvdata(hdev
, drvdata
);
267 drvdata
->quirks
= id
->driver_data
;
269 if (drvdata
->quirks
& QUIRK_NO_INIT_REPORTS
)
270 hdev
->quirks
|= HID_QUIRK_NO_INIT_REPORTS
;
272 ret
= hid_parse(hdev
);
274 hid_err(hdev
, "Asus hid parse failed: %d\n", ret
);
278 ret
= hid_hw_start(hdev
, HID_CONNECT_DEFAULT
);
280 hid_err(hdev
, "Asus hw start failed: %d\n", ret
);
284 if (!drvdata
->input
) {
285 hid_err(hdev
, "Asus input not registered\n");
290 if (drvdata
->quirks
& QUIRK_IS_MULTITOUCH
) {
291 drvdata
->input
->name
= "Asus TouchPad";
293 drvdata
->input
->name
= "Asus Keyboard";
296 if (drvdata
->quirks
& QUIRK_IS_MULTITOUCH
) {
297 ret
= asus_start_multitouch(hdev
);
308 static __u8
*asus_report_fixup(struct hid_device
*hdev
, __u8
*rdesc
,
311 struct asus_drvdata
*drvdata
= hid_get_drvdata(hdev
);
313 if (drvdata
->quirks
& QUIRK_FIX_NOTEBOOK_REPORT
&&
314 *rsize
>= 56 && rdesc
[54] == 0x25 && rdesc
[55] == 0x65) {
315 hid_info(hdev
, "Fixing up Asus notebook report descriptor\n");
321 static const struct hid_device_id asus_devices
[] = {
322 { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK
,
323 USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD
), KEYBOARD_QUIRKS
},
324 { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK
,
325 USB_DEVICE_ID_ASUSTEK_TOUCHPAD
), TOUCHPAD_QUIRKS
},
328 MODULE_DEVICE_TABLE(hid
, asus_devices
);
330 static struct hid_driver asus_driver
= {
332 .id_table
= asus_devices
,
333 .report_fixup
= asus_report_fixup
,
335 .input_mapping
= asus_input_mapping
,
336 .input_configured
= asus_input_configured
,
338 .reset_resume
= asus_reset_resume
,
340 .raw_event
= asus_raw_event
342 module_hid_driver(asus_driver
);
344 MODULE_LICENSE("GPL");