spice-gtk的usb通道分析

spice的usb必须有一个管理usb设备界面,因此在spice-gtk设计了一个usb_device_widget.c来管理USB设备。可以枚举当前的USB设备,添加USB设备到spice,从spice删除USB设备,通过usb_device_manager.c来管理。
1、通过 spice_usb_device_widget_new创建GtkWidget
GtkWidget *spice_usb_device_widget_new(SpiceSession *session,
                                       const gchar *device_format_string)
{
    return g_object_new(SPICE_TYPE_USB_DEVICE_WIDGET,
                        "orientation", GTK_ORIENTATION_VERTICAL,
                        "session", session,
                        "device-format-string", device_format_string,
                        "spacing", 6,
                        NULL);
}

2、通过构造函数绑定usb_device_manager
static void spice_usb_device_widget_constructed(GObject *gobject)
{
    SpiceUsbDeviceWidget *self;
    SpiceUsbDeviceWidgetPrivate *priv;
    GPtrArray *devices = NULL;
    GError *err = NULL;
    gchar *str;
    self = SPICE_USB_DEVICE_WIDGET(gobject);
    priv = self->priv;
    if (!priv->session) {
        g_error("SpiceUsbDeviceWidget constructed without a session");
    }

    priv->label = gtk_label_new(NULL);
    str = g_strdup_printf("%s", _("Select USB devices to redirect"));
    gtk_label_set_markup(GTK_LABEL (priv->label), str);
    g_free(str);
    gtk_label_set_xalign(GTK_LABEL(priv->label), 0.0);
    gtk_label_set_yalign(GTK_LABEL(priv->label), 0.5);
    gtk_box_pack_start(GTK_BOX(self), priv->label, FALSE, FALSE, 0);

    //获取usb_device_manager
    priv->manager = spice_usb_device_manager_get(priv->session, &err);
    if (err) {
        spice_usb_device_widget_show_info_bar(self, err->message,GTK_MESSAGE_WARNING,"dialog-warning");
        g_clear_error(&err);
        return;
    }
    //新增USB设备的信号,界面进行相应处理
    g_signal_connect(priv->manager, "device-added",G_CALLBACK(device_added_cb), self);
    //删除USB设备的信号,界面进行相应处理
    g_signal_connect(priv->manager, "device-removed",G_CALLBACK(device_removed_cb), self);
    //USB设备错误信号,界面进行相应处理
    g_signal_connect(priv->manager, "device-error",G_CALLBACK(device_error_cb), self);

    //清空界面USB设备列表
    spice_usb_device_widget_add_empty_cd(self);

        //首次获取当前已经连接的USB设备并显示
    devices = spice_usb_device_manager_get_devices(priv->manager);
    if (devices != NULL) {
        int i;
        for (i = 0; i < devices->len; i++) {
            device_added_cb(NULL, g_ptr_array_index(devices, i), self);
        }
        g_ptr_array_unref(devices);
    }
    spice_usb_device_widget_update_status(self);
}

3、核心usb_device_manager的对外接口
//获取格式描述
SPICE_GTK_AVAILABLE_IN_0_8
gchar *spice_usb_device_get_description(SpiceUsbDevice *device, const gchar *format); 

//获取指针
SPICE_GTK_AVAILABLE_IN_0_27
gconstpointer spice_usb_device_get_libusb_device(const SpiceUsbDevice *device);

//获取管理器句柄SpiceUsbDeviceManager
SPICE_GTK_AVAILABLE_IN_0_8
SpiceUsbDeviceManager *spice_usb_device_manager_get(SpiceSession *session,GError **err);

//获取设备列表
SPICE_GTK_AVAILABLE_IN_0_8
GPtrArray *spice_usb_device_manager_get_devices(SpiceUsbDeviceManager *manager);

//过滤出设备列表
SPICE_GTK_AVAILABLE_IN_0_20
GPtrArray* spice_usb_device_manager_get_devices_with_filter(SpiceUsbDeviceManager *manager,const gchar *filter);

//usb是否已经连接
SPICE_GTK_AVAILABLE_IN_0_8
gboolean spice_usb_device_manager_is_device_connected(SpiceUsbDeviceManager *manager,SpiceUsbDevice *device);

//异步连接设备,结果通过回调函数GAsyncReadyCallback返回
SPICE_GTK_AVAILABLE_IN_0_8
void spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *manager,SpiceUsbDevice *device,GCancellable *cancellable,GAsyncReadyCallback callback,gpointer user_data);

