whiterose

linux unikernel
Log | Files | Refs | README | LICENSE | git clone https://git.ne02ptzero.me/git/whiterose

hid-elan.c (13913B)


      1 /*
      2  * HID Driver for ELAN Touchpad
      3  *
      4  * Currently only supports touchpad found on HP Pavilion X2 10
      5  *
      6  * Copyright (c) 2016 Alexandrov Stanislav <neko@nya.ai>
      7  *
      8  * This program is free software; you can redistribute it and/or modify it
      9  * under the terms of the GNU General Public License as published by the Free
     10  * Software Foundation; either version 2 of the License, or (at your option)
     11  * any later version.
     12  */
     13 
     14 #include <linux/hid.h>
     15 #include <linux/input/mt.h>
     16 #include <linux/leds.h>
     17 #include <linux/module.h>
     18 #include <linux/usb.h>
     19 
     20 #include "hid-ids.h"
     21 
     22 #define ELAN_MT_I2C		0x5d
     23 #define ELAN_SINGLE_FINGER	0x81
     24 #define ELAN_MT_FIRST_FINGER	0x82
     25 #define ELAN_MT_SECOND_FINGER	0x83
     26 #define ELAN_INPUT_REPORT_SIZE	8
     27 #define ELAN_I2C_REPORT_SIZE	32
     28 #define ELAN_FINGER_DATA_LEN	5
     29 #define ELAN_MAX_FINGERS	5
     30 #define ELAN_MAX_PRESSURE	255
     31 #define ELAN_TP_USB_INTF	1
     32 
     33 #define ELAN_FEATURE_REPORT	0x0d
     34 #define ELAN_FEATURE_SIZE	5
     35 #define ELAN_PARAM_MAX_X	6
     36 #define ELAN_PARAM_MAX_Y	7
     37 #define ELAN_PARAM_RES		8
     38 
     39 #define ELAN_MUTE_LED_REPORT	0xBC
     40 #define ELAN_LED_REPORT_SIZE	8
     41 
     42 #define ELAN_HAS_LED		BIT(0)
     43 
     44 struct elan_drvdata {
     45 	struct input_dev *input;
     46 	u8 prev_report[ELAN_INPUT_REPORT_SIZE];
     47 	struct led_classdev mute_led;
     48 	u8 mute_led_state;
     49 	u16 max_x;
     50 	u16 max_y;
     51 	u16 res_x;
     52 	u16 res_y;
     53 };
     54 
     55 static int is_not_elan_touchpad(struct hid_device *hdev)
     56 {
     57 	if (hdev->bus == BUS_USB) {
     58 		struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
     59 
     60 		return (intf->altsetting->desc.bInterfaceNumber !=
     61 			ELAN_TP_USB_INTF);
     62 	}
     63 
     64 	return 0;
     65 }
     66 
     67 static int elan_input_mapping(struct hid_device *hdev, struct hid_input *hi,
     68 			      struct hid_field *field, struct hid_usage *usage,
     69 			      unsigned long **bit, int *max)
     70 {
     71 	if (is_not_elan_touchpad(hdev))
     72 		return 0;
     73 
     74 	if (field->report->id == ELAN_SINGLE_FINGER ||
     75 	    field->report->id == ELAN_MT_FIRST_FINGER ||
     76 	    field->report->id == ELAN_MT_SECOND_FINGER ||
     77 	    field->report->id == ELAN_MT_I2C)
     78 		return -1;
     79 
     80 	return 0;
     81 }
     82 
     83 static int elan_get_device_param(struct hid_device *hdev,
     84 				 unsigned char *dmabuf, unsigned char param)
     85 {
     86 	int ret;
     87 
     88 	dmabuf[0] = ELAN_FEATURE_REPORT;
     89 	dmabuf[1] = 0x05;
     90 	dmabuf[2] = 0x03;
     91 	dmabuf[3] = param;
     92 	dmabuf[4] = 0x01;
     93 
     94 	ret = hid_hw_raw_request(hdev, ELAN_FEATURE_REPORT, dmabuf,
     95 				 ELAN_FEATURE_SIZE, HID_FEATURE_REPORT,
     96 				 HID_REQ_SET_REPORT);
     97 	if (ret != ELAN_FEATURE_SIZE) {
     98 		hid_err(hdev, "Set report error for parm %d: %d\n", param, ret);
     99 		return ret;
    100 	}
    101 
    102 	ret = hid_hw_raw_request(hdev, ELAN_FEATURE_REPORT, dmabuf,
    103 				 ELAN_FEATURE_SIZE, HID_FEATURE_REPORT,
    104 				 HID_REQ_GET_REPORT);
    105 	if (ret != ELAN_FEATURE_SIZE) {
    106 		hid_err(hdev, "Get report error for parm %d: %d\n", param, ret);
    107 		return ret;
    108 	}
    109 
    110 	return 0;
    111 }
    112 
    113 static unsigned int elan_convert_res(char val)
    114 {
    115 	/*
    116 	 * (value from firmware) * 10 + 790 = dpi
    117 	 * dpi * 10 / 254 = dots/mm
    118 	 */
    119 	return (val * 10 + 790) * 10 / 254;
    120 }
    121 
    122 static int elan_get_device_params(struct hid_device *hdev)
    123 {
    124 	struct elan_drvdata *drvdata = hid_get_drvdata(hdev);
    125 	unsigned char *dmabuf;
    126 	int ret;
    127 
    128 	dmabuf = kmalloc(ELAN_FEATURE_SIZE, GFP_KERNEL);
    129 	if (!dmabuf)
    130 		return -ENOMEM;
    131 
    132 	ret = elan_get_device_param(hdev, dmabuf, ELAN_PARAM_MAX_X);
    133 	if (ret)
    134 		goto err;
    135 
    136 	drvdata->max_x = (dmabuf[4] << 8) | dmabuf[3];
    137 
    138 	ret = elan_get_device_param(hdev, dmabuf, ELAN_PARAM_MAX_Y);
    139 	if (ret)
    140 		goto err;
    141 
    142 	drvdata->max_y = (dmabuf[4] << 8) | dmabuf[3];
    143 
    144 	ret = elan_get_device_param(hdev, dmabuf, ELAN_PARAM_RES);
    145 	if (ret)
    146 		goto err;
    147 
    148 	drvdata->res_x = elan_convert_res(dmabuf[3]);
    149 	drvdata->res_y = elan_convert_res(dmabuf[4]);
    150 
    151 err:
    152 	kfree(dmabuf);
    153 	return ret;
    154 }
    155 
    156 static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi)
    157 {
    158 	int ret;
    159 	struct input_dev *input;
    160 	struct elan_drvdata *drvdata = hid_get_drvdata(hdev);
    161 
    162 	if (is_not_elan_touchpad(hdev))
    163 		return 0;
    164 
    165 	ret = elan_get_device_params(hdev);
    166 	if (ret)
    167 		return ret;
    168 
    169 	input = devm_input_allocate_device(&hdev->dev);
    170 	if (!input)
    171 		return -ENOMEM;
    172 
    173 	input->name = "Elan Touchpad";
    174 	input->phys = hdev->phys;
    175 	input->uniq = hdev->uniq;
    176 	input->id.bustype = hdev->bus;
    177 	input->id.vendor  = hdev->vendor;
    178 	input->id.product = hdev->product;
    179 	input->id.version = hdev->version;
    180 	input->dev.parent = &hdev->dev;
    181 
    182 	input_set_abs_params(input, ABS_MT_POSITION_X, 0, drvdata->max_x,
    183 			     0, 0);
    184 	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, drvdata->max_y,
    185 			     0, 0);
    186 	input_set_abs_params(input, ABS_MT_PRESSURE, 0, ELAN_MAX_PRESSURE,
    187 			     0, 0);
    188 
    189 	__set_bit(BTN_LEFT, input->keybit);
    190 	__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
    191 
    192 	ret = input_mt_init_slots(input, ELAN_MAX_FINGERS, INPUT_MT_POINTER);
    193 	if (ret) {
    194 		hid_err(hdev, "Failed to init elan MT slots: %d\n", ret);
    195 		return ret;
    196 	}
    197 
    198 	input_abs_set_res(input, ABS_X, drvdata->res_x);
    199 	input_abs_set_res(input, ABS_Y, drvdata->res_y);
    200 
    201 	ret = input_register_device(input);
    202 	if (ret) {
    203 		hid_err(hdev, "Failed to register elan input device: %d\n",
    204 			ret);
    205 		input_free_device(input);
    206 		return ret;
    207 	}
    208 
    209 	drvdata->input = input;
    210 
    211 	return 0;
    212 }
    213 
    214 static void elan_report_mt_slot(struct elan_drvdata *drvdata, u8 *data,
    215 				unsigned int slot_num)
    216 {
    217 	struct input_dev *input = drvdata->input;
    218 	int x, y, p;
    219 
    220 	bool active = !!data;
    221 
    222 	input_mt_slot(input, slot_num);
    223 	input_mt_report_slot_state(input, MT_TOOL_FINGER, active);
    224 	if (active) {
    225 		x = ((data[0] & 0xF0) << 4) | data[1];
    226 		y = drvdata->max_y -
    227 		    (((data[0] & 0x07) << 8) | data[2]);
    228 		p = data[4];
    229 
    230 		input_report_abs(input, ABS_MT_POSITION_X, x);
    231 		input_report_abs(input, ABS_MT_POSITION_Y, y);
    232 		input_report_abs(input, ABS_MT_PRESSURE, p);
    233 	}
    234 }
    235 
    236 static void elan_usb_report_input(struct elan_drvdata *drvdata, u8 *data)
    237 {
    238 	int i;
    239 	struct input_dev *input = drvdata->input;
    240 
    241 	/*
    242 	 * There is 3 types of reports: for single touch,
    243 	 * for multitouch - first finger and for multitouch - second finger
    244 	 *
    245 	 * packet structure for ELAN_SINGLE_FINGER and ELAN_MT_FIRST_FINGER:
    246 	 *
    247 	 * byte 1: 1   0   0   0   0   0   0   1  // 0x81 or 0x82
    248 	 * byte 2: 0   0   0   0   0   0   0   0  // looks like unused
    249 	 * byte 3: f5  f4  f3  f2  f1  0   0   L
    250 	 * byte 4: x12 x11 x10 x9  0?  y11 y10 y9
    251 	 * byte 5: x8  x7  x6  x5  x4  x3  x2  x1
    252 	 * byte 6: y8  y7  y6  y5  y4  y3  y2  y1
    253 	 * byte 7: sy4 sy3 sy2 sy1 sx4 sx3 sx2 sx1
    254 	 * byte 8: p8  p7  p6  p5  p4  p3  p2  p1
    255 	 *
    256 	 * packet structure for ELAN_MT_SECOND_FINGER:
    257 	 *
    258 	 * byte 1: 1   0   0   0   0   0   1   1  // 0x83
    259 	 * byte 2: x12 x11 x10 x9  0   y11 y10 y9
    260 	 * byte 3: x8  x7  x6  x5  x4  x3  x2  x1
    261 	 * byte 4: y8  y7  y6  y5  y4  y3  y2  y1
    262 	 * byte 5: sy4 sy3 sy2 sy1 sx4 sx3 sx2 sx1
    263 	 * byte 6: p8  p7  p6  p5  p4  p3  p2  p1
    264 	 * byte 7: 0   0   0   0   0   0   0   0
    265 	 * byte 8: 0   0   0   0   0   0   0   0
    266 	 *
    267 	 * f5-f1: finger touch bits
    268 	 * L: clickpad button
    269 	 * sy / sx: finger width / height expressed in traces, the total number
    270 	 *          of traces can be queried by doing a HID_REQ_SET_REPORT
    271 	 *          { 0x0d, 0x05, 0x03, 0x05, 0x01 } followed by a GET, in the
    272 	 *          returned buf, buf[3]=no-x-traces, buf[4]=no-y-traces.
    273 	 * p: pressure
    274 	 */
    275 
    276 	if (data[0] == ELAN_SINGLE_FINGER) {
    277 		for (i = 0; i < ELAN_MAX_FINGERS; i++) {
    278 			if (data[2] & BIT(i + 3))
    279 				elan_report_mt_slot(drvdata, data + 3, i);
    280 			else
    281 				elan_report_mt_slot(drvdata, NULL, i);
    282 		}
    283 		input_report_key(input, BTN_LEFT, data[2] & 0x01);
    284 	}
    285 	/*
    286 	 * When touched with two fingers Elan touchpad will emit two HID reports
    287 	 * first is ELAN_MT_FIRST_FINGER and second is ELAN_MT_SECOND_FINGER
    288 	 * we will save ELAN_MT_FIRST_FINGER report and wait for
    289 	 * ELAN_MT_SECOND_FINGER to finish multitouch
    290 	 */
    291 	if (data[0] == ELAN_MT_FIRST_FINGER) {
    292 		memcpy(drvdata->prev_report, data,
    293 		       sizeof(drvdata->prev_report));
    294 		return;
    295 	}
    296 
    297 	if (data[0] == ELAN_MT_SECOND_FINGER) {
    298 		int first = 0;
    299 		u8 *prev_report = drvdata->prev_report;
    300 
    301 		if (prev_report[0] != ELAN_MT_FIRST_FINGER)
    302 			return;
    303 
    304 		for (i = 0; i < ELAN_MAX_FINGERS; i++) {
    305 			if (prev_report[2] & BIT(i + 3)) {
    306 				if (!first) {
    307 					first = 1;
    308 					elan_report_mt_slot(drvdata, prev_report + 3, i);
    309 				} else {
    310 					elan_report_mt_slot(drvdata, data + 1, i);
    311 				}
    312 			} else {
    313 				elan_report_mt_slot(drvdata, NULL, i);
    314 			}
    315 		}
    316 		input_report_key(input, BTN_LEFT, prev_report[2] & 0x01);
    317 	}
    318 
    319 	input_mt_sync_frame(input);
    320 	input_sync(input);
    321 }
    322 
    323 static void elan_i2c_report_input(struct elan_drvdata *drvdata, u8 *data)
    324 {
    325 	struct input_dev *input = drvdata->input;
    326 	u8 *finger_data;
    327 	int i;
    328 
    329 	/*
    330 	 * Elan MT touchpads in i2c mode send finger data in the same format
    331 	 * as in USB mode, but then with all fingers in a single packet.
    332 	 *
    333 	 * packet structure for ELAN_MT_I2C:
    334 	 *
    335 	 * byte     1: 1   0   0   1   1   1   0   1   // 0x5d
    336 	 * byte     2: f5  f4  f3  f2  f1  0   0   L
    337 	 * byte     3: x12 x11 x10 x9  0?  y11 y10 y9
    338 	 * byte     4: x8  x7  x6  x5  x4  x3  x2  x1
    339 	 * byte     5: y8  y7  y6  y5  y4  y3  y2  y1
    340 	 * byte     6: sy4 sy3 sy2 sy1 sx4 sx3 sx2 sx1
    341 	 * byte     7: p8  p7  p6  p5  p4  p3  p2  p1
    342 	 * byte  8-12: Same as byte 3-7 for second finger down
    343 	 * byte 13-17: Same as byte 3-7 for third finger down
    344 	 * byte 18-22: Same as byte 3-7 for fourth finger down
    345 	 * byte 23-27: Same as byte 3-7 for fifth finger down
    346 	 */
    347 
    348 	finger_data = data + 2;
    349 	for (i = 0; i < ELAN_MAX_FINGERS; i++) {
    350 		if (data[1] & BIT(i + 3)) {
    351 			elan_report_mt_slot(drvdata, finger_data, i);
    352 			finger_data += ELAN_FINGER_DATA_LEN;
    353 		} else {
    354 			elan_report_mt_slot(drvdata, NULL, i);
    355 		}
    356 	}
    357 
    358 	input_report_key(input, BTN_LEFT, data[1] & 0x01);
    359 	input_mt_sync_frame(input);
    360 	input_sync(input);
    361 }
    362 
    363 static int elan_raw_event(struct hid_device *hdev,
    364 			  struct hid_report *report, u8 *data, int size)
    365 {
    366 	struct elan_drvdata *drvdata = hid_get_drvdata(hdev);
    367 
    368 	if (is_not_elan_touchpad(hdev))
    369 		return 0;
    370 
    371 	if (data[0] == ELAN_SINGLE_FINGER ||
    372 	    data[0] == ELAN_MT_FIRST_FINGER ||
    373 	    data[0] == ELAN_MT_SECOND_FINGER) {
    374 		if (size == ELAN_INPUT_REPORT_SIZE) {
    375 			elan_usb_report_input(drvdata, data);
    376 			return 1;
    377 		}
    378 	}
    379 
    380 	if (data[0] == ELAN_MT_I2C && size == ELAN_I2C_REPORT_SIZE) {
    381 		elan_i2c_report_input(drvdata, data);
    382 		return 1;
    383 	}
    384 
    385 	return 0;
    386 }
    387 
    388 static int elan_start_multitouch(struct hid_device *hdev)
    389 {
    390 	int ret;
    391 
    392 	/*
    393 	 * This byte sequence will enable multitouch mode and disable
    394 	 * mouse emulation
    395 	 */
    396 	static const unsigned char buf[] = { 0x0D, 0x00, 0x03, 0x21, 0x00 };
    397 	unsigned char *dmabuf = kmemdup(buf, sizeof(buf), GFP_KERNEL);
    398 
    399 	if (!dmabuf)
    400 		return -ENOMEM;
    401 
    402 	ret = hid_hw_raw_request(hdev, dmabuf[0], dmabuf, sizeof(buf),
    403 				 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
    404 
    405 	kfree(dmabuf);
    406 
    407 	if (ret != sizeof(buf)) {
    408 		hid_err(hdev, "Failed to start multitouch: %d\n", ret);
    409 		return ret;
    410 	}
    411 
    412 	return 0;
    413 }
    414 
    415 static enum led_brightness elan_mute_led_get_brigtness(struct led_classdev *led_cdev)
    416 {
    417 	struct device *dev = led_cdev->dev->parent;
    418 	struct hid_device *hdev = to_hid_device(dev);
    419 	struct elan_drvdata *drvdata = hid_get_drvdata(hdev);
    420 
    421 	return drvdata->mute_led_state;
    422 }
    423 
    424 static int elan_mute_led_set_brigtness(struct led_classdev *led_cdev,
    425 				       enum led_brightness value)
    426 {
    427 	int ret;
    428 	u8 led_state;
    429 	struct device *dev = led_cdev->dev->parent;
    430 	struct hid_device *hdev = to_hid_device(dev);
    431 	struct elan_drvdata *drvdata = hid_get_drvdata(hdev);
    432 
    433 	unsigned char *dmabuf = kzalloc(ELAN_LED_REPORT_SIZE, GFP_KERNEL);
    434 
    435 	if (!dmabuf)
    436 		return -ENOMEM;
    437 
    438 	led_state = !!value;
    439 
    440 	dmabuf[0] = ELAN_MUTE_LED_REPORT;
    441 	dmabuf[1] = 0x02;
    442 	dmabuf[2] = led_state;
    443 
    444 	ret = hid_hw_raw_request(hdev, dmabuf[0], dmabuf, ELAN_LED_REPORT_SIZE,
    445 				 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
    446 
    447 	kfree(dmabuf);
    448 
    449 	if (ret != ELAN_LED_REPORT_SIZE) {
    450 		hid_err(hdev, "Failed to set mute led brightness: %d\n", ret);
    451 		return ret;
    452 	}
    453 
    454 	drvdata->mute_led_state = led_state;
    455 	return 0;
    456 }
    457 
    458 static int elan_init_mute_led(struct hid_device *hdev)
    459 {
    460 	struct elan_drvdata *drvdata = hid_get_drvdata(hdev);
    461 	struct led_classdev *mute_led = &drvdata->mute_led;
    462 
    463 	mute_led->name = "elan:red:mute";
    464 	mute_led->brightness_get = elan_mute_led_get_brigtness;
    465 	mute_led->brightness_set_blocking = elan_mute_led_set_brigtness;
    466 	mute_led->max_brightness = LED_ON;
    467 	mute_led->dev = &hdev->dev;
    468 
    469 	return devm_led_classdev_register(&hdev->dev, mute_led);
    470 }
    471 
    472 static int elan_probe(struct hid_device *hdev, const struct hid_device_id *id)
    473 {
    474 	int ret;
    475 	struct elan_drvdata *drvdata;
    476 
    477 	drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
    478 
    479 	if (!drvdata)
    480 		return -ENOMEM;
    481 
    482 	hid_set_drvdata(hdev, drvdata);
    483 
    484 	ret = hid_parse(hdev);
    485 	if (ret) {
    486 		hid_err(hdev, "Hid Parse failed\n");
    487 		return ret;
    488 	}
    489 
    490 	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
    491 	if (ret) {
    492 		hid_err(hdev, "Hid hw start failed\n");
    493 		return ret;
    494 	}
    495 
    496 	if (is_not_elan_touchpad(hdev))
    497 		return 0;
    498 
    499 	if (!drvdata->input) {
    500 		hid_err(hdev, "Input device is not registered\n");
    501 		ret = -ENAVAIL;
    502 		goto err;
    503 	}
    504 
    505 	ret = elan_start_multitouch(hdev);
    506 	if (ret)
    507 		goto err;
    508 
    509 	if (id->driver_data & ELAN_HAS_LED) {
    510 		ret = elan_init_mute_led(hdev);
    511 		if (ret)
    512 			goto err;
    513 	}
    514 
    515 	return 0;
    516 err:
    517 	hid_hw_stop(hdev);
    518 	return ret;
    519 }
    520 
    521 static void elan_remove(struct hid_device *hdev)
    522 {
    523 	hid_hw_stop(hdev);
    524 }
    525 
    526 static const struct hid_device_id elan_devices[] = {
    527 	{ HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_HP_X2),
    528 	  .driver_data = ELAN_HAS_LED },
    529 	{ HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_HP_X2_10_COVER),
    530 	  .driver_data = ELAN_HAS_LED },
    531 	{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_TOSHIBA_CLICK_L9W) },
    532 	{ }
    533 };
    534 MODULE_DEVICE_TABLE(hid, elan_devices);
    535 
    536 static struct hid_driver elan_driver = {
    537 	.name = "elan",
    538 	.id_table = elan_devices,
    539 	.input_mapping = elan_input_mapping,
    540 	.input_configured = elan_input_configured,
    541 	.raw_event = elan_raw_event,
    542 	.probe = elan_probe,
    543 	.remove = elan_remove,
    544 };
    545 
    546 module_hid_driver(elan_driver);
    547 
    548 MODULE_LICENSE("GPL");
    549 MODULE_AUTHOR("Alexandrov Stanislav");
    550 MODULE_DESCRIPTION("Driver for HID ELAN Touchpads");