[Spice-commits] 4 commits - meson.build src/channel-usbredir.c src/meson.build src/usb-backend.c src/usb-backend.h src/usb-device-manager.c src/usb-device-manager-priv.h src/win-usb-dev.c src/win-usb-dev.h

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Jul 24 08:34:13 UTC 2019


 meson.build                   |    2 
 src/channel-usbredir.c        |   28 --
 src/meson.build               |    4 
 src/usb-backend.c             |  309 ++++++++++++++++++++++-------
 src/usb-backend.h             |   13 -
 src/usb-device-manager-priv.h |    6 
 src/usb-device-manager.c      |  139 -------------
 src/win-usb-dev.c             |  436 ------------------------------------------
 src/win-usb-dev.h             |   84 --------
 9 files changed, 245 insertions(+), 776 deletions(-)

New commits:
commit c8a166a549374027f629e1442fe0018b7f65abf5
Author: Yuri Benditovich <yuri.benditovich at daynix.com>
Date:   Tue Jul 23 18:13:49 2019 +0300

    usb-redir: use g_thread_try_new instead of g_thread_new
    
    Newer API (glib 2.32) is safe, in case of error it does not
    abort the process and returns error information.
    
    Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/src/usb-backend.c b/src/usb-backend.c
index 7c9b544..9ac8595 100644
--- a/src/usb-backend.c
+++ b/src/usb-backend.c
@@ -473,9 +473,14 @@ gboolean spice_usb_backend_register_hotplug(SpiceUsbBackend *be,
     }
 
     g_atomic_int_set(&be->event_thread_run, TRUE);
-    be->event_thread = g_thread_new("usb_ev_thread",
-                                    handle_libusb_events,
-                                    be);
+    be->event_thread = g_thread_try_new("usb_ev_thread",
+                                        handle_libusb_events,
+                                        be, error);
+    if (!be->event_thread) {
+        g_warning("Error starting event thread");
+        spice_usb_backend_deregister_hotplug(be);
+        return FALSE;
+    }
     return TRUE;
 }
 
commit 89a9d3915519ebd9681e01b33558f8d604842ce6
Author: Yuri Benditovich <yuri.benditovich at daynix.com>
Date:   Tue Jul 23 18:13:48 2019 +0300

    usb-redir: move USB events handling to USB backend
    
    Before this commit:
    usb-device-manager starts thread for handling libusb events:
    on Linux - from the beginning (as it is needed for hotplug
    callbacks), on Windows - starts it on first redirection and
    stops when there are no redirections (it can't keep the thread
    when there are no redirections as with libusb < 1.0.21 it will
    not be able to force the thread to exit if there are no events).
    
    Current commit moves the event thread and handling events
    completely to usb backend; usb-device-manager and other
    are not aware of libusb and should not assume what it needs
    to work. We start the event thread from the beginning on both
    Linux and Windows. On Linux it works only for hotplug callbacks,
    on Windows - just waits until device redirection starts.
    On dispose of usb-device-manager (when hotplug callbacks are
    deregistered), we interrupt the thread once to stop it.
    
    This removes many lines of code and also removes all the
    differences between Linux and Windows in usb-device-manager.
    
    Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/src/channel-usbredir.c b/src/channel-usbredir.c
index 04acf0b..8d4cd66 100644
--- a/src/channel-usbredir.c
+++ b/src/channel-usbredir.c
@@ -72,7 +72,6 @@ struct _SpiceUsbredirChannelPrivate {
     SpiceUsbAclHelper *acl_helper;
 #endif
     GMutex device_connect_mutex;
-    SpiceUsbDeviceManager *usb_device_manager;
 };
 
 static void channel_set_handlers(SpiceChannelClass *klass);
@@ -169,11 +168,6 @@ static void spice_usbredir_channel_dispose(GObject *obj)
     SpiceUsbredirChannel *channel = SPICE_USBREDIR_CHANNEL(obj);
 
     spice_usbredir_channel_disconnect_device(channel);
-    /* This should have been set to NULL during device disconnection,
-     * but better not to leak it if this does not happen for some reason
-     */
-    g_warn_if_fail(channel->priv->usb_device_manager == NULL);
-    g_clear_object(&channel->priv->usb_device_manager);
 
     /* Chain up to the parent class */
     if (G_OBJECT_CLASS(spice_usbredir_channel_parent_class)->dispose)
@@ -248,8 +242,6 @@ static gboolean spice_usbredir_channel_open_device(
     SpiceUsbredirChannel *channel, GError **err)
 {
     SpiceUsbredirChannelPrivate *priv = channel->priv;
-    SpiceSession *session;
-    SpiceUsbDeviceManager *manager;
 
     g_return_val_if_fail(priv->state == STATE_DISCONNECTED
 #ifdef USE_POLKIT
@@ -265,16 +257,6 @@ static gboolean spice_usbredir_channel_open_device(
         return FALSE;
     }
 
-    session = spice_channel_get_session(SPICE_CHANNEL(channel));
-    manager = spice_usb_device_manager_get(session, NULL);
-    g_return_val_if_fail(manager != NULL, FALSE);
-
-    priv->usb_device_manager = g_object_ref(manager);
-    if (!spice_usb_device_manager_start_event_listening(priv->usb_device_manager, err)) {
-        spice_usb_backend_channel_detach(priv->host);
-        return FALSE;
-    }
-
     priv->state = STATE_CONNECTED;
 
     return TRUE;
@@ -445,16 +427,6 @@ void spice_usbredir_channel_disconnect_device(SpiceUsbredirChannel *channel)
         break;
 #endif
     case STATE_CONNECTED:
-        /*
-         * This sets the usb event thread run condition to FALSE, therefor
-         * it must be done before usbredirhost_set_device NULL, as
-         * usbredirhost_set_device NULL will interrupt the
-         * libusb_handle_events call in the thread.
-         */
-        g_warn_if_fail(priv->usb_device_manager != NULL);
-        spice_usb_device_manager_stop_event_listening(priv->usb_device_manager);
-        g_clear_object(&priv->usb_device_manager);
-
         /* This also closes the libusb handle we passed from open_device */
         spice_usb_backend_channel_detach(priv->host);
         g_clear_pointer(&priv->device, spice_usb_backend_device_unref);
diff --git a/src/usb-backend.c b/src/usb-backend.c
index 2a2f9fa..7c9b544 100644
--- a/src/usb-backend.c
+++ b/src/usb-backend.c
@@ -58,6 +58,9 @@ struct _SpiceUsbBackend
     usb_hot_plug_callback hotplug_callback;
     void *hotplug_user_data;
     libusb_hotplug_callback_handle hotplug_handle;
+    GThread *event_thread;
+    gint event_thread_run;
+
 #ifdef G_OS_WIN32
     HANDLE hWnd;
     libusb_device **libusb_device_list;
@@ -410,28 +413,25 @@ SpiceUsbBackend *spice_usb_backend_new(GError **error)
     return be;
 }
 
-gboolean spice_usb_backend_handle_events(SpiceUsbBackend *be)
+static gpointer handle_libusb_events(gpointer user_data)
 {
+    SpiceUsbBackend *be = user_data;
     SPICE_DEBUG("%s >>", __FUNCTION__);
-    gboolean ok = FALSE;
-    if (be->libusb_context) {
-        int res = libusb_handle_events(be->libusb_context);
-        ok = res == 0;
+    int res = 0;
+    const char *desc = "";
+    while (g_atomic_int_get(&be->event_thread_run)) {
+        res = libusb_handle_events(be->libusb_context);
         if (res && res != LIBUSB_ERROR_INTERRUPTED) {
-            const char *desc = libusb_strerror(res);
+            desc = libusb_strerror(res);
             g_warning("Error handling USB events: %s [%i]", desc, res);
-            ok = FALSE;
+            break;
         }
     }
-    SPICE_DEBUG("%s << %d", __FUNCTION__, ok);
-    return ok;
-}
-
-void spice_usb_backend_interrupt_event_handler(SpiceUsbBackend *be)
-{
-    if (be->libusb_context) {
-        libusb_interrupt_event_handler(be->libusb_context);
+    if (be->event_thread_run) {
+        SPICE_DEBUG("%s: the thread aborted, %s(%d)", __FUNCTION__, desc, res);
     }
+    SPICE_DEBUG("%s <<", __FUNCTION__);
+    return NULL;
 }
 
 void spice_usb_backend_deregister_hotplug(SpiceUsbBackend *be)
@@ -442,6 +442,12 @@ void spice_usb_backend_deregister_hotplug(SpiceUsbBackend *be)
         be->hotplug_handle = 0;
     }
     be->hotplug_callback = NULL;
+    g_atomic_int_set(&be->event_thread_run, FALSE);
+    if (be->event_thread) {
+        libusb_interrupt_event_handler(be->libusb_context);
+        g_thread_join(be->event_thread);
+        be->event_thread = NULL;
+    }
 }
 
 gboolean spice_usb_backend_register_hotplug(SpiceUsbBackend *be,
@@ -465,6 +471,11 @@ gboolean spice_usb_backend_register_hotplug(SpiceUsbBackend *be,
                     _("Error on USB hotplug detection: %s [%i]"), desc, rc);
         return FALSE;
     }
+
+    g_atomic_int_set(&be->event_thread_run, TRUE);
+    be->event_thread = g_thread_new("usb_ev_thread",
+                                    handle_libusb_events,
+                                    be);
     return TRUE;
 }
 
