[Spice-devel] [PATCH spice-gtk 6/7] usbredir: Add device rejected errors

Hans de Goede hdegoede at redhat.com
Sat Feb 18 15:50:23 PST 2012


Signed-off-by: Hans de Goede <hdegoede at redhat.com>
---
 gtk/channel-usbredir.c   |   82 ++++++++++++++++++++++++++++++++++++++++++++-
 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, 147 insertions(+), 3 deletions(-)

diff --git a/gtk/channel-usbredir.c b/gtk/channel-usbredir.c
index e22aa6c..3b72372 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)
@@ -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.5



More information about the Spice-devel mailing list