Hi, I've recently come across a uaudio device which doesn't work in OpenBSD:
uaudio2 at uhub0 port 1 configuration 1 interface 3 "E+ Corp. DAC Audio" rev 1.10/0.01 addr 2 uaudio2: class v1, full-speed, async, channels: 2 play, 0 rec, 3 ctls audio3 at uaudio2 When opening the audio device, the kernel reports `uaudio0: can't get iface handle` in the dmesg buffer. I posted information about the device and sthen@ and kettenis@ spotted the problem: the device exposes non-consecutive interface numbers, and is thus not compliant with the USB standard. It has interfaces 0, 1 and 3, in that order. The audio stream is on interface 3, which the kernel expects to find at index 3 in the ifaces array, but actually it's at index 2! I've pasted a load of info about the device (lsusb and debug kernel output) here: https://gist.github.com/vext01/958756d0fd515cc321f99a3ee1e3351a The following diff makes this device work. It searches the ifaces array in the event that the correct entry is not found at the expect index. This should be a "no functional change" for all existing compliant devices. I've tested this for the past two days and all seems well, but I'd like some USB stack hackers to verify it. Cheers Index: usbdi.c =================================================================== RCS file: /cvs/src/sys/dev/usb/usbdi.c,v retrieving revision 1.106 diff -u -p -r1.106 usbdi.c --- usbdi.c 3 Apr 2020 20:11:47 -0000 1.106 +++ usbdi.c 24 Jan 2021 20:44:28 -0000 @@ -638,12 +638,23 @@ usbd_status usbd_device2interface_handle(struct usbd_device *dev, u_int8_t ifaceno, struct usbd_interface **iface) { + u_int8_t idx; + if (dev->cdesc == NULL) return (USBD_NOT_CONFIGURED); - if (ifaceno >= dev->cdesc->bNumInterface) - return (USBD_INVAL); - *iface = &dev->ifaces[ifaceno]; - return (USBD_NORMAL_COMPLETION); + if (ifaceno < dev->cdesc->bNumInterface && + dev->ifaces[ifaceno].idesc->bInterfaceNumber == ifaceno) { + *iface = &dev->ifaces[ifaceno]; + return (USBD_NORMAL_COMPLETION); + } + /* With some non-compliant devices, the interface may be at the wrong index */ + for (idx = 0; idx < dev->cdesc->bNumInterface; idx++) { + if (dev->ifaces[idx].idesc->bInterfaceNumber == ifaceno) { + *iface = &dev->ifaces[idx]; + return (USBD_NORMAL_COMPLETION); + } + } + return (USBD_INVAL); } /* XXXX use altno */ -- Best Regards Edd Barrett http://www.theunixzoo.co.uk