[Wine-devel] [eterhack branch] support of native Windows drivers for USB tokens (bug 1660)

Alexander Morozov =?iso-8859-1?q?amorozov_=CE=C1_etersoft=2Eru?=
Ср Июн 11 21:21:08 MSD 2008


----------- следующая часть -----------
diff --git a/Makefile.in b/Makefile.in
index b372ec8..fb05bc5 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -459,6 +459,7 @@ ALL_MAKEFILES = \
 	dlls/url/Makefile \
 	dlls/urlmon/Makefile \
 	dlls/urlmon/tests/Makefile \
+	dlls/usbd.sys/Makefile \
 	dlls/user32/Makefile \
 	dlls/user32/tests/Makefile \
 	dlls/userenv/Makefile \
@@ -493,6 +494,7 @@ ALL_MAKEFILES = \
 	dlls/wineoss.drv/Makefile \
 	dlls/wineps.drv/Makefile \
 	dlls/winequartz.drv/Makefile \
+	dlls/wineusbhub/Makefile \
 	dlls/winex11.drv/Makefile \
 	dlls/wing32/Makefile \
 	dlls/winhttp/Makefile \
@@ -564,6 +566,7 @@ ALL_MAKEFILES = \
 	programs/winemine/Makefile \
 	programs/winepath/Makefile \
 	programs/winetest/Makefile \
+	programs/wineusb/Makefile \
 	programs/winevdm/Makefile \
 	programs/winhlp32/Makefile \
 	programs/winver/Makefile \
@@ -888,6 +891,7 @@ dlls/unicows/Makefile: dlls/unicows/Makefile.in dlls/Makedll.rules
 dlls/url/Makefile: dlls/url/Makefile.in dlls/Makedll.rules
 dlls/urlmon/Makefile: dlls/urlmon/Makefile.in dlls/Makedll.rules
 dlls/urlmon/tests/Makefile: dlls/urlmon/tests/Makefile.in dlls/Maketest.rules
+dlls/usbd.sys/Makefile: dlls/usbd.sys/Makefile.in dlls/Makedll.rules
 dlls/user32/Makefile: dlls/user32/Makefile.in dlls/Makedll.rules
 dlls/user32/tests/Makefile: dlls/user32/tests/Makefile.in dlls/Maketest.rules
 dlls/userenv/Makefile: dlls/userenv/Makefile.in dlls/Makedll.rules
@@ -921,6 +925,7 @@ dlls/winenas.drv/Makefile: dlls/winenas.drv/Makefile.in dlls/Makedll.rules
 dlls/wineoss.drv/Makefile: dlls/wineoss.drv/Makefile.in dlls/Makedll.rules
 dlls/wineps.drv/Makefile: dlls/wineps.drv/Makefile.in dlls/Makedll.rules
 dlls/winequartz.drv/Makefile: dlls/winequartz.drv/Makefile.in dlls/Makedll.rules
+dlls/wineusbhub/Makefile: dlls/wineusbhub/Makefile.in dlls/Makedll.rules
 dlls/winex11.drv/Makefile: dlls/winex11.drv/Makefile.in dlls/Makedll.rules
 dlls/wing32/Makefile: dlls/wing32/Makefile.in dlls/Makedll.rules
 dlls/winhttp/Makefile: dlls/winhttp/Makefile.in dlls/Makedll.rules
@@ -991,6 +996,7 @@ programs/winemenubuilder/Makefile: programs/winemenubuilder/Makefile.in programs
 programs/winemine/Makefile: programs/winemine/Makefile.in programs/Makeprog.rules
 programs/winepath/Makefile: programs/winepath/Makefile.in programs/Makeprog.rules
 programs/winetest/Makefile: programs/winetest/Makefile.in programs/Makeprog.rules
+programs/wineusb/Makefile: programs/wineusb/Makefile.in programs/Makeprog.rules
 programs/winevdm/Makefile: programs/winevdm/Makefile.in programs/Makeprog.rules
 programs/winhlp32/Makefile: programs/winhlp32/Makefile.in programs/Makeprog.rules
 programs/winver/Makefile: programs/winver/Makefile.in programs/Makeprog.rules
diff --git a/configure b/configure
index 550be0a..d00c617 100755
--- a/configure
+++ b/configure
@@ -22853,6 +22853,8 @@ ac_config_files="$ac_config_files dlls/urlmon/Makefile"
 
 ac_config_files="$ac_config_files dlls/urlmon/tests/Makefile"
 
+ac_config_files="$ac_config_files dlls/usbd.sys/Makefile"
+
 ac_config_files="$ac_config_files dlls/user32/Makefile"
 
 ac_config_files="$ac_config_files dlls/user32/tests/Makefile"
@@ -22921,6 +22923,8 @@ ac_config_files="$ac_config_files dlls/wineps.drv/Makefile"
 
 ac_config_files="$ac_config_files dlls/winequartz.drv/Makefile"
 
+ac_config_files="$ac_config_files dlls/wineusbhub/Makefile"
+
 ac_config_files="$ac_config_files dlls/winex11.drv/Makefile"
 
 ac_config_files="$ac_config_files dlls/wing32/Makefile"
@@ -23063,6 +23067,8 @@ ac_config_files="$ac_config_files programs/winepath/Makefile"
 
 ac_config_files="$ac_config_files programs/winetest/Makefile"
 
+ac_config_files="$ac_config_files programs/wineusb/Makefile"
+
 ac_config_files="$ac_config_files programs/winevdm/Makefile"
 
 ac_config_files="$ac_config_files programs/winhlp32/Makefile"
@@ -23955,6 +23961,7 @@ do
     "dlls/url/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/url/Makefile" ;;
     "dlls/urlmon/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/urlmon/Makefile" ;;
     "dlls/urlmon/tests/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/urlmon/tests/Makefile" ;;
+    "dlls/usbd.sys/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/usbd.sys/Makefile" ;;
     "dlls/user32/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/user32/Makefile" ;;
     "dlls/user32/tests/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/user32/tests/Makefile" ;;
     "dlls/userenv/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/userenv/Makefile" ;;
@@ -23989,6 +23996,7 @@ do
     "dlls/wineoss.drv/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/wineoss.drv/Makefile" ;;
     "dlls/wineps.drv/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/wineps.drv/Makefile" ;;
     "dlls/winequartz.drv/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/winequartz.drv/Makefile" ;;
+    "dlls/wineusbhub/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/wineusbhub/Makefile" ;;
     "dlls/winex11.drv/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/winex11.drv/Makefile" ;;
     "dlls/wing32/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/wing32/Makefile" ;;
     "dlls/winhttp/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/winhttp/Makefile" ;;
@@ -24060,6 +24068,7 @@ do
     "programs/winemine/Makefile") CONFIG_FILES="$CONFIG_FILES programs/winemine/Makefile" ;;
     "programs/winepath/Makefile") CONFIG_FILES="$CONFIG_FILES programs/winepath/Makefile" ;;
     "programs/winetest/Makefile") CONFIG_FILES="$CONFIG_FILES programs/winetest/Makefile" ;;
+    "programs/wineusb/Makefile") CONFIG_FILES="$CONFIG_FILES programs/wineusb/Makefile" ;;
     "programs/winevdm/Makefile") CONFIG_FILES="$CONFIG_FILES programs/winevdm/Makefile" ;;
     "programs/winhlp32/Makefile") CONFIG_FILES="$CONFIG_FILES programs/winhlp32/Makefile" ;;
     "programs/winver/Makefile") CONFIG_FILES="$CONFIG_FILES programs/winver/Makefile" ;;
diff --git a/configure.ac b/configure.ac
index 10399e7..caa61de 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1975,6 +1975,7 @@ AC_CONFIG_FILES([dlls/unicows/Makefile])
 AC_CONFIG_FILES([dlls/url/Makefile])
 AC_CONFIG_FILES([dlls/urlmon/Makefile])
 AC_CONFIG_FILES([dlls/urlmon/tests/Makefile])
+AC_CONFIG_FILES([dlls/usbd.sys/Makefile])
 AC_CONFIG_FILES([dlls/user32/Makefile])
 AC_CONFIG_FILES([dlls/user32/tests/Makefile])
 AC_CONFIG_FILES([dlls/userenv/Makefile])
@@ -2009,6 +2010,7 @@ AC_CONFIG_FILES([dlls/winenas.drv/Makefile])
 AC_CONFIG_FILES([dlls/wineoss.drv/Makefile])
 AC_CONFIG_FILES([dlls/wineps.drv/Makefile])
 AC_CONFIG_FILES([dlls/winequartz.drv/Makefile])
+AC_CONFIG_FILES([dlls/wineusbhub/Makefile])
 AC_CONFIG_FILES([dlls/winex11.drv/Makefile])
 AC_CONFIG_FILES([dlls/wing32/Makefile])
 AC_CONFIG_FILES([dlls/winhttp/Makefile])
@@ -2080,6 +2082,7 @@ AC_CONFIG_FILES([programs/winemenubuilder/Makefile])
 AC_CONFIG_FILES([programs/winemine/Makefile])
 AC_CONFIG_FILES([programs/winepath/Makefile])
 AC_CONFIG_FILES([programs/winetest/Makefile])
+AC_CONFIG_FILES([programs/wineusb/Makefile])
 AC_CONFIG_FILES([programs/winevdm/Makefile])
 AC_CONFIG_FILES([programs/winhlp32/Makefile])
 AC_CONFIG_FILES([programs/winver/Makefile])
diff --git a/dlls/Makefile.in b/dlls/Makefile.in
index c4f1872..4d05a45 100644
--- a/dlls/Makefile.in
+++ b/dlls/Makefile.in
@@ -232,6 +232,7 @@ BASEDIRS = \
 	unicows \
 	url \
 	urlmon \
+	usbd.sys \
 	user32 \
 	userenv \
 	usp10 \
@@ -258,6 +259,7 @@ BASEDIRS = \
 	winenas.drv \
 	wineoss.drv \
 	wineps.drv \
+	wineusbhub \
 	wing32 \
 	winhttp \
 	wininet \
@@ -660,6 +662,7 @@ IMPORT_LIBS = \
 	version/libversion.$(IMPLIBEXT) \
 	wined3d/libwined3d.$(IMPLIBEXT) \
 	winedos/libwinedos.$(IMPLIBEXT) \
+	wineusbhub/libwineusbhub.$(IMPLIBEXT) \
 	wininet/libwininet.$(IMPLIBEXT) \
 	winmm/libwinmm.$(IMPLIBEXT) \
 	winnls32/libwinnls32.$(IMPLIBEXT) \
@@ -1038,6 +1041,9 @@ wined3d/libwined3d.$(IMPLIBEXT): wined3d/wined3d.spec $(WINEBUILD)
 winedos/libwinedos.$(IMPLIBEXT): winedos/winedos.spec $(WINEBUILD)
 	@cd winedos && $(MAKE) libwinedos.$(IMPLIBEXT)
 
+wineusbhub/libwineusbhub.$(IMPLIBEXT): wineusbhub/wineusbhub.spec $(WINEBUILD)
+	@cd wineusbhub && $(MAKE) libwineusbhub.$(IMPLIBEXT)
+
 wininet/libwininet.$(IMPLIBEXT): wininet/wininet.spec $(WINEBUILD)
 	@cd wininet && $(MAKE) libwininet.$(IMPLIBEXT)
 
diff --git a/dlls/hal/hal.c b/dlls/hal/hal.c
index 0b64809..253e01f 100644
--- a/dlls/hal/hal.c
+++ b/dlls/hal/hal.c
@@ -106,3 +106,9 @@ ULONG WINAPI HalGetBusData(BUS_DATA_TYPE BusDataType, ULONG BusNumber, ULONG Slo
     /* Claim that there is no such bus */
     return 0;
 }
+
+KIRQL WINAPI KeGetCurrentIrql(void)
+{
+    FIXME( "stub!\n" );
+    return 0;
+}
diff --git a/dlls/hal/hal.spec b/dlls/hal/hal.spec
index 5afbee0..84945eb 100644
--- a/dlls/hal/hal.spec
+++ b/dlls/hal/hal.spec
@@ -70,7 +70,7 @@
 @ stub KdComPortInUse
 @ stub KeAcquireSpinLock
 @ stub KeFlushWriteBuffer
-@ stub KeGetCurrentIrql
+@ stdcall KeGetCurrentIrql()
 @ stub KeLowerIrql
 @ stub KeQueryPerformanceCounter
 @ stub KeRaiseIrql
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index cda3476..0dc8be3 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -31,9 +31,11 @@
 #include "windef.h"
 #include "winternl.h"
 #include "excpt.h"
-#include "ddk/wdm.h"
+#include "winioctl.h"
+#include "ddk/ntddk.h"
 #include "wine/unicode.h"
 #include "wine/server.h"
+#include "wine/list.h"
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(ntoskrnl);
@@ -54,6 +56,14 @@ KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable[4];
 
 typedef void (WINAPI *PCREATE_PROCESS_NOTIFY_ROUTINE)(HANDLE,HANDLE,BOOLEAN);
 
+static struct list Irps = LIST_INIT(Irps);
+
+struct IrpInstance
+{
+    struct list entry;
+    IRP *irp;
+};
+
 #ifdef __i386__
 #define DEFINE_FASTCALL1_ENTRYPOINT( name ) \
     __ASM_GLOBAL_FUNC( name, \
@@ -125,55 +135,81 @@ static LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs )
 static NTSTATUS process_ioctl( DEVICE_OBJECT *device, ULONG code, void *in_buff, ULONG in_size,
                                void *out_buff, ULONG *out_size )
 {
-    IRP irp;
+    PIRP irp;
     MDL mdl;
-    IO_STACK_LOCATION irpsp;
+    PIO_STACK_LOCATION irpsp;
     PDRIVER_DISPATCH dispatch = device->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL];
     NTSTATUS status;
     LARGE_INTEGER count;
+    CHAR *buf = NULL;
 
     TRACE( "ioctl %x device %p in_size %u out_size %u\n", code, device, in_size, *out_size );
 
-    /* so we can spot things that we should initialize */
-    memset( &irp, 0x55, sizeof(irp) );
-    memset( &irpsp, 0x66, sizeof(irpsp) );
-    memset( &mdl, 0x77, sizeof(mdl) );
+    irp = IoAllocateIrp( device->StackSize, FALSE );
+    if (irp == NULL)
+        return STATUS_UNSUCCESSFUL;
 
-    irp.RequestorMode = UserMode;
-    irp.AssociatedIrp.SystemBuffer = in_buff;
-    irp.UserBuffer = out_buff;
-    irp.MdlAddress = &mdl;
-    irp.Tail.Overlay.s.u.CurrentStackLocation = &irpsp;
+    --irp->CurrentLocation;
+    irpsp = --irp->Tail.Overlay.s.u.CurrentStackLocation;
 
