diff options
author | Philip P. Moltmann <moltmann@google.com> | 2016-10-27 16:15:11 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2016-10-27 16:15:12 +0000 |
commit | 96c59d848a491c6b3aaaf2f78c17e9b54cd2071c (patch) | |
tree | 3025535b92c3dad417609666ecbbe15917e9c49d /libusbhost | |
parent | f7586d30454e65f723fca1d637911f2b182bb555 (diff) | |
parent | 3695285d5d743190ed88f982b0c531066e68b686 (diff) | |
download | core-96c59d848a491c6b3aaaf2f78c17e9b54cd2071c.tar.gz |
Merge "usblib: Wrap USBDEVFS_REAPURBNDELAY ioctl"
Diffstat (limited to 'libusbhost')
-rw-r--r-- | libusbhost/include/usbhost/usbhost.h | 5 | ||||
-rw-r--r-- | libusbhost/usbhost.c | 52 |
2 files changed, 36 insertions, 21 deletions
diff --git a/libusbhost/include/usbhost/usbhost.h b/libusbhost/include/usbhost/usbhost.h index c17f3c7ea..a8dd6737c 100644 --- a/libusbhost/include/usbhost/usbhost.h +++ b/libusbhost/include/usbhost/usbhost.h @@ -232,10 +232,11 @@ void usb_request_free(struct usb_request *req); /* Submits a read or write request on the specified device */ int usb_request_queue(struct usb_request *req); - /* Waits for the results of a previous usb_request_queue operation. + /* Waits for the results of a previous usb_request_queue operation. timeoutMillis == -1 requests + * to wait forever. * Returns a usb_request, or NULL for error. */ -struct usb_request *usb_request_wait(struct usb_device *dev); +struct usb_request *usb_request_wait(struct usb_device *dev, int timeoutMillis); /* Cancels a pending usb_request_queue() operation. */ int usb_request_cancel(struct usb_request *req); diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c index 9bec6e315..7adb4f2f7 100644 --- a/libusbhost/usbhost.c +++ b/libusbhost/usbhost.c @@ -14,6 +14,10 @@ * limitations under the License. */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + // #define DEBUG 1 #if DEBUG @@ -43,6 +47,7 @@ #include <fcntl.h> #include <errno.h> #include <ctype.h> +#include <poll.h> #include <pthread.h> #include <linux/usbdevice_fs.h> @@ -683,29 +688,38 @@ int usb_request_queue(struct usb_request *req) return res; } -struct usb_request *usb_request_wait(struct usb_device *dev) +struct usb_request *usb_request_wait(struct usb_device *dev, int timeoutMillis) { - struct usbdevfs_urb *urb = NULL; - struct usb_request *req = NULL; - - while (1) { - int res = ioctl(dev->fd, USBDEVFS_REAPURB, &urb); - D("USBDEVFS_REAPURB returned %d\n", res); - if (res < 0) { - if(errno == EINTR) { - continue; - } - D("[ reap urb - error ]\n"); + // Poll until a request becomes available if there is a timeout + if (timeoutMillis > 0) { + struct pollfd p = {.fd = dev->fd, .events = POLLOUT, .revents = 0}; + + int res = poll(&p, 1, timeoutMillis); + + if (res != 1 || p.revents != POLLOUT) { + D("[ poll - event %d, error %d]\n", p.revents, errno); return NULL; - } else { - D("[ urb @%p status = %d, actual = %d ]\n", - urb, urb->status, urb->actual_length); - req = (struct usb_request*)urb->usercontext; - req->actual_length = urb->actual_length; } - break; } - return req; + + // Read the request. This should usually succeed as we polled before, but it can fail e.g. when + // two threads are reading usb requests at the same time and only a single request is available. + struct usbdevfs_urb *urb = NULL; + int res = TEMP_FAILURE_RETRY(ioctl(dev->fd, timeoutMillis == -1 ? USBDEVFS_REAPURB : + USBDEVFS_REAPURBNDELAY, &urb)); + D("%s returned %d\n", timeoutMillis == -1 ? "USBDEVFS_REAPURB" : "USBDEVFS_REAPURBNDELAY", res); + + if (res < 0) { + D("[ reap urb - error %d]\n", errno); + return NULL; + } else { + D("[ urb @%p status = %d, actual = %d ]\n", urb, urb->status, urb->actual_length); + + struct usb_request *req = (struct usb_request*)urb->usercontext; + req->actual_length = urb->actual_length; + + return req; + } } int usb_request_cancel(struct usb_request *req) |