mountmgr.sys: Load drivers for keys plugged in after starting wine (eterbug #4301).
authorAlexander Morozov <amorozov@etersoft.ru>
Tue, 8 Feb 2011 18:21:02 +0000 (21:21 +0300)
committerTest Robot <wine-patches-test@office.etersoft.ru>
Fri, 4 Mar 2011 14:56:57 +0000 (17:56 +0300)
dlls/mountmgr.sys/hal.c
dlls/mountmgr.sys/mountmgr.h
dlls/mountmgr.sys/usbhub.c

index 1b31fcac3589063a0cbdcdca2e12531c467ee81b..a0e8c6818218bd41d42cf82a35e7d206cf43e7b1 100644 (file)
@@ -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 );
index ba62543c27c5a679af5f8165e1ba1ede61c97420..e0571f49205d00eb5269fd9087c553beb440a83d 100644 (file)
@@ -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);
index 73dac2c522bd5bfbd6d062ccaa874735698dda14..93d8f9424ec39a603ce24ddfa055de6ee4e85594 100644 (file)
 #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