[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20251118020723.6600-1-blhoward2@gmail.com>
Date: Mon, 17 Nov 2025 21:07:21 -0500
From: Brian Howard <blhoward2@...il.com>
To:
Cc: blhoward2@...il.com,
Andrei Shumailov <gentoo1993@...il.com>,
Jiri Kosina <jikos@...nel.org>,
Benjamin Tissoires <bentiss@...nel.org>,
linux-input@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: [PATCH] HID: multitouch: add quirks for Lenovo Yoga Book 9i
Add required quirks for Lenovo Yoga Book 9i Gen 8 to Gen 10 models,
including a new quirk providing for custom input device naming and
dropping erroneous InRange reports.
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 (with everything other than X/Y
as 0) being received after the stylus leaves proximity, blocking later
touch events.
Signed-off-by: Brian Howard <blhoward2@...il.com>
Tested-by: Brian Howard <blhoward2@...il.com>
Reported-by: Andrei Shumailov <gentoo1993@...il.com>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220386
---
drivers/hid/hid-ids.h | 1 +
drivers/hid/hid-multitouch.c | 73 ++++++++++++++++++++++++++++++++++++
2 files changed, 74 insertions(+)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 0723b4b1c9ec..e896a6310bb2 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -833,6 +833,7 @@
#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
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 179dc316b4b5..a828aac59cb2 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -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
@@ -229,6 +230,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
@@ -424,6 +426,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
},
{ }
};
@@ -1557,6 +1567,7 @@ static void mt_report(struct hid_device *hid, struct hid_report *report)
struct mt_device *td = hid_get_drvdata(hid);
struct hid_field *field = report->field[0];
struct mt_report_data *rdata;
+ int f, i;
if (!(hid->claimed & HID_CLAIMED_INPUT))
return;
@@ -1565,6 +1576,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 (f = 0; f < report->maxfield && all_zero_report; f++) {
+ struct hid_field *fld = report->field[f];
+
+ for (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);
}
@@ -1761,6 +1804,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);
@@ -2266,6 +2333,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,
--
2.49.0
Powered by blists - more mailing lists