33
33
34
34
#include "hid-ids.h"
35
35
36
+ /* Userspace expects F20 for mic-mute KEY_MICMUTE does not work */
37
+ #define LENOVO_KEY_MICMUTE KEY_F20
38
+
36
39
struct lenovo_drvdata {
37
40
u8 led_report [3 ]; /* Must be first for proper alignment */
38
41
int led_state ;
@@ -62,8 +65,8 @@ struct lenovo_drvdata {
62
65
#define TP10UBKBD_LED_OFF 1
63
66
#define TP10UBKBD_LED_ON 2
64
67
65
- static void lenovo_led_set_tp10ubkbd (struct hid_device * hdev , u8 led_code ,
66
- enum led_brightness value )
68
+ static int lenovo_led_set_tp10ubkbd (struct hid_device * hdev , u8 led_code ,
69
+ enum led_brightness value )
67
70
{
68
71
struct lenovo_drvdata * data = hid_get_drvdata (hdev );
69
72
int ret ;
@@ -75,10 +78,18 @@ static void lenovo_led_set_tp10ubkbd(struct hid_device *hdev, u8 led_code,
75
78
data -> led_report [2 ] = value ? TP10UBKBD_LED_ON : TP10UBKBD_LED_OFF ;
76
79
ret = hid_hw_raw_request (hdev , data -> led_report [0 ], data -> led_report , 3 ,
77
80
HID_OUTPUT_REPORT , HID_REQ_SET_REPORT );
78
- if (ret )
79
- hid_err (hdev , "Set LED output report error: %d\n" , ret );
81
+ if (ret != 3 ) {
82
+ if (ret != - ENODEV )
83
+ hid_err (hdev , "Set LED output report error: %d\n" , ret );
84
+
85
+ ret = ret < 0 ? ret : - EIO ;
86
+ } else {
87
+ ret = 0 ;
88
+ }
80
89
81
90
mutex_unlock (& data -> led_report_mutex );
91
+
92
+ return ret ;
82
93
}
83
94
84
95
static void lenovo_tp10ubkbd_sync_fn_lock (struct work_struct * work )
@@ -126,7 +137,7 @@ static int lenovo_input_mapping_tpkbd(struct hid_device *hdev,
126
137
if (usage -> hid == (HID_UP_BUTTON | 0x0010 )) {
127
138
/* This sub-device contains trackpoint, mark it */
128
139
hid_set_drvdata (hdev , (void * )1 );
129
- map_key_clear (KEY_MICMUTE );
140
+ map_key_clear (LENOVO_KEY_MICMUTE );
130
141
return 1 ;
131
142
}
132
143
return 0 ;
@@ -141,7 +152,7 @@ static int lenovo_input_mapping_cptkbd(struct hid_device *hdev,
141
152
(usage -> hid & HID_USAGE_PAGE ) == HID_UP_LNVENDOR ) {
142
153
switch (usage -> hid & HID_USAGE ) {
143
154
case 0x00f1 : /* Fn-F4: Mic mute */
144
- map_key_clear (KEY_MICMUTE );
155
+ map_key_clear (LENOVO_KEY_MICMUTE );
145
156
return 1 ;
146
157
case 0x00f2 : /* Fn-F5: Brightness down */
147
158
map_key_clear (KEY_BRIGHTNESSDOWN );
@@ -231,7 +242,7 @@ static int lenovo_input_mapping_tp10_ultrabook_kbd(struct hid_device *hdev,
231
242
map_key_clear (KEY_FN_ESC );
232
243
return 1 ;
233
244
case 9 : /* Fn-F4: Mic mute */
234
- map_key_clear (KEY_MICMUTE );
245
+ map_key_clear (LENOVO_KEY_MICMUTE );
235
246
return 1 ;
236
247
case 10 : /* Fn-F7: Control panel */
237
248
map_key_clear (KEY_CONFIG );
@@ -255,6 +266,54 @@ static int lenovo_input_mapping_tp10_ultrabook_kbd(struct hid_device *hdev,
255
266
return 0 ;
256
267
}
257
268
269
+ static int lenovo_input_mapping_x1_tab_kbd (struct hid_device * hdev ,
270
+ struct hid_input * hi , struct hid_field * field ,
271
+ struct hid_usage * usage , unsigned long * * bit , int * max )
272
+ {
273
+ /*
274
+ * The ThinkPad X1 Tablet Thin Keyboard uses 0x000c0001 usage for
275
+ * a bunch of keys which have no standard consumer page code.
276
+ */
277
+ if (usage -> hid == 0x000c0001 ) {
278
+ switch (usage -> usage_index ) {
279
+ case 0 : /* Fn-F10: Enable/disable bluetooth */
280
+ map_key_clear (KEY_BLUETOOTH );
281
+ return 1 ;
282
+ case 1 : /* Fn-F11: Keyboard settings */
283
+ map_key_clear (KEY_KEYBOARD );
284
+ return 1 ;
285
+ case 2 : /* Fn-F12: User function / Cortana */
286
+ map_key_clear (KEY_MACRO1 );
287
+ return 1 ;
288
+ case 3 : /* Fn-PrtSc: Snipping tool */
289
+ map_key_clear (KEY_SELECTIVE_SCREENSHOT );
290
+ return 1 ;
291
+ case 8 : /* Fn-Esc: Fn-lock toggle */
292
+ map_key_clear (KEY_FN_ESC );
293
+ return 1 ;
294
+ case 9 : /* Fn-F4: Mute/unmute microphone */
295
+ map_key_clear (KEY_MICMUTE );
296
+ return 1 ;
297
+ case 10 : /* Fn-F9: Settings */
298
+ map_key_clear (KEY_CONFIG );
299
+ return 1 ;
300
+ case 13 : /* Fn-F7: Manage external displays */
301
+ map_key_clear (KEY_SWITCHVIDEOMODE );
302
+ return 1 ;
303
+ case 14 : /* Fn-F8: Enable/disable wifi */
304
+ map_key_clear (KEY_WLAN );
305
+ return 1 ;
306
+ }
307
+ }
308
+
309
+ if (usage -> hid == (HID_UP_KEYBOARD | 0x009a )) {
310
+ map_key_clear (KEY_SYSRQ );
311
+ return 1 ;
312
+ }
313
+
314
+ return 0 ;
315
+ }
316
+
258
317
static int lenovo_input_mapping (struct hid_device * hdev ,
259
318
struct hid_input * hi , struct hid_field * field ,
260
319
struct hid_usage * usage , unsigned long * * bit , int * max )
@@ -278,6 +337,8 @@ static int lenovo_input_mapping(struct hid_device *hdev,
278
337
case USB_DEVICE_ID_LENOVO_TP10UBKBD :
279
338
return lenovo_input_mapping_tp10_ultrabook_kbd (hdev , hi , field ,
280
339
usage , bit , max );
340
+ case USB_DEVICE_ID_LENOVO_X1_TAB :
341
+ return lenovo_input_mapping_x1_tab_kbd (hdev , hi , field , usage , bit , max );
281
342
default :
282
343
return 0 ;
283
344
}
@@ -349,7 +410,7 @@ static ssize_t attr_fn_lock_store(struct device *dev,
349
410
{
350
411
struct hid_device * hdev = to_hid_device (dev );
351
412
struct lenovo_drvdata * data = hid_get_drvdata (hdev );
352
- int value ;
413
+ int value , ret ;
353
414
354
415
if (kstrtoint (buf , 10 , & value ))
355
416
return - EINVAL ;
@@ -364,7 +425,10 @@ static ssize_t attr_fn_lock_store(struct device *dev,
364
425
lenovo_features_set_cptkbd (hdev );
365
426
break ;
366
427
case USB_DEVICE_ID_LENOVO_TP10UBKBD :
367
- lenovo_led_set_tp10ubkbd (hdev , TP10UBKBD_FN_LOCK_LED , value );
428
+ case USB_DEVICE_ID_LENOVO_X1_TAB :
429
+ ret = lenovo_led_set_tp10ubkbd (hdev , TP10UBKBD_FN_LOCK_LED , value );
430
+ if (ret )
431
+ return ret ;
368
432
break ;
369
433
}
370
434
@@ -498,11 +562,15 @@ static int lenovo_event_cptkbd(struct hid_device *hdev,
498
562
static int lenovo_event (struct hid_device * hdev , struct hid_field * field ,
499
563
struct hid_usage * usage , __s32 value )
500
564
{
565
+ if (!hid_get_drvdata (hdev ))
566
+ return 0 ;
567
+
501
568
switch (hdev -> product ) {
502
569
case USB_DEVICE_ID_LENOVO_CUSBKBD :
503
570
case USB_DEVICE_ID_LENOVO_CBTKBD :
504
571
return lenovo_event_cptkbd (hdev , field , usage , value );
505
572
case USB_DEVICE_ID_LENOVO_TP10UBKBD :
573
+ case USB_DEVICE_ID_LENOVO_X1_TAB :
506
574
return lenovo_event_tp10ubkbd (hdev , field , usage , value );
507
575
default :
508
576
return 0 ;
@@ -761,30 +829,15 @@ static void lenovo_led_set_tpkbd(struct hid_device *hdev)
761
829
hid_hw_request (hdev , report , HID_REQ_SET_REPORT );
762
830
}
763
831
764
- static enum led_brightness lenovo_led_brightness_get (
765
- struct led_classdev * led_cdev )
766
- {
767
- struct device * dev = led_cdev -> dev -> parent ;
768
- struct hid_device * hdev = to_hid_device (dev );
769
- struct lenovo_drvdata * data_pointer = hid_get_drvdata (hdev );
770
- int led_nr = 0 ;
771
-
772
- if (led_cdev == & data_pointer -> led_micmute )
773
- led_nr = 1 ;
774
-
775
- return data_pointer -> led_state & (1 << led_nr )
776
- ? LED_FULL
777
- : LED_OFF ;
778
- }
779
-
780
- static void lenovo_led_brightness_set (struct led_classdev * led_cdev ,
832
+ static int lenovo_led_brightness_set (struct led_classdev * led_cdev ,
781
833
enum led_brightness value )
782
834
{
783
835
struct device * dev = led_cdev -> dev -> parent ;
784
836
struct hid_device * hdev = to_hid_device (dev );
785
837
struct lenovo_drvdata * data_pointer = hid_get_drvdata (hdev );
786
838
u8 tp10ubkbd_led [] = { TP10UBKBD_MUTE_LED , TP10UBKBD_MICMUTE_LED };
787
839
int led_nr = 0 ;
840
+ int ret = 0 ;
788
841
789
842
if (led_cdev == & data_pointer -> led_micmute )
790
843
led_nr = 1 ;
@@ -799,9 +852,12 @@ static void lenovo_led_brightness_set(struct led_classdev *led_cdev,
799
852
lenovo_led_set_tpkbd (hdev );
800
853
break ;
801
854
case USB_DEVICE_ID_LENOVO_TP10UBKBD :
802
- lenovo_led_set_tp10ubkbd (hdev , tp10ubkbd_led [led_nr ], value );
855
+ case USB_DEVICE_ID_LENOVO_X1_TAB :
856
+ ret = lenovo_led_set_tp10ubkbd (hdev , tp10ubkbd_led [led_nr ], value );
803
857
break ;
804
858
}
859
+
860
+ return ret ;
805
861
}
806
862
807
863
static int lenovo_register_leds (struct hid_device * hdev )
@@ -821,16 +877,20 @@ static int lenovo_register_leds(struct hid_device *hdev)
821
877
snprintf (name_micm , name_sz , "%s:amber:micmute" , dev_name (& hdev -> dev ));
822
878
823
879
data -> led_mute .name = name_mute ;
824
- data -> led_mute .brightness_get = lenovo_led_brightness_get ;
825
- data -> led_mute .brightness_set = lenovo_led_brightness_set ;
880
+ data -> led_mute .default_trigger = "audio-mute" ;
881
+ data -> led_mute .brightness_set_blocking = lenovo_led_brightness_set ;
882
+ data -> led_mute .max_brightness = 1 ;
883
+ data -> led_mute .flags = LED_HW_PLUGGABLE ;
826
884
data -> led_mute .dev = & hdev -> dev ;
827
885
ret = led_classdev_register (& hdev -> dev , & data -> led_mute );
828
886
if (ret < 0 )
829
887
return ret ;
830
888
831
889
data -> led_micmute .name = name_micm ;
832
- data -> led_micmute .brightness_get = lenovo_led_brightness_get ;
833
- data -> led_micmute .brightness_set = lenovo_led_brightness_set ;
890
+ data -> led_micmute .default_trigger = "audio-micmute" ;
891
+ data -> led_micmute .brightness_set_blocking = lenovo_led_brightness_set ;
892
+ data -> led_micmute .max_brightness = 1 ;
893
+ data -> led_micmute .flags = LED_HW_PLUGGABLE ;
834
894
data -> led_micmute .dev = & hdev -> dev ;
835
895
ret = led_classdev_register (& hdev -> dev , & data -> led_micmute );
836
896
if (ret < 0 ) {
@@ -952,11 +1012,24 @@ static const struct attribute_group lenovo_attr_group_tp10ubkbd = {
952
1012
953
1013
static int lenovo_probe_tp10ubkbd (struct hid_device * hdev )
954
1014
{
1015
+ struct hid_report_enum * rep_enum ;
955
1016
struct lenovo_drvdata * data ;
1017
+ struct hid_report * rep ;
1018
+ bool found ;
956
1019
int ret ;
957
1020
958
- /* All the custom action happens on the USBMOUSE device for USB */
959
- if (hdev -> type != HID_TYPE_USBMOUSE )
1021
+ /*
1022
+ * The LEDs and the Fn-lock functionality use output report 9,
1023
+ * with an application of 0xffa0001, add the LEDs on the interface
1024
+ * with this output report.
1025
+ */
1026
+ found = false;
1027
+ rep_enum = & hdev -> report_enum [HID_OUTPUT_REPORT ];
1028
+ list_for_each_entry (rep , & rep_enum -> report_list , list ) {
1029
+ if (rep -> application == 0xffa00001 )
1030
+ found = true;
1031
+ }
1032
+ if (!found )
960
1033
return 0 ;
961
1034
962
1035
data = devm_kzalloc (& hdev -> dev , sizeof (* data ), GFP_KERNEL );
@@ -1018,6 +1091,7 @@ static int lenovo_probe(struct hid_device *hdev,
1018
1091
ret = lenovo_probe_cptkbd (hdev );
1019
1092
break ;
1020
1093
case USB_DEVICE_ID_LENOVO_TP10UBKBD :
1094
+ case USB_DEVICE_ID_LENOVO_X1_TAB :
1021
1095
ret = lenovo_probe_tp10ubkbd (hdev );
1022
1096
break ;
1023
1097
default :
@@ -1083,6 +1157,7 @@ static void lenovo_remove(struct hid_device *hdev)
1083
1157
lenovo_remove_cptkbd (hdev );
1084
1158
break ;
1085
1159
case USB_DEVICE_ID_LENOVO_TP10UBKBD :
1160
+ case USB_DEVICE_ID_LENOVO_X1_TAB :
1086
1161
lenovo_remove_tp10ubkbd (hdev );
1087
1162
break ;
1088
1163
}
@@ -1122,6 +1197,12 @@ static const struct hid_device_id lenovo_devices[] = {
1122
1197
{ HID_USB_DEVICE (USB_VENDOR_ID_IBM , USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL_PRO ) },
1123
1198
{ HID_USB_DEVICE (USB_VENDOR_ID_LENOVO , USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL ) },
1124
1199
{ HID_USB_DEVICE (USB_VENDOR_ID_LENOVO , USB_DEVICE_ID_LENOVO_TP10UBKBD ) },
1200
+ /*
1201
+ * Note bind to the HID_GROUP_GENERIC group, so that we only bind to the keyboard
1202
+ * part, while letting hid-multitouch.c handle the touchpad and trackpoint.
1203
+ */
1204
+ { HID_DEVICE (BUS_USB , HID_GROUP_GENERIC ,
1205
+ USB_VENDOR_ID_LENOVO , USB_DEVICE_ID_LENOVO_X1_TAB ) },
1125
1206
{ }
1126
1207
};
1127
1208
0 commit comments