linux_usbfs: Update MAX_ISO_BUFFER_LENGTH
authorChris Dickens <christopher.a.dickens@gmail.com>
Thu, 22 Jan 2015 08:25:16 +0000 (00:25 -0800)
committerChris Dickens <christopher.a.dickens@gmail.com>
Thu, 22 Jan 2015 08:35:27 +0000 (00:35 -0800)
Newer kernels have raised the maximum length of individual ISO
packets and URBs. There's no easy way to detect the limit, so we
will define MAX_ISO_BUFFER_LENGTH as the largest known limit.

If a user runs this on an earlier kernel and submits an ISO transfer
that is too large, they will receive LIBUSB_ERROR_INVALID_PARAM.

The documentation has been updated to note this behavior, under
"Considerations for isochronous transfers".

Closes #23

Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
libusb/io.c
libusb/os/linux_usbfs.c
libusb/os/linux_usbfs.h
libusb/version_nano.h

index 9614086..d8a2bd6 100644 (file)
@@ -466,6 +466,14 @@ if (r == 0 && actual_length == sizeof(data)) {
  * libusb_get_iso_packet_buffer() and libusb_get_iso_packet_buffer_simple()
  * functions may help you here.
  *
+ * <b>Note</b>: Some operating systems (e.g. Linux) may impose limits on the
+ * length of individual isochronous packets and/or the total length of the
+ * isochronous transfer. Such limits can be difficult for libusb to detect,
+ * so the library will simply try and submit the transfer as set up by you.
+ * If the transfer fails to submit because it is too large,
+ * libusb_submit_transfer() will return
+ * \ref libusb_error::LIBUSB_ERROR_INVALID_PARAM "LIBUSB_ERROR_INVALID_PARAM".
+ *
  * \section asyncmem Memory caveats
  *
  * In most circumstances, it is not safe to use stack memory for transfer
index 05cf909..101cc95 100644 (file)
@@ -1942,15 +1942,11 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer)
        unsigned int packet_len;
        unsigned char *urb_buffer = transfer->buffer;
 
-       /* usbfs places a 32kb limit on iso URBs. we divide up larger requests
-        * into smaller units to meet such restriction, then fire off all the
-        * units at once. it would be simpler if we just fired one unit at a time,
-        * but there is a big performance gain through doing it this way.
-        *
-        * Newer kernels lift the 32k limit (USBFS_CAP_NO_PACKET_SIZE_LIM),
-        * using arbritary large transfers is still be a bad idea though, as
-        * the kernel needs to allocate physical contiguous memory for this,
-        * which may fail for large buffers.
+       /* usbfs places arbitrary limits on iso URBs. this limit has changed
+        * at least three times, and it's difficult to accurately detect which
+        * limit this running kernel might impose. so we attempt to submit
+        * whatever the user has provided. if the kernel rejects the request
+        * due to its size, we return an error indicating such to the user.
         */
 
        /* calculate how many URBs we need */
@@ -1961,11 +1957,14 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer)
                if (packet_len > space_remaining) {
                        num_urbs++;
                        this_urb_len = packet_len;
+                       /* check that we can actually support this packet length */
+                       if (this_urb_len > MAX_ISO_BUFFER_LENGTH)
+                               return LIBUSB_ERROR_INVALID_PARAM;
                } else {
                        this_urb_len += packet_len;
                }
        }
-       usbi_dbg("need %d 32k URBs for transfer", num_urbs);
+       usbi_dbg("need %d %dk URBs for transfer", num_urbs, MAX_ISO_BUFFER_LENGTH / 1024);
 
        alloc_size = num_urbs * sizeof(*urbs);
        urbs = calloc(1, alloc_size);
@@ -2033,6 +2032,10 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer)
                if (r < 0) {
                        if (errno == ENODEV) {
                                r = LIBUSB_ERROR_NO_DEVICE;
+                       } else if (errno == EINVAL) {
+                               usbi_warn(TRANSFER_CTX(transfer),
+                                       "submiturb failed, transfer too large");
+                               r = LIBUSB_ERROR_INVALID_PARAM;
                        } else {
                                usbi_err(TRANSFER_CTX(transfer),
                                        "submiturb failed error %d errno=%d", r, errno);
index f2404ab..43fe11b 100644 (file)
@@ -81,7 +81,7 @@ struct usbfs_iso_packet_desc {
        unsigned int status;
 };
 
-#define MAX_ISO_BUFFER_LENGTH          32768
+#define MAX_ISO_BUFFER_LENGTH          49152 * 128
 #define MAX_BULK_BUFFER_LENGTH         16384
 #define MAX_CTRL_BUFFER_LENGTH         4096
 
index 70d5df1..bc6bfe4 100644 (file)
@@ -1 +1 @@
-#define LIBUSB_NANO 10951
+#define LIBUSB_NANO 10952