All of lore.kernel.org
 help / color / mirror / Atom feed
* Unable to Use Isochronous Behavior w/ Isoc Endpoint in FunctionFC
@ 2020-06-21  3:38 Sid Spry
  2020-06-21 14:09 ` Alan Stern
  0 siblings, 1 reply; 7+ messages in thread
From: Sid Spry @ 2020-06-21  3:38 UTC (permalink / raw)
  To: linux-usb

Hello again, I didn't expect to post so quickly but was able to get quite a bit
of testing done.

All calls to write(2) on the device are blocking. This means data is only
transmitted after it has been received. Data should be transmitted continuously
as long as it does not exceed the allocated bandwidth. My test is as follows:

Device:
```
uint8_t pole = 0;
while (true) {
	int rc = write(fd, (void *)&pole, sizeof pole);
	pole++;
}
```

Host (with pyusb):
```
import usb
ds = [d for d in usb.core.find(find_all=True,
	idVendor=0x1d6b, idProduct=0x0104)]
ds[0].read(0x82, 1) # Up arrow enter as necessary.
```
(The library transparently calls the proper read type.)

When read I always receive the series of incremented numbers. I expect to read
more or less random numbers as unreceived writes are dropped. That I always
read incremented contiguous numbers indicates to me that no writes device-side
are dropped.

I have attempted to set the endpoint filehandle nonblocking. This works before
the UDC is bound but after it is bound or the first write the nonblocking
behavior is removed and resetting it inside the write loop seems to have no
effect.

In the full program the write loop is delayed by a timerfd so that I can more
easily inspect the host code paths for behavior when reads occur too quickly.
After the UDC is bound the timer is no longer the limiting factor in the speed
of the write loop.

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.

Below are the descriptors I am using. I set USB_ENDPOINT_SYNC_ASYNC on the two
isochronous endpoints. This did not change the behavior of the endpoints.

```
static const struct {
	struct usb_functionfs_descs_head_v2 header;
	__le32 fs_count;
	__le32 hs_count;
	//__le32 ss_count;
	struct {
		struct usb_interface_descriptor intf;
		struct usb_endpoint_descriptor sink;
		struct usb_endpoint_descriptor source;
		struct usb_endpoint_descriptor iso_sink;
		struct usb_endpoint_descriptor iso_source;
	} __attribute__((packed)) fs_descs, hs_descs;
	/*struct {
		struct usb_interface_descriptor intf;
		struct usb_endpoint_descriptor_no_audio sink;
		struct usb_ss_ep_comp_descriptor sink_comp;
		struct usb_endpoint_descriptor_no_audio source;
		struct usb_ss_ep_comp_descriptor source_comp;
	} ss_descs;*/
} __attribute__((packed)) descriptors = {
	.header = {
		.magic  = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
		.length = cpu_to_le32(sizeof descriptors),
		.flags  = cpu_to_le32(FUNCTIONFS_HAS_FS_DESC |
				     FUNCTIONFS_HAS_HS_DESC), // |
				     //FUNCTIONFS_HAS_SS_DESC),
	},
	.fs_count = cpu_to_le32(5),
	.hs_count = cpu_to_le32(5),
	//.ss_count = cpu_to_le32(5),
	.fs_descs = {
		.intf = {
			.bLength = sizeof descriptors.fs_descs.intf,
			.bDescriptorType = USB_DT_INTERFACE,
			.bNumEndpoints = 4,
			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
			.iInterface = 1,
		},
		.sink = {
			.bLength = sizeof descriptors.fs_descs.sink,
			.bDescriptorType = USB_DT_ENDPOINT,
			.bEndpointAddress = 1 | USB_DIR_IN,
			.bmAttributes = USB_ENDPOINT_XFER_BULK,
			/* .wMaxPacketSize = autoconfiguration (kernel) */
		},
		.source = {
			.bLength = sizeof descriptors.fs_descs.source,
			.bDescriptorType = USB_DT_ENDPOINT,
			.bEndpointAddress = 2 | USB_DIR_OUT,
			.bmAttributes = USB_ENDPOINT_XFER_BULK,
			/* .wMaxPacketSize = autoconfiguration (kernel) */
		},
		.iso_sink = {
			.bLength = sizeof descriptors.fs_descs.iso_sink,
			.bDescriptorType = USB_DT_ENDPOINT,
			.bEndpointAddress = 3 | USB_DIR_IN,
			.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
		},
		.iso_source = {
			.bLength = sizeof descriptors.fs_descs.iso_source,
			.bDescriptorType = USB_DT_ENDPOINT,
			.bEndpointAddress = 4 | USB_DIR_OUT,
			.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
		},
	},
	.hs_descs = {
		.intf = {
			.bLength = sizeof descriptors.fs_descs.intf,
			.bDescriptorType = USB_DT_INTERFACE,
			.bNumEndpoints = 4,
			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
			.iInterface = 1,
		},
		.sink = {
			.bLength = sizeof descriptors.hs_descs.sink,
			.bDescriptorType = USB_DT_ENDPOINT,
			.bEndpointAddress = 1 | USB_DIR_IN,
			.bmAttributes = USB_ENDPOINT_XFER_BULK,
			.wMaxPacketSize = cpu_to_le16(512),
		},
		.source = {
			.bLength = sizeof descriptors.hs_descs.iso_sink,
			.bDescriptorType = USB_DT_ENDPOINT,
			.bEndpointAddress = 2 | USB_DIR_OUT,
			.bmAttributes = USB_ENDPOINT_XFER_BULK,
			.wMaxPacketSize = cpu_to_le16(512),
			.bInterval = 1,
		},
		.iso_sink = {
			.bLength = sizeof descriptors.hs_descs.source,
			.bDescriptorType = USB_DT_ENDPOINT,
			.bEndpointAddress = 3 | USB_DIR_IN,
			.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
			.wMaxPacketSize = cpu_to_le16(512),
			.bInterval = 1,
		},
		.iso_source = {
			.bLength = sizeof descriptors.hs_descs.source,
			.bDescriptorType = USB_DT_ENDPOINT,
			.bEndpointAddress = 4 | USB_DIR_OUT,
			.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
			.wMaxPacketSize = cpu_to_le16(512),
			.bInterval = 1,
		},
	},
	/*.ss_descs = {
		.intf = {
			.bLength = sizeof descriptors.fs_descs.intf,
			.bDescriptorType = USB_DT_INTERFACE,
			.bNumEndpoints = 2,
			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
			.iInterface = 1,
		},
		.sink = {
			.bLength = sizeof descriptors.hs_descs.sink,
			.bDescriptorType = USB_DT_ENDPOINT,
			.bEndpointAddress = 1 | USB_DIR_IN,
			.bmAttributes = USB_ENDPOINT_XFER_BULK,
			.wMaxPacketSize = cpu_to_le16(1024),
		},
		.sink_comp = {
			.bLength = USB_DT_SS_EP_COMP_SIZE,
			.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
			.bMaxBurst = 0,
			.bmAttributes = 0,
			.wBytesPerInterval = 0,
		},
		.source = {
			.bLength = sizeof descriptors.hs_descs.source,
			.bDescriptorType = USB_DT_ENDPOINT,
			.bEndpointAddress = 2 | USB_DIR_OUT,
			.bmAttributes = USB_ENDPOINT_XFER_BULK,
			.wMaxPacketSize = cpu_to_le16(1024),
			.bInterval = 1,
		},
		.source_comp = {
			.bLength = USB_DT_SS_EP_COMP_SIZE,
			.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
			.bMaxBurst = 0,
			.bmAttributes = 0,
			.wBytesPerInterval = 0,
		},
	},*/
};
```

I have a more fully-featured reading example that uses libusb directly but it
too does not work. The library prints:

```
libusb: warning [submit_iso_transfer] submiturb failed, transfer too large
```

Though I am quite sure I have not exceeded the size. Setting it lower does not
seem to help.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Unable to Use Isochronous Behavior w/ Isoc Endpoint in FunctionFC
  2020-06-21  3:38 Unable to Use Isochronous Behavior w/ Isoc Endpoint in FunctionFC Sid Spry
@ 2020-06-21 14:09 ` Alan Stern
  2020-06-22  2:25   ` Sid Spry
  0 siblings, 1 reply; 7+ messages in thread
From: Alan Stern @ 2020-06-21 14:09 UTC (permalink / raw)
  To: Sid Spry; +Cc: linux-usb

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.

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.

Alan Stern

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Unable to Use Isochronous Behavior w/ Isoc Endpoint in FunctionFC
  2020-06-21 14:09 ` Alan Stern
