# --- T2-COPYRIGHT-NOTE-BEGIN --- # This copyright note is auto-generated by ./scripts/Create-CopyPatch. # # T2 SDE: package/.../libusb/speedup-v2.patch # Copyright (C) 2008 The T2 SDE Project # # More information can be found in the files COPYING and README. # # This patch file is dual-licensed. It is available under the license the # patched project is licensed under, as long as it is an OpenSource license # as defined at http://www.opensource.org/ (e.g. BSD, X11) or under the terms # of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # --- T2-COPYRIGHT-NOTE-END --- 2x speedup for the SANE/Avision driver. - Rene Rebe Truncated read fix. - Michael Wahl Refactoring to only submit single URBs for tiny transfers to fix the binary-only Brother SANE backend. - Rene Rebe --- libusb-0.1.12/linux.c 2006-03-04 02:52:46.000000000 +0000 +++ libusb-0.1.12-speedup-v3/linux.c 2008-02-17 21:29:28.000000000 +0000 @@ -159,14 +159,17 @@ #define URB_USERCONTEXT_COOKIE ((void *)0x1) /* Reading and writing are the same except for the endpoint */ -static int usb_urb_transfer(usb_dev_handle *dev, int ep, int urbtype, - char *bytes, int size, int timeout) +static int usb_urb_transfer_intern(usb_dev_handle *dev, int ep, int urbtype, + char *bytes, int size, int timeout) { - struct usb_urb urb; - int bytesdone = 0, requested; + int nurbs; + struct usb_urb* urbs; + int bytesdone = 0; struct timeval tv, tv_ref, tv_now; struct usb_urb *context; - int ret, waiting; + int rc = 0, ret = 0, waiting, i; + + fd_set writefds; /* * HACK: The use of urb.usercontext is a hack to get threaded applications @@ -189,37 +192,44 @@ tv_ref.tv_usec -= 1000000; tv_ref.tv_sec++; } - - do { - fd_set writefds; - - requested = size - bytesdone; + + /* allocate and fill all URBs */ + nurbs = (size + MAX_READ_WRITE - 1) / MAX_READ_WRITE; + urbs = malloc (sizeof(struct usb_urb) * nurbs); + for (i = 0; i < nurbs; ++i) { + int requested = size - i * MAX_READ_WRITE; if (requested > MAX_READ_WRITE) requested = MAX_READ_WRITE; - urb.type = urbtype; - urb.endpoint = ep; - urb.flags = 0; - urb.buffer = bytes + bytesdone; - urb.buffer_length = requested; - urb.signr = 0; - urb.actual_length = 0; - urb.number_of_packets = 0; /* don't do isochronous yet */ - urb.usercontext = NULL; + urbs[i].type = urbtype; + urbs[i].endpoint = ep; + urbs[i].flags = 0; + urbs[i].buffer = bytes + i * MAX_READ_WRITE; + urbs[i].buffer_length = requested; + urbs[i].signr = 0; + urbs[i].actual_length = 0; + urbs[i].number_of_packets = 0; /* don't do isochronous yet */ + urbs[i].usercontext = NULL; - ret = ioctl(dev->fd, IOCTL_USB_SUBMITURB, &urb); + ret = ioctl(dev->fd, IOCTL_USB_SUBMITURB, &urbs[i]); if (ret < 0) { USB_ERROR_STR(-errno, "error submitting URB: %s", strerror(errno)); - return ret; + rc = ret; + goto end; } + } - FD_ZERO(&writefds); - FD_SET(dev->fd, &writefds); + FD_ZERO(&writefds); + FD_SET(dev->fd, &writefds); -restart: + /* wait 'till all URBs completed */ + for (i = 0; i < nurbs; ) { waiting = 1; context = NULL; - while (!urb.usercontext && ((ret = ioctl(dev->fd, IOCTL_USB_REAPURBNDELAY, &context)) == -1) && waiting) { + + while (!urbs[i].usercontext && + ((ret = ioctl(dev->fd, IOCTL_USB_REAPURBNDELAY, &context)) == -1) && + waiting) { tv.tv_sec = 0; tv.tv_usec = 1000; // 1 msec select(dev->fd + 1, NULL, &writefds, NULL, &tv); //sub second wait @@ -234,10 +244,24 @@ } } - if (context && context != &urb) { + /* mark done */ + if (context) { context->usercontext = URB_USERCONTEXT_COOKIE; - /* We need to restart since we got a successful URB, but not ours */ - goto restart; + + /* is it ours? */ + //if (context && context == &urbs[i]) + //fprintf (stderr, "which was the one we have been waiting for.\n"); + } + + /* done= */ + if (urbs[i].usercontext) { + if(ep & USB_ENDPOINT_IN) /*only if this is a read*/ + if(bytesdone < i * MAX_READ_WRITE) /*previous data was shorter than expected*/ + if(context->actual_length) + memmove(bytes + bytesdone, bytes + i * MAX_READ_WRITE, context->actual_length); + bytesdone += context->actual_length; + ++i; /* next URB */ + continue; } /* @@ -245,36 +269,62 @@ * something happened during the reaping and we should return that * error now */ - if (ret < 0 && !urb.usercontext && errno != EAGAIN) + if (ret < 0 && !urbs[i].usercontext && errno != EAGAIN) USB_ERROR_STR(-errno, "error reaping URB: %s", strerror(errno)); - bytesdone += urb.actual_length; - } while ((ret == 0 || urb.usercontext) && bytesdone < size && urb.actual_length == requested); + /* If the URB didn't complete in success or error, then let's unlink it */ + if (ret < 0 && !urbs[i].usercontext) { - /* If the URB didn't complete in success or error, then let's unlink it */ - if (ret < 0 && !urb.usercontext) { - int rc; + if (!waiting) + rc = -ETIMEDOUT; + else + rc = urbs[i].status; + + ret = ioctl(dev->fd, IOCTL_USB_DISCARDURB, &urbs[i]); + if (ret < 0 && errno != EINVAL && usb_debug >= 1) + fprintf(stderr, "error discarding URB: %s", strerror(errno)); + + /* + * When the URB is unlinked, it gets moved to the completed list and + * then we need to reap it or else the next time we call this function, + * we'll get the previous completion and exit early + */ + ioctl(dev->fd, IOCTL_USB_REAPURB, &context); - if (!waiting) - rc = -ETIMEDOUT; - else - rc = urb.status; + goto end; + } + } - ret = ioctl(dev->fd, IOCTL_USB_DISCARDURB, &urb); - if (ret < 0 && errno != EINVAL && usb_debug >= 1) - fprintf(stderr, "error discarding URB: %s", strerror(errno)); + rc = bytesdone; - /* - * When the URB is unlinked, it gets moved to the completed list and - * then we need to reap it or else the next time we call this function, - * we'll get the previous completion and exit early - */ - ioctl(dev->fd, IOCTL_USB_REAPURB, &context); + end: + free (urbs); + return rc; +} - return rc; +/* Reading and writing are the same except for the endpoint */ +static int usb_urb_transfer(usb_dev_handle *dev, int ep, int urbtype, + char *bytes, int size, int timeout) +{ + int rc, transferred = 0; + + /* TODO: decrease timeout with elapsed time */ + int first_read = size <= MAX_READ_WRITE ? size : MAX_READ_WRITE; + rc = usb_urb_transfer_intern (dev, ep, urbtype, bytes, first_read, timeout); + if (rc > 0) + transferred += rc; + /* if no error, no short transfer and still something to transfer */ + if (rc > 0 && size - transferred > 0 && transferred == first_read) { + rc = usb_urb_transfer_intern (dev, ep, urbtype, bytes + transferred, + size - transferred, timeout); + if (rc > 0) + transferred += rc; } - - return bytesdone; + + if (transferred) + return transferred; + else + return rc; } int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size,