Unable to Use Isochronous Behavior w/ Isoc Endpoint in FunctionFC

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux