wineusb.sys: Create USB devices.
Signed-off-by: Zebediah Figura <z.figura12@gmail.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
eb8cb9e0cf
commit
b0c2e5c6ce
2 changed files with 161 additions and 1 deletions
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue