Zebediah Figura : wineusb.sys: Create USB devices.
Alexandre Julliard
julliard at winehq.org
Thu Apr 16 16:45:14 CDT 2020
Module: wine
Branch: master
Commit: b0c2e5c6ce0e116e33435db85c051d8feb07ecb2
URL: https://source.winehq.org/git/wine.git/?a=commit;h=b0c2e5c6ce0e116e33435db85c051d8feb07ecb2
Author: Zebediah Figura <z.figura12 at gmail.com>
Date: Wed Apr 15 09:43:22 2020 -0500
wineusb.sys: Create USB devices.
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
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)
More information about the wine-cvs
mailing list