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

Hans de Goede hdegoede at redhat.com
Wed Feb 22 08:28:21 PST 2012


Signed-off-by: Hans de Goede <hdegoede at redhat.com>
---
 gtk/channel-usbredir.c        |   61 +++++++++++++++++++++++++++++++++++++++-
 gtk/spicy.c                   |    2 +
 gtk/usb-device-manager-priv.h |    3 ++
 gtk/usb-device-manager.c      |   29 +++++++++++++++++++
 gtk/usb-device-manager.h      |    4 ++-
 gtk/usb-device-widget.c       |   21 ++++++++++++++
 6 files changed, 117 insertions(+), 3 deletions(-)

diff --git a/gtk/channel-usbredir.c b/gtk/channel-usbredir.c
index e22aa6c..fa7dce0 100644
--- a/gtk/channel-usbredir.c
+++ b/gtk/channel-usbredir.c
@@ -513,6 +513,42 @@ static void usbredir_free_lock(void *user_data) {
 }
 
 /* --------------------------------------------------------------------- */
+
+/* Events to be handled in main context */
+enum {
+    DEVICE_ERROR,
+};
+
+struct DEVICE_ERROR {
+    libusb_device *device;
+    GError *error;
+};
+
+/* main context */
+static void do_emit_main_context(GObject *object, int event, gpointer params)
+{
+    SpiceUsbredirChannel *channel = SPICE_USBREDIR_CHANNEL(object);
+    SpiceUsbredirChannelPrivate *priv = channel->priv;
+
+    switch (event) {
+    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) {
+            spice_usbredir_channel_disconnect_device(channel);
+            spice_usb_device_manager_device_error(
+                spice_usb_device_manager_get(
+                    spice_channel_get_session(SPICE_CHANNEL(channel)), NULL),
+                (SpiceUsbDevice *)p->device, p->error);
+        }
+        break;
+    }
+    default:
+        g_warn_if_reached();
+    }
+}
+
+/* --------------------------------------------------------------------- */
 /* coroutine context                                                     */
 static void spice_usbredir_handle_msg(SpiceChannel *c, SpiceMsgIn *msg)
 {
@@ -544,7 +580,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 +592,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/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-priv.h b/gtk/usb-device-manager-priv.h
index b0b2f74..912e3bf 100644
--- a/gtk/usb-device-manager-priv.h
+++ b/gtk/usb-device-manager-priv.h
@@ -31,6 +31,9 @@ gboolean spice_usb_device_manager_start_event_listening(
 void spice_usb_device_manager_stop_event_listening(
     SpiceUsbDeviceManager *manager);
 
+void spice_usb_device_manager_device_error(
+    SpiceUsbDeviceManager *manager, SpiceUsbDevice *device, GError *err);
+
 G_END_DECLS
 
 #endif /* __SPICE_USB_DEVICE_MANAGER_PRIV_H__ */
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index b6dfa20..dea0ab5 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));
 }
 
@@ -682,6 +705,12 @@ void spice_usb_device_manager_stop_event_listening(
     if (priv->event_listeners == 0)
         priv->event_thread_run = FALSE;
 }
+
+void spice_usb_device_manager_device_error(
+    SpiceUsbDeviceManager *self, SpiceUsbDevice *device, GError *err)
+{
+    g_signal_emit(self, signals[DEVICE_ERROR], 0, device, err);
+}
 #endif
 
 static SpiceUsbredirChannel *spice_usb_device_manager_get_channel_for_dev(
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