On Sun, Jun 21, 2020, at 9:09 AM, Alan Stern wrote: > On Sat, Jun 20, 2020 at 10:38:33PM -0500, Sid Spry wrote: > > > When I was using a repurposed audio device I had to set an alternate mode. Is > > that related to the issue here? The alternate mode seems to be a relic of the > > descriptor layout before I dropped the device class and substituted my own > > driver. The current descriptors specify no alternate modes. > > I don't know much about FunctionFS, so I can't help with your main > question about isochronous packets not being dropped. But I can explain > this. > Your responses have been quite helpful; I appreciate them. For those reading along I have gotten a set of descriptors working (detailed below) however write(2) still blocks meaning at least one stale data packet will be received. However, I realize now that typically a writer thread will be sending an asynchronously updated buffer and the single stale packet was probably never noticed, especially for AV applications. Unfortunately for my application the stale packet *does* matter, and I am still seeking a way to mitigate it. > In the USB-2.0 spec, at the end of section 5.6.3 the text says: > > All device default interface settings must not include any > isochronous endpoints with non-zero data payload sizes (specified > via wMaxPacketSize in the endpoint descriptor). Alternate > interface settings may specify non-zero data payload sizes for > isochronous endpoints. > > That's why you had to select an alternate setting before transferring > any isochronous data. Any isochronous endpoint in altsetting 0 must have > its maxpacket size set to 0. > This was the issue. I rely too heavily on the USB audio class spec, I should go through all of the spec. I now must ask the list: What is the relation of the isochronous endpoint setup to the allocated bandwidth on the bus? I understand the limit of 3 1024 byte transfers per frame, but this says nothing about how it will be allocated or how a device is refused bandwidth. Do I need to look for link degradation on the application layer? It seems like having a single non-spec device means the OS can't arbitrate link bandwidth. Also! For the list's consideration I have included an accepted but nonworking configuration that perplexes me. The application note for the original device I used specified a set of descriptors which was like so (device and configuration omitted): (Vendor Microphone Class Descriptors) ``` INTERFACE 0: Vendor Specific =========================== bLength : 0x9 (9 bytes) bDescriptorType : 0x4 Interface bInterfaceNumber : 0x0 bAlternateSetting : 0x0 bNumEndpoints : 0x0 bInterfaceClass : 0xff Vendor Specific bInterfaceSubClass : 0x1 bInterfaceProtocol : 0x0 iInterface : 0x0 INTERFACE 1: Vendor Specific =========================== bLength : 0x9 (9 bytes) bDescriptorType : 0x4 Interface bInterfaceNumber : 0x1 bAlternateSetting : 0x0 bNumEndpoints : 0x0 bInterfaceClass : 0xff Vendor Specific bInterfaceSubClass : 0x2 bInterfaceProtocol : 0x0 iInterface : 0x0 INTERFACE 1, 1: Vendor Specific ======================== bLength : 0x9 (9 bytes) bDescriptorType : 0x4 Interface bInterfaceNumber : 0x1 bAlternateSetting : 0x1 bNumEndpoints : 0x1 bInterfaceClass : 0xff Vendor Specific bInterfaceSubClass : 0x2 bInterfaceProtocol : 0x0 iInterface : 0x0 ENDPOINT 0x81: Isochronous IN ======================== bLength : 0x9 (7 bytes) bDescriptorType : 0x5 Endpoint bEndpointAddress : 0x81 IN bmAttributes : 0x5 Isochronous wMaxPacketSize : 0xc8 (200 bytes) bInterval : 0x1 ``` If I (almost) match that: (FunctionFS Device Descriptors) ``` INTERFACE 0: Vendor Specific =========================== bLength : 0x9 (9 bytes) bDescriptorType : 0x4 Interface bInterfaceNumber : 0x0 bAlternateSetting : 0x0 bNumEndpoints : 0x0 bInterfaceClass : 0xff Vendor Specific bInterfaceSubClass : 0x0 bInterfaceProtocol : 0x0 iInterface : 0x5 Source/Sink INTERFACE 1: Vendor Specific =========================== bLength : 0x9 (9 bytes) bDescriptorType : 0x4 Interface bInterfaceNumber : 0x1 bAlternateSetting : 0x0 bNumEndpoints : 0x0 bInterfaceClass : 0xff Vendor Specific bInterfaceSubClass : 0x0 bInterfaceProtocol : 0x0 iInterface : 0x6 Isoc Source/Sink INTERFACE 1, 1: Vendor Specific ======================== bLength : 0x9 (9 bytes) bDescriptorType : 0x4 Interface bInterfaceNumber : 0x1 bAlternateSetting : 0x1 bNumEndpoints : 0x2 bInterfaceClass : 0xff Vendor Specific bInterfaceSubClass : 0x0 bInterfaceProtocol : 0x0 iInterface : 0x6 Isoc Source/Sink ENDPOINT 0x81: Isochronous IN ======================== bLength : 0x9 (7 bytes) bDescriptorType : 0x5 Endpoint bEndpointAddress : 0x81 IN bmAttributes : 0x5 Isochronous wMaxPacketSize : 0x200 (512 bytes) bInterval : 0x1 ENDPOINT 0x1: Isochronous OUT ======================== bLength : 0x9 (7 bytes) bDescriptorType : 0x5 Endpoint bEndpointAddress : 0x1 OUT bmAttributes : 0x5 Isochronous wMaxPacketSize : 0x200 (512 bytes) bInterval : 0x1 ``` libusb seems to encounter an error: (pyusb error output) ``` >>> import usb >>> ds = [d for d in usb.core.find(find_all=True, idVendor=0x1d6b, idProduct=0x0104)] >>> d = ds[0] >>> d.set_interface_altsetting(interface=1, alternate_setting=1) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python3.7/site-packages/usb/core.py", line 902, in set_interface_altsetting self._ctx.managed_set_interface(self, interface, alternate_setting) File "/usr/lib/python3.7/site-packages/usb/core.py", line 102, in wrapper return f(self, *args, **kwargs) File "/usr/lib/python3.7/site-packages/usb/core.py", line 204, in managed_set_interface self.backend.set_interface_altsetting(self.handle, i.bInterfaceNumber, alt) File "/usr/lib/python3.7/site-packages/usb/backend/libusb1.py", line 807, in set_interface_altsetting altsetting)) File "/usr/lib/python3.7/site-packages/usb/backend/libusb1.py", line 595, in _check raise USBError(_strerror(ret), ret, _libusb_errno[ret]) usb.core.USBError: [Errno None] Other error ``` (libusb error from C code) ``` libusb: error [op_set_interface] setintf failed error -1 errno 32 ``` But, if interface 1 alternate setting 0 is dropped, and interface 1 alternate setting 1 is kept, both invocations work and my C code spits out data very fast, although I must inspect it further as I seem to be duplicating data in my reads.