[Spice-devel] [PATCH v2 2/2] UsbDk: Add UsbDk as a default backend

Kirill Moizik kirill at daynix.com
Tue Jun 9 05:53:02 PDT 2015


From: Kirill Moizik <kirillm at daynix.com>

Backend is chosen dynamically, if UsbDk is not installed, then WinUsb/usbclerk
will be chosen.

Signed-off-by: Kirill Moizik <kirillm at daynix.com>
---
 src/usb-device-manager.c | 297 +++++++++++++++++++++++++++++++++--------------
 1 file changed, 208 insertions(+), 89 deletions(-)

diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c
index 12ad4ba..3e2a679 100644
--- a/src/usb-device-manager.c
+++ b/src/usb-device-manager.c
@@ -29,6 +29,10 @@
 #include <errno.h>
 #include <libusb.h>
 
+#ifdef G_OS_WIN32
+#include "usbdk_api.h"
+#endif
+
 #if defined(USE_GUDEV)
 #include <gudev/gudev.h>
 #elif defined(G_OS_WIN32)
@@ -121,6 +125,9 @@ struct _SpiceUsbDeviceManagerPrivate {
     libusb_hotplug_callback_handle hp_handle;
 #endif
 #ifdef G_OS_WIN32
+    usbdk_api_wrapper     *usbdk_api;
+    HANDLE                 usbdk_hider_handle;
+    gboolean               use_usbclerk;
     SpiceWinUsbDriver     *installer;
 #endif
 #endif
@@ -185,7 +192,8 @@ static void  spice_usb_device_set_state(SpiceUsbDevice *device, guint8 s);
 #endif
 
 static gboolean spice_usb_device_equal_libdev(SpiceUsbDevice *device,
-                                              libusb_device *libdev);
+                                              libusb_device *libdev,
+                                              gboolean use_usbclerk);
 static libusb_device *
 spice_usb_device_manager_device_to_libdev(SpiceUsbDeviceManager *self,
                                           SpiceUsbDevice *device);
@@ -219,6 +227,16 @@ static void spice_usb_device_manager_init(SpiceUsbDeviceManager *self)
     priv = SPICE_USB_DEVICE_MANAGER_GET_PRIVATE(self);
     self->priv = priv;
 
+#ifdef G_OS_WIN32
+    priv->use_usbclerk = !usbdk_is_driver_installed();
+    if (!priv->use_usbclerk) {
+        if (usbdk_api_load(&priv->usbdk_api) != 0) {
+            priv->use_usbclerk = TRUE;
+            usbdk_api_unload(priv->usbdk_api);
+            SPICE_DEBUG("Failed to load UsbDk API DLL");
+        }
+    }
+#endif
     priv->channels = g_ptr_array_new();
 #ifdef USE_USBREDIR
     priv->devices  = g_ptr_array_new_with_free_func((GDestroyNotify)
@@ -351,14 +369,25 @@ static void spice_usb_device_manager_finalize(GObject *gobject)
     free(priv->auto_conn_filter_rules);
     free(priv->redirect_on_connect_rules);
 #ifdef G_OS_WIN32
-    if (priv->installer)
+    if (priv->installer) {
+        g_warn_if_fail(priv->use_usbclerk);
         g_object_unref(priv->installer);
+    }
 #endif
 #endif
 
     g_free(priv->auto_connect_filter);
     g_free(priv->redirect_on_connect);
 
+#ifdef G_OS_WIN32
+    if (!priv->use_usbclerk) {
+        if (priv->usbdk_hider_handle != NULL) {
+            usbdk_clear_hide_rules(priv->usbdk_api, priv->usbdk_hider_handle);
+            usbdk_close_hider_handle(priv->usbdk_api, priv->usbdk_hider_handle);
+        }
+        usbdk_api_unload(priv->usbdk_api);
+    }
+#endif
     /* Chain up to the parent class */
     if (G_OBJECT_CLASS(spice_usb_device_manager_parent_class)->finalize)
         G_OBJECT_CLASS(spice_usb_device_manager_parent_class)->finalize(gobject);
@@ -396,6 +425,13 @@ static void spice_usb_device_manager_get_property(GObject     *gobject,
     }
 }
 
