[NTOS:PNP] Misc IoInvalidateDeviceState fixes
authorVictor Perevertkin <victor.perevertkin@reactos.org>
Tue, 24 May 2022 01:57:42 +0000 (04:57 +0300)
committerVictor Perevertkin <victor.perevertkin@reactos.org>
Tue, 24 May 2022 02:04:11 +0000 (05:04 +0300)
- Add a check for correct PDO before doing anything
- Process the request only for started devices
- Send the request synchronously during the start sequence

This makes Windows' i8042prt.sys work on ReactOS.
Addendum to cf0bc1c1321047b879edcd19bfbf08138ba9c988

ntoskrnl/io/pnpmgr/devaction.c
ntoskrnl/io/pnpmgr/pnpirp.c
ntoskrnl/io/pnpmgr/pnpmgr.c

index a3b03d5..8b133ef 100644 (file)
@@ -1502,6 +1502,72 @@ done:
     return Status;
 }
 
+/**
+ * @brief      Processes the IoInvalidateDeviceState request
+ *
+ * Sends IRP_MN_QUERY_PNP_DEVICE_STATE request and sets device node's flags
+ * according to the result.
+ * Tree reenumeration should be started upon a successful return of the function.
+ * 
+ * @todo       Do not return STATUS_SUCCESS if nothing is changed.
+ */
+static
+NTSTATUS
+PiUpdateDeviceState(
+    _In_ PDEVICE_NODE DeviceNode)
+{
+    PNP_DEVICE_STATE PnPFlags;
+    NTSTATUS Status;
+
+    Status = PiIrpQueryPnPDeviceState(DeviceNode, &PnPFlags);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE)
+        DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE;
+    else
+        DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE;
+
+    if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI)
+        DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
+    else
+        DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
+
+    if (PnPFlags & PNP_DEVICE_REMOVED || PnPFlags & PNP_DEVICE_DISABLED)
+    {
+        PiSetDevNodeProblem(DeviceNode,
+                            PnPFlags & PNP_DEVICE_DISABLED 
+                            ? CM_PROB_HARDWARE_DISABLED
+                            : CM_PROB_DEVICE_NOT_THERE);
+
+        PiSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedRemoval);
+    }
+    else if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)
+    {
+        // Query resource rebalance
+
+        if (PnPFlags & PNP_DEVICE_FAILED)
+            DeviceNode->Flags &= DNF_NON_STOPPED_REBALANCE;
+        else
+            DeviceNode->Flags |= DNF_NON_STOPPED_REBALANCE;
+
+        // Clear DNF_NO_RESOURCE_REQUIRED just in case (will be set back if needed)
+        DeviceNode->Flags &= ~DNF_NO_RESOURCE_REQUIRED;
+
+        // This will be caught up later by enumeration
+        DeviceNode->Flags |= DNF_RESOURCE_REQUIREMENTS_CHANGED;
+    }
+    else if (PnPFlags & PNP_DEVICE_FAILED)
+    {
+        PiSetDevNodeProblem(DeviceNode, CM_PROB_FAILED_POST_START);
+        PiSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedRemoval);
+    }
+
+    return STATUS_SUCCESS;
+}
+
 static
 NTSTATUS
 PiStartDeviceFinal(
@@ -1553,7 +1619,7 @@ PiStartDeviceFinal(
     }
 
     // Query the device state (IRP_MN_QUERY_PNP_DEVICE_STATE)
-    PiQueueDeviceAction(DeviceNode->PhysicalDeviceObject, PiActionQueryState, NULL, NULL);
+    PiUpdateDeviceState(DeviceNode);
 
     DPRINT("Sending GUID_DEVICE_ARRIVAL %wZ\n", &DeviceNode->InstancePath);
     IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, &DeviceNode->InstancePath);
@@ -2025,72 +2091,6 @@ IopRemoveDevice(PDEVICE_NODE DeviceNode)
     return Status;
 }
 