@ 2020-06-22  2:25   ` Sid Spry
  2020-06-22 14:02     ` Alan Stern
  0 siblings, 1 reply; 7+ messages in thread
From: Sid Spry @ 2020-06-22  2:25 UTC (permalink / raw)
  To: Alan Stern; +Cc: linux-usb

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.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Unable to Use Isochronous Behavior w/ Isoc Endpoint in FunctionFC
  2020-06-22  2:25   ` Sid Spry
@ 2020-06-22 14:02     ` Alan Stern
  2020-06-22 15:41       ` Sid Spry
  0 siblings, 1 reply; 7+ messages in thread
From: Alan Stern @ 2020-06-22 14:02 UTC (permalink / raw)
  To: Sid Spry; +Cc: linux-usb

On Sun, Jun 21, 2020 at 09:25:53PM -0500, Sid Spry wrote:
> I now must ask the list: What is the relation of the isochronous endpoint setup
> to the allocated bandwidth on the bus?

Bandwidth allocation is determined by the host controller driver, or in 
the case of xHCI, hardware.  Therefore it will vary with different drivers 
or controllers.

> 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.

If allocation fails, the application will find out either when it tries to 
issue a Set-Interface request or when it tries to submit an isochronous 
URB.

Did you say earlier that your host controller is xHCI?  If it is then the 
OS doesn't arbitrate link bandwidth; the xHCI hardware does.

> 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):

[apparently irrelevant details omitted]

> 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
> ```

