diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..68bc27e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/libusb-*.tar.bz2 diff --git a/0001-Correctly-handle-LIBUSB_TRANSFER_OVERFLOW-in-libusb_.patch b/0001-Correctly-handle-LIBUSB_TRANSFER_OVERFLOW-in-libusb_.patch new file mode 100644 index 0000000..4f727f0 --- /dev/null +++ b/0001-Correctly-handle-LIBUSB_TRANSFER_OVERFLOW-in-libusb_.patch @@ -0,0 +1,32 @@ +From 1cc5b4a9fb984e83681ae5c797fa6b22bc20f809 Mon Sep 17 00:00:00 2001 +From: Ludovic Rousseau +Date: Fri, 16 Sep 2011 18:07:56 +0200 +Subject: [PATCH 01/40] Correctly handle LIBUSB_TRANSFER_OVERFLOW in + libusb_control_transfer() + +sync.c: In function `libusb_control_transfer': +sync.c:122: warning: enumeration value `LIBUSB_TRANSFER_OVERFLOW' not +handled in switch + +Fixes #120. +--- + libusb/sync.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/libusb/sync.c b/libusb/sync.c +index d50413b..8eed47b 100644 +--- a/libusb/sync.c ++++ b/libusb/sync.c +@@ -132,6 +132,9 @@ int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle, + case LIBUSB_TRANSFER_NO_DEVICE: + r = LIBUSB_ERROR_NO_DEVICE; + break; ++ case LIBUSB_TRANSFER_OVERFLOW: ++ r = LIBUSB_ERROR_OVERFLOW; ++ break; + default: + usbi_warn(HANDLE_CTX(dev_handle), + "unrecognised status code %d", transfer->status); +-- +1.7.9.3 + diff --git a/0002-linux-Fix-cancel_transfer-return-value-when-cancelli.patch b/0002-linux-Fix-cancel_transfer-return-value-when-cancelli.patch new file mode 100644 index 0000000..91be253 --- /dev/null +++ b/0002-linux-Fix-cancel_transfer-return-value-when-cancelli.patch @@ -0,0 +1,37 @@ +From 52508a86e26f0bc74b0a7a3b05ed08a29996b44c Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 20 Feb 2012 16:05:48 +0100 +Subject: [PATCH 1/6] linux: Fix cancel_transfer return value when cancelling + a multi-urb transfer + +If we fail to cancel the last urb of a multi-urb transfer because it +has already completed (errno == EINVAL on DISCARD_URB), then the entire +transfer has already completed, so returning NOT_FOUND is consistent with what +the documentation for libusb_cancel_transfer says. + +But if we've successfully cancelled the last urb, and then another urb +fails with errno == EINVAL, this means that we've still cancelled the +transfer, as it has only *partially* completed. + +Signed-off-by: Hans de Goede +--- + libusb/os/linux_usbfs.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c +index 2b81189..099fc61 100644 +--- a/libusb/os/linux_usbfs.c ++++ b/libusb/os/linux_usbfs.c +@@ -1466,7 +1466,8 @@ static int discard_urbs(struct usbi_transfer *itransfer, int first, int last_plu + + if (EINVAL == errno) { + usbi_dbg("URB not found --> assuming ready to be reaped"); +- ret = LIBUSB_ERROR_NOT_FOUND; ++ if (i == (last_plus_one - 1)) ++ ret = LIBUSB_ERROR_NOT_FOUND; + } else if (ENODEV == errno) { + usbi_dbg("Device not found for URB --> assuming ready to be reaped"); + ret = LIBUSB_ERROR_NO_DEVICE; +-- +1.7.9.3 + diff --git a/0003-Don-t-print-errors-when-cancel_transfer-fails-with-N.patch b/0003-Don-t-print-errors-when-cancel_transfer-fails-with-N.patch new file mode 100644 index 0000000..ccb76a1 --- /dev/null +++ b/0003-Don-t-print-errors-when-cancel_transfer-fails-with-N.patch @@ -0,0 +1,46 @@ +From e8c0b72bf8cc6d89c3546bbdbcc85b2c63086578 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 20 Feb 2012 16:12:19 +0100 +Subject: [PATCH 2/6] Don't print errors when cancel_transfer fails with + NOT_FOUND + +As stated in the documentation for libusb_cancel_transfer, +LIBUSB_ERROR_NOT_FOUND is an expected return value for +libusb_cancel_transfer (under certain circumstances) printing +an error each time this happens therefor is undesirable. + +More so because under Linux IOCTL_USBFS_DISCARDURB sets errno +to EINVAL when the kernel could not find the urb in the kernels +urbs in flight list. Which means that the urb has already completed +at the host controller level, but it has not necessarily already +been reaped. IOW under Linux libusb_cancel_transfer may yield a +result of LIBUSB_ERROR_NOT_FOUND *before* the transfer's callback +has been called! So there is no way for an application to avoid +calling libusb_cancel_transfer on already completed transfers. + +Signed-off-by: Hans de Goede +--- + libusb/io.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/libusb/io.c b/libusb/io.c +index bb6e275..9f46cf0 100644 +--- a/libusb/io.c ++++ b/libusb/io.c +@@ -1351,8 +1351,11 @@ int API_EXPORTED libusb_cancel_transfer(struct libusb_transfer *transfer) + usbi_mutex_lock(&itransfer->lock); + r = usbi_backend->cancel_transfer(itransfer); + if (r < 0) { +- usbi_err(TRANSFER_CTX(transfer), +- "cancel transfer failed error %d", r); ++ if (r != LIBUSB_ERROR_NOT_FOUND) ++ usbi_err(TRANSFER_CTX(transfer), ++ "cancel transfer failed error %d", r); ++ else ++ usbi_dbg("cancel transfer failed error %d", r); + + if (r == LIBUSB_ERROR_NO_DEVICE) + itransfer->flags |= USBI_TRANSFER_DEVICE_DISAPPEARED; +-- +1.7.9.3 + diff --git a/0004-linux-Fix-handling-of-urb-status-codes.patch b/0004-linux-Fix-handling-of-urb-status-codes.patch new file mode 100644 index 0000000..75ef04e --- /dev/null +++ b/0004-linux-Fix-handling-of-urb-status-codes.patch @@ -0,0 +1,92 @@ +From 3b6ed16cd2f098dd3920853d20940b3560c20ece Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 24 Feb 2012 10:24:00 +0100 +Subject: [PATCH 3/6] linux: Fix handling of urb status codes + +During testing of my usbredir code I hit a case where EOVERFLOW was not handled +in handle_control_completion. Instead of just fixing this one case I've audited +(and fixed where necessary) all handle_foo_completion functions to know about +all errors documented in linux/Documentation/usb/error-codes.txt. + +Note that for handle_iso_completion this patch actually removes the handling +of some codes, since these can never occur on an iso urb (they can only +occur on the iso packets included in the urb, see the next patch in this +series). Also in case an unknown status is encountered on an iso urb, this +patch actually sets the urb's status to ERROR, rather then leaving it at +completed. + +Signed-off-by: Hans de Goede +--- + libusb/os/linux_usbfs.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c +index 099fc61..36d37a4 100644 +--- a/libusb/os/linux_usbfs.c ++++ b/libusb/os/linux_usbfs.c +@@ -1952,6 +1952,7 @@ static int handle_bulk_completion(struct usbi_transfer *itransfer, + case -ENOENT: /* cancelled */ + case -ECONNRESET: + break; ++ case -ENODEV: + case -ESHUTDOWN: + usbi_dbg("device removed"); + tpriv->reap_status = LIBUSB_TRANSFER_NO_DEVICE; +@@ -1970,6 +1971,8 @@ static int handle_bulk_completion(struct usbi_transfer *itransfer, + case -ETIME: + case -EPROTO: + case -EILSEQ: ++ case -ECOMM: ++ case -ENOSR: + usbi_dbg("low level error %d", urb->status); + tpriv->reap_action = ERROR; + goto cancel_remaining; +@@ -2081,19 +2084,16 @@ static int handle_iso_completion(struct usbi_transfer *itransfer, + case 0: + break; + case -ENOENT: /* cancelled */ ++ case -ECONNRESET: + break; + case -ESHUTDOWN: + usbi_dbg("device removed"); + status = LIBUSB_TRANSFER_NO_DEVICE; + break; +- case -ETIME: +- case -EPROTO: +- case -EILSEQ: +- usbi_dbg("low-level USB error %d", urb->status); +- break; + default: + usbi_warn(TRANSFER_CTX(transfer), + "unrecognised urb status %d", urb->status); ++ status = LIBUSB_TRANSFER_ERROR; + break; + } + +@@ -2139,6 +2139,7 @@ static int handle_control_completion(struct usbi_transfer *itransfer, + case -ENOENT: /* cancelled */ + status = LIBUSB_TRANSFER_CANCELLED; + break; ++ case -ENODEV: + case -ESHUTDOWN: + usbi_dbg("device removed"); + status = LIBUSB_TRANSFER_NO_DEVICE; +@@ -2147,9 +2148,15 @@ static int handle_control_completion(struct usbi_transfer *itransfer, + usbi_dbg("unsupported control request"); + status = LIBUSB_TRANSFER_STALL; + break; ++ case -EOVERFLOW: ++ usbi_dbg("control overflow error"); ++ status = LIBUSB_TRANSFER_OVERFLOW; ++ break; + case -ETIME: + case -EPROTO: + case -EILSEQ: ++ case -ECOMM: ++ case -ENOSR: + usbi_dbg("low-level bus error occurred"); + status = LIBUSB_TRANSFER_ERROR; + break; +-- +1.7.9.3 + diff --git a/0005-linux-Translate-linux-iso-pkt-status-codes-to-libusb.patch b/0005-linux-Translate-linux-iso-pkt-status-codes-to-libusb.patch new file mode 100644 index 0000000..9323783 --- /dev/null +++ b/0005-linux-Translate-linux-iso-pkt-status-codes-to-libusb.patch @@ -0,0 +1,68 @@ +From 4c3e7f9818c0d1d0462fde6f219da65fb102a434 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 24 Feb 2012 11:15:30 +0100 +Subject: [PATCH 4/6] linux: Translate linux iso pkt status codes to libusb + transfer status codes + +During testing of my usbredir code I hit a scenario where my libusb app +was seeing EXDEV as status in the transfer's iso_packet_desc + +This happened because we don't translate linux negative errno errors +stored in iso pkts status to libusb transfer status codes at all! So this +patch adds translation for this. + +Signed-off-by: Hans de Goede +--- + libusb/os/linux_usbfs.c | 36 +++++++++++++++++++++++++++++++++++- + 1 file changed, 35 insertions(+), 1 deletion(-) + +diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c +index 36d37a4..a7d8298 100644 +--- a/libusb/os/linux_usbfs.c ++++ b/libusb/os/linux_usbfs.c +@@ -2053,7 +2053,41 @@ static int handle_iso_completion(struct usbi_transfer *itransfer, + struct usbfs_iso_packet_desc *urb_desc = &urb->iso_frame_desc[i]; + struct libusb_iso_packet_descriptor *lib_desc = + &transfer->iso_packet_desc[tpriv->iso_packet_offset++]; +- lib_desc->status = urb_desc->status; ++ lib_desc->status = LIBUSB_TRANSFER_COMPLETED; ++ switch (urb_desc->status) { ++ case 0: ++ break; ++ case -ENOENT: /* cancelled */ ++ case -ECONNRESET: ++ break; ++ case -ENODEV: ++ case -ESHUTDOWN: ++ usbi_dbg("device removed"); ++ lib_desc->status = LIBUSB_TRANSFER_NO_DEVICE; ++ break; ++ case -EPIPE: ++ usbi_dbg("detected endpoint stall"); ++ lib_desc->status = LIBUSB_TRANSFER_STALL; ++ break; ++ case -EOVERFLOW: ++ usbi_dbg("overflow error"); ++ lib_desc->status = LIBUSB_TRANSFER_OVERFLOW; ++ break; ++ case -ETIME: ++ case -EPROTO: ++ case -EILSEQ: ++ case -ECOMM: ++ case -ENOSR: ++ case -EXDEV: ++ usbi_dbg("low-level USB error %d", urb_desc->status); ++ lib_desc->status = LIBUSB_TRANSFER_ERROR; ++ break; ++ default: ++ usbi_warn(TRANSFER_CTX(transfer), ++ "unrecognised urb status %d", urb_desc->status); ++ lib_desc->status = LIBUSB_TRANSFER_ERROR; ++ break; ++ } + lib_desc->actual_length = urb_desc->actual_length; + } + +-- +1.7.9.3 + diff --git a/0006-linux_usbfs-Add-support-for-the-new-get_capabilities.patch b/0006-linux_usbfs-Add-support-for-the-new-get_capabilities.patch new file mode 100644 index 0000000..1a5c0c0 --- /dev/null +++ b/0006-linux_usbfs-Add-support-for-the-new-get_capabilities.patch @@ -0,0 +1,117 @@ +From 1fabeefda0fb31aa36203aa8b3f07debdc83d22a Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 28 Jun 2012 16:40:52 +0200 +Subject: [PATCH 1/6] linux_usbfs: Add support for the new get_capabilities + ioctl + +There were a few (new) usbdevfs capabilities which libusbx could not +discover in any other way then checking the kernel version. There are 3 +problems with this: +1) It is just not very pretty +2) Given the tendency of enterprise distros to backport stuff it is not + reliable +3) Some of these features turn out to not work with certain host controllers, + making depending on them based on the kernel version not a good idea + +Therefor a new USBDEVFS_GET_CAPABILITIES ioctl has been added to the kernel +to offer a better way to find out a device's capabilities (technically +the capabilities of the host controller to which the device is attached, +but that does not matter). + +Signed-off-by: Hans de Goede +--- + libusb/os/linux_usbfs.c | 24 ++++++++++++++++++++---- + libusb/os/linux_usbfs.h | 10 ++++++++++ + 2 files changed, 30 insertions(+), 4 deletions(-) + +diff -up libusb-1.0.8/libusb/os/linux_usbfs.c.caps libusb-1.0.8/libusb/os/linux_usbfs.c +--- libusb-1.0.8/libusb/os/linux_usbfs.c.caps 2012-08-22 15:32:34.677822979 +0200 ++++ libusb-1.0.8/libusb/os/linux_usbfs.c 2012-08-22 15:39:27.526002251 +0200 +@@ -107,6 +107,7 @@ struct linux_device_priv { + + struct linux_device_handle_priv { + int fd; ++ __u32 caps; + }; + + enum reap_action { +@@ -1139,6 +1140,7 @@ static int op_open(struct libusb_device_ + { + struct linux_device_handle_priv *hpriv = __device_handle_priv(handle); + char filename[PATH_MAX]; ++ int r; + + __get_usbfs_path(handle->dev, filename); + usbi_dbg("opening %s", filename); +@@ -1161,6 +1163,18 @@ static int op_open(struct libusb_device_ + } + } + ++ r = ioctl(hpriv->fd, IOCTL_USBFS_GET_CAPABILITIES, &hpriv->caps); ++ if (r < 0) { ++ if (errno == ENOTTY) ++ usbi_dbg("%s: getcap not available", filename); ++ else ++ usbi_err(HANDLE_CTX(handle), ++ "%s: getcap failed (%d)", filename, errno); ++ hpriv->caps = 0; ++ if (supports_flag_bulk_continuation) ++ hpriv->caps |= USBFS_CAP_BULK_CONTINUATION; ++ } ++ + return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT); + } + +@@ -1544,7 +1558,7 @@ static int submit_bulk_transfer(struct u + urb->type = urb_type; + urb->endpoint = transfer->endpoint; + urb->buffer = transfer->buffer + (i * MAX_BULK_BUFFER_LENGTH); +- if (supports_flag_bulk_continuation && !is_out) ++ if ((dpriv->caps & USBFS_CAP_BULK_CONTINUATION) && !is_out) + urb->flags = USBFS_URB_SHORT_NOT_OK; + if (i == num_urbs - 1 && last_urb_partial) + urb->buffer_length = transfer->length % MAX_BULK_BUFFER_LENGTH; +@@ -1553,7 +1567,7 @@ static int submit_bulk_transfer(struct u + else + urb->buffer_length = MAX_BULK_BUFFER_LENGTH; + +- if (i > 0 && supports_flag_bulk_continuation) ++ if (i > 0 && (dpriv->caps & USBFS_CAP_BULK_CONTINUATION)) + urb->flags |= USBFS_URB_BULK_CONTINUATION; + + r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb); +diff -up libusb-1.0.8/libusb/os/linux_usbfs.h.caps libusb-1.0.8/libusb/os/linux_usbfs.h +--- libusb-1.0.8/libusb/os/linux_usbfs.h.caps 2011-02-07 11:53:41.000000000 +0100 ++++ libusb-1.0.8/libusb/os/linux_usbfs.h 2012-08-22 15:33:21.224843100 +0200 +@@ -21,6 +21,8 @@ + #ifndef __LIBUSB_USBFS_H__ + #define __LIBUSB_USBFS_H__ + ++#include ++ + #define SYSFS_DEVICE_PATH "/sys/bus/usb/devices" + + struct usbfs_ctrltransfer { +@@ -115,6 +117,11 @@ struct usbfs_hub_portinfo { + unsigned char port[127]; /* port to device num mapping */ + }; + ++#define USBFS_CAP_ZERO_PACKET 0x01 ++#define USBFS_CAP_BULK_CONTINUATION 0x02 ++#define USBFS_CAP_NO_PACKET_SIZE_LIM 0x04 ++#define USBFS_CAP_BULK_SCATTER_GATHER 0x08 ++ + #define IOCTL_USBFS_CONTROL _IOWR('U', 0, struct usbfs_ctrltransfer) + #define IOCTL_USBFS_BULK _IOWR('U', 2, struct usbfs_bulktransfer) + #define IOCTL_USBFS_RESETEP _IOR('U', 3, unsigned int) +@@ -134,5 +141,8 @@ struct usbfs_hub_portinfo { + #define IOCTL_USBFS_CLEAR_HALT _IOR('U', 21, unsigned int) + #define IOCTL_USBFS_DISCONNECT _IO('U', 22) + #define IOCTL_USBFS_CONNECT _IO('U', 23) ++#define IOCTL_USBFS_CLAIM_PORT _IOR('U', 24, unsigned int) ++#define IOCTL_USBFS_RELEASE_PORT _IOR('U', 25, unsigned int) ++#define IOCTL_USBFS_GET_CAPABILITIES _IOR('U', 26, __u32) + + #endif +-- +1.7.11.4 diff --git a/0007-linux_usbfs-Avoid-unnecessary-splitting-of-bulk-tran.patch b/0007-linux_usbfs-Avoid-unnecessary-splitting-of-bulk-tran.patch new file mode 100644 index 0000000..761d82d --- /dev/null +++ b/0007-linux_usbfs-Avoid-unnecessary-splitting-of-bulk-tran.patch @@ -0,0 +1,141 @@ +From 9b1b7e0acd9f41e6df213e9eeb744e970bdc1544 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 29 Jun 2012 12:16:11 +0200 +Subject: [PATCH 2/6] linux_usbfs: Avoid unnecessary splitting of bulk + transfers (v2) + +With the latest kernels it is no longer needed to always split large bulk +transfers into multiple urbs. This patch takes advantage of this by not +splitting when not necessary. Note that the non-split code path is in essence +using the old split code path with an urb count which is always 1. + +This leads to more sane handling of large transfers with recent kernels, +although our splitting code is well tested, not splitting at all still is +a lot better :) + +When used with a recent kernel, this also fixes the problems, on XHCI attached +devices, when a large bulk-in transfer ends with a short read in an urb other +then the last urb. For details on this see the mailinglist thread titled +"usbdevfs: BULK_CONTINUATION flag does not work with XHCI controller". + +Changes in v2: +-avoid a divide by 0 on 0 size packets + +Signed-off-by: Hans de Goede +--- + libusb/os/linux_usbfs.c | 69 ++++++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 57 insertions(+), 12 deletions(-) + +diff -up libusb-1.0.8/libusb/os/linux_usbfs.c.bulk libusb-1.0.8/libusb/os/linux_usbfs.c +--- libusb-1.0.8/libusb/os/linux_usbfs.c.bulk 2012-08-22 15:40:51.814038955 +0200 ++++ libusb-1.0.8/libusb/os/linux_usbfs.c 2012-08-22 15:43:26.788106690 +0200 +@@ -1519,6 +1519,7 @@ static int submit_bulk_transfer(struct u + struct usbfs_urb *urbs; + int is_out = (transfer->endpoint & LIBUSB_ENDPOINT_DIR_MASK) + == LIBUSB_ENDPOINT_OUT; ++ int bulk_buffer_len, use_bulk_continuation; + int r; + int i; + size_t alloc_size; +@@ -1526,16 +1527,54 @@ static int submit_bulk_transfer(struct u + if (tpriv->urbs) + return LIBUSB_ERROR_BUSY; + +- /* usbfs places a 16kb limit on bulk 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. */ +- int num_urbs = transfer->length / MAX_BULK_BUFFER_LENGTH; ++ /* ++ * Older versions of usbfs place a 16kb limit on bulk URBs. We work ++ * around this by splitting large transfers into 16k blocks, and then ++ * submit all urbs at once. it would be simpler to submit one urb at ++ * a time, but there is a big performance gain doing it this way. ++ * ++ * Newer versions lift the 16k limit (USBFS_CAP_NO_PACKET_SIZE_LIM), ++ * using arbritary large transfers can still be a bad idea though, as ++ * the kernel needs to allocate physical contiguous memory for this, ++ * which may fail for large buffers. ++ * ++ * The kernel solves this problem by splitting the transfer into ++ * blocks itself when the host-controller is scatter-gather capable ++ * (USBFS_CAP_BULK_SCATTER_GATHER), which most controllers are. ++ * ++ * Last, there is the issue of short-transfers when splitting, for ++ * short split-transfers to work reliable USBFS_CAP_BULK_CONTINUATION ++ * is needed, but this is not always available. ++ */ ++ if (dpriv->caps & USBFS_CAP_BULK_SCATTER_GATHER) { ++ /* Good! Just submit everything in one go */ ++ bulk_buffer_len = transfer->length ? transfer->length : 1; ++ use_bulk_continuation = 0; ++ } else if (dpriv->caps & USBFS_CAP_BULK_CONTINUATION) { ++ /* Split the transfers and use bulk-continuation to ++ avoid issues with short-transfers */ ++ bulk_buffer_len = MAX_BULK_BUFFER_LENGTH; ++ use_bulk_continuation = 1; ++ } else if (dpriv->caps & USBFS_CAP_NO_PACKET_SIZE_LIM) { ++ /* Don't split, assume the kernel can alloc the buffer ++ (otherwise the submit will fail with -ENOMEM) */ ++ bulk_buffer_len = transfer->length ? transfer->length : 1; ++ use_bulk_continuation = 0; ++ } else { ++ /* Bad, splitting without bulk-continuation, short transfers ++ which end before the last urb will not work reliable! */ ++ /* Note we don't warn here as this is "normal" on kernels < ++ 2.6.32 and not a problem for most applications */ ++ bulk_buffer_len = MAX_BULK_BUFFER_LENGTH; ++ use_bulk_continuation = 0; ++ } ++ ++ int num_urbs = transfer->length / bulk_buffer_len; + int last_urb_partial = 0; + + if (transfer->length == 0) { + num_urbs = 1; +- } else if ((transfer->length % MAX_BULK_BUFFER_LENGTH) > 0) { ++ } else if ((transfer->length % bulk_buffer_len) > 0) { + last_urb_partial = 1; + num_urbs++; + } +@@ -1557,17 +1596,17 @@ static int submit_bulk_transfer(struct u + urb->usercontext = itransfer; + urb->type = urb_type; + urb->endpoint = transfer->endpoint; +- urb->buffer = transfer->buffer + (i * MAX_BULK_BUFFER_LENGTH); +- if ((dpriv->caps & USBFS_CAP_BULK_CONTINUATION) && !is_out) ++ urb->buffer = transfer->buffer + (i * bulk_buffer_len); ++ if (use_bulk_continuation && !is_out) + urb->flags = USBFS_URB_SHORT_NOT_OK; + if (i == num_urbs - 1 && last_urb_partial) +- urb->buffer_length = transfer->length % MAX_BULK_BUFFER_LENGTH; ++ urb->buffer_length = transfer->length % bulk_buffer_len; + else if (transfer->length == 0) + urb->buffer_length = 0; + else +- urb->buffer_length = MAX_BULK_BUFFER_LENGTH; ++ urb->buffer_length = bulk_buffer_len; + +- if (i > 0 && (dpriv->caps & USBFS_CAP_BULK_CONTINUATION)) ++ if (i > 0 && use_bulk_continuation) + urb->flags |= USBFS_URB_BULK_CONTINUATION; + + r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb); +@@ -1649,7 +1688,13 @@ static int submit_iso_transfer(struct us + /* 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. */ ++ * 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. ++ */ + + /* calculate how many URBs we need */ + for (i = 0; i < num_packets; i++) { +-- +1.7.11.4 + diff --git a/0008-detach-kernel-driver-return-ERROR_NOT_FOUND-if-usbfs.patch b/0008-detach-kernel-driver-return-ERROR_NOT_FOUND-if-usbfs.patch new file mode 100644 index 0000000..a60a756 --- /dev/null +++ b/0008-detach-kernel-driver-return-ERROR_NOT_FOUND-if-usbfs.patch @@ -0,0 +1,65 @@ +From daa923ac06cbf5bcac6922a9520aa7fc9919134e Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sat, 28 Jul 2012 11:43:52 +0200 +Subject: [PATCH 3/6] detach-kernel-driver: return ERROR_NOT_FOUND if usbfs is + already bound (v3) + +Currently applications for devices which only are accessed from userspace +can use claim / release interface to make sure they don't get in each others +way. The same however does not work for applications which first need to detach +a "native" / in kernel driver, as this detach will not only detach native +drivers but also the usbfs driver, thus stealing the device from another +userspace / libusbx app. + +This patch fixes libusb_detach_kernel_driver to only detach "real" kernel +drivers and not the special usbfs driver used for userspace access to +USB devices. If the usbfs driver is found LIBUSB_ERROR_NOT_FOUND will be +returned to indicate no driver was detached. + +Signed-off-by: Hans de Goede +--- + libusb/core.c | 4 ++++ + libusb/os/linux_usbfs.c | 6 ++++++ + 2 files changed, 10 insertions(+) + +diff --git a/libusb/core.c b/libusb/core.c +index 7c2f4d7..4c513f7 100644 +--- a/libusb/core.c ++++ b/libusb/core.c +@@ -1513,6 +1513,10 @@ int API_EXPORTED libusb_kernel_driver_active(libusb_device_handle *dev, + * + * This functionality is not available on Darwin or Windows. + * ++ * Note that libusb itself also talks to the device through a special kernel ++ * driver, if this driver is already attached to the device, this call will ++ * not detach it and return LIBUSB_ERROR_NOT_FOUND. ++ * + * \param dev a device handle + * \param interface_number the interface to detach the driver from + * \returns 0 on success +diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c +index 839ebde..1407866 100644 +--- a/libusb/os/linux_usbfs.c ++++ b/libusb/os/linux_usbfs.c +@@ -1538,12 +1538,18 @@ static int op_detach_kernel_driver(struct libusb_device_handle *handle, + { + int fd = __device_handle_priv(handle)->fd; + struct usbfs_ioctl command; ++ struct usbfs_getdriver getdrv; + int r; + + command.ifno = interface; + command.ioctl_code = IOCTL_USBFS_DISCONNECT; + command.data = NULL; + ++ getdrv.interface = interface; ++ r = ioctl(fd, IOCTL_USBFS_GETDRIVER, &getdrv); ++ if (r == 0 && strcmp(getdrv.driver, "usbfs") == 0) ++ return LIBUSB_ERROR_NOT_FOUND; ++ + r = ioctl(fd, IOCTL_USBFS_IOCTL, &command); + if (r) { + if (errno == ENODATA) +-- +1.7.11.4 + diff --git a/0009-linux_usbfs-Work-around-a-driver-binding-race-in-res.patch b/0009-linux_usbfs-Work-around-a-driver-binding-race-in-res.patch new file mode 100644 index 0000000..3a39c1c --- /dev/null +++ b/0009-linux_usbfs-Work-around-a-driver-binding-race-in-res.patch @@ -0,0 +1,86 @@ +From 78a150bfbbd84eb524e878bf05101c1ad2eac0b8 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 6 Jul 2012 14:35:53 +0200 +Subject: [PATCH 3/3] linux_usbfs: Work around a driver binding race in reset + handling + +I've been seeing these intermittent failures to reclaim an interface after +a device reset. After much debugging and inserting sleeps in strategic +places to make the race window larger I've found the following race: +1) A user is running some software using libusb which will automatically + detect, and "bind" to, any newly plugged in USB-devices. For example + a virtual machine viewer with automatic USB-redirection +2) The user plugs in a new usb-storage device +3) The usb-storage driver is not yet loaded, udev spawns + "modprobe usb-storage", this blocks on disk-io +4) The libusb app opens the device, claims all interfaces, does a device-reset +5) While the IOCTL_USBFS_RESET is running the modprobe completes +6) The driver registration blocks on an USB lock held by the reset code path +7) When the reset finishes the driver registration completes and the driver + binds itself to the device, before IOCTL_USBFS_RESET returns to userspace +8) libusb tries to re-claim all interfaces it had claimed before the reset +9) libusb fails as usb-storage is now bound to it + +This patch works around this issue by simply unbinding the driver for all +interfaces which were claimed before the reset. Normally this is a no-op as +no driver (other then usbfs) can be bound for claimed interfaces before the +reset. + +But as the above example shows, the exception is a driver completing +registration, and as part of this binding to any elegible devices, between +IOCTL_USBFS_RESET and our re-claiming of the interface. The largest part +of the race window here is the time IOCTL_USBFS_RESET takes, as that does a +fair amount of IO with the device. This part of the race window is +worked around by this patch. + +This still leaves a theoretical race window where the driver registration +finishes between our driver-unbind and interface-reclaim, I'm afraid there +is nothing we can against this. + +This patch also improves the error logging, and makes libusb_device_reset +properly return an error when re-claiming fails. + +Signed-off-by: Hans de Goede +--- + libusb/os/linux_usbfs.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c +index 3894554..10d138a 100644 +--- a/libusb/os/linux_usbfs.c ++++ b/libusb/os/linux_usbfs.c +@@ -108,6 +108,9 @@ static int sysfs_can_relate_devices = 0; + /* do we have a descriptors file? */ + static int sysfs_has_descriptors = 0; + ++static int op_detach_kernel_driver(struct libusb_device_handle *handle, ++ int interface); ++ + struct linux_device_priv { + char *sysfs_dir; + unsigned char *dev_descriptor; +@@ -1497,11 +1500,20 @@ static int op_reset_device(struct libusb_device_handle *handle) + /* And re-claim any interfaces which were claimed before the reset */ + for (i = 0; i < USB_MAXINTERFACES; i++) { + if (handle->claimed_interfaces & (1L << i)) { ++ /* ++ * A driver may have completed modprobing during ++ * IOCTL_USBFS_RESET, and bound itself as soon as ++ * IOCTL_USBFS_RESET released the device lock ++ */ ++ op_detach_kernel_driver(handle, i); ++ + r = op_claim_interface(handle, i); + if (r) { + usbi_warn(HANDLE_CTX(handle), +- "failed to re-claim interface %d after reset", i); ++ "failed to re-claim interface %d after reset: %s", ++ i, libusb_error_name(r)); + handle->claimed_interfaces &= ~(1L << i); ++ ret = LIBUSB_ERROR_NOT_FOUND; + } + } + } +-- +1.7.11.2 + diff --git a/Makefile b/Makefile deleted file mode 100644 index beeec88..0000000 --- a/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# Makefile for source rpm: libusb1 -# $Id$ -NAME := libusb1 -SPECFILE = $(firstword $(wildcard *.spec)) - -define find-makefile-common -for d in common ../common ../../common ; do if [ -f $$d/Makefile.common ] ; then if [ -f $$d/CVS/Root -a -w $$/Makefile.common ] ; then cd $$d ; cvs -Q update ; fi ; echo "$$d/Makefile.common" ; break ; fi ; done -endef - -MAKEFILE_COMMON := $(shell $(find-makefile-common)) - -ifeq ($(MAKEFILE_COMMON),) -# attept a checkout -define checkout-makefile-common -test -f CVS/Root && { cvs -Q -d $$(cat CVS/Root) checkout common && echo "common/Makefile.common" ; } || { echo "ERROR: I can't figure out how to checkout the 'common' module." ; exit -1 ; } >&2 -endef - -MAKEFILE_COMMON := $(shell $(checkout-makefile-common)) -endif - -include $(MAKEFILE_COMMON) diff --git a/libusb1.spec b/libusb1.spec new file mode 100644 index 0000000..12ed30e --- /dev/null +++ b/libusb1.spec @@ -0,0 +1,161 @@ +Summary: A library which allows userspace access to USB devices +Name: libusb1 +Version: 1.0.9 +Release: 0.6.rc1%{?dist} +Source0: libusb-1.0.9-rc1.tar.bz2 +#Source0: http://downloads.sourceforge.net/libusb/libusb-%{version}.tar.bz2 + +Patch1: 0001-Correctly-handle-LIBUSB_TRANSFER_OVERFLOW-in-libusb_.patch +Patch2: 0002-linux-Fix-cancel_transfer-return-value-when-cancelli.patch +Patch3: 0003-Don-t-print-errors-when-cancel_transfer-fails-with-N.patch +Patch4: 0004-linux-Fix-handling-of-urb-status-codes.patch +Patch5: 0005-linux-Translate-linux-iso-pkt-status-codes-to-libusb.patch +# For rhbz#830751 +Patch6: 0006-linux_usbfs-Add-support-for-the-new-get_capabilities.patch +Patch7: 0007-linux_usbfs-Avoid-unnecessary-splitting-of-bulk-tran.patch +# For rhbz#820205 +Patch8: 0008-detach-kernel-driver-return-ERROR_NOT_FOUND-if-usbfs.patch +Patch9: 0009-linux_usbfs-Work-around-a-driver-binding-race-in-res.patch + +License: LGPLv2+ +Group: System Environment/Libraries +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +URL: http://libusb.wiki.sourceforge.net/Libusb1.0 +ExcludeArch: s390 s390x +BuildRequires: doxygen + +%description +This package provides a way for applications to access USB devices. Note that +this library is not compatible with the original libusb-0.1 series. + +%package devel +Summary: Development files for libusb +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} +Requires: pkgconfig + +%description devel +This package contains the header files, libraries and documentation needed to +develop applications that use libusb1. + +%package static +Summary: Static development files for libusb +Group: Development/Libraries +Requires: %{name}-devel = %{version}-%{release} + +%description static +This package contains static libraries to develop applications that use libusb1. + +%prep +%setup -q -n libusb-1.0.8 +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 + +%build +%configure +make CFLAGS="$RPM_OPT_FLAGS" +pushd doc +make docs +popd + +%install +rm -rf $RPM_BUILD_ROOT +make install DESTDIR=$RPM_BUILD_ROOT +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la + +# Our snapshot reports itself as 1.0.8, change the pkg-config file version to +# 1.0.9 so that configure checks by apps who need the new 1.0.9 succeed +sed -i 's/1\.0\.8/1.0.9/' %{buildroot}/%{_libdir}/pkgconfig/libusb-1.0.pc + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -p /sbin/ldconfig +%postun -p /sbin/ldconfig + + +%files +%defattr(-,root,root) +%doc AUTHORS COPYING README NEWS ChangeLog +%{_libdir}/*.so.* + +%files devel +%defattr(-,root,root) +%doc doc/html examples/*.c +%{_libdir}/pkgconfig/libusb-1.0.pc +%{_includedir}/* +%{_libdir}/*.so + +%files static +%defattr(-,root,root) +%{_libdir}/*.a + +%changelog +* Wed Aug 22 2012 Hans de Goede - 1.0.9-0.6.rc1 +- Don't split bulk transfers unnecessary +- Resolves: rhbz#830751 +- Don't let disconnect_kernel_driver detach the usbfs driver +- Resolves: rhbz#820205 + +* Wed Mar 14 2012 Hans de Goede - 1.0.9-0.5.rc1 +- Add some small error handling fixes +- Related: rhbz#758094 + +* Tue Jan 17 2012 Hans de Goede - 1.0.9-0.4.rc1 +- Fix previous changelog entry to refer to the right bug +- Related: rhbz#758094 + +* Wed Jan 11 2012 Marc-Andre Lureau 1.0.9-0.3.rc1 +- update to 1.0.9rc1, sync with f16 +- Resolves: rhbz#758094 + +* Mon Sep 28 2009 Jindrich Novy 1.0.3-1 +- update to 1.0.3 + +* Sat Jul 25 2009 Fedora Release Engineering - 1.0.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Mon Jun 15 2009 Jindrich Novy 1.0.2-1 +- update to 1.0.2 + +* Wed May 13 2009 Jindrich Novy 1.0.1-1 +- update to 1.0.1 + +* Wed Feb 25 2009 Fedora Release Engineering - 1.0.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Mon Dec 15 2008 - Bastien Nocera - 1.0.0-1 +- Update to 1.0.0 + +* Fri Nov 21 2008 - Bastien Nocera - 0.9.4-1 +- Update to 0.9.4 + +* Tue Sep 23 2008 Jindrich Novy 0.9.3-0.1 +- update to 0.9.3 + +* Sun Jul 06 2008 - Bastien Nocera - 0.9.1 +- Update to 0.9.1 + +* Mon May 26 2008 Jindrich Novy 0.9.0-0.4 +- update to official beta + +* Thu May 23 2008 Jindrich Novy 0.9.0-0.3.gitbef33bb +- update comment on how the tarball was created +- use abbreviated git hash within package name to avoid conflicts +- add to %%description that libusb1 is incompatible with libsub-0.1 + +* Thu May 22 2008 Jindrich Novy 0.9.0-0.2.gitbef33bb +- add info on how the snapshot tarball was created + +* Wed May 21 2008 Jindrich Novy 0.9.0-0.1.gitbef33bb +- use proper version to denote it is a git snapshot + +* Thu May 15 2008 Jindrich Novy 0.9.0-0.1 +- initial packaging diff --git a/sources b/sources index e69de29..283cde1 100644 --- a/sources +++ b/sources @@ -0,0 +1 @@ +389dd12f7da1411aac2524c5de35e2f5 libusb-1.0.9-rc1.tar.bz2