Skip to content

Commit cf6473b

Browse files
author
Jiri Kosina
committed
Merge branch 'for-6.14/lenovo' into for-linus
- improved support for Thinkpad-X12-TAB-1/2 (Vishnu Sankar)
2 parents 2ec37df + 52e7d1f commit cf6473b

File tree

1 file changed

+108
-1
lines changed

1 file changed

+108
-1
lines changed

drivers/hid/hid-lenovo.c

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,22 @@
3232
#include <linux/leds.h>
3333
#include <linux/workqueue.h>
3434

35+
#if IS_ENABLED(CONFIG_ACPI_PLATFORM_PROFILE)
36+
#include <linux/platform_profile.h>
37+
#endif /* CONFIG_ACPI_PLATFORM_PROFILE */
38+
3539
#include "hid-ids.h"
3640

3741
/* Userspace expects F20 for mic-mute KEY_MICMUTE does not work */
3842
#define LENOVO_KEY_MICMUTE KEY_F20
3943

44+
/* HID raw events for ThinkPad X12 Tabs*/
45+
#define TP_X12_RAW_HOTKEY_FN_F4 0x00020003
46+
#define TP_X12_RAW_HOTKEY_FN_F8 0x38001003
47+
#define TP_X12_RAW_HOTKEY_FN_F10 0x00000803
48+
#define TP_X12_RAW_HOTKEY_FN_F12 0x00000403
49+
#define TP_X12_RAW_HOTKEY_FN_SPACE 0x18001003
50+
4051
struct lenovo_drvdata {
4152
u8 led_report[3]; /* Must be first for proper alignment */
4253
int led_state;
@@ -71,6 +82,14 @@ struct lenovo_drvdata {
7182
#define TP10UBKBD_LED_OFF 1
7283
#define TP10UBKBD_LED_ON 2
7384

85+
/* Function to report raw_events as key events*/
86+
static inline void report_key_event(struct input_dev *input, int keycode)
87+
{
88+
input_report_key(input, keycode, 1);
89+
input_report_key(input, keycode, 0);
90+
input_sync(input);
91+
}
92+
7493
static int lenovo_led_set_tp10ubkbd(struct hid_device *hdev, u8 led_code,
7594
enum led_brightness value)
7695
{
@@ -472,6 +491,8 @@ static int lenovo_input_mapping(struct hid_device *hdev,
472491
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
473492
return lenovo_input_mapping_tp10_ultrabook_kbd(hdev, hi, field,
474493
usage, bit, max);
494+
case USB_DEVICE_ID_LENOVO_X12_TAB:
495+
case USB_DEVICE_ID_LENOVO_X12_TAB2:
475496
case USB_DEVICE_ID_LENOVO_X1_TAB:
476497
case USB_DEVICE_ID_LENOVO_X1_TAB3:
477498
return lenovo_input_mapping_x1_tab_kbd(hdev, hi, field, usage, bit, max);
@@ -582,6 +603,8 @@ static ssize_t attr_fn_lock_store(struct device *dev,
582603
case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
583604
lenovo_features_set_cptkbd(hdev);
584605
break;
606+
case USB_DEVICE_ID_LENOVO_X12_TAB:
607+
case USB_DEVICE_ID_LENOVO_X12_TAB2:
585608
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
586609
case USB_DEVICE_ID_LENOVO_X1_TAB:
587610
case USB_DEVICE_ID_LENOVO_X1_TAB3:
@@ -680,6 +703,62 @@ static const struct attribute_group lenovo_attr_group_cptkbd = {
680703
.attrs = lenovo_attributes_cptkbd,
681704
};
682705

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

779+
/*
780+
* Lenovo TP X12 Tab KBD's Fn+XX is HID raw data defined. Report ID is 0x03
781+
* e.g.: Raw data received for MIC mute is 0x00020003.
782+
*/
783+
if (unlikely((hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB
784+
|| hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB2)
785+
&& size >= 3 && report->id == 0x03))
786+
return lenovo_raw_event_TP_X12_tab(hdev, le32_to_cpu(*(u32 *)data));
787+
700788
return 0;
701789
}
702790

@@ -776,6 +864,8 @@ static int lenovo_event(struct hid_device *hdev, struct hid_field *field,
776864
case USB_DEVICE_ID_LENOVO_TPIIUSBKBD:
777865
case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
778866
return lenovo_event_cptkbd(hdev, field, usage, value);
867+
case USB_DEVICE_ID_LENOVO_X12_TAB:
868+
case USB_DEVICE_ID_LENOVO_X12_TAB2:
779869
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
780870
case USB_DEVICE_ID_LENOVO_X1_TAB:
781871
case USB_DEVICE_ID_LENOVO_X1_TAB3:
@@ -1057,6 +1147,8 @@ static int lenovo_led_brightness_set(struct led_classdev *led_cdev,
10571147
case USB_DEVICE_ID_LENOVO_TPKBD:
10581148
lenovo_led_set_tpkbd(hdev);
10591149
break;
1150+
case USB_DEVICE_ID_LENOVO_X12_TAB:
1151+
case USB_DEVICE_ID_LENOVO_X12_TAB2:
10601152
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
10611153
case USB_DEVICE_ID_LENOVO_X1_TAB:
10621154
case USB_DEVICE_ID_LENOVO_X1_TAB3:
@@ -1243,8 +1335,15 @@ static int lenovo_probe_tp10ubkbd(struct hid_device *hdev)
12431335
* We cannot read the state, only set it, so we force it to on here
12441336
* (which should be a no-op) to make sure that our state matches the
12451337
* keyboard's FN-lock state. This is the same as what Windows does.
1338+
*
1339+
* For X12 TAB and TAB2, the default windows behaviour Fn-lock Off.
1340+
* Adding additional check to ensure the behaviour in case of
1341+
* Thinkpad X12 Tabs.
12461342
*/
1247-
data->fn_lock = true;
1343+
1344+
data->fn_lock = !(hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB ||
1345+
hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB2);
1346+
12481347
lenovo_led_set_tp10ubkbd(hdev, TP10UBKBD_FN_LOCK_LED, data->fn_lock);
12491348

12501349
ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_tp10ubkbd);
@@ -1288,6 +1387,8 @@ static int lenovo_probe(struct hid_device *hdev,
12881387
case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
12891388
ret = lenovo_probe_cptkbd(hdev);
12901389
break;
1390+
case USB_DEVICE_ID_LENOVO_X12_TAB:
1391+
case USB_DEVICE_ID_LENOVO_X12_TAB2:
12911392
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
12921393
case USB_DEVICE_ID_LENOVO_X1_TAB:
12931394
case USB_DEVICE_ID_LENOVO_X1_TAB3:
@@ -1375,6 +1476,8 @@ static void lenovo_remove(struct hid_device *hdev)
13751476
case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
13761477
lenovo_remove_cptkbd(hdev);
13771478
break;
1479+
case USB_DEVICE_ID_LENOVO_X12_TAB:
1480+
case USB_DEVICE_ID_LENOVO_X12_TAB2:
13781481
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
13791482
case USB_DEVICE_ID_LENOVO_X1_TAB:
13801483
case USB_DEVICE_ID_LENOVO_X1_TAB3:
@@ -1429,6 +1532,10 @@ static const struct hid_device_id lenovo_devices[] = {
14291532
USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_TAB) },
14301533
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
14311534
USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_TAB3) },
1535+
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
1536+
USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X12_TAB) },
1537+
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
1538+
USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X12_TAB2) },
14321539
{ }
14331540
};
14341541

0 commit comments

Comments
 (0)