summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2013-05-24 16:15:51 +0200
committerHans de Goede <hdegoede@redhat.com>2013-05-30 14:20:36 +0200
commitcedc7f6e289c427c84a9175045b06614be56ec5a (patch)
tree50837d92d28e3aac578ba4c20a531c4fc1245b3f
parent7ced70e14968bd6869a561d2cf8e7ac5a1df8938 (diff)
downloadlibusb-cedc7f6e289c427c84a9175045b06614be56ec5a.tar.gz
hotplug: Add a hotplug_poll backend function
Apps which were written before hotplug support, may listen for hotplug events on their own and call libusb_get_device_list on device addition. In this case libusb_get_device_list will likely return a list without the new device in there, as the hotplug event thread will still be busy enumerating the device, which may take a while, or may not even have seen the event yet. To avoid this add a new hotplug_poll backend function and make libusb_get_device_list call a this before copying ctx->usb_devs to the user. In this function the backend should ensure any pending hotplug events are fully processed before returning. This patch implements hotplug_poll for linux, it should probably be also implemented for darwin. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r--libusb/core.c3
-rw-r--r--libusb/libusbi.h19
-rw-r--r--libusb/os/linux_netlink.c11
-rw-r--r--libusb/os/linux_udev.c35
-rw-r--r--libusb/os/linux_usbfs.c10
-rw-r--r--libusb/os/linux_usbfs.h2
-rw-r--r--libusb/os/openbsd_usb.c1
-rw-r--r--libusb/os/wince_usb.c1
-rw-r--r--libusb/os/windows_usb.c1
-rw-r--r--libusb/version_nano.h2
10 files changed, 70 insertions, 15 deletions
diff --git a/libusb/core.c b/libusb/core.c
index 88757f8..1c3748d 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -654,6 +654,9 @@ ssize_t API_EXPORTED libusb_get_device_list(libusb_context *ctx,
/* backend provides hotplug support */
struct libusb_device *dev;
+ if (usbi_backend->hotplug_poll)
+ usbi_backend->hotplug_poll();
+
usbi_mutex_lock(&ctx->usb_devs_lock);
list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) {
discdevs = discovered_devs_append(discdevs, dev);
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
index 090ac5b..4dda97e 100644
--- a/libusb/libusbi.h
+++ b/libusb/libusbi.h
@@ -551,11 +551,30 @@ struct usbi_os_backend {
* This function is executed when the user wishes to retrieve a list
* of USB devices connected to the system.
*
+ * If the backend has hotplug support, this function is not used!
+ *
* Return 0 on success, or a LIBUSB_ERROR code on failure.
*/
int (*get_device_list)(struct libusb_context *ctx,
struct discovered_devs **discdevs);
+ /* Apps which were written before hotplug support, may listen for
+ * hotplug events on their own and call libusb_get_device_list on
+ * device addition. In this case libusb_get_device_list will likely
+ * return a list without the new device in there, as the hotplug
+ * event thread will still be busy enumerating the device, which may
+ * take a while, or may not even have seen the event yet.
+ *
+ * To avoid this libusb_get_device_list will call this optional
+ * function for backends with hotplug support before copying
+ * ctx->usb_devs to the user. In this function the backend should
+ * ensure any pending hotplug events are fully processed before
+ * returning.
+ *
+ * Optional, should be implemented by backends with hotplug support.
+ */
+ void (*hotplug_poll)(void);
+
/* Open a device for I/O and other USB operations. The device handle
* is preallocated for you, you can retrieve the device in question
* through handle->dev.
diff --git a/libusb/os/linux_netlink.c b/libusb/os/linux_netlink.c
index 7b1fdcd..3a68f69 100644
--- a/libusb/os/linux_netlink.c
+++ b/libusb/os/linux_netlink.c
@@ -241,3 +241,14 @@ static void *linux_netlink_event_thread_main(void *arg)
return NULL;
}
+
+void linux_netlink_hotplug_poll(void)
+{
+ int r;
+
+ usbi_mutex_static_lock(&linux_hotplug_lock);
+ do {
+ r = linux_netlink_read_message();
+ } while (r == 0);
+ usbi_mutex_static_unlock(&linux_hotplug_lock);
+}
diff --git a/libusb/os/linux_udev.c b/libusb/os/linux_udev.c
index cf5f08c..4a45c4b 100644
--- a/libusb/os/linux_udev.c
+++ b/libusb/os/linux_udev.c
@@ -49,7 +49,7 @@ static int udev_monitor_fd = -1;
static struct udev_monitor *udev_monitor = NULL;
static pthread_t linux_event_thread;
-static void udev_hotplug_event(void);
+static void udev_hotplug_event(struct udev_device* udev_dev);
static void *linux_udev_event_thread_main(void *arg);
int linux_udev_start_event_monitor(void)
@@ -125,6 +125,7 @@ int linux_udev_stop_event_monitor(void)
static void *linux_udev_event_thread_main(void *arg)
{
+ struct udev_device* udev_dev;
struct pollfd fds = {.fd = udev_monitor_fd,
.events = POLLIN};
@@ -136,7 +137,9 @@ static void *linux_udev_event_thread_main(void *arg)
}
usbi_mutex_static_lock(&linux_hotplug_lock);
- udev_hotplug_event();
+ udev_dev = udev_monitor_receive_device(udev_monitor);
+ if (udev_dev)
+ udev_hotplug_event(udev_dev);
usbi_mutex_static_unlock(&linux_hotplug_lock);
}
@@ -164,26 +167,15 @@ static int udev_device_info(struct libusb_context *ctx, int detached,
dev_node, *sys_name);
}
-static void udev_hotplug_event(void)
+static void udev_hotplug_event(struct udev_device* udev_dev)
{
- struct udev_device* udev_dev;
const char* udev_action;
const char* sys_name = NULL;
uint8_t busnum = 0, devaddr = 0;
int detached;
int r;
- if (NULL == udev_monitor) {
- return;
- }
-
do {
- udev_dev = udev_monitor_receive_device(udev_monitor);
- if (!udev_dev) {
- usbi_err(NULL, "failed to read data from udev monitor socket.");
- return;
- }
-
udev_action = udev_device_get_action(udev_dev);
if (!udev_action) {
break;
@@ -250,3 +242,18 @@ int linux_udev_scan_devices(struct libusb_context *ctx)
return LIBUSB_SUCCESS;
}
+
+void linux_udev_hotplug_poll(void)
+{
+ struct udev_device* udev_dev;
+
+ usbi_mutex_static_lock(&linux_hotplug_lock);
+ do {
+ udev_dev = udev_monitor_receive_device(udev_monitor);
+ if (udev_dev) {
+ usbi_dbg("Handling hotplug event from hotplug_poll");
+ udev_hotplug_event(udev_dev);
+ }
+ } while (udev_dev);
+ usbi_mutex_static_unlock(&linux_hotplug_lock);
+}
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index f86d37a..a27ed44 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -475,6 +475,15 @@ static int linux_scan_devices(struct libusb_context *ctx)
#endif
}
+static void op_hotplug_poll(void)
+{
+#if defined(USE_UDEV)
+ linux_udev_hotplug_poll();
+#else
+ linux_netlink_hotplug_poll();
+#endif
+}
+
static int _open_sysfs_attr(struct libusb_device *dev, const char *attr)
{
struct linux_device_priv *priv = _device_priv(dev);
@@ -2451,6 +2460,7 @@ const struct usbi_os_backend linux_usbfs_backend = {
.init = op_init,
.exit = op_exit,
.get_device_list = NULL,
+ .hotplug_poll = op_hotplug_poll,
.get_device_descriptor = op_get_device_descriptor,
.get_active_config_descriptor = op_get_active_config_descriptor,
.get_config_descriptor = op_get_config_descriptor,
diff --git a/libusb/os/linux_usbfs.h b/libusb/os/linux_usbfs.h
index 8525418..26f052d 100644
--- a/libusb/os/linux_usbfs.h
+++ b/libusb/os/linux_usbfs.h
@@ -152,9 +152,11 @@ extern usbi_mutex_static_t linux_hotplug_lock;
int linux_udev_start_event_monitor(void);
int linux_udev_stop_event_monitor(void);
int linux_udev_scan_devices(struct libusb_context *ctx);
+void linux_udev_hotplug_poll(void);
#else
int linux_netlink_start_event_monitor(void);
int linux_netlink_stop_event_monitor(void);
+void linux_netlink_hotplug_poll(void);
#endif
void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_name);
diff --git a/libusb/os/openbsd_usb.c b/libusb/os/openbsd_usb.c
index e1c91f4..ccad768 100644
--- a/libusb/os/openbsd_usb.c
+++ b/libusb/os/openbsd_usb.c
@@ -93,6 +93,7 @@ const struct usbi_os_backend openbsd_backend = {
NULL, /* init() */
NULL, /* exit() */
obsd_get_device_list,
+ NULL, /* hotplug_poll */
obsd_open,
obsd_close,
diff --git a/libusb/os/wince_usb.c b/libusb/os/wince_usb.c
index a9c0ef8..d8e8f55 100644
--- a/libusb/os/wince_usb.c
+++ b/libusb/os/wince_usb.c
@@ -978,6 +978,7 @@ const struct usbi_os_backend wince_backend = {
wince_exit,
wince_get_device_list,
+ NULL, /* hotplug_poll */
wince_open,
wince_close,
diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c
index 6d06128..63357b1 100644
--- a/libusb/os/windows_usb.c
+++ b/libusb/os/windows_usb.c
@@ -2270,6 +2270,7 @@ const struct usbi_os_backend windows_backend = {
windows_exit,
windows_get_device_list,
+ NULL, /* hotplug_poll */
windows_open,
windows_close,
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index 8064f14..a4f4d24 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 10723
+#define LIBUSB_NANO 10724