[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