summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Stuge <peter@stuge.se>2010-06-25 08:08:13 +0200
committerPete Batard <pbatard@gmail.com>2010-07-29 11:24:35 +0100
commitbfd95f6a632e65b2b5bab0bead2d769ef0e72e6d (patch)
treef666d04dc8d5ec2dbd6e986de5d071b22cec38a0
parentdb223f0879ce811988f5784f0b21b8f0bafb2992 (diff)
downloadlibusb-bfd95f6a632e65b2b5bab0bead2d769ef0e72e6d.tar.gz
Linux: Handle early complete of multi-URB transfer
-rw-r--r--libusb/os/linux_usbfs.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index 67d2a87..d0db7e2 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -1415,7 +1415,7 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer,
}
/* if it's not the first URB that failed, the situation is a bit
- * tricky. we must discard all previous URBs. there are
+ * tricky. we may need to discard all previous URBs. there are
* complications:
* - discarding is asynchronous - discarded urbs will be reaped
* later. the user must not have freed the transfer when the
@@ -1423,15 +1423,23 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer,
* freed memory.
* - the earlier URBs may have completed successfully and we do
* not want to throw away any data.
- * so, in this case we discard all the previous URBs BUT we report
- * that the transfer was submitted successfully. then later when
- * the final discard completes we can report error to the user.
+ * - this URB failing may be no error; EREMOTEIO means that
+ * this transfer simply didn't need all the URBs we submitted
+ * so, we report that the transfer was submitted successfully and
+ * in case of error we discard all previous URBs. later when
+ * the final reap completes we can report error to the user,
+ * or success if an earlier URB was completed successfully.
*/
- tpriv->reap_action = SUBMIT_FAILED;
+ tpriv->reap_action = EREMOTEIO == errno ? COMPLETED_EARLY : SUBMIT_FAILED;
/* The URBs we haven't submitted yet we count as already
* retired. */
tpriv->num_retired += num_urbs - i;
+
+ /* If we completed short then don't try to discard. */
+ if (COMPLETED_EARLY == tpriv->reap_action)
+ return 0;
+
for (j = 0; j < i; j++) {
int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, &urbs[j]);
if (tmp && errno != EINVAL)