[PATCH v2 4/6] ntoskrnl: Start the device even without a function driver if it reports RawDeviceOK.

Zebediah Figura z.figura12 at gmail.com
Fri Apr 9 00:17:41 CDT 2021


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/ntoskrnl.exe/pnp.c              | 43 +++++++++++++++-
 dlls/ntoskrnl.exe/tests/driver_pnp.c |  2 +-
 dlls/ntoskrnl.exe/tests/ntoskrnl.c   | 76 +++++++++++++++-------------
 3 files changed, 83 insertions(+), 38 deletions(-)

diff --git a/dlls/ntoskrnl.exe/pnp.c b/dlls/ntoskrnl.exe/pnp.c
index 7994a8b85b9..f8dc8c31935 100644
--- a/dlls/ntoskrnl.exe/pnp.c
+++ b/dlls/ntoskrnl.exe/pnp.c
@@ -165,6 +165,36 @@ static void send_power_irp( DEVICE_OBJECT *device, DEVICE_POWER_STATE power )
         KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
 }
 
+static NTSTATUS get_device_caps( DEVICE_OBJECT *device, DEVICE_CAPABILITIES *caps )
+{
+    IO_STACK_LOCATION *irpsp;
+    IO_STATUS_BLOCK irp_status;
+    KEVENT event;
+    IRP *irp;
+
+    memset( caps, 0, sizeof(*caps) );
+    caps->Size = sizeof(*caps);
+    caps->Version = 1;
+    caps->Address = 0xffffffff;
+    caps->UINumber = 0xffffffff;
+
+    device = IoGetAttachedDevice( device );
+
+    KeInitializeEvent( &event, NotificationEvent, FALSE );
+    if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, device, NULL, 0, NULL, NULL, &irp_status )))
+        return STATUS_NO_MEMORY;
+
+    irpsp = IoGetNextIrpStackLocation( irp );
+    irpsp->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
+    irpsp->Parameters.DeviceCapabilities.Capabilities = caps;
+
+    irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
+    if (IoCallDriver( device, irp ) == STATUS_PENDING)
+        KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
+
+    return irp_status.u.Status;
+}
+
 static void load_function_driver( DEVICE_OBJECT *device, HDEVINFO set, SP_DEVINFO_DATA *sp_device )
 {
     static const WCHAR driverW[] = {'\\','D','r','i','v','e','r','\\',0};
@@ -299,7 +329,9 @@ static void enumerate_new_device( DEVICE_OBJECT *device, HDEVINFO set )
 
     SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
     WCHAR device_instance_id[MAX_DEVICE_ID_LEN];
+    DEVICE_CAPABILITIES caps;
     BOOL need_driver = TRUE;
+    NTSTATUS status;
     HKEY key;
 
     if (get_device_instance_id( device, device_instance_id ))
@@ -324,8 +356,17 @@ static void enumerate_new_device( DEVICE_OBJECT *device, HDEVINFO set )
         RegCloseKey( key );
     }
 
-    if (need_driver && !install_device_driver( device, set, &sp_device ))
+    if ((status = get_device_caps( device, &caps )))
+    {
+        ERR("Failed to get caps for device %s, status %#x.\n", debugstr_w(device_instance_id), status);
         return;
+    }
+
+    if (need_driver && !install_device_driver( device, set, &sp_device ) && !caps.RawDeviceOK)
+    {
+        ERR("Unable to install a function driver for device %s.\n", debugstr_w(device_instance_id));
+        return;
+    }
 
     start_device( device, set, &sp_device );
 }
diff --git a/dlls/ntoskrnl.exe/tests/driver_pnp.c b/dlls/ntoskrnl.exe/tests/driver_pnp.c
index 2b3968fe395..b121e790aa7 100644
--- a/dlls/ntoskrnl.exe/tests/driver_pnp.c
+++ b/dlls/ntoskrnl.exe/tests/driver_pnp.c
@@ -217,7 +217,7 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp)
             IoSetDeviceInterfaceState(&device->child_symlink, TRUE);
 
             state = PoSetPowerState(device_obj, DevicePowerState, state);
-            ok(state.DeviceState == device->power_state, "got previous state %u\n", state.DeviceState);
+            todo_wine ok(state.DeviceState == device->power_state, "got previous state %u\n", state.DeviceState);
             device->power_state = PowerDeviceD0;
             ret = STATUS_SUCCESS;
             break;
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
index e0a6e0a30d4..fe0b271b9df 100644
--- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
@@ -1106,54 +1106,58 @@ static void test_pnp_devices(void)
     ok(set != INVALID_HANDLE_VALUE, "failed to get device list, error %#x\n", GetLastError());
 
     ret = SetupDiEnumDeviceInfo(set, 0, &device);
