Skip to content

Commit 84c9d2a

Browse files
vishnuocvJiri Kosina
authored andcommitted
HID: lenovo: Support for ThinkPad-X12-TAB-1/2 Kbd Fn keys
Fn Keys like Mic mute, Power Modes/Airplane mode,Selective screenshot/Pickup Phone, KBD Backlight and star/Favourites is emitted as HID raw events in X12 Tab1 and Tab2. This support has been added. Thinkpad X12 TAB 2 and TAB 1 Folio keyboard's raw events will get detected as Fn keys with this patch. Default fn_lock state for these Keyboards are OFF. Other than these changes, we follow TP10UKBD's processes. Tested on X12 Tab 2. Signed-off-by: Vishnu Sankar <vishnuocv@gmail.com> Signed-off-by: Vishnu Sankar <vsankar@lenovo.com> Suggested-by: Mark Pearson <mpearson-lenovo@squebb.ca> Signed-off-by: Jiri Kosina <jkosina@suse.com>
1 parent 2a770b4 commit 84c9d2a

File tree

1 file changed

+98
-1
lines changed

1 file changed

+98
-1
lines changed

drivers/hid/hid-lenovo.c

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,20 @@
3131
#include <linux/input.h>
3232
#include <linux/leds.h>
3333
#include <linux/workqueue.h>
34+
#include <linux/platform_profile.h>
3435

3536
#include "hid-ids.h"
3637

3738
/* Userspace expects F20 for mic-mute KEY_MICMUTE does not work */
3839
#define LENOVO_KEY_MICMUTE KEY_F20
3940

