Skip to content

Commit bc04b37

Browse files
jwrdegoedeJiri Kosina
authored andcommitted
HID: lenovo: Add ThinkPad 10 Ultrabook Keyboard support
Some of the function keys special functions all use the same 0x000c0001 usage code, add a mapping for these based on the usage_index; And add support for the Speaker and Mic mute LEDs integrated into the F1 and F4 keys. Signed-off-by: Hans de Goede <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent ef550c5 commit bc04b37

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

drivers/hid/hid-ids.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,7 @@
723723
#define USB_DEVICE_ID_LENOVO_CUSBKBD 0x6047
724724
#define USB_DEVICE_ID_LENOVO_CBTKBD 0x6048
725725
#define USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL 0x6049
726+
#define USB_DEVICE_ID_LENOVO_TP10UBKBD 0x6062
726727
#define USB_DEVICE_ID_LENOVO_TPPRODOCK 0x6067
727728
#define USB_DEVICE_ID_LENOVO_X1_COVER 0x6085
728729
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D 0x608d

drivers/hid/hid-lenovo.c

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@
3333
#include "hid-ids.h"
3434

3535
struct lenovo_drvdata {
36+
u8 led_report[3]; /* Must be first for proper alignment */
3637
int led_state;
38+
struct mutex led_report_mutex;
3739
struct led_classdev led_mute;
3840
struct led_classdev led_micmute;
3941
int press_to_select;
@@ -48,6 +50,34 @@ struct lenovo_drvdata {
4850

4951
#define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
5052

53+
#define TP10UBKBD_LED_OUTPUT_REPORT 9
54+
55+
#define TP10UBKBD_FN_LOCK_LED 0x54
56+
#define TP10UBKBD_MUTE_LED 0x64
57+
#define TP10UBKBD_MICMUTE_LED 0x74
58+
59+
#define TP10UBKBD_LED_OFF 1
60+
#define TP10UBKBD_LED_ON 2
61+
62+
static void lenovo_led_set_tp10ubkbd(struct hid_device *hdev, u8 led_code,
63+
enum led_brightness value)
64+
{
65+
struct lenovo_drvdata *data = hid_get_drvdata(hdev);
66+
int ret;
67+
68+
mutex_lock(&data->led_report_mutex);
69+
70+
data->led_report[0] = TP10UBKBD_LED_OUTPUT_REPORT;
71+
data->led_report[1] = led_code;
72+
data->led_report[2] = value ? TP10UBKBD_LED_ON : TP10UBKBD_LED_OFF;
73+
ret = hid_hw_raw_request(hdev, data->led_report[0], data->led_report, 3,
74+
HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
75+
if (ret)
76+
hid_err(hdev, "Set LED output report error: %d\n", ret);
77+
78+
mutex_unlock(&data->led_report_mutex);
79+
}
80+
5181
static const __u8 lenovo_pro_dock_need_fixup_collection[] = {
5282
0x05, 0x88, /* Usage Page (Vendor Usage Page 0x88) */
5383
0x09, 0x01, /* Usage (Vendor Usage 0x01) */
@@ -175,6 +205,37 @@ static int lenovo_input_mapping_scrollpoint(struct hid_device *hdev,
175205
return 0;
176206
}
177207

208+
static int lenovo_input_mapping_tp10_ultrabook_kbd(struct hid_device *hdev,
209+
struct hid_input *hi, struct hid_field *field,
210+
struct hid_usage *usage, unsigned long **bit, int *max)
211+
{
212+
/*
213+
* The ThinkPad 10 Ultrabook Keyboard uses 0x000c0001 usage for
214+
* a bunch of keys which have no standard consumer page code.
215+
*/
216+
if (usage->hid == 0x000c0001) {
217+
switch (usage->usage_index) {
218+
case 8: /* Fn-Esc: Fn-lock toggle */
219+
map_key_clear(KEY_FN_ESC);
220+
return 1;
221+
case 9: /* Fn-F4: Mic mute */
222+
map_key_clear(KEY_MICMUTE);
223+
return 1;
224+
case 10: /* Fn-F7: Control panel */
225+
map_key_clear(KEY_CONFIG);
226+
return 1;
227+
case 11: /* Fn-F8: Search (magnifier glass) */
228+
map_key_clear(KEY_SEARCH);
229+
return 1;
230+
case 12: /* Fn-F10: Open My computer (6 boxes) */
231+
map_key_clear(KEY_FILE);
232+
return 1;
233+
}
234+
}
235+
236+
return 0;
237+
}
238+
178239
static int lenovo_input_mapping(struct hid_device *hdev,
179240
struct hid_input *hi, struct hid_field *field,
180241
struct hid_usage *usage, unsigned long **bit, int *max)
@@ -195,6 +256,9 @@ static int lenovo_input_mapping(struct hid_device *hdev,
195256
case USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL:
196257
return lenovo_input_mapping_scrollpoint(hdev, hi, field,
197258
usage, bit, max);
259+
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
260+
return lenovo_input_mapping_tp10_ultrabook_kbd(hdev, hi, field,
261+
usage, bit, max);
198262
default:
199263
return 0;
200264
}
@@ -677,6 +741,7 @@ static void lenovo_led_brightness_set(struct led_classdev *led_cdev,
677741
struct device *dev = led_cdev->dev->parent;
678742
struct hid_device *hdev = to_hid_device(dev);
679743
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
744+
u8 tp10ubkbd_led[] = { TP10UBKBD_MUTE_LED, TP10UBKBD_MICMUTE_LED };
680745
int led_nr = 0;
681746

682747
if (led_cdev == &data_pointer->led_micmute)
@@ -691,6 +756,9 @@ static void lenovo_led_brightness_set(struct led_classdev *led_cdev,
691756
case USB_DEVICE_ID_LENOVO_TPKBD:
692757
lenovo_led_set_tpkbd(hdev);
693758
break;
759+
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
760+
lenovo_led_set_tp10ubkbd(hdev, tp10ubkbd_led[led_nr], value);
761+
break;
694762
}
695763
}
696764

@@ -831,6 +899,25 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev)
831899
return 0;
832900
}
833901

902+
static int lenovo_probe_tp10ubkbd(struct hid_device *hdev)
903+
{
904+
struct lenovo_drvdata *data;
905+
906+
/* All the custom action happens on the USBMOUSE device for USB */
907+
if (hdev->type != HID_TYPE_USBMOUSE)
908+
return 0;
909+
910+
data = devm_kzalloc(&hdev->dev, sizeof(*data), GFP_KERNEL);
911+
if (!data)
912+
return -ENOMEM;
913+
914+
mutex_init(&data->led_report_mutex);
915+
916+
hid_set_drvdata(hdev, data);
917+
918+
return lenovo_register_leds(hdev);
919+
}
920+
834921
static int lenovo_probe(struct hid_device *hdev,
835922
const struct hid_device_id *id)
836923
{
@@ -856,6 +943,9 @@ static int lenovo_probe(struct hid_device *hdev,
856943
case USB_DEVICE_ID_LENOVO_CBTKBD:
857944
ret = lenovo_probe_cptkbd(hdev);
858945
break;
946+
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
947+
ret = lenovo_probe_tp10ubkbd(hdev);
948+
break;
859949
default:
860950
ret = 0;
861951
break;
@@ -894,6 +984,17 @@ static void lenovo_remove_cptkbd(struct hid_device *hdev)
894984
&lenovo_attr_group_cptkbd);
895985
}
896986

987+
static void lenovo_remove_tp10ubkbd(struct hid_device *hdev)
988+
{
989+
struct lenovo_drvdata *data = hid_get_drvdata(hdev);
990+
991+
if (data == NULL)
992+
return;
993+
994+
led_classdev_unregister(&data->led_micmute);
995+
led_classdev_unregister(&data->led_mute);
996+
}
997+
897998
static void lenovo_remove(struct hid_device *hdev)
898999
{
8991000
switch (hdev->product) {
@@ -904,6 +1005,9 @@ static void lenovo_remove(struct hid_device *hdev)
9041005
case USB_DEVICE_ID_LENOVO_CBTKBD:
9051006
lenovo_remove_cptkbd(hdev);
9061007
break;
1008+
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
1009+
lenovo_remove_tp10ubkbd(hdev);
1010+
break;
9071011
}
9081012

9091013
hid_hw_stop(hdev);
@@ -940,6 +1044,7 @@ static const struct hid_device_id lenovo_devices[] = {
9401044
{ HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL) },
9411045
{ HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL_PRO) },
9421046
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL) },
1047+
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TP10UBKBD) },
9431048
{ }
9441049
};
9451050

0 commit comments

Comments
 (0)