[Wine-patches] [eterhack] eterbug #4301

Alexander Morozov amorozov на etersoft.ru
Чт Мар 3 22:09:57 MSK 2011


----------- следующая часть -----------
From ea6f2340eeccbf178ce0195b90207200f638b6c3 Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Thu, 3 Mar 2011 21:22:27 +0300
Subject: [eterhack 01/20] Move parport and usbhub drivers to mountmgr.sys (eterbug #4301).

---
 configure                           |    2 -
 configure.ac                        |    2 -
 dlls/hal/hal.c                      |   10 +-
 dlls/mountmgr.sys/Makefile.in       |    7 +-
 dlls/mountmgr.sys/device.c          |    2 -
 dlls/mountmgr.sys/mountmgr.c        |    8 +
 dlls/mountmgr.sys/mountmgr.h        |    4 +
 dlls/mountmgr.sys/mountmgr.sys.spec |    9 +-
 dlls/mountmgr.sys/parport.c         |  361 ++++++++
 dlls/mountmgr.sys/usbhub.c          | 1726 ++++++++++++++++++++++++++++++++++
 dlls/ntoskrnl.exe/instr.c           |   10 +-
 dlls/parport.sys/Makefile.in        |   10 -
 dlls/parport.sys/parport.c          |  393 --------
 dlls/parport.sys/parport.sys.spec   |    8 -
 dlls/usbhub.sys/Makefile.in         |   10 -
 dlls/usbhub.sys/usbhub.c            | 1733 -----------------------------------
 dlls/usbhub.sys/usbhub.sys.spec     |    1 -
 programs/services/services.c        |    4 +-
 tools/wine.inf.in                   |   18 -
 19 files changed, 2124 insertions(+), 2194 deletions(-)
 create mode 100644 dlls/mountmgr.sys/parport.c
 create mode 100644 dlls/mountmgr.sys/usbhub.c
 delete mode 100644 dlls/parport.sys/Makefile.in
 delete mode 100644 dlls/parport.sys/parport.c
 delete mode 100644 dlls/parport.sys/parport.sys.spec
 delete mode 100644 dlls/usbhub.sys/Makefile.in
 delete mode 100644 dlls/usbhub.sys/usbhub.c
 delete mode 100644 dlls/usbhub.sys/usbhub.sys.spec

diff --git a/configure b/configure
index 47d7c04..80c5c7d 100755
--- a/configure
+++ b/configure
@@ -15539,7 +15539,6 @@ wine_fn_config_dll openal32 enable_openal32
 wine_fn_config_dll opencl enable_opencl
 wine_fn_config_dll opengl32 enable_opengl32 implib
 wine_fn_config_test dlls/opengl32/tests opengl32_test
-wine_fn_config_dll parport.sys enable_parport_sys implib
 wine_fn_config_dll pdh enable_pdh implib
 wine_fn_config_test dlls/pdh/tests pdh_test
 wine_fn_config_dll pidgen enable_pidgen
@@ -15633,7 +15632,6 @@ wine_fn_config_dll url enable_url implib
 wine_fn_config_dll urlmon enable_urlmon implib
 wine_fn_config_test dlls/urlmon/tests urlmon_test
 wine_fn_config_dll usbd.sys enable_usbd_sys implib
-wine_fn_config_dll usbhub.sys enable_usbhub_sys
 wine_fn_config_dll user.exe16 enable_win16
 wine_fn_config_dll user32 enable_user32 po,implib
 wine_fn_config_test dlls/user32/tests user32_test
diff --git a/configure.ac b/configure.ac
index 1a80dc9..32eb80e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2734,7 +2734,6 @@ WINE_CONFIG_DLL(openal32)
 WINE_CONFIG_DLL(opencl)
 WINE_CONFIG_DLL(opengl32,,[implib])
 WINE_CONFIG_TEST(dlls/opengl32/tests)
-WINE_CONFIG_DLL(parport.sys,,[implib])
 WINE_CONFIG_DLL(pdh,,[implib])
 WINE_CONFIG_TEST(dlls/pdh/tests)
 WINE_CONFIG_DLL(pidgen)
@@ -2828,7 +2827,6 @@ WINE_CONFIG_DLL(url,,[implib])
 WINE_CONFIG_DLL(urlmon,,[implib])
 WINE_CONFIG_TEST(dlls/urlmon/tests)
 WINE_CONFIG_DLL(usbd.sys,,[implib])
-WINE_CONFIG_DLL(usbhub.sys)
 WINE_CONFIG_DLL(user.exe16,enable_win16)
 WINE_CONFIG_DLL(user32,,[po,implib])
 WINE_CONFIG_TEST(dlls/user32/tests)
diff --git a/dlls/hal/hal.c b/dlls/hal/hal.c
index d1f3764..7d1a23a 100644
--- a/dlls/hal/hal.c
+++ b/dlls/hal/hal.c
@@ -194,14 +194,14 @@ void WINAPI KeStallExecutionProcessor(ULONG MicroSeconds)
 
 static void init_parport(void)
 {
-    static const WCHAR parportW[] = {'p','a','r','p','o','r','t','.','s','y','s',0};
+    static const WCHAR mountmgrW[] = {'m','o','u','n','t','m','g','r','.','s','y','s',0};
 
-    HMODULE parport = GetModuleHandleW( parportW );
+    HMODULE mountmgr = GetModuleHandleW( mountmgrW );
 
-    if (parport)
+    if (mountmgr)
     {
-        pp_read = (void *)GetProcAddress( parport, "__wine_read_parport" );
-        pp_write = (void *)GetProcAddress( parport, "__wine_write_parport" );
+        pp_read = (void *)GetProcAddress( mountmgr, "__wine_read_parport" );
+        pp_write = (void *)GetProcAddress( mountmgr, "__wine_write_parport" );
     }
     if (!pp_read || !pp_write)
         ERR( "failed to load parport functions\n" );
diff --git a/dlls/mountmgr.sys/Makefile.in b/dlls/mountmgr.sys/Makefile.in
index c4605e4..14b033f 100644
--- a/dlls/mountmgr.sys/Makefile.in
+++ b/dlls/mountmgr.sys/Makefile.in
@@ -3,12 +3,15 @@ IMPORTS   = uuid advapi32 ntoskrnl.exe setupapi
 DELAYIMPORTS = user32
 EXTRADLLFLAGS = -Wb,--subsystem,native
 EXTRADEFS = @HALINCL@
-EXTRALIBS = @DISKARBITRATIONLIB@
+EXTRAINCL = @USBINCL@
+EXTRALIBS = @DISKARBITRATIONLIB@ @USBLIBS@ @IEEE1284LIBS@
 
 C_SRCS = \
 	device.c \
 	diskarb.c \
 	hal.c \
-	mountmgr.c
+	mountmgr.c \
+	parport.c \
+	usbhub.c
 
 @MAKE_DLL_RULES@
diff --git a/dlls/mountmgr.sys/device.c b/dlls/mountmgr.sys/device.c
index ed8e8c6..8142c93 100644
--- a/dlls/mountmgr.sys/device.c
+++ b/dlls/mountmgr.sys/device.c
@@ -29,8 +29,6 @@
 #include <sys/types.h>
 #include <dirent.h>
 
-#define INITGUID
-
 #include "mountmgr.h"
 #include "winreg.h"
 #include "winuser.h"
diff --git a/dlls/mountmgr.sys/mountmgr.c b/dlls/mountmgr.sys/mountmgr.c
index c6dca13..191d969 100644
--- a/dlls/mountmgr.sys/mountmgr.c
+++ b/dlls/mountmgr.sys/mountmgr.c
@@ -445,6 +445,8 @@ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
     static const WCHAR device_mountmgrW[] = {'\\','D','e','v','i','c','e','\\','M','o','u','n','t','P','o','i','n','t','M','a','n','a','g','e','r',0};
     static const WCHAR link_mountmgrW[] = {'\\','?','?','\\','M','o','u','n','t','P','o','i','n','t','M','a','n','a','g','e','r',0};
     static const WCHAR harddiskW[] = {'\\','D','r','i','v','e','r','\\','H','a','r','d','d','i','s','k',0};
+    static const WCHAR parportW[] = {'\\','D','r','i','v','e','r','\\','P','a','r','p','o','r','t',0};
+    static const WCHAR usbhubW[] = {'\\','D','r','i','v','e','r','\\','u','s','b','h','u','b',0};
     static const WCHAR devicemapW[] = {'H','A','R','D','W','A','R','E','\\','D','E','V','I','C','E','M','A','P',0};
     static const WCHAR parallelW[] = {'P','A','R','A','L','L','E','L',' ','P','O','R','T','S',0};
     static const WCHAR serialW[] = {'S','E','R','I','A','L','C','O','M','M',0};
@@ -486,6 +488,12 @@ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
     RtlInitUnicodeString( &nameW, harddiskW );
     status = IoCreateDriver( &nameW, harddisk_driver_entry );
 
+    RtlInitUnicodeString( &nameW, parportW );
+    status = IoCreateDriver( &nameW, parport_driver_entry );
+
+    RtlInitUnicodeString( &nameW, usbhubW );
+    status = IoCreateDriver( &nameW, usbhub_driver_entry );
+
     if (automount_enabled())
     {
         initialize_hal();
diff --git a/dlls/mountmgr.sys/mountmgr.h b/dlls/mountmgr.sys/mountmgr.h
index 6d29c2f..ba62543 100644
--- a/dlls/mountmgr.sys/mountmgr.h
+++ b/dlls/mountmgr.sys/mountmgr.h
@@ -32,12 +32,16 @@
 #define WINE_MOUNTMGR_EXTENSIONS
 #include "ntddstor.h"
 #include "ntddcdrm.h"
+#include "ntddpar.h"
 #include "ddk/wdm.h"
 #include "ddk/mountmgr.h"
 
 extern void initialize_hal(void);
 extern void initialize_diskarbitration(void);
 
+extern NTSTATUS WINAPI usbhub_driver_entry( DRIVER_OBJECT *driver, UNICODE_STRING *path );
+extern NTSTATUS WINAPI parport_driver_entry( DRIVER_OBJECT *driver, UNICODE_STRING *path );
+
 /* device functions */
 
 enum device_type
diff --git a/dlls/mountmgr.sys/mountmgr.sys.spec b/dlls/mountmgr.sys/mountmgr.sys.spec
index 76421d7..4848c4a 100644
--- a/dlls/mountmgr.sys/mountmgr.sys.spec
+++ b/dlls/mountmgr.sys/mountmgr.sys.spec
@@ -1 +1,8 @@
-# nothing to export
+################################################################
+# Wine internal extensions
+#
+# All functions must be prefixed with '__wine_' (for internal functions)
+# or 'wine_' (for user-visible functions) to avoid namespace conflicts.
+
+@ cdecl __wine_read_parport(ptr)
+@ cdecl __wine_write_parport(ptr long)
diff --git a/dlls/mountmgr.sys/parport.c b/dlls/mountmgr.sys/parport.c
new file mode 100644
index 0000000..4f460d0
--- /dev/null
+++ b/dlls/mountmgr.sys/parport.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright 2009 - 2011 Alexander Morozov for Etersoft
+ *
+ * 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"
+
+#ifdef HAVE_LIBIEEE1284
+#include <ieee1284.h>
+#endif
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
+#include "mountmgr.h"
+#include "winreg.h"
+#include "winuser.h"
+#include "setupapi.h"
+#include "ddk/parallel.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(parport);
+
+#ifdef HAVE_LIBIEEE1284
+static const WCHAR device_idW[] = {'A','C','P','I','\\',
+                                   'P','N','P','0','4','0','0','\\','%','d',0};
+
+struct ParPortExtension
+{
+    struct parport *pp;
+    int claimed;
+    int n;
+    UNICODE_STRING interface;
+};
+
+static struct parport_list pp_list;
+
+static DRIVER_OBJECT *parport_driver;
+
+static BOOLEAN WINAPI parport_try( void *context )
+{
+    struct ParPortExtension *ppe = context;
+
+    if (ieee1284_open( ppe->pp, 0, NULL ) != E1284_OK)
+        return FALSE;
+    if (ieee1284_claim( ppe->pp ) != E1284_OK)
+    {
+        ieee1284_close( ppe->pp );
+        return FALSE;
+    }
+    ppe->claimed = 1;
+    return TRUE;
+}
+
+static void WINAPI parport_free( void *context )
+{
+    struct ParPortExtension *ppe = context;
+
+    if (ppe->claimed)
+    {
+        ieee1284_release( ppe->pp );
+        ieee1284_close( ppe->pp );
+        ppe->claimed = 0;
+    }
+}
+
+static ULONG WINAPI parport_query_waiters( void *context )
+{
+    FIXME( "stub: %p\n", context );
+    return 0;
+}
+
+static NTSTATUS WINAPI parport_ioctl( DEVICE_OBJECT *device, IRP *irp )
+{
+    IO_STACK_LOCATION *irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
+    NTSTATUS status = STATUS_NOT_SUPPORTED;
+
+    TRACE( "%p, %p\n", device, irp );
+
+    switch(irpsp->Parameters.DeviceIoControl.IoControlCode)
+    {
+    case IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE:
+        if (parport_try( device->DeviceExtension ))
+            status = STATUS_SUCCESS;
+        else
+            status = STATUS_UNSUCCESSFUL;
+        break;
+    case IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO:
+    {
+        PARALLEL_PORT_INFORMATION *ppi = irp->AssociatedIrp.SystemBuffer;
+        struct ParPortExtension *ppe = device->DeviceExtension;
+
+        if (irpsp->Parameters.DeviceIoControl.OutputBufferLength
+                < sizeof(PARALLEL_PORT_INFORMATION))
+        {
+            status = STATUS_BUFFER_TOO_SMALL;
+            break;
+        }
+        RtlZeroMemory( ppi, sizeof(*ppi) );
+        ppi->OriginalController.QuadPart = ppe->pp->base_addr;
+        ppi->Controller = (PUCHAR)ppe->pp->base_addr;
+        ppi->TryAllocatePort = parport_try;
+        ppi->FreePort = parport_free;
+        ppi->QueryNumWaiters = parport_query_waiters;
+        ppi->Context = ppe;
+        irp->IoStatus.Information = sizeof(PARALLEL_PORT_INFORMATION);
+        status = STATUS_SUCCESS;
+        break;
+    }
+    case IOCTL_INTERNAL_GET_MORE_PARALLEL_PORT_INFO:
+        TRACE( "IOCTL_INTERNAL_GET_MORE_PARALLEL_PORT_INFO: stub\n" );
+        irp->IoStatus.Information = 0;
+        status = STATUS_SUCCESS;
+        break;
+    case IOCTL_INTERNAL_PARALLEL_PORT_FREE:
+        parport_free( device->DeviceExtension );
+        status = STATUS_SUCCESS;
+        break;
+    default:
+        FIXME( "IOCTL %08x is not implemented\n",
+                irpsp->Parameters.DeviceIoControl.IoControlCode );
+            status = STATUS_NOT_IMPLEMENTED;
+    }
+    irp->IoStatus.u.Status = status;
+    IoCompleteRequest( irp, IO_NO_INCREMENT );
+    return status;
+}
+
+static NTSTATUS WINAPI parport_pnp( DEVICE_OBJECT *device, IRP *irp )
+{
+    static const WCHAR fmtW[] = {'%','d',0};
+
+    IO_STACK_LOCATION *irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
+    NTSTATUS status;
+
+    TRACE( "%p, %p\n", device, irp );
+
+    switch (irpsp->MinorFunction)
+    {
+    case IRP_MN_QUERY_ID:
+        switch (irpsp->Parameters.QueryId.IdType)
+        {
+        case BusQueryDeviceID:
+        {
+            WCHAR *device_id = ExAllocatePool( PagedPool, sizeof(device_idW) );
+
+            if (device_id == NULL)
+            {
+                status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+            strcpyW( device_id, device_idW );
+            *strrchrW( device_id, '\\' ) = 0;
+            status = STATUS_SUCCESS;
+            irp->IoStatus.Information = (ULONG_PTR)device_id;
+            break;
+        }
+        case BusQueryInstanceID:
+        {
+            ULONG len = 16;
+            struct ParPortExtension *ppe = device->DeviceExtension;
+            WCHAR *instance_id = ExAllocatePool( PagedPool, len * sizeof(WCHAR) );
+
+            if (instance_id == NULL)
+            {
+                status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+            snprintfW( instance_id, len, fmtW, ppe->n );
+            status = STATUS_SUCCESS;
+            irp->IoStatus.Information = (ULONG_PTR)instance_id;
+            break;
+        }
+        default:
+            FIXME( "IRP_MN_QUERY_ID: IdType %u is not implemented\n",
+                    irpsp->Parameters.QueryId.IdType );
+            status = STATUS_NOT_IMPLEMENTED;
+        }
+        break;
+    default:
+        FIXME( "function %08x is not implemented\n", irpsp->MinorFunction );
+        status = STATUS_NOT_IMPLEMENTED;
+    }
+    irp->IoStatus.u.Status = status;
+    IoCompleteRequest( irp, IO_NO_INCREMENT );
+    return STATUS_SUCCESS;
+}
+
+static void register_parport_device( DEVICE_OBJECT *parport_dev, int n )
+{
+    static const WCHAR acpiW[] = {'A','C','P','I',0};
+
+    struct ParPortExtension *ppe;
+    HDEVINFO set;
+    SP_DEVINFO_DATA devInfo;
+    WCHAR *devnameW;
+    ULONG size;
+    NTSTATUS status;
+
+    size = sizeof(device_idW) + 16 * sizeof(WCHAR);
+    devnameW = ExAllocatePool( PagedPool, size );
+    if (devnameW == NULL) return;
+    snprintfW( devnameW, size / sizeof(WCHAR), device_idW, n );
+
+    set = SetupDiGetClassDevsW( NULL, acpiW, 0, DIGCF_ALLCLASSES );
+    if (set == INVALID_HANDLE_VALUE) goto done;
+    devInfo.cbSize = sizeof(SP_DEVINFO_DATA);
+    if (SetupDiCreateDeviceInfoW( set, devnameW, &GUID_SERENUM_BUS_ENUMERATOR,
+            NULL, NULL, 0, &devInfo ))
+    {
+        if (!SetupDiRegisterDeviceInfo( set, &devInfo, 0, NULL, NULL, NULL ))
+            goto done;
+    }
+    else
+    {
+        if (ERROR_DEVINST_ALREADY_EXISTS != GetLastError())
+            goto done;
+    }
+
+    ppe = parport_dev->DeviceExtension;
+    status = IoRegisterDeviceInterface( parport_dev, &GUID_DEVINTERFACE_PARALLEL,
+            NULL, &ppe->interface );
+    if (status == STATUS_SUCCESS)
+        IoSetDeviceInterfaceState( &ppe->interface, TRUE );
+done:
+    if (set != INVALID_HANDLE_VALUE)
+        SetupDiDestroyDeviceInfoList( set );
+    ExFreePool( devnameW );
+}
+
+static void create_parport_device( DRIVER_OBJECT *driver, int n, struct parport *pp )
+{
+    static const WCHAR parallel_portW[] = {'\\','D','e','v','i','c','e',
+                                           '\\','P','a','r','a','l','l','e','l',
+                                           'P','o','r','t','%','d',0};
+
+    struct ParPortExtension *ppe;
+    UNICODE_STRING parallel_port;
+    DEVICE_OBJECT *parport_dev;
+    WCHAR device_name[MAX_PATH];
+    NTSTATUS status;
+
+    snprintfW( device_name, MAX_PATH, parallel_portW, n );
+    RtlInitUnicodeString( &parallel_port, device_name );
+    status = IoCreateDevice( driver, sizeof(struct ParPortExtension), &parallel_port,
+            FILE_DEVICE_PARALLEL_PORT, FILE_DEVICE_SECURE_OPEN, FALSE, &parport_dev );
+    if (status == STATUS_SUCCESS)
+    {
+        ppe = parport_dev->DeviceExtension;
+        RtlZeroMemory( ppe, sizeof(*ppe) );
+        ppe->pp = pp;
+        ppe->n = n;
+        register_parport_device( parport_dev, n );
+        parport_dev->Flags &= ~DO_DEVICE_INITIALIZING;
+    }
+}
+
+static void enum_par_devices( DRIVER_OBJECT *driver )
+{
+    struct parport *pp;
+    int k;
+
+    ieee1284_find_ports( &pp_list, 0 );
+    for (k = 0; k < pp_list.portc; ++k)
+    {
+        pp = pp_list.portv[k];
+        create_parport_device( driver, k, pp );
+    }
+}
+
+static struct ParPortExtension *get_parport_ext( UCHAR *port, ULONG *offset )
+{
+    DEVICE_OBJECT *device = parport_driver->DeviceObject;
+    struct ParPortExtension *ppe;
+
+    while (device)
+    {
+        ppe = device->DeviceExtension;
+        *offset = (ULONG)port - ppe->pp->base_addr;
+        if (*offset <= DCR_OFFSET) return ppe;
+        device = device->NextDevice;
+    }
+    return NULL;
+}
+
+static int read_parport( struct parport *pp, ULONG offset )
+{
+    if (DATA_OFFSET == offset) return ieee1284_read_data( pp );
+    if (DSR_OFFSET == offset) return ieee1284_read_status( pp ) ^ S1284_INVERTED;
+    if (DCR_OFFSET == offset) return ieee1284_read_control( pp ) ^ C1284_INVERTED;
+    return -1;
+}
+
+static void write_parport( struct parport *pp, UCHAR value, ULONG offset )
+{
+    if (DATA_OFFSET == offset) ieee1284_write_data( pp, value );
+    /* FIXME: see NOTE in ieee1284.h */
+    else if (DCR_OFFSET == offset) ieee1284_write_control( pp, value ^ C1284_INVERTED );
+}
+#endif  /* HAVE_LIBIEEE1284 */
+
+UCHAR CDECL __wine_read_parport( UCHAR *port )
+{
+#ifdef HAVE_LIBIEEE1284
+    int ret = -1;
+    ULONG offset;
+    struct ParPortExtension *ppe = get_parport_ext( port, &offset );
+
+    if (!ppe) return 0xff;
+    if (ppe->claimed) ret = read_parport( ppe->pp, offset );
+    else if (parport_try( ppe ))
+    {
+        ret = read_parport( ppe->pp, offset );
+        parport_free( ppe );
+    }
+    if (ret >= 0) return ret;
+#endif
+    return 0xff;
+}
+
+void CDECL __wine_write_parport( UCHAR *port, UCHAR value )
+{
+#ifdef HAVE_LIBIEEE1284
+    ULONG offset;
+    struct ParPortExtension *ppe = get_parport_ext( port, &offset );
+
+    if (!ppe) return;
+    if (ppe->claimed) write_parport( ppe->pp, value, offset );
+    else if (parport_try( ppe ))
+    {
+        write_parport( ppe->pp, value, offset );
+        parport_free( ppe );
+    }
+#endif
+}
+
+NTSTATUS WINAPI parport_driver_entry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
+{
+#ifdef HAVE_LIBIEEE1284
+    driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = parport_ioctl;
+    driver->MajorFunction[IRP_MJ_PNP] = parport_pnp;
+    parport_driver = driver;
+    enum_par_devices( driver );
+#endif
+    return STATUS_SUCCESS;
+}
diff --git a/dlls/mountmgr.sys/usbhub.c b/dlls/mountmgr.sys/usbhub.c
new file mode 100644
index 0000000..2ec236e
--- /dev/null
+++ b/dlls/mountmgr.sys/usbhub.c
@@ -0,0 +1,1726 @@
+/*
+ * Copyright 2008 - 2011 Alexander Morozov for Etersoft
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_LIBUSB_H
+#include <libusb.h>
+#elif defined(HAVE_USB_H)
+#include <usb.h>
+#endif
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+#define INITGUID
+
+#include "mountmgr.h"
+#include "winreg.h"
+#include "winsvc.h"
+#include "winuser.h"
+#include "setupapi.h"
+#include "cfgmgr32.h"
+#include "devguid.h"
+#define WINE_USBHUB_EXTENSIONS
+#include "ddk/usbdrivr.h"
+#include "ddk/usbioctl.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+#include "wine/list.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(usbhub);
+
+extern NTSTATUS CDECL __wine_add_device( DRIVER_OBJECT *driver, DEVICE_OBJECT *dev );
+extern DRIVER_OBJECT * CDECL __wine_get_driver_object( const WCHAR *service );
+extern NTSTATUS CDECL __wine_start_device( DEVICE_OBJECT *device );
+
+#define NUMBER_OF_PORTS 8
+
+static const WCHAR usbW[] = {'U','S','B',0};
+
+static struct list Devices = LIST_INIT(Devices);
+
+struct DeviceInstance
+{
+    struct list entry;
+    USHORT vid;
+    USHORT pid;
+    char *instance_id;
+    WCHAR *service;
+#ifdef HAVE_LIBUSB_H
+    libusb_device *dev;
+#else
+    struct usb_device *dev;
+#endif
+};
+
+struct PdoExtension
+{
+    struct DeviceInstance *instance;
+};
+
+#ifdef HAVE_LIBUSB
+
+static void add_data( unsigned char **dst, ULONG *dst_size, const void *src, ULONG src_size )
+{
+    int copy;
+
+    copy = (src_size >= *dst_size) ? *dst_size : src_size;
+    memcpy( *dst, src, copy );
+    *dst += copy;
+    *dst_size -= copy;
+}
+
+static NTSTATUS WINAPI usbhub_ioctl( DEVICE_OBJECT *device, IRP *irp )
+{
+    static const WCHAR device_idW[] = {'U','S','B','\\',
+                                       'V','i','d','_','%','0','4','x','&',
+                                       'P','i','d','_','%','0','4','x','\\',0};
+    static const WCHAR root_hub_idW[] = {'U','S','B','\\',
+                                         'R','O','O','T','_','H','U','B','\\',0};
+
+    IO_STACK_LOCATION *irpsp;
+    NTSTATUS status = STATUS_UNSUCCESSFUL;
+    struct DeviceInstance *inst;
+    ULONG_PTR info = 0;
+
+    TRACE( "%p, %p\n", device, irp );
+
+    inst = ((struct PdoExtension *)device->DeviceExtension)->instance;
+    if (inst->service) goto done;
+    irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
+
+    switch (irpsp->Parameters.DeviceIoControl.IoControlCode)
+    {
+    case IOCTL_USB_GET_NODE_INFORMATION:
+    {
+        USB_NODE_INFORMATION *node_info = irp->AssociatedIrp.SystemBuffer;
+
+        if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(*node_info))
+        {
+            status = STATUS_BUFFER_TOO_SMALL;
+            break;
+        }
+        RtlZeroMemory( node_info, sizeof(*node_info) );
+        node_info->u.HubInformation.HubDescriptor.bDescriptorLength = 9;
+        node_info->u.HubInformation.HubDescriptor.bDescriptorType = 41;
+        node_info->u.HubInformation.HubDescriptor.bNumberOfPorts = NUMBER_OF_PORTS;
+        status = STATUS_SUCCESS;
+        info = sizeof(*node_info);
+        break;
+    }
+    case IOCTL_USB_GET_NODE_CONNECTION_INFORMATION:
+    {
+        USB_NODE_CONNECTION_INFORMATION *conn_info = irp->AssociatedIrp.SystemBuffer;
+        ULONG index = 0;
+#ifdef HAVE_LIBUSB_H
+        struct DeviceInstance *instance;
+        uint8_t bus_number = libusb_get_bus_number( inst->dev );
+#else
+        struct usb_device *dev;
+#endif
+
+        if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(*conn_info))
+        {
+            status = STATUS_BUFFER_TOO_SMALL;
+            break;
+        }
+        if (!conn_info->ConnectionIndex || conn_info->ConnectionIndex > NUMBER_OF_PORTS)
+        {
+            status = STATUS_INVALID_PARAMETER;
+            break;
+        }
+        RtlZeroMemory( (ULONG *)conn_info + 1, sizeof(*conn_info) - sizeof(ULONG) );
+#ifdef HAVE_LIBUSB_H
+        LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
+        {
+            if (instance->dev && instance->dev != inst->dev &&
+                libusb_get_bus_number( instance->dev ) == bus_number &&
+                ++index == conn_info->ConnectionIndex)
+            {
+                struct libusb_device_descriptor desc;
+
+                if (libusb_get_device_descriptor( instance->dev, &desc ))
+                    break;
+                memcpy( &conn_info->DeviceDescriptor, &desc,
+                        sizeof(USB_DEVICE_DESCRIPTOR) );
+                conn_info->ConnectionStatus = 1;
+                break;
+            }
+        }
+#else
+        for (dev = inst->dev->next; dev; dev = dev->next)
+            if (++index == conn_info->ConnectionIndex)
+            {
+                memcpy( &conn_info->DeviceDescriptor, &dev->descriptor,
+                        sizeof(USB_DEVICE_DESCRIPTOR) );
+                conn_info->ConnectionStatus = 1;
+                break;
+            }
+#endif
+        status = STATUS_SUCCESS;
+        info = sizeof(*conn_info);
+        break;
+    }
+    case IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME:
+    {
+        USB_NODE_CONNECTION_DRIVERKEY_NAME *driver_key_name =
+                irp->AssociatedIrp.SystemBuffer;
+        WCHAR *dev_instance_idW, *bufW;
+        struct DeviceInstance *instance;
+        HDEVINFO set;
+        SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
+        ULONG len, index = 0, found = 0;
+#ifdef HAVE_LIBUSB_H
+        uint8_t bus_number = libusb_get_bus_number( inst->dev );
+#else
+        struct usb_device *dev;
+#endif
+
+        if (irpsp->Parameters.DeviceIoControl.OutputBufferLength <
+                sizeof(*driver_key_name))
+        {
+            status = STATUS_BUFFER_TOO_SMALL;
+            break;
+        }
+#ifdef HAVE_LIBUSB_H
+        LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
+        {
+            if (instance->dev && instance->dev != inst->dev &&
+                libusb_get_bus_number( instance->dev ) == bus_number &&
+                ++index == driver_key_name->ConnectionIndex)
+            {
+                found = 1;
+                break;
+            }
+        }
+#else
+        for (dev = inst->dev->next; dev; dev = dev->next)
+            if (++index == driver_key_name->ConnectionIndex)
+            {
+                LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
+                {
+                    if (instance->dev == dev)
+                    {
+                        found = 1;
+                        break;
+                    }
+                }
+                break;
+            }
+#endif
+        if (!found)
+        {
+            status = STATUS_INVALID_PARAMETER;
+            break;
+        }
+        bufW = HeapAlloc( GetProcessHeap(), 0,
+                2 * MAX_DEVICE_ID_LEN * sizeof(WCHAR) );
+        if (bufW == NULL)
+        {
+            status = STATUS_INSUFFICIENT_RESOURCES;
+            break;
+        }
+        dev_instance_idW = bufW + MAX_DEVICE_ID_LEN;
+        snprintfW( dev_instance_idW, MAX_DEVICE_ID_LEN, device_idW,
+                instance->vid, instance->pid );
+        len = strlenW(dev_instance_idW);
+        RtlMultiByteToUnicodeN( dev_instance_idW + len,
+                (MAX_DEVICE_ID_LEN - len) * sizeof(WCHAR), NULL,
+                instance->instance_id, strlen(instance->instance_id) + 1 );
+        set = SetupDiGetClassDevsW( NULL, usbW, 0, DIGCF_ALLCLASSES );
+        if (set == INVALID_HANDLE_VALUE)
+        {
+            HeapFree( GetProcessHeap(), 0, bufW );
+            break;
+        }
+        index = 0;
+        while (SetupDiEnumDeviceInfo( set, index++, &devInfo ))
+        {
+            if (!SetupDiGetDeviceInstanceIdW( set, &devInfo, bufW,
+                    MAX_DEVICE_ID_LEN, NULL ))
+                break;
+            if (!strcmpiW( dev_instance_idW, bufW ))
+            {
+                SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_DRIVER,
+                        NULL, NULL, 0, &len );
+                driver_key_name->ActualLength = 2 * sizeof(ULONG) + len;
+                if (irpsp->Parameters.DeviceIoControl.OutputBufferLength <
+                        driver_key_name->ActualLength)
+                {
+                    status = STATUS_SUCCESS;
+                    info = sizeof(*driver_key_name);
+                }
+                else if (SetupDiGetDeviceRegistryPropertyW( set, &devInfo,
+                        SPDRP_DRIVER, NULL, (BYTE *)driver_key_name->DriverKeyName,
+                        len, NULL ))
+                {
+                    status = STATUS_SUCCESS;
+                    info = driver_key_name->ActualLength;
+                }
+                break;
+            }
+        }
+        SetupDiDestroyDeviceInfoList( set );
+        HeapFree( GetProcessHeap(), 0, bufW );
+        break;
+    }
+    case IOCTL_USB_GET_DEVICE_INFO:
+    {
+        struct usb_device_info *dev_info = irp->AssociatedIrp.SystemBuffer;
+        struct DeviceInstance *instance;
+        ULONG len, index = 0;
+#ifdef HAVE_LIBUSB_H
+        uint8_t bus_number = libusb_get_bus_number( inst->dev );
+#else
+        struct usb_device *dev;
+#endif
+
+        if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(*dev_info))
+        {
+            status = STATUS_BUFFER_TOO_SMALL;
+            break;
+        }
+        if (!dev_info->connection_index || dev_info->connection_index > NUMBER_OF_PORTS)
+        {
+            status = STATUS_INVALID_PARAMETER;
+            break;
+        }
+        RtlZeroMemory( (ULONG *)dev_info + 1, sizeof(*dev_info) - sizeof(ULONG) );
+        memcpy( dev_info->root_hub_id, root_hub_idW, sizeof(root_hub_idW) );
+        len = strlenW(root_hub_idW);
+        RtlMultiByteToUnicodeN( dev_info->root_hub_id + len,
+                (MAX_DEVICE_ID_LEN - len) * sizeof(WCHAR), NULL,
+                inst->instance_id, strlen(inst->instance_id) + 1 );
+#ifdef HAVE_LIBUSB_H
+        LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
+        {
+            if (instance->dev && instance->dev != inst->dev &&
+                libusb_get_bus_number( instance->dev ) == bus_number &&
+                ++index == dev_info->connection_index)
+            {
+                dev_info->device_address = libusb_get_device_address( instance->dev );
+                break;
+            }
+        }
+#else
+        for (dev = inst->dev->next; dev; dev = dev->next)
+            if (++index == dev_info->connection_index)
+            {
+                dev_info->device_address = dev->devnum;
+                LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
+                {
+                    if (instance->dev == dev) break;
+                }
+                break;
+            }
+#endif
+        if (dev_info->device_address)
+        {
+            snprintfW( dev_info->device_id, MAX_DEVICE_ID_LEN, device_idW,
+                    instance->vid, instance->pid );
+            len = strlenW(dev_info->device_id);
+            RtlMultiByteToUnicodeN( dev_info->device_id + len,
+                    (MAX_DEVICE_ID_LEN - len) * sizeof(WCHAR), NULL,
+                    instance->instance_id, strlen(instance->instance_id) + 1 );
+        }
+        status = STATUS_SUCCESS;
+        info = sizeof(*dev_info);
+        break;
+    }
+    default:
+        FIXME( "IOCTL %08x is not implemented\n",
+                irpsp->Parameters.DeviceIoControl.IoControlCode );
+    }
+
+done:
+    irp->IoStatus.u.Status = status;
+    irp->IoStatus.Information = info;
+    IoCompleteRequest( irp, IO_NO_INCREMENT );
+
+    return status;
+}
+
+#ifdef HAVE_LIBUSB_H
+
+static NTSTATUS WINAPI usbhub_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
+{
+    IO_STACK_LOCATION *irpsp;
+    URB *urb;
+    NTSTATUS status = STATUS_UNSUCCESSFUL;
+    struct DeviceInstance *inst;
+
+    TRACE( "%p, %p\n", device, irp );
+
+    inst = ((struct PdoExtension *)device->DeviceExtension)->instance;
+    if (!inst->service) goto done;
+    irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
+    urb = irpsp->Parameters.Others.Argument1;
+
+    switch (irpsp->Parameters.DeviceIoControl.IoControlCode)
+    {
+    case IOCTL_INTERNAL_USB_SUBMIT_URB:
+        switch (urb->u.UrbHeader.Function)
+        {
+        case URB_FUNCTION_SELECT_CONFIGURATION:
+            {
+                struct _URB_SELECT_CONFIGURATION *request =
+                        &urb->u.UrbSelectConfiguration;
+                libusb_device_handle *husb;
+
+                TRACE( "URB_FUNCTION_SELECT_CONFIGURATION\n" );
+
+                if (!libusb_open( inst->dev, &husb ))
+                {
+                    USB_CONFIGURATION_DESCRIPTOR *conf_desc =
+                            request->ConfigurationDescriptor;
+                    struct libusb_config_descriptor *conf;
+                    int ret;
+
+                    ret = libusb_set_configuration( husb, (conf_desc != NULL) ?
+                            conf_desc->bConfigurationValue : -1 );
+                    if (ret < 0)
+                        ERR( "libusb_set_configuration: %d\n", ret );
+                    else if (conf_desc == NULL)
+                        status = STATUS_SUCCESS;
+                    else if (!libusb_get_active_config_descriptor( inst->dev, &conf ))
+                    {
+                        USBD_INTERFACE_INFORMATION *if_info = &request->Interface;
+                        const struct libusb_interface_descriptor *intf;
+                        ULONG k, n;
+
+                        /* FIXME: case of num_altsetting > 1 */
+
+                        for (n = 0; n < conf_desc->bNumInterfaces; ++n)
+                        {
+                            intf = &conf->interface[n].altsetting[0];
+                            if_info->Class = intf->bInterfaceClass;
+                            if_info->SubClass = intf->bInterfaceSubClass;
+                            if_info->Protocol = intf->bInterfaceProtocol;
+                            if_info->InterfaceHandle =
+                                    (void *)(intf->bInterfaceNumber + 1);
+                            for (k = 0; k < if_info->NumberOfPipes; ++k)
+                            {
+                                if_info->Pipes[k].MaximumPacketSize =
+                                        intf->endpoint[k].wMaxPacketSize;
+                                if_info->Pipes[k].EndpointAddress =
+                                        intf->endpoint[k].bEndpointAddress;
+                                if_info->Pipes[k].Interval =
+                                        intf->endpoint[k].bInterval;
+                                if_info->Pipes[k].PipeType =
+                                        intf->endpoint[k].bmAttributes & 3;
+                                if_info->Pipes[k].PipeHandle =
+                                        (void *)(intf->endpoint[k].bEndpointAddress +
+                                        ((intf->bInterfaceNumber + 1) << 8));
+                            }
+                            if_info = (USBD_INTERFACE_INFORMATION *)
+                                    ((char *)if_info + if_info->Length);
+                        }
+                        libusb_free_config_descriptor( conf );
+                        status = STATUS_SUCCESS;
+                    }
+                    libusb_close( husb );
+                }
+            }
+            break;
+        case URB_FUNCTION_SELECT_INTERFACE:
+            {
+                struct _URB_SELECT_INTERFACE *request =
+                        &urb->u.UrbSelectInterface;
+                libusb_device_handle *husb;
+
+                TRACE( "URB_FUNCTION_SELECT_INTERFACE\n" );
+
+                if (!libusb_open( inst->dev, &husb ))
+                {
+                    int ret;
+
+                    ret = libusb_claim_interface( husb,
+                            request->Interface.InterfaceNumber );
+                    if (!ret)
+                    {
+                        ret = libusb_set_interface_alt_setting( husb,
+                                request->Interface.InterfaceNumber,
+                                request->Interface.AlternateSetting );
+                        if (!libusb_release_interface( husb,
+                                request->Interface.InterfaceNumber ) && !ret)
+                            status = STATUS_SUCCESS;
+                    }
+                    libusb_close( husb );
+                }
+            }
+            break;
+        case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
+            {
+                struct _URB_BULK_OR_INTERRUPT_TRANSFER *request =
+                        &urb->u.UrbBulkOrInterruptTransfer;
+                unsigned char *buf = request->TransferBuffer;
+                libusb_device_handle *husb;
+
+                TRACE( "URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER\n" );
+
+                if (buf == NULL && request->TransferBufferMDL != NULL)
+                    buf = request->TransferBufferMDL->MappedSystemVa;
+                if (!libusb_open( inst->dev, &husb ))
+                {
+                    int ret, transferred;
+
+                    ret = libusb_claim_interface( husb,
+                            ((int)request->PipeHandle >> 8) - 1 );
+                    if (!ret)
+                    {
+                        /* FIXME: add support for an interrupt transfer */
+                        ret = libusb_bulk_transfer( husb,
+                                (unsigned int)request->PipeHandle,
+                                buf, request->TransferBufferLength,
+                                &transferred, 0 );
+                        if (!libusb_release_interface( husb,
+                                ((int)request->PipeHandle >> 8) - 1 ) && !ret)
+                        {
+                            request->TransferBufferLength = transferred;
+                            status = STATUS_SUCCESS;
+                        }
+                    }
+                    libusb_close( husb );
+                }
+            }
+            break;
+        case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
+            {
+                struct _URB_CONTROL_DESCRIPTOR_REQUEST *request =
+                        &urb->u.UrbControlDescriptorRequest;
+                ULONG size = request->TransferBufferLength;
+                unsigned char *buf = request->TransferBuffer;
+
+                TRACE( "URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n" );
+
+                if (!size)
+                {
+                    status = STATUS_SUCCESS;
+                    break;
+                }
+                if (buf == NULL && request->TransferBufferMDL != NULL)
+                    buf = request->TransferBufferMDL->MappedSystemVa;
+                if (buf == NULL)
+                {
+                    status = STATUS_INVALID_PARAMETER;
+                    break;
+                }
+
+                switch (request->DescriptorType)
+                {
+                case USB_DEVICE_DESCRIPTOR_TYPE:
+                    TRACE( "USB_DEVICE_DESCRIPTOR_TYPE\n" );
+                    {
+                        struct libusb_device_descriptor desc;
+
+                        if (libusb_get_device_descriptor( inst->dev, &desc ))
+                            break;
+                        memcpy( buf, &desc, (size < sizeof(USB_DEVICE_DESCRIPTOR)) ?
+                                size : sizeof(USB_DEVICE_DESCRIPTOR) );
+                        status = STATUS_SUCCESS;
+                    }
+                    break;
+                case USB_CONFIGURATION_DESCRIPTOR_TYPE:
+                    TRACE( "USB_CONFIGURATION_DESCRIPTOR_TYPE\n" );
+                    {
+                        unsigned int i, k;
+                        struct libusb_config_descriptor *conf;
+                        const struct libusb_interface_descriptor *intf;
+                        const struct libusb_endpoint_descriptor *endp;
+
+                        /* FIXME: case of num_altsetting > 1 */
+
+                        if (libusb_get_active_config_descriptor( inst->dev, &conf ))
+                            break;
+                        add_data( &buf, &size, conf,
+                                sizeof(USB_CONFIGURATION_DESCRIPTOR) );
+                        if (size > 0 && conf->extra)
+                            add_data( &buf, &size, conf->extra, conf->extra_length );
+                        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->extra_length );
+                            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->extra_length );
+                            }
+                        }
+                        libusb_free_config_descriptor( conf );
+                        status = STATUS_SUCCESS;
+                    }
+                    break;
+                case USB_STRING_DESCRIPTOR_TYPE:
+                    TRACE( "USB_STRING_DESCRIPTOR_TYPE\n" );
+                    {
+                        libusb_device_handle *husb;
+                        int ret;
+
+                        if (!libusb_open( inst->dev, &husb ))
+                        {
+                            ret = libusb_get_string_descriptor( husb, request->Index,
+                                    request->LanguageId, buf, size );
+                            libusb_close( husb );
+                            if (ret < 0) break;
+                            status = STATUS_SUCCESS;
+                        }
+                    }
+                }
+            }
+            break;
+        case URB_FUNCTION_GET_STATUS_FROM_DEVICE:
+            {
+                struct _URB_CONTROL_GET_STATUS_REQUEST *request =
+                        &urb->u.UrbControlGetStatusRequest;
+                void *buf = request->TransferBuffer;
+                libusb_device_handle *husb;
+                int ret;
+
+                TRACE( "URB_FUNCTION_GET_STATUS_FROM_DEVICE\n" );
+
+                if (buf == NULL && request->TransferBufferMDL != NULL)
+                    buf = request->TransferBufferMDL->MappedSystemVa;
+                if (buf == NULL || request->TransferBufferLength < sizeof(USHORT))
+                {
+                    status = STATUS_INVALID_PARAMETER;
+                    break;
+                }
+                if (!libusb_open( inst->dev, &husb ))
+                {
+                    ret = libusb_control_transfer( husb, 1 << 7,
+                            LIBUSB_REQUEST_GET_STATUS, 0, request->Index, buf,
+                            sizeof(USHORT), 0 );
+                    libusb_close( husb );
+                    if (ret < 0) break;
+                    status = STATUS_SUCCESS;
+                }
+            }
+            break;
+        case URB_FUNCTION_VENDOR_DEVICE:
+        case URB_FUNCTION_VENDOR_INTERFACE:
+        case URB_FUNCTION_VENDOR_ENDPOINT:
+        case URB_FUNCTION_CLASS_DEVICE:
+        case URB_FUNCTION_CLASS_INTERFACE:
+        case URB_FUNCTION_CLASS_ENDPOINT:
+            {
+                libusb_device_handle *husb;
+                struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *request =
+                        &urb->u.UrbControlVendorClassRequest;
+                unsigned char *req_buf = request->TransferBuffer;
+                ULONG size = request->TransferBufferLength;
+
+                TRACE( "URB_FUNCTION_{VENDOR,CLASS}_*\n" );
+
+                if (req_buf == NULL && request->TransferBufferMDL != NULL)
+                    req_buf = request->TransferBufferMDL->MappedSystemVa;
+                if (size && req_buf == NULL)
+                {
+                    status = STATUS_INVALID_PARAMETER;
+                    break;
+                }
+                if (!libusb_open( inst->dev, &husb ))
+                {
+                    UCHAR req_type = request->RequestTypeReservedBits;
+                    unsigned char *buf;
+                    int ret;
+
+                    switch (urb->u.UrbHeader.Function)
+                    {
+                    case URB_FUNCTION_VENDOR_DEVICE:    req_type |= 0x40; break;
+                    case URB_FUNCTION_VENDOR_INTERFACE: req_type |= 0x41; break;
+                    case URB_FUNCTION_VENDOR_ENDPOINT:  req_type |= 0x42; break;
+                    case URB_FUNCTION_CLASS_DEVICE:     req_type |= 0x20; break;
+                    case URB_FUNCTION_CLASS_INTERFACE:  req_type |= 0x21; break;
+                    case URB_FUNCTION_CLASS_ENDPOINT:   req_type |= 0x22; break;
+                    }
+                    buf = HeapAlloc( GetProcessHeap(), 0, size );
+                    if (buf != NULL)
+                    {
+                        memcpy( buf, req_buf, size );
+                        if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
+                            req_type |= (1 << 7);
+                        ret = libusb_control_transfer( husb, req_type,
+                                request->Request, request->Value, request->Index,
+                                buf, size, 0 );
+                        if (ret < 0)
+                            ERR( "libusb_control_transfer: %d\n", ret );
+                        else
+                        {
+                            if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
+                            {
+                                request->TransferBufferLength =
+                                        (ret < size) ? ret : size;
+                                memcpy( req_buf, buf, request->TransferBufferLength );
+                            }
+                            status = STATUS_SUCCESS;
+                        }
+                        HeapFree( GetProcessHeap(), 0, buf );
+                    }
+                    libusb_close( husb );
+                }
+            }
+            break;
+        default:
+            FIXME( "unsupported URB function %x\n", urb->u.UrbHeader.Function );
+        }
+        urb->u.UrbHeader.Status = status;
+        break;
+    default:
+        FIXME( "IOCTL %08x is not implemented\n",
+                irpsp->Parameters.DeviceIoControl.IoControlCode );
+    }
+
+done:
+    irp->IoStatus.u.Status = status;
+    irp->IoStatus.Information = 0;
+    IoCompleteRequest( irp, IO_NO_INCREMENT );
+
+    return status;
+}
+
+#else
+
+static NTSTATUS WINAPI usbhub_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
+{
+    IO_STACK_LOCATION *irpsp;
+    URB *urb;
+    NTSTATUS status = STATUS_UNSUCCESSFUL;
+    struct DeviceInstance *inst;
+
+    TRACE( "%p, %p\n", device, irp );
+
+    inst = ((struct PdoExtension *)device->DeviceExtension)->instance;
+    if (!inst->service) goto done;
+    irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
+    urb = irpsp->Parameters.Others.Argument1;
+
+    switch (irpsp->Parameters.DeviceIoControl.IoControlCode)
+    {
+    case IOCTL_INTERNAL_USB_SUBMIT_URB:
+        switch (urb->u.UrbHeader.Function)
+        {
+        case URB_FUNCTION_SELECT_CONFIGURATION:
+            {
+                struct _URB_SELECT_CONFIGURATION *request =
+                        &urb->u.UrbSelectConfiguration;
+                usb_dev_handle *husb;
+
+                TRACE( "URB_FUNCTION_SELECT_CONFIGURATION\n" );
+
+                husb = usb_open( inst->dev );
+                if (husb)
+                {
+                    USB_CONFIGURATION_DESCRIPTOR *conf_desc =
+                            urb->u.UrbSelectConfiguration.ConfigurationDescriptor;
+                    int ret;
+
+                    ret = usb_set_configuration( husb, (conf_desc != NULL) ?
+                            conf_desc->bConfigurationValue : -1 );
+                    if (ret < 0)
+                        ERR( "%s\n", usb_strerror() );
+                    else if (conf_desc == NULL)
+                        status = STATUS_SUCCESS;
+                    else
+                    {
+                        USBD_INTERFACE_INFORMATION *if_info = &request->Interface;
+                        struct usb_config_descriptor *conf;
+                        struct usb_interface_descriptor *intf;
+                        ULONG k, n;
+
+                        /* FIXME: case of num_altsetting > 1 */
+
+                        for (n = 0; n < inst->dev->descriptor.bNumConfigurations; ++n)
+                            if (inst->dev->config[n].bConfigurationValue ==
+                                conf_desc->bConfigurationValue)
+                            {
+                                conf = &inst->dev->config[n];
+                                break;
+                            }
+                        for (n = 0; n < conf_desc->bNumInterfaces; ++n)
+                        {
+                            intf = &conf->interface[n].altsetting[0];
+                            if_info->Class = intf->bInterfaceClass;
+                            if_info->SubClass = intf->bInterfaceSubClass;
+                            if_info->Protocol = intf->bInterfaceProtocol;
+                            if_info->SubClass = intf->bInterfaceSubClass;
+                            if_info->Protocol = intf->bInterfaceProtocol;
+                            if_info->InterfaceHandle =
+                                    (void *)(intf->bInterfaceNumber + 1);
+                            for (k = 0; k < if_info->NumberOfPipes; ++k)
+                            {
+                                if_info->Pipes[k].MaximumPacketSize =
+                                        intf->endpoint[k].wMaxPacketSize;
+                                if_info->Pipes[k].EndpointAddress =
+                                        intf->endpoint[k].bEndpointAddress;
+                                if_info->Pipes[k].Interval =
+                                        intf->endpoint[k].bInterval;
+                                if_info->Pipes[k].PipeType =
+                                        intf->endpoint[k].bmAttributes & 3;
+                                if_info->Pipes[k].PipeHandle =
+                                        (void *)(intf->endpoint[k].bEndpointAddress +
+                                        ((intf->bInterfaceNumber + 1) << 8));
+                            }
+                            if_info = (USBD_INTERFACE_INFORMATION *)
+                                    ((char *)if_info + if_info->Length);
+                        }
+                        status = STATUS_SUCCESS;
+                    }
+                    usb_close( husb );
+                }
+            }
+            break;
+        case URB_FUNCTION_SELECT_INTERFACE:
+            {
+                struct _URB_SELECT_INTERFACE *request =
+                        &urb->u.UrbSelectInterface;
+                usb_dev_handle *husb;
+
+                TRACE( "URB_FUNCTION_SELECT_INTERFACE\n" );
+
+                husb = usb_open( inst->dev );
+                if (husb)
+                {
+                    int ret;
+
+                    ret = usb_claim_interface( husb,
+                            request->Interface.InterfaceNumber );
+                    if (!ret)
+                    {
+                        ret = usb_set_altinterface( husb,
+                                request->Interface.AlternateSetting );
+                        if (!usb_release_interface( husb,
+                                request->Interface.InterfaceNumber ) && !ret)
+                            status = STATUS_SUCCESS;
+                    }
+                    usb_close( husb );
+                }
+            }
+            break;
+        case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
+            {
+                struct _URB_BULK_OR_INTERRUPT_TRANSFER *request =
+                        &urb->u.UrbBulkOrInterruptTransfer;
+                char *buf = request->TransferBuffer;
+                usb_dev_handle *husb;
+
+                TRACE( "URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER\n" );
+
+                if (buf == NULL && request->TransferBufferMDL != NULL)
+                    buf = request->TransferBufferMDL->MappedSystemVa;
+                husb = usb_open( inst->dev );
+                if (husb)
+                {
+                    int ret;
+
+                    ret = usb_claim_interface( husb,
+                            ((int)request->PipeHandle >> 8) - 1 );
+                    if (!ret)
+                    {
+                        /* FIXME: add support for an interrupt transfer */
+                        if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
+                            ret = usb_bulk_read( husb, (int)request->PipeHandle & 0xff,
+                                    buf, request->TransferBufferLength, 0 );
+                        else
+                            ret = usb_bulk_write( husb, (int)request->PipeHandle & 0xff,
+                                    buf, request->TransferBufferLength, 0 );
+                        if (!usb_release_interface( husb,
+                                ((int)request->PipeHandle >> 8) - 1 ) && ret >= 0)
+                        {
+                            request->TransferBufferLength = ret;
+                            status = STATUS_SUCCESS;
+                        }
+                    }
+                    usb_close( husb );
+                }
+            }
+            break;
+        case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
+            {
+                struct _URB_CONTROL_DESCRIPTOR_REQUEST *request =
+                        &urb->u.UrbControlDescriptorRequest;
+                ULONG size = request->TransferBufferLength;
+                unsigned char *buf = request->TransferBuffer;
+
+                TRACE( "URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n" );
+
+                if (!size)
+                {
+                    status = STATUS_SUCCESS;
+                    break;
+                }
+                if (buf == NULL && request->TransferBufferMDL != NULL)
+                    buf = request->TransferBufferMDL->MappedSystemVa;
+                if (buf == NULL)
+                {
+                    status = STATUS_INVALID_PARAMETER;
+                    break;
+                }
+
+                switch (request->DescriptorType)
+                {
+                case USB_DEVICE_DESCRIPTOR_TYPE:
+                    TRACE( "USB_DEVICE_DESCRIPTOR_TYPE\n" );
+                    memcpy( buf, &inst->dev->descriptor,
+                            (size < sizeof(USB_DEVICE_DESCRIPTOR)) ?
+                            size : sizeof(USB_DEVICE_DESCRIPTOR) );
+                    status = STATUS_SUCCESS;
+                    break;
+                case USB_CONFIGURATION_DESCRIPTOR_TYPE:
+                    TRACE( "USB_CONFIGURATION_DESCRIPTOR_TYPE\n" );
+                    {
+                        unsigned int i, k;
+                        struct usb_config_descriptor *conf = &inst->dev->config[0];
+                        struct usb_interface_descriptor *intf;
+                        struct usb_endpoint_descriptor *endp;
+
+                        /* FIXME: case of num_altsetting > 1 */
+
+                        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;
+                case USB_STRING_DESCRIPTOR_TYPE:
+                    TRACE( "USB_STRING_DESCRIPTOR_TYPE\n" );
+                    {
+                        usb_dev_handle *husb;
+                        int ret;
+
+                        husb = usb_open( inst->dev );
+                        if (husb)
+                        {
+                            ret = usb_get_string( husb, request->Index,
+                                    request->LanguageId, (void *)buf, size );
+                            if (ret < 0)
+                                ERR( "%s\n", usb_strerror() );
+                            else
+                                status = STATUS_SUCCESS;
+                            usb_close( husb );
+                        }
+                    }
+                }
+            }
+            break;
+        case URB_FUNCTION_GET_STATUS_FROM_DEVICE:
+            {
+                struct _URB_CONTROL_GET_STATUS_REQUEST *request =
+                        &urb->u.UrbControlGetStatusRequest;
+                void *buf = request->TransferBuffer;
+                usb_dev_handle *husb;
+                int ret;
+
+                TRACE( "URB_FUNCTION_GET_STATUS_FROM_DEVICE\n" );
+
+                if (buf == NULL && request->TransferBufferMDL != NULL)
+                    buf = request->TransferBufferMDL->MappedSystemVa;
+                if (buf == NULL || request->TransferBufferLength < sizeof(USHORT))
+                {
+                    status = STATUS_INVALID_PARAMETER;
+                    break;
+                }
+                husb = usb_open( inst->dev );
+                if (husb)
+                {
+                    ret = usb_control_msg( husb, 1 << 7, USB_REQ_GET_STATUS, 0,
+                            request->Index, buf, sizeof(USHORT), 0 );
+                    if (ret < 0)
+                        ERR( "%s\n", usb_strerror() );
+                    else
+                        status = STATUS_SUCCESS;
+                    usb_close( husb );
+                }
+            }
+            break;
+        case URB_FUNCTION_VENDOR_DEVICE:
+        case URB_FUNCTION_VENDOR_INTERFACE:
+        case URB_FUNCTION_VENDOR_ENDPOINT:
+        case URB_FUNCTION_CLASS_DEVICE:
+        case URB_FUNCTION_CLASS_INTERFACE:
+        case URB_FUNCTION_CLASS_ENDPOINT:
+            {
+                usb_dev_handle *husb;
+                struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *request =
+                        &urb->u.UrbControlVendorClassRequest;
+                unsigned char *req_buf = request->TransferBuffer;
+                ULONG size = request->TransferBufferLength;
+
+                TRACE( "URB_FUNCTION_{VENDOR,CLASS}_*\n" );
+
+                if (req_buf == NULL && request->TransferBufferMDL != NULL)
+                    req_buf = request->TransferBufferMDL->MappedSystemVa;
+                if (size && req_buf == NULL)
+                {
+                    status = STATUS_INVALID_PARAMETER;
+                    break;
+                }
+                husb = usb_open( inst->dev );
+                if (husb)
+                {
+                    UCHAR req_type = request->RequestTypeReservedBits;
+                    char *buf;
+                    int ret;
+
+                    switch (urb->u.UrbHeader.Function)
+                    {
+                    case URB_FUNCTION_VENDOR_DEVICE:    req_type |= 0x40; break;
+                    case URB_FUNCTION_VENDOR_INTERFACE: req_type |= 0x41; break;
+                    case URB_FUNCTION_VENDOR_ENDPOINT:  req_type |= 0x42; break;
+                    case URB_FUNCTION_CLASS_DEVICE:     req_type |= 0x20; break;
+                    case URB_FUNCTION_CLASS_INTERFACE:  req_type |= 0x21; break;
+                    case URB_FUNCTION_CLASS_ENDPOINT:   req_type |= 0x22; break;
+                    }
+                    buf = HeapAlloc( GetProcessHeap(), 0, size );
+                    if (buf != NULL)
+                    {
+                        memcpy( buf, req_buf, size );
+                        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, size, 0 );
+                        if (ret < 0)
+                            ERR( "%s\n", usb_strerror() );
+                        else
+                        {
+                            if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
+                            {
+                                request->TransferBufferLength =
+                                        (ret < size) ? ret : size;
+                                memcpy( req_buf, 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;
+        break;
+    default:
+        FIXME( "IOCTL %08x is not implemented\n",
+                irpsp->Parameters.DeviceIoControl.IoControlCode );
+    }
+
+done:
+    irp->IoStatus.u.Status = status;
+    irp->IoStatus.Information = 0;
+    IoCompleteRequest( irp, IO_NO_INCREMENT );
+
+    return status;
+}
+
+#endif
+
+static NTSTATUS WINAPI usbhub_dispatch_pnp( DEVICE_OBJECT *device, IRP *irp )
+{
+    static const WCHAR device_idW[] = {'U','S','B','\\',
+                                       'V','i','d','_','%','0','4','x','&',
+                                       'P','i','d','_','%','0','4','x',0};
+    static const WCHAR root_hub_idW[] = {'U','S','B','\\',
+                                         'R','O','O','T','_','H','U','B',0};
+
+    struct PdoExtension *dx;
+    IO_STACK_LOCATION *irpsp;
+    NTSTATUS status;
+    ULONG_PTR info = 0;
+
+    TRACE( "%p, %p\n", device, irp );
+
+    dx = device->DeviceExtension;
+    irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
+    switch (irpsp->MinorFunction)
+    {
+    case IRP_MN_QUERY_DEVICE_RELATIONS:
+        /* dx->instance->service is NULL for root hubs */
+        if (dx->instance->service)
+        {
+            status = irp->IoStatus.u.Status;
+            info = irp->IoStatus.Information;
+        }
+        else
+        {
+            FIXME( "IRP_MN_QUERY_DEVICE_RELATIONS is not implemented for root hubs\n" );
+            status = STATUS_NOT_IMPLEMENTED;
+        }
+        break;
+    case IRP_MN_QUERY_ID:
+        switch (irpsp->Parameters.QueryId.IdType)
+        {
+        case BusQueryDeviceID:
+        {
+            WCHAR *device_id = ExAllocatePool( PagedPool, dx->instance->service ?
+                    sizeof(device_idW) : sizeof(root_hub_idW) );
+
+            if (device_id == NULL)
+            {
+                status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+            if (dx->instance->service)
+                snprintfW( device_id, strlenW(device_idW) + 1, device_idW,
+                        dx->instance->vid, dx->instance->pid );
+            else
+                strcpyW( device_id, root_hub_idW );
+            status = STATUS_SUCCESS;
+            info = (ULONG_PTR)device_id;
+            break;
+        }
+        case BusQueryInstanceID:
+        {
+            char *instance_id;
+            ULONG len;
+            ULONG size;
+            WCHAR *instance_idW;
+
+            instance_id = strrchr( dx->instance->instance_id, '&' );
+            instance_id = instance_id ? (instance_id + 1) : dx->instance->instance_id;
+            len = strlen(instance_id) + 1;
+            size = len * sizeof(WCHAR);
+            instance_idW = ExAllocatePool( PagedPool, size );
+            if (instance_idW == NULL)
+            {
+                status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+            RtlMultiByteToUnicodeN( instance_idW, size, NULL, instance_id, len );
+            status = STATUS_SUCCESS;
+            info = (ULONG_PTR)instance_idW;
+            break;
+        }
+        default:
+            FIXME( "IRP_MN_QUERY_ID: IdType %u is not implemented\n",
+                    irpsp->Parameters.QueryId.IdType );
+            status = STATUS_NOT_IMPLEMENTED;
+        }
+        break;
+    default:
+        status = STATUS_SUCCESS;
+    }
+
+    irp->IoStatus.u.Status = status;
+    irp->IoStatus.Information = info;
+    IoCompleteRequest( irp, IO_NO_INCREMENT );
+
+    return STATUS_SUCCESS;
+}
+
+static BOOL start_service( const WCHAR *name )
+{
+    SC_HANDLE scm, service;
+    BOOL ret;
+
+    scm = OpenSCManagerA( NULL, NULL, SC_MANAGER_ALL_ACCESS );
+    if (scm == NULL)
+        return FALSE;
+
+    service = OpenServiceW( scm, name, SERVICE_ALL_ACCESS );
+    if (service == NULL)
+    {
+        CloseServiceHandle( scm );
+        return FALSE;
+    }
+
+    do {
+        ret = StartServiceW( service, 0, NULL );
+        if (!ret)
+        {
+            if (ERROR_SERVICE_ALREADY_RUNNING == GetLastError())
+                ret = TRUE;
+            else if (ERROR_SERVICE_DATABASE_LOCKED == GetLastError())
+                Sleep( 100 );
+            else
+                break;
+        }
+    } while (!ret);
+
+    CloseServiceHandle( service );
+    CloseServiceHandle( scm );
+
+    return ret;
+}
+
+static BOOL create_pdo_name( UNICODE_STRING *pdo_name )
+{
+    static const WCHAR usbpdoW[] = {'\\','D','e','v','i','c','e','\\',
+                                     'U','S','B','P','D','O','-','%','u',0};
+
+    static unsigned int last_pdo_num;
+    WCHAR *buf = RtlAllocateHeap( GetProcessHeap(), 0, 30 * sizeof(WCHAR) );
+
+    if (buf == NULL) return FALSE;
+    snprintfW( buf, 30, usbpdoW, last_pdo_num++ );
+    RtlInitUnicodeString( pdo_name, buf );
+    return TRUE;
+}
+
+static DEVICE_OBJECT *create_pdo( struct DeviceInstance *inst, DRIVER_OBJECT *hubdrv )
+{
+    UNICODE_STRING pdo_name;
+    DEVICE_OBJECT *usbdev = NULL;
+
+    if (!create_pdo_name( &pdo_name )) return NULL;
+    if (IoCreateDevice( hubdrv, sizeof(struct PdoExtension), &pdo_name,
+        0, 0, FALSE, &usbdev ) == STATUS_SUCCESS)
+    {
+        ((struct PdoExtension *)usbdev->DeviceExtension)->instance = inst;
+        usbdev->Flags |= DO_BUS_ENUMERATED_DEVICE | DO_POWER_PAGABLE;
+        usbdev->Flags &= ~DO_DEVICE_INITIALIZING;
+    }
+    RtlFreeUnicodeString( &pdo_name );
+    return usbdev;
+}
+
+static void register_root_hub_device( DEVICE_OBJECT *dev, unsigned int instance_id )
+{
+    static const WCHAR root_hub_idW[] = {'U','S','B',
+                                         '\\','R','O','O','T','_','H','U','B',
+                                         '\\','%','u',0};
+
+    HDEVINFO set;
+    SP_DEVINFO_DATA devInfo;
+    WCHAR *devnameW;
+    ULONG size;
+    BOOL ret;
+    UNICODE_STRING link;
+    NTSTATUS status;
+
+    size = sizeof(root_hub_idW) + 16 * sizeof(WCHAR);
+    devnameW = HeapAlloc( GetProcessHeap(), 0, size );
+    if (devnameW == NULL) return;
+    snprintfW( devnameW, size / sizeof(WCHAR), root_hub_idW, instance_id );
+
+    set = SetupDiGetClassDevsW( NULL, usbW, 0, DIGCF_ALLCLASSES );
+    if (set == INVALID_HANDLE_VALUE) goto done;
+    devInfo.cbSize = sizeof(SP_DEVINFO_DATA);
+    ret = SetupDiCreateDeviceInfoW( set, devnameW, &GUID_DEVCLASS_USB,
+            NULL, NULL, 0, &devInfo );
+    if (ret)
+    {
+        ret = SetupDiRegisterDeviceInfo( set, &devInfo, 0, NULL, NULL, NULL );
+        if (!ret) goto done;
+    }
+    else if (ERROR_DEVINST_ALREADY_EXISTS != GetLastError()) goto done;
+
+    status = IoRegisterDeviceInterface( dev, &GUID_DEVINTERFACE_USB_HUB,
+            NULL, &link );
+    if (status == STATUS_SUCCESS)
+    {
+        IoSetDeviceInterfaceState( &link, TRUE );
+        RtlFreeUnicodeString( &link );
+    }
+done:
+    if (set != INVALID_HANDLE_VALUE)
+        SetupDiDestroyDeviceInfoList( set );
+    HeapFree( GetProcessHeap(), 0, devnameW );
+}
+
+static void create_root_hub_device( USHORT vid, USHORT pid, void *dev,
+        DRIVER_OBJECT *hubdrv )
+{
+    static unsigned int instance_id;
+    struct DeviceInstance *instance = NULL;
+    DEVICE_OBJECT *hubdev;
+    UNICODE_STRING pdo_name = {0, 0, NULL};
+
+    instance = HeapAlloc( GetProcessHeap(), 0, sizeof(*instance) );
+    if (instance == NULL) return;
+    instance->instance_id = HeapAlloc( GetProcessHeap(), 0, 16 );
+    if (instance->instance_id == NULL) goto fail;
+    instance->vid = vid;
+    instance->pid = pid;
+    snprintf( instance->instance_id, 16, "%u", instance_id );
+    instance->service = NULL;
+    instance->dev = dev;
+
+    if (!create_pdo_name( &pdo_name )) goto fail;
+    if (IoCreateDevice( hubdrv, sizeof(struct PdoExtension), &pdo_name,
+        0, 0, FALSE, &hubdev ) != STATUS_SUCCESS) goto fail;
+
+    list_add_tail( &Devices, &instance->entry );
+    ((struct PdoExtension *)hubdev->DeviceExtension)->instance = instance;
+    hubdev->Flags |= DO_POWER_PAGABLE;
+    hubdev->Flags &= ~DO_DEVICE_INITIALIZING;
+    register_root_hub_device( hubdev, instance_id );
+    ++instance_id;
+    return;
+fail:
+    if (instance->instance_id)
+        HeapFree( GetProcessHeap(), 0, instance->instance_id );
+    HeapFree( GetProcessHeap(), 0, instance );
+    RtlFreeUnicodeString( &pdo_name );
+    return;
+}
+
+static BOOL enum_reg_usb_devices(void)
+{
+    SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
+    char *instance_id = NULL;
+    struct DeviceInstance *instance, *instance2;
+    HDEVINFO set;
+    DWORD size, i = 0;
+    USHORT vid, pid;
+    char *str, *buf;
+    BOOL ret;
+
+    set = SetupDiGetClassDevsW( NULL, usbW, 0, DIGCF_ALLCLASSES );
+    if (set == INVALID_HANDLE_VALUE) return FALSE;
+
+    while (SetupDiEnumDeviceInfo( set, i++, &devInfo ))
+    {
+        /* get VID, PID and instance ID */
+        buf = HeapAlloc( GetProcessHeap(), 0, MAX_DEVICE_ID_LEN );
+        if (buf == NULL) goto fail;
+        ret = SetupDiGetDeviceInstanceIdA( set, &devInfo, buf,
+                MAX_DEVICE_ID_LEN, NULL );
+        if (!ret) goto fail;
+        str = strstr( buf, "VID_" );
+        if (str != NULL)
+        {
+            str += 4;
+            vid = strtol( str, NULL, 16 );
+            str = strstr( str, "PID_" );
+        }
+        if (str == NULL)
+        {
+            HeapFree( GetProcessHeap(), 0, buf );
+            continue;
+        }
+        str += 4;
+        pid = strtol( str, NULL, 16 );
+        str = strrchr( str, '\\' );
+        if (str != NULL) ++str;
+        if (str == NULL || *str == 0)
+        {
+            ERR( "bad instance ID\n" );
+            HeapFree( GetProcessHeap(), 0, buf );
+            continue;
+        }
+        instance_id = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
+        if (instance_id == NULL) goto fail;
+        strcpy( instance_id, str );
+        HeapFree( GetProcessHeap(), 0, buf );
+
+        /* get service name */
+        SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE,
+                NULL, NULL, 0, &size );
+        buf = HeapAlloc( GetProcessHeap(), 0, size );
+        if (buf == NULL) goto fail;
+        ret = SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE,
+                NULL, (BYTE *)buf, size, NULL );
+        if (!ret)
+        {
+            HeapFree( GetProcessHeap(), 0, buf );
+            buf = NULL;
+        }
+
+        /* add DeviceInstance structure to Devices list */
+        instance = HeapAlloc( GetProcessHeap(), 0, sizeof(*instance) );
+        if (instance == NULL) goto fail;
+        instance->vid = vid;
+        instance->pid = pid;
+        instance->instance_id = instance_id;
+        instance->service = (WCHAR *)buf;
+        instance->dev = NULL;
+        list_add_tail( &Devices, &instance->entry );
+        instance_id = NULL;
+    }
+
+    SetupDiDestroyDeviceInfoList( set );
+    return TRUE;
+fail:
+    if (buf) HeapFree( GetProcessHeap(), 0, buf );
+    if (instance_id) HeapFree( GetProcessHeap(), 0, instance_id );
+    SetupDiDestroyDeviceInfoList( set );
+    LIST_FOR_EACH_ENTRY_SAFE( instance, instance2, &Devices,
+            struct DeviceInstance, entry )
+    {
+        HeapFree( GetProcessHeap(), 0, instance->instance_id );
+        HeapFree( GetProcessHeap(), 0, instance->service );
+        list_remove( &instance->entry );
+        HeapFree( GetProcessHeap(), 0, instance );
+    }
+    return FALSE;
+}
+
+static char *new_instance_id( USHORT vid, USHORT pid )
+{
+    struct DeviceInstance *instance;
+    char *p, *prefix = NULL;
+    unsigned int id = 0, n, prefix_len = 0;
+    char *ret;
+
+    LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
+    {
+        if (vid == instance->vid && pid == instance->pid)
+        {
+            if (prefix == NULL)
+            {
+                prefix = instance->instance_id;
+                p = strrchr( instance->instance_id, '&' );
+                if (p == NULL) prefix_len = 0;
+                else prefix_len = p + 1 - prefix;
+                id = strtoul( prefix + prefix_len, NULL, 10 ) + 1;
+            }
+            else
+            {
+                p = strrchr( instance->instance_id, '&' );
+                if (prefix_len)
+                {
+                    if (p == NULL || p + 1 - instance->instance_id != prefix_len ||
+                        strncmp( instance->instance_id, prefix, prefix_len ))
+                        continue;
+                }
+                else if (p != NULL) continue;
+                n = strtoul( instance->instance_id + prefix_len, NULL, 10 ) + 1;
+                if (n > id) id = n;
+            }
+        }
+    }
+    ret = HeapAlloc( GetProcessHeap(), 0, prefix_len + 16 );
+    if (ret == NULL) return NULL;
+    memcpy( ret, prefix, prefix_len );
+    snprintf( ret + prefix_len, prefix_len + 16, "%d", id );
+    return ret;
+}
+
+#ifdef HAVE_LIBUSB_H
+
+static BOOL is_mass_storage( libusb_device *dev )
+{
+    struct libusb_config_descriptor *conf;
+    int i, k;
+    BOOL ret = FALSE;
+
+    if (libusb_get_active_config_descriptor( dev, &conf ))
+        return FALSE;
+    for (i = 0; !ret && i < conf->bNumInterfaces; ++i)
+        for (k = 0; !ret && k < conf->interface[i].num_altsetting; ++k)
+            if (conf->interface[i].altsetting[k].bInterfaceClass == 8)
+                ret = TRUE;
+    libusb_free_config_descriptor( conf );
+    return ret;
+}
+
+#else
+
+static BOOL is_mass_storage( struct usb_device *dev )
+{
+    struct usb_config_descriptor *conf = &dev->config[0];
+    int i, k;
+    BOOL ret = FALSE;
+
+    for (i = 0; !ret && i < conf->bNumInterfaces; ++i)
+        for (k = 0; !ret && k < conf->interface[i].num_altsetting; ++k)
+            if (conf->interface[i].altsetting[k].bInterfaceClass == 8)
+                ret = TRUE;
+    return ret;
+}
+
+#endif
+
+static void register_usb_device( USHORT vid, USHORT pid, void *dev )
+{
+    static const WCHAR id_fmtW[] = {'U','S','B',
+                                    '\\','V','i','d','_','%','0','4','x',
+                                    '&','P','i','d','_','%','0','4','x',
+                                    '\\','%','s',0};
+    static const WCHAR driverW[] = {'{','3','6','F','C','9','E','6','0','-',
+                                    'C','4','6','5','-','1','1','C','F','-',
+                                    '8','0','5','6','-','4','4','4','5',
+                                    '5','3','5','4','0','0','0','0','}',
+                                    '\\','0','0','0','0',0};
+
+    struct DeviceInstance *instance;
+    HDEVINFO set = INVALID_HANDLE_VALUE;
+    SP_DEVINFO_DATA devInfo;
+    WCHAR *devnameW = NULL, *instance_idW = NULL;
+    char *instance_id;
+    ULONG size;
+
+    instance_id = new_instance_id( vid, pid );
+    if (instance_id == NULL) return;
+
+    instance = HeapAlloc( GetProcessHeap(), 0, sizeof(*instance) );
+    if (instance == NULL)
+    {
+        HeapFree( GetProcessHeap(), 0, instance_id );
+        goto done;
+    }
+    instance->vid = vid;
+    instance->pid = pid;
+    instance->instance_id = instance_id;
+    instance->service = NULL;
+    instance->dev = dev;
+    list_add_tail( &Devices, &instance->entry );
+
+    size = (strlen(instance_id) + 1) * sizeof(WCHAR);
+    instance_idW = HeapAlloc( GetProcessHeap(), 0, size );
+    if (instance_idW == NULL) goto done;
+    RtlMultiByteToUnicodeN( instance_idW, size, NULL,
+            instance_id, strlen(instance_id) + 1 );
+
+    size = sizeof(id_fmtW) + (strlenW(instance_idW) - 2) * sizeof(WCHAR);
+    devnameW = HeapAlloc( GetProcessHeap(), 0, size );
+    if (devnameW == NULL) goto done;
+    snprintfW( devnameW, size / sizeof(WCHAR), id_fmtW, vid, pid, instance_idW );
+
+    set = SetupDiGetClassDevsW( NULL, usbW, 0, DIGCF_ALLCLASSES );
+    if (set == INVALID_HANDLE_VALUE) goto done;
+    devInfo.cbSize = sizeof(SP_DEVINFO_DATA);
+    if (SetupDiCreateDeviceInfoW( set, devnameW, &GUID_DEVCLASS_USB,
+            NULL, NULL, 0, &devInfo ))
+    {
+        SetupDiRegisterDeviceInfo( set, &devInfo, 0, NULL, NULL, NULL );
+        /* This is need for Consultant+ for flash drive */
+        if (is_mass_storage( dev ))
+            SetupDiSetDeviceRegistryPropertyW( set, &devInfo, SPDRP_DRIVER,
+                    (BYTE *)driverW, sizeof(driverW) );
+    }
+done:
+    if (set != INVALID_HANDLE_VALUE)
+        SetupDiDestroyDeviceInfoList( set );
+    if (devnameW) HeapFree( GetProcessHeap(), 0, devnameW );
+    if (instance_idW) HeapFree( GetProcessHeap(), 0, instance_idW );
+}
+
+static void start_root_devices( DRIVER_OBJECT *driver_obj )
+{
+    static const WCHAR rootW[] = {'r','o','o','t',0};
+
+    SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
+    HDEVINFO set;
+    DRIVER_OBJECT *driver;
+    DEVICE_OBJECT *pdo;
+    NTSTATUS status;
+    DWORD size, i = 0;
+    WCHAR *serviceW;
+
+    set = SetupDiGetClassDevsW( NULL, rootW, 0, DIGCF_ALLCLASSES );
+    if (set == INVALID_HANDLE_VALUE) return;
+    while (SetupDiEnumDeviceInfo( set, i++, &devInfo ))
+    {
+        SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE,
+                NULL, NULL, 0, &size );
+        serviceW = HeapAlloc( GetProcessHeap(), 0, size );
+        if (serviceW == NULL) break;
+        if (SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE,
+                NULL, (BYTE *)serviceW, size, NULL ) && start_service( serviceW ))
+        {
+            status = IoCreateDevice( driver_obj, 0, NULL, 0, 0, FALSE, &pdo );
+            if (status == STATUS_SUCCESS)
+            {
+                while (!(driver = __wine_get_driver_object( serviceW )))
+                    Sleep( 100 );
+                status = __wine_add_device( driver, pdo );
+                if (status == STATUS_SUCCESS && pdo->AttachedDevice != NULL)
+                    __wine_start_device( pdo->AttachedDevice );
+            }
+        }
+        HeapFree( GetProcessHeap(), 0, serviceW );
+    }
+    SetupDiDestroyDeviceInfoList( set );
+}
+
+static void start_device_drivers( DRIVER_OBJECT *hubdrv )
+{
+    struct DeviceInstance *instance;
+    DRIVER_OBJECT *driver;
+    DEVICE_OBJECT *pdo;
+    NTSTATUS status;
+
+    LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
+    {
+        if (instance->service == NULL || instance->dev == NULL) continue;
+        if (start_service( instance->service ))
+        {
+            pdo = create_pdo( instance, hubdrv );
+            if (pdo == NULL) continue;
+            while (!(driver = __wine_get_driver_object(
+                    instance->service )))
+                Sleep( 100 );
+            status = __wine_add_device( driver, pdo );
+            if (status == STATUS_SUCCESS && pdo->AttachedDevice != NULL)
+                __wine_start_device( pdo->AttachedDevice );
+        }
+    }
+}
+
+static DWORD CALLBACK enum_usb_devices( void *usbhubdrv )
+{
+    static const WCHAR usbhub_started_eventW[] = {'_','_','w','i','n','e',
+                                                  '_','U','s','b','h','u','b',
+                                                  'S','t','a','r','t','e','d',0};
+
+#ifdef HAVE_LIBUSB_H
+    libusb_device **devs, *dev;
+    struct libusb_device_descriptor desc;
+    unsigned int i = 0;
+#else
+    struct usb_device *dev;
+    struct usb_bus *bus;
+    struct usb_device_descriptor *desc;
+#endif
+    struct DeviceInstance *instance;
+    HANDLE event;
+    BOOL new_device;
+
+    if (!enum_reg_usb_devices())
+    {
+        ERR( "failed to enumerate USB devices\n" );
+        goto end;
+    }
+
+#ifdef HAVE_LIBUSB_H
+    if (libusb_init( NULL ))
+    {
+        ERR( "failed to initialize libusb\n" );
+        goto end;
+    }
+    if (libusb_get_device_list( NULL, &devs ) < 0)
+    {
+        libusb_exit( NULL );
+        goto end;
+    }
+    while ((dev = devs[i++]))
+    {
+        if (libusb_get_device_descriptor( dev, &desc ))
+        {
+            ERR( "failed to get USB device descriptor\n" );
+            continue;
+        }
+        libusb_ref_device( dev );
+        if (libusb_get_device_address( dev ) == 1)
+        {
+            create_root_hub_device( desc.idVendor, desc.idProduct, dev, usbhubdrv );
+            continue;
+        }
+        new_device = TRUE;
+        LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
+        {
+            if (instance->dev == NULL && desc.idVendor == instance->vid &&
+                desc.idProduct == instance->pid)
+            {
+                instance->dev = dev;
+                new_device = FALSE;
+                break;
+            }
+        }
+        if (new_device)
+            register_usb_device( desc.idVendor, desc.idProduct, dev );
+    }
+    libusb_free_device_list( devs, 1 );
+#else
+    usb_init();
+    usb_find_busses();
+    usb_find_devices();
+
+    for (bus = usb_busses; bus; bus = bus->next)
+        for (dev = bus->devices; dev; dev = dev->next)
+        {
+            if (dev->devnum > 1) continue;
+            desc = &bus->devices->descriptor;
+            create_root_hub_device( desc->idVendor, desc->idProduct,
+                    bus->devices, usbhubdrv );
+        }
+    for (bus = usb_busses; bus; bus = bus->next)
+        for (dev = bus->devices; dev; dev = dev->next)
+        {
+            if (dev->devnum <= 1) continue;
+            new_device = TRUE;
+            LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
+            {
+                if (instance->dev == NULL &&
+                    dev->descriptor.idVendor == instance->vid &&
+                    dev->descriptor.idProduct == instance->pid)
+                {
+                    instance->dev = dev;
+                    new_device = FALSE;
+                    break;
+                }
+            }
+            if (new_device)
+                register_usb_device( dev->descriptor.idVendor,
+                        dev->descriptor.idProduct, dev );
+        }
+#endif
+    start_root_devices( usbhubdrv );
+    start_device_drivers( usbhubdrv );
+end:
+    event = CreateEventW( NULL, TRUE, FALSE, usbhub_started_eventW );
+    SetEvent( event );
+    CloseHandle( event );
+    return 0;
+}
+
+#endif
+
+NTSTATUS WINAPI usbhub_driver_entry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
+{
+#ifdef HAVE_LIBUSB
+    HANDLE thread;
+
+    driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = usbhub_ioctl;
+    driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = usbhub_internal_ioctl;
+    driver->MajorFunction[IRP_MJ_PNP] = usbhub_dispatch_pnp;
+
+    thread = CreateThread( NULL, 0, enum_usb_devices, driver, 0, NULL );
+    if (!thread) return STATUS_UNSUCCESSFUL;
+    CloseHandle( thread );
+#else
+    TRACE( "USB support not compiled in\n" );
+#endif
+    return STATUS_SUCCESS;
+}
diff --git a/dlls/ntoskrnl.exe/instr.c b/dlls/ntoskrnl.exe/instr.c
index 53e79fb..7accf3e 100644
--- a/dlls/ntoskrnl.exe/instr.c
+++ b/dlls/ntoskrnl.exe/instr.c
@@ -253,14 +253,14 @@ static BYTE *INSTR_GetOperandAddr( CONTEXT *context, BYTE *instr,
  */
 static void init_parport(void)
 {
-    static const WCHAR parportW[] = {'p','a','r','p','o','r','t','.','s','y','s',0};
+    static const WCHAR mountmgrW[] = {'m','o','u','n','t','m','g','r','.','s','y','s',0};
 
-    HMODULE parport = GetModuleHandleW( parportW );
+    HMODULE mountmgr = GetModuleHandleW( mountmgrW );
 
-    if (parport)
+    if (mountmgr)
     {
-        pp_read = (void *)GetProcAddress( parport, "__wine_read_parport" );
-        pp_write = (void *)GetProcAddress( parport, "__wine_write_parport" );
+        pp_read = (void *)GetProcAddress( mountmgr, "__wine_read_parport" );
+        pp_write = (void *)GetProcAddress( mountmgr, "__wine_write_parport" );
     }
     if (!pp_read || !pp_write)
         ERR( "failed to load parport functions\n" );
diff --git a/dlls/parport.sys/Makefile.in b/dlls/parport.sys/Makefile.in
deleted file mode 100644
index c59e329..0000000
--- a/dlls/parport.sys/Makefile.in
+++ /dev/null
@@ -1,10 +0,0 @@
-MODULE    = parport.sys
-IMPORTLIB = parport.sys
-IMPORTS   = ntoskrnl.exe setupapi
-EXTRADLLFLAGS = -Wb,--subsystem,native
-EXTRALIBS = @IEEE1284LIBS@
-
-C_SRCS = \
-	parport.c
-
- на MAKE_DLL_RULES@
diff --git a/dlls/parport.sys/parport.c b/dlls/parport.sys/parport.c
deleted file mode 100644
index 903ee74..0000000
--- a/dlls/parport.sys/parport.c
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * Copyright 2009 Alexander Morozov for Etersoft
- *
- * 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"
-
-#ifdef HAVE_LIBIEEE1284
-#include <ieee1284.h>
-#endif
-
-#define NONAMELESSUNION
-#define NONAMELESSSTRUCT
-#define INITGUID
-
-#include "ntstatus.h"
-#define WIN32_NO_STATUS
-#include "windef.h"
-#include "winternl.h"
-#include "winioctl.h"
-#include "winbase.h"
-#include "winuser.h"
-#include "winreg.h"
-#include "setupapi.h"
-#include "ntddpar.h"
-#include "ddk/ntddk.h"
-#include "ddk/parallel.h"
-#include "wine/unicode.h"
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(parport);
-
-
-#ifdef HAVE_LIBIEEE1284
-static const WCHAR device_idW[] = {'A','C','P','I','\\',
-                                   'P','N','P','0','4','0','0','\\','%','d',0};
-
-struct ParPortExtension
-{
-    struct parport *pp;
-    int claimed;
-    int n;
-    UNICODE_STRING interface;
-};
-
-static struct parport_list pp_list;
-
-static DRIVER_OBJECT *parport_driver;
-
-static BOOLEAN WINAPI parport_try( void *context )
-{
-    struct ParPortExtension *ppe = context;
-
-    if (ieee1284_open( ppe->pp, 0, NULL ) != E1284_OK)
-        return FALSE;
-    if (ieee1284_claim( ppe->pp ) != E1284_OK)
-    {
-        ieee1284_close( ppe->pp );
-        return FALSE;
-    }
-    ppe->claimed = 1;
-    return TRUE;
-}
-
-static void WINAPI parport_free( void *context )
-{
-    struct ParPortExtension *ppe = context;
-
-    if (ppe->claimed)
-    {
-        ieee1284_release( ppe->pp );
-        ieee1284_close( ppe->pp );
-        ppe->claimed = 0;
-    }
-}
-
-static ULONG WINAPI parport_query_waiters( void *context )
-{
-    FIXME( "stub: %p\n", context );
-    return 0;
-}
-
-static NTSTATUS WINAPI parport_ioctl( DEVICE_OBJECT *device, IRP *irp )
-{
-    IO_STACK_LOCATION *irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
-    NTSTATUS status = STATUS_NOT_SUPPORTED;
-
-    TRACE( "%p, %p\n", device, irp );
-
-    switch(irpsp->Parameters.DeviceIoControl.IoControlCode)
-    {
-    case IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE:
-        if (parport_try( device->DeviceExtension ))
-            status = STATUS_SUCCESS;
-        else
-            status = STATUS_UNSUCCESSFUL;
-        break;
-    case IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO:
-    {
-        PARALLEL_PORT_INFORMATION *ppi = irp->AssociatedIrp.SystemBuffer;
-        struct ParPortExtension *ppe = device->DeviceExtension;
-
-        if (irpsp->Parameters.DeviceIoControl.OutputBufferLength
-                < sizeof(PARALLEL_PORT_INFORMATION))
-        {
-            status = STATUS_BUFFER_TOO_SMALL;
-            break;
-        }
-        RtlZeroMemory( ppi, sizeof(*ppi) );
-        ppi->OriginalController.QuadPart = ppe->pp->base_addr;
-        ppi->Controller = (PUCHAR)ppe->pp->base_addr;
-        ppi->TryAllocatePort = parport_try;
-        ppi->FreePort = parport_free;
-        ppi->QueryNumWaiters = parport_query_waiters;
-        ppi->Context = ppe;
-        irp->IoStatus.Information = sizeof(PARALLEL_PORT_INFORMATION);
-        status = STATUS_SUCCESS;
-        break;
-    }
-    case IOCTL_INTERNAL_GET_MORE_PARALLEL_PORT_INFO:
-        TRACE( "IOCTL_INTERNAL_GET_MORE_PARALLEL_PORT_INFO: stub\n" );
-        irp->IoStatus.Information = 0;
-        status = STATUS_SUCCESS;
-        break;
-    case IOCTL_INTERNAL_PARALLEL_PORT_FREE:
-        parport_free( device->DeviceExtension );
-        status = STATUS_SUCCESS;
-        break;
-    default:
-        FIXME( "IOCTL %08x is not implemented\n",
-                irpsp->Parameters.DeviceIoControl.IoControlCode );
-            status = STATUS_NOT_IMPLEMENTED;
-    }
-    irp->IoStatus.u.Status = status;
-    IoCompleteRequest( irp, IO_NO_INCREMENT );
-    return status;
-}
-
-static NTSTATUS WINAPI parport_pnp( DEVICE_OBJECT *device, IRP *irp )
-{
-    static const WCHAR fmtW[] = {'%','d',0};
-
-    IO_STACK_LOCATION *irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
-    NTSTATUS status;
-
-    TRACE( "%p, %p\n", device, irp );
-
-    switch (irpsp->MinorFunction)
-    {
-    case IRP_MN_QUERY_ID:
-        switch (irpsp->Parameters.QueryId.IdType)
-        {
-        case BusQueryDeviceID:
-        {
-            WCHAR *device_id = ExAllocatePool( PagedPool, sizeof(device_idW) );
-
-            if (device_id == NULL)
-            {
-                status = STATUS_INSUFFICIENT_RESOURCES;
-                break;
-            }
-            strcpyW( device_id, device_idW );
-            *strrchrW( device_id, '\\' ) = 0;
-            status = STATUS_SUCCESS;
-            irp->IoStatus.Information = (ULONG_PTR)device_id;
-            break;
-        }
-        case BusQueryInstanceID:
-        {
-            ULONG len = 16;
-            struct ParPortExtension *ppe = device->DeviceExtension;
-            WCHAR *instance_id = ExAllocatePool( PagedPool, len * sizeof(WCHAR) );
-
-            if (instance_id == NULL)
-            {
-                status = STATUS_INSUFFICIENT_RESOURCES;
-                break;
-            }
-            snprintfW( instance_id, len, fmtW, ppe->n );
-            status = STATUS_SUCCESS;
-            irp->IoStatus.Information = (ULONG_PTR)instance_id;
-            break;
-        }
-        default:
-            FIXME( "IRP_MN_QUERY_ID: IdType %u is not implemented\n",
-                    irpsp->Parameters.QueryId.IdType );
-            status = STATUS_NOT_IMPLEMENTED;
-        }
-        break;
-    default:
-        FIXME( "function %08x is not implemented\n", irpsp->MinorFunction );
-        status = STATUS_NOT_IMPLEMENTED;
-    }
-    irp->IoStatus.u.Status = status;
-    IoCompleteRequest( irp, IO_NO_INCREMENT );
-    return STATUS_SUCCESS;
-}
-
-static void register_parport_device( DEVICE_OBJECT *parport_dev, int n )
-{
-    static const WCHAR acpiW[] = {'A','C','P','I',0};
-
-    struct ParPortExtension *ppe;
-    HDEVINFO set;
-    SP_DEVINFO_DATA devInfo;
-    WCHAR *devnameW;
-    ULONG size;
-    NTSTATUS status;
-
-    size = sizeof(device_idW) + 16 * sizeof(WCHAR);
-    devnameW = ExAllocatePool( PagedPool, size );
-    if (devnameW == NULL) return;
-    snprintfW( devnameW, size / sizeof(WCHAR), device_idW, n );
-
-    set = SetupDiGetClassDevsW( NULL, acpiW, 0, DIGCF_ALLCLASSES );
-    if (set == INVALID_HANDLE_VALUE) goto done;
-    devInfo.cbSize = sizeof(SP_DEVINFO_DATA);
-    if (SetupDiCreateDeviceInfoW( set, devnameW, &GUID_SERENUM_BUS_ENUMERATOR,
-            NULL, NULL, 0, &devInfo ))
-    {
-        if (!SetupDiRegisterDeviceInfo( set, &devInfo, 0, NULL, NULL, NULL ))
-            goto done;
-    }
-    else
-    {
-        if (ERROR_DEVINST_ALREADY_EXISTS != GetLastError())
-            goto done;
-    }
-
-    ppe = parport_dev->DeviceExtension;
-    status = IoRegisterDeviceInterface( parport_dev, &GUID_DEVINTERFACE_PARALLEL,
-            NULL, &ppe->interface );
-    if (status == STATUS_SUCCESS)
-        IoSetDeviceInterfaceState( &ppe->interface, TRUE );
-done:
-    if (set != INVALID_HANDLE_VALUE)
-        SetupDiDestroyDeviceInfoList( set );
-    ExFreePool( devnameW );
-}
-
-static void create_parport_device( DRIVER_OBJECT *driver, int n, struct parport *pp )
-{
-    static const WCHAR parallel_portW[] = {'\\','D','e','v','i','c','e',
-                                           '\\','P','a','r','a','l','l','e','l',
-                                           'P','o','r','t','%','d',0};
-
-    struct ParPortExtension *ppe;
-    UNICODE_STRING parallel_port;
-    DEVICE_OBJECT *parport_dev;
-    WCHAR device_name[MAX_PATH];
-    NTSTATUS status;
-
-    snprintfW( device_name, MAX_PATH, parallel_portW, n );
-    RtlInitUnicodeString( &parallel_port, device_name );
-    status = IoCreateDevice( driver, sizeof(struct ParPortExtension), &parallel_port,
-            FILE_DEVICE_PARALLEL_PORT, FILE_DEVICE_SECURE_OPEN, FALSE, &parport_dev );
-    if (status == STATUS_SUCCESS)
-    {
-        ppe = parport_dev->DeviceExtension;
-        RtlZeroMemory( ppe, sizeof(*ppe) );
-        ppe->pp = pp;
-        ppe->n = n;
-        register_parport_device( parport_dev, n );
-        parport_dev->Flags &= ~DO_DEVICE_INITIALIZING;
-    }
-}
-
-static void enum_par_devices( DRIVER_OBJECT *driver )
-{
-    struct parport *pp;
-    int k;
-
-    ieee1284_find_ports( &pp_list, 0 );
-    for (k = 0; k < pp_list.portc; ++k)
-    {
-        pp = pp_list.portv[k];
-        create_parport_device( driver, k, pp );
-    }
-}
-
-static struct ParPortExtension *get_parport_ext( UCHAR *port, ULONG *offset )
-{
-    DEVICE_OBJECT *device = parport_driver->DeviceObject;
-    struct ParPortExtension *ppe;
-
-    while (device)
-    {
-        ppe = device->DeviceExtension;
-        *offset = (ULONG)port - ppe->pp->base_addr;
-        if (*offset <= DCR_OFFSET) return ppe;
-        device = device->NextDevice;
-    }
-    return NULL;
-}
-
-static int read_parport( struct parport *pp, ULONG offset )
-{
-    if (DATA_OFFSET == offset) return ieee1284_read_data( pp );
-    if (DSR_OFFSET == offset) return ieee1284_read_status( pp ) ^ S1284_INVERTED;
-    if (DCR_OFFSET == offset) return ieee1284_read_control( pp ) ^ C1284_INVERTED;
-    return -1;
-}
-
-static void write_parport( struct parport *pp, UCHAR value, ULONG offset )
-{
-    if (DATA_OFFSET == offset) ieee1284_write_data( pp, value );
-    /* FIXME: see NOTE in ieee1284.h */
-    else if (DCR_OFFSET == offset) ieee1284_write_control( pp, value ^ C1284_INVERTED );
-}
-#endif  /* HAVE_LIBIEEE1284 */
-
-UCHAR CDECL __wine_read_parport( UCHAR *port )
-{
-#ifdef HAVE_LIBIEEE1284
-    int ret = -1;
-    ULONG offset;
-    struct ParPortExtension *ppe = get_parport_ext( port, &offset );
-
-    if (!ppe) return 0xff;
-    if (ppe->claimed) ret = read_parport( ppe->pp, offset );
-    else if (parport_try( ppe ))
-    {
-        ret = read_parport( ppe->pp, offset );
-        parport_free( ppe );
-    }
-    if (ret >= 0) return ret;
-#endif
-    return 0xff;
-}
-
-void CDECL __wine_write_parport( UCHAR *port, UCHAR value )
-{
-#ifdef HAVE_LIBIEEE1284
-    ULONG offset;
-    struct ParPortExtension *ppe = get_parport_ext( port, &offset );
-
-    if (!ppe) return;
-    if (ppe->claimed) write_parport( ppe->pp, value, offset );
-    else if (parport_try( ppe ))
-    {
-        write_parport( ppe->pp, value, offset );
-        parport_free( ppe );
-    }
-#endif
-}
-
-static void WINAPI parport_unload( DRIVER_OBJECT *driver )
-{
-#ifdef HAVE_LIBIEEE1284
-    DEVICE_OBJECT *device = driver->DeviceObject, *device2;
-    struct ParPortExtension *ppe;
-
-    while (device)
-    {
-        device2 = device->NextDevice;
-        ppe = device->DeviceExtension;
-        if (ppe->interface.Buffer)
-        {
-            IoSetDeviceInterfaceState( &ppe->interface, FALSE );
-            RtlFreeUnicodeString( &ppe->interface );
-        }
-        IoDeleteDevice( device );
-        device = device2;
-    }
-    ieee1284_free_ports( &pp_list );
-#endif
-}
-
-NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
-{
-    driver->DriverUnload = parport_unload;
-#ifdef HAVE_LIBIEEE1284
-    driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = parport_ioctl;
-    driver->MajorFunction[IRP_MJ_PNP] = parport_pnp;
-    parport_driver = driver;
-    enum_par_devices( driver );
-#endif
-    return STATUS_SUCCESS;
-}
diff --git a/dlls/parport.sys/parport.sys.spec b/dlls/parport.sys/parport.sys.spec
deleted file mode 100644
index 4848c4a..0000000
--- a/dlls/parport.sys/parport.sys.spec
+++ /dev/null
@@ -1,8 +0,0 @@
-################################################################
-# Wine internal extensions
-#
-# All functions must be prefixed with '__wine_' (for internal functions)
-# or 'wine_' (for user-visible functions) to avoid namespace conflicts.
-
-@ cdecl __wine_read_parport(ptr)
-@ cdecl __wine_write_parport(ptr long)
diff --git a/dlls/usbhub.sys/Makefile.in b/dlls/usbhub.sys/Makefile.in
deleted file mode 100644
index 7594887..0000000
--- a/dlls/usbhub.sys/Makefile.in
+++ /dev/null
@@ -1,10 +0,0 @@
-MODULE    = usbhub.sys
-IMPORTS   = ntoskrnl.exe advapi32 setupapi
-EXTRADLLFLAGS = -Wb,--subsystem,native
-EXTRAINCL = @USBINCL@
-EXTRALIBS = @USBLIBS@
-
-C_SRCS = \
-	usbhub.c
-
- на MAKE_DLL_RULES@
diff --git a/dlls/usbhub.sys/usbhub.c b/dlls/usbhub.sys/usbhub.c
deleted file mode 100644
index 2bed715..0000000
--- a/dlls/usbhub.sys/usbhub.c
+++ /dev/null
@@ -1,1733 +0,0 @@
-/*
- * Copyright 2008-2009 Alexander Morozov for Etersoft
- *
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-#ifdef HAVE_LIBUSB_H
-#include <libusb.h>
-#elif defined(HAVE_USB_H)
-#include <usb.h>
-#endif
-
-#define NONAMELESSUNION
-#define NONAMELESSSTRUCT
-#define INITGUID
-
-#include "ntstatus.h"
-#define WIN32_NO_STATUS
-#include "windef.h"
-#include "winbase.h"
-#include "winternl.h"
-#include "winioctl.h"
-#include "winreg.h"
-#include "winsvc.h"
-#include "winuser.h"
-#include "setupapi.h"
-#include "cfgmgr32.h"
-#include "devguid.h"
-#include "ddk/ntddk.h"
-#define WINE_USBHUB_EXTENSIONS
-#include "ddk/usbdrivr.h"
-#include "ddk/usbioctl.h"
-#include "wine/unicode.h"
-#include "wine/debug.h"
-#include "wine/list.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(usbhub);
-
-extern NTSTATUS CDECL __wine_add_device( DRIVER_OBJECT *driver, DEVICE_OBJECT *dev );
-extern DRIVER_OBJECT * CDECL __wine_get_driver_object( const WCHAR *service );
-extern NTSTATUS CDECL __wine_start_device( DEVICE_OBJECT *device );
-
-#define NUMBER_OF_PORTS 8
-
-static const WCHAR usbW[] = {'U','S','B',0};
-
-static struct list Devices = LIST_INIT(Devices);
-
-struct DeviceInstance
-{
-    struct list entry;
-    USHORT vid;
-    USHORT pid;
-    char *instance_id;
-    WCHAR *service;
-#ifdef HAVE_LIBUSB_H
-    libusb_device *dev;
-#else
-    struct usb_device *dev;
-#endif
-};
-
-struct PdoExtension
-{
-    struct DeviceInstance *instance;
-};
-
-#ifdef HAVE_LIBUSB
-
-static void add_data( unsigned char **dst, ULONG *dst_size, const void *src, ULONG src_size )
-{
-    int copy;
-
-    copy = (src_size >= *dst_size) ? *dst_size : src_size;
-    memcpy( *dst, src, copy );
-    *dst += copy;
-    *dst_size -= copy;
-}
-
-static NTSTATUS WINAPI usbhub_ioctl( DEVICE_OBJECT *device, IRP *irp )
-{
-    static const WCHAR device_idW[] = {'U','S','B','\\',
-                                       'V','i','d','_','%','0','4','x','&',
-                                       'P','i','d','_','%','0','4','x','\\',0};
-    static const WCHAR root_hub_idW[] = {'U','S','B','\\',
-                                         'R','O','O','T','_','H','U','B','\\',0};
-
-    IO_STACK_LOCATION *irpsp;
-    NTSTATUS status = STATUS_UNSUCCESSFUL;
-    struct DeviceInstance *inst;
-    ULONG_PTR info = 0;
-
-    TRACE( "%p, %p\n", device, irp );
-
-    inst = ((struct PdoExtension *)device->DeviceExtension)->instance;
-    if (inst->service) goto done;
-    irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
-
-    switch (irpsp->Parameters.DeviceIoControl.IoControlCode)
-    {
-    case IOCTL_USB_GET_NODE_INFORMATION:
-    {
-        USB_NODE_INFORMATION *node_info = irp->AssociatedIrp.SystemBuffer;
-
-        if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(*node_info))
-        {
-            status = STATUS_BUFFER_TOO_SMALL;
-            break;
-        }
-        RtlZeroMemory( node_info, sizeof(*node_info) );
-        node_info->u.HubInformation.HubDescriptor.bDescriptorLength = 9;
-        node_info->u.HubInformation.HubDescriptor.bDescriptorType = 41;
-        node_info->u.HubInformation.HubDescriptor.bNumberOfPorts = NUMBER_OF_PORTS;
-        status = STATUS_SUCCESS;
-        info = sizeof(*node_info);
-        break;
-    }
-    case IOCTL_USB_GET_NODE_CONNECTION_INFORMATION:
-    {
-        USB_NODE_CONNECTION_INFORMATION *conn_info = irp->AssociatedIrp.SystemBuffer;
-        ULONG index = 0;
-#ifdef HAVE_LIBUSB_H
-        struct DeviceInstance *instance;
-        uint8_t bus_number = libusb_get_bus_number( inst->dev );
-#else
-        struct usb_device *dev;
-#endif
-
-        if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(*conn_info))
-        {
-            status = STATUS_BUFFER_TOO_SMALL;
-            break;
-        }
-        if (!conn_info->ConnectionIndex || conn_info->ConnectionIndex > NUMBER_OF_PORTS)
-        {
-            status = STATUS_INVALID_PARAMETER;
-            break;
-        }
-        RtlZeroMemory( (ULONG *)conn_info + 1, sizeof(*conn_info) - sizeof(ULONG) );
-#ifdef HAVE_LIBUSB_H
-        LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
-        {
-            if (instance->dev && instance->dev != inst->dev &&
-                libusb_get_bus_number( instance->dev ) == bus_number &&
-                ++index == conn_info->ConnectionIndex)
-            {
-                struct libusb_device_descriptor desc;
-
-                if (libusb_get_device_descriptor( instance->dev, &desc ))
-                    break;
-                memcpy( &conn_info->DeviceDescriptor, &desc,
-                        sizeof(USB_DEVICE_DESCRIPTOR) );
-                conn_info->ConnectionStatus = 1;
-                break;
-            }
-        }
-#else
-        for (dev = inst->dev->next; dev; dev = dev->next)
-            if (++index == conn_info->ConnectionIndex)
-            {
-                memcpy( &conn_info->DeviceDescriptor, &dev->descriptor,
-                        sizeof(USB_DEVICE_DESCRIPTOR) );
-                conn_info->ConnectionStatus = 1;
-                break;
-            }
-#endif
-        status = STATUS_SUCCESS;
-        info = sizeof(*conn_info);
-        break;
-    }
-    case IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME:
-    {
-        USB_NODE_CONNECTION_DRIVERKEY_NAME *driver_key_name =
-                irp->AssociatedIrp.SystemBuffer;
-        WCHAR *dev_instance_idW, *bufW;
-        struct DeviceInstance *instance;
-        HDEVINFO set;
-        SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
-        ULONG len, index = 0, found = 0;
-#ifdef HAVE_LIBUSB_H
-        uint8_t bus_number = libusb_get_bus_number( inst->dev );
-#else
-        struct usb_device *dev;
-#endif
-
-        if (irpsp->Parameters.DeviceIoControl.OutputBufferLength <
-                sizeof(*driver_key_name))
-        {
-            status = STATUS_BUFFER_TOO_SMALL;
-            break;
-        }
-#ifdef HAVE_LIBUSB_H
-        LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
-        {
-            if (instance->dev && instance->dev != inst->dev &&
-                libusb_get_bus_number( instance->dev ) == bus_number &&
-                ++index == driver_key_name->ConnectionIndex)
-            {
-                found = 1;
-                break;
-            }
-        }
-#else
-        for (dev = inst->dev->next; dev; dev = dev->next)
-            if (++index == driver_key_name->ConnectionIndex)
-            {
-                LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
-                {
-                    if (instance->dev == dev)
-                    {
-                        found = 1;
-                        break;
-                    }
-                }
-                break;
-            }
-#endif
-        if (!found)
-        {
-            status = STATUS_INVALID_PARAMETER;
-            break;
-        }
-        bufW = HeapAlloc( GetProcessHeap(), 0,
-                2 * MAX_DEVICE_ID_LEN * sizeof(WCHAR) );
-        if (bufW == NULL)
-        {
-            status = STATUS_INSUFFICIENT_RESOURCES;
-            break;
-        }
-        dev_instance_idW = bufW + MAX_DEVICE_ID_LEN;
-        snprintfW( dev_instance_idW, MAX_DEVICE_ID_LEN, device_idW,
-                instance->vid, instance->pid );
-        len = strlenW(dev_instance_idW);
-        RtlMultiByteToUnicodeN( dev_instance_idW + len,
-                (MAX_DEVICE_ID_LEN - len) * sizeof(WCHAR), NULL,
-                instance->instance_id, strlen(instance->instance_id) + 1 );
-        set = SetupDiGetClassDevsW( NULL, usbW, 0, DIGCF_ALLCLASSES );
-        if (set == INVALID_HANDLE_VALUE)
-        {
-            HeapFree( GetProcessHeap(), 0, bufW );
-            break;
-        }
-        index = 0;
-        while (SetupDiEnumDeviceInfo( set, index++, &devInfo ))
-        {
-            if (!SetupDiGetDeviceInstanceIdW( set, &devInfo, bufW,
-                    MAX_DEVICE_ID_LEN, NULL ))
-                break;
-            if (!strcmpiW( dev_instance_idW, bufW ))
-            {
-                SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_DRIVER,
-                        NULL, NULL, 0, &len );
-                driver_key_name->ActualLength = 2 * sizeof(ULONG) + len;
-                if (irpsp->Parameters.DeviceIoControl.OutputBufferLength <
-                        driver_key_name->ActualLength)
-                {
-                    status = STATUS_SUCCESS;
-                    info = sizeof(*driver_key_name);
-                }
-                else if (SetupDiGetDeviceRegistryPropertyW( set, &devInfo,
-                        SPDRP_DRIVER, NULL, (BYTE *)driver_key_name->DriverKeyName,
-                        len, NULL ))
-                {
-                    status = STATUS_SUCCESS;
-                    info = driver_key_name->ActualLength;
-                }
-                break;
-            }
-        }
-        SetupDiDestroyDeviceInfoList( set );
-        HeapFree( GetProcessHeap(), 0, bufW );
-        break;
-    }
-    case IOCTL_USB_GET_DEVICE_INFO:
-    {
-        struct usb_device_info *dev_info = irp->AssociatedIrp.SystemBuffer;
-        struct DeviceInstance *instance;
-        ULONG len, index = 0;
-#ifdef HAVE_LIBUSB_H
-        uint8_t bus_number = libusb_get_bus_number( inst->dev );
-#else
-        struct usb_device *dev;
-#endif
-
-        if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(*dev_info))
-        {
-            status = STATUS_BUFFER_TOO_SMALL;
-            break;
-        }
-        if (!dev_info->connection_index || dev_info->connection_index > NUMBER_OF_PORTS)
-        {
-            status = STATUS_INVALID_PARAMETER;
-            break;
-        }
-        RtlZeroMemory( (ULONG *)dev_info + 1, sizeof(*dev_info) - sizeof(ULONG) );
-        memcpy( dev_info->root_hub_id, root_hub_idW, sizeof(root_hub_idW) );
-        len = strlenW(root_hub_idW);
-        RtlMultiByteToUnicodeN( dev_info->root_hub_id + len,
-                (MAX_DEVICE_ID_LEN - len) * sizeof(WCHAR), NULL,
-                inst->instance_id, strlen(inst->instance_id) + 1 );
-#ifdef HAVE_LIBUSB_H
-        LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
-        {
-            if (instance->dev && instance->dev != inst->dev &&
-                libusb_get_bus_number( instance->dev ) == bus_number &&
-                ++index == dev_info->connection_index)
-            {
-                dev_info->device_address = libusb_get_device_address( instance->dev );
-                break;
-            }
-        }
-#else
-        for (dev = inst->dev->next; dev; dev = dev->next)
-            if (++index == dev_info->connection_index)
-            {
-                dev_info->device_address = dev->devnum;
-                LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
-                {
-                    if (instance->dev == dev) break;
-                }
-                break;
-            }
-#endif
-        if (dev_info->device_address)
-        {
-            snprintfW( dev_info->device_id, MAX_DEVICE_ID_LEN, device_idW,
-                    instance->vid, instance->pid );
-            len = strlenW(dev_info->device_id);
-            RtlMultiByteToUnicodeN( dev_info->device_id + len,
-                    (MAX_DEVICE_ID_LEN - len) * sizeof(WCHAR), NULL,
-                    instance->instance_id, strlen(instance->instance_id) + 1 );
-        }
-        status = STATUS_SUCCESS;
-        info = sizeof(*dev_info);
-        break;
-    }
-    default:
-        FIXME( "IOCTL %08x is not implemented\n",
-                irpsp->Parameters.DeviceIoControl.IoControlCode );
-    }
-
-done:
-    irp->IoStatus.u.Status = status;
-    irp->IoStatus.Information = info;
-    IoCompleteRequest( irp, IO_NO_INCREMENT );
-
-    return status;
-}
-
-#ifdef HAVE_LIBUSB_H
-
-static NTSTATUS WINAPI usbhub_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
-{
-    IO_STACK_LOCATION *irpsp;
-    URB *urb;
-    NTSTATUS status = STATUS_UNSUCCESSFUL;
-    struct DeviceInstance *inst;
-
-    TRACE( "%p, %p\n", device, irp );
-
-    inst = ((struct PdoExtension *)device->DeviceExtension)->instance;
-    if (!inst->service) goto done;
-    irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
-    urb = irpsp->Parameters.Others.Argument1;
-
-    switch (irpsp->Parameters.DeviceIoControl.IoControlCode)
-    {
-    case IOCTL_INTERNAL_USB_SUBMIT_URB:
-        switch (urb->u.UrbHeader.Function)
-        {
-        case URB_FUNCTION_SELECT_CONFIGURATION:
-            {
-                struct _URB_SELECT_CONFIGURATION *request =
-                        &urb->u.UrbSelectConfiguration;
-                libusb_device_handle *husb;
-
-                TRACE( "URB_FUNCTION_SELECT_CONFIGURATION\n" );
-
-                if (!libusb_open( inst->dev, &husb ))
-                {
-                    USB_CONFIGURATION_DESCRIPTOR *conf_desc =
-                            request->ConfigurationDescriptor;
-                    struct libusb_config_descriptor *conf;
-                    int ret;
-
-                    ret = libusb_set_configuration( husb, (conf_desc != NULL) ?
-                            conf_desc->bConfigurationValue : -1 );
-                    if (ret < 0)
-                        ERR( "libusb_set_configuration: %d\n", ret );
-                    else if (conf_desc == NULL)
-                        status = STATUS_SUCCESS;
-                    else if (!libusb_get_active_config_descriptor( inst->dev, &conf ))
-                    {
-                        USBD_INTERFACE_INFORMATION *if_info = &request->Interface;
-                        const struct libusb_interface_descriptor *intf;
-                        ULONG k, n;
-
-                        /* FIXME: case of num_altsetting > 1 */
-
-                        for (n = 0; n < conf_desc->bNumInterfaces; ++n)
-                        {
-                            intf = &conf->interface[n].altsetting[0];
-                            if_info->Class = intf->bInterfaceClass;
-                            if_info->SubClass = intf->bInterfaceSubClass;
-                            if_info->Protocol = intf->bInterfaceProtocol;
-                            if_info->InterfaceHandle =
-                                    (void *)(intf->bInterfaceNumber + 1);
-                            for (k = 0; k < if_info->NumberOfPipes; ++k)
-                            {
-                                if_info->Pipes[k].MaximumPacketSize =
-                                        intf->endpoint[k].wMaxPacketSize;
-                                if_info->Pipes[k].EndpointAddress =
-                                        intf->endpoint[k].bEndpointAddress;
-                                if_info->Pipes[k].Interval =
-                                        intf->endpoint[k].bInterval;
-                                if_info->Pipes[k].PipeType =
-                                        intf->endpoint[k].bmAttributes & 3;
-                                if_info->Pipes[k].PipeHandle =
-                                        (void *)(intf->endpoint[k].bEndpointAddress +
-                                        ((intf->bInterfaceNumber + 1) << 8));
-                            }
-                            if_info = (USBD_INTERFACE_INFORMATION *)
-                                    ((char *)if_info + if_info->Length);
-                        }
-                        libusb_free_config_descriptor( conf );
-                        status = STATUS_SUCCESS;
-                    }
-                    libusb_close( husb );
-                }
-            }
-            break;
-        case URB_FUNCTION_SELECT_INTERFACE:
-            {
-                struct _URB_SELECT_INTERFACE *request =
-                        &urb->u.UrbSelectInterface;
-                libusb_device_handle *husb;
-
-                TRACE( "URB_FUNCTION_SELECT_INTERFACE\n" );
-
-                if (!libusb_open( inst->dev, &husb ))
-                {
-                    int ret;
-
-                    ret = libusb_claim_interface( husb,
-                            request->Interface.InterfaceNumber );
-                    if (!ret)
-                    {
-                        ret = libusb_set_interface_alt_setting( husb,
-                                request->Interface.InterfaceNumber,
-                                request->Interface.AlternateSetting );
-                        if (!libusb_release_interface( husb,
-                                request->Interface.InterfaceNumber ) && !ret)
-                            status = STATUS_SUCCESS;
-                    }
-                    libusb_close( husb );
-                }
-            }
-            break;
-        case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
-            {
-                struct _URB_BULK_OR_INTERRUPT_TRANSFER *request =
-                        &urb->u.UrbBulkOrInterruptTransfer;
-                unsigned char *buf = request->TransferBuffer;
-                libusb_device_handle *husb;
-
-                TRACE( "URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER\n" );
-
-                if (buf == NULL && request->TransferBufferMDL != NULL)
-                    buf = request->TransferBufferMDL->MappedSystemVa;
-                if (!libusb_open( inst->dev, &husb ))
-                {
-                    int ret, transferred;
-
-                    ret = libusb_claim_interface( husb,
-                            ((int)request->PipeHandle >> 8) - 1 );
-                    if (!ret)
-                    {
-                        /* FIXME: add support for an interrupt transfer */
-                        ret = libusb_bulk_transfer( husb,
-                                (unsigned int)request->PipeHandle,
-                                buf, request->TransferBufferLength,
-                                &transferred, 0 );
-                        if (!libusb_release_interface( husb,
-                                ((int)request->PipeHandle >> 8) - 1 ) && !ret)
-                        {
-                            request->TransferBufferLength = transferred;
-                            status = STATUS_SUCCESS;
-                        }
-                    }
-                    libusb_close( husb );
-                }
-            }
-            break;
-        case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
-            {
-                struct _URB_CONTROL_DESCRIPTOR_REQUEST *request =
-                        &urb->u.UrbControlDescriptorRequest;
-                ULONG size = request->TransferBufferLength;
-                unsigned char *buf = request->TransferBuffer;
-
-                TRACE( "URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n" );
-
-                if (!size)
-                {
-                    status = STATUS_SUCCESS;
-                    break;
-                }
-                if (buf == NULL && request->TransferBufferMDL != NULL)
-                    buf = request->TransferBufferMDL->MappedSystemVa;
-                if (buf == NULL)
-                {
-                    status = STATUS_INVALID_PARAMETER;
-                    break;
-                }
-
-                switch (request->DescriptorType)
-                {
-                case USB_DEVICE_DESCRIPTOR_TYPE:
-                    TRACE( "USB_DEVICE_DESCRIPTOR_TYPE\n" );
-                    {
-                        struct libusb_device_descriptor desc;
-
-                        if (libusb_get_device_descriptor( inst->dev, &desc ))
-                            break;
-                        memcpy( buf, &desc, (size < sizeof(USB_DEVICE_DESCRIPTOR)) ?
-                                size : sizeof(USB_DEVICE_DESCRIPTOR) );
-                        status = STATUS_SUCCESS;
-                    }
-                    break;
-                case USB_CONFIGURATION_DESCRIPTOR_TYPE:
-                    TRACE( "USB_CONFIGURATION_DESCRIPTOR_TYPE\n" );
-                    {
-                        unsigned int i, k;
-                        struct libusb_config_descriptor *conf;
-                        const struct libusb_interface_descriptor *intf;
-                        const struct libusb_endpoint_descriptor *endp;
-
-                        /* FIXME: case of num_altsetting > 1 */
-
-                        if (libusb_get_active_config_descriptor( inst->dev, &conf ))
-                            break;
-                        add_data( &buf, &size, conf,
-                                sizeof(USB_CONFIGURATION_DESCRIPTOR) );
-                        if (size > 0 && conf->extra)
-                            add_data( &buf, &size, conf->extra, conf->extra_length );
-                        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->extra_length );
-                            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->extra_length );
-                            }
-                        }
-                        libusb_free_config_descriptor( conf );
-                        status = STATUS_SUCCESS;
-                    }
-                    break;
-                case USB_STRING_DESCRIPTOR_TYPE:
-                    TRACE( "USB_STRING_DESCRIPTOR_TYPE\n" );
-                    {
-                        libusb_device_handle *husb;
-                        int ret;
-
-                        if (!libusb_open( inst->dev, &husb ))
-                        {
-                            ret = libusb_get_string_descriptor( husb, request->Index,
-                                    request->LanguageId, buf, size );
-                            libusb_close( husb );
-                            if (ret < 0) break;
-                            status = STATUS_SUCCESS;
-                        }
-                    }
-                }
-            }
-            break;
-        case URB_FUNCTION_GET_STATUS_FROM_DEVICE:
-            {
-                struct _URB_CONTROL_GET_STATUS_REQUEST *request =
-                        &urb->u.UrbControlGetStatusRequest;
-                void *buf = request->TransferBuffer;
-                libusb_device_handle *husb;
-                int ret;
-
-                TRACE( "URB_FUNCTION_GET_STATUS_FROM_DEVICE\n" );
-
-                if (buf == NULL && request->TransferBufferMDL != NULL)
-                    buf = request->TransferBufferMDL->MappedSystemVa;
-                if (buf == NULL || request->TransferBufferLength < sizeof(USHORT))
-                {
-                    status = STATUS_INVALID_PARAMETER;
-                    break;
-                }
-                if (!libusb_open( inst->dev, &husb ))
-                {
-                    ret = libusb_control_transfer( husb, 1 << 7,
-                            LIBUSB_REQUEST_GET_STATUS, 0, request->Index, buf,
-                            sizeof(USHORT), 0 );
-                    libusb_close( husb );
-                    if (ret < 0) break;
-                    status = STATUS_SUCCESS;
-                }
-            }
-            break;
-        case URB_FUNCTION_VENDOR_DEVICE:
-        case URB_FUNCTION_VENDOR_INTERFACE:
-        case URB_FUNCTION_VENDOR_ENDPOINT:
-        case URB_FUNCTION_CLASS_DEVICE:
-        case URB_FUNCTION_CLASS_INTERFACE:
-        case URB_FUNCTION_CLASS_ENDPOINT:
-            {
-                libusb_device_handle *husb;
-                struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *request =
-                        &urb->u.UrbControlVendorClassRequest;
-                unsigned char *req_buf = request->TransferBuffer;
-                ULONG size = request->TransferBufferLength;
-
-                TRACE( "URB_FUNCTION_{VENDOR,CLASS}_*\n" );
-
-                if (req_buf == NULL && request->TransferBufferMDL != NULL)
-                    req_buf = request->TransferBufferMDL->MappedSystemVa;
-                if (size && req_buf == NULL)
-                {
-                    status = STATUS_INVALID_PARAMETER;
-                    break;
-                }
-                if (!libusb_open( inst->dev, &husb ))
-                {
-                    UCHAR req_type = request->RequestTypeReservedBits;
-                    unsigned char *buf;
-                    int ret;
-
-                    switch (urb->u.UrbHeader.Function)
-                    {
-                    case URB_FUNCTION_VENDOR_DEVICE:    req_type |= 0x40; break;
-                    case URB_FUNCTION_VENDOR_INTERFACE: req_type |= 0x41; break;
-                    case URB_FUNCTION_VENDOR_ENDPOINT:  req_type |= 0x42; break;
-                    case URB_FUNCTION_CLASS_DEVICE:     req_type |= 0x20; break;
-                    case URB_FUNCTION_CLASS_INTERFACE:  req_type |= 0x21; break;
-                    case URB_FUNCTION_CLASS_ENDPOINT:   req_type |= 0x22; break;
-                    }
-                    buf = HeapAlloc( GetProcessHeap(), 0, size );
-                    if (buf != NULL)
-                    {
-                        memcpy( buf, req_buf, size );
-                        if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
-                            req_type |= (1 << 7);
-                        ret = libusb_control_transfer( husb, req_type,
-                                request->Request, request->Value, request->Index,
-                                buf, size, 0 );
-                        if (ret < 0)
-                            ERR( "libusb_control_transfer: %d\n", ret );
-                        else
-                        {
-                            if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
-                            {
-                                request->TransferBufferLength =
-                                        (ret < size) ? ret : size;
-                                memcpy( req_buf, buf, request->TransferBufferLength );
-                            }
-                            status = STATUS_SUCCESS;
-                        }
-                        HeapFree( GetProcessHeap(), 0, buf );
-                    }
-                    libusb_close( husb );
-                }
-            }
-            break;
-        default:
-            FIXME( "unsupported URB function %x\n", urb->u.UrbHeader.Function );
-        }
-        urb->u.UrbHeader.Status = status;
-        break;
-    default:
-        FIXME( "IOCTL %08x is not implemented\n",
-                irpsp->Parameters.DeviceIoControl.IoControlCode );
-    }
-
-done:
-    irp->IoStatus.u.Status = status;
-    irp->IoStatus.Information = 0;
-    IoCompleteRequest( irp, IO_NO_INCREMENT );
-
-    return status;
-}
-
-#else
-
-static NTSTATUS WINAPI usbhub_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
-{
-    IO_STACK_LOCATION *irpsp;
-    URB *urb;
-    NTSTATUS status = STATUS_UNSUCCESSFUL;
-    struct DeviceInstance *inst;
-
-    TRACE( "%p, %p\n", device, irp );
-
-    inst = ((struct PdoExtension *)device->DeviceExtension)->instance;
-    if (!inst->service) goto done;
-    irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
-    urb = irpsp->Parameters.Others.Argument1;
-
-    switch (irpsp->Parameters.DeviceIoControl.IoControlCode)
-    {
-    case IOCTL_INTERNAL_USB_SUBMIT_URB:
-        switch (urb->u.UrbHeader.Function)
-        {
-        case URB_FUNCTION_SELECT_CONFIGURATION:
-            {
-                struct _URB_SELECT_CONFIGURATION *request =
-                        &urb->u.UrbSelectConfiguration;
-                usb_dev_handle *husb;
-
-                TRACE( "URB_FUNCTION_SELECT_CONFIGURATION\n" );
-
-                husb = usb_open( inst->dev );
-                if (husb)
-                {
-                    USB_CONFIGURATION_DESCRIPTOR *conf_desc =
-                            urb->u.UrbSelectConfiguration.ConfigurationDescriptor;
-                    int ret;
-
-                    ret = usb_set_configuration( husb, (conf_desc != NULL) ?
-                            conf_desc->bConfigurationValue : -1 );
-                    if (ret < 0)
-                        ERR( "%s\n", usb_strerror() );
-                    else if (conf_desc == NULL)
-                        status = STATUS_SUCCESS;
-                    else
-                    {
-                        USBD_INTERFACE_INFORMATION *if_info = &request->Interface;
-                        struct usb_config_descriptor *conf;
-                        struct usb_interface_descriptor *intf;
-                        ULONG k, n;
-
-                        /* FIXME: case of num_altsetting > 1 */
-
-                        for (n = 0; n < inst->dev->descriptor.bNumConfigurations; ++n)
-                            if (inst->dev->config[n].bConfigurationValue ==
-                                conf_desc->bConfigurationValue)
-                            {
-                                conf = &inst->dev->config[n];
-                                break;
-                            }
-                        for (n = 0; n < conf_desc->bNumInterfaces; ++n)
-                        {
-                            intf = &conf->interface[n].altsetting[0];
-                            if_info->Class = intf->bInterfaceClass;
-                            if_info->SubClass = intf->bInterfaceSubClass;
-                            if_info->Protocol = intf->bInterfaceProtocol;
-                            if_info->SubClass = intf->bInterfaceSubClass;
-                            if_info->Protocol = intf->bInterfaceProtocol;
-                            if_info->InterfaceHandle =
-                                    (void *)(intf->bInterfaceNumber + 1);
-                            for (k = 0; k < if_info->NumberOfPipes; ++k)
-                            {
-                                if_info->Pipes[k].MaximumPacketSize =
-                                        intf->endpoint[k].wMaxPacketSize;
-                                if_info->Pipes[k].EndpointAddress =
-                                        intf->endpoint[k].bEndpointAddress;
-                                if_info->Pipes[k].Interval =
-                                        intf->endpoint[k].bInterval;
-                                if_info->Pipes[k].PipeType =
-                                        intf->endpoint[k].bmAttributes & 3;
-                                if_info->Pipes[k].PipeHandle =
-                                        (void *)(intf->endpoint[k].bEndpointAddress +
-                                        ((intf->bInterfaceNumber + 1) << 8));
-                            }
-                            if_info = (USBD_INTERFACE_INFORMATION *)
-                                    ((char *)if_info + if_info->Length);
-                        }
-                        status = STATUS_SUCCESS;
-                    }
-                    usb_close( husb );
-                }
-            }
-            break;
-        case URB_FUNCTION_SELECT_INTERFACE:
-            {
-                struct _URB_SELECT_INTERFACE *request =
-                        &urb->u.UrbSelectInterface;
-                usb_dev_handle *husb;
-
-                TRACE( "URB_FUNCTION_SELECT_INTERFACE\n" );
-
-                husb = usb_open( inst->dev );
-                if (husb)
-                {
-                    int ret;
-
-                    ret = usb_claim_interface( husb,
-                            request->Interface.InterfaceNumber );
-                    if (!ret)
-                    {
-                        ret = usb_set_altinterface( husb,
-                                request->Interface.AlternateSetting );
-                        if (!usb_release_interface( husb,
-                                request->Interface.InterfaceNumber ) && !ret)
-                            status = STATUS_SUCCESS;
-                    }
-                    usb_close( husb );
-                }
-            }
-            break;
-        case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
-            {
-                struct _URB_BULK_OR_INTERRUPT_TRANSFER *request =
-                        &urb->u.UrbBulkOrInterruptTransfer;
-                char *buf = request->TransferBuffer;
-                usb_dev_handle *husb;
-
-                TRACE( "URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER\n" );
-
-                if (buf == NULL && request->TransferBufferMDL != NULL)
-                    buf = request->TransferBufferMDL->MappedSystemVa;
-                husb = usb_open( inst->dev );
-                if (husb)
-                {
-                    int ret;
-
-                    ret = usb_claim_interface( husb,
-                            ((int)request->PipeHandle >> 8) - 1 );
-                    if (!ret)
-                    {
-                        /* FIXME: add support for an interrupt transfer */
-                        if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
-                            ret = usb_bulk_read( husb, (int)request->PipeHandle & 0xff,
-                                    buf, request->TransferBufferLength, 0 );
-                        else
-                            ret = usb_bulk_write( husb, (int)request->PipeHandle & 0xff,
-                                    buf, request->TransferBufferLength, 0 );
-                        if (!usb_release_interface( husb,
-                                ((int)request->PipeHandle >> 8) - 1 ) && ret >= 0)
-                        {
-                            request->TransferBufferLength = ret;
-                            status = STATUS_SUCCESS;
-                        }
-                    }
-                    usb_close( husb );
-                }
-            }
-            break;
-        case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
-            {
-                struct _URB_CONTROL_DESCRIPTOR_REQUEST *request =
-                        &urb->u.UrbControlDescriptorRequest;
-                ULONG size = request->TransferBufferLength;
-                unsigned char *buf = request->TransferBuffer;
-
-                TRACE( "URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n" );
-
-                if (!size)
-                {
-                    status = STATUS_SUCCESS;
-                    break;
-                }
-                if (buf == NULL && request->TransferBufferMDL != NULL)
-                    buf = request->TransferBufferMDL->MappedSystemVa;
-                if (buf == NULL)
-                {
-                    status = STATUS_INVALID_PARAMETER;
-                    break;
-                }
-
-                switch (request->DescriptorType)
-                {
-                case USB_DEVICE_DESCRIPTOR_TYPE:
-                    TRACE( "USB_DEVICE_DESCRIPTOR_TYPE\n" );
-                    memcpy( buf, &inst->dev->descriptor,
-                            (size < sizeof(USB_DEVICE_DESCRIPTOR)) ?
-                            size : sizeof(USB_DEVICE_DESCRIPTOR) );
-                    status = STATUS_SUCCESS;
-                    break;
-                case USB_CONFIGURATION_DESCRIPTOR_TYPE:
-                    TRACE( "USB_CONFIGURATION_DESCRIPTOR_TYPE\n" );
-                    {
-                        unsigned int i, k;
-                        struct usb_config_descriptor *conf = &inst->dev->config[0];
-                        struct usb_interface_descriptor *intf;
-                        struct usb_endpoint_descriptor *endp;
-
-                        /* FIXME: case of num_altsetting > 1 */
-
-                        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;
-                case USB_STRING_DESCRIPTOR_TYPE:
-                    TRACE( "USB_STRING_DESCRIPTOR_TYPE\n" );
-                    {
-                        usb_dev_handle *husb;
-                        int ret;
-
-                        husb = usb_open( inst->dev );
-                        if (husb)
-                        {
-                            ret = usb_get_string( husb, request->Index,
-                                    request->LanguageId, (void *)buf, size );
-                            if (ret < 0)
-                                ERR( "%s\n", usb_strerror() );
-                            else
-                                status = STATUS_SUCCESS;
-                            usb_close( husb );
-                        }
-                    }
-                }
-            }
-            break;
-        case URB_FUNCTION_GET_STATUS_FROM_DEVICE:
-            {
-                struct _URB_CONTROL_GET_STATUS_REQUEST *request =
-                        &urb->u.UrbControlGetStatusRequest;
-                void *buf = request->TransferBuffer;
-                usb_dev_handle *husb;
-                int ret;
-
-                TRACE( "URB_FUNCTION_GET_STATUS_FROM_DEVICE\n" );
-
-                if (buf == NULL && request->TransferBufferMDL != NULL)
-                    buf = request->TransferBufferMDL->MappedSystemVa;
-                if (buf == NULL || request->TransferBufferLength < sizeof(USHORT))
-                {
-                    status = STATUS_INVALID_PARAMETER;
-                    break;
-                }
-                husb = usb_open( inst->dev );
-                if (husb)
-                {
-                    ret = usb_control_msg( husb, 1 << 7, USB_REQ_GET_STATUS, 0,
-                            request->Index, buf, sizeof(USHORT), 0 );
-                    if (ret < 0)
-                        ERR( "%s\n", usb_strerror() );
-                    else
-                        status = STATUS_SUCCESS;
-                    usb_close( husb );
-                }
-            }
-            break;
-        case URB_FUNCTION_VENDOR_DEVICE:
-        case URB_FUNCTION_VENDOR_INTERFACE:
-        case URB_FUNCTION_VENDOR_ENDPOINT:
-        case URB_FUNCTION_CLASS_DEVICE:
-        case URB_FUNCTION_CLASS_INTERFACE:
-        case URB_FUNCTION_CLASS_ENDPOINT:
-            {
-                usb_dev_handle *husb;
-                struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *request =
-                        &urb->u.UrbControlVendorClassRequest;
-                unsigned char *req_buf = request->TransferBuffer;
-                ULONG size = request->TransferBufferLength;
-
-                TRACE( "URB_FUNCTION_{VENDOR,CLASS}_*\n" );
-
-                if (req_buf == NULL && request->TransferBufferMDL != NULL)
-                    req_buf = request->TransferBufferMDL->MappedSystemVa;
-                if (size && req_buf == NULL)
-                {
-                    status = STATUS_INVALID_PARAMETER;
-                    break;
-                }
-                husb = usb_open( inst->dev );
-                if (husb)
-                {
-                    UCHAR req_type = request->RequestTypeReservedBits;
-                    char *buf;
-                    int ret;
-
-                    switch (urb->u.UrbHeader.Function)
-                    {
-                    case URB_FUNCTION_VENDOR_DEVICE:    req_type |= 0x40; break;
-                    case URB_FUNCTION_VENDOR_INTERFACE: req_type |= 0x41; break;
-                    case URB_FUNCTION_VENDOR_ENDPOINT:  req_type |= 0x42; break;
-                    case URB_FUNCTION_CLASS_DEVICE:     req_type |= 0x20; break;
-                    case URB_FUNCTION_CLASS_INTERFACE:  req_type |= 0x21; break;
-                    case URB_FUNCTION_CLASS_ENDPOINT:   req_type |= 0x22; break;
-                    }
-                    buf = HeapAlloc( GetProcessHeap(), 0, size );
-                    if (buf != NULL)
-                    {
-                        memcpy( buf, req_buf, size );
-                        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, size, 0 );
-                        if (ret < 0)
-                            ERR( "%s\n", usb_strerror() );
-                        else
-                        {
-                            if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
-                            {
-                                request->TransferBufferLength =
-                                        (ret < size) ? ret : size;
-                                memcpy( req_buf, 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;
-        break;
-    default:
-        FIXME( "IOCTL %08x is not implemented\n",
-                irpsp->Parameters.DeviceIoControl.IoControlCode );
-    }
-
-done:
-    irp->IoStatus.u.Status = status;
-    irp->IoStatus.Information = 0;
-    IoCompleteRequest( irp, IO_NO_INCREMENT );
-
-    return status;
-}
-
-#endif
-
-static NTSTATUS WINAPI usbhub_dispatch_pnp( DEVICE_OBJECT *device, IRP *irp )
-{
-    static const WCHAR device_idW[] = {'U','S','B','\\',
-                                       'V','i','d','_','%','0','4','x','&',
-                                       'P','i','d','_','%','0','4','x',0};
-    static const WCHAR root_hub_idW[] = {'U','S','B','\\',
-                                         'R','O','O','T','_','H','U','B',0};
-
-    struct PdoExtension *dx;
-    IO_STACK_LOCATION *irpsp;
-    NTSTATUS status;
-    ULONG_PTR info = 0;
-
-    TRACE( "%p, %p\n", device, irp );
-
-    dx = device->DeviceExtension;
-    irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
-    switch (irpsp->MinorFunction)
-    {
-    case IRP_MN_QUERY_DEVICE_RELATIONS:
-        /* dx->instance->service is NULL for root hubs */
-        if (dx->instance->service)
-        {
-            status = irp->IoStatus.u.Status;
-            info = irp->IoStatus.Information;
-        }
-        else
-        {
-            FIXME( "IRP_MN_QUERY_DEVICE_RELATIONS is not implemented for root hubs\n" );
-            status = STATUS_NOT_IMPLEMENTED;
-        }
-        break;
-    case IRP_MN_QUERY_ID:
-        switch (irpsp->Parameters.QueryId.IdType)
-        {
-        case BusQueryDeviceID:
-        {
-            WCHAR *device_id = ExAllocatePool( PagedPool, dx->instance->service ?
-                    sizeof(device_idW) : sizeof(root_hub_idW) );
-
-            if (device_id == NULL)
-            {
-                status = STATUS_INSUFFICIENT_RESOURCES;
-                break;
-            }
-            if (dx->instance->service)
-                snprintfW( device_id, strlenW(device_idW) + 1, device_idW,
-                        dx->instance->vid, dx->instance->pid );
-            else
-                strcpyW( device_id, root_hub_idW );
-            status = STATUS_SUCCESS;
-            info = (ULONG_PTR)device_id;
-            break;
-        }
-        case BusQueryInstanceID:
-        {
-            char *instance_id;
-            ULONG len;
-            ULONG size;
-            WCHAR *instance_idW;
-
-            instance_id = strrchr( dx->instance->instance_id, '&' );
-            instance_id = instance_id ? (instance_id + 1) : dx->instance->instance_id;
-            len = strlen(instance_id) + 1;
-            size = len * sizeof(WCHAR);
-            instance_idW = ExAllocatePool( PagedPool, size );
-            if (instance_idW == NULL)
-            {
-                status = STATUS_INSUFFICIENT_RESOURCES;
-                break;
-            }
-            RtlMultiByteToUnicodeN( instance_idW, size, NULL, instance_id, len );
-            status = STATUS_SUCCESS;
-            info = (ULONG_PTR)instance_idW;
-            break;
-        }
-        default:
-            FIXME( "IRP_MN_QUERY_ID: IdType %u is not implemented\n",
-                    irpsp->Parameters.QueryId.IdType );
-            status = STATUS_NOT_IMPLEMENTED;
-        }
-        break;
-    default:
-        status = STATUS_SUCCESS;
-    }
-
-    irp->IoStatus.u.Status = status;
-    irp->IoStatus.Information = info;
-    IoCompleteRequest( irp, IO_NO_INCREMENT );
-
-    return STATUS_SUCCESS;
-}
-
-static BOOL start_service( const WCHAR *name )
-{
-    SC_HANDLE scm, service;
-    BOOL ret;
-
-    scm = OpenSCManagerA( NULL, NULL, SC_MANAGER_ALL_ACCESS );
-    if (scm == NULL)
-        return FALSE;
-
-    service = OpenServiceW( scm, name, SERVICE_ALL_ACCESS );
-    if (service == NULL)
-    {
-        CloseServiceHandle( scm );
-        return FALSE;
-    }
-
-    do {
-        ret = StartServiceW( service, 0, NULL );
-        if (!ret)
-        {
-            if (ERROR_SERVICE_ALREADY_RUNNING == GetLastError())
-                ret = TRUE;
-            else if (ERROR_SERVICE_DATABASE_LOCKED == GetLastError())
-                Sleep( 100 );
-            else
-                break;
-        }
-    } while (!ret);
-
-    CloseServiceHandle( service );
-    CloseServiceHandle( scm );
-
-    return ret;
-}
-
-static BOOL create_pdo_name( UNICODE_STRING *pdo_name )
-{
-    static const WCHAR usbpdoW[] = {'\\','D','e','v','i','c','e','\\',
-                                     'U','S','B','P','D','O','-','%','u',0};
-
-    static unsigned int last_pdo_num;
-    WCHAR *buf = RtlAllocateHeap( GetProcessHeap(), 0, 30 * sizeof(WCHAR) );
-
-    if (buf == NULL) return FALSE;
-    snprintfW( buf, 30, usbpdoW, last_pdo_num++ );
-    RtlInitUnicodeString( pdo_name, buf );
-    return TRUE;
-}
-
-static DEVICE_OBJECT *create_pdo( struct DeviceInstance *inst, DRIVER_OBJECT *hubdrv )
-{
-    UNICODE_STRING pdo_name;
-    DEVICE_OBJECT *usbdev = NULL;
-
-    if (!create_pdo_name( &pdo_name )) return NULL;
-    if (IoCreateDevice( hubdrv, sizeof(struct PdoExtension), &pdo_name,
-        0, 0, FALSE, &usbdev ) == STATUS_SUCCESS)
-    {
-        ((struct PdoExtension *)usbdev->DeviceExtension)->instance = inst;
-        usbdev->Flags |= DO_BUS_ENUMERATED_DEVICE | DO_POWER_PAGABLE;
-        usbdev->Flags &= ~DO_DEVICE_INITIALIZING;
-    }
-    RtlFreeUnicodeString( &pdo_name );
-    return usbdev;
-}
-
-static void register_root_hub_device( DEVICE_OBJECT *dev, unsigned int instance_id )
-{
-    static const WCHAR root_hub_idW[] = {'U','S','B',
-                                         '\\','R','O','O','T','_','H','U','B',
-                                         '\\','%','u',0};
-
-    HDEVINFO set;
-    SP_DEVINFO_DATA devInfo;
-    WCHAR *devnameW;
-    ULONG size;
-    BOOL ret;
-    UNICODE_STRING link;
-    NTSTATUS status;
-
-    size = sizeof(root_hub_idW) + 16 * sizeof(WCHAR);
-    devnameW = HeapAlloc( GetProcessHeap(), 0, size );
-    if (devnameW == NULL) return;
-    snprintfW( devnameW, size / sizeof(WCHAR), root_hub_idW, instance_id );
-
-    set = SetupDiGetClassDevsW( NULL, usbW, 0, DIGCF_ALLCLASSES );
-    if (set == INVALID_HANDLE_VALUE) goto done;
-    devInfo.cbSize = sizeof(SP_DEVINFO_DATA);
-    ret = SetupDiCreateDeviceInfoW( set, devnameW, &GUID_DEVCLASS_USB,
-            NULL, NULL, 0, &devInfo );
-    if (ret)
-    {
-        ret = SetupDiRegisterDeviceInfo( set, &devInfo, 0, NULL, NULL, NULL );
-        if (!ret) goto done;
-    }
-    else if (ERROR_DEVINST_ALREADY_EXISTS != GetLastError()) goto done;
-
-    status = IoRegisterDeviceInterface( dev, &GUID_DEVINTERFACE_USB_HUB,
-            NULL, &link );
-    if (status == STATUS_SUCCESS)
-    {
-        IoSetDeviceInterfaceState( &link, TRUE );
-        RtlFreeUnicodeString( &link );
-    }
-done:
-    if (set != INVALID_HANDLE_VALUE)
-        SetupDiDestroyDeviceInfoList( set );
-    HeapFree( GetProcessHeap(), 0, devnameW );
-}
-
-static void create_root_hub_device( USHORT vid, USHORT pid, void *dev,
-        DRIVER_OBJECT *hubdrv )
-{
-    static unsigned int instance_id;
-    struct DeviceInstance *instance = NULL;
-    DEVICE_OBJECT *hubdev;
-    UNICODE_STRING pdo_name = {0, 0, NULL};
-
-    instance = HeapAlloc( GetProcessHeap(), 0, sizeof(*instance) );
-    if (instance == NULL) return;
-    instance->instance_id = HeapAlloc( GetProcessHeap(), 0, 16 );
-    if (instance->instance_id == NULL) goto fail;
-    instance->vid = vid;
-    instance->pid = pid;
-    snprintf( instance->instance_id, 16, "%u", instance_id );
-    instance->service = NULL;
-    instance->dev = dev;
-
-    if (!create_pdo_name( &pdo_name )) goto fail;
-    if (IoCreateDevice( hubdrv, sizeof(struct PdoExtension), &pdo_name,
-        0, 0, FALSE, &hubdev ) != STATUS_SUCCESS) goto fail;
-
-    list_add_tail( &Devices, &instance->entry );
-    ((struct PdoExtension *)hubdev->DeviceExtension)->instance = instance;
-    hubdev->Flags |= DO_POWER_PAGABLE;
-    hubdev->Flags &= ~DO_DEVICE_INITIALIZING;
-    register_root_hub_device( hubdev, instance_id );
-    ++instance_id;
-    return;
-fail:
-    if (instance->instance_id)
-        HeapFree( GetProcessHeap(), 0, instance->instance_id );
-    HeapFree( GetProcessHeap(), 0, instance );
-    RtlFreeUnicodeString( &pdo_name );
-    return;
-}
-
-static BOOL enum_reg_usb_devices(void)
-{
-    SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
-    char *instance_id = NULL;
-    struct DeviceInstance *instance, *instance2;
-    HDEVINFO set;
-    DWORD size, i = 0;
-    USHORT vid, pid;
-    char *str, *buf;
-    BOOL ret;
-
-    set = SetupDiGetClassDevsW( NULL, usbW, 0, DIGCF_ALLCLASSES );
-    if (set == INVALID_HANDLE_VALUE) return FALSE;
-
-    while (SetupDiEnumDeviceInfo( set, i++, &devInfo ))
-    {
-        /* get VID, PID and instance ID */
-        buf = HeapAlloc( GetProcessHeap(), 0, MAX_DEVICE_ID_LEN );
-        if (buf == NULL) goto fail;
-        ret = SetupDiGetDeviceInstanceIdA( set, &devInfo, buf,
-                MAX_DEVICE_ID_LEN, NULL );
-        if (!ret) goto fail;
-        str = strstr( buf, "VID_" );
-        if (str != NULL)
-        {
-            str += 4;
-            vid = strtol( str, NULL, 16 );
-            str = strstr( str, "PID_" );
-        }
-        if (str == NULL)
-        {
-            HeapFree( GetProcessHeap(), 0, buf );
-            continue;
-        }
-        str += 4;
-        pid = strtol( str, NULL, 16 );
-        str = strrchr( str, '\\' );
-        if (str != NULL) ++str;
-        if (str == NULL || *str == 0)
-        {
-            ERR( "bad instance ID\n" );
-            HeapFree( GetProcessHeap(), 0, buf );
-            continue;
-        }
-        instance_id = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
-        if (instance_id == NULL) goto fail;
-        strcpy( instance_id, str );
-        HeapFree( GetProcessHeap(), 0, buf );
-
-        /* get service name */
-        SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE,
-                NULL, NULL, 0, &size );
-        buf = HeapAlloc( GetProcessHeap(), 0, size );
-        if (buf == NULL) goto fail;
-        ret = SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE,
-                NULL, (BYTE *)buf, size, NULL );
-        if (!ret)
-        {
-            HeapFree( GetProcessHeap(), 0, buf );
-            buf = NULL;
-        }
-
-        /* add DeviceInstance structure to Devices list */
-        instance = HeapAlloc( GetProcessHeap(), 0, sizeof(*instance) );
-        if (instance == NULL) goto fail;
-        instance->vid = vid;
-        instance->pid = pid;
-        instance->instance_id = instance_id;
-        instance->service = (WCHAR *)buf;
-        instance->dev = NULL;
-        list_add_tail( &Devices, &instance->entry );
-        instance_id = NULL;
-    }
-
-    SetupDiDestroyDeviceInfoList( set );
-    return TRUE;
-fail:
-    if (buf) HeapFree( GetProcessHeap(), 0, buf );
-    if (instance_id) HeapFree( GetProcessHeap(), 0, instance_id );
-    SetupDiDestroyDeviceInfoList( set );
-    LIST_FOR_EACH_ENTRY_SAFE( instance, instance2, &Devices,
-            struct DeviceInstance, entry )
-    {
-        HeapFree( GetProcessHeap(), 0, instance->instance_id );
-        HeapFree( GetProcessHeap(), 0, instance->service );
-        list_remove( &instance->entry );
-        HeapFree( GetProcessHeap(), 0, instance );
-    }
-    return FALSE;
-}
-
-static char *new_instance_id( USHORT vid, USHORT pid )
-{
-    struct DeviceInstance *instance;
-    char *p, *prefix = NULL;
-    unsigned int id = 0, n, prefix_len = 0;
-    char *ret;
-
-    LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
-    {
-        if (vid == instance->vid && pid == instance->pid)
-        {
-            if (prefix == NULL)
-            {
-                prefix = instance->instance_id;
-                p = strrchr( instance->instance_id, '&' );
-                if (p == NULL) prefix_len = 0;
-                else prefix_len = p + 1 - prefix;
-                id = strtoul( prefix + prefix_len, NULL, 10 ) + 1;
-            }
-            else
-            {
-                p = strrchr( instance->instance_id, '&' );
-                if (prefix_len)
-                {
-                    if (p == NULL || p + 1 - instance->instance_id != prefix_len ||
-                        strncmp( instance->instance_id, prefix, prefix_len ))
-                        continue;
-                }
-                else if (p != NULL) continue;
-                n = strtoul( instance->instance_id + prefix_len, NULL, 10 ) + 1;
-                if (n > id) id = n;
-            }
-        }
-    }
-    ret = HeapAlloc( GetProcessHeap(), 0, prefix_len + 16 );
-    if (ret == NULL) return NULL;
-    memcpy( ret, prefix, prefix_len );
-    snprintf( ret + prefix_len, prefix_len + 16, "%d", id );
-    return ret;
-}
-
-#ifdef HAVE_LIBUSB_H
-
-static BOOL is_mass_storage( libusb_device *dev )
-{
-    struct libusb_config_descriptor *conf;
-    int i, k;
-    BOOL ret = FALSE;
-
-    if (libusb_get_active_config_descriptor( dev, &conf ))
-        return FALSE;
-    for (i = 0; !ret && i < conf->bNumInterfaces; ++i)
-        for (k = 0; !ret && k < conf->interface[i].num_altsetting; ++k)
-            if (conf->interface[i].altsetting[k].bInterfaceClass == 8)
-                ret = TRUE;
-    libusb_free_config_descriptor( conf );
-    return ret;
-}
-
-#else
-
-static BOOL is_mass_storage( struct usb_device *dev )
-{
-    struct usb_config_descriptor *conf = &dev->config[0];
-    int i, k;
-    BOOL ret = FALSE;
-
-    for (i = 0; !ret && i < conf->bNumInterfaces; ++i)
-        for (k = 0; !ret && k < conf->interface[i].num_altsetting; ++k)
-            if (conf->interface[i].altsetting[k].bInterfaceClass == 8)
-                ret = TRUE;
-    return ret;
-}
-
-#endif
-
-static void register_usb_device( USHORT vid, USHORT pid, void *dev )
-{
-    static const WCHAR id_fmtW[] = {'U','S','B',
-                                    '\\','V','i','d','_','%','0','4','x',
-                                    '&','P','i','d','_','%','0','4','x',
-                                    '\\','%','s',0};
-    static const WCHAR driverW[] = {'{','3','6','F','C','9','E','6','0','-',
-                                    'C','4','6','5','-','1','1','C','F','-',
-                                    '8','0','5','6','-','4','4','4','5',
-                                    '5','3','5','4','0','0','0','0','}',
-                                    '\\','0','0','0','0',0};
-
-    struct DeviceInstance *instance;
-    HDEVINFO set = INVALID_HANDLE_VALUE;
-    SP_DEVINFO_DATA devInfo;
-    WCHAR *devnameW = NULL, *instance_idW = NULL;
-    char *instance_id;
-    ULONG size;
-
-    instance_id = new_instance_id( vid, pid );
-    if (instance_id == NULL) return;
-
-    instance = HeapAlloc( GetProcessHeap(), 0, sizeof(*instance) );
-    if (instance == NULL)
-    {
-        HeapFree( GetProcessHeap(), 0, instance_id );
-        goto done;
-    }
-    instance->vid = vid;
-    instance->pid = pid;
-    instance->instance_id = instance_id;
-    instance->service = NULL;
-    instance->dev = dev;
-    list_add_tail( &Devices, &instance->entry );
-
-    size = (strlen(instance_id) + 1) * sizeof(WCHAR);
-    instance_idW = HeapAlloc( GetProcessHeap(), 0, size );
-    if (instance_idW == NULL) goto done;
-    RtlMultiByteToUnicodeN( instance_idW, size, NULL,
-            instance_id, strlen(instance_id) + 1 );
-
-    size = sizeof(id_fmtW) + (strlenW(instance_idW) - 2) * sizeof(WCHAR);
-    devnameW = HeapAlloc( GetProcessHeap(), 0, size );
-    if (devnameW == NULL) goto done;
-    snprintfW( devnameW, size / sizeof(WCHAR), id_fmtW, vid, pid, instance_idW );
-
-    set = SetupDiGetClassDevsW( NULL, usbW, 0, DIGCF_ALLCLASSES );
-    if (set == INVALID_HANDLE_VALUE) goto done;
-    devInfo.cbSize = sizeof(SP_DEVINFO_DATA);
-    if (SetupDiCreateDeviceInfoW( set, devnameW, &GUID_DEVCLASS_USB,
-            NULL, NULL, 0, &devInfo ))
-    {
-        SetupDiRegisterDeviceInfo( set, &devInfo, 0, NULL, NULL, NULL );
-        /* This is need for Consultant+ for flash drive */
-        if (is_mass_storage( dev ))
-            SetupDiSetDeviceRegistryPropertyW( set, &devInfo, SPDRP_DRIVER,
-                    (BYTE *)driverW, sizeof(driverW) );
-    }
-done:
-    if (set != INVALID_HANDLE_VALUE)
-        SetupDiDestroyDeviceInfoList( set );
-    if (devnameW) HeapFree( GetProcessHeap(), 0, devnameW );
-    if (instance_idW) HeapFree( GetProcessHeap(), 0, instance_idW );
-}
-
-static void start_root_devices( DRIVER_OBJECT *driver_obj )
-{
-    static const WCHAR rootW[] = {'r','o','o','t',0};
-
-    SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
-    HDEVINFO set;
-    DRIVER_OBJECT *driver;
-    DEVICE_OBJECT *pdo;
-    NTSTATUS status;
-    DWORD size, i = 0;
-    WCHAR *serviceW;
-
-    set = SetupDiGetClassDevsW( NULL, rootW, 0, DIGCF_ALLCLASSES );
-    if (set == INVALID_HANDLE_VALUE) return;
-    while (SetupDiEnumDeviceInfo( set, i++, &devInfo ))
-    {
-        SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE,
-                NULL, NULL, 0, &size );
-        serviceW = HeapAlloc( GetProcessHeap(), 0, size );
-        if (serviceW == NULL) break;
-        if (SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE,
-                NULL, (BYTE *)serviceW, size, NULL ) && start_service( serviceW ))
-        {
-            status = IoCreateDevice( driver_obj, 0, NULL, 0, 0, FALSE, &pdo );
-            if (status == STATUS_SUCCESS)
-            {
-                while (!(driver = __wine_get_driver_object( serviceW )))
-                    Sleep( 100 );
-                status = __wine_add_device( driver, pdo );
-                if (status == STATUS_SUCCESS && pdo->AttachedDevice != NULL)
-                    __wine_start_device( pdo->AttachedDevice );
-            }
-        }
-        HeapFree( GetProcessHeap(), 0, serviceW );
-    }
-    SetupDiDestroyDeviceInfoList( set );
-}
-
-static void start_device_drivers( DRIVER_OBJECT *hubdrv )
-{
-    struct DeviceInstance *instance;
-    DRIVER_OBJECT *driver;
-    DEVICE_OBJECT *pdo;
-    NTSTATUS status;
-
-    LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
-    {
-        if (instance->service == NULL || instance->dev == NULL) continue;
-        if (start_service( instance->service ))
-        {
-            pdo = create_pdo( instance, hubdrv );
-            if (pdo == NULL) continue;
-            while (!(driver = __wine_get_driver_object(
-                    instance->service )))
-                Sleep( 100 );
-            status = __wine_add_device( driver, pdo );
-            if (status == STATUS_SUCCESS && pdo->AttachedDevice != NULL)
-                __wine_start_device( pdo->AttachedDevice );
-        }
-    }
-}
-
-static DWORD CALLBACK enum_usb_devices( void *usbhubdrv )
-{
-    static const WCHAR usbhub_started_eventW[] = {'_','_','w','i','n','e',
-                                                  '_','U','s','b','h','u','b',
-                                                  'S','t','a','r','t','e','d',0};
-
-#ifdef HAVE_LIBUSB_H
-    libusb_device **devs, *dev;
-    struct libusb_device_descriptor desc;
-    unsigned int i = 0;
-#else
-    struct usb_device *dev;
-    struct usb_bus *bus;
-    struct usb_device_descriptor *desc;
-#endif
-    struct DeviceInstance *instance;
-    HANDLE event;
-    BOOL new_device;
-
-    if (!enum_reg_usb_devices())
-    {
-        ERR( "failed to enumerate USB devices\n" );
-        goto end;
-    }
-
-#ifdef HAVE_LIBUSB_H
-    if (libusb_init( NULL ))
-    {
-        ERR( "failed to initialize libusb\n" );
-        goto end;
-    }
-    if (libusb_get_device_list( NULL, &devs ) < 0)
-    {
-        libusb_exit( NULL );
-        goto end;
-    }
-    while ((dev = devs[i++]))
-    {
-        if (libusb_get_device_descriptor( dev, &desc ))
-        {
-            ERR( "failed to get USB device descriptor\n" );
-            continue;
-        }
-        libusb_ref_device( dev );
-        if (libusb_get_device_address( dev ) == 1)
-        {
-            create_root_hub_device( desc.idVendor, desc.idProduct, dev, usbhubdrv );
-            continue;
-        }
-        new_device = TRUE;
-        LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
-        {
-            if (instance->dev == NULL && desc.idVendor == instance->vid &&
-                desc.idProduct == instance->pid)
-            {
-                instance->dev = dev;
-                new_device = FALSE;
-                break;
-            }
-        }
-        if (new_device)
-            register_usb_device( desc.idVendor, desc.idProduct, dev );
-    }
-    libusb_free_device_list( devs, 1 );
-#else
-    usb_init();
-    usb_find_busses();
-    usb_find_devices();
-
-    for (bus = usb_busses; bus; bus = bus->next)
-        for (dev = bus->devices; dev; dev = dev->next)
-        {
-            if (dev->devnum > 1) continue;
-            desc = &bus->devices->descriptor;
-            create_root_hub_device( desc->idVendor, desc->idProduct,
-                    bus->devices, usbhubdrv );
-        }
-    for (bus = usb_busses; bus; bus = bus->next)
-        for (dev = bus->devices; dev; dev = dev->next)
-        {
-            if (dev->devnum <= 1) continue;
-            new_device = TRUE;
-            LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
-            {
-                if (instance->dev == NULL &&
-                    dev->descriptor.idVendor == instance->vid &&
-                    dev->descriptor.idProduct == instance->pid)
-                {
-                    instance->dev = dev;
-                    new_device = FALSE;
-                    break;
-                }
-            }
-            if (new_device)
-                register_usb_device( dev->descriptor.idVendor,
-                        dev->descriptor.idProduct, dev );
-        }
-#endif
-    start_root_devices( usbhubdrv );
-    start_device_drivers( usbhubdrv );
-end:
-    event = CreateEventW( NULL, TRUE, FALSE, usbhub_started_eventW );
-    SetEvent( event );
-    CloseHandle( event );
-    return 0;
-}
-
-#endif
-
-NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
-{
-#ifdef HAVE_LIBUSB
-    HANDLE thread;
-
-    driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = usbhub_ioctl;
-    driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = usbhub_internal_ioctl;
-    driver->MajorFunction[IRP_MJ_PNP] = usbhub_dispatch_pnp;
-
-    thread = CreateThread( NULL, 0, enum_usb_devices, driver, 0, NULL );
-    if (!thread) return STATUS_UNSUCCESSFUL;
-    CloseHandle( thread );
-#else
-    TRACE( "USB support not compiled in\n" );
-#endif
-    return STATUS_SUCCESS;
-}
diff --git a/dlls/usbhub.sys/usbhub.sys.spec b/dlls/usbhub.sys/usbhub.sys.spec
deleted file mode 100644
index 76421d7..0000000
--- a/dlls/usbhub.sys/usbhub.sys.spec
+++ /dev/null
@@ -1 +0,0 @@
-# nothing to export
diff --git a/programs/services/services.c b/programs/services/services.c
index 12b4437..9743c25 100644
--- a/programs/services/services.c
+++ b/programs/services/services.c
@@ -254,7 +254,7 @@ static void scmdatabase_autostart_services(struct scmdatabase *db)
 #ifdef HAVE_LIBUSB
     static const WCHAR usbhub_started_event[] = {'_','_','w','i','n','e',
         '_','U','s','b','h','u','b','S','t','a','r','t','e','d',0};
-    static const WCHAR usbhub[] = {'U','s','b','h','u','b',0};
+    static const WCHAR mountmgr[] = {'M','o','u','n','t','M','g','r',0};
 #endif
     struct service_entry **services_list;
     unsigned int i = 0;
@@ -302,7 +302,7 @@ static void scmdatabase_autostart_services(struct scmdatabase *db)
         argv[0] = service->name;
         argv[1] = NULL;
 #ifdef HAVE_LIBUSB
-        if (!strcmpW(service->name, usbhub))
+        if (!strcmpW(service->name, mountmgr))
             event = CreateEventW(NULL, TRUE, FALSE, usbhub_started_event);
 #endif
         err = service_start(service, 1, argv);
diff --git a/tools/wine.inf.in b/tools/wine.inf.in
index 395c6db..8f94c06 100644
--- a/tools/wine.inf.in
+++ b/tools/wine.inf.in
@@ -127,17 +127,13 @@ AddReg=\
 
 [DefaultInstall.Services]
 AddService=MountMgr,0x800,MountMgrService
-AddService=Parport,0,ParPortService
 AddService=Spooler,0,SpoolerService
-AddService=Usbhub,0,UsbhubService
 AddService=TermService,0,TerminalServices
 AddService=PlugPlay,0,PlugPlayService
 
 [DefaultInstall.NT.Services]
 AddService=MountMgr,0x800,MountMgrService
-AddService=Parport,0,ParPortService
 AddService=Spooler,0,SpoolerService
-AddService=Usbhub,0,UsbhubService
 AddService=TermService,0,TerminalServices
 AddService=PlugPlay,0,PlugPlayService
 
@@ -2608,8 +2604,6 @@ HKLM,%CurrentVersion%\Telephony\Country List\998,"SameAreaRule",,"G"
 11,,notepad.exe
 11,,winetest.exe,-
 12,,mountmgr.sys
-12,,parport.sys
-12,,usbhub.sys
 10,Microsoft.NET\Framework\v1.1.4322,aspnet_regiis.exe
 10,Microsoft.NET\Framework\v1.1.4322,ngen.exe
 10,Microsoft.NET\Framework\v1.1.4322,fusion.dll
@@ -3010,12 +3004,6 @@ ServiceType=1
 StartType=2
 ErrorControl=1
 
-[ParPortService]
-ServiceBinary="%12%\parport.sys"
-ServiceType=1
-StartType=2
-ErrorControl=1
-
 [SpoolerService]
 Description="Loads files to memory for later printing"
 DisplayName="Print Spooler"
@@ -3025,12 +3013,6 @@ StartType=4
 ErrorControl=1
 LoadOrderGroup="SpoolerGroup"
 
-[UsbhubService]
-ServiceBinary="%12%\usbhub.sys"
-ServiceType=1
-StartType=2
-ErrorControl=1
-
 [TerminalServices]
 Description="Remote desktop access"
 DisplayName="Terminal Services"
-- 
1.7.4.1

----------- следующая часть -----------
From aca1800ca905c45c7b5aea9969e2db23d8a29328 Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Wed, 9 Feb 2011 17:44:00 +0300
Subject: [eterhack 02/20] mountmgr.sys: Fix enumerating USB devices with libusb-0.1 (eterbug #4301).

---
 dlls/mountmgr.sys/usbhub.c |   15 +++++++--------
 1 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/dlls/mountmgr.sys/usbhub.c b/dlls/mountmgr.sys/usbhub.c
index 2ec236e..899714f 100644
--- a/dlls/mountmgr.sys/usbhub.c
+++ b/dlls/mountmgr.sys/usbhub.c
@@ -1671,20 +1671,20 @@ static DWORD CALLBACK enum_usb_devices( void *usbhubdrv )
         for (dev = bus->devices; dev; dev = dev->next)
         {
             if (dev->devnum > 1) continue;
-            desc = &bus->devices->descriptor;
-            create_root_hub_device( desc->idVendor, desc->idProduct,
-                    bus->devices, usbhubdrv );
+            desc = &dev->descriptor;
+            create_root_hub_device( desc->idVendor, desc->idProduct, dev,
+                    usbhubdrv );
         }
     for (bus = usb_busses; bus; bus = bus->next)
         for (dev = bus->devices; dev; dev = dev->next)
         {
             if (dev->devnum <= 1) continue;
+            desc = &dev->descriptor;
             new_device = TRUE;
             LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
             {
-                if (instance->dev == NULL &&
-                    dev->descriptor.idVendor == instance->vid &&
-                    dev->descriptor.idProduct == instance->pid)
+                if (instance->dev == NULL && desc->idVendor == instance->vid &&
+                    desc->idProduct == instance->pid)
                 {
                     instance->dev = dev;
                     new_device = FALSE;
@@ -1692,8 +1692,7 @@ static DWORD CALLBACK enum_usb_devices( void *usbhubdrv )
                 }
             }
             if (new_device)
-                register_usb_device( dev->descriptor.idVendor,
-                        dev->descriptor.idProduct, dev );
+                register_usb_device( desc->idVendor, desc->idProduct, dev );
         }
 #endif
     start_root_devices( usbhubdrv );
-- 
1.7.4.1

----------- следующая часть -----------
From 41de9d53fe857c96c3914ed4c31de91049393d24 Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Tue, 8 Feb 2011 17:50:02 +0300
Subject: [eterhack 03/20] mountmgr.sys: Move WINEAUTOMOUNT check to hal.c (eterbug #4301).

---
 dlls/mountmgr.sys/hal.c      |   15 +++++++++++++++
 dlls/mountmgr.sys/mountmgr.c |   16 +++-------------
 2 files changed, 18 insertions(+), 13 deletions(-)

diff --git a/dlls/mountmgr.sys/hal.c b/dlls/mountmgr.sys/hal.c
index e87ee0c..1b31fca 100644
--- a/dlls/mountmgr.sys/hal.c
+++ b/dlls/mountmgr.sys/hal.c
@@ -134,6 +134,18 @@ static GUID *parse_uuid( GUID *guid, const char *str )
     return NULL;
 }
 
+static int automount_disabled(void)
+{
+    static int disabled = -1;
+
+    if (disabled < 0)
+    {
+        char *automount = getenv( "WINEAUTOMOUNT" );
+        disabled = (automount && !strcmp( automount, "no" ));
+    }
+    return disabled;
+}
+
 static int get_num_from_file( const char *path, const char *filename )
 {
     char *fullpath, str[16];
@@ -182,6 +194,9 @@ static void new_device( LibHalContext *ctx, const char *udi )
 
     p_dbus_error_init( &error );
 
+    if (automount_disabled())
+        goto done;
+
     if (!(device = p_libhal_device_get_property_string( ctx, udi, "block.device", &error )))
         goto done;
 
diff --git a/dlls/mountmgr.sys/mountmgr.c b/dlls/mountmgr.sys/mountmgr.c
index 191d969..20e6dde 100644
--- a/dlls/mountmgr.sys/mountmgr.c
+++ b/dlls/mountmgr.sys/mountmgr.c
@@ -19,7 +19,6 @@
  */
 
 #include <stdarg.h>
-#include <stdlib.h>
 #include <unistd.h>
 
 #define NONAMELESSUNION
@@ -431,13 +430,6 @@ static NTSTATUS WINAPI mountmgr_ioctl( DEVICE_OBJECT *device, IRP *irp )
     return status;
 }
 
-static int automount_enabled(void)
-{
-    char *automount = getenv( "WINEAUTOMOUNT" );
-    if (automount && !strcmp( automount, "no" )) return 0;
-    return 1;
-}
-
 /* main entry point for the mount point manager driver */
 NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
 {
@@ -494,10 +486,8 @@ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
     RtlInitUnicodeString( &nameW, usbhubW );
     status = IoCreateDriver( &nameW, usbhub_driver_entry );
 
-    if (automount_enabled())
-    {
-        initialize_hal();
-        initialize_diskarbitration();
-    }
+    initialize_hal();
+    initialize_diskarbitration();
+
     return status;
 }
-- 
1.7.4.1

----------- следующая часть -----------
From d6bf99942de8ef877d9711e664af04c226e5656e Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Wed, 9 Feb 2011 15:32:44 +0300
Subject: [eterhack 04/20] mountmgr.sys: Use create_pdo for creating PDO (eterbug #4301).

---
 dlls/mountmgr.sys/usbhub.c |   19 +++++++------------
 1 files changed, 7 insertions(+), 12 deletions(-)

diff --git a/dlls/mountmgr.sys/usbhub.c b/dlls/mountmgr.sys/usbhub.c
index 899714f..73dac2c 100644
--- a/dlls/mountmgr.sys/usbhub.c
+++ b/dlls/mountmgr.sys/usbhub.c
@@ -1206,7 +1206,8 @@ static BOOL create_pdo_name( UNICODE_STRING *pdo_name )
     return TRUE;
 }
 
-static DEVICE_OBJECT *create_pdo( struct DeviceInstance *inst, DRIVER_OBJECT *hubdrv )
+static DEVICE_OBJECT *create_pdo( struct DeviceInstance *inst,
+        DRIVER_OBJECT *hubdrv, ULONG flags )
 {
     UNICODE_STRING pdo_name;
     DEVICE_OBJECT *usbdev = NULL;
@@ -1216,7 +1217,7 @@ static DEVICE_OBJECT *create_pdo( struct DeviceInstance *inst, DRIVER_OBJECT *hu
         0, 0, FALSE, &usbdev ) == STATUS_SUCCESS)
     {
         ((struct PdoExtension *)usbdev->DeviceExtension)->instance = inst;
-        usbdev->Flags |= DO_BUS_ENUMERATED_DEVICE | DO_POWER_PAGABLE;
+        usbdev->Flags |= flags;
         usbdev->Flags &= ~DO_DEVICE_INITIALIZING;
     }
     RtlFreeUnicodeString( &pdo_name );
@@ -1273,7 +1274,6 @@ static void create_root_hub_device( USHORT vid, USHORT pid, void *dev,
     static unsigned int instance_id;
     struct DeviceInstance *instance = NULL;
     DEVICE_OBJECT *hubdev;
-    UNICODE_STRING pdo_name = {0, 0, NULL};
 
     instance = HeapAlloc( GetProcessHeap(), 0, sizeof(*instance) );
     if (instance == NULL) return;
@@ -1285,14 +1285,9 @@ static void create_root_hub_device( USHORT vid, USHORT pid, void *dev,
     instance->service = NULL;
     instance->dev = dev;
 
-    if (!create_pdo_name( &pdo_name )) goto fail;
-    if (IoCreateDevice( hubdrv, sizeof(struct PdoExtension), &pdo_name,
-        0, 0, FALSE, &hubdev ) != STATUS_SUCCESS) goto fail;
-
+    hubdev = create_pdo( instance, hubdrv, DO_POWER_PAGABLE );
+    if (hubdev == NULL) goto fail;
     list_add_tail( &Devices, &instance->entry );
-    ((struct PdoExtension *)hubdev->DeviceExtension)->instance = instance;
-    hubdev->Flags |= DO_POWER_PAGABLE;
-    hubdev->Flags &= ~DO_DEVICE_INITIALIZING;
     register_root_hub_device( hubdev, instance_id );
     ++instance_id;
     return;
@@ -1300,7 +1295,6 @@ fail:
     if (instance->instance_id)
         HeapFree( GetProcessHeap(), 0, instance->instance_id );
     HeapFree( GetProcessHeap(), 0, instance );
-    RtlFreeUnicodeString( &pdo_name );
     return;
 }
 
@@ -1586,7 +1580,8 @@ static void start_device_drivers( DRIVER_OBJECT *hubdrv )
         if (instance->service == NULL || instance->dev == NULL) continue;
         if (start_service( instance->service ))
         {
-            pdo = create_pdo( instance, hubdrv );
+            pdo = create_pdo( instance, hubdrv,
+                    DO_BUS_ENUMERATED_DEVICE | DO_POWER_PAGABLE );
             if (pdo == NULL) continue;
             while (!(driver = __wine_get_driver_object(
                     instance->service )))
-- 
1.7.4.1

----------- следующая часть -----------
From 0ad76ef6b9fdb30cfc4fb224bf3f5e60ba1bb7e5 Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Tue, 8 Feb 2011 21:21:02 +0300
Subject: [eterhack 05/20] mountmgr.sys: Load drivers for keys plugged in after starting wine (eterbug #4301).

---
 dlls/mountmgr.sys/hal.c      |    6 ++
 dlls/mountmgr.sys/mountmgr.h |    4 +
 dlls/mountmgr.sys/usbhub.c   |  177 ++++++++++++++++++++++++++++++------------
 3 files changed, 138 insertions(+), 49 deletions(-)

diff --git a/dlls/mountmgr.sys/hal.c b/dlls/mountmgr.sys/hal.c
index 1b31fca..a0e8c68 100644
--- a/dlls/mountmgr.sys/hal.c
+++ b/dlls/mountmgr.sys/hal.c
@@ -174,6 +174,7 @@ static int get_num_from_file( const char *path, const char *filename )
 static void new_device( LibHalContext *ctx, const char *udi )
 {
     DBusError error;
+    char *subsys = NULL;
     char *parent = NULL;
     char *mount_point = NULL;
     char *device = NULL;
@@ -194,6 +195,10 @@ static void new_device( LibHalContext *ctx, const char *udi )
 
     p_dbus_error_init( &error );
 
+    if ((subsys = p_libhal_device_get_property_string( ctx, udi, "info.subsystem", NULL )) &&
+        !strcmp( subsys, "usb_device" ))
+        enum_usb_devices();
+
     if (automount_disabled())
         goto done;
 
@@ -258,6 +263,7 @@ static void new_device( LibHalContext *ctx, const char *udi )
     else if (guid_ptr) add_volume( udi, device, mount_point, DEVICE_HARDDISK_VOL, guid_ptr );
 
 done:
+    if (subsys) p_libhal_free_string( subsys );
     if (type) p_libhal_free_string( type );
     if (parent) p_libhal_free_string( parent );
     if (device) p_libhal_free_string( device );
diff --git a/dlls/mountmgr.sys/mountmgr.h b/dlls/mountmgr.sys/mountmgr.h
index ba62543..e0571f4 100644
--- a/dlls/mountmgr.sys/mountmgr.h
+++ b/dlls/mountmgr.sys/mountmgr.h
@@ -76,3 +76,7 @@ extern struct mount_point *add_volume_mount_point( DEVICE_OBJECT *device, UNICOD
                                                    const GUID *guid );
 extern void delete_mount_point( struct mount_point *mount );
 extern void set_mount_point_id( struct mount_point *mount, const void *id, unsigned int id_len );
+
+/* usb functions */
+
+extern void enum_usb_devices(void);
diff --git a/dlls/mountmgr.sys/usbhub.c b/dlls/mountmgr.sys/usbhub.c
index 73dac2c..93d8f94 100644
--- a/dlls/mountmgr.sys/usbhub.c
+++ b/dlls/mountmgr.sys/usbhub.c
@@ -26,6 +26,11 @@
 #include <libusb.h>
 #elif defined(HAVE_USB_H)
 #include <usb.h>
+#undef USB_ENDPOINT_TYPE_MASK
+#undef USB_ENDPOINT_TYPE_CONTROL
+#undef USB_ENDPOINT_TYPE_ISOCHRONOUS
+#undef USB_ENDPOINT_TYPE_BULK
+#undef USB_ENDPOINT_TYPE_INTERRUPT
 #endif
 
 #define NONAMELESSUNION
@@ -48,6 +53,8 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(usbhub);
 
+#ifdef HAVE_LIBUSB
+
 extern NTSTATUS CDECL __wine_add_device( DRIVER_OBJECT *driver, DEVICE_OBJECT *dev );
 extern DRIVER_OBJECT * CDECL __wine_get_driver_object( const WCHAR *service );
 extern NTSTATUS CDECL __wine_start_device( DEVICE_OBJECT *device );
@@ -65,6 +72,7 @@ struct DeviceInstance
     USHORT pid;
     char *instance_id;
     WCHAR *service;
+    DEVICE_OBJECT *pdo;
 #ifdef HAVE_LIBUSB_H
     libusb_device *dev;
 #else
@@ -77,7 +85,18 @@ struct PdoExtension
     struct DeviceInstance *instance;
 };
 
-#ifdef HAVE_LIBUSB
+static DRIVER_OBJECT *usbhub_driver;
+
+static CRITICAL_SECTION usbhub_cs;
+static CRITICAL_SECTION_DEBUG usbhub_cs_debug =
+{
+    0, 0, &usbhub_cs,
+    { &usbhub_cs_debug.ProcessLocksList, &usbhub_cs_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": usbhub_cs") }
+};
+static CRITICAL_SECTION usbhub_cs = { &usbhub_cs_debug, -1, 0, 0, 0, 0 };
+
+static BOOL libusb_initialized;
 
 static void add_data( unsigned char **dst, ULONG *dst_size, const void *src, ULONG src_size )
 {
@@ -104,6 +123,7 @@ static NTSTATUS WINAPI usbhub_ioctl( DEVICE_OBJECT *device, IRP *irp )
 
     TRACE( "%p, %p\n", device, irp );
 
+    EnterCriticalSection( &usbhub_cs );
     inst = ((struct PdoExtension *)device->DeviceExtension)->instance;
     if (inst->service) goto done;
     irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
@@ -352,6 +372,7 @@ static NTSTATUS WINAPI usbhub_ioctl( DEVICE_OBJECT *device, IRP *irp )
     }
 
 done:
+    LeaveCriticalSection( &usbhub_cs );
     irp->IoStatus.u.Status = status;
     irp->IoStatus.Information = info;
     IoCompleteRequest( irp, IO_NO_INCREMENT );
@@ -370,6 +391,7 @@ static NTSTATUS WINAPI usbhub_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
 
     TRACE( "%p, %p\n", device, irp );
 
+    EnterCriticalSection( &usbhub_cs );
     inst = ((struct PdoExtension *)device->DeviceExtension)->instance;
     if (!inst->service) goto done;
     irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
@@ -699,6 +721,7 @@ static NTSTATUS WINAPI usbhub_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
     }
 
 done:
+    LeaveCriticalSection( &usbhub_cs );
     irp->IoStatus.u.Status = status;
     irp->IoStatus.Information = 0;
     IoCompleteRequest( irp, IO_NO_INCREMENT );
@@ -717,6 +740,7 @@ static NTSTATUS WINAPI usbhub_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
 
     TRACE( "%p, %p\n", device, irp );
 
+    EnterCriticalSection( &usbhub_cs );
     inst = ((struct PdoExtension *)device->DeviceExtension)->instance;
     if (!inst->service) goto done;
     irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
@@ -1055,6 +1079,7 @@ static NTSTATUS WINAPI usbhub_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
     }
 
 done:
+    LeaveCriticalSection( &usbhub_cs );
     irp->IoStatus.u.Status = status;
     irp->IoStatus.Information = 0;
     IoCompleteRequest( irp, IO_NO_INCREMENT );
@@ -1079,6 +1104,7 @@ static NTSTATUS WINAPI usbhub_dispatch_pnp( DEVICE_OBJECT *device, IRP *irp )
 
     TRACE( "%p, %p\n", device, irp );
 
+    EnterCriticalSection( &usbhub_cs );
     dx = device->DeviceExtension;
     irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
     switch (irpsp->MinorFunction)
@@ -1150,6 +1176,7 @@ static NTSTATUS WINAPI usbhub_dispatch_pnp( DEVICE_OBJECT *device, IRP *irp )
         status = STATUS_SUCCESS;
     }
 
+    LeaveCriticalSection( &usbhub_cs );
     irp->IoStatus.u.Status = status;
     irp->IoStatus.Information = info;
     IoCompleteRequest( irp, IO_NO_INCREMENT );
@@ -1273,7 +1300,6 @@ static void create_root_hub_device( USHORT vid, USHORT pid, void *dev,
 {
     static unsigned int instance_id;
     struct DeviceInstance *instance = NULL;
-    DEVICE_OBJECT *hubdev;
 
     instance = HeapAlloc( GetProcessHeap(), 0, sizeof(*instance) );
     if (instance == NULL) return;
@@ -1285,10 +1311,10 @@ static void create_root_hub_device( USHORT vid, USHORT pid, void *dev,
     instance->service = NULL;
     instance->dev = dev;
 
-    hubdev = create_pdo( instance, hubdrv, DO_POWER_PAGABLE );
-    if (hubdev == NULL) goto fail;
+    instance->pdo = create_pdo( instance, hubdrv, DO_POWER_PAGABLE );
+    if (instance->pdo == NULL) goto fail;
     list_add_tail( &Devices, &instance->entry );
-    register_root_hub_device( hubdev, instance_id );
+    register_root_hub_device( instance->pdo, instance_id );
     ++instance_id;
     return;
 fail:
@@ -1367,6 +1393,7 @@ static BOOL enum_reg_usb_devices(void)
         instance->pid = pid;
         instance->instance_id = instance_id;
         instance->service = (WCHAR *)buf;
+        instance->pdo = NULL;
         instance->dev = NULL;
         list_add_tail( &Devices, &instance->entry );
         instance_id = NULL;
@@ -1497,6 +1524,7 @@ static void register_usb_device( USHORT vid, USHORT pid, void *dev )
     instance->pid = pid;
     instance->instance_id = instance_id;
     instance->service = NULL;
+    instance->pdo = NULL;
     instance->dev = dev;
     list_add_tail( &Devices, &instance->entry );
 
@@ -1572,74 +1600,70 @@ static void start_device_drivers( DRIVER_OBJECT *hubdrv )
 {
     struct DeviceInstance *instance;
     DRIVER_OBJECT *driver;
-    DEVICE_OBJECT *pdo;
+    DEVICE_OBJECT *dev;
     NTSTATUS status;
 
     LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
     {
-        if (instance->service == NULL || instance->dev == NULL) continue;
+        if (instance->service == NULL || instance->dev == NULL ||
+            instance->pdo != NULL) continue;
         if (start_service( instance->service ))
         {
-            pdo = create_pdo( instance, hubdrv,
+            instance->pdo = create_pdo( instance, hubdrv,
                     DO_BUS_ENUMERATED_DEVICE | DO_POWER_PAGABLE );
-            if (pdo == NULL) continue;
-            while (!(driver = __wine_get_driver_object(
-                    instance->service )))
+            if (instance->pdo == NULL) continue;
+            while (!(driver = __wine_get_driver_object( instance->service )))
                 Sleep( 100 );
-            status = __wine_add_device( driver, pdo );
-            if (status == STATUS_SUCCESS && pdo->AttachedDevice != NULL)
-                __wine_start_device( pdo->AttachedDevice );
+            status = __wine_add_device( driver, instance->pdo );
+            dev = instance->pdo->AttachedDevice;
+            if (status == STATUS_SUCCESS && dev != NULL)
+                __wine_start_device( dev );
         }
     }
 }
 
-static DWORD CALLBACK enum_usb_devices( void *usbhubdrv )
+static BOOL is_new( void *dev )
 {
-    static const WCHAR usbhub_started_eventW[] = {'_','_','w','i','n','e',
-                                                  '_','U','s','b','h','u','b',
-                                                  'S','t','a','r','t','e','d',0};
+    struct DeviceInstance *instance;
+
+    LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
+        if (instance->dev == dev)
+            return FALSE;
+    return TRUE;
+}
 
 #ifdef HAVE_LIBUSB_H
+
+static int initialize_libusb(void)
+{
+    return libusb_init( NULL );
+}
+
+void enum_usb_devices(void)
+{
     libusb_device **devs, *dev;
     struct libusb_device_descriptor desc;
     unsigned int i = 0;
-#else
-    struct usb_device *dev;
-    struct usb_bus *bus;
-    struct usb_device_descriptor *desc;
-#endif
     struct DeviceInstance *instance;
-    HANDLE event;
     BOOL new_device;
 
-    if (!enum_reg_usb_devices())
-    {
-        ERR( "failed to enumerate USB devices\n" );
+    EnterCriticalSection( &usbhub_cs );
+    if (!libusb_initialized || libusb_get_device_list( NULL, &devs ) < 0)
         goto end;
-    }
-
-#ifdef HAVE_LIBUSB_H
-    if (libusb_init( NULL ))
-    {
-        ERR( "failed to initialize libusb\n" );
-        goto end;
-    }
-    if (libusb_get_device_list( NULL, &devs ) < 0)
-    {
-        libusb_exit( NULL );
-        goto end;
-    }
     while ((dev = devs[i++]))
     {
+        if (!is_new( dev ))
+            continue;
         if (libusb_get_device_descriptor( dev, &desc ))
         {
             ERR( "failed to get USB device descriptor\n" );
             continue;
         }
+        TRACE( "add %04x:%04x\n", desc.idVendor, desc.idProduct );
         libusb_ref_device( dev );
         if (libusb_get_device_address( dev ) == 1)
         {
-            create_root_hub_device( desc.idVendor, desc.idProduct, dev, usbhubdrv );
+            create_root_hub_device( desc.idVendor, desc.idProduct, dev, usbhub_driver );
             continue;
         }
         new_device = TRUE;
@@ -1657,24 +1681,47 @@ static DWORD CALLBACK enum_usb_devices( void *usbhubdrv )
             register_usb_device( desc.idVendor, desc.idProduct, dev );
     }
     libusb_free_device_list( devs, 1 );
+    start_device_drivers( usbhub_driver );
+end:
+    LeaveCriticalSection( &usbhub_cs );
+}
+
 #else
+
+static int initialize_libusb(void)
+{
     usb_init();
+    return 0;
+}
+
+void enum_usb_devices(void)
+{
+    struct usb_device *dev;
+    struct usb_bus *bus;
+    struct usb_device_descriptor *desc;
+    struct DeviceInstance *instance;
+    BOOL new_device;
+
+    EnterCriticalSection( &usbhub_cs );
+    if (!libusb_initialized)
+        goto end;
     usb_find_busses();
     usb_find_devices();
-
     for (bus = usb_busses; bus; bus = bus->next)
         for (dev = bus->devices; dev; dev = dev->next)
         {
-            if (dev->devnum > 1) continue;
+            if (dev->devnum > 1 || !is_new( dev )) continue;
             desc = &dev->descriptor;
+            TRACE( "add %04x:%04x\n", desc->idVendor, desc->idProduct );
             create_root_hub_device( desc->idVendor, desc->idProduct, dev,
-                    usbhubdrv );
+                    usbhub_driver );
         }
     for (bus = usb_busses; bus; bus = bus->next)
         for (dev = bus->devices; dev; dev = dev->next)
         {
-            if (dev->devnum <= 1) continue;
+            if (dev->devnum <= 1 || !is_new( dev )) continue;
             desc = &dev->descriptor;
+            TRACE( "add %04x:%04x\n", desc->idVendor, desc->idProduct );
             new_device = TRUE;
             LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
             {
@@ -1689,10 +1736,41 @@ static DWORD CALLBACK enum_usb_devices( void *usbhubdrv )
             if (new_device)
                 register_usb_device( desc->idVendor, desc->idProduct, dev );
         }
-#endif
-    start_root_devices( usbhubdrv );
-    start_device_drivers( usbhubdrv );
+    start_device_drivers( usbhub_driver );
 end:
+    LeaveCriticalSection( &usbhub_cs );
+}
+
+#endif
+
+#else
+
+void enum_usb_devices(void)
+{
+}
+
+#endif
+
+#ifdef HAVE_LIBUSB
+
+static DWORD CALLBACK initialize_usbhub( void *arg )
+{
+    static const WCHAR usbhub_started_eventW[] = {'_','_','w','i','n','e',
+                                                  '_','U','s','b','h','u','b',
+                                                  'S','t','a','r','t','e','d',0};
+
+    HANDLE event;
+
+    start_root_devices( usbhub_driver );
+    EnterCriticalSection( &usbhub_cs );
+    if (!enum_reg_usb_devices())
+        ERR( "failed to enumerate USB devices\n" );
+    else if (initialize_libusb())
+        ERR( "failed to initialize libusb\n" );
+    else
+        libusb_initialized = TRUE;
+    LeaveCriticalSection( &usbhub_cs );
+    enum_usb_devices();
     event = CreateEventW( NULL, TRUE, FALSE, usbhub_started_eventW );
     SetEvent( event );
     CloseHandle( event );
@@ -1706,11 +1784,12 @@ NTSTATUS WINAPI usbhub_driver_entry( DRIVER_OBJECT *driver, UNICODE_STRING *path
 #ifdef HAVE_LIBUSB
     HANDLE thread;
 
+    usbhub_driver = driver;
     driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = usbhub_ioctl;
     driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = usbhub_internal_ioctl;
     driver->MajorFunction[IRP_MJ_PNP] = usbhub_dispatch_pnp;
 
-    thread = CreateThread( NULL, 0, enum_usb_devices, driver, 0, NULL );
+    thread = CreateThread( NULL, 0, initialize_usbhub, NULL, 0, NULL );
     if (!thread) return STATUS_UNSUCCESSFUL;
     CloseHandle( thread );
 #else
-- 
1.7.4.1

----------- следующая часть -----------
From cbdd5731d99b9111616559c9a489542d29a8471e Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Thu, 10 Feb 2011 17:02:42 +0300
Subject: [eterhack 06/20] ntoskrnl.exe: Add stub for IoDetachDevice (eterbug #4301).

---
 dlls/ntoskrnl.exe/ntoskrnl.c        |    9 +++++++++
 dlls/ntoskrnl.exe/ntoskrnl.exe.spec |    2 +-
 include/ddk/wdm.h                   |    1 +
 3 files changed, 11 insertions(+), 1 deletions(-)

diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 60bc6dd..a6e6b5e 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -1161,6 +1161,15 @@ PDEVICE_OBJECT WINAPI IoAttachDeviceToDeviceStack( DEVICE_OBJECT *source,
 
 
 /***********************************************************************
+ *           IoDetachDevice  (NTOSKRNL.EXE.@)
+ */
+void WINAPI IoDetachDevice( DEVICE_OBJECT *device )
+{
+    FIXME( "stub: %p\n", device );
+}
+
+
+/***********************************************************************
  *           IoBuildDeviceIoControlRequest  (NTOSKRNL.EXE.@)
  */
 PIRP WINAPI IoBuildDeviceIoControlRequest( ULONG IoControlCode,
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
index 3e21d5a..dd379fe 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
+++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
@@ -356,7 +356,7 @@
 @ stdcall IoDeleteDevice(ptr)
 @ stdcall IoDeleteDriver(ptr)
 @ stdcall IoDeleteSymbolicLink(ptr)
-@ stub IoDetachDevice
+@ stdcall IoDetachDevice(ptr)
 @ stub IoDeviceHandlerObjectSize
 @ stub IoDeviceHandlerObjectType
 @ stub IoDeviceObjectType
diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h
index 40a331c..27d96f9 100644
--- a/include/ddk/wdm.h
+++ b/include/ddk/wdm.h
@@ -1191,6 +1191,7 @@ NTSTATUS  WINAPI IoCreateSymbolicLink(UNICODE_STRING*,UNICODE_STRING*);
 void      WINAPI IoDeleteDevice(DEVICE_OBJECT*);
 void      WINAPI IoDeleteDriver(DRIVER_OBJECT*);
 NTSTATUS  WINAPI IoDeleteSymbolicLink(UNICODE_STRING*);
+void      WINAPI IoDetachDevice(DEVICE_OBJECT*);
 void      WINAPI IoFreeIrp(IRP*);
 PDEVICE_OBJECT WINAPI IoGetAttachedDeviceReference(PDEVICE_OBJECT);
 PEPROCESS WINAPI IoGetCurrentProcess(void);
-- 
1.7.4.1

----------- следующая часть -----------
From 678b55777f6c23c0e956dde6280407f3d49a5dfc Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Thu, 10 Feb 2011 21:13:06 +0300
Subject: [eterhack 07/20] mountmgr.sys: Fix return value (eterbug #4301).

---
 dlls/mountmgr.sys/usbhub.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/dlls/mountmgr.sys/usbhub.c b/dlls/mountmgr.sys/usbhub.c
index 93d8f94..22cc411 100644
--- a/dlls/mountmgr.sys/usbhub.c
+++ b/dlls/mountmgr.sys/usbhub.c
@@ -1181,7 +1181,7 @@ static NTSTATUS WINAPI usbhub_dispatch_pnp( DEVICE_OBJECT *device, IRP *irp )
     irp->IoStatus.Information = info;
     IoCompleteRequest( irp, IO_NO_INCREMENT );
 
-    return STATUS_SUCCESS;
+    return status;
 }
 
 static BOOL start_service( const WCHAR *name )
-- 
1.7.4.1

----------- следующая часть -----------
From 5fe95791d917ef084585e4dd10a82f1678d0a78d Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Tue, 22 Feb 2011 17:41:53 +0300
Subject: [eterhack 08/20] mountmgr.sys: Add support for removing USB devices (eterbug #4301).

---
 dlls/mountmgr.sys/hal.c      |    3 +-
 dlls/mountmgr.sys/mountmgr.h |    3 +-
 dlls/mountmgr.sys/usbhub.c   |  215 ++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 213 insertions(+), 8 deletions(-)

diff --git a/dlls/mountmgr.sys/hal.c b/dlls/mountmgr.sys/hal.c
index a0e8c68..889d2b7 100644
--- a/dlls/mountmgr.sys/hal.c
+++ b/dlls/mountmgr.sys/hal.c
@@ -197,7 +197,7 @@ static void new_device( LibHalContext *ctx, const char *udi )
 
     if ((subsys = p_libhal_device_get_property_string( ctx, udi, "info.subsystem", NULL )) &&
         !strcmp( subsys, "usb_device" ))
-        enum_usb_devices();
+        add_usb_devices();
 
     if (automount_disabled())
         goto done;
@@ -285,6 +285,7 @@ static void removed_device( LibHalContext *ctx, const char *udi )
 
     TRACE( "removed %s\n", wine_dbgstr_a(udi) );
 
+    remove_usb_devices();
     if (!remove_dos_device( -1, udi ))
     {
         p_dbus_error_init( &error );
diff --git a/dlls/mountmgr.sys/mountmgr.h b/dlls/mountmgr.sys/mountmgr.h
index e0571f4..2e97272 100644
--- a/dlls/mountmgr.sys/mountmgr.h
+++ b/dlls/mountmgr.sys/mountmgr.h
@@ -79,4 +79,5 @@ extern void set_mount_point_id( struct mount_point *mount, const void *id, unsig
 
 /* usb functions */
 
-extern void enum_usb_devices(void);
+extern void add_usb_devices(void);
+extern void remove_usb_devices(void);
diff --git a/dlls/mountmgr.sys/usbhub.c b/dlls/mountmgr.sys/usbhub.c
index 22cc411..8812f79 100644
--- a/dlls/mountmgr.sys/usbhub.c
+++ b/dlls/mountmgr.sys/usbhub.c
@@ -98,6 +98,16 @@ static CRITICAL_SECTION usbhub_cs = { &usbhub_cs_debug, -1, 0, 0, 0, 0 };
 
 static BOOL libusb_initialized;
 
+static BOOL device_exists( DEVICE_OBJECT *device )
+{
+    struct DeviceInstance *instance;
+
+    LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
+        if (instance->pdo == device)
+            return TRUE;
+    return FALSE;
+}
+
 static void add_data( unsigned char **dst, ULONG *dst_size, const void *src, ULONG src_size )
 {
     int copy;
@@ -124,6 +134,7 @@ static NTSTATUS WINAPI usbhub_ioctl( DEVICE_OBJECT *device, IRP *irp )
     TRACE( "%p, %p\n", device, irp );
 
     EnterCriticalSection( &usbhub_cs );
+    if (!device_exists( device )) goto done;
     inst = ((struct PdoExtension *)device->DeviceExtension)->instance;
     if (inst->service) goto done;
     irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
@@ -392,6 +403,7 @@ static NTSTATUS WINAPI usbhub_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
     TRACE( "%p, %p\n", device, irp );
 
     EnterCriticalSection( &usbhub_cs );
+    if (!device_exists( device )) goto done;
     inst = ((struct PdoExtension *)device->DeviceExtension)->instance;
     if (!inst->service) goto done;
     irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
@@ -741,6 +753,7 @@ static NTSTATUS WINAPI usbhub_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
     TRACE( "%p, %p\n", device, irp );
 
     EnterCriticalSection( &usbhub_cs );
+    if (!device_exists( device )) goto done;
     inst = ((struct PdoExtension *)device->DeviceExtension)->instance;
     if (!inst->service) goto done;
     irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
@@ -1099,14 +1112,21 @@ static NTSTATUS WINAPI usbhub_dispatch_pnp( DEVICE_OBJECT *device, IRP *irp )
 
     struct PdoExtension *dx;
     IO_STACK_LOCATION *irpsp;
-    NTSTATUS status;
+    NTSTATUS status = STATUS_UNSUCCESSFUL;
     ULONG_PTR info = 0;
 
     TRACE( "%p, %p\n", device, irp );
 
     EnterCriticalSection( &usbhub_cs );
-    dx = device->DeviceExtension;
     irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
+    if (!device_exists( device ))
+    {
+        if (irpsp->MinorFunction == IRP_MN_SURPRISE_REMOVAL ||
+            irpsp->MinorFunction == IRP_MN_REMOVE_DEVICE)
+            status = STATUS_SUCCESS;
+        goto done;
+    }
+    dx = device->DeviceExtension;
     switch (irpsp->MinorFunction)
     {
     case IRP_MN_QUERY_DEVICE_RELATIONS:
@@ -1176,6 +1196,7 @@ static NTSTATUS WINAPI usbhub_dispatch_pnp( DEVICE_OBJECT *device, IRP *irp )
         status = STATUS_SUCCESS;
     }
 
+done:
     LeaveCriticalSection( &usbhub_cs );
     irp->IoStatus.u.Status = status;
     irp->IoStatus.Information = info;
@@ -1219,6 +1240,28 @@ static BOOL start_service( const WCHAR *name )
     return ret;
 }
 
+static void stop_service( const WCHAR *name )
+{
+    SC_HANDLE scm, service;
+    SERVICE_STATUS ss;
+
+    scm = OpenSCManagerA( NULL, NULL, SC_MANAGER_ALL_ACCESS );
+    if (scm == NULL)
+        return;
+
+    service = OpenServiceW( scm, name, SERVICE_ALL_ACCESS );
+    if (service == NULL)
+    {
+        CloseServiceHandle( scm );
+        return;
+    }
+
+    ControlService( service, SERVICE_CONTROL_STOP, &ss );
+
+    CloseServiceHandle( service );
+    CloseServiceHandle( scm );
+}
+
 static BOOL create_pdo_name( UNICODE_STRING *pdo_name )
 {
     static const WCHAR usbpdoW[] = {'\\','D','e','v','i','c','e','\\',
@@ -1622,6 +1665,72 @@ static void start_device_drivers( DRIVER_OBJECT *hubdrv )
     }
 }
 
+static NTSTATUS call_pnp_func( DEVICE_OBJECT *device, UCHAR minor_func )
+{
+    DRIVER_OBJECT *driver = device->DriverObject;
+    IO_STACK_LOCATION *irpsp;
+    PIRP irp;
+    NTSTATUS status;
+
+    if (driver->MajorFunction[IRP_MJ_PNP] == NULL)
+        return STATUS_NOT_SUPPORTED;
+    irp = IoAllocateIrp( device->StackSize, FALSE );
+    if (irp == NULL) return STATUS_NO_MEMORY;
+
+    irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation - 1;
+    irp->RequestorMode = KernelMode;
+    irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
+    irpsp->MajorFunction = IRP_MJ_PNP;
+    irpsp->MinorFunction = minor_func;
+    irpsp->DeviceObject = device;
+    device->CurrentIrp = irp;
+    status = IoCallDriver( device, irp );
+    IoFreeIrp( irp );
+    return status;
+}
+
+static void stop_device_driver( struct DeviceInstance *instance )
+{
+    if (instance->pdo)
+    {
+        NTSTATUS status;
+        DEVICE_OBJECT *attd = instance->pdo->AttachedDevice;
+        DEVICE_OBJECT *dev = (attd != NULL) ? attd : instance->pdo;
+
+        status = call_pnp_func( dev, IRP_MN_SURPRISE_REMOVAL );
+        if (status != STATUS_SUCCESS)
+            WARN( "handling IRP_MN_SURPRISE_REMOVAL failed: %08x\n", status );
+        status = call_pnp_func( dev, IRP_MN_REMOVE_DEVICE );
+        if (status != STATUS_SUCCESS)
+            WARN( "handling IRP_MN_REMOVE_DEVICE failed: %08x\n", status );
+        IoDeleteDevice( instance->pdo );
+    }
+    if (instance->service)
+    {
+        struct DeviceInstance *it;
+        BOOL stop = TRUE;
+
+        EnterCriticalSection( &usbhub_cs );
+        LIST_FOR_EACH_ENTRY( it, &Devices, struct DeviceInstance, entry )
+            if (it->pdo != NULL && it->service != NULL &&
+                !strcmpiW( it->service, instance->service ))
+            {
+                stop = FALSE;
+                break;
+            }
+        LeaveCriticalSection( &usbhub_cs );
+        if (stop)
+            stop_service( instance->service );
+    }
+    else
+        HeapFree( GetProcessHeap(), 0, instance->instance_id );
+#ifdef HAVE_LIBUSB_H
+    libusb_unref_device( instance->dev );
+#endif
+    list_remove( &instance->entry );
+    HeapFree( GetProcessHeap(), 0, instance );
+}
+
 static BOOL is_new( void *dev )
 {
     struct DeviceInstance *instance;
@@ -1632,6 +1741,24 @@ static BOOL is_new( void *dev )
     return TRUE;
 }
 
+static int add_to_remove_list( struct DeviceInstance *it, struct list *remove )
+{
+    struct DeviceInstance *copy;
+
+    if (it->service)
+    {
+        copy = HeapAlloc( GetProcessHeap(), 0, sizeof(*copy) );
+        if (!copy) return 1;
+        memcpy( copy, it, sizeof(struct DeviceInstance) );
+        copy->pdo = NULL;
+        copy->dev = NULL;
+        list_add_tail( &Devices, &copy->entry);
+    }
+    list_remove( &it->entry );
+    list_add_tail( remove, &it->entry );
+    return 0;
+}
+
 #ifdef HAVE_LIBUSB_H
 
 static int initialize_libusb(void)
@@ -1639,7 +1766,7 @@ static int initialize_libusb(void)
     return libusb_init( NULL );
 }
 
-void enum_usb_devices(void)
+void add_usb_devices(void)
 {
     libusb_device **devs, *dev;
     struct libusb_device_descriptor desc;
@@ -1686,6 +1813,41 @@ end:
     LeaveCriticalSection( &usbhub_cs );
 }
 
+void remove_usb_devices(void)
+{
+    struct list remove_list = LIST_INIT(remove_list);
+    libusb_device **devs, *dev;
+    struct DeviceInstance *it, *next;
+    unsigned int i;
+    BOOL found;
+
+    EnterCriticalSection( &usbhub_cs );
+    if (!libusb_initialized || libusb_get_device_list( NULL, &devs ) < 0)
+        goto end;
+    LIST_FOR_EACH_ENTRY_SAFE( it, next, &Devices, struct DeviceInstance, entry )
+    {
+        if (!it->dev)
+            continue;
+        found = FALSE;
+        i = 0;
+        while ((dev = devs[i++]))
+            if (it->dev == dev)
+            {
+                found = TRUE;
+                break;
+            }
+        if (!found && add_to_remove_list( it, &remove_list ))
+            break;
+    }
+end:
+    LeaveCriticalSection( &usbhub_cs );
+    LIST_FOR_EACH_ENTRY_SAFE( it, next, &remove_list, struct DeviceInstance, entry )
+    {
+        TRACE( "remove %04x:%04x\n", it->vid, it->pid );
+        stop_device_driver( it );
+    }
+}
+
 #else
 
 static int initialize_libusb(void)
@@ -1694,7 +1856,7 @@ static int initialize_libusb(void)
     return 0;
 }
 
-void enum_usb_devices(void)
+void add_usb_devices(void)
 {
     struct usb_device *dev;
     struct usb_bus *bus;
@@ -1741,11 +1903,52 @@ end:
     LeaveCriticalSection( &usbhub_cs );
 }
 
+void remove_usb_devices(void)
+{
+    struct list remove_list = LIST_INIT(remove_list);
+    struct usb_device *dev;
+    struct usb_bus *bus;
+    struct DeviceInstance *it, *next;
+    BOOL found;
+
+    EnterCriticalSection( &usbhub_cs );
+    if (!libusb_initialized)
+        goto end;
+    usb_find_busses();
+    usb_find_devices();
+    LIST_FOR_EACH_ENTRY_SAFE( it, next, &Devices, struct DeviceInstance, entry )
+    {
+        if (!it->dev)
+            continue;
+        found = FALSE;
+        for (bus = usb_busses; bus; bus = bus->next)
+            for (dev = bus->devices; dev; dev = dev->next)
+                if (it->dev == dev)
+                {
+                    found = TRUE;
+                    break;
+                }
+        if (!found && add_to_remove_list( it, &remove_list ))
+            break;
+    }
+end:
+    LeaveCriticalSection( &usbhub_cs );
+    LIST_FOR_EACH_ENTRY_SAFE( it, next, &remove_list, struct DeviceInstance, entry )
+    {
+        TRACE( "remove %04x:%04x\n", it->vid, it->pid );
+        stop_device_driver( it );
+    }
+}
+
 #endif
 
 #else
 
-void enum_usb_devices(void)
+void add_usb_devices(void)
+{
+}
+
+void remove_usb_devices(void)
 {
 }
 
@@ -1770,7 +1973,7 @@ static DWORD CALLBACK initialize_usbhub( void *arg )
     else
         libusb_initialized = TRUE;
     LeaveCriticalSection( &usbhub_cs );
-    enum_usb_devices();
+    add_usb_devices();
     event = CreateEventW( NULL, TRUE, FALSE, usbhub_started_eventW );
     SetEvent( event );
     CloseHandle( event );
-- 
1.7.4.1

----------- следующая часть -----------
From 099bcb1b17c04201098cb91783f364d5acf29d00 Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Mon, 28 Feb 2011 19:47:08 +0300
Subject: [eterhack 09/20] ntoskrnl.exe: Implement IoDetachDevice (eterbug #4301).

---
 dlls/ntoskrnl.exe/ntoskrnl.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index a6e6b5e..c75c21d 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -1165,7 +1165,8 @@ PDEVICE_OBJECT WINAPI IoAttachDeviceToDeviceStack( DEVICE_OBJECT *source,
  */
 void WINAPI IoDetachDevice( DEVICE_OBJECT *device )
 {
-    FIXME( "stub: %p\n", device );
+    TRACE( "%p\n", device );
+    device->AttachedDevice = NULL;
 }
 
 
-- 
1.7.4.1

----------- следующая часть -----------
From 047c829f9b2c2ada1667f8cbc95cb50aeedec221 Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Mon, 28 Feb 2011 19:49:42 +0300
Subject: [eterhack 10/20] ntoskrnl.exe: Attach to the highest device object (eterbug #4301).

---
 dlls/ntoskrnl.exe/ntoskrnl.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index c75c21d..bd8fa35 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -1154,6 +1154,8 @@ PDEVICE_OBJECT WINAPI IoAttachDeviceToDeviceStack( DEVICE_OBJECT *source,
                                                    DEVICE_OBJECT *target )
 {
     TRACE( "%p, %p\n", source, target );
+    while (target->AttachedDevice)
+        target = target->AttachedDevice;
     target->AttachedDevice = source;
     source->StackSize = target->StackSize + 1;
     return target;
-- 
1.7.4.1

----------- следующая часть -----------
From 5195111a8350b7071c0facff11d1d19d19dd65e0 Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Tue, 22 Feb 2011 21:29:10 +0300
Subject: [eterhack 11/20] ntoskrnl.exe: Fix merge error.

---
 dlls/ntoskrnl.exe/ntoskrnl.c |    9 ---------
 1 files changed, 0 insertions(+), 9 deletions(-)

diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index bd8fa35..e58a55d 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -1203,15 +1203,6 @@ PIRP WINAPI IoBuildDeviceIoControlRequest( ULONG IoControlCode,
     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 = IoGetNextIrpStackLocation( irp );
     irpsp->MajorFunction = InternalDeviceIoControl ?
             IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL;
-- 
1.7.4.1

----------- следующая часть -----------
From f612a0b1105a55a07a47c6adbf75b52f392e96d7 Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Mon, 28 Feb 2011 16:09:53 +0300
Subject: [eterhack 12/20] mountmgr.sys: Remove unneeded checks.

---
 dlls/mountmgr.sys/device.c |    2 +-
 dlls/mountmgr.sys/usbhub.c |   11 +++++------
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/dlls/mountmgr.sys/device.c b/dlls/mountmgr.sys/device.c
index 8142c93..550263f 100644
--- a/dlls/mountmgr.sys/device.c
+++ b/dlls/mountmgr.sys/device.c
@@ -819,7 +819,7 @@ static void register_usbstor_device( struct dos_drive *drive, const char *vendor
     RtlInitUnicodeString( &target, diskW );
     IoCreateSymbolicLink( &drive->volume->device->usbstor, &target );
 done:
-    if (detail) RtlFreeHeap( GetProcessHeap(), 0, detail );
+    RtlFreeHeap( GetProcessHeap(), 0, detail );
     SetupDiDestroyDeviceInfoList( set );
     RtlFreeHeap( GetProcessHeap(), 0, devnameW );
 }
diff --git a/dlls/mountmgr.sys/usbhub.c b/dlls/mountmgr.sys/usbhub.c
index 8812f79..90ed1d9 100644
--- a/dlls/mountmgr.sys/usbhub.c
+++ b/dlls/mountmgr.sys/usbhub.c
@@ -1361,8 +1361,7 @@ static void create_root_hub_device( USHORT vid, USHORT pid, void *dev,
     ++instance_id;
     return;
 fail:
-    if (instance->instance_id)
-        HeapFree( GetProcessHeap(), 0, instance->instance_id );
+    HeapFree( GetProcessHeap(), 0, instance->instance_id );
     HeapFree( GetProcessHeap(), 0, instance );
     return;
 }
@@ -1445,8 +1444,8 @@ static BOOL enum_reg_usb_devices(void)
     SetupDiDestroyDeviceInfoList( set );
     return TRUE;
 fail:
-    if (buf) HeapFree( GetProcessHeap(), 0, buf );
-    if (instance_id) HeapFree( GetProcessHeap(), 0, instance_id );
+    HeapFree( GetProcessHeap(), 0, buf );
+    HeapFree( GetProcessHeap(), 0, instance_id );
     SetupDiDestroyDeviceInfoList( set );
     LIST_FOR_EACH_ENTRY_SAFE( instance, instance2, &Devices,
             struct DeviceInstance, entry )
@@ -1597,8 +1596,8 @@ static void register_usb_device( USHORT vid, USHORT pid, void *dev )
 done:
     if (set != INVALID_HANDLE_VALUE)
         SetupDiDestroyDeviceInfoList( set );
-    if (devnameW) HeapFree( GetProcessHeap(), 0, devnameW );
-    if (instance_idW) HeapFree( GetProcessHeap(), 0, instance_idW );
+    HeapFree( GetProcessHeap(), 0, devnameW );
+    HeapFree( GetProcessHeap(), 0, instance_idW );
 }
 
 static void start_root_devices( DRIVER_OBJECT *driver_obj )
-- 
1.7.4.1

----------- следующая часть -----------
From 8a3ceaa1e5f20ea9ecbf0c6cad10caa3cff3c38e Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Mon, 28 Feb 2011 22:10:35 +0300
Subject: [eterhack 13/20] mountmgr.sys: Remove old symlink before creating new one (eterbug #4301).

---
 dlls/mountmgr.sys/device.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/dlls/mountmgr.sys/device.c b/dlls/mountmgr.sys/device.c
index 550263f..f84ff5e 100644
--- a/dlls/mountmgr.sys/device.c
+++ b/dlls/mountmgr.sys/device.c
@@ -815,6 +815,11 @@ static void register_usbstor_device( struct dos_drive *drive, const char *vendor
     if (!linkW) goto done;
     strcpyW( linkW, dos_devicesW );
     strcatW( linkW, detail->DevicePath + 3 );
+    if (drive->volume->device->usbstor.Buffer)
+    {
+        IoDeleteSymbolicLink( &drive->volume->device->usbstor );
+        RtlFreeUnicodeString( &drive->volume->device->usbstor );
+    }
     RtlInitUnicodeString( &drive->volume->device->usbstor, linkW );
     RtlInitUnicodeString( &target, diskW );
     IoCreateSymbolicLink( &drive->volume->device->usbstor, &target );
-- 
1.7.4.1

----------- следующая часть -----------
From 423c04336b3252779eae4ee449659aedd8e5a086 Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Tue, 1 Mar 2011 17:40:53 +0300
Subject: [eterhack 14/20] mountmgr.sys: Device ID does not contain spaces (eterbug #4301).

---
 dlls/mountmgr.sys/device.c |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/dlls/mountmgr.sys/device.c b/dlls/mountmgr.sys/device.c
index f84ff5e..4f4956a 100644
--- a/dlls/mountmgr.sys/device.c
+++ b/dlls/mountmgr.sys/device.c
@@ -720,6 +720,16 @@ NTSTATUS remove_volume( const char *udi )
     return status;
 }
 
+/* replace spaces with '_' */
+static void replace_spcW( WCHAR *str )
+{
+    while (*str)
+    {
+        if (*str == ' ') *str = '_';
+        ++str;
+    }
+}
+
 /* write information about USBSTOR device to registry and create symbolic link */
 static void register_usbstor_device( struct dos_drive *drive, const char *vendor,
                                      const char *product, const char *revision,
@@ -767,6 +777,7 @@ static void register_usbstor_device( struct dos_drive *drive, const char *vendor
     MultiByteToWideChar( CP_ACP, 0, serial, -1, serialW, size );
 
     sprintfW( devnameW, disk_idW, usbstorW, vendorW, productW, revisionW, serialW );
+    replace_spcW( devnameW );
 
     set = SetupDiGetClassDevsW( NULL, usbstorW, 0, DIGCF_ALLCLASSES );
     if (set == INVALID_HANDLE_VALUE)
-- 
1.7.4.1

----------- следующая часть -----------
From 67dfcb66293e5c797739371ce8c30a00c251e03c Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Wed, 2 Mar 2011 19:37:24 +0300
Subject: [eterhack 15/20] Do not duplicate a function for starting service (eterbug #4301).

---
 dlls/mountmgr.sys/usbhub.c          |   41 +++-------------------------------
 dlls/ntoskrnl.exe/ntoskrnl.c        |    4 +-
 dlls/ntoskrnl.exe/ntoskrnl.exe.spec |    1 +
 3 files changed, 7 insertions(+), 39 deletions(-)

diff --git a/dlls/mountmgr.sys/usbhub.c b/dlls/mountmgr.sys/usbhub.c
index 90ed1d9..4328964 100644
--- a/dlls/mountmgr.sys/usbhub.c
+++ b/dlls/mountmgr.sys/usbhub.c
@@ -58,6 +58,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(usbhub);
 extern NTSTATUS CDECL __wine_add_device( DRIVER_OBJECT *driver, DEVICE_OBJECT *dev );
 extern DRIVER_OBJECT * CDECL __wine_get_driver_object( const WCHAR *service );
 extern NTSTATUS CDECL __wine_start_device( DEVICE_OBJECT *device );
+extern BOOL CDECL __wine_start_service( const WCHAR *name );
 
 #define NUMBER_OF_PORTS 8
 
@@ -1205,41 +1206,6 @@ done:
     return status;
 }
 
-static BOOL start_service( const WCHAR *name )
-{
-    SC_HANDLE scm, service;
-    BOOL ret;
-
-    scm = OpenSCManagerA( NULL, NULL, SC_MANAGER_ALL_ACCESS );
-    if (scm == NULL)
-        return FALSE;
-
-    service = OpenServiceW( scm, name, SERVICE_ALL_ACCESS );
-    if (service == NULL)
-    {
-        CloseServiceHandle( scm );
-        return FALSE;
-    }
-
-    do {
-        ret = StartServiceW( service, 0, NULL );
-        if (!ret)
-        {
-            if (ERROR_SERVICE_ALREADY_RUNNING == GetLastError())
-                ret = TRUE;
-            else if (ERROR_SERVICE_DATABASE_LOCKED == GetLastError())
-                Sleep( 100 );
-            else
-                break;
-        }
-    } while (!ret);
-
-    CloseServiceHandle( service );
-    CloseServiceHandle( scm );
-
-    return ret;
-}
-
 static void stop_service( const WCHAR *name )
 {
     SC_HANDLE scm, service;
@@ -1621,7 +1587,8 @@ static void start_root_devices( DRIVER_OBJECT *driver_obj )
         serviceW = HeapAlloc( GetProcessHeap(), 0, size );
         if (serviceW == NULL) break;
         if (SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE,
-                NULL, (BYTE *)serviceW, size, NULL ) && start_service( serviceW ))
+                NULL, (BYTE *)serviceW, size, NULL ) &&
+                __wine_start_service( serviceW ))
         {
             status = IoCreateDevice( driver_obj, 0, NULL, 0, 0, FALSE, &pdo );
             if (status == STATUS_SUCCESS)
@@ -1649,7 +1616,7 @@ static void start_device_drivers( DRIVER_OBJECT *hubdrv )
     {
         if (instance->service == NULL || instance->dev == NULL ||
             instance->pdo != NULL) continue;
-        if (start_service( instance->service ))
+        if (__wine_start_service( instance->service ))
         {
             instance->pdo = create_pdo( instance, hubdrv,
                     DO_BUS_ENUMERATED_DEVICE | DO_POWER_PAGABLE );
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index e58a55d..c775b6d 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -172,7 +172,7 @@ static inline LPCSTR debugstr_us( const UNICODE_STRING *us )
     return debugstr_wn( us->Buffer, us->Length / sizeof(WCHAR) );
 }
 
-static BOOL start_service( WCHAR *name )
+BOOL CDECL __wine_start_service( const WCHAR *name )
 {
     SC_HANDLE scm, service;
     BOOL ret;
@@ -1467,7 +1467,7 @@ void WINAPI IoInvalidateDeviceRelations( PDEVICE_OBJECT DeviceObject,
                     WCHAR *service;
 
                     if (get_service( (WCHAR *)irp->IoStatus.Information, &service )
-                        && start_service( service ))
+                        && __wine_start_service( service ))
                     {
                         DRIVER_OBJECT *driver;
 
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
index dd379fe..a60953a 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
+++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
@@ -1494,3 +1494,4 @@
 @ cdecl __wine_del_driver_object(ptr)
 @ cdecl __wine_get_driver_object(wstr)
 @ cdecl __wine_start_device(ptr)
+@ cdecl __wine_start_service(wstr)
-- 
1.7.4.1

----------- следующая часть -----------
From 3dbc7c7fc3cc96118d236645704572f1c3160d2e Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Wed, 2 Mar 2011 22:11:23 +0300
Subject: [eterhack 16/20] mountmgr.sys: Fix processing PnP requests for ROOT devices (eterbug #4301).

---
 dlls/mountmgr.sys/usbhub.c |   32 +++++++++++++++++++++++++++++++-
 1 files changed, 31 insertions(+), 1 deletions(-)

diff --git a/dlls/mountmgr.sys/usbhub.c b/dlls/mountmgr.sys/usbhub.c
index 4328964..640a145 100644
--- a/dlls/mountmgr.sys/usbhub.c
+++ b/dlls/mountmgr.sys/usbhub.c
@@ -64,8 +64,15 @@ extern BOOL CDECL __wine_start_service( const WCHAR *name );
 
 static const WCHAR usbW[] = {'U','S','B',0};
 
+static struct list RootDevices = LIST_INIT(RootDevices);
 static struct list Devices = LIST_INIT(Devices);
 
+struct RootDevInstance
+{
+    struct list entry;
+    DEVICE_OBJECT *pdo;
+};
+
 struct DeviceInstance
 {
     struct list entry;
@@ -1103,6 +1110,16 @@ done:
 
 #endif
 
+static BOOL is_root_dev( DEVICE_OBJECT *device )
+{
+    struct RootDevInstance *instance;
+
+    LIST_FOR_EACH_ENTRY( instance, &RootDevices, struct RootDevInstance, entry )
+        if (instance->pdo == device)
+            return TRUE;
+    return FALSE;
+}
+
 static NTSTATUS WINAPI usbhub_dispatch_pnp( DEVICE_OBJECT *device, IRP *irp )
 {
     static const WCHAR device_idW[] = {'U','S','B','\\',
@@ -1123,7 +1140,8 @@ static NTSTATUS WINAPI usbhub_dispatch_pnp( DEVICE_OBJECT *device, IRP *irp )
     if (!device_exists( device ))
     {
         if (irpsp->MinorFunction == IRP_MN_SURPRISE_REMOVAL ||
-            irpsp->MinorFunction == IRP_MN_REMOVE_DEVICE)
+            irpsp->MinorFunction == IRP_MN_REMOVE_DEVICE ||
+            is_root_dev( device ))
             status = STATUS_SUCCESS;
         goto done;
     }
@@ -1593,6 +1611,18 @@ static void start_root_devices( DRIVER_OBJECT *driver_obj )
             status = IoCreateDevice( driver_obj, 0, NULL, 0, 0, FALSE, &pdo );
             if (status == STATUS_SUCCESS)
             {
+                struct RootDevInstance *instance;
+
+                instance = HeapAlloc( GetProcessHeap(), 0, sizeof(*instance) );
+                if (instance == NULL)
+                {
+                    HeapFree( GetProcessHeap(), 0, serviceW );
+                    break;
+                }
+                instance->pdo = pdo;
+                EnterCriticalSection( &usbhub_cs );
+                list_add_tail( &RootDevices, &instance->entry );
+                LeaveCriticalSection( &usbhub_cs );
                 while (!(driver = __wine_get_driver_object( serviceW )))
                     Sleep( 100 );
                 status = __wine_add_device( driver, pdo );
-- 
1.7.4.1

----------- следующая часть -----------
From 30277336186f60209ce85a48c5a648d8c0a7a1be Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Thu, 3 Mar 2011 14:48:50 +0300
Subject: [eterhack 17/20] mountmgr.sys: Add comments to conditional inclusion preprocessing directives (eterbug #4301).

---
 dlls/mountmgr.sys/usbhub.c |   14 +++++++-------
 1 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/dlls/mountmgr.sys/usbhub.c b/dlls/mountmgr.sys/usbhub.c
index 640a145..e4d8211 100644
--- a/dlls/mountmgr.sys/usbhub.c
+++ b/dlls/mountmgr.sys/usbhub.c
@@ -749,7 +749,7 @@ done:
     return status;
 }
 
-#else
+#else  /* HAVE_LIBUSB_H */
 
 static NTSTATUS WINAPI usbhub_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
 {
@@ -1108,7 +1108,7 @@ done:
     return status;
 }
 
-#endif
+#endif  /* HAVE_LIBUSB_H */
 
 static BOOL is_root_dev( DEVICE_OBJECT *device )
 {
@@ -1844,7 +1844,7 @@ end:
     }
 }
 
-#else
+#else  /* HAVE_LIBUSB_H */
 
 static int initialize_libusb(void)
 {
@@ -1936,9 +1936,9 @@ end:
     }
 }
 
-#endif
+#endif  /* HAVE_LIBUSB_H */
 
-#else
+#else  /* HAVE_LIBUSB */
 
 void add_usb_devices(void)
 {
@@ -1948,7 +1948,7 @@ void remove_usb_devices(void)
 {
 }
 
-#endif
+#endif  /* HAVE_LIBUSB */
 
 #ifdef HAVE_LIBUSB
 
@@ -1976,7 +1976,7 @@ static DWORD CALLBACK initialize_usbhub( void *arg )
     return 0;
 }
 
-#endif
+#endif  /* HAVE_LIBUSB */
 
 NTSTATUS WINAPI usbhub_driver_entry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
 {
-- 
1.7.4.1

----------- следующая часть -----------
From 2df0a2cd0d7bf9530bc51680cf38b26bf1fa2c1c Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Thu, 3 Mar 2011 15:38:09 +0300
Subject: [eterhack 18/20] ntoskrnl.exe: Initialize critical section statically.

---
 dlls/ntoskrnl.exe/ntoskrnl.c |    9 +++++++--
 1 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index c775b6d..6da50b2 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -68,6 +68,13 @@ typedef void (WINAPI *PCREATE_PROCESS_NOTIFY_ROUTINE)(HANDLE,HANDLE,BOOLEAN);
 typedef void (WINAPI *PCREATE_THREAD_NOTIFY_ROUTINE)(HANDLE,HANDLE,BOOLEAN);
 
 static CRITICAL_SECTION cs;
+static CRITICAL_SECTION_DEBUG cs_debug =
+{
+    0, 0, &cs,
+    { &cs_debug.ProcessLocksList, &cs_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": cs") }
+};
+static CRITICAL_SECTION cs = { &cs_debug, -1, 0, 0, 0, 0 };
 
 static struct list Irps = LIST_INIT(Irps);
 
@@ -3243,10 +3250,8 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
         handler = RtlAddVectoredExceptionHandler( TRUE, vectored_handler );
 #endif
         KeQueryTickCount( &count );  /* initialize the global KeTickCount */
-        InitializeCriticalSection( &cs );
         break;
     case DLL_PROCESS_DETACH:
-        DeleteCriticalSection( &cs );
         RtlRemoveVectoredExceptionHandler( handler );
         LIST_FOR_EACH_ENTRY_SAFE( ext, ext2, &DriverObjExtensions,
                 struct DriverObjExtension, entry )
-- 
1.7.4.1

----------- следующая часть -----------
From de3033a4e5d76a88f9caf26e2bd9cb968203acba Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Thu, 3 Mar 2011 17:12:17 +0300
Subject: [eterhack 19/20] mountmgr.sys: Handling IRP in WINE на Etersoft is different from upstream.

---
 dlls/mountmgr.sys/device.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/dlls/mountmgr.sys/device.c b/dlls/mountmgr.sys/device.c
index 4f4956a..59cc68d 100644
--- a/dlls/mountmgr.sys/device.c
+++ b/dlls/mountmgr.sys/device.c
@@ -1111,9 +1111,9 @@ static NTSTATUS WINAPI harddisk_ioctl( DEVICE_OBJECT *device, IRP *irp )
         DWORD len = min( 32, irpsp->Parameters.DeviceIoControl.OutputBufferLength );
 
         FIXME( "returning zero-filled buffer for ioctl 0x560000\n" );
-        memset( irp->MdlAddress->StartVa, 0, len );
+        memset( irp->AssociatedIrp.SystemBuffer, 0, len );
         irp->IoStatus.Information = len;
-        irp->IoStatus.u.Status = STATUS_SUCCESS;
+        status = STATUS_SUCCESS;
         break;
     }
     default:
-- 
1.7.4.1

----------- следующая часть -----------
From 96109ba364ae9dab647d627fc4dad70d70235533 Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Thu, 3 Mar 2011 21:17:45 +0300
Subject: [eterhack 20/20] Use IoGet*IrpStackLocation.

---
 dlls/mountmgr.sys/parport.c  |    4 ++--
 dlls/mountmgr.sys/usbhub.c   |   10 +++++-----
 dlls/ntoskrnl.exe/ntoskrnl.c |   16 ++++++++--------
 3 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/dlls/mountmgr.sys/parport.c b/dlls/mountmgr.sys/parport.c
index 4f460d0..4193476 100644
--- a/dlls/mountmgr.sys/parport.c
+++ b/dlls/mountmgr.sys/parport.c
@@ -87,7 +87,7 @@ static ULONG WINAPI parport_query_waiters( void *context )
 
 static NTSTATUS WINAPI parport_ioctl( DEVICE_OBJECT *device, IRP *irp )
 {
-    IO_STACK_LOCATION *irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
+    IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
     NTSTATUS status = STATUS_NOT_SUPPORTED;
 
     TRACE( "%p, %p\n", device, irp );
@@ -145,7 +145,7 @@ static NTSTATUS WINAPI parport_pnp( DEVICE_OBJECT *device, IRP *irp )
 {
     static const WCHAR fmtW[] = {'%','d',0};
 
-    IO_STACK_LOCATION *irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
+    IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
     NTSTATUS status;
 
     TRACE( "%p, %p\n", device, irp );
diff --git a/dlls/mountmgr.sys/usbhub.c b/dlls/mountmgr.sys/usbhub.c
index e4d8211..3005771 100644
--- a/dlls/mountmgr.sys/usbhub.c
+++ b/dlls/mountmgr.sys/usbhub.c
@@ -145,7 +145,7 @@ static NTSTATUS WINAPI usbhub_ioctl( DEVICE_OBJECT *device, IRP *irp )
     if (!device_exists( device )) goto done;
     inst = ((struct PdoExtension *)device->DeviceExtension)->instance;
     if (inst->service) goto done;
-    irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
+    irpsp = IoGetCurrentIrpStackLocation( irp );
 
     switch (irpsp->Parameters.DeviceIoControl.IoControlCode)
     {
@@ -414,7 +414,7 @@ static NTSTATUS WINAPI usbhub_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
     if (!device_exists( device )) goto done;
     inst = ((struct PdoExtension *)device->DeviceExtension)->instance;
     if (!inst->service) goto done;
-    irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
+    irpsp = IoGetCurrentIrpStackLocation( irp );
     urb = irpsp->Parameters.Others.Argument1;
 
     switch (irpsp->Parameters.DeviceIoControl.IoControlCode)
@@ -764,7 +764,7 @@ static NTSTATUS WINAPI usbhub_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
     if (!device_exists( device )) goto done;
     inst = ((struct PdoExtension *)device->DeviceExtension)->instance;
     if (!inst->service) goto done;
-    irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
+    irpsp = IoGetCurrentIrpStackLocation( irp );
     urb = irpsp->Parameters.Others.Argument1;
 
     switch (irpsp->Parameters.DeviceIoControl.IoControlCode)
@@ -1136,7 +1136,7 @@ static NTSTATUS WINAPI usbhub_dispatch_pnp( DEVICE_OBJECT *device, IRP *irp )
     TRACE( "%p, %p\n", device, irp );
 
     EnterCriticalSection( &usbhub_cs );
-    irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
+    irpsp = IoGetCurrentIrpStackLocation( irp );
     if (!device_exists( device ))
     {
         if (irpsp->MinorFunction == IRP_MN_SURPRISE_REMOVAL ||
@@ -1673,7 +1673,7 @@ static NTSTATUS call_pnp_func( DEVICE_OBJECT *device, UCHAR minor_func )
     irp = IoAllocateIrp( device->StackSize, FALSE );
     if (irp == NULL) return STATUS_NO_MEMORY;
 
-    irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation - 1;
+    irpsp = IoGetNextIrpStackLocation( irp );
     irp->RequestorMode = KernelMode;
     irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
     irpsp->MajorFunction = IRP_MJ_PNP;
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 6da50b2..690ccbf 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -274,7 +274,7 @@ static NTSTATUS get_device_id( DEVICE_OBJECT *pdo, BUS_QUERY_ID_TYPE id_type,
     *id = NULL;
     irp = IoAllocateIrp( pdo->StackSize, FALSE );
     if (irp == NULL) return STATUS_NO_MEMORY;
-    irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation - 1;
+    irpsp = IoGetNextIrpStackLocation( irp );
     irpsp->MajorFunction = IRP_MJ_PNP;
     irpsp->MinorFunction = IRP_MN_QUERY_ID;
     irpsp->Parameters.QueryId.IdType = id_type;
@@ -563,7 +563,7 @@ static NTSTATUS process_ioctl( DEVICE_OBJECT *device, ULONG code, void *in_buff,
         status = STATUS_NO_MEMORY;
         goto end;
     }
-    irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation - 1;
+    irpsp = IoGetNextIrpStackLocation( irp );
     irp->RequestorMode = UserMode;
     irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
     irp->Tail.Overlay.OriginalFileObject = file;
@@ -598,7 +598,7 @@ static NTSTATUS process_read( DEVICE_OBJECT *device, void *buff, ULONG *size )
     if (irp == NULL)
         return STATUS_NO_MEMORY;
     irp->RequestorMode = UserMode;
-    irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation - 1;
+    irpsp = IoGetNextIrpStackLocation( irp );
     irpsp->DeviceObject = device;
     irpsp->MajorFunction = IRP_MJ_READ;
     irpsp->Parameters.Read.Length = *size;
@@ -639,7 +639,7 @@ static NTSTATUS process_write( DEVICE_OBJECT *device, void *buff, ULONG *size )
     if (irp == NULL)
         return STATUS_NO_MEMORY;
     irp->RequestorMode = UserMode;
-    irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation - 1;
+    irpsp = IoGetNextIrpStackLocation( irp );
     irpsp->DeviceObject = device;
     irpsp->MajorFunction = IRP_MJ_WRITE;
     irpsp->Parameters.Write.Length = *size;
@@ -865,7 +865,7 @@ NTSTATUS CDECL __wine_start_device( DEVICE_OBJECT *device )
     irp = IoAllocateIrp( device->StackSize, FALSE );
     if (irp == NULL) return STATUS_NO_MEMORY;
 
-    irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation - 1;
+    irpsp = IoGetNextIrpStackLocation( irp );
     irp->RequestorMode = KernelMode;
     irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
     irpsp->MajorFunction = IRP_MJ_PNP;
@@ -1449,7 +1449,7 @@ void WINAPI IoInvalidateDeviceRelations( PDEVICE_OBJECT DeviceObject,
 
         irp = IoAllocateIrp( DeviceObject->StackSize, FALSE );
         if (irp == NULL) return;
-        irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation - 1;
+        irpsp = IoGetNextIrpStackLocation( irp );
         irpsp->MajorFunction = IRP_MJ_PNP;
         irpsp->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
         irpsp->Parameters.QueryDeviceRelations.Type = BusRelations;
@@ -1464,7 +1464,7 @@ void WINAPI IoInvalidateDeviceRelations( PDEVICE_OBJECT DeviceObject,
                 IoFreeIrp( irp );
                 irp = IoAllocateIrp( rel->Objects[k]->StackSize, FALSE );
                 if (irp == NULL) return;
-                irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation - 1;
+                irpsp = IoGetNextIrpStackLocation( irp );
                 irpsp->MajorFunction = IRP_MJ_PNP;
                 irpsp->MinorFunction = IRP_MN_QUERY_ID;
                 irpsp->Parameters.QueryId.IdType = BusQueryDeviceID;
@@ -2172,7 +2172,7 @@ VOID WINAPI IoCompleteRequest( IRP *irp, UCHAR priority_boost )
     status = irp->IoStatus.u.Status;
     while (irp->CurrentLocation <= irp->StackCount)
     {
-        irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
+        irpsp = IoGetCurrentIrpStackLocation( irp );
         routine = irpsp->CompletionRoutine;
         call_flag = 0;
         /* FIXME: add SL_INVOKE_ON_CANCEL support */
-- 
1.7.4.1



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