summaryrefslogtreecommitdiff
path: root/libusbhost
diff options
context:
space:
mode:
authorPhilip P. Moltmann <moltmann@google.com>2016-10-27 16:15:11 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2016-10-27 16:15:12 +0000
commit96c59d848a491c6b3aaaf2f78c17e9b54cd2071c (patch)
tree3025535b92c3dad417609666ecbbe15917e9c49d /libusbhost
parentf7586d30454e65f723fca1d637911f2b182bb555 (diff)
parent3695285d5d743190ed88f982b0c531066e68b686 (diff)
downloadcore-96c59d848a491c6b3aaaf2f78c17e9b54cd2071c.tar.gz
Merge "usblib: Wrap USBDEVFS_REAPURBNDELAY ioctl"
Diffstat (limited to 'libusbhost')
-rw-r--r--libusbhost/include/usbhost/usbhost.h5
-rw-r--r--libusbhost/usbhost.c52
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)