hid-lenovo.c 25.4 KB
Newer Older
1
/*
2 3
 *  HID driver for Lenovo:
 *  - ThinkPad USB Keyboard with TrackPoint (tpkbd)
4 5
 *  - ThinkPad Compact Bluetooth Keyboard with TrackPoint (cptkbd)
 *  - ThinkPad Compact USB Keyboard with TrackPoint (cptkbd)
6 7
 *
 *  Copyright (c) 2012 Bernhard Seibold
8
 *  Copyright (c) 2014 Jamie Lentin <jm@lentin.co.uk>
9 10 11 12 13 14 15 16 17 18 19
 *
 * Linux IBM/Lenovo Scrollpoint mouse driver:
 * - IBM Scrollpoint III
 * - IBM Scrollpoint Pro
 * - IBM Scrollpoint Optical
 * - IBM Scrollpoint Optical 800dpi
 * - IBM Scrollpoint Optical 800dpi Pro
 * - Lenovo Scrollpoint Optical
 *
 *  Copyright (c) 2012 Peter De Wachter <pdewacht@gmail.com>
 *  Copyright (c) 2018 Peter Ganzhorn <peter.ganzhorn@gmail.com>
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
 */

/*
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 */

#include <linux/module.h>
#include <linux/sysfs.h>
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/input.h>
#include <linux/leds.h>

#include "hid-ids.h"

38
struct lenovo_drvdata_tpkbd {
39 40 41 42 43 44 45 46 47 48 49
	int led_state;
	struct led_classdev led_mute;
	struct led_classdev led_micmute;
	int press_to_select;
	int dragging;
	int release_to_select;
	int select_right;
	int sensitivity;
	int press_speed;
};

50
struct lenovo_drvdata_cptkbd {
51
	u8 middlebutton_state; /* 0:Up, 1:Down (undecided), 2:Scrolling */
52
	bool fn_lock;
53
	int sensitivity;
54 55
};

56 57
#define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
static const __u8 lenovo_pro_dock_need_fixup_collection[] = {
	0x05, 0x88,		/* Usage Page (Vendor Usage Page 0x88)	*/
	0x09, 0x01,		/* Usage (Vendor Usage 0x01)		*/
	0xa1, 0x01,		/* Collection (Application)		*/
	0x85, 0x04,		/*  Report ID (4)			*/
	0x19, 0x00,		/*  Usage Minimum (0)			*/
	0x2a, 0xff, 0xff,	/*  Usage Maximum (65535)		*/
};

static __u8 *lenovo_report_fixup(struct hid_device *hdev, __u8 *rdesc,
		unsigned int *rsize)
{
	switch (hdev->product) {
	case USB_DEVICE_ID_LENOVO_TPPRODOCK:
		/* the fixups that need to be done:
		 *   - get a reasonable usage max for the vendor collection
		 *     0x8801 from the report ID 4
		 */
		if (*rsize >= 153 &&
		    memcmp(&rdesc[140], lenovo_pro_dock_need_fixup_collection,
			  sizeof(lenovo_pro_dock_need_fixup_collection)) == 0) {
			rdesc[151] = 0x01;
			rdesc[152] = 0x00;
		}
		break;
	}
	return rdesc;
}