Error 32 means that the device returned a STALL status when it received 
the Set-Interface request.  The code responsible for this error response 
might be in FunctionFS or in your driver.

> 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.

If you drop altsetting 0 then you're probably not issuing a Set-Interface 
request.  That would explain why you don't get a failure.

If you like, you can try issuing a Set-Interface(0) request (even though 
it's redundant) just to see if it fails.

Alan Stern

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Unable to Use Isochronous Behavior w/ Isoc Endpoint in FunctionFC
  2020-06-22 14:02     ` Alan Stern
@ 2020-06-22 15:41       ` Sid Spry
  2020-06-22 16:41         ` Alan Stern
  0 siblings, 1 reply; 7+ messages in thread
From: Sid Spry @ 2020-06-22 15:41 UTC (permalink / raw)
  To: Alan Stern; +Cc: linux-usb

On Mon, Jun 22, 2020, at 9:02 AM, Alan Stern wrote:
> On Sun, Jun 21, 2020 at 09:25:53PM -0500, Sid Spry wrote:
> > I now must ask the list: What is the relation of the isochronous endpoint setup
> > to the allocated bandwidth on the bus?
> 
> Bandwidth allocation is determined by the host controller driver, or in 
> the case of xHCI, hardware.  Therefore it will vary with different drivers 
> or controllers.
> 

Ok, variation I expected. Sadly it seems like I am not made aware of which
interface alternate setting is chosen.

See: https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/
function/f_fs.c#L3265.

The ctrlrequest struct (https://elixir.bootlin.com/linux/latest/source/include
/uapi/linux/usb/ch9.h#L213) is only sent for SETUP events. Of which I have
yet to triggered.

> > 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.
> 
> If allocation fails, the application will find out either when it tries to 
> issue a Set-Interface request or when it tries to submit an isochronous 
> URB.
> 
> Did you say earlier that your host controller is xHCI?  If it is then the 
> OS doesn't arbitrate link bandwidth; the xHCI hardware does.
> 

It is. The device is HS USB2. Eventually I'll find a platform with a superspeed
UDC. Suspecting I will have to repurpose a rooted Android phone. If anyone
has a lead on something with an easily accessible hardware serial port I am
interested.

> > 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):
> 
> [apparently irrelevant details omitted]
> 
> > 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
> > ```
> 
> Error 32 means that the device returned a STALL status when it received 
> the Set-Interface request.  The code responsible for this error response 
> might be in FunctionFS or in your driver.
>

I see the set-interface request in my code as a read/write error on the endpoints
(errno 11: resource temporarily unavailable) and an enable event. Otherwise
most things "just happen."

I've had issues reusing endpoint numbers like you are supposed to. Either the
descriptors aren't accepted or more commonly the UDC won't bind. E.g. I have
to give interface 0 eps 1, 2 and interface 1 eps 3, 4. The numbering is preserved
on the host, kind of. Eps are compacted into their numbering based on direction.
So you see interface 0 with eps 0x81 and 0x01, and interface 1 with eps 0x82 
and 0x02.

This isn't causing me problems per se but does seem improper.

I'll look through the functionfs code when I have some time. The user mode
does not seem to be passed much information.

> > 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.
> 
> If you drop altsetting 0 then you're probably not issuing a Set-Interface 
> request.  That would explain why you don't get a failure.
> 
> If you like, you can try issuing a Set-Interface(0) request (even though 
> it's redundant) just to see if it fails.
> 

Ah, yes, I had done set-interface(0 [, 0]). set-interface(1, 0) also works. It is just
set-interface(1, 1) that is nonfunctional when an alternate mode 0 is provided.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Unable to Use Isochronous Behavior w/ Isoc Endpoint in FunctionFC
  2020-06-22 15:41       ` Sid Spry
@ 2020-06-22 16:41         ` Alan Stern
  2020-06-22 21:13           ` Sid Spry
  0 siblings, 1 reply; 7+ messages in thread
From: Alan Stern @ 2020-06-22 16:41 UTC (permalink / raw)
  To: Sid Spry; +Cc: linux-usb

On Mon, Jun 22, 2020 at 10:41:14AM -0500, Sid Spry wrote:
> On Mon, Jun 22, 2020, at 9:02 AM, Alan Stern wrote:
> > On Sun, Jun 21, 2020 at 09:25:53PM -0500, Sid Spry wrote:
> > > I now must ask the list: What is the relation of the isochronous endpoint setup
> > > to the allocated bandwidth on the bus?
> > 
> > Bandwidth allocation is determined by the host controller driver, or in 
> > the case of xHCI, hardware.  Therefore it will vary with different drivers 
> > or controllers.
> > 
> 
> Ok, variation I expected. Sadly it seems like I am not made aware of which
> interface alternate setting is chosen.
> 
> See: https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/
> function/f_fs.c#L3265.
> 
> The ctrlrequest struct (https://elixir.bootlin.com/linux/latest/source/include
> /uapi/linux/usb/ch9.h#L213) is only sent for SETUP events. Of which I have
> yet to triggered.

Like I said before, you'll need to ask someone who knows more about 
FunctionFS.

> > > 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
> > > ```
> > 
> > Error 32 means that the device returned a STALL status when it received 
> > the Set-Interface request.  The code responsible for this error response 
> > might be in FunctionFS or in your driver.
> >
> 
> I see the set-interface request in my code as a read/write error on the endpoints
> (errno 11: resource temporarily unavailable) and an enable event. Otherwise
> most things "just happen."
> 
> I've had issues reusing endpoint numbers like you are supposed to. Either the
> descriptors aren't accepted or more commonly the UDC won't bind. E.g. I have
> to give interface 0 eps 1, 2 and interface 1 eps 3, 4. The numbering is preserved
> on the host, kind of. Eps are compacted into their numbering based on direction.
> So you see interface 0 with eps 0x81 and 0x01, and interface 1 with eps 0x82 
> and 0x02.

That's exactly how it's supposed to work.  Don't mix up endpoint _numbers_ 
with endpoint _addresses_; they aren't the same thing.  Read through the 
USB-2.0 specification for more information.

Also don't forget that two interfaces in the same configuration are not 
allowed to share an endpoint (other than endpoint 0, which doesn't really 
belong to any interface).

> This isn't causing me problems per se but does seem improper.

Why?

> I'll look through the functionfs code when I have some time. The user mode
> does not seem to be passed much information.

If you think this is a weakness of FunctionFS and it needs to be fixed, 
report it to the FunctionFS maintainers.  See the MAINTAINERS file in the 
top-level directory of the kernel source code.

> > > 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.
> > 
> > If you drop altsetting 0 then you're probably not issuing a Set-Interface 
> > request.  That would explain why you don't get a failure.
> > 
> > If you like, you can try issuing a Set-Interface(0) request (even though 
> > it's redundant) just to see if it fails.
> > 
> 
> Ah, yes, I had done set-interface(0 [, 0]). set-interface(1, 0) also works. It is just
> set-interface(1, 1) that is nonfunctional when an alternate mode 0 is provided.

Okay.  Maybe the problem occurs in the code that enables the endpoints for 
altsetting 1.

Alan Stern

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Unable to Use Isochronous Behavior w/ Isoc Endpoint in FunctionFC
  2020-06-22 16:41         ` Alan Stern
@ 2020-06-22 21:13           ` Sid Spry
  0 siblings, 0 replies; 7+ messages in thread
From: Sid Spry @ 2020-06-22 21:13 UTC (permalink / raw)
  To: Alan Stern; +Cc: linux-usb

On Mon, Jun 22, 2020, at 11:41 AM, Alan Stern wrote:
> On Mon, Jun 22, 2020 at 10:41:14AM -0500, Sid Spry wrote:
> > On Mon, Jun 22, 2020, at 9:02 AM, Alan Stern wrote:
> > > On Sun, Jun 21, 2020 at 09:25:53PM -0500, Sid Spry wrote:
> > > > I now must ask the list: What is the relation of the isochronous endpoint setup
> > > > to the allocated bandwidth on the bus?
> > > 
> > > Bandwidth allocation is determined by the host controller driver, or in 
> > > the case of xHCI, hardware.  Therefore it will vary with different drivers 
> > > or controllers.
> > > 
> > 
> > Ok, variation I expected. Sadly it seems like I am not made aware of which
> > interface alternate setting is chosen.
> > 
> > See: https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/
> > function/f_fs.c#L3265.
> > 
> > The ctrlrequest struct (https://elixir.bootlin.com/linux/latest/source/include
> > /uapi/linux/usb/ch9.h#L213) is only sent for SETUP events. Of which I have
> > yet to triggered.
> 
> Like I said before, you'll need to ask someone who knows more about 
> FunctionFS.
> 

This is a mailing list, I am not only expecting you to reply.

> > > > 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
> > > > ```
> > > 
> > > Error 32 means that the device returned a STALL status when it received 
> > > the Set-Interface request.  The code responsible for this error response 
> > > might be in FunctionFS or in your driver.
> > >
> > 
> > I see the set-interface request in my code as a read/write error on the endpoints
> > (errno 11: resource temporarily unavailable) and an enable event. Otherwise
> > most things "just happen."
> > 
> > I've had issues reusing endpoint numbers like you are supposed to. Either the
> > descriptors aren't accepted or more commonly the UDC won't bind. E.g. I have
> > to give interface 0 eps 1, 2 and interface 1 eps 3, 4. The numbering is preserved
> > on the host, kind of. Eps are compacted into their numbering based on direction.
> > So you see interface 0 with eps 0x81 and 0x01, and interface 1 with eps 0x82 
> > and 0x02.
> 
> That's exactly how it's supposed to work.  Don't mix up endpoint _numbers_ 
> with endpoint _addresses_; they aren't the same thing.  Read through the 
> USB-2.0 specification for more information.
> 
> Also don't forget that two interfaces in the same configuration are not 
> allowed to share an endpoint (other than endpoint 0, which doesn't really 
> belong to any interface).
> 
> > This isn't causing me problems per se but does seem improper.
> 
> Why?
> 

Ah, yes, I was mixing up numbers/addresses. Strange as the only useful
number to me seems to be the address.

> > I'll look through the functionfs code when I have some time. The user mode
> > does not seem to be passed much information.
> 
> If you think this is a weakness of FunctionFS and it needs to be fixed, 
> report it to the FunctionFS maintainers.  See the MAINTAINERS file in the 
> top-level directory of the kernel source code.
> 
> > > > 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.
> > > 
> > > If you drop altsetting 0 then you're probably not issuing a Set-Interface 
> > > request.  That would explain why you don't get a failure.
> > > 
> > > If you like, you can try issuing a Set-Interface(0) request (even though 
> > > it's redundant) just to see if it fails.
> > > 
> > 
> > Ah, yes, I had done set-interface(0 [, 0]). set-interface(1, 0) also works. It is just
> > set-interface(1, 1) that is nonfunctional when an alternate mode 0 is provided.
> 
> Okay.  Maybe the problem occurs in the code that enables the endpoints for 
> altsetting 1.
> 

I do appreciate the help, I'll report to the maintainers later. I'll have to table it for
now. As it is I'm able to send reliably on each frame so I'm happy.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2020-06-22 21:14 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-21  3:38 Unable to Use Isochronous Behavior w/ Isoc Endpoint in FunctionFC Sid Spry
2020-06-21 14:09 ` Alan Stern
2020-06-22  2:25   ` Sid Spry
2020-06-22 14:02     ` Alan Stern
2020-06-22 15:41       ` Sid Spry
2020-06-22 16:41         ` Alan Stern
2020-06-22 21:13           ` Sid Spry

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.