diff options
author | Chris Dickens <christopher.a.dickens@gmail.com> | 2013-06-27 09:14:15 -0700 |
---|---|---|
committer | Hans de Goede <hdegoede@redhat.com> | 2013-08-21 15:58:00 +0200 |
commit | 6732582bb17662aa02a913008be899ef9ace5870 (patch) | |
tree | 6c9534fdff1757f5e94135c4f876b6ecf953904c /libusb/os | |
parent | a06eafdc528d5f3ea21a26c34ceaa13e09dfd4f3 (diff) | |
download | libusb-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.c | 2 | ||||
-rw-r--r-- | libusb/os/linux_udev.c | 2 | ||||
-rw-r--r-- | libusb/os/linux_usbfs.c | 23 | ||||
-rw-r--r-- | libusb/os/linux_usbfs.h | 2 |
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, |