@@ -472,6 +483,14 @@ void spice_usb_backend_delete(SpiceUsbBackend *be)
 {
     g_return_if_fail(be != NULL);
     SPICE_DEBUG("%s >>", __FUNCTION__);
+    /*
+        we expect hotplug callbacks are deregistered
+        and the event thread is terminated. If not,
+        we do that anyway before delete the backend
+    */
+    g_warn_if_fail(be->hotplug_handle == 0);
+    g_warn_if_fail(be->event_thread == NULL);
+    spice_usb_backend_deregister_hotplug(be);
     if (be->libusb_context) {
         libusb_exit(be->libusb_context);
     }
diff --git a/src/usb-backend.h b/src/usb-backend.h
index 814da46..69a490b 100644
--- a/src/usb-backend.h
+++ b/src/usb-backend.h
@@ -56,8 +56,6 @@ enum {
 SpiceUsbBackend *spice_usb_backend_new(GError **error);
 void spice_usb_backend_delete(SpiceUsbBackend *context);
 
-gboolean spice_usb_backend_handle_events(SpiceUsbBackend *be);
-void spice_usb_backend_interrupt_event_handler(SpiceUsbBackend *be);
 gboolean spice_usb_backend_register_hotplug(SpiceUsbBackend *be,
                                             void *user_data,
                                             usb_hot_plug_callback proc,
diff --git a/src/usb-device-manager-priv.h b/src/usb-device-manager-priv.h
index 39aaf2f..66acf6d 100644
--- a/src/usb-device-manager-priv.h
+++ b/src/usb-device-manager-priv.h
@@ -25,12 +25,6 @@
 
 G_BEGIN_DECLS
 
-gboolean spice_usb_device_manager_start_event_listening(
-    SpiceUsbDeviceManager *manager, GError **err);
-
-void spice_usb_device_manager_stop_event_listening(
-    SpiceUsbDeviceManager *manager);
-
 #ifdef USE_USBREDIR
 void spice_usb_device_manager_device_error(
     SpiceUsbDeviceManager *manager, SpiceUsbDevice *device, GError *err);
diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c
index 857d057..a530be9 100644
--- a/src/usb-device-manager.c
+++ b/src/usb-device-manager.c
@@ -93,9 +93,6 @@ struct _SpiceUsbDeviceManagerPrivate {
     gchar *redirect_on_connect;
 #ifdef USE_USBREDIR
     SpiceUsbBackend *context;
-    int event_listeners;
-    GThread *event_thread;
-    gint event_thread_run;
     struct usbredirfilter_rule *auto_conn_filter_rules;
     struct usbredirfilter_rule *redirect_on_connect_rules;
     int auto_conn_filter_rules_count;
@@ -261,9 +258,6 @@ static gboolean spice_usb_device_manager_initable_init(GInitable  *initable,
                                             err)) {
         return FALSE;
     }
-#ifndef G_OS_WIN32
-    spice_usb_device_manager_start_event_listening(self, NULL);
-#endif
 
     /* Start listening for usb channels connect/disconnect */
     spice_g_signal_connect_object(priv->session, "channel-new", G_CALLBACK(channel_new), self, G_CONNECT_AFTER);
@@ -285,27 +279,8 @@ static void spice_usb_device_manager_dispose(GObject *gobject)
     SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(gobject);
     SpiceUsbDeviceManagerPrivate *priv = self->priv;
 
-#ifndef G_OS_WIN32
-    spice_usb_device_manager_stop_event_listening(self);
-    if (g_atomic_int_get(&priv->event_thread_run)) {
-        /* Force termination of the event thread even if there were some
-         * mismatched spice_usb_device_manager_{start,stop}_event_listening
-         * calls. Otherwise, the usb event thread will be leaked, and will
-         * try to use the libusb context we destroy in finalize(), which would
-         * cause a crash */
-        g_warn_if_reached();
-        g_atomic_int_set(&priv->event_thread_run, FALSE);
-    }
-#endif
     spice_usb_backend_deregister_hotplug(priv->context);
 
-    if (priv->event_thread) {
-        g_warn_if_fail(g_atomic_int_get(&priv->event_thread_run) == FALSE);
-        g_atomic_int_set(&priv->event_thread_run, FALSE);
-        spice_usb_backend_interrupt_event_handler(priv->context);
-        g_thread_join(priv->event_thread);
-        priv->event_thread = NULL;
-    }
 #endif
 
     /* Chain up to the parent class */
@@ -323,7 +298,6 @@ static void spice_usb_device_manager_finalize(GObject *gobject)
     if (priv->devices) {
         g_ptr_array_unref(priv->devices);
     }
-    g_return_if_fail(priv->event_thread == NULL);
     if (priv->context) {
         spice_usb_backend_delete(priv->context);
     }
@@ -915,59 +889,6 @@ static void spice_usb_device_manager_channel_connect_cb(
 /* ------------------------------------------------------------------ */
 /* private api                                                        */
 
-static gpointer spice_usb_device_manager_usb_ev_thread(gpointer user_data)
-{
-    SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(user_data);
-    SpiceUsbDeviceManagerPrivate *priv = self->priv;
-
-    while (g_atomic_int_get(&priv->event_thread_run)) {
-        if (!spice_usb_backend_handle_events(priv->context)) {
-            break;
-        }
-    }
-
-    return NULL;
-}
-
-gboolean spice_usb_device_manager_start_event_listening(
-    SpiceUsbDeviceManager *self, GError **err)
-{
-    SpiceUsbDeviceManagerPrivate *priv = self->priv;
-
-    g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
-
-    priv->event_listeners++;
-    if (priv->event_listeners > 1)
-        return TRUE;
-
-    /* We don't join the thread when we stop event listening, as the
-       libusb_handle_events call in the thread won't exit until the
-       libusb_close call for the device is made from usbredirhost_close. */
-    if (priv->event_thread) {
-        g_atomic_int_set(&priv->event_thread_run, FALSE);
-        spice_usb_backend_interrupt_event_handler(priv->context);
-         g_thread_join(priv->event_thread);
-         priv->event_thread = NULL;
-    }
-    g_atomic_int_set(&priv->event_thread_run, TRUE);
-    priv->event_thread = g_thread_new("usb_ev_thread",
-                                      spice_usb_device_manager_usb_ev_thread,
-                                      self);
-    return priv->event_thread != NULL;
-}
-
-void spice_usb_device_manager_stop_event_listening(
-    SpiceUsbDeviceManager *self)
-{
-    SpiceUsbDeviceManagerPrivate *priv = self->priv;
-
-    g_return_if_fail(priv->event_listeners > 0);
-
-    priv->event_listeners--;
-    if (priv->event_listeners == 0)
-        g_atomic_int_set(&priv->event_thread_run, FALSE);
-}
-
 static void spice_usb_device_manager_check_redir_on_connect(
     SpiceUsbDeviceManager *self, SpiceChannel *channel)
 {
commit 6ef530332758f36ad4530c9761b84d5ab69c83a0
Author: Yuri Benditovich <yuri.benditovich at daynix.com>
Date:   Tue Jul 23 18:13:47 2019 +0300

    usb-redir: pass GError to hotplug registration procedure
    
    In case of possible error the procedure of hotplug
    registration does not return error information, just
    issues warning to the stderr, so the reason of the problem,
    if any, is not visible. Current commit adds GError parameter
    to the procedure to return the error details conventionally.
    
    Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/src/usb-backend.c b/src/usb-backend.c
index 3f99739..2a2f9fa 100644
--- a/src/usb-backend.c
+++ b/src/usb-backend.c
@@ -446,7 +446,8 @@ void spice_usb_backend_deregister_hotplug(SpiceUsbBackend *be)
 
 gboolean spice_usb_backend_register_hotplug(SpiceUsbBackend *be,
                                             void *user_data,
-                                            usb_hot_plug_callback proc)
+                                            usb_hot_plug_callback proc,
+                                            GError **error)
 {
     int rc;
     const char *desc;
@@ -460,6 +461,8 @@ gboolean spice_usb_backend_register_hotplug(SpiceUsbBackend *be,
     if (rc != LIBUSB_SUCCESS) {
         g_warning("Error initializing USB hotplug support: %s [%i]", desc, rc);
         be->hotplug_callback = NULL;
+        g_set_error(error, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
+                    _("Error on USB hotplug detection: %s [%i]"), desc, rc);
         return FALSE;
     }
     return TRUE;
diff --git a/src/usb-backend.h b/src/usb-backend.h
index 6da3981..814da46 100644
--- a/src/usb-backend.h
+++ b/src/usb-backend.h
@@ -60,7 +60,8 @@ gboolean spice_usb_backend_handle_events(SpiceUsbBackend *be);
 void spice_usb_backend_interrupt_event_handler(SpiceUsbBackend *be);
 gboolean spice_usb_backend_register_hotplug(SpiceUsbBackend *be,
                                             void *user_data,
-                                            usb_hot_plug_callback proc);
+                                            usb_hot_plug_callback proc,
+                                            GError **error);
 void spice_usb_backend_deregister_hotplug(SpiceUsbBackend *be);
 
 /* Spice USB backend device API */
diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c
index 9300ad2..857d057 100644
--- a/src/usb-device-manager.c
+++ b/src/usb-device-manager.c
@@ -257,7 +257,8 @@ static gboolean spice_usb_device_manager_initable_init(GInitable  *initable,
 
     /* Start listening for usb devices plug / unplug */
     if (!spice_usb_backend_register_hotplug(priv->context, self,
-                                            spice_usb_device_manager_hotplug_cb)) {
+                                            spice_usb_device_manager_hotplug_cb,
+                                            err)) {
         return FALSE;
     }
 #ifndef G_OS_WIN32
commit 9ae25e11490a546dbe62e7d217f34222a77167f8
Author: Yuri Benditovich <yuri.benditovich at daynix.com>
Date:   Tue Jul 23 18:13:46 2019 +0300

    usb-redir: unify device hotplug/unplug for Windows and Linux
    
    Remove Windows-specific part of hotplug detection from
    usb-device-manager and win-usb-dev and place it into
    USB backend module. Connect the hotplug/unplug detection
    in Windows to the same callbacks already used in Linux.
    This removes significant part of Windows-specific code
    and simpifies things.
    Note regarding 'redirecting' property of usb-device-manager:
    - Previously usb-device-manager under Windows maintained
      'redirection' property in win-usb-dev
    - Now it maintains its own property in both Windows and
      Linux (for GUI and single redirect at a time)
    - The USB backend maintains its own 'redirecting' field
      in Windows to prevent update of device list when
      libusb opens the device (device redirection causes
      temporary removal of target device)
    
    Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/meson.build b/meson.build
index 4bfc80e..7817c73 100644
--- a/meson.build
+++ b/meson.build
@@ -113,7 +113,7 @@ endforeach
 
 deps = []
 if host_machine.system() == 'windows'
-  deps += ['libws2_32', 'libgdi32']
+  deps += ['libws2_32', 'libgdi32', 'libcomctl32']
 endif
 
 foreach dep : deps
diff --git a/src/meson.build b/src/meson.build
index a51d0a9..adcfaec 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -158,9 +158,7 @@ endif
 
 if spice_gtk_has_usbredir and host_machine.system() == 'windows'
   spice_client_glib_sources += ['usbdk_api.c',
-                                'usbdk_api.h',
-                                'win-usb-dev.c',
-                                'win-usb-dev.h']
+                                'usbdk_api.h']
 endif
 
 #
diff --git a/src/usb-backend.c b/src/usb-backend.c
index e837579..3f99739 100644
--- a/src/usb-backend.c
+++ b/src/usb-backend.c
@@ -32,6 +32,9 @@
 #include <libusb.h>
 #include <string.h>
 #include <fcntl.h>
+#ifdef G_OS_WIN32
+#include <commctrl.h>
+#endif
 #include "usbredirhost.h"
 #include "usbredirparser.h"
 #include "spice-util.h"
@@ -55,6 +58,11 @@ struct _SpiceUsbBackend
     usb_hot_plug_callback hotplug_callback;
     void *hotplug_user_data;
     libusb_hotplug_callback_handle hotplug_handle;
+#ifdef G_OS_WIN32
+    HANDLE hWnd;
+    libusb_device **libusb_device_list;
+    gint redirecting;
+#endif
 };
 
 struct _SpiceUsbBackendChannel
@@ -66,6 +74,7 @@ struct _SpiceUsbBackendChannel
     int rules_count;
     SpiceUsbBackendDevice *attached;
     SpiceUsbredirChannel  *user_data;
+    SpiceUsbBackend *backend;
     GError **error;
 };
 
@@ -128,6 +137,170 @@ static int LIBUSB_CALL hotplug_callback(libusb_context *ctx,
     return 0;
 }
 
+#ifdef G_OS_WIN32
+/* Windows-specific: get notification on device change */
+
+static gboolean is_same_libusb_dev(libusb_device *libdev1,
+                                   libusb_device *libdev2)
+{
+    UsbDeviceInformation info1, info2;
+    g_return_val_if_fail(libdev1 != NULL && libdev2 != NULL, FALSE);
+
+    get_usb_device_info_from_libusb_device(&info1, libdev1);
+    get_usb_device_info_from_libusb_device(&info2, libdev2);
+
+    return info1.bus == info2.bus &&
+           info1.address == info2.address &&
+           info1.vid == info2.vid &&
+           info1.pid == info2.pid;
+}
+
+/*
+    Compares context and list1 and list2 and fire callback for each
+    device in list1 that not present in list2.
+    Returns number of such devices.
+*/
+static int compare_dev_list_fire_callback(SpiceUsbBackend *be,
+                                          libusb_device * const *list1,
+                                          libusb_device * const *list2,
+                                          gboolean add)
+{
+    int num_changed = 0;
+    libusb_hotplug_event event = add ?
+        LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED : LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT;
+    while (*list1) {
+        gboolean found = 0;
+        uint32_t n = 0;
+        while (!found && list2[n]) {
+            found = is_same_libusb_dev(*list1, list2[n]);
+            n++;
+        }
+        if (!found) {
+            UsbDeviceInformation info;
+            get_usb_device_info_from_libusb_device(&info, *list1);
+            SPICE_DEBUG("%s %04X:%04X at %d:%d", add ? "adding" : "removing",
+                        info.vid, info.pid, info.bus, info.address);
+            hotplug_callback(NULL, *list1, event, be);
+            num_changed++;
+        }
+        list1++;
+    }
+    return num_changed;
+}
+
+static LRESULT subclass_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
+                            UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
+{
+    SpiceUsbBackend *be = (SpiceUsbBackend *)dwRefData;
+    if (uMsg == WM_DEVICECHANGE && !be->redirecting) {
+        libusb_device **new_list = NULL;
+        libusb_get_device_list(be->libusb_context, &new_list);
+        if (new_list) {
+            int num_changed = compare_dev_list_fire_callback(be, be->libusb_device_list, new_list, FALSE);
+            num_changed += compare_dev_list_fire_callback(be, new_list, be->libusb_device_list, TRUE);
+            if (num_changed > 0) {
+                libusb_free_device_list(be->libusb_device_list, TRUE);
+                be->libusb_device_list = new_list;
+            } else {
+                libusb_free_device_list(new_list, TRUE);
+            }
+        } else {
+            g_warn_if_reached();
+        }
+    }
+    return DefSubclassProc(hWnd, uMsg, wParam, lParam);
+}
+
+static void disable_hotplug_support(SpiceUsbBackend *be)
+{
+    if (be->hWnd) {
+        DestroyWindow(be->hWnd);
+        be->hWnd = NULL;
+    }
+    if (be->libusb_device_list) {
+        libusb_free_device_list(be->libusb_device_list, TRUE);
+        be->libusb_device_list = NULL;
+    }
+}
+
+static int enable_hotplug_support(SpiceUsbBackend *be, const char **error_on_enable)
+{
+    long win_err;
+    libusb_device **libdev_list = NULL;
+    libusb_device *empty_list = NULL;
+
+    libusb_get_device_list(be->libusb_context, &libdev_list);
+    if (!libdev_list) {
+        *error_on_enable = "Getting device list";
+        goto error;
+    }
+    /* using standard class for window to receive messages */
+    be->hWnd = CreateWindow("Static", NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+    if (!be->hWnd) {
+        *error_on_enable = "CreateWindow";
+        goto error;
+    }
+    if (!SetWindowSubclass(be->hWnd, subclass_proc, 0, (DWORD_PTR)be)) {
+        *error_on_enable = "SetWindowSubclass";
+        goto error;
+    }
+    be->hotplug_handle = 1;
+    be->libusb_device_list = libdev_list;
+
+    compare_dev_list_fire_callback(be, be->libusb_device_list, &empty_list, TRUE);
+
+    return LIBUSB_SUCCESS;
+error:
+    win_err = GetLastError();
+    if (!win_err) {
+        win_err = -1;
+    }
+    g_warning("%s failed: %ld", *error_on_enable, win_err);
+    if (libdev_list) {
+        libusb_free_device_list(libdev_list, TRUE);
+    }
+    return win_err;
+}
+
+static void set_redirecting(SpiceUsbBackend *be, gboolean on)
+{
+    if (on) {
+        g_atomic_int_inc(&be->redirecting);
+    } else {
+        gboolean no_redir;
+        no_redir = g_atomic_int_dec_and_test(&be->redirecting);
+        if (no_redir && be->hWnd) {
+            PostMessage(be->hWnd, WM_DEVICECHANGE, 0, 0);
+        }
+    }
+}
+
+#else
+/* Linux-specific: use hot callback from libusb */
+
+static void disable_hotplug_support(SpiceUsbBackend *be)
+{
+    libusb_hotplug_deregister_callback(be->libusb_context, be->hotplug_handle);
+}
+
+static int enable_hotplug_support(SpiceUsbBackend *be, const char **error_on_enable)
+{
+    int rc = 0;
+    rc = libusb_hotplug_register_callback(be->libusb_context,
+        LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
+        LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY,
+        LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
+        hotplug_callback, be, &be->hotplug_handle);
+    *error_on_enable = libusb_strerror(rc);
+    return rc;
+}
+
+static inline void set_redirecting(SpiceUsbBackend *be, gboolean on) {
+    /* nothing on Linux */
+}
+
+#endif
+
 /* lock functions for usbredirhost and usbredirparser */
 static void *usbredir_alloc_lock(void) {
     GMutex *mutex;
@@ -265,7 +438,7 @@ void spice_usb_backend_deregister_hotplug(SpiceUsbBackend *be)
 {
     g_return_if_fail(be != NULL);
     if (be->hotplug_handle) {
-        libusb_hotplug_deregister_callback(be->libusb_context, be->hotplug_handle);
+        disable_hotplug_support(be);
         be->hotplug_handle = 0;
     }
     be->hotplug_callback = NULL;
@@ -276,17 +449,15 @@ gboolean spice_usb_backend_register_hotplug(SpiceUsbBackend *be,
                                             usb_hot_plug_callback proc)
 {
     int rc;
+    const char *desc;
     g_return_val_if_fail(be != NULL, FALSE);
 
     be->hotplug_callback = proc;
     be->hotplug_user_data = user_data;
-    rc = libusb_hotplug_register_callback(be->libusb_context,
-        LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
-        LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY,
-        LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
-        hotplug_callback, be, &be->hotplug_handle);
+
+    rc = enable_hotplug_support(be, &desc);
+
     if (rc != LIBUSB_SUCCESS) {
-        const char *desc = libusb_strerror(rc);
         g_warning("Error initializing USB hotplug support: %s [%i]", desc, rc);
         be->hotplug_callback = NULL;
         return FALSE;
@@ -305,45 +476,6 @@ void spice_usb_backend_delete(SpiceUsbBackend *be)
     SPICE_DEBUG("%s <<", __FUNCTION__);
 }
 
-SpiceUsbBackendDevice **spice_usb_backend_get_device_list(SpiceUsbBackend *be)
-{
-    LOUD_DEBUG("%s >>", __FUNCTION__);
-    libusb_device **devlist = NULL, **dev;
-    SpiceUsbBackendDevice *d, **list;
-
-    int n = 0, index;
-
-    if (be && be->libusb_context) {
-        libusb_get_device_list(be->libusb_context, &devlist);
-    }
-
-    /* add all the libusb device that not present in our list */
-    for (dev = devlist; dev && *dev; dev++) {
-        n++;
-    }
-
-    list = g_new0(SpiceUsbBackendDevice*, n + 1);
-
-    index = 0;
-
-    for (dev = devlist; dev && *dev; dev++) {
-        d = allocate_backend_device(*dev);
-        if (!d) {
-            libusb_unref_device(*dev);
-        } else {
-            SPICE_DEBUG("created dev %p, usblib dev %p", d, *dev);
-            list[index++] = d;
-        }
-    }
-
-    if (devlist) {
-        libusb_free_device_list(devlist, 0);
-    }
-
-    LOUD_DEBUG("%s <<", __FUNCTION__);
-    return list;
-}
-
 const UsbDeviceInformation* spice_usb_backend_device_get_info(SpiceUsbBackendDevice *dev)
 {
     return &dev->device_info;
@@ -354,18 +486,6 @@ gconstpointer spice_usb_backend_device_get_libdev(SpiceUsbBackendDevice *dev)
     return dev->libusb_device;
 }
 
-void spice_usb_backend_free_device_list(SpiceUsbBackendDevice **devlist)
-{
-    LOUD_DEBUG("%s >>", __FUNCTION__);
-    SpiceUsbBackendDevice **dev;
-    for (dev = devlist; *dev; dev++) {
-        SpiceUsbBackendDevice *d = *dev;
-        spice_usb_backend_device_unref(d);
-    }
-    g_free(devlist);
-    LOUD_DEBUG("%s <<", __FUNCTION__);
-}
-
 SpiceUsbBackendDevice *spice_usb_backend_device_ref(SpiceUsbBackendDevice *dev)
 {
     LOUD_DEBUG("%s >> %p", __FUNCTION__, dev);
@@ -533,12 +653,23 @@ gboolean spice_usb_backend_channel_attach(SpiceUsbBackendChannel *ch,
                                           SpiceUsbBackendDevice *dev,
                                           GError **error)
 {
+    int rc;
     SPICE_DEBUG("%s >> ch %p, dev %p (was attached %p)", __FUNCTION__, ch, dev, ch->attached);
 
     g_return_val_if_fail(dev != NULL, FALSE);
 
     libusb_device_handle *handle = NULL;
-    int rc = libusb_open(dev->libusb_device, &handle);
+
+    /*
+       Under Windows we need to avoid updating
+       list of devices when we are acquiring the device
+    */
+    set_redirecting(ch->backend, TRUE);
+
+    rc = libusb_open(dev->libusb_device, &handle);
+
+    set_redirecting(ch->backend, FALSE);
+
     if (rc) {
         const char *desc = libusb_strerror(rc);
         g_set_error(error, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
@@ -586,6 +717,7 @@ SpiceUsbBackendChannel *spice_usb_backend_channel_new(SpiceUsbBackend *be,
     SPICE_DEBUG("%s >>", __FUNCTION__);
     ch->user_data = SPICE_USBREDIR_CHANNEL(user_data);
     if (be->libusb_context) {
+        ch->backend = be;
         ch->usbredirhost = usbredirhost_open_full(
             be->libusb_context,
             NULL,
diff --git a/src/usb-backend.h b/src/usb-backend.h
index cbb73c2..6da3981 100644
--- a/src/usb-backend.h
+++ b/src/usb-backend.h
@@ -56,14 +56,6 @@ enum {
 SpiceUsbBackend *spice_usb_backend_new(GError **error);
 void spice_usb_backend_delete(SpiceUsbBackend *context);
 
-/*
-returns newly-allocated null-terminated list of
-SpiceUsbBackendDevice pointers.
-The caller must call spice_usb_backend_free_device_list
-after it finishes list processing
-*/
-SpiceUsbBackendDevice **spice_usb_backend_get_device_list(SpiceUsbBackend *backend);
-void spice_usb_backend_free_device_list(SpiceUsbBackendDevice **devlist);
 gboolean spice_usb_backend_handle_events(SpiceUsbBackend *be);
 void spice_usb_backend_interrupt_event_handler(SpiceUsbBackend *be);
 gboolean spice_usb_backend_register_hotplug(SpiceUsbBackend *be,
diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c
index 9aba275..9300ad2 100644
--- a/src/usb-device-manager.c
+++ b/src/usb-device-manager.c
@@ -29,7 +29,6 @@
 #ifdef G_OS_WIN32
 #include <windows.h>
 #include "usbdk_api.h"
-#include "win-usb-dev.h"
 #endif
 
 #include "channel-usbredir-priv.h"
@@ -101,12 +100,10 @@ struct _SpiceUsbDeviceManagerPrivate {
     struct usbredirfilter_rule *redirect_on_connect_rules;
     int auto_conn_filter_rules_count;
     int redirect_on_connect_rules_count;
+    gboolean redirecting;
 #ifdef G_OS_WIN32
-    GUdevClient *udev;
     usbdk_api_wrapper *usbdk_api;
     HANDLE usbdk_hider_handle;
-#else
-    gboolean redirecting; /* Handled by GUdevClient in the gudev case */
 #endif
     GPtrArray *devices;
     GPtrArray *channels;
@@ -139,16 +136,9 @@ static void channel_destroy(SpiceSession *session, SpiceChannel *channel,
                             gpointer user_data);
 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,
-                                               SpiceUsbBackendDevice *udevice,
-                                               gboolean         add,
-                                               gpointer         user_data);
-#else
 static void spice_usb_device_manager_hotplug_cb(void *user_data,
                                                 SpiceUsbBackendDevice *dev,
                                                 gboolean added);
-#endif
 static void spice_usb_device_manager_check_redir_on_connect(
     SpiceUsbDeviceManager *self, SpiceChannel *channel);
 
@@ -190,11 +180,7 @@ G_DEFINE_BOXED_TYPE(SpiceUsbDevice, spice_usb_device,
 static void
 _set_redirecting(SpiceUsbDeviceManager *self, gboolean is_redirecting)
 {
-#ifdef G_OS_WIN32
-    g_object_set(self->priv->udev, "redirecting", is_redirecting, NULL);
-#else
     self->priv->redirecting = is_redirecting;
-#endif
 }
 
 #else
@@ -215,10 +201,6 @@ gboolean spice_usb_device_manager_is_redirecting(SpiceUsbDeviceManager *self)
 {
 #ifndef USE_USBREDIR
     return FALSE;
-#elif defined(G_OS_WIN32)
-    gboolean redirecting;
-    g_object_get(self->priv->udev, "redirecting", &redirecting, NULL);
-    return redirecting;
 #else
     return self->priv->redirecting;
 #endif
@@ -267,29 +249,18 @@ static gboolean spice_usb_device_manager_initable_init(GInitable  *initable,
     GList *list;
     GList *it;
 
-    /* Start listening for usb devices plug / unplug */
-#ifdef G_OS_WIN32
-    priv->udev = g_udev_client_new();
-    if (priv->udev == NULL) {
-        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) */
-    g_udev_client_report_devices(priv->udev);
-#else
     /* Initialize libusb */
     priv->context = spice_usb_backend_new(err);
     if (!priv->context) {
         return FALSE;
     }
 
+    /* Start listening for usb devices plug / unplug */
     if (!spice_usb_backend_register_hotplug(priv->context, self,
                                             spice_usb_device_manager_hotplug_cb)) {
         return FALSE;
     }
+#ifndef G_OS_WIN32
     spice_usb_device_manager_start_event_listening(self, NULL);
 #endif
 
@@ -324,8 +295,9 @@ static void spice_usb_device_manager_dispose(GObject *gobject)
         g_warn_if_reached();
         g_atomic_int_set(&priv->event_thread_run, FALSE);
     }
-    spice_usb_backend_deregister_hotplug(priv->context);
 #endif
+    spice_usb_backend_deregister_hotplug(priv->context);
+
     if (priv->event_thread) {
         g_warn_if_fail(g_atomic_int_get(&priv->event_thread_run) == FALSE);
         g_atomic_int_set(&priv->event_thread_run, FALSE);
@@ -350,14 +322,10 @@ static void spice_usb_device_manager_finalize(GObject *gobject)
     if (priv->devices) {
         g_ptr_array_unref(priv->devices);
     }
-#ifdef G_OS_WIN32
-    g_clear_object(&priv->udev);
-#endif
     g_return_if_fail(priv->event_thread == NULL);
-#ifndef G_OS_WIN32
-    if (priv->context)
+    if (priv->context) {
         spice_usb_backend_delete(priv->context);
-#endif
+    }
     free(priv->auto_conn_filter_rules);
     free(priv->redirect_on_connect_rules);
 #ifdef G_OS_WIN32
@@ -891,20 +859,6 @@ static void spice_usb_device_manager_remove_dev(SpiceUsbDeviceManager *self,
     spice_usb_device_unref(device);
 }
 
-#ifdef G_OS_WIN32
-static void spice_usb_device_manager_uevent_cb(GUdevClient     *client,
-                                               SpiceUsbBackendDevice *bdev,
-                                               gboolean         add,
-                                               gpointer         user_data)
-{
-    SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(user_data);
-
-    if (add)
-        spice_usb_device_manager_add_dev(self, bdev);
-    else
-        spice_usb_device_manager_remove_dev(self, bdev);
-}
-#else
 struct hotplug_idle_cb_args {
     SpiceUsbDeviceManager *self;
     SpiceUsbBackendDevice *device;
@@ -940,7 +894,6 @@ static void spice_usb_device_manager_hotplug_cb(void *user_data,
     args->added = added;
     g_idle_add(spice_usb_device_manager_hotplug_idle_cb, args);
 }
-#endif // USE_USBREDIR
 
 static void spice_usb_device_manager_channel_connect_cb(
     GObject *gobject, GAsyncResult *channel_res, gpointer user_data)
diff --git a/src/win-usb-dev.c b/src/win-usb-dev.c
deleted file mode 100644
index c2a5115..0000000
--- a/src/win-usb-dev.c
+++ /dev/null
@@ -1,436 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2012 Red Hat, Inc.
-
-   Red Hat Authors:
-   Arnon Gilboa <agilboa at redhat.com>
-   Uri Lublin   <uril at redhat.com>
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "config.h"
-
-#include <windows.h>
-#include "win-usb-dev.h"
-#include "spice-marshal.h"
-#include "spice-util.h"
-
-enum {
-    PROP_0,
-    PROP_REDIRECTING
-};
-
-struct _GUdevClientPrivate {
-    SpiceUsbBackend *ctx;
-    GList *udev_list;
-    HWND hwnd;
-    gboolean redirecting;
-};
-
-#define G_UDEV_CLIENT_WINCLASS_NAME  TEXT("G_UDEV_CLIENT")
-
-static void g_udev_client_initable_iface_init(GInitableIface  *iface);
-
-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))
-
-enum
-{
-    UEVENT_SIGNAL,
-    LAST_SIGNAL,
-};
-
-static guint signals[LAST_SIGNAL] = { 0, };
-static GUdevClient *singleton = NULL;
-
-static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
-
-//uncomment to debug gudev device lists.
-//#define DEBUG_GUDEV_DEVICE_LISTS
-
-#ifdef DEBUG_GUDEV_DEVICE_LISTS
-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(SpiceUsbBackendDevice *dev, const gchar *msg);
-
-GQuark g_udev_client_error_quark(void)
-{
-    return g_quark_from_static_string("win-gudev-client-error-quark");
-}
-
-GUdevClient *g_udev_client_new(void)
-{
-    if (singleton != NULL)
-        return g_object_ref(singleton);
-
-    singleton = g_initable_new(G_UDEV_TYPE_CLIENT, NULL, NULL, NULL);
-    return singleton;
-}
-
-SpiceUsbBackend *g_udev_client_get_context(GUdevClient *client)
-{
-    return client->priv->ctx;
-}
-
-/*
- * devs [in,out] an empty devs list in, full devs list out
- * Returns: number-of-devices, or a negative value on error.
- */
-static ssize_t
-g_udev_client_list_devices(GUdevClient *self, GList **devs,
-                           GError **err, const gchar *name)
-{
-    SpiceUsbBackendDevice **lusb_list, **dev;
-    GUdevClientPrivate *priv;
-    ssize_t n;
-
-    g_return_val_if_fail(G_UDEV_IS_CLIENT(self), -1);
-    g_return_val_if_fail(devs != NULL, -2);
-
-    priv = self->priv;
-
-    g_return_val_if_fail(self->priv->ctx != NULL, -3);
-
-    lusb_list = spice_usb_backend_get_device_list(priv->ctx);
-    if (!lusb_list) {
-        g_set_error(err, G_UDEV_CLIENT_ERROR, G_UDEV_CLIENT_LIBUSB_FAILED,
-                    "%s: Error getting USB device list", name);
-        return -4;
-    }
-
-    n = 0;
-    for (dev = lusb_list; *dev; dev++) {
-        *devs = g_list_prepend(*devs, spice_usb_backend_device_ref(*dev));
-        n++;
-    }
-    spice_usb_backend_free_device_list(lusb_list);
-
-    return n;
-}
-
-static void unreference_backend_device(gpointer data)
-{
-    spice_usb_backend_device_unref((SpiceUsbBackendDevice *)data);
-}
-
-static void g_udev_client_free_device_list(GList **devs)
-{
-    g_return_if_fail(devs != NULL);
-    if (*devs) {
-        g_list_free_full(*devs, unreference_backend_device);
-        *devs = NULL;
-    }
-}
-
-
-static gboolean
-g_udev_client_initable_init(GInitable *initable, GCancellable *cancellable,
-                            GError **err)
-{
-    GUdevClient *self;
-    GUdevClientPrivate *priv;
-    WNDCLASS wcls;
-
-    g_return_val_if_fail(G_UDEV_IS_CLIENT(initable), FALSE);
-    g_return_val_if_fail(cancellable == NULL, FALSE);
-
-    self = G_UDEV_CLIENT(initable);
-    priv = self->priv;
-
-    priv->ctx = spice_usb_backend_new(err);
-    if (!priv->ctx) {
-        return FALSE;
-    }
-
-#ifdef G_OS_WIN32
-#if LIBUSB_API_VERSION >= 0x01000106
-    libusb_set_option(priv->ctx, LIBUSB_OPTION_USE_USBDK);
-#endif
-#endif
-
-    /* get initial device list */
-    if (g_udev_client_list_devices(self, &priv->udev_list, err, __FUNCTION__) < 0) {
-        goto g_udev_client_init_failed;
-    }
-
-    g_udev_device_print_list(priv->udev_list, "init: first list is: ");
-
-    /* create a hidden window */
-    memset(&wcls, 0, sizeof(wcls));
-    wcls.lpfnWndProc = wnd_proc;
-    wcls.lpszClassName = G_UDEV_CLIENT_WINCLASS_NAME;
-    if (!RegisterClass(&wcls)) {
-        DWORD e = GetLastError();
-        g_warning("RegisterClass failed , %ld", (long)e);
-        g_set_error(err, G_UDEV_CLIENT_ERROR, G_UDEV_CLIENT_WINAPI_FAILED,
-                    "RegisterClass failed: %ld", (long)e);
-        goto g_udev_client_init_failed;
-    }
-    priv->hwnd = CreateWindow(G_UDEV_CLIENT_WINCLASS_NAME,
-                              NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
-    if (!priv->hwnd) {
-        DWORD e = GetLastError();
-        g_warning("CreateWindow failed: %ld", (long)e);
-        g_set_error(err, G_UDEV_CLIENT_ERROR, G_UDEV_CLIENT_LIBUSB_FAILED,
-                    "CreateWindow failed: %ld", (long)e);
-        goto g_udev_client_init_failed_unreg;
-    }
-
-    return TRUE;
-
- g_udev_client_init_failed_unreg:
-    UnregisterClass(G_UDEV_CLIENT_WINCLASS_NAME, NULL);
- g_udev_client_init_failed:
-    return FALSE;
-}
-
-static void g_udev_client_initable_iface_init(GInitableIface *iface)
-{
-    iface->init = g_udev_client_initable_init;
-}
-
-static void report_one_device(gpointer data, gpointer self)
-{
-    g_signal_emit(self, signals[UEVENT_SIGNAL], 0, data, TRUE);
-}
-
-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)
-{
-    self->priv = g_udev_client_get_instance_private(self);
-}
-
-static void g_udev_client_finalize(GObject *gobject)
-{
-    GUdevClient *self = G_UDEV_CLIENT(gobject);
-    GUdevClientPrivate *priv = self->priv;
-
-    singleton = NULL;
-    DestroyWindow(priv->hwnd);
-    UnregisterClass(G_UDEV_CLIENT_WINCLASS_NAME, NULL);
-    g_udev_client_free_device_list(&priv->udev_list);
-
-    /* free backend context */
-    g_warn_if_fail(priv->ctx != NULL);
-    spice_usb_backend_delete(priv->ctx);
-
-    /* Chain up to the parent class */
-    if (G_OBJECT_CLASS(g_udev_client_parent_class)->finalize)
-        G_OBJECT_CLASS(g_udev_client_parent_class)->finalize(gobject);
-}
-
-static void g_udev_client_get_property(GObject     *gobject,
-                                       guint        prop_id,
-                                       GValue      *value,
-                                       GParamSpec  *pspec)
-{
-    GUdevClient *self = G_UDEV_CLIENT(gobject);
-    GUdevClientPrivate *priv = self->priv;
-
-    switch (prop_id) {
-    case PROP_REDIRECTING:
-        g_value_set_boolean(value, priv->redirecting);
-        break;
-    default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec);
-        break;
-    }
-}
-
-static void handle_dev_change(GUdevClient *self);
-
-static void g_udev_client_set_property(GObject       *gobject,
-                                       guint          prop_id,
-                                       const GValue  *value,
-                                       GParamSpec    *pspec)
-{
-    GUdevClient *self = G_UDEV_CLIENT(gobject);
-    GUdevClientPrivate *priv = self->priv;
-    gboolean old_val;
-
-    switch (prop_id) {
-    case PROP_REDIRECTING:
-        old_val = priv->redirecting;
-        priv->redirecting = g_value_get_boolean(value);
-        if (old_val && !priv->redirecting) {
-            /* This is a redirection completion case.
-               Inject hotplug event in case we missed device changes
-               during redirection processing. */
-            handle_dev_change(self);
-        }
-        break;
-    default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec);
-        break;
-    }
-}
-
-static void g_udev_client_class_init(GUdevClientClass *klass)
-{
-    GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
-    GParamSpec *pspec;
-
-    gobject_class->finalize = g_udev_client_finalize;
-    gobject_class->get_property = g_udev_client_get_property;
-    gobject_class->set_property = g_udev_client_set_property;
-
-    signals[UEVENT_SIGNAL] =
-        g_signal_new("uevent",
-                     G_OBJECT_CLASS_TYPE(klass),
-                     G_SIGNAL_RUN_FIRST,
-                     G_STRUCT_OFFSET(GUdevClientClass, uevent),
-                     NULL, NULL,
-                     g_cclosure_user_marshal_VOID__POINTER_BOOLEAN,
-                     G_TYPE_NONE,
-                     2,
-                     G_TYPE_POINTER,
-                     G_TYPE_BOOLEAN);
-
-    /**
-    * GUdevClient::redirecting:
-    *
-    * This property indicates when a redirection operation
-    * is in progress on a device. It's set back to FALSE
-    * once the device is fully redirected to the guest.
-    */
-    pspec = g_param_spec_boolean("redirecting", "Redirecting",
-                                 "USB redirection operation is in progress",
-                                 FALSE,
-                                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-    g_object_class_install_property(gobject_class, PROP_REDIRECTING, pspec);
-}
-
-/* comparing bus:addr and vid:pid */
-static gint compare_usb_devices(gconstpointer a, gconstpointer b)
-{
-    const UsbDeviceInformation *a_info, *b_info;
-    gboolean same_bus, same_addr, same_vid, same_pid;
-    a_info = spice_usb_backend_device_get_info((SpiceUsbBackendDevice *)a);
-    b_info = spice_usb_backend_device_get_info((SpiceUsbBackendDevice *)b);
-
-
-    same_bus = (a_info->bus == b_info->bus);
-    same_addr = (a_info->address == b_info->address);
-    same_vid = (a_info->vid == b_info->vid);
-    same_pid = (a_info->pid == b_info->pid);
-
-    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_usb_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 */
-            SpiceUsbBackendDevice *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,
-                                    gboolean add)
-{
-    GList *dev;
-
-    for (dev = g_list_first(old_list); dev != NULL; dev = g_list_next(dev)) {
-        GList *found = g_list_find_custom(new_list, dev->data, compare_usb_devices);
-        if (found == NULL) {
-            g_udev_device_print(dev->data, add ? "add" : "remove");
-            g_signal_emit(self, signals[UEVENT_SIGNAL], 0, dev->data, add);
-        }
-    }
-}
-
-static void handle_dev_change(GUdevClient *self)
-{
-    GUdevClientPrivate *priv = self->priv;
-    GError *err = NULL;
-    GList *now_devs = NULL;
-
-    if (priv->redirecting == TRUE) {
-        /* On Windows, querying USB device list may return inconsistent results
-           if performed in parallel to redirection flow.
-           A simulated hotplug event will be injected after redirection
-           completion in order to process real device list changes that may
-           had taken place during redirection process. */
-        return;
-    }
-
-    if(g_udev_client_list_devices(self, &now_devs, &err, __FUNCTION__) < 0) {
-        g_warning("could not retrieve device list");
-        return;
-    }
-
-    g_udev_device_print_list(now_devs, "handle_dev_change: current list:");
-    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, FALSE);
-
-    /* Register newly inserted devices */
-    notify_dev_state_change(self, now_devs, priv->udev_list, TRUE);
-
-    /* keep most recent info: free previous list, and keep current list */
-    update_device_list(self, now_devs);
-}
-
-static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
-{
-    /* Only DBT_DEVNODES_CHANGED recieved */
-    if (message == WM_DEVICECHANGE) {
-        handle_dev_change(singleton);
-    }
-    return DefWindowProc(hwnd, message, wparam, lparam);
-}
-
-#ifdef DEBUG_GUDEV_DEVICE_LISTS
-static void g_udev_device_print_list(GList *l, const gchar *msg)
-{
-    GList *it;
-
-    for (it = g_list_first(l); it != NULL; it=g_list_next(it)) {
-        g_udev_device_print(it->data, msg);
-    }
-}
-#endif
-
-static void g_udev_device_print(SpiceUsbBackendDevice *dev, const gchar *msg)
-{
-    const UsbDeviceInformation *info = spice_usb_backend_device_get_info(dev);
-
-    SPICE_DEBUG("%s: %d.%d 0x%04x:0x%04x class %d", msg,
-                info->bus, info->address,
-                info->vid, info->pid, info->class);
-}
diff --git a/src/win-usb-dev.h b/src/win-usb-dev.h
deleted file mode 100644
index fdfe73a..0000000
--- a/src/win-usb-dev.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2012 Red Hat, Inc.
-
-   Red Hat Authors:
-   Arnon Gilboa <agilboa at redhat.com>
-   Uri Lublin   <uril at redhat.com>
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-#ifndef __WIN_USB_DEV_H__
-#define __WIN_USB_DEV_H__
-
-#include <gio/gio.h>
-#include "usb-backend.h"
-
-G_BEGIN_DECLS
-
-/* GUdevClient */
-
-#define G_UDEV_TYPE_CLIENT         (g_udev_client_get_type())
-#define G_UDEV_CLIENT(o)           (G_TYPE_CHECK_INSTANCE_CAST((o), G_UDEV_TYPE_CLIENT, GUdevClient))
-#define G_UDEV_CLIENT_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_CLIENT, GUdevClientClass))
-#define G_UDEV_IS_CLIENT(o)        (G_TYPE_CHECK_INSTANCE_TYPE((o), G_UDEV_TYPE_CLIENT))
-#define G_UDEV_IS_CLIENT_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE((k), G_UDEV_TYPE_CLIENT))
-#define G_UDEV_CLIENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), G_UDEV_TYPE_CLIENT, GUdevClientClass))
-
-typedef struct _GUdevClient GUdevClient;
-typedef struct _GUdevClientClass GUdevClientClass;
-typedef struct _GUdevClientPrivate GUdevClientPrivate;
-
-struct _GUdevClient
-{
-    GObject parent;
-
-    GUdevClientPrivate *priv;
-};
-
-struct _GUdevClientClass
-{
-    GObjectClass parent_class;
-
-    /* signals */
-    void (*uevent)(GUdevClient *client, SpiceUsbBackendDevice *device, gboolean add);
-};
-
-GType g_udev_client_get_type(void) G_GNUC_CONST;
-GUdevClient *g_udev_client_new(void);
-SpiceUsbBackend *g_udev_client_get_context(GUdevClient *client);
-void g_udev_client_report_devices(GUdevClient *client);
-
-GQuark g_udev_client_error_quark(void);
-#define G_UDEV_CLIENT_ERROR g_udev_client_error_quark()
-
-/**
- * GUdevClientError:
- * @G_UDEV_CLIENT_ERROR_FAILED: generic error code
- * @G_UDEV_CLIENT_LIBUSB_FAILED: a libusb call failed
- * @G_UDEV_CLIENT_WINAPI_FAILED: a winapi call failed
- *
- * Error codes returned by spice-client API.
- */
-typedef enum
-{
-    G_UDEV_CLIENT_ERROR_FAILED = 1,
-    G_UDEV_CLIENT_LIBUSB_FAILED,
-    G_UDEV_CLIENT_WINAPI_FAILED
-} GUdevClientError;
-
-
-G_END_DECLS
-
-#endif /* __WIN_USB_DEV_H__ */


More information about the Spice-commits mailing list