This is enough to allow CASIO FA-124 to function, tested here with an fx-9750GII graphing calculator. The software must be installed in a 32-bit Windows XP prefix to work around bug 45455, and also requires native mfc42, but works nicely afterwards.
Linux does not make USB devices writable by default, so users will need to set udev rules, or perform some other configuration, for devices which they wish to use through Wine.
The code supports hotplugging in theory, but I ran into a problem where udev rules race with libusb discovery, such that libusb will pick up a device before udev has granted us write permissions. I'm not sure how to resolve this; possibly it's something that can be fixed on the host side.
Zebediah Figura (17): wineusb.sys: New stub driver. wineusb.sys: Implement AddDevice(). wineusb.sys: Implement basic IRP_MJ_PNP requests for the bus FDO. wineusb.sys: Start an event handler thread. wineusb.sys: Create USB devices. wineusb.sys: Implement IRP_MN_QUERY_DEVICE_RELATIONS. wineusb.sys: Implement device and instance IDs. wineusb.sys: Implement hardware IDs. wineusb.sys: Return compatible IDs. wineusb.inf: Add new INF file. wineboot: Install wineusb as a root-enumerated PnP service. wineusb.sys: Implement URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE. wineusb.sys: Stub URB_FUNCTION_SELECT_CONFIGURATION. wineusb.sys: Implement URB_FUNCTION_VENDOR_INTERFACE. wineusb.sys: Implement URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER. wineusb.sys: Implement URB_FUNCTION_ABORT_PIPE. wineusb.sys: Implement URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL.
configure.ac | 13 + dlls/wineusb.sys/Makefile.in | 8 + dlls/wineusb.sys/wineusb.c | 759 ++++++++++++++++++++++++++++++ dlls/wineusb.sys/wineusb.sys.spec | 1 + include/ddk/usbioctl.h | 2 + loader/Makefile.in | 3 +- loader/wine.inf.in | 3 + loader/wineusb.inf.in | 22 + programs/wineboot/wineboot.c | 1 + 9 files changed, 811 insertions(+), 1 deletion(-) create mode 100644 dlls/wineusb.sys/Makefile.in create mode 100644 dlls/wineusb.sys/wineusb.c create mode 100644 dlls/wineusb.sys/wineusb.sys.spec create mode 100644 loader/wineusb.inf.in
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- configure.ac | 13 +++++++ dlls/wineusb.sys/Makefile.in | 8 ++++ dlls/wineusb.sys/wineusb.c | 61 +++++++++++++++++++++++++++++++ dlls/wineusb.sys/wineusb.sys.spec | 1 + loader/wine.inf.in | 2 + 5 files changed, 85 insertions(+) create mode 100644 dlls/wineusb.sys/Makefile.in create mode 100644 dlls/wineusb.sys/wineusb.c create mode 100644 dlls/wineusb.sys/wineusb.sys.spec
diff --git a/configure.ac b/configure.ac index 862745ef62..4f8a3cace9 100644 --- a/configure.ac +++ b/configure.ac @@ -84,6 +84,7 @@ AC_ARG_WITH(sdl, AS_HELP_STRING([--without-sdl],[do not use SDL])) AC_ARG_WITH(tiff, AS_HELP_STRING([--without-tiff],[do not use TIFF])) AC_ARG_WITH(udev, AS_HELP_STRING([--without-udev],[do not use udev (plug and play support)])) AC_ARG_WITH(unwind, AS_HELP_STRING([--without-unwind],[do not use the libunwind library (exception handling)])) +AC_ARG_WITH(usb, AS_HELP_STRING([--without-usb],[do not use the libusb library])) AC_ARG_WITH(v4l2, AS_HELP_STRING([--without-v4l2],[do not use v4l2 (video capture)])) AC_ARG_WITH(vkd3d, AS_HELP_STRING([--without-vkd3d],[do not use vkd3d (Direct3D 12 support)])) AC_ARG_WITH(vulkan, AS_HELP_STRING([--without-vulkan],[do not use Vulkan])) @@ -1474,6 +1475,17 @@ fi WINE_NOTICE_WITH(sane,[test "x$ac_cv_lib_soname_sane" = "x"], [libsane ${notice_platform}development files not found, scanners won't be supported.])
+dnl **** Check for libusb **** +if test "x$with_usb" != "xno" +then + WINE_PACKAGE_FLAGS(USB,[libusb-1.0],[-lusb-1.0],,, + [AC_CHECK_HEADER([libusb.h], + [AC_CHECK_LIB(usb-1.0,libusb_init,[:],[USB_LIBS=""],[$USB_LIBS])], + [USB_LIBS=""])]) +fi +WINE_NOTICE_WITH(usb,[test "$ac_cv_lib_usb_1_0_libusb_init" != "yes"], + [libusb-1.0 ${notice_platform}development files not found, USB devices won't be supported.]) + dnl **** Check for libv4l2 **** if test "x$with_v4l2" != "xno" then @@ -3781,6 +3793,7 @@ WINE_CONFIG_MAKEFILE(dlls/wineps.drv) WINE_CONFIG_MAKEFILE(dlls/wineps16.drv16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/winepulse.drv) WINE_CONFIG_MAKEFILE(dlls/wineqtdecoder) +WINE_CONFIG_MAKEFILE(dlls/wineusb.sys) WINE_CONFIG_MAKEFILE(dlls/winevulkan) WINE_CONFIG_MAKEFILE(dlls/winex11.drv) WINE_CONFIG_MAKEFILE(dlls/wing.dll16,enable_win16) diff --git a/dlls/wineusb.sys/Makefile.in b/dlls/wineusb.sys/Makefile.in new file mode 100644 index 0000000000..bac79f668e --- /dev/null +++ b/dlls/wineusb.sys/Makefile.in @@ -0,0 +1,8 @@ +MODULE = wineusb.sys +IMPORTS = ntoskrnl +EXTRALIBS = $(USB_LIBS) +EXTRAINCL = $(USB_CFLAGS) +EXTRADLLFLAGS = -Wl,--subsystem,native + +C_SRCS = \ + wineusb.c diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c new file mode 100644 index 0000000000..b26f1036d8 --- /dev/null +++ b/dlls/wineusb.sys/wineusb.c @@ -0,0 +1,61 @@ +/* + * USB root device enumerator using libusb + * + * 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 + */ + +#include <assert.h> +#include <stdarg.h> +#include <stdlib.h> +#include <libusb.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winioctl.h" +#include "winternl.h" +#include "ddk/wdm.h" +#include "ddk/usb.h" +#include "ddk/usbioctl.h" +#include "wine/asm.h" +#include "wine/debug.h" +#include "wine/list.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wineusb); + +static void WINAPI driver_unload(DRIVER_OBJECT *driver) +{ + libusb_exit(NULL); +} + +NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, UNICODE_STRING *path) +{ + int err; + + TRACE("driver %p, path %s.\n", driver, debugstr_w(path->Buffer)); + + if ((err = libusb_init(NULL))) + { + ERR("Failed to initialize libusb: %s\n", libusb_strerror(err)); + return STATUS_UNSUCCESSFUL; + } + + driver->DriverUnload = driver_unload; + + return STATUS_SUCCESS; +} diff --git a/dlls/wineusb.sys/wineusb.sys.spec b/dlls/wineusb.sys/wineusb.sys.spec new file mode 100644 index 0000000000..76421d7e35 --- /dev/null +++ b/dlls/wineusb.sys/wineusb.sys.spec @@ -0,0 +1 @@ +# nothing to export diff --git a/loader/wine.inf.in b/loader/wine.inf.in index d321c4c826..e1546713db 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2614,6 +2614,7 @@ HKLM,%CurrentVersion%\Telephony\Country List\998,"SameAreaRule",,"G" 12,,tdi.sys,- 12,,winebus.sys,- 12,,winehid.sys,- +12,,wineusb.sys,- ; skip .NET fake dlls in Wine Mono package 11,,aspnet_regiis.exe,- 11,,ngen.exe,- @@ -2665,6 +2666,7 @@ HKLM,%CurrentVersion%\Telephony\Country List\998,"SameAreaRule",,"G" 12,,tdi.sys 12,,winebus.sys 12,,winehid.sys +12,,wineusb.sys ; skip .NET fake dlls in Wine Mono package 11,,aspnet_regiis.exe,- 11,,ngen.exe,-
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=69639
Your paranoid android.
=== debiant (build log) ===
Task: The win32 Wine build failed
=== debiant (build log) ===
Task: The wow64 Wine build failed
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/wineusb.sys/wineusb.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c index b26f1036d8..6af8a9aaa5 100644 --- a/dlls/wineusb.sys/wineusb.c +++ b/dlls/wineusb.sys/wineusb.c @@ -38,6 +38,27 @@
WINE_DEFAULT_DEBUG_CHANNEL(wineusb);
+static DEVICE_OBJECT *bus_fdo, *bus_pdo; + +static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *pdo) +{ + NTSTATUS ret; + + TRACE("driver %p, pdo %p.\n", driver, pdo); + + if ((ret = IoCreateDevice(driver, 0, NULL, FILE_DEVICE_BUS_EXTENDER, 0, FALSE, &bus_fdo))) + { + ERR("Failed to create FDO, status %#x.\n", ret); + return ret; + } + + IoAttachDeviceToDeviceStack(bus_fdo, pdo); + bus_pdo = pdo; + bus_fdo->Flags &= ~DO_DEVICE_INITIALIZING; + + return STATUS_SUCCESS; +} + static void WINAPI driver_unload(DRIVER_OBJECT *driver) { libusb_exit(NULL); @@ -55,6 +76,7 @@ NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, UNICODE_STRING *path) return STATUS_UNSUCCESSFUL; }
+ driver->DriverExtension->AddDevice = driver_add_device; driver->DriverUnload = driver_unload;
return STATUS_SUCCESS;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=69640
Your paranoid android.
=== debiant (build log) ===
Task: The win32 Wine build failed
=== debiant (build log) ===
Task: The wow64 Wine build failed
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/wineusb.sys/wineusb.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+)
diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c index 6af8a9aaa5..14795f4ec4 100644 --- a/dlls/wineusb.sys/wineusb.c +++ b/dlls/wineusb.sys/wineusb.c @@ -40,6 +40,41 @@ WINE_DEFAULT_DEBUG_CHANNEL(wineusb);
static DEVICE_OBJECT *bus_fdo, *bus_pdo;
+static NTSTATUS fdo_pnp(IRP *irp) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); + NTSTATUS ret; + + TRACE("irp %p, minor function %#x.\n", irp, stack->MinorFunction); + + switch (stack->MinorFunction) + { + case IRP_MN_START_DEVICE: + case IRP_MN_SURPRISE_REMOVAL: + irp->IoStatus.Status = STATUS_SUCCESS; + break; + + case IRP_MN_REMOVE_DEVICE: + irp->IoStatus.Status = STATUS_SUCCESS; + IoSkipCurrentIrpStackLocation(irp); + ret = IoCallDriver(bus_pdo, irp); + IoDetachDevice(bus_pdo); + IoDeleteDevice(bus_fdo); + return ret; + + default: + FIXME("Unhandled minor function %#x.\n", stack->MinorFunction); + } + + IoSkipCurrentIrpStackLocation(irp); + return IoCallDriver(bus_pdo, irp); +} + +static NTSTATUS WINAPI driver_pnp(DEVICE_OBJECT *device, IRP *irp) +{ + return fdo_pnp(irp); +} + static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *pdo) { NTSTATUS ret; @@ -78,6 +113,7 @@ NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, UNICODE_STRING *path)
driver->DriverExtension->AddDevice = driver_add_device; driver->DriverUnload = driver_unload; + driver->MajorFunction[IRP_MJ_PNP] = driver_pnp;
return STATUS_SUCCESS; }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=69641
Your paranoid android.
=== debiant (build log) ===
Task: The win32 Wine build failed
=== debiant (build log) ===
Task: The wow64 Wine build failed
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/wineusb.sys/wineusb.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c index 14795f4ec4..060fb3d0d2 100644 --- a/dlls/wineusb.sys/wineusb.c +++ b/dlls/wineusb.sys/wineusb.c @@ -40,6 +40,25 @@ WINE_DEFAULT_DEBUG_CHANNEL(wineusb);
static DEVICE_OBJECT *bus_fdo, *bus_pdo;
+static BOOL thread_shutdown; +static HANDLE event_thread; + +static DWORD CALLBACK event_thread_proc(void *arg) +{ + int ret; + + TRACE("Starting event thread.\n"); + + while (!thread_shutdown) + { + if ((ret = libusb_handle_events(NULL))) + ERR("Error handling events: %s\n", libusb_strerror(ret)); + } + + TRACE("Shutting down event thread.\n"); + return 0; +} + static NTSTATUS fdo_pnp(IRP *irp) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); @@ -55,6 +74,11 @@ static NTSTATUS fdo_pnp(IRP *irp) break;
case IRP_MN_REMOVE_DEVICE: + thread_shutdown = TRUE; + libusb_interrupt_event_handler(NULL); + WaitForSingleObject(event_thread, INFINITE); + CloseHandle(event_thread); + irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(irp); ret = IoCallDriver(bus_pdo, irp); @@ -111,6 +135,8 @@ NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, UNICODE_STRING *path) return STATUS_UNSUCCESSFUL; }
+ event_thread = CreateThread(NULL, 0, event_thread_proc, NULL, 0, NULL); + driver->DriverExtension->AddDevice = driver_add_device; driver->DriverUnload = driver_unload; driver->MajorFunction[IRP_MJ_PNP] = driver_pnp;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=69642
Your paranoid android.
=== debiant (build log) ===
Task: The win32 Wine build failed
=== debiant (build log) ===
Task: The wow64 Wine build failed
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/wineusb.sys/wineusb.c | 160 ++++++++++++++++++++++++++++++++++++- include/ddk/usbioctl.h | 2 + 2 files changed, 161 insertions(+), 1 deletion(-)
diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c index 060fb3d0d2..22804d8657 100644 --- a/dlls/wineusb.sys/wineusb.c +++ b/dlls/wineusb.sys/wineusb.c @@ -38,11 +38,115 @@
WINE_DEFAULT_DEBUG_CHANNEL(wineusb);
+#define DECLARE_CRITICAL_SECTION(cs) \ + static CRITICAL_SECTION cs; \ + static CRITICAL_SECTION_DEBUG cs##_debug = \ + { 0, 0, &cs, { &cs##_debug.ProcessLocksList, &cs##_debug.ProcessLocksList }, \ + 0, 0, { (DWORD_PTR)(__FILE__ ": " # cs) }}; \ + static CRITICAL_SECTION cs = { &cs##_debug, -1, 0, 0, 0, 0 }; + +DECLARE_CRITICAL_SECTION(wineusb_cs); + +static struct list device_list = LIST_INIT(device_list); + +struct usb_device +{ + struct list entry; + + DEVICE_OBJECT *device_obj; + + libusb_device *libusb_device; + libusb_device_handle *handle; +}; + +static DRIVER_OBJECT *driver_obj; static DEVICE_OBJECT *bus_fdo, *bus_pdo;
+static libusb_hotplug_callback_handle hotplug_cb_handle; + +static void add_usb_device(libusb_device *libusb_device) +{ + static const WCHAR formatW[] = {'\','D','e','v','i','c','e','\','U','S','B','P','D','O','-','%','u',0}; + 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; + NTSTATUS status; + WCHAR name[20]; + 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 ((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); + LeaveCriticalSection(&wineusb_cs); + libusb_close(handle); + return; + } + + device = device_obj->DeviceExtension; + device->device_obj = device_obj; + device->libusb_device = libusb_ref_device(libusb_device); + device->handle = handle; + + EnterCriticalSection(&wineusb_cs); + list_add_tail(&device_list, &device->entry); + LeaveCriticalSection(&wineusb_cs); + + IoInvalidateDeviceRelations(bus_pdo, BusRelations); +} + +static void remove_usb_device(libusb_device *libusb_device) +{ + struct usb_device *device; + + TRACE("Removing device %p.\n", libusb_device); + + EnterCriticalSection(&wineusb_cs); + LIST_FOR_EACH_ENTRY(device, &device_list, struct usb_device, entry) + { + if (device->libusb_device == libusb_device) + { + libusb_unref_device(device->libusb_device); + libusb_close(device->handle); + list_remove(&device->entry); + IoInvalidateDeviceRelations(bus_pdo, BusRelations); + IoDeleteDevice(device->device_obj); + break; + } + } + LeaveCriticalSection(&wineusb_cs); +} + static BOOL thread_shutdown; static HANDLE event_thread;
+static int LIBUSB_CALL hotplug_cb(libusb_context *context, libusb_device *device, + libusb_hotplug_event event, void *user_data) +{ + if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) + add_usb_device(device); + else + remove_usb_device(device); + + return 0; +} + static DWORD CALLBACK event_thread_proc(void *arg) { int ret; @@ -69,22 +173,49 @@ static NTSTATUS fdo_pnp(IRP *irp) switch (stack->MinorFunction) { case IRP_MN_START_DEVICE: + if ((ret = libusb_hotplug_register_callback(NULL, + 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_cb, NULL, &hotplug_cb_handle))) + { + ERR("Failed to register callback: %s\n", libusb_strerror(ret)); + irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + break; + } + irp->IoStatus.Status = STATUS_SUCCESS; + break; + case IRP_MN_SURPRISE_REMOVAL: irp->IoStatus.Status = STATUS_SUCCESS; break;
case IRP_MN_REMOVE_DEVICE: + { + struct usb_device *device, *cursor; + + libusb_hotplug_deregister_callback(NULL, hotplug_cb_handle); thread_shutdown = TRUE; libusb_interrupt_event_handler(NULL); WaitForSingleObject(event_thread, INFINITE); CloseHandle(event_thread);
+ EnterCriticalSection(&wineusb_cs); + LIST_FOR_EACH_ENTRY_SAFE(device, cursor, &device_list, struct usb_device, entry) + { + libusb_unref_device(device->libusb_device); + libusb_close(device->handle); + list_remove(&device->entry); + IoDeleteDevice(device->device_obj); + } + LeaveCriticalSection(&wineusb_cs); + irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(irp); ret = IoCallDriver(bus_pdo, irp); IoDetachDevice(bus_pdo); IoDeleteDevice(bus_fdo); return ret; + }
default: FIXME("Unhandled minor function %#x.\n", stack->MinorFunction); @@ -94,9 +225,34 @@ static NTSTATUS fdo_pnp(IRP *irp) return IoCallDriver(bus_pdo, irp); }
+static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); + NTSTATUS ret = irp->IoStatus.Status; + + TRACE("device_obj %p, irp %p, minor function %#x.\n", device_obj, irp, stack->MinorFunction); + + switch (stack->MinorFunction) + { + case IRP_MN_START_DEVICE: + case IRP_MN_QUERY_CAPABILITIES: + ret = STATUS_SUCCESS; + break; + + default: + FIXME("Unhandled minor function %#x.\n", stack->MinorFunction); + } + + irp->IoStatus.Status = ret; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return ret; +} + static NTSTATUS WINAPI driver_pnp(DEVICE_OBJECT *device, IRP *irp) { - return fdo_pnp(irp); + if (device == bus_fdo) + return fdo_pnp(irp); + return pdo_pnp(device, irp); }
static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *pdo) @@ -129,6 +285,8 @@ NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, UNICODE_STRING *path)
TRACE("driver %p, path %s.\n", driver, debugstr_w(path->Buffer));
+ driver_obj = driver; + if ((err = libusb_init(NULL))) { ERR("Failed to initialize libusb: %s\n", libusb_strerror(err)); diff --git a/include/ddk/usbioctl.h b/include/ddk/usbioctl.h index 003e2b6786..0438dce8bf 100644 --- a/include/ddk/usbioctl.h +++ b/include/ddk/usbioctl.h @@ -19,6 +19,8 @@ #ifndef __DDK_USBIOCTL_H__ #define __DDK_USBIOCTL_H__
+#include "ddk/usbiodef.h" + #define IOCTL_INTERNAL_USB_SUBMIT_URB \ CTL_CODE(FILE_DEVICE_USB, USB_SUBMIT_URB, METHOD_NEITHER, FILE_ANY_ACCESS)
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=69643
Your paranoid android.
=== debiant (build log) ===
Task: The win32 Wine build failed
=== debiant (build log) ===
Task: The wow64 Wine build failed
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/wineusb.sys/wineusb.c | 53 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+)
diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c index 22804d8657..b60d496e9e 100644 --- a/dlls/wineusb.sys/wineusb.c +++ b/dlls/wineusb.sys/wineusb.c @@ -38,6 +38,23 @@
WINE_DEFAULT_DEBUG_CHANNEL(wineusb);
+#if defined(__i386__) && !defined(_WIN32) + +extern void * WINAPI wrap_fastcall_func1( void *func, const void *a ); +__ASM_STDCALL_FUNC( wrap_fastcall_func1, 8, + "popl %ecx\n\t" + "popl %eax\n\t" + "xchgl (%esp),%ecx\n\t" + "jmp *%eax" ); + +#define call_fastcall_func1(func,a) wrap_fastcall_func1(func,a) + +#else + +#define call_fastcall_func1(func,a) func(a) + +#endif + #define DECLARE_CRITICAL_SECTION(cs) \ static CRITICAL_SECTION cs; \ static CRITICAL_SECTION_DEBUG cs##_debug = \ @@ -172,6 +189,42 @@ static NTSTATUS fdo_pnp(IRP *irp)
switch (stack->MinorFunction) { + case IRP_MN_QUERY_DEVICE_RELATIONS: + { + struct usb_device *device; + DEVICE_RELATIONS *devices; + unsigned int i = 0; + + if (stack->Parameters.QueryDeviceRelations.Type != BusRelations) + { + FIXME("Unhandled device relations type %#x.\n", stack->Parameters.QueryDeviceRelations.Type); + break; + } + + EnterCriticalSection(&wineusb_cs); + + if (!(devices = ExAllocatePool(PagedPool, + offsetof(DEVICE_RELATIONS, Objects[list_count(&device_list)])))) + { + LeaveCriticalSection(&wineusb_cs); + irp->IoStatus.Status = STATUS_NO_MEMORY; + break; + } + + LIST_FOR_EACH_ENTRY(device, &device_list, struct usb_device, entry) + { + devices->Objects[i++] = device->device_obj; + call_fastcall_func1(ObfReferenceObject, device->device_obj); + } + + LeaveCriticalSection(&wineusb_cs); + + devices->Count = i; + irp->IoStatus.Information = (ULONG_PTR)devices; + irp->IoStatus.Status = STATUS_SUCCESS; + break; + } + case IRP_MN_START_DEVICE: if ((ret = libusb_hotplug_register_callback(NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=69644
Your paranoid android.
=== debiant (build log) ===
Task: The win32 Wine build failed
=== debiant (build log) ===
Task: The wow64 Wine build failed
On Apr 14, 2020, at 8:28 PM, Zebediah Figura z.figura12@gmail.com wrote:
Linux does not make USB devices writable by default, so users will need to set udev rules, or perform some other configuration, for devices which they wish to use through Wine.
The code supports hotplugging in theory, but I ran into a problem where udev rules race with libusb discovery, such that libusb will pick up a device before udev has granted us write permissions. I'm not sure how to resolve this; possibly it's something that can be fixed on the host side.
I had this problem a few years ago when using hidapi (which uses libudev for discovery). The fix was to check udev_device_get_is_initialized(), and ignore the device until it returns true. Seems like this would have to be added to libusb though, or maybe even udev (should udev really send events for devices it hasn’t initialized?)
https://github.com/signal11/hidapi/issues/217 https://github.com/signal11/hidapi/pull/220
Brendan
On 4/15/20 1:23 AM, Brendan Shanks wrote:
On Apr 14, 2020, at 8:28 PM, Zebediah Figura z.figura12@gmail.com wrote:
Linux does not make USB devices writable by default, so users will need to set udev rules, or perform some other configuration, for devices which they wish to use through Wine.
The code supports hotplugging in theory, but I ran into a problem where udev rules race with libusb discovery, such that libusb will pick up a device before udev has granted us write permissions. I'm not sure how to resolve this; possibly it's something that can be fixed on the host side.
I had this problem a few years ago when using hidapi (which uses libudev for discovery). The fix was to check udev_device_get_is_initialized(), and ignore the device until it returns true. Seems like this would have to be added to libusb though, or maybe even udev (should udev really send events for devices it hasn’t initialized?)
https://github.com/signal11/hidapi/issues/217 https://github.com/signal11/hidapi/pull/220
Brendan
Turns out that libusb actually does this (or something equivalent). It was actually a setup issue on my end—I unwittingly had my rules and those shipped by the distribution configured so that the default permissions (664) overrode my custom permissions at "add" time, but not at "bind" time.