[Spice-devel] [spice-gtk 2/5] usb-redir: unify device hotplug/unplug for Windows and Linux
Victor Toso
victortoso at redhat.com
Fri Jul 19 10:14:11 UTC 2019
Hi,
On Sun, Jul 14, 2019 at 05:07:38PM +0300, Yuri Benditovich wrote:
> Remove Windows-specific part of hotplug detection from
> usb-device-manager and win-usb-dev and place it into
> USB backend module. Connect the hotplug/unplug detection
> in Windows to the same callbacks already used in Linux.
> This removes significant part of Windows-specific code
> and simpifies things.
> Note regarding 'redirecting' property of usb-device-manager:
> - Previously usb-device-manager under Windows maintained
> 'redirection' property in win-usb-dev
> - Now it maintains its own property in both Windows and
> Linux (for GUI and single redirect at a time)
> - The USB backend maintains its own 'redirecting' field
> in Windows to prevent update of device list when
> libusb opens the device (device redirection causes
> temporary removal of target device)
Thanks for the description. Only minor things, logic seems fine,
did quick tests only. Would be nice to reduce diff from things
that can be smaller patches whenever needed, function renames or
being moved or variables being dropped for instance so it would
get easier to focus on the actual interesting part of proposal.
This is always mentioned and that's one of the reasons that it
takes time to review.
> Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
> ---
> meson.build | 2 +-
> src/meson.build | 4 +-
> src/usb-backend.c | 360 ++++++++++++++++++++++----------
> src/usb-backend.h | 8 -
> src/usb-device-manager.c | 61 +-----
> src/win-usb-dev.c | 436 ---------------------------------------
> src/win-usb-dev.h | 84 --------
> 7 files changed, 255 insertions(+), 700 deletions(-)
Quite happy with the code reduction! That's one thing I was
expecting from introducing usb-backend.[ch]
> delete mode 100644 src/win-usb-dev.c
> delete mode 100644 src/win-usb-dev.h
>
> diff --git a/meson.build b/meson.build
> index 54160f9..1f6ea6d 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -117,7 +117,7 @@ endforeach
>
> deps = []
> if host_machine.system() == 'windows'
> - deps += ['libws2_32', 'libgdi32']
> + deps += ['libws2_32', 'libgdi32', 'libcomctl32']
> endif
>
> foreach dep : deps
> diff --git a/src/meson.build b/src/meson.build
> index a51d0a9..adcfaec 100644
> --- a/src/meson.build
> +++ b/src/meson.build
> @@ -158,9 +158,7 @@ endif
>
> if spice_gtk_has_usbredir and host_machine.system() == 'windows'
> spice_client_glib_sources += ['usbdk_api.c',
> - 'usbdk_api.h',
> - 'win-usb-dev.c',
> - 'win-usb-dev.h']
> + 'usbdk_api.h']
> endif
>
> #
> diff --git a/src/usb-backend.c b/src/usb-backend.c
> index a2c502d..9964c4f 100644
> --- a/src/usb-backend.c
> +++ b/src/usb-backend.c
> @@ -32,6 +32,9 @@
> #include <libusb.h>
> #include <string.h>
> #include <fcntl.h>
> +#ifdef G_OS_WIN32
> +#include <commctrl.h>
> +#endif
> #include "usbredirhost.h"
> #include "usbredirparser.h"
> #include "spice-util.h"
> @@ -55,6 +58,11 @@ struct _SpiceUsbBackend
> usb_hot_plug_callback hotplug_callback;
> void *hotplug_user_data;
> libusb_hotplug_callback_handle hotplug_handle;
> +#ifdef G_OS_WIN32
> + HANDLE hWnd;
> + libusb_device **libusb_device_list;
> + gint redirecting;
> +#endif
> };
>
> struct _SpiceUsbBackendChannel
> @@ -66,9 +74,229 @@ struct _SpiceUsbBackendChannel
> int rules_count;
> SpiceUsbBackendDevice *attached;
> SpiceUsbredirChannel *user_data;
> + SpiceUsbBackend *backend;
> GError **error;
> };
>
Some code below is just being moved, makes the diff a little
bigger and review a bit slower. If I comment on code that has
been only moved and you consider the comments relevant, please
address them in different patches.
> +static gboolean fill_usb_info(SpiceUsbBackendDevice *bdev)
In several places we have different variable names for giving
structures, it would be good to have it somewhat similar so that
reading the code you don't have to think if dev is libusb_device
or SpiceUsbBackendDevice, etc.
> +{
> + UsbDeviceInformation *info = &bdev->device_info;
> +
> + struct libusb_device_descriptor desc;
> + libusb_device *libdev = bdev->libusb_device;
> + libusb_get_device_descriptor(libdev, &desc);
> + info->bus = libusb_get_bus_number(libdev);
> + info->address = libusb_get_device_address(libdev);
> + if (info->address == 0xff || /* root hub (HCD) */
> + info->address <= 1 || /* root hub or bad address */
> + (desc.bDeviceClass == LIBUSB_CLASS_HUB) /*hub*/) {
> + return FALSE;
> + }
> +
> + info->vid = desc.idVendor;
> + info->pid = desc.idProduct;
> + info->class = desc.bDeviceClass;
> + info->subclass = desc.bDeviceSubClass;
> + info->protocol = desc.bDeviceProtocol;
Filling UsbDeviceInformation from libusb_device can be made into
a utility function as this happens here and is_same_libusb_dev(),
but also because it can remove a extra parameter on the later.
Taking a shot at the name, get_device_info_from_libusb_device()!
> +
> + return TRUE;
> +}
> +
> +static SpiceUsbBackendDevice *allocate_backend_device(libusb_device *libdev)
> +{
> + SpiceUsbBackendDevice *dev = g_new0(SpiceUsbBackendDevice, 1);
> + dev->ref_count = 1;
> + dev->libusb_device = libdev;
> + if (!fill_usb_info(dev)) {
> + g_clear_pointer(&dev, g_free);
> + }
> + return dev;
> +}
> +
> +static int LIBUSB_CALL hotplug_callback(libusb_context *ctx,
> + libusb_device *device,
> + libusb_hotplug_event event,
Perhaps adding lib prefix to libusb related variables, as you did
in the other functions above, would be enough.
> + void *user_data)
> +{
> + SpiceUsbBackend *be = (SpiceUsbBackend *)user_data;
No need to cast void*
> + if (be->hotplug_callback) {
Should warn if fail, no? This callback should only be called
after spice_usb_backend_register_hotplug() - If you agree,
g_return_val_if_fail() might fit
> + SpiceUsbBackendDevice *dev;
> + gboolean val = event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED;
val -> has_arrived
> + dev = allocate_backend_device(device);
> + if (dev) {
> + SPICE_DEBUG("created dev %p, usblib dev %p", dev, device);
> + libusb_ref_device(device);
> + be->hotplug_callback(be->hotplug_user_data, dev, val);
> + spice_usb_backend_device_unref(dev);
> + }
> + }
> + return 0;
> +}
> +
> +#ifdef G_OS_WIN32
> +/* Windows-specific: get notification on device change */
> +
> +static gboolean is_same_libusb_dev(libusb_device *dev1,
> + UsbDeviceInformation *info1,
> + libusb_device *dev2)
This function should just be comparing both libusb_devices, info1
argument is for debug on the caller so can be removed...
> +{
> + struct libusb_device_descriptor desc;
> + info1->bus = libusb_get_bus_number(dev1);
> + info1->address = libusb_get_device_address(dev1);
> + libusb_get_device_descriptor(dev1, &desc);
> + info1->vid = desc.idVendor;
> + info1->pid = desc.idProduct;
> + if (dev2 == NULL) {
> + return FALSE;
> + }
... I think the first check is if either libdev1 or libdev2 are NULL
and return FALSE, otherwise you can then compare after
info1 = get_device_info_from_libusb_device(dev1);
info2 = get_device_info_from_libusb_device(dev2);
> + libusb_get_device_descriptor(dev2, &desc);
> + return info1->bus == libusb_get_bus_number(dev2) &&
> + info1->address == libusb_get_device_address(dev2) &&
> + info1->vid == desc.idVendor &&
> + info1->pid == desc.idProduct;
> +}
> +
> +static int compare_dev_list(SpiceUsbBackend *be,
> + libusb_device **l1,
> + libusb_device **l2,
Hmm const them? Or..
> + gboolean value)
value -> has_arrived
.. This function tries to find elements of list1 in list2 and calls
hotplug_callback() for every element not found. This is a bit
more than the name of the function suggests.
I would rather have it as
GList* dev_list_difference(libusb_device **libdevp1,
libusb_device **libdevp2);
and the caller would call hotplug_callback() and
g_list_free() it.
> +{
> + int res = 0;
> + while (*l1) {
> + gboolean found = 0;
> + uint32_t n = 0;
> + UsbDeviceInformation info1;
> + while (!found) {
> + found = is_same_libusb_dev(*l1, &info1, l2[n]);
> + if (l2[n] == NULL) {
> + break;
> + }
> + n++;
> + }
> + if (!found) {
> + SPICE_DEBUG("%s %04X:%04X at %d:%d", value ? "adding" : "removing",
> + info1.vid, info1.pid, info1.bus, info1.address);
> + hotplug_callback(NULL, *l1,
> + value ? LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED : LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
> + be);
> + res++;
> + }
> + l1++;
> + }
> + return res;
> +}
> +
> +static LRESULT subclass_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
> + UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
> +{
> + SpiceUsbBackend *be = (SpiceUsbBackend *)dwRefData;
> + if (uMsg == WM_DEVICECHANGE && !be->redirecting) {
> + libusb_device **new_list = NULL;
> + libusb_get_device_list(be->libusb_context, &new_list);
> + if (new_list) {
> + int res = compare_dev_list(be, be->libusb_device_list, new_list, FALSE);
> + res += compare_dev_list(be, new_list, be->libusb_device_list, TRUE);
> + if (res) {
> + /* there were changes in device tree */
> + libusb_free_device_list(be->libusb_device_list, TRUE);
> + be->libusb_device_list = new_list;
> + } else {
> + libusb_free_device_list(new_list, TRUE);
> + }
> + } else {
> + g_warn_if_reached();
> + }
> + }
> + return DefSubclassProc(hWnd, uMsg, wParam, lParam);
> +}
> +
> +static void disable_hotplug_support(SpiceUsbBackend *be)
> +{
> + if (be->hWnd) {
> + DestroyWindow(be->hWnd);
> + be->hWnd = NULL;
> + }
> + if (be->libusb_device_list) {
> + libusb_free_device_list(be->libusb_device_list, TRUE);
> + be->libusb_device_list = NULL;
> + }
> +}
> +
> +static int enable_hotplug_support(SpiceUsbBackend *be, const char **error_on_enable)
> +{
> + long win_err;
> + libusb_device **dev_list = NULL;
> + libusb_device *dummy = NULL;
> +
> + libusb_get_device_list(be->libusb_context, &dev_list);
> + if (!dev_list) {
> + *error_on_enable = "Getting device list";
> + goto error;
> + }
> + be->hWnd = CreateWindow("Static", NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
Not sure if can be important but it was G_UDEV_CLIENT_WINCLASS_NAME before,
#define G_UDEV_CLIENT_WINCLASS_NAME TEXT("G_UDEV_CLIENT")
and I notice that you dropped RegisterClass call, not needed
anymore?
> + if (!be->hWnd) {
> + *error_on_enable = "CreateWindow";
> + goto error;
> + }
> + if (!SetWindowSubclass(be->hWnd, subclass_proc, 0, (DWORD_PTR)be)) {
> + *error_on_enable = "SetWindowSubclass";
> + goto error;
> + }
> + be->hotplug_handle = 1;
> + be->libusb_device_list = dev_list;
> +
> + compare_dev_list(be, be->libusb_device_list, &dummy, TRUE);
What's the point of this function call? to call
hotplug_callback() on dev_list? You might as well just do it here
with a comment
> +
> + return LIBUSB_SUCCESS;
> +error:
> + win_err = GetLastError();
> + if (!win_err) {
> + win_err = -1;
> + }
> + g_warning("%s failed: %ld", *error_on_enable, win_err);
> + if (dev_list) {
> + libusb_free_device_list(dev_list, TRUE);
> + }
> + return win_err;
> +}
> +
> +static void set_redirecting(SpiceUsbBackend *be, gboolean on)
> +{
> + gboolean no_redir;
> + if (on) {
> + g_atomic_int_inc(&be->redirecting);
> + } else {
> + no_redir = g_atomic_int_dec_and_test(&be->redirecting);
You can move declaration of no_redir here
> + if (no_redir && be->hWnd) {
> + PostMessage(be->hWnd, WM_DEVICECHANGE, 0, 0);
> + }
> + }
> +}
> +
> +#else
> +/* Linux-specific: use hot callback from libusb */
> +
> +static void disable_hotplug_support(SpiceUsbBackend *be)
> +{
> + libusb_hotplug_deregister_callback(be->libusb_context, be->hotplug_handle);
> +}
> +
> +static int enable_hotplug_support(SpiceUsbBackend *be, const char **error_on_enable)
> +{
> + int rc = 0;
> + rc = libusb_hotplug_register_callback(be->libusb_context,
> + LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
> + LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY,
> + LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
> + hotplug_callback, be, &be->hotplug_handle);
> + *error_on_enable = libusb_strerror(rc);
> + return rc;
> +}
> +
> +#define set_redirecting(...)
ok
> +
> +#endif
> +
> /* lock functions for usbredirhost and usbredirparser */
> static void *usbredir_alloc_lock(void) {
> GMutex *mutex;
> @@ -131,41 +359,6 @@ gboolean spice_usb_backend_device_isoch(SpiceUsbBackendDevice *dev)
> return isoc_found;
> }
>
> -static gboolean fill_usb_info(SpiceUsbBackendDevice *bdev)
> -{
> - UsbDeviceInformation *info = &bdev->device_info;
> -
> - struct libusb_device_descriptor desc;
> - libusb_device *libdev = bdev->libusb_device;
> - libusb_get_device_descriptor(libdev, &desc);
> - info->bus = libusb_get_bus_number(libdev);
> - info->address = libusb_get_device_address(libdev);
> - if (info->address == 0xff || /* root hub (HCD) */
> - info->address <= 1 || /* root hub or bad address */
> - (desc.bDeviceClass == LIBUSB_CLASS_HUB) /*hub*/) {
> - return FALSE;
> - }
> -
> - info->vid = desc.idVendor;
> - info->pid = desc.idProduct;
> - info->class = desc.bDeviceClass;
> - info->subclass = desc.bDeviceSubClass;
> - info->protocol = desc.bDeviceProtocol;
> -
> - return TRUE;
> -}
> -
> -static SpiceUsbBackendDevice *allocate_backend_device(libusb_device *libdev)
> -{
> - SpiceUsbBackendDevice *dev = g_new0(SpiceUsbBackendDevice, 1);
> - dev->ref_count = 1;
> - dev->libusb_device = libdev;
> - if (!fill_usb_info(dev)) {
> - g_clear_pointer(&dev, g_free);
> - }
> - return dev;
> -}
> -
> static gboolean is_channel_ready(SpiceUsbredirChannel *channel)
> {
> return spice_channel_get_state(SPICE_CHANNEL(channel)) == SPICE_CHANNEL_STATE_READY;
> @@ -237,31 +430,11 @@ void spice_usb_backend_interrupt_event_handler(SpiceUsbBackend *be)
> }
> }
>
> -static int LIBUSB_CALL hotplug_callback(libusb_context *ctx,
> - libusb_device *device,
> - libusb_hotplug_event event,
> - void *user_data)
> -{
> - SpiceUsbBackend *be = (SpiceUsbBackend *)user_data;
> - if (be->hotplug_callback) {
> - SpiceUsbBackendDevice *dev;
> - gboolean val = event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED;
> - dev = allocate_backend_device(device);
> - if (dev) {
> - SPICE_DEBUG("created dev %p, usblib dev %p", dev, device);
> - libusb_ref_device(device);
> - be->hotplug_callback(be->hotplug_user_data, dev, val);
> - spice_usb_backend_device_unref(dev);
> - }
> - }
> - return 0;
> -}
> -
> void spice_usb_backend_deregister_hotplug(SpiceUsbBackend *be)
> {
> g_return_if_fail(be != NULL);
> if (be->hotplug_handle) {
> - libusb_hotplug_deregister_callback(be->libusb_context, be->hotplug_handle);
> + disable_hotplug_support(be);
> be->hotplug_handle = 0;
> }
> be->hotplug_callback = NULL;
> @@ -272,17 +445,15 @@ gboolean spice_usb_backend_register_hotplug(SpiceUsbBackend *be,
> usb_hot_plug_callback proc)
> {
> int rc;
> + const char *desc;
> g_return_val_if_fail(be != NULL, FALSE);
>
> be->hotplug_callback = proc;
> be->hotplug_user_data = user_data;
> - rc = libusb_hotplug_register_callback(be->libusb_context,
> - LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
> - LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY,
> - LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
> - hotplug_callback, be, &be->hotplug_handle);
> +
> + rc = enable_hotplug_support(be, &desc);
> +
> if (rc != LIBUSB_SUCCESS) {
> - const char *desc = libusb_strerror(rc);
> g_warning("Error initializing USB hotplug support: %s [%i]", desc, rc);
> be->hotplug_callback = NULL;
> return FALSE;
> @@ -301,45 +472,6 @@ void spice_usb_backend_delete(SpiceUsbBackend *be)
> SPICE_DEBUG("%s <<", __FUNCTION__);
> }
>
> -SpiceUsbBackendDevice **spice_usb_backend_get_device_list(SpiceUsbBackend *be)
> -{
> - LOUD_DEBUG("%s >>", __FUNCTION__);
> - libusb_device **devlist = NULL, **dev;
> - SpiceUsbBackendDevice *d, **list;
> -
> - int n = 0, index;
> -
> - if (be && be->libusb_context) {
> - libusb_get_device_list(be->libusb_context, &devlist);
> - }
> -
> - /* add all the libusb device that not present in our list */
> - for (dev = devlist; dev && *dev; dev++) {
> - n++;
> - }
> -
> - list = g_new0(SpiceUsbBackendDevice*, n + 1);
> -
> - index = 0;
> -
> - for (dev = devlist; dev && *dev; dev++) {
> - d = allocate_backend_device(*dev);
> - if (!d) {
> - libusb_unref_device(*dev);
> - } else {
> - SPICE_DEBUG("created dev %p, usblib dev %p", d, *dev);
> - list[index++] = d;
> - }
> - }
> -
> - if (devlist) {
> - libusb_free_device_list(devlist, 0);
> - }
> -
> - LOUD_DEBUG("%s <<", __FUNCTION__);
> - return list;
> -}
> -
> const UsbDeviceInformation* spice_usb_backend_device_get_info(SpiceUsbBackendDevice *dev)
> {
> return &dev->device_info;
> @@ -350,18 +482,6 @@ gconstpointer spice_usb_backend_device_get_libdev(SpiceUsbBackendDevice *dev)
> return dev->libusb_device;
> }
>
> -void spice_usb_backend_free_device_list(SpiceUsbBackendDevice **devlist)
> -{
> - LOUD_DEBUG("%s >>", __FUNCTION__);
> - SpiceUsbBackendDevice **dev;
> - for (dev = devlist; *dev; dev++) {
> - SpiceUsbBackendDevice *d = *dev;
> - spice_usb_backend_device_unref(d);
> - }
> - g_free(devlist);
> - LOUD_DEBUG("%s <<", __FUNCTION__);
> -}
> -
> SpiceUsbBackendDevice *spice_usb_backend_device_ref(SpiceUsbBackendDevice *dev)
> {
> LOUD_DEBUG("%s >> %p", __FUNCTION__, dev);
> @@ -529,12 +649,23 @@ gboolean spice_usb_backend_channel_attach(SpiceUsbBackendChannel *ch,
> SpiceUsbBackendDevice *dev,
> GError **error)
> {
> + int rc;
> SPICE_DEBUG("%s >> ch %p, dev %p (was attached %p)", __FUNCTION__, ch, dev, ch->attached);
>
> g_return_val_if_fail(dev != NULL, FALSE);
>
> libusb_device_handle *handle = NULL;
> - int rc = libusb_open(dev->libusb_device, &handle);
> +
> + /*
> + Under Windows we need to avoid updating
> + list of devices when we are acquiring the device
> + */
I'd rather have
/* start comment
* end comment */
but I don't mind much.
Apart from those comments, not much to add.
Victor
> + set_redirecting(ch->backend, TRUE);
> +
> + rc = libusb_open(dev->libusb_device, &handle);
> +
> + set_redirecting(ch->backend, FALSE);
> +
> if (rc) {
> const char *desc = libusb_strerror(rc);
> g_set_error(error, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
> @@ -582,6 +713,7 @@ SpiceUsbBackendChannel *spice_usb_backend_channel_new(SpiceUsbBackend *be,
> SPICE_DEBUG("%s >>", __FUNCTION__);
> ch->user_data = SPICE_USBREDIR_CHANNEL(user_data);
> if (be->libusb_context) {
> + ch->backend = be;
> ch->usbredirhost = usbredirhost_open_full(
> be->libusb_context,
> NULL,
> diff --git a/src/usb-backend.h b/src/usb-backend.h
> index cbb73c2..6da3981 100644
> --- a/src/usb-backend.h
> +++ b/src/usb-backend.h
> @@ -56,14 +56,6 @@ enum {
> SpiceUsbBackend *spice_usb_backend_new(GError **error);
> void spice_usb_backend_delete(SpiceUsbBackend *context);
>
> -/*
> -returns newly-allocated null-terminated list of
> -SpiceUsbBackendDevice pointers.
> -The caller must call spice_usb_backend_free_device_list
> -after it finishes list processing
> -*/
> -SpiceUsbBackendDevice **spice_usb_backend_get_device_list(SpiceUsbBackend *backend);
> -void spice_usb_backend_free_device_list(SpiceUsbBackendDevice **devlist);
> gboolean spice_usb_backend_handle_events(SpiceUsbBackend *be);
> void spice_usb_backend_interrupt_event_handler(SpiceUsbBackend *be);
> gboolean spice_usb_backend_register_hotplug(SpiceUsbBackend *be,
> diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c
> index 9aba275..9300ad2 100644
> --- a/src/usb-device-manager.c
> +++ b/src/usb-device-manager.c
> @@ -29,7 +29,6 @@
> #ifdef G_OS_WIN32
> #include <windows.h>
> #include "usbdk_api.h"
> -#include "win-usb-dev.h"
> #endif
>
> #include "channel-usbredir-priv.h"
> @@ -101,12 +100,10 @@ struct _SpiceUsbDeviceManagerPrivate {
> struct usbredirfilter_rule *redirect_on_connect_rules;
> int auto_conn_filter_rules_count;
> int redirect_on_connect_rules_count;
> + gboolean redirecting;
> #ifdef G_OS_WIN32
> - GUdevClient *udev;
> usbdk_api_wrapper *usbdk_api;
> HANDLE usbdk_hider_handle;
> -#else
> - gboolean redirecting; /* Handled by GUdevClient in the gudev case */
> #endif
> GPtrArray *devices;
> GPtrArray *channels;
> @@ -139,16 +136,9 @@ static void channel_destroy(SpiceSession *session, SpiceChannel *channel,
> gpointer user_data);
> static void channel_event(SpiceChannel *channel, SpiceChannelEvent event,
> gpointer user_data);
> -#ifdef G_OS_WIN32
> -static void spice_usb_device_manager_uevent_cb(GUdevClient *client,
> - SpiceUsbBackendDevice *udevice,
> - gboolean add,
> - gpointer user_data);
> -#else
> static void spice_usb_device_manager_hotplug_cb(void *user_data,
> SpiceUsbBackendDevice *dev,
> gboolean added);
> -#endif
> static void spice_usb_device_manager_check_redir_on_connect(
> SpiceUsbDeviceManager *self, SpiceChannel *channel);
>
> @@ -190,11 +180,7 @@ G_DEFINE_BOXED_TYPE(SpiceUsbDevice, spice_usb_device,
> static void
> _set_redirecting(SpiceUsbDeviceManager *self, gboolean is_redirecting)
> {
> -#ifdef G_OS_WIN32
> - g_object_set(self->priv->udev, "redirecting", is_redirecting, NULL);
> -#else
> self->priv->redirecting = is_redirecting;
> -#endif
> }
>
> #else
> @@ -215,10 +201,6 @@ gboolean spice_usb_device_manager_is_redirecting(SpiceUsbDeviceManager *self)
> {
> #ifndef USE_USBREDIR
> return FALSE;
> -#elif defined(G_OS_WIN32)
> - gboolean redirecting;
> - g_object_get(self->priv->udev, "redirecting", &redirecting, NULL);
> - return redirecting;
> #else
> return self->priv->redirecting;
> #endif
> @@ -267,29 +249,18 @@ static gboolean spice_usb_device_manager_initable_init(GInitable *initable,
> GList *list;
> GList *it;
>
> - /* Start listening for usb devices plug / unplug */
> -#ifdef G_OS_WIN32
> - priv->udev = g_udev_client_new();
> - if (priv->udev == NULL) {
> - g_warning("Error initializing GUdevClient");
> - return FALSE;
> - }
> - priv->context = g_udev_client_get_context(priv->udev);
> - g_signal_connect(G_OBJECT(priv->udev), "uevent",
> - G_CALLBACK(spice_usb_device_manager_uevent_cb), self);
> - /* Do coldplug (detection of already connected devices) */
> - g_udev_client_report_devices(priv->udev);
> -#else
> /* Initialize libusb */
> priv->context = spice_usb_backend_new(err);
> if (!priv->context) {
> return FALSE;
> }
>
> + /* Start listening for usb devices plug / unplug */
> if (!spice_usb_backend_register_hotplug(priv->context, self,
> spice_usb_device_manager_hotplug_cb)) {
> return FALSE;
> }
> +#ifndef G_OS_WIN32
> spice_usb_device_manager_start_event_listening(self, NULL);
> #endif
>
> @@ -324,8 +295,9 @@ static void spice_usb_device_manager_dispose(GObject *gobject)
> g_warn_if_reached();
> g_atomic_int_set(&priv->event_thread_run, FALSE);
> }
> - spice_usb_backend_deregister_hotplug(priv->context);
> #endif
> + spice_usb_backend_deregister_hotplug(priv->context);
> +
> if (priv->event_thread) {
> g_warn_if_fail(g_atomic_int_get(&priv->event_thread_run) == FALSE);
> g_atomic_int_set(&priv->event_thread_run, FALSE);
> @@ -350,14 +322,10 @@ static void spice_usb_device_manager_finalize(GObject *gobject)
> if (priv->devices) {
> g_ptr_array_unref(priv->devices);
> }
> -#ifdef G_OS_WIN32
> - g_clear_object(&priv->udev);
> -#endif
> g_return_if_fail(priv->event_thread == NULL);
> -#ifndef G_OS_WIN32
> - if (priv->context)
> + if (priv->context) {
> spice_usb_backend_delete(priv->context);
> -#endif
> + }
> free(priv->auto_conn_filter_rules);
> free(priv->redirect_on_connect_rules);
> #ifdef G_OS_WIN32
> @@ -891,20 +859,6 @@ static void spice_usb_device_manager_remove_dev(SpiceUsbDeviceManager *self,
> spice_usb_device_unref(device);
> }
>
> -#ifdef G_OS_WIN32
> -static void spice_usb_device_manager_uevent_cb(GUdevClient *client,
> - SpiceUsbBackendDevice *bdev,
> - gboolean add,
> - gpointer user_data)
> -{
> - SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(user_data);
> -
> - if (add)
> - spice_usb_device_manager_add_dev(self, bdev);
> - else
> - spice_usb_device_manager_remove_dev(self, bdev);
> -}
> -#else
> struct hotplug_idle_cb_args {
> SpiceUsbDeviceManager *self;
> SpiceUsbBackendDevice *device;
> @@ -940,7 +894,6 @@ static void spice_usb_device_manager_hotplug_cb(void *user_data,
> args->added = added;
> g_idle_add(spice_usb_device_manager_hotplug_idle_cb, args);
> }
> -#endif // USE_USBREDIR
>
> static void spice_usb_device_manager_channel_connect_cb(
> GObject *gobject, GAsyncResult *channel_res, gpointer user_data)
> diff --git a/src/win-usb-dev.c b/src/win-usb-dev.c
> deleted file mode 100644
> index c2a5115..0000000
> --- a/src/win-usb-dev.c
> +++ /dev/null
> @@ -1,436 +0,0 @@
> -/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
> -/*
> - Copyright (C) 2012 Red Hat, Inc.
> -
> - Red Hat Authors:
> - Arnon Gilboa <agilboa at redhat.com>
> - Uri Lublin <uril at redhat.com>
> -
> - This library is free software; you can redistribute it and/or
> - modify it under the terms of the GNU Lesser General Public
> - License as published by the Free Software Foundation; either
> - version 2.1 of the License, or (at your option) any later version.
> -
> - This library is distributed in the hope that it will be useful,
> - but WITHOUT ANY WARRANTY; without even the implied warranty of
> - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> - Lesser General Public License for more details.
> -
> - You should have received a copy of the GNU Lesser General Public
> - License along with this library; if not, see <http://www.gnu.org/licenses/>.
> -*/
> -
> -#include "config.h"
> -
> -#include <windows.h>
> -#include "win-usb-dev.h"
> -#include "spice-marshal.h"
> -#include "spice-util.h"
> -
> -enum {
> - PROP_0,
> - PROP_REDIRECTING
> -};
> -
> -struct _GUdevClientPrivate {
> - SpiceUsbBackend *ctx;
> - GList *udev_list;
> - HWND hwnd;
> - gboolean redirecting;
> -};
> -
> -#define G_UDEV_CLIENT_WINCLASS_NAME TEXT("G_UDEV_CLIENT")
> -
> -static void g_udev_client_initable_iface_init(GInitableIface *iface);
> -
> -G_DEFINE_TYPE_WITH_CODE(GUdevClient, g_udev_client, G_TYPE_OBJECT,
> - G_ADD_PRIVATE(GUdevClient)
> - G_IMPLEMENT_INTERFACE(G_TYPE_INITABLE, g_udev_client_initable_iface_init))
> -
> -enum
> -{
> - UEVENT_SIGNAL,
> - LAST_SIGNAL,
> -};
> -
> -static guint signals[LAST_SIGNAL] = { 0, };
> -static GUdevClient *singleton = NULL;
> -
> -static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
> -
> -//uncomment to debug gudev device lists.
> -//#define DEBUG_GUDEV_DEVICE_LISTS
> -
> -#ifdef DEBUG_GUDEV_DEVICE_LISTS
> -static void g_udev_device_print_list(GList *l, const gchar *msg);
> -#else
> -static void g_udev_device_print_list(GList *l, const gchar *msg) {}
> -#endif
> -static void g_udev_device_print(SpiceUsbBackendDevice *dev, const gchar *msg);
> -
> -GQuark g_udev_client_error_quark(void)
> -{
> - return g_quark_from_static_string("win-gudev-client-error-quark");
> -}
> -
> -GUdevClient *g_udev_client_new(void)
> -{
> - if (singleton != NULL)
> - return g_object_ref(singleton);
> -
> - singleton = g_initable_new(G_UDEV_TYPE_CLIENT, NULL, NULL, NULL);
> - return singleton;
> -}
> -
> -SpiceUsbBackend *g_udev_client_get_context(GUdevClient *client)
> -{
> - return client->priv->ctx;
> -}
> -
> -/*
> - * devs [in,out] an empty devs list in, full devs list out
> - * Returns: number-of-devices, or a negative value on error.
> - */
> -static ssize_t
> -g_udev_client_list_devices(GUdevClient *self, GList **devs,
> - GError **err, const gchar *name)
> -{
> - SpiceUsbBackendDevice **lusb_list, **dev;
> - GUdevClientPrivate *priv;
> - ssize_t n;
> -
> - g_return_val_if_fail(G_UDEV_IS_CLIENT(self), -1);
> - g_return_val_if_fail(devs != NULL, -2);
> -
> - priv = self->priv;
> -
> - g_return_val_if_fail(self->priv->ctx != NULL, -3);
> -
> - lusb_list = spice_usb_backend_get_device_list(priv->ctx);
> - if (!lusb_list) {
> - g_set_error(err, G_UDEV_CLIENT_ERROR, G_UDEV_CLIENT_LIBUSB_FAILED,
> - "%s: Error getting USB device list", name);
> - return -4;
> - }
> -
> - n = 0;
> - for (dev = lusb_list; *dev; dev++) {
> - *devs = g_list_prepend(*devs, spice_usb_backend_device_ref(*dev));
> - n++;
> - }
> - spice_usb_backend_free_device_list(lusb_list);
> -
> - return n;
> -}
> -
> -static void unreference_backend_device(gpointer data)
> -{
> - spice_usb_backend_device_unref((SpiceUsbBackendDevice *)data);
> -}
> -
> -static void g_udev_client_free_device_list(GList **devs)
> -{
> - g_return_if_fail(devs != NULL);
> - if (*devs) {
> - g_list_free_full(*devs, unreference_backend_device);
> - *devs = NULL;
> - }
> -}
> -
> -
> -static gboolean
> -g_udev_client_initable_init(GInitable *initable, GCancellable *cancellable,
> - GError **err)
> -{
> - GUdevClient *self;
> - GUdevClientPrivate *priv;
> - WNDCLASS wcls;
> -
> - g_return_val_if_fail(G_UDEV_IS_CLIENT(initable), FALSE);
> - g_return_val_if_fail(cancellable == NULL, FALSE);
> -
> - self = G_UDEV_CLIENT(initable);
> - priv = self->priv;
> -
> - priv->ctx = spice_usb_backend_new(err);
> - if (!priv->ctx) {
> - return FALSE;
> - }
> -
> -#ifdef G_OS_WIN32
> -#if LIBUSB_API_VERSION >= 0x01000106
> - libusb_set_option(priv->ctx, LIBUSB_OPTION_USE_USBDK);
> -#endif
> -#endif
> -
> - /* get initial device list */
> - if (g_udev_client_list_devices(self, &priv->udev_list, err, __FUNCTION__) < 0) {
> - goto g_udev_client_init_failed;
> - }
> -
> - g_udev_device_print_list(priv->udev_list, "init: first list is: ");
> -
> - /* create a hidden window */
> - memset(&wcls, 0, sizeof(wcls));
> - wcls.lpfnWndProc = wnd_proc;
> - wcls.lpszClassName = G_UDEV_CLIENT_WINCLASS_NAME;
> - if (!RegisterClass(&wcls)) {
> - DWORD e = GetLastError();
> - g_warning("RegisterClass failed , %ld", (long)e);
> - g_set_error(err, G_UDEV_CLIENT_ERROR, G_UDEV_CLIENT_WINAPI_FAILED,
> - "RegisterClass failed: %ld", (long)e);
> - goto g_udev_client_init_failed;
> - }
> - priv->hwnd = CreateWindow(G_UDEV_CLIENT_WINCLASS_NAME,
> - NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
> - if (!priv->hwnd) {
> - DWORD e = GetLastError();
> - g_warning("CreateWindow failed: %ld", (long)e);
> - g_set_error(err, G_UDEV_CLIENT_ERROR, G_UDEV_CLIENT_LIBUSB_FAILED,
> - "CreateWindow failed: %ld", (long)e);
> - goto g_udev_client_init_failed_unreg;
> - }
> -
> - return TRUE;
> -
> - g_udev_client_init_failed_unreg:
> - UnregisterClass(G_UDEV_CLIENT_WINCLASS_NAME, NULL);
> - g_udev_client_init_failed:
> - return FALSE;
> -}
> -
> -static void g_udev_client_initable_iface_init(GInitableIface *iface)
> -{
> - iface->init = g_udev_client_initable_init;
> -}
> -
> -static void report_one_device(gpointer data, gpointer self)
> -{
> - g_signal_emit(self, signals[UEVENT_SIGNAL], 0, data, TRUE);
> -}
> -
> -void g_udev_client_report_devices(GUdevClient *self)
> -{
> - g_list_foreach(self->priv->udev_list, report_one_device, self);
> -}
> -
> -static void g_udev_client_init(GUdevClient *self)
> -{
> - self->priv = g_udev_client_get_instance_private(self);
> -}
> -
> -static void g_udev_client_finalize(GObject *gobject)
> -{
> - GUdevClient *self = G_UDEV_CLIENT(gobject);
> - GUdevClientPrivate *priv = self->priv;
> -
> - singleton = NULL;
> - DestroyWindow(priv->hwnd);
> - UnregisterClass(G_UDEV_CLIENT_WINCLASS_NAME, NULL);
> - g_udev_client_free_device_list(&priv->udev_list);
> -
> - /* free backend context */
> - g_warn_if_fail(priv->ctx != NULL);
> - spice_usb_backend_delete(priv->ctx);
> -
> - /* Chain up to the parent class */
> - if (G_OBJECT_CLASS(g_udev_client_parent_class)->finalize)
> - G_OBJECT_CLASS(g_udev_client_parent_class)->finalize(gobject);
> -}
> -
> -static void g_udev_client_get_property(GObject *gobject,
> - guint prop_id,
> - GValue *value,
> - GParamSpec *pspec)
> -{
> - GUdevClient *self = G_UDEV_CLIENT(gobject);
> - GUdevClientPrivate *priv = self->priv;
> -
> - switch (prop_id) {
> - case PROP_REDIRECTING:
> - g_value_set_boolean(value, priv->redirecting);
> - break;
> - default:
> - G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec);
> - break;
> - }
> -}
> -
> -static void handle_dev_change(GUdevClient *self);
> -
> -static void g_udev_client_set_property(GObject *gobject,
> - guint prop_id,
> - const GValue *value,
> - GParamSpec *pspec)
> -{
> - GUdevClient *self = G_UDEV_CLIENT(gobject);
> - GUdevClientPrivate *priv = self->priv;
> - gboolean old_val;
> -
> - switch (prop_id) {
> - case PROP_REDIRECTING:
> - old_val = priv->redirecting;
> - priv->redirecting = g_value_get_boolean(value);
> - if (old_val && !priv->redirecting) {
> - /* This is a redirection completion case.
> - Inject hotplug event in case we missed device changes
> - during redirection processing. */
> - handle_dev_change(self);
> - }
> - break;
> - default:
> - G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec);
> - break;
> - }
> -}
> -
> -static void g_udev_client_class_init(GUdevClientClass *klass)
> -{
> - GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
> - GParamSpec *pspec;
> -
> - gobject_class->finalize = g_udev_client_finalize;
> - gobject_class->get_property = g_udev_client_get_property;
> - gobject_class->set_property = g_udev_client_set_property;
> -
> - signals[UEVENT_SIGNAL] =
> - g_signal_new("uevent",
> - G_OBJECT_CLASS_TYPE(klass),
> - G_SIGNAL_RUN_FIRST,
> - G_STRUCT_OFFSET(GUdevClientClass, uevent),
> - NULL, NULL,
> - g_cclosure_user_marshal_VOID__POINTER_BOOLEAN,
> - G_TYPE_NONE,
> - 2,
> - G_TYPE_POINTER,
> - G_TYPE_BOOLEAN);
> -
> - /**
> - * GUdevClient::redirecting:
> - *
> - * This property indicates when a redirection operation
> - * is in progress on a device. It's set back to FALSE
> - * once the device is fully redirected to the guest.
> - */
> - pspec = g_param_spec_boolean("redirecting", "Redirecting",
> - "USB redirection operation is in progress",
> - FALSE,
> - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
> -
> - g_object_class_install_property(gobject_class, PROP_REDIRECTING, pspec);
> -}
> -
> -/* comparing bus:addr and vid:pid */
> -static gint compare_usb_devices(gconstpointer a, gconstpointer b)
> -{
> - const UsbDeviceInformation *a_info, *b_info;
> - gboolean same_bus, same_addr, same_vid, same_pid;
> - a_info = spice_usb_backend_device_get_info((SpiceUsbBackendDevice *)a);
> - b_info = spice_usb_backend_device_get_info((SpiceUsbBackendDevice *)b);
> -
> -
> - same_bus = (a_info->bus == b_info->bus);
> - same_addr = (a_info->address == b_info->address);
> - same_vid = (a_info->vid == b_info->vid);
> - same_pid = (a_info->pid == b_info->pid);
> -
> - return (same_bus && same_addr && same_vid && same_pid) ? 0 : -1;
> -}
> -
> -static void update_device_list(GUdevClient *self, GList *new_device_list)
> -{
> - GList *dev;
> -
> - for (dev = g_list_first(new_device_list); dev != NULL; dev = g_list_next(dev)) {
> - GList *found = g_list_find_custom(self->priv->udev_list, dev->data, compare_usb_devices);
> - if (found != NULL) {
> - /* keep old existing libusb_device in the new list, when
> - usb-dev-manager will maintain its own list of libusb_device,
> - these lists will be completely consistent */
> - SpiceUsbBackendDevice *temp = found->data;
> - found->data = dev->data;
> - dev->data = temp;
> - }
> - }
> -
> - g_udev_client_free_device_list(&self->priv->udev_list);
> - self->priv->udev_list = new_device_list;
> -}
> -
> -static void notify_dev_state_change(GUdevClient *self,
> - GList *old_list,
> - GList *new_list,
> - gboolean add)
> -{
> - GList *dev;
> -
> - for (dev = g_list_first(old_list); dev != NULL; dev = g_list_next(dev)) {
> - GList *found = g_list_find_custom(new_list, dev->data, compare_usb_devices);
> - if (found == NULL) {
> - g_udev_device_print(dev->data, add ? "add" : "remove");
> - g_signal_emit(self, signals[UEVENT_SIGNAL], 0, dev->data, add);
> - }
> - }
> -}
> -
> -static void handle_dev_change(GUdevClient *self)
> -{
> - GUdevClientPrivate *priv = self->priv;
> - GError *err = NULL;
> - GList *now_devs = NULL;
> -
> - if (priv->redirecting == TRUE) {
> - /* On Windows, querying USB device list may return inconsistent results
> - if performed in parallel to redirection flow.
> - A simulated hotplug event will be injected after redirection
> - completion in order to process real device list changes that may
> - had taken place during redirection process. */
> - return;
> - }
> -
> - if(g_udev_client_list_devices(self, &now_devs, &err, __FUNCTION__) < 0) {
> - g_warning("could not retrieve device list");
> - return;
> - }
> -
> - g_udev_device_print_list(now_devs, "handle_dev_change: current list:");
> - g_udev_device_print_list(priv->udev_list, "handle_dev_change: previous list:");
> -
> - /* Unregister devices that are not present anymore */
> - notify_dev_state_change(self, priv->udev_list, now_devs, FALSE);
> -
> - /* Register newly inserted devices */
> - notify_dev_state_change(self, now_devs, priv->udev_list, TRUE);
> -
> - /* keep most recent info: free previous list, and keep current list */
> - update_device_list(self, now_devs);
> -}
> -
> -static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
> -{
> - /* Only DBT_DEVNODES_CHANGED recieved */
> - if (message == WM_DEVICECHANGE) {
> - handle_dev_change(singleton);
> - }
> - return DefWindowProc(hwnd, message, wparam, lparam);
> -}
> -
> -#ifdef DEBUG_GUDEV_DEVICE_LISTS
> -static void g_udev_device_print_list(GList *l, const gchar *msg)
> -{
> - GList *it;
> -
> - for (it = g_list_first(l); it != NULL; it=g_list_next(it)) {
> - g_udev_device_print(it->data, msg);
> - }
> -}
> -#endif
> -
> -static void g_udev_device_print(SpiceUsbBackendDevice *dev, const gchar *msg)
> -{
> - const UsbDeviceInformation *info = spice_usb_backend_device_get_info(dev);
> -
> - SPICE_DEBUG("%s: %d.%d 0x%04x:0x%04x class %d", msg,
> - info->bus, info->address,
> - info->vid, info->pid, info->class);
> -}
> diff --git a/src/win-usb-dev.h b/src/win-usb-dev.h
> deleted file mode 100644
> index fdfe73a..0000000
> --- a/src/win-usb-dev.h
> +++ /dev/null
> @@ -1,84 +0,0 @@
> -/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
> -/*
> - Copyright (C) 2012 Red Hat, Inc.
> -
> - Red Hat Authors:
> - Arnon Gilboa <agilboa at redhat.com>
> - Uri Lublin <uril at redhat.com>
> -
> - This library is free software; you can redistribute it and/or
> - modify it under the terms of the GNU Lesser General Public
> - License as published by the Free Software Foundation; either
> - version 2.1 of the License, or (at your option) any later version.
> -
> - This library is distributed in the hope that it will be useful,
> - but WITHOUT ANY WARRANTY; without even the implied warranty of
> - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> - Lesser General Public License for more details.
> -
> - You should have received a copy of the GNU Lesser General Public
> - License along with this library; if not, see <http://www.gnu.org/licenses/>.
> -*/
> -#ifndef __WIN_USB_DEV_H__
> -#define __WIN_USB_DEV_H__
> -
> -#include <gio/gio.h>
> -#include "usb-backend.h"
> -
> -G_BEGIN_DECLS
> -
> -/* GUdevClient */
> -
> -#define G_UDEV_TYPE_CLIENT (g_udev_client_get_type())
> -#define G_UDEV_CLIENT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), G_UDEV_TYPE_CLIENT, GUdevClient))
> -#define G_UDEV_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_CLIENT, GUdevClientClass))
> -#define G_UDEV_IS_CLIENT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), G_UDEV_TYPE_CLIENT))
> -#define G_UDEV_IS_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), G_UDEV_TYPE_CLIENT))
> -#define G_UDEV_CLIENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), G_UDEV_TYPE_CLIENT, GUdevClientClass))
> -
> -typedef struct _GUdevClient GUdevClient;
> -typedef struct _GUdevClientClass GUdevClientClass;
> -typedef struct _GUdevClientPrivate GUdevClientPrivate;
> -
> -struct _GUdevClient
> -{
> - GObject parent;
> -
> - GUdevClientPrivate *priv;
> -};
> -
> -struct _GUdevClientClass
> -{
> - GObjectClass parent_class;
> -
> - /* signals */
> - void (*uevent)(GUdevClient *client, SpiceUsbBackendDevice *device, gboolean add);
> -};
> -
> -GType g_udev_client_get_type(void) G_GNUC_CONST;
> -GUdevClient *g_udev_client_new(void);
> -SpiceUsbBackend *g_udev_client_get_context(GUdevClient *client);
> -void g_udev_client_report_devices(GUdevClient *client);
> -
> -GQuark g_udev_client_error_quark(void);
> -#define G_UDEV_CLIENT_ERROR g_udev_client_error_quark()
> -
> -/**
> - * GUdevClientError:
> - * @G_UDEV_CLIENT_ERROR_FAILED: generic error code
> - * @G_UDEV_CLIENT_LIBUSB_FAILED: a libusb call failed
> - * @G_UDEV_CLIENT_WINAPI_FAILED: a winapi call failed
> - *
> - * Error codes returned by spice-client API.
> - */
> -typedef enum
> -{
> - G_UDEV_CLIENT_ERROR_FAILED = 1,
> - G_UDEV_CLIENT_LIBUSB_FAILED,
> - G_UDEV_CLIENT_WINAPI_FAILED
> -} GUdevClientError;
> -
> -
> -G_END_DECLS
> -
> -#endif /* __WIN_USB_DEV_H__ */
> --
> 2.17.1
>
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/spice-devel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/spice-devel/attachments/20190719/965f6a6f/attachment-0001.sig>
More information about the Spice-devel
mailing list