[Spice-devel] [PATCH spice-gtk 1/6] usbredir: Add device rejected errors
Hans de Goede
hdegoede at redhat.com
Tue Feb 21 06:12:20 PST 2012
Signed-off-by: Hans de Goede <hdegoede at redhat.com>
---
gtk/channel-usbredir.c | 84 ++++++++++++++++++++++++++++++++++++++++++++--
gtk/channel-usbredir.h | 4 ++
gtk/spicy.c | 2 +
gtk/usb-device-manager.c | 37 ++++++++++++++++++++
gtk/usb-device-manager.h | 4 ++-
gtk/usb-device-widget.c | 21 +++++++++++
6 files changed, 148 insertions(+), 4 deletions(-)
diff --git a/gtk/channel-usbredir.c b/gtk/channel-usbredir.c
index e22aa6c..bf614e6 100644
--- a/gtk/channel-usbredir.c
+++ b/gtk/channel-usbredir.c
@@ -33,6 +33,7 @@
#include "spice-client.h"
#include "spice-common.h"
+#include "spice-marshal.h"
#include "spice-channel-priv.h"
#include "glib-compat.h"
@@ -98,6 +99,13 @@ static void usbredir_free_lock(void *user_data);
G_DEFINE_TYPE(SpiceUsbredirChannel, spice_usbredir_channel, SPICE_TYPE_CHANNEL)
+/* Signals */
+enum {
+ DEVICE_ERROR,
+ LAST_SIGNAL,
+};
+
+static guint signals[LAST_SIGNAL];
/* ------------------------------------------------------------------ */
static void spice_usbredir_channel_init(SpiceUsbredirChannel *channel)
@@ -116,8 +124,8 @@ static void spice_usbredir_channel_reset(SpiceChannel *channel, gboolean migrati
static void spice_usbredir_channel_class_init(SpiceUsbredirChannelClass *klass)
{
-#ifdef USE_USBREDIR
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+#ifdef USE_USBREDIR
SpiceChannelClass *channel_class = SPICE_CHANNEL_CLASS(klass);
gobject_class->dispose = spice_usbredir_channel_dispose;
@@ -128,6 +136,27 @@ static void spice_usbredir_channel_class_init(SpiceUsbredirChannelClass *klass)
g_type_class_add_private(klass, sizeof(SpiceUsbredirChannelPrivate));
#endif
+ /**
+ * SpiceUsbredirChannel::device-error:
+ * @channel: #SpiceUsbredirChannel that emitted the signal
+ * @device: #SpiceUsbDevice boxed object corresponding to the device which has an error
+ * @error: #GError describing the error
+ *
+ * The #SpiceUsbredirChannel::device-error signal is emitted whenever an
+ * error happens which causes a device to no longer be available to the
+ * guest.
+ **/
+ signals[DEVICE_ERROR] =
+ g_signal_new("device-error",
+ G_OBJECT_CLASS_TYPE(gobject_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET(SpiceUsbredirChannelClass, device_error),
+ NULL, NULL,
+ g_cclosure_user_marshal_VOID__BOXED_BOXED,
+ G_TYPE_NONE,
+ 2,
+ SPICE_TYPE_USB_DEVICE,
+ G_TYPE_ERROR);
}
#ifdef USE_USBREDIR
@@ -513,6 +542,34 @@ static void usbredir_free_lock(void *user_data) {
}
/* --------------------------------------------------------------------- */
+struct DEVICE_ERROR {
+ libusb_device *device;
+ GError *error;
+};
+
+/* main context */
+static void do_emit_main_context(GObject *object, int signum, gpointer params)
+{
+ SpiceUsbredirChannel *channel = SPICE_USBREDIR_CHANNEL(object);
+ SpiceUsbredirChannelPrivate *priv = channel->priv;
+
+ switch (signum) {
+ case DEVICE_ERROR: {
+ struct DEVICE_ERROR *p = params;
+ /* Check that the device has not changed before we manage to run */
+ if (p->device == priv->device) {
+ g_signal_emit(object, signals[DEVICE_ERROR], 0,
+ p->device, p->error);
+ spice_usbredir_channel_disconnect_device(channel);
+ }
+ break;
+ }
+ default:
+ g_warn_if_reached();
+ }
+}
+
+/* --------------------------------------------------------------------- */
/* coroutine context */
static void spice_usbredir_handle_msg(SpiceChannel *c, SpiceMsgIn *msg)
{
@@ -544,7 +601,7 @@ static void usbredir_handle_msg(SpiceChannel *c, SpiceMsgIn *in)
{
SpiceUsbredirChannel *channel = SPICE_USBREDIR_CHANNEL(c);
SpiceUsbredirChannelPrivate *priv = channel->priv;
- int size;
+ int r, size;
uint8_t *buf;
g_return_if_fail(priv->host != NULL);
@@ -556,7 +613,28 @@ static void usbredir_handle_msg(SpiceChannel *c, SpiceMsgIn *in)
priv->read_buf = buf;
priv->read_buf_size = size;
- usbredirhost_read_guest_data(priv->host);
+ r = usbredirhost_read_guest_data(priv->host);
+ if (r == usbredirhost_read_device_rejected) {
+ libusb_device *device = priv->device;
+ gchar *desc;
+ GError *err;
+
+ g_return_if_fail(device != NULL);
+
+ desc = spice_usb_device_get_description((SpiceUsbDevice *)device,
+ NULL);
+ err = g_error_new(SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
+ "%s rejected by host", desc);
+ g_free(desc);
+
+ SPICE_DEBUG("%s", err->message);
+
+ g_boxed_copy(spice_usb_device_get_type(), device);
+ emit_main_context(channel, DEVICE_ERROR, device, err);
+ g_boxed_free(spice_usb_device_get_type(), device);
+
+ g_error_free(err);
+ }
}
#endif /* USE_USBREDIR */
diff --git a/gtk/channel-usbredir.h b/gtk/channel-usbredir.h
index c7263b9..9fe4c32 100644
--- a/gtk/channel-usbredir.h
+++ b/gtk/channel-usbredir.h
@@ -36,6 +36,8 @@ typedef struct _SpiceUsbredirChannel SpiceUsbredirChannel;
typedef struct _SpiceUsbredirChannelClass SpiceUsbredirChannelClass;
typedef struct _SpiceUsbredirChannelPrivate SpiceUsbredirChannelPrivate;
+typedef struct _SpiceUsbDevice SpiceUsbDevice;
+
/**
* SpiceUsbredirChannel:
* @parent: Parent instance.
@@ -60,6 +62,8 @@ struct _SpiceUsbredirChannelClass {
SpiceChannelClass parent_class;
/* signals */
+ void (*device_error) (SpiceUsbredirChannel *channel,
+ SpiceUsbDevice *device, GError *error);
/*< private >*/
/* Do not add fields to this struct */
diff --git a/gtk/spicy.c b/gtk/spicy.c
index 2757bd7..40b724e 100644
--- a/gtk/spicy.c
+++ b/gtk/spicy.c
@@ -1573,6 +1573,8 @@ static spice_connection *connection_new(void)
if (manager) {
g_signal_connect(manager, "auto-connect-failed",
G_CALLBACK(usb_connect_failed), NULL);
+ g_signal_connect(manager, "device-error",
+ G_CALLBACK(usb_connect_failed), NULL);
}
connections++;
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index b6dfa20..cc67131 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -85,6 +85,7 @@ enum
DEVICE_ADDED,
DEVICE_REMOVED,
AUTO_CONNECT_FAILED,
+ DEVICE_ERROR,
LAST_SIGNAL,
};
@@ -433,6 +434,28 @@ static void spice_usb_device_manager_class_init(SpiceUsbDeviceManagerClass *klas
SPICE_TYPE_USB_DEVICE,
G_TYPE_ERROR);
+ /**
+ * SpiceUsbDeviceManager::device-error:
+ * @manager: #SpiceUsbDeviceManager that emitted the signal
+ * @device: #SpiceUsbDevice boxed object corresponding to the device which has an error
+ * @error: #GError describing the error
+ *
+ * The #SpiceUsbDeviceManager::device-error signal is emitted whenever an
+ * error happens which causes a device to no longer be available to the
+ * guest.
+ **/
+ signals[DEVICE_ERROR] =
+ g_signal_new("device-error",
+ G_OBJECT_CLASS_TYPE(gobject_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET(SpiceUsbDeviceManagerClass, device_error),
+ NULL, NULL,
+ g_cclosure_user_marshal_VOID__BOXED_BOXED,
+ G_TYPE_NONE,
+ 2,
+ SPICE_TYPE_USB_DEVICE,
+ G_TYPE_ERROR);
+
g_type_class_add_private(klass, sizeof(SpiceUsbDeviceManagerPrivate));
}
@@ -461,6 +484,18 @@ static gboolean spice_usb_device_manager_get_udev_bus_n_address(
/* ------------------------------------------------------------------ */
/* callbacks */
+#ifdef USE_USBREDIR
+static void channel_device_error(GObject *object,
+ SpiceUsbDevice *device,
+ GError *err,
+ gpointer user_data)
+{
+ SpiceUsbDeviceManager *self = user_data;
+
+ g_signal_emit(self, signals[DEVICE_ERROR], 0, device, err);
+}
+#endif
+
static void channel_new(SpiceSession *session, SpiceChannel *channel,
gpointer user_data)
{
@@ -468,6 +503,8 @@ static void channel_new(SpiceSession *session, SpiceChannel *channel,
if (SPICE_IS_USBREDIR_CHANNEL(channel)) {
#ifdef USE_USBREDIR
+ g_signal_connect(channel, "device-error",
+ G_CALLBACK(channel_device_error), self);
spice_usbredir_channel_set_context(SPICE_USBREDIR_CHANNEL(channel),
self->priv->context);
spice_channel_connect(channel);
diff --git a/gtk/usb-device-manager.h b/gtk/usb-device-manager.h
index ec1a896..eabfd00 100644
--- a/gtk/usb-device-manager.h
+++ b/gtk/usb-device-manager.h
@@ -76,12 +76,14 @@ struct _SpiceUsbDeviceManagerClass
SpiceUsbDevice *device);
void (*auto_connect_failed) (SpiceUsbDeviceManager *manager,
SpiceUsbDevice *device, GError *error);
+ void (*device_error) (SpiceUsbDeviceManager *manager,
+ SpiceUsbDevice *device, GError *error);
/*< private >*/
/*
* If adding fields to this struct, remove corresponding
* amount of padding to avoid changing overall struct size
*/
- gchar _spice_reserved[SPICE_RESERVED_PADDING];
+ gchar _spice_reserved[SPICE_RESERVED_PADDING - sizeof(void*)];
};
GType spice_usb_device_get_type(void);
diff --git a/gtk/usb-device-widget.c b/gtk/usb-device-widget.c
index 028723f..4b504ca 100644
--- a/gtk/usb-device-widget.c
+++ b/gtk/usb-device-widget.c
@@ -45,6 +45,8 @@ static void device_added_cb(SpiceUsbDeviceManager *manager,
SpiceUsbDevice *device, gpointer user_data);
static void device_removed_cb(SpiceUsbDeviceManager *manager,
SpiceUsbDevice *device, gpointer user_data);
+static void device_error_cb(SpiceUsbDeviceManager *manager,
+ SpiceUsbDevice *device, GError *err, gpointer user_data);
/* ------------------------------------------------------------------ */
/* gobject glue */
@@ -156,6 +158,8 @@ static GObject *spice_usb_device_widget_constructor(
G_CALLBACK(device_added_cb), self);
g_signal_connect(priv->manager, "device-removed",
G_CALLBACK(device_removed_cb), self);
+ g_signal_connect(priv->manager, "device-error",
+ G_CALLBACK(device_error_cb), self);
devices = spice_usb_device_manager_get_devices(priv->manager);
} else
err_msg = err->message;
@@ -189,6 +193,8 @@ static void spice_usb_device_widget_finalize(GObject *object)
device_added_cb, self);
g_signal_handlers_disconnect_by_func(priv->manager,
device_removed_cb, self);
+ g_signal_handlers_disconnect_by_func(priv->manager,
+ device_error_cb, self);
}
g_object_unref(priv->session);
g_free(priv->device_format_string);
@@ -392,3 +398,18 @@ static void device_removed_cb(SpiceUsbDeviceManager *manager,
gtk_container_foreach(GTK_CONTAINER(self),
destroy_widget_by_usb_device, device);
}
+
+static void set_inactive_by_usb_device(GtkWidget *widget, gpointer user_data)
+{
+ if (g_object_get_data(G_OBJECT(widget), "usb-device") == user_data)
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), FALSE);
+}
+
+static void device_error_cb(SpiceUsbDeviceManager *manager,
+ SpiceUsbDevice *device, GError *err, gpointer user_data)
+{
+ SpiceUsbDeviceWidget *self = SPICE_USB_DEVICE_WIDGET(user_data);
+
+ gtk_container_foreach(GTK_CONTAINER(self),
+ set_inactive_by_usb_device, device);
+}
--
1.7.7.6
More information about the Spice-devel
mailing list