87
static int lenovo_input_mapping_tpkbd(struct hid_device *hdev,
88 89 90
		struct hid_input *hi, struct hid_field *field,
		struct hid_usage *usage, unsigned long **bit, int *max)
{
91
	if (usage->hid == (HID_UP_BUTTON | 0x0010)) {
92
		/* This sub-device contains trackpoint, mark it */
93
		hid_set_drvdata(hdev, (void *)1);
94 95 96 97 98 99
		map_key_clear(KEY_MICMUTE);
		return 1;
	}
	return 0;
}

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
static int lenovo_input_mapping_cptkbd(struct hid_device *hdev,
		struct hid_input *hi, struct hid_field *field,
		struct hid_usage *usage, unsigned long **bit, int *max)
{
	/* HID_UP_LNVENDOR = USB, HID_UP_MSVENDOR = BT */
	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR ||
	    (usage->hid & HID_USAGE_PAGE) == HID_UP_LNVENDOR) {
		switch (usage->hid & HID_USAGE) {
		case 0x00f1: /* Fn-F4: Mic mute */
			map_key_clear(KEY_MICMUTE);
			return 1;
		case 0x00f2: /* Fn-F5: Brightness down */
			map_key_clear(KEY_BRIGHTNESSDOWN);
			return 1;
		case 0x00f3: /* Fn-F6: Brightness up */
			map_key_clear(KEY_BRIGHTNESSUP);
			return 1;
		case 0x00f4: /* Fn-F7: External display (projector) */
			map_key_clear(KEY_SWITCHVIDEOMODE);
			return 1;
		case 0x00f5: /* Fn-F8: Wireless */
			map_key_clear(KEY_WLAN);
			return 1;
		case 0x00f6: /* Fn-F9: Control panel */
			map_key_clear(KEY_CONFIG);
			return 1;
		case 0x00f8: /* Fn-F11: View open applications (3 boxes) */
			map_key_clear(KEY_SCALE);
			return 1;
129
		case 0x00f9: /* Fn-F12: Open My computer (6 boxes) USB-only */
130 131 132
			/* NB: This mapping is invented in raw_event below */
			map_key_clear(KEY_FILE);
			return 1;
133 134 135
		case 0x00fa: /* Fn-Esc: Fn-lock toggle */
			map_key_clear(KEY_FN_ESC);
			return 1;
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
		case 0x00fb: /* Middle mouse button (in native mode) */
			map_key_clear(BTN_MIDDLE);
			return 1;
		}
	}

	/* Compatibility middle/wheel mappings should be ignored */
	if (usage->hid == HID_GD_WHEEL)
		return -1;
	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON &&
			(usage->hid & HID_USAGE) == 0x003)
		return -1;
	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER &&
			(usage->hid & HID_USAGE) == 0x238)
		return -1;

	/* Map wheel emulation reports: 0xffa1 = USB, 0xff10 = BT */
	if ((usage->hid & HID_USAGE_PAGE) == 0xff100000 ||
	    (usage->hid & HID_USAGE_PAGE) == 0xffa10000) {
		field->flags |= HID_MAIN_ITEM_RELATIVE | HID_MAIN_ITEM_VARIABLE;
		field->logical_minimum = -127;
		field->logical_maximum = 127;

		switch (usage->hid & HID_USAGE) {
		case 0x0000:
161
			hid_map_usage(hi, usage, bit, max, EV_REL, REL_HWHEEL);
162 163
			return 1;
		case 0x0001:
164
			hid_map_usage(hi, usage, bit, max, EV_REL, REL_WHEEL);
165 166 167
			return 1;
		default:
			return -1;
168 169 170 171 172 173
		}
	}

	return 0;
}

174 175 176 177 178 179 180 181 182 183 184
static int lenovo_input_mapping_scrollpoint(struct hid_device *hdev,
		struct hid_input *hi, struct hid_field *field,
		struct hid_usage *usage, unsigned long **bit, int *max)
{
	if (usage->hid == HID_GD_Z) {
		hid_map_usage(hi, usage, bit, max, EV_REL, REL_HWHEEL);
		return 1;
	}
	return 0;
}

185 186 187 188 189 190 191 192
static int lenovo_input_mapping(struct hid_device *hdev,
		struct hid_input *hi, struct hid_field *field,
		struct hid_usage *usage, unsigned long **bit, int *max)
{
	switch (hdev->product) {
	case USB_DEVICE_ID_LENOVO_TPKBD:
		return lenovo_input_mapping_tpkbd(hdev, hi, field,
							usage, bit, max);
193 194 195 196
	case USB_DEVICE_ID_LENOVO_CUSBKBD:
	case USB_DEVICE_ID_LENOVO_CBTKBD:
		return lenovo_input_mapping_cptkbd(hdev, hi, field,
							usage, bit, max);
197 198 199 200 201 202 203 204
	case USB_DEVICE_ID_IBM_SCROLLPOINT_III:
	case USB_DEVICE_ID_IBM_SCROLLPOINT_PRO:
	case USB_DEVICE_ID_IBM_SCROLLPOINT_OPTICAL:
	case USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL:
	case USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL_PRO:
	case USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL:
		return lenovo_input_mapping_scrollpoint(hdev, hi, field,
							usage, bit, max);
205 206 207 208 209
	default:
		return 0;
	}
}

210 211
#undef map_key_clear

