commit bc1e4e1ae1d5a4f9b2d263f22c651dd5ba4f8ff9 Author: Kurt Garloff Date: Sun Sep 22 11:54:59 2013 +0200 From: Kurt Garloff Subject: Tolerate wrong direction bit endpoint index for control messages Signed-off-by: Kurt Garloff Trying to read data from the Pegasus Technologies NoteTaker (0e20:0101) [1] with the Windows App (EasyNote) works natively but fails when WIndows is running under KVM (and the USB device handed to KVM). The reason is a USB control message usb 4-2.2: control urb: bRequestType=22 bRequest=09 wValue=0200 wIndex=0001 wLength=0008 This goes to endpoint 1 (wIndex), however, the endpoint is an input endpoint and thus enumerated 0x81. The kernel thus rejects the IO and thus we see the failure. Apparently, Linux is more strict here than Windows ... we can't change the Win app easily, so that's a problem. However, the app might not even be buggy here. Browsing the USB HID spec, there's a note that the bit for direction is ignored for control endpoints ... so Linux might be overly strict? With attached patch, everything works. usb 4-2.2: check_ctrlrecip: process 13073 (qemu-kvm) requesting ep 01 but needs 81 (or 00) Notes: - I have not checked whether the ignorance of the direction bit for control endpoints only applies to USB HID devices, thus I have not special-cased depending on the device type. - We do output a warning into the kernel log, as this might still be caused by an application error. - We don't risk sending to a wrong endpoint, as there can't be two endpoints with same index and just different direction. - I suspect this will mostly affect apps in virtual environments; as on Linux the apps would have been adapted to the stricter handling of the kernel. I have done that for mine[2], although delaying the release by two years .... [1} http://www.pegatech.com/ [2] https://sourceforge.net/projects/notetakerpen/ diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index c2f62a3..8acbc2f 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -623,6 +623,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, switch (requesttype & USB_RECIP_MASK) { case USB_RECIP_ENDPOINT: ret = findintfep(ps->dev, index); + if (ret < 0) { + /* OK, give it a second try -- user might have confused + * direction -- this happens from virtualized win apps + * e.g. -- warn, but be graceful */ + ret = findintfep(ps->dev, index ^ 0x80); + if (ret >= 0) + dev_info(&ps->dev->dev , + "%s: process %i (%s) requesting ep %02x but needs %02x (or 00)\n", + __func__, + task_pid_nr(current), + current->comm, + index, index ^ 0x80); + } if (ret >= 0) ret = checkintf(ps, ret); break;