diff mbox series

[v3] HID: lenovo: Support for ThinkPad-X12-TAB-1/2 Kbd Fn keys

Message ID 20241218143309.86811-1-vishnuocv@gmail.com (mailing list archive)
State New
Delegated to: Jiri Kosina
Headers show
Series [v3] HID: lenovo: Support for ThinkPad-X12-TAB-1/2 Kbd Fn keys | expand

Commit Message

Vishnu Sankar Dec. 18, 2024, 2:33 p.m. UTC
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>
---
V2
-Rebased to hid.git
V3
-Renamed the patch to HID: lenovo: Support for ThinkPad-X12-TAB-1/2 Kbd Fn keys
-Fn Key macros changed to 4 bytes.
-Raw data check will look for 4 bytes instead of 3
-le32_to_cpu () used instead of shift operator to make 32 bit data.
-iternate through all hid inputs to find the device who generated the event,
instead of selecting the first available input.
-removed Fn-F7 as it is working by default.
-only 4 bytes hid raw data being handled now.
-additional check to ensure report-id is 0x03.
---
 drivers/hid/hid-lenovo.c | 99 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 98 insertions(+), 1 deletion(-)

Comments

Mark Pearson Dec. 18, 2024, 2:35 p.m. UTC | #1
Two thumbs up :)