212 213 214 215 216
/* Send a config command to the keyboard */
static int lenovo_send_cmd_cptkbd(struct hid_device *hdev,
			unsigned char byte2, unsigned char byte3)
{
	int ret;
217 218 219 220 221 222 223 224 225
	unsigned char *buf;

	buf = kzalloc(3, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	buf[0] = 0x18;
	buf[1] = byte2;
	buf[2] = byte3;
226 227 228

	switch (hdev->product) {
	case USB_DEVICE_ID_LENOVO_CUSBKBD:
229
		ret = hid_hw_raw_request(hdev, 0x13, buf, 3,
230 231 232
					HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
		break;
	case USB_DEVICE_ID_LENOVO_CBTKBD:
233
		ret = hid_hw_output_report(hdev, buf, 3);
234 235 236 237 238 239
		break;
	default:
		ret = -EINVAL;
		break;
	}

240 241
	kfree(buf);

242 243 244 245 246 247 248 249 250 251 252
	return ret < 0 ? ret : 0; /* BT returns 0, USB returns sizeof(buf) */
}

static void lenovo_features_set_cptkbd(struct hid_device *hdev)
{
	int ret;
	struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);

	ret = lenovo_send_cmd_cptkbd(hdev, 0x05, cptkbd_data->fn_lock);
	if (ret)
		hid_err(hdev, "Fn-lock setting failed: %d\n", ret);
253 254 255 256

	ret = lenovo_send_cmd_cptkbd(hdev, 0x02, cptkbd_data->sensitivity);
	if (ret)
		hid_err(hdev, "Sensitivity setting failed: %d\n", ret);
257 258 259 260 261 262
}

static ssize_t attr_fn_lock_show_cptkbd(struct device *dev,
		struct device_attribute *attr,
		char *buf)
{
Geliang Tang's avatar
Geliang Tang committed
263
	struct hid_device *hdev = to_hid_device(dev);
264 265 266 267 268 269 270 271 272 273
	struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);

	return snprintf(buf, PAGE_SIZE, "%u\n", cptkbd_data->fn_lock);
}

static ssize_t attr_fn_lock_store_cptkbd(struct device *dev,
		struct device_attribute *attr,
		const char *buf,
		size_t count)
{
Geliang Tang's avatar
Geliang Tang committed
274
	struct hid_device *hdev = to_hid_device(dev);
275 276 277 278 279 280 281 282 283 284 285 286 287 288
	struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
	int value;

	if (kstrtoint(buf, 10, &value))
		return -EINVAL;
	if (value < 0 || value > 1)
		return -EINVAL;

	cptkbd_data->fn_lock = !!value;
	lenovo_features_set_cptkbd(hdev);

	return count;
}

289 290 291 292
static ssize_t attr_sensitivity_show_cptkbd(struct device *dev,
		struct device_attribute *attr,
		char *buf)
{
Geliang Tang's avatar
Geliang Tang committed
293
	struct hid_device *hdev = to_hid_device(dev);
294 295 296 297 298 299 300 301 302 303 304
	struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);

	return snprintf(buf, PAGE_SIZE, "%u\n",
		cptkbd_data->sensitivity);
}

static ssize_t attr_sensitivity_store_cptkbd(struct device *dev,
		struct device_attribute *attr,
		const char *buf,
		size_t count)
{
Geliang Tang's avatar
Geliang Tang committed
305
	struct hid_device *hdev = to_hid_device(dev);
306 307 308 309 310 311 312 313 314 315 316 317 318
	struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
	int value;

	if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
		return -EINVAL;

	cptkbd_data->sensitivity = value;
	lenovo_features_set_cptkbd(hdev);

	return count;
}


319 320 321 322 323
static struct device_attribute dev_attr_fn_lock_cptkbd =
	__ATTR(fn_lock, S_IWUSR | S_IRUGO,
			attr_fn_lock_show_cptkbd,
			attr_fn_lock_store_cptkbd);

324 325 326 327 328 329
static struct device_attribute dev_attr_sensitivity_cptkbd =
	__ATTR(sensitivity, S_IWUSR | S_IRUGO,
			attr_sensitivity_show_cptkbd,
			attr_sensitivity_store_cptkbd);


330 331
static struct attribute *lenovo_attributes_cptkbd[] = {
	&dev_attr_fn_lock_cptkbd.attr,
332
	&dev_attr_sensitivity_cptkbd.attr,
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
	NULL
};