-    irpsp.MajorFunction = IRP_MJ_DEVICE_CONTROL;
-    irpsp.Parameters.DeviceIoControl.OutputBufferLength = *out_size;
-    irpsp.Parameters.DeviceIoControl.InputBufferLength = in_size;
-    irpsp.Parameters.DeviceIoControl.IoControlCode = code;
-    irpsp.Parameters.DeviceIoControl.Type3InputBuffer = in_buff;
-    irpsp.DeviceObject = device;
-
-    mdl.Next = NULL;
-    mdl.Size = 0;
-    mdl.StartVa = out_buff;
-    mdl.ByteCount = *out_size;
-    mdl.ByteOffset = 0;
+    switch (code & 3)
+    {
+    case METHOD_BUFFERED:
+        buf = ExAllocatePool( NonPagedPool, (*out_size > in_size) ? *out_size : in_size );
+        if (buf == NULL)
+        {
+            IoFreeIrp( irp );
+            return STATUS_UNSUCCESSFUL;
+        }
+        memcpy( buf, in_buff, in_size );
+        irp->AssociatedIrp.SystemBuffer = buf;
+        irp->UserBuffer = out_buff;
+        break;
+    case METHOD_NEITHER:
+        irpsp->Parameters.DeviceIoControl.Type3InputBuffer = in_buff;
+        irp->UserBuffer = out_buff;
+        break;
+    default:
+        irp->AssociatedIrp.SystemBuffer = in_buff;
+        irp->MdlAddress = &mdl;
+        mdl.Next = NULL;
+        mdl.Size = 0;
+        mdl.StartVa = out_buff;
+        mdl.ByteCount = *out_size;
+        mdl.ByteOffset = 0;
+    }
 
-    device->CurrentIrp = &irp;
+    irp->RequestorMode = UserMode;
+    irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
+    irpsp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
+    irpsp->Parameters.DeviceIoControl.OutputBufferLength = *out_size;
+    irpsp->Parameters.DeviceIoControl.InputBufferLength = in_size;
+    irpsp->Parameters.DeviceIoControl.IoControlCode = code;
+    irpsp->DeviceObject = device;
+    device->CurrentIrp = irp;
 
     KeQueryTickCount( &count );  /* update the global KeTickCount */
 
     if (TRACE_ON(relay))
         DPRINTF( "%04x:Call driver dispatch %p (device=%p,irp=%p)\n",
-                 GetCurrentThreadId(), dispatch, device, &irp );
+                 GetCurrentThreadId(), dispatch, device, irp );
 
-    status = dispatch( device, &irp );
+    status = dispatch( device, irp );
 
     if (TRACE_ON(relay))
         DPRINTF( "%04x:Ret  driver dispatch %p (device=%p,irp=%p) retval=%08x\n",
-                 GetCurrentThreadId(), dispatch, device, &irp, status );
+                 GetCurrentThreadId(), dispatch, device, irp, status );
 
-    *out_size = (irp.IoStatus.u.Status >= 0) ? irp.IoStatus.Information : 0;
-    return irp.IoStatus.u.Status;
+    status = irp->IoStatus.u.Status;
+    *out_size = (status >= 0) ? irp->IoStatus.Information : 0;
+    IoFreeIrp( irp );
+    if (buf != NULL)
+    {
+        memcpy( out_buff, buf, *out_size );
+        ExFreePool( buf );
+    }
+
+    return status;
 }
 
 
@@ -248,6 +284,71 @@ NTSTATUS wine_ntoskrnl_main_loop( HANDLE stop_event )
 }
 
 /***********************************************************************
+ *           IoAcquireCancelSpinLock  (NTOSKRNL.EXE.@)
+ */
+void WINAPI IoAcquireCancelSpinLock( PKIRQL Irql )
+{
+    FIXME( "%p\n", Irql );
+}
+
+/***********************************************************************
+ *           IoReleaseCancelSpinLock  (NTOSKRNL.EXE.@)
+ */
+void WINAPI IoReleaseCancelSpinLock( KIRQL Irql )
+{
+    FIXME( "%u\n", Irql );
+}
+
+/***********************************************************************
+ *           IoInitializeIrp  (NTOSKRNL.EXE.@)
+ */
+void WINAPI IoInitializeIrp( IRP *irp, USHORT size, CCHAR stack_size )
+{
+    TRACE( "%p, %u, %d\n", irp, size, stack_size );
+
+    RtlZeroMemory( irp, size );
+
+    irp->Type = 6;
+    irp->Size = size;
+    InitializeListHead( &irp->ThreadListEntry );
+    irp->StackCount = stack_size;
+    irp->CurrentLocation = stack_size + 1;
+    irp->Tail.Overlay.s.u.CurrentStackLocation =
+            (PIO_STACK_LOCATION)(irp + 1) + stack_size;
+}
+
+/***********************************************************************
+ *           IoAllocateIrp  (NTOSKRNL.EXE.@)
+ */
+PIRP WINAPI IoAllocateIrp( CCHAR stack_size, BOOLEAN charge_quota )
+{
+    SIZE_T size;
+    PIRP irp;
+
+    TRACE( "%d, %d\n", stack_size, charge_quota );
+
+    size = sizeof(IRP) + stack_size * sizeof(IO_STACK_LOCATION);
+    irp = ExAllocatePool( NonPagedPool, size );
+    if (irp != NULL)
+        IoInitializeIrp( irp, size, stack_size );
+    irp->AllocationFlags = IRP_ALLOCATED_FIXED_SIZE;
+    if (charge_quota)
+        irp->AllocationFlags |= IRP_LOOKASIDE_ALLOCATION;
+
+    return irp;
+}
+
+/***********************************************************************
+ *           IoFreeIrp  (NTOSKRNL.EXE.@)
+ */
+void WINAPI IoFreeIrp( IRP *irp )
+{
+    TRACE( "%p\n", irp );
+
+    ExFreePool( irp );
+}
+
+/***********************************************************************
  *           IoAllocateMdl  (NTOSKRNL.EXE.@)
  */
 PMDL WINAPI IoAllocateMdl( PVOID VirtualAddress, ULONG Length, BOOLEAN SecondaryBuffer, BOOLEAN ChargeQuota, PIRP Irp )
@@ -266,6 +367,65 @@ PIO_WORKITEM WINAPI IoAllocateWorkItem( PDEVICE_OBJECT DeviceObject )
     return NULL;
 }
 
+/***********************************************************************
+ *           IoAttachDeviceToDeviceStack  (NTOSKRNL.EXE.@)
+ */
+PDEVICE_OBJECT WINAPI IoAttachDeviceToDeviceStack( DEVICE_OBJECT *source,
+                                                   DEVICE_OBJECT *target )
+{
+    TRACE( "%p, %p\n", source, target );
+    target->AttachedDevice = source;
+    source->StackSize = target->StackSize + 1;
+    return target;
+}
+
+/***********************************************************************
+ *           IoBuildDeviceIoControlRequest  (NTOSKRNL.EXE.@)
+ */
+PIRP WINAPI IoBuildDeviceIoControlRequest( ULONG IoControlCode,
+                                           PDEVICE_OBJECT DeviceObject,
+                                           PVOID InputBuffer,
+                                           ULONG InputBufferLength,
+                                           PVOID OutputBuffer,
+                                           ULONG OutputBufferLength,
+                                           BOOLEAN InternalDeviceIoControl,
+                                           PKEVENT Event,
+                                           PIO_STATUS_BLOCK IoStatusBlock )
+{
+    PIRP irp;
+    PIO_STACK_LOCATION irpsp;
+    struct IrpInstance *instance;
+
+    TRACE( "%x, %p, %p, %u, %p, %u, %u, %p, %p\n",
+           IoControlCode, DeviceObject, InputBuffer, InputBufferLength,
+           OutputBuffer, OutputBufferLength, InternalDeviceIoControl,
+           Event, IoStatusBlock );
+
+    if (DeviceObject == NULL)
+        return NULL;
+
+    irp = IoAllocateIrp( DeviceObject->StackSize, FALSE );
+    if (irp == NULL)
+        return NULL;
+
+    instance = HeapAlloc( GetProcessHeap(), 0, sizeof(struct IrpInstance) );
+    if (instance == NULL)
+    {
+        IoFreeIrp( irp );
+        return NULL;
+    }
+    instance->irp = irp;
+    list_add_tail( &Irps, &instance->entry );
+
+    irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation - 1;
+    irpsp->MajorFunction = InternalDeviceIoControl ?
+            IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL;
+    irpsp->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
+    irp->UserIosb = IoStatusBlock;
+    irp->UserEvent = Event;
+
+    return irp;
+}
 
 /***********************************************************************
  *           IoCreateDriver   (NTOSKRNL.EXE.@)
@@ -347,9 +507,14 @@ NTSTATUS WINAPI IoCreateDevice( DRIVER_OBJECT *driver, ULONG ext_size,
 
     if (status == STATUS_SUCCESS)
     {
+        device->Type            = 3;
+        device->Size            = sizeof(*device) + ext_size;
         device->DriverObject    = driver;
+        device->Flags           = DO_DEVICE_INITIALIZING;
+        if (name) device->Flags |= DO_DEVICE_HAS_NAME;
         device->DeviceExtension = device + 1;
         device->DeviceType      = type;
+        device->StackSize       = 1;
         device->Reserved        = handle;
 
         device->NextDevice   = driver->DeviceObject;
@@ -412,6 +577,58 @@ NTSTATUS WINAPI IoCreateSymbolicLink( UNICODE_STRING *name, UNICODE_STRING *targ
 
 
 /***********************************************************************
+ *           IoRegisterDeviceInterface   (NTOSKRNL.EXE.@)
+ */
+NTSTATUS WINAPI IoRegisterDeviceInterface( PDEVICE_OBJECT PhysicalDeviceObject,
+                                           CONST GUID *InterfaceClassGuid,
+                                           PUNICODE_STRING ReferenceString,
+                                           PUNICODE_STRING SymbolicLinkName )
+{
+    FIXME( "%p %p %p %p\n", PhysicalDeviceObject, InterfaceClassGuid,
+           ReferenceString, SymbolicLinkName );
+    return STATUS_SUCCESS;
+}
+
+
+/***********************************************************************
+ *           IoSetDeviceInterfaceState   (NTOSKRNL.EXE.@)
+ */
+NTSTATUS WINAPI IoSetDeviceInterfaceState( PUNICODE_STRING SymbolicLinkName,
+                                           BOOLEAN Enable )
+{
+    FIXME( "%p %d\n", SymbolicLinkName, Enable );
+    return STATUS_SUCCESS;
+}
+
+
+/***********************************************************************
+ *           IofCallDriver   (NTOSKRNL.EXE.@)
+ */
+#ifdef DEFINE_FASTCALL2_ENTRYPOINT
+DEFINE_FASTCALL2_ENTRYPOINT( IofCallDriver )
+NTSTATUS WINAPI __regs_IofCallDriver( DEVICE_OBJECT *device, IRP *irp )
+#else
+NTSTATUS WINAPI IofCallDriver( DEVICE_OBJECT *device, IRP *irp )
+#endif
+{
+    PDRIVER_DISPATCH dispatch;
+    IO_STACK_LOCATION *irpsp;
+    NTSTATUS status;
+
+    TRACE( "%p %p\n", device, irp );
+
+    --irp->CurrentLocation;
+    irpsp = --irp->Tail.Overlay.s.u.CurrentStackLocation;
+    dispatch = device->DriverObject->MajorFunction[irpsp->MajorFunction];
+    status = dispatch( device, irp );
+    ++irp->CurrentLocation;
+    ++irp->Tail.Overlay.s.u.CurrentStackLocation;
+
+    return status;
+}
+
+
+/***********************************************************************
  *           IofCompleteRequest   (NTOSKRNL.EXE.@)
  */
 #ifdef DEFINE_FASTCALL2_ENTRYPOINT
@@ -421,8 +638,57 @@ void WINAPI __regs_IofCompleteRequest( IRP *irp, UCHAR priority_boost )
 void WINAPI IofCompleteRequest( IRP *irp, UCHAR priority_boost )
 #endif
 {
+    IO_STACK_LOCATION *irpsp;
+    PIO_COMPLETION_ROUTINE routine;
+
     TRACE( "%p %u\n", irp, priority_boost );
-    /* nothing to do for now */
+
+    irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation;
+    routine = irpsp->CompletionRoutine;
+    /* FIXME: check other stack locations */
+    if (routine)
+    {
+        NTSTATUS status;
+        int call_flag = 0;
+
+        switch (irp->IoStatus.u.Status)
+        {
+        case STATUS_SUCCESS:
+            if (irpsp->Control & SL_INVOKE_ON_SUCCESS)
+                call_flag = 1;
+            break;
+        case STATUS_CANCELLED:
+            if (irpsp->Control & SL_INVOKE_ON_CANCEL)
+                call_flag = 1;
+            break;
+        default:
+            if (irpsp->Control & SL_INVOKE_ON_ERROR)
+                call_flag = 1;
+        }
+
+        if (call_flag)
+        {
+            TRACE( "calling %p( %p, %p, %p )\n", routine, irpsp->DeviceObject,
+                   irp, irpsp->Context );
+            status = routine( irpsp->DeviceObject, irp, irpsp->Context );
+            TRACE( "CompletionRoutine returned %x\n", status );
+            if (status != STATUS_MORE_PROCESSING_REQUIRED)
+            {
+                struct IrpInstance *instance;
+
+                LIST_FOR_EACH_ENTRY( instance, &Irps, struct IrpInstance, entry )
+                {
+                    if (instance->irp == irp)
+                    {
+                        list_remove( &instance->entry );
+                        HeapFree( GetProcessHeap(), 0, instance );
+                        IoFreeIrp( irp );
+                        break;
+                    }
+                }
+            }
+        }
+    }
 }
 
 