//异步断开设备,结果通过回调函数GAsyncReadyCallback返回
SPICE_GTK_AVAILABLE_IN_0_32
void spice_usb_device_manager_disconnect_device_async(SpiceUsbDeviceManager *manager,SpiceUsbDevice *device,GCancellable *cancellable,GAsyncReadyCallback callback,gpointer user_data);

//在spice_usb_device_manager_connect_device_async的GAsyncReadyCallback回调函数中,可以获取连接结果
SPICE_GTK_AVAILABLE_IN_0_8
gboolean spice_usb_device_manager_connect_device_finish(SpiceUsbDeviceManager *manager,GAsyncResult *res,GError **err);

//在spice_usb_device_manager_disconnect_device_async的GAsyncReadyCallback回调函数中,可以获取断开结果
SPICE_GTK_AVAILABLE_IN_0_32
gboolean spice_usb_device_manager_disconnect_device_finish(SpiceUsbDeviceManager *manager,GAsyncResult *res,GError **err);

//过时接口
#ifndef SPICE_DISABLE_DEPRECATED
SPICE_GTK_DEPRECATED_IN_0_32_FOR(spice_usb_device_manager_disconnect_device_async)
void spice_usb_device_manager_disconnect_device(SpiceUsbDeviceManager *manager,SpiceUsbDevice *device);
#endif

//能否重定向
SPICE_GTK_AVAILABLE_IN_0_10
gboolean spice_usb_device_manager_can_redirect_device(SpiceUsbDeviceManager *manager,SpiceUsbDevice *device,GError **err);

//判断是否在USB重定向,弹出提示告诉用户
SPICE_GTK_AVAILABLE_IN_0_32
gboolean spice_usb_device_manager_is_redirecting(SpiceUsbDeviceManager *manager);

//创建共享的CDROM设备
SPICE_GTK_AVAILABLE_IN_0_38
gboolean spice_usb_device_manager_create_shared_cd_device(SpiceUsbDeviceManager *manager,gchar *filename,GError **err);

//是CDROM设备
SPICE_GTK_AVAILABLE_IN_0_38
gboolean spice_usb_device_manager_is_device_shared_cd(SpiceUsbDeviceManager *manager,SpiceUsbDevice *device);

//文件描述符分配USB操作句柄
SPICE_GTK_AVAILABLE_IN_0_40
SpiceUsbDevice *spice_usb_device_manager_allocate_device_for_file_descriptor(SpiceUsbDeviceManager *manager,int file_descriptor,GError **err);

4、USB设备描述字符串,显示给用户看
gchar *spice_usb_backend_device_get_description(SpiceUsbDevice *dev, const gchar *format)
{
    guint16 bus, address, vid, pid;
    gchar *description, *descriptor, *manufacturer = NULL, *product = NULL;
    g_return_val_if_fail(dev != NULL, NULL);
    bus     = dev->device_info.bus;
    address = dev->device_info.address;
    vid     = dev->device_info.vid;
    pid     = dev->device_info.pid;
    if ((vid > 0) && (pid > 0)) {
        descriptor = g_strdup_printf("[%04x:%04x]", vid, pid);
    } else {
        descriptor = g_strdup("");
    }

    if (dev->libusb_device) {
        spice_usb_util_get_device_strings(bus, address, vid, pid, &manufacturer, &product);
    } else {
        product = device_ops(dev->edev)->get_product_description(dev->edev);
    }

    if (!format) {
        format = _("%s %s %s at %d-%d");
    }
    description = g_strdup_printf(format, manufacturer ? manufacturer : "",product, descriptor, bus, address);
    g_free(manufacturer);
    g_free(descriptor);
    g_free(product);
    return description;
}

5、是否为CDROM设备
gboolean
spice_usb_device_manager_is_device_shared_cd(SpiceUsbDeviceManager *manager, SpiceUsbDevice *device)
{
#ifdef USE_USBREDIR
    /* TODO This function currently return TRUE for all emulated
     * devices. Currently only shared CDs are implemented as shared
     * devices but this will break adding new emulated devices.
     * Check VID/PID in the future.
     */
    gboolean is_cd = (spice_usb_backend_device_get_libdev(device) == NULL);
    return is_cd;
#else
    return FALSE;
#endif
}

gconstpointer spice_usb_backend_device_get_libdev(const SpiceUsbDevice *dev)
{
    return dev->libusb_device;
}

你可能感兴趣的:(spice,spice)