1 /* 2 * HID driver for Asus notebook built-in keyboard. 3 * Fixes small logical maximum to match usage maximum. 4 * 5 * Currently supported devices are: 6 * EeeBook X205TA 7 * VivoBook E200HA 8 * 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 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> 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 29 #include <linux/hid.h> 30 #include <linux/module.h> 31 #include <linux/input/mt.h> 32 33 #include "hid-ids.h" 34 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"); 40 41 #define FEATURE_REPORT_ID 0x0d 42 #define INPUT_REPORT_ID 0x5d 43 44 #define INPUT_REPORT_SIZE 28 45 46 #define MAX_CONTACTS 5 47 48 #define MAX_X 2794 49 #define MAX_Y 1758 50 #define MAX_TOUCH_MAJOR 8 51 #define MAX_PRESSURE 128 52 53 #define CONTACT_DATA_SIZE 5 54 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) 66 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 | \ 71 QUIRK_IS_MULTITOUCH) 72 73 #define TRKID_SGN ((TRKID_MAX + 1) >> 1) 74 75 struct asus_drvdata { 76 unsigned long quirks; 77 struct input_dev *input; 78 }; 79 80 static void asus_report_contact_down(struct input_dev *input, 81 int toolType, u8 *data) 82 { 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]); 86 87 if (toolType == MT_TOOL_PALM) { 88 touch_major = MAX_TOUCH_MAJOR; 89 pressure = MAX_PRESSURE; 90 } else { 91 touch_major = (data[3] >> 4) & CONTACT_TOUCH_MAJOR_MASK; 92 pressure = data[4] & CONTACT_PRESSURE_MASK; 93 } 94 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); 99 } 100 101 /* Required for Synaptics Palm Detection */ 102 static void asus_report_tool_width(struct input_dev *input) 103 { 104 struct input_mt *mt = input->mt; 105 struct input_mt_slot *oldest; 106 int oldid, count, i; 107 108 oldest = NULL; 109 oldid = mt->trkid; 110 count = 0; 111 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); 115 116 if (id < 0) 117 continue; 118 if ((id - oldid) & TRKID_SGN) { 119 oldest = ps; 120 oldid = id; 121 } 122 count++; 123 } 124 125 if (oldest) { 126 input_report_abs(input, ABS_TOOL_WIDTH, 127 input_mt_get_value(oldest, ABS_MT_TOUCH_MAJOR)); 128 } 129 } 130 131 static void asus_report_input(struct input_dev *input, u8 *data) 132 { 133 int i; 134 u8 *contactData = data + 2; 135 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; 140 141 input_mt_slot(input, i); 142 input_mt_report_slot_state(input, toolType, down); 143 144 if (down) { 145 asus_report_contact_down(input, toolType, contactData); 146 contactData += CONTACT_DATA_SIZE; 147 } 148 } 149 150 input_report_key(input, BTN_LEFT, data[1] & BTN_LEFT_MASK); 151 asus_report_tool_width(input); 152 153 input_mt_sync_frame(input); 154 input_sync(input); 155 } 156 157 static int asus_raw_event(struct hid_device *hdev, 158 struct hid_report *report, u8 *data, int size) 159 { 160 struct asus_drvdata *drvdata = hid_get_drvdata(hdev); 161 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); 166 return 1; 167 } 168 169 return 0; 170 } 171 172 static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) 173 { 174 struct input_dev *input = hi->input; 175 struct asus_drvdata *drvdata = hid_get_drvdata(hdev); 176 177 if (drvdata->quirks & QUIRK_IS_MULTITOUCH) { 178 int ret; 179 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); 185 186 __set_bit(BTN_LEFT, input->keybit); 187 __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); 188 189 ret = input_mt_init_slots(input, MAX_CONTACTS, INPUT_MT_POINTER); 190 191 if (ret) { 192 hid_err(hdev, "Asus input mt init slots failed: %d\n", ret); 193 return ret; 194 } 195 } 196 197 drvdata->input = input; 198 199 return 0; 200 } 201 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, 205 int *max) 206 { 207 struct asus_drvdata *drvdata = hid_get_drvdata(hdev); 208 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 212 */ 213 return -1; 214 } 215 216 return 0; 217 } 218 219 static int asus_start_multitouch(struct hid_device *hdev) 220 { 221 int ret; 222 const unsigned char buf[] = { FEATURE_REPORT_ID, 0x00, 0x03, 0x01, 0x00 }; 223 unsigned char *dmabuf = kmemdup(buf, sizeof(buf), GFP_KERNEL); 224 225 if (!dmabuf) { 226 ret = -ENOMEM; 227 hid_err(hdev, "Asus failed to alloc dma buf: %d\n", ret); 228 return ret; 229 } 230 231 ret = hid_hw_raw_request(hdev, dmabuf[0], dmabuf, sizeof(buf), 232 HID_FEATURE_REPORT, HID_REQ_SET_REPORT); 233 234 kfree(dmabuf); 235 236 if (ret != sizeof(buf)) { 237 hid_err(hdev, "Asus failed to start multitouch: %d\n", ret); 238 return ret; 239 } 240 241 return 0; 242 } 243 244 static int __maybe_unused asus_reset_resume(struct hid_device *hdev) 245 { 246 struct asus_drvdata *drvdata = hid_get_drvdata(hdev); 247 248 if (drvdata->quirks & QUIRK_IS_MULTITOUCH) 249 return asus_start_multitouch(hdev); 250 251 return 0; 252 } 253 254 static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) 255 { 256 int ret; 257 struct asus_drvdata *drvdata; 258 259 drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL); 260 if (drvdata == NULL) { 261 hid_err(hdev, "Can't alloc Asus descriptor\n"); 262 return -ENOMEM; 263 } 264 265 hid_set_drvdata(hdev, drvdata); 266 267 drvdata->quirks = id->driver_data; 268 269 if (drvdata->quirks & QUIRK_NO_INIT_REPORTS) 270 hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; 271 272 ret = hid_parse(hdev); 273 if (ret) { 274 hid_err(hdev, "Asus hid parse failed: %d\n", ret); 275 return ret; 276 } 277 278 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 279 if (ret) { 280 hid_err(hdev, "Asus hw start failed: %d\n", ret); 281 return ret; 282 } 283 284 if (!drvdata->input) { 285 hid_err(hdev, "Asus input not registered\n"); 286 ret = -ENOMEM; 287 goto err_stop_hw; 288 } 289 290 if (drvdata->quirks & QUIRK_IS_MULTITOUCH) { 291 drvdata->input->name = "Asus TouchPad"; 292 } else { 293 drvdata->input->name = "Asus Keyboard"; 294 } 295 296 if (drvdata->quirks & QUIRK_IS_MULTITOUCH) { 297 ret = asus_start_multitouch(hdev); 298 if (ret) 299 goto err_stop_hw; 300 } 301 302 return 0; 303 err_stop_hw: 304 hid_hw_stop(hdev); 305 return ret; 306 } 307 308 static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc, 309 unsigned int *rsize) 310 { 311 struct asus_drvdata *drvdata = hid_get_drvdata(hdev); 312 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"); 316 rdesc[55] = 0xdd; 317 } 318 return rdesc; 319 } 320 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 }, 326 { } 327 }; 328 MODULE_DEVICE_TABLE(hid, asus_devices); 329 330 static struct hid_driver asus_driver = { 331 .name = "asus", 332 .id_table = asus_devices, 333 .report_fixup = asus_report_fixup, 334 .probe = asus_probe, 335 .input_mapping = asus_input_mapping, 336 .input_configured = asus_input_configured, 337 #ifdef CONFIG_PM 338 .reset_resume = asus_reset_resume, 339 #endif 340 .raw_event = asus_raw_event 341 }; 342 module_hid_driver(asus_driver); 343 344 MODULE_LICENSE("GPL"); 345