[Spice-commits] 11 commits - configure.ac gtk/Makefile.am gtk/channel-usbredir-priv.h gtk/channel-usbredir.c gtk/gusb gtk/spice-channel-priv.h gtk/spice-channel.c gtk/spice-gtk-session.c gtk/spicy.c gtk/usb-device-manager-priv.h gtk/usb-device-manager.c gtk/usb-device-manager.h

Hans de Goede jwrdegoede at kemper.freedesktop.org
Tue Jan 3 02:17:09 PST 2012


 configure.ac                    |    2 
 gtk/Makefile.am                 |   22 -
 gtk/channel-usbredir-priv.h     |   12 -
 gtk/channel-usbredir.c          |  104 +++++---
 gtk/gusb/README.txt             |    5 
 gtk/gusb/gusb-context-private.h |   35 ---
 gtk/gusb/gusb-context.c         |  290 -------------------------
 gtk/gusb/gusb-context.h         |   63 -----
 gtk/gusb/gusb-device-list.c     |  358 ------------------------------
 gtk/gusb/gusb-device-list.h     |   72 ------
 gtk/gusb/gusb-device-private.h  |   34 --
 gtk/gusb/gusb-device.c          |  232 --------------------
 gtk/gusb/gusb-device.h          |   71 ------
 gtk/gusb/gusb-marshal.h         |    7 
 gtk/gusb/gusb-source.c          |  307 --------------------------
 gtk/gusb/gusb-source.h          |   58 -----
 gtk/gusb/gusb-util.c            |   65 -----
 gtk/gusb/gusb-util.h            |   32 --
 gtk/spice-channel-priv.h        |    3 
 gtk/spice-channel.c             |   38 ++-
 gtk/spice-gtk-session.c         |    2 
 gtk/spicy.c                     |    2 
 gtk/usb-device-manager-priv.h   |   38 +++
 gtk/usb-device-manager.c        |  463 +++++++++++++++++++++++++++-------------
 gtk/usb-device-manager.h        |    1 
 25 files changed, 462 insertions(+), 1854 deletions(-)

New commits:
commit 81f3de7058c57ff78c0ee73136454660b435e15e
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Fri Dec 23 16:21:43 2011 +0100

    usbredir: Don't call spice_usbredir_channel_disconnect on channel reset
    
    channel_reset gets called from spice_channel_disconnect, and
    spice_usbredir_channel_disconnect calls spice_channel_disconnect
    (so as to disconnect the channel when a usb device gets disconnected).
    
    So calling spice_usbredir_channel_disconnect from channel_reset leads to
    undesirable recursion. More over calling spice_usbredir_channel_disconnect
    disconnects / closes both the channel and *the usb device* and closing the
    usb device on migration is not what we want.
    
    Note that currently migration of usbredir channels does not work, and this
    patch does not fix this, but it does fix a regression when disconnecting
    usb devices normally (by unplugging them for example).
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/gtk/channel-usbredir.c b/gtk/channel-usbredir.c
index 1866775..bc1356a 100644
--- a/gtk/channel-usbredir.c
+++ b/gtk/channel-usbredir.c
@@ -103,8 +103,6 @@ static void spice_usbredir_channel_init(SpiceUsbredirChannel *channel)
 #ifdef USE_USBREDIR
 static void spice_usbredir_channel_reset(SpiceChannel *channel, gboolean migrating)
 {
-    spice_usbredir_channel_disconnect(SPICE_USBREDIR_CHANNEL(channel));
-
     SPICE_CHANNEL_CLASS(spice_usbredir_channel_parent_class)->channel_reset(channel, migrating);
 }
 #endif
commit 63069cec885491ad4ad8dd46d4aef91379425386
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Mon Dec 19 11:37:53 2011 +0100

    usbredir: Give devices a user friendly description
    
    Before this patch devices were described like this to the user:
    USB device at 2-14
    After this patch the description is:
    SanDisk Cruzer Blade [0781:5567] at 2-14
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index e8587bb..e55caae 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -22,10 +22,17 @@
 #include "config.h"
 
 #include <glib-object.h>
+#include <glib/gi18n.h>
 
 #include "glib-compat.h"
 
 #ifdef USE_USBREDIR
+#ifdef __linux__
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
 #include <libusb.h>
 #include <gudev/gudev.h>
 #include "channel-usbredir-priv.h"
@@ -422,6 +429,33 @@ const char *spice_usb_device_manager_libusb_strerror(enum libusb_error error_cod
     }
     return "Unknown error";
 }
+
+#ifdef __linux__
+/* <Sigh> libusb does not allow getting the manufacturer and product strings
+   without opening the device, so grab them directly from sysfs */
+static gchar *spice_usb_device_manager_get_sysfs_attribute(
+    int bus, int address, const char *attribute)
+{
+    struct stat stat_buf;
+    char filename[256];
+    gchar *contents;
+
+    snprintf(filename, sizeof(filename), "/dev/bus/usb/%03d/%03d",
+             bus, address);
+    if (stat(filename, &stat_buf) != 0)
+        return NULL;
+
+    snprintf(filename, sizeof(filename), "/sys/dev/char/%d:%d/%s",
+             major(stat_buf.st_rdev), minor(stat_buf.st_rdev), attribute);
+    if (!g_file_get_contents(filename, &contents, NULL, NULL))
+        return NULL;
+
+    /* Remove the newline at the end */
+    contents[strlen(contents) - 1] = '\0';
+
+    return contents;
+}
+#endif
 #endif
 
 /* ------------------------------------------------------------------ */
@@ -848,14 +882,40 @@ gchar *spice_usb_device_get_description(SpiceUsbDevice *_device)
 {
 #ifdef USE_USBREDIR
     libusb_device *device = (libusb_device *)_device;
-    int bus, address;
+    struct libusb_device_descriptor desc;
+    int rc, bus, address;
+    gchar *description, *manufacturer = NULL, *product = NULL;
 
     g_return_val_if_fail(device != NULL, NULL);
 
     bus     = libusb_get_bus_number(device);
     address = libusb_get_device_address(device);
 
-    return g_strdup_printf("USB device at %d-%d", bus, address);
+#if __linux__
+    manufacturer = spice_usb_device_manager_get_sysfs_attribute(bus, address,
+                                                              "manufacturer");
+    product = spice_usb_device_manager_get_sysfs_attribute(bus, address,
+                                                           "product");
+#endif
+    if (!manufacturer)
+        manufacturer = g_strdup(_("USB"));
+    if (!product)
+        product = g_strdup(_("Device"));
+
+    rc = libusb_get_device_descriptor(device, &desc);
+    if (rc == LIBUSB_SUCCESS) {
+        description = g_strdup_printf(_("%s %s [%04x:%04x] at %d-%d"),
+                                      manufacturer, product, desc.idVendor,
+                                      desc.idProduct, bus, address);
+    } else {
+        description = g_strdup_printf(_("%s %s at %d-%d"), manufacturer,
+                                      product, bus, address);
+    }
+
+    g_free(manufacturer);
+    g_free(product);
+
+    return description;
 #else
     return NULL;
 #endif
commit cebf1091c1df916846216919297af46ef36c0fa6
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Sun Dec 18 21:10:12 2011 +0100

    usbredir: Drop our embeddied GUsb copy
    
    No that we no longer use GUsbSource we're hardly using any code from GUsb,
    so drop our embeddied GUsb copy and do the last few things (device
    enumeration through gudev) ourselves.
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 1aaf0ec..82a0cbf 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -15,7 +15,6 @@ EXTRA_DIST =					\
 	generated_demarshallers1.c		\
 	generated_marshallers.c			\
 	generated_marshallers1.c		\
-	gusb/README.txt				\
 	spice-client-gtk.override		\
 	spice-client-gtk-manual.defs		\
 	$(NULL)
@@ -176,25 +175,6 @@ libspice_client_glib_2_0_la_LIBADD =	\
 	$(LIBUSBREDIRHOST_LIBS)		\
 	$(NULL)
 
-if WITH_USBREDIR
-GUSB_SRCS =				\
-	gusb/gusb-context.c		\
-	gusb/gusb-context.h		\
-	gusb/gusb-context-private.h	\
-	gusb/gusb-device.c		\
-	gusb/gusb-device.h		\
-	gusb/gusb-device-private.h	\
-	gusb/gusb-device-list.c		\
-	gusb/gusb-device-list.h		\
-	gusb/gusb-marshal.h		\
-	gusb/gusb-source.c		\
-	gusb/gusb-source.h		\
-	gusb/gusb-util.c		\
-	gusb/gusb-util.h
-else
-GUSB_SRCS =
-endif
-
 if WITH_POLKIT
 USB_ACL_HELPER_SRCS = \
 	usb-acl-helper.c		\
@@ -240,7 +220,6 @@ libspice_client_glib_2_0_la_SOURCES =	\
 	smartcard-manager-priv.h	\
 	usb-device-manager.c		\
 	usb-device-manager-priv.h	\
-	$(GUSB_SRCS)			\
 	$(USB_ACL_HELPER_SRCS)		\
 	\
 	decode.h			\
diff --git a/gtk/channel-usbredir-priv.h b/gtk/channel-usbredir-priv.h
index 305e897..5d75e26 100644
--- a/gtk/channel-usbredir-priv.h
+++ b/gtk/channel-usbredir-priv.h
@@ -21,16 +21,14 @@
 #ifndef __SPICE_CLIENT_USBREDIR_CHANNEL_PRIV_H__
 #define __SPICE_CLIENT_USBREDIR_CHANNEL_PRIV_H__
 
-#include <gusb/gusb-context.h>
-#include <gusb/gusb-device.h>
-
+#include <libusb.h>
 #include "spice-client.h"
 
 G_BEGIN_DECLS
 
 void spice_usbredir_channel_connect_async(SpiceUsbredirChannel *channel,
-                                          GUsbContext          *context,
-                                          GUsbDevice           *device,
+                                          libusb_context       *context,
+                                          libusb_device        *device,
                                           GCancellable         *cancellable,
                                           GAsyncReadyCallback   callback,
                                           gpointer              user_data);
@@ -40,7 +38,7 @@ gboolean spice_usbredir_channel_connect_finish(SpiceUsbredirChannel *channel,
 
 void spice_usbredir_channel_disconnect(SpiceUsbredirChannel *channel);
 
-GUsbDevice *spice_usbredir_channel_get_device(SpiceUsbredirChannel *channel);
+libusb_device *spice_usbredir_channel_get_device(SpiceUsbredirChannel *channel);
 
 G_END_DECLS
 
diff --git a/gtk/channel-usbredir.c b/gtk/channel-usbredir.c
index cc08af9..1866775 100644
--- a/gtk/channel-usbredir.c
+++ b/gtk/channel-usbredir.c
@@ -23,9 +23,6 @@
 
 #ifdef USE_USBREDIR
 #include <usbredirhost.h>
-#include <gusb/gusb-context-private.h>
-#include <gusb/gusb-device-private.h>
-#include <gusb/gusb-util.h>
 #if USE_POLKIT
 #include "usb-acl-helper.h"
 #endif
@@ -66,8 +63,8 @@ enum SpiceUsbredirChannelState {
 };
 
 struct _SpiceUsbredirChannelPrivate {
-    GUsbContext *context;
-    GUsbDevice *device;
+    libusb_context *context;
+    libusb_device *device;
     struct usbredirhost *host;
     /* To catch usbredirhost error messages and report them as a GError */
     GError **catch_error;
@@ -180,17 +177,17 @@ static gboolean spice_usbredir_channel_open_device(
 #endif
                          , FALSE);
 
-    rc = libusb_open(_g_usb_device_get_device(priv->device), &handle);
+    rc = libusb_open(priv->device, &handle);
     if (rc != 0) {
         g_set_error(err, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
                     "Could not open usb device: %s [%i]",
-                    gusb_strerror(rc), rc);
+                    spice_usb_device_manager_libusb_strerror(rc), rc);
         return FALSE;
     }
 
     priv->catch_error = err;
     priv->host = usbredirhost_open_full(
-                                   _g_usb_context_get_context(priv->context),
+                                   priv->context,
                                    handle, usbredir_log,
                                    usbredir_read_callback,
                                    usbredir_write_callback,
@@ -246,8 +243,9 @@ static void spice_usbredir_channel_open_acl_cb(
     }
     if (err) {
         g_simple_async_result_take_error(priv->result, err);
-        g_clear_object(&priv->context);
-        g_clear_object(&priv->device);
+        libusb_unref_device(priv->device);
+        priv->device  = NULL;
+        priv->context = NULL;
         priv->state = STATE_DISCONNECTED;
     }
 
@@ -263,8 +261,8 @@ static void spice_usbredir_channel_open_acl_cb(
 
 G_GNUC_INTERNAL
 void spice_usbredir_channel_connect_async(SpiceUsbredirChannel *channel,
-                                          GUsbContext          *context,
-                                          GUsbDevice           *device,
+                                          libusb_context       *context,
+                                          libusb_device        *device,
                                           GCancellable         *cancellable,
                                           GAsyncReadyCallback   callback,
                                           gpointer              user_data)
@@ -288,8 +286,8 @@ void spice_usbredir_channel_connect_async(SpiceUsbredirChannel *channel,
         goto done;
     }
 
-    priv->context = g_object_ref(context);
-    priv->device  = g_object_ref(device);
+    priv->context = context;
+    priv->device  = libusb_ref_device(device);
 #if USE_POLKIT
     priv->result = result;
     priv->state = STATE_WAITING_FOR_ACL_HELPER;
@@ -297,8 +295,8 @@ void spice_usbredir_channel_connect_async(SpiceUsbredirChannel *channel,
     g_object_set(spice_channel_get_session(SPICE_CHANNEL(channel)),
                  "inhibit-keyboard-grab", TRUE, NULL);
     spice_usb_acl_helper_open_acl(priv->acl_helper,
-                                  g_usb_device_get_bus(device),
-                                  g_usb_device_get_address(device),
+                                  libusb_get_bus_number(device),
+                                  libusb_get_device_address(device),
                                   cancellable,
                                   spice_usbredir_channel_open_acl_cb,
                                   channel);
@@ -307,8 +305,9 @@ void spice_usbredir_channel_connect_async(SpiceUsbredirChannel *channel,
     GError *err = NULL;
     if (!spice_usbredir_channel_open_device(channel, &err)) {
         g_simple_async_result_take_error(result, err);
-        g_clear_object(&priv->context);
-        g_clear_object(&priv->device);
+        libusb_unref_device(priv->device);
+        priv->device  = NULL;
+        priv->context = NULL;
     }
 #endif
 
@@ -366,15 +365,16 @@ void spice_usbredir_channel_disconnect(SpiceUsbredirChannel *channel)
         /* This also closes the libusb handle we passed to its _open */
         usbredirhost_close(priv->host);
         priv->host = NULL;
-        g_clear_object(&priv->device);
-        g_clear_object(&priv->context);
+        libusb_unref_device(priv->device);
+        priv->device  = NULL;
+        priv->context = NULL;
         priv->state = STATE_DISCONNECTED;
         break;
     }
 }
 
 G_GNUC_INTERNAL
-GUsbDevice *spice_usbredir_channel_get_device(SpiceUsbredirChannel *channel)
+libusb_device *spice_usbredir_channel_get_device(SpiceUsbredirChannel *channel)
 {
     return channel->priv->device;
 }
diff --git a/gtk/gusb/README.txt b/gtk/gusb/README.txt
deleted file mode 100644
index 8d76ed7..0000000
--- a/gtk/gusb/README.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-HDG: this is a private copy of gusb, from:
-https://gitorious.org/gusb
-
-This is a temporary solution until gusb upstream has a stable release out
-the door.
diff --git a/gtk/gusb/gusb-context-private.h b/gtk/gusb/gusb-context-private.h
deleted file mode 100644
index 4069a4d..0000000
--- a/gtk/gusb/gusb-context-private.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2011 Richard Hughes <richard at hughsie.com>
- *
- * Licensed under the GNU Lesser General Public License Version 2.1
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#ifndef __GUSB_CONTEXT_PRIVATE_H__
-#define __GUSB_CONTEXT_PRIVATE_H__
-
-#include <libusb-1.0/libusb.h>
-
-#include <gusb/gusb-context.h>
-
-G_BEGIN_DECLS
-
-libusb_context	*_g_usb_context_get_context	(GUsbContext	*context);
-
-G_END_DECLS
-
-#endif /* __GUSB_CONTEXT_PRIVATE_H__ */
diff --git a/gtk/gusb/gusb-context.c b/gtk/gusb/gusb-context.c
deleted file mode 100644
index 01eac06..0000000
--- a/gtk/gusb/gusb-context.c
+++ /dev/null
@@ -1,290 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2011 Richard Hughes <richard at hughsie.com>
- * Copyright (C) 2011 Hans de Goede <hdegoede at redhat.com>
- *
- * Licensed under the GNU Lesser General Public License Version 2.1
- *
- * 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/>.
- */
-
-/**
- * SECTION:gusb-context
- * @short_description: Per-thread instance integration for libusb
- *
- * This object is used to get a context that is thread safe.
- */
-
-#include "config.h"
-
-#include <libusb-1.0/libusb.h>
-
-#include "gusb-util.h"
-#include "gusb-context.h"
-#include "gusb-context-private.h"
-
-static void g_usb_context_finalize (GObject *object);
-
-#define G_USB_CONTEXT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), G_USB_TYPE_CONTEXT, GUsbContextPrivate))
-
-enum {
-	PROP_0,
-	PROP_LIBUSB_CONTEXT,
-	PROP_DEBUG_LEVEL,
-};
-
-/**
- * GUsbContextPrivate:
- *
- * Private #GUsbContext data
- **/
-struct _GUsbContextPrivate
-{
-	libusb_context		*context;
-	int			 debug_level;
-};
-
-G_DEFINE_TYPE (GUsbContext, g_usb_context, G_TYPE_OBJECT)
-
-/**
- * usb_context_get_property:
- **/
-static void
-g_usb_context_get_property (GObject		*object,
-			    guint		 prop_id,
-			    GValue		*value,
-			    GParamSpec		*pspec)
-{
-	GUsbContext *context = G_USB_CONTEXT (object);
-	GUsbContextPrivate *priv = context->priv;
-
-	switch (prop_id) {
-	case PROP_LIBUSB_CONTEXT:
-		g_value_set_pointer (value, priv->context);
-		break;
-	case PROP_DEBUG_LEVEL:
-		g_value_set_int (value, priv->debug_level);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
-}
-
-/**
- * usb_context_set_property:
- **/
-static void
-g_usb_context_set_property (GObject		*object,
-			   guint		 prop_id,
-			   const GValue		*value,
-			   GParamSpec		*pspec)
-{
-	GUsbContext *context = G_USB_CONTEXT (object);
-	GUsbContextPrivate *priv = context->priv;
-
-	switch (prop_id) {
-	case PROP_LIBUSB_CONTEXT:
-		priv->context = g_value_get_pointer (value);
-		break;
-	case PROP_DEBUG_LEVEL:
-		priv->debug_level = g_value_get_int (value);
-		libusb_set_debug (priv->context, priv->debug_level);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
-}
-
-static GObject *
-g_usb_context_constructor (GType			 gtype,
-			   guint			 n_properties,
-			   GObjectConstructParam	*properties)
-{
-	GObject *obj;
-	GUsbContext *context;
-	GUsbContextPrivate *priv;
-
-	{
-		/* Always chain up to the parent constructor */
-		GObjectClass *parent_class;
-		parent_class = G_OBJECT_CLASS (g_usb_context_parent_class);
-		obj = parent_class->constructor (gtype, n_properties,
-						 properties);
-	}
-
-	context = G_USB_CONTEXT (obj);
-	priv = context->priv;
-
-	/*
-	 * Yes you're reading this right the sole reason for this constructor
-	 * is to check the context has been set (for now).
-	 */
-	if (!priv->context)
-		g_error("constructed without a context");
-
-	return obj;
-}
-
-/**
- * usb_context_class_init:
- **/
-static void
-g_usb_context_class_init (GUsbContextClass *klass)
-{
-	GParamSpec *pspec;
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-	object_class->constructor	= g_usb_context_constructor;
-	object_class->finalize		= g_usb_context_finalize;
-	object_class->get_property	= g_usb_context_get_property;
-	object_class->set_property	= g_usb_context_set_property;
-
-	/**
-	 * GUsbContext:libusb_context:
-	 */
-	pspec = g_param_spec_pointer ("libusb_context", NULL, NULL,
-				      G_PARAM_CONSTRUCT_ONLY|
-				      G_PARAM_READWRITE);
-	g_object_class_install_property (object_class, PROP_LIBUSB_CONTEXT,
-					 pspec);
-
-	/**
-	 * GUsbContext:debug_level:
-	 */
-	pspec = g_param_spec_int ("debug_level", NULL, NULL,
-				  0, 3, 0,
-				  G_PARAM_READWRITE);
-	g_object_class_install_property (object_class, PROP_DEBUG_LEVEL,
-					 pspec);
-
-	g_type_class_add_private (klass, sizeof (GUsbContextPrivate));
-}
-
-/**
- * g_usb_context_init:
- **/
-static void
-g_usb_context_init (GUsbContext *context)
-{
-	context->priv = G_USB_CONTEXT_GET_PRIVATE (context);
-}
-
-/**
- * g_usb_context_finalize:
- **/
-static void
-g_usb_context_finalize (GObject *object)
-{
-	GUsbContext *context = G_USB_CONTEXT (object);
-	GUsbContextPrivate *priv = context->priv;
-
-	libusb_exit (priv->context);
-
-	G_OBJECT_CLASS (g_usb_context_parent_class)->finalize (object);
-}
-
-/**
- * g_usb_context_error_quark:
- *
- * Return value: Our personal error quark.
- *
- * Since: 0.0.1
- **/
-GQuark
-g_usb_context_error_quark (void)
-{
-	static GQuark quark = 0;
-	if (!quark)
-		quark = g_quark_from_static_string ("g_usb_context_error");
-	return quark;
-}
-
-/**
- * _g_usb_context_get_context:
- * @context: a #GUsbContext
- *
- * Gets the internal libusb_context.
- *
- * Return value: (transfer none): the libusb_context
- *
- * Since: 0.0.1
- **/
-libusb_context *
-_g_usb_context_get_context (GUsbContext *context)
-{
-	return context->priv->context;
-}
-
-/**
- * g_usb_context_set_debug:
- * @context: a #GUsbContext
- * @flags: a GLogLevelFlags such as %G_LOG_LEVEL_ERROR | %G_LOG_LEVEL_INFO, or 0
- *
- * Sets the debug flags which control what is logged to the console.
- *
- * Using %G_LOG_LEVEL_INFO will output to standard out, and everything
- * else logs to standard error.
- *
- * Since: 0.0.1
- **/
-void
-g_usb_context_set_debug (GUsbContext *context, GLogLevelFlags flags)
-{
-	GUsbContextPrivate *priv = context->priv;
-
-	if (flags & (G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_INFO))
-		priv->debug_level = 3;
-	else if (flags & (G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_WARNING))
-		priv->debug_level = 2;
-	else if (flags & (G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR))
-		priv->debug_level = 1;
-	else
-		priv->debug_level = 0;
-
-	libusb_set_debug (priv->context, priv->debug_level);
-}
-
-/**
- * g_usb_context_new:
- * @error: a #GError, or %NULL
- *
- * Creates a new context for accessing USB devices.
- *
- * Return value: a new %GUsbContext object or %NULL on error.
- *
- * Since: 0.0.1
- **/
-GUsbContext *
-g_usb_context_new (GError **error)
-{
-	gint rc;
-	GObject *obj;
-	libusb_context *context;
-
-	rc = libusb_init (&context);
-	if (rc < 0) {
-		g_set_error (error,
-			     G_USB_CONTEXT_ERROR,
-			     G_USB_CONTEXT_ERROR_INTERNAL,
-			     "failed to init libusb: %s [%i]",
-			     gusb_strerror (rc), rc);
-		return NULL;
-	}
-
-	obj = g_object_new (G_USB_TYPE_CONTEXT, "libusb_context", context,
-			    NULL);
-	return G_USB_CONTEXT (obj);
-}
diff --git a/gtk/gusb/gusb-context.h b/gtk/gusb/gusb-context.h
deleted file mode 100644
index ca9d28c..0000000
--- a/gtk/gusb/gusb-context.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2011 Richard Hughes <richard at hughsie.com>
- * Copyright (C) 2011 Hans de Goede <hdegoede at redhat.com>
- *
- * Licensed under the GNU Lesser General Public License Version 2.1
- *
- * 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 __GUSB_CONTEXT_H__
-#define __GUSB_CONTEXT_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define G_USB_TYPE_CONTEXT		(g_usb_context_get_type ())
-#define G_USB_CONTEXT(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), G_USB_TYPE_CONTEXT, GUsbContext))
-#define G_USB_IS_CONTEXT(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), G_USB_TYPE_CONTEXT))
-#define G_USB_CONTEXT_ERROR		(g_usb_context_error_quark ())
-
-typedef struct _GUsbContextPrivate	GUsbContextPrivate;
-typedef struct _GUsbContext		GUsbContext;
-typedef struct _GUsbContextClass	GUsbContextClass;
-
-struct _GUsbContext
-{
-	 GObject			 parent;
-	 GUsbContextPrivate		*priv;
-};
-
-struct _GUsbContextClass
-{
-	GObjectClass			 parent_class;
-};
-
-typedef enum {
-	G_USB_CONTEXT_ERROR_INTERNAL
-} GUsbContextError;
-
-GType		 g_usb_context_get_type		(void);
-GQuark		 g_usb_context_error_quark	(void);
-
-GUsbContext	*g_usb_context_new		(GError		**error);
-
-void		 g_usb_context_set_debug	(GUsbContext	*context,
-						 GLogLevelFlags	 flags);
-
-G_END_DECLS
-
-#endif /* __GUSB_CONTEXT_H__ */
diff --git a/gtk/gusb/gusb-device-list.c b/gtk/gusb/gusb-device-list.c
deleted file mode 100644
index dbe73f8..0000000
--- a/gtk/gusb/gusb-device-list.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2011 Hans de Goede <hdegoede at redhat.com>
- *
- * Licensed under the GNU Lesser General Public License Version 2.1
- *
- * 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 <string.h>
-#include <stdlib.h>
-#include <gudev/gudev.h>
-#include <libusb-1.0/libusb.h>
-
-#include "gusb-marshal.h"
-#include "gusb-context.h"
-#include "gusb-context-private.h"
-#include "gusb-device.h"
-#include "gusb-device-private.h"
-
-#include "gusb-device-list.h"
-
-#define G_USB_DEVICE_LIST_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), G_USB_TYPE_DEVICE_LIST, GUsbDeviceListPrivate))
-
-enum {
-	PROP_0,
-	PROP_CONTEXT,
-};
-
-enum
-{
-	DEVICE_ADDED_SIGNAL,
-	DEVICE_REMOVED_SIGNAL,
-	LAST_SIGNAL,
-};
-
-struct _GUsbDeviceListPrivate {
-	GUsbContext	 *context;
-	GUdevClient	 *udev;
-	GPtrArray	 *devices;
-	libusb_device	**coldplug_list;
-};
-
-static void g_usb_device_list_uevent_cb (GUdevClient	*client,
-					const gchar	*action,
-					GUdevDevice	*udevice,
-					gpointer	 user_data);
-
-static guint signals[LAST_SIGNAL] = { 0, };
-
-G_DEFINE_TYPE (GUsbDeviceList, g_usb_device_list, G_TYPE_OBJECT);
-
-static void
-g_usb_device_list_finalize (GObject *object)
-{
-	GUsbDeviceList *list = G_USB_DEVICE_LIST (object);
-	GUsbDeviceListPrivate *priv = list->priv;
-
-	g_object_unref (priv->udev);
-	g_ptr_array_unref (priv->devices);
-}
-
-/**
- * g_usb_device_list_get_property:
- **/
-static void
-g_usb_device_list_get_property (GObject		*object,
-				guint		 prop_id,
-				GValue		*value,
-				GParamSpec	*pspec)
-{
-	GUsbDeviceList *list = G_USB_DEVICE_LIST (object);
-	GUsbDeviceListPrivate *priv = list->priv;
-
-	switch (prop_id) {
-	case PROP_CONTEXT:
-		g_value_set_object (value, priv->context);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
-}
-
-/**
- * usb_device_list_set_property:
- **/
-static void
-g_usb_device_list_set_property (GObject		*object,
-				guint		 prop_id,
-				const GValue	*value,
-				GParamSpec	*pspec)
-{
-	GUsbDeviceList *list = G_USB_DEVICE_LIST (object);
-	GUsbDeviceListPrivate *priv = list->priv;
-
-	switch (prop_id) {
-	case PROP_CONTEXT:
-		priv->context = g_value_get_object (value);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
-}
-
-static GObject *
-g_usb_device_list_constructor (GType			 gtype,
-			       guint			 n_properties,
-			       GObjectConstructParam	*properties)
-{
-	GObject *obj;
-	GUsbDeviceList *list;
-	GUsbDeviceListPrivate *priv;
-	const gchar *const subsystems[] = {"usb", NULL};
-
-	{
-		/* Always chain up to the parent constructor */
-		GObjectClass *parent_class;
-		parent_class = G_OBJECT_CLASS (g_usb_device_list_parent_class);
-		obj = parent_class->constructor (gtype, n_properties,
-						 properties);
-	}
-
-	list = G_USB_DEVICE_LIST (obj);
-	priv = list->priv;
-
-	if (!priv->context)
-		g_error("constructed without a context");
-
-	priv->udev = g_udev_client_new (subsystems);
-	g_signal_connect (G_OBJECT (priv->udev), "uevent",
-			  G_CALLBACK (g_usb_device_list_uevent_cb), list);
-
-	priv->devices = g_ptr_array_new_with_free_func ((GDestroyNotify)
-							g_object_unref);
-
-	priv->coldplug_list = NULL;
-
-	return obj;
-}
-
-/**
- * g_usb_device_list_class_init:
- **/
-static void
-g_usb_device_list_class_init (GUsbDeviceListClass *klass)
-{
-	GParamSpec *pspec;
-	GObjectClass *object_class = (GObjectClass *) klass;
-
-	object_class->constructor	= g_usb_device_list_constructor;
-	object_class->finalize		= g_usb_device_list_finalize;
-	object_class->get_property	= g_usb_device_list_get_property;
-	object_class->set_property	= g_usb_device_list_set_property;
-
-	/**
-	 * GUsbDeviceList:context:
-	 */
-	pspec = g_param_spec_object ("context", NULL, NULL,
-				     G_USB_TYPE_CONTEXT,
-				     G_PARAM_CONSTRUCT_ONLY|
-				     G_PARAM_READWRITE);
-	g_object_class_install_property (object_class, PROP_CONTEXT, pspec);
-
-	signals[DEVICE_ADDED_SIGNAL] = g_signal_new ("device_added",
-			G_TYPE_FROM_CLASS (klass),
-			G_SIGNAL_RUN_LAST,
-			G_STRUCT_OFFSET (GUsbDeviceListClass, device_added),
-			NULL,
-			NULL,
-			g_cclosure_user_marshal_VOID__OBJECT_OBJECT,
-			G_TYPE_NONE,
-			2,
-			G_TYPE_OBJECT,
-			G_TYPE_OBJECT);
-
-	signals[DEVICE_REMOVED_SIGNAL] = g_signal_new ("device_removed",
-			G_TYPE_FROM_CLASS (klass),
-			G_SIGNAL_RUN_LAST,
-			G_STRUCT_OFFSET (GUsbDeviceListClass, device_removed),
-			NULL,
-			NULL,
-			g_cclosure_user_marshal_VOID__OBJECT_OBJECT,
-			G_TYPE_NONE,
-			2,
-			G_TYPE_OBJECT,
-			G_TYPE_OBJECT);
-
-	g_type_class_add_private (klass, sizeof (GUsbDeviceListPrivate));
-}
-
-static void
-g_usb_device_list_init (GUsbDeviceList *list)
-{
-	list->priv = G_USB_DEVICE_LIST_GET_PRIVATE (list);
-}
-
-static gboolean
-g_usb_device_list_get_bus_n_address (GUdevDevice	*udev,
-				     gint		*bus,
-				     gint		*address)
-{
-	const gchar *bus_str, *address_str;
-
-	*bus = *address = 0;
-
-	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;
-}
-
-static void
-g_usb_device_list_add_dev (GUsbDeviceList *list, GUdevDevice *udev)
-{
-	GUsbDeviceListPrivate *priv = list->priv;
-	GUsbDevice *device = NULL;
-	libusb_device **dev_list = NULL;
-	const gchar *devtype, *devclass;
-	gint i, bus, address;
-	libusb_context *ctx = _g_usb_context_get_context (priv->context);
-
-	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;
-
-	/* Skip hubs */
-	devclass = g_udev_device_get_sysfs_attr(udev, "bDeviceClass");
-	if (!devclass || !strcmp(devclass, "09"))
-		return;
-
-	if (!g_usb_device_list_get_bus_n_address (udev, &bus, &address)) {
-		g_warning ("usb-device without bus number or device address");
-		return;
-	}
-
-	if (priv->coldplug_list)
-		dev_list = priv->coldplug_list;
-	else
-		libusb_get_device_list(ctx, &dev_list);
-
-	for (i = 0; dev_list && dev_list[i]; i++) {
-		if (libusb_get_bus_number (dev_list[i]) == bus &&
-		    libusb_get_device_address (dev_list[i]) == address) {
-			device = _g_usb_device_new (dev_list[i]);
-			break;
-		}
-	}
-
-	if (!priv->coldplug_list)
-		libusb_free_device_list (dev_list, 1);
-
-	if (!device) {
-		g_warning ("Could not find usb dev at busnum %d devaddr %d",
-			   bus, address);
-		return;
-	}
-
-	g_ptr_array_add (priv->devices, device);
-	g_signal_emit (list, signals[DEVICE_ADDED_SIGNAL], 0, device, udev);
-}
-
-static void
-g_usb_device_list_remove_dev (GUsbDeviceList *list, GUdevDevice *udev)
-{
-	GUsbDeviceListPrivate *priv = list->priv;
-	GUsbDevice *device;
-	gint bus, address;
-
-	if (!g_usb_device_list_get_bus_n_address (udev, &bus, &address))
-		return;
-
-	device = g_usb_device_list_get_dev_by_bus_n_address (list, bus,
-							     address);
-	if (!device)
-		return;
-
-	g_signal_emit (list, signals[DEVICE_REMOVED_SIGNAL], 0, device, udev);
-	g_ptr_array_remove (priv->devices, device);
-}
-
-static void
-g_usb_device_list_uevent_cb (GUdevClient		*client,
-			     const gchar		*action,
-			     GUdevDevice		*udevice,
-			     gpointer			 user_data)
-{
-	GUsbDeviceList *list = G_USB_DEVICE_LIST (user_data);
-
-	if (g_str_equal (action, "add"))
-		g_usb_device_list_add_dev (list, udevice);
-	else if (g_str_equal (action, "remove"))
-		g_usb_device_list_remove_dev (list, udevice);
-}
-
-void
-g_usb_device_list_coldplug (GUsbDeviceList *list)
-{
-	GUsbDeviceListPrivate *priv = list->priv;
-	GList *devices, *elem;
-	libusb_context *ctx = _g_usb_context_get_context (priv->context);
-
-	libusb_get_device_list(ctx, &priv->coldplug_list);
-	devices = g_udev_client_query_by_subsystem (priv->udev, "usb");
-	for (elem = g_list_first (devices); elem; elem = g_list_next (elem)) {
-		g_usb_device_list_add_dev (list, elem->data);
-		g_object_unref (elem->data);
-	}
-	g_list_free (devices);
-	libusb_free_device_list (priv->coldplug_list, 1);
-	priv->coldplug_list = NULL;
-}
-
-GUsbDevice *
-g_usb_device_list_get_dev_by_bus_n_address (GUsbDeviceList	*list,
-					    guint8		 bus,
-					    guint8		 address)
-{
-	GUsbDeviceListPrivate *priv = list->priv;
-	GUsbDevice *device = NULL;
-	guint i;
-
-	for (i = 0; i < priv->devices->len; i++) {
-		GUsbDevice *curr = g_ptr_array_index (priv->devices, i);
-		if (g_usb_device_get_bus (curr) == bus &&
-		    g_usb_device_get_address (curr) == address) {
-			device = curr;
-			break;
-                }
-	}
-
-	return device;
-}
-
-GUsbDeviceList *
-g_usb_device_list_new (GUsbContext *context)
-{
-	GObject *obj;
-	obj = g_object_new (G_USB_TYPE_DEVICE_LIST, "context", context, NULL);
-	return G_USB_DEVICE_LIST (obj);
-}
diff --git a/gtk/gusb/gusb-device-list.h b/gtk/gusb/gusb-device-list.h
deleted file mode 100644
index 430984f..0000000
--- a/gtk/gusb/gusb-device-list.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2011 Hans de Goede <hdegoede at redhat.com>
- *
- * Licensed under the GNU Lesser General Public License Version 2.1
- *
- * 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 __GUSB_DEVICE_LIST_H__
-#define __GUSB_DEVICE_LIST_H__
-
-#include <glib-object.h>
-#include <gudev/gudev.h>
-
-#include <gusb/gusb-context.h>
-#include <gusb/gusb-device.h>
-
-G_BEGIN_DECLS
-
-#define G_USB_TYPE_DEVICE_LIST		(g_usb_device_list_get_type ())
-#define G_USB_DEVICE_LIST(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), G_USB_TYPE_DEVICE_LIST, GUsbDeviceList))
-#define G_USB_IS_DEVICE_LIST(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), G_USB_TYPE_DEVICE_LIST))
-
-typedef struct _GUsbDeviceListPrivate	GUsbDeviceListPrivate;
-typedef struct _GUsbDeviceList		GUsbDeviceList;
-typedef struct _GUsbDeviceListClass	GUsbDeviceListClass;
-
-struct _GUsbDeviceList
-{
-	 GObject			 parent;
-	 GUsbDeviceListPrivate		*priv;
-};
-
-struct _GUsbDeviceListClass
-{
-	GObjectClass			 parent_class;
-	/* Signals */
-	void (*device_added)		(GUsbDeviceList		*list,
-					 GUsbDevice		*device,
-					 GUdevDevice		*udev);
-	void (*device_removed)		(GUsbDeviceList		*list,
-					 GUsbDevice		*device,
-					 GUdevDevice		*udev);
-};
-
-GType			 g_usb_device_list_get_type (void);
-
-GUsbDeviceList		*g_usb_device_list_new (GUsbContext *context);
-
-void			 g_usb_device_list_coldplug (GUsbDeviceList *list);
-
-GUsbDevice		*g_usb_device_list_get_dev_by_bus_n_address (
-					GUsbDeviceList	*list,
-					guint8		 bus,
-					guint8		 address);
-
-
-G_END_DECLS
-
-#endif /* __GUSB_DEVICE_LIST_H__ */
diff --git a/gtk/gusb/gusb-device-private.h b/gtk/gusb/gusb-device-private.h
deleted file mode 100644
index c93b51a..0000000
--- a/gtk/gusb/gusb-device-private.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2011 Hans de Goede <hdegoede at redhat.com>
- *
- * Licensed under the GNU Lesser General Public License Version 2.1
- *
- * 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 __GUSB_DEVICE_PRIVATE_H__
-#define __GUSB_DEVICE_PRIVATE_H__
-
-#include <gusb/gusb-device.h>
-
-G_BEGIN_DECLS
-
-GUsbDevice	*_g_usb_device_new		(libusb_device	*device);
-
-libusb_device	*_g_usb_device_get_device	(GUsbDevice	*device);
-
-G_END_DECLS
-
-#endif /* __GUSB_DEVICE_PRIVATE_H__ */
diff --git a/gtk/gusb/gusb-device.c b/gtk/gusb/gusb-device.c
deleted file mode 100644
index 26a25f3..0000000
--- a/gtk/gusb/gusb-device.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2010-2011 Richard Hughes <richard at hughsie.com>
- * Copyright (C) 2011 Hans de Goede <hdegoede at redhat.com>
- *
- * Licensed under the GNU Lesser General Public License Version 2.1
- *
- * 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/>.
- */
-
-/**
- * SECTION:usb-device
- * @short_description: GLib device integration for libusb
- *
- * This object is a thin glib wrapper around a libusb_device
- */
-
-#include "config.h"
-
-#include <libusb-1.0/libusb.h>
-
-#include "gusb-device.h"
-#include "gusb-device-private.h"
-
-static void     g_usb_device_finalize	(GObject     *object);
-
-#define G_USB_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), G_USB_TYPE_DEVICE, GUsbDevicePrivate))
-
-/**
- * GUsbDevicePrivate:
- *
- * Private #GUsbDevice data
- **/
-struct _GUsbDevicePrivate
-{
-	libusb_device		*device;
-};
-
-enum {
-	PROP_0,
-	PROP_LIBUSB_DEVICE,
-};
-
-G_DEFINE_TYPE (GUsbDevice, g_usb_device, G_TYPE_OBJECT)
-
-
-/**
- * g_usb_device_error_quark:
- *
- * Return value: Our personal error quark.
- *
- * Since: 0.0.1
- **/
-GQuark
-g_usb_device_error_quark (void)
-{
-	static GQuark quark = 0;
-	if (!quark)
-		quark = g_quark_from_static_string ("g_usb_device_error");
-	return quark;
-}
-
-/**
- * usb_device_get_property:
- **/
-static void
-g_usb_device_get_property (GObject		*object,
-			   guint		 prop_id,
-			   GValue		*value,
-			   GParamSpec		*pspec)
-{
-	GUsbDevice *device = G_USB_DEVICE (object);
-	GUsbDevicePrivate *priv = device->priv;
-
-	switch (prop_id) {
-	case PROP_LIBUSB_DEVICE:
-		g_value_set_pointer (value, priv->device);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
-}
-
-/**
- * usb_device_set_property:
- **/
-static void
-g_usb_device_set_property (GObject		*object,
-			   guint		 prop_id,
-			   const GValue		*value,
-			   GParamSpec		*pspec)
-{
-	GUsbDevice *device = G_USB_DEVICE (object);
-	GUsbDevicePrivate *priv = device->priv;
-
-	switch (prop_id) {
-	case PROP_LIBUSB_DEVICE:
-		priv->device = g_value_get_pointer (value);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
-}
-
-static GObject *
-g_usb_device_constructor (GType			 gtype,
-			  guint			 n_properties,
-			  GObjectConstructParam	*properties)
-{
-	GObject *obj;
-	GUsbDevice *device;
-	GUsbDevicePrivate *priv;
-
-	{
-		/* Always chain up to the parent constructor */
-		GObjectClass *parent_class;
-		parent_class = G_OBJECT_CLASS (g_usb_device_parent_class);
-		obj = parent_class->constructor (gtype, n_properties,
-						 properties);
-	}
-
-	device = G_USB_DEVICE (obj);
-	priv = device->priv;
-
-	if (!priv->device)
-		g_error("constructed without a libusb_device");
-
-	libusb_ref_device(priv->device);
-
-	return obj;
-}
-
-/**
- * usb_device_class_init:
- **/
-static void
-g_usb_device_class_init (GUsbDeviceClass *klass)
-{
-	GParamSpec *pspec;
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-	object_class->constructor	= g_usb_device_constructor;
-	object_class->finalize		= g_usb_device_finalize;
-	object_class->get_property	= g_usb_device_get_property;
-	object_class->set_property	= g_usb_device_set_property;
-
-	/**
-	 * GUsbDevice:libusb_device:
-	 */
-	pspec = g_param_spec_pointer ("libusb_device", NULL, NULL,
-				     G_PARAM_CONSTRUCT_ONLY|
-				     G_PARAM_READWRITE);
-	g_object_class_install_property (object_class, PROP_LIBUSB_DEVICE,
-					 pspec);
-
-	g_type_class_add_private (klass, sizeof (GUsbDevicePrivate));
-}
-
-/**
- * g_usb_device_init:
- **/
-static void
-g_usb_device_init (GUsbDevice *device)
-{
-	device->priv = G_USB_DEVICE_GET_PRIVATE (device);
-}
-
-/**
- * g_usb_device_finalize:
- **/
-static void
-g_usb_device_finalize (GObject *object)
-{
-	GUsbDevice *device = G_USB_DEVICE (object);
-	GUsbDevicePrivate *priv = device->priv;
-
-	libusb_unref_device(priv->device);
-
-	G_OBJECT_CLASS (g_usb_device_parent_class)->finalize (object);
-}
-
-/**
- * _g_usb_device_new:
- *
- * Return value: a new #GUsbDevice object.
- **/
-GUsbDevice *
-_g_usb_device_new (libusb_device	*device)
-{
-	GObject *obj;
-	obj = g_object_new (G_USB_TYPE_DEVICE, "libusb_device", device, NULL);
-	return G_USB_DEVICE (obj);
-}
-
-/**
- * _g_usb_device_get_device:
- * @device: a #GUsbDevice instance
- *
- * Gets the low-level libusb_device
- *
- * Return value: The #libusb_device or %NULL. Do not unref this value.
- **/
-libusb_device *
-_g_usb_device_get_device (GUsbDevice	*device)
-{
-	return device->priv->device;
-}
-
-guint8
-g_usb_device_get_bus (GUsbDevice	*device)
-{
-	return libusb_get_bus_number (device->priv->device);
-}
-
-guint8
-g_usb_device_get_address (GUsbDevice	*device)
-{
-	return libusb_get_device_address (device->priv->device);
-}
diff --git a/gtk/gusb/gusb-device.h b/gtk/gusb/gusb-device.h
deleted file mode 100644
index a504182..0000000
--- a/gtk/gusb/gusb-device.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2010-2011 Richard Hughes <richard at hughsie.com>
- * Copyright (C) 2011 Hans de Goede <hdegoede at redhat.com>
- *
- * Licensed under the GNU Lesser General Public License Version 2.1
- *
- * 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 __GUSB_DEVICE_H__
-#define __GUSB_DEVICE_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define G_USB_TYPE_DEVICE		(g_usb_device_get_type ())
-#define G_USB_DEVICE(o)			(G_TYPE_CHECK_INSTANCE_CAST ((o), G_USB_TYPE_DEVICE, GUsbDevice))
-#define G_USB_IS_DEVICE(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), G_USB_TYPE_DEVICE))
-#define G_USB_DEVICE_ERROR		(g_usb_device_error_quark ())
-
-typedef struct _GUsbDevicePrivate	GUsbDevicePrivate;
-typedef struct _GUsbDevice		GUsbDevice;
-typedef struct _GUsbDeviceClass		GUsbDeviceClass;
-
-/**
- * GUsbDeviceError:
- *
- * The error code.
- **/
-typedef enum {
-	G_USB_DEVICE_ERROR_INTERNAL
-} GUsbDeviceError;
-
-struct _GUsbDevice
-{
-	 GObject			 parent;
-	 GUsbDevicePrivate		*priv;
-};
-
-struct _GUsbDeviceClass
-{
-	GObjectClass			 parent_class;
-};
-
-GType			 g_usb_device_get_type		(void);
-GQuark			 g_usb_device_error_quark	(void);
-
-guint8			 g_usb_device_get_bus		(GUsbDevice      *device);
-guint8			 g_usb_device_get_address	(GUsbDevice      *device);
-
-#if 0 /* TODO */
-GUsbDeviceHandle 	*g_usb_device_get_device_handle	(GUsbDevice	 *device,
-							 GError		**err);
-#endif
-
-G_END_DECLS
-
-#endif /* __GUSB_DEVICE_H__ */
diff --git a/gtk/gusb/gusb-marshal.h b/gtk/gusb/gusb-marshal.h
deleted file mode 100644
index b00fd65..0000000
--- a/gtk/gusb/gusb-marshal.h
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * HDG: hack
- * Important: Don't forget to remove VOID:OBJECT,OBJECT from spice-marshal.txt
- * when we remove our bundled gusb.
- */
-
-#include "spice-marshal.h"
diff --git a/gtk/gusb/gusb-source.c b/gtk/gusb/gusb-source.c
deleted file mode 100644
index bb0af49..0000000
--- a/gtk/gusb/gusb-source.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2010-2011 Richard Hughes <richard at hughsie.com>
- * Copyright (C) 2011 Hans de Goede <hdegoede at redhat.com>
- *
- * Licensed under the GNU Lesser General Public License Version 2.1
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/**
- * SECTION:gusb-source
- * @short_description: GSource integration for libusb
- *
- * This object can be used to integrate libusb into the GLib main loop.
- */
-
-#include "config.h"
-
-#include <libusb-1.0/libusb.h>
-#include <poll.h>
-#include <stdlib.h>
-
-#include "gusb-util.h"
-#include "gusb-context.h"
-#include "gusb-context-private.h"
-#include "gusb-source.h"
-
-/**
- * g_usb_source_error_quark:
- *
- * Return value: Our personal error quark.
- *
- * Since: 0.0.1
- **/
-GQuark
-g_usb_source_error_quark (void)
-{
-	static GQuark quark = 0;
-	if (!quark)
-		quark = g_quark_from_static_string ("g_usb_source_error");
-	return quark;
-}
-
-struct _GUsbSource {
-	GSource		 source;
-	GSList		*pollfds;
-	GUsbContext	*usbcontext;
-	libusb_context	*ctx;
-};
-
-static void
-g_usb_source_pollfd_add (GUsbSource *source, int fd, short events)
-{
-	GPollFD *pollfd = g_slice_new(GPollFD);
-	pollfd->fd = fd;
-	pollfd->events = 0;
-	pollfd->revents = 0;
-	if (events & POLLIN)
-		pollfd->events |= G_IO_IN;
-	if (events & POLLOUT)
-		pollfd->events |= G_IO_OUT;
-
-	source->pollfds = g_slist_prepend(source->pollfds, pollfd);
-	g_source_add_poll((GSource *)source, pollfd);
-}
-
-static void
-g_usb_source_pollfd_added_cb (int fd, short events, void *user_data)
-{
-	GUsbSource *source = user_data;
-	g_usb_source_pollfd_add (source, fd, events);
-}
-
-static void
-g_usb_source_pollfd_remove (GUsbSource *source, int fd)
-{
-	GPollFD *pollfd;
-	GSList *elem = source->pollfds;
-
-	/* nothing to see here, move along */
-	if (elem == NULL) {
-		g_warning("cannot remove from list as list is empty?");
-		return;
-	}
-
-	/* find the pollfd in the list */
-	do {
-		pollfd = elem->data;
-		if (pollfd->fd != fd)
-			continue;
-
-		g_source_remove_poll((GSource *)source, pollfd);
-		g_slice_free(GPollFD, pollfd);
-		source->pollfds = g_slist_delete_link(source->pollfds, elem);
-		return;
-	} while ((elem = g_slist_next(elem)));
-	g_warning ("couldn't find fd %d in list", fd);
-}
-
-static void
-g_usb_source_pollfd_removed_cb(int fd, void *user_data)
-{
-	GUsbSource *source = user_data;
-
-	g_usb_source_pollfd_remove (source, fd);
-}
-
-static void
-g_usb_source_pollfd_remove_all (GUsbSource *source)
-{
-	GPollFD *pollfd;
-	GSList *curr, *next;
-
-	next = source->pollfds;
-	while (next) {
-		curr = next;
-		next = g_slist_next(curr);
-		pollfd = curr->data;
-		g_source_remove_poll((GSource *)source, pollfd);
-		g_slice_free (GPollFD, pollfd);
-		source->pollfds = g_slist_delete_link(source->pollfds, curr);
-	}
-}
-
-/**
- * g_usb_source_prepare:
- *
- * Called before all the file descriptors are polled.
- * As we are a file descriptor source, the prepare function returns FALSE.
- * It sets the returned timeout to -1 to indicate that it doesn't mind
- * how long the poll() call blocks.
- *
- * No, we're not going to support FreeBSD.
- **/
-static gboolean
-g_usb_source_prepare (GSource *source, gint *timeout)
-{
-	*timeout = -1;
-	return FALSE;
-}
-
-/**
- * g_usb_source_check:
- *
- * In the check function, it tests the results of the poll() call to see
- * if the required condition has been met, and returns TRUE if so.
- **/
-static gboolean
-g_usb_source_check (GSource *source)
-{
-	GUsbSource *usb_source = (GUsbSource *)source;
-	GPollFD *pollfd;
-	GSList *elem = usb_source->pollfds;
-
-	/* no fds */
-	if (elem == NULL)
-		return FALSE;
-
-	/* check each pollfd */
-	do {
-		pollfd = elem->data;
-		if (pollfd->revents)
-			return TRUE;
-	} while ((elem = g_slist_next(elem)));
-
-	return FALSE;
-}
-
-static gboolean
-g_usb_source_dispatch (GSource *source,
-		       GSourceFunc callback,
-		       gpointer user_data)
-{
-	GUsbSource *usb_source = (GUsbSource *)source;
-	struct timeval tv = { 0, 0 };
-	gint rc;
-
-	rc = libusb_handle_events_timeout (usb_source->ctx, &tv);
-	if (rc < 0) {
-		g_warning ("failed to handle event: %s [%i]",
-			   gusb_strerror (rc), rc);
-	}
-
-	if (callback)
-		callback(user_data);
-
-	return TRUE;
-}
-
-static void
-g_usb_source_finalize (GSource *source)
-{
-	GUsbSource *usb_source = (GUsbSource *)source;
-	g_object_unref (usb_source->usbcontext);
-	g_slist_free (usb_source->pollfds);
-}
-
-static GSourceFuncs usb_source_funcs = {
-	g_usb_source_prepare,
-	g_usb_source_check,
-	g_usb_source_dispatch,
-	g_usb_source_finalize,
-	NULL, NULL
-};
-
-/**
- * g_usb_source_new:
- * @main_ctx: a #GMainContext, or %NULL
- * @gusb_ctx: a #GUsbContext
- * @error: a #GError, or %NULL
- *
- * Creates a source for integration into libusb1.
- *
- * Return value: (transfer none): the #GUsbSource, or %NULL. Use g_usb_source_destroy() to unref.
- *
- * Since: 0.0.1
- **/
-GUsbSource *
-g_usb_source_new (GMainContext *main_ctx,
-		  GUsbContext *gusb_ctx,
-		  GError **error)
-{
-	guint i;
-	const struct libusb_pollfd **pollfds;
-	GUsbSource *gusb_source;
-
-	gusb_source = (GUsbSource *)g_source_new (&usb_source_funcs,
-						  sizeof(GUsbSource));
-	gusb_source->pollfds = NULL;
-	gusb_source->usbcontext = g_object_ref (gusb_ctx);
-	gusb_source->ctx = _g_usb_context_get_context (gusb_ctx);
-
-	/* watch the fd's already created */
-	pollfds = libusb_get_pollfds (gusb_source->ctx);
-	if (pollfds == NULL) {
-		g_set_error_literal (error,
-				     G_USB_SOURCE_ERROR,
-				     G_USB_SOURCE_ERROR_INTERNAL,
-				     "failed to allocate memory");
-		g_free (gusb_source);
-		gusb_source = NULL;
-		goto out;
-	}
-	for (i=0; pollfds[i] != NULL; i++)
-		g_usb_source_pollfd_add (gusb_source,
-					 pollfds[i]->fd,
-					 pollfds[i]->events);
-	free (pollfds);
-
-	/* watch for PollFD changes */
-	g_source_attach ((GSource *)gusb_source, main_ctx);
-	libusb_set_pollfd_notifiers (gusb_source->ctx,
-				     g_usb_source_pollfd_added_cb,
-				     g_usb_source_pollfd_removed_cb,
-				     gusb_source);
-out:
-	return gusb_source;
-}
-
-/**
- * g_usb_source_destroy:
- * @source: a #GUsbSource
- *
- * Destroys a #GUsbSource
- *
- * Since: 0.0.1
- **/
-void
-g_usb_source_destroy (GUsbSource *source)
-{
-	libusb_set_pollfd_notifiers (source->ctx, NULL, NULL, NULL);
-	g_usb_source_pollfd_remove_all (source);
-	g_source_destroy ((GSource *)source);
-}
-
-/**
- * g_usb_source_set_callback:
- * @source: a #GUsbSource
- * @func: a function to call
- * @data: data to pass to @func
- * @notify: a #GDestroyNotify
- *
- * Set a callback to be called when the source is dispatched.
- *
- * Since: 0.0.1
- **/
-void
-g_usb_source_set_callback (GUsbSource *source,
-			   GSourceFunc func,
-			   gpointer data,
-			   GDestroyNotify notify)
-{
-	g_source_set_callback ((GSource *)source, func, data, notify);
-}
diff --git a/gtk/gusb/gusb-source.h b/gtk/gusb/gusb-source.h
deleted file mode 100644
index 40f6880..0000000
--- a/gtk/gusb/gusb-source.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2010-2011 Richard Hughes <richard at hughsie.com>
- * Copyright (C) 2011 Hans de Goede <hdegoede at redhat.com>
- *
- * Licensed under the GNU Lesser General Public License Version 2.1
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#ifndef __GUSB_SOURCE_H__
-#define __GUSB_SOURCE_H__
-
-#include <glib.h>
-
-#include <gusb/gusb-context.h>
-
-G_BEGIN_DECLS
-
-#define G_USB_SOURCE_ERROR			(g_usb_source_error_quark ())
-
-typedef struct _GUsbSource GUsbSource;
-
-/**
- * GUsbSourceError:
- *
- * The error code.
- **/
-typedef enum {
-	G_USB_SOURCE_ERROR_INTERNAL
-} GUsbSourceError;
-
-GQuark		 g_usb_source_error_quark	(void);
-GUsbSource	*g_usb_source_new		(GMainContext	*main_ctx,
-						 GUsbContext	*gusb_ctx,
-						 GError		**error);
-void		 g_usb_source_destroy		(GUsbSource	*source);
-
-void		 g_usb_source_set_callback	(GUsbSource	*source,
-						 GSourceFunc	 func,
-						 gpointer	 data,
-						 GDestroyNotify	 notify);
-
-G_END_DECLS
-
-#endif /* __GUSB_SOURCE_H__ */
diff --git a/gtk/gusb/gusb-util.c b/gtk/gusb/gusb-util.c
deleted file mode 100644
index ca91700..0000000
--- a/gtk/gusb/gusb-util.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2011 Hans de Goede <hdegoede at redhat.com>
- *
- * Licensed under the GNU Lesser General Public License Version 2.1
- *
- * 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 <libusb-1.0/libusb.h>
-
-#include "gusb-util.h"
-
-/* libusb_strerror is not going upstream in the forseeable future because of
-   i18n worries, provide our own implementation for now, later this can
-   hopefully became just a wrapper of the upstream version */
-const gchar* gusb_strerror(gint error_code)
-{
-    enum libusb_error error = error_code;
-
-    switch (error) {
-    case LIBUSB_SUCCESS:
-        return "Success";
-    case LIBUSB_ERROR_IO:
-        return "Input/output error";
-    case LIBUSB_ERROR_INVALID_PARAM:
-        return "Invalid parameter";
-    case LIBUSB_ERROR_ACCESS:
-        return "Access denied (insufficient permissions)";
-    case LIBUSB_ERROR_NO_DEVICE:
-        return "No such device (it may have been disconnected)";
-    case LIBUSB_ERROR_NOT_FOUND:
-        return "Entity not found";
-    case LIBUSB_ERROR_BUSY:
-        return "Resource busy";
-    case LIBUSB_ERROR_TIMEOUT:
-        return "Operation timed out";
-    case LIBUSB_ERROR_OVERFLOW:
-        return "Overflow";
-    case LIBUSB_ERROR_PIPE:
-        return "Pipe error";
-    case LIBUSB_ERROR_INTERRUPTED:
-        return "System call interrupted (perhaps due to signal)";
-    case LIBUSB_ERROR_NO_MEM:
-        return "Insufficient memory";
-    case LIBUSB_ERROR_NOT_SUPPORTED:
-        return "Operation not supported or unimplemented on this platform";
-    case LIBUSB_ERROR_OTHER:
-        return "Other error";
-    }
-    return "Unknown error";
-}
diff --git a/gtk/gusb/gusb-util.h b/gtk/gusb/gusb-util.h
deleted file mode 100644
index c270853..0000000
--- a/gtk/gusb/gusb-util.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2011 Hans de Goede <hdegoede at redhat.com>
- *
- * Licensed under the GNU Lesser General Public License Version 2.1
- *
- * 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 __GUSB_UTIL_H__
-#define __GUSB_UTIL_H__
-
-#include <glib.h>
-
-G_BEGIN_DECLS
-
-const gchar* gusb_strerror(gint error_code);
-
-G_END_DECLS
-
-#endif /* __GUSB_UTIL_H__ */
diff --git a/gtk/usb-device-manager-priv.h b/gtk/usb-device-manager-priv.h
index 841c725..e6e116c 100644
--- a/gtk/usb-device-manager-priv.h
+++ b/gtk/usb-device-manager-priv.h
@@ -25,6 +25,8 @@
 
 G_BEGIN_DECLS
 
+const char *spice_usb_device_manager_libusb_strerror(enum libusb_error error_code);
+
 gboolean spice_usb_device_manager_start_event_listening(
     SpiceUsbDeviceManager *manager, GError **err);
 
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index 53c0b8f..e8587bb 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -26,9 +26,8 @@
 #include "glib-compat.h"
 
 #ifdef USE_USBREDIR
-#include <gusb/gusb-device-list.h>
-#include <gusb/gusb-context-private.h>
-#include <gusb/gusb-util.h>
+#include <libusb.h>
+#include <gudev/gudev.h>
 #include "channel-usbredir-priv.h"
 #endif
 
@@ -88,25 +87,24 @@ struct _SpiceUsbDeviceManagerPrivate {
     SpiceSession *session;
     gboolean auto_connect;
 #ifdef USE_USBREDIR
-    GUsbContext *context;
-    GUsbDeviceList *devlist;
+    libusb_context *context;
+    GUdevClient *udev;
     int event_listeners;
     GThread *event_thread;
     gboolean event_thread_run;
+    libusb_device **coldplug_list; /* Avoid needless reprobing during init */
 #endif
     GPtrArray *devices;
     GPtrArray *channels;
 };
 
 #ifdef USE_USBREDIR
-static void spice_usb_device_manager_dev_added(GUsbDeviceList *devlist,
-                                               GUsbDevice     *device,
-                                               GUdevDevice    *udev,
-                                               gpointer        user_data);
-static void spice_usb_device_manager_dev_removed(GUsbDeviceList *devlist,
-                                                 GUsbDevice     *device,
-                                                 GUdevDevice    *udev,
-                                                 gpointer        user_data);
+static void spice_usb_device_manager_uevent_cb(GUdevClient     *client,
+                                               const gchar     *action,
+                                               GUdevDevice     *udevice,
+                                               gpointer         user_data);
+static void spice_usb_device_manager_add_dev(SpiceUsbDeviceManager  *self,
+                                             GUdevDevice            *udev);
 #endif
 static void spice_usb_device_manager_initable_iface_init(GInitableIface *iface);
 
@@ -115,7 +113,9 @@ static guint signals[LAST_SIGNAL] = { 0, };
 G_DEFINE_TYPE_WITH_CODE(SpiceUsbDeviceManager, spice_usb_device_manager, G_TYPE_OBJECT,
      G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, spice_usb_device_manager_initable_iface_init));
 
-G_DEFINE_BOXED_TYPE(SpiceUsbDevice, spice_usb_device, g_object_ref, g_object_unref)
+G_DEFINE_BOXED_TYPE(SpiceUsbDevice, spice_usb_device,
+                    (GBoxedCopyFunc)libusb_ref_device,
+                    (GBoxedFreeFunc)libusb_unref_device)
 
 static void spice_usb_device_manager_init(SpiceUsbDeviceManager *self)
 {
@@ -126,7 +126,7 @@ static void spice_usb_device_manager_init(SpiceUsbDeviceManager *self)
 
     priv->channels = g_ptr_array_new();
     priv->devices  = g_ptr_array_new_with_free_func((GDestroyNotify)
-                                                    g_object_unref);
+                                                    libusb_unref_device);
 }
 
 static gboolean spice_usb_device_manager_initable_init(GInitable  *initable,
@@ -138,7 +138,8 @@ static gboolean spice_usb_device_manager_initable_init(GInitable  *initable,
     SpiceUsbDeviceManager *self;
     SpiceUsbDeviceManagerPrivate *priv;
 #ifdef USE_USBREDIR
-    GError *my_err = NULL;
+    int rc;
+    const gchar *const subsystems[] = {"usb", NULL};
 #endif
 
     g_return_val_if_fail(SPICE_IS_USB_DEVICE_MANAGER(initable), FALSE);
@@ -170,26 +171,30 @@ static gboolean spice_usb_device_manager_initable_init(GInitable  *initable,
     g_list_free(list);
 
 #ifdef USE_USBREDIR
-    priv->context = g_usb_context_new(&my_err);
-    if (priv->context == NULL) {
-        g_warning("Could not get a GUsbContext, disabling USB support: %s",
-                  my_err->message);
-        if (err) {
-            *err = my_err;
-        } else {
-            g_error_free(my_err);
-        }
+    rc = libusb_init(&priv->context);
+    if (rc < 0) {
+        const char *desc = spice_usb_device_manager_libusb_strerror(rc);
+        g_warning("Error initializing USB support: %s [%i]", desc, rc);
+        g_set_error(err, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
+                    "Error initializing USB support: %s [%i]", desc, rc);
         return FALSE;
     }
 
-    priv->devlist = g_usb_device_list_new(priv->context);
-    g_signal_connect(G_OBJECT(priv->devlist), "device_added",
-                     G_CALLBACK(spice_usb_device_manager_dev_added),
-                     self);
-    g_signal_connect(G_OBJECT(priv->devlist), "device_removed",
-                     G_CALLBACK(spice_usb_device_manager_dev_removed),
-                     self);
-    g_usb_device_list_coldplug(priv->devlist);
+    priv->udev = g_udev_client_new(subsystems);
+    g_signal_connect(G_OBJECT(priv->udev), "uevent",
+                     G_CALLBACK(spice_usb_device_manager_uevent_cb), self);
+
+    /* Do coldplug (detection of already connected devices) */
+    libusb_get_device_list(priv->context, &priv->coldplug_list);
+    list = g_udev_client_query_by_subsystem(priv->udev, "usb");
+    for (it = g_list_first(list); it; it = g_list_next(it)) {
+        spice_usb_device_manager_add_dev(self, it->data);
+        g_object_unref(it->data);
+    }
+    g_list_free(list);
+    libusb_free_device_list(priv->coldplug_list, 1);
+    priv->coldplug_list = NULL;
+
     return TRUE;
 #else
     g_set_error_literal(err, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
@@ -203,19 +208,17 @@ static void spice_usb_device_manager_finalize(GObject *gobject)
     SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(gobject);
     SpiceUsbDeviceManagerPrivate *priv = self->priv;
 
+    g_ptr_array_unref(priv->channels);
+    g_ptr_array_unref(priv->devices);
+
 #ifdef USE_USBREDIR
+    g_clear_object(&priv->udev);
+    if (priv->context)
+        libusb_exit(priv->context);
     if (priv->event_thread)
         g_thread_join(priv->event_thread);
-
-    if (priv->devlist) {
-        g_object_unref(priv->devlist);
-        g_object_unref(priv->context);
-    }
 #endif
 
-    g_ptr_array_unref(priv->channels);
-    g_ptr_array_unref(priv->devices);
-
     /* Chain up to the parent class */
     if (G_OBJECT_CLASS(spice_usb_device_manager_parent_class)->finalize)
         G_OBJECT_CLASS(spice_usb_device_manager_parent_class)->finalize(gobject);
@@ -365,6 +368,63 @@ static void spice_usb_device_manager_class_init(SpiceUsbDeviceManagerClass *klas
 }
 
 /* ------------------------------------------------------------------ */
+/* gudev / libusb Helper functions                                    */
+
+#ifdef USE_USBREDIR
+static gboolean spice_usb_device_manager_get_udev_bus_n_address(
+    GUdevDevice *udev, int *bus, int *address)
+{
+    const gchar *bus_str, *address_str;
+
+    *bus = *address = 0;
+
+    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;
+}
+
+const char *spice_usb_device_manager_libusb_strerror(enum libusb_error error_code)
+{
+    switch (error_code) {
+    case LIBUSB_SUCCESS:
+        return "Success";
+    case LIBUSB_ERROR_IO:
+        return "Input/output error";
+    case LIBUSB_ERROR_INVALID_PARAM:
+        return "Invalid parameter";
+    case LIBUSB_ERROR_ACCESS:
+        return "Access denied (insufficient permissions)";
+    case LIBUSB_ERROR_NO_DEVICE:
+        return "No such device (it may have been disconnected)";
+    case LIBUSB_ERROR_NOT_FOUND:
+        return "Entity not found";
+    case LIBUSB_ERROR_BUSY:
+        return "Resource busy";
+    case LIBUSB_ERROR_TIMEOUT:
+        return "Operation timed out";
+    case LIBUSB_ERROR_OVERFLOW:
+        return "Overflow";
+    case LIBUSB_ERROR_PIPE:
+        return "Pipe error";
+    case LIBUSB_ERROR_INTERRUPTED:
+        return "System call interrupted (perhaps due to signal)";
+    case LIBUSB_ERROR_NO_MEM:
+        return "Insufficient memory";
+    case LIBUSB_ERROR_NOT_SUPPORTED:
+        return "Operation not supported or unimplemented on this platform";
+    case LIBUSB_ERROR_OTHER:
+        return "Other error";
+    }
+    return "Unknown error";
+}
+#endif
+
+/* ------------------------------------------------------------------ */
 /* callbacks                                                          */
 
 static void channel_new(SpiceSession *session, SpiceChannel *channel,
@@ -391,12 +451,12 @@ static void spice_usb_device_manager_auto_connect_cb(GObject      *gobject,
                                                      gpointer      user_data)
 {
     SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(gobject);
-    SpiceUsbDevice *device = user_data;
+    libusb_device *device = user_data;
     GError *err = NULL;
 
     spice_usb_device_manager_connect_device_finish(self, res, &err);
     if (err) {
-        gchar *desc = spice_usb_device_get_description(device);
+        gchar *desc = spice_usb_device_get_description((SpiceUsbDevice *)device);
         g_prefix_error(&err, "Could not auto-redirect %s: ", desc);
         g_free(desc);
 
@@ -404,46 +464,109 @@ static void spice_usb_device_manager_auto_connect_cb(GObject      *gobject,
         g_signal_emit(self, signals[AUTO_CONNECT_FAILED], 0, device, err);
         g_error_free(err);
     }
-    g_object_unref(device);
+    libusb_unref_device(device);
 }
 
-static void spice_usb_device_manager_dev_added(GUsbDeviceList *devlist,
-                                               GUsbDevice     *_device,
-                                               GUdevDevice    *udev,
-                                               gpointer        user_data)
+static void spice_usb_device_manager_add_dev(SpiceUsbDeviceManager  *self,
+                                             GUdevDevice            *udev)
 {
-    SpiceUsbDeviceManager *manager = user_data;
-    SpiceUsbDeviceManagerPrivate *priv = manager->priv;
-    SpiceUsbDevice *device = (SpiceUsbDevice *)_device;
+    SpiceUsbDeviceManagerPrivate *priv = self->priv;
+    libusb_device *device = NULL, **dev_list = NULL;
+    const gchar *devtype, *devclass;
+    int i, bus, address;
 
-    g_ptr_array_add(priv->devices, g_object_ref(device));
+    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;
+
+    /* Skip hubs */
+    devclass = g_udev_device_get_sysfs_attr(udev, "bDeviceClass");
+    if (!devclass || !strcmp(devclass, "09"))
+        return;
+
+    if (!spice_usb_device_manager_get_udev_bus_n_address(udev, &bus, &address)) {
+        g_warning("USB device without bus number or device address");
+        return;
+    }
+
+    if (priv->coldplug_list)
+        dev_list = priv->coldplug_list;
+    else
+        libusb_get_device_list(priv->context, &dev_list);
+
+    for (i = 0; dev_list && dev_list[i]; i++) {
+        if (libusb_get_bus_number(dev_list[i]) == bus &&
+            libusb_get_device_address(dev_list[i]) == address) {
+            device = libusb_ref_device(dev_list[i]);
+            break;
+        }
+    }
+
+    if (!priv->coldplug_list)
+        libusb_free_device_list(dev_list, 1);
+
+    if (!device) {
+        g_warning("Could not find USB device at busnum %d devaddr %d",
+                  bus, address);
+        return;
+    }
+
+    g_ptr_array_add(priv->devices, device);
 
     if (priv->auto_connect) {
-        spice_usb_device_manager_connect_device_async(manager, device, NULL,
+        spice_usb_device_manager_connect_device_async(self,
+                                   (SpiceUsbDevice *)device, NULL,
                                    spice_usb_device_manager_auto_connect_cb,
-                                   g_object_ref(device));
+                                   libusb_ref_device(device));
     }
 
     SPICE_DEBUG("device added %p", device);
-    g_signal_emit(manager, signals[DEVICE_ADDED], 0, device);
+    g_signal_emit(self, signals[DEVICE_ADDED], 0, device);
 }
 
-static void spice_usb_device_manager_dev_removed(GUsbDeviceList *devlist,
-                                                 GUsbDevice     *device,
-                                                 GUdevDevice    *udev,
-                                                 gpointer        user_data)
+static void spice_usb_device_manager_remove_dev(SpiceUsbDeviceManager  *self,
+                                                GUdevDevice            *udev)
 {
-    SpiceUsbDeviceManager *manager = user_data;
-    SpiceUsbDeviceManagerPrivate *priv = manager->priv;
+    SpiceUsbDeviceManagerPrivate *priv = self->priv;
+    libusb_device *curr, *device = NULL;
+    int bus, address;
+    guint i;
 
-    spice_usb_device_manager_disconnect_device(manager,
-                                               (SpiceUsbDevice *)device);
+    if (!spice_usb_device_manager_get_udev_bus_n_address(udev, &bus, &address))
+        return;
+
+    for (i = 0; i < priv->devices->len; i++) {
+        curr = g_ptr_array_index(priv->devices, i);
+        if (libusb_get_bus_number(curr) == bus &&
+               libusb_get_device_address(curr) == address) {
+            device = curr;
+            break;
+        }
+    }
+    if (!device)
+        return;
+
+    spice_usb_device_manager_disconnect_device(self, (SpiceUsbDevice *)device);
 
     SPICE_DEBUG("device removed %p", device);
-    g_signal_emit(manager, signals[DEVICE_REMOVED], 0, device);
+    g_signal_emit(self, signals[DEVICE_REMOVED], 0, device);
     g_ptr_array_remove(priv->devices, device);
 }
 
+static void spice_usb_device_manager_uevent_cb(GUdevClient     *client,
+                                               const gchar     *action,
+                                               GUdevDevice     *udevice,
+                                               gpointer         user_data)
+{
+    SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(user_data);
+
+    if (g_str_equal(action, "add"))
+        spice_usb_device_manager_add_dev(self, udevice);
+    else if (g_str_equal (action, "remove"))
+        spice_usb_device_manager_remove_dev(self, udevice);
+}
+
 static void spice_usb_device_manager_channel_connect_cb(
     GObject *gobject, GAsyncResult *channel_res, gpointer user_data)
 {
@@ -469,9 +592,9 @@ static gpointer spice_usb_device_manager_usb_ev_thread(gpointer user_data)
     int rc;
 
     while (priv->event_thread_run) {
-        rc = libusb_handle_events(_g_usb_context_get_context(priv->context));
+        rc = libusb_handle_events(priv->context);
         if (rc) {
-            const char *desc = gusb_strerror(rc);
+            const char *desc = spice_usb_device_manager_libusb_strerror(rc);
             g_warning("Error handling USB events: %s [%i]", desc, rc);
         }
     }
@@ -522,7 +645,7 @@ static SpiceUsbredirChannel *spice_usb_device_manager_get_channel_for_dev(
 {
 #ifdef USE_USBREDIR
     SpiceUsbDeviceManagerPrivate *priv = manager->priv;
-    GUsbDevice *device = (GUsbDevice *)_device;
+    libusb_device *device = (libusb_device *)_device;
     guint i;
 
     for (i = 0; i < priv->channels->len; i++) {
@@ -586,10 +709,10 @@ GPtrArray* spice_usb_device_manager_get_devices(SpiceUsbDeviceManager *self)
 
     priv = self->priv;
     devices_copy = g_ptr_array_new_with_free_func((GDestroyNotify)
-                                                  g_object_unref);
+                                                  libusb_unref_device);
     for (i = 0; i < priv->devices->len; i++) {
-        SpiceUsbDevice *device = g_ptr_array_index(priv->devices, i);
-        g_ptr_array_add(devices_copy, g_object_ref(device));
+        libusb_device *device = g_ptr_array_index(priv->devices, i);
+        g_ptr_array_add(devices_copy, libusb_ref_device(device));
     }
 
     return devices_copy;
@@ -654,7 +777,7 @@ void spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
 
         spice_usbredir_channel_connect_async(channel,
                                  priv->context,
-                                 (GUsbDevice *)device,
+                                 (libusb_device *)device,
                                  cancellable,
                                  spice_usb_device_manager_channel_connect_cb,
                                  result);
@@ -721,16 +844,16 @@ void spice_usb_device_manager_disconnect_device(SpiceUsbDeviceManager *self,
  *
  * Returns: a newly-allocated string holding the description
  */
-gchar *spice_usb_device_get_description(SpiceUsbDevice *device)
+gchar *spice_usb_device_get_description(SpiceUsbDevice *_device)
 {
 #ifdef USE_USBREDIR
-    /* FIXME, extend gusb to get vid:pid + usb descriptor strings, use those */
+    libusb_device *device = (libusb_device *)_device;
     int bus, address;
 
     g_return_val_if_fail(device != NULL, NULL);
 
-    bus = g_usb_device_get_bus((GUsbDevice *)device);
-    address = g_usb_device_get_address((GUsbDevice *)device);
+    bus     = libusb_get_bus_number(device);
+    address = libusb_get_device_address(device);
 
     return g_strdup_printf("USB device at %d-%d", bus, address);
 #else
commit d65c19cb1e01a9bec981cf97c5aa24c7ebd96141
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Sun Dec 18 16:53:02 2011 +0100

    usbredir: Remove spice_usb_device_manager_get main_context argument
    
    Now that we no longer use a GUsbSource this is no longer needed.
    
    Note this is a change to our public API, but that is ok since we have not
    yet done an official release with usbredir support.
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/gtk/channel-usbredir.c b/gtk/channel-usbredir.c
index bb3303e..cc08af9 100644
--- a/gtk/channel-usbredir.c
+++ b/gtk/channel-usbredir.c
@@ -210,8 +210,7 @@ static gboolean spice_usbredir_channel_open_device(
 
     if (!spice_usb_device_manager_start_event_listening(
             spice_usb_device_manager_get(
-                spice_channel_get_session(SPICE_CHANNEL(channel)),
-                NULL, NULL),
+                spice_channel_get_session(SPICE_CHANNEL(channel)), NULL),
             err)) {
         usbredirhost_close(priv->host);
         priv->host = NULL;
@@ -363,8 +362,7 @@ void spice_usbredir_channel_disconnect(SpiceUsbredirChannel *channel)
          */
         spice_usb_device_manager_stop_event_listening(
             spice_usb_device_manager_get(
-                spice_channel_get_session(SPICE_CHANNEL(channel)),
-                NULL, NULL));
+                spice_channel_get_session(SPICE_CHANNEL(channel)), NULL));
         /* This also closes the libusb handle we passed to its _open */
         usbredirhost_close(priv->host);
         priv->host = NULL;
diff --git a/gtk/spice-gtk-session.c b/gtk/spice-gtk-session.c
index afabe8e..32848fa 100644
--- a/gtk/spice-gtk-session.c
+++ b/gtk/spice-gtk-session.c
@@ -799,7 +799,7 @@ void spice_gtk_session_update_keyboard_focus(SpiceGtkSession *self,
     if (s->auto_usbredir_enable && s->keyboard_focus)
         auto_connect = TRUE;
 
-    manager = spice_usb_device_manager_get(s->session, NULL, NULL);
+    manager = spice_usb_device_manager_get(s->session, NULL);
     if (manager) {
         g_object_set(manager, "auto-connect", auto_connect, NULL);
     }
diff --git a/gtk/spicy.c b/gtk/spicy.c
index 58a9b5c..e37ce82 100644
--- a/gtk/spicy.c
+++ b/gtk/spicy.c
@@ -1519,7 +1519,7 @@ static spice_connection *connection_new(void)
     g_signal_connect(conn->session, "notify::migration-state",
                      G_CALLBACK(migration_state), conn);
 
-    manager = spice_usb_device_manager_get(conn->session, NULL, NULL);
+    manager = spice_usb_device_manager_get(conn->session, NULL);
     if (manager) {
         g_signal_connect(manager, "auto-connect-failed",
                          G_CALLBACK(auto_connect_failed), NULL);
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index 910fd4e..53c0b8f 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -73,7 +73,6 @@ static void channel_destroy(SpiceSession *session, SpiceChannel *channel,
 enum {
     PROP_0,
     PROP_SESSION,
-    PROP_MAIN_CONTEXT,
     PROP_AUTO_CONNECT,
 };
 
@@ -87,7 +86,6 @@ enum
 
 struct _SpiceUsbDeviceManagerPrivate {
     SpiceSession *session;
-    GMainContext *main_context;
     gboolean auto_connect;
 #ifdef USE_USBREDIR
     GUsbContext *context;
@@ -215,11 +213,6 @@ static void spice_usb_device_manager_finalize(GObject *gobject)
     }
 #endif
 
-    if (priv->main_context) {
-        g_main_context_unref(priv->main_context);
-        priv->main_context = NULL;
-    }
-
     g_ptr_array_unref(priv->channels);
     g_ptr_array_unref(priv->devices);
 
@@ -245,9 +238,6 @@ static void spice_usb_device_manager_get_property(GObject     *gobject,
     case PROP_SESSION:
         g_value_set_object(value, priv->session);
         break;
-    case PROP_MAIN_CONTEXT:
-        g_value_set_boxed(value, priv->main_context);
-        break;
     case PROP_AUTO_CONNECT:
         g_value_set_boolean(value, priv->auto_connect);
         break;
@@ -269,9 +259,6 @@ static void spice_usb_device_manager_set_property(GObject       *gobject,
     case PROP_SESSION:
         priv->session = g_value_get_object(value);
         break;
-    case PROP_MAIN_CONTEXT:
-        priv->main_context = g_value_dup_boxed(value);
-        break;
     case PROP_AUTO_CONNECT:
         priv->auto_connect = g_value_get_boolean(value);
         break;
@@ -306,16 +293,6 @@ static void spice_usb_device_manager_class_init(SpiceUsbDeviceManagerClass *klas
                              G_PARAM_STATIC_STRINGS));
 
     /**
-     * SpiceUsbDeviceManager:main-context:
-     */
-    pspec = g_param_spec_boxed("main-context", "Main Context",
-                               "GMainContext to use for the event source",
-                               G_TYPE_MAIN_CONTEXT,
-                               G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
-                               G_PARAM_STATIC_STRINGS);
-    g_object_class_install_property(gobject_class, PROP_MAIN_CONTEXT, pspec);
-
-    /**
      * SpiceUsbDeviceManager:auto-connect:
      */
     pspec = g_param_spec_boolean("auto-connect", "Auto Connect",
@@ -563,7 +540,6 @@ static SpiceUsbredirChannel *spice_usb_device_manager_get_channel_for_dev(
 /**
  * spice_usb_device_manager_get:
  * @session: #SpiceSession for which to get the #SpiceUsbDeviceManager
- * @main_context: #GMainContext to use. If %NULL, the default context is used.
  *
  * Gets the #SpiceUsbDeviceManager associated with the passed in #SpiceSession.
  * A new #SpiceUsbDeviceManager instance will be created the first time this
@@ -575,7 +551,6 @@ static SpiceUsbredirChannel *spice_usb_device_manager_get_channel_for_dev(
  * Returns: (transfer none): a weak reference to the #SpiceUsbDeviceManager associated with the passed in #SpiceSession
  */
 SpiceUsbDeviceManager *spice_usb_device_manager_get(SpiceSession *session,
-                                                    GMainContext *main_context,
                                                     GError **err)
 {
     SpiceUsbDeviceManager *self;
@@ -587,8 +562,7 @@ SpiceUsbDeviceManager *spice_usb_device_manager_get(SpiceSession *session,
     self = session->priv->usb_manager;
     if (self == NULL) {
         self = g_initable_new(SPICE_TYPE_USB_DEVICE_MANAGER, NULL, err,
-                              "session", session,
-                              "main-context", main_context, NULL);
+                              "session", session, NULL);
         session->priv->usb_manager = self;
     }
     g_static_mutex_unlock(&mutex);
diff --git a/gtk/usb-device-manager.h b/gtk/usb-device-manager.h
index 2417674..a8b3969 100644
--- a/gtk/usb-device-manager.h
+++ b/gtk/usb-device-manager.h
@@ -90,7 +90,6 @@ GType spice_usb_device_manager_get_type(void);
 gchar *spice_usb_device_get_description(SpiceUsbDevice *device);
 
 SpiceUsbDeviceManager *spice_usb_device_manager_get(SpiceSession *session,
-                                                    GMainContext *main_context,
                                                     GError **err);
 
 GPtrArray *spice_usb_device_manager_get_devices(SpiceUsbDeviceManager *manager);
commit 0e4bec65353c645ce850c840bee4b63008db51e6
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Sun Dec 18 15:58:31 2011 +0100

    usbredir: Handle usb events from a thread
    
    This solves various latency issues with USB handling.
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/gtk/channel-usbredir.c b/gtk/channel-usbredir.c
index 09bd47d..bb3303e 100644
--- a/gtk/channel-usbredir.c
+++ b/gtk/channel-usbredir.c
@@ -356,6 +356,11 @@ void spice_usbredir_channel_disconnect(SpiceUsbredirChannel *channel)
     case STATE_CONNECTING:
     case STATE_CONNECTED:
         spice_channel_disconnect(SPICE_CHANNEL(channel), SPICE_CHANNEL_NONE);
+        /*
+         * This sets the usb event thread run condition to FALSE, therefor
+         * it must be done before usbredirhost_close, as usbredirhost_close
+         * will interrupt the libusb_handle_events call in the thread.
+         */
         spice_usb_device_manager_stop_event_listening(
             spice_usb_device_manager_get(
                 spice_channel_get_session(SPICE_CHANNEL(channel)),
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index 6fba6f6..910fd4e 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -26,8 +26,9 @@
 #include "glib-compat.h"
 
 #ifdef USE_USBREDIR
-#include <gusb/gusb-source.h>
 #include <gusb/gusb-device-list.h>
+#include <gusb/gusb-context-private.h>
+#include <gusb/gusb-util.h>
 #include "channel-usbredir-priv.h"
 #endif
 
@@ -91,8 +92,9 @@ struct _SpiceUsbDeviceManagerPrivate {
 #ifdef USE_USBREDIR
     GUsbContext *context;
     GUsbDeviceList *devlist;
-    GUsbSource *source;
     int event_listeners;
+    GThread *event_thread;
+    gboolean event_thread_run;
 #endif
     GPtrArray *devices;
     GPtrArray *channels;
@@ -204,6 +206,9 @@ static void spice_usb_device_manager_finalize(GObject *gobject)
     SpiceUsbDeviceManagerPrivate *priv = self->priv;
 
 #ifdef USE_USBREDIR
+    if (priv->event_thread)
+        g_thread_join(priv->event_thread);
+
     if (priv->devlist) {
         g_object_unref(priv->devlist);
         g_object_unref(priv->context);
@@ -480,6 +485,23 @@ 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;
+    int rc;
+
+    while (priv->event_thread_run) {
+        rc = libusb_handle_events(_g_usb_context_get_context(priv->context));
+        if (rc) {
+            const char *desc = gusb_strerror(rc);
+            g_warning("Error handling USB events: %s [%i]", desc, rc);
+        }
+    }
+
+    return NULL;
+}
+
 gboolean spice_usb_device_manager_start_event_listening(
     SpiceUsbDeviceManager *self, GError **err)
 {
@@ -491,10 +513,18 @@ gboolean spice_usb_device_manager_start_event_listening(
     if (priv->event_listeners > 1)
         return TRUE;
 
-    g_return_val_if_fail(priv->source == NULL, FALSE);
-
-    priv->source = g_usb_source_new(priv->main_context, priv->context, err);
-    return priv->source != NULL;
+    /* 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_thread_join(priv->event_thread);
+         priv->event_thread = NULL;
+    }
+    priv->event_thread_run = TRUE;
+    priv->event_thread = g_thread_create(
+                             spice_usb_device_manager_usb_ev_thread,
+                             self, TRUE, err);
+    return priv->event_thread != NULL;
 }
 
 void spice_usb_device_manager_stop_event_listening(
@@ -505,13 +535,8 @@ void spice_usb_device_manager_stop_event_listening(
     g_return_if_fail(priv->event_listeners > 0);
 
     priv->event_listeners--;
-    if (priv->event_listeners != 0)
-        return;
-
-    g_return_if_fail(priv->source != NULL);
-
-    g_usb_source_destroy(priv->source);
-    priv->source = NULL;
+    if (priv->event_listeners == 0)
+        priv->event_thread_run = FALSE;
 }
 #endif
 
commit 3db994f56295b0b946a9eb19cd469db7799006e4
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Sat Dec 17 12:21:24 2011 +0100

    usbredir: Add locking callbacks for libusbredirhost
    
    This is a preparation patch for handling usb packet completion in a
    separate thread.
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/gtk/channel-usbredir.c b/gtk/channel-usbredir.c
index f266cf3..09bd47d 100644
--- a/gtk/channel-usbredir.c
+++ b/gtk/channel-usbredir.c
@@ -195,10 +195,10 @@ static gboolean spice_usbredir_channel_open_device(
                                    usbredir_read_callback,
                                    usbredir_write_callback,
                                    usbredir_write_flush_callback,
-                                   NULL,
-                                   NULL,
-                                   NULL,
-                                   NULL,
+                                   (usbredirparser_alloc_lock)g_mutex_new,
+                                   (usbredirparser_lock)g_mutex_lock,
+                                   (usbredirparser_unlock)g_mutex_unlock,
+                                   (usbredirparser_free_lock)g_mutex_free,
                                    channel, PACKAGE_STRING,
                                    spice_util_get_debug() ? usbredirparser_debug : usbredirparser_warning,
                                    usbredirhost_fl_write_cb_owns_buffer);
commit 23ba4d499d0a1f5a5672adadb83bce176e8315d7
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Sat Dec 17 12:11:42 2011 +0100

    usbredir: Create USB event source on demand
    
    This is a preparation patch for handling usb packet completion in a
    separate thread.
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 2e76014..1aaf0ec 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -239,6 +239,7 @@ libspice_client_glib_2_0_la_SOURCES =	\
 	smartcard-manager.c		\
 	smartcard-manager-priv.h	\
 	usb-device-manager.c		\
+	usb-device-manager-priv.h	\
 	$(GUSB_SRCS)			\
 	$(USB_ACL_HELPER_SRCS)		\
 	\
diff --git a/gtk/channel-usbredir.c b/gtk/channel-usbredir.c
index 9db31ce..f266cf3 100644
--- a/gtk/channel-usbredir.c
+++ b/gtk/channel-usbredir.c
@@ -30,6 +30,7 @@
 #include "usb-acl-helper.h"
 #endif
 #include "channel-usbredir-priv.h"
+#include "usb-device-manager-priv.h"
 #endif
 
 #include "spice-client.h"
@@ -207,6 +208,16 @@ static gboolean spice_usbredir_channel_open_device(
         return FALSE;
     }
 
+    if (!spice_usb_device_manager_start_event_listening(
+            spice_usb_device_manager_get(
+                spice_channel_get_session(SPICE_CHANNEL(channel)),
+                NULL, NULL),
+            err)) {
+        usbredirhost_close(priv->host);
+        priv->host = NULL;
+        return FALSE;
+    }
+
     spice_channel_connect(SPICE_CHANNEL(channel));
     priv->state = STATE_CONNECTING;
 
@@ -345,6 +356,10 @@ void spice_usbredir_channel_disconnect(SpiceUsbredirChannel *channel)
     case STATE_CONNECTING:
     case STATE_CONNECTED:
         spice_channel_disconnect(SPICE_CHANNEL(channel), SPICE_CHANNEL_NONE);
+        spice_usb_device_manager_stop_event_listening(
+            spice_usb_device_manager_get(
+                spice_channel_get_session(SPICE_CHANNEL(channel)),
+                NULL, NULL));
         /* This also closes the libusb handle we passed to its _open */
         usbredirhost_close(priv->host);
         priv->host = NULL;
diff --git a/gtk/usb-device-manager-priv.h b/gtk/usb-device-manager-priv.h
new file mode 100644
index 0000000..841c725
--- /dev/null
+++ b/gtk/usb-device-manager-priv.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2011 Red Hat, Inc.
+
+   Red Hat Authors:
+   Hans de Goede <hdegoede 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 __SPICE_USB_DEVICE_MANAGER_PRIV_H__
+#define __SPICE_USB_DEVICE_MANAGER_PRIV_H__
+
+#include "usb-device-manager.h"
+
+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);
+
+G_END_DECLS
+
+#endif /* __SPICE_USB_DEVICE_MANAGER_PRIV_H__ */
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index fcd1685..6fba6f6 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -34,6 +34,7 @@
 #include "spice-session-priv.h"
 #include "spice-client.h"
 #include "spice-marshal.h"
+#include "usb-device-manager-priv.h"
 
 /**
  * SECTION:usb-device-manager
@@ -91,6 +92,7 @@ struct _SpiceUsbDeviceManagerPrivate {
     GUsbContext *context;
     GUsbDeviceList *devlist;
     GUsbSource *source;
+    int event_listeners;
 #endif
     GPtrArray *devices;
     GPtrArray *channels;
@@ -202,8 +204,6 @@ static void spice_usb_device_manager_finalize(GObject *gobject)
     SpiceUsbDeviceManagerPrivate *priv = self->priv;
 
 #ifdef USE_USBREDIR
-    if (priv->source)
-        g_usb_source_destroy(priv->source);
     if (priv->devlist) {
         g_object_unref(priv->devlist);
         g_object_unref(priv->context);
@@ -476,10 +476,45 @@ static void spice_usb_device_manager_channel_connect_cb(
     g_simple_async_result_complete(result);
     g_object_unref(result);
 }
-#endif
 
 /* ------------------------------------------------------------------ */
 /* private api                                                        */
+
+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;
+
+    g_return_val_if_fail(priv->source == NULL, FALSE);
+
+    priv->source = g_usb_source_new(priv->main_context, priv->context, err);
+    return priv->source != 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)
+        return;
+
+    g_return_if_fail(priv->source != NULL);
+
+    g_usb_source_destroy(priv->source);
+    priv->source = NULL;
+}
+#endif
+
 static SpiceUsbredirChannel *spice_usb_device_manager_get_channel_for_dev(
     SpiceUsbDeviceManager *manager, SpiceUsbDevice *_device)
 {
@@ -603,7 +638,6 @@ void spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
 
 #ifdef USE_USBREDIR
     SpiceUsbDeviceManagerPrivate *priv = self->priv;
-    GError *e = NULL;
     guint i;
 
     if (spice_usb_device_manager_is_device_connected(self, device)) {
@@ -613,14 +647,6 @@ void spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
         goto done;
     }
 
-    if (!priv->source) {
-        priv->source = g_usb_source_new(priv->main_context, priv->context, &e);
-        if (e) {
-            g_simple_async_result_take_error(result, e);
-            goto done;
-        }
-    }
-
     for (i = 0; i < priv->channels->len; i++) {
         SpiceUsbredirChannel *channel = g_ptr_array_index(priv->channels, i);
 
commit 65fef5265178ca45bfc50020e57382f63470cf6a
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Thu Dec 15 16:01:56 2011 +0100

    usbredir: Use new libusbredirhost write flush callback
    
    The new (in usbredir-0.3.2) usbredirhost_open_full()
    function allows us to be notified whenever usb packets completing
    result in data to be send to the host. This removes the need for using
    g_usb_source_set_callback and seeing if there is data to write on
    any of the usb channels each time some usb event happens.
    
    This also bumps the minimum needed libusbredirhost version to 0.3.2
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/configure.ac b/configure.ac
index 3c5689d..5788532 100644
--- a/configure.ac
+++ b/configure.ac
@@ -330,7 +330,7 @@ if test "x$enable_usbredir" = "xno"; then
 else
   PKG_CHECK_MODULES(GUDEV, gudev-1.0)
   PKG_CHECK_MODULES(LIBUSB, libusb-1.0 >= 1.0.9)
-  PKG_CHECK_MODULES(LIBUSBREDIRHOST, libusbredirhost >= 0.3.1)
+  PKG_CHECK_MODULES(LIBUSBREDIRHOST, libusbredirhost >= 0.3.2)
   AC_DEFINE(USE_USBREDIR, [1], [Define if supporting usbredir proxying])
   AM_CONDITIONAL(WITH_USBREDIR, true)
   if test "x$enable_polkit" = "xno"; then
diff --git a/gtk/channel-usbredir-priv.h b/gtk/channel-usbredir-priv.h
index 8bb42a5..305e897 100644
--- a/gtk/channel-usbredir-priv.h
+++ b/gtk/channel-usbredir-priv.h
@@ -42,8 +42,6 @@ void spice_usbredir_channel_disconnect(SpiceUsbredirChannel *channel);
 
 GUsbDevice *spice_usbredir_channel_get_device(SpiceUsbredirChannel *channel);
 
-void spice_usbredir_channel_do_write(SpiceUsbredirChannel *channel);
-
 G_END_DECLS
 
 #endif /* __SPICE_CLIENT_USBREDIR_CHANNEL_PRIV_H__ */
diff --git a/gtk/channel-usbredir.c b/gtk/channel-usbredir.c
index bbfb9e9..9db31ce 100644
--- a/gtk/channel-usbredir.c
+++ b/gtk/channel-usbredir.c
@@ -73,7 +73,6 @@ struct _SpiceUsbredirChannelPrivate {
     /* Data passed from channel handle msg to the usbredirhost read cb */
     const uint8_t *read_buf;
     int read_buf_size;
-    SpiceMsgOut *msg_out;
     enum SpiceUsbredirChannelState state;
 #if USE_POLKIT
     GSimpleAsyncResult *result;
@@ -89,6 +88,7 @@ static void usbredir_handle_msg(SpiceChannel *channel, SpiceMsgIn *in);
 static void usbredir_log(void *user_data, int level, const char *msg);
 static int usbredir_read_callback(void *user_data, uint8_t *data, int count);
 static int usbredir_write_callback(void *user_data, uint8_t *data, int count);
+static void usbredir_write_flush_callback(void *user_data);
 #endif
 
 G_DEFINE_TYPE(SpiceUsbredirChannel, spice_usbredir_channel, SPICE_TYPE_CHANNEL)
@@ -188,10 +188,16 @@ static gboolean spice_usbredir_channel_open_device(
     }
 
     priv->catch_error = err;
-    priv->host = usbredirhost_open(_g_usb_context_get_context(priv->context),
+    priv->host = usbredirhost_open_full(
+                                   _g_usb_context_get_context(priv->context),
                                    handle, usbredir_log,
                                    usbredir_read_callback,
                                    usbredir_write_callback,
+                                   usbredir_write_flush_callback,
+                                   NULL,
+                                   NULL,
+                                   NULL,
+                                   NULL,
                                    channel, PACKAGE_STRING,
                                    spice_util_get_debug() ? usbredirparser_debug : usbredirparser_warning,
                                    usbredirhost_fl_write_cb_owns_buffer);
@@ -355,26 +361,17 @@ GUsbDevice *spice_usbredir_channel_get_device(SpiceUsbredirChannel *channel)
     return channel->priv->device;
 }
 
-G_GNUC_INTERNAL
-void spice_usbredir_channel_do_write(SpiceUsbredirChannel *channel)
+/* Note that this function must be re-entrant safe, as it can get called
+   from both the main thread as well as from the usb event handling thread */
+static void usbredir_write_flush_callback(void *user_data)
 {
+    SpiceUsbredirChannel *channel = SPICE_USBREDIR_CHANNEL(user_data);
     SpiceUsbredirChannelPrivate *priv = channel->priv;
 
-    /* No recursion allowed! */
-    g_return_if_fail(priv->msg_out == NULL);
-
-    if (priv->state != STATE_CONNECTED ||
-            !usbredirhost_has_data_to_write(priv->host))
+    if (priv->state != STATE_CONNECTED)
         return;
 
-    priv->msg_out = spice_msg_out_new(SPICE_CHANNEL(channel),
-                                      SPICE_MSGC_SPICEVMC_DATA);
-
-    /* Collect all pending writes in priv->msg_out->marshaller */
     usbredirhost_write_guest_data(priv->host);
-
-    spice_msg_out_send(priv->msg_out);
-    priv->msg_out = NULL;
 }
 
 /* ------------------------------------------------------------------ */
@@ -434,10 +431,14 @@ static void usbredir_free_write_cb_data(uint8_t *data, void *user_data)
 static int usbredir_write_callback(void *user_data, uint8_t *data, int count)
 {
     SpiceUsbredirChannel *channel = user_data;
-    SpiceUsbredirChannelPrivate *priv = channel->priv;
+    SpiceMsgOut *msg_out;
 
-    spice_marshaller_add_ref_full(priv->msg_out->marshaller, data, count,
+    msg_out = spice_msg_out_new(SPICE_CHANNEL(channel),
+                                SPICE_MSGC_SPICEVMC_DATA);
+    spice_marshaller_add_ref_full(msg_out->marshaller, data, count,
                                   usbredir_free_write_cb_data, channel);
+    spice_msg_out_send(msg_out);
+
     return count;
 }
 
@@ -469,7 +470,7 @@ static void spice_usbredir_channel_up(SpiceChannel *c)
 
     priv->state = STATE_CONNECTED;
     /* Flush any pending writes */
-    spice_usbredir_channel_do_write(channel);
+    usbredirhost_write_guest_data(priv->host);
 }
 
 static void usbredir_handle_msg(SpiceChannel *c, SpiceMsgIn *in)
@@ -489,8 +490,6 @@ static void usbredir_handle_msg(SpiceChannel *c, SpiceMsgIn *in)
     priv->read_buf_size = size;
 
     usbredirhost_read_guest_data(priv->host);
-    /* Send any acks, etc. which may be queued now */
-    spice_usbredir_channel_do_write(channel);
 }
 
 #endif /* USE_USBREDIR */
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index ea43b75..fcd1685 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -404,25 +404,6 @@ static void channel_destroy(SpiceSession *session, SpiceChannel *channel,
 }
 
 #ifdef USE_USBREDIR
-static gboolean spice_usb_device_manager_source_callback(gpointer user_data)
-{
-    SpiceUsbDeviceManager *self = user_data;
-    SpiceUsbDeviceManagerPrivate *priv = self->priv;
-    guint i;
-
-    /*
-     * Flush any writes which may have been caused by async usb packets
-     * completing.
-     */
-    for (i = 0; i < priv->channels->len; i++) {
-        SpiceUsbredirChannel *channel = g_ptr_array_index(priv->channels, i);
-
-        spice_usbredir_channel_do_write(channel);
-    }
-
-    return TRUE;
-}
-
 static void spice_usb_device_manager_auto_connect_cb(GObject      *gobject,
                                                      GAsyncResult *res,
                                                      gpointer      user_data)
@@ -638,10 +619,6 @@ void spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
             g_simple_async_result_take_error(result, e);
             goto done;
         }
-
-        g_usb_source_set_callback(priv->source,
-                                  spice_usb_device_manager_source_callback,
-                                  self, NULL);
     }
 
     for (i = 0; i < priv->channels->len; i++) {
commit a0aab8b57a9ddd8abba934715cee02f72ca75096
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Sun Dec 18 15:59:41 2011 +0100

    usbredir: USB channels can not be read only
    
    A usbredir channel must always be bi-directional. spice-server
    allows only one client to connect even when in multi-client mode. Since
    usually there are multiple usb channels available, it is allowed for one client
    to use one channel, while another client uses another usb channel.
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/gtk/channel-usbredir.c b/gtk/channel-usbredir.c
index d9cc03e..bbfb9e9 100644
--- a/gtk/channel-usbredir.c
+++ b/gtk/channel-usbredir.c
@@ -360,9 +360,6 @@ void spice_usbredir_channel_do_write(SpiceUsbredirChannel *channel)
 {
     SpiceUsbredirChannelPrivate *priv = channel->priv;
 
-    if (spice_channel_get_read_only(SPICE_CHANNEL(channel)))
-        return;
-
     /* No recursion allowed! */
     g_return_if_fail(priv->msg_out == NULL);
 
commit b4d5d887b432e37dfbd9f89c1e9e3299ed469e8d
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Sun Dec 18 16:31:30 2011 +0100

    usbredir: Stop setting private data explictly to NULL on init
    
    This is not necessary and as we get more private data it becomes
    unyieldly.
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index 313b6ab..ea43b75 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -122,15 +122,9 @@ static void spice_usb_device_manager_init(SpiceUsbDeviceManager *self)
     priv = SPICE_USB_DEVICE_MANAGER_GET_PRIVATE(self);
     self->priv = priv;
 
-    priv->main_context = NULL;
     priv->channels = g_ptr_array_new();
     priv->devices  = g_ptr_array_new_with_free_func((GDestroyNotify)
                                                     g_object_unref);
-#ifdef USE_USBREDIR
-    priv->context = NULL;
-    priv->source  = NULL;
-    priv->devlist = NULL;
-#endif
 }
 
 static gboolean spice_usb_device_manager_initable_init(GInitable  *initable,
commit c2ba62666beaee526e1b4288f9bd66976ce780ef
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Fri Dec 16 11:42:42 2011 +0100

    spice-channel: Allow spice_msg_out_send to be called from multiple threads
    
    This is a preparation patch for handling usb packet completion in a
    separate thread.
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h
index 5585f13..df35e4c 100644
--- a/gtk/spice-channel-priv.h
+++ b/gtk/spice-channel-priv.h
@@ -95,6 +95,9 @@ struct _SpiceChannelPrivate {
 
     struct wait_queue           wait;
     GQueue                      xmit_queue;
+    gboolean                    xmit_queue_blocked;
+    GStaticMutex                xmit_queue_lock;
+    GThread                     *main_thread;
 
     char                        name[16];
     enum spice_channel_state    state;
diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
index f4c398d..079028a 100644
--- a/gtk/spice-channel.c
+++ b/gtk/spice-channel.c
@@ -107,6 +107,8 @@ static void spice_channel_init(SpiceChannel *channel)
     c->remote_common_caps = g_array_new(FALSE, TRUE, sizeof(guint32));
     spice_channel_set_common_capability(channel, SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION);
     g_queue_init(&c->xmit_queue);
+    g_static_mutex_init(&c->xmit_queue_lock);
+    c->main_thread = g_thread_self();
 }
 
 static void spice_channel_constructed(GObject *gobject)
@@ -538,16 +540,35 @@ void spice_msg_out_unref(SpiceMsgOut *out)
 }
 
 /* system context */
+static gboolean spice_channel_idle_wakeup(gpointer user_data)
+{
+    SpiceChannel *channel = SPICE_CHANNEL(user_data);
+
+    spice_channel_wakeup(channel);
+    g_object_unref(channel);
+
+    return FALSE;
+}
+
+/* system context */
 G_GNUC_INTERNAL
 void spice_msg_out_send(SpiceMsgOut *out)
 {
     g_return_if_fail(out != NULL);
     g_return_if_fail(out->channel != NULL);
 
-    g_queue_push_tail(&out->channel->priv->xmit_queue, out);
+    g_static_mutex_lock(&out->channel->priv->xmit_queue_lock);
+    if (!out->channel->priv->xmit_queue_blocked)
+        g_queue_push_tail(&out->channel->priv->xmit_queue, out);
+    g_static_mutex_unlock(&out->channel->priv->xmit_queue_lock);
 
     /* TODO: we currently flush/wakeup immediately all buffered messages */
-    spice_channel_wakeup(out->channel);
+    if (g_thread_self() != out->channel->priv->main_thread)
+        /* We use g_timeout_add_full so that can specify the priority */
+        g_timeout_add_full(G_PRIORITY_HIGH, 0, spice_channel_idle_wakeup,
+                           g_object_ref(out->channel), NULL);
+    else
+        spice_channel_wakeup(out->channel);
 }
 
 /* coroutine context */
@@ -1788,8 +1809,13 @@ static void spice_channel_iterate_write(SpiceChannel *channel)
     SpiceChannelPrivate *c = channel->priv;
     SpiceMsgOut *out;
 
-    while ((out = g_queue_pop_head(&c->xmit_queue)))
-        spice_channel_write_msg(channel, out);
+    do {
+        g_static_mutex_lock(&c->xmit_queue_lock);
+        out = g_queue_pop_head(&c->xmit_queue);
+        g_static_mutex_unlock(&c->xmit_queue_lock);
+        if (out)
+            spice_channel_write_msg(channel, out);
+    } while (out);
 }
 
 /* coroutine context */
@@ -2089,6 +2115,7 @@ static gboolean channel_connect(SpiceChannel *channel)
         }
     }
     c->state = SPICE_CHANNEL_STATE_CONNECTING;
+    c->xmit_queue_blocked = FALSE;
 
     g_return_val_if_fail(c->sock == NULL, FALSE);
     g_object_ref(G_OBJECT(channel)); /* Unref'd when co-routine exits */
@@ -2181,8 +2208,11 @@ static void channel_reset(SpiceChannel *channel, gboolean migrating)
     c->peer_msg = NULL;
     c->peer_pos = 0;
 
+    g_static_mutex_lock(&c->xmit_queue_lock);
+    c->xmit_queue_blocked = TRUE; /* Disallow queuing new messages */
     g_queue_foreach(&c->xmit_queue, (GFunc)spice_msg_out_unref, NULL);
     g_queue_clear(&c->xmit_queue);
+    g_static_mutex_unlock(&c->xmit_queue_lock);
 
     g_array_set_size(c->remote_common_caps, 0);
     g_array_set_size(c->remote_caps, 0);


More information about the Spice-commits mailing list