From: Kirill Moizik <kirillm@xxxxxxxxxx> Backend is chosen dynamically, if UsbDk is not installed, then WinUsb/usbclerk will be chosen. Signed-off-by: Kirill Moizik <kirillm@xxxxxxxxxx> --- 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 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel