summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKirill Moizik <kmoizik@redhat.com>2016-03-08 16:05:55 +0200
committerJonathon Jongsma <jjongsma@redhat.com>2016-03-24 11:00:01 -0500
commit205e16d6d95e7966fb5ec69990468f748165c779 (patch)
treef7fb4f990d2bf095fcad7468e58e2d1bb77d522f
parenta123feddf906e961c9ee0eed5001d371f825e6d8 (diff)
UsbDeviceManager: Implement asynchronous disconnect device flow
This commit introduces functions for asynchronous disconnection flows. Following commits will make use of those. Thread safety is ensured the same way it was done for connection flow in previous commits. Disconnect logic is protected by the same locks that protect connect/usbredir/channel management logic. Signed-off-by: Kirill Moizik <kmoizik@redhat.com> Signed-off-by: Dmitry Fleytman <dfleytma@redhat.com> Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
-rw-r--r--src/channel-usbredir-priv.h9
-rw-r--r--src/channel-usbredir.c34
-rw-r--r--src/map-file2
-rw-r--r--src/usb-device-manager.c84
-rw-r--r--src/usb-device-manager.h11
5 files changed, 140 insertions, 0 deletions
diff --git a/src/channel-usbredir-priv.h b/src/channel-usbredir-priv.h
index c987474..17e9716 100644
--- a/src/channel-usbredir-priv.h
+++ b/src/channel-usbredir-priv.h
@@ -33,6 +33,15 @@ G_BEGIN_DECLS
void spice_usbredir_channel_set_context(SpiceUsbredirChannel *channel,
libusb_context *context);
+void spice_usbredir_channel_disconnect_device_async(SpiceUsbredirChannel *channel,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean spice_usbredir_channel_disconnect_device_finish(SpiceUsbredirChannel *channel,
+ GAsyncResult *res,
+ GError **err);
+
/* Note the context must be set, and the channel must be brought up
(through spice_channel_connect()), before calling this. */
void spice_usbredir_channel_connect_device_async(
diff --git a/src/channel-usbredir.c b/src/channel-usbredir.c
index 6ced764..3803f77 100644
--- a/src/channel-usbredir.c
+++ b/src/channel-usbredir.c
@@ -429,6 +429,8 @@ void spice_usbredir_channel_disconnect_device(SpiceUsbredirChannel *channel)
CHANNEL_DEBUG(channel, "disconnecting device from usb channel %p", channel);
+ spice_usbredir_channel_lock(channel);
+
switch (priv->state) {
case STATE_DISCONNECTED:
case STATE_DISCONNECTING:
@@ -462,6 +464,38 @@ void spice_usbredir_channel_disconnect_device(SpiceUsbredirChannel *channel)
priv->state = STATE_DISCONNECTED;
break;
}
+
+ spice_usbredir_channel_unlock(channel);
+}
+
+static void
+_disconnect_device_thread(GTask *task,
+ gpointer object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ spice_usbredir_channel_disconnect_device(SPICE_USBREDIR_CHANNEL(object));
+ g_task_return_boolean(task, TRUE);
+}
+
+G_GNUC_INTERNAL
+gboolean spice_usbredir_channel_disconnect_device_finish(
+ SpiceUsbredirChannel *channel,
+ GAsyncResult *res,
+ GError **err)
+{
+ return g_task_propagate_boolean(G_TASK(res), err);
+}
+
+void spice_usbredir_channel_disconnect_device_async(SpiceUsbredirChannel *channel,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask* task = g_task_new(channel, cancellable, callback, user_data);
+
+ g_return_if_fail(channel != NULL);
+ g_task_run_in_thread(task, _disconnect_device_thread);
}
G_GNUC_INTERNAL
diff --git a/src/map-file b/src/map-file
index 123ef96..112b5ea 100644
--- a/src/map-file
+++ b/src/map-file
@@ -131,6 +131,8 @@ spice_usb_device_manager_can_redirect_device;
spice_usb_device_manager_connect_device_async;
spice_usb_device_manager_connect_device_finish;
spice_usb_device_manager_disconnect_device;
+spice_usb_device_manager_disconnect_device_async;
+spice_usb_device_manager_disconnect_device_finish;
spice_usb_device_manager_get;
spice_usb_device_manager_get_devices;
spice_usb_device_manager_get_devices_with_filter;
diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c
index 0f8134f..312dae7 100644
--- a/src/usb-device-manager.c
+++ b/src/usb-device-manager.c
@@ -1676,6 +1676,26 @@ gboolean spice_usb_device_manager_connect_device_finish(
return g_task_propagate_boolean(task, err);
}
+/**
+ * spice_usb_device_manager_disconnect_device_finish:
+ * @self: a #SpiceUsbDeviceManager.
+ * @res: a #GAsyncResult
+ * @err: (allow-none): a return location for a #GError, or %NULL.
+ *
+ * Finishes an async operation. See spice_usb_device_manager_disconnect_device_async().
+ *
+ * Returns: %TRUE if disconnection is successful
+ */
+gboolean spice_usb_device_manager_disconnect_device_finish(
+ SpiceUsbDeviceManager *self, GAsyncResult *res, GError **err)
+{
+ GTask *task = G_TASK(res);
+
+ g_return_val_if_fail(g_task_is_valid(task, G_OBJECT(self)), FALSE);
+
+ return g_task_propagate_boolean(task, err);
+}
+
#ifdef USE_USBREDIR
static
void _connect_device_async_cb(GObject *gobject,
@@ -1722,6 +1742,70 @@ void spice_usb_device_manager_disconnect_device(SpiceUsbDeviceManager *self,
#endif
}
+typedef struct _disconnect_cb_data
+{
+ SpiceUsbDeviceManager *self;
+ SpiceUsbDevice *device;
+} disconnect_cb_data;
+
+#ifdef USE_USBREDIR
+static
+void _disconnect_device_async_cb(GObject *gobject,
+ GAsyncResult *channel_res,
+ gpointer user_data)
+{
+ SpiceUsbredirChannel *channel = SPICE_USBREDIR_CHANNEL(gobject);
+ GTask *task = user_data;
+ GError *err = NULL;
+
+#ifdef G_OS_WIN32
+ disconnect_cb_data *data = g_task_get_task_data(task);
+ SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(data->self);
+
+ if (self->priv->use_usbclerk) {
+ _spice_usb_device_manager_uninstall_driver_async(self, data->device);
+ }
+#endif
+
+ spice_usbredir_channel_disconnect_device_finish(channel, channel_res, &err);
+ if (err)
+ g_task_return_error(task, err);
+ else
+ g_task_return_boolean(task, TRUE);
+
+ g_object_unref(task);
+}
+#endif
+
+void spice_usb_device_manager_disconnect_device_async(SpiceUsbDeviceManager *self,
+ SpiceUsbDevice *device,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+#ifdef USE_USBREDIR
+ GTask *nested;
+ g_return_if_fail(SPICE_IS_USB_DEVICE_MANAGER(self));
+
+ g_return_if_fail(device != NULL);
+
+ SPICE_DEBUG("disconnecting device %p", device);
+
+ SpiceUsbredirChannel *channel;
+
+ channel = spice_usb_device_manager_get_channel_for_dev(self, device);
+ nested = g_task_new(G_OBJECT(self), cancellable, callback, user_data);
+ disconnect_cb_data *data = g_new(disconnect_cb_data, 1);
+ data->self = self;
+ data->device = device;
+ g_task_set_task_data(nested, data, g_free);
+
+ spice_usbredir_channel_disconnect_device_async(channel, cancellable,
+ _disconnect_device_async_cb,
+ nested);
+#endif
+}
+
/**
* spice_usb_device_manager_can_redirect_device:
* @self: the #SpiceUsbDeviceManager manager
diff --git a/src/usb-device-manager.h b/src/usb-device-manager.h
index e05ebae..d1b0a96 100644
--- a/src/usb-device-manager.h
+++ b/src/usb-device-manager.h
@@ -116,9 +116,20 @@ void spice_usb_device_manager_connect_device_async(
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
+
+void spice_usb_device_manager_disconnect_device_async(
+ SpiceUsbDeviceManager *manager,
+ SpiceUsbDevice *device,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
gboolean spice_usb_device_manager_connect_device_finish(
SpiceUsbDeviceManager *self, GAsyncResult *res, GError **err);
+gboolean spice_usb_device_manager_disconnect_device_finish(
+ SpiceUsbDeviceManager *self, GAsyncResult *res, GError **err);
+
void spice_usb_device_manager_disconnect_device(SpiceUsbDeviceManager *manager,
SpiceUsbDevice *device);