On Wed, Dec 18, 2024, at 9:33 AM, Vishnu Sankar wrote:
> 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>
> ---
> V2
> -Rebased to hid.git
> V3
> -Renamed the patch to HID: lenovo: Support for ThinkPad-X12-TAB-1/2 Kbd Fn keys
> -Fn Key macros changed to 4 bytes.
> -Raw data check will look for 4 bytes instead of 3
> -le32_to_cpu () used instead of shift operator to make 32 bit data.
> -iternate through all hid inputs to find the device who generated the event,
> instead of selecting the first available input.
> -removed Fn-F7 as it is working by default.
> -only 4 bytes hid raw data being handled now.
> -additional check to ensure report-id is 0x03.
> ---
>  drivers/hid/hid-lenovo.c | 99 +++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 98 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c
> index f66194fde891..bfaadd54cba1 100644
> --- a/drivers/hid/hid-lenovo.c
> +++ b/drivers/hid/hid-lenovo.c
> @@ -31,12 +31,20 @@
>  #include <linux/input.h>
>  #include <linux/leds.h>
>  #include <linux/workqueue.h>
> +#include <linux/platform_profile.h>
> 
>  #include "hid-ids.h"
> 
>  /* Userspace expects F20 for mic-mute KEY_MICMUTE does not work */
>  #define LENOVO_KEY_MICMUTE KEY_F20
> 
> +/* HID raw events for ThinkPad X12 Tabs*/
> +#define TP_X12_RAW_HOTKEY_FN_F4		0x00020003
> +#define TP_X12_RAW_HOTKEY_FN_F8		0x38001003
> +#define TP_X12_RAW_HOTKEY_FN_F10	0x00000803
> +#define TP_X12_RAW_HOTKEY_FN_F12	0x00000403
> +#define TP_X12_RAW_HOTKEY_FN_SPACE	0x18001003
> +
>  struct lenovo_drvdata {
>  	u8 led_report[3]; /* Must be first for proper alignment */
>  	int led_state;
> @@ -71,6 +79,14 @@ struct lenovo_drvdata {
>  #define TP10UBKBD_LED_OFF		1
>  #define TP10UBKBD_LED_ON		2
> 
> +/* Function to report raw_events as key events*/
> +static inline void report_key_event(struct input_dev *input, int 
> keycode)
> +{
> +	input_report_key(input, keycode, 1);
> +	input_report_key(input, keycode, 0);
> +	input_sync(input);
> +}
> +
>  static int lenovo_led_set_tp10ubkbd(struct hid_device *hdev, u8 
> led_code,
>  				    enum led_brightness value)
>  {
> @@ -472,6 +488,8 @@ static int lenovo_input_mapping(struct hid_device 
> *hdev,
>  	case USB_DEVICE_ID_LENOVO_TP10UBKBD:
>  		return lenovo_input_mapping_tp10_ultrabook_kbd(hdev, hi, field,
>  							       usage, bit, max);
> +	case USB_DEVICE_ID_LENOVO_X12_TAB:
> +	case USB_DEVICE_ID_LENOVO_X12_TAB2:
>  	case USB_DEVICE_ID_LENOVO_X1_TAB:
>  	case USB_DEVICE_ID_LENOVO_X1_TAB3:
>  		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,
>  	case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
>  		lenovo_features_set_cptkbd(hdev);
>  		break;
> +	case USB_DEVICE_ID_LENOVO_X12_TAB:
> +	case USB_DEVICE_ID_LENOVO_X12_TAB2:
>  	case USB_DEVICE_ID_LENOVO_TP10UBKBD:
>  	case USB_DEVICE_ID_LENOVO_X1_TAB:
>  	case USB_DEVICE_ID_LENOVO_X1_TAB3:
> @@ -680,6 +700,55 @@ static const struct attribute_group 
> lenovo_attr_group_cptkbd = {
>  	.attrs = lenovo_attributes_cptkbd,
>  };
> 
> +/* Function to handle Lenovo Thinkpad TAB X12's HID raw inputs for fn keys*/
> +static int lenovo_raw_event_TP_X12_tab(struct hid_device *hdev, u32 raw_data)
> +{
> +	struct hid_input *hidinput;
> +	struct input_dev *input = NULL;
> +
> +	/* Iterate through all associated input devices */
> +	list_for_each_entry(hidinput, &hdev->inputs, list) {
> +		input = hidinput->input;
> +		if (!input)
> +			continue;
> +
> +		switch (raw_data) {
> +			/* fn-F20 being used here for MIC mute*/
> +		case TP_X12_RAW_HOTKEY_FN_F4:
> +			report_key_event(input, LENOVO_KEY_MICMUTE);
> +			return 1;
> +		/* Power-mode or Airplane mode will be called based on the device*/
> +		case TP_X12_RAW_HOTKEY_FN_F8:
> +			/*
> +			 * TP X12 TAB uses Fn-F8 calls Airplanemode
> +			 * Whereas TP X12 TAB2 uses Fn-F8 for toggling
> +			 * Power modes
> +			 */
> +			(hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB) ?
> +				report_key_event(input, KEY_RFKILL) :
> +				platform_profile_cycle();
> +			return 1;
> +		case TP_X12_RAW_HOTKEY_FN_F10:
> +			/* TAB1 has PICKUP Phone and TAB2 use Snipping tool*/
> +			(hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB) ?
> +			report_key_event(input, KEY_PICKUP_PHONE) :
> +			report_key_event(input, KEY_SELECTIVE_SCREENSHOT);
> +			return 1;
> +		case TP_X12_RAW_HOTKEY_FN_F12:
> +			/* BookMarks/STAR key*/
> +			report_key_event(input, KEY_BOOKMARKS);
> +			return 1;
> +		case TP_X12_RAW_HOTKEY_FN_SPACE:
> +			/* Keyboard LED backlight toggle*/
> +			report_key_event(input, KEY_KBDILLUMTOGGLE);
> +			return 1;
> +		default:
> +			break;
> +		}
> +	}
> +	return 0;
> +}
> +
>  static int lenovo_raw_event(struct hid_device *hdev,
>  			struct hid_report *report, u8 *data, int size)
>  {
> @@ -697,6 +766,15 @@ static int lenovo_raw_event(struct hid_device *hdev,
>  		data[2] = 0x01;
>  	}
> 
> +	/*
> +	 * Lenovo TP X12 Tab KBD's Fn+XX is HID raw data defined. Report ID is 0x03
> +	 * e.g.: Raw data received for MIC mute is 0x00020003.
> +	 */
> +	if (unlikely((hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB
> +			|| hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB2)
> +			&& size >= 3 && report->id == 0x03))
> +		return lenovo_raw_event_TP_X12_tab(hdev, le32_to_cpu(*(u32 *)data));
> +
>  	return 0;
>  }
> 
> @@ -776,6 +854,8 @@ static int lenovo_event(struct hid_device *hdev, 
> struct hid_field *field,
>  	case USB_DEVICE_ID_LENOVO_TPIIUSBKBD:
>  	case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
>  		return lenovo_event_cptkbd(hdev, field, usage, value);
> +	case USB_DEVICE_ID_LENOVO_X12_TAB:
> +	case USB_DEVICE_ID_LENOVO_X12_TAB2:
>  	case USB_DEVICE_ID_LENOVO_TP10UBKBD:
>  	case USB_DEVICE_ID_LENOVO_X1_TAB:
>  	case USB_DEVICE_ID_LENOVO_X1_TAB3:
> @@ -1057,6 +1137,8 @@ static int lenovo_led_brightness_set(struct 
> led_classdev *led_cdev,
>  	case USB_DEVICE_ID_LENOVO_TPKBD:
>  		lenovo_led_set_tpkbd(hdev);
>  		break;
> +	case USB_DEVICE_ID_LENOVO_X12_TAB:
> +	case USB_DEVICE_ID_LENOVO_X12_TAB2:
>  	case USB_DEVICE_ID_LENOVO_TP10UBKBD:
>  	case USB_DEVICE_ID_LENOVO_X1_TAB:
>  	case USB_DEVICE_ID_LENOVO_X1_TAB3:
> @@ -1243,8 +1325,15 @@ static int lenovo_probe_tp10ubkbd(struct 
> hid_device *hdev)
>  	 * We cannot read the state, only set it, so we force it to on here
>  	 * (which should be a no-op) to make sure that our state matches the
>  	 * keyboard's FN-lock state. This is the same as what Windows does.
> +	 *
> +	 * For X12 TAB and TAB2, the default windows behaviour Fn-lock Off.
> +	 * Adding additional check to ensure the behaviour in case of
> +	 * Thinkpad X12 Tabs.
>  	 */
> -	data->fn_lock = true;
> +
> +	data->fn_lock = !(hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB ||
> +			hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB2);
> +
>  	lenovo_led_set_tp10ubkbd(hdev, TP10UBKBD_FN_LOCK_LED, data->fn_lock);
> 
>  	ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_tp10ubkbd);
> @@ -1288,6 +1377,8 @@ static int lenovo_probe(struct hid_device *hdev,
>  	case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
>  		ret = lenovo_probe_cptkbd(hdev);
>  		break;
> +	case USB_DEVICE_ID_LENOVO_X12_TAB:
> +	case USB_DEVICE_ID_LENOVO_X12_TAB2:
>  	case USB_DEVICE_ID_LENOVO_TP10UBKBD:
>  	case USB_DEVICE_ID_LENOVO_X1_TAB:
>  	case USB_DEVICE_ID_LENOVO_X1_TAB3:
> @@ -1375,6 +1466,8 @@ static void lenovo_remove(struct hid_device *hdev)
>  	case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
>  		lenovo_remove_cptkbd(hdev);
>  		break;
> +	case USB_DEVICE_ID_LENOVO_X12_TAB:
> +	case USB_DEVICE_ID_LENOVO_X12_TAB2:
>  	case USB_DEVICE_ID_LENOVO_TP10UBKBD:
>  	case USB_DEVICE_ID_LENOVO_X1_TAB:
>  	case USB_DEVICE_ID_LENOVO_X1_TAB3:
> @@ -1429,6 +1522,10 @@ static const struct hid_device_id lenovo_devices[] = {
>  		     USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_TAB) },
>  	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
>  		     USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_TAB3) },
> +	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
> +		     USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X12_TAB) },
> +	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
> +		     USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X12_TAB2) },
>  	{ }
>  };
> 
> -- 
> 2.43.0
diff mbox series