41+
/* HID raw events for ThinkPad X12 Tabs*/
42+
#define TP_X12_RAW_HOTKEY_FN_F4 0x00020003
43+
#define TP_X12_RAW_HOTKEY_FN_F8 0x38001003
44+
#define TP_X12_RAW_HOTKEY_FN_F10 0x00000803
45+
#define TP_X12_RAW_HOTKEY_FN_F12 0x00000403
46+
#define TP_X12_RAW_HOTKEY_FN_SPACE 0x18001003
47+
4048
struct lenovo_drvdata {
4149
u8 led_report[3]; /* Must be first for proper alignment */
4250
int led_state;
@@ -71,6 +79,14 @@ struct lenovo_drvdata {
7179
#define TP10UBKBD_LED_OFF 1
7280
#define TP10UBKBD_LED_ON 2
7381

82+
/* Function to report raw_events as key events*/
83+
static inline void report_key_event(struct input_dev *input, int keycode)
84+
{
85+
input_report_key(input, keycode, 1);
86+
input_report_key(input, keycode, 0);
87+
input_sync(input);
88+
}
89+
7490
static int lenovo_led_set_tp10ubkbd(struct hid_device *hdev, u8 led_code,
7591
enum led_brightness value)
7692
{
@@ -472,6 +488,8 @@ static int lenovo_input_mapping(struct hid_device *hdev,
472488
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
473489
return lenovo_input_mapping_tp10_ultrabook_kbd(hdev, hi, field,
474490
usage, bit, max);
491+
case USB_DEVICE_ID_LENOVO_X12_TAB:
492+
case USB_DEVICE_ID_LENOVO_X12_TAB2:
475493
case USB_DEVICE_ID_LENOVO_X1_TAB:
476494
case USB_DEVICE_ID_LENOVO_X1_TAB3:
477495
return lenovo_input_mapping_x1_tab_kbd(hdev, hi, field, usage, bit, max);
@@ -582,6 +600,8 @@ static ssize_t attr_fn_lock_store(struct device *dev,
582600
case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
583601
lenovo_features_set_cptkbd(hdev);
584602
break;
603+
case USB_DEVICE_ID_LENOVO_X12_TAB:
604+
case USB_DEVICE_ID_LENOVO_X12_TAB2:
585605
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
586606
case USB_DEVICE_ID_LENOVO_X1_TAB:
587607
case USB_DEVICE_ID_LENOVO_X1_TAB3:
@@ -680,6 +700,55 @@ static const struct attribute_group lenovo_attr_group_cptkbd = {
680700
.attrs = lenovo_attributes_cptkbd,
681701
};
682702

703+
/* Function to handle Lenovo Thinkpad TAB X12's HID raw inputs for fn keys*/
704+
static int lenovo_raw_event_TP_X12_tab(struct hid_device *hdev, u32 raw_data)
705+
{
706+
struct hid_input *hidinput;
707+
struct input_dev *input = NULL;
708+
709+
/* Iterate through all associated input devices */
710+
list_for_each_entry(hidinput, &hdev->inputs, list) {
711+
input = hidinput->input;
712+
if (!input)
713+
continue;
714+
715+
switch (raw_data) {
716+
/* fn-F20 being used here for MIC mute*/
717+
case TP_X12_RAW_HOTKEY_FN_F4:
718+
report_key_event(input, LENOVO_KEY_MICMUTE);
719+
return 1;
720+
/* Power-mode or Airplane mode will be called based on the device*/
721+
case TP_X12_RAW_HOTKEY_FN_F8:
722+
/*
723+
* TP X12 TAB uses Fn-F8 calls Airplanemode
724+
* Whereas TP X12 TAB2 uses Fn-F8 for toggling
725+
* Power modes
726+
*/
727+
(hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB) ?
728+
report_key_event(input, KEY_RFKILL) :
729+
platform_profile_cycle();
730+
return 1;
731+
case TP_X12_RAW_HOTKEY_FN_F10:
732+
/* TAB1 has PICKUP Phone and TAB2 use Snipping tool*/
733+
(hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB) ?
734+
report_key_event(input, KEY_PICKUP_PHONE) :
735+
report_key_event(input, KEY_SELECTIVE_SCREENSHOT);
736+
return 1;
737+
case TP_X12_RAW_HOTKEY_FN_F12:
738+
/* BookMarks/STAR key*/
739+
report_key_event(input, KEY_BOOKMARKS);
740+
return 1;
741+
case TP_X12_RAW_HOTKEY_FN_SPACE:
742+
/* Keyboard LED backlight toggle*/
743+
report_key_event(input, KEY_KBDILLUMTOGGLE);
744+
return 1;
745+
default:
746+
break;
747+
}
748+
}
749+
return 0;
750+
}
751+
683752
static int lenovo_raw_event(struct hid_device *hdev,
684753
struct hid_report *report, u8 *data, int size)
685754
{
@@ -697,6 +766,15 @@ static int lenovo_raw_event(struct hid_device *hdev,
697766
data[2] = 0x01;
698767
}
699768

769+
/*
770+
* Lenovo TP X12 Tab KBD's Fn+XX is HID raw data defined. Report ID is 0x03
771+
* e.g.: Raw data received for MIC mute is 0x00020003.
772+
*/
773+
if (unlikely((hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB
774+
|| hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB2)
775+
&& size >= 3 && report->id == 0x03))
776+
return lenovo_raw_event_TP_X12_tab(hdev, le32_to_cpu(*(u32 *)data));
777+
700778
return 0;
701779
}
702780

@@ -776,6 +854,8 @@ static int lenovo_event(struct hid_device *hdev, struct hid_field *field,
776854
case USB_DEVICE_ID_LENOVO_TPIIUSBKBD:
777855
case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
778856
return lenovo_event_cptkbd(hdev, field, usage, value);
857+
case USB_DEVICE_ID_LENOVO_X12_TAB:
858+
case USB_DEVICE_ID_LENOVO_X12_TAB2:
779859
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
780860
case USB_DEVICE_ID_LENOVO_X1_TAB:
781861
case USB_DEVICE_ID_LENOVO_X1_TAB3:
@@ -1057,6 +1137,8 @@ static int lenovo_led_brightness_set(struct led_classdev *led_cdev,
10571137
case USB_DEVICE_ID_LENOVO_TPKBD:
10581138
lenovo_led_set_tpkbd(hdev);
10591139
break;
1140+
case USB_DEVICE_ID_LENOVO_X12_TAB:
1141+
case USB_DEVICE_ID_LENOVO_X12_TAB2:
10601142
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
10611143
case USB_DEVICE_ID_LENOVO_X1_TAB:
10621144
case USB_DEVICE_ID_LENOVO_X1_TAB3:
@@ -1243,8 +1325,15 @@ static int lenovo_probe_tp10ubkbd(struct hid_device *hdev)
12431325
* We cannot read the state, only set it, so we force it to on here
12441326
* (which should be a no-op) to make sure that our state matches the
12451327
* keyboard's FN-lock state. This is the same as what Windows does.
1328+
*
1329+
* For X12 TAB and TAB2, the default windows behaviour Fn-lock Off.
1330+
* Adding additional check to ensure the behaviour in case of
1331+
* Thinkpad X12 Tabs.
12461332
*/
1247-
data->fn_lock = true;
1333+
1334+
data->fn_lock = !(hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB ||
1335+
hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB2);
1336+
12481337
lenovo_led_set_tp10ubkbd(hdev, TP10UBKBD_FN_LOCK_LED, data->fn_lock);
12491338

12501339
ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_tp10ubkbd);
@@ -1288,6 +1377,8 @@ static int lenovo_probe(struct hid_device *hdev,
12881377
case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
12891378
ret = lenovo_probe_cptkbd(hdev);
12901379
break;
1380+
case USB_DEVICE_ID_LENOVO_X12_TAB:
1381+
case USB_DEVICE_ID_LENOVO_X12_TAB2:
12911382
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
12921383
case USB_DEVICE_ID_LENOVO_X1_TAB:
12931384
case USB_DEVICE_ID_LENOVO_X1_TAB3:
@@ -1375,6 +1466,8 @@ static void lenovo_remove(struct hid_device *hdev)
13751466
case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
13761467
lenovo_remove_cptkbd(hdev);
13771468
break;
1469+
case USB_DEVICE_ID_LENOVO_X12_TAB:
1470+
case USB_DEVICE_ID_LENOVO_X12_TAB2:
13781471
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
13791472
case USB_DEVICE_ID_LENOVO_X1_TAB:
13801473
case USB_DEVICE_ID_LENOVO_X1_TAB3:
@@ -1429,6 +1522,10 @@ static const struct hid_device_id lenovo_devices[] = {
14291522
USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_TAB) },
14301523
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
14311524
USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_TAB3) },
1525+
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
1526+
USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X12_TAB) },
1527+
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
1528+
USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X12_TAB2) },
14321529
{ }
14331530
};
14341531

0 commit comments

Comments
 (0)