usblib: Wrap USBDEVFS_REAPURBNDELAY ioctl

Test: Test is submitted alongside this change
Bug: 31288102
Change-Id: I99311879150ef3f647c65205b35254736dde6de7
This commit is contained in:
Philip P. Moltmann 2016-10-17 16:57:43 -07:00
parent 70e1e9aeb1
commit 3695285d5d
2 changed files with 35 additions and 20 deletions

View File

@ -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);

View File

@ -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>
@ -681,29 +686,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;
// Poll until a request becomes available if there is a timeout
if (timeoutMillis > 0) {
struct pollfd p = {.fd = dev->fd, .events = POLLOUT, .revents = 0};
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");
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)