Patch

diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c
index f66194fde891..bfaadd54cba1 100644
--- a/drivers/hid/hid-lenovo.c
+++ b/drivers/hid/hid-lenovo.c
@@ -31,12 +31,20 @@ 
 #include <linux/input.h>
 #include <linux/leds.h>
 #include <linux/workqueue.h>
+#include <linux/platform_profile.h>
 
 #include "hid-ids.h"
 
 /* Userspace expects F20 for mic-mute KEY_MICMUTE does not work */
 #define LENOVO_KEY_MICMUTE KEY_F20
 
+/* HID raw events for ThinkPad X12 Tabs*/
+#define TP_X12_RAW_HOTKEY_FN_F4		0x00020003
+#define TP_X12_RAW_HOTKEY_FN_F8		0x38001003
+#define TP_X12_RAW_HOTKEY_FN_F10	0x00000803
+#define TP_X12_RAW_HOTKEY_FN_F12	0x00000403
+#define TP_X12_RAW_HOTKEY_FN_SPACE	0x18001003
+
 struct lenovo_drvdata {
 	u8 led_report[3]; /* Must be first for proper alignment */
 	int led_state;
@@ -71,6 +79,14 @@  struct lenovo_drvdata {
 #define TP10UBKBD_LED_OFF		1
 #define TP10UBKBD_LED_ON		2
 
+/* Function to report raw_events as key events*/
+static inline void report_key_event(struct input_dev *input, int keycode)
+{
+	input_report_key(input, keycode, 1);
+	input_report_key(input, keycode, 0);
+	input_sync(input);
+}
+
 static int lenovo_led_set_tp10ubkbd(struct hid_device *hdev, u8 led_code,
 				    enum led_brightness value)
 {
@@ -472,6 +488,8 @@  static int lenovo_input_mapping(struct hid_device *hdev,
 	case USB_DEVICE_ID_LENOVO_TP10UBKBD:
 		return lenovo_input_mapping_tp10_ultrabook_kbd(hdev, hi, field,
 							       usage, bit, max);
+	case USB_DEVICE_ID_LENOVO_X12_TAB:
+	case USB_DEVICE_ID_LENOVO_X12_TAB2:
 	case USB_DEVICE_ID_LENOVO_X1_TAB:
 	case USB_DEVICE_ID_LENOVO_X1_TAB3:
 		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,
 	case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
 		lenovo_features_set_cptkbd(hdev);
 		break;
+	case USB_DEVICE_ID_LENOVO_X12_TAB:
+	case USB_DEVICE_ID_LENOVO_X12_TAB2:
 	case USB_DEVICE_ID_LENOVO_TP10UBKBD:
 	case USB_DEVICE_ID_LENOVO_X1_TAB:
 	case USB_DEVICE_ID_LENOVO_X1_TAB3:
@@ -680,6 +700,55 @@  static const struct attribute_group lenovo_attr_group_cptkbd = {
 	.attrs = lenovo_attributes_cptkbd,
 };
 
+/* Function to handle Lenovo Thinkpad TAB X12's HID raw inputs for fn keys*/
+static int lenovo_raw_event_TP_X12_tab(struct hid_device *hdev, u32 raw_data)
+{
+	struct hid_input *hidinput;
+	struct input_dev *input = NULL;
+
+	/* Iterate through all associated input devices */
+	list_for_each_entry(hidinput, &hdev->inputs, list) {
+		input = hidinput->input;
+		if (!input)
+			continue;
+
+		switch (raw_data) {
+			/* fn-F20 being used here for MIC mute*/
+		case TP_X12_RAW_HOTKEY_FN_F4:
+			report_key_event(input, LENOVO_KEY_MICMUTE);
+			return 1;
+		/* Power-mode or Airplane mode will be called based on the device*/
+		case TP_X12_RAW_HOTKEY_FN_F8:
+			/*
+			 * TP X12 TAB uses Fn-F8 calls Airplanemode
+			 * Whereas TP X12 TAB2 uses Fn-F8 for toggling
+			 * Power modes
+			 */
+			(hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB) ?
+				report_key_event(input, KEY_RFKILL) :
+				platform_profile_cycle();
+			return 1;
+		case TP_X12_RAW_HOTKEY_FN_F10:
+			/* TAB1 has PICKUP Phone and TAB2 use Snipping tool*/
+			(hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB) ?
+			report_key_event(input, KEY_PICKUP_PHONE) :
+			report_key_event(input, KEY_SELECTIVE_SCREENSHOT);
+			return 1;
+		case TP_X12_RAW_HOTKEY_FN_F12:
+			/* BookMarks/STAR key*/
+			report_key_event(input, KEY_BOOKMARKS);
+			return 1;
+		case TP_X12_RAW_HOTKEY_FN_SPACE:
+			/* Keyboard LED backlight toggle*/
+			report_key_event(input, KEY_KBDILLUMTOGGLE);
+			return 1;
+		default:
+			break;
+		}
+	}
+	return 0;
+}
+
 static int lenovo_raw_event(struct hid_device *hdev,
 			struct hid_report *report, u8 *data, int size)
 {
@@ -697,6 +766,15 @@  static int lenovo_raw_event(struct hid_device *hdev,
 		data[2] = 0x01;
 	}
 
+	/*
+	 * Lenovo TP X12 Tab KBD's Fn+XX is HID raw data defined. Report ID is 0x03
+	 * e.g.: Raw data received for MIC mute is 0x00020003.
+	 */
+	if (unlikely((hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB
+			|| hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB2)
+			&& size >= 3 && report->id == 0x03))
+		return lenovo_raw_event_TP_X12_tab(hdev, le32_to_cpu(*(u32 *)data));
+
 	return 0;
 }
 
@@ -776,6 +854,8 @@  static int lenovo_event(struct hid_device *hdev, struct hid_field *field,
 	case USB_DEVICE_ID_LENOVO_TPIIUSBKBD:
 	case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
 		return lenovo_event_cptkbd(hdev, field, usage, value);
+	case USB_DEVICE_ID_LENOVO_X12_TAB:
+	case USB_DEVICE_ID_LENOVO_X12_TAB2:
 	case USB_DEVICE_ID_LENOVO_TP10UBKBD:
 	case USB_DEVICE_ID_LENOVO_X1_TAB:
 	case USB_DEVICE_ID_LENOVO_X1_TAB3:
@@ -1057,6 +1137,8 @@  static int lenovo_led_brightness_set(struct led_classdev *led_cdev,
 	case USB_DEVICE_ID_LENOVO_TPKBD:
 		lenovo_led_set_tpkbd(hdev);
 		break;
+	case USB_DEVICE_ID_LENOVO_X12_TAB:
+	case USB_DEVICE_ID_LENOVO_X12_TAB2:
 	case USB_DEVICE_ID_LENOVO_TP10UBKBD:
 	case USB_DEVICE_ID_LENOVO_X1_TAB:
 	case USB_DEVICE_ID_LENOVO_X1_TAB3:
@@ -1243,8 +1325,15 @@  static int lenovo_probe_tp10ubkbd(struct hid_device *hdev)
 	 * We cannot read the state, only set it, so we force it to on here
 	 * (which should be a no-op) to make sure that our state matches the
 	 * keyboard's FN-lock state. This is the same as what Windows does.
+	 *
+	 * For X12 TAB and TAB2, the default windows behaviour Fn-lock Off.
+	 * Adding additional check to ensure the behaviour in case of
+	 * Thinkpad X12 Tabs.
 	 */
-	data->fn_lock = true;
+
+	data->fn_lock = !(hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB ||
+			hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB2);
+
 	lenovo_led_set_tp10ubkbd(hdev, TP10UBKBD_FN_LOCK_LED, data->fn_lock);
 
 	ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_tp10ubkbd);
@@ -1288,6 +1377,8 @@  static int lenovo_probe(struct hid_device *hdev,
 	case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
 		ret = lenovo_probe_cptkbd(hdev);
 		break;
+	case USB_DEVICE_ID_LENOVO_X12_TAB:
+	case USB_DEVICE_ID_LENOVO_X12_TAB2:
 	case USB_DEVICE_ID_LENOVO_TP10UBKBD:
 	case USB_DEVICE_ID_LENOVO_X1_TAB:
 	case USB_DEVICE_ID_LENOVO_X1_TAB3:
@@ -1375,6 +1466,8 @@  static void lenovo_remove(struct hid_device *hdev)
 	case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
 		lenovo_remove_cptkbd(hdev);
 		break;
+	case USB_DEVICE_ID_LENOVO_X12_TAB:
+	case USB_DEVICE_ID_LENOVO_X12_TAB2:
 	case USB_DEVICE_ID_LENOVO_TP10UBKBD:
 	case USB_DEVICE_ID_LENOVO_X1_TAB:
 	case USB_DEVICE_ID_LENOVO_X1_TAB3:
@@ -1429,6 +1522,10 @@  static const struct hid_device_id lenovo_devices[] = {
 		     USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_TAB) },
 	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
 		     USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_TAB3) },
+	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
+		     USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X12_TAB) },
+	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
+		     USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X12_TAB2) },
 	{ }
 };