]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
HID: multitouch: add quirks for Lenovo Yoga Book 9i
authorBrian Howard <blhoward2@gmail.com>
Wed, 3 Dec 2025 02:35:47 +0000 (21:35 -0500)
committerJiri Kosina <jkosina@suse.com>
Sat, 10 Jan 2026 09:04:59 +0000 (10:04 +0100)
The Lenovo Yoga Book 9i is a dual-screen laptop, with a single composite
USB device providing both touch and tablet interfaces for both screens.
All inputs report through a single device, differentiated solely by report
numbers. As there is no way for udev to differentiate the inputs based on
USB vendor/product ID or interface numbers, custom naming is required to
match against for downstream configuration. A firmware bug also results
in an erroneous InRange message report being received after the stylus
leaves proximity, blocking later touch events. Add required quirks for
Gen 8 to Gen 10 models, including a new quirk providing for custom input
device naming and dropping erroneous InRange reports.

Signed-off-by: Brian Howard <blhoward2@gmail.com>
Tested-by: Brian Howard <blhoward2@gmail.com>
Tested-by: Kris Fredrick <linux.baguette800@slmail.me>
Reported-by: Andrei Shumailov <gentoo1993@gmail.com>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220386
Signed-off-by: Jiri Kosina <jkosina@suse.com>
drivers/hid/hid-ids.h
drivers/hid/hid-multitouch.c

index 943399e2b44420e0743845686679c4c723f58431..40364cd69f8e3d5d31eb7eeb92f31781d37542db 100644 (file)
 #define USB_DEVICE_ID_LENOVO_X1_TAB3   0x60b5
 #define USB_DEVICE_ID_LENOVO_X12_TAB   0x60fe
 #define USB_DEVICE_ID_LENOVO_X12_TAB2  0x61ae
+#define USB_DEVICE_ID_LENOVO_YOGABOOK9I        0x6161
 #define USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E    0x600e
 #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D     0x608d
 #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019     0x6019
index b1c3ef1290587780c7f68f53a34ac575c2fd7c92..f21850f7d89e4dd92553d5e251921eb7f146e6b5 100644 (file)
@@ -76,6 +76,7 @@ MODULE_LICENSE("GPL");
 #define MT_QUIRK_DISABLE_WAKEUP                BIT(21)
 #define MT_QUIRK_ORIENTATION_INVERT    BIT(22)
 #define MT_QUIRK_APPLE_TOUCHBAR                BIT(23)
+#define MT_QUIRK_YOGABOOK9I            BIT(24)
 
 #define MT_INPUTMODE_TOUCHSCREEN       0x02
 #define MT_INPUTMODE_TOUCHPAD          0x03
@@ -231,6 +232,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
 #define MT_CLS_RAZER_BLADE_STEALTH             0x0112
 #define MT_CLS_SMART_TECH                      0x0113
 #define MT_CLS_APPLE_TOUCHBAR                  0x0114
+#define MT_CLS_YOGABOOK9I                      0x0115
 #define MT_CLS_SIS                             0x0457
 
 #define MT_DEFAULT_MAXCONTACT  10
@@ -427,6 +429,14 @@ static const struct mt_class mt_classes[] = {
                .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
                        MT_QUIRK_ALWAYS_VALID |
                        MT_QUIRK_CONTACT_CNT_ACCURATE,
+       },
+               { .name = MT_CLS_YOGABOOK9I,
+               .quirks = MT_QUIRK_ALWAYS_VALID |
+                       MT_QUIRK_FORCE_MULTI_INPUT |
+                       MT_QUIRK_SEPARATE_APP_REPORT |
+                       MT_QUIRK_HOVERING |
+                       MT_QUIRK_YOGABOOK9I,
+               .export_all_inputs = true
        },
        { }
 };
@@ -1576,6 +1586,38 @@ static void mt_report(struct hid_device *hid, struct hid_report *report)
        if (rdata && rdata->is_mt_collection)
                return mt_touch_report(hid, rdata);
 
+       /* Lenovo Yoga Book 9i requires consuming and dropping certain bogus reports */
+       if (rdata && rdata->application &&
+               (rdata->application->quirks & MT_QUIRK_YOGABOOK9I)) {
+
+               bool all_zero_report = true;
+
+               for (int f = 0; f < report->maxfield && all_zero_report; f++) {
+                       struct hid_field *fld = report->field[f];
+
+                       for (int i = 0; i < fld->report_count; i++) {
+                               unsigned int usage = fld->usage[i].hid;
+
+                               if (usage == HID_DG_INRANGE ||
+                                       usage == HID_DG_TIPSWITCH ||
+                                       usage == HID_DG_BARRELSWITCH ||
+                                       usage == HID_DG_BARRELSWITCH2 ||
+                                       usage == HID_DG_CONTACTID ||
+                                       usage == HID_DG_TILT_X ||
+                                       usage == HID_DG_TILT_Y) {
+
+                                       if (fld->value[i] != 0) {
+                                               all_zero_report = false;
+                                               break;
+                                       }
+                               }
+                       }
+               }
+
+               if (all_zero_report)
+                       return;
+       }
+
        if (field && field->hidinput && field->hidinput->input)
                input_sync(field->hidinput->input);
 }
@@ -1772,6 +1814,30 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
                break;
        }
 
+       /* Lenovo Yoga Book 9i requires custom naming to allow differentiation in udev */
+       if (hi->report && td->mtclass.quirks & MT_QUIRK_YOGABOOK9I) {
+               switch (hi->report->id) {
+               case 48:
+                       suffix = "Touchscreen Top";
+                       break;
+               case 56:
+                       suffix = "Touchscreen Bottom";
+                       break;
+               case 20:
+                       suffix = "Stylus Top";
+                       break;
+               case 40:
+                       suffix = "Stylus Bottom";
+                       break;
+               case 80:
+                       suffix = "Emulated Touchpad";
+                       break;
+               default:
+                       suffix = "";
+                       break;
+               }
+       }
+
        if (suffix) {
                hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
                                                 "%s %s", hdev->name, suffix);
@@ -2277,6 +2343,12 @@ static const struct hid_device_id mt_devices[] = {
                           USB_VENDOR_ID_LENOVO,
                           USB_DEVICE_ID_LENOVO_X12_TAB2) },
 
+       /* Lenovo Yoga Book 9i */
+       { .driver_data = MT_CLS_YOGABOOK9I,
+               HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8,
+                          USB_VENDOR_ID_LENOVO,
+                          USB_DEVICE_ID_LENOVO_YOGABOOK9I) },
+
        /* Logitech devices */
        { .driver_data = MT_CLS_NSMU,
                HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH_WIN_8,