diff options
author | Richard Hughes <richard@hughsie.com> | 2014-11-20 09:18:55 +0000 |
---|---|---|
committer | Richard Hughes <richard@hughsie.com> | 2014-11-20 09:41:35 +0000 |
commit | 7df975327f9bb079c77c33ba3ea01a08fcbf7041 (patch) | |
tree | c05554ecea8293eafdc1a4f64d4c3466ace35613 /gusb/gusb-device-list.c | |
parent | c6d9602518e5c09948f5a8eca4bf3ef839bcd7b8 (diff) | |
download | gusb-7df975327f9bb079c77c33ba3ea01a08fcbf7041.tar.gz |
Manually coldplug devices and poll if hotplugging is not available
Diffstat (limited to 'gusb/gusb-device-list.c')
-rw-r--r-- | gusb/gusb-device-list.c | 152 |
1 files changed, 123 insertions, 29 deletions
diff --git a/gusb/gusb-device-list.c b/gusb/gusb-device-list.c index f7a5e78..544d92d 100644 --- a/gusb/gusb-device-list.c +++ b/gusb/gusb-device-list.c @@ -56,6 +56,7 @@ struct _GUsbDeviceListPrivate { GUsbContext *context; GPtrArray *devices; libusb_hotplug_callback_handle hotplug_id; + guint hotplug_poll_id; gboolean done_coldplug; }; @@ -72,6 +73,8 @@ g_usb_device_list_finalize (GObject *object) if (priv->hotplug_id > 0) libusb_hotplug_deregister_callback (ctx, priv->hotplug_id); + if (priv->hotplug_poll_id > 0) + g_source_remove (priv->hotplug_poll_id); g_ptr_array_unref (priv->devices); G_OBJECT_CLASS (g_usb_device_list_parent_class)->finalize (object); @@ -213,16 +216,12 @@ g_usb_device_list_class_init (GUsbDeviceListClass *klass) } /** - * g_usb_device_list_hotplug_cb: + * g_usb_device_list_add_device: **/ -static int -g_usb_device_list_hotplug_cb (struct libusb_context *ctx, - struct libusb_device *dev, - libusb_hotplug_event event, - void *user_data) +static void +g_usb_device_list_add_device (GUsbDeviceList *list, struct libusb_device *dev) { GUsbDevice *device = NULL; - GUsbDeviceList *list = G_USB_DEVICE_LIST (user_data); GUsbDeviceListPrivate *priv = list->priv; guint8 bus; guint8 address; @@ -232,34 +231,67 @@ g_usb_device_list_hotplug_cb (struct libusb_context *ctx, address = libusb_get_device_address (dev); if (priv->done_coldplug) device = g_usb_device_list_find_by_bus_address (list, bus, address, NULL); + if (device != NULL) { + g_debug ("%i:%i already exists", bus, address); + goto out; + } + device = _g_usb_device_new (priv->context, dev, NULL); + if (g_usb_device_get_device_class (device) == 0x09) { + g_debug ("%i:%i is a hub, ignoring", bus, address); + goto out; + } + g_ptr_array_add (priv->devices, g_object_ref (device)); + g_signal_emit (list, signals[DEVICE_ADDED_SIGNAL], 0, device); +out: + if (device != NULL) + g_object_unref (device); +} + +/** + * g_usb_device_list_remove_device: + **/ +static void +g_usb_device_list_remove_device (GUsbDeviceList *list, struct libusb_device *dev) +{ + GUsbDevice *device = NULL; + GUsbDeviceListPrivate *priv = list->priv; + guint8 bus; + guint8 address; + + /* does any existing device exist */ + bus = libusb_get_bus_number (dev); + address = libusb_get_device_address (dev); + device = g_usb_device_list_find_by_bus_address (list, bus, address, NULL); + if (device == NULL) { + g_debug ("%i:%i does not exist", bus, address); + return; + } + g_signal_emit (list, signals[DEVICE_REMOVED_SIGNAL], 0, device); + g_ptr_array_remove (priv->devices, device); + g_object_unref (device); +} + +/** + * g_usb_device_list_hotplug_cb: + **/ +static int +g_usb_device_list_hotplug_cb (struct libusb_context *ctx, + struct libusb_device *dev, + libusb_hotplug_event event, + void *user_data) +{ + GUsbDeviceList *list = G_USB_DEVICE_LIST (user_data); + switch (event) { case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: - if (device != NULL) { - g_debug ("%i:%i already exists", bus, address); - goto out; - } - device = _g_usb_device_new (priv->context, dev, NULL); - if (g_usb_device_get_device_class (device) == 0x09) { - g_debug ("%i:%i is a hub, ignoring", bus, address); - goto out; - } - g_ptr_array_add (priv->devices, g_object_ref (device)); - g_signal_emit (list, signals[DEVICE_ADDED_SIGNAL], 0, device); + g_usb_device_list_add_device (list, dev); break; case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: - if (device == NULL) { - g_debug ("%i:%i does not exist", bus, address); - goto out; - } - g_signal_emit (list, signals[DEVICE_REMOVED_SIGNAL], 0, device); - g_ptr_array_remove (priv->devices, device); + g_usb_device_list_remove_device (list, dev); break; default: break; } -out: - if (device != NULL) - g_object_unref (device); return 0; } @@ -288,6 +320,64 @@ g_usb_device_list_get_devices (GUsbDeviceList *list) } /** + * g_usb_device_list_rescan: + **/ +static void +g_usb_device_list_rescan (GUsbDeviceList *list) +{ + GList *existing_devices = NULL; + GList *l; + GUsbDevice *device; + GUsbDeviceListPrivate *priv = list->priv; + gboolean found; + guint i; + libusb_context *ctx = _g_usb_context_get_context (priv->context); + libusb_device **dev_list = NULL; + + /* add any devices not yet added (duplicates will be filtered */ + libusb_get_device_list (ctx, &dev_list); + for (i = 0; dev_list && dev_list[i]; i++) + g_usb_device_list_add_device (list, dev_list[i]); + + /* copy to a list so we can remove from the array */ + for (i = 0; i < priv->devices->len; i++) { + device = g_ptr_array_index (priv->devices, i); + existing_devices = g_list_prepend (existing_devices, device); + } + + /* look for any removed devices */ + for (l = existing_devices; l != NULL; l = l->next) { + device = G_USB_DEVICE (l->data); + found = FALSE; + for (i = 0; dev_list && dev_list[i]; i++) { + if (libusb_get_bus_number (dev_list[i]) == g_usb_device_get_bus (device) && + libusb_get_device_address (dev_list[i]) == g_usb_device_get_address (device)) { + found = TRUE; + break; + } + } + if (!found) { + g_signal_emit (list, signals[DEVICE_REMOVED_SIGNAL], 0, device); + g_ptr_array_remove (priv->devices, device); + } + } + + g_list_free (existing_devices); + libusb_free_device_list (dev_list, 1); +} + +/** + * g_usb_device_list_rescan_cb: + **/ +static gboolean +g_usb_device_list_rescan_cb (gpointer user_data) +{ + GUsbDeviceList *list = G_USB_DEVICE_LIST (user_data); + g_usb_device_list_rescan (list); + return TRUE; +} + +/** * g_usb_device_list_coldplug: * @list: a #GUsbDeviceList * @@ -308,9 +398,13 @@ g_usb_device_list_coldplug (GUsbDeviceList *list) if (priv->done_coldplug) return; - /* only Linux has hotplug capability */ + /* fall back to polling for platforms without hotplug capability */ if (!libusb_has_capability (LIBUSB_CAP_HAS_HOTPLUG)) { - g_warning ("Platform does not have hotplug capability"); + g_usb_device_list_rescan (list); + priv->hotplug_poll_id = g_timeout_add (500, + g_usb_device_list_rescan_cb, + list); + g_warning ("Platform does not have hotplug cap, using polling"); priv->done_coldplug = TRUE; return; } |