[Spice-commits] 14 commits - src/spice-marshal.txt src/usb-device-manager.c src/win-usb-dev.c src/win-usb-dev.h

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Mar 27 14:54:22 UTC 2019


 src/spice-marshal.txt    |    1 
 src/usb-device-manager.c |  267 ++++++-----------------------------------------
 src/win-usb-dev.c        |  260 +++++++++++++--------------------------------
 src/win-usb-dev.h        |   35 ------
 4 files changed, 120 insertions(+), 443 deletions(-)

New commits:
commit 0b263aedebb5ac9de2afb5cf19490c1cdd062a44
Author: Yuri Benditovich <yuri.benditovich at daynix.com>
Date:   Tue Mar 19 07:56:08 2019 +0200

    win-usb-dev: remove unused code
    
    Remove unused code related to GUdevDevice.
    
    Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
    Acked-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/src/win-usb-dev.c b/src/win-usb-dev.c
index 34c18ee..a4dfa78 100644
--- a/src/win-usb-dev.c
+++ b/src/win-usb-dev.c
@@ -49,31 +49,6 @@ G_DEFINE_TYPE_WITH_CODE(GUdevClient, g_udev_client, G_TYPE_OBJECT,
                         G_ADD_PRIVATE(GUdevClient)
                         G_IMPLEMENT_INTERFACE(G_TYPE_INITABLE, g_udev_client_initable_iface_init))
 
-
-typedef struct _GUdevDeviceInfo GUdevDeviceInfo;
-
-struct _GUdevDeviceInfo {
-    guint16 bus;
-    guint16 addr;
-    guint16 vid;
-    guint16 pid;
-    guint16 class;
-    gchar sclass[4];
-    gchar sbus[4];
-    gchar saddr[4];
-    gchar svid[8];
-    gchar spid[8];
-};
-
-struct _GUdevDevicePrivate
-{
-    /* FixMe: move above fields to this structure and access them directly */
-    GUdevDeviceInfo *udevinfo;
-};
-
-G_DEFINE_TYPE_WITH_PRIVATE(GUdevDevice, g_udev_device, G_TYPE_OBJECT)
-
-
 enum
 {
     UEVENT_SIGNAL,
@@ -461,55 +436,6 @@ static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM
     return DefWindowProc(hwnd, message, wparam, lparam);
 }
 
-/*** GUdevDevice ***/
-
-static void g_udev_device_finalize(GObject *object)
-{
-    GUdevDevice *device =  G_UDEV_DEVICE(object);
-
-    g_free(device->priv->udevinfo);
-    if (G_OBJECT_CLASS(g_udev_device_parent_class)->finalize != NULL)
-        (* G_OBJECT_CLASS(g_udev_device_parent_class)->finalize)(object);
-}
-
-static void g_udev_device_class_init(GUdevDeviceClass *klass)
-{
-    GObjectClass *gobject_class = (GObjectClass *) klass;
-
-    gobject_class->finalize = g_udev_device_finalize;
-}
-
-static void g_udev_device_init(GUdevDevice *device)
-{
-    device->priv = g_udev_device_get_instance_private(device);
-}
-
-const gchar *g_udev_device_get_property(GUdevDevice *udev, const gchar *property)
-{
-    GUdevDeviceInfo* udevinfo;
-
-    g_return_val_if_fail(G_UDEV_DEVICE(udev), NULL);
-    g_return_val_if_fail(property != NULL, NULL);
-
-    udevinfo = udev->priv->udevinfo;
-    g_return_val_if_fail(udevinfo != NULL, NULL);
-
-    if (g_strcmp0(property, "BUSNUM") == 0) {
-        return udevinfo->sbus;
-    } else if (g_strcmp0(property, "DEVNUM") == 0) {
-        return udevinfo->saddr;
-    } else if (g_strcmp0(property, "DEVTYPE") == 0) {
-        return "usb_device";
-    } else if (g_strcmp0(property, "VID") == 0) {
-        return udevinfo->svid;
-    } else if (g_strcmp0(property, "PID") == 0) {
-        return udevinfo->spid;
-    }
-
-    g_warn_if_reached();
-    return NULL;
-}
-
 #ifdef DEBUG_GUDEV_DEVICE_LISTS
 static void g_udev_device_print_list(GList *l, const gchar *msg)
 {
diff --git a/src/win-usb-dev.h b/src/win-usb-dev.h
index b960dfc..b1c0e27 100644
--- a/src/win-usb-dev.h
+++ b/src/win-usb-dev.h
@@ -26,30 +26,6 @@
 
 G_BEGIN_DECLS
 
-/* GUdevDevice */
-
-#define G_UDEV_TYPE_DEVICE         (g_udev_device_get_type())
-#define G_UDEV_DEVICE(o)           (G_TYPE_CHECK_INSTANCE_CAST((o), G_UDEV_TYPE_DEVICE, GUdevDevice))
-#define G_UDEV_DEVICE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_DEVICE, GUdevDeviceClass))
-#define G_UDEV_IS_DEVICE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_DEVICE))
-#define G_UDEV_IS_DEVICE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE((k), G_UDEV_TYPE_DEVICE))
-#define G_UDEV_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), G_UDEV_TYPE_DEVICE, GUdevDeviceClass))
-
-typedef struct _GUdevDevice GUdevDevice;
-typedef struct _GUdevDeviceClass GUdevDeviceClass;
-typedef struct _GUdevDevicePrivate GUdevDevicePrivate;
-
-struct _GUdevDevice
-{
-  GObject parent;
-  GUdevDevicePrivate *priv;
-};
-
-struct _GUdevDeviceClass
-{
-  GObjectClass parent_class;
-};
-
 /* GUdevClient */
 
 #define G_UDEV_TYPE_CLIENT         (g_udev_client_get_type())
@@ -83,9 +59,6 @@ GUdevClient *g_udev_client_new(void);
 libusb_context *g_udev_client_get_context(GUdevClient *client);
 void g_udev_client_report_devices(GUdevClient *client);
 
-GType g_udev_device_get_type(void) G_GNUC_CONST;
-const gchar *g_udev_device_get_property(GUdevDevice *udev, const gchar *property);
-
 GQuark g_udev_client_error_quark(void);
 #define G_UDEV_CLIENT_ERROR g_udev_client_error_quark()
 
commit 8ba30e069e4700cbe864ad7a0cb3c5f3012a5740
Author: Yuri Benditovich <yuri.benditovich at daynix.com>
Date:   Tue Mar 19 07:56:07 2019 +0200

    usb-redir: use persistent libusb_device under Windows also
    
    Unify SpiceUsbDeviceInfo for Linux and Windows by using
    persistent libusb_device. Probably there was some problem
    doing it long time ago with winusb, but at least with
    existing libusb and UsbDk the the libusb device can be
    accessed as long as it is referenced.
    
    Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
    Acked-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c
index 7f3031b..bd42142 100644
--- a/src/usb-device-manager.c
+++ b/src/usb-device-manager.c
@@ -136,11 +136,7 @@ typedef struct _SpiceUsbDeviceInfo {
     guint16 vid;
     guint16 pid;
     gboolean isochronous;
-#ifdef G_OS_WIN32
-    guint8  state;
-#else
     libusb_device *libdev;
-#endif
     gint    ref;
 } SpiceUsbDeviceInfo;
 
@@ -758,14 +754,12 @@ gconstpointer
 spice_usb_device_get_libusb_device(const SpiceUsbDevice *device G_GNUC_UNUSED)
 {
 #ifdef USE_USBREDIR
-#ifndef G_OS_WIN32
     const SpiceUsbDeviceInfo *info = (const SpiceUsbDeviceInfo *)device;
 
     g_return_val_if_fail(info != NULL, FALSE);
 
     return info->libdev;
 #endif
-#endif
     return NULL;
 }
 
@@ -886,17 +880,6 @@ spice_usb_device_manager_device_match(SpiceUsbDeviceManager *self, SpiceUsbDevic
             spice_usb_device_get_devaddr(device) == address);
 }
 
