summaryrefslogtreecommitdiff
path: root/libusb/os/linux_usbfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'libusb/os/linux_usbfs.c')
-rw-r--r--libusb/os/linux_usbfs.c27
1 files changed, 18 insertions, 9 deletions
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index 470b511..cf69286 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -72,14 +72,21 @@
static const char *usbfs_path = NULL;
-/* Linux 2.6.32 adds support for a bulk continuation URB flag. this should
- * be set on all URBs in the transfer except the first. also set the
- * SHORT_NOT_OK flag on all of them, to raise error conditions on short
- * transfers.
- * then, on any error except a cancellation, all URBs until the next
- * non-continuation URB will be cancelled with the endpoint disabled,
- * meaning that no more data can creep in during the time it takes us to
- * cancel the remaining URBs. */
+/* Linux 2.6.32 adds support for a bulk continuation URB flag. this basically
+ * allows us to mark URBs as being part of a specific logical transfer when
+ * we submit them to the kernel. then, on any error error except a
+ * cancellation, all URBs within that transfer will be cancelled with the
+ * endpoint is disabled, meaning that no more data can creep in during the
+ * time it takes to cancel the remaining URBs.
+ *
+ * The BULK_CONTINUATION flag must be set on all URBs within a bulk transfer
+ * (in either direction) except the first.
+ * For IN transfers, we must also set SHORT_NOT_OK on all the URBs.
+ * For OUT transfers, SHORT_NOT_OK must not be set. The effective behaviour
+ * (where an OUT transfer does not complete, the rest of the URBs in the
+ * transfer get cancelled) is already in effect, and setting this flag is
+ * disallowed (a kernel with USB debugging enabled will reject such URBs).
+ */
static int supports_flag_bulk_continuation = -1;
/* clock ID for monotonic clock, as not all clock sources are available on all
@@ -1334,6 +1341,8 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer,
struct linux_device_handle_priv *dpriv =
__device_handle_priv(transfer->dev_handle);
struct usbfs_urb *urbs;
+ int is_out = (transfer->endpoint & LIBUSB_ENDPOINT_DIR_MASK)
+ == LIBUSB_ENDPOINT_OUT;
int r;
int i;
size_t alloc_size;
@@ -1372,7 +1381,7 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer,
urb->type = urb_type;
urb->endpoint = transfer->endpoint;
urb->buffer = transfer->buffer + (i * MAX_BULK_BUFFER_LENGTH);
- if (supports_flag_bulk_continuation)
+ if (supports_flag_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;