Skip to content

Commit 822bc5b

Browse files
blhoward2Jiri Kosina
authored andcommitted
HID: multitouch: add quirks for Lenovo Yoga Book 9i
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>
1 parent e680764 commit 822bc5b

2 files changed

Lines changed: 73 additions & 0 deletions

File tree

drivers/hid/hid-ids.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,7 @@
841841
#define USB_DEVICE_ID_LENOVO_X1_TAB3 0x60b5
842842
#define USB_DEVICE_ID_LENOVO_X12_TAB 0x60fe
843843
#define USB_DEVICE_ID_LENOVO_X12_TAB2 0x61ae
844+
#define USB_DEVICE_ID_LENOVO_YOGABOOK9I 0x6161
844845
#define USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E 0x600e
845846
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D 0x608d
846847
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019 0x6019

drivers/hid/hid-multitouch.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ MODULE_LICENSE("GPL");
7676
#define MT_QUIRK_DISABLE_WAKEUP BIT(21)
7777
#define MT_QUIRK_ORIENTATION_INVERT BIT(22)
7878
#define MT_QUIRK_APPLE_TOUCHBAR BIT(23)
79+
#define MT_QUIRK_YOGABOOK9I BIT(24)
7980

8081
#define MT_INPUTMODE_TOUCHSCREEN 0x02
8182
#define MT_INPUTMODE_TOUCHPAD 0x03
@@ -231,6 +232,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
231232
#define MT_CLS_RAZER_BLADE_STEALTH 0x0112
232233
#define MT_CLS_SMART_TECH 0x0113
233234
#define MT_CLS_APPLE_TOUCHBAR 0x0114
235+
#define MT_CLS_YOGABOOK9I 0x0115
234236
#define MT_CLS_SIS 0x0457
235237

236238
#define MT_DEFAULT_MAXCONTACT 10
@@ -427,6 +429,14 @@ static const struct mt_class mt_classes[] = {
427429
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
428430
MT_QUIRK_ALWAYS_VALID |
429431
MT_QUIRK_CONTACT_CNT_ACCURATE,
432+
},
433+
{ .name = MT_CLS_YOGABOOK9I,
434+
.quirks = MT_QUIRK_ALWAYS_VALID |
435+
MT_QUIRK_FORCE_MULTI_INPUT |
436+
MT_QUIRK_SEPARATE_APP_REPORT |
437+
MT_QUIRK_HOVERING |
438+
MT_QUIRK_YOGABOOK9I,
439+
.export_all_inputs = true
430440
},
431441
{ }
432442
};
@@ -1576,6 +1586,38 @@ static void mt_report(struct hid_device *hid, struct hid_report *report)
15761586
if (rdata && rdata->is_mt_collection)
15771587
return mt_touch_report(hid, rdata);
15781588

1589+
/* Lenovo Yoga Book 9i requires consuming and dropping certain bogus reports */
1590+
if (rdata && rdata->application &&
1591+
(rdata->application->quirks & MT_QUIRK_YOGABOOK9I)) {
1592+
1593+
bool all_zero_report = true;
1594+
1595+
for (int f = 0; f < report->maxfield && all_zero_report; f++) {
1596+
struct hid_field *fld = report->field[f];
1597+
1598+
for (int i = 0; i < fld->report_count; i++) {
1599+
unsigned int usage = fld->usage[i].hid;
1600+
1601+
if (usage == HID_DG_INRANGE ||
1602+
usage == HID_DG_TIPSWITCH ||
1603+
usage == HID_DG_BARRELSWITCH ||
1604+
usage == HID_DG_BARRELSWITCH2 ||
1605+
usage == HID_DG_CONTACTID ||
1606+
usage == HID_DG_TILT_X ||
1607+
usage == HID_DG_TILT_Y) {
1608+
1609+
if (fld->value[i] != 0) {
1610+
all_zero_report = false;
1611+
break;
1612+
}
1613+
}
1614+
}
1615+
}
1616+
1617+
if (all_zero_report)
1618+
return;
1619+
}
1620+
15791621
if (field && field->hidinput && field->hidinput->input)
15801622
input_sync(field->hidinput->input);
15811623
}
@@ -1772,6 +1814,30 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
17721814
break;
17731815
}
17741816

1817+
/* Lenovo Yoga Book 9i requires custom naming to allow differentiation in udev */
1818+
if (hi->report && td->mtclass.quirks & MT_QUIRK_YOGABOOK9I) {
1819+
switch (hi->report->id) {
1820+
case 48:
1821+
suffix = "Touchscreen Top";
1822+
break;
1823+
case 56:
1824+
suffix = "Touchscreen Bottom";
1825+
break;
1826+
case 20:
1827+
suffix = "Stylus Top";
1828+
break;
1829+
case 40:
1830+
suffix = "Stylus Bottom";
1831+
break;
1832+
case 80:
1833+
suffix = "Emulated Touchpad";
1834+
break;
1835+
default:
1836+
suffix = "";
1837+
break;
1838+
}
1839+
}
1840+
17751841
if (suffix) {
17761842
hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
17771843
"%s %s", hdev->name, suffix);
@@ -2277,6 +2343,12 @@ static const struct hid_device_id mt_devices[] = {
22772343
USB_VENDOR_ID_LENOVO,
22782344
USB_DEVICE_ID_LENOVO_X12_TAB2) },
22792345

2346+
/* Lenovo Yoga Book 9i */
2347+
{ .driver_data = MT_CLS_YOGABOOK9I,
2348+
HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8,
2349+
USB_VENDOR_ID_LENOVO,
2350+
USB_DEVICE_ID_LENOVO_YOGABOOK9I) },
2351+
22802352
/* Logitech devices */
22812353
{ .driver_data = MT_CLS_NSMU,
22822354
HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH_WIN_8,

0 commit comments

Comments
 (0)