Do we have any more comments? Should I proceed with the same approach with the changes you asked for? Regards, Vishnu On Thu, Oct 10, 2024 at 6:46 PM Vishnu Sankar <vishnuocv@xxxxxxxxx> wrote: > > Benjamin, > Thanks a lot for the comments. > And sorry for the delayed response. > > On Mon, Oct 7, 2024 at 6:19 PM Benjamin Tissoires <bentiss@xxxxxxxxxx> wrote: > > > > On Oct 05 2024, Vishnu Sankar wrote: > > > Thanks a lot for the comments. > > > > > > On Fri, Oct 4, 2024 at 4:38 PM Benjamin Tissoires <bentiss@xxxxxxxxxx> wrote: > > > > > > > > > > > > IIRC, we already saw a previous version of this patch on the list. So > > > > you are missing a v2, and the changelog after the first "---". > > > Acknowledged. > > > > > > > > All in all, the subject should be: > > > > [PATCH v2] HID: lenovo: Support for TP-X12-TAB-1/2 Kbd Fn keys > > > > > > > > (dropped the "that use HID raw events" to make it more concise, and > > > > split hid-lenovo into "HID: lenovo"). > > > Acknowledged. > > > > > > > > If you are happy with my remarks below, please send a v3 with the > > > > subject following the pattern from above. > > > Acknowledged. > > > > > > > > On Oct 03 2024, Vishnu Sankar wrote: > > > > > Fn Keys like Mic mute, Power Modes/Airplane mode,Selective > > > > > screenshot/Pickup Phone, KBD Backlight, Display mode 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@xxxxxxxxx> > > > > > Signed-off-by: Vishnu Sankar <vsankar@xxxxxxxxxx> > > > > > Reviewed-by: Mark Pearson <mpearson-lenovo@xxxxxxxxx> > > > > > --- > > > > > drivers/hid/hid-lenovo.c | 122 ++++++++++++++++++++++++++++++++++++++- > > > > > 1 file changed, 121 insertions(+), 1 deletion(-) > > > > > > > > > > diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c > > > > > index 3b0c779ce8f7..86ce6152429d 100644 > > > > > --- a/drivers/hid/hid-lenovo.c > > > > > +++ b/drivers/hid/hid-lenovo.c > > > > > @@ -31,12 +31,21 @@ > > > > > #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 ThinkPas X12 Tabs*/ > > > > > +#define TP_X12_RAW_HOTKEY_FN_F4 0x000200 > > > > > +#define TP_X12_RAW_HOTKEY_FN_F8 0x100038 > > > > > +#define TP_X12_RAW_HOTKEY_FN_F10 0x080000 > > > > > +#define TP_X12_RAW_HOTKEY_FN_F12 0x040000 > > > > > +#define TP_X12_RAW_HOTKEY_FN_SPACE 0x100018 > > > > > +#define TP_X12_RAW_HOTKEY_FN_F7 0x080013 > > > > > + > > > > > struct lenovo_drvdata { > > > > > u8 led_report[3]; /* Must be first for proper alignment */ > > > > > int led_state; > > > > > @@ -71,6 +80,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 +489,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: > > > > > return lenovo_input_mapping_x1_tab_kbd(hdev, hi, field, usage, bit, max); > > > > > default: > > > > > @@ -581,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: > > > > > ret = lenovo_led_set_tp10ubkbd(hdev, TP10UBKBD_FN_LOCK_LED, value); > > > > > @@ -678,9 +699,63 @@ 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 the associated inputs to find the correct input device */ > > > > > + list_for_each_entry(hidinput, &hdev->inputs, list) { > > > > > + input = hidinput->input; > > > > > + if (input) > > > > > + break; /* Use the first valid input device */ > > > > > + } > > > > > + > > > > > + 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); > > > > > > > > Now I'm puzzled: you are reporting in this function keys that you never > > > > declared in the input device. > > > > > > > > So how can you get the events in userspace, they should be filtered out > > > > by the input stack? > > > > > > As per my testing all the events are reaching user space and the fn > > > keys are also working. > > > > How are you testing those keys? > I did some generic functionality testing on Ubuntu 24.04. > The functionalities are working: > FN + F4 - MIC mute + LED ON > FN + F8 - Profile selection (Performance profile will get changed on each press) > FN + F7 - Display selection (I have noticed that we can remove the > support of Fn + F7 from this patch as it is already working) > FN + F10 - No impact as this is supposed to be the snipping tool (Future). > FN + F12 - Bookmarks (Tried with Mozilla) > FN + SPACE - KBD backlight notification came up (No control for now, > We can add this later) > > > > AFAICT, some usages would never be declared in the input device, even > > when relying on lenovo_input_mapping_x1_tab_kbd(). > > > Understood. > > > > > > > > > > > This applies to all the reported keys from here. > > > > > > > > Are you sure using raw events is the correct approach? > > > > > > Open to discussion. It would be helpful if you can guide me with > > > alternatives, if any. > > > As per the data sheet, it should be taken as hid raw events and AFAIK > > > Windows also use hid raw events. > > > > Usually, we prefer to rely on the HID input processing. So we need to > > intercept the .input_mapping() call matching the HID usage of the key, > > then map it to a know input keycode, and the HID stack does the rest. > > > > In your case, there is a slight problem in which some keys are reported > > through a undeclared usage in the HID report descriptor (FN_F8, FN_F7, > > FN_SPACE AFAICT). Their raw value is bigger than 2047, and so they > > should be ignored by hid-input as they do not match the usable range. > > > > In those cases, we have 3 solutions: > > - fix the report descriptor to include those usages (but that will make > > it a tad long usage list) > > - change the raw_event and optionally change the report descritor to > > remap the keys to a better usage > > - use what you did, only use raw_event processing. > > > Understood. > We may have more 6-byte Keys (Hotkeys) to be added in the Future. > Open to discussion. > > > > > > > > > > > Also, in other words: could you please share a full hid-recorder output > > > > of the device when you press the keys so I understand where the events > > > > are mapped? > > > > > > > Please find the full hid-recorder output. > > > > Thanks, but it's hard to know which keys have been pressed. Could you > > either amend the output either re-record another log with a given > > sequence, so I can map which events comes from which action. > > Sorry for the inconvenience. > > Please find the new hid-recorder results as below: > hera-2@hera-2-ThinkPad-X12-Detachable-Gen-2:~/Kernel/hid-tools$ sudo > ./hid-recorder > Available devices: > /dev/hidraw0: Darfon ThinkPad X12 Detachable Gen 2 Folio Keyboard > /dev/hidraw1: Darfon ThinkPad X12 Detachable Gen 2 Folio Keyboard > /dev/hidraw2: Darfon ThinkPad X12 Detachable Gen 2 Folio Keyboard > /dev/hidraw3: Darfon ThinkPad X12 Detachable Gen 2 Folio Keyboard > /dev/hidraw4: hid-ishtp 8087:0AC2 > /dev/hidraw5: WACF2200:00 056A:53A3 > /dev/hidraw6: hid-ishtp 8087:0AC2 > Select the device event number [0-6]: 1 > # Darfon ThinkPad X12 Detachable Gen 2 Folio Keyboard > # 0x05, 0x01, // Usage Page (Generic Desktop) 0 > # 0x09, 0x02, // Usage (Mouse) 2 > # 0xa1, 0x01, // Collection (Application) 4 > # 0x85, 0x01, // Report ID (1) 6 > # 0x09, 0x01, // Usage (Pointer) 8 > # 0xa1, 0x00, // Collection (Physical) 10 > # 0x05, 0x09, // Usage Page (Button) 12 > # 0x15, 0x00, // Logical Minimum (0) 14 > # 0x25, 0x01, // Logical Maximum (1) 16 > # 0x19, 0x01, // Usage Minimum (1) 18 > # 0x29, 0x05, // Usage Maximum (5) 20 > # 0x75, 0x01, // Report Size (1) 22 > # 0x95, 0x05, // Report Count (5) 24 > # 0x81, 0x02, // Input (Data,Var,Abs) 26 > # 0x95, 0x03, // Report Count (3) 28 > # 0x81, 0x01, // Input (Cnst,Arr,Abs) 30 > # 0x05, 0x01, // Usage Page (Generic Desktop) 32 > # 0x16, 0x01, 0x80, // Logical Minimum (-32767) 34 > # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 37 > # 0x09, 0x30, // Usage (X) 40 > # 0x09, 0x31, // Usage (Y) 42 > # 0x75, 0x10, // Report Size (16) 44 > # 0x95, 0x02, // Report Count (2) 46 > # 0x81, 0x06, // Input (Data,Var,Rel) 48 > # 0x15, 0x81, // Logical Minimum (-127) 50 > # 0x25, 0x7f, // Logical Maximum (127) 52 > # 0x09, 0x38, // Usage (Wheel) 54 > # 0x75, 0x08, // Report Size (8) 56 > # 0x95, 0x01, // Report Count (1) 58 > # 0x81, 0x06, // Input (Data,Var,Rel) 60 > # 0x05, 0x0c, // Usage Page (Consumer Devices) 62 > # 0x0a, 0x38, 0x02, // Usage (AC Pan) 64 > # 0x95, 0x01, // Report Count (1) 67 > # 0x81, 0x06, // Input (Data,Var,Rel) 69 > # 0xc0, // End Collection 71 > # 0xc0, // End Collection 72 > # 0x05, 0x01, // Usage Page (Generic Desktop) 73 > # 0x09, 0x80, // Usage (System Control) 75 > # 0xa1, 0x01, // Collection (Application) 77 > # 0x85, 0x02, // Report ID (2) 79 > # 0x19, 0x81, // Usage Minimum (129) 81 > # 0x29, 0x83, // Usage Maximum (131) 83 > # 0x15, 0x00, // Logical Minimum (0) 85 > # 0x25, 0x01, // Logical Maximum (1) 87 > # 0x75, 0x01, // Report Size (1) 89 > # 0x95, 0x03, // Report Count (3) 91 > # 0x81, 0x02, // Input (Data,Var,Abs) 93 > # 0x95, 0x05, // Report Count (5) 95 > # 0x81, 0x01, // Input (Cnst,Arr,Abs) 97 > # 0xc0, // End Collection 99 > # 0x05, 0x0c, // Usage Page (Consumer Devices) 100 > # 0x09, 0x01, // Usage (Consumer Control) 102 > # 0xa1, 0x01, // Collection (Application) 104 > # 0x85, 0x03, // Report ID (3) 106 > # 0x19, 0x00, // Usage Minimum (0) 108 > # 0x2a, 0xff, 0x07, // Usage Maximum (2047) 110 > # 0x15, 0x00, // Logical Minimum (0) 113 > # 0x26, 0xff, 0x07, // Logical Maximum (2047) 115 > # 0x95, 0x01, // Report Count (1) 118 > # 0x75, 0x18, // Report Size (24) 120 > # 0x81, 0x00, // Input (Data,Arr,Abs) 122 > # 0xc0, // End Collection 124 > # 0x05, 0x01, // Usage Page (Generic Desktop) 125 > # 0x09, 0x06, // Usage (Keyboard) 127 > # 0xa1, 0x01, // Collection (Application) 129 > # 0x85, 0x04, // Report ID (4) 131 > # 0x05, 0x07, // Usage Page (Keyboard) 133 > # 0x95, 0x01, // Report Count (1) 135 > # 0x75, 0x08, // Report Size (8) 137 > # 0x81, 0x03, // Input (Cnst,Var,Abs) 139 > # 0x95, 0xe8, // Report Count (232) 141 > # 0x75, 0x01, // Report Size (1) 143 > # 0x15, 0x00, // Logical Minimum (0) 145 > # 0x25, 0x01, // Logical Maximum (1) 147 > # 0x05, 0x07, // Usage Page (Keyboard) 149 > # 0x19, 0x00, // Usage Minimum (0) 151 > # 0x29, 0xe7, // Usage Maximum (231) 153 > # 0x81, 0x00, // Input (Data,Arr,Abs) 155 > # 0xc0, // End Collection 157 > # 0x05, 0x01, // Usage Page (Generic Desktop) 158 > # 0x09, 0x0c, // Usage (Wireless Radio Controls) 160 > # 0xa1, 0x01, // Collection (Application) 162 > # 0x85, 0x08, // Report ID (8) 164 > # 0x15, 0x00, // Logical Minimum (0) 166 > # 0x25, 0x01, // Logical Maximum (1) 168 > # 0x09, 0xc6, // Usage (Wireless Radio Button) 170 > # 0x95, 0x01, // Report Count (1) 172 > # 0x75, 0x01, // Report Size (1) 174 > # 0x81, 0x06, // Input (Data,Var,Rel) 176 > # 0x75, 0x07, // Report Size (7) 178 > # 0x81, 0x03, // Input (Cnst,Var,Abs) 180 > # 0xc0, // End Collection 182 > # 0x06, 0xa0, 0xff, // Usage Page (Vendor Usage Page 0xffa0) 183 > # 0x09, 0x01, // Usage (Vendor Usage 0x01) 186 > # 0xa1, 0x01, // Collection (Application) 188 > # 0x85, 0x09, // Report ID (9) 190 > # 0x09, 0x01, // Usage (Vendor Usage 0x01) 192 > # 0x75, 0x08, // Report Size (8) 194 > # 0x95, 0x02, // Report Count (2) 196 > # 0x91, 0x82, // Output (Data,Var,Abs,Vol) 198 > # 0x09, 0x02, // Usage (Vendor Usage 0x02) 200 > # 0x75, 0x08, // Report Size (8) 202 > # 0x95, 0x02, // Report Count (2) 204 > # 0x81, 0x82, // Input (Data,Var,Abs,Vol) 206 > # 0xc0, // End Collection 208 > # 0x06, 0xa1, 0xff, // Usage Page (Vendor Usage Page 0xffa1) 209 > # 0x09, 0x11, // Usage (Vendor Usage 0x11) 212 > # 0xa1, 0x01, // Collection (Application) 214 > # 0x85, 0x54, // Report ID (84) 216 > # 0x09, 0x11, // Usage (Vendor Usage 0x11) 218 > # 0x75, 0x08, // Report Size (8) 220 > # 0x95, 0x01, // Report Count (1) 222 > # 0xb1, 0x02, // Feature (Data,Var,Abs) 224 > # 0xc0, // End Collection 226 > # 0x06, 0xa3, 0xff, // Usage Page (Vendor Usage Page 0xffa3) 227 > # 0x09, 0x13, // Usage (Vendor Usage 0x13) 230 > # 0xa1, 0x01, // Collection (Application) 232 > # 0x85, 0x74, // Report ID (116) 234 > # 0x09, 0x13, // Usage (Vendor Usage 0x13) 236 > # 0x75, 0x08, // Report Size (8) 238 > # 0x95, 0x01, // Report Count (1) 240 > # 0xb1, 0x02, // Feature (Data,Var,Abs) 242 > # 0xc0, // End Collection 244 > # 0x06, 0xa2, 0xff, // Usage Page (Vendor Usage Page 0xffa2) 245 > # 0x09, 0x12, // Usage (Vendor Usage 0x12) 248 > # 0xa1, 0x01, // Collection (Application) 250 > # 0x85, 0x64, // Report ID (100) 252 > # 0x09, 0x12, // Usage (Vendor Usage 0x12) 254 > # 0x75, 0x08, // Report Size (8) 256 > # 0x95, 0x01, // Report Count (1) 258 > # 0xb1, 0x02, // Feature (Data,Var,Abs) 260 > # 0xc0, // End Collection 262 > # 0x06, 0xa6, 0xff, // Usage Page (Vendor Usage Page 0xffa6) 263 > # 0x09, 0x16, // Usage (Vendor Usage 0x16) 266 > # 0xa1, 0x01, // Collection (Application) 268 > # 0x85, 0xb4, // Report ID (180) 270 > # 0x09, 0x16, // Usage (Vendor Usage 0x16) 272 > # 0x75, 0x08, // Report Size (8) 274 > # 0x95, 0x01, // Report Count (1) 276 > # 0xb1, 0x02, // Feature (Data,Var,Abs) 278 > # 0xc0, // End Collection 280 > # 0x06, 0xa8, 0xff, // Usage Page (Vendor Usage Page 0xffa8) 281 > # 0x09, 0x18, // Usage (Vendor Usage 0x18) 284 > # 0xa1, 0x01, // Collection (Application) 286 > # 0x85, 0xc4, // Report ID (196) 288 > # 0x09, 0x18, // Usage (Vendor Usage 0x18) 290 > # 0x75, 0x08, // Report Size (8) 292 > # 0x95, 0x01, // Report Count (1) 294 > # 0xb1, 0x02, // Feature (Data,Var,Abs) 296 > # 0xc0, // End Collection 298 > # > R: 299 05 01 09 02 a1 01 85 01 09 01 a1 00 05 09 15 00 25 01 19 01 29 > 05 75 01 95 05 81 02 95 03 81 01 05 01 16 01 80 26 ff 7f 09 30 09 31 > 75 10 95 02 81 06 15 81 25 7f 09 38 75 08 95 01 81 06 05 0c 0a 38 02 > 95 01 81 06 c0 c0 05 01 09 80 a1 01 85 02 19 81 29 83 15 00 25 01 75 > 01 95 03 81 02 95 05 81 01 c0 05 0c 09 01 a1 01 85 03 19 00 2a ff 07 > 15 00 26 ff 07 95 01 75 18 81 00 c0 05 01 09 06 a1 01 85 04 05 07 95 > 01 75 08 81 03 95 e8 75 01 15 00 25 01 05 07 19 00 29 e7 81 00 c0 05 > 01 09 0c a1 01 85 08 15 00 25 01 09 c6 95 01 75 01 81 06 75 07 81 03 > c0 06 a0 ff 09 01 a1 01 85 09 09 01 75 08 95 02 91 82 09 02 75 08 95 > 02 81 82 c0 06 a1 ff 09 11 a1 01 85 54 09 11 75 08 95 01 b1 02 c0 06 > a3 ff 09 13 a1 01 85 74 09 13 75 08 95 01 b1 02 c0 06 a2 ff 09 12 a1 > 01 85 64 09 12 75 08 95 01 b1 02 c0 06 a6 ff 09 16 a1 01 85 b4 09 16 > 75 08 95 01 b1 02 c0 06 a8 ff 09 18 a1 01 85 c4 09 18 75 08 95 01 b1 > 02 c0 > N: Darfon ThinkPad X12 Detachable Gen 2 Folio Keyboard > I: 3 17ef 61ae > # ReportID: 3 /Consumer Devices ['Generic GUIApplication Controls'] > E: 000000.000000 4 03 00 02 00 // FN + F4 > # ReportID: 3 /Consumer Devices ['0xc0000'] > E: 000000.047767 4 03 00 00 00 > # ReportID: 3 /Consumer Devices [] > E: 000045.419818 4 03 10 00 38 // FN + F8 > # ReportID: 3 /Consumer Devices ['0xc0000'] > E: 000045.559054 4 03 00 00 00 > # ReportID: 3 /Consumer Devices ['0xc0008'] > E: 000055.833262 4 03 08 00 00 // FN + F10 > # ReportID: 3 /Consumer Devices ['0xc0000'] > E: 000056.033361 4 03 00 00 00 > # ReportID: 3 /Consumer Devices [] > E: 000058.144866 4 03 10 00 37 // FN + F11 > # ReportID: 3 /Consumer Devices ['0xc0000'] > E: 000058.324825 4 03 00 00 00 > # ReportID: 3 /Consumer Devices ['Microphone'] > E: 000059.616713 4 03 04 00 00 // FN + F12 > # ReportID: 3 /Consumer Devices ['0xc0000'] > E: 000059.720631 4 03 00 00 00 > # ReportID: 3 /Consumer Devices [] > E: 000000.000000 4 03 10 00 18 // FN + SPACE > # ReportID: 3 /Consumer Devices ['0xc0000'] > E: 000000.119853 4 03 00 00 00 > > > > > > > $ sudo ./hid-recorder > > > Available devices: > > > /dev/hidraw0: Darfon ThinkPad X12 Detachable Gen 2 Folio Keyboard > > > /dev/hidraw1: Darfon ThinkPad X12 Detachable Gen 2 Folio Keyboard > > > /dev/hidraw2: Darfon ThinkPad X12 Detachable Gen 2 Folio Keyboard > > > /dev/hidraw3: Darfon ThinkPad X12 Detachable Gen 2 Folio Keyboard > > > /dev/hidraw4: hid-ishtp 8087:0AC2 > > > /dev/hidraw5: WACF2200:00 056A:53A3 > > > /dev/hidraw6: hid-ishtp 8087:0AC2 > > > Select the device event number [0-6]: 1 > > > # Darfon ThinkPad X12 Detachable Gen 2 Folio Keyboard > > > # 0x05, 0x01, // Usage Page (Generic Desktop) 0 > > > # 0x09, 0x02, // Usage (Mouse) 2 > > > # 0xa1, 0x01, // Collection (Application) 4 > > > # 0x85, 0x01, // Report ID (1) 6 > > > # 0x09, 0x01, // Usage (Pointer) 8 > > > # 0xa1, 0x00, // Collection (Physical) 10 > > > # 0x05, 0x09, // Usage Page (Button) 12 > > > # 0x15, 0x00, // Logical Minimum (0) 14 > > > # 0x25, 0x01, // Logical Maximum (1) 16 > > > # 0x19, 0x01, // Usage Minimum (1) 18 > > > # 0x29, 0x05, // Usage Maximum (5) 20 > > > # 0x75, 0x01, // Report Size (1) 22 > > > # 0x95, 0x05, // Report Count (5) 24 > > > # 0x81, 0x02, // Input (Data,Var,Abs) 26 > > > # 0x95, 0x03, // Report Count (3) 28 > > > # 0x81, 0x01, // Input (Cnst,Arr,Abs) 30 > > > # 0x05, 0x01, // Usage Page (Generic Desktop) 32 > > > # 0x16, 0x01, 0x80, // Logical Minimum (-32767) 34 > > > # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 37 > > > # 0x09, 0x30, // Usage (X) 40 > > > # 0x09, 0x31, // Usage (Y) 42 > > > # 0x75, 0x10, // Report Size (16) 44 > > > # 0x95, 0x02, // Report Count (2) 46 > > > # 0x81, 0x06, // Input (Data,Var,Rel) 48 > > > # 0x15, 0x81, // Logical Minimum (-127) 50 > > > # 0x25, 0x7f, // Logical Maximum (127) 52 > > > # 0x09, 0x38, // Usage (Wheel) 54 > > > # 0x75, 0x08, // Report Size (8) 56 > > > # 0x95, 0x01, // Report Count (1) 58 > > > # 0x81, 0x06, // Input (Data,Var,Rel) 60 > > > # 0x05, 0x0c, // Usage Page (Consumer Devices) 62 > > > # 0x0a, 0x38, 0x02, // Usage (AC Pan) 64 > > > # 0x95, 0x01, // Report Count (1) 67 > > > # 0x81, 0x06, // Input (Data,Var,Rel) 69 > > > # 0xc0, // End Collection 71 > > > # 0xc0, // End Collection 72 > > > # 0x05, 0x01, // Usage Page (Generic Desktop) 73 > > > # 0x09, 0x80, // Usage (System Control) 75 > > > # 0xa1, 0x01, // Collection (Application) 77 > > > # 0x85, 0x02, // Report ID (2) 79 > > > # 0x19, 0x81, // Usage Minimum (129) 81 > > > # 0x29, 0x83, // Usage Maximum (131) 83 > > > # 0x15, 0x00, // Logical Minimum (0) 85 > > > # 0x25, 0x01, // Logical Maximum (1) 87 > > > # 0x75, 0x01, // Report Size (1) 89 > > > # 0x95, 0x03, // Report Count (3) 91 > > > # 0x81, 0x02, // Input (Data,Var,Abs) 93 > > > # 0x95, 0x05, // Report Count (5) 95 > > > # 0x81, 0x01, // Input (Cnst,Arr,Abs) 97 > > > # 0xc0, // End Collection 99 > > > # 0x05, 0x0c, // Usage Page (Consumer Devices) 100 > > > # 0x09, 0x01, // Usage (Consumer Control) 102 > > > # 0xa1, 0x01, // Collection (Application) 104 > > > # 0x85, 0x03, // Report ID (3) 106 > > > # 0x19, 0x00, // Usage Minimum (0) 108 > > > # 0x2a, 0xff, 0x07, // Usage Maximum (2047) 110 > > > # 0x15, 0x00, // Logical Minimum (0) 113 > > > # 0x26, 0xff, 0x07, // Logical Maximum (2047) 115 > > > # 0x95, 0x01, // Report Count (1) 118 > > > # 0x75, 0x18, // Report Size (24) 120 > > > # 0x81, 0x00, // Input (Data,Arr,Abs) 122 > > > # 0xc0, // End Collection 124 > > > # 0x05, 0x01, // Usage Page (Generic Desktop) 125 > > > # 0x09, 0x06, // Usage (Keyboard) 127 > > > # 0xa1, 0x01, // Collection (Application) 129 > > > # 0x85, 0x04, // Report ID (4) 131 > > > # 0x05, 0x07, // Usage Page (Keyboard) 133 > > > # 0x95, 0x01, // Report Count (1) 135 > > > # 0x75, 0x08, // Report Size (8) 137 > > > # 0x81, 0x03, // Input (Cnst,Var,Abs) 139 > > > # 0x95, 0xe8, // Report Count (232) 141 > > > # 0x75, 0x01, // Report Size (1) 143 > > > # 0x15, 0x00, // Logical Minimum (0) 145 > > > # 0x25, 0x01, // Logical Maximum (1) 147 > > > # 0x05, 0x07, // Usage Page (Keyboard) 149 > > > # 0x19, 0x00, // Usage Minimum (0) 151 > > > # 0x29, 0xe7, // Usage Maximum (231) 153 > > > # 0x81, 0x00, // Input (Data,Arr,Abs) 155 > > > # 0xc0, // End Collection 157 > > > # 0x05, 0x01, // Usage Page (Generic Desktop) 158 > > > # 0x09, 0x0c, // Usage (Wireless Radio Controls) 160 > > > # 0xa1, 0x01, // Collection (Application) 162 > > > # 0x85, 0x08, // Report ID (8) 164 > > > # 0x15, 0x00, // Logical Minimum (0) 166 > > > # 0x25, 0x01, // Logical Maximum (1) 168 > > > # 0x09, 0xc6, // Usage (Wireless Radio Button) 170 > > > # 0x95, 0x01, // Report Count (1) 172 > > > # 0x75, 0x01, // Report Size (1) 174 > > > # 0x81, 0x06, // Input (Data,Var,Rel) 176 > > > # 0x75, 0x07, // Report Size (7) 178 > > > # 0x81, 0x03, // Input (Cnst,Var,Abs) 180 > > > # 0xc0, // End Collection 182 > > > # 0x06, 0xa0, 0xff, // Usage Page (Vendor Usage Page 0xffa0) 183 > > > # 0x09, 0x01, // Usage (Vendor Usage 0x01) 186 > > > # 0xa1, 0x01, // Collection (Application) 188 > > > # 0x85, 0x09, // Report ID (9) 190 > > > # 0x09, 0x01, // Usage (Vendor Usage 0x01) 192 > > > # 0x75, 0x08, // Report Size (8) 194 > > > # 0x95, 0x02, // Report Count (2) 196 > > > # 0x91, 0x82, // Output (Data,Var,Abs,Vol) 198 > > > # 0x09, 0x02, // Usage (Vendor Usage 0x02) 200 > > > # 0x75, 0x08, // Report Size (8) 202 > > > # 0x95, 0x02, // Report Count (2) 204 > > > # 0x81, 0x82, // Input (Data,Var,Abs,Vol) 206 > > > # 0xc0, // End Collection 208 > > > # 0x06, 0xa1, 0xff, // Usage Page (Vendor Usage Page 0xffa1) 209 > > > # 0x09, 0x11, // Usage (Vendor Usage 0x11) 212 > > > # 0xa1, 0x01, // Collection (Application) 214 > > > # 0x85, 0x54, // Report ID (84) 216 > > > # 0x09, 0x11, // Usage (Vendor Usage 0x11) 218 > > > # 0x75, 0x08, // Report Size (8) 220 > > > # 0x95, 0x01, // Report Count (1) 222 > > > # 0xb1, 0x02, // Feature (Data,Var,Abs) 224 > > > # 0xc0, // End Collection 226 > > > # 0x06, 0xa3, 0xff, // Usage Page (Vendor Usage Page 0xffa3) 227 > > > # 0x09, 0x13, // Usage (Vendor Usage 0x13) 230 > > > # 0xa1, 0x01, // Collection (Application) 232 > > > # 0x85, 0x74, // Report ID (116) 234 > > > # 0x09, 0x13, // Usage (Vendor Usage 0x13) 236 > > > # 0x75, 0x08, // Report Size (8) 238 > > > # 0x95, 0x01, // Report Count (1) 240 > > > # 0xb1, 0x02, // Feature (Data,Var,Abs) 242 > > > # 0xc0, // End Collection 244 > > > # 0x06, 0xa2, 0xff, // Usage Page (Vendor Usage Page 0xffa2) 245 > > > # 0x09, 0x12, // Usage (Vendor Usage 0x12) 248 > > > # 0xa1, 0x01, // Collection (Application) 250 > > > # 0x85, 0x64, // Report ID (100) 252 > > > # 0x09, 0x12, // Usage (Vendor Usage 0x12) 254 > > > # 0x75, 0x08, // Report Size (8) 256 > > > # 0x95, 0x01, // Report Count (1) 258 > > > # 0xb1, 0x02, // Feature (Data,Var,Abs) 260 > > > # 0xc0, // End Collection 262 > > > # 0x06, 0xa6, 0xff, // Usage Page (Vendor Usage Page 0xffa6) 263 > > > # 0x09, 0x16, // Usage (Vendor Usage 0x16) 266 > > > # 0xa1, 0x01, // Collection (Application) 268 > > > # 0x85, 0xb4, // Report ID (180) 270 > > > # 0x09, 0x16, // Usage (Vendor Usage 0x16) 272 > > > # 0x75, 0x08, // Report Size (8) 274 > > > # 0x95, 0x01, // Report Count (1) 276 > > > # 0xb1, 0x02, // Feature (Data,Var,Abs) 278 > > > # 0xc0, // End Collection 280 > > > # 0x06, 0xa8, 0xff, // Usage Page (Vendor Usage Page 0xffa8) 281 > > > # 0x09, 0x18, // Usage (Vendor Usage 0x18) 284 > > > # 0xa1, 0x01, // Collection (Application) 286 > > > # 0x85, 0xc4, // Report ID (196) 288 > > > # 0x09, 0x18, // Usage (Vendor Usage 0x18) 290 > > > # 0x75, 0x08, // Report Size (8) 292 > > > # 0x95, 0x01, // Report Count (1) 294 > > > # 0xb1, 0x02, // Feature (Data,Var,Abs) 296 > > > # 0xc0, // End Collection 298 > > > # > > > R: 299 05 01 09 02 a1 01 85 01 09 01 a1 00 05 09 15 00 25 01 19 01 29 > > > 05 75 01 95 05 81 02 95 03 81 01 05 01 16 01 80 26 ff 7f 09 30 09 31 > > > 75 10 95 02 81 06 15 81 25 7f 09 38 75 08 95 01 81 06 05 0c 0a 38 02 > > > 95 01 81 06 c0 c0 05 01 09 80 a1 01 85 02 19 81 29 83 15 00 25 01 75 > > > 01 95 03 81 02 95 05 81 01 c0 05 0c 09 01 a1 01 85 03 19 00 2a ff 07 > > > 15 00 26 ff 07 95 01 75 18 81 00 c0 05 01 09 06 a1 01 85 04 05 07 95 > > > 01 75 08 81 03 95 e8 75 01 15 00 25 01 05 07 19 00 29 e7 81 00 c0 05 > > > 01 09 0c a1 01 85 08 15 00 25 01 09 c6 95 01 75 01 81 06 75 07 81 03 > > > c0 06 a0 ff 09 01 a1 01 85 09 09 01 75 08 95 02 91 82 09 02 75 08 95 > > > 02 81 82 c0 06 a1 ff 09 11 a1 01 85 54 09 11 75 08 95 01 b1 02 c0 06 > > > a3 ff 09 13 a1 01 85 74 09 13 75 08 95 01 b1 02 c0 06 a2 ff 09 12 a1 > > > 01 85 64 09 12 75 08 95 01 b1 02 c0 06 a6 ff 09 16 a1 01 85 b4 09 16 > > > 75 08 95 01 b1 02 c0 06 a8 ff 09 18 a1 01 85 c4 09 18 75 08 95 01 b1 > > > 02 c0 > > > N: Darfon ThinkPad X12 Detachable Gen 2 Folio Keyboard > > > I: 3 17ef 61ae > > > # ReportID: 3 /Consumer Devices ['Generic GUIApplication Controls'] > > > E: 000000.000000 4 03 00 02 00 > > > # ReportID: 3 /Consumer Devices ['0xc0000'] > > > E: 000000.132007 4 03 00 00 00 > > > # ReportID: 3 /Consumer Devices ['Generic GUIApplication Controls'] > > > E: 000009.547181 4 03 00 02 00 > > > # ReportID: 3 /Consumer Devices ['0xc0000'] > > > E: 000009.634834 4 03 00 00 00 > > > # ReportID: 3 /Consumer Devices ['0xc0008'] > > > E: 000014.439367 4 03 08 00 00 > > > # ReportID: 3 /Consumer Devices ['0xc0000'] > > > E: 000014.623384 4 03 00 00 00 > > > # ReportID: 3 /Consumer Devices [] > > > E: 000019.087751 4 03 10 00 37 > > > # ReportID: 3 /Consumer Devices ['0xc0000'] > > > E: 000019.311717 4 03 00 00 00 > > > # ReportID: 3 /Consumer Devices ['Microphone'] > > > E: 000019.951779 4 03 04 00 00 > > > # ReportID: 3 /Consumer Devices ['0xc0000'] > > > E: 000020.107736 4 03 00 00 00 > > > # ReportID: 3 /Consumer Devices ['0xc0008'] > > > E: 000025.516053 4 03 08 00 00 > > > # ReportID: 3 /Consumer Devices ['0xc0000'] > > > E: 000025.656104 4 03 00 00 00 > > > # ReportID: 3 /Consumer Devices ['Generic GUIApplication Controls'] > > > E: 000056.272830 4 03 00 02 00 > > > # ReportID: 3 /Consumer Devices ['0xc0000'] > > > E: 000056.404601 4 03 00 00 00 > > > # ReportID: 3 /Consumer Devices [] > > > E: 000060.665584 4 03 10 00 38 > > > # ReportID: 3 /Consumer Devices ['0xc0000'] > > > E: 000060.852819 4 03 00 00 00 > > > # ReportID: 3 /Consumer Devices ['Microphone'] > > > E: 000069.436756 4 03 04 00 00 > > > # ReportID: 3 /Consumer Devices ['0xc0000'] > > > E: 000069.500424 4 03 00 00 00 > > > # ReportID: 3 /Consumer Devices ['Microphone'] > > > E: 000073.176694 4 03 04 00 00 > > > # ReportID: 3 /Consumer Devices ['0xc0000'] > > > E: 000073.288663 4 03 00 00 00 > > > # ReportID: 3 /Consumer Devices [] > > > E: 000082.328406 4 03 10 00 37 > > > # ReportID: 3 /Consumer Devices ['0xc0000'] > > > E: 000082.460400 4 03 00 00 00 > > > # ReportID: 3 /Consumer Devices ['0xc0008'] > > > E: 000084.784371 4 03 08 00 00 > > > # ReportID: 3 /Consumer Devices ['0xc0000'] > > > E: 000084.944337 4 03 00 00 00 > > > # ReportID: 3 /Consumer Devices [] > > > E: 000088.721089 4 03 10 00 38 > > > # ReportID: 3 /Consumer Devices ['0xc0000'] > > > E: 000088.848242 4 03 00 00 00 > > > # ReportID: 3 /Consumer Devices ['Generic GUIApplication Controls'] > > > E: 000091.423969 4 03 00 02 00 > > > # ReportID: 3 /Consumer Devices ['0xc0000'] > > > E: 000091.539696 4 03 00 00 00 > > > > > > HID recorder is showing Keys differently. ( for eg: F8 key, Which is > > > power profile manager / Airplane mode based on the device ID is not > > > detected). Is this something to do with my implementation? > > > > I thought initially yes, but looking more carefully at your code, you > > are ignoring the return value of lenovo_raw_event_TP_X12_tab(), so in > > theory all the events are still processed by hid-input.c after your > > call. You probably want to change that if we stick to your way of > > processing the events. > I did modify the code as below: > return lenovo_raw_event_TP_X12_tab(hdev, raw_data); > > I got the same results. > > Should I be doing any more additional checks with the return? > > > > > What could happening is that you have multiple hidraw nodes attached to > > the same physical device. And some key sequences might got through a > > different hidraw node. > > > This is correct. Almost all the other keys which is not handled in > this patch are getting through the other hidraw node. > Thats why other keys were working by default. > > It might be worth checking the other nodes when the key sequence doesn't > > seem to output anything. > > > This is Checked. > hidraw0 - Almost all the other keys except those on this patch. > hidraw1 - The FN Keys added in this patch (FN + F7 key going through > hidraw0 and its working without this patch, can be removed). > hidraw3 - Not emitting any key events (I may have missed some special > hot key combinations). > hidraw4 - Touchpad > > > . > > > > > > > > + 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; > > > > > + case TP_X12_RAW_HOTKEY_FN_F7: > > > > > + /* DISPLAY switching when connecting to external monitors*/ > > > > > + report_key_event(input, KEY_SWITCHVIDEOMODE); > > > > > + return 1; > > > > > + default: > > > > > + break; > > > > > + } > > > > > + return 0; > > > > > +} > > > > > + > > > > > static int lenovo_raw_event(struct hid_device *hdev, > > > > > struct hid_report *report, u8 *data, int size) > > > > > { > > > > > + u32 raw_data; > > > > > /* > > > > > * Compact USB keyboard's Fn-F12 report holds down many other keys, and > > > > > * its own key is outside the usage page range. Remove extra > > > > > @@ -695,6 +770,32 @@ 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 > > > > > + * For eg: Raw data received for MIC mute is 0x03000200. > > > > > + */ > > > > > + if (unlikely((hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB > > > > > + || hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB2) > > > > > + && size >= 3)) { > > > > > + /* > > > > > + * data[0] is report ID and is same for all 4byte raw_events from this KBD > > > > > + * for eg: Fn+F8 0x03,0x10,0x00,0x38 > > > > > + * report ID here for most of the keys are 0x03. > > > > > + */ > > > > > + if (report->id == 0x03) > > > > > + raw_data = (data[1] << 16) | (data[2] << 8) | data[3]; > > > > > + /* > > > > > + * For some Keys the raw data is 6 bytes long but the last 3 bytes > > > > > + * will be always Zeros. There is no report-id documented. > > > > > + * For eg: for Fn+F7: 0x08,0x00,0x13,0x00,0x00,0x00. > > > > > + * In other words the last 3 bytes are dummy for now. > > > > > + */ > > > > > + else > > > > > + raw_data = (data[0] << 16) | (data[1] << 8) | data[2]; > > > > > > > > This seems error prone: in one case you takes bytes 1-3, and the other > > > > 0-2. > > > > Why not using all the time 0-4, and change your #defines? > > > > > > > > Plus using 4 bytes means you can use le32_to_cpu(data) directly (if I'm > > > > not wrong). > > > > > > > > Which also means that raw_data can be skipped entirely with the > > > > following below: > > > > > > > > lenovo_raw_event_TP_X12_tab(hdev, le32_to_cpu(data)); > > > > > > Understood and acknowledged. > > > I will test using le32_to_cpu(data) function. > > > > > > > > > > > > + > > > > > + /* Calling function to generate Key events */ > > > > > + lenovo_raw_event_TP_X12_tab(hdev, raw_data); > > > > > + } > > > > > return 0; > > > > > } > > > > > > > > > > @@ -774,6 +875,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: > > > > > return lenovo_event_tp10ubkbd(hdev, field, usage, value); > > > > > @@ -1054,6 +1157,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: > > > > > ret = lenovo_led_set_tp10ubkbd(hdev, tp10ubkbd_led[led_nr], value); > > > > > @@ -1239,8 +1344,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 behavious 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); > > > > > > > > If that list grows too much, we will probably have to rely on > > > > .driver_data. But something for later IMO. > > > > > > > Acknowledged > > > > > + > > > > > lenovo_led_set_tp10ubkbd(hdev, TP10UBKBD_FN_LOCK_LED, data->fn_lock); > > > > > > > > > > ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_tp10ubkbd); > > > > > @@ -1284,6 +1396,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: > > > > > ret = lenovo_probe_tp10ubkbd(hdev); > > > > > @@ -1370,6 +1484,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: > > > > > lenovo_remove_tp10ubkbd(hdev); > > > > > @@ -1421,6 +1537,10 @@ static const struct hid_device_id lenovo_devices[] = { > > > > > */ > > > > > { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, > > > > > 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_X12_TAB) }, > > > > > + { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, > > > > > + USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X12_TAB2) }, > > > > > { } > > > > > }; > > > > > > > > > > > > > Cheers, > > Benjamin > > > -- > > Regards, > > Vishnu Sankar -- Regards, Vishnu Sankar +817015150407 (Japan)