static const struct attribute_group lenovo_attr_group_cptkbd = {
	.attrs = lenovo_attributes_cptkbd,
};

static int lenovo_raw_event(struct hid_device *hdev,
			struct hid_report *report, u8 *data, int size)
{
	/*
	 * Compact USB keyboard's Fn-F12 report holds down many other keys, and
	 * its own key is outside the usage page range. Remove extra
	 * keypresses and remap to inside usage page.
	 */
	if (unlikely(hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD
			&& size == 3
			&& data[0] == 0x15
			&& data[1] == 0x94
			&& data[2] == 0x01)) {
353 354
		data[1] = 0x00;
		data[2] = 0x01;
355 356 357 358 359
	}

	return 0;
}

360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
static int lenovo_event_cptkbd(struct hid_device *hdev,
		struct hid_field *field, struct hid_usage *usage, __s32 value)
{
	struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);

	/* "wheel" scroll events */
	if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
			usage->code == REL_HWHEEL)) {
		/* Scroll events disable middle-click event */
		cptkbd_data->middlebutton_state = 2;
		return 0;
	}

	/* Middle click events */
	if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) {
		if (value == 1) {
			cptkbd_data->middlebutton_state = 1;
		} else if (value == 0) {
			if (cptkbd_data->middlebutton_state == 1) {
				/* No scrolling inbetween, send middle-click */
				input_event(field->hidinput->input,
					EV_KEY, BTN_MIDDLE, 1);
				input_sync(field->hidinput->input);
				input_event(field->hidinput->input,
					EV_KEY, BTN_MIDDLE, 0);
				input_sync(field->hidinput->input);
			}
			cptkbd_data->middlebutton_state = 0;
		}
		return 1;
	}

	return 0;
}

static int lenovo_event(struct hid_device *hdev, struct hid_field *field,
		struct hid_usage *usage, __s32 value)
{
	switch (hdev->product) {
	case USB_DEVICE_ID_LENOVO_CUSBKBD:
	case USB_DEVICE_ID_LENOVO_CBTKBD:
		return lenovo_event_cptkbd(hdev, field, usage, value);
	default:
		return 0;
	}
}

407
static int lenovo_features_set_tpkbd(struct hid_device *hdev)
408 409
{
	struct hid_report *report;
410
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
411 412 413 414 415 416 417 418 419 420 421

	report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[4];

	report->field[0]->value[0]  = data_pointer->press_to_select   ? 0x01 : 0x02;
	report->field[0]->value[0] |= data_pointer->dragging          ? 0x04 : 0x08;
	report->field[0]->value[0] |= data_pointer->release_to_select ? 0x10 : 0x20;
	report->field[0]->value[0] |= data_pointer->select_right      ? 0x80 : 0x40;
	report->field[1]->value[0] = 0x03; // unknown setting, imitate windows driver
	report->field[2]->value[0] = data_pointer->sensitivity;
	report->field[3]->value[0] = data_pointer->press_speed;

422
	hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
423 424 425
	return 0;
}

426
static ssize_t attr_press_to_select_show_tpkbd(struct device *dev,
427 428 429
		struct device_attribute *attr,
		char *buf)
{
Geliang Tang's avatar
Geliang Tang committed
430
	struct hid_device *hdev = to_hid_device(dev);
431
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
432 433 434 435

	return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->press_to_select);
}

436
static ssize_t attr_press_to_select_store_tpkbd(struct device *dev,
437 438 439 440
		struct device_attribute *attr,
		const char *buf,
		size_t count)
{
Geliang Tang's avatar
Geliang Tang committed
441
	struct hid_device *hdev = to_hid_device(dev);
442
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
443 444 445 446 447 448 449 450
	int value;

	if (kstrtoint(buf, 10, &value))
		return -EINVAL;
	if (value < 0 || value > 1)
		return -EINVAL;

	data_pointer->press_to_select = value;
451
	lenovo_features_set_tpkbd(hdev);
452 453 454 455

	return count;
}

456
static ssize_t attr_dragging_show_tpkbd(struct device *dev,
457 458 459
		struct device_attribute *attr,
		char *buf)
{
Geliang Tang's avatar
Geliang Tang committed
460
	struct hid_device *hdev = to_hid_device(dev);
461
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
462 463 464 465

	return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->dragging);
}

