linux: Handle device disconnection early when possible
authorChris Dickens <christopher.a.dickens@gmail.com>
Thu, 27 Jun 2013 16:14:15 +0000 (09:14 -0700)
committerHans de Goede <hdegoede@redhat.com>
Wed, 21 Aug 2013 13:58:00 +0000 (15:58 +0200)
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>
libusb/os/linux_netlink.c
libusb/os/linux_udev.c
libusb/os/linux_usbfs.c
libusb/os/linux_usbfs.h
libusb/version_nano.h

index 40f3fef..f1c1be1 100644 (file)
@@ -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);
 
index 70f632d..99ac943 100644 (file)
@@ -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);
                }
index 8c0ef6f..142fa2b 100644 (file)
@@ -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;
                }
 
index 499bab7..1f5b191 100644 (file)
@@ -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,
index 4c3e712..b5a3ca9 100644 (file)
@@ -1 +1 @@
-#define LIBUSB_NANO 10816
+#define LIBUSB_NANO 10817