-#ifdef G_OS_WIN32
-static gboolean
-spice_usb_device_manager_libdev_match(SpiceUsbDeviceManager *self, libusb_device *libdev,
-                                      const int bus, const int address)
-{
-    /* match functions for Linux/UsbDk -- match by bus.addr */
-    return (libusb_get_bus_number(libdev) == bus &&
-            libusb_get_device_address(libdev) == address);
-}
-#endif
-
 static SpiceUsbDevice*
 spice_usb_device_manager_find_device(SpiceUsbDeviceManager *self,
                                      const int bus, const int address)
@@ -1150,10 +1133,6 @@ static void spice_usb_device_manager_check_redir_on_connect(
             continue;
 
         libdev = spice_usb_device_manager_device_to_libdev(self, device);
-#ifdef G_OS_WIN32
-        if (libdev == NULL)
-            continue;
-#endif
         if (usbredirhost_check_device_filter(
                             priv->redirect_on_connect_rules,
                             priv->redirect_on_connect_rules_count,
@@ -1258,10 +1237,6 @@ GPtrArray* spice_usb_device_manager_get_devices_with_filter(
         if (rules) {
             libusb_device *libdev =
                 spice_usb_device_manager_device_to_libdev(self, device);
-#ifdef G_OS_WIN32
-            if (libdev == NULL)
-                continue;
-#endif
             if (usbredirhost_check_device_filter(rules, count, libdev, 0) != 0)
                 continue;
         }
@@ -1353,24 +1328,6 @@ _spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
             continue; /* Skip already used channels */
 
         libdev = spice_usb_device_manager_device_to_libdev(self, device);
-#ifdef G_OS_WIN32
-        if (libdev == NULL) {
-            /* Most likely, the device was plugged out at driver installation
-             * time, and its remove-device event was ignored.
-             * So remove the device now
-             */
-            SPICE_DEBUG("libdev does not exist for %p -- removing", device);
-            spice_usb_device_ref(device);
-            g_ptr_array_remove(priv->devices, device);
-            g_signal_emit(self, signals[DEVICE_REMOVED], 0, device);
-            spice_usb_device_unref(device);
-            g_task_return_new_error(task,
-                                    SPICE_CLIENT_ERROR,
-                                    SPICE_CLIENT_ERROR_FAILED,
-                                    _("Device was not found"));
-            goto done;
-        }
-#endif
         spice_usbredir_channel_connect_device_async(channel,
                                  libdev,
                                  device,
@@ -1642,13 +1599,6 @@ spice_usb_device_manager_can_redirect_device(SpiceUsbDeviceManager  *self,
         libusb_device *libdev;
 
         libdev = spice_usb_device_manager_device_to_libdev(self, device);
-#ifdef G_OS_WIN32
-        if (libdev == NULL) {
-            g_set_error_literal(err, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
-                                _("Some USB devices were not found"));
-            return FALSE;
-        }
-#endif
         filter_ok = (usbredirhost_check_device_filter(
                             guest_filter_rules, guest_filter_rules_count,
                             libdev, 0) == 0);
@@ -1799,9 +1749,7 @@ static SpiceUsbDeviceInfo *spice_usb_device_new(libusb_device *libdev)
     info->pid = pid;
     info->ref = 1;
     info->isochronous = probe_isochronous_endpoint(libdev);
-#ifndef G_OS_WIN32
     info->libdev = libusb_ref_device(libdev);
-#endif
 
     return info;
 }
@@ -1937,14 +1885,11 @@ static void spice_usb_device_unref(SpiceUsbDevice *device)
 
     ref_count_is_0 = g_atomic_int_dec_and_test(&info->ref);
     if (ref_count_is_0) {
-#ifndef G_OS_WIN32
         libusb_unref_device(info->libdev);
-#endif
         g_free(info);
     }
 }
 
-#ifndef G_OS_WIN32 /* Linux -- directly compare libdev */
 static gboolean
 spice_usb_manager_device_equal_libdev(SpiceUsbDeviceManager *manager,
                                       SpiceUsbDevice *device,
@@ -1957,23 +1902,6 @@ spice_usb_manager_device_equal_libdev(SpiceUsbDeviceManager *manager,
 
     return info->libdev == libdev;
 }
-#else /* Windows -- compare vid:pid of device and libdev */
-static gboolean
-spice_usb_manager_device_equal_libdev(SpiceUsbDeviceManager *manager,
-                                      SpiceUsbDevice *device,
-                                      libusb_device  *libdev)
-{
-    int busnum, devaddr;
-
-    if ((device == NULL) || (libdev == NULL))
-        return FALSE;
-
-    busnum = spice_usb_device_get_busnum(device);
-    devaddr = spice_usb_device_get_devaddr(device);
-    return spice_usb_device_manager_libdev_match(manager, libdev,
-                                                 busnum, devaddr);
-}
-#endif
 
 /*
  * Caller must libusb_unref_device the libusb_device returned by this function.
@@ -1983,42 +1911,9 @@ static libusb_device *
 spice_usb_device_manager_device_to_libdev(SpiceUsbDeviceManager *self,
                                           SpiceUsbDevice *device)
 {
-#ifdef G_OS_WIN32
-    /*
-     * On win32 we need to do this the hard and slow way, by asking libusb to
-     * re-enumerate all devices and then finding a matching device.
-     * We cannot cache the libusb_device like we do under Linux since the
-     * driver swap we do under windows invalidates the cached libdev.
-     */
-
-    libusb_device *d, **devlist;
-    int i;
-
-    g_return_val_if_fail(SPICE_IS_USB_DEVICE_MANAGER(self), NULL);
-    g_return_val_if_fail(device != NULL, NULL);
-    g_return_val_if_fail(self->priv != NULL, NULL);
-    g_return_val_if_fail(self->priv->context != NULL, NULL);
-
-    libusb_get_device_list(self->priv->context, &devlist);
-    if (!devlist)
-        return NULL;
-
-    for (i = 0; (d = devlist[i]) != NULL; i++) {
-        if (spice_usb_manager_device_equal_libdev(self, device, d)) {
-            libusb_ref_device(d);
-            break;
-        }
-    }
-
-    libusb_free_device_list(devlist, 1);
-
-    return d;
-
-#else
     /* Simply return a ref to the cached libdev */
     SpiceUsbDeviceInfo *info = (SpiceUsbDeviceInfo *)device;
 
     return libusb_ref_device(info->libdev);
-#endif
 }
 #endif /* USE_USBREDIR */
commit 171e3041d3e8eb663b3ac6be989785caf58955f9
Author: Yuri Benditovich <yuri.benditovich at daynix.com>
Date:   Tue Mar 19 07:56:06 2019 +0200

    win-usb-dev: pass libusb_device in "uevent" signal
    
    Change the signal to report libusb_device instead of GUdevDevice
    object. This simplifies the callback procedure in usb-dev-manager
    and avoids additional reenumeration immediately after reenumeration
    that already done by win-usb-dev.
    
    Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
    Acked-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c
index 48952de..7f3031b 100644
--- a/src/usb-device-manager.c
+++ b/src/usb-device-manager.c
@@ -153,11 +153,9 @@ static void channel_event(SpiceChannel *channel, SpiceChannelEvent event,
                           gpointer user_data);
 #ifdef G_OS_WIN32
 static void spice_usb_device_manager_uevent_cb(GUdevClient     *client,
-                                               GUdevDevice     *udevice,
+                                               libusb_device   *udevice,
                                                gboolean         add,
                                                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,
@@ -720,28 +718,6 @@ static void spice_usb_device_manager_class_init(SpiceUsbDeviceManagerClass *klas
 /* ------------------------------------------------------------------ */
 /* gudev / libusb Helper functions                                    */
 
-#ifdef G_OS_WIN32
-static gboolean spice_usb_device_manager_get_udev_bus_n_address(
-    SpiceUsbDeviceManager *manager, GUdevDevice *udev,
-    int *bus, int *address)
-{
-    const gchar *bus_str, *address_str;
-
-    *bus = *address = 0;
-
-   /* Linux or UsbDk backend on Windows*/
-    bus_str = g_udev_device_get_property(udev, "BUSNUM");
-    address_str = g_udev_device_get_property(udev, "DEVNUM");
-
-    if (bus_str)
-        *bus = atoi(bus_str);
-    if (address_str)
-        *address = atoi(address_str);
-
-    return *bus && *address;
-}
-#endif
-
 static gboolean spice_usb_device_manager_get_device_descriptor(
     libusb_device *libdev,
     struct libusb_device_descriptor *desc)
@@ -1022,64 +998,19 @@ static void spice_usb_device_manager_remove_dev(SpiceUsbDeviceManager *self,
 }
 
 #ifdef G_OS_WIN32
-static void spice_usb_device_manager_add_udev(SpiceUsbDeviceManager  *self,
-                                              GUdevDevice            *udev)
-{
-    SpiceUsbDeviceManagerPrivate *priv = self->priv;
-    libusb_device *libdev = NULL, **dev_list = NULL;
-    const gchar *devtype;
-    int i, bus, address;
-
-    devtype = g_udev_device_get_property(udev, "DEVTYPE");
-    /* Check if this is a usb device (and not an interface) */
-    if (!devtype || strcmp(devtype, "usb_device"))
-        return;
-
-    if (!spice_usb_device_manager_get_udev_bus_n_address(self, udev, &bus, &address)) {
-        g_warning("USB device without bus number or device address");
-        return;
-    }
-
-    libusb_get_device_list(priv->context, &dev_list);
-
-    for (i = 0; dev_list && dev_list[i]; i++) {
-        if (spice_usb_device_manager_libdev_match(self, dev_list[i], bus, address)) {
-            libdev = dev_list[i];
-            break;
-        }
-    }
-
-    if (libdev)
-        spice_usb_device_manager_add_dev(self, libdev);
-    else
-        g_warning("Could not find USB device to add " DEV_ID_FMT,
-                  (guint) bus, (guint) address);
-
-    libusb_free_device_list(dev_list, 1);
-}
-
-static void spice_usb_device_manager_remove_udev(SpiceUsbDeviceManager  *self,
-                                                 GUdevDevice            *udev)
-{
-    int bus, address;
-
-    if (!spice_usb_device_manager_get_udev_bus_n_address(self, udev, &bus, &address))
-        return;
-
-    spice_usb_device_manager_remove_dev(self, bus, address);
-}
-
 static void spice_usb_device_manager_uevent_cb(GUdevClient     *client,
-                                               GUdevDevice     *udevice,
+                                               libusb_device   *dev,
                                                gboolean         add,
                                                gpointer         user_data)
 {
     SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(user_data);
 
     if (add)
-        spice_usb_device_manager_add_udev(self, udevice);
+        spice_usb_device_manager_add_dev(self, dev);
     else
-        spice_usb_device_manager_remove_udev(self, udevice);
+        spice_usb_device_manager_remove_dev(self,
+                                            libusb_get_bus_number(dev),
+                                            libusb_get_device_address(dev));
 }
 #else
 struct hotplug_idle_cb_args {
diff --git a/src/win-usb-dev.c b/src/win-usb-dev.c
index 84f35e3..34c18ee 100644
--- a/src/win-usb-dev.c
+++ b/src/win-usb-dev.c
@@ -83,9 +83,7 @@ enum
 static guint signals[LAST_SIGNAL] = { 0, };
 static GUdevClient *singleton = NULL;
 
-static GUdevDevice *g_udev_device_new(GUdevDeviceInfo *udevinfo);
 static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
-static gboolean get_usb_dev_info(libusb_device *dev, GUdevDeviceInfo *udevinfo);
 
 //uncomment to debug gudev device lists.
 //#define DEBUG_GUDEV_DEVICE_LISTS
@@ -250,22 +248,9 @@ static void g_udev_client_initable_iface_init(GInitableIface *iface)
     iface->init = g_udev_client_initable_init;
 }
 
-static void g_udev_notify_device(GUdevClient *self, libusb_device *dev, gboolean add)
-{
-    GUdevDeviceInfo *udevinfo;
-    GUdevDevice *udevice;
-    udevinfo = g_new0(GUdevDeviceInfo, 1);
-    if (get_usb_dev_info(dev, udevinfo)) {
-        udevice = g_udev_device_new(udevinfo);
-        g_signal_emit(self, signals[UEVENT_SIGNAL], 0, udevice, add);
-    } else {
-        g_free(udevinfo);
-    }
-}
-
 static void report_one_device(gpointer data, gpointer self)
 {
-    g_udev_notify_device(self, data, TRUE);
+    g_signal_emit(self, signals[UEVENT_SIGNAL], 0, data, TRUE);
 }
 
 void g_udev_client_report_devices(GUdevClient *self)
@@ -379,31 +364,6 @@ static void g_udev_client_class_init(GUdevClientClass *klass)
     g_object_class_install_property(gobject_class, PROP_REDIRECTING, pspec);
 }
 
-static gboolean get_usb_dev_info(libusb_device *dev, GUdevDeviceInfo *udevinfo)
-{
-    struct libusb_device_descriptor desc;
-
-    g_return_val_if_fail(dev, FALSE);
-    g_return_val_if_fail(udevinfo, FALSE);
-
-    if (libusb_get_device_descriptor(dev, &desc) < 0) {
-        g_warning("cannot get device descriptor %p", dev);
-        return FALSE;
-    }
-
-    udevinfo->bus   = libusb_get_bus_number(dev);
-    udevinfo->addr  = libusb_get_device_address(dev);
-    udevinfo->class = desc.bDeviceClass;
-    udevinfo->vid   = desc.idVendor;
-    udevinfo->pid   = desc.idProduct;
-    g_snprintf(udevinfo->sclass, sizeof(udevinfo->sclass), "%d", udevinfo->class);
-    g_snprintf(udevinfo->sbus,   sizeof(udevinfo->sbus),   "%d", udevinfo->bus);
-    g_snprintf(udevinfo->saddr,  sizeof(udevinfo->saddr),  "%d", udevinfo->addr);
-    g_snprintf(udevinfo->svid,   sizeof(udevinfo->svid),   "%d", udevinfo->vid);
-    g_snprintf(udevinfo->spid,   sizeof(udevinfo->spid),   "%d", udevinfo->pid);
-    return TRUE;
-}
-
 /* comparing bus:addr and vid:pid */
 static gint compare_libusb_devices(gconstpointer a, gconstpointer b)
 {
@@ -454,7 +414,7 @@ static void notify_dev_state_change(GUdevClient *self,
         GList *found = g_list_find_custom(new_list, dev->data, compare_libusb_devices);
         if (found == NULL) {
             g_udev_device_print(dev->data, add ? "add" : "remove");
-            g_udev_notify_device(self, dev->data, add);
+            g_signal_emit(self, signals[UEVENT_SIGNAL], 0, dev->data, add);
         }
     }
 }
@@ -524,17 +484,6 @@ static void g_udev_device_init(GUdevDevice *device)
     device->priv = g_udev_device_get_instance_private(device);
 }
 
-static GUdevDevice *g_udev_device_new(GUdevDeviceInfo *udevinfo)
-{
-    GUdevDevice *device;
-
-    g_return_val_if_fail(udevinfo != NULL, NULL);
-
-    device =  G_UDEV_DEVICE(g_object_new(G_UDEV_TYPE_DEVICE, NULL));
-    device->priv->udevinfo = udevinfo;
-    return device;
-}
-
 const gchar *g_udev_device_get_property(GUdevDevice *udev, const gchar *property)
 {
     GUdevDeviceInfo* udevinfo;
diff --git a/src/win-usb-dev.h b/src/win-usb-dev.h
index 64ebd67..b960dfc 100644
--- a/src/win-usb-dev.h
+++ b/src/win-usb-dev.h
@@ -75,7 +75,7 @@ struct _GUdevClientClass
     GObjectClass parent_class;
 
     /* signals */
-    void (*uevent)(GUdevClient *client, GUdevDevice  *device, gboolean add);
+    void (*uevent)(GUdevClient *client, libusb_device *device, gboolean add);
 };
 
 GType g_udev_client_get_type(void) G_GNUC_CONST;
commit 8090ce599f0f1d6b7de6493cd78d1b1e46ce8190
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Mon Mar 25 16:27:19 2019 +0100

    win-usb-dev: Use 'stable' libusb_device pointers in GUdevClient::udev_list
    
    When getting a new list of USB devices after a WM_DEVICECHANGE event,
    libusb_device which were already present before the event may be
    represented by a different instance than the one we got in the new list.
    
    Since other layers of spice-gtk may be using that older instance of
    libusb_device, this commit makes sure that we always keep the older
    instance in GUdevClient::udev_list.
    
    At the moment, this should not be making any difference, but will make
    things more consistent later on.
    
    Based on a patch from Yuri Benditovich.
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/src/win-usb-dev.c b/src/win-usb-dev.c
index 192ab17..84f35e3 100644
--- a/src/win-usb-dev.c
+++ b/src/win-usb-dev.c
@@ -423,6 +423,26 @@ static gint compare_libusb_devices(gconstpointer a, gconstpointer b)
     return (same_bus && same_addr && same_vid && same_pid) ? 0 : -1;
 }
 
+static void update_device_list(GUdevClient *self, GList *new_device_list)
+{
+    GList *dev;
+
+    for (dev = g_list_first(new_device_list); dev != NULL; dev = g_list_next(dev)) {
+        GList *found = g_list_find_custom(self->priv->udev_list, dev->data, compare_libusb_devices);
+        if (found != NULL) {
+            /* keep old existing libusb_device in the new list, when
+               usb-dev-manager will maintain its own list of libusb_device,
+               these lists will be completely consistent */
+            libusb_device *temp = found->data;
+            found->data = dev->data;
+            dev->data = temp;
+        }
+    }
+
+    g_udev_client_free_device_list(&self->priv->udev_list);
+    self->priv->udev_list = new_device_list;
+}
+
 static void notify_dev_state_change(GUdevClient *self,
                                     GList *old_list,
                                     GList *new_list,
@@ -469,8 +489,7 @@ static void handle_dev_change(GUdevClient *self)
     notify_dev_state_change(self, now_devs, priv->udev_list, TRUE);
 
     /* keep most recent info: free previous list, and keep current list */
-    g_udev_client_free_device_list(&priv->udev_list);
-    priv->udev_list = now_devs;
+    update_device_list(self, now_devs);
 }
 
 static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
commit f3f669be2e3386ccb43a5a7bc75bcd39d95fbe6c
Author: Yuri Benditovich <yuri.benditovich at daynix.com>
Date:   Tue Mar 19 07:56:05 2019 +0200

    win-usb-dev: maintain list of libusb devices
    
    Change internal device list to maintain libusb devices
    instead of GUdevDevice objects. Create temporary
    GUdevDevice object only for indication to usb-dev-manager.
    
    Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
    Acked-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/src/win-usb-dev.c b/src/win-usb-dev.c
index 7f0213d..192ab17 100644
--- a/src/win-usb-dev.c
+++ b/src/win-usb-dev.c
@@ -95,7 +95,7 @@ static void g_udev_device_print_list(GList *l, const gchar *msg);
 #else
 static void g_udev_device_print_list(GList *l, const gchar *msg) {}
 #endif
-static void g_udev_device_print(GUdevDevice *udev, const gchar *msg);
+static void g_udev_device_print(libusb_device *dev, const gchar *msg);
 
 static gboolean g_udev_skip_search(libusb_device *dev);
 
@@ -129,8 +129,6 @@ g_udev_client_list_devices(GUdevClient *self, GList **devs,
     gssize rc;
     libusb_device **lusb_list, **dev;
     GUdevClientPrivate *priv;
-    GUdevDeviceInfo *udevinfo;
-    GUdevDevice *udevice;
     ssize_t n;
 
     g_return_val_if_fail(G_UDEV_IS_CLIENT(self), -1);
@@ -155,10 +153,7 @@ g_udev_client_list_devices(GUdevClient *self, GList **devs,
         if (g_udev_skip_search(*dev)) {
             continue;
         }
-        udevinfo = g_new0(GUdevDeviceInfo, 1);
-        get_usb_dev_info(*dev, udevinfo);
-        udevice = g_udev_device_new(udevinfo);
-        *devs = g_list_prepend(*devs, udevice);
+        *devs = g_list_prepend(*devs, libusb_ref_device(*dev));
         n++;
     }
     libusb_free_device_list(lusb_list, 1);
@@ -166,11 +161,20 @@ g_udev_client_list_devices(GUdevClient *self, GList **devs,
     return n;
 }
 
+static void unreference_libusb_device(gpointer data)
+{
+    libusb_unref_device((libusb_device *)data);
+}
+
 static void g_udev_client_free_device_list(GList **devs)
 {
     g_return_if_fail(devs != NULL);
     if (*devs) {
-        g_list_free_full(*devs, g_object_unref);
+        /* the unreference_libusb_device method is required as
+         * libusb_unref_device calling convention differs from glib's
+         * see 558c967ec
+         */
+        g_list_free_full(*devs, unreference_libusb_device);
         *devs = NULL;
     }
 }
@@ -246,9 +250,22 @@ static void g_udev_client_initable_iface_init(GInitableIface *iface)
     iface->init = g_udev_client_initable_init;
 }
 
+static void g_udev_notify_device(GUdevClient *self, libusb_device *dev, gboolean add)
+{
+    GUdevDeviceInfo *udevinfo;
+    GUdevDevice *udevice;
+    udevinfo = g_new0(GUdevDeviceInfo, 1);
+    if (get_usb_dev_info(dev, udevinfo)) {
+        udevice = g_udev_device_new(udevinfo);
+        g_signal_emit(self, signals[UEVENT_SIGNAL], 0, udevice, add);
+    } else {
+        g_free(udevinfo);
+    }
+}
+
 static void report_one_device(gpointer data, gpointer self)
 {
-    g_signal_emit(self, signals[UEVENT_SIGNAL], 0, data, TRUE);
+    g_udev_notify_device(self, data, TRUE);
 }
 
 void g_udev_client_report_devices(GUdevClient *self)
@@ -388,18 +405,20 @@ static gboolean get_usb_dev_info(libusb_device *dev, GUdevDeviceInfo *udevinfo)
 }
 
 /* comparing bus:addr and vid:pid */
-static gint gudev_devices_differ(gconstpointer a, gconstpointer b)
+static gint compare_libusb_devices(gconstpointer a, gconstpointer b)
 {
-    GUdevDeviceInfo *ai, *bi;
+    libusb_device *a_dev = (libusb_device *)a;
+    libusb_device *b_dev = (libusb_device *)b;
+    struct libusb_device_descriptor a_desc, b_desc;
     gboolean same_bus, same_addr, same_vid, same_pid;
 
-    ai = G_UDEV_DEVICE(a)->priv->udevinfo;
-    bi = G_UDEV_DEVICE(b)->priv->udevinfo;
+    libusb_get_device_descriptor(a_dev, &a_desc);
+    libusb_get_device_descriptor(b_dev, &b_desc);
 
-    same_bus = (ai->bus == bi->bus);
-    same_addr = (ai->addr == bi->addr);
-    same_vid = (ai->vid == bi->vid);
-    same_pid = (ai->pid == bi->pid);
+    same_bus = (libusb_get_bus_number(a_dev) == libusb_get_bus_number(b_dev));
+    same_addr = (libusb_get_device_address(a_dev) == libusb_get_device_address(b_dev));
+    same_vid = (a_desc.idVendor == b_desc.idVendor);
+    same_pid = (a_desc.idProduct == b_desc.idProduct);
 
     return (same_bus && same_addr && same_vid && same_pid) ? 0 : -1;
 }
@@ -412,10 +431,10 @@ static void notify_dev_state_change(GUdevClient *self,
     GList *dev;
 
     for (dev = g_list_first(old_list); dev != NULL; dev = g_list_next(dev)) {
-        if (g_list_find_custom(new_list, dev->data, gudev_devices_differ) == NULL) {
-            /* Found a device that changed its state */
+        GList *found = g_list_find_custom(new_list, dev->data, compare_libusb_devices);
+        if (found == NULL) {
             g_udev_device_print(dev->data, add ? "add" : "remove");
-            g_signal_emit(self, signals[UEVENT_SIGNAL], 0, dev->data, add);
+            g_udev_notify_device(self, dev->data, add);
         }
     }
 }
@@ -534,18 +553,16 @@ static void g_udev_device_print_list(GList *l, const gchar *msg)
 }
 #endif
 
-static void g_udev_device_print(GUdevDevice *udev, const gchar *msg)
+static void g_udev_device_print(libusb_device *dev, const gchar *msg)
 {
-    GUdevDeviceInfo* udevinfo;
-
-    g_return_if_fail(G_UDEV_DEVICE(udev));
+    struct libusb_device_descriptor desc;
 
-    udevinfo = udev->priv->udevinfo;
-    g_return_if_fail(udevinfo != NULL);
+    libusb_get_device_descriptor(dev, &desc);
 
     SPICE_DEBUG("%s: %d.%d 0x%04x:0x%04x class %d", msg,
-                udevinfo->bus, udevinfo->addr,
-                udevinfo->vid, udevinfo->pid, udevinfo->class);
+                libusb_get_bus_number(dev),
+                libusb_get_device_address(dev),
+                desc.idVendor, desc.idProduct, desc.bDeviceClass);
 }
 
 static gboolean g_udev_skip_search(libusb_device *dev)
commit 5a125d2dc8e6e99934d8c7c85114efbb79cb9280
Author: Yuri Benditovich <yuri.benditovich at daynix.com>
Date:   Tue Mar 19 07:56:04 2019 +0200

    win-usb-dev: skip hub devices early in g_udev_client_list_devices
    
    When processing list of USB devices, avoid allocating memory
    for devices which later will be skipped. Use existing libusb
    struct first to check whether the device shall be excluded.
    
    Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
    Acked-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/src/win-usb-dev.c b/src/win-usb-dev.c
index bb11e8b..7f0213d 100644
--- a/src/win-usb-dev.c
+++ b/src/win-usb-dev.c
@@ -97,7 +97,7 @@ static void g_udev_device_print_list(GList *l, const gchar *msg) {}
 #endif
 static void g_udev_device_print(GUdevDevice *udev, const gchar *msg);
 
-static gboolean g_udev_skip_search(GUdevDevice *udev);
+static gboolean g_udev_skip_search(libusb_device *dev);
 
 GQuark g_udev_client_error_quark(void)
 {
@@ -152,13 +152,12 @@ g_udev_client_list_devices(GUdevClient *self, GList **devs,
 
     n = 0;
     for (dev = lusb_list; *dev; dev++) {
+        if (g_udev_skip_search(*dev)) {
+            continue;
+        }
         udevinfo = g_new0(GUdevDeviceInfo, 1);
         get_usb_dev_info(*dev, udevinfo);
         udevice = g_udev_device_new(udevinfo);
-        if (g_udev_skip_search(udevice)) {
-            g_object_unref(udevice);
-            continue;
-        }
         *devs = g_list_prepend(*devs, udevice);
         n++;
     }
@@ -549,19 +548,17 @@ static void g_udev_device_print(GUdevDevice *udev, const gchar *msg)
                 udevinfo->vid, udevinfo->pid, udevinfo->class);
 }
 
-static gboolean g_udev_skip_search(GUdevDevice *udev)
+static gboolean g_udev_skip_search(libusb_device *dev)
 {
-    GUdevDeviceInfo* udevinfo;
     gboolean skip;
+    uint8_t addr = libusb_get_device_address(dev);
+    struct libusb_device_descriptor desc;
 
-    g_return_val_if_fail(G_UDEV_DEVICE(udev), FALSE);
-
-    udevinfo = udev->priv->udevinfo;
-    g_return_val_if_fail(udevinfo != NULL, FALSE);
+    libusb_get_device_descriptor(dev, &desc);
 
-    skip = ((udevinfo->addr == 0xff) ||  /* root hub (HCD) */
-            (udevinfo->addr == 1) || /* root hub addr */
-            (udevinfo->class == LIBUSB_CLASS_HUB) || /* hub*/
-            (udevinfo->addr == 0)); /* bad address */
+    skip = ((addr == 0xff) ||  /* root hub (HCD) */
+            (addr == 1) || /* root hub addr */
+            (desc.bDeviceClass == LIBUSB_CLASS_HUB) || /* hub*/
+            (addr == 0)); /* bad address */
     return skip;
 }
commit ead0a11b21b20cc62318ae80d6fc796002b29f56
Author: Yuri Benditovich <yuri.benditovich at daynix.com>
Date:   Tue Mar 19 07:56:03 2019 +0200

    usb-redir: change signal prototype of win-usb-dev
    
    Changing signal definition from (boxed-boxed) to (pointer,int).
    There is no need for additional referencing of GUdevDevice
    object before signal callback. Second parameter (action) is
    FALSE for device removal and TRUE for device addition.
    
    Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
    Acked-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/src/spice-marshal.txt b/src/spice-marshal.txt
index cf35790..46be405 100644
--- a/src/spice-marshal.txt
+++ b/src/spice-marshal.txt
@@ -5,6 +5,7 @@ VOID:UINT,UINT,UINT,UINT
 VOID:INT,INT,INT,INT,POINTER
 VOID:INT,INT,INT,INT,INT,POINTER
 VOID:POINTER,INT
+VOID:POINTER,BOOLEAN
 BOOLEAN:POINTER,UINT
 BOOLEAN:UINT
 VOID:UINT,POINTER,UINT
diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c
index 6cc0b96..48952de 100644
--- a/src/usb-device-manager.c
+++ b/src/usb-device-manager.c
@@ -153,8 +153,8 @@ static void channel_event(SpiceChannel *channel, SpiceChannelEvent event,
                           gpointer user_data);
 #ifdef G_OS_WIN32
 static void spice_usb_device_manager_uevent_cb(GUdevClient     *client,
-                                               const gchar     *action,
                                                GUdevDevice     *udevice,
+                                               gboolean         add,
                                                gpointer         user_data);
 static void spice_usb_device_manager_add_udev(SpiceUsbDeviceManager  *self,
                                               GUdevDevice            *udev);
@@ -1070,15 +1070,15 @@ static void spice_usb_device_manager_remove_udev(SpiceUsbDeviceManager  *self,
 }
 
 static void spice_usb_device_manager_uevent_cb(GUdevClient     *client,
-                                               const gchar     *action,
                                                GUdevDevice     *udevice,
+                                               gboolean         add,
                                                gpointer         user_data)
 {
     SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(user_data);
 
-    if (g_str_equal(action, "add"))
+    if (add)
         spice_usb_device_manager_add_udev(self, udevice);
-    else if (g_str_equal (action, "remove"))
+    else
         spice_usb_device_manager_remove_udev(self, udevice);
 }
 #else
diff --git a/src/win-usb-dev.c b/src/win-usb-dev.c
index 50db4e5..bb11e8b 100644
--- a/src/win-usb-dev.c
+++ b/src/win-usb-dev.c
@@ -249,7 +249,7 @@ static void g_udev_client_initable_iface_init(GInitableIface *iface)
 
 static void report_one_device(gpointer data, gpointer self)
 {
-    g_signal_emit(self, signals[UEVENT_SIGNAL], 0, "add", data);
+    g_signal_emit(self, signals[UEVENT_SIGNAL], 0, data, TRUE);
 }
 
 void g_udev_client_report_devices(GUdevClient *self)
@@ -342,11 +342,11 @@ static void g_udev_client_class_init(GUdevClientClass *klass)
                      G_SIGNAL_RUN_FIRST,
                      G_STRUCT_OFFSET(GUdevClientClass, uevent),
                      NULL, NULL,
-                     g_cclosure_user_marshal_VOID__BOXED_BOXED,
+                     g_cclosure_user_marshal_VOID__POINTER_BOOLEAN,
                      G_TYPE_NONE,
                      2,
-                     G_TYPE_STRING,
-                     G_UDEV_TYPE_DEVICE);
+                     G_TYPE_POINTER,
+                     G_TYPE_BOOLEAN);
 
     /**
     * GUdevClient::redirecting:
@@ -408,15 +408,15 @@ static gint gudev_devices_differ(gconstpointer a, gconstpointer b)
 static void notify_dev_state_change(GUdevClient *self,
                                     GList *old_list,
                                     GList *new_list,
-                                    const gchar *action)
+                                    gboolean add)
 {
     GList *dev;
 
     for (dev = g_list_first(old_list); dev != NULL; dev = g_list_next(dev)) {
         if (g_list_find_custom(new_list, dev->data, gudev_devices_differ) == NULL) {
             /* Found a device that changed its state */
