From: Zebediah Figura zfigura@codeweavers.com
Since multiple interfaces can hold onto it, we need to refcount it. In order to do this just refcount the parent device, and close the handle only when the parent device refcount reaches 0. --- dlls/wineusb.sys/unixlib.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-)
diff --git a/dlls/wineusb.sys/unixlib.c b/dlls/wineusb.sys/unixlib.c index f269d3e96fd..4f190319f0f 100644 --- a/dlls/wineusb.sys/unixlib.c +++ b/dlls/wineusb.sys/unixlib.c @@ -45,8 +45,8 @@ struct unix_device struct list entry;
libusb_device_handle *handle; - - bool interface; + struct unix_device *parent; + unsigned int refcount; };
static libusb_hotplug_callback_handle hotplug_cb_handle; @@ -138,7 +138,7 @@ static void add_usb_device(libusb_device *libusb_device) free(unix_device); return; } - unix_device->interface = false; + unix_device->refcount = 1;
pthread_mutex_lock(&device_mutex); list_add_tail(&device_list, &unix_device->entry); @@ -185,8 +185,10 @@ static void add_usb_device(libusb_device *libusb_device) if (!(unix_iface = calloc(1, sizeof(*unix_iface)))) return;
+ ++unix_device->refcount; + unix_iface->refcount = 1; unix_iface->handle = unix_device->handle; - unix_iface->interface = true; + unix_iface->parent = unix_device; pthread_mutex_lock(&device_mutex); list_add_tail(&device_list, &unix_iface->entry); pthread_mutex_unlock(&device_mutex); @@ -548,16 +550,33 @@ static NTSTATUS usb_cancel_transfer(void *args) return STATUS_SUCCESS; }
-static NTSTATUS usb_destroy_device(void *args) +static void decref_device(struct unix_device *device) { - const struct usb_destroy_device_params *params = args; - struct unix_device *device = params->device; - pthread_mutex_lock(&device_mutex); - libusb_close(device->handle); + + if (--device->refcount) + { + pthread_mutex_unlock(&device_mutex); + return; + } + list_remove(&device->entry); + pthread_mutex_unlock(&device_mutex); + + if (device->parent) + decref_device(device->parent); + else + libusb_close(device->handle); free(device); +} + +static NTSTATUS usb_destroy_device(void *args) +{ + const struct usb_destroy_device_params *params = args; + struct unix_device *device = params->device; + + decref_device(device);
return STATUS_SUCCESS; }