@@ -555,6 +821,88 @@ void WINAPI ExFreePoolWithTag( void *ptr, ULONG tag )
 
 
 /***********************************************************************
+ *           KeInitializeEvent   (NTOSKRNL.EXE.@)
+ */
+void WINAPI KeInitializeEvent( PRKEVENT Event, EVENT_TYPE Type,
+                               BOOLEAN State )
+{
+    FIXME( "%p %u %u\n", Event, Type, State );
+    RtlZeroMemory( Event, sizeof(KEVENT) );
+    Event->Header.Type = Type;
+    Event->Header.Size = 4;
+    if (State)
+        Event->Header.SignalState = 1;
+    InitializeListHead( &Event->Header.WaitListHead );
+}
+
+
+/***********************************************************************
+ *           KeClearEvent   (NTOSKRNL.EXE.@)
+ */
+void WINAPI KeClearEvent( PRKEVENT Event )
+{
+    FIXME( "%p\n", Event );
+    Event->Header.SignalState = 0;
+}
+
+
+/***********************************************************************
+ *           KeResetEvent   (NTOSKRNL.EXE.@)
+ */
+LONG WINAPI KeResetEvent( PRKEVENT Event )
+{
+    LONG ret;
+
+    FIXME( "%p\n", Event );
+
+    ret = Event->Header.SignalState;
+    Event->Header.SignalState = 0;
+    return ret;
+}
+
+
+/***********************************************************************
+ *           KeSetEvent   (NTOSKRNL.EXE.@)
+ */
+LONG WINAPI KeSetEvent( PRKEVENT Event, KPRIORITY Increment,
+                        BOOLEAN Wait )
+{
+    LONG ret;
+
+    FIXME("%p %d %d\n", Event, Increment, Wait);
+
+    ret = Event->Header.SignalState;
+    Event->Header.SignalState = 1;
+    return ret;
+}
+
+
+/***********************************************************************
+ *           KeInitializeMutex   (NTOSKRNL.EXE.@)
+ */
+void WINAPI KeInitializeMutex( PRKMUTEX Mutex, ULONG Level )
+{
+    FIXME( "%p %u\n", Mutex, Level );
+    RtlZeroMemory( Mutex, sizeof(KMUTEX) );
+    Mutex->Header.Type = 2;
+    Mutex->Header.Size = 8;
+    Mutex->Header.SignalState = 1;
+    InitializeListHead( &Mutex->Header.WaitListHead );
+    Mutex->ApcDisable = 1;
+}
+
+
+/***********************************************************************
+ *           KeReleaseMutex   (NTOSKRNL.EXE.@)
+ */
+LONG WINAPI KeReleaseMutex( PRKMUTEX Mutex, BOOLEAN Wait )
+{
+    FIXME("%p %d\n", Mutex, Wait);
+    return STATUS_SUCCESS;
+}
+
+
+/***********************************************************************
  *           KeInitializeSpinLock   (NTOSKRNL.EXE.@)
  */
 void WINAPI KeInitializeSpinLock( PKSPIN_LOCK SpinLock )
@@ -564,6 +912,17 @@ void WINAPI KeInitializeSpinLock( PKSPIN_LOCK SpinLock )
 
 
 /***********************************************************************
+ *           PoSetPowerState   (NTOSKRNL.EXE.@)
+ */
+UINT WINAPI PoSetPowerState( PDEVICE_OBJECT DeviceObject,
+                             POWER_STATE_TYPE Type, POWER_STATE State )
+{
+    FIXME("%p %u %u\n", DeviceObject, Type, State.DeviceState);
+    return State.DeviceState;
+}
+
+
+/***********************************************************************
  *           KeInitializeTimerEx   (NTOSKRNL.EXE.@)
  */
 void WINAPI KeInitializeTimerEx( PKTIMER Timer, TIMER_TYPE Type )
@@ -646,6 +1005,18 @@ ULONG WINAPI KeQueryTimeIncrement(void)
 
 
 /***********************************************************************
+ *           KeWaitForSingleObject   (NTOSKRNL.EXE.@)
+ */
+NTSTATUS WINAPI KeWaitForSingleObject( PVOID Object, KWAIT_REASON WaitReason,
+                                       KPROCESSOR_MODE WaitMode, BOOLEAN Alertable,
+                                       PLARGE_INTEGER Timeout )
+{
+    FIXME("%p %u %d %d %p\n", Object, WaitReason, WaitMode, Alertable, Timeout);
+    return STATUS_SUCCESS;
+}
+
+
+/***********************************************************************
  *           MmAllocateNonCachedMemory   (NTOSKRNL.EXE.@)
  */
 PVOID WINAPI MmAllocateNonCachedMemory( SIZE_T size )
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
index 0e7b8e8..729ed54 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
+++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
@@ -39,7 +39,7 @@
 @ stub IoReadPartitionTable
 @ stub IoSetPartitionInformation
 @ stub IoWritePartitionTable
-@ stub IofCallDriver
+@ stdcall -norelay IofCallDriver(ptr ptr)
 @ stdcall -norelay IofCompleteRequest(ptr long)
 @ stub KeAcquireInStackQueuedSpinLockAtDpcLevel
 @ stub KeReleaseInStackQueuedSpinLockFromDpcLevel
@@ -303,7 +303,7 @@
 @ stub InbvSetTextColor
 @ stub InbvSolidColorFill
 @ stub InitSafeBootMode
-@ stub IoAcquireCancelSpinLock
+@ stdcall IoAcquireCancelSpinLock(ptr)
 @ stub IoAcquireRemoveLockEx
 @ stub IoAcquireVpbSpinLock
 @ stub IoAdapterObjectType
@@ -311,16 +311,16 @@
 @ stub IoAllocateController
 @ stub IoAllocateDriverObjectExtension
 @ stub IoAllocateErrorLogEntry
-@ stub IoAllocateIrp
+@ stdcall IoAllocateIrp(long long)
 @ stdcall IoAllocateMdl(ptr long long long ptr)
 @ stdcall IoAllocateWorkItem(ptr)
 @ stub IoAssignResources
 @ stub IoAttachDevice
 @ stub IoAttachDeviceByPointer
-@ stub IoAttachDeviceToDeviceStack
+@ stdcall IoAttachDeviceToDeviceStack(ptr ptr)
 @ stub IoAttachDeviceToDeviceStackSafe
 @ stub IoBuildAsynchronousFsdRequest
-@ stub IoBuildDeviceIoControlRequest
+@ stdcall IoBuildDeviceIoControlRequest(long ptr ptr long ptr long long ptr ptr)
 @ stub IoBuildPartialMdl
 @ stub IoBuildSynchronousFsdRequest
 @ stub IoCallDriver
@@ -370,7 +370,7 @@
 @ stub IoForwardIrpSynchronously
 @ stub IoFreeController
 @ stub IoFreeErrorLogEntry
-@ stub IoFreeIrp
+@ stdcall IoFreeIrp(ptr)
 @ stub IoFreeMdl
 @ stub IoFreeWorkItem
 @ stub IoGetAttachedDevice
@@ -397,7 +397,7 @@
 @ stub IoGetRequestorSessionId
 @ stub IoGetStackLimits
 @ stub IoGetTopLevelIrp
-@ stub IoInitializeIrp
+@ stdcall IoInitializeIrp(ptr long long)
 @ stub IoInitializeRemoveLockEx
 @ stub IoInitializeTimer
 @ stub IoInvalidateDeviceRelations
@@ -425,14 +425,14 @@
 @ stub IoReadPartitionTableEx
 @ stub IoReadTransferCount
 @ stub IoRegisterBootDriverReinitialization
-@ stub IoRegisterDeviceInterface
+@ stdcall IoRegisterDeviceInterface(ptr ptr ptr ptr)
 @ stub IoRegisterDriverReinitialization
 @ stub IoRegisterFileSystem
 @ stub IoRegisterFsRegistrationChange
 @ stub IoRegisterLastChanceShutdownNotification
 @ stub IoRegisterPlugPlayNotification
 @ stub IoRegisterShutdownNotification
-@ stub IoReleaseCancelSpinLock
+@ stdcall IoReleaseCancelSpinLock(long)
 @ stub IoReleaseRemoveLockAndWaitEx
 @ stub IoReleaseRemoveLockEx
 @ stub IoReleaseVpbSpinLock
@@ -446,7 +446,7 @@
 @ stub IoRequestDeviceEject
 @ stub IoReuseIrp
 @ stub IoSetCompletionRoutineEx
-@ stub IoSetDeviceInterfaceState
+@ stdcall IoSetDeviceInterfaceState(ptr long)
 @ stub IoSetDeviceToVerify
 @ stub IoSetFileOrigin
 @ stub IoSetHardErrorOrVerifyDevice
@@ -515,7 +515,7 @@
 @ stub KeBugCheckEx
 @ stub KeCancelTimer
 @ stub KeCapturePersistentThreadState
-@ stub KeClearEvent
+@ stdcall KeClearEvent(ptr)
 @ stub KeConnectInterrupt
 @ stub KeDcacheFlushCount
 @ stub KeDelayExecutionThread
@@ -546,10 +546,10 @@
 @ stub KeInitializeApc
 @ stub KeInitializeDeviceQueue
 @ stub KeInitializeDpc
-@ stub KeInitializeEvent
+@ stdcall KeInitializeEvent(ptr long long)
 @ stub KeInitializeInterrupt
 @ stub KeInitializeMutant
-@ stub KeInitializeMutex
+@ stdcall KeInitializeMutex(ptr long)
 @ stub KeInitializeQueue
 @ stub KeInitializeSemaphore
 @ stdcall KeInitializeSpinLock(ptr)
@@ -587,7 +587,7 @@
 @ stub KeRegisterBugCheckReasonCallback
 @ stub KeReleaseInterruptSpinLock
 @ stub KeReleaseMutant
-@ stub KeReleaseMutex
+@ stdcall KeReleaseMutex(ptr long)
 @ stub KeReleaseSemaphore
 @ stub KeReleaseSpinLockFromDpcLevel
 @ stub KeRemoveByKeyDeviceQueue
@@ -597,7 +597,7 @@
 @ stub KeRemoveQueue
 @ stub KeRemoveQueueDpc
 @ stub KeRemoveSystemServiceTable
-@ stub KeResetEvent
+@ stdcall KeResetEvent(ptr)
 @ stub KeRestoreFloatingPointState
 @ stub KeRevertToUserAffinityThread
 @ stub KeRundownQueue
@@ -607,7 +607,7 @@
 @ stub KeSetAffinityThread
 @ stub KeSetBasePriorityThread
 @ stub KeSetDmaIoCoherency
-@ stub KeSetEvent
+@ stdcall KeSetEvent(ptr long long)
 @ stub KeSetEventBoostPriority
 @ stub KeSetIdealProcessorThread
 @ stub KeSetImportanceDpc
@@ -629,7 +629,7 @@
 @ stub KeUserModeCallback
 @ stub KeWaitForMultipleObjects
 @ stub KeWaitForMutexObject
-@ stub KeWaitForSingleObject
+@ stdcall KeWaitForSingleObject(ptr long long long ptr)
 @ stub KiBugCheckData
 @ stub KiCoprocessorError
 @ stub KiDeliverApc
@@ -830,7 +830,7 @@
 @ stub PoRequestPowerIrp
 @ stub PoRequestShutdownEvent
 @ stub PoSetHiberRange
-@ stub PoSetPowerState
+@ stdcall PoSetPowerState(ptr long long)
 @ stub PoSetSystemState
 @ stub PoShutdownBugCheck
 @ stub PoStartNextPowerIrp
