[PATCH 3/3] wineboot: Start root PnP devices on startup.

Zebediah Figura zfigura at codeweavers.com
Tue Jun 11 09:47:39 CDT 2019


From: Zebediah Figura <z.figura12 at gmail.com>

Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/ntoskrnl.exe/ntoskrnl.exe.spec |   1 +
 dlls/ntoskrnl.exe/pnp.c             | 111 +++++++++++++++++++++++++---
 programs/wineboot/Makefile.in       |   2 +-
 programs/wineboot/wineboot.c        |  49 ++++++++++++
 programs/winedevice/device.c        |   5 ++
 5 files changed, 158 insertions(+), 10 deletions(-)

diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
index 7c9370579dd..114b764fbe9 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
+++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
@@ -1522,3 +1522,4 @@
 # or 'wine_' (for user-visible functions) to avoid namespace conflicts.
 
 @ cdecl wine_ntoskrnl_main_loop(long)
+@ cdecl wine_enumerate_root_pnp_devices(wstr)
diff --git a/dlls/ntoskrnl.exe/pnp.c b/dlls/ntoskrnl.exe/pnp.c
index fc99928a247..2c907d16314 100644
--- a/dlls/ntoskrnl.exe/pnp.c
+++ b/dlls/ntoskrnl.exe/pnp.c
@@ -376,6 +376,18 @@ static BOOL install_device_driver( DEVICE_OBJECT *device, HDEVINFO set, SP_DEVIN
     return TRUE;
 }
 
+/* Load the function driver for a newly created PDO, if one is present, and
+ * send IRPs to start the device. */
+static void start_device( DEVICE_OBJECT *device, HDEVINFO set, SP_DEVINFO_DATA *sp_device )
+{
+    load_function_driver( device, set, sp_device );
+    if (device->DriverObject)
+    {
+        send_pnp_irp( device, IRP_MN_START_DEVICE );
+        send_power_irp( device, PowerDeviceD0 );
+    }
+}
+
 static void handle_bus_relations( DEVICE_OBJECT *device )
 {
     static const WCHAR infpathW[] = {'I','n','f','P','a','t','h',0};
@@ -421,19 +433,14 @@ static void handle_bus_relations( DEVICE_OBJECT *device )
         return;
     }
 
-    load_function_driver( device, set, &sp_device );
-    if (device->DriverObject)
-    {
-        send_pnp_irp( device, IRP_MN_START_DEVICE );
-        send_power_irp( device, PowerDeviceD0 );
-    }
+    start_device( device, set, &sp_device );
 
     SetupDiDestroyDeviceInfoList( set );
 }
 