-    todo_wine ok(ret, "failed to get device, error %#x\n", GetLastError());
+    ok(ret, "failed to get device, error %#x\n", GetLastError());
+    ok(IsEqualGUID(&device.ClassGuid, &GUID_NULL), "wrong class %s\n", debugstr_guid(&device.ClassGuid));
+
+    ret = SetupDiGetDeviceInstanceIdA(set, &device, buffer, sizeof(buffer), NULL);
+    ok(ret, "failed to get device ID, error %#x\n", GetLastError());
+    ok(!strcasecmp(buffer, "wine\\test\\1"), "got ID %s\n", debugstr_a(buffer));
+
+    ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_CAPABILITIES,
+            &type, (BYTE *)&dword, sizeof(dword), NULL);
+    todo_wine ok(ret, "got error %#x\n", GetLastError());
     if (ret)
     {
-        ok(IsEqualGUID(&device.ClassGuid, &GUID_NULL), "wrong class %s\n", debugstr_guid(&device.ClassGuid));
-
-        ret = SetupDiGetDeviceInstanceIdA(set, &device, buffer, sizeof(buffer), NULL);
-        ok(ret, "failed to get device ID, error %#x\n", GetLastError());
-        ok(!strcasecmp(buffer, "wine\\test\\1"), "got ID %s\n", debugstr_a(buffer));
-
-        ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_CAPABILITIES,
-                &type, (BYTE *)&dword, sizeof(dword), NULL);
-        ok(ret, "got error %#x\n", GetLastError());
         ok(dword == (CM_DEVCAP_EJECTSUPPORTED | CM_DEVCAP_UNIQUEID
                 | CM_DEVCAP_RAWDEVICEOK | CM_DEVCAP_SURPRISEREMOVALOK), "got flags %#x\n", dword);
         ok(type == REG_DWORD, "got type %u\n", type);
+    }
 
-        ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_CLASSGUID,
-                &type, (BYTE *)buffer, sizeof(buffer), NULL);
-        ok(!ret, "expected failure\n");
+    ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_CLASSGUID,
+            &type, (BYTE *)buffer, sizeof(buffer), NULL);
+    todo_wine ok(!ret, "expected failure\n");
+    if (ret)
         ok(GetLastError() == ERROR_INVALID_DATA, "got error %#x\n", GetLastError());
 
-        ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_DEVTYPE,
-                &type, (BYTE *)&dword, sizeof(dword), NULL);
-        ok(!ret, "expected failure\n");
-        ok(GetLastError() == ERROR_INVALID_DATA, "got error %#x\n", GetLastError());
+    ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_DEVTYPE,
+            &type, (BYTE *)&dword, sizeof(dword), NULL);
+    ok(!ret, "expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_DATA, "got error %#x\n", GetLastError());
 
-        ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_DRIVER,
-                &type, (BYTE *)buffer, sizeof(buffer), NULL);
-        ok(!ret, "expected failure\n");
-        ok(GetLastError() == ERROR_INVALID_DATA, "got error %#x\n", GetLastError());
+    ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_DRIVER,
+            &type, (BYTE *)buffer, sizeof(buffer), NULL);
+    ok(!ret, "expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_DATA, "got error %#x\n", GetLastError());
 
-        ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_HARDWAREID,
-                &type, (BYTE *)buffer, sizeof(buffer), &size);
-        ok(ret, "got error %#x\n", GetLastError());
-        ok(type == REG_MULTI_SZ, "got type %u\n", type);
-        ok(size == sizeof(expect_hardware_id), "got size %u\n", size);
-        ok(!memcmp(buffer, expect_hardware_id, size), "got hardware IDs %s\n", debugstr_an(buffer, size));
+    ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_HARDWAREID,
+            &type, (BYTE *)buffer, sizeof(buffer), &size);
+    ok(ret, "got error %#x\n", GetLastError());
+    ok(type == REG_MULTI_SZ, "got type %u\n", type);
+    ok(size == sizeof(expect_hardware_id), "got size %u\n", size);
+    ok(!memcmp(buffer, expect_hardware_id, size), "got hardware IDs %s\n", debugstr_an(buffer, size));
 
-        ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_COMPATIBLEIDS,
-                &type, (BYTE *)buffer, sizeof(buffer), &size);
-        ok(ret, "got error %#x\n", GetLastError());
-        ok(type == REG_MULTI_SZ, "got type %u\n", type);
-        ok(size == sizeof(expect_compat_id), "got size %u\n", size);
-        ok(!memcmp(buffer, expect_compat_id, size), "got compatible IDs %s\n", debugstr_an(buffer, size));
+    ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_COMPATIBLEIDS,
+            &type, (BYTE *)buffer, sizeof(buffer), &size);
+    ok(ret, "got error %#x\n", GetLastError());
+    ok(type == REG_MULTI_SZ, "got type %u\n", type);
+    ok(size == sizeof(expect_compat_id), "got size %u\n", size);
+    ok(!memcmp(buffer, expect_compat_id, size), "got compatible IDs %s\n", debugstr_an(buffer, size));
 
-        ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME,
-                &type, (BYTE *)buffer, sizeof(buffer), NULL);
-        ok(ret, "got error %#x\n", GetLastError());
+    ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME,
+            &type, (BYTE *)buffer, sizeof(buffer), NULL);
+    todo_wine ok(ret, "got error %#x\n", GetLastError());
+    if (ret)
+    {
         ok(type == REG_SZ, "got type %u\n", type);
         ok(!strcmp(buffer, "\\Device\\winetest_pnp_1"), "got PDO name %s\n", debugstr_a(buffer));
     }
-- 
2.30.2




More information about the wine-devel mailing list