3333#include "hid-ids.h"
3434
3535struct 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+
5181static 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+
178239static 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+
834921static 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+
897998static 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