466
static ssize_t attr_dragging_store_tpkbd(struct device *dev,
467 468 469 470
		struct device_attribute *attr,
		const char *buf,
		size_t count)
{
Geliang Tang's avatar
Geliang Tang committed
471
	struct hid_device *hdev = to_hid_device(dev);
472
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
473 474 475 476 477 478 479 480
	int value;

	if (kstrtoint(buf, 10, &value))
		return -EINVAL;
	if (value < 0 || value > 1)
		return -EINVAL;

	data_pointer->dragging = value;
481
	lenovo_features_set_tpkbd(hdev);
482 483 484 485

	return count;
}

486
static ssize_t attr_release_to_select_show_tpkbd(struct device *dev,
487 488 489
		struct device_attribute *attr,
		char *buf)
{
Geliang Tang's avatar
Geliang Tang committed
490
	struct hid_device *hdev = to_hid_device(dev);
491
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
492 493 494 495

	return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->release_to_select);
}

496
static ssize_t attr_release_to_select_store_tpkbd(struct device *dev,
497 498 499 500
		struct device_attribute *attr,
		const char *buf,
		size_t count)
{
Geliang Tang's avatar
Geliang Tang committed
501
	struct hid_device *hdev = to_hid_device(dev);
502
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
503 504 505 506 507 508 509 510
	int value;

	if (kstrtoint(buf, 10, &value))
		return -EINVAL;
	if (value < 0 || value > 1)
		return -EINVAL;

	data_pointer->release_to_select = value;
511
	lenovo_features_set_tpkbd(hdev);
512 513 514 515

	return count;
}

516
static ssize_t attr_select_right_show_tpkbd(struct device *dev,
517 518 519
		struct device_attribute *attr,
		char *buf)
{
Geliang Tang's avatar
Geliang Tang committed
520
	struct hid_device *hdev = to_hid_device(dev);
521
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
522 523 524 525

	return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->select_right);
}

526
static ssize_t attr_select_right_store_tpkbd(struct device *dev,
527 528 529 530
		struct device_attribute *attr,
		const char *buf,
		size_t count)
{
Geliang Tang's avatar
Geliang Tang committed
531
	struct hid_device *hdev = to_hid_device(dev);
532
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
533 534 535 536 537 538 539 540
	int value;

	if (kstrtoint(buf, 10, &value))
		return -EINVAL;
	if (value < 0 || value > 1)
		return -EINVAL;

	data_pointer->select_right = value;
541
	lenovo_features_set_tpkbd(hdev);
542 543 544 545

	return count;
}

546
static ssize_t attr_sensitivity_show_tpkbd(struct device *dev,
547 548 549
		struct device_attribute *attr,
		char *buf)
{
Geliang Tang's avatar
Geliang Tang committed
550
	struct hid_device *hdev = to_hid_device(dev);
551
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
552 553 554 555 556

	return snprintf(buf, PAGE_SIZE, "%u\n",
		data_pointer->sensitivity);
}

557
static ssize_t attr_sensitivity_store_tpkbd(struct device *dev,
558 559 560 561
		struct device_attribute *attr,
		const char *buf,
		size_t count)
{
Geliang Tang's avatar
Geliang Tang committed
562
	struct hid_device *hdev = to_hid_device(dev);
563
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
564 565 566 567 568 569
	int value;

	if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
		return -EINVAL;

	data_pointer->sensitivity = value;
570
	lenovo_features_set_tpkbd(hdev);
571 572 573 574

	return count;
}

575
static ssize_t attr_press_speed_show_tpkbd(struct device *dev,
576 577 578
		struct device_attribute *attr,
		char *buf)
{
Geliang Tang's avatar
Geliang Tang committed
579
	struct hid_device *hdev = to_hid_device(dev);
580
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
581 582 583 584 585

	return snprintf(buf, PAGE_SIZE, "%u\n",
		data_pointer->press_speed);
}

586
static ssize_t attr_press_speed_store_tpkbd(struct device *dev,
587 588 589 590
		struct device_attribute *attr,
		const char *buf,
		size_t count)
{
Geliang Tang's avatar
Geliang Tang committed
591
	struct hid_device *hdev = to_hid_device(dev);
592
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
593 594 595 596 597 598
	int value;

	if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
		return -EINVAL;

	data_pointer->press_speed = value;
599
	lenovo_features_set_tpkbd(hdev);
600 601 602 603

	return count;
}