-/**
- * @brief      Processes the IoInvalidateDeviceState request
- *
- * Sends IRP_MN_QUERY_PNP_DEVICE_STATE request and sets device node's flags
- * according to the result.
- * Tree reenumeration should be started upon a successful return of the function.
- * 
- * @todo       Do not return STATUS_SUCCESS if nothing is changed.
- */
-static
-NTSTATUS
-PiUpdateDeviceState(
-    _In_ PDEVICE_NODE DeviceNode)
-{
-    PNP_DEVICE_STATE PnPFlags;
-    NTSTATUS Status;
-
-    Status = PiIrpQueryPnPDeviceState(DeviceNode, &PnPFlags);
-    if (!NT_SUCCESS(Status))
-    {
-        return Status;
-    }
-
-    if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE)
-        DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE;
-    else
-        DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE;
-
-    if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI)
-        DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
-    else
-        DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
-
-    if (PnPFlags & PNP_DEVICE_REMOVED || PnPFlags & PNP_DEVICE_DISABLED)
-    {
-        PiSetDevNodeProblem(DeviceNode,
-                            PnPFlags & PNP_DEVICE_DISABLED 
-                            ? CM_PROB_HARDWARE_DISABLED
-                            : CM_PROB_DEVICE_NOT_THERE);
-
-        PiSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedRemoval);
-    }
-    else if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)
-    {
-        // Query resource rebalance
-
-        if (PnPFlags & PNP_DEVICE_FAILED)
-            DeviceNode->Flags &= DNF_NON_STOPPED_REBALANCE;
-        else
-            DeviceNode->Flags |= DNF_NON_STOPPED_REBALANCE;
-
-        // Clear DNF_NO_RESOURCE_REQUIRED just in case (will be set back if needed)
-        DeviceNode->Flags &= ~DNF_NO_RESOURCE_REQUIRED;
-
-        // This will be caught up later by enumeration
-        DeviceNode->Flags |= DNF_RESOURCE_REQUIREMENTS_CHANGED;
-    }
-    else if (PnPFlags & PNP_DEVICE_FAILED)
-    {
-        PiSetDevNodeProblem(DeviceNode, CM_PROB_FAILED_POST_START);
-        PiSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedRemoval);
-    }
-
-    return STATUS_SUCCESS;
-}
-
 static
 NTSTATUS
 PiEnumerateDevice(
@@ -2386,6 +2386,7 @@ PiDevNodeStateMachine(
                 break;
             case DeviceNodeStartPostWork:
                 DPRINT("DeviceNodeStartPostWork %wZ\n", &currentNode->InstancePath);
+                // TODO: inspect the status
                 status = PiStartDeviceFinal(currentNode);
                 doProcessAgain = TRUE;
                 break;
@@ -2599,13 +2600,20 @@ PipDeviceActionWorker(
                 break;
 
             case PiActionQueryState:
-                // First, do a IRP_MN_QUERY_PNP_DEVICE_STATE request,
-                // it will update node's flags and then do enumeration if something changed
-                status = PiUpdateDeviceState(deviceNode);
-                if (NT_SUCCESS(status))
+                // This action is only valid for started devices. If the device is not yet
+                // started, the PnP manager issues IRP_MN_QUERY_PNP_DEVICE_STATE by itself.
+                if (deviceNode->State == DeviceNodeStarted)
                 {
-                    PiDevNodeStateMachine(deviceNode);
+                    // Issue a IRP_MN_QUERY_PNP_DEVICE_STATE request: it will update node's flags
+                    // and then do enumeration if something has changed
+                    status = PiUpdateDeviceState(deviceNode);
+                    if (NT_SUCCESS(status))
+                    {
+                        PiDevNodeStateMachine(deviceNode);
+                    }
                 }
+                // TODO: Windows may return STATUS_DELETE_PENDING here
+                status = STATUS_SUCCESS;                
                 break;
 
             default:
index 952150b..4a6a50c 100644 (file)
@@ -288,8 +288,7 @@ PiIrpQueryPnPDeviceState(
     PAGED_CODE();
 
     ASSERT(DeviceNode);
-    ASSERT(DeviceNode->State == DeviceNodeResourcesAssigned ||
-           DeviceNode->State == DeviceNodeStartPostWork ||
+    ASSERT(DeviceNode->State == DeviceNodeStartPostWork ||
            DeviceNode->State == DeviceNodeStarted);
 
     ULONG_PTR longState;
index e2f7ba9..87bf857 100644 (file)
@@ -4,7 +4,7 @@
  * FILE:            ntoskrnl/io/pnpmgr/pnpmgr.c
  * PURPOSE:         Initializes the PnP manager
  * PROGRAMMERS:     Casper S. Hornstrup (chorns@users.sourceforge.net)
- *                  Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
+ *                  Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
  */
 
 /* INCLUDES ******************************************************************/
@@ -2418,5 +2418,10 @@ NTAPI
 IoInvalidateDeviceState(
     IN PDEVICE_OBJECT DeviceObject)
 {
+    if (!IopIsValidPhysicalDeviceObject(DeviceObject))
+    {
+        KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 0x2, (ULONG_PTR)DeviceObject, 0, 0);
+    }
+
     PiQueueDeviceAction(DeviceObject, PiActionQueryState, NULL, NULL);
 }