Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

USB: cdc-acm: Add quirks for Yoga Book 9 14IAH10 INGENIC touchscreen

The Lenovo Yoga Book 9 14IAH10 (83KJ) has a composite USB device
(17EF:6161) that controls both touchscreens via a CDC ACM interface.
Interface 0 is a standard CDC ACM control interface, but interface 1
(the data interface) incorrectly declares vendor-specific class (0xFF)
instead of USB_CLASS_CDC_DATA. cdc-acm rejects the device at probe with
-EINVAL, leaving interface 0 unbound and EP 0x82 never polled.

With no consumer polling EP 0x82, the firmware's watchdog fires every
~20 seconds and resets the USB bus, producing a continuous disconnect/
reconnect loop that prevents the touchscreens from ever initialising.

Add two new quirk flags:

VENDOR_CLASS_DATA_IFACE: Bypasses the bInterfaceClass check in
acm_probe() that would otherwise reject the vendor-class data
interface with -EINVAL.

ALWAYS_POLL_CTRL: Submits the notification URB at probe() rather than
waiting for a TTY open. This keeps EP 0x82 polled at all times,
permanently suppressing the firmware watchdog. The URB is resubmitted
after port_shutdown() and on system resume. SET_CONTROL_LINE_STATE
(DTR|RTS) is sent at probe and after port_shutdown() to complete
firmware handshake.

Note: the firmware performs exactly 4 USB connect/disconnect cycles
(~19 s each) on every cold boot before stabilising. This is a fixed
firmware property; touch is available ~75-80 s after power-on.

Signed-off-by: Dave Carey <carvsdriver@gmail.com>
Cc: stable <stable@kernel.org>
Tested-by: Dave Carey <carvsdriver@gmail.com>
Acked-by: Oliver Neukum <oneukum@suse.com>
Link: https://patch.msgid.link/20260402182950.389016-1-carvsdriver@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Dave Carey and committed by
Greg Kroah-Hartman
f58752eb 609865ab

+46 -7
+46 -7
drivers/usb/class/cdc-acm.c
··· 114 114 int retval; 115 115 116 116 retval = usb_autopm_get_interface(acm->control); 117 + #define VENDOR_CLASS_DATA_IFACE BIT(9) /* data interface uses vendor-specific class */ 118 + #define ALWAYS_POLL_CTRL BIT(10) /* keep ctrl URB active even without an open TTY */ 117 119 if (retval) 118 120 return retval; 119 121 ··· 712 710 set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); 713 711 acm->control->needs_remote_wakeup = 1; 714 712 715 - acm->ctrlurb->dev = acm->dev; 716 - retval = usb_submit_urb(acm->ctrlurb, GFP_KERNEL); 717 - if (retval) { 718 - dev_err(&acm->control->dev, 719 - "%s - usb_submit_urb(ctrl irq) failed\n", __func__); 720 - goto error_submit_urb; 713 + if (!(acm->quirks & ALWAYS_POLL_CTRL)) { 714 + acm->ctrlurb->dev = acm->dev; 715 + retval = usb_submit_urb(acm->ctrlurb, GFP_KERNEL); 716 + if (retval) { 717 + dev_err(&acm->control->dev, 718 + "%s - usb_submit_urb(ctrl irq) failed\n", __func__); 719 + goto error_submit_urb; 720 + } 721 721 } 722 722 723 723 acm_tty_set_termios(tty, NULL); ··· 792 788 793 789 acm_unpoison_urbs(acm); 794 790 791 + if (acm->quirks & ALWAYS_POLL_CTRL) { 792 + acm->ctrlurb->dev = acm->dev; 793 + if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) 794 + dev_dbg(&acm->control->dev, 795 + "ctrl polling restart failed after port close\n"); 796 + /* port_shutdown() cleared DTR/RTS; restore them */ 797 + acm_set_control(acm, USB_CDC_CTRL_DTR | USB_CDC_CTRL_RTS); 798 + } 795 799 } 796 800 797 801 static void acm_tty_cleanup(struct tty_struct *tty) ··· 1340 1328 dev_dbg(&intf->dev, 1341 1329 "Your device has switched interfaces.\n"); 1342 1330 swap(control_interface, data_interface); 1331 + } else if (quirks & VENDOR_CLASS_DATA_IFACE) { 1332 + dev_dbg(&intf->dev, 1333 + "Vendor-specific data interface class, continuing.\n"); 1343 1334 } else { 1344 1335 return -EINVAL; 1345 1336 } ··· 1537 1522 acm->line.bDataBits = 8; 1538 1523 acm_set_line(acm, &acm->line); 1539 1524 1525 + if (quirks & ALWAYS_POLL_CTRL) 1526 + acm_set_control(acm, USB_CDC_CTRL_DTR | USB_CDC_CTRL_RTS); 1527 + 1540 1528 if (!acm->combined_interfaces) { 1541 1529 rv = usb_driver_claim_interface(&acm_driver, data_interface, acm); 1542 1530 if (rv) ··· 1560 1542 } 1561 1543 1562 1544 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); 1545 + 1546 + if (acm->quirks & ALWAYS_POLL_CTRL) { 1547 + acm->ctrlurb->dev = acm->dev; 1548 + if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) 1549 + dev_warn(&intf->dev, 1550 + "failed to start persistent ctrl polling\n"); 1551 + } 1563 1552 1564 1553 return 0; 1565 1554 ··· 1694 1669 1695 1670 acm_unpoison_urbs(acm); 1696 1671 1697 - if (tty_port_initialized(&acm->port)) { 1672 + if (tty_port_initialized(&acm->port) || (acm->quirks & ALWAYS_POLL_CTRL)) { 1698 1673 rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC); 1699 1674 1700 1675 for (;;) { ··· 2040 2015 2041 2016 /* CH343 supports CAP_BRK, but doesn't advertise it */ 2042 2017 { USB_DEVICE(0x1a86, 0x55d3), .driver_info = MISSING_CAP_BRK, }, 2018 + 2019 + /* 2020 + * Lenovo Yoga Book 9 14IAH10 (83KJ) — INGENIC 17EF:6161 touchscreen 2021 + * composite device. The CDC ACM control interface (0) uses a standard 2022 + * Union descriptor, but the data interface (1) is declared as vendor- 2023 + * specific class (0xff) with no CDC data descriptors, so cdc-acm would 2024 + * normally reject it. The firmware also requires continuous polling of 2025 + * the notification endpoint (EP 0x82) to suppress a 20-second watchdog 2026 + * reset; ALWAYS_POLL_CTRL keeps the ctrlurb active even when no TTY is 2027 + * open. Match only the control interface by class to avoid probing the 2028 + * vendor-specific data interface. 2029 + */ 2030 + { USB_DEVICE_INTERFACE_CLASS(0x17ef, 0x6161, USB_CLASS_COMM), 2031 + .driver_info = VENDOR_CLASS_DATA_IFACE | ALWAYS_POLL_CTRL }, 2043 2032 2044 2033 /* control interfaces without any protocol set */ 2045 2034 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,