From: Zebediah Figura Subject: [PATCH 4/4] wineusb.sys: Create a separate unix_device struct to wrap the libusb device handle. Message-Id: Date: Fri, 01 Jul 2022 05:55:04 +0000 In-Reply-To: References: From: Zebediah Figura Keep unix_device objects in a separate list. --- dlls/wineusb.sys/Makefile.in | 2 +- dlls/wineusb.sys/wineusb.c | 100 +++++++++++++++++++++++++++-------- 2 files changed, 78 insertions(+), 24 deletions(-) diff --git a/dlls/wineusb.sys/Makefile.in b/dlls/wineusb.sys/Makefile.in index ee3bfffdbeb..5547200596e 100644 --- a/dlls/wineusb.sys/Makefile.in +++ b/dlls/wineusb.sys/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DWINE_NO_LONG_TYPES MODULE = wineusb.sys UNIXLIB = wineusb.so IMPORTS = ntoskrnl -UNIX_LIBS = $(USB_LIBS) +UNIX_LIBS = $(USB_LIBS) $(PTHREAD_LIBS) UNIX_CFLAGS = $(USB_CFLAGS) EXTRADLLFLAGS = -Wl,--subsystem,native -mcygwin diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c index 59d8bd93fc4..cfa88616a8f 100644 --- a/dlls/wineusb.sys/wineusb.c +++ b/dlls/wineusb.sys/wineusb.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "ntstatus.h" @@ -68,8 +69,18 @@ DECLARE_CRITICAL_SECTION(wineusb_cs); static unixlib_handle_t unix_handle; +static pthread_mutex_t unix_device_mutex = PTHREAD_MUTEX_INITIALIZER; + +static struct list unix_device_list = LIST_INIT(unix_device_list); static struct list device_list = LIST_INIT(device_list); +struct unix_device +{ + struct list entry; + + libusb_device_handle *handle; +}; + struct usb_device { struct list entry; @@ -86,7 +97,7 @@ struct usb_device uint16_t vendor, product, revision; - libusb_device_handle *handle; + struct unix_device *unix_device; LIST_ENTRY irp_list; }; @@ -96,6 +107,15 @@ static DEVICE_OBJECT *bus_fdo, *bus_pdo; static libusb_hotplug_callback_handle hotplug_cb_handle; +static void destroy_unix_device(struct unix_device *unix_device) +{ + pthread_mutex_lock(&unix_device_mutex); + libusb_close(unix_device->handle); + list_remove(&unix_device->entry); + pthread_mutex_unlock(&unix_device_mutex); + free(unix_device); +} + static void add_usb_interface(struct usb_device *parent, const struct libusb_interface_descriptor *desc) { struct usb_device *device; @@ -112,7 +132,7 @@ static void add_usb_interface(struct usb_device *parent, const struct libusb_int device = device_obj->DeviceExtension; device->device_obj = device_obj; device->parent = parent; - device->handle = parent->handle; + device->unix_device = parent->unix_device; device->interface_index = desc->bInterfaceNumber; device->class = desc->bInterfaceClass; device->subclass = desc->bInterfaceSubClass; @@ -127,13 +147,13 @@ static void add_usb_interface(struct usb_device *parent, const struct libusb_int LeaveCriticalSection(&wineusb_cs); } -static void add_usb_device(libusb_device *libusb_device) +static void add_unix_device(struct unix_device *unix_device) { static const WCHAR formatW[] = {'\\','D','e','v','i','c','e','\\','U','S','B','P','D','O','-','%','u',0}; + libusb_device *libusb_device = libusb_get_device(unix_device->handle); struct libusb_config_descriptor *config_desc; struct libusb_device_descriptor device_desc; static unsigned int name_index; - libusb_device_handle *handle; struct usb_device *device; DEVICE_OBJECT *device_obj; UNICODE_STRING string; @@ -143,28 +163,21 @@ static void add_usb_device(libusb_device *libusb_device) libusb_get_device_descriptor(libusb_device, &device_desc); - TRACE("Adding new device %p, vendor %04x, product %04x.\n", libusb_device, + TRACE("Adding new device %p, vendor %04x, product %04x.\n", unix_device, device_desc.idVendor, device_desc.idProduct); - if ((ret = libusb_open(libusb_device, &handle))) - { - WARN("Failed to open device: %s\n", libusb_strerror(ret)); - return; - } - sprintfW(name, formatW, name_index++); RtlInitUnicodeString(&string, name); if ((status = IoCreateDevice(driver_obj, sizeof(*device), &string, FILE_DEVICE_USB, 0, FALSE, &device_obj))) { ERR("Failed to create device, status %#x.\n", status); - libusb_close(handle); return; } device = device_obj->DeviceExtension; device->device_obj = device_obj; - device->handle = handle; + device->unix_device = unix_device; InitializeListHead(&device->irp_list); EnterCriticalSection(&wineusb_cs); @@ -215,16 +228,43 @@ static void add_usb_device(libusb_device *libusb_device) IoInvalidateDeviceRelations(bus_pdo, BusRelations); } -static void remove_usb_device(libusb_device *libusb_device) +static void add_usb_device(libusb_device *libusb_device) +{ + struct libusb_device_descriptor device_desc; + struct unix_device *unix_device; + int ret; + + libusb_get_device_descriptor(libusb_device, &device_desc); + + TRACE("Adding new device %p, vendor %04x, product %04x.\n", libusb_device, + device_desc.idVendor, device_desc.idProduct); + + if (!(unix_device = calloc(1, sizeof(*unix_device)))) + return; + + if ((ret = libusb_open(libusb_device, &unix_device->handle))) + { + WARN("Failed to open device: %s\n", libusb_strerror(ret)); + free(unix_device); + return; + } + pthread_mutex_lock(&unix_device_mutex); + list_add_tail(&unix_device_list, &unix_device->entry); + pthread_mutex_unlock(&unix_device_mutex); + + add_unix_device(unix_device); +} + +static void remove_unix_device(struct unix_device *unix_device) { struct usb_device *device; - TRACE("Removing device %p.\n", libusb_device); + TRACE("Removing device %p.\n", unix_device); EnterCriticalSection(&wineusb_cs); LIST_FOR_EACH_ENTRY(device, &device_list, struct usb_device, entry) { - if (libusb_get_device(device->handle) == libusb_device) + if (device->unix_device == unix_device) { if (!device->removed) { @@ -239,6 +279,19 @@ static void remove_usb_device(libusb_device *libusb_device) IoInvalidateDeviceRelations(bus_pdo, BusRelations); } +static void remove_usb_device(libusb_device *libusb_device) +{ + struct unix_device *unix_device; + + TRACE("Removing device %p.\n", libusb_device); + + LIST_FOR_EACH_ENTRY(unix_device, &unix_device_list, struct unix_device, entry) + { + if (libusb_get_device(unix_device->handle) == libusb_device) + remove_unix_device(unix_device); + } +} + static BOOL thread_shutdown; static HANDLE event_thread; @@ -361,7 +414,7 @@ static NTSTATUS fdo_pnp(IRP *irp) { assert(!device->removed); if (!device->parent) - libusb_close(device->handle); + destroy_unix_device(device->unix_device); list_remove(&device->entry); IoDeleteDevice(device->device_obj); } @@ -558,7 +611,7 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp) remove_pending_irps(device); if (!device->parent) - libusb_close(device->handle); + destroy_unix_device(device->unix_device); IoDeleteDevice(device->device_obj); ret = STATUS_SUCCESS; @@ -691,6 +744,7 @@ static struct pipe get_pipe(HANDLE handle) static NTSTATUS usb_submit_urb(struct usb_device *device, IRP *irp) { URB *urb = IoGetCurrentIrpStackLocation(irp)->Parameters.Others.Argument1; + libusb_device_handle *handle = device->unix_device->handle; struct libusb_transfer *transfer; int ret; @@ -727,7 +781,7 @@ static NTSTATUS usb_submit_urb(struct usb_device *device, IRP *irp) struct _URB_PIPE_REQUEST *req = &urb->UrbPipeRequest; struct pipe pipe = get_pipe(req->PipeHandle); - if ((ret = libusb_clear_halt(device->handle, pipe.endpoint)) < 0) + if ((ret = libusb_clear_halt(handle, pipe.endpoint)) < 0) ERR("Failed to clear halt: %s\n", libusb_strerror(ret)); return STATUS_SUCCESS; @@ -746,12 +800,12 @@ static NTSTATUS usb_submit_urb(struct usb_device *device, IRP *irp) if (pipe.type == UsbdPipeTypeBulk) { - libusb_fill_bulk_transfer(transfer, device->handle, pipe.endpoint, + libusb_fill_bulk_transfer(transfer, handle, pipe.endpoint, req->TransferBuffer, req->TransferBufferLength, transfer_cb, irp, 0); } else if (pipe.type == UsbdPipeTypeInterrupt) { - libusb_fill_interrupt_transfer(transfer, device->handle, pipe.endpoint, + libusb_fill_interrupt_transfer(transfer, handle, pipe.endpoint, req->TransferBuffer, req->TransferBufferLength, transfer_cb, irp, 0); } else @@ -792,7 +846,7 @@ static NTSTATUS usb_submit_urb(struct usb_device *device, IRP *irp) LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, LIBUSB_REQUEST_GET_DESCRIPTOR, (req->DescriptorType << 8) | req->Index, req->LanguageId, req->TransferBufferLength); - libusb_fill_control_transfer(transfer, device->handle, buffer, transfer_cb, irp, 0); + libusb_fill_control_transfer(transfer, handle, buffer, transfer_cb, irp, 0); transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; ret = libusb_submit_transfer(transfer); if (ret < 0) @@ -849,7 +903,7 @@ static NTSTATUS usb_submit_urb(struct usb_device *device, IRP *irp) req->Value, req->Index, req->TransferBufferLength); if (!(req->TransferFlags & USBD_TRANSFER_DIRECTION_IN)) memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, req->TransferBuffer, req->TransferBufferLength); - libusb_fill_control_transfer(transfer, device->handle, buffer, transfer_cb, irp, 0); + libusb_fill_control_transfer(transfer, handle, buffer, transfer_cb, irp, 0); transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; ret = libusb_submit_transfer(transfer); if (ret < 0) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/356