3333
3434#include "hid-ids.h"
3535
36+ /* Userspace expects F20 for mic-mute KEY_MICMUTE does not work */
37+ #define LENOVO_KEY_MICMUTE KEY_F20
38+
3639struct lenovo_drvdata {
3740 u8 led_report [3 ]; /* Must be first for proper alignment */
3841 int led_state ;
@@ -62,8 +65,8 @@ struct lenovo_drvdata {
6265#define TP10UBKBD_LED_OFF 1
6366#define TP10UBKBD_LED_ON 2
6467
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 )
6770{
6871 struct lenovo_drvdata * data = hid_get_drvdata (hdev );
6972 int ret ;
@@ -75,10 +78,18 @@ static void lenovo_led_set_tp10ubkbd(struct hid_device *hdev, u8 led_code,
7578 data -> led_report [2 ] = value ? TP10UBKBD_LED_ON : TP10UBKBD_LED_OFF ;
7679 ret = hid_hw_raw_request (hdev , data -> led_report [0 ], data -> led_report , 3 ,
7780 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+ }
8089
8190 mutex_unlock (& data -> led_report_mutex );
91+
92+ return ret ;
8293}
8394
8495static void lenovo_tp10ubkbd_sync_fn_lock (struct work_struct * work )
@@ -126,7 +137,7 @@ static int lenovo_input_mapping_tpkbd(struct hid_device *hdev,
126137 if (usage -> hid == (HID_UP_BUTTON | 0x0010 )) {
127138 /* This sub-device contains trackpoint, mark it */
128139 hid_set_drvdata (hdev , (void * )1 );
129- map_key_clear (KEY_MICMUTE );
140+ map_key_clear (LENOVO_KEY_MICMUTE );
130141 return 1 ;
131142 }
132143 return 0 ;
@@ -141,7 +152,7 @@ static int lenovo_input_mapping_cptkbd(struct hid_device *hdev,
141152 (usage -> hid & HID_USAGE_PAGE ) == HID_UP_LNVENDOR ) {
142153 switch (usage -> hid & HID_USAGE ) {
143154 case 0x00f1 : /* Fn-F4: Mic mute */
144- map_key_clear (KEY_MICMUTE );
155+ map_key_clear (LENOVO_KEY_MICMUTE );
145156 return 1 ;
146157 case 0x00f2 : /* Fn-F5: Brightness down */
147158 map_key_clear (KEY_BRIGHTNESSDOWN );
@@ -231,7 +242,7 @@ static int lenovo_input_mapping_tp10_ultrabook_kbd(struct hid_device *hdev,
231242 map_key_clear (KEY_FN_ESC );
232243 return 1 ;
233244 case 9 : /* Fn-F4: Mic mute */
234- map_key_clear (KEY_MICMUTE );
245+ map_key_clear (LENOVO_KEY_MICMUTE );
235246 return 1 ;
236247 case 10 : /* Fn-F7: Control panel */
237248 map_key_clear (KEY_CONFIG );
@@ -255,6 +266,54 @@ static int lenovo_input_mapping_tp10_ultrabook_kbd(struct hid_device *hdev,
255266 return 0 ;
256267}
257268
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+
258317static int lenovo_input_mapping (struct hid_device * hdev ,
259318 struct hid_input * hi , struct hid_field * field ,
260319 struct hid_usage * usage , unsigned long * * bit , int * max )
@@ -278,6 +337,8 @@ static int lenovo_input_mapping(struct hid_device *hdev,
278337 case USB_DEVICE_ID_LENOVO_TP10UBKBD :
279338 return lenovo_input_mapping_tp10_ultrabook_kbd (hdev , hi , field ,
280339 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 );
281342 default :
282343 return 0 ;
283344 }
@@ -349,7 +410,7 @@ static ssize_t attr_fn_lock_store(struct device *dev,
349410{
350411 struct hid_device * hdev = to_hid_device (dev );
351412 struct lenovo_drvdata * data = hid_get_drvdata (hdev );
352- int value ;
413+ int value , ret ;
353414
354415 if (kstrtoint (buf , 10 , & value ))
355416 return - EINVAL ;
@@ -364,7 +425,10 @@ static ssize_t attr_fn_lock_store(struct device *dev,
364425 lenovo_features_set_cptkbd (hdev );
365426 break ;
366427 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 ;
368432 break ;
369433 }
370434
@@ -498,11 +562,15 @@ static int lenovo_event_cptkbd(struct hid_device *hdev,
498562static int lenovo_event (struct hid_device * hdev , struct hid_field * field ,
499563 struct hid_usage * usage , __s32 value )
500564{
565+ if (!hid_get_drvdata (hdev ))
566+ return 0 ;
567+
501568 switch (hdev -> product ) {
502569 case USB_DEVICE_ID_LENOVO_CUSBKBD :
503570 case USB_DEVICE_ID_LENOVO_CBTKBD :
504571 return lenovo_event_cptkbd (hdev , field , usage , value );
505572 case USB_DEVICE_ID_LENOVO_TP10UBKBD :
573+ case USB_DEVICE_ID_LENOVO_X1_TAB :
506574 return lenovo_event_tp10ubkbd (hdev , field , usage , value );
507575 default :
508576 return 0 ;
@@ -761,30 +829,15 @@ static void lenovo_led_set_tpkbd(struct hid_device *hdev)
761829 hid_hw_request (hdev , report , HID_REQ_SET_REPORT );
762830}
763831
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 ,
781833 enum led_brightness value )
782834{
783835 struct device * dev = led_cdev -> dev -> parent ;
784836 struct hid_device * hdev = to_hid_device (dev );
785837 struct lenovo_drvdata * data_pointer = hid_get_drvdata (hdev );
786838 u8 tp10ubkbd_led [] = { TP10UBKBD_MUTE_LED , TP10UBKBD_MICMUTE_LED };
787839 int led_nr = 0 ;
840+ int ret = 0 ;
788841
789842 if (led_cdev == & data_pointer -> led_micmute )
790843 led_nr = 1 ;
@@ -799,9 +852,12 @@ static void lenovo_led_brightness_set(struct led_classdev *led_cdev,
799852 lenovo_led_set_tpkbd (hdev );
800853 break ;
801854 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 );
803857 break ;
804858 }
859+
860+ return ret ;
805861}
806862
807863static int lenovo_register_leds (struct hid_device * hdev )
@@ -821,16 +877,20 @@ static int lenovo_register_leds(struct hid_device *hdev)
821877 snprintf (name_micm , name_sz , "%s:amber:micmute" , dev_name (& hdev -> dev ));
822878
823879 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 ;
826884 data -> led_mute .dev = & hdev -> dev ;
827885 ret = led_classdev_register (& hdev -> dev , & data -> led_mute );
828886 if (ret < 0 )
829887 return ret ;
830888
831889 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 ;
834894 data -> led_micmute .dev = & hdev -> dev ;
835895 ret = led_classdev_register (& hdev -> dev , & data -> led_micmute );
836896 if (ret < 0 ) {
@@ -952,11 +1012,24 @@ static const struct attribute_group lenovo_attr_group_tp10ubkbd = {
9521012
9531013static int lenovo_probe_tp10ubkbd (struct hid_device * hdev )
9541014{
1015+ struct hid_report_enum * rep_enum ;
9551016 struct lenovo_drvdata * data ;
1017+ struct hid_report * rep ;
1018+ bool found ;
9561019 int ret ;
9571020
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 )
9601033 return 0 ;
9611034
9621035 data = devm_kzalloc (& hdev -> dev , sizeof (* data ), GFP_KERNEL );
@@ -1018,6 +1091,7 @@ static int lenovo_probe(struct hid_device *hdev,
10181091 ret = lenovo_probe_cptkbd (hdev );
10191092 break ;
10201093 case USB_DEVICE_ID_LENOVO_TP10UBKBD :
1094+ case USB_DEVICE_ID_LENOVO_X1_TAB :
10211095 ret = lenovo_probe_tp10ubkbd (hdev );
10221096 break ;
10231097 default :
@@ -1083,6 +1157,7 @@ static void lenovo_remove(struct hid_device *hdev)
10831157 lenovo_remove_cptkbd (hdev );
10841158 break ;
10851159 case USB_DEVICE_ID_LENOVO_TP10UBKBD :
1160+ case USB_DEVICE_ID_LENOVO_X1_TAB :
10861161 lenovo_remove_tp10ubkbd (hdev );
10871162 break ;
10881163 }
@@ -1122,6 +1197,12 @@ static const struct hid_device_id lenovo_devices[] = {
11221197 { HID_USB_DEVICE (USB_VENDOR_ID_IBM , USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL_PRO ) },
11231198 { HID_USB_DEVICE (USB_VENDOR_ID_LENOVO , USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL ) },
11241199 { 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 ) },
11251206 { }
11261207};
11271208
0 commit comments