#include <sys/mman.h>
#include <sys/utsname.h>
#include <sys/vfs.h>
+#include <unistd.h>
/* sysfs vs usbfs:
* opening a usbfs node causes the device to be resumed, so we attempt to
/* how many times have we initted (and not exited) ? */
static int init_count = 0;
-/* Serialize hotplug start/stop */
-static usbi_mutex_static_t linux_hotplug_startstop_lock = USBI_MUTEX_INITIALIZER;
+/* have no authority to operate usb device directly */
+static int no_enumeration = 0;
+
/* Serialize scan-devices, event-thread, and poll */
usbi_mutex_static_t linux_hotplug_lock = USBI_MUTEX_INITIALIZER;
void *descriptors;
size_t descriptors_len;
struct config_descriptor *config_descriptors;
- uint8_t active_config; /* cache val for !sysfs_available */
+ int active_config; /* cache val for !sysfs_available */
};
struct linux_device_handle_priv {
int iso_packet_offset;
};
+static int dev_has_config0(struct libusb_device *dev)
+{
+ struct linux_device_priv *priv = usbi_get_device_priv(dev);
+ struct config_descriptor *config;
+ uint8_t idx;
+
+ for (idx = 0; idx < dev->device_descriptor.bNumConfigurations; idx++) {
+ config = &priv->config_descriptors[idx];
+ if (config->desc->bConfigurationValue == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
static int get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent)
{
struct libusb_context *ctx = DEVICE_CTX(dev);
if (sscanf(name, "usbdev%d.%d", &busnum, &devnum) != 2)
return 0;
if (busnum < 0 || busnum > UINT8_MAX || devnum < 0 || devnum > UINT8_MAX) {
- usbi_dbg("invalid usbdev format '%s'", name);
+ usbi_dbg(NULL, "invalid usbdev format '%s'", name);
return 0;
}
- usbi_dbg("found: %s", name);
+ usbi_dbg(NULL, "found: %s", name);
if (bus_p)
*bus_p = (uint8_t)busnum;
if (dev_p)
if (atoms < 3)
ver->sublevel = -1;
- usbi_dbg("reported kernel version is %s", uts.release);
+ usbi_dbg(ctx, "reported kernel version is %s", uts.release);
return 0;
}
return LIBUSB_ERROR_OTHER;
}
- usbi_dbg("found usbfs at %s", usbfs_path);
+ usbi_dbg(ctx, "found usbfs at %s", usbfs_path);
if (!max_iso_packet_len) {
if (kernel_version_ge(&kversion, 5, 2, 0))
max_iso_packet_len = 8192;
}
- usbi_dbg("max iso packet length is (likely) %u bytes", max_iso_packet_len);
+ usbi_dbg(ctx, "max iso packet length is (likely) %u bytes", max_iso_packet_len);
if (sysfs_available == -1) {
struct statfs statfsbuf;
r = statfs(SYSFS_MOUNT_PATH, &statfsbuf);
if (r == 0 && statfsbuf.f_type == SYSFS_MAGIC) {
- usbi_dbg("sysfs is available");
+ usbi_dbg(ctx, "sysfs is available");
sysfs_available = 1;
} else {
usbi_warn(ctx, "sysfs not mounted");
}
}
- usbi_mutex_static_lock(&linux_hotplug_startstop_lock);
+ if (no_enumeration) {
+ return LIBUSB_SUCCESS;
+ }
+
r = LIBUSB_SUCCESS;
if (init_count == 0) {
/* start up hotplug event handler */
} else {
usbi_err(ctx, "error starting hotplug event monitor");
}
- usbi_mutex_static_unlock(&linux_hotplug_startstop_lock);
return r;
}
static void op_exit(struct libusb_context *ctx)
{
UNUSED(ctx);
- usbi_mutex_static_lock(&linux_hotplug_startstop_lock);
+
+ if (no_enumeration) {
+ return;
+ }
+
assert(init_count != 0);
if (!--init_count) {
/* tear down event handler */
linux_stop_event_monitor();
}
- usbi_mutex_static_unlock(&linux_hotplug_startstop_lock);
+}
+
+static int op_set_option(struct libusb_context *ctx, enum libusb_option option, va_list ap)
+{
+ UNUSED(ctx);
+ UNUSED(ap);
+
+ if (option == LIBUSB_OPTION_NO_DEVICE_DISCOVERY) {
+ usbi_dbg(ctx, "no enumeration will be performed");
+ no_enumeration = 1;
+ return LIBUSB_SUCCESS;
+ }
+
+ return LIBUSB_ERROR_NOT_SUPPORTED;
}
static int linux_scan_devices(struct libusb_context *ctx)
if (fd < 0)
return fd;
- r = read(fd, buf, sizeof(buf));
+ r = read(fd, buf, sizeof(buf) - 1);
if (r < 0) {
r = errno;
close(fd);
return 0;
}
- /* The kernel does *not* NULL-terminate the string, but every attribute
+ /* The kernel does *not* NUL-terminate the string, but every attribute
* should be terminated with a newline character. */
if (!isdigit(buf[0])) {
usbi_err(ctx, "attribute %s doesn't have numeric value?", attr);
return LIBUSB_ERROR_IO;
} else if (buf[r - 1] != '\n') {
- usbi_err(ctx, "attribute %s doesn't end with newline?", attr);
- return LIBUSB_ERROR_IO;
+ usbi_warn(ctx, "attribute %s doesn't end with newline?", attr);
+ } else {
+ /* Remove the terminating newline character */
+ r--;
}
- buf[r - 1] = '\0';
+ buf[r] = '\0';
errno = 0;
value = strtol(buf, &endptr, 10);
}
/* read the bConfigurationValue for a device */
-static int sysfs_get_active_config(struct libusb_device *dev, uint8_t *config)
+static int sysfs_get_active_config(struct libusb_device *dev, int *config)
{
struct linux_device_priv *priv = usbi_get_device_priv(dev);
- int ret, tmp;
-
- ret = read_sysfs_attr(DEVICE_CTX(dev), priv->sysfs_dir, "bConfigurationValue",
- UINT8_MAX, &tmp);
- if (ret < 0)
- return ret;
-
- if (tmp == -1)
- tmp = 0; /* unconfigured */
- *config = (uint8_t)tmp;
-
- return 0;
+ return read_sysfs_attr(DEVICE_CTX(dev), priv->sysfs_dir, "bConfigurationValue",
+ UINT8_MAX, config);
}
int linux_get_device_address(struct libusb_context *ctx, int detached,
int sysfs_val;
int r;
- usbi_dbg("getting address for device: %s detached: %d", sys_name, detached);
+ usbi_dbg(ctx, "getting address for device: %s detached: %d", sys_name, detached);
/* can't use sysfs to read the bus and device number if the
* device has been detached */
if (!sysfs_available || detached || !sys_name) {
return LIBUSB_SUCCESS;
}
- usbi_dbg("scan %s", sys_name);
+ usbi_dbg(ctx, "scan %s", sys_name);
r = read_sysfs_attr(ctx, sys_name, "busnum", UINT8_MAX, &sysfs_val);
if (r < 0)
return r;
*devaddr = (uint8_t)sysfs_val;
- usbi_dbg("bus=%u dev=%u", *busnum, *devaddr);
+ usbi_dbg(ctx, "bus=%u dev=%u", *busnum, *devaddr);
return LIBUSB_SUCCESS;
}
uint8_t *buffer, size_t len)
{
struct usbi_descriptor_header *header;
- int offset = 0;
+ int offset;
+
+ /* Start seeking past the config descriptor */
+ offset = LIBUSB_DT_CONFIG_SIZE;
+ buffer += LIBUSB_DT_CONFIG_SIZE;
+ len -= LIBUSB_DT_CONFIG_SIZE;
while (len > 0) {
if (len < 2) {
uint8_t *buffer;
size_t remaining;
- device_desc = (struct usbi_device_descriptor *)priv->descriptors;
+ device_desc = priv->descriptors;
num_configs = device_desc->bNumConfigurations;
if (num_configs == 0)
if (!priv->config_descriptors)
return LIBUSB_ERROR_NO_MEM;
- buffer = priv->descriptors + LIBUSB_DT_DEVICE_SIZE;
+ buffer = (uint8_t *)priv->descriptors + LIBUSB_DT_DEVICE_SIZE;
remaining = priv->descriptors_len - LIBUSB_DT_DEVICE_SIZE;
for (idx = 0; idx < num_configs; idx++) {
}
if (priv->sysfs_dir) {
- /*
+ /*
* In sysfs wTotalLength is ignored, instead the kernel returns a
* config descriptor with verified bLength fields, with descriptors
* with an invalid bLength removed.
int offset;
if (num_configs > 1 && idx < num_configs - 1) {
- offset = seek_to_next_config(ctx, buffer + LIBUSB_DT_CONFIG_SIZE,
- remaining - LIBUSB_DT_CONFIG_SIZE);
+ offset = seek_to_next_config(ctx, buffer, remaining);
if (offset < 0)
return offset;
sysfs_config_len = (uint16_t)offset;
}
}
+ if (config_desc->bConfigurationValue == 0)
+ usbi_warn(ctx, "device has configuration 0");
+
priv->config_descriptors[idx].desc = config_desc;
priv->config_descriptors[idx].actual_len = config_len;
{
struct linux_device_priv *priv = usbi_get_device_priv(dev);
void *config_desc;
- uint8_t active_config;
+ int active_config;
int r;
if (priv->sysfs_dir) {
active_config = priv->active_config;
}
- if (active_config == 0) {
+ if (active_config == -1) {
usbi_err(DEVICE_CTX(dev), "device unconfigured");
return LIBUSB_ERROR_NOT_FOUND;
}
- r = op_get_config_descriptor_by_value(dev, active_config, &config_desc);
+ r = op_get_config_descriptor_by_value(dev, (uint8_t)active_config, &config_desc);
if (r < 0)
return r;
/* we hit this error path frequently with buggy devices :( */
usbi_warn(DEVICE_CTX(dev), "get configuration failed, errno=%d", errno);
+
+ /* assume the current configuration is the first one if we have
+ * the configuration descriptors, otherwise treat the device
+ * as unconfigured. */
+ if (priv->config_descriptors)
+ priv->active_config = (int)priv->config_descriptors[0].desc->bConfigurationValue;
+ else
+ priv->active_config = -1;
} else if (active_config == 0) {
- /* some buggy devices have a configuration 0, but we're
- * reaching into the corner of a corner case here, so let's
- * not support buggy devices in these circumstances.
- * stick to the specs: a configuration value of 0 means
- * unconfigured. */
- usbi_warn(DEVICE_CTX(dev), "active cfg 0? assuming unconfigured device");
+ if (dev_has_config0(dev)) {
+ /* some buggy devices have a configuration 0, but we're
+ * reaching into the corner of a corner case here. */
+ priv->active_config = 0;
+ } else {
+ priv->active_config = -1;
+ }
+ } else {
+ priv->active_config = (int)active_config;
}
- priv->active_config = active_config;
-
return LIBUSB_SUCCESS;
}
+static enum libusb_speed usbfs_get_speed(struct libusb_context *ctx, int fd)
+{
+ int r;
+
+ r = ioctl(fd, IOCTL_USBFS_GET_SPEED, NULL);
+ switch (r) {
+ case USBFS_SPEED_UNKNOWN: return LIBUSB_SPEED_UNKNOWN;
+ case USBFS_SPEED_LOW: return LIBUSB_SPEED_LOW;
+ case USBFS_SPEED_FULL: return LIBUSB_SPEED_FULL;
+ case USBFS_SPEED_HIGH: return LIBUSB_SPEED_HIGH;
+ case USBFS_SPEED_WIRELESS: return LIBUSB_SPEED_HIGH;
+ case USBFS_SPEED_SUPER: return LIBUSB_SPEED_SUPER;
+ case USBFS_SPEED_SUPER_PLUS: return LIBUSB_SPEED_SUPER_PLUS;
+ default:
+ usbi_warn(ctx, "Error getting device speed: %d", r);
+ }
+
+ return LIBUSB_SPEED_UNKNOWN;
+}
+
static int initialize_device(struct libusb_device *dev, uint8_t busnum,
uint8_t devaddr, const char *sysfs_dir, int wrapped_fd)
{
usbi_warn(ctx, "unknown device speed: %d Mbps", speed);
}
}
+ } else if (wrapped_fd >= 0) {
+ dev->speed = usbfs_get_speed(ctx, wrapped_fd);
}
/* cache descriptors in memory */
alloc_len = 0;
do {
- alloc_len += 256;
+ const size_t desc_read_length = 256;
+ uint8_t *read_ptr;
+
+ alloc_len += desc_read_length;
priv->descriptors = usbi_reallocf(priv->descriptors, alloc_len);
if (!priv->descriptors) {
if (fd != wrapped_fd)
close(fd);
return LIBUSB_ERROR_NO_MEM;
}
+ read_ptr = (uint8_t *)priv->descriptors + priv->descriptors_len;
/* usbfs has holes in the file */
if (!sysfs_dir)
- memset(priv->descriptors + priv->descriptors_len,
- 0, alloc_len - priv->descriptors_len);
- nb = read(fd, priv->descriptors + priv->descriptors_len,
- alloc_len - priv->descriptors_len);
+ memset(read_ptr, 0, desc_read_length);
+ nb = read(fd, read_ptr, desc_read_length);
if (nb < 0) {
usbi_err(ctx, "read descriptor failed, errno=%d", errno);
if (fd != wrapped_fd)
usbi_warn(ctx, "Missing rw usbfs access; cannot determine "
"active configuration descriptor");
if (priv->config_descriptors)
- priv->active_config = priv->config_descriptors[0].desc->bConfigurationValue;
+ priv->active_config = (int)priv->config_descriptors[0].desc->bConfigurationValue;
else
- priv->active_config = 0; /* No config dt */
+ priv->active_config = -1; /* No config dt */
return LIBUSB_SUCCESS;
}
retry:
/* find the parent in the context */
usbi_mutex_lock(&ctx->usb_devs_lock);
- list_for_each_entry(it, &ctx->usb_devs, list, struct libusb_device) {
+ for_each_device(ctx, it) {
struct linux_device_priv *priv = usbi_get_device_priv(it);
if (priv->sysfs_dir) {
usbi_mutex_unlock(&ctx->usb_devs_lock);
if (!dev->parent_dev && add_parent) {
- usbi_dbg("parent_dev %s not enumerated yet, enumerating now",
+ usbi_dbg(ctx, "parent_dev %s not enumerated yet, enumerating now",
parent_sysfs_dir);
sysfs_scan_device(ctx, parent_sysfs_dir);
add_parent = 0;
goto retry;
}
- usbi_dbg("dev %p (%s) has parent %p (%s) port %u", dev, sysfs_dir,
+ usbi_dbg(ctx, "dev %p (%s) has parent %p (%s) port %u", dev, sysfs_dir,
dev->parent_dev, parent_sysfs_dir, dev->port_number);
free(parent_sysfs_dir);
* will be reused. instead we should add a simple sysfs attribute with
* a session ID. */
session_id = busnum << 8 | devaddr;
- usbi_dbg("busnum %u devaddr %u session_id %lu", busnum, devaddr, session_id);
+ usbi_dbg(ctx, "busnum %u devaddr %u session_id %lu", busnum, devaddr, session_id);
dev = usbi_get_device_by_session_id(ctx, session_id);
if (dev) {
/* device already exists in the context */
- usbi_dbg("session_id %lu already exists", session_id);
+ usbi_dbg(ctx, "session_id %lu already exists", session_id);
libusb_unref_device(dev);
return LIBUSB_SUCCESS;
}
- usbi_dbg("allocating new device for %u/%u (session %lu)",
+ usbi_dbg(ctx, "allocating new device for %u/%u (session %lu)",
busnum, devaddr, session_id);
dev = usbi_alloc_device(ctx, session_id);
if (!dev)
struct libusb_context *ctx;
usbi_mutex_static_lock(&active_contexts_lock);
- list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
+ for_each_context(ctx) {
linux_enumerate_device(ctx, busnum, devaddr, sys_name);
}
usbi_mutex_static_unlock(&active_contexts_lock);
unsigned long session_id = busnum << 8 | devaddr;
usbi_mutex_static_lock(&active_contexts_lock);
- list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
+ for_each_context(ctx) {
dev = usbi_get_device_by_session_id(ctx, session_id);
if (dev) {
usbi_disconnect_device(dev);
libusb_unref_device(dev);
} else {
- usbi_dbg("device not found for session %lx", session_id);
+ usbi_dbg(ctx, "device not found for session %lx", session_id);
}
}
usbi_mutex_static_unlock(&active_contexts_lock);
int r = LIBUSB_ERROR_IO;
sprintf(dirpath, USB_DEVTMPFS_PATH "/%03u", busnum);
- usbi_dbg("%s", dirpath);
+ usbi_dbg(ctx, "%s", dirpath);
dir = opendir(dirpath);
if (!dir) {
usbi_err(ctx, "opendir '%s' failed, errno=%d", dirpath, errno);
continue;
if (!parse_u8(entry->d_name, &devaddr)) {
- usbi_dbg("unknown dir entry %s", entry->d_name);
+ usbi_dbg(ctx, "unknown dir entry %s", entry->d_name);
continue;
}
if (linux_enumerate_device(ctx, busnum, devaddr, NULL)) {
- usbi_dbg("failed to enumerate dir entry %s", entry->d_name);
+ usbi_dbg(ctx, "failed to enumerate dir entry %s", entry->d_name);
continue;
}
r = linux_enumerate_device(ctx, busnum, devaddr, NULL);
if (r < 0) {
- usbi_dbg("failed to enumerate dir entry %s", entry->d_name);
+ usbi_dbg(ctx, "failed to enumerate dir entry %s", entry->d_name);
continue;
}
} else {
if (!parse_u8(entry->d_name, &busnum)) {
- usbi_dbg("unknown dir entry %s", entry->d_name);
+ usbi_dbg(ctx, "unknown dir entry %s", entry->d_name);
continue;
}
num_devices++;
if (sysfs_scan_device(ctx, entry->d_name)) {
- usbi_dbg("failed to enumerate dir entry %s", entry->d_name);
+ usbi_dbg(ctx, "failed to enumerate dir entry %s", entry->d_name);
continue;
}
r = ioctl(fd, IOCTL_USBFS_GET_CAPABILITIES, &hpriv->caps);
if (r < 0) {
if (errno == ENOTTY)
- usbi_dbg("getcap not available");
+ usbi_dbg(HANDLE_CTX(handle), "getcap not available");
else
usbi_err(HANDLE_CTX(handle), "getcap failed, errno=%d", errno);
hpriv->caps = USBFS_CAP_BULK_CONTINUATION;
}
- return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT);
+ return usbi_add_event_source(HANDLE_CTX(handle), hpriv->fd, POLLOUT);
}
static int op_wrap_sys_device(struct libusb_context *ctx,
/* Session id is unused as we do not add the device to the list of
* connected devices. */
- usbi_dbg("allocating new device for fd %d", fd);
+ usbi_dbg(ctx, "allocating new device for fd %d", fd);
dev = usbi_alloc_device(ctx, 0);
if (!dev)
return LIBUSB_ERROR_NO_MEM;
goto out;
/* Consider the device as connected, but do not add it to the managed
* device list. */
- dev->attached = 1;
+ usbi_atomic_store(&dev->attached, 1);
handle->dev = dev;
r = initialize_handle(handle, fd);
/* device will still be marked as attached if hotplug monitor thread
* hasn't processed remove event yet */
usbi_mutex_static_lock(&linux_hotplug_lock);
- if (handle->dev->attached) {
- usbi_dbg("open failed with no device, but device still attached");
+ if (usbi_atomic_load(&handle->dev->attached)) {
+ usbi_dbg(HANDLE_CTX(handle), "open failed with no device, but device still attached");
linux_device_disconnected(handle->dev->bus_number,
handle->dev->device_address);
}
/* fd may have already been removed by POLLERR condition in op_handle_events() */
if (!hpriv->fd_removed)
- usbi_remove_pollfd(HANDLE_CTX(dev_handle), hpriv->fd);
+ usbi_remove_event_source(HANDLE_CTX(dev_handle), hpriv->fd);
if (!hpriv->fd_keep)
close(hpriv->fd);
}
uint8_t *config)
{
struct linux_device_priv *priv = usbi_get_device_priv(handle->dev);
+ int active_config;
int r;
if (priv->sysfs_dir) {
- r = sysfs_get_active_config(handle->dev, config);
+ r = sysfs_get_active_config(handle->dev, &active_config);
} else {
struct linux_device_handle_priv *hpriv = usbi_get_device_handle_priv(handle);
r = usbfs_get_active_config(handle->dev, hpriv->fd);
if (r == LIBUSB_SUCCESS)
- *config = priv->active_config;
+ active_config = priv->active_config;
}
if (r < 0)
return r;
- if (*config == 0)
- usbi_err(HANDLE_CTX(handle), "device unconfigured");
+ if (active_config == -1) {
+ usbi_warn(HANDLE_CTX(handle), "device unconfigured");
+ active_config = 0;
+ }
+
+ *config = (uint8_t)active_config;
return 0;
}
return LIBUSB_ERROR_OTHER;
}
- if (config == -1)
- config = 0;
+ /* if necessary, update our cached active config descriptor */
+ if (!priv->sysfs_dir) {
+ if (config == 0 && !dev_has_config0(handle->dev))
+ config = -1;
- /* update our cached active config descriptor */
- priv->active_config = (uint8_t)config;
+ priv->active_config = config;
+ }
return LIBUSB_SUCCESS;
}
continue;
if (errno == EINVAL) {
- usbi_dbg("URB not found --> assuming ready to be reaped");
+ usbi_dbg(TRANSFER_CTX(transfer), "URB not found --> assuming ready to be reaped");
if (i == (last_plus_one - 1))
ret = LIBUSB_ERROR_NOT_FOUND;
} else if (errno == ENODEV) {
- usbi_dbg("Device not found for URB --> assuming ready to be reaped");
+ usbi_dbg(TRANSFER_CTX(transfer), "Device not found for URB --> assuming ready to be reaped");
ret = LIBUSB_ERROR_NO_DEVICE;
} else {
usbi_warn(TRANSFER_CTX(transfer), "unrecognised discard errno %d", errno);
* a time, but there is a big performance gain doing it this way.
*
* Newer versions lift the 16k limit (USBFS_CAP_NO_PACKET_SIZE_LIM),
- * using arbritary large transfers can still be a bad idea though, as
+ * using arbitrary large transfers can still be a bad idea though, as
* the kernel needs to allocate physical contiguous memory for this,
* which may fail for large buffers.
*
last_urb_partial = 1;
num_urbs++;
}
- usbi_dbg("need %d urbs for new transfer with length %d", num_urbs, transfer->length);
+ usbi_dbg(TRANSFER_CTX(transfer), "need %d urbs for new transfer with length %d", num_urbs, transfer->length);
urbs = calloc(num_urbs, sizeof(*urbs));
if (!urbs)
return LIBUSB_ERROR_NO_MEM;
/* if the first URB submission fails, we can simply free up and
* return failure immediately. */
if (i == 0) {
- usbi_dbg("first URB failed, easy peasy");
+ usbi_dbg(TRANSFER_CTX(transfer), "first URB failed, easy peasy");
free(urbs);
tpriv->urbs = NULL;
return r;
discard_urbs(itransfer, 0, i);
- usbi_dbg("reporting successful submission but waiting for %d "
+ usbi_dbg(TRANSFER_CTX(transfer), "reporting successful submission but waiting for %d "
"discards before reporting error", i);
return 0;
}
/* usbfs limits the number of iso packets per URB */
num_urbs = (num_packets + (MAX_ISO_PACKETS_PER_URB - 1)) / MAX_ISO_PACKETS_PER_URB;
- usbi_dbg("need %d urbs for new transfer with length %d", num_urbs, transfer->length);
+ usbi_dbg(TRANSFER_CTX(transfer), "need %d urbs for new transfer with length %d", num_urbs, transfer->length);
urbs = calloc(num_urbs, sizeof(*urbs));
if (!urbs)
/* if the first URB submission fails, we can simply free up and
* return failure immediately. */
if (i == 0) {
- usbi_dbg("first URB failed, easy peasy");
+ usbi_dbg(TRANSFER_CTX(transfer), "first URB failed, easy peasy");
free_iso_urbs(tpriv);
return r;
}
tpriv->num_retired = num_urbs - i;
discard_urbs(itransfer, 0, i);
- usbi_dbg("reporting successful submission but waiting for %d "
+ usbi_dbg(TRANSFER_CTX(transfer), "reporting successful submission but waiting for %d "
"discards before reporting error", i);
return 0;
}
int urb_idx = urb - tpriv->urbs;
usbi_mutex_lock(&itransfer->lock);
- usbi_dbg("handling completion status %d of bulk urb %d/%d", urb->status,
+ usbi_dbg(TRANSFER_CTX(transfer), "handling completion status %d of bulk urb %d/%d", urb->status,
urb_idx + 1, tpriv->num_urbs);
tpriv->num_retired++;
if (tpriv->reap_action != NORMAL) {
/* cancelled, submit_fail, or completed early */
- usbi_dbg("abnormal reap: urb status %d", urb->status);
+ usbi_dbg(TRANSFER_CTX(transfer), "abnormal reap: urb status %d", urb->status);
/* even though we're in the process of cancelling, it's possible that
* we may receive some data in these URBs that we don't want to lose.
if (urb->actual_length > 0) {
unsigned char *target = transfer->buffer + itransfer->transferred;
- usbi_dbg("received %d bytes of surplus data", urb->actual_length);
+ usbi_dbg(TRANSFER_CTX(transfer), "received %d bytes of surplus data", urb->actual_length);
if (urb->buffer != target) {
- usbi_dbg("moving surplus data from offset %zu to offset %zu",
+ usbi_dbg(TRANSFER_CTX(transfer), "moving surplus data from offset %zu to offset %zu",
(unsigned char *)urb->buffer - transfer->buffer,
target - transfer->buffer);
memmove(target, urb->buffer, urb->actual_length);
}
if (tpriv->num_retired == tpriv->num_urbs) {
- usbi_dbg("abnormal reap: last URB handled, reporting");
+ usbi_dbg(TRANSFER_CTX(transfer), "abnormal reap: last URB handled, reporting");
if (tpriv->reap_action != COMPLETED_EARLY &&
tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED)
tpriv->reap_status = LIBUSB_TRANSFER_ERROR;
break;
case -ENODEV:
case -ESHUTDOWN:
- usbi_dbg("device removed");
+ usbi_dbg(TRANSFER_CTX(transfer), "device removed");
tpriv->reap_status = LIBUSB_TRANSFER_NO_DEVICE;
goto cancel_remaining;
case -EPIPE:
- usbi_dbg("detected endpoint stall");
+ usbi_dbg(TRANSFER_CTX(transfer), "detected endpoint stall");
if (tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED)
tpriv->reap_status = LIBUSB_TRANSFER_STALL;
goto cancel_remaining;
case -EOVERFLOW:
/* overflow can only ever occur in the last urb */
- usbi_dbg("overflow, actual_length=%d", urb->actual_length);
+ usbi_dbg(TRANSFER_CTX(transfer), "overflow, actual_length=%d", urb->actual_length);
if (tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED)
tpriv->reap_status = LIBUSB_TRANSFER_OVERFLOW;
goto completed;
case -EILSEQ:
case -ECOMM:
case -ENOSR:
- usbi_dbg("low-level bus error %d", urb->status);
+ usbi_dbg(TRANSFER_CTX(transfer), "low-level bus error %d", urb->status);
tpriv->reap_action = ERROR;
goto cancel_remaining;
default:
/* if we've reaped all urbs or we got less data than requested then we're
* done */
if (tpriv->num_retired == tpriv->num_urbs) {
- usbi_dbg("all URBs in transfer reaped --> complete!");
+ usbi_dbg(TRANSFER_CTX(transfer), "all URBs in transfer reaped --> complete!");
goto completed;
} else if (urb->actual_length < urb->buffer_length) {
- usbi_dbg("short transfer %d/%d --> complete!",
+ usbi_dbg(TRANSFER_CTX(transfer), "short transfer %d/%d --> complete!",
urb->actual_length, urb->buffer_length);
if (tpriv->reap_action == NORMAL)
tpriv->reap_action = COMPLETED_EARLY;
return LIBUSB_ERROR_NOT_FOUND;
}
- usbi_dbg("handling completion status %d of iso urb %d/%d", urb->status,
+ usbi_dbg(TRANSFER_CTX(transfer), "handling completion status %d of iso urb %d/%d", urb->status,
urb_idx, num_urbs);
/* copy isochronous results back in */
break;
case -ENODEV:
case -ESHUTDOWN:
- usbi_dbg("packet %d - device removed", i);
+ usbi_dbg(TRANSFER_CTX(transfer), "packet %d - device removed", i);
lib_desc->status = LIBUSB_TRANSFER_NO_DEVICE;
break;
case -EPIPE:
- usbi_dbg("packet %d - detected endpoint stall", i);
+ usbi_dbg(TRANSFER_CTX(transfer), "packet %d - detected endpoint stall", i);
lib_desc->status = LIBUSB_TRANSFER_STALL;
break;
case -EOVERFLOW:
- usbi_dbg("packet %d - overflow error", i);
+ usbi_dbg(TRANSFER_CTX(transfer), "packet %d - overflow error", i);
lib_desc->status = LIBUSB_TRANSFER_OVERFLOW;
break;
case -ETIME:
case -ECOMM:
case -ENOSR:
case -EXDEV:
- usbi_dbg("packet %d - low-level USB error %d", i, urb_desc->status);
+ usbi_dbg(TRANSFER_CTX(transfer), "packet %d - low-level USB error %d", i, urb_desc->status);
lib_desc->status = LIBUSB_TRANSFER_ERROR;
break;
default:
tpriv->num_retired++;
if (tpriv->reap_action != NORMAL) { /* cancelled or submit_fail */
- usbi_dbg("CANCEL: urb status %d", urb->status);
+ usbi_dbg(TRANSFER_CTX(transfer), "CANCEL: urb status %d", urb->status);
if (tpriv->num_retired == num_urbs) {
- usbi_dbg("CANCEL: last URB handled, reporting");
+ usbi_dbg(TRANSFER_CTX(transfer), "CANCEL: last URB handled, reporting");
free_iso_urbs(tpriv);
if (tpriv->reap_action == CANCELLED) {
usbi_mutex_unlock(&itransfer->lock);
case -ECONNRESET:
break;
case -ESHUTDOWN:
- usbi_dbg("device removed");
+ usbi_dbg(TRANSFER_CTX(transfer), "device removed");
status = LIBUSB_TRANSFER_NO_DEVICE;
break;
default:
/* if we've reaped all urbs then we're done */
if (tpriv->num_retired == num_urbs) {
- usbi_dbg("all URBs in transfer reaped --> complete!");
+ usbi_dbg(TRANSFER_CTX(transfer), "all URBs in transfer reaped --> complete!");
free_iso_urbs(tpriv);
usbi_mutex_unlock(&itransfer->lock);
return usbi_handle_transfer_completion(itransfer, status);
int status;
usbi_mutex_lock(&itransfer->lock);
- usbi_dbg("handling completion status %d", urb->status);
+ usbi_dbg(ITRANSFER_CTX(itransfer), "handling completion status %d", urb->status);
itransfer->transferred += urb->actual_length;
break;
case -ENODEV:
case -ESHUTDOWN:
- usbi_dbg("device removed");
+ usbi_dbg(ITRANSFER_CTX(itransfer), "device removed");
status = LIBUSB_TRANSFER_NO_DEVICE;
break;
case -EPIPE:
- usbi_dbg("unsupported control request");
+ usbi_dbg(ITRANSFER_CTX(itransfer), "unsupported control request");
status = LIBUSB_TRANSFER_STALL;
break;
case -EOVERFLOW:
- usbi_dbg("overflow, actual_length=%d", urb->actual_length);
+ usbi_dbg(ITRANSFER_CTX(itransfer), "overflow, actual_length=%d", urb->actual_length);
status = LIBUSB_TRANSFER_OVERFLOW;
break;
case -ETIME:
case -EILSEQ:
case -ECOMM:
case -ENOSR:
- usbi_dbg("low-level bus error %d", urb->status);
+ usbi_dbg(ITRANSFER_CTX(itransfer), "low-level bus error %d", urb->status);
status = LIBUSB_TRANSFER_ERROR;
break;
default:
itransfer = urb->usercontext;
transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- usbi_dbg("urb type=%u status=%d transferred=%d", urb->type, urb->status, urb->actual_length);
+ usbi_dbg(HANDLE_CTX(handle), "urb type=%u status=%d transferred=%d", urb->type, urb->status, urb->actual_length);
switch (transfer->type) {
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
}
static int op_handle_events(struct libusb_context *ctx,
- struct pollfd *fds, usbi_nfds_t nfds, int num_ready)
+ void *event_data, unsigned int count, unsigned int num_ready)
{
- usbi_nfds_t n;
+ struct pollfd *fds = event_data;
+ unsigned int n;
int r;
usbi_mutex_lock(&ctx->open_devs_lock);
- for (n = 0; n < nfds && num_ready > 0; n++) {
+ for (n = 0; n < count && num_ready > 0; n++) {
struct pollfd *pollfd = &fds[n];
struct libusb_device_handle *handle;
struct linux_device_handle_priv *hpriv = NULL;
+ int reap_count;
if (!pollfd->revents)
continue;
num_ready--;
- list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) {
+ for_each_open_device(ctx, handle) {
hpriv = usbi_get_device_handle_priv(handle);
if (hpriv->fd == pollfd->fd)
break;
/* remove the fd from the pollfd set so that it doesn't continuously
* trigger an event, and flag that it has been removed so op_close()
* doesn't try to remove it a second time */
- usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fd);
+ usbi_remove_event_source(HANDLE_CTX(handle), hpriv->fd);
hpriv->fd_removed = 1;
/* device will still be marked as attached if hotplug monitor thread
* hasn't processed remove event yet */
usbi_mutex_static_lock(&linux_hotplug_lock);
- if (handle->dev->attached)
+ if (usbi_atomic_load(&handle->dev->attached))
linux_device_disconnected(handle->dev->bus_number,
handle->dev->device_address);
usbi_mutex_static_unlock(&linux_hotplug_lock);
continue;
}
+ reap_count = 0;
do {
r = reap_for_handle(handle);
- } while (r == 0);
+ } while (r == 0 && ++reap_count <= 25);
+
if (r == 1 || r == LIBUSB_ERROR_NO_DEVICE)
continue;
else if (r < 0)
.caps = USBI_CAP_HAS_HID_ACCESS|USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER,
.init = op_init,
.exit = op_exit,
+ .set_option = op_set_option,
.hotplug_poll = op_hotplug_poll,
.get_active_config_descriptor = op_get_active_config_descriptor,
.get_config_descriptor = op_get_config_descriptor,