604
static struct device_attribute dev_attr_press_to_select_tpkbd =
605
	__ATTR(press_to_select, S_IWUSR | S_IRUGO,
606 607
			attr_press_to_select_show_tpkbd,
			attr_press_to_select_store_tpkbd);
608

609
static struct device_attribute dev_attr_dragging_tpkbd =
610
	__ATTR(dragging, S_IWUSR | S_IRUGO,
611 612
			attr_dragging_show_tpkbd,
			attr_dragging_store_tpkbd);
613

614
static struct device_attribute dev_attr_release_to_select_tpkbd =
615
	__ATTR(release_to_select, S_IWUSR | S_IRUGO,
616 617
			attr_release_to_select_show_tpkbd,
			attr_release_to_select_store_tpkbd);
618

619
static struct device_attribute dev_attr_select_right_tpkbd =
620
	__ATTR(select_right, S_IWUSR | S_IRUGO,
621 622
			attr_select_right_show_tpkbd,
			attr_select_right_store_tpkbd);
623

624
static struct device_attribute dev_attr_sensitivity_tpkbd =
625
	__ATTR(sensitivity, S_IWUSR | S_IRUGO,
626 627
			attr_sensitivity_show_tpkbd,
			attr_sensitivity_store_tpkbd);
628

629
static struct device_attribute dev_attr_press_speed_tpkbd =
630
	__ATTR(press_speed, S_IWUSR | S_IRUGO,
631 632 633 634 635 636 637 638 639 640
			attr_press_speed_show_tpkbd,
			attr_press_speed_store_tpkbd);

static struct attribute *lenovo_attributes_tpkbd[] = {
	&dev_attr_press_to_select_tpkbd.attr,
	&dev_attr_dragging_tpkbd.attr,
	&dev_attr_release_to_select_tpkbd.attr,
	&dev_attr_select_right_tpkbd.attr,
	&dev_attr_sensitivity_tpkbd.attr,
	&dev_attr_press_speed_tpkbd.attr,
641 642 643
	NULL
};

644 645
static const struct attribute_group lenovo_attr_group_tpkbd = {
	.attrs = lenovo_attributes_tpkbd,
646 647
};

648
static enum led_brightness lenovo_led_brightness_get_tpkbd(
649 650
			struct led_classdev *led_cdev)
{
651
	struct device *dev = led_cdev->dev->parent;
Geliang Tang's avatar
Geliang Tang committed
652
	struct hid_device *hdev = to_hid_device(dev);
653
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
654 655 656 657 658 659 660 661 662 663
	int led_nr = 0;

	if (led_cdev == &data_pointer->led_micmute)
		led_nr = 1;

	return data_pointer->led_state & (1 << led_nr)
				? LED_FULL
				: LED_OFF;
}

664
static void lenovo_led_brightness_set_tpkbd(struct led_classdev *led_cdev,
665 666
			enum led_brightness value)
{
667
	struct device *dev = led_cdev->dev->parent;
Geliang Tang's avatar
Geliang Tang committed
668
	struct hid_device *hdev = to_hid_device(dev);
669
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
670 671 672 673 674 675 676 677 678 679 680 681 682 683
	struct hid_report *report;
	int led_nr = 0;

	if (led_cdev == &data_pointer->led_micmute)
		led_nr = 1;

	if (value == LED_OFF)
		data_pointer->led_state &= ~(1 << led_nr);
	else
		data_pointer->led_state |= 1 << led_nr;

	report = hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[3];
	report->field[0]->value[0] = (data_pointer->led_state >> 0) & 1;
	report->field[0]->value[1] = (data_pointer->led_state >> 1) & 1;
684
	hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
685 686
}

687
static int lenovo_probe_tpkbd(struct hid_device *hdev)
688 689
{
	struct device *dev = &hdev->dev;
690
	struct lenovo_drvdata_tpkbd *data_pointer;
691 692
	size_t name_sz = strlen(dev_name(dev)) + 16;
	char *name_mute, *name_micmute;
693
	int i;
694
	int ret;
695

696 697 698 699 700 701 702 703 704
	/*
	 * Only register extra settings against subdevice where input_mapping
	 * set drvdata to 1, i.e. the trackpoint.
	 */
	if (!hid_get_drvdata(hdev))
		return 0;

	hid_set_drvdata(hdev, NULL);

705 706 707 708 709 710 711
	/* Validate required reports. */
	for (i = 0; i < 4; i++) {
		if (!hid_validate_values(hdev, HID_FEATURE_REPORT, 4, i, 1))
			return -ENODEV;
	}
	if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 3, 0, 2))
		return -ENODEV;
