summaryrefslogtreecommitdiff
path: root/libusb/os/linux_usbfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'libusb/os/linux_usbfs.c')
-rw-r--r--libusb/os/linux_usbfs.c162
1 files changed, 52 insertions, 110 deletions
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index 867893c..72db57a 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -363,7 +363,7 @@ static int sysfs_get_active_config(struct libusb_device *dev, int *config)
char tmp[4] = {0, 0, 0, 0};
long num;
int fd;
- size_t r;
+ ssize_t r;
fd = __open_sysfs_attr(dev, "bConfigurationValue");
if (fd < 0)
@@ -407,7 +407,7 @@ static int seek_to_next_config(struct libusb_context *ctx, int fd,
struct libusb_config_descriptor config;
unsigned char tmp[6];
off_t off;
- int r;
+ ssize_t r;
/* read first 6 bytes of descriptor */
r = read(fd, tmp, sizeof(tmp));
@@ -1331,6 +1331,39 @@ static void op_destroy_device(struct libusb_device *dev)
free(priv->sysfs_dir);
}
+/* URBs are discarded in reverse order of submission to avoid races. */
+static int discard_urbs(struct usbi_transfer *itransfer, int first, int last_plus_one)
+{
+ struct libusb_transfer *transfer =
+ __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct linux_transfer_priv *tpriv =
+ usbi_transfer_get_os_priv(itransfer);
+ struct linux_device_handle_priv *dpriv =
+ __device_handle_priv(transfer->dev_handle);
+ int i, ret = 0;
+ struct usbfs_urb *urb;
+
+ for (i = last_plus_one - 1; i >= first; i--) {
+ if (LIBUSB_TRANSFER_TYPE_ISOCHRONOUS == transfer->type)
+ urb = tpriv->iso_urbs[i];
+ else
+ urb = &tpriv->urbs[i];
+
+ if (0 == ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, urb))
+ continue;
+
+ if (EINVAL == errno) {
+ usbi_dbg("URB not found --> assuming ready to be reaped");
+ ret = LIBUSB_ERROR_NOT_FOUND;
+ } else {
+ usbi_warn(TRANSFER_CTX(transfer),
+ "unrecognised discard errno %d", errno);
+ ret = LIBUSB_ERROR_OTHER;
+ }
+ }
+ return ret;
+}
+
static void free_iso_urbs(struct linux_transfer_priv *tpriv)
{
int i;
@@ -1409,8 +1442,6 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer,
r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb);
if (r < 0) {
- int j;
-
if (errno == ENODEV) {
r = LIBUSB_ERROR_NO_DEVICE;
} else {
@@ -1454,14 +1485,7 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer,
if (COMPLETED_EARLY == tpriv->reap_action)
return 0;
- /* The URBs are discarded in reverse order of
- * submission, to avoid races. */
- for (j = i - 1; j >= 0; j--) {
- int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, &urbs[j]);
- if (tmp && errno != EINVAL)
- usbi_warn(TRANSFER_CTX(transfer),
- "unrecognised discard errno %d", errno);
- }
+ discard_urbs(itransfer, 0, i);
usbi_dbg("reporting successful submission but waiting for %d "
"discards before reporting error", i);
@@ -1577,8 +1601,6 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer)
for (i = 0; i < num_urbs; i++) {
int r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urbs[i]);
if (r < 0) {
- int j;
-
if (errno == ENODEV) {
r = LIBUSB_ERROR_NO_DEVICE;
} else {
@@ -1613,12 +1635,7 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer)
/* The URBs we haven't submitted yet we count as already
* retired. */
tpriv->num_retired = num_urbs - i;
- for (j = i - 1; j >= 0; j--) {
- int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, urbs[j]);
- if (tmp && errno != EINVAL)
- usbi_warn(TRANSFER_CTX(transfer),
- "unrecognised discard errno %d", errno);
- }
+ discard_urbs(itransfer, 0, i);
usbi_dbg("reporting successful submission but waiting for %d "
"discards before reporting error", i);
@@ -1650,6 +1667,7 @@ static int submit_control_transfer(struct usbi_transfer *itransfer)
return LIBUSB_ERROR_NO_MEM;
memset(urb, 0, sizeof(struct usbfs_urb));
tpriv->urbs = urb;
+ tpriv->num_urbs = 1;
tpriv->reap_action = NORMAL;
urb->usercontext = itransfer;
@@ -1693,98 +1711,32 @@ static int op_submit_transfer(struct usbi_transfer *itransfer)
}
}
-static int cancel_control_transfer(struct usbi_transfer *itransfer)
-{
- struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
- struct libusb_transfer *transfer =
- __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct linux_device_handle_priv *dpriv =
- __device_handle_priv(transfer->dev_handle);
- int r;
-
- if (!tpriv->urbs)
- return LIBUSB_ERROR_NOT_FOUND;
-
- tpriv->reap_action = CANCELLED;
- r = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, tpriv->urbs);
- if(r) {
- if (errno == EINVAL) {
- usbi_dbg("URB not found --> assuming ready to be reaped");
- return 0;
- } else {
- usbi_err(TRANSFER_CTX(transfer),
- "unrecognised DISCARD code %d", errno);
- return LIBUSB_ERROR_OTHER;
- }
- }
-
- return 0;
-}
-
-static int cancel_bulk_transfer(struct usbi_transfer *itransfer)
-{
- struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
- struct libusb_transfer *transfer =
- __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct linux_device_handle_priv *dpriv =
- __device_handle_priv(transfer->dev_handle);
- int i;
-
- if (!tpriv->urbs)
- return LIBUSB_ERROR_NOT_FOUND;
-
- if (tpriv->reap_action != ERROR)
- tpriv->reap_action = CANCELLED;
-
- for (i = tpriv->num_urbs - 1; i >= 0; i--) {
- int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, &tpriv->urbs[i]);
- if (tmp && errno != EINVAL)
- usbi_warn(TRANSFER_CTX(transfer),
- "unrecognised discard errno %d", errno);
- }
- return 0;
-}
-
-static int cancel_iso_transfer(struct usbi_transfer *itransfer)
-{
- struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
- struct libusb_transfer *transfer =
- __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct linux_device_handle_priv *dpriv =
- __device_handle_priv(transfer->dev_handle);
- int i;
-
- if (!tpriv->iso_urbs)
- return LIBUSB_ERROR_NOT_FOUND;
-
- tpriv->reap_action = CANCELLED;
- for (i = tpriv->num_urbs - 1; i >= 0; i--) {
- int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, tpriv->iso_urbs[i]);
- if (tmp && errno != EINVAL)
- usbi_warn(TRANSFER_CTX(transfer),
- "unrecognised discard errno %d", errno);
- }
- return 0;
-}
-
static int op_cancel_transfer(struct usbi_transfer *itransfer)
{
+ struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
struct libusb_transfer *transfer =
__USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
switch (transfer->type) {
- case LIBUSB_TRANSFER_TYPE_CONTROL:
- return cancel_control_transfer(itransfer);
case LIBUSB_TRANSFER_TYPE_BULK:
+ if (tpriv->reap_action == ERROR)
+ break;
+ /* else, fall through */
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- return cancel_bulk_transfer(itransfer);
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- return cancel_iso_transfer(itransfer);
+ tpriv->reap_action = CANCELLED;
+ break;
default:
usbi_err(TRANSFER_CTX(transfer),
"unknown endpoint type %d", transfer->type);
return LIBUSB_ERROR_INVALID_PARAM;
}
+
+ if (!tpriv->urbs)
+ return LIBUSB_ERROR_NOT_FOUND;
+
+ return discard_urbs(itransfer, 0, tpriv->num_urbs);
}
static void op_clear_transfer_priv(struct usbi_transfer *itransfer)
@@ -1814,7 +1766,6 @@ static int handle_bulk_completion(struct usbi_transfer *itransfer,
{
struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct linux_device_handle_priv *dpriv = __device_handle_priv(transfer->dev_handle);
int urb_idx = urb - tpriv->urbs;
usbi_mutex_lock(&itransfer->lock);
@@ -1928,16 +1879,7 @@ cancel_remaining:
/* cancel remaining urbs and wait for their completion before
* reporting results */
- for (int i = tpriv->num_urbs - 1; i > urb_idx; i--) {
- /* remaining URBs with continuation flag are
- * automatically cancelled by the kernel */
- if (tpriv->urbs[i].flags & USBFS_URB_BULK_CONTINUATION)
- continue;
- int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, &tpriv->urbs[i]);
- if (tmp && errno != EINVAL)
- usbi_warn(TRANSFER_CTX(transfer),
- "unrecognised discard errno %d", errno);
- }
+ discard_urbs(itransfer, urb_idx + 1, tpriv->num_urbs);
out_unlock:
usbi_mutex_unlock(&itransfer->lock);
@@ -2142,7 +2084,7 @@ static int reap_for_handle(struct libusb_device_handle *handle)
}
static int op_handle_events(struct libusb_context *ctx,
- struct pollfd *fds, nfds_t nfds, int num_ready)
+ struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready)
{
int r;
int i = 0;