MT_QUIRK_CONTACT_CNT_ACCURATE,
},
{ .name = MT_CLS_YOGABOOK9I,
- .quirks = MT_QUIRK_ALWAYS_VALID |
+ .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
+ MT_QUIRK_ALWAYS_VALID |
MT_QUIRK_FORCE_MULTI_INPUT |
MT_QUIRK_SEPARATE_APP_REPORT |
MT_QUIRK_HOVERING |
MT_QUIRK_YOGABOOK9I,
+ .maxcontacts = 10,
.export_all_inputs = true
},
{ .name = MT_CLS_EGALAX_P80H84,
return 0;
}
+/*
+ * Yoga Book 9 14IAH10 descriptor fixup.
+ *
+ * The device includes a HID_DG_TOUCHPAD application collection designed for
+ * the Windows inbox HID driver's Win8 PTP touchpad mode. On Linux we want
+ * only the HID_DG_TOUCHSCREEN collections. The touchpad collection (and the
+ * HID_DG_BUTTONTYPE and Win8 compliance blob features it contains) must be
+ * removed so hid-multitouch does not misclassify the touchscreen nodes as
+ * indirect buttonpads.
+ *
+ * The firmware also resets if any USB control request is received while the
+ * CDC-ACM interface is initialising (~1.18 s after enumeration). Dropping
+ * the Win8 blob and Contact Count Max feature reports prevents the
+ * GET_REPORT calls that hid-multitouch issues at probe.
+ */
+static void mt_yogabook9_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *size)
+{
+ /* Usage Page (Digitizer), Usage (Touch Pad), Collection (Application) */
+ static const __u8 tp_app_hdr[] = { 0x05, 0x0d, 0x09, 0x05, 0xa1, 0x01 };
+ /* Vendor Usage Page 0xff00 (Win8 compliance blob header) */
+ static const __u8 win8_page[] = { 0x06, 0x00, 0xff };
+ /* Usage (Contact Count Max = 0x55) */
+ static const __u8 ccmax_usage[] = { 0x09, 0x55 };
+ unsigned int i;
+
+ /*
+ * Step 1: find and remove the Touch Pad application collection.
+ * Walk HID short items from the collection header to its matching
+ * End Collection, then close the gap with memmove.
+ */
+ for (i = 0; i + sizeof(tp_app_hdr) <= *size; i++) {
+ if (memcmp(rdesc + i, tp_app_hdr, sizeof(tp_app_hdr)) == 0) {
+ __u8 *start = rdesc + i;
+ __u8 *coll_end = NULL;
+ __u8 *p = start;
+ unsigned int drop;
+ int depth = 0;
+
+ while (p < rdesc + *size) {
+ __u8 b = *p;
+ int ds = b & 3;
+ int item_len;
+
+ if (b == 0xfe) { /* long item */
+ if (p + 2 >= rdesc + *size)
+ break;
+ item_len = p[1] + 3;
+ } else {
+ item_len = (ds == 3) ? 5 : ds + 1;
+ }
+ if (p + item_len > rdesc + *size)
+ break;
+
+ if ((b & 0xfc) == 0xa0)
+ depth++; /* Collection */
+ else if (b == 0xc0) {
+ depth--; /* End Collection */
+ if (depth == 0) {
+ coll_end = p;
+ break;
+ }
+ }
+ p += item_len;
+ }
+
+ if (!coll_end) {
+ hid_err(hdev,
+ "Yoga Book 9: Touch Pad End Collection not found\n");
+ break;
+ }
+
+ drop = coll_end - start + 1;
+ memmove(start, coll_end + 1, rdesc + *size - coll_end - 1);
+ *size -= drop;
+ hid_dbg(hdev,
+ "Yoga Book 9: dropped Touch Pad collection (%u bytes)\n",
+ drop);
+ break;
+ }
+ }
+
+ /*
+ * Step 2: neutralize Win8 compliance blob feature reports remaining
+ * in the touchscreen collections. Change Usage Page 0xff00 to 0x0f00
+ * so the case 0xff0000c5 branch in mt_feature_mapping() is not reached
+ * and no GET_REPORT is issued.
+ */
+ for (i = 0; i + sizeof(win8_page) <= *size; i++) {
+ if (memcmp(rdesc + i, win8_page, sizeof(win8_page)) == 0) {
+ rdesc[i + 2] = 0x0f; /* 0xff00 -> 0x0f00 */
+ hid_dbg(hdev,
+ "Yoga Book 9: neutralized Win8 blob at offset %u\n",
+ i);
+ }
+ }
+
+ /*
+ * Step 3: neutralize Contact Count Max feature reports. Change usage
+ * 0x55 (HID_DG_CONTACTMAX) to 0x00 so mt_feature_mapping() does not
+ * issue GET_REPORT. The class maxcontacts field provides the value.
+ */
+ for (i = 0; i + sizeof(ccmax_usage) <= *size; i++) {
+ if (memcmp(rdesc + i, ccmax_usage, sizeof(ccmax_usage)) == 0) {
+ rdesc[i + 1] = 0x00;
+ hid_dbg(hdev,
+ "Yoga Book 9: neutralized ContactMax at offset %u\n",
+ i);
+ }
+ }
+
+ /*
+ * Step 4: neutralize Surface Switch (0x57) and Button Switch (0x58)
+ * feature report usages in the Device Configuration collection.
+ * mt_set_modes() issues HID_REQ_SET_REPORT for these on every
+ * input-device open/close; those repeated control requests hit the
+ * firmware's CDC-ACM init window and trigger resets.
+ *
+ * Input Mode (0x52) is intentionally left intact. mt_set_modes()
+ * sends it once at probe to set the device into touchscreen mode,
+ * which flushes the firmware's contact buffer and clears a persistent
+ * ghost contact (cid 2, fixed coordinates) that otherwise appears on
+ * every enumeration. By probe time cdc_acm has already satisfied the
+ * CDC-ACM init watchdog (~130 ms), so the single SET_REPORT for Input
+ * Mode arrives safely after the reset window has closed.
+ */
+ for (i = 0; i + 2 <= *size; i++) {
+ if (rdesc[i] == 0x09 &&
+ (rdesc[i + 1] == 0x57 ||
+ rdesc[i + 1] == 0x58)) {
+ hid_dbg(hdev,
+ "Yoga Book 9: neutralized set-modes usage 0x%02x at offset %u\n",
+ rdesc[i + 1], i);
+ rdesc[i + 1] = 0x00;
+ }
+ }
+}
+
static const __u8 *mt_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *size)
{
}
}
+ if (hdev->vendor == USB_VENDOR_ID_LENOVO &&
+ hdev->product == USB_DEVICE_ID_LENOVO_YOGABOOK9I)
+ mt_yogabook9_fixup(hdev, rdesc, size);
+
return rdesc;
}