712

713 714 715
	ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_tpkbd);
	if (ret)
		hid_warn(hdev, "Could not create sysfs group: %d\n", ret);
716

717
	data_pointer = devm_kzalloc(&hdev->dev,
718
				    sizeof(struct lenovo_drvdata_tpkbd),
719
				    GFP_KERNEL);
720 721
	if (data_pointer == NULL) {
		hid_err(hdev, "Could not allocate memory for driver data\n");
722 723
		ret = -ENOMEM;
		goto err;
724 725 726 727 728 729
	}

	// set same default values as windows driver
	data_pointer->sensitivity = 0xa0;
	data_pointer->press_speed = 0x38;

730 731 732
	name_mute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL);
	name_micmute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL);
	if (name_mute == NULL || name_micmute == NULL) {
733
		hid_err(hdev, "Could not allocate memory for led data\n");
734 735
		ret = -ENOMEM;
		goto err;
736 737 738 739 740 741 742
	}
	snprintf(name_mute, name_sz, "%s:amber:mute", dev_name(dev));
	snprintf(name_micmute, name_sz, "%s:amber:micmute", dev_name(dev));

	hid_set_drvdata(hdev, data_pointer);

	data_pointer->led_mute.name = name_mute;
743 744
	data_pointer->led_mute.brightness_get = lenovo_led_brightness_get_tpkbd;
	data_pointer->led_mute.brightness_set = lenovo_led_brightness_set_tpkbd;
745
	data_pointer->led_mute.dev = dev;
746 747 748
	ret = led_classdev_register(dev, &data_pointer->led_mute);
	if (ret < 0)
		goto err;
749 750

	data_pointer->led_micmute.name = name_micmute;
751 752 753 754
	data_pointer->led_micmute.brightness_get =
		lenovo_led_brightness_get_tpkbd;
	data_pointer->led_micmute.brightness_set =
		lenovo_led_brightness_set_tpkbd;
755
	data_pointer->led_micmute.dev = dev;
756 757 758 759 760
	ret = led_classdev_register(dev, &data_pointer->led_micmute);
	if (ret < 0) {
		led_classdev_unregister(&data_pointer->led_mute);
		goto err;
	}
761

762
	lenovo_features_set_tpkbd(hdev);
763 764

	return 0;
765 766 767
err:
	sysfs_remove_group(&hdev->dev.kobj, &lenovo_attr_group_tpkbd);
	return ret;
768 769
}

770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
static int lenovo_probe_cptkbd(struct hid_device *hdev)
{
	int ret;
	struct lenovo_drvdata_cptkbd *cptkbd_data;

	/* All the custom action happens on the USBMOUSE device for USB */
	if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD
			&& hdev->type != HID_TYPE_USBMOUSE) {
		hid_dbg(hdev, "Ignoring keyboard half of device\n");
		return 0;
	}

	cptkbd_data = devm_kzalloc(&hdev->dev,
					sizeof(*cptkbd_data),
					GFP_KERNEL);
	if (cptkbd_data == NULL) {
		hid_err(hdev, "can't alloc keyboard descriptor\n");
		return -ENOMEM;
	}
	hid_set_drvdata(hdev, cptkbd_data);

	/*
	 * Tell the keyboard a driver understands it, and turn F7, F9, F11 into
	 * regular keys
	 */
	ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03);
	if (ret)
		hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);

799 800 801 802 803
	/* Switch middle button to native mode */
	ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01);
	if (ret)
		hid_warn(hdev, "Failed to switch middle button: %d\n", ret);

804
	/* Set keyboard settings to known state */
805
	cptkbd_data->middlebutton_state = 0;
806
	cptkbd_data->fn_lock = true;
807
	cptkbd_data->sensitivity = 0x05;
808 809 810 811 812 813 814 815 816
	lenovo_features_set_cptkbd(hdev);

	ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_cptkbd);
	if (ret)
		hid_warn(hdev, "Could not create sysfs group: %d\n", ret);

	return 0;
}

