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

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.