[Spice-devel] [PATCH spice-gtk] usb-device-manager: Add support for libusb hotplug API

Marc-André Lureau mlureau at redhat.com
Fri Jul 5 04:02:20 PDT 2013


ack

----- Mensaje original -----
> For now this makes the usb-code even more of a #ifdef party (albeit only
> slightly so). But it does give us (theoretical, untested) usb support on
> Mac OS X, and once the libusb Windows backend also gets hotplug support, we
> can bump the required libusb version to a new enough one, and drop both the
> windows gudev emulation as well as the gudev code-paths.
> 
> Signed-off-by: Hans de Goede <hdegoede at redhat.com>
> ---
>  configure.ac             |  41 ++++++++++------
>  gtk/usb-device-manager.c | 119
>  ++++++++++++++++++++++++++++++++++++++++++++---
>  2 files changed, 139 insertions(+), 21 deletions(-)
> 
> diff --git a/configure.ac b/configure.ac
> index bd59ccf..11f11fc 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -367,21 +367,34 @@ else
>    if test "x$have_usbredir" = "xno" && test "x$enable_usbredir" = "xyes";
>    then
>      AC_MSG_ERROR([usbredir support explicitly requested, but some required
>      packages are not available])
>    fi
> -  if test "x$have_usbredir" = "xyes"; then
> -    AC_DEFINE(USE_USBREDIR, [1], [Define if supporting usbredir proxying])
> -  fi
>  
> -  # Require gudev for non-windows
> -  if test "x$os_win32" = "xno"; then
> -    PKG_CHECK_MODULES([GUDEV],
> -                      [gudev-1.0],
> -                      [have_gudev=yes],
> -                      [have_gudev=no])
> -
> -    if test "x$have_usbredir" = "xyes" && test "x$have_gudev" = "xno"; then
> -      AC_MSG_ERROR([usbredir requested but required gudev is not available])
> +  # On non windows we need either libusb hotplug support or gudev
> +  if test "x$have_usbredir" = "xyes" && test "x$os_win32" = "xno"; then
> +    PKG_CHECK_MODULES([LIBUSB_HOTPLUG], [libusb-1.0 >= 1.0.16],
> +                      [have_libusb_hotplug=yes], [have_libusb_hotplug=no])
> +    if test "x$have_libusb_hotplug" = "xyes"; then
> +      AC_DEFINE(USE_LIBUSB_HOTPLUG, [1], [Define if libusb has hotplug
> support])
> +      with_usbredir_hotplug="with libusb hotplug"
> +    else
> +      PKG_CHECK_MODULES([GUDEV],
> +                        [gudev-1.0],
> +                        [have_gudev=yes],
> +                        [have_gudev=no])
> +
> +      if test "x$have_gudev" = "xno" && test "x$enable_usbredir" = "xyes";
> then
> +        AC_MSG_ERROR([usbredir requested but required gudev is not
> available])
> +      fi
> +      if test "x$have_gudev" = "xyes"; then
> +        AC_DEFINE(USE_GUDEV, [1], [Define if supporting gudev])
> +        with_usbredir_hotplug="with gudev hotplug"
> +      else
> +        have_usbredir=no
> +      fi
>      fi
> -    AC_DEFINE(USE_GUDEV, [1], [Define if supporting gudev])
> +  fi
> +
> +  if test "x$have_usbredir" = "xyes"; then
> +    AC_DEFINE(USE_USBREDIR, [1], [Define if supporting usbredir proxying])
>    fi
>  fi
>  AM_CONDITIONAL([WITH_USBREDIR], [test "x$have_usbredir" = "xyes"])
> @@ -686,7 +699,7 @@ AC_MSG_NOTICE([
>          Target:                   ${red_target}
>          SASL support:             ${enable_sasl}
>          Smartcard support:        ${have_smartcard}
> -        USB redirection support:  ${have_usbredir}
> +        USB redirection support:  ${have_usbredir} ${with_usbredir_hotplug}
>          Gtk:                      $GTK_API_VERSION
>  
>          Now type 'make' to build $PACKAGE
> diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
> index 8b8bb8b..bdcfd13 100644
> --- a/gtk/usb-device-manager.c
> +++ b/gtk/usb-device-manager.c
> @@ -34,8 +34,9 @@
>  #elif defined(G_OS_WIN32)
>  #include "win-usb-dev.h"
>  #include "win-usb-driver-install.h"
> -#else
> -#warning "Expecting one of G_OS_WIN32 and USE_GUDEV to be defined"
> +#define USE_GUDEV /* win-usb-dev.h provides a fake gudev interface */
> +#elif !defined USE_LIBUSB_HOTPLUG
> +#error "Expecting one of USE_GUDEV or USE_LIBUSB_HOTPLUG to be defined"
>  #endif
>  
>  #include "channel-usbredir-priv.h"
> @@ -106,15 +107,19 @@ struct _SpiceUsbDeviceManagerPrivate {
>      gchar *redirect_on_connect;
>  #ifdef USE_USBREDIR
>      libusb_context *context;
> -    GUdevClient *udev;
>      int event_listeners;
>      GThread *event_thread;
>      gboolean event_thread_run;
> -    libusb_device **coldplug_list; /* Avoid needless reprobing during init
> */
>      struct usbredirfilter_rule *auto_conn_filter_rules;
>      struct usbredirfilter_rule *redirect_on_connect_rules;
>      int auto_conn_filter_rules_count;
>      int redirect_on_connect_rules_count;
> +#ifdef USE_GUDEV
> +    GUdevClient *udev;
> +    libusb_device **coldplug_list; /* Avoid needless reprobing during init
> */
> +#else
> +    libusb_hotplug_callback_handle hp_handle;
> +#endif
>  #ifdef G_OS_WIN32
>      SpiceWinUsbDriver     *installer;
>  #endif
> @@ -153,12 +158,19 @@ static void channel_new(SpiceSession *session,
> SpiceChannel *channel,
>                          gpointer user_data);
>  static void channel_destroy(SpiceSession *session, SpiceChannel *channel,
>                              gpointer user_data);
> +#ifdef USE_GUDEV
>  static void spice_usb_device_manager_uevent_cb(GUdevClient     *client,
>                                                 const gchar     *action,
>                                                 GUdevDevice     *udevice,
>                                                 gpointer         user_data);
>  static void spice_usb_device_manager_add_udev(SpiceUsbDeviceManager  *self,
>                                                GUdevDevice            *udev);
> +#else
> +static int spice_usb_device_manager_hotplug_cb(libusb_context       *ctx,
> +                                               libusb_device        *device,
> +                                               libusb_hotplug_event  event,
> +                                               void                 *data);
> +#endif
>  static void spice_usb_device_manager_check_redir_on_connect(
>      SpiceUsbDeviceManager *self, SpiceChannel *channel);
>  
> @@ -231,8 +243,10 @@ static gboolean
> spice_usb_device_manager_initable_init(GInitable  *initable,
>      GList *list;
>      GList *it;
>      int rc;
> +#ifdef USE_GUDEV
>      const gchar *const subsystems[] = {"usb", NULL};
>  #endif
> +#endif
>  
>      g_return_val_if_fail(SPICE_IS_USB_DEVICE_MANAGER(initable), FALSE);
>      g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
> @@ -264,10 +278,10 @@ static gboolean
> spice_usb_device_manager_initable_init(GInitable  *initable,
>      }
>  
>      /* Start listening for usb devices plug / unplug */
> +#ifdef USE_GUDEV
>      priv->udev = g_udev_client_new(subsystems);
>      g_signal_connect(G_OBJECT(priv->udev), "uevent",
>                       G_CALLBACK(spice_usb_device_manager_uevent_cb), self);
> -
>      /* Do coldplug (detection of already connected devices) */
>      libusb_get_device_list(priv->context, &priv->coldplug_list);
>      list = g_udev_client_query_by_subsystem(priv->udev, "usb");
> @@ -278,6 +292,21 @@ static gboolean
> spice_usb_device_manager_initable_init(GInitable  *initable,
>      g_list_free(list);
>      libusb_free_device_list(priv->coldplug_list, 1);
>      priv->coldplug_list = NULL;
> +#else
> +    rc = libusb_hotplug_register_callback(priv->context,
> +        LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED |
> LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
> +        LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY,
> +        LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
> +        spice_usb_device_manager_hotplug_cb, self, &priv->hp_handle);
> +    if (rc < 0) {
> +        const char *desc = spice_usbutil_libusb_strerror(rc);
> +        g_warning("Error initializing USB hotplug support: %s [%i]", desc,
> rc);
> +        g_set_error(err, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
> +                  "Error initializing USB hotplug support: %s [%i]", desc,
> rc);
> +        return FALSE;
> +    }
> +    spice_usb_device_manager_start_event_listening(self, NULL);
> +#endif
>  
>      /* Start listening for usb channels connect/disconnect */
>      g_signal_connect(priv->session, "channel-new",
> @@ -298,6 +327,31 @@ static gboolean
> spice_usb_device_manager_initable_init(GInitable  *initable,
>  #endif
>  }
>  
> +static void spice_usb_device_manager_dispose(GObject *gobject)
> +{
> +    SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(gobject);
> +    SpiceUsbDeviceManagerPrivate *priv = self->priv;
> +
> +#ifdef USE_USBREDIR
> +#ifdef USE_LIBUSB_HOTPLUG
> +    if (priv->hp_handle) {
> +        spice_usb_device_manager_stop_event_listening(self);
> +        /* This also wakes up the libusb_handle_events() in the event_thread
> */
> +        libusb_hotplug_deregister_callback(priv->context, priv->hp_handle);
> +        priv->hp_handle = 0;
> +    }
> +#endif
> +    if (priv->event_thread && !priv->event_thread_run) {
> +        g_thread_join(priv->event_thread);
> +        priv->event_thread = NULL;
> +    }
> +#endif
> +
> +    /* Chain up to the parent class */
> +    if (G_OBJECT_CLASS(spice_usb_device_manager_parent_class)->dispose)
> +
> G_OBJECT_CLASS(spice_usb_device_manager_parent_class)->dispose(gobject);
> +}
> +
>  static void spice_usb_device_manager_finalize(GObject *gobject)
>  {
>      SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(gobject);
> @@ -308,11 +362,12 @@ static void spice_usb_device_manager_finalize(GObject
> *gobject)
>          g_ptr_array_unref(priv->devices);
>  
>  #ifdef USE_USBREDIR
> +#ifdef USE_GUDEV
>      g_clear_object(&priv->udev);
> +#endif
> +    g_return_if_fail(priv->event_thread == NULL);
>      if (priv->context)
>          libusb_exit(priv->context);
> -    if (priv->event_thread)
> -        g_thread_join(priv->event_thread);
>      free(priv->auto_conn_filter_rules);
>      free(priv->redirect_on_connect_rules);
>  #ifdef G_OS_WIN32
> @@ -433,6 +488,7 @@ static void
> spice_usb_device_manager_class_init(SpiceUsbDeviceManagerClass *klas
>      GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
>      GParamSpec *pspec;
>  
> +    gobject_class->dispose      = spice_usb_device_manager_dispose;
>      gobject_class->finalize     = spice_usb_device_manager_finalize;
>      gobject_class->get_property = spice_usb_device_manager_get_property;
>      gobject_class->set_property = spice_usb_device_manager_set_property;
> @@ -601,6 +657,7 @@ static void
> spice_usb_device_manager_class_init(SpiceUsbDeviceManagerClass *klas
>  /* ------------------------------------------------------------------ */
>  /* gudev / libusb Helper functions                                    */
>  
> +#ifdef USE_GUDEV
>  static gboolean spice_usb_device_manager_get_udev_bus_n_address(
>      GUdevDevice *udev, int *bus, int *address)
>  {
> @@ -622,6 +679,7 @@ static gboolean
> spice_usb_device_manager_get_udev_bus_n_address(
>  
>      return *bus && *address;
>  }
> +#endif
>  
>  static gboolean spice_usb_device_manager_get_device_descriptor(
>      libusb_device *libdev,
> @@ -724,6 +782,7 @@ spice_usb_device_manager_device_match(SpiceUsbDevice
> *device,
>              spice_usb_device_get_devaddr(device) == address);
>  }
>  
> +#ifdef USE_GUDEV
>  static gboolean
>  spice_usb_device_manager_libdev_match(libusb_device *libdev,
>                                        const int bus, const int address)
> @@ -731,6 +790,7 @@ spice_usb_device_manager_libdev_match(libusb_device
> *libdev,
>      return (libusb_get_bus_number(libdev) == bus &&
>              libusb_get_device_address(libdev) == address);
>  }
> +#endif
>  
>  #else /* Win32 -- match functions for Windows -- match by vid:pid */
>  static gboolean
> @@ -846,6 +906,7 @@ static void
> spice_usb_device_manager_remove_dev(SpiceUsbDeviceManager *self,
>      spice_usb_device_unref(device);
>  }
>  
> +#ifdef USE_GUDEV
>  static void spice_usb_device_manager_add_udev(SpiceUsbDeviceManager  *self,
>                                                GUdevDevice            *udev)
>  {
> @@ -920,6 +981,50 @@ static void
> spice_usb_device_manager_uevent_cb(GUdevClient     *client,
>      else if (g_str_equal (action, "remove"))
>          spice_usb_device_manager_remove_udev(self, udevice);
>  }
> +#else
> +struct hotplug_idle_cb_args {
> +    SpiceUsbDeviceManager *self;
> +    libusb_device *device;
> +    libusb_hotplug_event event;
> +};
> +
> +static gboolean spice_usb_device_manager_hotplug_idle_cb(gpointer user_data)
> +{
> +    struct hotplug_idle_cb_args *args = user_data;
> +    SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(args->self);
> +
> +    switch (args->event) {
> +    case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED:
> +        spice_usb_device_manager_add_dev(self, args->device);
> +        break;
> +    case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT:
> +        spice_usb_device_manager_remove_dev(self,
> +                                    libusb_get_bus_number(args->device),
> +
> libusb_get_device_address(args->device));
> +        break;
> +    }
> +    libusb_unref_device(args->device);
> +    g_object_unref(self);
> +    g_free(args);
> +    return FALSE;
> +}
> +
> +/* Can be called from both the main-thread as well as the event_thread */
> +static int spice_usb_device_manager_hotplug_cb(libusb_context       *ctx,
> +                                               libusb_device        *device,
> +                                               libusb_hotplug_event  event,
> +                                               void
> *user_data)
> +{
> +    SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(user_data);
> +    struct hotplug_idle_cb_args *args = g_malloc(sizeof(*args));
> +
> +    args->self = g_object_ref(self);
> +    args->device = libusb_ref_device(device);
> +    args->event = event;
> +    g_idle_add(spice_usb_device_manager_hotplug_idle_cb, args);
> +    return 0;
> +}
> +#endif
>  
>  static void spice_usb_device_manager_channel_connect_cb(
>      GObject *gobject, GAsyncResult *channel_res, gpointer user_data)
> --
> 1.8.3.1
> 
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel
> 


More information about the Spice-devel mailing list