hid-lenovo.c 20.0 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 20 21 22 23 24 25 26
 */

/*
 * 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"

27
struct lenovo_drvdata_tpkbd {
28 29 30 31 32 33 34 35 36 37 38
	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;
};

39 40
struct lenovo_drvdata_cptkbd {
	bool fn_lock;
41
	int sensitivity;
42 43
};

44 45
#define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))

46
static int lenovo_input_mapping_tpkbd(struct hid_device *hdev,
47 48 49
		struct hid_input *hi, struct hid_field *field,
		struct hid_usage *usage, unsigned long **bit, int *max)
{
50
	if (usage->hid == (HID_UP_BUTTON | 0x0010)) {
51
		/* This sub-device contains trackpoint, mark it */
52
		hid_set_drvdata(hdev, (void *)1);
53 54 55 56 57 58
		map_key_clear(KEY_MICMUTE);
		return 1;
	}
	return 0;
}

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 87
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;
88
		case 0x00f9: /* Fn-F12: Open My computer (6 boxes) USB-only */
89 90 91
			/* NB: This mapping is invented in raw_event below */
			map_key_clear(KEY_FILE);
			return 1;
92 93 94
		case 0x00fa: /* Fn-Esc: Fn-lock toggle */
			map_key_clear(KEY_FN_ESC);
			return 1;
95 96 97 98 99 100
		}
	}

	return 0;
}

101 102 103 104 105 106 107 108
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);
109 110 111 112
	case USB_DEVICE_ID_LENOVO_CUSBKBD:
	case USB_DEVICE_ID_LENOVO_CBTKBD:
		return lenovo_input_mapping_cptkbd(hdev, hi, field,
							usage, bit, max);
113 114 115 116 117
	default:
		return 0;
	}
}