diff --git a/dlls/usbd.sys/Makefile.in b/dlls/usbd.sys/Makefile.in
new file mode 100644
index 0000000..f745ffb
--- /dev/null
+++ b/dlls/usbd.sys/Makefile.in
@@ -0,0 +1,15 @@
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../..
+SRCDIR    = @srcdir@
+VPATH     = @srcdir@
+MODULE    = usbd.sys
+IMPORTLIB = usbd.sys
+IMPORTS   = kernel32 ntoskrnl.exe
+EXTRADLLFLAGS = -Wb,--subsystem,native
+
+C_SRCS = \
+	usbd.c
+
+ на MAKE_DLL_RULES@
+
+ на DEPENDENCIES@  # everything below this line is overwritten by make depend
diff --git a/dlls/usbd.sys/usbd.c b/dlls/usbd.sys/usbd.c
new file mode 100644
index 0000000..cec3015
--- /dev/null
+++ b/dlls/usbd.sys/usbd.c
@@ -0,0 +1,129 @@
+/*
+ * 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 <stdarg.h>
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winbase.h"
+#include "winternl.h"
+#include "ddk/wdm.h"
+#include "ddk/usb.h"
+#include "ddk/usbdlib.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(usbd);
+
+static int find_descriptor( PUSB_CONFIGURATION_DESCRIPTOR conf,
+        void **from, UCHAR type )
+{
+    USB_COMMON_DESCRIPTOR *desc = *from;
+
+    while ((char *)desc < (char *)conf + conf->wTotalLength)
+    {
+        if (desc->bDescriptorType == type)
+        {
+            *from = desc;
+            return 1;
+        }
+        desc = (USB_COMMON_DESCRIPTOR *)((char *)desc + desc->bLength);
+    }
+    return 0;
+}
+
+PURB WINAPI USBD_CreateConfigurationRequestEx(
+        PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
+        PUSBD_INTERFACE_LIST_ENTRY InterfaceList )
+{
+    URB *urb;
+    UCHAR k, num_interfaces = 0;
+    SIZE_T size;
+    struct _URB_SELECT_CONFIGURATION *sel_conf;
+    USBD_INTERFACE_INFORMATION *if_info;
+    USB_INTERFACE_DESCRIPTOR *if_desc;
+    USB_ENDPOINT_DESCRIPTOR *ep_desc;
+    USBD_INTERFACE_LIST_ENTRY *entry;
+
+    TRACE( "%p, %p\n", ConfigurationDescriptor, InterfaceList );
+
+    entry = InterfaceList;
+    size = sizeof(struct _URB_SELECT_CONFIGURATION);
+    while (entry->InterfaceDescriptor)
+    {
+        size += (entry->InterfaceDescriptor->bNumEndpoints - 1) *
+                sizeof(USBD_PIPE_INFORMATION);
+        ++num_interfaces;
+        ++entry;
+    }
+    size += (num_interfaces - 1) * sizeof(USBD_INTERFACE_INFORMATION);
+
+    urb = ExAllocatePool( NonPagedPool, size );
+    RtlZeroMemory( urb, size );
+
+    sel_conf = &urb->u.UrbSelectConfiguration;
+    sel_conf->Hdr.Length = size;
+    sel_conf->Hdr.Function = URB_FUNCTION_SELECT_CONFIGURATION;
+    sel_conf->ConfigurationDescriptor = ConfigurationDescriptor;
+
+    entry = InterfaceList;
+    if_info = &sel_conf->Interface;
+    while (entry->InterfaceDescriptor)
+    {
+        if_desc = entry->InterfaceDescriptor;
+        entry->Interface = if_info;
+        if_info->InterfaceNumber = if_desc->bInterfaceNumber;
+        if_info->Class = if_desc->bInterfaceClass;
+        if_info->SubClass = if_desc->bInterfaceSubClass;
+        if_info->Protocol = if_desc->bInterfaceProtocol;
+        if_info->NumberOfPipes = if_desc->bNumEndpoints;
+        ep_desc = (USB_ENDPOINT_DESCRIPTOR *)(if_desc + 1);
+        k = 0;
+        while (find_descriptor( ConfigurationDescriptor, (void **)&ep_desc,
+                USB_ENDPOINT_DESCRIPTOR_TYPE ))
+        {
+            if_info->Pipes[k].MaximumPacketSize = ep_desc->wMaxPacketSize;
+            if_info->Pipes[k].EndpointAddress = ep_desc->bEndpointAddress;
+            if_info->Pipes[k].Interval = ep_desc->bInterval;
+            ++k;
+        }
+        if_info->Length = sizeof(USBD_INTERFACE_INFORMATION) +
+                (k - 1) * sizeof(USBD_PIPE_INFORMATION);
+        ++entry;
+    }
+
+    return urb;
+}
+
+PUSB_INTERFACE_DESCRIPTOR WINAPI USBD_ParseConfigurationDescriptorEx(
+        PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
+        PVOID StartPosition, LONG InterfaceNumber,
+        LONG AlternateSetting, LONG InterfaceClass,
+        LONG InterfaceSubClass, LONG InterfaceProtocol )
+{
+    FIXME( "%p, %p, %d, %d, %d, %d, %d\n", ConfigurationDescriptor,
+            StartPosition, InterfaceNumber, AlternateSetting,
+            InterfaceClass, InterfaceSubClass, InterfaceProtocol );
+    return (PUSB_INTERFACE_DESCRIPTOR)++ConfigurationDescriptor;
+}
+
+NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
+{
+    return STATUS_SUCCESS;
+}
diff --git a/dlls/usbd.sys/usbd.sys.spec b/dlls/usbd.sys/usbd.sys.spec
new file mode 100644
index 0000000..8384f77
--- /dev/null
+++ b/dlls/usbd.sys/usbd.sys.spec
@@ -0,0 +1,35 @@
+@ stdcall USBD_CreateConfigurationRequestEx(ptr ptr)
+@ stdcall USBD_ParseConfigurationDescriptorEx(ptr ptr)
+@ stub USBD_ParseDescriptors
+@ stub DllInitialize
+@ stub DllUnload
+@ stub USBD_AllocateDeviceName
+@ stub USBD_CalculateUsbBandwidth
+@ stub USBD_CompleteRequest
+@ stub USBD_CreateConfigurationRequest
+@ stdcall _USBD_CreateConfigurationRequestEx\@8(ptr ptr) USBD_CreateConfigurationRequestEx
+@ stub USBD_CreateDevice
+@ stub USBD_Debug_GetHeap
+@ stub USBD_Debug_LogEntry
+@ stub USBD_Debug_RetHeap
+@ stub USBD_Dispatch
+@ stub USBD_FreeDeviceMutex
+@ stub USBD_FreeDeviceName
+@ stub USBD_GetDeviceInformation
+@ stub USBD_GetInterfaceLength
+@ stub USBD_GetPdoRegistryParameter
+@ stub USBD_GetSuspendPowerState
+@ stub USBD_GetUSBDIVersion
+@ stub USBD_InitializeDevice
+@ stub USBD_MakePdoName
+@ stub USBD_ParseConfigurationDescriptor
+@ stdcall _USBD_ParseConfigurationDescriptorEx\@28(ptr ptr long long long long long) USBD_ParseConfigurationDescriptorEx
+@ stub _USBD_ParseDescriptors\@16
+@ stub USBD_QueryBusTime
+@ stub USBD_RegisterHcDeviceCapabilities
+@ stub USBD_RegisterHcFilter
+@ stub USBD_RegisterHostController
+@ stub USBD_RemoveDevice
+@ stub USBD_RestoreDevice
+@ stub USBD_SetSuspendPowerState
+@ stub USBD_WaitDeviceMutex
diff --git a/dlls/wineusbhub/Makefile.in b/dlls/wineusbhub/Makefile.in
new file mode 100644
index 0000000..5fc0556
--- /dev/null
+++ b/dlls/wineusbhub/Makefile.in
@@ -0,0 +1,15 @@
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../..
+SRCDIR    = @srcdir@
+VPATH     = @srcdir@
+MODULE    = wineusbhub.dll
+IMPORTLIB = wineusbhub
+IMPORTS   = ntoskrnl.exe kernel32
+EXTRALIBS = -lusb
+
+C_SRCS = \
+	wineusbhub.c
+
+ на MAKE_DLL_RULES@
+
+ на DEPENDENCIES@  # everything below this line is overwritten by make depend
diff --git a/dlls/wineusbhub/wineusbhub.c b/dlls/wineusbhub/wineusbhub.c
new file mode 100644
index 0000000..a855253
--- /dev/null
+++ b/dlls/wineusbhub/wineusbhub.c
@@ -0,0 +1,334 @@
+/*
+ * 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 "config.h"
+#include "wine/port.h"
+
+#include <stdarg.h>
+#include <usb.h>
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winbase.h"
+#include "winternl.h"
+#include "ddk/ntddk.h"
+#include "ddk/usb.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wineusbhub);
+
+extern void WINAPI IofCompleteRequest( IRP *irp, UCHAR priority_boost );
+
+DRIVER_OBJECT hubdrv;
+DEVICE_OBJECT *usbdev;      /* USB PDO */
+static struct usb_device *dev;
+
+static void add_data( char **dst, int *dst_size, void *src, int src_size )
+{
+    int copy;
+
+    copy = (src_size >= *dst_size) ? *dst_size : src_size;
+    memcpy( *dst, src, copy );
+    *dst += copy;
+    *dst_size -= copy;
+}
+
+void WINAPI __wine_IofCompleteRequest( IRP *irp, UCHAR priority_boost )
+{
+    #ifdef __i386__
+    __asm__( "movl %1,%%edx\n\t"
+             "movl %0,%%ecx\n\t"
+             "call " __ASM_NAME("IofCompleteRequest")
+             : : "g" (irp), "g" (priority_boost) );
+    #else
+    IofCompleteRequest( irp, priority_boost );
+    #endif
+}
+
+NTSTATUS WINAPI __wine_usbhub_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
+{
+    IO_STACK_LOCATION *irpsp;
+    URB *urb;
+    NTSTATUS status = STATUS_UNSUCCESSFUL;
+
+    TRACE( "%p, %p\n", device, irp );
+
+    irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation;
+    urb = irpsp->Parameters.Others.Argument1;
+
+    switch (urb->u.UrbHeader.Function)
+    {
+    case URB_FUNCTION_SELECT_CONFIGURATION:
+        {
+            USB_CONFIGURATION_DESCRIPTOR *conf_desc =
+                    urb->u.UrbSelectConfiguration.ConfigurationDescriptor;
+            usb_dev_handle *husb;
+
+            TRACE( "URB_FUNCTION_SELECT_CONFIGURATION\n" );
+
+            husb = usb_open( dev );
+            if (husb)
+            {
+                int ret;
+
+                ret = usb_set_configuration( husb, conf_desc->bConfigurationValue );
+                if (ret < 0)
+                    ERR( "%s\n", usb_strerror() );
+                else
+                    status = STATUS_SUCCESS;
+                usb_close( husb );
+            }
+        }
+        break;
+    case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
+        {
+            struct _URB_CONTROL_DESCRIPTOR_REQUEST *request =
+                    &urb->u.UrbControlDescriptorRequest;
+
+            TRACE( "URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n" );
+
+            switch (request->DescriptorType)
+            {
+            case USB_DEVICE_DESCRIPTOR_TYPE:
+                TRACE( "USB_DEVICE_DESCRIPTOR_TYPE\n" );
+                if (request->TransferBuffer == NULL)
+                    break;
+                if (sizeof(USB_DEVICE_DESCRIPTOR) <= request->TransferBufferLength)
+                {
+                    memcpy( request->TransferBuffer, &dev->descriptor,
+                            sizeof(USB_DEVICE_DESCRIPTOR) );
+                    status = STATUS_SUCCESS;
+                }
+                break;
+            case USB_CONFIGURATION_DESCRIPTOR_TYPE:
+                TRACE( "USB_CONFIGURATION_DESCRIPTOR_TYPE\n" );
+                {
+                    unsigned int i, k;
+                    char *buf = request->TransferBuffer;
+                    struct usb_config_descriptor *conf = &dev->config[0];
+                    struct usb_interface_descriptor *intf;
+                    struct usb_endpoint_descriptor *endp;
+                    int size = request->TransferBufferLength;
+
+                    /* FIXME: case of num_altsetting > 1 */
+
+                    if (buf == NULL)
+                        break;
+                    add_data( &buf, &size, conf,
+                            sizeof(USB_CONFIGURATION_DESCRIPTOR) );
+                    if (size > 0 && conf->extra)
+                        add_data( &buf, &size, conf->extra, conf->extralen );
+                    for (i = 0; i < conf->bNumInterfaces; ++i)
+                    {
+                        intf = &conf->interface[i].altsetting[0];
+                        if (size > 0)
+                            add_data( &buf, &size, intf,
+                                    sizeof(USB_INTERFACE_DESCRIPTOR) );
+                        if (size > 0 && intf->extra)
+                            add_data( &buf, &size, intf->extra, intf->extralen );
+                        for (k = 0; k < intf->bNumEndpoints; ++k)
+                        {
+                            endp = &intf->endpoint[k];
+                            if (size > 0)
+                                add_data( &buf, &size, endp,
+                                        sizeof(USB_ENDPOINT_DESCRIPTOR) );
+                            if (size > 0 && endp->extra)
+                                add_data( &buf, &size, endp->extra, endp->extralen );
+                        }
+                    }
+                    status = STATUS_SUCCESS;
+                }
+                break;
+            default:
+                FIXME( "unsupported descriptor type %x\n", request->DescriptorType );
+            }
+        }
+        break;
+    case URB_FUNCTION_VENDOR_DEVICE:
+    case URB_FUNCTION_VENDOR_INTERFACE:
+        {
+            usb_dev_handle *husb;
+            struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *request =
+                    &urb->u.UrbControlVendorClassRequest;
+
+            TRACE( "%s\n", (urb->u.UrbHeader.Function == URB_FUNCTION_VENDOR_DEVICE) ?
+                    "URB_FUNCTION_VENDOR_DEVICE" : "URB_FUNCTION_VENDOR_INTERFACE" );
+
+            husb = usb_open( dev );
+            if (husb)
+            {
+                UCHAR req_type = request->RequestTypeReservedBits | (2 << 5);
+                char *buf;
+                int ret;
+
+                if (urb->u.UrbHeader.Function == URB_FUNCTION_VENDOR_INTERFACE)
+                    req_type |= 1;
+                buf = HeapAlloc( GetProcessHeap(), 0, request->TransferBufferLength );
+                if (buf != NULL)
+                {
+                    memcpy( buf, request->TransferBuffer, request->TransferBufferLength );
+                    if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
+                        req_type |= (1 << 7);
+                    ret = usb_control_msg( husb, req_type, request->Request, request->Value,
+                            request->Index, buf, request->TransferBufferLength, 1000 );
+                    if (ret < 0)
+                        ERR( "%s\n", usb_strerror() );
+                    else
+                    {
+                        if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
+                        {
+                            request->TransferBufferLength =
+                                    (ret <= request->TransferBufferLength) ?
+                                    ret : request->TransferBufferLength;
+                            memcpy( request->TransferBuffer, buf,
+                                    request->TransferBufferLength );
+                        }
+                        status = STATUS_SUCCESS;
+                    }
+                    HeapFree( GetProcessHeap(), 0, buf );
+                }
+                usb_close( husb );
+            }
+        }
+        break;
+    default:
+        FIXME( "unsupported URB function %x\n", urb->u.UrbHeader.Function );
+    }
+
+    urb->u.UrbHeader.Status = status;
+    if (irp->UserIosb != NULL)
+    {
+        irp->UserIosb->u.Status = status;
+        irp->UserIosb->Information = 0;
+    }
+    irp->IoStatus.u.Status = status;
+    irp->IoStatus.Information = 0;
+    __wine_IofCompleteRequest( irp, IO_NO_INCREMENT );
+
+    return status;
+}
+
+NTSTATUS WINAPI __wine_usbhub_dispatch_pnp( DEVICE_OBJECT *device, IRP *irp )
+{
+    IO_STACK_LOCATION *irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation;
+    NTSTATUS status = STATUS_UNSUCCESSFUL;
+
+    TRACE( "%p, %p\n", device, irp );
+
+    switch (irpsp->MinorFunction)
+    {
+    case IRP_MN_START_DEVICE:
+        status = STATUS_SUCCESS;
+        break;
+    case IRP_MN_QUERY_DEVICE_RELATIONS:
+        FIXME( "IRP_MN_QUERY_DEVICE_RELATIONS\n" );
+        status = STATUS_SUCCESS;
+        break;
+    case IRP_MN_QUERY_CAPABILITIES:
+        FIXME( "IRP_MN_QUERY_CAPABILITIES\n" );
+        {
+            PDEVICE_CAPABILITIES devCapab = irpsp->Parameters.DeviceCapabilities.Capabilities;
+
+            if (devCapab != NULL)
+            {
+                devCapab->Removable = 1;
+                devCapab->Address = 1;
+                devCapab->UINumber = 0;
+                devCapab->DeviceState[PowerSystemUnspecified] = PowerDeviceUnspecified;
+                devCapab->DeviceState[PowerSystemWorking] = PowerDeviceD0;
+                devCapab->DeviceState[PowerSystemSleeping1] = PowerDeviceD3;
+                devCapab->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
+                devCapab->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
+                devCapab->DeviceState[PowerSystemHibernate] = PowerDeviceD3;
+                devCapab->DeviceState[PowerSystemShutdown] = PowerDeviceD3;
+                devCapab->DeviceState[PowerSystemMaximum] = PowerDeviceD1;
+                devCapab->SystemWake = PowerSystemSleeping1;
+                devCapab->DeviceWake = PowerDeviceD0;
+                status = STATUS_SUCCESS;
+            }
+        }
+        break;
+    case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
+        FIXME( "IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n" );
+        status = STATUS_SUCCESS;
+        break;
+    case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
+        FIXME( "IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n" );
+        status = STATUS_SUCCESS;
+        break;
+    case IRP_MN_QUERY_PNP_DEVICE_STATE:
+        FIXME( "IRP_MN_QUERY_PNP_DEVICE_STATE\n" );
+        status = STATUS_SUCCESS;
+        break;
+    case IRP_MN_QUERY_LEGACY_BUS_INFORMATION:
+        FIXME( "IRP_MN_QUERY_LEGACY_BUS_INFORMATION\n" );
+        status = STATUS_SUCCESS;
+        break;
+    default:
+        FIXME( "unsupported MinorFunction %x\n", irpsp->MinorFunction );
+    }
+
+    irp->IoStatus.u.Status = status;
+    irp->IoStatus.Information = 0;
+    __wine_IofCompleteRequest( irp, IO_NO_INCREMENT );
+
+    return status;
+}
+
+DEVICE_OBJECT *__wine_usbhub_get_pdo( ULONG pdonum, ULONG location, ULONG devnum )
+{
+    static const WCHAR usbpdoW[] = {'\\','D','e','v','i','c','e','\\',
+                                    'U','S','B','P','D','O','-','%','u',0};
+    static WCHAR bufW[20];
+    UNICODE_STRING pdo_name;
+    struct usb_bus *bus;
+
+
+    TRACE( "%u, %u, %u\n", pdonum, location, devnum );
+
+    for (bus = usb_busses; bus; bus = bus->next)
+        for (dev = bus->devices; dev; dev = dev->next)
+            if (bus->location == location && dev->devnum == devnum)
+            {
+                hubdrv.MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = __wine_usbhub_internal_ioctl;
+                hubdrv.MajorFunction[IRP_MJ_PNP] = __wine_usbhub_dispatch_pnp;
+
+                snprintfW( bufW, sizeof(bufW), usbpdoW, pdonum );
+                RtlInitUnicodeString( &pdo_name, bufW );
+
+                if (STATUS_SUCCESS == IoCreateDevice( &hubdrv, 0, &pdo_name, 0, 0, FALSE, &usbdev ))
+                {
+                    usbdev->Flags |= DO_BUS_ENUMERATED_DEVICE | DO_POWER_PAGABLE;
+                    return usbdev;
+                }
+            }
+
+    return NULL;
+}
+
+BOOL WINAPI DllMain( HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv )
+{
+    usb_init();
+    usb_find_busses();
+    usb_find_devices();
+
+    return TRUE;
+}
diff --git a/dlls/wineusbhub/wineusbhub.spec b/dlls/wineusbhub/wineusbhub.spec
new file mode 100644
index 0000000..e91487e
--- /dev/null
+++ b/dlls/wineusbhub/wineusbhub.spec
@@ -0,0 +1,7 @@
+##################
+# Wine extensions
+#
+# All functions must be prefixed with '__wine_' (for internal functions)
+# or 'wine_' (for user-visible functions) to avoid namespace conflicts.
+
+@ cdecl __wine_usbhub_get_pdo(long long)
diff --git a/include/ddk/ntddk.h b/include/ddk/ntddk.h
index 47b6b1e..fdc9179 100644
--- a/include/ddk/ntddk.h
+++ b/include/ddk/ntddk.h
@@ -46,4 +46,13 @@ typedef enum _BUS_DATA_TYPE
     MaximumBusDataType
 } BUS_DATA_TYPE, *PBUS_DATA_TYPE;
 