-            g_udev_device_print(dev->data, action);
-            g_signal_emit(self, signals[UEVENT_SIGNAL], 0, action, dev->data);
+            g_udev_device_print(dev->data, add ? "add" : "remove");
+            g_signal_emit(self, signals[UEVENT_SIGNAL], 0, dev->data, add);
         }
     }
 }
@@ -445,10 +445,10 @@ static void handle_dev_change(GUdevClient *self)
     g_udev_device_print_list(priv->udev_list, "handle_dev_change: previous list:");
 
     /* Unregister devices that are not present anymore */
-    notify_dev_state_change(self, priv->udev_list, now_devs, "remove");
+    notify_dev_state_change(self, priv->udev_list, now_devs, FALSE);
 
     /* Register newly inserted devices */
-    notify_dev_state_change(self, now_devs, priv->udev_list, "add");
+    notify_dev_state_change(self, now_devs, priv->udev_list, TRUE);
 
     /* keep most recent info: free previous list, and keep current list */
     g_udev_client_free_device_list(&priv->udev_list);
diff --git a/src/win-usb-dev.h b/src/win-usb-dev.h
index bca8285..64ebd67 100644
--- a/src/win-usb-dev.h
+++ b/src/win-usb-dev.h
@@ -75,7 +75,7 @@ struct _GUdevClientClass
     GObjectClass parent_class;
 
     /* signals */