118 119
#undef map_key_clear

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
/* 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;
	unsigned char buf[] = {0x18, byte2, byte3};

	switch (hdev->product) {
	case USB_DEVICE_ID_LENOVO_CUSBKBD:
		ret = hid_hw_raw_request(hdev, 0x13, buf, sizeof(buf),
					HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
		break;
	case USB_DEVICE_ID_LENOVO_CBTKBD:
		ret = hid_hw_output_report(hdev, buf, sizeof(buf));
		break;
	default:
		ret = -EINVAL;
		break;
	}

	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);
149
	ret = lenovo_send_cmd_cptkbd(hdev, 0x02, cptkbd_data->sensitivity);
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
	if (ret)
		hid_err(hdev, "Fn-lock setting failed: %d\n", ret);
}

static ssize_t attr_fn_lock_show_cptkbd(struct device *dev,
		struct device_attribute *attr,
		char *buf)
{
	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
	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)
{
	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
	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;
}

184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
static ssize_t attr_sensitivity_show_cptkbd(struct device *dev,
		struct device_attribute *attr,
		char *buf)
{
	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
	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)
{
	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
	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;
}


214 215 216 217 218
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);

219 220 221 222 223 224
static struct device_attribute dev_attr_sensitivity_cptkbd =
	__ATTR(sensitivity, S_IWUSR | S_IRUGO,
			attr_sensitivity_show_cptkbd,
			attr_sensitivity_store_cptkbd);


225 226
static struct attribute *lenovo_attributes_cptkbd[] = {
	&dev_attr_fn_lock_cptkbd.attr,
227
	&dev_attr_sensitivity_cptkbd.attr,
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
	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)) {
248 249
		data[1] = 0x00;
		data[2] = 0x01;
250 251 252 253 254
	}

	return 0;
}

255
static int lenovo_features_set_tpkbd(struct hid_device *hdev)
256 257
{
	struct hid_report *report;
258
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
259 260 261 262 263 264 265 266 267 268 269

	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;

270
	hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
271 272 273
	return 0;
}

274
static ssize_t attr_press_to_select_show_tpkbd(struct device *dev,
275 276 277
		struct device_attribute *attr,
		char *buf)
{
278
	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
279
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
280 281 282 283

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

284
static ssize_t attr_press_to_select_store_tpkbd(struct device *dev,
285 286 287 288
		struct device_attribute *attr,
		const char *buf,
		size_t count)
{
289
	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
290
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
291 292 293 294 295 296 297 298
	int value;

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

	data_pointer->press_to_select = value;
299
	lenovo_features_set_tpkbd(hdev);
300 301 302 303

	return count;
}

304
static ssize_t attr_dragging_show_tpkbd(struct device *dev,
305 306 307
		struct device_attribute *attr,
		char *buf)
{
308
	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
309
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
310 311 312 313

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

314
static ssize_t attr_dragging_store_tpkbd(struct device *dev,
315 316 317 318
		struct device_attribute *attr,
		const char *buf,
		size_t count)
{
319
	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
320
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
321 322 323 324 325 326 327 328
	int value;

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

	data_pointer->dragging = value;
329
	lenovo_features_set_tpkbd(hdev);
330 331 332 333

	return count;
}

334
static ssize_t attr_release_to_select_show_tpkbd(struct device *dev,
335 336 337
		struct device_attribute *attr,
		char *buf)
{
338
	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
339
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
340 341 342 343

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

344
static ssize_t attr_release_to_select_store_tpkbd(struct device *dev,
345 346 347 348
		struct device_attribute *attr,
		const char *buf,
		size_t count)
{
349
	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
350
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
351 352 353 354 355 356 357 358
	int value;

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

	data_pointer->release_to_select = value;
359
	lenovo_features_set_tpkbd(hdev);
360 361 362 363

	return count;
}

364
static ssize_t attr_select_right_show_tpkbd(struct device *dev,
365 366 367
		struct device_attribute *attr,
		char *buf)
{
368
	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
369
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
370 371 372 373

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

374
static ssize_t attr_select_right_store_tpkbd(struct device *dev,
375 376 377 378
		struct device_attribute *attr,
		const char *buf,
		size_t count)
{
379
	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
380
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
381 382 383 384 385 386 387 388
	int value;

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

	data_pointer->select_right = value;
389
	lenovo_features_set_tpkbd(hdev);
390 391 392 393

	return count;
}

394
static ssize_t attr_sensitivity_show_tpkbd(struct device *dev,
395 396 397
		struct device_attribute *attr,
		char *buf)
{
398
	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
399
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
400 401 402 403 404

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

405
static ssize_t attr_sensitivity_store_tpkbd(struct device *dev,
406 407 408 409
		struct device_attribute *attr,
		const char *buf,
		size_t count)
{
410
	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
411
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
412 413 414 415 416 417
	int value;

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

	data_pointer->sensitivity = value;
418
	lenovo_features_set_tpkbd(hdev);
419 420 421 422

	return count;
}

423
static ssize_t attr_press_speed_show_tpkbd(struct device *dev,
424 425 426
		struct device_attribute *attr,
		char *buf)
{
427
	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
428
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
429 430 431 432 433

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

434
static ssize_t attr_press_speed_store_tpkbd(struct device *dev,
435 436 437 438
		struct device_attribute *attr,
		const char *buf,
		size_t count)
{
439
	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
440
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
441 442 443 444 445 446
	int value;

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

	data_pointer->press_speed = value;
447
	lenovo_features_set_tpkbd(hdev);
448 449 450 451

	return count;
}

452
static struct device_attribute dev_attr_press_to_select_tpkbd =
453
	__ATTR(press_to_select, S_IWUSR | S_IRUGO,
454 455
			attr_press_to_select_show_tpkbd,
			attr_press_to_select_store_tpkbd);
456

457
static struct device_attribute dev_attr_dragging_tpkbd =
458
	__ATTR(dragging, S_IWUSR | S_IRUGO,
459 460
			attr_dragging_show_tpkbd,
			attr_dragging_store_tpkbd);
461

462
static struct device_attribute dev_attr_release_to_select_tpkbd =
463
	__ATTR(release_to_select, S_IWUSR | S_IRUGO,
464 465
			attr_release_to_select_show_tpkbd,
			attr_release_to_select_store_tpkbd);
466

467
static struct device_attribute dev_attr_select_right_tpkbd =
468
	__ATTR(select_right, S_IWUSR | S_IRUGO,
469 470
			attr_select_right_show_tpkbd,
			attr_select_right_store_tpkbd);
471

472
static struct device_attribute dev_attr_sensitivity_tpkbd =
473
	__ATTR(sensitivity, S_IWUSR | S_IRUGO,
474 475
			attr_sensitivity_show_tpkbd,
			attr_sensitivity_store_tpkbd);
476

477
static struct device_attribute dev_attr_press_speed_tpkbd =
478
	__ATTR(press_speed, S_IWUSR | S_IRUGO,
479 480 481 482 483 484 485 486 487 488
			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,
489 490 491
	NULL
};

492 493
static const struct attribute_group lenovo_attr_group_tpkbd = {
	.attrs = lenovo_attributes_tpkbd,
494 495
};

496
static enum led_brightness lenovo_led_brightness_get_tpkbd(
497 498
			struct led_classdev *led_cdev)
{
499 500
	struct device *dev = led_cdev->dev->parent;
	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
501
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
502 503 504 505 506 507 508 509 510 511
	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;
}

512
static void lenovo_led_brightness_set_tpkbd(struct led_classdev *led_cdev,
513 514
			enum led_brightness value)
{
515 516
	struct device *dev = led_cdev->dev->parent;
	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
517
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
518 519 520 521 522 523 524 525 526 527 528 529 530 531
	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;
532
	hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
533 534
}

535
static int lenovo_probe_tpkbd(struct hid_device *hdev)
536 537
{
	struct device *dev = &hdev->dev;
538
	struct lenovo_drvdata_tpkbd *data_pointer;
539 540
	size_t name_sz = strlen(dev_name(dev)) + 16;
	char *name_mute, *name_micmute;
541
	int i;
542
	int ret;
543

544 545 546 547 548 549 550 551 552
	/*
	 * 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);

553 554 555 556 557 558 559
	/* 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;
560

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

565
	data_pointer = devm_kzalloc(&hdev->dev,
566
				    sizeof(struct lenovo_drvdata_tpkbd),
567
				    GFP_KERNEL);
568 569 570 571 572 573 574 575 576
	if (data_pointer == NULL) {
		hid_err(hdev, "Could not allocate memory for driver data\n");
		return -ENOMEM;
	}

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

577 578 579
	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) {
580
		hid_err(hdev, "Could not allocate memory for led data\n");
581
		return -ENOMEM;
582 583 584 585 586 587 588
	}
	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;
589 590
	data_pointer->led_mute.brightness_get = lenovo_led_brightness_get_tpkbd;
	data_pointer->led_mute.brightness_set = lenovo_led_brightness_set_tpkbd;
591 592 593 594
	data_pointer->led_mute.dev = dev;
	led_classdev_register(dev, &data_pointer->led_mute);

	data_pointer->led_micmute.name = name_micmute;
595 596 597 598
	data_pointer->led_micmute.brightness_get =
		lenovo_led_brightness_get_tpkbd;
	data_pointer->led_micmute.brightness_set =
		lenovo_led_brightness_set_tpkbd;
599 600 601
	data_pointer->led_micmute.dev = dev;
	led_classdev_register(dev, &data_pointer->led_micmute);

602
	lenovo_features_set_tpkbd(hdev);
603 604 605 606

	return 0;
}

607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
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);

636
	/* Set keyboard settings to known state */