+#define IRP_MN_QUERY_LEGACY_BUS_INFORMATION   0x18
+
+#define DO_VERIFY_VOLUME                0x00000002
+#define DO_DEVICE_HAS_NAME              0x00000040
+#define DO_SYSTEM_BOOT_PARTITION        0x00000100
+#define DO_LONG_TERM_REQUESTS           0x00000200
+#define DO_NEVER_LAST_DEVICE            0x00000400
+#define DO_LOW_PRIORITY_FILESYSTEM      0x00010000
+
 #endif
diff --git a/include/ddk/usb.h b/include/ddk/usb.h
new file mode 100644
index 0000000..3573b30
--- /dev/null
+++ b/include/ddk/usb.h
@@ -0,0 +1,340 @@
+/*
+ * 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 _USB_
+#define _USB_
+
+#include "usb200.h"
+
+#define URB_FUNCTION_SELECT_CONFIGURATION            0x0000
+#define URB_FUNCTION_SELECT_INTERFACE                0x0001
+#define URB_FUNCTION_ABORT_PIPE                      0x0002
+#define URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL       0x0003
+#define URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL    0x0004
+#define URB_FUNCTION_GET_FRAME_LENGTH                0x0005
+#define URB_FUNCTION_SET_FRAME_LENGTH                0x0006
+#define URB_FUNCTION_GET_CURRENT_FRAME_NUMBER        0x0007
+#define URB_FUNCTION_CONTROL_TRANSFER                0x0008
+#define URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER      0x0009
+#define URB_FUNCTION_ISOCH_TRANSFER                  0x000A
+#define URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE      0x000B
+#define URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE        0x000C
+#define URB_FUNCTION_SET_FEATURE_TO_DEVICE           0x000D
+#define URB_FUNCTION_SET_FEATURE_TO_INTERFACE        0x000E
+#define URB_FUNCTION_SET_FEATURE_TO_ENDPOINT         0x000F
+#define URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE         0x0010
+#define URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE      0x0011
+#define URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT       0x0012
+#define URB_FUNCTION_GET_STATUS_FROM_DEVICE          0x0013
+#define URB_FUNCTION_GET_STATUS_FROM_INTERFACE       0x0014
+#define URB_FUNCTION_GET_STATUS_FROM_ENDPOINT        0x0015
+#define URB_FUNCTION_RESERVED_0X0016                 0x0016
+#define URB_FUNCTION_VENDOR_DEVICE                   0x0017
+#define URB_FUNCTION_VENDOR_INTERFACE                0x0018
+#define URB_FUNCTION_VENDOR_ENDPOINT                 0x0019
+#define URB_FUNCTION_CLASS_DEVICE                    0x001A
+#define URB_FUNCTION_CLASS_INTERFACE                 0x001B
+#define URB_FUNCTION_CLASS_ENDPOINT                  0x001C
+#define URB_FUNCTION_RESERVE_0X001D                  0x001D
+#define URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL 0x001E
+#define URB_FUNCTION_CLASS_OTHER                     0x001F
+#define URB_FUNCTION_VENDOR_OTHER                    0x0020
+#define URB_FUNCTION_GET_STATUS_FROM_OTHER           0x0021
+#define URB_FUNCTION_CLEAR_FEATURE_TO_OTHER          0x0022
+#define URB_FUNCTION_SET_FEATURE_TO_OTHER            0x0023
+#define URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT    0x0024
+#define URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT      0x0025
+#define URB_FUNCTION_GET_CONFIGURATION               0x0026
+#define URB_FUNCTION_GET_INTERFACE                   0x0027
+#define URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE   0x0028
+#define URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE     0x0029
+#define URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR       0x002A
+#define URB_FUNCTION_RESERVE_0X002B                  0x002B
+#define URB_FUNCTION_RESERVE_0X002C                  0x002C
+#define URB_FUNCTION_RESERVE_0X002D                  0x002D
+#define URB_FUNCTION_RESERVE_0X002E                  0x002E
+#define URB_FUNCTION_RESERVE_0X002F                  0x002F
+#define URB_FUNCTION_SYNC_RESET_PIPE                 0x0030
+#define URB_FUNCTION_SYNC_CLEAR_STALL                0x0031
+
+#define USBD_SHORT_TRANSFER_OK                       0x00000002
+#define USBD_TRANSFER_DIRECTION_OUT                  0
+#define USBD_TRANSFER_DIRECTION_IN                   1
+
+typedef LONG USBD_STATUS;
+
+typedef PVOID USBD_PIPE_HANDLE;
+typedef PVOID USBD_CONFIGURATION_HANDLE;
+typedef PVOID USBD_INTERFACE_HANDLE;
+
+typedef enum _USBD_PIPE_TYPE {
+    UsbdPipeTypeControl,
+    UsbdPipeTypeIsochronous,
+    UsbdPipeTypeBulk,
+    UsbdPipeTypeInterrupt
+} USBD_PIPE_TYPE;
+
+typedef struct _USBD_PIPE_INFORMATION {
+    USHORT MaximumPacketSize;
+    UCHAR EndpointAddress;
+    UCHAR Interval;
+    USBD_PIPE_TYPE PipeType;
+    USBD_PIPE_HANDLE PipeHandle;
+    ULONG MaximumTransferSize;
+    ULONG PipeFlags;
+} USBD_PIPE_INFORMATION;
+typedef struct _USBD_PIPE_INFORMATION *PUSBD_PIPE_INFORMATION;
+
+typedef struct _USBD_INTERFACE_INFORMATION {
+    USHORT Length;
+    UCHAR InterfaceNumber;
+    UCHAR AlternateSetting;
+    UCHAR Class;
+    UCHAR SubClass;
+    UCHAR Protocol;
+    UCHAR Reserved;
+    USBD_INTERFACE_HANDLE InterfaceHandle;
+    ULONG NumberOfPipes; 
+    USBD_PIPE_INFORMATION Pipes[1];
+} USBD_INTERFACE_INFORMATION;
+typedef struct _USBD_INTERFACE_INFORMATION *PUSBD_INTERFACE_INFORMATION;
+
+typedef struct _USBD_ISO_PACKET_DESCRIPTOR {
+    ULONG Offset;
+    ULONG Length;
+    USBD_STATUS Status;
+} USBD_ISO_PACKET_DESCRIPTOR;
+typedef struct _USBD_ISO_PACKET_DESCRIPTOR *PUSBD_ISO_PACKET_DESCRIPTOR;
+
+struct _URB_HCD_AREA {
+    PVOID Reserved8[8];
+};
+
+struct _URB_HEADER {
+    USHORT Length;
+    USHORT Function;
+    USBD_STATUS Status;
+    PVOID UsbdDeviceHandle;
+    ULONG UsbdFlags;
+};
+
+struct _URB_SELECT_INTERFACE {
+    struct _URB_HEADER Hdr;
+    USBD_CONFIGURATION_HANDLE ConfigurationHandle;
+    USBD_INTERFACE_INFORMATION Interface;
+};
+
+struct _URB_SELECT_CONFIGURATION {
+    struct _URB_HEADER Hdr;
+    PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
+    USBD_CONFIGURATION_HANDLE ConfigurationHandle;
+    USBD_INTERFACE_INFORMATION Interface;
+};
+
+struct _URB_PIPE_REQUEST {
+    struct _URB_HEADER Hdr;
+    USBD_PIPE_HANDLE PipeHandle;
+    ULONG Reserved;
+};
+
+struct _URB_FRAME_LENGTH_CONTROL {
+    struct _URB_HEADER Hdr;
+};
+
+struct _URB_GET_FRAME_LENGTH {
+    struct _URB_HEADER Hdr;
+    ULONG FrameLength;
+    ULONG FrameNumber;
+};
+
+struct _URB_SET_FRAME_LENGTH {
+    struct _URB_HEADER Hdr;
+    LONG FrameLengthDelta;
+};
+
+struct _URB_GET_CURRENT_FRAME_NUMBER {
+    struct _URB_HEADER Hdr;
+    ULONG FrameNumber;
+};
+
+struct _URB_CONTROL_TRANSFER {
+    struct _URB_HEADER Hdr;
+    USBD_PIPE_HANDLE PipeHandle;
+    ULONG TransferFlags;
+    ULONG TransferBufferLength;
+    PVOID TransferBuffer;
+    PMDL TransferBufferMDL;
+    struct _URB *UrbLink;
+    struct _URB_HCD_AREA hca;
+    UCHAR SetupPacket[8];
+};
+
+struct _URB_BULK_OR_INTERRUPT_TRANSFER {
+    struct _URB_HEADER Hdr;
+    USBD_PIPE_HANDLE PipeHandle;
+    ULONG TransferFlags;
+    ULONG TransferBufferLength;
+    PVOID TransferBuffer;
+    PMDL TransferBufferMDL;
+    struct _URB *UrbLink;
+    struct _URB_HCD_AREA hca;
+};
+
+struct _URB_ISOCH_TRANSFER {
+    struct _URB_HEADER Hdr;
+    USBD_PIPE_HANDLE PipeHandle;
+    ULONG TransferFlags;
+    ULONG TransferBufferLength;
+    PVOID TransferBuffer;
+    PMDL TransferBufferMDL;
+    struct _URB *UrbLink;
+    struct _URB_HCD_AREA hca;
+    ULONG StartFrame;
+    ULONG NumberOfPackets;
+    ULONG ErrorCount;
+    USBD_ISO_PACKET_DESCRIPTOR IsoPacket[1];
+};
+
+struct _URB_CONTROL_DESCRIPTOR_REQUEST {
+    struct _URB_HEADER Hdr;
+    PVOID Reserved;
+    ULONG Reserved0;
+    ULONG TransferBufferLength;
+    PVOID TransferBuffer;
+    PMDL TransferBufferMDL;
+    struct _URB *UrbLink;
+    struct _URB_HCD_AREA hca;
+    USHORT Reserved1;
+    UCHAR Index;
+    UCHAR DescriptorType;
+    USHORT LanguageId;
+    USHORT Reserved2;
+};
+
+struct _URB_CONTROL_GET_STATUS_REQUEST {
+    struct _URB_HEADER Hdr;
+    PVOID Reserved;
+    ULONG Reserved0;
+    ULONG TransferBufferLength;
+    PVOID TransferBuffer;
+    PMDL TransferBufferMDL;
+    struct _URB *UrbLink;
+    struct _URB_HCD_AREA hca;
+    UCHAR Reserved1[4];
+    USHORT Index;
+    USHORT Reserved2;
+};
+
+struct _URB_CONTROL_FEATURE_REQUEST {
+    struct _URB_HEADER Hdr;
+    PVOID Reserved;
+    ULONG Reserved2;
+    ULONG Reserved3;
+    PVOID Reserved4;
+    PMDL Reserved5;
+    struct _URB *UrbLink;
+    struct _URB_HCD_AREA hca;
+    USHORT Reserved0;
+    USHORT FeatureSelector;
+    USHORT Index;
+    USHORT Reserved1;
+};
+
+struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST {
+    struct _URB_HEADER Hdr;
+    PVOID Reserved;
+    ULONG TransferFlags;
+    ULONG TransferBufferLength;
+    PVOID TransferBuffer;
+    PMDL TransferBufferMDL;
+    struct _URB *UrbLink;
+    struct _URB_HCD_AREA hca;
+    UCHAR RequestTypeReservedBits;
+    UCHAR Request;
+    USHORT Value;
+    USHORT Index;
+    USHORT Reserved1;
+};
+
+struct _URB_CONTROL_GET_INTERFACE_REQUEST {
+    struct _URB_HEADER Hdr;
+    PVOID Reserved;
+    ULONG Reserved0;
+    ULONG TransferBufferLength;
+    PVOID TransferBuffer;
+    PMDL TransferBufferMDL;
+    struct _URB *UrbLink;
+    struct _URB_HCD_AREA hca;
+    UCHAR Reserved1[4];
+    USHORT Interface;
+    USHORT Reserved2;
+};
+
+struct _URB_CONTROL_GET_CONFIGURATION_REQUEST {
+    struct _URB_HEADER Hdr;
+    PVOID Reserved;
+    ULONG Reserved0;
+    ULONG TransferBufferLength;
+    PVOID TransferBuffer;
+    PMDL TransferBufferMDL;
+    struct _URB *UrbLink;
+    struct _URB_HCD_AREA hca;
+    UCHAR Reserved1[8];
+};
+
+struct _URB_OS_FEATURE_DESCRIPTOR_REQUEST {
+    struct _URB_HEADER Hdr;
+    PVOID Reserved;
+    ULONG Reserved0;
+    ULONG TransferBufferLength;
+    PVOID TransferBuffer;
+    PMDL TransferBufferMDL;
+    struct _URB *UrbLink;
+    struct _URB_HCD_AREA hca;
+    UCHAR   Recipient:5;
+    UCHAR   Reserved1:3;
+    UCHAR   Reserved2;
+    UCHAR   InterfaceNumber;
+    UCHAR   MS_PageIndex;
+    USHORT  MS_FeatureDescriptorIndex;
+    USHORT  Reserved3;
+};
+
+typedef struct _URB {
+    union {
+        struct _URB_HEADER UrbHeader;
+        struct _URB_SELECT_INTERFACE UrbSelectInterface;
+        struct _URB_SELECT_CONFIGURATION UrbSelectConfiguration;
+        struct _URB_PIPE_REQUEST UrbPipeRequest;
+        struct _URB_FRAME_LENGTH_CONTROL UrbFrameLengthControl;
+        struct _URB_GET_FRAME_LENGTH UrbGetFrameLength;
+        struct _URB_SET_FRAME_LENGTH UrbSetFrameLength;
+        struct _URB_GET_CURRENT_FRAME_NUMBER UrbGetCurrentFrameNumber;
+        struct _URB_CONTROL_TRANSFER UrbControlTransfer;
+        struct _URB_BULK_OR_INTERRUPT_TRANSFER UrbBulkOrInterruptTransfer;
+        struct _URB_ISOCH_TRANSFER UrbIsochronousTransfer;
+        struct _URB_CONTROL_DESCRIPTOR_REQUEST UrbControlDescriptorRequest;
+        struct _URB_CONTROL_GET_STATUS_REQUEST UrbControlGetStatusRequest;
+        struct _URB_CONTROL_FEATURE_REQUEST UrbControlFeatureRequest;
+        struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST UrbControlVendorClassRequest;
+        struct _URB_CONTROL_GET_INTERFACE_REQUEST UrbControlGetInterfaceRequest;
+        struct _URB_CONTROL_GET_CONFIGURATION_REQUEST UrbControlGetConfigurationRequest;
+        struct _URB_OS_FEATURE_DESCRIPTOR_REQUEST UrbOSFeatureDescriptorRequest;
+    } DUMMYUNIONNAME;
+} URB;
+typedef struct _URB *PURB;
+
+#endif
diff --git a/include/ddk/usb100.h b/include/ddk/usb100.h
new file mode 100644
index 0000000..5b72ee7
--- /dev/null
+++ b/include/ddk/usb100.h
@@ -0,0 +1,99 @@
+/*
+ * 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 _USB100_
+#define _USB100_
+
+#define USB_DEVICE_DESCRIPTOR_TYPE                0x01
+#define USB_CONFIGURATION_DESCRIPTOR_TYPE         0x02
+#define USB_STRING_DESCRIPTOR_TYPE                0x03
+#define USB_INTERFACE_DESCRIPTOR_TYPE             0x04
+#define USB_ENDPOINT_DESCRIPTOR_TYPE              0x05
+#define USB_RESERVED_DESCRIPTOR_TYPE              0x06
+#define USB_CONFIG_POWER_DESCRIPTOR_TYPE          0x07
+#define USB_INTERFACE_POWER_DESCRIPTOR_TYPE       0x08
+
+#include <pshpack1.h>
+
+typedef struct _USB_DEVICE_DESCRIPTOR {
+    UCHAR bLength;
+    UCHAR bDescriptorType;
+    USHORT bcdUSB;
+    UCHAR bDeviceClass;
+    UCHAR bDeviceSubClass;
+    UCHAR bDeviceProtocol;
+    UCHAR bMaxPacketSize0;
+    USHORT idVendor;
+    USHORT idProduct;
+    USHORT bcdDevice;
+    UCHAR iManufacturer;
+    UCHAR iProduct;
+    UCHAR iSerialNumber;
+    UCHAR bNumConfigurations;
+} USB_DEVICE_DESCRIPTOR;
+typedef struct _USB_DEVICE_DESCRIPTOR *PUSB_DEVICE_DESCRIPTOR;
+
+typedef struct _USB_ENDPOINT_DESCRIPTOR {
+    UCHAR bLength;
+    UCHAR bDescriptorType;
+    UCHAR bEndpointAddress;
+    UCHAR bmAttributes;
+    USHORT wMaxPacketSize;
+    UCHAR bInterval;
+} USB_ENDPOINT_DESCRIPTOR;
+typedef struct _USB_ENDPOINT_DESCRIPTOR *PUSB_ENDPOINT_DESCRIPTOR;
+
+typedef struct _USB_CONFIGURATION_DESCRIPTOR {
+    UCHAR bLength;
+    UCHAR bDescriptorType;
+    USHORT wTotalLength;
+    UCHAR bNumInterfaces;
+    UCHAR bConfigurationValue;
+    UCHAR iConfiguration;
+    UCHAR bmAttributes;
+    UCHAR MaxPower;
+} USB_CONFIGURATION_DESCRIPTOR;
+typedef struct _USB_CONFIGURATION_DESCRIPTOR *PUSB_CONFIGURATION_DESCRIPTOR;
+
+typedef struct _USB_INTERFACE_DESCRIPTOR {
+    UCHAR bLength;
+    UCHAR bDescriptorType;
+    UCHAR bInterfaceNumber;
+    UCHAR bAlternateSetting;
+    UCHAR bNumEndpoints;
+    UCHAR bInterfaceClass;
+    UCHAR bInterfaceSubClass;
+    UCHAR bInterfaceProtocol;
+    UCHAR iInterface;
+} USB_INTERFACE_DESCRIPTOR;
+typedef struct _USB_INTERFACE_DESCRIPTOR *PUSB_INTERFACE_DESCRIPTOR;
+
+typedef struct _USB_STRING_DESCRIPTOR {
+    UCHAR bLength;
+    UCHAR bDescriptorType;
+    WCHAR bString[1];
+} USB_STRING_DESCRIPTOR; 
+typedef struct _USB_STRING_DESCRIPTOR *PUSB_STRING_DESCRIPTOR;
+
+typedef struct _USB_COMMON_DESCRIPTOR {
+    UCHAR bLength;
+    UCHAR bDescriptorType;
+} USB_COMMON_DESCRIPTOR;
+typedef struct _USB_COMMON_DESCRIPTOR *PUSB_COMMON_DESCRIPTOR;
+
+#include <poppack.h>
+
+#endif
diff --git a/include/ddk/usb200.h b/include/ddk/usb200.h
new file mode 100644
index 0000000..162f532
--- /dev/null
+++ b/include/ddk/usb200.h
@@ -0,0 +1,22 @@
+/*
+ * 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 _USB200_
+#define _USB200_
+
+#include "usb100.h"
+
+#endif
diff --git a/include/ddk/usbdlib.h b/include/ddk/usbdlib.h
new file mode 100644
index 0000000..ef9a773
--- /dev/null
+++ b/include/ddk/usbdlib.h
@@ -0,0 +1,26 @@
+/*
+ * 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 __USBDLIB_H__
+#define __USBDLIB_H__
+
+typedef struct _USBD_INTERFACE_LIST_ENTRY {
+    PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+    PUSBD_INTERFACE_INFORMATION Interface;
+} USBD_INTERFACE_LIST_ENTRY;
+typedef struct _USBD_INTERFACE_LIST_ENTRY *PUSBD_INTERFACE_LIST_ENTRY;
+
+#endif
diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h
index 931a130..bfbe0e9 100644
--- a/include/ddk/wdm.h
+++ b/include/ddk/wdm.h
@@ -28,6 +28,8 @@
 #define POINTER_ALIGNMENT
 #endif
 
+typedef LONG KPRIORITY;
+
 typedef ULONG_PTR KSPIN_LOCK, *PKSPIN_LOCK;
 
 struct _KDPC;
@@ -84,6 +86,44 @@ typedef struct _KDEVICE_QUEUE {
   BOOLEAN  Busy;
 } KDEVICE_QUEUE, *PKDEVICE_QUEUE, *RESTRICTED_POINTER PRKDEVICE_QUEUE;
 
+typedef struct _KMUTANT {
+    DISPATCHER_HEADER Header;
+    LIST_ENTRY MutantListEntry;
+    struct _KTHREAD *RESTRICTED_POINTER OwnerThread;
+    BOOLEAN Abandoned;
+    UCHAR ApcDisable;
+} KMUTANT, *PKMUTANT, *RESTRICTED_POINTER PRKMUTANT, KMUTEX, *PKMUTEX, *RESTRICTED_POINTER PRKMUTEX;
+
+typedef enum _KWAIT_REASON
+{
+    Executive,
+    FreePage,
+    PageIn,
+    PoolAllocation,
+    DelayExecution,
+    Suspended,
+    UserRequest,
+    WrExecutive,
+    WrFreePage,
+    WrPageIn,
+    WrDelayExecution,
+    WrSuspended,
+    WrUserRequest,
+    WrQueue,
+    WrLpcReceive,
+    WrLpcReply,
+    WrVirtualMemory,
+    WrPageOut,
+    WrRendezvous,
+    Spare2,
+    Spare3,
+    Spare4,
+    Spare5,
+    Spare6,
+    WrKernel,
+    MaximumWaitReason,
+} KWAIT_REASON;
+
 typedef struct _IO_TIMER *PIO_TIMER;
 typedef struct _ETHREAD *PETHREAD;
 typedef struct _KTHREAD *PKTHREAD;
@@ -125,11 +165,90 @@ typedef struct _WAIT_CONTEXT_BLOCK {
   PKDPC  BufferChainingDpc;
 } WAIT_CONTEXT_BLOCK, *PWAIT_CONTEXT_BLOCK;
 
+#define DO_BUFFERED_IO                  0x00000004
+#define DO_EXCLUSIVE                    0x00000008
+#define DO_DIRECT_IO                    0x00000010
+#define DO_MAP_IO_BUFFER                0x00000020
+#define DO_DEVICE_INITIALIZING          0x00000080
+#define DO_SHUTDOWN_REGISTERED          0x00000800
+#define DO_BUS_ENUMERATED_DEVICE        0x00001000
+#define DO_POWER_PAGABLE                0x00002000
+#define DO_POWER_INRUSH                 0x00004000
+
+#define IO_NO_INCREMENT                     0
+#define IO_CD_ROM_INCREMENT                 1
+#define IO_DISK_INCREMENT                   1
+#define IO_KEYBOARD_INCREMENT               6
+#define IO_MAILSLOT_INCREMENT               2
+#define IO_MOUSE_INCREMENT                  6
+#define IO_NAMED_PIPE_INCREMENT             2
+#define IO_NETWORK_INCREMENT                2
+#define IO_PARALLEL_INCREMENT               1
+#define IO_SERIAL_INCREMENT                 2
+#define IO_SOUND_INCREMENT                  8
+#define IO_VIDEO_INCREMENT                  1
+
 #ifndef DEVICE_TYPE
 #define DEVICE_TYPE ULONG
 #endif
-#define IRP_MJ_MAXIMUM_FUNCTION           0x1b
-#define IRP_MJ_DEVICE_CONTROL             0x0e
+#define IRP_MJ_MAXIMUM_FUNCTION             0x1b
+#define IRP_MJ_CREATE                       0x00
+#define IRP_MJ_CREATE_NAMED_PIPE            0x01
+#define IRP_MJ_CLOSE                        0x02
+#define IRP_MJ_READ                         0x03
+#define IRP_MJ_WRITE                        0x04
+#define IRP_MJ_QUERY_INFORMATION            0x05
+#define IRP_MJ_SET_INFORMATION              0x06
+#define IRP_MJ_QUERY_EA                     0x07
+#define IRP_MJ_SET_EA                       0x08
+#define IRP_MJ_FLUSH_BUFFERS                0x09
+#define IRP_MJ_QUERY_VOLUME_INFORMATION     0x0a
+#define IRP_MJ_SET_VOLUME_INFORMATION       0x0b
+#define IRP_MJ_DIRECTORY_CONTROL            0x0c
+#define IRP_MJ_FILE_SYSTEM_CONTROL          0x0d
+#define IRP_MJ_DEVICE_CONTROL               0x0e
+#define IRP_MJ_INTERNAL_DEVICE_CONTROL      0x0f
+#define IRP_MJ_SHUTDOWN                     0x10
+#define IRP_MJ_LOCK_CONTROL                 0x11
+#define IRP_MJ_CLEANUP                      0x12
+#define IRP_MJ_CREATE_MAILSLOT              0x13
+#define IRP_MJ_QUERY_SECURITY               0x14
+#define IRP_MJ_SET_SECURITY                 0x15
+#define IRP_MJ_POWER                        0x16
+#define IRP_MJ_SYSTEM_CONTROL               0x17
+#define IRP_MJ_DEVICE_CHANGE                0x18
+#define IRP_MJ_QUERY_QUOTA                  0x19
+#define IRP_MJ_SET_QUOTA                    0x1a
+#define IRP_MJ_PNP                          0x1b
+
+#define IRP_MN_START_DEVICE                 0x00
+#define IRP_MN_QUERY_REMOVE_DEVICE          0x01
+#define IRP_MN_REMOVE_DEVICE                0x02
+#define IRP_MN_CANCEL_REMOVE_DEVICE         0x03
+#define IRP_MN_STOP_DEVICE                  0x04
+#define IRP_MN_QUERY_STOP_DEVICE            0x05
+#define IRP_MN_CANCEL_STOP_DEVICE           0x06
+#define IRP_MN_QUERY_DEVICE_RELATIONS       0x07
+#define IRP_MN_QUERY_INTERFACE              0x08
+#define IRP_MN_QUERY_CAPABILITIES           0x09
+#define IRP_MN_QUERY_RESOURCES              0x0A
+#define IRP_MN_QUERY_RESOURCE_REQUIREMENTS  0x0B
+#define IRP_MN_QUERY_DEVICE_TEXT            0x0C
+#define IRP_MN_FILTER_RESOURCE_REQUIREMENTS 0x0D
+#define IRP_MN_READ_CONFIG                  0x0F
+#define IRP_MN_WRITE_CONFIG                 0x10
+#define IRP_MN_EJECT                        0x11
+#define IRP_MN_SET_LOCK                     0x12
+#define IRP_MN_QUERY_ID                     0x13
+#define IRP_MN_QUERY_PNP_DEVICE_STATE       0x14
+#define IRP_MN_QUERY_BUS_INFORMATION        0x15
+#define IRP_MN_DEVICE_USAGE_NOTIFICATION    0x16
+#define IRP_MN_SURPRISE_REMOVAL             0x17
+
+#define IRP_QUOTA_CHARGED               0x01
+#define IRP_ALLOCATED_MUST_SUCCEED      0x02
+#define IRP_ALLOCATED_FIXED_SIZE        0x04
+#define IRP_LOOKASIDE_ALLOCATION        0x08
 
 typedef struct _DEVICE_OBJECT {
   CSHORT  Type;
@@ -628,6 +747,11 @@ typedef NTSTATUS (WINAPI *PIO_COMPLETION_ROUTINE)(
   IN struct _IRP  *Irp,
   IN PVOID  Context);
 
+#define SL_PENDING_RETURNED             0x01
+#define SL_INVOKE_ON_CANCEL             0x20
+#define SL_INVOKE_ON_SUCCESS            0x40
+#define SL_INVOKE_ON_ERROR              0x80
+
 #include <pshpack1.h>
 typedef struct _IO_STACK_LOCATION {
   UCHAR  MajorFunction;
@@ -877,12 +1001,14 @@ PVOID     WINAPI ExAllocatePoolWithQuotaTag(POOL_TYPE,SIZE_T,ULONG);
 void      WINAPI ExFreePool(PVOID);
 void      WINAPI ExFreePoolWithTag(PVOID,ULONG);
 
+PIRP      WINAPI IoAllocateIrp(CCHAR, BOOLEAN);
 NTSTATUS  WINAPI IoCreateDevice(DRIVER_OBJECT*,ULONG,UNICODE_STRING*,DEVICE_TYPE,ULONG,BOOLEAN,DEVICE_OBJECT**);
 NTSTATUS  WINAPI IoCreateDriver(UNICODE_STRING*,PDRIVER_INITIALIZE);
 NTSTATUS  WINAPI IoCreateSymbolicLink(UNICODE_STRING*,UNICODE_STRING*);
 void      WINAPI IoDeleteDevice(DEVICE_OBJECT*);
 void      WINAPI IoDeleteDriver(DRIVER_OBJECT*);
 NTSTATUS  WINAPI IoDeleteSymbolicLink(UNICODE_STRING*);
+void      WINAPI IoFreeIrp(IRP*);
 PEPROCESS WINAPI IoGetCurrentProcess(void);
 
 PKTHREAD  WINAPI KeGetCurrentThread(void);
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 810464c..75777cd 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -4281,6 +4281,33 @@ struct add_fd_completion_reply
 };
 
 
+
+struct call_add_device_request
+{
+    struct request_header __header;
+    data_size_t    drvname_len;
+    /* VARARG(drvname,unicode_str); */
+    /* VARARG(data,bytes); */
+};
+struct call_add_device_reply
+{
+    struct reply_header __header;
+};
+
+
+
+struct get_add_device_request_request
+{
+    struct request_header __header;
+    /* VARARG(drvname,unicode_str); */
+};
+struct get_add_device_request_reply
+{
+    struct reply_header __header;
+    /* VARARG(data,bytes); */
+};
+
+
 enum request
 {
     REQ_new_process,
@@ -4516,6 +4543,8 @@ enum request
     REQ_query_completion,
     REQ_set_completion_info,
     REQ_add_fd_completion,
+    REQ_call_add_device,
+    REQ_get_add_device_request,
     REQ_NB_REQUESTS
 };
 