-    void (*uevent)(GUdevClient *client, const gchar *action, GUdevDevice  *device);
+    void (*uevent)(GUdevClient *client, GUdevDevice  *device, gboolean add);
 };
 
 GType g_udev_client_get_type(void) G_GNUC_CONST;
commit 50c3a11f3655cb688a8c6c4e5870ffda963a4982
Author: Yuri Benditovich <yuri.benditovich at daynix.com>
Date:   Tue Mar 19 07:56:02 2019 +0200

    usb-redir: remove SpiceUsbDeviceManager::coldplug_list
    
    Discard the optimization of initial device enumeration.
    Just after connection to the 'uevent' signal, request to report all the
    devices one by one as if they are inserted.
    Further commits will remove device enumeration in usb-dev-manager
    completely.
    
    Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
    Acked-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c
index feba61b..6cc0b96 100644
--- a/src/usb-device-manager.c
+++ b/src/usb-device-manager.c
@@ -104,7 +104,6 @@ struct _SpiceUsbDeviceManagerPrivate {
     int redirect_on_connect_rules_count;
 #ifdef G_OS_WIN32
     GUdevClient *udev;
-    libusb_device **coldplug_list; /* Avoid needless reprobing during init */
 #else
     gboolean redirecting; /* Handled by GUdevClient in the gudev case */
     libusb_hotplug_callback_handle hp_handle;
@@ -307,15 +306,7 @@ static gboolean spice_usb_device_manager_initable_init(GInitable  *initable,
     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");
-    for (it = g_list_first(list); it; it = g_list_next(it)) {
-        spice_usb_device_manager_add_udev(self, it->data);
-        g_object_unref(it->data);
-    }
-    g_list_free(list);
-    libusb_free_device_list(priv->coldplug_list, 1);
-    priv->coldplug_list = NULL;
+    g_udev_client_report_devices(priv->udev);
 #else
     rc = libusb_hotplug_register_callback(priv->context,
         LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
@@ -1049,10 +1040,7 @@ static void spice_usb_device_manager_add_udev(SpiceUsbDeviceManager  *self,
         return;
     }
 
-    if (priv->coldplug_list)
-        dev_list = priv->coldplug_list;
-    else
-        libusb_get_device_list(priv->context, &dev_list);
+    libusb_get_device_list(priv->context, &dev_list);
 
     for (i = 0; dev_list && dev_list[i]; i++) {
         if (spice_usb_device_manager_libdev_match(self, dev_list[i], bus, address)) {
@@ -1067,8 +1055,7 @@ static void spice_usb_device_manager_add_udev(SpiceUsbDeviceManager  *self,
         g_warning("Could not find USB device to add " DEV_ID_FMT,
                   (guint) bus, (guint) address);
 
-    if (!priv->coldplug_list)
-        libusb_free_device_list(dev_list, 1);
+    libusb_free_device_list(dev_list, 1);
 }
 
 static void spice_usb_device_manager_remove_udev(SpiceUsbDeviceManager  *self,
diff --git a/src/win-usb-dev.c b/src/win-usb-dev.c
index 6273cbe..50db4e5 100644
--- a/src/win-usb-dev.c
+++ b/src/win-usb-dev.c
@@ -247,11 +247,14 @@ static void g_udev_client_initable_iface_init(GInitableIface *iface)
     iface->init = g_udev_client_initable_init;
 }
 
-GList *g_udev_client_query_by_subsystem(GUdevClient *self, const gchar *subsystem)
+static void report_one_device(gpointer data, gpointer self)
 {
-    GList *l = g_list_copy(self->priv->udev_list);
-    g_list_foreach(l, (GFunc)g_object_ref, NULL);
-    return l;
+    g_signal_emit(self, signals[UEVENT_SIGNAL], 0, "add", data);
+}
+
+void g_udev_client_report_devices(GUdevClient *self)
+{
+    g_list_foreach(self->priv->udev_list, report_one_device, self);
 }
 
 static void g_udev_client_init(GUdevClient *self)
diff --git a/src/win-usb-dev.h b/src/win-usb-dev.h
index b7b7eda..bca8285 100644
--- a/src/win-usb-dev.h
+++ b/src/win-usb-dev.h
@@ -81,7 +81,7 @@ struct _GUdevClientClass
 GType g_udev_client_get_type(void) G_GNUC_CONST;
 GUdevClient *g_udev_client_new(void);
 libusb_context *g_udev_client_get_context(GUdevClient *client);
-GList *g_udev_client_query_by_subsystem(GUdevClient *client, const gchar *subsystem);
+void g_udev_client_report_devices(GUdevClient *client);
 
 GType g_udev_device_get_type(void) G_GNUC_CONST;
 const gchar *g_udev_device_get_property(GUdevDevice *udev, const gchar *property);
commit 9340d7649dfa2cb02d9c411f8abcc744973cfe9f
Author: Yuri Benditovich <yuri.benditovich at daynix.com>
Date:   Tue Mar 19 07:56:01 2019 +0200

    win-usb-dev: remove unused procedure
    
    Remove unused g_udev_device_get_sysfs_attr.
    
    Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
    Acked-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/src/win-usb-dev.c b/src/win-usb-dev.c
index 52e61a8..6273cbe 100644
--- a/src/win-usb-dev.c
+++ b/src/win-usb-dev.c
@@ -521,24 +521,6 @@ const gchar *g_udev_device_get_property(GUdevDevice *udev, const gchar *property
     return NULL;
 }
 
-const gchar *g_udev_device_get_sysfs_attr(GUdevDevice *udev, const gchar *attr)
-{
-    GUdevDeviceInfo* udevinfo;
-
-    g_return_val_if_fail(G_UDEV_DEVICE(udev), NULL);
-    g_return_val_if_fail(attr != NULL, NULL);
-
-    udevinfo = udev->priv->udevinfo;
-    g_return_val_if_fail(udevinfo != NULL, NULL);
-
-
-    if (g_strcmp0(attr, "bDeviceClass") == 0) {
-        return udevinfo->sclass;
-    }
-    g_warn_if_reached();
-    return NULL;
-}
-
 #ifdef DEBUG_GUDEV_DEVICE_LISTS
 static void g_udev_device_print_list(GList *l, const gchar *msg)
 {
diff --git a/src/win-usb-dev.h b/src/win-usb-dev.h
index f3c7466..b7b7eda 100644
--- a/src/win-usb-dev.h
+++ b/src/win-usb-dev.h
@@ -85,7 +85,6 @@ GList *g_udev_client_query_by_subsystem(GUdevClient *client, const gchar *subsys
 
 GType g_udev_device_get_type(void) G_GNUC_CONST;
 const gchar *g_udev_device_get_property(GUdevDevice *udev, const gchar *property);
-const gchar *g_udev_device_get_sysfs_attr(GUdevDevice *udev, const gchar *attr);
 
 GQuark g_udev_client_error_quark(void);
 #define G_UDEV_CLIENT_ERROR g_udev_client_error_quark()
commit ece69367d3cc318e8f424a1a56873d6ff49bf1c5
Author: Yuri Benditovich <yuri.benditovich at daynix.com>
Date:   Tue Mar 19 07:56:00 2019 +0200

    win-usb-dev: strict comparison of USB devices
    
    If when calling handle_dev_change, the new device has the same
    bus:address as an existing device cached in GUdevClient::udev_list, then
    an "uevent" signal will not be emitted to notify about the new device.
    For example, when due to some reason the 'redirecting' property is set
    for a long time and during this time one device is unplugged and then
    replugged.
    This commit makes the device comparison more strict by checking not only
    bus:addr, but also vid:pid.
    
    Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
    Acked-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/src/win-usb-dev.c b/src/win-usb-dev.c
index b08bf02..52e61a8 100644
--- a/src/win-usb-dev.c
+++ b/src/win-usb-dev.c
@@ -385,20 +385,21 @@ static gboolean get_usb_dev_info(libusb_device *dev, GUdevDeviceInfo *udevinfo)
     return TRUE;
 }
 
-/* Only bus:addr are compared */
+/* comparing bus:addr and vid:pid */
 static gint gudev_devices_differ(gconstpointer a, gconstpointer b)
 {
     GUdevDeviceInfo *ai, *bi;
-    gboolean same_bus;
-    gboolean same_addr;
+    gboolean same_bus, same_addr, same_vid, same_pid;
 
     ai = G_UDEV_DEVICE(a)->priv->udevinfo;
     bi = G_UDEV_DEVICE(b)->priv->udevinfo;
 
     same_bus = (ai->bus == bi->bus);
     same_addr = (ai->addr == bi->addr);
+    same_vid = (ai->vid == bi->vid);
+    same_pid = (ai->pid == bi->pid);
 
-    return (same_bus && same_addr) ? 0 : -1;
+    return (same_bus && same_addr && same_vid && same_pid) ? 0 : -1;
 }
 
 static void notify_dev_state_change(GUdevClient *self,
commit eb9f067a163f60edc2bc5d4dc11cbbb30c215136
Author: Yuri Benditovich <yuri.benditovich at daynix.com>
Date:   Tue Mar 19 07:55:59 2019 +0200

    usb-redir: do not add device if one with the same bus:addr exists
    
    In initial device enumeration, hotplug notification can be
    called twice with the same libusb device. For details, see
    http://libusb.sourceforge.net/api-1.0/group__libusb__hotplug.html#ga00e0c69ddf1fb1b6774dc918192e8dc7
    This commit filters out devices that are already present in the list.
    It also removes the identical call in spice_usb_device_manager_add_udev,
    which adds devices under Windows.
    
    Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
    Acked-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c
index debba4d..feba61b 100644
--- a/src/usb-device-manager.c
+++ b/src/usb-device-manager.c
@@ -962,6 +962,17 @@ static void spice_usb_device_manager_add_dev(SpiceUsbDeviceManager  *self,
     if (desc.bDeviceClass == LIBUSB_CLASS_HUB)
         return;
 
+    if (spice_usb_device_manager_find_device(self,
+                                             libusb_get_bus_number(libdev),
+                                             libusb_get_device_address(libdev))) {
+        SPICE_DEBUG("device not added %d:%d %04x:%04x",
+                    libusb_get_bus_number(libdev),
+                    libusb_get_device_address(libdev),
+                    desc.idVendor,
+                    desc.idProduct);
+        return;
+    }
+
     device = (SpiceUsbDevice*)spice_usb_device_new(libdev);
     if (!device)
         return;
@@ -1025,7 +1036,6 @@ static void spice_usb_device_manager_add_udev(SpiceUsbDeviceManager  *self,
 {
     SpiceUsbDeviceManagerPrivate *priv = self->priv;
     libusb_device *libdev = NULL, **dev_list = NULL;
-    SpiceUsbDevice *device;
     const gchar *devtype;
     int i, bus, address;
 
@@ -1039,16 +1049,6 @@ static void spice_usb_device_manager_add_udev(SpiceUsbDeviceManager  *self,
         return;
     }
 
-    device = spice_usb_device_manager_find_device(self, bus, address);
-    if (device) {
-        SPICE_DEBUG("USB device 0x%04x:0x%04x at %d.%d already exists, ignored",
-                    spice_usb_device_get_vid(device),
-                    spice_usb_device_get_pid(device),
-                    spice_usb_device_get_busnum(device),
-                    spice_usb_device_get_devaddr(device));
-        return;
-    }
-
     if (priv->coldplug_list)
         dev_list = priv->coldplug_list;
     else
commit a268ebc55af04cacbd4c021741d2d7f238ebbbac
Author: Yuri Benditovich <yuri.benditovich at daynix.com>
Date:   Tue Mar 19 07:55:58 2019 +0200

    usb-redir: reuse libusb context under Windows
    
    Do not create our own libusb context in usb-device-manager.
    Reuse existing context created by win-usb-dev instead,
    this will later allow usb-device-manager to use libusb
    devices enumerated in win-usb-dev.
    
    Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
    Acked-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c
index 6435be8..debba4d 100644
--- a/src/usb-device-manager.c
+++ b/src/usb-device-manager.c
@@ -282,8 +282,9 @@ static gboolean spice_usb_device_manager_initable_init(GInitable  *initable,
     SpiceUsbDeviceManagerPrivate *priv = self->priv;
     GList *list;
     GList *it;
-    int rc;
 
+#ifndef G_OS_WIN32
+    int rc;
     /* Initialize libusb */
     rc = libusb_init(&priv->context);
     if (rc < 0) {
@@ -293,11 +294,6 @@ static gboolean spice_usb_device_manager_initable_init(GInitable  *initable,
                     "Error initializing USB support: %s [%i]", desc, rc);
         return FALSE;
     }
-
-#ifdef G_OS_WIN32
-#if LIBUSB_API_VERSION >= 0x01000106
-    libusb_set_option(priv->context, LIBUSB_OPTION_USE_USBDK);
-#endif
 #endif
 
     /* Start listening for usb devices plug / unplug */
@@ -307,6 +303,7 @@ static gboolean spice_usb_device_manager_initable_init(GInitable  *initable,
         g_warning("Error initializing GUdevClient");
         return FALSE;
     }
+    priv->context = g_udev_client_get_context(priv->udev);
     g_signal_connect(G_OBJECT(priv->udev), "uevent",
                      G_CALLBACK(spice_usb_device_manager_uevent_cb), self);
     /* Do coldplug (detection of already connected devices) */
@@ -402,8 +399,10 @@ static void spice_usb_device_manager_finalize(GObject *gobject)
     g_clear_object(&priv->udev);
 #endif
     g_return_if_fail(priv->event_thread == NULL);
+#ifndef G_OS_WIN32
     if (priv->context)
         libusb_exit(priv->context);
+#endif
     free(priv->auto_conn_filter_rules);
     free(priv->redirect_on_connect_rules);
 #ifdef G_OS_WIN32
diff --git a/src/win-usb-dev.c b/src/win-usb-dev.c
index d3ff55a..b08bf02 100644
--- a/src/win-usb-dev.c
+++ b/src/win-usb-dev.c
@@ -113,6 +113,10 @@ GUdevClient *g_udev_client_new(void)
     return singleton;
 }
 
+libusb_context *g_udev_client_get_context(GUdevClient *client)
+{
+    return client->priv->ctx;
+}
 
 /*
  * devs [in,out] an empty devs list in, full devs list out
diff --git a/src/win-usb-dev.h b/src/win-usb-dev.h
index 0f34a01..f3c7466 100644
--- a/src/win-usb-dev.h
+++ b/src/win-usb-dev.h
@@ -80,6 +80,7 @@ struct _GUdevClientClass
 
 GType g_udev_client_get_type(void) G_GNUC_CONST;
 GUdevClient *g_udev_client_new(void);
+libusb_context *g_udev_client_get_context(GUdevClient *client);
 GList *g_udev_client_query_by_subsystem(GUdevClient *client, const gchar *subsystem);
 
 GType g_udev_device_get_type(void) G_GNUC_CONST;
commit 9738c58e9d867db5d8a8c6d030ba2f77d0b48959
Author: Yuri Benditovich <yuri.benditovich at daynix.com>
Date:   Tue Mar 19 07:55:57 2019 +0200

    usb-redir: remove unused 'subsystem' parameter
    
    Removing unused parameter from GUdevClient constructor.
    This code is used only in Windows builds.
    
    Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
    Acked-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c
index 6a36cfa..6435be8 100644
--- a/src/usb-device-manager.c
+++ b/src/usb-device-manager.c
@@ -283,9 +283,6 @@ static gboolean spice_usb_device_manager_initable_init(GInitable  *initable,
     GList *list;
     GList *it;
     int rc;
-#ifdef G_OS_WIN32
-    const gchar *const subsystems[] = {"usb", NULL};
-#endif
 
     /* Initialize libusb */
     rc = libusb_init(&priv->context);
@@ -305,7 +302,7 @@ static gboolean spice_usb_device_manager_initable_init(GInitable  *initable,
 
     /* Start listening for usb devices plug / unplug */
 #ifdef G_OS_WIN32
-    priv->udev = g_udev_client_new(subsystems);
+    priv->udev = g_udev_client_new();
     if (priv->udev == NULL) {
         g_warning("Error initializing GUdevClient");
         return FALSE;
diff --git a/src/win-usb-dev.c b/src/win-usb-dev.c
index 964719c..d3ff55a 100644
--- a/src/win-usb-dev.c
+++ b/src/win-usb-dev.c
@@ -104,7 +104,7 @@ GQuark g_udev_client_error_quark(void)
     return g_quark_from_static_string("win-gudev-client-error-quark");
 }
 
-GUdevClient *g_udev_client_new(const gchar* const *subsystems)
+GUdevClient *g_udev_client_new(void)
 {
     if (singleton != NULL)
         return g_object_ref(singleton);
diff --git a/src/win-usb-dev.h b/src/win-usb-dev.h
index 7f40197..0f34a01 100644
--- a/src/win-usb-dev.h
+++ b/src/win-usb-dev.h
@@ -79,7 +79,7 @@ struct _GUdevClientClass
 };
 
 GType g_udev_client_get_type(void) G_GNUC_CONST;
-GUdevClient *g_udev_client_new(const gchar* const *subsystems);
+GUdevClient *g_udev_client_new(void);
 GList *g_udev_client_query_by_subsystem(GUdevClient *client, const gchar *subsystem);
 
 GType g_udev_device_get_type(void) G_GNUC_CONST;
commit b0869ece2571dadd75d07444ae5eeffe7da7193e
Author: Yuri Benditovich <yuri.benditovich at daynix.com>
Date:   Tue Mar 19 07:55:56 2019 +0200

    usb-redir: replace USE_GUDEV with G_OS_WIN32
    
    Replacing USE_GUDEV with G_OS_WIN32 anywhere. GUDEV simulation
    is used only in Windows build.
    
    Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
    Acked-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c
index 2578350..6a36cfa 100644
--- a/src/usb-device-manager.c
+++ b/src/usb-device-manager.c
@@ -29,11 +29,7 @@
 
 #ifdef G_OS_WIN32
 #include "usbdk_api.h"
-#endif
-
-#if defined(G_OS_WIN32)
 #include "win-usb-dev.h"
-#define USE_GUDEV /* win-usb-dev.h provides a fake gudev interface */
 #endif
 
 #include "channel-usbredir-priv.h"
@@ -106,7 +102,7 @@ struct _SpiceUsbDeviceManagerPrivate {
     struct usbredirfilter_rule *redirect_on_connect_rules;
     int auto_conn_filter_rules_count;
     int redirect_on_connect_rules_count;
-#ifdef USE_GUDEV
+#ifdef G_OS_WIN32
     GUdevClient *udev;
     libusb_device **coldplug_list; /* Avoid needless reprobing during init */
 #else
@@ -156,7 +152,7 @@ static void channel_destroy(SpiceSession *session, SpiceChannel *channel,
                             gpointer user_data);
 static void channel_event(SpiceChannel *channel, SpiceChannelEvent event,
                           gpointer user_data);
-#ifdef USE_GUDEV
+#ifdef G_OS_WIN32
 static void spice_usb_device_manager_uevent_cb(GUdevClient     *client,
                                                const gchar     *action,
                                                GUdevDevice     *udevice,
@@ -210,7 +206,7 @@ G_DEFINE_BOXED_TYPE(SpiceUsbDevice, spice_usb_device,
 static void
 _set_redirecting(SpiceUsbDeviceManager *self, gboolean is_redirecting)
 {
-#ifdef USE_GUDEV
+#ifdef G_OS_WIN32
     g_object_set(self->priv->udev, "redirecting", is_redirecting, NULL);
 #else
     self->priv->redirecting = is_redirecting;
@@ -235,7 +231,7 @@ gboolean spice_usb_device_manager_is_redirecting(SpiceUsbDeviceManager *self)
 {
 #ifdef USE_USBREDIR
 
-#ifdef USE_GUDEV
+#ifdef G_OS_WIN32
     gboolean redirecting;
     g_object_get(self->priv->udev, "redirecting", &redirecting, NULL);
     return redirecting;
@@ -287,7 +283,7 @@ static gboolean spice_usb_device_manager_initable_init(GInitable  *initable,
     GList *list;
     GList *it;
     int rc;
-#ifdef USE_GUDEV
+#ifdef G_OS_WIN32
     const gchar *const subsystems[] = {"usb", NULL};
 #endif
 
@@ -308,7 +304,7 @@ static gboolean spice_usb_device_manager_initable_init(GInitable  *initable,
 #endif
 
     /* Start listening for usb devices plug / unplug */
-#ifdef USE_GUDEV
+#ifdef G_OS_WIN32
     priv->udev = g_udev_client_new(subsystems);
     if (priv->udev == NULL) {
         g_warning("Error initializing GUdevClient");
@@ -366,7 +362,7 @@ static void spice_usb_device_manager_dispose(GObject *gobject)
     SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(gobject);
     SpiceUsbDeviceManagerPrivate *priv = self->priv;
 
-#ifndef USE_GUDEV
+#ifndef G_OS_WIN32
     if (priv->hp_handle) {
         spice_usb_device_manager_stop_event_listening(self);
         if (g_atomic_int_get(&priv->event_thread_run)) {
@@ -405,7 +401,7 @@ static void spice_usb_device_manager_finalize(GObject *gobject)
         g_ptr_array_unref(priv->devices);
 
 #ifdef USE_USBREDIR
-#ifdef USE_GUDEV
+#ifdef G_OS_WIN32
     g_clear_object(&priv->udev);
 #endif
     g_return_if_fail(priv->event_thread == NULL);
@@ -737,7 +733,7 @@ static void spice_usb_device_manager_class_init(SpiceUsbDeviceManagerClass *klas
 /* ------------------------------------------------------------------ */
 /* gudev / libusb Helper functions                                    */
 
-#ifdef USE_GUDEV
+#ifdef G_OS_WIN32
 static gboolean spice_usb_device_manager_get_udev_bus_n_address(
     SpiceUsbDeviceManager *manager, GUdevDevice *udev,
     int *bus, int *address)
@@ -927,7 +923,7 @@ spice_usb_device_manager_device_match(SpiceUsbDeviceManager *self, SpiceUsbDevic
             spice_usb_device_get_devaddr(device) == address);
 }
 
-#ifdef USE_GUDEV
+#ifdef G_OS_WIN32
 static gboolean
 spice_usb_device_manager_libdev_match(SpiceUsbDeviceManager *self, libusb_device *libdev,
                                       const int bus, const int address)
@@ -1027,7 +1023,7 @@ static void spice_usb_device_manager_remove_dev(SpiceUsbDeviceManager *self,
     spice_usb_device_unref(device);
 }
 
-#ifdef USE_GUDEV
+#ifdef G_OS_WIN32
 static void spice_usb_device_manager_add_udev(SpiceUsbDeviceManager  *self,
                                               GUdevDevice            *udev)
 {


More information about the Spice-commits mailing list