-static void handle_removal_relations( DEVICE_OBJECT *device )
+static void remove_device( DEVICE_OBJECT *device )
 {
-    TRACE( "(%p)\n", device );
+    TRACE("Removing device %p.\n", device);
 
     send_power_irp( device, PowerDeviceD3 );
     send_pnp_irp( device, IRP_MN_SURPRISE_REMOVAL );
@@ -453,7 +460,7 @@ void WINAPI IoInvalidateDeviceRelations( DEVICE_OBJECT *device_object, DEVICE_RE
             handle_bus_relations( device_object );
             break;
         case RemovalRelations:
-            handle_removal_relations( device_object );
+            remove_device( device_object );
             break;
         default:
             FIXME("Unhandled relation %#x.\n", type);
@@ -754,6 +761,23 @@ POWER_STATE WINAPI PoSetPowerState( DEVICE_OBJECT *device, POWER_STATE_TYPE type
 
 static DRIVER_OBJECT *pnp_manager;
 
+struct root_pnp_device
+{
+    WCHAR id[MAX_DEVICE_ID_LEN];
+    struct wine_rb_entry entry;
+    DEVICE_OBJECT *device;
+};
+
+static int root_pnp_devices_rb_compare( const void *key, const struct wine_rb_entry *entry )
+{
+    const struct root_pnp_device *device = WINE_RB_ENTRY_VALUE( entry, const struct root_pnp_device, entry );
+    const WCHAR *k = key;
+
+    return strcmpiW( k, device->id );
+}
+
+static struct wine_rb_tree root_pnp_devices = { root_pnp_devices_rb_compare };
+
 static NTSTATUS WINAPI pnp_manager_device_pnp( DEVICE_OBJECT *device, IRP *irp )
 {
     IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp );
@@ -782,7 +806,76 @@ void pnp_manager_start(void)
         ERR("Failed to create PnP manager driver, status %#x.\n", status);
 }
 
+static void destroy_root_pnp_device( struct wine_rb_entry *entry, void *context )
+{
+    struct root_pnp_device *device = WINE_RB_ENTRY_VALUE(entry, struct root_pnp_device, entry);
+    remove_device( device->device );
+}
+
 void pnp_manager_stop(void)
 {
+    wine_rb_destroy( &root_pnp_devices, destroy_root_pnp_device, NULL );
     IoDeleteDriver( pnp_manager );
 }
+
+/***********************************************************************
+ *           wine_enumerate_root_pnp_devices   (Not a Windows API)
+ */
+NTSTATUS CDECL wine_enumerate_root_pnp_devices( const WCHAR *driver_name )
+{
+    static const WCHAR driverW[] = {'\\','D','r','i','v','e','r','\\',0};
+    static const WCHAR rootW[] = {'R','O','O','T',0};
+    WCHAR buffer[MAX_SERVICE_NAME + ARRAY_SIZE(driverW)], id[MAX_DEVICE_ID_LEN];
+    SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
+    struct root_pnp_device *pnp_device;
+    DEVICE_OBJECT *device;
+    NTSTATUS status;
+    unsigned int i;
+    HDEVINFO set;
+
+    TRACE("Searching for new root-enumerated devices for driver %s.\n", debugstr_w(driver_name));
+
+    set = SetupDiGetClassDevsW( NULL, rootW, NULL, DIGCF_ALLCLASSES );
+    if (set == INVALID_HANDLE_VALUE)
+        return GetLastError();
+
+    for (i = 0; SetupDiEnumDeviceInfo( set, i, &sp_device ); ++i)
+    {
+        if (!SetupDiGetDeviceRegistryPropertyW( set, &sp_device, SPDRP_SERVICE,
+                NULL, (BYTE *)buffer, sizeof(buffer), NULL )
+                || lstrcmpiW( buffer, driver_name ))
+        {
+            continue;
+        }
+
+        SetupDiGetDeviceInstanceIdW( set, &sp_device, id, ARRAY_SIZE(id), NULL );
+
+        if (wine_rb_get( &root_pnp_devices, id ))
+            continue;
+
+        TRACE("Adding new root-enumerated device %s.\n", debugstr_w(id));
+
+        if ((status = IoCreateDevice( pnp_manager, sizeof(struct root_pnp_device), NULL,
+                FILE_DEVICE_CONTROLLER, FILE_AUTOGENERATED_DEVICE_NAME, FALSE, &device )))
+        {
+            ERR("Failed to create root-enumerated PnP device %s, status %#x.\n", debugstr_w(id), status);
+            continue;
+        }
+
+        pnp_device = device->DeviceExtension;
+        strcpyW( pnp_device->id, id );
+        pnp_device->device = device;
+        if (wine_rb_put( &root_pnp_devices, id, &pnp_device->entry ))
+        {
+            ERR("Failed to insert device %s into tree.\n", debugstr_w(id));
+            IoDeleteDevice( device );
+            continue;
+        }
+
+        start_device( device, set, &sp_device );
+    }
+
+    SetupDiDestroyDeviceInfoList(set);
+
+    return ERROR_SUCCESS;
+}
diff --git a/programs/wineboot/Makefile.in b/programs/wineboot/Makefile.in
index f6da0f9df65..6224eb887b8 100644
--- a/programs/wineboot/Makefile.in
+++ b/programs/wineboot/Makefile.in
@@ -1,7 +1,7 @@
 MODULE    = wineboot.exe
 APPMODE   = -mconsole
 IMPORTS   = uuid advapi32
-DELAYIMPORTS = shell32 shlwapi version user32
+DELAYIMPORTS = shell32 shlwapi version user32 setupapi
 
 C_SRCS = \
 	shutdown.c \
diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c
index defd12627d6..4dd4f16c277 100644
--- a/programs/wineboot/wineboot.c
+++ b/programs/wineboot/wineboot.c
@@ -82,6 +82,7 @@
 #include <shobjidl.h>
 #include <shlwapi.h>
 #include <shellapi.h>
+#include <setupapi.h>
 #include "resource.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(wineboot);
@@ -1226,6 +1227,52 @@ done:
     return ret;
 }
 
+static void start_root_pnp_services(void)
+{
+    static const WCHAR rootW[] = {'R','O','O','T',0};
+    SP_DEVINFO_DATA device = {sizeof(device)};
+    SC_HANDLE manager, service;
+    SERVICE_STATUS status;
+    WCHAR svc_name[260];
+    unsigned int i;
+    HDEVINFO set;
+
+    if (!(manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT)))
+    {
+        WINE_ERR("Failed to connect to service control manager, error %u.\n", GetLastError());
+        return;
+    }
+
+    if ((set = SetupDiGetClassDevsW(NULL, rootW, NULL, DIGCF_ALLCLASSES)) == INVALID_HANDLE_VALUE)
+    {
+        WINE_ERR("Failed to enumerate devices, error %u.\n", GetLastError());
+        CloseServiceHandle(manager);
+        return;
+    }
+
+    for (i = 0; SetupDiEnumDeviceInfo(set, i, &device); ++i)
+    {
+        if (!SetupDiGetDeviceRegistryPropertyW(set, &device, SPDRP_SERVICE, NULL, (BYTE *)svc_name, sizeof(svc_name), NULL))
+            continue;
+
+        if (!(service = OpenServiceW(manager, svc_name, SERVICE_START|SERVICE_USER_DEFINED_CONTROL)))
+        {
+            WINE_ERR("Failed to open service %s, error %u.\n", debugstr_w(svc_name), GetLastError());
+            continue;
+        }
+
+        if (!StartServiceW(service, 0, NULL) && GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
+            WINE_ERR("Failed to start service %s, error %u.\n", debugstr_w(svc_name), GetLastError());
+        if (!ControlService(service, 128, &status))
+            WINE_ERR("Failed to reenumerate PnP devices for service %s, error %u.\n", debugstr_w(svc_name), GetLastError());
+
+        CloseServiceHandle(service);
+    }
+
+    SetupDiDestroyDeviceInfoList(set);
+    CloseServiceHandle(manager);
+}
+
 static void usage(void)
 {
     WINE_MESSAGE( "Usage: wineboot [options]\n" );
@@ -1362,6 +1409,8 @@ int __cdecl main( int argc, char *argv[] )
         ProcessStartupItems();
     }
 
+    start_root_pnp_services();
+
     WINE_TRACE("Operation done\n");
 
     SetEvent( event );
diff --git a/programs/winedevice/device.c b/programs/winedevice/device.c
index f4ebad2f2d0..0dc7cfd9569 100644
--- a/programs/winedevice/device.c
+++ b/programs/winedevice/device.c
@@ -40,6 +40,7 @@ static const WCHAR servicesW[] = {'\\','R','e','g','i','s','t','r','y',
                                   '\\',0};
 
 extern NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event );
+extern NTSTATUS CDECL wine_enumerate_root_pnp_devices( const WCHAR *driver_name );
 
 static const WCHAR winedeviceW[] = {'w','i','n','e','d','e','v','i','c','e',0};
 static SERVICE_STATUS_HANDLE service_handle;
@@ -83,6 +84,10 @@ static DWORD device_handler( DWORD ctrl, const WCHAR *driver_name )
         result = RtlNtStatusToDosError(ZwUnloadDriver( &service_name ));
         break;
 
+    case 128:
+        result = RtlNtStatusToDosError(wine_enumerate_root_pnp_devices( driver_name ));
+        break;
+
     default:
         FIXME( "got driver ctrl %x for %s\n", ctrl, wine_dbgstr_w(driver_name) );
         break;
-- 
2.20.1




More information about the wine-devel mailing list