817
static int lenovo_probe(struct hid_device *hdev,
818 819 820 821 822 823 824
		const struct hid_device_id *id)
{
	int ret;

	ret = hid_parse(hdev);
	if (ret) {
		hid_err(hdev, "hid_parse failed\n");
825
		goto err;
826 827 828 829 830
	}

	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
	if (ret) {
		hid_err(hdev, "hid_hw_start failed\n");
831
		goto err;
832 833
	}

834 835
	switch (hdev->product) {
	case USB_DEVICE_ID_LENOVO_TPKBD:
836
		ret = lenovo_probe_tpkbd(hdev);
837
		break;
838 839 840 841
	case USB_DEVICE_ID_LENOVO_CUSBKBD:
	case USB_DEVICE_ID_LENOVO_CBTKBD:
		ret = lenovo_probe_cptkbd(hdev);
		break;
842 843 844
	default:
		ret = 0;
		break;
845
	}
846 847
	if (ret)
		goto err_hid;
848 849

	return 0;
850 851 852
err_hid:
	hid_hw_stop(hdev);
err:
853 854 855
	return ret;
}

856
static void lenovo_remove_tpkbd(struct hid_device *hdev)
857
{
858
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
859

860 861 862 863 864 865 866
	/*
	 * Only the trackpoint half of the keyboard has drvdata and stuff that
	 * needs unregistering.
	 */
	if (data_pointer == NULL)
		return;

867
	sysfs_remove_group(&hdev->dev.kobj,
868
			&lenovo_attr_group_tpkbd);
869 870 871 872 873 874 875

	led_classdev_unregister(&data_pointer->led_micmute);
	led_classdev_unregister(&data_pointer->led_mute);

	hid_set_drvdata(hdev, NULL);
}

876 877 878 879 880 881
static void lenovo_remove_cptkbd(struct hid_device *hdev)
{
	sysfs_remove_group(&hdev->dev.kobj,
			&lenovo_attr_group_cptkbd);
}

882
static void lenovo_remove(struct hid_device *hdev)
883
{
884 885
	switch (hdev->product) {
	case USB_DEVICE_ID_LENOVO_TPKBD:
886
		lenovo_remove_tpkbd(hdev);
887
		break;
888 889 890 891
	case USB_DEVICE_ID_LENOVO_CUSBKBD:
	case USB_DEVICE_ID_LENOVO_CBTKBD:
		lenovo_remove_cptkbd(hdev);
		break;
892
	}
893 894 895 896

	hid_hw_stop(hdev);
}

897
static int lenovo_input_configured(struct hid_device *hdev,
898 899 900 901 902 903 904 905 906 907 908 909 910 911
		struct hid_input *hi)
{
	switch (hdev->product) {
		case USB_DEVICE_ID_LENOVO_TPKBD:
		case USB_DEVICE_ID_LENOVO_CUSBKBD:
		case USB_DEVICE_ID_LENOVO_CBTKBD:
			if (test_bit(EV_REL, hi->input->evbit)) {
				/* set only for trackpoint device */
				__set_bit(INPUT_PROP_POINTER, hi->input->propbit);
				__set_bit(INPUT_PROP_POINTING_STICK,
						hi->input->propbit);
			}
			break;
	}
912 913

	return 0;
914 915 916
}


917
static const struct hid_device_id lenovo_devices[] = {
918
	{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) },
919 920
	{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CUSBKBD) },
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CBTKBD) },
921
	{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPPRODOCK) },
922 923 924 925 926 927
	{ HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_III) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_PRO) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_OPTICAL) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL_PRO) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL) },
928 929 930
	{ }
};

931
MODULE_DEVICE_TABLE(hid, lenovo_devices);
932

933 934 935
static struct hid_driver lenovo_driver = {
	.name = "lenovo",
	.id_table = lenovo_devices,
936
	.input_configured = lenovo_input_configured,
937
	.input_mapping = lenovo_input_mapping,
938 939
	.probe = lenovo_probe,
	.remove = lenovo_remove,
940
	.raw_event = lenovo_raw_event,
941
	.event = lenovo_event,
942
	.report_fixup = lenovo_report_fixup,
943
};
944
module_hid_driver(lenovo_driver);
945 946

MODULE_LICENSE("GPL");