<div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Tue, Sep 25, 2018 at 4:39 PM Christophe Fergeau <<a href="mailto:cfergeau@redhat.com" target="_blank">cfergeau@redhat.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hey,<br>
<br>
Thanks for doing some splitting work!<br>
<br>
I would personally squash these 2 patches, as there is some code<br>
movement between the new file introduced in this patch, and the files<br>
which are modified in the other one.<br>
You seem to have left out some of the comments I made previously (the<br>
__FUNCTION__ comment for example), replying to these suggestions would<br>
be nice.. ;)<br></blockquote><div><br></div><div>In spice-gtk logs the function name is never printed if not explicitly requested.</div><div>As I can see in gmacros.h</div><div><div style="color:rgb(212,212,212);background-color:rgb(30,30,30);font-family:Consolas,"Courier New",monospace;font-size:14px;line-height:19px;white-space:pre-wrap"><div><span style="color:rgb(96,139,78)">/* Provide a string identifying the current code position */</span></div><div><span style="color:rgb(197,134,192)">#if</span><span style="color:rgb(86,156,214)"> </span><span style="color:rgb(197,134,192)">defined</span><span style="color:rgb(86,156,214)">(</span><span style="color:rgb(220,220,170)">__GNUC__</span><span style="color:rgb(86,156,214)">) </span>&&<span style="color:rgb(86,156,214)"> (</span><span style="color:rgb(220,220,170)">__GNUC__</span><span style="color:rgb(86,156,214)"> </span><<span style="color:rgb(86,156,214)"> </span><span style="color:rgb(181,206,168)">3</span><span style="color:rgb(86,156,214)">) </span>&&<span style="color:rgb(86,156,214)"> </span>!<span style="color:rgb(197,134,192)">defined</span><span style="color:rgb(86,156,214)">(</span><span style="color:rgb(220,220,170)">__cplusplus</span><span style="color:rgb(86,156,214)">)</span></div><div><span style="color:rgb(197,134,192)">#define</span><span style="color:rgb(86,156,214)"> </span><span style="color:rgb(220,220,170)">G_STRLOC</span><span style="color:rgb(86,156,214)">  __FILE__ </span><span style="color:rgb(206,145,120)">":"</span><span style="color:rgb(86,156,214)"> </span><span style="color:rgb(220,220,170)">G_STRINGIFY</span><span style="color:rgb(86,156,214)"> (__LINE__) </span><span style="color:rgb(206,145,120)">":"</span><span style="color:rgb(86,156,214)"> __PRETTY_FUNCTION__ </span><span style="color:rgb(206,145,120)">"()"</span></div><div><span style="color:rgb(197,134,192)">#else</span></div><div><span style="color:rgb(197,134,192)">#define</span><span style="color:rgb(86,156,214)"> </span><span style="color:rgb(220,220,170)">G_STRLOC</span><span style="color:rgb(86,156,214)">  __FILE__ </span><span style="color:rgb(206,145,120)">":"</span><span style="color:rgb(86,156,214)"> </span><span style="color:rgb(220,220,170)">G_STRINGIFY</span><span style="color:rgb(86,156,214)"> (__LINE__)</span></div><div><span style="color:rgb(197,134,192)">#endif</span></div><br></div></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
On Mon, Sep 24, 2018 at 11:43:54AM +0300, Yuri Benditovich wrote:<br>
> This layer communicates with libusb and libusbredir and<br>
> provides the API for USB redirection procedures.<br>
> In future all the modules of spice-gtk will communicate<br>
> only with usb backend instead of calling libusb and<br>
> usbredirhost directly. This is prerequisite of further<br>
> implementation of cd-sharing via USB redirection.<br>
> <br>
> Signed-off-by: Yuri Benditovich <<a href="mailto:yuri.benditovich@daynix.com" target="_blank">yuri.benditovich@daynix.com</a>><br>
> ---<br>
>  src/usb-backend-common.c | 809 +++++++++++++++++++++++++++++++++++++++++++++++<br>
>  src/usb-backend.h        |  97 ++++++<br>
>  2 files changed, 906 insertions(+)<br>
>  create mode 100644 src/usb-backend-common.c<br>
>  create mode 100644 src/usb-backend.h<br>
> <br>
> diff --git a/src/usb-backend-common.c b/src/usb-backend-common.c<br>
> new file mode 100644<br>
> index 0000000..b3963ad<br>
> --- /dev/null<br>
> +++ b/src/usb-backend-common.c<br>
> @@ -0,0 +1,809 @@<br>
> +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */<br>
> +/*<br>
> +    Copyright (C) 2018 Red Hat, Inc.<br>
> +<br>
> +    Red Hat Authors:<br>
> +    Yuri Benditovich<<a href="mailto:ybendito@redhat.com" target="_blank">ybendito@redhat.com</a>><br>
<br>
You probably want to copy some of the authors from the files you are<br>
copying code from, and reuse the (C) date from there too<br>
> +<br>
> +struct _SpiceUsbBackendDevice<br>
> +{<br>
> +    union<br>
> +    {<br>
> +        void *libusb_device;<br>
<br>
Why void * rather than the proper libusb_device * type?<br>
<br>
> +        void *msc;<br>
> +    } d;<br>
> +    uint32_t isLibUsb   : 1;<br>
<br>
Should be name "is_libusb", but it's really used in this patch.<br>
<br>
> +    uint32_t configured : 1;<br>
<br>
This is not used at all. I think using 'bool' rather than a bitfield<br>
should be good enough.<br>
<br>
> +    int refCount;<br>
<br>
'ref_count'. Have you considered making this a GObject which would give<br>
you the refcounting?<br>
<br></blockquote><div><br></div><div>IMO, less code is better and making it GObject does not provide any added value.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +    void *mutex;<br>
<br>
A proper type would be good to have here, but see my comments in the<br>
acquire/release methods.<br>
<br>
> +    SpiceUsbBackendChannel *attached_to;<br>
<br>
Or just 'backend_channel'?<br>
<br></blockquote><div><br></div><div>Please let me know whether this change is mandatory.</div><div>I'm fine with existing name.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +    UsbDeviceInformation device_info;<br>
> +};<br>
> +<br>
> +struct _SpiceUsbBackend<br>
<br>
I think I would call this SpiceUsbContext<br>
<br></blockquote><div><div>Please let me know whether this change is mandatory.</div><div>I'm fine with existing name.</div><br class="gmail-Apple-interchange-newline"></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +{<br>
> +    libusb_context *libusbContext;<br>
<br>
No CamelCase.<br>
<br>
<br>
> +    usb_hot_plug_callback hp_callback;<br>
<br>
usb_hotplug_callback<br>
<br>
> +    void *hp_user_data;<br>
> +    libusb_hotplug_callback_handle hp_handle;<br>
<br>
s/hp_/hotplug_<br>
<br>
> +    void *dev_change_user_data;<br>
> +    uint32_t suppressed : 1;<br>
<br>
This is not used in this patch save for:<br>
#ifndef USE_CD_SHARING<br>
    be->suppressed = TRUE;<br>
#endif<br>
<br>
Later it will only be used for<br>
if (!be->suppressed) {<br>
...<br>
}<br>
Not clear why this code block could not be surrounded by #ifndef<br>
USE_CD_SHARING, which would get rid of the code altogether when<br>
cd sharing was disabled at compile time.<br>
<br></blockquote><div><br></div><div>For now I remove till cd sharing commit.</div><div>In general, I would like to avoid making code like a zebra.</div><div>All the cd sharing functionality is disabled this is undefined.</div><div>If this is mandatory requirement for future commits, please let me know.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +};<br>
> +<br>
> +/* backend object for device change notification */<br>
> +static SpiceUsbBackend *notify_backend;<br>
<br>
This is not used at the moment. Looking at the final state of the series<br>
you sent previously, you need that global variable at one point because<br>
otherwise you have no way of getting the SpiceUsbBackend associated with<br>
the device you are currently processing. If SpiceUsbBackendDevice is a GObject,<br>
it seems this stuff could be replaced by a<br>
SpiceUsbBackendDevice::lun-changed signal (?)<br></blockquote><div><br></div><div>This is because SpiceUsbBackendDevice is not associated with</div><div>SpiceUsbBackend, not because it is not a GObject. This notify routine</div><div>required only for updating the widget upon event in CD device.</div><div>I'll remove it for now till cd sharing.  <br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
> +<br>
> +struct _SpiceUsbBackendChannel<br>
> +{<br>
> +    struct usbredirhost *usbredirhost;<br>
> +    uint8_t *read_buf;<br>
> +    int read_buf_size;<br>
> +    struct usbredirfilter_rule *rules;<br>
> +    int rules_count;<br>
<br>
I could not find where rules/rules_count are initialized in the current<br>
patch, is there something missing?<br></blockquote><div><br></div><div>The SpiceUsbBackendChannel is allocated with new0.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
> +    uint32_t rejected          : 1;<br>
<br>
Could be bool, but not used.<br>
<br>
> +    SpiceUsbBackendDevice *attached;<br>
<br>
I think I'd name this backend_device.<br>
<br>
> +    SpiceUsbBackendChannelInitData data;<br>
<br>
Better name than 'data' needed.<br>
<br>
> +};<br>
> +<br>
> +static const char *spice_usbutil_libusb_strerror(enum libusb_error error_code)<br>
> +{<br>
> +    switch (error_code) {<br>
> +    case LIBUSB_SUCCESS:<br>
> +        return "Success";<br>
> +    case LIBUSB_ERROR_IO:<br>
> +        return "Input/output error";<br>
> +    case LIBUSB_ERROR_INVALID_PARAM:<br>
> +        return "Invalid parameter";<br>
> +    case LIBUSB_ERROR_ACCESS:<br>
> +        return "Access denied (insufficient permissions)";<br>
> +    case LIBUSB_ERROR_NO_DEVICE:<br>
> +        return "No such device (it may have been disconnected)";<br>
> +    case LIBUSB_ERROR_NOT_FOUND:<br>
> +        return "Entity not found";<br>
> +    case LIBUSB_ERROR_BUSY:<br>
> +        return "Resource busy";<br>
> +    case LIBUSB_ERROR_TIMEOUT:<br>
> +        return "Operation timed out";<br>
> +    case LIBUSB_ERROR_OVERFLOW:<br>
> +        return "Overflow";<br>
> +    case LIBUSB_ERROR_PIPE:<br>
> +        return "Pipe error";<br>
> +    case LIBUSB_ERROR_INTERRUPTED:<br>
> +        return "System call interrupted (perhaps due to signal)";<br>
> +    case LIBUSB_ERROR_NO_MEM:<br>
> +        return "Insufficient memory";<br>
> +    case LIBUSB_ERROR_NOT_SUPPORTED:<br>
> +        return "Operation not supported or unimplemented on this platform";<br>
> +    case LIBUSB_ERROR_OTHER:<br>
> +        return "Other error";<br>
> +    }<br>
> +    return "Unknown error";<br>
> +}<br>
> +<br>
> +// lock functions for usbredirhost and usbredirparser<br>
> +static void *usbredir_alloc_lock(void) {<br>
> +    GMutex *mutex;<br>
> +<br>
> +    mutex = g_new0(GMutex, 1);<br>
> +    g_mutex_init(mutex);<br>
> +<br>
> +    return mutex;<br>
> +}<br>
> +<br>
> +static void usbredir_free_lock(void *user_data) {<br>
> +    GMutex *mutex = user_data;<br>
> +<br>
> +    g_mutex_clear(mutex);<br>
> +    g_free(mutex);<br>
> +}<br>
> +<br>
> +static void usbredir_lock_lock(void *user_data) {<br>
> +    GMutex *mutex = user_data;<br>
> +<br>
> +    g_mutex_lock(mutex);<br>
> +}<br>
> +<br>
> +static void usbredir_unlock_lock(void *user_data) {<br>
> +    GMutex *mutex = user_data;<br>
> +<br>
> +    g_mutex_unlock(mutex);<br>
> +}<br>
> +<br>
> +static gboolean fill_usb_info(SpiceUsbBackendDevice *bdev)<br>
> +{<br>
> +    UsbDeviceInformation *pi = &bdev->device_info;<br>
<br>
pi? what about info?<br>
<br>
> +<br>
> +    if (bdev->isLibUsb)<br>
> +    {<br>
> +        struct libusb_device_descriptor desc;<br>
> +        libusb_device *libdev = bdev->d.libusb_device;<br>
> +        int res = libusb_get_device_descriptor(libdev, &desc);<br>
> +        pi->bus = libusb_get_bus_number(libdev);<br>
> +        pi->address = libusb_get_device_address(libdev);<br>
> +        if (res < 0) {<br>
> +            g_warning("cannot get device descriptor for (%p) %d.%d",<br>
> +                libdev, pi->bus, pi->address);<br>
> +            return FALSE;<br>
> +        }<br>
> +        pi->vid = desc.idVendor;<br>
> +        pi->pid = desc.idProduct;<br>
> +        pi->class = desc.bDeviceClass;<br>
> +        pi->subclass = desc.bDeviceSubClass;<br>
> +        pi->protocol = desc.bDeviceProtocol;<br>
> +        pi->isochronous = 0;<br>
> +        pi->max_luns = 0;<br>
> +    }<br>
> +    return TRUE;<br>
> +}<br>
> +<br>
> +/* Note that this function must be re-entrant safe, as it can get called<br>
> +from both the main thread as well as from the usb event handling thread */<br>
> +static void usbredir_write_flush_callback(void *user_data)<br>
> +{<br>
> +    SpiceUsbBackendChannel *ch = user_data;<br>
> +    gboolean b = ch->data.is_channel_ready(ch->data.user_data);<br>
<br>
backend_channel and ready would be far better names...<br></blockquote><div><br></div><div>I understand that you'd like to change many names.</div><div>The 'ch' in this file is consistently designates backend channel and nothing other.</div><div>Please let me know whether this change is mandatory.</div><div>Note also many one-letter and two letters identifiers in existing code.</div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
> +    if (b) {<br>
> +        if (ch->usbredirhost) {<br>
> +            SPICE_DEBUG("%s ch %p -> usbredirhost", __FUNCTION__, ch);<br>
> +            usbredirhost_write_guest_data(ch->usbredirhost);<br>
> +        }<br>
> +        else {<br>
> +            b = FALSE;<br>
> +        }<br>
> +    }<br>
> +<br>
> +    if (!b) {<br>
<br>
Could go in an } else { block<br>
<br>
> +        SPICE_DEBUG("%s ch %p (not ready)", __FUNCTION__, ch);<br>
> +    }<br>
> +}<br>
> +<br>
> +#ifdef INTERCEPT_LOG<br>
> +static void log_handler(<br>
> +    const gchar *log_domain,<br>
> +    GLogLevelFlags log_level,<br>
> +    const gchar *message,<br>
> +    gpointer user_data)<br>
<br>
Indentation is wrong<br>
<br>
> +{<br>
> +    GString *log_msg;<br>
> +    log_msg = g_string_new(NULL);<br>
> +    if (log_msg)<br>
> +    {<br>
> +        gchar *timestamp;<br>
> +        GThread *th = g_thread_self();<br>
> +        GDateTime *current_time = g_date_time_new_now_local();<br>
> +        gint micros = g_date_time_get_microsecond(current_time);<br>
> +        timestamp = g_date_time_format(current_time, "%H:%M:%S");<br>
> +        g_string_append_printf(log_msg, "[%p][%s.%03d]", th, timestamp, micros / 1000);<br>
> +        g_date_time_unref(current_time);<br>
> +        g_free(timestamp);<br>
> +        g_string_append(log_msg, message);<br>
> +#ifdef INTERCEPT_LOG2FILE<br>
> +        g_string_append(log_msg, "\n");<br>
> +        fwrite(log_msg->str, 1, strlen(log_msg->str), fLog);<br>
> +#else<br>
> +        g_log_default_handler(log_domain, log_level, log_msg->str, NULL);<br>
> +#endif<br>
> +        g_string_free(log_msg, TRUE);<br>
> +    }<br>
> +}<br>
> +#endif<br>
> +<br>
> +static void configure_log(void)<br>
> +{<br>
> +#ifdef INTERCEPT_LOG2FILE<br>
> +    fLog = fopen("remote-viewer.log", "w+t");<br>
> +#endif<br>
> +#ifdef INTERCEPT_LOG<br>
> +    g_log_set_default_handler(log_handler, NULL);<br>
> +#endif<br>
> +}<br>
<br>
I'd drop that logging stuff, or move it to a separate commit. Imo this<br>
is better addressed with log categories, or grep+redirection, and I<br>
don't think this is something that should be specific to the usb code.<br>
<br>
> +<br>
> +SpiceUsbBackend *spice_usb_backend_initialize(void)<br>
> +{<br>
> +    SpiceUsbBackend *be;<br>
> +    SPICE_DEBUG("%s >>", __FUNCTION__);<br>
> +    if (!g_mutex) {<br>
> +        g_mutex = usbredir_alloc_lock();<br>
> +        configure_log();<br>
> +    }<br>
> +    be = (SpiceUsbBackend *)g_new0(SpiceUsbBackend, 1);<br>
> +#ifndef USE_CD_SHARING<br>
> +    be->suppressed = TRUE;<br>
> +#endif<br>
> +    int rc;<br>
> +    rc = libusb_init(&be->libusbContext);<br>
> +    if (rc < 0) {<br>
> +        const char *desc = spice_usbutil_libusb_strerror(rc);<br>
> +        g_warning("Error initializing LIBUSB support: %s [%i]", desc, rc);<br>
<br>
Maybe have a GError **error argument so that we can properly report<br>
failures? This is what the initial code was doing.<br>
<br>
> +    } else {<br>
> +#ifdef G_OS_WIN32<br>
> +#if LIBUSB_API_VERSION >= 0x01000106<br>
> +    libusb_set_option(be->libusbContext, LIBUSB_OPTION_USE_USBDK);<br>
> +#endif<br>
> +#endif<br>
> +    }<br>
> +    SPICE_DEBUG("%s <<", __FUNCTION__);<br>
> +    return be;<br>
> +}<br>
> +<br>
> +gboolean spice_usb_backend_handle_events(SpiceUsbBackend *be)<br>
<br>
s/be/backend?<br>
<br></blockquote><div><div><br></div><div>Please let me know whether this change is mandatory.</div><div> <br></div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +{<br>
> +    SPICE_DEBUG("%s >>", __FUNCTION__);<br>
> +    gboolean b = TRUE;<br>
<br>
Something more expressive than 'b' would be nice.<br>
<br>
<br>
> +    if (be->libusbContext) {<br>
> +        SPICE_DEBUG("%s >> libusb", __FUNCTION__);<br>
> +        int res = libusb_handle_events(be->libusbContext);<br>
> +        if (res && res != LIBUSB_ERROR_INTERRUPTED) {<br>
<br>
((res != 0) && (res != LIBUSB_ERROR_INTERRUPTED)) maybe?<br>
<br>
> +            const char *desc = spice_usbutil_libusb_strerror(res);<br>
> +            g_warning("Error handling USB events: %s [%i]", desc, res);<br>
> +            b = FALSE;<br>
> +        }<br>
> +        SPICE_DEBUG("%s << libusb %d", __FUNCTION__, res);<br>
> +    }<br>
> +    else {<br>
> +        b = TRUE;<br>
> +        g_usleep(1000000);<br>
<br>
I don't think that belongs to this commit.<br>
<br>
> +    }<br>
> +    SPICE_DEBUG("%s <<", __FUNCTION__);<br>
> +    return b;<br>
> +}<br>
> +<br>
> +static int LIBUSB_CALL hotplug_callback(libusb_context *ctx,<br>
> +    libusb_device *device,<br>
> +    libusb_hotplug_event event,<br>
> +    void *user_data)<br>
<br>
indentation<br>
<br>
> +{<br>
> +    SpiceUsbBackend *be = (SpiceUsbBackend *)user_data;<br>
> +    if (be->hp_callback) {<br>
> +        SpiceUsbBackendDevice *d;<br>
<br>
Once again, 'd' and 'be' naming could be improved<br>
<br>
> +        gboolean val = event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED;<br>
<br>
'val' naming. I usually prefer to add () around the condition in such<br>
assignments.<br>
<br>
> +        d = g_new0(SpiceUsbBackendDevice, 1);<br>
> +        d->isLibUsb = 1;<br>
> +        d->refCount = 1;<br>
> +        d->mutex = g_mutex;<br>
> +        d->d.libusb_device = device;<br>
> +        if (fill_usb_info(d)) {<br>
> +            SPICE_DEBUG("created dev %p, usblib dev %p", d, device);<br>
> +            be->hp_callback(be->hp_user_data, d, val);<br>
> +        } else {<br>
> +            g_free(d);<br>
> +        }<br>
> +    }<br>
> +    return 0;<br>
> +}<br>
> +<br>
> +gboolean spice_usb_backend_handle_hotplug(<br>
> +    SpiceUsbBackend *be,<br>
> +    void *user_data,<br>
> +    usb_hot_plug_callback proc)<br>
<br>
Indentation<br>
<br>
> +{<br>
> +    int rc;<br>
> +    if (!proc) {<br>
> +        if (be->hp_handle) {<br>
> +            libusb_hotplug_deregister_callback(be->libusbContext, be->hp_handle);<br>
> +            be->hp_handle = 0;<br>
> +        }<br>
> +        be->hp_callback = proc;<br>
> +        return TRUE;<br>
> +    }<br>
> +<br>
> +    be->hp_callback = proc;<br>
> +    be->hp_user_data = user_data;<br>
> +    if (!be->libusbContext) {<br>
> +        // it is acceptable if libusb is not available at all<br>
<br>
Not in this commit I think?<br>
<br>
> +        return TRUE;<br>
> +    }<br>
> +    rc = libusb_hotplug_register_callback(be->libusbContext,<br>
> +        LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,<br>
> +        LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY,<br>
> +        LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,<br>
> +        hotplug_callback, be, &be->hp_handle);<br>
> +    if (rc != LIBUSB_SUCCESS) {<br>
> +        const char *desc = spice_usbutil_libusb_strerror(rc);<br>
> +        g_warning("Error initializing USB hotplug support: %s [%i]", desc, rc);<br>
<br>
This could be reported through a GError<br>
<br>
> +        be->hp_callback = NULL;<br>
> +        return FALSE;<br>
> +    }<br>
> +    return TRUE;<br>
> +}<br>
> +<br>
> +void spice_usb_backend_finalize(SpiceUsbBackend *be)<br>
> +{<br>
> +    SPICE_DEBUG("%s >>", __FUNCTION__);<br>
> +    if (be->libusbContext) {<br>
> +        libusb_exit(be->libusbContext);<br>
> +    }<br>
> +    if (be == notify_backend) {<br>
> +        notify_backend = NULL;<br>
> +    }<br>
> +    g_free(be);<br>
> +    SPICE_DEBUG("%s <<", __FUNCTION__);<br>
> +}<br>
> +<br>
> +SpiceUsbBackendDevice **spice_usb_backend_get_device_list(SpiceUsbBackend *be)<br>
> +{<br>
> +    LOUD_DEBUG("%s >>", __FUNCTION__);<br>
> +    libusb_device **devlist = NULL, **dev;<br>
> +    SpiceUsbBackendDevice *d, **list;<br>
> +<br>
> +    int n = 0, index;<br>
> +<br>
> +    if (be->libusbContext) {<br>
> +        libusb_get_device_list(be->libusbContext, &devlist);<br>
> +    }<br>
> +<br>
> +    // add all the libusb device that not present in our list<br>
> +    for (dev = devlist; dev && *dev; dev++) {<br>
> +        n++;<br>
> +    }<br>
> +<br>
> +    list = g_new0(SpiceUsbBackendDevice*, n + 1);<br>
> +<br>
> +    index = 0;<br>
> +<br>
> +    for (dev = devlist; dev && *dev; dev++) {<br>
> +        d = g_new0(SpiceUsbBackendDevice, 1);<br>
> +        d->isLibUsb = 1;<br>
> +        d->refCount = 1;<br>
> +        d->mutex = g_mutex;<br>
> +        d->d.libusb_device = *dev;<br>
<br>
You want a spice_usb_backend_device_new() method as this code is<br>
duplicated twice.<br>
<br>
> +        if (index >= n || !fill_usb_info(d)) {<br>
> +            g_free(d);<br>
> +            libusb_unref_device(*dev);<br>
> +        }<br>
> +        else {<br>
> +            SPICE_DEBUG("created dev %p, usblib dev %p", d, *dev);<br>
> +            list[index++] = d;<br>
> +        }<br>
> +    }<br>
<br>
Have you considered using GPtrArray? It looks like it would avoid the<br>
iteration to count the number of items, and make that function overall<br>
simpler.<br>
<br></blockquote><div><br></div><div>IMO, this does not make the function simpler and requires additional changes in callers code.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +<br>
> +    if (devlist) {<br>
> +        libusb_free_device_list(devlist, 0);<br>
> +    }<br>
> +<br>
> +    LOUD_DEBUG("%s <<", __FUNCTION__);<br>
> +    return list;<br>
> +}<br>
> +<br>
> +gboolean spice_usb_backend_device_is_hub(SpiceUsbBackendDevice *dev)<br>
> +{<br>
> +    return dev->device_info.class == LIBUSB_CLASS_HUB;<br>
> +}<br>
> +<br>
> +static uint8_t is_libusb_isochronous(libusb_device *libdev)<br>
<br>
This could return bool I think?<br>
<br></blockquote><div><br></div><div><div>Please let me know whether this change is mandatory.</div><div> <br></div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +{<br>
> +    struct libusb_config_descriptor *conf_desc;<br>
> +    uint8_t isoc_found = FALSE;<br>
> +    gint i, j, k;<br>
> +<br>
> +    if (!libdev) {<br>
> +        SPICE_DEBUG("%s - unexpected libdev = 0", __FUNCTION__);<br>
> +        return 0;<br>
> +    }<br>
<br>
If we should never pass a NULL libdev, I would keep the<br>
g_return_val_if_fail() the initial code has<br>
<br>
> +<br>
> +    if (libusb_get_active_config_descriptor(libdev, &conf_desc) != 0) {<br>
> +        SPICE_DEBUG("%s - no active configuration for libdev %p", __FUNCTION__, libdev);<br>
> +        return 0;<br>
<br>
Initial code had a more verbose g_return_val_if_reached()<br>
<br>
> +    }<br>
> +<br>
> +    for (i = 0; !isoc_found && i < conf_desc->bNumInterfaces; i++) {<br>
> +        for (j = 0; !isoc_found && j < conf_desc->interface[i].num_altsetting; j++) {<br>
> +            for (k = 0; !isoc_found && k < conf_desc->interface[i].altsetting[j].bNumEndpoints;k++) {<br>
> +                gint attributes = conf_desc->interface[i].altsetting[j].endpoint[k].bmAttributes;<br>
> +                gint type = attributes & LIBUSB_TRANSFER_TYPE_MASK;<br>
> +                if (type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS)<br>
> +                    isoc_found = TRUE;<br>
> +            }<br>
> +        }<br>
> +    }<br>
> +<br>
> +    libusb_free_config_descriptor(conf_desc);<br>
> +    return isoc_found;<br>
> +}<br>
> +<br>
> +const UsbDeviceInformation*  spice_usb_backend_device_get_info(SpiceUsbBackendDevice *dev)<br>
<br>
spacing looks off, should be const UsbDeviceInformation *spice_usb_backend_device_get_info<br>
<br>
> +{<br>
> +    dev->device_info.isochronous = dev->isLibUsb ? is_libusb_isochronous(dev->d.libusb_device) : 0;<br>
<br>
Why is it not done in fill_info?<br>
<br>
> +    return &dev->device_info;<br>
> +}<br>
> +<br>
> +gboolean spice_usb_backend_devices_same(<br>
> +    SpiceUsbBackendDevice *dev1,<br>
> +    SpiceUsbBackendDevice *dev2)<br>
<br>
Indentation<br>
<br>
> +{<br>
> +    if (dev1->isLibUsb != dev2->isLibUsb) {<br>
> +        return FALSE;<br>
> +    }<br>
> +    if (dev1->isLibUsb) {<br>
> +        return dev1->d.libusb_device == dev2->d.libusb_device;<br>
> +    }<br>
> +    // assuming CD redir devices are static<br>
> +    return dev1 == dev2;<br>
> +}<br>
> +<br>
> +gconstpointer spice_usb_backend_device_get_libdev(SpiceUsbBackendDevice *dev)<br>
> +{<br>
> +    if (dev->isLibUsb) {<br>
> +        return dev->d.libusb_device;<br>
> +    }<br>
> +    return NULL;<br>
> +}<br>
> +<br>
> +void spice_usb_backend_free_device_list(SpiceUsbBackendDevice **devlist)<br>
> +{<br>
> +    LOUD_DEBUG("%s >>", __FUNCTION__);<br>
> +    SpiceUsbBackendDevice **dev;<br>
> +    for (dev = devlist; *dev; dev++) {<br>
> +        SpiceUsbBackendDevice *d = *dev;<br>
> +        spice_usb_backend_device_release(d);<br>
> +    }<br>
> +    g_free(devlist);<br>
> +    LOUD_DEBUG("%s <<", __FUNCTION__);<br>
> +}<br>
> +<br>
> +void spice_usb_backend_device_acquire(SpiceUsbBackendDevice *dev)<br>
> +{<br>
> +    void *mutex = dev->mutex;<br>
> +    LOUD_DEBUG("%s >> %p", __FUNCTION__, dev);<br>
> +    usbredir_lock_lock(mutex);<br>
> +    if (dev->isLibUsb) {<br>
> +        libusb_ref_device(dev->d.libusb_device);<br>
> +    }<br>
> +    dev->refCount++;<br>
> +    usbredir_unlock_lock(mutex);<br>
<br>
Why do you need to raise both 'libusb_device' refcount, and 'dev'<br>
refcount? It would seem to me that the ref on 'dev' would be enough, as<br>
as long as it's alive thanks to that ref, it won't release the ref it<br>
owns on its 'libusb_device'? If it can be done that way, then updating<br>
the refcount can be done with an atomic operation, and you don't need<br>
g_mutex anymore.<br>
<br>
> +}<br>
> +<br>
> +void spice_usb_backend_device_release(SpiceUsbBackendDevice *dev)<br>
<br>
Why not _ref/_unref btw?<br>
<br></blockquote><div><br></div><div>Due to personal preference.</div><div><div>Please let me know whether this change is mandatory.</div><div> <br></div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +{<br>
> +    void *mutex = dev->mutex;<br>
> +    LOUD_DEBUG("%s >> %p(%d)", __FUNCTION__, dev, dev->refCount);<br>
> +    usbredir_lock_lock(mutex);<br>
> +    if (dev->isLibUsb) {<br>
> +        libusb_unref_device(dev->d.libusb_device);<br>
> +        dev->refCount--;<br>
> +        if (dev->refCount == 0) {<br>
> +            LOUD_DEBUG("%s freeing %p (libusb %p)", __FUNCTION__, dev, dev->d.libusb_device);<br>
> +            g_free(dev);<br>
> +        }<br>
> +    }<br>
> +    else {<br>
> +        dev->refCount--;<br>
<br>
This codepath won't get trigger here. However, in the previous series<br>
that you sent, it's done this way in the final patch. Is this correct?<br>
It's odd to always decrease this without never checking the value..<br>
<br>
> +    }<br>
> +    usbredir_unlock_lock(mutex);<br>
> +    LOUD_DEBUG("%s <<", __FUNCTION__);<br>
> +}<br>
> +<br>
> +gboolean spice_usb_backend_device_need_thread(SpiceUsbBackendDevice *dev)<br>
<br>
'needs_thread' I'd say. However it should probably be introduced later.<br>
<br>
> +{<br>
> +    gboolean b = dev->isLibUsb != 0;<br>
> +    SPICE_DEBUG("%s << %d", __FUNCTION__, b);<br>
> +    return b;<br>
> +}<br>
> +<br>
> +int spice_usb_backend_device_check_filter(<br>
> +    SpiceUsbBackendDevice *dev,<br>
> +    const struct usbredirfilter_rule *rules,<br>
> +    int count)<br>
> +{<br>
> +    if (dev->isLibUsb) {<br>
> +        return usbredirhost_check_device_filter(<br>
> +            rules, count, dev->d.libusb_device, 0);<br>
> +    }<br>
> +    return -1;<br>
> +}<br>
> +<br>
> +static int usbredir_read_callback(void *user_data, uint8_t *data, int count)<br>
> +{<br>
> +    SpiceUsbBackendChannel *ch = user_data;<br>
> +<br>
> +    count = MIN(ch->read_buf_size, count);<br>
> +<br>
> +    if (count != 0) {<br>
> +        memcpy(data, ch->read_buf, count);<br>
> +    }<br>
> +<br>
> +    ch->read_buf_size -= count;<br>
> +    if (ch->read_buf_size) {<br>
> +        ch->read_buf += count;<br>
> +    }<br>
> +    else {<br>
> +        ch->read_buf = NULL;<br>
> +    }<br>
> +    SPICE_DEBUG("%s ch %p, %d bytes", __FUNCTION__, ch, count);<br>
> +<br>
> +    return count;<br>
> +}<br>
> +<br>
> +static const char *strip_usbredir_prefix(const char *msg)<br>
> +{<br>
> +    if (strncmp(msg, "usbredirhost: ", 14) == 0) {<br>
> +        msg += 14;<br>
> +    }<br>
> +    return msg;<br>
> +}<br>
> +<br>
> +static void usbredir_log(void *user_data, int level, const char *msg)<br>
> +{<br>
> +    SpiceUsbBackendChannel *ch = (SpiceUsbBackendChannel *)user_data;<br>
> +    const char *stripped_msg = strip_usbredir_prefix(msg);<br>
> +    switch (level) {<br>
> +    case usbredirparser_error:<br>
> +        g_critical("%s", msg);<br>
> +        ch->data.log(ch->data.user_data, stripped_msg, TRUE);<br>
> +        break;<br>
> +    case usbredirparser_warning:<br>
> +        g_warning("%s", msg);<br>
> +        ch->data.log(ch->data.user_data, stripped_msg, TRUE);<br>
> +        break;<br>
> +    default:<br>
> +        ch->data.log(ch->data.user_data, stripped_msg, FALSE);<br>
> +        break;<br>
<br>
usbredir_log in channel-usbredir.c will not do anything when the last<br>
arg is FALSE, in other words it only cares about errors. I would turn<br>
the 'log' callback into an 'error' callback and pass a GError.<br>
<br>
> +    }<br>
> +}<br>
> +<br>
> +static int usbredir_write_callback(void *user_data, uint8_t *data, int count)<br>
> +{<br>
> +    SpiceUsbBackendChannel *ch = user_data;<br>
> +    int res;<br>
> +    SPICE_DEBUG("%s ch %p, %d bytes", __FUNCTION__, ch, count);<br>
> +    res = ch->data.write_callback(ch->data.user_data, data, count);<br>
> +    return res;<br>
> +}<br>
> +<br>
> +#if USBREDIR_VERSION >= 0x000701<br>
> +static uint64_t usbredir_buffered_output_size_callback(void *user_data)<br>
> +{<br>
> +    SpiceUsbBackendChannel *ch = user_data;<br>
> +    return ch->data.get_queue_size(ch->data.user_data);<br>
> +}<br>
> +#endif<br>
> +<br>
> +int spice_usb_backend_provide_read_data(SpiceUsbBackendChannel *ch, uint8_t *data, int count)<br>
> +{<br>
<br>
The initial code had a<br>
-    /* No recursion allowed! */<br>
-    g_return_if_fail(priv->read_buf == NULL);<br>
guard which is gone now.<br>
<br>
> +    int res = 0;<br>
> +    if (!ch->read_buf) {<br>
> +        typedef int(*readproc_t)(void *);<br>
> +        readproc_t fn = NULL;<br>
> +        void *param;<br>
> +        ch->read_buf = data;<br>
> +        ch->read_buf_size = count;<br>
> +        if (ch->usbredirhost) {<br>
> +            fn = (readproc_t)usbredirhost_read_guest_data;<br>
> +            param = ch->usbredirhost;<br>
> +        }<br>
> +        res = fn ? fn(param) : USB_REDIR_ERROR_IO;<br>
<br>
Why not this:<br>
if (ch->usbredirhost) {<br>
    res = usbredirhost_read_guest_data(ch->usbredirhost);<br>
} else {<br>
    res = USB_REDIR_ERROR_IO;<br>
}<br>
?<br>
<br>
<br>
<br>
> +        switch (res)<br>
> +        {<br>
> +        case usbredirhost_read_io_error:<br>
> +            res = USB_REDIR_ERROR_IO;<br>
> +            break;<br>
> +        case usbredirhost_read_parse_error:<br>
> +            res = USB_REDIR_ERROR_READ_PARSE;<br>
> +            break;<br>
> +        case usbredirhost_read_device_rejected:<br>
> +            res = USB_REDIR_ERROR_DEV_REJECTED;<br>
> +            break;<br>
> +        case usbredirhost_read_device_lost:<br>
> +            res = USB_REDIR_ERROR_DEV_LOST;<br>
> +            break;<br>
> +        }<br>
> +        SPICE_DEBUG("%s ch %p, %d bytes, res %d", __FUNCTION__, ch, count, res);<br>
> +<br>
> +    } else {<br>
> +        res = USB_REDIR_ERROR_READ_PARSE;<br>
> +        SPICE_DEBUG("%s ch %p, %d bytes, already has data", __FUNCTION__, ch, count);<br>
> +    }<br>
> +    if (ch->rejected) {<br>
> +        ch->rejected = 0;<br>
> +        res = USB_REDIR_ERROR_DEV_REJECTED;<br>
> +    }<br>
> +    return res;<br>
> +}<br>
> +<br>
> +void spice_usb_backend_return_write_data(SpiceUsbBackendChannel *ch, void *data)<br>
<br>
_release_write_data?<br>
<br></blockquote><div><br></div><div><div>Please let me know whether this change is mandatory.</div><div> <br></div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +{<br>
> +    typedef void(*retdata)(void *, void *);<br>
> +    retdata fn = NULL;<br>
> +    void *param;<br>
> +    if (ch->usbredirhost) {<br>
> +        fn = (retdata)usbredirhost_free_write_buffer;<br>
> +        param = ch->usbredirhost;<br>
> +    }<br>
> +    if (fn) {<br>
> +        SPICE_DEBUG("%s ch %p", __FUNCTION__, ch);<br>
> +        fn(param, data);<br>
> +    } else {<br>
> +        SPICE_DEBUG("%s ch %p - NOBODY TO CALL", __FUNCTION__, ch);<br>
> +    }<br>
<br>
Same question as above,<br>
if (ch->usbredirhost) {<br>
    SPICE_DEBUG("%s ch %p", __FUNCTION__, ch);<br>
    usbredirhost_free_write_buffer(ch->usbredirhost);<br>
} else {<br>
    SPICE_DEBUG("%s ch %p - NOBODY TO CALL", __FUNCTION__, ch);<br>
}<br>
is both simpler and easier to read.<br>
<br>
> +}<br>
> +<br>
> +gboolean spice_usb_backend_channel_attach(SpiceUsbBackendChannel *ch, SpiceUsbBackendDevice *dev, const char **msg)<br>
> +{<br>
> +    const char *dummy;<br>
> +    if (!msg) {<br>
> +        msg = &dummy;<br>
> +    }<br>
<br>
It seems you could replace msg with a GError<br>
<br></blockquote><div><div>Please let me know whether this change is mandatory.</div><div><br></div></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +    SPICE_DEBUG("%s >> ch %p, dev %p (was attached %p)", __FUNCTION__, ch, dev, ch->attached);<br>
> +    gboolean b = FALSE;<br>
<br>
Naming...<br>
<br>
<br>
> +    if (!dev) {<br>
> +        return b;<br>
> +    }<br>
> +<br>
> +    if (dev->isLibUsb) {<br>
> +        libusb_device_handle *handle = NULL;<br>
> +        int rc = libusb_open(dev->d.libusb_device, &handle);<br>
> +        b = rc == 0 && handle;<br>
<br>
Do you really need to test both?<br>
<a href="http://libusb.sourceforge.net/api-1.0/group__dev.html#ga8163100afdf933fabed0db7fa81c89d1" rel="noreferrer" target="_blank">http://libusb.sourceforge.net/api-1.0/group__dev.html#ga8163100afdf933fabed0db7fa81c89d1</a><br>
says<br>
"handle: output location for the returned device handle pointer. Only<br>
populated when the return code is 0." so it seems testing 'rc' should be<br>
enough? I guess I would set 'b' here, and just have if (rc == 0 &&<br>
handle != NULL) {<br>
...<br>
}<br>
<br>
> +        if (b) {<br>
> +            rc = usbredirhost_set_device(ch->usbredirhost, handle);<br>
> +            if (rc) {<br>
> +                SPICE_DEBUG("%s ch %p, dev %p usbredirhost error %d", __FUNCTION__, ch, dev, rc);<br>
> +                b = FALSE;<br>
> +            } else {<br>
> +                ch->attached = dev;<br>
> +                dev->attached_to = ch;<br>
> +            }<br>
> +        } else {<br>
> +            const char *desc = spice_usbutil_libusb_strerror(rc);<br>
> +            g_warning("Error libusb_open: %s [%i]", desc, rc);<br>
> +            *msg = desc;<br>
> +        }<br>
> +    }<br>
> +<br>
> +    return b;<br>
> +}<br>
> +<br>
> +void spice_usb_backend_channel_detach(SpiceUsbBackendChannel *ch)<br>
> +{<br>
> +    SPICE_DEBUG("%s >> ch %p, was attached %p", __FUNCTION__, ch, ch->attached);<br>
> +    if (!ch->attached) {<br>
> +        SPICE_DEBUG("%s: nothing to detach", __FUNCTION__);<br>
> +        return;<br>
> +    }<br>
> +    if (ch->usbredirhost) {<br>
> +        // it will call libusb_close internally<br>
> +        usbredirhost_set_device(ch->usbredirhost, NULL);<br>
> +    }<br>
> +    SPICE_DEBUG("%s ch %p, detach done", __FUNCTION__, ch);<br>
> +    ch->attached->attached_to = NULL;<br>
> +    ch->attached = NULL;<br>
> +}<br>
> +<br>
> +SpiceUsbBackendChannel *spice_usb_backend_channel_initialize(<br>
> +    SpiceUsbBackend *be,<br>
> +    const SpiceUsbBackendChannelInitData *init_data)<br>
<br>
Indentation<br>
<br>
> +{<br>
> +    SpiceUsbBackendChannel *ch = g_new0(SpiceUsbBackendChannel, 1);<br>
> +    SPICE_DEBUG("%s >>", __FUNCTION__);<br>
> +    gboolean ok = FALSE;<br>
> +    ch->data = *init_data;<br>
> +    ch->usbredirhost = !be->libusbContext ? NULL :<br>
> +        usbredirhost_open_full(<br>
<br>
Please,<br>
if (be->libusbContext == NULL) {<br>
  ch->usbredirhost = NULL;<br>
  ok = true;<br>
} else {<br>
  ch->usbredirhost = usbredirhost_open_full(...);<br>
  if (ch->usbredirhost != NULL) {<br>
#if USBREDIR_VERSION >= 0x000701<br>
        usbredirhost_set_buffered_output_size_cb(ch->usbredirhost, usbredir_buffered_output_size_callback);<br>
#endif<br>
        ok = true;<br>
  }<br>
}<br>
<br>
<br>
<br>
<br>
> +            be->libusbContext,<br>
> +            NULL,<br>
> +            usbredir_log,<br>
> +            usbredir_read_callback,<br>
> +            usbredir_write_callback,<br>
> +            usbredir_write_flush_callback,<br>
> +            usbredir_alloc_lock,<br>
> +            usbredir_lock_lock,<br>
> +            usbredir_unlock_lock,<br>
> +            usbredir_free_lock,<br>
> +            ch, PACKAGE_STRING,<br>
> +            init_data->debug ? usbredirparser_debug : usbredirparser_warning,<br>
<br>
Why not call spice_util_get_debug() here rather than passing it through<br>
init_data?<br>
<br>
> +            usbredirhost_fl_write_cb_owns_buffer);<br>
> +    ok = be->libusbContext == NULL || ch->usbredirhost != NULL;<br>
> +    if (ch->usbredirhost) {<br>
> +#if USBREDIR_VERSION >= 0x000701<br>
> +        usbredirhost_set_buffered_output_size_cb(ch->usbredirhost, usbredir_buffered_output_size_callback);<br>
> +#endif<br>
> +    }<br>
> +<br>
> +    if (!ok) {<br>
> +        g_free(ch);<br>
> +        ch = NULL;<br>
<br>
The previous code was aborting (g_error()) when ch->usbredirhost was<br>
NULL, now we just return NULL, and apparently don't handle this case in the<br>
caller?<br>
<br>
> +    }<br>
> +    SPICE_DEBUG("%s << %p", __FUNCTION__, ch);<br>
> +    return ch;<br>
> +}<br>
> +<br>
> +void spice_usb_backend_channel_up(SpiceUsbBackendChannel *ch)<br>
> +{<br>
> +    SPICE_DEBUG("%s %p, host %p", __FUNCTION__, ch, ch->usbredirhost);<br>
> +    if (ch->usbredirhost) {<br>
> +        usbredirhost_write_guest_data(ch->usbredirhost);<br>
> +    }<br>
> +}<br>
> +<br>
> +void spice_usb_backend_channel_finalize(SpiceUsbBackendChannel *ch)<br>
<br>
I think I would name it '_free', as _finalize for me is associated with<br>
gobject destruction, which is not what is happening here.<br>
<br></blockquote><div><br></div><div><div>Please let me know whether this change is mandatory.</div><div><br></div></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +{<br>
> +    SPICE_DEBUG("%s >> %p", __FUNCTION__, ch);<br>
> +    if (ch->usbredirhost) {<br>
> +        usbredirhost_close(ch->usbredirhost);<br>
> +    }<br>
> +<br>
> +    if (ch->rules) {<br>
> +        // is it ok to g_free the memory that was allocated by parser?<br>
<br>
Yes, I think you are supposed to free the memory for the rules you got<br>
from filter_filter_func. free() should be used though.<br>
<br>
> +        g_free(ch->rules);<br>
> +    }<br>
> +<br>
> +    g_free(ch);<br>
> +    SPICE_DEBUG("%s << %p", __FUNCTION__, ch);<br>
> +}<br>
> +<br>
> +void spice_usb_backend_channel_get_guest_filter(<br>
> +    SpiceUsbBackendChannel *ch,<br>
> +    const struct usbredirfilter_rule **r,<br>
> +    int *count)<br>
<br>
Indentation<br>
<br>
> +{<br>
> +    int i;<br>
> +    *r = NULL;<br>
> +    *count = 0;<br>
> +    if (ch->usbredirhost) {<br>
> +        usbredirhost_get_guest_filter(ch->usbredirhost, r, count);<br>
> +    }<br>
> +    if (*r == NULL) {<br>
> +        *r = ch->rules;<br>
> +        *count = ch->rules_count;<br>
<br>
Not really clear why we are not returning right away? This is what the<br>
initial code was doing<br>
<br></blockquote><div><br></div><div>If there are guest filters, we print it out.</div><div><div>Please let me know whether removal of this printout is mandatory.<br></div><div> <br></div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +    }<br>
> +<br>
> +    if (*count) {<br>
> +        SPICE_DEBUG("%s ch %p: %d filters", __FUNCTION__, ch, *count);<br>
> +    }<br>
> +    for (i = 0; i < *count; i++) {<br>
> +        const struct usbredirfilter_rule *ra = *r;<br>
> +        SPICE_DEBUG("%s class %d, %X:%X",<br>
> +            ra[i].allow ? "allowed" : "denied", ra[i].device_class,<br>
> +            (uint32_t)ra[i].vendor_id, (uint32_t)ra[i].product_id);<br>
> +    }<br>
> +}<br>
> +<br>
> +#endif // USB_REDIR<br>
> diff --git a/src/usb-backend.h b/src/usb-backend.h<br>
> new file mode 100644<br>
> index 0000000..f6a3604<br>
> --- /dev/null<br>
> +++ b/src/usb-backend.h<br>
> @@ -0,0 +1,97 @@<br>
> +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */<br>
> +/*<br>
> +    Copyright (C) 2018 Red Hat, Inc.<br>
> +<br>
> +    Red Hat Authors:<br>
> +    Yuri Benditovich<<a href="mailto:ybendito@redhat.com" target="_blank">ybendito@redhat.com</a>><br>
> +<br>
> +    This library is free software; you can redistribute it and/or<br>
> +    modify it under the terms of the GNU Lesser General Public<br>
> +    License as published by the Free Software Foundation; either<br>
> +    version 2.1 of the License, or (at your option) any later version.<br>
> +<br>
> +    This library is distributed in the hope that it will be useful,<br>
> +    but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
> +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br>
> +    Lesser General Public License for more details.<br>
> +<br>
> +    You should have received a copy of the GNU Lesser General Public<br>
> +    License along with this library; if not, see <<a href="http://www.gnu.org/licenses/" rel="noreferrer" target="_blank">http://www.gnu.org/licenses/</a>>.<br>
> +*/<br>
> +<br>
> +#ifndef __SPICE_USB_BACKEND_H__<br>
> +#define __SPICE_USB_BACKEND_H__<br>
> +<br>
> +#include <usbredirfilter.h><br>
> +#include "usb-device-manager.h"<br>
> +<br>
> +G_BEGIN_DECLS<br>
> +<br>
> +typedef struct _SpiceUsbBackend SpiceUsbBackend;<br>
> +typedef struct _SpiceUsbBackendDevice SpiceUsbBackendDevice;<br>
> +typedef struct _SpiceUsbBackendChannel SpiceUsbBackendChannel;<br>
> +<br>
> +typedef struct UsbDeviceInformation<br>
> +{<br>
> +    uint16_t bus;<br>
> +    uint16_t address;<br>
> +    uint16_t vid;<br>
> +    uint16_t pid;<br>
> +    uint8_t class;<br>
> +    uint8_t subclass;<br>
> +    uint8_t protocol;<br>
> +    uint8_t isochronous;<br>
> +    uint8_t max_luns;<br>
<br>
max_luns is not used.<br>
<br>
> +} UsbDeviceInformation;<br>
> +<br>
> +typedef struct SpiceUsbBackendChannelInitData<br>
> +{<br>
> +    void *user_data;<br>
> +    void (*log)(void *user_data, const char *msg, gboolean error);<br>
> +    int (*write_callback)(void *user_data, uint8_t *data, int count);<br>
> +    int (*is_channel_ready)(void *user_data);<br>
> +    uint64_t (*get_queue_size)(void *user_data);<br>
> +    gboolean debug;<br>
> +} SpiceUsbBackendChannelInitData;<br>
> +<br>
> +typedef void(*usb_hot_plug_callback)(<br>
> +    void *user_data, SpiceUsbBackendDevice *dev, gboolean added);<br>
<br>
Indentation<br>
<br>
> +<br>
> +enum {<br>
> +    USB_REDIR_ERROR_IO = -1,<br>
> +    USB_REDIR_ERROR_READ_PARSE = -2,<br>
> +    USB_REDIR_ERROR_DEV_REJECTED = -3,<br>
> +    USB_REDIR_ERROR_DEV_LOST = -4,<br>
> +};<br>
> +<br>
> +SpiceUsbBackend *spice_usb_backend_initialize(void);<br>
> +gboolean spice_usb_backend_handle_events(SpiceUsbBackend *);<br>
> +gboolean spice_usb_backend_handle_hotplug(SpiceUsbBackend *, void *user_data, usb_hot_plug_callback proc);<br>
> +void spice_usb_backend_finalize(SpiceUsbBackend *context);<br>
> +// returns NULL-terminated array of SpiceUsbBackendDevice *<br>
> +SpiceUsbBackendDevice **spice_usb_backend_get_device_list(SpiceUsbBackend *backend);<br>
> +gboolean spice_usb_backend_device_is_hub(SpiceUsbBackendDevice *dev);<br>
> +gboolean spice_usb_backend_device_need_thread(SpiceUsbBackendDevice *dev);<br>
> +void spice_usb_backend_free_device_list(SpiceUsbBackendDevice **devlist);<br>
> +void spice_usb_backend_device_acquire(SpiceUsbBackendDevice *dev);<br>
> +void spice_usb_backend_device_release(SpiceUsbBackendDevice *dev);<br>
> +gboolean spice_usb_backend_devices_same(SpiceUsbBackendDevice *dev1, SpiceUsbBackendDevice *dev2);<br>
> +gconstpointer spice_usb_backend_device_get_libdev(SpiceUsbBackendDevice *dev);<br>
> +const UsbDeviceInformation*  spice_usb_backend_device_get_info(SpiceUsbBackendDevice *dev);<br>
   const UsbDeviceInformation *spice_usb_backend_device_get_info<br>
<br>
<br>
> +gboolean  spice_usb_backend_device_get_info_by_address(guint8 bus, guint8 addr, UsbDeviceInformation *info);<br>
<br>
Extra space after gboolean<br>
<br>
> +// returns 0 if the device passes the filter<br>
> +int spice_usb_backend_device_check_filter(SpiceUsbBackendDevice *dev, const struct usbredirfilter_rule *rules, int count);<br>
> +<br>
> +SpiceUsbBackendChannel *spice_usb_backend_channel_initialize(SpiceUsbBackend *context, const SpiceUsbBackendChannelInitData *init_data);<br>
> +// returns 0 for success or error code<br>
> +int spice_usb_backend_provide_read_data(SpiceUsbBackendChannel *ch, uint8_t *data, int count);<br>
> +gboolean spice_usb_backend_channel_attach(SpiceUsbBackendChannel *ch, SpiceUsbBackendDevice *dev, const char **msg);<br>
> +void spice_usb_backend_channel_detach(SpiceUsbBackendChannel *ch);<br>
> +void spice_usb_backend_channel_up(SpiceUsbBackendChannel *ch);<br>
> +void spice_usb_backend_channel_get_guest_filter(SpiceUsbBackendChannel *ch, const struct usbredirfilter_rule  **rules, int *count);<br>
> +void spice_usb_backend_return_write_data(SpiceUsbBackendChannel *ch, void *data);<br>
> +void spice_usb_backend_channel_finalize(SpiceUsbBackendChannel *ch);<br>
> +<br>
> +G_END_DECLS<br>
> +<br>
> +#endif<br>
> -- <br>
> 2.9.4<br>
> <br>
> _______________________________________________<br>
> Spice-devel mailing list<br>
> <a href="mailto:Spice-devel@lists.freedesktop.org" target="_blank">Spice-devel@lists.freedesktop.org</a><br>
> <a href="https://lists.freedesktop.org/mailman/listinfo/spice-devel" rel="noreferrer" target="_blank">https://lists.freedesktop.org/mailman/listinfo/spice-devel</a><br>
</blockquote></div></div>