637
	cptkbd_data->fn_lock = true;
638
	cptkbd_data->sensitivity = 0x05;
639 640 641 642 643 644 645 646 647
	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;
}

648
static int lenovo_probe(struct hid_device *hdev,
649 650 651 652 653 654 655
		const struct hid_device_id *id)
{
	int ret;

	ret = hid_parse(hdev);
	if (ret) {
		hid_err(hdev, "hid_parse failed\n");
656
		goto err;
657 658 659 660 661
	}

	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
	if (ret) {
		hid_err(hdev, "hid_hw_start failed\n");
662
		goto err;
663 664
	}

665 666
	switch (hdev->product) {
	case USB_DEVICE_ID_LENOVO_TPKBD:
667
		ret = lenovo_probe_tpkbd(hdev);
668
		break;
669 670 671 672
	case USB_DEVICE_ID_LENOVO_CUSBKBD:
	case USB_DEVICE_ID_LENOVO_CBTKBD:
		ret = lenovo_probe_cptkbd(hdev);
		break;
673 674 675
	default:
		ret = 0;
		break;
676
	}
677 678
	if (ret)
		goto err_hid;
679 680

	return 0;
681 682 683
err_hid:
	hid_hw_stop(hdev);
err:
684 685 686
	return ret;
}

687
static void lenovo_remove_tpkbd(struct hid_device *hdev)
688
{
689
	struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
690

691 692 693 694 695 696 697
	/*
	 * Only the trackpoint half of the keyboard has drvdata and stuff that
	 * needs unregistering.
	 */
	if (data_pointer == NULL)
		return;

698
	sysfs_remove_group(&hdev->dev.kobj,
699
			&lenovo_attr_group_tpkbd);
700 701 702 703 704 705 706

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

	hid_set_drvdata(hdev, NULL);
}

707 708 709 710 711 712
static void lenovo_remove_cptkbd(struct hid_device *hdev)
{
	sysfs_remove_group(&hdev->dev.kobj,
			&lenovo_attr_group_cptkbd);
}

713
static void lenovo_remove(struct hid_device *hdev)
714
{
715 716
	switch (hdev->product) {
	case USB_DEVICE_ID_LENOVO_TPKBD:
717
		lenovo_remove_tpkbd(hdev);
718
		break;
719 720 721 722
	case USB_DEVICE_ID_LENOVO_CUSBKBD:
	case USB_DEVICE_ID_LENOVO_CBTKBD:
		lenovo_remove_cptkbd(hdev);
		break;
723
	}
724 725 726 727

	hid_hw_stop(hdev);
}

728
static const struct hid_device_id lenovo_devices[] = {
729
	{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) },
730 731
	{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CUSBKBD) },
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CBTKBD) },
732 733 734
	{ }
};

735
MODULE_DEVICE_TABLE(hid, lenovo_devices);
736

737 738 739
static struct hid_driver lenovo_driver = {
	.name = "lenovo",
	.id_table = lenovo_devices,
740
	.input_mapping = lenovo_input_mapping,
741 742
	.probe = lenovo_probe,
	.remove = lenovo_remove,
743
	.raw_event = lenovo_raw_event,
744
};
745
module_hid_driver(lenovo_driver);
746 747

MODULE_LICENSE("GPL");