From: Zebediah Figura zfigura@codeweavers.com
--- dlls/wineusb.sys/Makefile.in | 2 ++ dlls/wineusb.sys/unixlib.c | 50 ++++++++++++++++++++++++++++++++++++ dlls/wineusb.sys/unixlib.h | 38 +++++++++++++++++++++++++++ dlls/wineusb.sys/wineusb.c | 21 +++++++++++++-- 4 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 dlls/wineusb.sys/unixlib.c create mode 100644 dlls/wineusb.sys/unixlib.h
diff --git a/dlls/wineusb.sys/Makefile.in b/dlls/wineusb.sys/Makefile.in index 8145213fbef..ee3bfffdbeb 100644 --- a/dlls/wineusb.sys/Makefile.in +++ b/dlls/wineusb.sys/Makefile.in @@ -1,5 +1,6 @@ EXTRADEFS = -DWINE_NO_LONG_TYPES MODULE = wineusb.sys +UNIXLIB = wineusb.so IMPORTS = ntoskrnl UNIX_LIBS = $(USB_LIBS) UNIX_CFLAGS = $(USB_CFLAGS) @@ -7,6 +8,7 @@ UNIX_CFLAGS = $(USB_CFLAGS) EXTRADLLFLAGS = -Wl,--subsystem,native -mcygwin
C_SRCS = \ + unixlib.c \ wineusb.c
RC_SRCS = wineusb.rc diff --git a/dlls/wineusb.sys/unixlib.c b/dlls/wineusb.sys/unixlib.c new file mode 100644 index 00000000000..cdc84d98ede --- /dev/null +++ b/dlls/wineusb.sys/unixlib.c @@ -0,0 +1,50 @@ +/* + * libusb backend + * + * Copyright 2020 Zebediah Figura + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include <libusb.h> +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "wine/debug.h" +#include "wine/list.h" + +#include "unixlib.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wineusb); + +static NTSTATUS usb_cancel_transfer(void *args) +{ + const struct usb_cancel_transfer_params *params = args; + int ret; + + if ((ret = libusb_cancel_transfer(params->transfer)) < 0) + ERR("Failed to cancel transfer: %s\n", libusb_strerror(ret)); + + return STATUS_SUCCESS; +} + +const unixlib_entry_t __wine_unix_call_funcs[] = +{ +#define X(name) [unix_ ## name] = name + X(usb_cancel_transfer), +}; diff --git a/dlls/wineusb.sys/unixlib.h b/dlls/wineusb.sys/unixlib.h new file mode 100644 index 00000000000..d046062cd5f --- /dev/null +++ b/dlls/wineusb.sys/unixlib.h @@ -0,0 +1,38 @@ +/* + * wineusb Unix library interface + * + * Copyright 2022 Zebediah Figura for CodeWeavers + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_WINEUSB_UNIXLIB_H +#define __WINE_WINEUSB_UNIXLIB_H + +#include "windef.h" +#include "winternl.h" +#include "wine/unixlib.h" + +struct usb_cancel_transfer_params +{ + void *transfer; +}; + +enum unix_funcs +{ + unix_usb_cancel_transfer, +}; + +#endif diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c index 87669b5c65d..1f3435b67a4 100644 --- a/dlls/wineusb.sys/wineusb.c +++ b/dlls/wineusb.sys/wineusb.c @@ -36,6 +36,8 @@ #include "wine/list.h" #include "wine/unicode.h"
+#include "unixlib.h" + WINE_DEFAULT_DEBUG_CHANNEL(wineusb);
#ifdef __ASM_USE_FASTCALL_WRAPPER @@ -64,6 +66,8 @@ __ASM_STDCALL_FUNC( wrap_fastcall_func1, 8,
DECLARE_CRITICAL_SECTION(wineusb_cs);
+static unixlib_handle_t unix_handle; + static struct list device_list = LIST_INIT(device_list);
struct usb_device @@ -712,9 +716,12 @@ static NTSTATUS usb_submit_urb(struct usb_device *device, IRP *irp) for (entry = mark->Flink; entry != mark; entry = entry->Flink) { IRP *queued_irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry); + struct usb_cancel_transfer_params params = + { + .transfer = queued_irp->Tail.Overlay.DriverContext[0], + };
- if ((ret = libusb_cancel_transfer(queued_irp->Tail.Overlay.DriverContext[0])) < 0) - ERR("Failed to cancel transfer: %s\n", libusb_strerror(ret)); + __wine_unix_call(unix_handle, unix_usb_cancel_transfer, ¶ms); } LeaveCriticalSection(&wineusb_cs);
@@ -930,10 +937,20 @@ static void WINAPI driver_unload(DRIVER_OBJECT *driver)
NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, UNICODE_STRING *path) { + NTSTATUS status; + void *instance; int err;
TRACE("driver %p, path %s.\n", driver, debugstr_w(path->Buffer));
+ RtlPcToFileHeader(DriverEntry, &instance); + if ((status = NtQueryVirtualMemory(GetCurrentProcess(), instance, + MemoryWineUnixFuncs, &unix_handle, sizeof(unix_handle), NULL))) + { + ERR("Failed to initialize Unix library, status %#x.\n", status); + return status; + } + driver_obj = driver;
if ((err = libusb_init(NULL)))
From: Zebediah Figura zfigura@codeweavers.com
These are already cached by libusb, but for convenience we want to cache them on the PE side. --- dlls/wineusb.sys/wineusb.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c index 1f3435b67a4..f5c727fa823 100644 --- a/dlls/wineusb.sys/wineusb.c +++ b/dlls/wineusb.sys/wineusb.c @@ -84,6 +84,8 @@ struct usb_device
uint8_t class, subclass, protocol;
+ uint16_t vendor, product, revision; + libusb_device *libusb_device; libusb_device_handle *handle;
@@ -117,6 +119,9 @@ static void add_usb_interface(struct usb_device *parent, const struct libusb_int device->class = desc->bInterfaceClass; device->subclass = desc->bInterfaceSubClass; device->protocol = desc->bInterfaceProtocol; + device->vendor = parent->vendor; + device->product = parent->product; + device->revision = parent->revision; InitializeListHead(&device->irp_list);
EnterCriticalSection(&wineusb_cs); @@ -173,6 +178,9 @@ static void add_usb_device(libusb_device *libusb_device) device->class = device_desc.bDeviceClass; device->subclass = device_desc.bDeviceSubClass; device->protocol = device_desc.bDeviceProtocol; + device->vendor = device_desc.idVendor; + device->product = device_desc.idProduct; + device->revision = device_desc.bcdDevice;
if (!(ret = libusb_get_active_config_descriptor(libusb_device, &config_desc))) { @@ -423,13 +431,11 @@ static void get_device_id(const struct usb_device *device, struct string_buffer '&','P','I','D','_','%','0','4','X','&','M','I','_','%','0','2','X',0}; static const WCHAR formatW[] = {'U','S','B','\','V','I','D','_','%','0','4','X', '&','P','I','D','_','%','0','4','X',0}; - struct libusb_device_descriptor desc;
- libusb_get_device_descriptor(device->libusb_device, &desc); if (device->parent) - append_id(buffer, interface_formatW, desc.idVendor, desc.idProduct, device->interface_index); + append_id(buffer, interface_formatW, device->vendor, device->product, device->interface_index); else - append_id(buffer, formatW, desc.idVendor, desc.idProduct); + append_id(buffer, formatW, device->vendor, device->product); }
static void get_hardware_ids(const struct usb_device *device, struct string_buffer *buffer) @@ -438,14 +444,11 @@ static void get_hardware_ids(const struct usb_device *device, struct string_buff '&','P','I','D','_','%','0','4','X','&','R','E','V','_','%','0','4','X','&','M','I','_','%','0','2','X',0}; static const WCHAR formatW[] = {'U','S','B','\','V','I','D','_','%','0','4','X', '&','P','I','D','_','%','0','4','X','&','R','E','V','_','%','0','4','X',0}; - struct libusb_device_descriptor desc; - - libusb_get_device_descriptor(device->libusb_device, &desc);
if (device->parent) - append_id(buffer, interface_formatW, desc.idVendor, desc.idProduct, desc.bcdDevice, device->interface_index); + append_id(buffer, interface_formatW, device->vendor, device->product, device->revision, device->interface_index); else - append_id(buffer, formatW, desc.idVendor, desc.idProduct, desc.bcdDevice); + append_id(buffer, formatW, device->vendor, device->product, device->revision); get_device_id(device, buffer); append_id(buffer, emptyW); }
From: Zebediah Figura zfigura@codeweavers.com
Retrieve it from the handle if necessary.
For simplicity. --- dlls/wineusb.sys/wineusb.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-)
diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c index f5c727fa823..59d8bd93fc4 100644 --- a/dlls/wineusb.sys/wineusb.c +++ b/dlls/wineusb.sys/wineusb.c @@ -86,7 +86,6 @@ struct usb_device
uint16_t vendor, product, revision;
- libusb_device *libusb_device; libusb_device_handle *handle;
LIST_ENTRY irp_list; @@ -114,7 +113,6 @@ static void add_usb_interface(struct usb_device *parent, const struct libusb_int device->device_obj = device_obj; device->parent = parent; device->handle = parent->handle; - device->libusb_device = parent->libusb_device; device->interface_index = desc->bInterfaceNumber; device->class = desc->bInterfaceClass; device->subclass = desc->bInterfaceSubClass; @@ -166,7 +164,6 @@ static void add_usb_device(libusb_device *libusb_device)
device = device_obj->DeviceExtension; device->device_obj = device_obj; - device->libusb_device = libusb_ref_device(libusb_device); device->handle = handle; InitializeListHead(&device->irp_list);
@@ -227,7 +224,7 @@ static void remove_usb_device(libusb_device *libusb_device) EnterCriticalSection(&wineusb_cs); LIST_FOR_EACH_ENTRY(device, &device_list, struct usb_device, entry) { - if (device->libusb_device == libusb_device) + if (libusb_get_device(device->handle) == libusb_device) { if (!device->removed) { @@ -364,10 +361,7 @@ static NTSTATUS fdo_pnp(IRP *irp) { assert(!device->removed); if (!device->parent) - { - libusb_unref_device(device->libusb_device); libusb_close(device->handle); - } list_remove(&device->entry); IoDeleteDevice(device->device_obj); } @@ -564,10 +558,7 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp) remove_pending_irps(device);
if (!device->parent) - { - libusb_unref_device(device->libusb_device); libusb_close(device->handle); - }
IoDeleteDevice(device->device_obj); ret = STATUS_SUCCESS;
From: Zebediah Figura zfigura@codeweavers.com
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 <assert.h> #include <stdarg.h> #include <stdlib.h> +#include <pthread.h> #include <libusb.h>
#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)