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 NOTEBOOK_QUIRKS QUIRK_FIX_NOTEBOOK_REPORT
68 #define TOUCHPAD_QUIRKS (QUIRK_NO_INIT_REPORTS | \
69 QUIRK_SKIP_INPUT_MAPPING | \
72 #define TRKID_SGN ((TRKID_MAX + 1) >> 1)
76 struct input_dev
*input
;
79 static void asus_report_contact_down(struct input_dev
*input
,
80 int toolType
, u8
*data
)
82 int touch_major
, pressure
;
83 int x
= (data
[0] & CONTACT_X_MSB_MASK
) << 4 | data
[1];
84 int y
= MAX_Y
- ((data
[0] & CONTACT_Y_MSB_MASK
) << 8 | data
[2]);
86 if (toolType
== MT_TOOL_PALM
) {
87 touch_major
= MAX_TOUCH_MAJOR
;
88 pressure
= MAX_PRESSURE
;
90 touch_major
= (data
[3] >> 4) & CONTACT_TOUCH_MAJOR_MASK
;
91 pressure
= data
[4] & CONTACT_PRESSURE_MASK
;
94 input_report_abs(input
, ABS_MT_POSITION_X
, x
);
95 input_report_abs(input
, ABS_MT_POSITION_Y
, y
);
96 input_report_abs(input
, ABS_MT_TOUCH_MAJOR
, touch_major
);
97 input_report_abs(input
, ABS_MT_PRESSURE
, pressure
);
100 /* Required for Synaptics Palm Detection */
101 static void asus_report_tool_width(struct input_dev
*input
)
103 struct input_mt
*mt
= input
->mt
;
104 struct input_mt_slot
*oldest
;
111 for (i
= 0; i
< mt
->num_slots
; ++i
) {
112 struct input_mt_slot
*ps
= &mt
->slots
[i
];
113 int id
= input_mt_get_value(ps
, ABS_MT_TRACKING_ID
);
117 if ((id
- oldid
) & TRKID_SGN
) {
125 input_report_abs(input
, ABS_TOOL_WIDTH
,
126 input_mt_get_value(oldest
, ABS_MT_TOUCH_MAJOR
));
130 static void asus_report_input(struct input_dev
*input
, u8
*data
)
133 u8
*contactData
= data
+ 2;
135 for (i
= 0; i
< MAX_CONTACTS
; i
++) {
136 bool down
= !!(data
[1] & BIT(i
+3));
137 int toolType
= contactData
[3] & CONTACT_TOOL_TYPE_MASK
?
138 MT_TOOL_PALM
: MT_TOOL_FINGER
;
140 input_mt_slot(input
, i
);
141 input_mt_report_slot_state(input
, toolType
, down
);
144 asus_report_contact_down(input
, toolType
, contactData
);
145 contactData
+= CONTACT_DATA_SIZE
;
149 input_report_key(input
, BTN_LEFT
, data
[1] & BTN_LEFT_MASK
);
150 asus_report_tool_width(input
);
152 input_mt_sync_frame(input
);
156 static int asus_raw_event(struct hid_device
*hdev
,
157 struct hid_report
*report
, u8
*data
, int size
)
159 struct asus_drvdata
*drvdata
= hid_get_drvdata(hdev
);
161 if (drvdata
->quirks
& QUIRK_IS_MULTITOUCH
&&
162 data
[0] == INPUT_REPORT_ID
&&
163 size
== INPUT_REPORT_SIZE
) {
164 asus_report_input(drvdata
->input
, data
);
171 static int asus_input_configured(struct hid_device
*hdev
, struct hid_input
*hi
)
173 struct asus_drvdata
*drvdata
= hid_get_drvdata(hdev
);
175 if (drvdata
->quirks
& QUIRK_IS_MULTITOUCH
) {
177 struct input_dev
*input
= hi
->input
;
179 input_set_abs_params(input
, ABS_MT_POSITION_X
, 0, MAX_X
, 0, 0);
180 input_set_abs_params(input
, ABS_MT_POSITION_Y
, 0, MAX_Y
, 0, 0);
181 input_set_abs_params(input
, ABS_TOOL_WIDTH
, 0, MAX_TOUCH_MAJOR
, 0, 0);
182 input_set_abs_params(input
, ABS_MT_TOUCH_MAJOR
, 0, MAX_TOUCH_MAJOR
, 0, 0);
183 input_set_abs_params(input
, ABS_MT_PRESSURE
, 0, MAX_PRESSURE
, 0, 0);
185 __set_bit(BTN_LEFT
, input
->keybit
);
186 __set_bit(INPUT_PROP_BUTTONPAD
, input
->propbit
);
188 ret
= input_mt_init_slots(input
, MAX_CONTACTS
, INPUT_MT_POINTER
);
191 hid_err(hdev
, "Asus input mt init slots failed: %d\n", ret
);
195 drvdata
->input
= input
;
201 static int asus_input_mapping(struct hid_device
*hdev
,
202 struct hid_input
*hi
, struct hid_field
*field
,
203 struct hid_usage
*usage
, unsigned long **bit
,
206 struct asus_drvdata
*drvdata
= hid_get_drvdata(hdev
);
208 if (drvdata
->quirks
& QUIRK_SKIP_INPUT_MAPPING
) {
209 /* Don't map anything from the HID report.
210 * We do it all manually in asus_input_configured
218 static int asus_start_multitouch(struct hid_device
*hdev
)
221 const unsigned char buf
[] = { FEATURE_REPORT_ID
, 0x00, 0x03, 0x01, 0x00 };
222 unsigned char *dmabuf
= kmemdup(buf
, sizeof(buf
), GFP_KERNEL
);
226 hid_err(hdev
, "Asus failed to alloc dma buf: %d\n", ret
);
230 ret
= hid_hw_raw_request(hdev
, dmabuf
[0], dmabuf
, sizeof(buf
),
231 HID_FEATURE_REPORT
, HID_REQ_SET_REPORT
);
235 if (ret
!= sizeof(buf
)) {
236 hid_err(hdev
, "Asus failed to start multitouch: %d\n", ret
);
243 static int __maybe_unused
asus_reset_resume(struct hid_device
*hdev
)
245 struct asus_drvdata
*drvdata
= hid_get_drvdata(hdev
);
247 if (drvdata
->quirks
& QUIRK_IS_MULTITOUCH
)
248 return asus_start_multitouch(hdev
);
253 static int asus_probe(struct hid_device
*hdev
, const struct hid_device_id
*id
)
256 struct asus_drvdata
*drvdata
;
258 drvdata
= devm_kzalloc(&hdev
->dev
, sizeof(*drvdata
), GFP_KERNEL
);
259 if (drvdata
== NULL
) {
260 hid_err(hdev
, "Can't alloc Asus descriptor\n");
264 hid_set_drvdata(hdev
, drvdata
);
266 drvdata
->quirks
= id
->driver_data
;
268 if (drvdata
->quirks
& QUIRK_NO_INIT_REPORTS
)
269 hdev
->quirks
|= HID_QUIRK_NO_INIT_REPORTS
;
271 ret
= hid_parse(hdev
);
273 hid_err(hdev
, "Asus hid parse failed: %d\n", ret
);
277 ret
= hid_hw_start(hdev
, HID_CONNECT_DEFAULT
);
279 hid_err(hdev
, "Asus hw start failed: %d\n", ret
);
283 if (!drvdata
->input
) {
284 hid_err(hdev
, "Asus input not registered\n");
289 drvdata
->input
->name
= "Asus TouchPad";
291 if (drvdata
->quirks
& QUIRK_IS_MULTITOUCH
) {
292 ret
= asus_start_multitouch(hdev
);
303 static __u8
*asus_report_fixup(struct hid_device
*hdev
, __u8
*rdesc
,
306 struct asus_drvdata
*drvdata
= hid_get_drvdata(hdev
);
308 if (drvdata
->quirks
& QUIRK_FIX_NOTEBOOK_REPORT
&&
309 *rsize
>= 56 && rdesc
[54] == 0x25 && rdesc
[55] == 0x65) {
310 hid_info(hdev
, "Fixing up Asus notebook report descriptor\n");
316 static const struct hid_device_id asus_devices
[] = {
317 { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK
,
318 USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD
), NOTEBOOK_QUIRKS
},
319 { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK
,
320 USB_DEVICE_ID_ASUSTEK_TOUCHPAD
), TOUCHPAD_QUIRKS
},
323 MODULE_DEVICE_TABLE(hid
, asus_devices
);
325 static struct hid_driver asus_driver
= {
327 .id_table
= asus_devices
,
328 .report_fixup
= asus_report_fixup
,
330 .input_mapping
= asus_input_mapping
,
331 .input_configured
= asus_input_configured
,
333 .reset_resume
= asus_reset_resume
,
335 .raw_event
= asus_raw_event
337 module_hid_driver(asus_driver
);
339 MODULE_LICENSE("GPL");