summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Dickens <christopher.a.dickens@gmail.com>2015-01-22 00:25:16 -0800
committerChris Dickens <christopher.a.dickens@gmail.com>2015-01-22 00:35:27 -0800
commit51b10191033ca3a3819dcf46e1da2465b99497c2 (patch)
tree95adc18a2fa392b24e5a58d7a793ac69910c82fe
parenta3d3313c5d7cdc22bb41b1e75a959e070f05c5b7 (diff)
downloadlibusb-51b10191033ca3a3819dcf46e1da2465b99497c2.tar.gz
linux_usbfs: Update MAX_ISO_BUFFER_LENGTH
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>
-rw-r--r--libusb/io.c8
-rw-r--r--libusb/os/linux_usbfs.c23
-rw-r--r--libusb/os/linux_usbfs.h2
-rw-r--r--libusb/version_nano.h2
4 files changed, 23 insertions, 12 deletions
diff --git a/libusb/io.c b/libusb/io.c
index 9614086..d8a2bd6 100644
--- a/libusb/io.c
+++ b/libusb/io.c
@@ -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
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index 05cf909..101cc95 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -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);
diff --git a/libusb/os/linux_usbfs.h b/libusb/os/linux_usbfs.h
index f2404ab..43fe11b 100644
--- a/libusb/os/linux_usbfs.h
+++ b/libusb/os/linux_usbfs.h
@@ -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
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index 70d5df1..bc6bfe4 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 10951
+#define LIBUSB_NANO 10952