diff options
Diffstat (limited to 'drivers/hid/hid-lenovo.c')
-rw-r--r-- | drivers/hid/hid-lenovo.c | 53 |
1 files changed, 45 insertions, 8 deletions
diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index 0320b96ddf24..a56b9e7413ce 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * HID driver for Lenovo ThinkPad USB Keyboard with TrackPoint | 2 | * HID driver for Lenovo: |
3 | * - ThinkPad USB Keyboard with TrackPoint (tpkbd) | ||
3 | * | 4 | * |
4 | * Copyright (c) 2012 Bernhard Seibold | 5 | * Copyright (c) 2012 Bernhard Seibold |
5 | */ | 6 | */ |
@@ -39,7 +40,7 @@ static int lenovo_input_mapping_tpkbd(struct hid_device *hdev, | |||
39 | struct hid_usage *usage, unsigned long **bit, int *max) | 40 | struct hid_usage *usage, unsigned long **bit, int *max) |
40 | { | 41 | { |
41 | if (usage->hid == (HID_UP_BUTTON | 0x0010)) { | 42 | if (usage->hid == (HID_UP_BUTTON | 0x0010)) { |
42 | /* mark the device as pointer */ | 43 | /* This sub-device contains trackpoint, mark it */ |
43 | hid_set_drvdata(hdev, (void *)1); | 44 | hid_set_drvdata(hdev, (void *)1); |
44 | map_key_clear(KEY_MICMUTE); | 45 | map_key_clear(KEY_MICMUTE); |
45 | return 1; | 46 | return 1; |
@@ -47,6 +48,19 @@ static int lenovo_input_mapping_tpkbd(struct hid_device *hdev, | |||
47 | return 0; | 48 | return 0; |
48 | } | 49 | } |
49 | 50 | ||
51 | static int lenovo_input_mapping(struct hid_device *hdev, | ||
52 | struct hid_input *hi, struct hid_field *field, | ||
53 | struct hid_usage *usage, unsigned long **bit, int *max) | ||
54 | { | ||
55 | switch (hdev->product) { | ||
56 | case USB_DEVICE_ID_LENOVO_TPKBD: | ||
57 | return lenovo_input_mapping_tpkbd(hdev, hi, field, | ||
58 | usage, bit, max); | ||
59 | default: | ||
60 | return 0; | ||
61 | } | ||
62 | } | ||
63 | |||
50 | #undef map_key_clear | 64 | #undef map_key_clear |
51 | 65 | ||
52 | static int lenovo_features_set_tpkbd(struct hid_device *hdev) | 66 | static int lenovo_features_set_tpkbd(struct hid_device *hdev) |
@@ -337,6 +351,15 @@ static int lenovo_probe_tpkbd(struct hid_device *hdev) | |||
337 | char *name_mute, *name_micmute; | 351 | char *name_mute, *name_micmute; |
338 | int i; | 352 | int i; |
339 | 353 | ||
354 | /* | ||
355 | * Only register extra settings against subdevice where input_mapping | ||
356 | * set drvdata to 1, i.e. the trackpoint. | ||
357 | */ | ||
358 | if (!hid_get_drvdata(hdev)) | ||
359 | return 0; | ||
360 | |||
361 | hid_set_drvdata(hdev, NULL); | ||
362 | |||
340 | /* Validate required reports. */ | 363 | /* Validate required reports. */ |
341 | for (i = 0; i < 4; i++) { | 364 | for (i = 0; i < 4; i++) { |
342 | if (!hid_validate_values(hdev, HID_FEATURE_REPORT, 4, i, 1)) | 365 | if (!hid_validate_values(hdev, HID_FEATURE_REPORT, 4, i, 1)) |
@@ -409,12 +432,16 @@ static int lenovo_probe(struct hid_device *hdev, | |||
409 | goto err; | 432 | goto err; |
410 | } | 433 | } |
411 | 434 | ||
412 | if (hid_get_drvdata(hdev)) { | 435 | switch (hdev->product) { |
413 | hid_set_drvdata(hdev, NULL); | 436 | case USB_DEVICE_ID_LENOVO_TPKBD: |
414 | ret = lenovo_probe_tpkbd(hdev); | 437 | ret = lenovo_probe_tpkbd(hdev); |
415 | if (ret) | 438 | break; |
416 | goto err_hid; | 439 | default: |
440 | ret = 0; | ||
441 | break; | ||
417 | } | 442 | } |
443 | if (ret) | ||
444 | goto err_hid; | ||
418 | 445 | ||
419 | return 0; | 446 | return 0; |
420 | err_hid: | 447 | err_hid: |
@@ -427,6 +454,13 @@ static void lenovo_remove_tpkbd(struct hid_device *hdev) | |||
427 | { | 454 | { |
428 | struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); | 455 | struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); |
429 | 456 | ||
457 | /* | ||
458 | * Only the trackpoint half of the keyboard has drvdata and stuff that | ||
459 | * needs unregistering. | ||
460 | */ | ||
461 | if (data_pointer == NULL) | ||
462 | return; | ||
463 | |||
430 | sysfs_remove_group(&hdev->dev.kobj, | 464 | sysfs_remove_group(&hdev->dev.kobj, |
431 | &lenovo_attr_group_tpkbd); | 465 | &lenovo_attr_group_tpkbd); |
432 | 466 | ||
@@ -438,8 +472,11 @@ static void lenovo_remove_tpkbd(struct hid_device *hdev) | |||
438 | 472 | ||
439 | static void lenovo_remove(struct hid_device *hdev) | 473 | static void lenovo_remove(struct hid_device *hdev) |
440 | { | 474 | { |
441 | if (hid_get_drvdata(hdev)) | 475 | switch (hdev->product) { |
476 | case USB_DEVICE_ID_LENOVO_TPKBD: | ||
442 | lenovo_remove_tpkbd(hdev); | 477 | lenovo_remove_tpkbd(hdev); |
478 | break; | ||
479 | } | ||
443 | 480 | ||
444 | hid_hw_stop(hdev); | 481 | hid_hw_stop(hdev); |
445 | } | 482 | } |
@@ -454,7 +491,7 @@ MODULE_DEVICE_TABLE(hid, lenovo_devices); | |||
454 | static struct hid_driver lenovo_driver = { | 491 | static struct hid_driver lenovo_driver = { |
455 | .name = "lenovo", | 492 | .name = "lenovo", |
456 | .id_table = lenovo_devices, | 493 | .id_table = lenovo_devices, |
457 | .input_mapping = lenovo_input_mapping_tpkbd, | 494 | .input_mapping = lenovo_input_mapping, |
458 | .probe = lenovo_probe, | 495 | .probe = lenovo_probe, |
459 | .remove = lenovo_remove, | 496 | .remove = lenovo_remove, |
460 | }; | 497 | }; |