+#ifdef G_OS_WIN32
+static
+void _usbdk_autoredir_enable(SpiceUsbDeviceManager *manager);
+static
+void _usbdk_autoredir_disable(SpiceUsbDeviceManager *manager);
+#endif
+
 static void spice_usb_device_manager_set_property(GObject       *gobject,
                                                   guint          prop_id,
                                                   const GValue  *value,
@@ -410,6 +446,15 @@ static void spice_usb_device_manager_set_property(GObject       *gobject,
         break;
     case PROP_AUTO_CONNECT:
         priv->auto_connect = g_value_get_boolean(value);
+#ifdef G_OS_WIN32
+        if (!priv->use_usbclerk) {
+            if (priv->auto_connect) {
+                _usbdk_autoredir_enable(self);
+            } else {
+                _usbdk_autoredir_disable(self);
+            }
+        }
+#endif
         break;
     case PROP_AUTO_CONNECT_FILTER: {
         const gchar *filter = g_value_get_string(value);
@@ -639,19 +684,20 @@ static void spice_usb_device_manager_class_init(SpiceUsbDeviceManagerClass *klas
 
 #ifdef USE_GUDEV
 static gboolean spice_usb_device_manager_get_udev_bus_n_address(
-    GUdevDevice *udev, int *bus, int *address)
+    GUdevDevice *udev, int *bus, int *address, gboolean use_usbclerk)
 {
     const gchar *bus_str, *address_str;
 
     *bus = *address = 0;
 
-#ifndef G_OS_WIN32
-    bus_str = g_udev_device_get_property(udev, "BUSNUM");
-    address_str = g_udev_device_get_property(udev, "DEVNUM");
-#else /* Windows -- request vid:pid instead */
-    bus_str = g_udev_device_get_property(udev, "VID");
-    address_str = g_udev_device_get_property(udev, "PID");
-#endif
+    if (!use_usbclerk) {/* Linux or UsbDk backend on Windows*/
+        bus_str = g_udev_device_get_property(udev, "BUSNUM");
+        address_str = g_udev_device_get_property(udev, "DEVNUM");
+    }
+    else { /* Windows WinUsb/UsbClerk -- request vid:pid instead */
+        bus_str = g_udev_device_get_property(udev, "VID");
+        address_str = g_udev_device_get_property(udev, "PID");
+    }
     if (bus_str)
         *bus = atoi(bus_str);
     if (address_str)
@@ -788,19 +834,26 @@ static void spice_usb_device_manager_auto_connect_cb(GObject      *gobject,
     spice_usb_device_unref(device);
 }
 
-#ifndef G_OS_WIN32 /* match functions for Linux -- match by bus.addr */
 static gboolean
 spice_usb_device_manager_device_match(SpiceUsbDevice *device,
-                                      const int bus, const int address)
+                                      const int vid, const int pid, gboolean use_usbclerk)
 {
-    return (spice_usb_device_get_busnum(device) == bus &&
-            spice_usb_device_get_devaddr(device) == address);
+   if (use_usbclerk) {
+        return (spice_usb_device_get_vid(device) == vid &&
+            spice_usb_device_get_pid(device) == pid);
+    }
+    else {
+        return (spice_usb_device_get_busnum(device) == vid &&
+            spice_usb_device_get_devaddr(device) == pid);
+    }
+    return TRUE;
 }
 
+#ifndef G_OS_WIN32 /* match functions for Linux -- match by bus.addr */
 #ifdef USE_GUDEV
 static gboolean
 spice_usb_device_manager_libdev_match(libusb_device *libdev,
-                                      const int bus, const int address)
+                                      const int bus, const int address, gboolean use_usbclerk)
 {
     return (libusb_get_bus_number(libdev) == bus &&
             libusb_get_device_address(libdev) == address);
@@ -809,23 +862,22 @@ spice_usb_device_manager_libdev_match(libusb_device *libdev,
 
 #else /* Win32 -- match functions for Windows -- match by vid:pid */
 static gboolean
-spice_usb_device_manager_device_match(SpiceUsbDevice *device,
-                                      const int vid, const int pid)
-{
-    return (spice_usb_device_get_vid(device) == vid &&
-            spice_usb_device_get_pid(device) == pid);
-}
-
-static gboolean
 spice_usb_device_manager_libdev_match(libusb_device *libdev,
-                                      const int vid, const int pid)
+                                      const int vid, const int pid, gboolean use_usbclerk)
 {
-    int vid2, pid2;
+    if (use_usbclerk) {
+        int vid2, pid2;
 
-    if (!spice_usb_device_manager_get_libdev_vid_pid(libdev, &vid2, &pid2)) {
-        return FALSE;
+        if (!spice_usb_device_manager_get_libdev_vid_pid(libdev, &vid2, &pid2)) {
+            return FALSE;
+        }
+        return (vid == vid2 && pid == pid2);
+    }
+    else {
+        return (libusb_get_bus_number(libdev) == vid &&
+            libusb_get_device_address(libdev) == pid);
     }
-    return (vid == vid2 && pid == pid2);
+    return TRUE;
 }
 #endif /* of Win32 -- match functions */
 
@@ -839,7 +891,7 @@ spice_usb_device_manager_find_device(SpiceUsbDeviceManager *self,
 
     for (i = 0; i < priv->devices->len; i++) {
         curr = g_ptr_array_index(priv->devices, i);
-        if (spice_usb_device_manager_device_match(curr, bus, address)) {
+        if (spice_usb_device_manager_device_match(curr, bus, address, priv->use_usbclerk)) {
             device = curr;
             break;
         }
@@ -903,12 +955,14 @@ static void spice_usb_device_manager_remove_dev(SpiceUsbDeviceManager *self,
     }
 
 #ifdef G_OS_WIN32
-    const guint8 state = spice_usb_device_get_state(device);
-    if ((state == SPICE_USB_DEVICE_STATE_INSTALLING) ||
-        (state == SPICE_USB_DEVICE_STATE_UNINSTALLING)) {
-        SPICE_DEBUG("skipping " DEV_ID_FMT ". It is un/installing its driver",
-                    bus, address);
-        return;
+    if (priv->use_usbclerk) {
+        const guint8 state = spice_usb_device_get_state(device);
+        if ((state == SPICE_USB_DEVICE_STATE_INSTALLING) ||
+            (state == SPICE_USB_DEVICE_STATE_UNINSTALLING)) {
+            SPICE_DEBUG("skipping " DEV_ID_FMT ". It is un/installing its driver",
+                        bus, address);
+            return;
+        }
     }
 #endif
 
@@ -936,7 +990,7 @@ static void spice_usb_device_manager_add_udev(SpiceUsbDeviceManager  *self,
     if (!devtype || strcmp(devtype, "usb_device"))
         return;
 
-    if (!spice_usb_device_manager_get_udev_bus_n_address(udev, &bus, &address)) {
+    if (!spice_usb_device_manager_get_udev_bus_n_address(udev, &bus, &address, self->priv->use_usbclerk)) {
         g_warning("USB device without bus number or device address");
         return;
     }
@@ -957,7 +1011,7 @@ static void spice_usb_device_manager_add_udev(SpiceUsbDeviceManager  *self,
         libusb_get_device_list(priv->context, &dev_list);
 
     for (i = 0; dev_list && dev_list[i]; i++) {
-        if (spice_usb_device_manager_libdev_match(dev_list[i], bus, address)) {
+        if (spice_usb_device_manager_libdev_match(dev_list[i], bus, address, priv->use_usbclerk)) {
             libdev = dev_list[i];
             break;
         }
@@ -978,7 +1032,7 @@ static void spice_usb_device_manager_remove_udev(SpiceUsbDeviceManager  *self,
 {
     int bus, address;
 
-    if (!spice_usb_device_manager_get_udev_bus_n_address(udev, &bus, &address))
+    if (!spice_usb_device_manager_get_udev_bus_n_address(udev, &bus, &address, self->priv->use_usbclerk))
         return;
 
     spice_usb_device_manager_remove_dev(self, bus, address);
@@ -1106,6 +1160,7 @@ static void spice_usb_device_manager_drv_install_cb(GObject *gobject,
     g_free(cbinfo);
 
     g_return_if_fail(SPICE_IS_USB_DEVICE_MANAGER(self));
+    g_return_if_fail(self->priv->use_usbclerk);
     g_return_if_fail(SPICE_IS_WIN_USB_DRIVER(installer));
     g_return_if_fail(device!= NULL);
 
@@ -1138,6 +1193,7 @@ static void spice_usb_device_manager_drv_uninstall_cb(GObject *gobject,
 
     SPICE_DEBUG("Win USB driver uninstall finished");
     g_return_if_fail(SPICE_IS_USB_DEVICE_MANAGER(self));
+    g_return_if_fail(self->priv->use_usbclerk);
 
     if (!spice_win_usb_driver_uninstall_finish(cbinfo->installer, res, &err)) {
         g_warning("win usb driver uninstall failed -- %s", err->message);
@@ -1281,7 +1337,7 @@ static SpiceUsbredirChannel *spice_usb_device_manager_get_channel_for_dev(
     for (i = 0; i < priv->channels->len; i++) {
         SpiceUsbredirChannel *channel = g_ptr_array_index(priv->channels, i);
         libusb_device *libdev = spice_usbredir_channel_get_device(channel);
-        if (spice_usb_device_equal_libdev(device, libdev))
+        if (spice_usb_device_equal_libdev(device, libdev, priv->use_usbclerk))
             return channel;
     }
 #endif
@@ -1470,25 +1526,35 @@ void spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
 {
 
 #if defined(USE_USBREDIR) && defined(G_OS_WIN32)
-    SpiceWinUsbDriver *installer;
-    UsbInstallCbInfo *cbinfo;
 
-    g_return_if_fail(self->priv->installer);
+    if (self->priv->use_usbclerk) {
+        SpiceWinUsbDriver *installer;
+        UsbInstallCbInfo *cbinfo;
 
-    spice_usb_device_set_state(device, SPICE_USB_DEVICE_STATE_INSTALLING);
+        g_return_if_fail(self->priv->installer);
 
-    installer = self->priv->installer;
-    cbinfo = g_new0(UsbInstallCbInfo, 1);
-    cbinfo->manager     = self;
-    cbinfo->device      = spice_usb_device_ref(device);
-    cbinfo->installer   = installer;
-    cbinfo->cancellable = cancellable;
-    cbinfo->callback    = callback;
-    cbinfo->user_data   = user_data;
+        spice_usb_device_set_state(device, SPICE_USB_DEVICE_STATE_INSTALLING);
 
-    spice_win_usb_driver_install_async(installer, device, cancellable,
-                                       spice_usb_device_manager_drv_install_cb,
-                                       cbinfo);
+        installer = self->priv->installer;
+        cbinfo = g_new0(UsbInstallCbInfo, 1);
+        cbinfo->manager     = self;
+        cbinfo->device      = spice_usb_device_ref(device);
+        cbinfo->installer   = installer;
+        cbinfo->cancellable = cancellable;
+        cbinfo->callback    = callback;
+        cbinfo->user_data   = user_data;
+
+        spice_win_usb_driver_install_async(installer, device, cancellable,
+                                           spice_usb_device_manager_drv_install_cb,
+                                           cbinfo);
+    }
+    else {
+        _spice_usb_device_manager_connect_device_async(self,
+            device,
+            cancellable,
+            callback,
+            user_data);
+    }
 #else
     _spice_usb_device_manager_connect_device_async(self,
                                                    device,
@@ -1536,30 +1602,32 @@ void spice_usb_device_manager_disconnect_device(SpiceUsbDeviceManager *self,
         spice_usbredir_channel_disconnect_device(channel);
 
 #ifdef G_OS_WIN32
-    SpiceWinUsbDriver *installer;
-    UsbInstallCbInfo *cbinfo;
-    guint8 state;
-
-    g_warn_if_fail(device != NULL);
-    g_return_if_fail(self->priv->installer);
-
-    state = spice_usb_device_get_state(device);
-    if ((state != SPICE_USB_DEVICE_STATE_INSTALLED) &&
-        (state != SPICE_USB_DEVICE_STATE_CONNECTED)) {
-        return;
-    }
+   if (self->priv->use_usbclerk) {
+        SpiceWinUsbDriver *installer;
+        UsbInstallCbInfo *cbinfo;
+        guint8 state;
+
+        g_warn_if_fail(device != NULL);
+        g_warn_if_fail(self->priv->installer != NULL);
+
+        state = spice_usb_device_get_state(device);
+        if ((state != SPICE_USB_DEVICE_STATE_INSTALLED) &&
+           (state != SPICE_USB_DEVICE_STATE_CONNECTED)) {
+           return;
+        }
 
-    spice_usb_device_set_state(device, SPICE_USB_DEVICE_STATE_UNINSTALLING);
+        spice_usb_device_set_state(device, SPICE_USB_DEVICE_STATE_UNINSTALLING);
 
-    installer = self->priv->installer;
-    cbinfo = g_new0(UsbInstallCbInfo, 1);
-    cbinfo->manager     = self;
-    cbinfo->device      = spice_usb_device_ref(device);
-    cbinfo->installer   = installer;
+        installer = self->priv->installer;
+        cbinfo = g_new0(UsbInstallCbInfo, 1);
+        cbinfo->manager     = self;
+        cbinfo->device      = spice_usb_device_ref(device);
+        cbinfo->installer   = installer;
 
-    spice_win_usb_driver_uninstall_async(installer, device, NULL,
-                                         spice_usb_device_manager_drv_uninstall_cb,
-                                         cbinfo);
+        spice_win_usb_driver_uninstall_async (installer, device, NULL,
+                                       spice_usb_device_manager_drv_uninstall_cb,
+                                       cbinfo);
+    }
 #endif
 
 #endif
@@ -1792,6 +1860,36 @@ guint8 spice_usb_device_get_state(SpiceUsbDevice *device)
 
     return info->state;
 }
+static
+void _usbdk_autoredir_enable(SpiceUsbDeviceManager *manager)
+{
+    SpiceUsbDeviceManagerPrivate *priv = manager->priv;
+
+    if (priv->redirect_on_connect == NULL) {
+        SPICE_DEBUG("No autoredirect rules, no hider setup needed");
+        return;
+    }
+
+    priv->usbdk_hider_handle = usbdk_create_hider_handle(priv->usbdk_api);
+    if (priv->usbdk_hider_handle == NULL) {
+        SPICE_DEBUG("Failed to instanciate UsbDk interface");
+        return;
+    }
+    usbdk_api_set_hide_rules(priv->usbdk_api, priv->usbdk_hider_handle, priv->redirect_on_connect);
+}
+
+static
+void _usbdk_autoredir_disable(SpiceUsbDeviceManager *manager)
+{
+    SpiceUsbDeviceManagerPrivate *priv = manager->priv;
+    g_return_if_fail(!priv->use_usbclerk);
+
+    if (priv->usbdk_hider_handle != NULL) {
+        usbdk_clear_hide_rules(priv->usbdk_api, priv->usbdk_hider_handle);
+        usbdk_close_hider_handle(priv->usbdk_api, priv->usbdk_hider_handle);
+        priv->usbdk_hider_handle = NULL;
+    }
+}
 #endif
 
 static SpiceUsbDevice *spice_usb_device_ref(SpiceUsbDevice *device)
@@ -1823,7 +1921,7 @@ static void spice_usb_device_unref(SpiceUsbDevice *device)
 #ifndef G_OS_WIN32 /* Linux -- directly compare libdev */
 static gboolean
 spice_usb_device_equal_libdev(SpiceUsbDevice *device,
-                              libusb_device  *libdev)
+                              libusb_device  *libdev, gboolean use_usbclerk)
 {
     SpiceUsbDeviceInfo *info = (SpiceUsbDeviceInfo *)device;
 
@@ -1835,21 +1933,37 @@ spice_usb_device_equal_libdev(SpiceUsbDevice *device,
 #else /* Windows -- compare vid:pid of device and libdev */
 static gboolean
 spice_usb_device_equal_libdev(SpiceUsbDevice *device,
-                              libusb_device  *libdev)
+                              libusb_device  *libdev, gboolean use_usbclerk)
 {
-    int vid1, vid2, pid1, pid2;
+    if (use_usbclerk) {
+        int vid1, vid2, pid1, pid2;
 
-    if ((device == NULL) || (libdev == NULL))
-        return FALSE;
+        if ((device == NULL) || (libdev == NULL))
+            return FALSE;
 
-    vid1 = spice_usb_device_get_vid(device);
-    pid1 = spice_usb_device_get_pid(device);
+        vid1 = spice_usb_device_get_vid(device);
+        pid1 = spice_usb_device_get_pid(device);
 
-    if (!spice_usb_device_manager_get_libdev_vid_pid(libdev, &vid2, &pid2)) {
-        return FALSE;
+        if (!spice_usb_device_manager_get_libdev_vid_pid(libdev, &vid2, &pid2)) {
+            return FALSE;
+        }
+
+        return ((vid1 == vid2) && (pid1 == pid2));
     }
+    else {
+        int busnum1, devaddr1, busnum2, devaddr2;
+
+        if ((device == NULL) || (libdev == NULL))
+            return FALSE;
+
+        busnum1 = spice_usb_device_get_busnum(device);
+        devaddr1 = spice_usb_device_get_devaddr(device);
 
-    return ((vid1 == vid2) && (pid1 == pid2));
+        busnum2 = libusb_get_bus_number(libdev);
+        devaddr2 = libusb_get_device_address(libdev);
+
+        return ((busnum1 == busnum2) && (devaddr1 == devaddr2));
+    }
 }
 #endif
 
@@ -1879,15 +1993,20 @@ spice_usb_device_manager_device_to_libdev(SpiceUsbDeviceManager *self,
     g_return_val_if_fail(self->priv->context != NULL, NULL);
 
     /* On windows we match by vid / pid, since the address may change */
-    bus  = spice_usb_device_get_vid(device);
-    addr = spice_usb_device_get_pid(device);
-
+    if (self->priv->use_usbclerk) {
+        bus  = spice_usb_device_get_vid(device);
+        addr = spice_usb_device_get_pid(device);
+    }
+    else{
+        bus  = spice_usb_device_get_busnum(device);
+        addr = spice_usb_device_get_devaddr(device);
+    }
     libusb_get_device_list(self->priv->context, &devlist);
     if (!devlist)
         return NULL;
 
     for (i = 0; (d = devlist[i]) != NULL; i++) {
-        if (spice_usb_device_manager_libdev_match(d, bus, addr)) {
+        if (spice_usb_device_manager_libdev_match(d, bus, addr, self->priv->use_usbclerk)) {
             libusb_ref_device(d);
             break;
         }
-- 
2.1.0



More information about the Spice-devel mailing list