summaryrefslogtreecommitdiff
path: root/libusb/os
diff options
context:
space:
mode:
authorChris Dickens <christopher.a.dickens@gmail.com>2013-06-27 09:14:15 -0700
committerHans de Goede <hdegoede@redhat.com>2013-08-21 15:58:00 +0200
commit6732582bb17662aa02a913008be899ef9ace5870 (patch)
tree6c9534fdff1757f5e94135c4f876b6ecf953904c /libusb/os
parenta06eafdc528d5f3ea21a26c34ceaa13e09dfd4f3 (diff)
downloadlibusb-6732582bb17662aa02a913008be899ef9ace5870.tar.gz
linux: Handle device disconnection early when possible
If a device is open, the device's fd will trigger a POLLERR condition once it is removed. Sometimes this can occur well before the udev monitor sends the remove event. This can also be caught early if the device is not currently open but an attempt to open it is made. In both situations, this can be caught early and processed so that the device does not continue to show up in the device list after it has been disconnected but before the udev monitor processes the event. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Diffstat (limited to 'libusb/os')
-rw-r--r--libusb/os/linux_netlink.c2
-rw-r--r--libusb/os/linux_udev.c2
-rw-r--r--libusb/os/linux_usbfs.c23
-rw-r--r--libusb/os/linux_usbfs.h2
4 files changed, 24 insertions, 5 deletions
diff --git a/libusb/os/linux_netlink.c b/libusb/os/linux_netlink.c
index 40f3fef..f1c1be1 100644
--- a/libusb/os/linux_netlink.c
+++ b/libusb/os/linux_netlink.c
@@ -293,7 +293,7 @@ static int linux_netlink_read_message(void)
/* signal device is available (or not) to all contexts */
if (detached)
- linux_hotplug_disconnected(busnum, devaddr, sys_name);
+ linux_device_disconnected(busnum, devaddr, sys_name);
else
linux_hotplug_enumerate(busnum, devaddr, sys_name);
diff --git a/libusb/os/linux_udev.c b/libusb/os/linux_udev.c
index 70f632d..99ac943 100644
--- a/libusb/os/linux_udev.c
+++ b/libusb/os/linux_udev.c
@@ -240,7 +240,7 @@ static void udev_hotplug_event(struct udev_device* udev_dev)
if (strncmp(udev_action, "add", 3) == 0) {
linux_hotplug_enumerate(busnum, devaddr, sys_name);
} else if (detached) {
- linux_hotplug_disconnected(busnum, devaddr, sys_name);
+ linux_device_disconnected(busnum, devaddr, sys_name);
} else {
usbi_err(NULL, "ignoring udev action %s", udev_action);
}
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index 8c0ef6f..142fa2b 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -1090,7 +1090,7 @@ void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_na
usbi_mutex_static_unlock(&active_contexts_lock);
}
-void linux_hotplug_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys_name)
+void linux_device_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys_name)
{
struct libusb_context *ctx;
struct libusb_device *dev;
@@ -1265,8 +1265,20 @@ static int op_open(struct libusb_device_handle *handle)
int r;
hpriv->fd = _get_usbfs_fd(handle->dev, O_RDWR, 0);
- if (hpriv->fd < 0)
+ if (hpriv->fd < 0) {
+ if (hpriv->fd == LIBUSB_ERROR_NO_DEVICE) {
+ /* 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");
+ linux_device_disconnected(handle->dev->bus_number,
+ handle->dev->device_address, NULL);
+ }
+ usbi_mutex_static_unlock(&linux_hotplug_lock);
+ }
return hpriv->fd;
+ }
r = ioctl(hpriv->fd, IOCTL_USBFS_GET_CAPABILITIES, &hpriv->caps);
if (r < 0) {
@@ -2500,6 +2512,13 @@ static int op_handle_events(struct libusb_context *ctx,
if (pollfd->revents & POLLERR) {
usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fd);
usbi_handle_disconnect(handle);
+ /* 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)
+ linux_device_disconnected(handle->dev->bus_number,
+ handle->dev->device_address, NULL);
+ usbi_mutex_static_unlock(&linux_hotplug_lock);
continue;
}
diff --git a/libusb/os/linux_usbfs.h b/libusb/os/linux_usbfs.h
index 499bab7..1f5b191 100644
--- a/libusb/os/linux_usbfs.h
+++ b/libusb/os/linux_usbfs.h
@@ -170,7 +170,7 @@ void linux_netlink_hotplug_poll(void);
#endif
void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_name);
-void linux_hotplug_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys_name);
+void linux_device_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys_name);
int linux_get_device_address (struct libusb_context *ctx, int detached,
uint8_t *busnum, uint8_t *devaddr, const char *dev_node,