@@ -4756,6 +4785,8 @@ union generic_request
     struct query_completion_request query_completion_request;
     struct set_completion_info_request set_completion_info_request;
     struct add_fd_completion_request add_fd_completion_request;
+    struct call_add_device_request call_add_device_request;
+    struct get_add_device_request_request get_add_device_request_request;
 };
 union generic_reply
 {
@@ -4994,8 +5025,10 @@ union generic_reply
     struct query_completion_reply query_completion_reply;
     struct set_completion_info_reply set_completion_info_reply;
     struct add_fd_completion_reply add_fd_completion_reply;
+    struct call_add_device_reply call_add_device_reply;
+    struct get_add_device_request_reply get_add_device_request_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 339
+#define SERVER_PROTOCOL_VERSION 340
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/programs/Makefile.in b/programs/Makefile.in
index cd84a36..08ab5eb 100644
--- a/programs/Makefile.in
+++ b/programs/Makefile.in
@@ -46,6 +46,7 @@ SUBDIRS = \
 	winemine \
 	winepath \
 	winetest \
+	wineusb \
 	winevdm \
 	winhlp32 \
 	winver \
@@ -92,6 +93,7 @@ INSTALLSUBDIRS = \
 	winemenubuilder \
 	winemine \
 	winepath \
+	wineusb \
 	winevdm \
 	winhlp32 \
 	winver \
diff --git a/programs/winedevice/Makefile.in b/programs/winedevice/Makefile.in
index 7effe56..5eaa31d 100644
--- a/programs/winedevice/Makefile.in
+++ b/programs/winedevice/Makefile.in
@@ -4,7 +4,7 @@ SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = winedevice.exe
 APPMODE   = -mwindows -municode
-IMPORTS   = advapi32 ntoskrnl.exe kernel32 ntdll
+IMPORTS   = advapi32 ntoskrnl.exe kernel32 ntdll wineusbhub
 
 C_SRCS = \
 	device.c
diff --git a/programs/winedevice/device.c b/programs/winedevice/device.c
index d48017a..6945f96 100644
--- a/programs/winedevice/device.c
+++ b/programs/winedevice/device.c
@@ -22,6 +22,10 @@
 #include "wine/port.h"
 
 #include <stdarg.h>
+#include <limits.h>
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
 
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
@@ -31,13 +35,15 @@
 #include "winreg.h"
 #include "winnls.h"
 #include "winsvc.h"
-#include "ddk/wdm.h"
+#include "ddk/ntddk.h"
 #include "wine/unicode.h"
+#include "wine/server.h"
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(winedevice);
 WINE_DECLARE_DEBUG_CHANNEL(relay);
 
+extern DEVICE_OBJECT *__wine_usbhub_get_pdo( ULONG pdonum, ULONG location, ULONG devnum );
 extern NTSTATUS wine_ntoskrnl_main_loop( HANDLE stop_event );
 
 static WCHAR *driver_name;
@@ -138,6 +144,7 @@ static NTSTATUS init_driver( HMODULE module, UNICODE_STRING *keyname )
     WINE_TRACE( "- DriverInit = %p\n", driver_obj.DriverInit );
     WINE_TRACE( "- DriverStartIo = %p\n", driver_obj.DriverStartIo );
     WINE_TRACE( "- DriverUnload = %p\n", driver_obj.DriverUnload );
+    WINE_TRACE( "- AddDevice = %p\n", driver_extension.AddDevice );
     for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
         WINE_TRACE( "- MajorFunction[%d] = %p\n", i, driver_obj.MajorFunction[i] );
 
@@ -255,10 +262,103 @@ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
 
     if (load_driver())
     {
+        UNICODE_STRING drvname;
+        NTSTATUS ret = STATUS_SUCCESS;
+        UCHAR pnpFuncs[] = { IRP_MN_QUERY_LEGACY_BUS_INFORMATION,
+                             IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
+                             IRP_MN_FILTER_RESOURCE_REQUIREMENTS,
+                             IRP_MN_START_DEVICE,
+                             IRP_MN_QUERY_CAPABILITIES,
+                             IRP_MN_QUERY_PNP_DEVICE_STATE,
+                             IRP_MN_QUERY_DEVICE_RELATIONS };
+        ULONG k;
+        IRP *irp;
+        IO_STACK_LOCATION *irpsp;
+        PDRIVER_DISPATCH dispatch;
+        DEVICE_CAPABILITIES cpbts;
+
         status.dwCurrentState     = SERVICE_RUNNING;
         status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
         SetServiceStatus( service_handle, &status );
 
+        RtlInitUnicodeString( &drvname, driver_name );
+
+        if (driver_extension.AddDevice)
+        {
+            NTSTATUS (*AddDevice)( PDRIVER_OBJECT, PDEVICE_OBJECT ) = driver_extension.AddDevice;
+            PDEVICE_OBJECT pdev_obj = NULL;
+            ULONG pdo_info[3];
+            data_size_t reply_size = 0;
+
+            while (!reply_size)
+                SERVER_START_REQ( get_add_device_request )
+                {
+                    wine_server_add_data( req, drvname.Buffer, drvname.Length );
+                    wine_server_set_reply( req, pdo_info, sizeof(pdo_info) );
+                    ret = wine_server_call( req );
+                    if (STATUS_SUCCESS == ret)
+                        reply_size = wine_server_reply_size( reply );
+                }
+                SERVER_END_REQ;
+
+            pdev_obj = __wine_usbhub_get_pdo( pdo_info[0], pdo_info[1], pdo_info[2] );
+            if (pdev_obj)
+            {
+                WINE_TRACE( "calling AddDevice( %p, %p )\n", &driver_obj, pdev_obj );
+                ret = AddDevice( &driver_obj, pdev_obj );
+                if (STATUS_SUCCESS != ret)
+                    WINE_ERR( "AddDevice failed: %x\n", ret );
+            }
+            else
+            {
+                ret = STATUS_UNSUCCESSFUL;
+                WINE_ERR( "wineusbhub error\n" );
+            }
+        }
+
+        for (k = 0; k < sizeof(pnpFuncs); ++k)
+        {
+            if (STATUS_SUCCESS != ret)
+                break;
+            if (driver_obj.MajorFunction[IRP_MJ_PNP])
+            {
+                irp = IoAllocateIrp( driver_obj.DeviceObject->StackSize, FALSE );
+                if (irp != NULL)
+                {
+                    --irp->CurrentLocation;
+                    irpsp = --irp->Tail.Overlay.s.u.CurrentStackLocation;
+
+                    irp->RequestorMode = KernelMode;
+                    irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
+
+                    irpsp->MajorFunction = IRP_MJ_PNP;
+                    irpsp->MinorFunction = pnpFuncs[k];
+                    irpsp->DeviceObject = driver_obj.DeviceObject;
+
+                    driver_obj.DeviceObject->CurrentIrp = irp;
+
+                    if (IRP_MN_QUERY_CAPABILITIES == pnpFuncs[k])
+                    {
+                        RtlZeroMemory( &cpbts, sizeof(cpbts) );
+                        cpbts.Size = 64;
+                        cpbts.Version = 1;
+                        cpbts.Address = ULONG_MAX;
+                        cpbts.UINumber = ULONG_MAX;
+                        irpsp->Parameters.DeviceCapabilities.Capabilities = &cpbts;
+                    }
+
+                    dispatch = driver_obj.MajorFunction[IRP_MJ_PNP];
+                    ret = dispatch( driver_obj.DeviceObject, irp );
+                    if (STATUS_SUCCESS != ret)
+                        WINE_ERR( "MajorFunction[IRP_MJ_PNP] failed: %x\n", ret );
+
+                    IoFreeIrp( irp );
+                }
+                else
+                    ret = STATUS_UNSUCCESSFUL;
+            }
+        }
+
         wine_ntoskrnl_main_loop( stop_event );
     }
     else WINE_ERR( "driver %s failed to load\n", wine_dbgstr_w(driver_name) );
diff --git a/programs/wineusb/Makefile.in b/programs/wineusb/Makefile.in
new file mode 100644
index 0000000..d985846
--- /dev/null
+++ b/programs/wineusb/Makefile.in
@@ -0,0 +1,15 @@
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../..
+SRCDIR    = @srcdir@
+VPATH     = @srcdir@
+MODULE    = wineusb.exe
+APPMODE   = -mwindows -municode
+IMPORTS   = advapi32 ntoskrnl.exe kernel32 ntdll setupapi
+EXTRALIBS = -lusb
+
+C_SRCS = \
+	main.c
+
+ на MAKE_PROG_RULES@
+
+ на DEPENDENCIES@  # everything below this line is overwritten by make depend
diff --git a/programs/wineusb/main.c b/programs/wineusb/main.c
new file mode 100644
index 0000000..c1a8476
--- /dev/null
+++ b/programs/wineusb/main.c
@@ -0,0 +1,217 @@
+/*
+ * Service process to call USB driver`s AddDevice routine
+ *
+ * Based on winedevice
+ *
+ * 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 "config.h"
+#include "wine/port.h"
+
+#include <stdarg.h>
+#include <usb.h>
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winbase.h"
+#include "winternl.h"
+#include "winreg.h"
+#include "winnls.h"
+#include "winsvc.h"
+#include "winuser.h"
+#include "setupapi.h"
+#include "ddk/wdm.h"
+#include "ddk/usb.h"
+#include "wine/unicode.h"
+#include "wine/server.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wineusb);
+
+static WCHAR service_nameW[] = {'w','i','n','e','u','s','b',0};
+static SERVICE_STATUS_HANDLE service_handle;
+static HANDLE stop_event;
+
+static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context )
+{
+    SERVICE_STATUS status;
+
+    status.dwServiceType             = SERVICE_WIN32;
+    status.dwControlsAccepted        = SERVICE_ACCEPT_STOP;
+    status.dwWin32ExitCode           = 0;
+    status.dwServiceSpecificExitCode = 0;
+    status.dwCheckPoint              = 0;
+    status.dwWaitHint                = 0;
+
+    switch(ctrl)
+    {
+    case SERVICE_CONTROL_STOP:
+    case SERVICE_CONTROL_SHUTDOWN:
+        WINE_TRACE( "shutting down\n" );
+        status.dwCurrentState     = SERVICE_STOP_PENDING;
+        status.dwControlsAccepted = 0;
+        SetServiceStatus( service_handle, &status );
+        SetEvent( stop_event );
+        return NO_ERROR;
+    default:
+        status.dwCurrentState = SERVICE_RUNNING;
+        SetServiceStatus( service_handle, &status );
+        return NO_ERROR;
+    }
+}
+
+static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
+{
+    HDEVINFO set;
+    GUID guid = {0x36FC9E60, 0xC465, 0x11CF, {0x80,0x56,0x44,0x45,0x53,0x54,0x00,0x00}};
+    SERVICE_STATUS status;
+
+    WINE_TRACE( "starting service\n" );
+
+    stop_event = CreateEventW( NULL, TRUE, FALSE, NULL );
+
+    service_handle = RegisterServiceCtrlHandlerExW( service_nameW, service_handler, NULL );
+    if (!service_handle)
+        return;
+
+    status.dwServiceType             = SERVICE_WIN32;
+    status.dwCurrentState            = SERVICE_START_PENDING;
+    status.dwControlsAccepted        = 0;
+    status.dwWin32ExitCode           = 0;
+    status.dwServiceSpecificExitCode = 0;
+    status.dwCheckPoint              = 0;
+    status.dwWaitHint                = 10000;
+    SetServiceStatus( service_handle, &status );
+
+    set = SetupDiGetClassDevsW( &guid, NULL, 0, 0 );
+    if (set != INVALID_HANDLE_VALUE)
+    {
+        UNICODE_STRING drvname;
+        ULONG pdo_info[3] = { 0, 0, 0 };
+        struct usb_device *dev;
+        struct usb_bus *bus;
+        SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
+        DWORD size = 0, i = 0;
+        USHORT vid, pid;
+        char *str;
+        BYTE *buf;
+        BOOL ret;
+
+        usb_init();
+        usb_find_busses();
+        usb_find_devices();
+
+        while (SetupDiEnumDeviceInfo( set, i++, &devInfo ))
+        {
+            SetupDiGetDeviceRegistryPropertyA( set, &devInfo, SPDRP_HARDWAREID,
+                    NULL, NULL, 0, &size );
+            buf = HeapAlloc( GetProcessHeap(), 0, size );
+            if (buf == NULL)
+            {
+                WINE_ERR( "insufficient memory\n" );
+                continue;
+            }
+            ret = SetupDiGetDeviceRegistryPropertyA( set, &devInfo, SPDRP_HARDWAREID,
+                    NULL, buf, size, NULL );
+            if (!ret)
+            {
+                WINE_ERR( "SetupDiGetDeviceRegistryPropertyA failed\n" );
+                HeapFree( GetProcessHeap(), 0, buf );
+                continue;
+            }
+            str = strstr( (char *)buf, "Vid_" );
+            if (str != NULL)
+            {
+                str += 4;
+                vid = strtol( str, NULL, 16 );
+                str = strstr( str, "Pid_" );
+            }
+            if (str == NULL)
+            {
+                WINE_ERR( "bad hardware ID\n" );
+                HeapFree( GetProcessHeap(), 0, buf );
+                continue;
+            }
+            str += 4;
+            pid = strtol( str, NULL, 16 );
+            HeapFree( GetProcessHeap(), 0, buf );
+
+            for (bus = usb_busses; bus && ret; bus = bus->next)
+                for (dev = bus->devices; dev && ret; dev = dev->next)
+                    if (dev->descriptor.idVendor == vid &&
+                            dev->descriptor.idProduct == pid)
+                    {
+                        SetupDiGetDeviceRegistryPropertyW( set, &devInfo,
+                                SPDRP_SERVICE, NULL, NULL, 0, &size );
+                        buf = HeapAlloc( GetProcessHeap(), 0, size );
+                        if (buf == NULL)
+                        {
+                            WINE_ERR( "insufficient memory\n" );
+                            ret = FALSE;
+                            break;
+                        }
+                        ret = SetupDiGetDeviceRegistryPropertyW( set, &devInfo,
+                                SPDRP_SERVICE, NULL, buf, size, NULL );
+                        if (!ret)
+                        {
+                            WINE_ERR( "SetupDiGetDeviceRegistryPropertyW failed\n" );
+                            HeapFree( GetProcessHeap(), 0, buf );
+                            break;
+                        }
+                        /* FIXME: check if driver is loaded */
+                        RtlInitUnicodeString( &drvname, (PWSTR)buf );
+                        pdo_info[1] = bus->location;
+                        pdo_info[2] = dev->devnum;
+
+                        SERVER_START_REQ( call_add_device )
+                        {
+                            req->drvname_len = drvname.Length;
+                            wine_server_add_data( req, drvname.Buffer, drvname.Length );
+                            wine_server_add_data( req, pdo_info, sizeof(pdo_info) );
+                            wine_server_call( req );
+                        }
+                        SERVER_END_REQ;
+
+                        ++pdo_info[0];
+                        HeapFree( GetProcessHeap(), 0, buf );
+                        ret = FALSE;
+                        break;
+                    }
+        }
+        SetupDiDestroyDeviceInfoList( set );
+    }
+    else
+        WINE_ERR( "SetupDiGetClassDevsW failed\n" );
+
+    status.dwCurrentState     = SERVICE_STOPPED;
+    status.dwControlsAccepted = 0;
+    SetServiceStatus( service_handle, &status );
+    WINE_TRACE( "service stopped\n" );
+}
+
+int wmain( int argc, WCHAR *argv[] )
+{
+    SERVICE_TABLE_ENTRYW service_table[2];
+
+    service_table[0].lpServiceName = service_nameW;
+    service_table[0].lpServiceProc = ServiceMain;
+    service_table[1].lpServiceName = NULL;
+    service_table[1].lpServiceProc = NULL;
+
+    StartServiceCtrlDispatcherW( service_table );
+    return 0;
+}
diff --git a/server/device.c b/server/device.c
index abf0ac5..eb1b593 100644
--- a/server/device.c
+++ b/server/device.c
@@ -32,6 +32,7 @@
 #include "file.h"
 #include "handle.h"
 #include "request.h"
