[Spice-commits] 22 commits - configure.ac gtk/channel-usbredir.c gtk/controller gtk/Makefile.am gtk/spicy.c gtk/usb-device-manager.c gtk/usb-device-manager-priv.h gtk/win-usb-clerk.h gtk/win-usb-dev.c gtk/win-usb-dev.h gtk/win-usb-driver-install.c gtk/win-usb-driver-install.h
Uri Lublin
uril at kemper.freedesktop.org
Tue Jul 10 07:48:43 PDT 2012
configure.ac | 15 +
gtk/Makefile.am | 18 +
gtk/channel-usbredir.c | 2
gtk/controller/test.c | 4
gtk/spicy.c | 2
gtk/usb-device-manager-priv.h | 11
gtk/usb-device-manager.c | 574 +++++++++++++++++++++++++++++++++++++-----
gtk/win-usb-clerk.h | 35 ++
gtk/win-usb-dev.c | 532 ++++++++++++++++++++++++++++++++++++++
gtk/win-usb-dev.h | 110 ++++++++
gtk/win-usb-driver-install.c | 384 ++++++++++++++++++++++++++++
gtk/win-usb-driver-install.h | 104 +++++++
12 files changed, 1725 insertions(+), 66 deletions(-)
New commits:
commit 00cbbf53af886b79a30655726d57f1d9e60f8167
Author: Uri Lublin <uril at redhat.com>
Date: Thu Jul 5 23:44:08 2012 +0300
usb-device-manager: mingw: ignore "remove" udev event when un/installing a driver
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index 5228394..58dde67 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -719,6 +719,16 @@ static void spice_usb_device_manager_remove_dev(SpiceUsbDeviceManager *self,
return;
}
+#ifdef G_OS_WIN32
+ const guint8 state = spice_usb_device_get_state(device);
+ if ((state == SPICE_USB_DEVICE_STATE_INSTALLING) ||
+ (state == SPICE_USB_DEVICE_STATE_UNINSTALLING)) {
+ SPICE_DEBUG("skipping device at %d.%d. It is un/installing it's driver",
+ bus, address);
+ return;
+ }
+#endif
+
spice_usb_device_manager_disconnect_device(self, device);
SPICE_DEBUG("device removed %p", device);
commit 62e9488868e96ac69fb97d24dd1b509db2fdaf68
Author: Uri Lublin <uril at redhat.com>
Date: Thu Jul 5 23:44:07 2012 +0300
usb-device-manager: mingw: keep driver install/uninstall state of a device
Currently only driver install/unsinstall is of interest, such that
extra udev events can be ignored.
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index 2670713..5228394 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -820,6 +820,8 @@ static void spice_usb_device_manager_drv_install_cb(GObject *gobject,
g_object_unref(installer);
spice_usb_device_unref(device);
+ spice_usb_device_set_state(device, SPICE_USB_DEVICE_STATE_NONE);
+
if (err) {
g_warning("win usb driver %s failed -- %s", opstr, err->message);
g_error_free(err);
@@ -1091,6 +1093,7 @@ void spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
SpiceWinUsbDriver *installer;
UsbInstallCbInfo *cbinfo;
+ spice_usb_device_set_state(device, SPICE_USB_DEVICE_STATE_INSTALLING);
installer = spice_win_usb_driver_new();
cbinfo = g_new0(UsbInstallCbInfo, 1);
cbinfo->manager = self;
@@ -1156,6 +1159,7 @@ void spice_usb_device_manager_disconnect_device(SpiceUsbDeviceManager *self,
g_warn_if_fail(device != NULL);
+ spice_usb_device_set_state(device, SPICE_USB_DEVICE_STATE_UNINSTALLING);
installer = spice_win_usb_driver_new();
cbinfo = g_new0(UsbInstallCbInfo, 1);
cbinfo->manager = self;
commit fb6eb40ab48b437b9d8e5f884765844b56f39d9c
Author: Uri Lublin <uril at redhat.com>
Date: Thu Jul 5 23:44:06 2012 +0300
usb-device-manager: add 'state' field to SpiceUsbDeviceInfo
To be used on Win32 to ignore extra udev events
received during driver install/uninstall.
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index e5b02c0..2670713 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -110,6 +110,16 @@ struct _SpiceUsbDeviceManagerPrivate {
GPtrArray *channels;
};
+enum {
+ SPICE_USB_DEVICE_STATE_NONE = 0, /* this is also DISCONNECTED */
+ SPICE_USB_DEVICE_STATE_CONNECTING,
+ SPICE_USB_DEVICE_STATE_CONNECTED,
+ SPICE_USB_DEVICE_STATE_DISCONNECTING,
+ SPICE_USB_DEVICE_STATE_INSTALLING,
+ SPICE_USB_DEVICE_STATE_UNINSTALLING,
+ SPICE_USB_DEVICE_STATE_MAX
+};
+
#ifdef USE_USBREDIR
typedef struct _SpiceUsbDeviceInfo {
@@ -117,6 +127,8 @@ typedef struct _SpiceUsbDeviceInfo {
guint8 devaddr;
guint16 vid;
guint16 pid;
+ guint8 state;
+ guint8 reserved;
gint ref;
} SpiceUsbDeviceInfo;
@@ -136,6 +148,11 @@ static SpiceUsbDeviceInfo *spice_usb_device_new(libusb_device *libdev);
static SpiceUsbDevice *spice_usb_device_ref(SpiceUsbDevice *device);
static void spice_usb_device_unref(SpiceUsbDevice *device);
+#ifdef G_OS_WIN32
+static guint8 spice_usb_device_get_state(SpiceUsbDevice *device);
+static void spice_usb_device_set_state(SpiceUsbDevice *device, guint8 s);
+#endif
+
static gboolean spice_usb_device_equal_libdev(SpiceUsbDevice *device,
libusb_device *libdev);
static SpiceUsbDevice *
@@ -1364,6 +1381,26 @@ guint16 spice_usb_device_get_pid(SpiceUsbDevice *device)
return info->pid;
}
+#ifdef G_OS_WIN32
+void spice_usb_device_set_state(SpiceUsbDevice *device, guint8 state)
+{
+ SpiceUsbDeviceInfo *info = (SpiceUsbDeviceInfo *)device;
+
+ g_return_if_fail(info != NULL);
+
+ info->state = state;
+}
+
+guint8 spice_usb_device_get_state(SpiceUsbDevice *device)
+{
+ SpiceUsbDeviceInfo *info = (SpiceUsbDeviceInfo *)device;
+
+ g_return_val_if_fail(info != NULL, 0);
+
+ return info->state;
+}
+#endif
+
static SpiceUsbDevice *spice_usb_device_ref(SpiceUsbDevice *device)
{
SpiceUsbDeviceInfo *info = (SpiceUsbDeviceInfo *)device;
commit e26f4bffa41ec73ec7abdbde149117d5649d7ad0
Author: Uri Lublin <uril at redhat.com>
Date: Thu Jul 5 23:44:02 2012 +0300
Win32/mingw: win-usb-dev: skip hubs
also skip devices with bad (0) device-address.
diff --git a/gtk/win-usb-dev.c b/gtk/win-usb-dev.c
index bc21e08..c188807 100644
--- a/gtk/win-usb-dev.c
+++ b/gtk/win-usb-dev.c
@@ -94,6 +94,8 @@ static void g_udev_device_print_list(GList *l, const gchar *msg) {}
#endif
static void g_udev_device_print(GUdevDevice *udev, const gchar *msg);
+static gboolean g_udev_skip_search(GUdevDevice *udev);
+
GQuark g_udev_client_error_quark(void)
{
return g_quark_from_static_string("win-gudev-client-error-quark");
@@ -142,13 +144,17 @@ g_udev_client_list_devices(GUdevClient *self, GList **devs,
return -4;
}
- n = rc;
-
+ n = 0;
for (dev = lusb_list; *dev; dev++) {
udevinfo = g_new0(GUdevDeviceInfo, 1);
get_usb_dev_info(*dev, udevinfo);
udevice = g_udev_device_new(udevinfo);
+ if (g_udev_skip_search(udevice)) {
+ g_object_unref(udevice);
+ continue;
+ }
*devs = g_list_prepend(*devs, udevice);
+ n++;
}
libusb_free_device_list(lusb_list, 1);
@@ -508,3 +514,19 @@ static void g_udev_device_print(GUdevDevice *udev, const gchar *msg)
udevinfo->bus, udevinfo->addr,
udevinfo->vid, udevinfo->pid, udevinfo->class);
}
+
+static gboolean g_udev_skip_search(GUdevDevice *udev)
+{
+ GUdevDeviceInfo* udevinfo;
+ gboolean skip;
+
+ g_return_val_if_fail(G_UDEV_DEVICE(udev), FALSE);
+
+ udevinfo = udev->priv->udevinfo;
+ g_return_val_if_fail(udevinfo != NULL, FALSE);
+
+ skip = ((udevinfo->addr == 0xff) || /* root hub (HCD) */
+ (udevinfo->class == LIBUSB_CLASS_HUB) || /* hub*/
+ (udevinfo->addr == 0)); /* bad address */
+ return skip;
+}
commit 6b806a6e1e31489db78e7ebb8d51ab677ef4a92c
Author: Uri Lublin <uril at redhat.com>
Date: Sun Jul 8 18:12:39 2012 +0300
Win32/mingw: usb-device-manager: uninstall win usb driver upon device disconnect
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index 2f0d6f1..e5b02c0 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -746,6 +746,7 @@ typedef struct _UsbInstallCbInfo {
GCancellable *cancellable;
GAsyncReadyCallback callback;
gpointer user_data;
+ gboolean is_install;
} UsbInstallCbInfo;
/**
@@ -774,8 +775,8 @@ static void spice_usb_device_manager_drv_install_cb(GObject *gobject,
UsbInstallCbInfo *cbinfo;
GCancellable *cancellable;
GAsyncReadyCallback callback;
-
- SPICE_DEBUG("Win USB driver Installation finished");
+ gboolean is_install;
+ const gchar *opstr;
g_return_if_fail(user_data != NULL);
@@ -786,6 +787,7 @@ static void spice_usb_device_manager_drv_install_cb(GObject *gobject,
cancellable = cbinfo->cancellable;
callback = cbinfo->callback;
user_data = cbinfo->user_data;
+ is_install = cbinfo->is_install;
g_free(cbinfo);
@@ -793,19 +795,25 @@ static void spice_usb_device_manager_drv_install_cb(GObject *gobject,
g_return_if_fail(SPICE_IS_WIN_USB_DRIVER(installer));
g_return_if_fail(device!= NULL);
+ opstr = is_install ? "install" : "uninstall";
+ SPICE_DEBUG("Win USB driver %s finished", opstr);
+
status = spice_win_usb_driver_install_finish(installer, res, &err);
g_object_unref(installer);
spice_usb_device_unref(device);
if (err) {
- g_warning("win usb driver installation failed -- %s",
- err->message);
+ g_warning("win usb driver %s failed -- %s", opstr, err->message);
g_error_free(err);
}
if (!status) {
- g_warning("failed to install win usb driver (status=0)");
+ g_warning("failed to %s win usb driver (status=0)", opstr);
+ }
+
+ if (! is_install) {
+ return;
}
/* device is already ref'ed */
@@ -1074,6 +1082,8 @@ void spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
cbinfo->cancellable = cancellable;
cbinfo->callback = callback;
cbinfo->user_data = user_data;
+ cbinfo->is_install = TRUE;
+
spice_win_usb_driver_install(installer, device, cancellable,
spice_usb_device_manager_drv_install_cb,
cbinfo);
@@ -1122,6 +1132,28 @@ void spice_usb_device_manager_disconnect_device(SpiceUsbDeviceManager *self,
channel = spice_usb_device_manager_get_channel_for_dev(self, device);
if (channel)
spice_usbredir_channel_disconnect_device(channel);
+
+#ifdef G_OS_WIN32
+ SpiceWinUsbDriver *installer;
+ UsbInstallCbInfo *cbinfo;
+
+ g_warn_if_fail(device != NULL);
+
+ installer = spice_win_usb_driver_new();
+ cbinfo = g_new0(UsbInstallCbInfo, 1);
+ cbinfo->manager = self;
+ cbinfo->device = spice_usb_device_ref(device);
+ cbinfo->installer = installer;
+ cbinfo->cancellable = NULL;
+ cbinfo->callback = NULL;
+ cbinfo->user_data = NULL;
+ cbinfo->is_install = FALSE;
+
+ spice_win_usb_driver_uninstall(installer, device, NULL,
+ spice_usb_device_manager_drv_install_cb,
+ cbinfo);
+#endif
+
#endif
}
commit 147c0d1bb293c3888b34880f7a7adcf7ac622523
Author: Uri Lublin <uril at redhat.com>
Date: Thu Jul 5 23:44:00 2012 +0300
win-usb-driver-install: add capability to remove (uninstall) a win usb driver
diff --git a/gtk/win-usb-driver-install.c b/gtk/win-usb-driver-install.c
index 5b9db62..8b326b5 100644
--- a/gtk/win-usb-driver-install.c
+++ b/gtk/win-usb-driver-install.c
@@ -246,29 +246,19 @@ SpiceWinUsbDriver *spice_win_usb_driver_new(void)
return SPICE_WIN_USB_DRIVER(obj);
}
-/**
- * spice_win_usb_driver_install:
- * Start libusb driver installation for @device
- *
- * A new NamedPipe is created for each request.
- *
- * Returns: TRUE if a request was sent to usbclerk
- * FALSE upon failure to send a request.
- */
-G_GNUC_INTERNAL
-void spice_win_usb_driver_install(SpiceWinUsbDriver *self,
- SpiceUsbDevice *device,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+static
+void spice_win_usb_driver_op(SpiceWinUsbDriver *self,
+ SpiceUsbDevice *device,
+ guint16 op_type,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
guint16 vid, pid;
GError *err = NULL;
GSimpleAsyncResult *result;
SpiceWinUsbDriverPrivate *priv;
- SPICE_DEBUG("Win usb driver installation started");
-
g_return_if_fail(SPICE_IS_WIN_USB_DRIVER(self));
g_return_if_fail(device != NULL);
@@ -277,7 +267,7 @@ void spice_win_usb_driver_install(SpiceWinUsbDriver *self,
g_return_if_fail(priv->result == NULL);
result = g_simple_async_result_new(G_OBJECT(self), callback, user_data,
- spice_win_usb_driver_install);
+ spice_win_usb_driver_op);
vid = spice_usb_device_get_vid(device);
pid = spice_usb_device_get_pid(device);
@@ -300,7 +290,7 @@ void spice_win_usb_driver_install(SpiceWinUsbDriver *self,
goto failed_request;
}
- if (!spice_win_usb_driver_send_request(self, USB_CLERK_DRIVER_INSTALL,
+ if (!spice_win_usb_driver_send_request(self, op_type,
vid, pid, &err)) {
g_warning("failed to send a request to usbclerk %s", err->message);
g_simple_async_result_take_error(result, err);
@@ -323,6 +313,43 @@ void spice_win_usb_driver_install(SpiceWinUsbDriver *self,
}
+
+/**
+ * spice_win_usb_driver_install:
+ * Start libusb driver installation for @device
+ *
+ * A new NamedPipe is created for each request.
+ *
+ * Returns: TRUE if a request was sent to usbclerk
+ * FALSE upon failure to send a request.
+ */
+G_GNUC_INTERNAL
+void spice_win_usb_driver_install(SpiceWinUsbDriver *self,
+ SpiceUsbDevice *device,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ SPICE_DEBUG("Win usb driver installation started");
+
+ spice_win_usb_driver_op(self, device, USB_CLERK_DRIVER_INSTALL, cancellable,
+ callback, user_data);
+}
+
+G_GNUC_INTERNAL
+void spice_win_usb_driver_uninstall(SpiceWinUsbDriver *self,
+ SpiceUsbDevice *device,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ SPICE_DEBUG("Win usb driver uninstall operation started");
+
+ spice_win_usb_driver_op(self, device, USB_CLERK_DRIVER_REMOVE, cancellable,
+ callback, user_data);
+}
+
+
/**
* Returns: currently returns 0 (failure) and 1 (success)
* possibly later we'll add error-codes
@@ -335,7 +362,7 @@ gint spice_win_usb_driver_install_finish(SpiceWinUsbDriver *self,
g_return_val_if_fail(SPICE_IS_WIN_USB_DRIVER(self), 0);
g_return_val_if_fail(g_simple_async_result_is_valid(res, G_OBJECT(self),
- spice_win_usb_driver_install),
+ spice_win_usb_driver_op),
FALSE);
if (g_simple_async_result_propagate_error(result, err))
return 0;
diff --git a/gtk/win-usb-driver-install.h b/gtk/win-usb-driver-install.h
index b0ccf33..034abf9 100644
--- a/gtk/win-usb-driver-install.h
+++ b/gtk/win-usb-driver-install.h
@@ -70,6 +70,12 @@ void spice_win_usb_driver_install(SpiceWinUsbDriver *self,
GAsyncReadyCallback callback,
gpointer user_data);
+void spice_win_usb_driver_uninstall(SpiceWinUsbDriver *self,
+ SpiceUsbDevice *device,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
gint spice_win_usb_driver_install_finish(SpiceWinUsbDriver *self,
GAsyncResult *res, GError **err);
commit 714def3df0dc5547c459dcdcae5f8aa3232999ff
Author: Uri Lublin <uril at redhat.com>
Date: Thu Jul 5 23:43:58 2012 +0300
Windows mingw: usb: Dynamically install a libusb driver for USB devices
- Added win-usb-driver-install.[ch]
- Added win-usb-clerk.h
Operation (on Windows, spice-gtk point of view):
- After some sanity checks, just before redir'ing a USB device
a libusb driver needs to be installed (before libusb can open the device)
- A connection (NamedPipe) is established with usb-clerk, a libusb
driver installation service, and a request for driver installation
is sent.
- Installation status is asynchronously read from the pipe, and
spice_usb_drv_install_finished() is called.
- Upon a successful intallation, usbredir continues.
Linux operation is not changed.
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 8edea9a..fcfc086 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -316,6 +316,9 @@ endif
WIN_USB_FILES= \
win-usb-dev.h \
win-usb-dev.c \
+ win-usb-clerk.h \
+ win-usb-driver-install.h \
+ win-usb-driver-install.c \
$(NULL)
if OS_WIN32
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index c183158..2f0d6f1 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -33,6 +33,7 @@
#include <gudev/gudev.h>
#elif defined(G_OS_WIN32)
#include "win-usb-dev.h"
+#include "win-usb-driver-install.h"
#else
#warning "Expecting one of G_OS_WIN32 and USE_GUDEV to be defined"
#endif
@@ -144,6 +145,13 @@ static libusb_device *
spice_usb_device_manager_device_to_libdev(SpiceUsbDeviceManager *self,
SpiceUsbDevice *device);
+static void
+_spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
+ SpiceUsbDevice *device,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
G_DEFINE_BOXED_TYPE(SpiceUsbDevice, spice_usb_device,
(GBoxedCopyFunc)spice_usb_device_ref,
(GBoxedFreeFunc)spice_usb_device_unref)
@@ -154,6 +162,12 @@ G_DEFINE_BOXED_TYPE(SpiceUsbDevice, spice_usb_device, g_object_ref, g_object_unr
static void spice_usb_device_manager_initable_iface_init(GInitableIface *iface);
+#ifdef G_OS_WIN32
+static void spice_usb_device_manager_drv_install_cb(GObject *gobject,
+ GAsyncResult *res,
+ gpointer user_data);
+#endif
+
static guint signals[LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE_WITH_CODE(SpiceUsbDeviceManager, spice_usb_device_manager, G_TYPE_OBJECT,
@@ -723,6 +737,87 @@ static void spice_usb_device_manager_channel_connect_cb(
g_object_unref(result);
}
+#ifdef G_OS_WIN32
+
+typedef struct _UsbInstallCbInfo {
+ SpiceUsbDeviceManager *manager;
+ SpiceUsbDevice *device;
+ SpiceWinUsbDriver *installer;
+ GCancellable *cancellable;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+} UsbInstallCbInfo;
+
+/**
+ * spice_usb_device_manager_drv_install_cb:
+ * @gobject: #SpiceWinUsbDriver in charge of installing the driver
+ * @res: #GAsyncResult of async win usb driver installation
+ * @user_data: #SpiceUsbDeviceManager requested the installation
+ *
+ * Called when an Windows libusb driver installation completed.
+ *
+ * If the driver installation was successful, continue with USB
+ * device redirection
+ *
+ * Always call _spice_usb_device_manager_connect_device_async.
+ * When installation fails, libusb_open fails too, but cleanup would be better.
+ */
+static void spice_usb_device_manager_drv_install_cb(GObject *gobject,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ SpiceUsbDeviceManager *self;
+ SpiceWinUsbDriver *installer;
+ gint status;
+ GError *err = NULL;
+ SpiceUsbDevice *device;
+ UsbInstallCbInfo *cbinfo;
+ GCancellable *cancellable;
+ GAsyncReadyCallback callback;
+
+ SPICE_DEBUG("Win USB driver Installation finished");
+
+ g_return_if_fail(user_data != NULL);
+
+ cbinfo = user_data;
+ self = cbinfo->manager;
+ device = cbinfo->device;
+ installer = cbinfo->installer;
+ cancellable = cbinfo->cancellable;
+ callback = cbinfo->callback;
+ user_data = cbinfo->user_data;
+
+ g_free(cbinfo);
+
+ g_return_if_fail(SPICE_IS_USB_DEVICE_MANAGER(self));
+ g_return_if_fail(SPICE_IS_WIN_USB_DRIVER(installer));
+ g_return_if_fail(device!= NULL);
+
+ status = spice_win_usb_driver_install_finish(installer, res, &err);
+
+ g_object_unref(installer);
+ spice_usb_device_unref(device);
+
+ if (err) {
+ g_warning("win usb driver installation failed -- %s",
+ err->message);
+ g_error_free(err);
+ }
+
+ if (!status) {
+ g_warning("failed to install win usb driver (status=0)");
+ }
+
+ /* device is already ref'ed */
+ _spice_usb_device_manager_connect_device_async(self,
+ device,
+ cancellable,
+ callback,
+ user_data);
+
+}
+#endif
+
/* ------------------------------------------------------------------ */
/* private api */
@@ -903,11 +998,12 @@ gboolean spice_usb_device_manager_is_device_connected(SpiceUsbDeviceManager *sel
* @callback: a #GAsyncReadyCallback to call when the request is satisfied
* @user_data: data to pass to callback
*/
-void spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
- SpiceUsbDevice *device,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+static void
+_spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
+ SpiceUsbDevice *device,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
GSimpleAsyncResult *result;
@@ -958,6 +1054,38 @@ done:
g_object_unref(result);
}
+
+void spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
+ SpiceUsbDevice *device,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+
+#if defined(USE_USBREDIR) && defined(G_OS_WIN32)
+ SpiceWinUsbDriver *installer;
+ UsbInstallCbInfo *cbinfo;
+
+ installer = spice_win_usb_driver_new();
+ cbinfo = g_new0(UsbInstallCbInfo, 1);
+ cbinfo->manager = self;
+ cbinfo->device = spice_usb_device_ref(device);
+ cbinfo->installer = installer;
+ cbinfo->cancellable = cancellable;
+ cbinfo->callback = callback;
+ cbinfo->user_data = user_data;
+ spice_win_usb_driver_install(installer, device, cancellable,
+ spice_usb_device_manager_drv_install_cb,
+ cbinfo);
+#else
+ _spice_usb_device_manager_connect_device_async(self,
+ device,
+ cancellable,
+ callback,
+ user_data);
+#endif
+}
+
gboolean spice_usb_device_manager_connect_device_finish(
SpiceUsbDeviceManager *self, GAsyncResult *res, GError **err)
{
diff --git a/gtk/win-usb-clerk.h b/gtk/win-usb-clerk.h
new file mode 100644
index 0000000..5b1e3cf
--- /dev/null
+++ b/gtk/win-usb-clerk.h
@@ -0,0 +1,35 @@
+#ifndef _H_USBCLERK
+#define _H_USBCLERK
+
+#include <windows.h>
+
+#define USB_CLERK_PIPE_NAME TEXT("\\\\.\\pipe\\usbclerkpipe")
+#define USB_CLERK_MAGIC 0xDADA
+#define USB_CLERK_VERSION 0x0002
+
+typedef struct USBClerkHeader {
+ UINT16 magic;
+ UINT16 version;
+ UINT16 type;
+ UINT16 size;
+} USBClerkHeader;
+
+enum {
+ USB_CLERK_DRIVER_INSTALL = 1,
+ USB_CLERK_DRIVER_REMOVE,
+ USB_CLERK_REPLY,
+ USB_CLERK_END_MESSAGE,
+};
+
+typedef struct USBClerkDriverOp {
+ USBClerkHeader hdr;
+ UINT16 vid;
+ UINT16 pid;
+} USBClerkDriverOp;
+
+typedef struct USBClerkReply {
+ USBClerkHeader hdr;
+ UINT32 status;
+} USBClerkReply;
+
+#endif
diff --git a/gtk/win-usb-driver-install.c b/gtk/win-usb-driver-install.c
new file mode 100644
index 0000000..5b9db62
--- /dev/null
+++ b/gtk/win-usb-driver-install.c
@@ -0,0 +1,357 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2011 Red Hat, Inc.
+
+ Red Hat Authors:
+ Uri Lublin <uril at redhat.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Some notes:
+ * Each installer (instance) opens a named-pipe to talk with win-usb-clerk.
+ * Each installer (instance) requests driver installation for a single device.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <windows.h>
+#include <gio/gio.h>
+#include <gio/gwin32inputstream.h>
+#include <gio/gwin32outputstream.h>
+#include "spice-util.h"
+#include "win-usb-clerk.h"
+#include "win-usb-driver-install.h"
+#include "usb-device-manager-priv.h"
+
+/* ------------------------------------------------------------------ */
+/* gobject glue */
+
+#define SPICE_WIN_USB_DRIVER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), SPICE_TYPE_WIN_USB_DRIVER, SpiceWinUsbDriverPrivate))
+
+struct _SpiceWinUsbDriverPrivate {
+ USBClerkReply reply;
+ GSimpleAsyncResult *result;
+ GCancellable *cancellable;
+ HANDLE handle;
+ SpiceUsbDevice *device;
+};
+
+
+
+G_DEFINE_TYPE(SpiceWinUsbDriver, spice_win_usb_driver, G_TYPE_OBJECT);
+
+static void spice_win_usb_driver_init(SpiceWinUsbDriver *self)
+{
+ self->priv = SPICE_WIN_USB_DRIVER_GET_PRIVATE(self);
+}
+
+static void spice_win_usb_driver_close(SpiceWinUsbDriver *self)
+{
+ if (self->priv->handle) {
+ CloseHandle(self->priv->handle);
+ self->priv->handle = 0;
+ }
+}
+
+static void spice_win_usb_driver_finalize(GObject *gobject)
+{
+ SpiceWinUsbDriver *self = SPICE_WIN_USB_DRIVER(gobject);
+ SpiceWinUsbDriverPrivate *priv = self->priv;
+
+ spice_win_usb_driver_close(self);
+ g_clear_object(&priv->result);
+}
+
+static void spice_win_usb_driver_class_init(SpiceWinUsbDriverClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = spice_win_usb_driver_finalize;
+
+ g_type_class_add_private(klass, sizeof(SpiceWinUsbDriverPrivate));
+}
+
+/* ------------------------------------------------------------------ */
+/* callbacks */
+
+void win_usb_driver_handle_reply_cb(GObject *gobject,
+ GAsyncResult *read_res,
+ gpointer user_data)
+{
+ SpiceWinUsbDriver *self;
+ SpiceWinUsbDriverPrivate *priv;
+
+ GInputStream *istream;
+ GError *err = NULL;
+ gssize bytes;
+
+ g_return_if_fail(SPICE_IS_WIN_USB_DRIVER(user_data));
+ self = SPICE_WIN_USB_DRIVER(user_data);
+ priv = self->priv;
+ istream = G_INPUT_STREAM(gobject);
+
+ bytes = g_input_stream_read_finish(istream, read_res, &err);
+
+ SPICE_DEBUG("Finished reading reply-msg from usbclerk: bytes=%ld "
+ "err_exist?=%d", (long)bytes, err!=NULL);
+
+ g_warn_if_fail(g_input_stream_close(istream, NULL, NULL));
+ g_clear_object(&istream);
+ spice_win_usb_driver_close(self);
+
+ if (err) {
+ g_warning("failed to read reply from usbclerk (%s)", err->message);
+ g_simple_async_result_take_error(priv->result, err);
+ goto failed_reply;
+ }
+
+ if (bytes == 0) {
+ g_warning("unexpected EOF from usbclerk");
+ g_simple_async_result_set_error(priv->result,
+ SPICE_WIN_USB_DRIVER_ERROR,
+ SPICE_WIN_USB_DRIVER_ERROR_FAILED,
+ "unexpected EOF from usbclerk");
+ goto failed_reply;
+ }
+
+ if (bytes != sizeof(priv->reply)) {
+ g_warning("usbclerk size mismatch: read %d bytes, expected %d (header %d, size in header %d)",
+ bytes, sizeof(priv->reply), sizeof(priv->reply.hdr), priv->reply.hdr.size);
+ /* For now just warn, do not fail */
+ }
+
+ if (priv->reply.hdr.magic != USB_CLERK_MAGIC) {
+ g_warning("usbclerk magic mismatch: mine=0x%04x server=0x%04x",
+ USB_CLERK_MAGIC, priv->reply.hdr.magic);
+ g_simple_async_result_set_error(priv->result,
+ SPICE_WIN_USB_DRIVER_ERROR,
+ SPICE_WIN_USB_DRIVER_ERROR_MESSAGE,
+ "usbclerk magic mismatch");
+ goto failed_reply;
+ }
+
+ if (priv->reply.hdr.version != USB_CLERK_VERSION) {
+ g_warning("usbclerk version mismatch: mine=0x%04x server=0x%04x",
+ USB_CLERK_VERSION, priv->reply.hdr.version);
+ /* For now just warn, do not fail */
+ }
+
+ if (priv->reply.hdr.type != USB_CLERK_REPLY) {
+ g_warning("usbclerk message with unexpected type %d",
+ priv->reply.hdr.type);
+ g_simple_async_result_set_error(priv->result,
+ SPICE_WIN_USB_DRIVER_ERROR,
+ SPICE_WIN_USB_DRIVER_ERROR_MESSAGE,
+ "usbclerk message with unexpected type");
+ goto failed_reply;
+ }
+
+ if (priv->reply.hdr.size != bytes) {
+ g_warning("usbclerk message size mismatch: read %d bytes hdr.size=%d",
+ bytes, priv->reply.hdr.size);
+ g_simple_async_result_set_error(priv->result,
+ SPICE_WIN_USB_DRIVER_ERROR,
+ SPICE_WIN_USB_DRIVER_ERROR_MESSAGE,
+ "usbclerk message with unexpected size");
+ goto failed_reply;
+ }
+
+ failed_reply:
+ g_simple_async_result_complete_in_idle(priv->result);
+ g_clear_object(&priv->result);
+}
+
+/* ------------------------------------------------------------------ */
+/* helper functions */
+
+static
+gboolean spice_win_usb_driver_send_request(SpiceWinUsbDriver *self, guint16 op,
+ guint16 vid, guint16 pid, GError **err)
+{
+ USBClerkDriverOp req = {0,};
+ GOutputStream *ostream;
+ SpiceWinUsbDriverPrivate *priv;
+ gsize bytes;
+ gboolean ret;
+
+ SPICE_DEBUG("sending a request to usbclerk service (op=%d vid=0x%04x pid=0x%04x",
+ op, vid, pid);
+
+ g_return_val_if_fail(SPICE_IS_WIN_USB_DRIVER(self), FALSE);
+ priv = self->priv;
+
+ req.hdr.magic = USB_CLERK_MAGIC;
+ req.hdr.version = USB_CLERK_VERSION;
+ req.hdr.type = op;
+ req.hdr.size = sizeof(req);
+ req.vid = vid;
+ req.pid = pid;
+
+ ostream = g_win32_output_stream_new(priv->handle, FALSE);
+
+ ret = g_output_stream_write_all(ostream, &req, sizeof(req), &bytes, NULL, err);
+ g_warn_if_fail(g_output_stream_close(ostream, NULL, NULL));
+ g_object_unref(ostream);
+ SPICE_DEBUG("write_all request returned %d written bytes %u expecting %u",
+ ret, bytes, sizeof(req));
+ return ret;
+}
+
+static
+void spice_win_usb_driver_read_reply_async(SpiceWinUsbDriver *self)
+{
+ SpiceWinUsbDriverPrivate *priv;
+ GInputStream *istream;
+
+ g_return_if_fail(SPICE_IS_WIN_USB_DRIVER(self));
+ priv = self->priv;
+
+ SPICE_DEBUG("waiting for a reply from usbclerk");
+
+ istream = g_win32_input_stream_new(priv->handle, FALSE);
+
+ g_input_stream_read_async(istream, &priv->reply, sizeof(priv->reply),
+ G_PRIORITY_DEFAULT, priv->cancellable,
+ win_usb_driver_handle_reply_cb, self);
+}
+
+
+/* ------------------------------------------------------------------ */
+/* private api */
+
+
+G_GNUC_INTERNAL
+SpiceWinUsbDriver *spice_win_usb_driver_new(void)
+{
+ GObject *obj;
+
+ obj = g_object_new(SPICE_TYPE_WIN_USB_DRIVER, NULL);
+
+ return SPICE_WIN_USB_DRIVER(obj);
+}
+
+/**
+ * spice_win_usb_driver_install:
+ * Start libusb driver installation for @device
+ *
+ * A new NamedPipe is created for each request.
+ *
+ * Returns: TRUE if a request was sent to usbclerk
+ * FALSE upon failure to send a request.
+ */
+G_GNUC_INTERNAL
+void spice_win_usb_driver_install(SpiceWinUsbDriver *self,
+ SpiceUsbDevice *device,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ guint16 vid, pid;
+ GError *err = NULL;
+ GSimpleAsyncResult *result;
+ SpiceWinUsbDriverPrivate *priv;
+
+ SPICE_DEBUG("Win usb driver installation started");
+
+ g_return_if_fail(SPICE_IS_WIN_USB_DRIVER(self));
+ g_return_if_fail(device != NULL);
+
+ priv = self->priv;
+
+ g_return_if_fail(priv->result == NULL);
+
+ result = g_simple_async_result_new(G_OBJECT(self), callback, user_data,
+ spice_win_usb_driver_install);
+
+ vid = spice_usb_device_get_vid(device);
+ pid = spice_usb_device_get_pid(device);
+
+ SPICE_DEBUG("win-usb-driver-install: connecting to usbclerk named pipe");
+ priv->handle = CreateFile(USB_CLERK_PIPE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ 0, NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL);
+ if (priv->handle == INVALID_HANDLE_VALUE) {
+ DWORD errval = GetLastError();
+ gchar *errstr = g_win32_error_message(errval);
+ g_warning("failed to create a named pipe to usbclerk (%ld) %s",
+ errval,errstr);
+ g_simple_async_result_set_error(result,
+ G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Failed to create named pipe (%ld) %s", errval, errstr);
+ goto failed_request;
+ }
+
+ if (!spice_win_usb_driver_send_request(self, USB_CLERK_DRIVER_INSTALL,
+ vid, pid, &err)) {
+ g_warning("failed to send a request to usbclerk %s", err->message);
+ g_simple_async_result_take_error(result, err);
+ goto failed_request;
+ }
+
+ /* set up for async read */
+ priv->result = result;
+ priv->device = device;
+ priv->cancellable = cancellable;
+
+ spice_win_usb_driver_read_reply_async(self);
+
+ return;
+
+ failed_request:
+ spice_win_usb_driver_close(self);
+ g_simple_async_result_complete_in_idle(result);
+ g_clear_object(&result);
+}
+
+
+/**
+ * Returns: currently returns 0 (failure) and 1 (success)
+ * possibly later we'll add error-codes
+ */
+G_GNUC_INTERNAL
+gint spice_win_usb_driver_install_finish(SpiceWinUsbDriver *self,
+ GAsyncResult *res, GError **err)
+{
+ GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT(res);
+
+ g_return_val_if_fail(SPICE_IS_WIN_USB_DRIVER(self), 0);
+ g_return_val_if_fail(g_simple_async_result_is_valid(res, G_OBJECT(self),
+ spice_win_usb_driver_install),
+ FALSE);
+ if (g_simple_async_result_propagate_error(result, err))
+ return 0;
+
+ return self->priv->reply.status;
+}
+
+G_GNUC_INTERNAL
+SpiceUsbDevice *spice_win_usb_driver_get_device(SpiceWinUsbDriver *self)
+{
+ g_return_val_if_fail(SPICE_IS_WIN_USB_DRIVER(self), 0);
+
+ return self->priv->device;
+}
+
+GQuark spice_win_usb_driver_error_quark(void)
+{
+ return g_quark_from_static_string("spice-win-usb-driver-error-quark");
+}
diff --git a/gtk/win-usb-driver-install.h b/gtk/win-usb-driver-install.h
new file mode 100644
index 0000000..b0ccf33
--- /dev/null
+++ b/gtk/win-usb-driver-install.h
@@ -0,0 +1,98 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2011 Red Hat, Inc.
+
+ Red Hat Authors:
+ Uri Lublin <uril at redhat.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef SPICE_WIN_USB_DRIVER_H
+#define SPICE_WIN_USB_DRIVER_H
+
+#include "usb-device-manager.h"
+
+G_BEGIN_DECLS
+
+GQuark win_usb_driver_error_quark(void);
+
+
+#define SPICE_TYPE_WIN_USB_DRIVER (spice_win_usb_driver_get_type ())
+#define SPICE_WIN_USB_DRIVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ SPICE_TYPE_WIN_USB_DRIVER, SpiceWinUsbDriver))
+#define SPICE_IS_WIN_USB_DRIVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ SPICE_TYPE_WIN_USB_DRIVER))
+#define SPICE_WIN_USB_DRIVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ SPICE_TYPE_WIN_USB_DRIVER, SpiceWinUsbDriverClass))
+#define SPICE_IS_WIN_USB_DRIVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
+ SPICE_TYPE_WIN_USB_DRIVER))
+#define SPICE_WIN_USB_DRIVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+ SPICE_TYPE_WIN_USB_DRIVER, SpiceWinUsbDriverClass))
+
+typedef struct _SpiceWinUsbDriver SpiceWinUsbDriver;
+typedef struct _SpiceWinUsbDriverClass SpiceWinUsbDriverClass;
+typedef struct _SpiceWinUsbDriverPrivate SpiceWinUsbDriverPrivate;
+
+struct _SpiceWinUsbDriver
+{
+ GObject parent;
+
+ /*< private >*/
+ SpiceWinUsbDriverPrivate *priv;
+ /* Do not add fields to this struct */
+};
+
+struct _SpiceWinUsbDriverClass
+{
+ GObjectClass parent_class;
+};
+
+GType spice_win_usb_driver_get_type(void);
+
+SpiceWinUsbDriver *spice_win_usb_driver_new(void);
+
+
+void spice_win_usb_driver_install(SpiceWinUsbDriver *self,
+ SpiceUsbDevice *device,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gint spice_win_usb_driver_install_finish(SpiceWinUsbDriver *self,
+ GAsyncResult *res, GError **err);
+
+
+SpiceUsbDevice *spice_win_usb_driver_get_device(SpiceWinUsbDriver *self);
+
+#define SPICE_WIN_USB_DRIVER_ERROR spice_win_usb_driver_error_quark()
+
+/**
+ * SpiceWinUsbDriverError:
+ * @SPICE_WIN_USB_DRIVER_ERROR_FAILED: generic error code
+ * @SPICE_WIN_USB_DRIVER_ERROR_MESSAGE: bad message read from clerk
+ *
+ * Error codes returned by spice-client API.
+ */
+typedef enum
+{
+ SPICE_WIN_USB_DRIVER_ERROR_FAILED,
+ SPICE_WIN_USB_DRIVER_ERROR_MESSAGE,
+} SpiceWinUsbDriverError;
+
+GQuark spice_win_usb_driver_error_quark(void);
+
+G_END_DECLS
+
+#endif /* SPICE_WIN_USB_DRIVER_H */
commit 5525ce973402704cfa48b275516509448210dcc0
Author: Arnon Gilboa <agilboa at redhat.com>
Date: Thu Jul 5 23:43:57 2012 +0300
Windows mingw: usb: implement GUdevDevice & GUdevClient for windows
- Added win-usb-dev.[ch]
- Added GUdevDevice and GUdevClient like classes
- Added uevent signal based on WM_DEVICECHANGE
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 10fa9cd..8edea9a 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -312,6 +312,19 @@ libspice_client_glib_2_0_la_SOURCES += coroutine_gthread.c
libspice_client_glib_2_0_la_LIBADD += $(GTHREAD_LIBS)
endif
+
+WIN_USB_FILES= \
+ win-usb-dev.h \
+ win-usb-dev.c \
+ $(NULL)
+
+if OS_WIN32
+if WITH_USBREDIR
+libspice_client_glib_2_0_la_SOURCES += \
+ $(WIN_USB_FILES)
+endif
+endif
+
displaysrc = \
glib-compat.h \
display/edid.h \
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index a20c414..c183158 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -28,7 +28,15 @@
#ifdef USE_USBREDIR
#include <errno.h>
#include <libusb.h>
+
+#if defined(USE_GUDEV)
#include <gudev/gudev.h>
+#elif defined(G_OS_WIN32)
+#include "win-usb-dev.h"
+#else
+#warning "Expecting one of G_OS_WIN32 and USE_GUDEV to be defined"
+#endif
+
#include "channel-usbredir-priv.h"
#include "usbredirhost.h"
#include "usbutil.h"
diff --git a/gtk/win-usb-dev.c b/gtk/win-usb-dev.c
new file mode 100644
index 0000000..bc21e08
--- /dev/null
+++ b/gtk/win-usb-dev.c
@@ -0,0 +1,510 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2012 Red Hat, Inc.
+
+ Red Hat Authors:
+ Arnon Gilboa <agilboa at redhat.com>
+ Uri Lublin <uril at redhat.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <windows.h>
+#include <libusb.h>
+#include "win-usb-dev.h"
+#include "spice-marshal.h"
+#include "spice-util.h"
+#include "usbutil.h"
+
+#define G_UDEV_CLIENT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), G_UDEV_TYPE_CLIENT, GUdevClientPrivate))
+
+struct _GUdevClientPrivate {
+ libusb_context *ctx;
+ gssize udev_list_size;
+ GList *udev_list;
+ HWND hwnd;
+};
+
+#define G_UDEV_CLIENT_WINCLASS_NAME TEXT("G_UDEV_CLIENT")
+
+static void g_udev_client_initable_iface_init(GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE(GUdevClient, g_udev_client, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE(G_TYPE_INITABLE, g_udev_client_initable_iface_init));
+
+
+typedef struct _GUdevDeviceInfo GUdevDeviceInfo;
+
+struct _GUdevDeviceInfo {
+ guint16 bus;
+ guint16 addr;
+ guint16 vid;
+ guint16 pid;
+ guint16 class;
+ gchar sclass[4];
+ gchar sbus[4];
+ gchar saddr[4];
+};
+
+struct _GUdevDevicePrivate
+{
+ /* FixMe: move above fields to this structure and access them directly */
+ GUdevDeviceInfo *udevinfo;
+};
+
+G_DEFINE_TYPE(GUdevDevice, g_udev_device, G_TYPE_OBJECT)
+
+
+enum
+{
+ UEVENT_SIGNAL,
+ LAST_SIGNAL,
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+static GUdevClient *singleton = NULL;
+
+static GUdevDevice *g_udev_device_new(GUdevDeviceInfo *udevinfo);
+static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
+static gboolean get_usb_dev_info(libusb_device *dev, GUdevDeviceInfo *udevinfo);
+
+//uncomment to debug gudev device lists.
+//#define DEBUG_GUDEV_DEVICE_LISTS
+
+#ifdef DEBUG_GUDEV_DEVICE_LISTS
+static void g_udev_device_print_list(GList *l, const gchar *msg);
+#else
+static void g_udev_device_print_list(GList *l, const gchar *msg) {}
+#endif
+static void g_udev_device_print(GUdevDevice *udev, const gchar *msg);
+
+GQuark g_udev_client_error_quark(void)
+{
+ return g_quark_from_static_string("win-gudev-client-error-quark");
+}
+
+GUdevClient *g_udev_client_new(const gchar* const *subsystems)
+{
+ if (!singleton) {
+ singleton = g_initable_new(G_UDEV_TYPE_CLIENT, NULL, NULL, NULL);
+ return singleton;
+ } else {
+ return g_object_ref(singleton);
+ }
+}
+
+
+/*
+ * devs [in,out] an empty devs list in, full devs list out
+ * Returns: number-of-devices, or a negative value on error.
+ */
+static ssize_t
+g_udev_client_list_devices(GUdevClient *self, GList **devs,
+ GError **err, const gchar *name)
+{
+ gssize rc;
+ libusb_device **lusb_list, **dev;
+ GUdevClientPrivate *priv;
+ GUdevDeviceInfo *udevinfo;
+ GUdevDevice *udevice;
+ ssize_t n;
+
+ g_return_val_if_fail(G_UDEV_IS_CLIENT(self), -1);
+ g_return_val_if_fail(devs != NULL, -2);
+
+ priv = self->priv;
+
+ g_return_val_if_fail(self->priv->ctx != NULL, -3);
+
+ rc = libusb_get_device_list(priv->ctx, &lusb_list);
+ if (rc < 0) {
+ const char *errstr = spice_usbutil_libusb_strerror(rc);
+ g_warning("%s: libusb_get_device_list failed", name);
+ g_set_error(err, G_UDEV_CLIENT_ERROR, G_UDEV_CLIENT_LIBUSB_FAILED,
+ "%s: Error getting device list from libusb: %s [%i]",
+ name, errstr, rc);
+ return -4;
+ }
+
+ n = rc;
+
+ for (dev = lusb_list; *dev; dev++) {
+ udevinfo = g_new0(GUdevDeviceInfo, 1);
+ get_usb_dev_info(*dev, udevinfo);
+ udevice = g_udev_device_new(udevinfo);
+ *devs = g_list_prepend(*devs, udevice);
+ }
+ libusb_free_device_list(lusb_list, 1);
+
+ return n;
+}
+
+static void g_udev_client_free_device_list(GList **devs)
+{
+ g_return_if_fail(devs != NULL);
+ if (*devs) {
+ g_list_free_full(*devs, g_object_unref);
+ *devs = NULL;
+ }
+}
+
+
+static gboolean
+g_udev_client_initable_init(GInitable *initable, GCancellable *cancellable,
+ GError **err)
+{
+ GUdevClient *self;
+ GUdevClientPrivate *priv;
+ WNDCLASS wcls;
+ int rc;
+
+ g_return_val_if_fail(G_UDEV_IS_CLIENT(initable), FALSE);
+ g_return_val_if_fail(cancellable == NULL, FALSE);
+
+ self = G_UDEV_CLIENT(initable);
+ priv = self->priv;
+
+ rc = libusb_init(&priv->ctx);
+ if (rc < 0) {
+ const char *errstr = spice_usbutil_libusb_strerror(rc);
+ g_warning("Error initializing USB support: %s [%i]", errstr, rc);
+ g_set_error(err, G_UDEV_CLIENT_ERROR, G_UDEV_CLIENT_LIBUSB_FAILED,
+ "Error initializing USB support: %s [%i]", errstr, rc);
+ return FALSE;
+ }
+
+ /* get initial device list */
+ priv->udev_list_size = g_udev_client_list_devices(self, &priv->udev_list,
+ err, __FUNCTION__);
+ if (priv->udev_list_size < 0) {
+ goto g_udev_client_init_failed;
+ }
+
+ g_udev_device_print_list(priv->udev_list, "init: first list is: ");
+
+ /* create a hidden window */
+ memset(&wcls, 0, sizeof(wcls));
+ wcls.lpfnWndProc = wnd_proc;
+ wcls.lpszClassName = G_UDEV_CLIENT_WINCLASS_NAME;
+ if (!RegisterClass(&wcls)) {
+ DWORD e = GetLastError();
+ g_warning("RegisterClass failed , %ld", (long)e);
+ g_set_error(err, G_UDEV_CLIENT_ERROR, G_UDEV_CLIENT_WINAPI_FAILED,
+ "RegisterClass failed: %ld", (long)e);
+ goto g_udev_client_init_failed;
+ }
+ priv->hwnd = CreateWindow(G_UDEV_CLIENT_WINCLASS_NAME,
+ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+ if (!priv->hwnd) {
+ DWORD e = GetLastError();
+ g_warning("CreateWindow failed: %ld", (long)e);
+ g_set_error(err, G_UDEV_CLIENT_ERROR, G_UDEV_CLIENT_LIBUSB_FAILED,
+ "CreateWindow failed: %ld", (long)e);
+ goto g_udev_client_init_failed_unreg;
+ }
+
+ return TRUE;
+
+ g_udev_client_init_failed_unreg:
+ UnregisterClass(G_UDEV_CLIENT_WINCLASS_NAME, NULL);
+ g_udev_client_init_failed:
+ libusb_exit(priv->ctx);
+ priv->ctx = NULL;
+
+ return FALSE;
+}
+
+static void g_udev_client_initable_iface_init(GInitableIface *iface)
+{
+ iface->init = g_udev_client_initable_init;
+}
+
+GList *g_udev_client_query_by_subsystem(GUdevClient *self, const gchar *subsystem)
+{
+ GList *l = g_list_copy(self->priv->udev_list);
+ g_list_foreach(l, (GFunc)g_object_ref, NULL);
+ return l;
+}
+
+static void g_udev_client_init(GUdevClient *self)
+{
+ self->priv = G_UDEV_CLIENT_GET_PRIVATE(self);
+}
+
+static void g_udev_client_finalize(GObject *gobject)
+{
+ GUdevClient *self = G_UDEV_CLIENT(gobject);
+ GUdevClientPrivate *priv = self->priv;
+
+ singleton = NULL;
+ DestroyWindow(priv->hwnd);
+ UnregisterClass(G_UDEV_CLIENT_WINCLASS_NAME, NULL);
+ g_udev_client_free_device_list(&priv->udev_list);
+
+ /* free libusb context initializing by libusb_init() */
+ g_warn_if_fail(priv->ctx != NULL);
+ libusb_exit(priv->ctx);
+
+ /* Chain up to the parent class */
+ if (G_OBJECT_CLASS(g_udev_client_parent_class)->finalize)
+ G_OBJECT_CLASS(g_udev_client_parent_class)->finalize(gobject);
+}
+
+static void g_udev_client_class_init(GUdevClientClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+
+ gobject_class->finalize = g_udev_client_finalize;
+
+ signals[UEVENT_SIGNAL] =
+ g_signal_new("uevent",
+ G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET(GUdevClientClass, uevent),
+ NULL, NULL,
+ g_cclosure_user_marshal_VOID__BOXED_BOXED,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_STRING,
+ G_UDEV_TYPE_DEVICE);
+
+ g_type_class_add_private(klass, sizeof(GUdevClientPrivate));
+}
+
+static gboolean get_usb_dev_info(libusb_device *dev, GUdevDeviceInfo *udevinfo)
+{
+ struct libusb_device_descriptor desc;
+
+ g_return_val_if_fail(dev, FALSE);
+ g_return_val_if_fail(udevinfo, FALSE);
+
+ if (libusb_get_device_descriptor(dev, &desc) < 0) {
+ g_warning("cannot get device descriptor %p", dev);
+ return FALSE;
+ }
+
+ udevinfo->bus = libusb_get_bus_number(dev);
+ udevinfo->addr = libusb_get_device_address(dev);
+ udevinfo->class = desc.bDeviceClass;
+ udevinfo->vid = desc.idVendor;
+ udevinfo->pid = desc.idProduct;
+ snprintf(udevinfo->sclass, sizeof(udevinfo->sclass), "%d", udevinfo->class);
+ snprintf(udevinfo->sbus, sizeof(udevinfo->sbus), "%d", udevinfo->bus);
+ snprintf(udevinfo->saddr, sizeof(udevinfo->saddr), "%d", udevinfo->addr);
+ return TRUE;
+}
+
+/* Only bus,addr are compared */
+static gboolean gudev_devices_are_equal(GUdevDevice *a, GUdevDevice *b)
+{
+ GUdevDeviceInfo *ai, *bi;
+ gboolean same_bus;
+ gboolean same_addr;
+
+ ai = a->priv->udevinfo;
+ bi = b->priv->udevinfo;
+
+ same_bus = (ai->bus == bi->bus);
+ same_addr = (ai->addr == bi->addr);
+
+ return (same_bus && same_addr);
+}
+
+
+/* Assumes each event stands for a single device change (at most) */
+static void handle_dev_change(GUdevClient *self)
+{
+ GUdevClientPrivate *priv = self->priv;
+ GUdevDevice *changed_dev = NULL;
+ ssize_t dev_count;
+ int is_dev_change;
+ GError *err;
+ GList *now_devs = NULL;
+ GList *llist, *slist; /* long-list and short-list*/
+ GList *lit, *sit; /* iterators for long-list and short-list */
+ GUdevDevice *ldev, *sdev; /* devices on long-list and short-list */
+
+ dev_count = g_udev_client_list_devices(self, &now_devs, &err,
+ __FUNCTION__);
+ g_return_if_fail(dev_count >= 0);
+
+ SPICE_DEBUG("number of current devices %d, I know about %d devices",
+ dev_count, priv->udev_list_size);
+
+ is_dev_change = dev_count - priv->udev_list_size;
+ if (is_dev_change == 0) {
+ g_udev_client_free_device_list(&now_devs);
+ return;
+ }
+
+ if (is_dev_change > 0) {
+ llist = now_devs;
+ slist = priv->udev_list;
+ } else {
+ llist = priv->udev_list;
+ slist = now_devs;
+ }
+
+ g_udev_device_print_list(llist, "handle_dev_change: long list:");
+ g_udev_device_print_list(slist, "handle_dev_change: short list:");
+
+ /* Go over the longer list */
+ for (lit = g_list_first(llist); lit != NULL; lit=g_list_next(lit)) {
+ ldev = lit->data;
+ /* Look for dev in the shorther list */
+ for (sit = g_list_first(slist); sit != NULL; sit=g_list_next(sit)) {
+ sdev = sit->data;
+ if (gudev_devices_are_equal(ldev, sdev))
+ break;
+ }
+ if (sit == NULL) {
+ /* Found a device which appears only in the longer list */
+ changed_dev = ldev;
+ break;
+ }
+ }
+
+ if (!changed_dev) {
+ g_warning("couldn't find any device change");
+ goto leave;
+ }
+
+ if (is_dev_change > 0) {
+ g_udev_device_print(changed_dev, ">>> USB device inserted");
+ g_signal_emit(self, signals[UEVENT_SIGNAL], 0, "add", changed_dev);
+ } else {
+ g_udev_device_print(changed_dev, "<<< USB device removed");
+ g_signal_emit(self, signals[UEVENT_SIGNAL], 0, "remove", changed_dev);
+ }
+
+leave:
+ /* keep most recent info: free previous list, and keep current list */
+ g_udev_client_free_device_list(&priv->udev_list);
+ priv->udev_list = now_devs;
+ priv->udev_list_size = dev_count;
+}
+
+static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
+{
+ /* Only DBT_DEVNODES_CHANGED recieved */
+ if (message == WM_DEVICECHANGE) {
+ handle_dev_change(singleton);
+ }
+ return DefWindowProc(hwnd, message, wparam, lparam);
+}
+
+/*** GUdevDevice ***/
+
+static void g_udev_device_finalize(GObject *object)
+{
+ GUdevDevice *device = G_UDEV_DEVICE(object);
+
+ g_free(device->priv->udevinfo);
+ if (G_OBJECT_CLASS(g_udev_device_parent_class)->finalize != NULL)
+ (* G_OBJECT_CLASS(g_udev_device_parent_class)->finalize)(object);
+}
+
+static void g_udev_device_class_init(GUdevDeviceClass *klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+
+ gobject_class->finalize = g_udev_device_finalize;
+ g_type_class_add_private (klass, sizeof(GUdevDevicePrivate));
+}
+
+static void g_udev_device_init(GUdevDevice *device)
+{
+ device->priv = G_TYPE_INSTANCE_GET_PRIVATE(device, G_UDEV_TYPE_DEVICE, GUdevDevicePrivate);
+}
+
+static GUdevDevice *g_udev_device_new(GUdevDeviceInfo *udevinfo)
+{
+ GUdevDevice *device;
+
+ g_return_val_if_fail(udevinfo != NULL, NULL);
+
+ device = G_UDEV_DEVICE(g_object_new(G_UDEV_TYPE_DEVICE, NULL));
+ device->priv->udevinfo = udevinfo;
+ return device;
+}
+
+const gchar *g_udev_device_get_property(GUdevDevice *udev, const gchar *property)
+{
+ GUdevDeviceInfo* udevinfo;
+
+ g_return_val_if_fail(G_UDEV_DEVICE(udev), NULL);
+ g_return_val_if_fail(property != NULL, NULL);
+
+ udevinfo = udev->priv->udevinfo;
+ g_return_val_if_fail(udevinfo != NULL, NULL);
+
+ if (g_strcmp0(property, "BUSNUM") == 0) {
+ return udevinfo->sbus;
+ } else if (g_strcmp0(property, "DEVNUM") == 0) {
+ return udevinfo->saddr;
+ } else if (g_strcmp0(property, "DEVTYPE") == 0) {
+ return "usb_device";
+ }
+
+ g_warn_if_reached();
+ return NULL;
+}
+
+const gchar *g_udev_device_get_sysfs_attr(GUdevDevice *udev, const gchar *attr)
+{
+ GUdevDeviceInfo* udevinfo;
+
+ g_return_val_if_fail(G_UDEV_DEVICE(udev), NULL);
+ g_return_val_if_fail(attr != NULL, NULL);
+
+ udevinfo = udev->priv->udevinfo;
+ g_return_val_if_fail(udevinfo != NULL, NULL);
+
+
+ if (g_strcmp0(attr, "bDeviceClass") == 0) {
+ return udevinfo->sclass;
+ }
+ g_warn_if_reached();
+ return NULL;
+}
+
+#ifdef DEBUG_GUDEV_DEVICE_LISTS
+static void g_udev_device_print_list(GList *l, const gchar *msg)
+{
+ GList *it;
+
+ for (it = g_list_first(l); it != NULL; it=g_list_next(it)) {
+ g_udev_device_print(it->data, msg);
+ }
+}
+#endif
+
+static void g_udev_device_print(GUdevDevice *udev, const gchar *msg)
+{
+ GUdevDeviceInfo* udevinfo;
+
+ g_return_if_fail(G_UDEV_DEVICE(udev));
+
+ udevinfo = udev->priv->udevinfo;
+ g_return_if_fail(udevinfo != NULL);
+
+ SPICE_DEBUG("%s: %d.%d 0x%04x:0x%04x class %d", msg,
+ udevinfo->bus, udevinfo->addr,
+ udevinfo->vid, udevinfo->pid, udevinfo->class);
+}
diff --git a/gtk/win-usb-dev.h b/gtk/win-usb-dev.h
new file mode 100644
index 0000000..b5c4fce
--- /dev/null
+++ b/gtk/win-usb-dev.h
@@ -0,0 +1,110 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2012 Red Hat, Inc.
+
+ Red Hat Authors:
+ Arnon Gilboa <agilboa at redhat.com>
+ Uri Lublin <uril at redhat.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef __WIN_USB_DEV_H__
+#define __WIN_USB_DEV_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+/* GUdevDevice */
+
+#define G_UDEV_TYPE_DEVICE (g_udev_device_get_type())
+#define G_UDEV_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST((o), G_UDEV_TYPE_DEVICE, GUdevDevice))
+#define G_UDEV_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_DEVICE, GUdevDeviceClass))
+#define G_UDEV_IS_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_DEVICE))
+#define G_UDEV_IS_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), G_UDEV_TYPE_DEVICE))
+#define G_UDEV_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), G_UDEV_TYPE_DEVICE, GUdevDeviceClass))
+
+typedef struct _GUdevDevice GUdevDevice;
+typedef struct _GUdevDeviceClass GUdevDeviceClass;
+typedef struct _GUdevDevicePrivate GUdevDevicePrivate;
+
+struct _GUdevDevice
+{
+ GObject parent;
+ GUdevDevicePrivate *priv;
+};
+
+struct _GUdevDeviceClass
+{
+ GObjectClass parent_class;
+};
+
+/* GUdevClient */
+
+#define G_UDEV_TYPE_CLIENT (g_udev_client_get_type())
+#define G_UDEV_CLIENT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), G_UDEV_TYPE_CLIENT, GUdevClient))
+#define G_UDEV_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_CLIENT, GUdevClientClass))
+#define G_UDEV_IS_CLIENT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), G_UDEV_TYPE_CLIENT))
+#define G_UDEV_IS_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), G_UDEV_TYPE_CLIENT))
+#define G_UDEV_CLIENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), G_UDEV_TYPE_CLIENT, GUdevClientClass))
+
+typedef struct _GUdevClient GUdevClient;
+typedef struct _GUdevClientClass GUdevClientClass;
+typedef struct _GUdevClientPrivate GUdevClientPrivate;
+
+struct _GUdevClient
+{
+ GObject parent;
+
+ GUdevClientPrivate *priv;
+};
+
+struct _GUdevClientClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+ void (*uevent)(GUdevClient *client, const gchar *action, GUdevDevice *device);
+};
+
+GType g_udev_client_get_type(void) G_GNUC_CONST;
+GUdevClient *g_udev_client_new(const gchar* const *subsystems);
+GList *g_udev_client_query_by_subsystem(GUdevClient *client, const gchar *subsystem);
+
+GType g_udev_device_get_type(void) G_GNUC_CONST;
+const gchar *g_udev_device_get_property(GUdevDevice *udev, const gchar *property);
+const gchar *g_udev_device_get_sysfs_attr(GUdevDevice *udev, const gchar *attr);
+
+GQuark g_udev_client_error_quark(void);
+#define G_UDEV_CLIENT_ERROR g_udev_client_error_quark()
+
+/**
+ * GUdevClientError:
+ * @G_UDEV_CLIENT_ERROR_FAILED: generic error code
+ * @G_UDEV_CLIENT_LIBUSB_FAILED: a libusb call failed
+ * @G_UDEV_CLIENT_WINAPI_FAILED: a winapi call failed
+ *
+ * Error codes returned by spice-client API.
+ */
+typedef enum
+{
+ G_UDEV_CLIENT_ERROR_FAILED = 1,
+ G_UDEV_CLIENT_LIBUSB_FAILED,
+ G_UDEV_CLIENT_WINAPI_FAILED
+} GUdevClientError;
+
+
+G_END_DECLS
+
+#endif /* __WIN_USB_DEV_H__ */
commit cb68b670bb616e9886b9382667a01050f5a3e073
Author: Uri Lublin <uril at redhat.com>
Date: Thu Jul 5 23:43:55 2012 +0300
Make SpiceUsbDevice a box for SpiceUsbDeviceInfo, instead of a box for libusb_device
Note that this change may affect performance a bit, as sometimes there is
a need to find the libusb_device or the SpiceUsbDevice. Likely it's negligible.
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index abfac2b..a20c414 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -129,13 +129,21 @@ static void spice_usb_device_unref(SpiceUsbDevice *device);
static gboolean spice_usb_device_equal_libdev(SpiceUsbDevice *device,
libusb_device *libdev);
+static SpiceUsbDevice *
+spice_usb_device_manager_libdev_to_device(SpiceUsbDeviceManager *self,
+ libusb_device *libdev);
+static libusb_device *
+spice_usb_device_manager_device_to_libdev(SpiceUsbDeviceManager *self,
+ SpiceUsbDevice *device);
+
G_DEFINE_BOXED_TYPE(SpiceUsbDevice, spice_usb_device,
- (GBoxedCopyFunc)libusb_ref_device,
- (GBoxedFreeFunc)libusb_unref_device)
+ (GBoxedCopyFunc)spice_usb_device_ref,
+ (GBoxedFreeFunc)spice_usb_device_unref)
#else
G_DEFINE_BOXED_TYPE(SpiceUsbDevice, spice_usb_device, g_object_ref, g_object_unref)
#endif
+
static void spice_usb_device_manager_initable_iface_init(GInitableIface *iface);
static guint signals[LAST_SIGNAL] = { 0, };
@@ -153,7 +161,7 @@ static void spice_usb_device_manager_init(SpiceUsbDeviceManager *self)
priv->channels = g_ptr_array_new();
#ifdef USE_USBREDIR
priv->devices = g_ptr_array_new_with_free_func((GDestroyNotify)
- libusb_unref_device);
+ spice_usb_device_unref);
#endif
}
@@ -549,7 +557,7 @@ 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);
}
- libusb_unref_device((libusb_device*)device);
+ spice_usb_device_unref(device);
}
static SpiceUsbDevice*
@@ -562,8 +570,8 @@ spice_usb_device_manager_find_device(SpiceUsbDeviceManager *self,
for (i = 0; i < priv->devices->len; i++) {
curr = g_ptr_array_index(priv->devices, i);
- if (libusb_get_bus_number((libusb_device*)curr) == bus &&
- libusb_get_device_address((libusb_device*)curr) == address) {
+ if (spice_usb_device_get_busnum(curr) == bus &&
+ spice_usb_device_get_devaddr(curr) == address) {
device = curr;
break;
}
@@ -618,7 +626,7 @@ static void spice_usb_device_manager_add_dev(SpiceUsbDeviceManager *self,
}
if (libdev)
- device = (SpiceUsbDevice*)libusb_ref_device(libdev);
+ device = (SpiceUsbDevice*)spice_usb_device_new(libdev);
if (device && priv->auto_connect) {
auto_ok = usbredirhost_check_device_filter(
@@ -648,7 +656,7 @@ static void spice_usb_device_manager_add_dev(SpiceUsbDeviceManager *self,
spice_usb_device_manager_connect_device_async(self,
device, NULL,
spice_usb_device_manager_auto_connect_cb,
- libusb_ref_device(libdev));
+ spice_usb_device_ref(device));
}
SPICE_DEBUG("device added %p", device);
@@ -772,22 +780,28 @@ void spice_usb_device_manager_stop_event_listening(
void spice_usb_device_manager_device_error(
SpiceUsbDeviceManager *self, libusb_device *libdev, GError *err)
{
- SpiceUsbDevice *device = (SpiceUsbDevice *)libdev;
+ SpiceUsbDevice *device;
+
+ g_return_if_fail(SPICE_IS_USB_DEVICE_MANAGER(self));
+ g_return_if_fail(libdev != 0);
+
+ device = spice_usb_device_manager_libdev_to_device(self, libdev);
+
g_signal_emit(self, signals[DEVICE_ERROR], 0, device, err);
}
#endif
static SpiceUsbredirChannel *spice_usb_device_manager_get_channel_for_dev(
- SpiceUsbDeviceManager *manager, SpiceUsbDevice *_device)
+ SpiceUsbDeviceManager *manager, SpiceUsbDevice *device)
{
#ifdef USE_USBREDIR
SpiceUsbDeviceManagerPrivate *priv = manager->priv;
- libusb_device *device = (libusb_device *)_device;
guint i;
for (i = 0; i < priv->channels->len; i++) {
SpiceUsbredirChannel *channel = g_ptr_array_index(priv->channels, i);
- if (spice_usbredir_channel_get_device(channel) == device)
+ libusb_device *libdev = spice_usbredir_channel_get_device(channel);
+ if (spice_usb_device_equal_libdev(device, libdev))
return channel;
}
#endif
@@ -847,10 +861,10 @@ GPtrArray* spice_usb_device_manager_get_devices(SpiceUsbDeviceManager *self)
guint i;
devices_copy = g_ptr_array_new_with_free_func((GDestroyNotify)
- libusb_unref_device);
+ spice_usb_device_unref);
for (i = 0; i < priv->devices->len; i++) {
- libusb_device *device = g_ptr_array_index(priv->devices, i);
- g_ptr_array_add(devices_copy, libusb_ref_device(device));
+ SpiceUsbDevice *device = g_ptr_array_index(priv->devices, i);
+ g_ptr_array_add(devices_copy, spice_usb_device_ref(device));
}
#endif
@@ -899,6 +913,7 @@ void spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
#ifdef USE_USBREDIR
SpiceUsbDeviceManagerPrivate *priv = self->priv;
+ libusb_device *libdev;
guint i;
if (spice_usb_device_manager_is_device_connected(self, device)) {
@@ -914,11 +929,13 @@ void spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
if (spice_usbredir_channel_get_device(channel))
continue; /* Skip already used channels */
+ libdev = spice_usb_device_manager_device_to_libdev(self, device);
spice_usbredir_channel_connect_device_async(channel,
- (libusb_device *)device,
+ libdev,
cancellable,
spice_usb_device_manager_channel_connect_cb,
result);
+ libusb_unref_device(libdev);
return;
}
#endif
@@ -1010,13 +1027,21 @@ spice_usb_device_manager_can_redirect_device(SpiceUsbDeviceManager *self,
g_ptr_array_index(priv->channels, 0),
&guest_filter_rules, &guest_filter_rules_count);
- if (guest_filter_rules &&
- usbredirhost_check_device_filter(
+ if (guest_filter_rules) {
+ gboolean filter_ok;
+ libusb_device *libdev;
+
+ libdev = spice_usb_device_manager_device_to_libdev(self, device);
+ g_return_val_if_fail(libdev != NULL, FALSE);
+ filter_ok = (usbredirhost_check_device_filter(
guest_filter_rules, guest_filter_rules_count,
- (libusb_device *)device, 0) != 0) {
- g_set_error_literal(err, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
- _("Some USB devices are blocked by host policy"));
- return FALSE;
+ libdev, 0) == 0);
+ libusb_unref_device(libdev);
+ if (!filter_ok) {
+ g_set_error_literal(err, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
+ _("Some USB devices are blocked by host policy"));
+ return FALSE;
+ }
}
/* Check if there are free channels */
@@ -1060,28 +1085,21 @@ spice_usb_device_manager_can_redirect_device(SpiceUsbDeviceManager *self,
*
* Returns: a newly-allocated string holding the description, or %NULL if failed
*/
-gchar *spice_usb_device_get_description(SpiceUsbDevice *_device, const gchar *format)
+gchar *spice_usb_device_get_description(SpiceUsbDevice *device, const gchar *format)
{
#ifdef USE_USBREDIR
- libusb_device *device = (libusb_device *)_device;
- struct libusb_device_descriptor desc;
int bus, address, vid, pid;
gchar *description, *descriptor, *manufacturer = NULL, *product = NULL;
g_return_val_if_fail(device != NULL, NULL);
- bus = libusb_get_bus_number(device);
- address = libusb_get_device_address(device);
- vid = -1;
- pid = -1;
-
- if (libusb_get_device_descriptor(device, &desc) == LIBUSB_SUCCESS) {
- vid = desc.idVendor;
- pid = desc.idProduct;
- }
+ bus = spice_usb_device_get_busnum(device);
+ address = spice_usb_device_get_devaddr(device);
+ vid = spice_usb_device_get_vid(device);
+ pid = spice_usb_device_get_pid(device);
if ((vid > 0) && (pid > 0)) {
- descriptor = g_strdup_printf("[%04x:%04x]", desc.idVendor, desc.idProduct);
+ descriptor = g_strdup_printf("[%04x:%04x]", vid, pid);
} else {
descriptor = g_strdup("");
}
@@ -1217,4 +1235,53 @@ spice_usb_device_equal_libdev(SpiceUsbDevice *device,
return ((bus1 == bus2) && (addr1 == addr2));
}
+
+static SpiceUsbDevice *
+spice_usb_device_manager_libdev_to_device(SpiceUsbDeviceManager *self,
+ libusb_device *libdev)
+{
+ guint8 bus, addr;
+
+ bus = libusb_get_bus_number(libdev);
+ addr = libusb_get_device_address(libdev);
+
+ return spice_usb_device_manager_find_device(self, bus, addr);
+}
+
+/*
+ * Caller must libusb_unref_device the libusb_device returned by this function.
+ * Returns a libusb_device, or NULL upon failure
+ */
+static libusb_device *
+spice_usb_device_manager_device_to_libdev(SpiceUsbDeviceManager *self,
+ SpiceUsbDevice *device)
+{
+ libusb_device *d, **devlist;
+ guint8 bus, addr;
+ int i;
+
+ g_return_val_if_fail(SPICE_IS_USB_DEVICE_MANAGER(self), NULL);
+ g_return_val_if_fail(device != NULL, NULL);
+ g_return_val_if_fail(self->priv != NULL, NULL);
+ g_return_val_if_fail(self->priv->context != NULL, NULL);
+
+ bus = spice_usb_device_get_busnum(device);
+ addr = spice_usb_device_get_devaddr(device);
+
+ libusb_get_device_list(self->priv->context, &devlist);
+ if (!devlist)
+ return NULL;
+
+ for (i = 0; (d = devlist[i]) != NULL; i++) {
+ if ((libusb_get_bus_number(d) == bus) &&
+ (libusb_get_device_address(d) == addr)) {
+ libusb_ref_device(d);
+ break;
+ }
+ }
+
+ libusb_free_device_list(devlist, 1);
+
+ return d;
+}
#endif /* USE_USBREDIR */
commit 4c1202f994fe52aa1242fe0e88e6fd51a3b24207
Author: Uri Lublin <uril at redhat.com>
Date: Thu Jul 5 23:43:54 2012 +0300
Introduce SpiceUsbDeviceInfo to be kept instead of a libusb_device
For Windows, it's better not to keep references for libusb_devices
that are not used.
So instead of makeing SpiceUsbDevice a box for a libusb_device
it is going to be a box for a SpiceUsbDeviceInfo.
diff --git a/gtk/usb-device-manager-priv.h b/gtk/usb-device-manager-priv.h
index 079f638..a8617ba 100644
--- a/gtk/usb-device-manager-priv.h
+++ b/gtk/usb-device-manager-priv.h
@@ -35,6 +35,12 @@ void spice_usb_device_manager_stop_event_listening(
#include <libusb.h>
void spice_usb_device_manager_device_error(
SpiceUsbDeviceManager *manager, libusb_device *libdev, GError *err);
+
+guint8 spice_usb_device_get_busnum(SpiceUsbDevice *device);
+guint8 spice_usb_device_get_devaddr(SpiceUsbDevice *device);
+guint16 spice_usb_device_get_vid(SpiceUsbDevice *device);
+guint16 spice_usb_device_get_pid(SpiceUsbDevice *device);
+
#endif
G_END_DECLS
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index 09cb1f9..abfac2b 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -102,6 +102,16 @@ struct _SpiceUsbDeviceManagerPrivate {
};
#ifdef USE_USBREDIR
+
+typedef struct _SpiceUsbDeviceInfo {
+ guint8 busnum;
+ guint8 devaddr;
+ guint16 vid;
+ guint16 pid;
+ gint ref;
+} SpiceUsbDeviceInfo;
+
+
static void channel_new(SpiceSession *session, SpiceChannel *channel,
gpointer user_data);
static void channel_destroy(SpiceSession *session, SpiceChannel *channel,
@@ -113,6 +123,12 @@ static void spice_usb_device_manager_uevent_cb(GUdevClient *client,
static void spice_usb_device_manager_add_dev(SpiceUsbDeviceManager *self,
GUdevDevice *udev);
+static SpiceUsbDeviceInfo *spice_usb_device_new(libusb_device *libdev);
+static SpiceUsbDevice *spice_usb_device_ref(SpiceUsbDevice *device);
+static void spice_usb_device_unref(SpiceUsbDevice *device);
+
+static gboolean spice_usb_device_equal_libdev(SpiceUsbDevice *device,
+ libusb_device *libdev);
G_DEFINE_BOXED_TYPE(SpiceUsbDevice, spice_usb_device,
(GBoxedCopyFunc)libusb_ref_device,
(GBoxedFreeFunc)libusb_unref_device)
@@ -1087,3 +1103,118 @@ gchar *spice_usb_device_get_description(SpiceUsbDevice *_device, const gchar *fo
return NULL;
#endif
}
+
+
+
+#ifdef USE_USBREDIR
+/*
+ * SpiceUsbDeviceInfo
+ */
+static SpiceUsbDeviceInfo *spice_usb_device_new(libusb_device *libdev)
+{
+ SpiceUsbDeviceInfo *info;
+ struct libusb_device_descriptor desc;
+ int errcode;
+ const gchar *errstr;
+ guint8 bus, addr;
+
+ g_return_val_if_fail(libdev != NULL, NULL);
+
+ bus = libusb_get_bus_number(libdev);
+ addr = libusb_get_device_address(libdev);
+
+ errcode = libusb_get_device_descriptor(libdev, &desc);
+ if (errcode < 0) {
+ errstr = spice_usbutil_libusb_strerror(errcode);
+ g_warning("cannot get device descriptor for (%p) %d.%d -- %s(%d)",
+ libdev, bus, addr, errstr, errcode);
+ return NULL;
+ }
+
+ info = g_new0(SpiceUsbDeviceInfo, 1);
+
+ info->busnum = bus;
+ info->devaddr = addr;
+ info->vid = desc.idVendor;
+ info->pid = desc.idProduct;
+ info->ref = 1;
+
+ return info;
+}
+
+guint8 spice_usb_device_get_busnum(SpiceUsbDevice *device)
+{
+ SpiceUsbDeviceInfo *info = (SpiceUsbDeviceInfo *)device;
+
+ g_return_val_if_fail(info != NULL, 0);
+
+ return info->busnum;
+}
+
+guint8 spice_usb_device_get_devaddr(SpiceUsbDevice *device)
+{
+ SpiceUsbDeviceInfo *info = (SpiceUsbDeviceInfo *)device;
+
+ g_return_val_if_fail(info != NULL, 0);
+
+ return info->devaddr;
+}
+
+guint16 spice_usb_device_get_vid(SpiceUsbDevice *device)
+{
+ SpiceUsbDeviceInfo *info = (SpiceUsbDeviceInfo *)device;
+
+ g_return_val_if_fail(info != NULL, 0);
+
+ return info->vid;
+}
+
+guint16 spice_usb_device_get_pid(SpiceUsbDevice *device)
+{
+ SpiceUsbDeviceInfo *info = (SpiceUsbDeviceInfo *)device;
+
+ g_return_val_if_fail(info != NULL, 0);
+
+ return info->pid;
+}
+
+static SpiceUsbDevice *spice_usb_device_ref(SpiceUsbDevice *device)
+{
+ SpiceUsbDeviceInfo *info = (SpiceUsbDeviceInfo *)device;
+
+ g_return_val_if_fail(info != NULL, NULL);
+ g_atomic_int_inc(&info->ref);
+ return device;
+}
+
+static void spice_usb_device_unref(SpiceUsbDevice *device)
+{
+ gboolean ref_count_is_0;
+
+ SpiceUsbDeviceInfo *info = (SpiceUsbDeviceInfo *)device;
+
+ g_return_if_fail(info != NULL);
+
+ ref_count_is_0 = g_atomic_int_dec_and_test(&info->ref);
+ if (ref_count_is_0) {
+ g_free(info);
+ }
+}
+
+static gboolean
+spice_usb_device_equal_libdev(SpiceUsbDevice *device,
+ libusb_device *libdev)
+{
+ guint8 addr1, addr2, bus1, bus2;
+
+ if ((device == NULL) || (libdev == NULL))
+ return FALSE;
+
+ bus1 = spice_usb_device_get_busnum(device);
+ addr1 = spice_usb_device_get_devaddr(device);
+ bus2 = libusb_get_bus_number(libdev);
+ addr2 = libusb_get_device_address(libdev);
+
+ return ((bus1 == bus2) && (addr1 == addr2));
+}
+#endif /* USE_USBREDIR */
commit 42216eb7de4228db8fd30b4ad87846b21a76cc70
Author: Uri Lublin <uril at redhat.com>
Date: Thu Jul 5 23:43:56 2012 +0300
Windows mingw: usb: configure.ac: do not require GUDEV for USBREDIR
For windows GUDEV is not required
For Linux GUDEV is checked as a part of USBREDIR block, but
as a separate check.
diff --git a/configure.ac b/configure.ac
index 3841c56..233ce4d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -343,7 +343,7 @@ if test "x$enable_usbredir" = "xno"; then
have_usbredir="no"
else
PKG_CHECK_MODULES([USBREDIR],
- [gudev-1.0 libusb-1.0 >= 1.0.9 libusbredirhost >= 0.4.2 libusbredirparser >= 0.4],
+ [libusb-1.0 >= 1.0.9 libusbredirhost >= 0.4.2 libusbredirparser >= 0.4],
[have_usbredir=yes],
[have_usbredir=no])
if test "x$have_usbredir" = "xno" && test "x$enable_usbredir" = "xyes"; then
@@ -352,6 +352,19 @@ else
if test "x$have_usbredir" = "xyes"; then
AC_DEFINE(USE_USBREDIR, [1], [Define if supporting usbredir proxying])
fi
+
+ # Require gudev for non-windows
+ if test "x$os_win32" = "xno"; then
+ PKG_CHECK_MODULES([GUDEV],
+ [gudev-1.0],
+ [have_gudev=yes],
+ [have_gudev=no])
+
+ if test "x$have_usbredir" = "xyes" && test "x$have_gudev" = "xno"; then
+ AC_MSG_ERROR([usbredir requested but required gudev is not available])
+ fi
+ AC_DEFINE(USE_GUDEV, [1], [Define if supporting gudev])
+ fi
fi
AM_CONDITIONAL([WITH_USBREDIR], [test "x$have_usbredir" = "xyes"])
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index f5f6bc6..10fa9cd 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -83,6 +83,7 @@ SPICE_COMMON_CPPFLAGS = \
$(GST_CFLAGS) \
$(SMARTCARD_CFLAGS) \
$(USBREDIR_CFLAGS) \
+ $(GUDEV_CFLAGS) \
$(NULL)
AM_CPPFLAGS = \
@@ -183,6 +184,7 @@ libspice_client_glib_2_0_la_LIBADD = \
$(SASL_LIBS) \
$(SMARTCARD_LIBS) \
$(USBREDIR_LIBS) \
+ $(GUDEV_LIBS) \
$(NULL)
if WITH_POLKIT
commit f871ed2176abb95a4335882a438be6c77a3f1b69
Author: Uri Lublin <uril at redhat.com>
Date: Thu Jul 5 23:44:05 2012 +0300
usb-device-manager: mingw: add_dev: ignore already known devices
Sometimes on a Windows client, udev events are received while
the driver is being un/installed. so just ignore it
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index ffddb3b..09cb1f9 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -580,6 +580,14 @@ static void spice_usb_device_manager_add_dev(SpiceUsbDeviceManager *self,
return;
}
+#ifdef G_OS_WIN32
+ device = spice_usb_device_manager_find_device(self, bus, address);
+ if (device) {
+ SPICE_DEBUG("USB device at %d.%d already exists, ignored", bus, address);
+ return;
+ }
+#endif
+
if (priv->coldplug_list)
dev_list = priv->coldplug_list;
else
commit 235e878181dfb97e0a0f116ff33e25dcfad66361
Author: Uri Lublin <uril at redhat.com>
Date: Thu Jul 5 23:44:03 2012 +0300
usb-device-manager: add a helper function to find a usb device <bus, addr>
And use it in spice_usb_device_manager_remove_dev
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index 04c3169..ffddb3b 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -536,6 +536,25 @@ static void spice_usb_device_manager_auto_connect_cb(GObject *gobject,
libusb_unref_device((libusb_device*)device);
}
+static SpiceUsbDevice*
+spice_usb_device_manager_find_device(SpiceUsbDeviceManager *self,
+ guint8 bus, guint8 address)
+{
+ SpiceUsbDeviceManagerPrivate *priv = self->priv;
+ SpiceUsbDevice *curr, *device = NULL;
+ guint i;
+
+ for (i = 0; i < priv->devices->len; i++) {
+ curr = g_ptr_array_index(priv->devices, i);
+ if (libusb_get_bus_number((libusb_device*)curr) == bus &&
+ libusb_get_device_address((libusb_device*)curr) == address) {
+ device = curr;
+ break;
+ }
+ }
+ return device;
+}
+
static void spice_usb_device_manager_add_dev(SpiceUsbDeviceManager *self,
GUdevDevice *udev)
{
@@ -616,22 +635,13 @@ static void spice_usb_device_manager_remove_dev(SpiceUsbDeviceManager *self,
GUdevDevice *udev)
{
SpiceUsbDeviceManagerPrivate *priv = self->priv;
- SpiceUsbDevice *curr, *device = NULL;
+ SpiceUsbDevice *device = NULL;
int bus, address;
- guint i;
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((libusb_device*)curr) == bus &&
- libusb_get_device_address((libusb_device*)curr) == address) {
- device = curr;
- break;
- }
- }
-
+ device = spice_usb_device_manager_find_device(self, bus, address);
if (!device) {
g_warning("Could not find USB device to remove at busnum %d devaddr %d",
bus, address);
commit 0ba45213b0f44660e9e06da3c68b9d28e1736a14
Author: Uri Lublin <uril at redhat.com>
Date: Sun Jul 8 13:16:31 2012 +0300
spice_usb_device_get_description: use device-descriptor only to get <vid,pid>
In preparation for a different SpiceUsbDevice.
With the new SpiceUsbDeviceInfo, <vid,pid> will be provided by
SpiceUsbDevice, and not by the device_descriptor (from libusb)
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index 9f29c76..04c3169 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -1031,25 +1031,30 @@ gchar *spice_usb_device_get_description(SpiceUsbDevice *_device, const gchar *fo
#ifdef USE_USBREDIR
libusb_device *device = (libusb_device *)_device;
struct libusb_device_descriptor desc;
- int bus, address;
+ int bus, address, vid, pid;
gchar *description, *descriptor, *manufacturer = NULL, *product = NULL;
g_return_val_if_fail(device != NULL, NULL);
bus = libusb_get_bus_number(device);
address = libusb_get_device_address(device);
+ vid = -1;
+ pid = -1;
if (libusb_get_device_descriptor(device, &desc) == LIBUSB_SUCCESS) {
- spice_usb_util_get_device_strings(bus, address,
- desc.idVendor, desc.idProduct,
- &manufacturer, &product);
+ vid = desc.idVendor;
+ pid = desc.idProduct;
+ }
+
+ if ((vid > 0) && (pid > 0)) {
descriptor = g_strdup_printf("[%04x:%04x]", desc.idVendor, desc.idProduct);
} else {
- spice_usb_util_get_device_strings(bus, address, -1, -1,
- &manufacturer, &product);
descriptor = g_strdup("");
}
+ spice_usb_util_get_device_strings(bus, address, vid, pid,
+ &manufacturer, &product);
+
if (!format)
format = _("%s %s %s at %d-%d");
commit 15b4e7890faf3e5d65490d4650f3bf4649b3fd5a
Author: Uri Lublin <uril at redhat.com>
Date: Sun Jul 8 12:40:59 2012 +0300
spice_usb_device_manager_device_error: replace SpiceUsbDevice with libusb_device
Its only user is channel-usbredir, which needs the libusb_device.
In preparations for a different SpiceUsbDevice.
diff --git a/gtk/channel-usbredir.c b/gtk/channel-usbredir.c
index 3d57152..354d2e1 100644
--- a/gtk/channel-usbredir.c
+++ b/gtk/channel-usbredir.c
@@ -569,7 +569,7 @@ static void do_emit_main_context(GObject *object, int event, gpointer params)
spice_usb_device_manager_device_error(
spice_usb_device_manager_get(
spice_channel_get_session(SPICE_CHANNEL(channel)), NULL),
- (SpiceUsbDevice *)p->device, p->error);
+ p->device, p->error);
}
break;
}
diff --git a/gtk/usb-device-manager-priv.h b/gtk/usb-device-manager-priv.h
index 912e3bf..079f638 100644
--- a/gtk/usb-device-manager-priv.h
+++ b/gtk/usb-device-manager-priv.h
@@ -31,8 +31,11 @@ gboolean spice_usb_device_manager_start_event_listening(
void spice_usb_device_manager_stop_event_listening(
SpiceUsbDeviceManager *manager);
+#ifdef USE_USBREDIR
+#include <libusb.h>
void spice_usb_device_manager_device_error(
- SpiceUsbDeviceManager *manager, SpiceUsbDevice *device, GError *err);
+ SpiceUsbDeviceManager *manager, libusb_device *libdev, GError *err);
+#endif
G_END_DECLS
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index dbf3493..9f29c76 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -736,8 +736,9 @@ void spice_usb_device_manager_stop_event_listening(
}
void spice_usb_device_manager_device_error(
- SpiceUsbDeviceManager *self, SpiceUsbDevice *device, GError *err)
+ SpiceUsbDeviceManager *self, libusb_device *libdev, GError *err)
{
+ SpiceUsbDevice *device = (SpiceUsbDevice *)libdev;
g_signal_emit(self, signals[DEVICE_ERROR], 0, device, err);
}
#endif
commit c1799ead7e0577a201663ade9acc2935db1a9b9e
Author: Uri Lublin <uril at redhat.com>
Date: Sun Jul 8 16:21:15 2012 +0300
spice_usb_device_manager_auto_connect_cb: use type SpiceUsbDevice for "device"
Currently SpiceUsbDevice is a BOX for libusb_device.
In preparation for a different SpiceUsbDevice.
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index d4ad1f9..dbf3493 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -520,12 +520,12 @@ static void spice_usb_device_manager_auto_connect_cb(GObject *gobject,
gpointer user_data)
{
SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(gobject);
- libusb_device *device = user_data;
+ SpiceUsbDevice *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((SpiceUsbDevice *)device, NULL);
+ gchar *desc = spice_usb_device_get_description(device, NULL);
g_prefix_error(&err, "Could not auto-redirect %s: ", desc);
g_free(desc);
@@ -533,7 +533,7 @@ 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);
}
- libusb_unref_device(device);
+ libusb_unref_device((libusb_device*)device);
}
static void spice_usb_device_manager_add_dev(SpiceUsbDeviceManager *self,
commit 97740e38e641de0fa5a90a049bfb40125c07ab45
Author: Uri Lublin <uril at redhat.com>
Date: Sun Jul 8 12:12:38 2012 +0300
spice_usb_device_manager_add_dev: use type SpiceUsbDevice for "device"
Currently SpiceUsbDevice is a BOX for libusb_device.
In preparation for a different SpiceUsbDevice.
Renamed the libusb_device variable to libdev. Needed when
asking usbredir to check the filter.
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index a81db57..d4ad1f9 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -540,7 +540,8 @@ static void spice_usb_device_manager_add_dev(SpiceUsbDeviceManager *self,
GUdevDevice *udev)
{
SpiceUsbDeviceManagerPrivate *priv = self->priv;
- libusb_device *device = NULL, **dev_list = NULL;
+ libusb_device *libdev = NULL, **dev_list = NULL;
+ SpiceUsbDevice *device = NULL;
const gchar *devtype, *devclass;
int i, bus, address;
gboolean auto_ok = FALSE;
@@ -568,16 +569,19 @@ static void spice_usb_device_manager_add_dev(SpiceUsbDeviceManager *self,
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]);
+ libdev = dev_list[i];
break;
}
}
+ if (libdev)
+ device = (SpiceUsbDevice*)libusb_ref_device(libdev);
+
if (device && priv->auto_connect) {
auto_ok = usbredirhost_check_device_filter(
priv->auto_conn_filter_rules,
priv->auto_conn_filter_rules_count,
- device, 0) == 0;
+ libdev, 0) == 0;
}
if (!priv->coldplug_list)
@@ -595,13 +599,13 @@ static void spice_usb_device_manager_add_dev(SpiceUsbDeviceManager *self,
gboolean can_redirect;
can_redirect = spice_usb_device_manager_can_redirect_device(
- self, (SpiceUsbDevice *)device, NULL);
+ self, device, NULL);
if (can_redirect && auto_ok)
spice_usb_device_manager_connect_device_async(self,
- (SpiceUsbDevice *)device, NULL,
+ device, NULL,
spice_usb_device_manager_auto_connect_cb,
- libusb_ref_device(device));
+ libusb_ref_device(libdev));
}
SPICE_DEBUG("device added %p", device);
commit a0ec25a1706074a2db062df36ecc96828f960a2f
Author: Uri Lublin <uril at redhat.com>
Date: Sun Jul 8 12:04:26 2012 +0300
spice_usb_device_manager_add_dev: check auto_ok before freeing libusb device list
In preparation for a different SpiceUsbDevice.
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index c50a7da..a81db57 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -543,6 +543,7 @@ static void spice_usb_device_manager_add_dev(SpiceUsbDeviceManager *self,
libusb_device *device = NULL, **dev_list = NULL;
const gchar *devtype, *devclass;
int i, bus, address;
+ gboolean auto_ok = FALSE;
devtype = g_udev_device_get_property(udev, "DEVTYPE");
/* Check if this is a usb device (and not an interface) */
@@ -572,6 +573,13 @@ static void spice_usb_device_manager_add_dev(SpiceUsbDeviceManager *self,
}
}
+ if (device && priv->auto_connect) {
+ auto_ok = usbredirhost_check_device_filter(
+ priv->auto_conn_filter_rules,
+ priv->auto_conn_filter_rules_count,
+ device, 0) == 0;
+ }
+
if (!priv->coldplug_list)
libusb_free_device_list(dev_list, 1);
@@ -584,16 +592,11 @@ static void spice_usb_device_manager_add_dev(SpiceUsbDeviceManager *self,
g_ptr_array_add(priv->devices, device);
if (priv->auto_connect) {
- gboolean can_redirect, auto_ok;
+ gboolean can_redirect;
can_redirect = spice_usb_device_manager_can_redirect_device(
self, (SpiceUsbDevice *)device, NULL);
- auto_ok = usbredirhost_check_device_filter(
- priv->auto_conn_filter_rules,
- priv->auto_conn_filter_rules_count,
- device, 0) == 0;
-
if (can_redirect && auto_ok)
spice_usb_device_manager_connect_device_async(self,
(SpiceUsbDevice *)device, NULL,
commit 2339c0005ce38e2fb57a748390cb12c11241f756
Author: Uri Lublin <uril at redhat.com>
Date: Sun Jul 8 10:08:11 2012 +0300
spice_usb_device_manager_remove_dev: use type SpiceUsbDevice for "device"
Currently SpiceUsbDevice is a BOX for libusb_device.
In preparation for a different SpiceUsbDevice.
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index 8b277cc..c50a7da 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -609,7 +609,7 @@ static void spice_usb_device_manager_remove_dev(SpiceUsbDeviceManager *self,
GUdevDevice *udev)
{
SpiceUsbDeviceManagerPrivate *priv = self->priv;
- libusb_device *curr, *device = NULL;
+ SpiceUsbDevice *curr, *device = NULL;
int bus, address;
guint i;
@@ -618,8 +618,8 @@ static void spice_usb_device_manager_remove_dev(SpiceUsbDeviceManager *self,
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) {
+ if (libusb_get_bus_number((libusb_device*)curr) == bus &&
+ libusb_get_device_address((libusb_device*)curr) == address) {
device = curr;
break;
}
@@ -631,7 +631,7 @@ static void spice_usb_device_manager_remove_dev(SpiceUsbDeviceManager *self,
return;
}
- spice_usb_device_manager_disconnect_device(self, (SpiceUsbDevice *)device);
+ spice_usb_device_manager_disconnect_device(self, device);
SPICE_DEBUG("device removed %p", device);
g_signal_emit(self, signals[DEVICE_REMOVED], 0, device);
commit ad6127256316a227a5167db1f731069285323c7d
Author: Uri Lublin <uril at redhat.com>
Date: Thu Jul 5 23:44:09 2012 +0300
controller/test.c: mingw: fix compiler bad param warning for ReadFile
It seems that ssize_t is int, while DWORD is long
Compiler warning (some whitespaces where added for readability):
../../../gtk/controller/test.c: In function 'read_from_pipe':
../../../gtk/controller/test.c:108:5: warning: passing argument 4 \
of 'ReadFile' from incompatible pointer type [enabled by default]
In file included from /usr/i686-w64-mingw32/sys-root/mingw/include/windows.h:70:0,
from ../../../gtk/controller/test.c:27:
/usr/i686-w64-mingw32/sys-root/mingw/include/winbase.h:1426:29: note: expected \
'LPDWORD' but argument is of type 'ssize_t *'
diff --git a/gtk/controller/test.c b/gtk/controller/test.c
index 3f3eb55..f6f3975 100644
--- a/gtk/controller/test.c
+++ b/gtk/controller/test.c
@@ -105,9 +105,11 @@ ssize_t read_from_pipe (void* data, size_t size)
{
ssize_t read;
#ifdef WIN32
- if (!ReadFile (pipe, data, size, &read, NULL)) {
+ DWORD bytes;
+ if (!ReadFile (pipe, data, size, &bytes, NULL)) {
printf ("Read from pipe failed %u\n", GetLastError());
}
+ read = bytes;
#else
read = recv (sock, data, size, 0);
if ((read == -1 || read == 0)) {
commit b22a0976f4ae89fc9cd9eb188af16ca309318bd3
Author: Uri Lublin <uril at redhat.com>
Date: Thu Jul 5 23:43:59 2012 +0300
usb-device-manager: warn if a device to remove was not found
Also changed a bit the warning text on device-add to differentiate the two.
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index b39c2d4..8b277cc 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -576,7 +576,7 @@ static void spice_usb_device_manager_add_dev(SpiceUsbDeviceManager *self,
libusb_free_device_list(dev_list, 1);
if (!device) {
- g_warning("Could not find USB device at busnum %d devaddr %d",
+ g_warning("Could not find USB device to add at busnum %d devaddr %d",
bus, address);
return;
}
@@ -624,8 +624,12 @@ static void spice_usb_device_manager_remove_dev(SpiceUsbDeviceManager *self,
break;
}
}
- if (!device)
+
+ if (!device) {
+ g_warning("Could not find USB device to remove at busnum %d devaddr %d",
+ bus, address);
return;
+ }
spice_usb_device_manager_disconnect_device(self, (SpiceUsbDevice *)device);
commit 9edc7885264832d0ecbccbfb1df943ac5ef39bf2
Author: Uri Lublin <uril at redhat.com>
Date: Thu Jul 5 23:43:53 2012 +0300
spicy: more informative presentation of usb devices in menu
Using the default format.
diff --git a/gtk/spicy.c b/gtk/spicy.c
index 98a44d5..5ffe3b7 100644
--- a/gtk/spicy.c
+++ b/gtk/spicy.c
@@ -460,7 +460,7 @@ static void menu_cb_select_usb_devices(GtkAction *action, void *data)
area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
usb_device_widget = spice_usb_device_widget_new(win->conn->session,
- "%s %s");
+ NULL); /* default format */
g_signal_connect(usb_device_widget, "connect-failed",
G_CALLBACK(usb_connect_failed), NULL);
gtk_box_pack_start(GTK_BOX(area), usb_device_widget, TRUE, TRUE, 0);
More information about the Spice-commits
mailing list