[Spice-devel] [spice-gtk Win32 v3 08/12] Windows mingw: usb: Dynamically install a libusb driver for USB devices
Uri Lublin
uril at redhat.com
Wed Jun 27 18:46:37 PDT 2012
- 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.
---
gtk/Makefile.am | 11 ++
gtk/usb-device-manager.c | 143 +++++++++++++++-
gtk/win-usb-clerk.h | 35 ++++
gtk/win-usb-driver-install.c | 379 ++++++++++++++++++++++++++++++++++++++++++
gtk/win-usb-driver-install.h | 98 +++++++++++
5 files changed, 660 insertions(+), 6 deletions(-)
create mode 100644 gtk/win-usb-clerk.h
create mode 100644 gtk/win-usb-driver-install.c
create mode 100644 gtk/win-usb-driver-install.h
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 4df3ee5..646b614 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -313,9 +313,20 @@ libspice_client_glib_2_0_la_LIBADD += $(GTHREAD_LIBS)
endif
+NAMED_PIPE_FILES = \
+ controller/namedpipe.h \
+ controller/namedpipe.c \
+ controller/namedpipeconnection.c \
+ controller/namedpipeconnection.h \
+ $(NULL)
+
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 \
+ $(NAMED_PIPE_FILES) \
$(NULL)
if OS_WIN32
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index e4c8c32..8340335 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
@@ -122,6 +123,14 @@ static void spice_usb_device_manager_uevent_cb(GUdevClient *client,
gpointer user_data);
static void spice_usb_device_manager_add_dev(SpiceUsbDeviceManager *self,
GUdevDevice *udev);
+
+static void
+_spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
+ SpiceUsbDevice *device,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
static
libusb_device *spice_usb_device_find_libusb_device(SpiceUsbDeviceManager *self,
SpiceUsbDevice *device);
@@ -129,6 +138,12 @@ libusb_device *spice_usb_device_find_libusb_device(SpiceUsbDeviceManager *self,
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,
@@ -604,7 +619,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,
- g_object_ref(device));
+ device);
}
}
@@ -669,6 +684,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
+ */
+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(SPICE_IS_USB_DEVICE(device));
+
+ status = spice_win_usb_driver_install_finish(installer, res, &err);
+
+ g_object_unref(installer);
+
+ if (err) {
+ g_warning("win usb driver installation failed -- %s",
+ err->message);
+ g_error_free(err);
+ g_object_unref(device);
+ return;
+ }
+
+ if (!status) {
+ g_warning("failed to install win usb driver (status=0)");
+ g_object_unref(device);
+ return;
+ }
+
+ /* device is already ref'ed */
+ _spice_usb_device_manager_connect_device_async(self,
+ device,
+ cancellable,
+ callback,
+ user_data);
+
+}
+#endif
+
/* ------------------------------------------------------------------ */
/* private api */
@@ -841,11 +937,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;
@@ -893,6 +990,40 @@ done:
g_object_unref(result);
}
+
+void spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
+ SpiceUsbDevice *device,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+
+ device = g_object_ref(device);
+
+#ifdef G_OS_WIN32
+ SpiceWinUsbDriver *installer;
+ UsbInstallCbInfo *cbinfo;
+
+ installer = spice_win_usb_driver_new();
+ cbinfo = g_new0(UsbInstallCbInfo, 1);
+ cbinfo->manager = self;
+ cbinfo->device = device;
+ cbinfo->installer = installer;
+ cbinfo->cancellable = cancellable;
+ cbinfo->callback = callback;
+ cbinfo->user_data = user_data;
+ spice_win_usb_driver_install(installer, device, NULL,
+ 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..9f4fdfc
--- /dev/null
+++ b/gtk/win-usb-driver-install.c
@@ -0,0 +1,379 @@
+/* -*- 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/>.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gio/gio.h>
+#include "spice-util.h"
+#include "win-usb-clerk.h"
+#include "win-usb-driver-install.h"
+#include "controller/namedpipe.h"
+#include "controller/namedpipeconnection.h"
+#include "spice-usb-device.h"
+#include "spice-usb-device-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;
+ gulong cancellable_id;
+ GIOStream *gios;
+ 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)
+{
+ SpiceWinUsbDriverPrivate *priv;
+ GError *err = NULL;
+
+ g_return_if_fail(self != NULL);
+ priv = self->priv;
+ g_return_if_fail(priv != NULL);
+
+ if (priv->gios) {
+ g_io_stream_close(priv->gios, NULL, &err);
+ if (err) { /* just warn about it */
+ g_warning("failed to close namedpipe stream %s", err->message);
+ }
+
+ g_clear_object(&priv->gios);
+ }
+}
+
+static void spice_win_usb_driver_cleanup(SpiceWinUsbDriver *self)
+{
+ SpiceWinUsbDriverPrivate *priv = self->priv;
+
+ spice_win_usb_driver_close(self);
+
+ if (priv->cancellable_id) { /* FIXME: should be in acl_helper too ? */
+ g_cancellable_disconnect(priv->cancellable, priv->cancellable_id);
+ priv->cancellable = NULL;
+ priv->cancellable_id = 0;
+ }
+
+ g_clear_object(&priv->result);
+
+}
+
+static void spice_win_usb_driver_finalize(GObject *gobject)
+{
+ spice_win_usb_driver_cleanup(SPICE_WIN_USB_DRIVER(gobject));
+}
+
+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 */
+
+static void win_usb_driver_async_result_set_cancelled(GSimpleAsyncResult *result)
+{
+ g_simple_async_result_set_error(result,
+ G_IO_ERROR, G_IO_ERROR_CANCELLED,
+ "Win USB driver installation cancelled");
+}
+
+static void win_usb_driver_cancelled_cb(GCancellable *cancellable, gpointer user_data)
+{
+ SpiceWinUsbDriver *self = SPICE_WIN_USB_DRIVER(user_data);
+ SpiceWinUsbDriverPrivate *priv = self->priv;
+
+ g_message("IN %s result=%p", __FUNCTION__, priv->result);
+ if (priv->result) {
+ win_usb_driver_async_result_set_cancelled(priv->result);
+ g_simple_async_result_complete_in_idle(priv->result);
+ }
+}
+
+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_io_stream_get_input_stream(priv->gios);
+ bytes = g_input_stream_read_finish(istream, read_res, &err);
+
+ SPICE_DEBUG("Finished reading: bytes=%ld err_exist?=%d", (long)bytes, err!=NULL);
+
+ 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 (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;
+ GOutputStream *ostream;
+ SpiceWinUsbDriverPrivate *priv;
+ gsize bytes;
+ gboolean b;
+
+ 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;
+
+ memset(&req, 0, sizeof(req));
+ 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_io_stream_get_output_stream(priv->gios);
+
+ b = g_output_stream_write_all(ostream, &req, sizeof(req), &bytes, NULL, err);
+ SPICE_DEBUG("write_all request returned %d written bytes %u expecting %u",
+ b, bytes, sizeof(req));
+ return b;
+}
+
+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_io_stream_get_input_stream(priv->gios);
+
+ g_input_stream_read_async(istream, &priv->reply, sizeof(priv->reply),
+ G_PRIORITY_DEFAULT, NULL,
+ 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;
+ SpiceNamedPipe *np;
+ SpiceNamedPipeConnection *npc;
+ 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(SPICE_IS_USB_DEVICE(device));
+
+ priv = self->priv;
+
+ 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");
+ np = spice_named_pipe_new(USB_CLERK_PIPE_NAME, FALSE, &err);
+ if (!np) {
+ g_warning("failed to create a named pipe to usbclerk %s", err->message);
+ g_simple_async_result_take_error(result, err);
+ goto failed_request;
+ }
+
+ npc = g_object_new(SPICE_TYPE_NAMED_PIPE_CONNECTION, "namedpipe", np, NULL);
+ priv->gios = G_IO_STREAM(npc);
+
+ 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;
+ if (cancellable) {
+ priv->cancellable = cancellable;
+ priv->cancellable_id = g_cancellable_connect(cancellable,
+ G_CALLBACK(win_usb_driver_cancelled_cb),
+ self, NULL);
+ }
+
+ spice_win_usb_driver_read_reply_async(self);
+
+ return;
+
+ failed_request:
+ 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..eb04707
--- /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
+
+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);
+
+
+#include "spice-usb-device.h"
+
+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 */
--
1.7.7.6
More information about the Spice-devel
mailing list