+#include "unicode.h"
 
 struct ioctl_call
 {
@@ -160,6 +161,41 @@ static const struct fd_ops device_fd_ops =
 };
 
 
+static struct list add_dev_requests_list = LIST_INIT(add_dev_requests_list);
+
+struct add_dev_request
+{
+    struct object          obj;       /* object header */
+    struct unicode_str     drvname;   /* driver name */
+    void                  *data;      /* driver specific data */
+    data_size_t            size;      /* driver specific data size */
+    struct list            entry;     /* entry in add_dev_requests_list */
+};
+
+static void add_dev_req_dump( struct object *obj, int verbose );
+static void add_dev_req_destroy( struct object *obj );
+
+static const struct object_ops add_dev_requests_ops =
+{
+    sizeof(struct add_dev_request),   /* size */
+    add_dev_req_dump,                 /* dump */
+    no_get_type,                      /* get_type */
+    no_add_queue,                     /* add_queue */
+    NULL,                             /* remove_queue */
+    NULL,                             /* signaled */
+    no_satisfied,                     /* satisfied */
+    no_signal,                        /* signal */
+    no_get_fd,                        /* get_fd */
+    no_map_access,                    /* map_access */
+    default_get_sd,                   /* get_sd */
+    default_set_sd,                   /* set_sd */
+    no_lookup_name,                   /* lookup_name */
+    no_open_file,                     /* open_file */
+    no_close_handle,                  /* close_handle */
+    add_dev_req_destroy               /* destroy */
+};
+
+
 static void ioctl_call_dump( struct object *obj, int verbose )
 {
     struct ioctl_call *ioctl = (struct ioctl_call *)obj;
@@ -425,6 +461,27 @@ static struct device_manager *create_device_manager(void)
 }
 
 
