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 NOTEBOOK_QUIRKS QUIRK_FIX_NOTEBOOK_REPORT 68 #define TOUCHPAD_QUIRKS (QUIRK_NO_INIT_REPORTS | \ 69 QUIRK_SKIP_INPUT_MAPPING | \ 70 QUIRK_IS_MULTITOUCH) 71 72 #define TRKID_SGN ((TRKID_MAX + 1) >> 1) 73 74 struct asus_drvdata { 75 unsigned long quirks; 76 struct input_dev *input; 77 }; 78 79 static void asus_report_contact_down(struct input_dev *input, 80 int toolType, u8 *data) 81 { 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]); 85 86 if (toolType == MT_TOOL_PALM) { 87 touch_major = MAX_TOUCH_MAJOR; 88 pressure = MAX_PRESSURE; 89 } else { 90 touch_major = (data[3] >> 4) & CONTACT_TOUCH_MAJOR_MASK; 91 pressure = data[4] & CONTACT_PRESSURE_MASK; 92 } 93 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); 98 } 99 100 /* Required for Synaptics Palm Detection */ 101 static void asus_report_tool_width(struct input_dev *input) 102 { 103 struct input_mt *mt = input->mt; 104 struct input_mt_slot *oldest; 105 int oldid, count, i; 106 107 oldest = NULL; 108 oldid = mt->trkid; 109 count = 0; 110 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); 114 115 if (id < 0) 116 continue; 117 if ((id - oldid) & TRKID_SGN) { 118 oldest = ps; 119 oldid = id; 120 } 121 count++; 122 } 123 124 if (oldest) { 125 input_report_abs(input, ABS_TOOL_WIDTH, 126 input_mt_get_value(oldest, ABS_MT_TOUCH_MAJOR)); 127 } 128 } 129 130 static void asus_report_input(struct input_dev *input, u8 *data) 131 { 132 int i; 133 u8 *contactData = data + 2; 134 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; 139 140 input_mt_slot(input, i); 141 input_mt_report_slot_state(input, toolType, down); 142 143 if (down) { 144 asus_report_contact_down(input, toolType, contactData); 145 contactData += CONTACT_DATA_SIZE; 146 } 147 } 148 149 input_report_key(input, BTN_LEFT, data[1] & BTN_LEFT_MASK); 150 asus_report_tool_width(input); 151 152 input_mt_sync_frame(input); 153 input_sync(input); 154 } 155 156 static int asus_raw_event(struct hid_device *hdev, 157 struct hid_report *report, u8 *data, int size) 158 { 159 struct asus_drvdata *drvdata = hid_get_drvdata(hdev); 160 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); 165 return 1; 166 } 167 168 return 0; 169 } 170 171 static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) 172 { 173 struct asus_drvdata *drvdata = hid_get_drvdata(hdev); 174 175 if (drvdata->quirks & QUIRK_IS_MULTITOUCH) { 176 int ret; 177 struct input_dev *input = hi->input; 178 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); 184 185 __set_bit(BTN_LEFT, input->keybit); 186 __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); 187 188 ret = input_mt_init_slots(input, MAX_CONTACTS, INPUT_MT_POINTER); 189 190 if (ret) { 191 hid_err(hdev, "Asus input mt init slots failed: %d\n", ret); 192 return ret; 193 } 194 195 drvdata->input = input; 196 } 197 198 return 0; 199 } 200 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, 204 int *max) 205 { 206 struct asus_drvdata *drvdata = hid_get_drvdata(hdev); 207 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 211 */ 212 return -1; 213 } 214 215 return 0; 216 } 217 218 static int asus_start_multitouch(struct hid_device *hdev) 219 { 220 int ret; 221 const unsigned char buf[] = { FEATURE_REPORT_ID, 0x00, 0x03, 0x01, 0x00 }; 222 unsigned char *dmabuf = kmemdup(buf, sizeof(buf), GFP_KERNEL); 223 224 if (!dmabuf) { 225 ret = -ENOMEM; 226 hid_err(hdev, "Asus failed to alloc dma buf: %d\n", ret); 227 return ret; 228 } 229 230 ret = hid_hw_raw_request(hdev, dmabuf[0], dmabuf, sizeof(buf), 231 HID_FEATURE_REPORT, HID_REQ_SET_REPORT); 232 233 kfree(dmabuf); 234 235 if (ret != sizeof(buf)) { 236 hid_err(hdev, "Asus failed to start multitouch: %d\n", ret); 237 return ret; 238 } 239 240 return 0; 241 } 242 243 static int __maybe_unused asus_reset_resume(struct hid_device *hdev) 244 { 245 struct asus_drvdata *drvdata = hid_get_drvdata(hdev); 246 247 if (drvdata->quirks & QUIRK_IS_MULTITOUCH) 248 return asus_start_multitouch(hdev); 249 250 return 0; 251 } 252 253 static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) 254 { 255 int ret; 256 struct asus_drvdata *drvdata; 257 258 drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL); 259 if (drvdata == NULL) { 260 hid_err(hdev, "Can't alloc Asus descriptor\n"); 261 return -ENOMEM; 262 } 263 264 hid_set_drvdata(hdev, drvdata); 265 266 drvdata->quirks = id->driver_data; 267 268 if (drvdata->quirks & QUIRK_NO_INIT_REPORTS) 269 hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; 270 271 ret = hid_parse(hdev); 272 if (ret) { 273 hid_err(hdev, "Asus hid parse failed: %d\n", ret); 274 return ret; 275 } 276 277 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 278 if (ret) { 279 hid_err(hdev, "Asus hw start failed: %d\n", ret); 280 return ret; 281 } 282 283 if (!drvdata->input) { 284 hid_err(hdev, "Asus input not registered\n"); 285 ret = -ENOMEM; 286 goto err_stop_hw; 287 } 288 289 drvdata->input->name = "Asus TouchPad"; 290 291 if (drvdata->quirks & QUIRK_IS_MULTITOUCH) { 292 ret = asus_start_multitouch(hdev); 293 if (ret) 294 goto err_stop_hw; 295 } 296 297 return 0; 298 err_stop_hw: 299 hid_hw_stop(hdev); 300 return ret; 301 } 302 303 static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc, 304 unsigned int *rsize) 305 { 306 struct asus_drvdata *drvdata = hid_get_drvdata(hdev); 307 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"); 311 rdesc[55] = 0xdd; 312 } 313 return rdesc; 314 } 315 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 }, 321 { } 322 }; 323 MODULE_DEVICE_TABLE(hid, asus_devices); 324 325 static struct hid_driver asus_driver = { 326 .name = "asus", 327 .id_table = asus_devices, 328 .report_fixup = asus_report_fixup, 329 .probe = asus_probe, 330 .input_mapping = asus_input_mapping, 331 .input_configured = asus_input_configured, 332 #ifdef CONFIG_PM 333 .reset_resume = asus_reset_resume, 334 #endif 335 .raw_event = asus_raw_event 336 }; 337 module_hid_driver(asus_driver); 338 339 MODULE_LICENSE("GPL"); 340