+static void add_dev_req_dump( struct object *obj, int verbose )
+{
+    struct add_dev_request *add_dev_req = (struct add_dev_request *)obj;
+    struct unicode_str *drvname = &add_dev_req->drvname;
+
+    fprintf( stderr, "AddDevice " );
+    if (drvname)
+        dump_strW( drvname->str, drvname->len / sizeof(WCHAR), stderr, "" );
+    fputc( '\n', stderr );
+}
+
+static void add_dev_req_destroy( struct object *obj )
+{
+    struct add_dev_request *add_dev_req = (struct add_dev_request *)obj;
+
+    list_remove( &add_dev_req->entry );
+    /* data and drvname.str are in the same memory block pointed to by drvname.str */
+    free( (void *)add_dev_req->drvname.str );
+}
+
+
 /* create a device manager */
 DECL_HANDLER(create_device_manager)
 {
@@ -554,3 +611,57 @@ DECL_HANDLER(get_ioctl_result)
     }
     release_object( device );
 }
+
+
+DECL_HANDLER(call_add_device)
+{
+    void *p;
+    struct add_dev_request *add_dev_req;
+    data_size_t size;
+
+    size = get_req_data_size();
+    p = mem_alloc( size );
+    if (p)
+    {
+        add_dev_req = alloc_object( &add_dev_requests_ops );
+        if (add_dev_req)
+        {
+            memcpy( p, get_req_data(), size );
+            add_dev_req->drvname.len = req->drvname_len;
+            add_dev_req->drvname.str = p;
+            add_dev_req->data = (char *)p + req->drvname_len;
+            add_dev_req->size = size - req->drvname_len;
+            list_add_tail( &add_dev_requests_list, &add_dev_req->entry );
+        }
+        else
+            free( p );
+    }
+}
+
+
+DECL_HANDLER(get_add_device_request)
+{
+    struct unicode_str drvname;
+    struct add_dev_request *add_dev_req;
+    int found = 0;
+
+    get_req_unicode_str( &drvname );
+    LIST_FOR_EACH_ENTRY( add_dev_req, &add_dev_requests_list, struct add_dev_request, entry )
+    {
+        struct unicode_str *p = &add_dev_req->drvname;
+
+        if (p->len != drvname.len) continue;
+        if (!strncmpiW( drvname.str, p->str, p->len/sizeof(WCHAR) ))
+        {
+            found = 1;
+            break;
+        }
+    }
+    if (found)
+    {
+        set_reply_data( add_dev_req->data, add_dev_req->size );
+        release_object( add_dev_req );
+    }
+    else
+        set_reply_data( NULL, 0 );
+}
diff --git a/server/protocol.def b/server/protocol.def
index 01d94d2..239a9c4 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -3066,3 +3066,19 @@ enum message_type
     unsigned int   status;        /* completion status */
     unsigned long  information;   /* IO_STATUS_BLOCK Information */
 @END
+
+
+/* Call AddDevice function in driver */
+ на REQ(call_add_device)
+    data_size_t    drvname_len;   /* driver name length */
+    VARARG(drvname,unicode_str);  /* driver name */
+    VARARG(data,bytes);           /* driver specific data */
+ на END
+
+
+/* Check if it should call AddDevice function */
+ на REQ(get_add_device_request)
+    VARARG(drvname,unicode_str);  /* driver name */
+ на REPLY
+    VARARG(data,bytes);           /* driver specific data */
+ на END
diff --git a/server/request.h b/server/request.h
index 496c5ff..e9864e8 100644
--- a/server/request.h
+++ b/server/request.h
@@ -344,6 +344,8 @@ DECL_HANDLER(remove_completion);
 DECL_HANDLER(query_completion);
 DECL_HANDLER(set_completion_info);
 DECL_HANDLER(add_fd_completion);
+DECL_HANDLER(call_add_device);
+DECL_HANDLER(get_add_device_request);
 
 #ifdef WANT_REQUEST_HANDLERS
 
@@ -583,6 +585,8 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
     (req_handler)req_query_completion,
     (req_handler)req_set_completion_info,
     (req_handler)req_add_fd_completion,
+    (req_handler)req_call_add_device,
+    (req_handler)req_get_add_device_request,
 };
 #endif  /* WANT_REQUEST_HANDLERS */
 
diff --git a/server/trace.c b/server/trace.c
index bbae524..1fd2cf9 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -3782,6 +3782,28 @@ static void dump_add_fd_completion_request( const struct add_fd_completion_reque
     fprintf( stderr, " information=%lx", req->information );
 }
 
+static void dump_call_add_device_request( const struct call_add_device_request *req )
+{
+    fprintf( stderr, " drvname_len=%u,", req->drvname_len );
+    fprintf( stderr, " drvname=" );
+    dump_varargs_unicode_str( cur_size );
+    fputc( ',', stderr );
+    fprintf( stderr, " data=" );
+    dump_varargs_bytes( cur_size );
+}
+
+static void dump_get_add_device_request_request( const struct get_add_device_request_request *req )
+{
+    fprintf( stderr, " drvname=" );
+    dump_varargs_unicode_str( cur_size );
+}
+
+static void dump_get_add_device_request_reply( const struct get_add_device_request_reply *req )
+{
+    fprintf( stderr, " data=" );
+    dump_varargs_bytes( cur_size );
+}
+
 static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_new_process_request,
     (dump_func)dump_get_new_process_info_request,
@@ -4016,6 +4038,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_query_completion_request,
     (dump_func)dump_set_completion_info_request,
     (dump_func)dump_add_fd_completion_request,
+    (dump_func)dump_call_add_device_request,
+    (dump_func)dump_get_add_device_request_request,
 };
 
 static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -4252,6 +4276,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_query_completion_reply,
     (dump_func)0,
     (dump_func)0,
+    (dump_func)0,
+    (dump_func)dump_get_add_device_request_reply,
 };
 
 static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -4488,6 +4514,8 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
     "query_completion",
     "set_completion_info",
     "add_fd_completion",
+    "call_add_device",
+    "get_add_device_request",
 };
 
 static const struct
diff --git a/tools/wine.inf.in b/tools/wine.inf.in
index e5028e0..989c9f9 100644
--- a/tools/wine.inf.in
+++ b/tools/wine.inf.in
@@ -80,10 +80,12 @@ AddReg=\
 [DefaultInstall.Services]
 AddService=MountMgr,0x800,MountMgrService
 AddService=Spooler,0,SpoolerService
+AddService=Wineusb,0,WineusbService
 
 [DefaultInstall.NT.Services]
 AddService=MountMgr,0x800,MountMgrService
 AddService=Spooler,0,SpoolerService
+AddService=Wineusb,0,WineusbService
 
 [Strings]
 MciExtStr="Software\Microsoft\Windows NT\CurrentVersion\MCI Extensions"
@@ -2701,6 +2703,14 @@ StartType=4
 ErrorControl=1
 LoadOrderGroup="SpoolerGroup"
 
+[WineusbService]
+Description="WineUSB"
+DisplayName="WineUSB"
+ServiceBinary="%11%\wineusb.exe"
+ServiceType=0x10
+StartType=2
+ErrorControl=1
+
 [Services]
 HKLM,"System\CurrentControlSet\Services\VxD\MSTCP",,,""
 


Подробная информация о списке рассылки Wine-devel