https://git.reactos.org/?p=reactos.git;a=commitdiff;h=798fc13b482b56a785b91…
commit 798fc13b482b56a785b910f7febb396d608e14b0
Author: Victor Perevertkin <victor.perevertkin(a)reactos.org>
AuthorDate: Thu Dec 10 03:19:31 2020 +0300
Commit: Victor Perevertkin <victor.perevertkin(a)reactos.org>
CommitDate: Wed Jan 27 05:15:15 2021 +0300
[NTOS:PNP] Implement NT5.2-like DEVICE_NODE state management
- Use DeviceNode->State field and its values, instead of
DeviceNode->Flags for tracking current node state
- Change DNF_* flags to the ones compatible with Windows XP+
- Simplify state changes for device nodes and encapsulate all the logic
inside the PiDevNodeStateMachine routine. This makes the ground for
future improvements in the device removal sequence and
resource management
- Now values inside DeviceNode->State and ->Flags are compatible with
the windbg !devnode macro and can be tracked using it
- BUGFIX: fixed cases where IRP_MN_START_DEVICE or
IRP_MN_QUERY_DEVICE_RELATIONS may be sent to a device after a
IRP_MN_REMOVE_DEVICE
CORE-7826
---
ntoskrnl/include/internal/io.h | 71 ++-
ntoskrnl/io/iomgr/iomgr.c | 3 -
ntoskrnl/io/pnpmgr/devaction.c | 1024 +++++++++++++---------------------------
ntoskrnl/io/pnpmgr/devnode.c | 34 +-
ntoskrnl/io/pnpmgr/plugplay.c | 51 +-
ntoskrnl/io/pnpmgr/pnpinit.c | 14 +-
ntoskrnl/io/pnpmgr/pnpirp.c | 225 +++++++++
ntoskrnl/io/pnpmgr/pnpmgr.c | 76 ---
ntoskrnl/io/pnpmgr/pnpreport.c | 85 +---
ntoskrnl/io/pnpmgr/pnpres.c | 15 +-
ntoskrnl/ntos.cmake | 1 +
sdk/include/ndk/iotypes.h | 75 +--
12 files changed, 715 insertions(+), 959 deletions(-)
diff --git a/ntoskrnl/include/internal/io.h b/ntoskrnl/include/internal/io.h
index 65005373bd2..3819bea1124 100644
--- a/ntoskrnl/include/internal/io.h
+++ b/ntoskrnl/include/internal/io.h
@@ -567,11 +567,6 @@ IopDetectResourceConflict(
//
// PNP Routines
//
-NTSTATUS
-PiCallDriverAddDevice(
- _In_ PDEVICE_NODE DeviceNode,
- _In_ BOOLEAN LoadDrivers);
-
NTSTATUS
NTAPI
IopInitializePlugPlayServices(
@@ -609,6 +604,11 @@ PiInsertDevNode(
_In_ PDEVICE_NODE DeviceNode,
_In_ PDEVICE_NODE ParentNode);
+PNP_DEVNODE_STATE
+PiSetDevNodeState(
+ _In_ PDEVICE_NODE DeviceNode,
+ _In_ PNP_DEVNODE_STATE NewState);
+
VOID
PiSetDevNodeProblem(
_In_ PDEVICE_NODE DeviceNode,
@@ -629,7 +629,6 @@ IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
PDEVICE_CAPABILITIES DeviceCaps);
NTSTATUS
-NTAPI
IopSynchronousCall(
IN PDEVICE_OBJECT DeviceObject,
IN PIO_STACK_LOCATION IoStackLocation,
@@ -651,18 +650,6 @@ IopGetDeviceNode(
IN PDEVICE_OBJECT DeviceObject
);
-NTSTATUS
-IopActionConfigureChildServices(
- IN PDEVICE_NODE DeviceNode,
- IN PVOID Context
-);
-
-NTSTATUS
-IopActionInitChildServices(
- IN PDEVICE_NODE DeviceNode,
- IN PVOID Context
-);
-
NTSTATUS
IoCreateDriverList(
VOID
@@ -682,10 +669,6 @@ IopQueueTargetDeviceEvent(
PUNICODE_STRING DeviceIds
);
-NTSTATUS
-IopInitializePnpServices(
- IN PDEVICE_NODE DeviceNode);
-
NTSTATUS
NTAPI
IopOpenRegistryKeyEx(
@@ -817,21 +800,6 @@ IopReadyDeviceObjects(
IN PDRIVER_OBJECT Driver
);
-NTSTATUS
-IopStartDevice(
- IN PDEVICE_NODE DeviceNode
-);
-
-NTSTATUS
-IopStopDevice(
- IN PDEVICE_NODE DeviceNode
-);
-
-NTSTATUS
-IopRemoveDevice(
- IN PDEVICE_NODE DeviceNode
-);
-
PVPB
NTAPI
IopCheckVpbMounted(
@@ -1387,6 +1355,35 @@ PiNotifyTargetDeviceChange(
_In_ PDEVICE_OBJECT DeviceObject,
_In_opt_ PTARGET_DEVICE_CUSTOM_NOTIFICATION CustomNotification);
+//
+// PnP IRPs
+//
+NTSTATUS
+PiIrpStartDevice(
+ _In_ PDEVICE_NODE DeviceNode);
+
+NTSTATUS
+PiIrpStopDevice(
+ _In_ PDEVICE_NODE DeviceNode);
+
+NTSTATUS
+PiIrpQueryStopDevice(
+ _In_ PDEVICE_NODE DeviceNode);
+
+NTSTATUS
+PiIrpCancelStopDevice(
+ _In_ PDEVICE_NODE DeviceNode);
+
+NTSTATUS
+PiIrpQueryDeviceRelations(
+ _In_ PDEVICE_NODE DeviceNode,
+ _In_ DEVICE_RELATION_TYPE Type);
+
+NTSTATUS
+PiIrpQueryPnPDeviceState(
+ _In_ PDEVICE_NODE DeviceNode,
+ _Out_ PPNP_DEVICE_STATE DeviceState);
+
//
// Global I/O Data
//
diff --git a/ntoskrnl/io/iomgr/iomgr.c b/ntoskrnl/io/iomgr/iomgr.c
index 5d272cb8af7..06df1ceac8f 100644
--- a/ntoskrnl/io/iomgr/iomgr.c
+++ b/ntoskrnl/io/iomgr/iomgr.c
@@ -596,9 +596,6 @@ IoInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
KdInitSystem(3, LoaderBlock);
#endif
- /* Load services for devices found by PnP manager */
- IopInitializePnpServices(IopRootDeviceNode);
-
/* Load system start drivers */
IopInitializeSystemDrivers();
PnpSystemInit = TRUE;
diff --git a/ntoskrnl/io/pnpmgr/devaction.c b/ntoskrnl/io/pnpmgr/devaction.c
index 8b4db9d387a..166a1d69acd 100644
--- a/ntoskrnl/io/pnpmgr/devaction.c
+++ b/ntoskrnl/io/pnpmgr/devaction.c
@@ -113,6 +113,12 @@ static
NTSTATUS
IopPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject, BOOLEAN Force);
+static
+NTSTATUS
+IopSetServiceEnumData(
+ _In_ PDEVICE_NODE DeviceNode,
+ _In_ HANDLE InstanceHandle);
+
static
BOOLEAN
IopValidateID(
@@ -256,14 +262,9 @@ IopCreateDeviceInstancePath(
if (DeviceCapabilities.HardwareDisabled)
{
/* FIXME: Cleanup device */
- DeviceNode->Flags |= DNF_DISABLED;
RtlFreeUnicodeString(&DeviceId);
return STATUS_PLUGPLAY_NO_DEVICE;
}
- else
- {
- DeviceNode->Flags &= ~DNF_DISABLED;
- }
if (!DeviceCapabilities.UniqueID)
{
@@ -584,6 +585,7 @@ PiAttachFilterDrivers(
* @param[in] LoadDrivers Whether to load drivers if they are not loaded yet
* (used when storage subsystem is not yet initialized)
*/
+static
NTSTATUS
PiCallDriverAddDevice(
_In_ PDEVICE_NODE DeviceNode,
@@ -636,7 +638,7 @@ PiCallDriverAddDevice(
}
else
{
- // open the CCS\Constol\Class\<ClassGUID> key
+ // open the CCS\Control\Class\<ClassGUID> key
Status = IopOpenRegistryKeyEx(&ClassKey, ccsControlHandle,
&classGUID, KEY_READ);
ZwClose(ccsControlHandle);
if (!NT_SUCCESS(Status))
@@ -794,15 +796,13 @@ PiCallDriverAddDevice(
}
ObDereferenceObject(fdo);
-
- IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
+ PiSetDevNodeState(DeviceNode, DeviceNodeDriversAdded);
}
else
{
// lower filters (if already started) will be removed upon this request
PiSetDevNodeProblem(DeviceNode, CM_PROB_FAILED_ADD);
- IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
- IopRemoveDevice(DeviceNode);
+ PiSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedRemoval);
break;
}
}
@@ -837,11 +837,6 @@ Cleanup:
ZwClose(ClassKey);
}
- if (DeviceNode->Flags & DNF_ADDED)
- {
- IopStartDevice(DeviceNode);
- }
-
return Status;
}
@@ -1078,30 +1073,14 @@ IopQueryCompatibleIds(PDEVICE_NODE DeviceNode,
return Status;
}
-/*
- * IopActionInterrogateDeviceStack
- *
- * Retrieve information for all (direct) child nodes of a parent node.
- *
- * Parameters
- * DeviceNode
- * Pointer to device node.
- * Context
- * Pointer to parent node to retrieve child node information for.
- *
- * Remarks
- * Any errors that occur are logged instead so that all child services have a chance
- * of being interrogated.
- */
-
+static
NTSTATUS
-IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
- PVOID Context)
+PiInitializeDevNode(
+ _In_ PDEVICE_NODE DeviceNode)
{
IO_STATUS_BLOCK IoStatusBlock;
PWSTR DeviceDescription;
PWSTR LocationInformation;
- PDEVICE_NODE ParentDeviceNode;
IO_STACK_LOCATION Stack;
NTSTATUS Status;
ULONG RequiredLength;
@@ -1111,38 +1090,9 @@ IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
UNICODE_STRING InstancePathU;
PDEVICE_OBJECT OldDeviceObject;
- DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
+ DPRINT("PiProcessNewDevNode(%p)\n", DeviceNode);
DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
- ParentDeviceNode = (PDEVICE_NODE)Context;
-
- /*
- * We are called for the parent too, but we don't need to do special
- * handling for this node
- */
- if (DeviceNode == ParentDeviceNode)
- {
- DPRINT("Success\n");
- return STATUS_SUCCESS;
- }
-
- /*
- * Make sure this device node is a direct child of the parent device node
- * that is given as an argument
- */
- if (DeviceNode->Parent != ParentDeviceNode)
- {
- DPRINT("Skipping 2+ level child\n");
- return STATUS_SUCCESS;
- }
-
- /* Skip processing if it was already completed before */
- if (DeviceNode->Flags & DNF_PROCESSED)
- {
- /* Nothing to do */
- return STATUS_SUCCESS;
- }
-
/* Get Locale ID */
Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
if (!NT_SUCCESS(Status))
@@ -1163,9 +1113,7 @@ IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
{
DPRINT1("IopCreateDeviceInstancePath() failed with status 0x%lx\n",
Status);
}
-
- /* We have to return success otherwise we abort the traverse operation */
- return STATUS_SUCCESS;
+ return Status;
}
/* Verify that this is not a duplicate */
@@ -1205,6 +1153,8 @@ IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
IopQueryCompatibleIds(DeviceNode, InstanceKey);
+ DeviceNode->Flags |= DNF_IDS_QUERIED;
+
DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device
stack\n");
Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
@@ -1348,9 +1298,15 @@ IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
IopSetDeviceInstanceData(InstanceKey, DeviceNode);
}
+ // Try installing a critical device, so its Service key is populated
+ // then call IopSetServiceEnumData to populate service's Enum key.
+ // That allows us to start devices during an early boot
+ IopInstallCriticalDevice(DeviceNode);
+ IopSetServiceEnumData(DeviceNode, InstanceKey);
+
ZwClose(InstanceKey);
- IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED);
+ PiSetDevNodeState(DeviceNode, DeviceNodeInitialized);
if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
{
@@ -1362,235 +1318,46 @@ IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
return STATUS_SUCCESS;
}
-/*
- * IopActionConfigureChildServices
- *
- * Retrieve configuration for all (direct) child nodes of a parent node.
- *
- * Parameters
- * DeviceNode
- * Pointer to device node.
- * Context
- * Pointer to parent node to retrieve child node configuration for.
- *
- * Remarks
- * Any errors that occur are logged instead so that all child services have a chance
of beeing
- * configured.
- */
-
-NTSTATUS
-IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
- PVOID Context)
-{
- RTL_QUERY_REGISTRY_TABLE QueryTable[3];
- PDEVICE_NODE ParentDeviceNode;
- PUNICODE_STRING Service;
- UNICODE_STRING ClassGUID;
- NTSTATUS Status;
- DEVICE_CAPABILITIES DeviceCaps;
-
- DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
-
- ParentDeviceNode = (PDEVICE_NODE)Context;
-
- /*
- * We are called for the parent too, but we don't need to do special
- * handling for this node
- */
- if (DeviceNode == ParentDeviceNode)
- {
- DPRINT("Success\n");
- return STATUS_SUCCESS;
- }
-
- /*
- * Make sure this device node is a direct child of the parent device node
- * that is given as an argument
- */
-
- if (DeviceNode->Parent != ParentDeviceNode)
- {
- DPRINT("Skipping 2+ level child\n");
- return STATUS_SUCCESS;
- }
-
- if (!(DeviceNode->Flags & DNF_PROCESSED))
- {
- DPRINT1("Child not ready to be configured\n");
- return STATUS_SUCCESS;
- }
-
- if (!(DeviceNode->Flags & (DNF_DISABLED | DNF_STARTED | DNF_ADDED)))
- {
- UNICODE_STRING RegKey;
-
- /* Install the service for this if it's in the CDDB */
- IopInstallCriticalDevice(DeviceNode);
-
- /*
- * Retrieve configuration from Enum key
- */
-
- Service = &DeviceNode->ServiceName;
-
- RtlZeroMemory(QueryTable, sizeof(QueryTable));
- RtlInitUnicodeString(Service, NULL);
- RtlInitUnicodeString(&ClassGUID, NULL);
-
- QueryTable[0].Name = L"Service";
- QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
- QueryTable[0].EntryContext = Service;
-
- QueryTable[1].Name = L"ClassGUID";
- QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
- QueryTable[1].EntryContext = &ClassGUID;
- QueryTable[1].DefaultType = REG_SZ;
- QueryTable[1].DefaultData = L"";
- QueryTable[1].DefaultLength = 0;
-
- RegKey.Length = 0;
- RegKey.MaximumLength = sizeof(ENUM_ROOT) + sizeof(WCHAR) +
DeviceNode->InstancePath.Length;
- RegKey.Buffer = ExAllocatePoolWithTag(PagedPool,
- RegKey.MaximumLength,
- TAG_IO);
- if (RegKey.Buffer == NULL)
- {
- IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- RtlAppendUnicodeToString(&RegKey, ENUM_ROOT);
- RtlAppendUnicodeToString(&RegKey, L"\\");
- RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
-
- Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
- RegKey.Buffer, QueryTable, NULL, NULL);
- ExFreePoolWithTag(RegKey.Buffer, TAG_IO);
-
- if (!NT_SUCCESS(Status))
- {
- /* FIXME: Log the error */
- DPRINT("Could not retrieve configuration for device %wZ (Status
0x%08x)\n",
- &DeviceNode->InstancePath, Status);
- IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
- return STATUS_SUCCESS;
- }
-
- if (Service->Buffer == NULL)
- {
- if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps))
&&
- DeviceCaps.RawDeviceOK)
- {
- DPRINT("%wZ is using parent bus driver (%wZ)\n",
&DeviceNode->InstancePath, &ParentDeviceNode->ServiceName);
- RtlInitEmptyUnicodeString(&DeviceNode->ServiceName, NULL, 0);
- }
- else if (ClassGUID.Length != 0)
- {
- /* Device has a ClassGUID value, but no Service value.
- * Suppose it is using the NULL driver, so state the
- * device is started */
- DPRINT("%wZ is using NULL driver\n",
&DeviceNode->InstancePath);
- IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
- }
- else
- {
- DeviceNode->Problem = CM_PROB_FAILED_INSTALL;
- IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
- }
- return STATUS_SUCCESS;
- }
-
- DPRINT("Got Service %S\n", Service->Buffer);
- }
-
- return STATUS_SUCCESS;
-}
-
-/*
- * IopActionInitChildServices
- *
- * Initialize the service for all (direct) child nodes of a parent node
- *
- * Parameters
- * DeviceNode
- * Pointer to device node.
- * Context
- * Pointer to parent node to initialize child node services for.
- *
- * Remarks
- * If the driver image for a service is not loaded and initialized
- * it is done here too. Any errors that occur are logged instead so
- * that all child services have a chance of being initialized.
- */
-
-NTSTATUS
-IopActionInitChildServices(PDEVICE_NODE DeviceNode,
- PVOID Context)
-{
- PDEVICE_NODE ParentDeviceNode;
-
- DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
-
- ParentDeviceNode = Context;
-
- /*
- * We are called for the parent too, but we don't need to do special
- * handling for this node
- */
- if (DeviceNode == ParentDeviceNode)
- {
- DPRINT("Success\n");
- return STATUS_SUCCESS;
- }
-
- /*
- * We don't want to check for a direct child because
- * this function is called during boot to reinitialize
- * devices with drivers that couldn't load yet due to
- * stage 0 limitations (ie can't load from disk yet).
- */
-
- if (!(DeviceNode->Flags & DNF_PROCESSED))
- {
- DPRINT1("Child not ready to be added\n");
- return STATUS_SUCCESS;
- }
-
- if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) ||
- IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) ||
- IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
- return STATUS_SUCCESS;
-
- PiCallDriverAddDevice(DeviceNode, PnPBootDriversInitialized);
- return STATUS_SUCCESS;
-}
-
static
NTSTATUS
-IopSetServiceEnumData(PDEVICE_NODE DeviceNode)
+IopSetServiceEnumData(
+ _In_ PDEVICE_NODE DeviceNode,
+ _In_ HANDLE InstanceHandle)
{
UNICODE_STRING ServicesKeyPath =
RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
UNICODE_STRING ServiceKeyName;
UNICODE_STRING EnumKeyName;
UNICODE_STRING ValueName;
- PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
+ UNICODE_STRING ServiceName;
+ PKEY_VALUE_FULL_INFORMATION KeyValueInformation, kvInfo2;
HANDLE ServiceKey = NULL, ServiceEnumKey = NULL;
ULONG Disposition;
ULONG Count = 0, NextInstance = 0;
WCHAR ValueBuffer[6];
NTSTATUS Status = STATUS_SUCCESS;
- DPRINT("IopSetServiceEnumData(%p)\n", DeviceNode);
- DPRINT("Instance: %wZ\n", &DeviceNode->InstancePath);
- DPRINT("Service: %wZ\n", &DeviceNode->ServiceName);
+ // obtain the device node's ServiceName
+ Status = IopGetRegistryValue(InstanceHandle, L"Service", &kvInfo2);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
- if (DeviceNode->ServiceName.Buffer == NULL)
+ if (kvInfo2->Type != REG_SZ || kvInfo2->DataLength <= sizeof(WCHAR))
{
- DPRINT1("No service!\n");
- return STATUS_SUCCESS;
+ ExFreePool(kvInfo2);
+ return STATUS_UNSUCCESSFUL;
}
- ServiceKeyName.MaximumLength = ServicesKeyPath.Length +
DeviceNode->ServiceName.Length + sizeof(UNICODE_NULL);
+ ServiceName.MaximumLength = kvInfo2->DataLength;
+ ServiceName.Length = kvInfo2->DataLength - sizeof(UNICODE_NULL);
+ ServiceName.Buffer = (PVOID)((ULONG_PTR)kvInfo2 + kvInfo2->DataOffset);
+
+ DPRINT("IopSetServiceEnumData(%p)\n", DeviceNode);
+ DPRINT("Instance: %wZ\n", &DeviceNode->InstancePath);
+ DPRINT("Service: %wZ\n", &ServiceName);
+
+ ServiceKeyName.MaximumLength = ServicesKeyPath.Length + ServiceName.Length +
sizeof(UNICODE_NULL);
ServiceKeyName.Length = 0;
ServiceKeyName.Buffer = ExAllocatePool(PagedPool, ServiceKeyName.MaximumLength);
if (ServiceKeyName.Buffer == NULL)
@@ -1600,7 +1367,7 @@ IopSetServiceEnumData(PDEVICE_NODE DeviceNode)
}
RtlAppendUnicodeStringToString(&ServiceKeyName, &ServicesKeyPath);
- RtlAppendUnicodeStringToString(&ServiceKeyName,
&DeviceNode->ServiceName);
+ RtlAppendUnicodeStringToString(&ServiceKeyName, &ServiceName);
DPRINT("ServiceKeyName: %wZ\n", &ServiceKeyName);
@@ -1694,6 +1461,10 @@ IopSetServiceEnumData(PDEVICE_NODE DeviceNode)
sizeof(NextInstance));
}
+ RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING,
+ &ServiceName,
+ &DeviceNode->ServiceName);
+
done:
if (ServiceEnumKey != NULL)
ZwClose(ServiceEnumKey);
@@ -1702,51 +1473,53 @@ done:
ZwClose(ServiceKey);
ExFreePool(ServiceKeyName.Buffer);
+ ExFreePool(kvInfo2);
return Status;
}
static
-VOID
-NTAPI
-IopStartDevice2(IN PDEVICE_OBJECT DeviceObject)
+NTSTATUS
+PiStartDeviceFinal(
+ _In_ PDEVICE_NODE DeviceNode)
{
- IO_STACK_LOCATION Stack;
- PDEVICE_NODE DeviceNode;
- NTSTATUS Status;
- PVOID Dummy;
DEVICE_CAPABILITIES DeviceCapabilities;
+ NTSTATUS Status;
- /* Get the device node */
- DeviceNode = IopGetDeviceNode(DeviceObject);
-
- ASSERT(!(DeviceNode->Flags & DNF_DISABLED));
-
- /* Build the I/O stack location */
- RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
- Stack.MajorFunction = IRP_MJ_PNP;
- Stack.MinorFunction = IRP_MN_START_DEVICE;
+ if (!(DeviceNode->Flags & DNF_IDS_QUERIED))
+ {
+ // query ids (for reported devices)
+ UNICODE_STRING enumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
+ HANDLE enumRootHandle, instanceHandle;
- Stack.Parameters.StartDevice.AllocatedResources =
- DeviceNode->ResourceList;
- Stack.Parameters.StartDevice.AllocatedResourcesTranslated =
- DeviceNode->ResourceListTranslated;
+ // open the enumeration root key
+ Status = IopOpenRegistryKeyEx(&enumRootHandle, NULL, &enumRoot,
KEY_READ);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("IopOpenRegistryKeyEx() failed for \"%wZ\" (status
%x)\n", &enumRoot, Status);
+ return Status;
+ }
- /* Do the call */
- Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy);
- if (!NT_SUCCESS(Status))
- {
- /* Send an IRP_MN_REMOVE_DEVICE request */
- IopRemoveDevice(DeviceNode);
+ // open an instance subkey
+ Status = IopOpenRegistryKeyEx(&instanceHandle, enumRootHandle,
&DeviceNode->InstancePath, KEY_READ);
+ ZwClose(enumRootHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to open a devnode instance key for \"%wZ\"
(status %x)\n",
+ &DeviceNode->InstancePath, Status);
+ return Status;
+ }
- /* Set the appropriate flag */
- DeviceNode->Flags |= DNF_START_FAILED;
- DeviceNode->Problem = CM_PROB_FAILED_START;
+ IopQueryHardwareIds(DeviceNode, instanceHandle);
+ IopQueryCompatibleIds(DeviceNode, instanceHandle);
- DPRINT1("Warning: PnP Start failed (%wZ) [Status: 0x%x]\n",
&DeviceNode->InstancePath, Status);
- return;
+ DeviceNode->Flags |= DNF_IDS_QUERIED;
+ ZwClose(instanceHandle);
}
+ // we're about to start - needs enumeration
+ DeviceNode->Flags |= DNF_REENUMERATE;
+
DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after
start)\n");
Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
@@ -1756,181 +1529,14 @@ IopStartDevice2(IN PDEVICE_OBJECT DeviceObject)
}
/* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */
- IoInvalidateDeviceState(DeviceObject);
+ IoInvalidateDeviceState(DeviceNode->PhysicalDeviceObject);
- /* Otherwise, mark us as started */
- DeviceNode->Flags |= DNF_STARTED;
- DeviceNode->Flags &= ~DNF_STOPPED;
+ DPRINT("Sending GUID_DEVICE_ARRIVAL %wZ\n",
&DeviceNode->InstancePath);
+ IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
&DeviceNode->InstancePath);
- /* We now need enumeration */
- DeviceNode->Flags |= DNF_NEED_ENUMERATION_ONLY;
-}
+ PiSetDevNodeState(DeviceNode, DeviceNodeStarted);
-static
-NTSTATUS
-NTAPI
-IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode)
-{
- PDEVICE_OBJECT DeviceObject;
- NTSTATUS Status;
- PAGED_CODE();
-
- /* Sanity check */
- ASSERT((DeviceNode->Flags & DNF_ADDED));
- ASSERT((DeviceNode->Flags & (DNF_RESOURCE_ASSIGNED |
- DNF_RESOURCE_REPORTED |
- DNF_NO_RESOURCE_REQUIRED)));
-
- /* Get the device object */
- DeviceObject = DeviceNode->PhysicalDeviceObject;
-
- /* Check if we're not started yet */
- if (!(DeviceNode->Flags & DNF_STARTED))
- {
- /* Start us */
- IopStartDevice2(DeviceObject);
- }
-
- /* Do we need to query IDs? This happens in the case of manual reporting */
-#if 0
- if (DeviceNode->Flags & DNF_NEED_QUERY_IDS)
- {
- DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n");
- /* And that case shouldn't happen yet */
- ASSERT(FALSE);
- }
-#endif
-
- IopSetServiceEnumData(DeviceNode);
-
- /* Make sure we're started, and check if we need enumeration */
- if ((DeviceNode->Flags & DNF_STARTED) &&
- (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY))
- {
- /* Enumerate us */
- IoInvalidateDeviceRelations(DeviceObject, BusRelations);
- Status = STATUS_SUCCESS;
- }
- else
- {
- /* Nothing to do */
- Status = STATUS_SUCCESS;
- }
-
- /* Return */
- return Status;
-}
-
-NTSTATUS
-IopStartDevice(
- PDEVICE_NODE DeviceNode)
-{
- NTSTATUS Status;
- HANDLE InstanceHandle = NULL, ControlHandle = NULL;
- UNICODE_STRING KeyName, ValueString;
- OBJECT_ATTRIBUTES ObjectAttributes;
-
- if (DeviceNode->Flags & DNF_DISABLED)
- return STATUS_SUCCESS;
-
- Status = IopAssignDeviceResources(DeviceNode);
- if (!NT_SUCCESS(Status))
- goto ByeBye;
-
- /* New PnP ABI */
- IopStartAndEnumerateDevice(DeviceNode);
-
- /* FIX: Should be done in new device instance code */
- Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath,
REG_OPTION_NON_VOLATILE, &InstanceHandle);
- if (!NT_SUCCESS(Status))
- goto ByeBye;
-
- /* FIX: Should be done in IoXxxPrepareDriverLoading */
- // {
- RtlInitUnicodeString(&KeyName, L"Control");
- InitializeObjectAttributes(&ObjectAttributes,
- &KeyName,
- OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
- InstanceHandle,
- NULL);
- Status = ZwCreateKey(&ControlHandle,
- KEY_SET_VALUE,
- &ObjectAttributes,
- 0,
- NULL,
- REG_OPTION_VOLATILE,
- NULL);
- if (!NT_SUCCESS(Status))
- goto ByeBye;
-
- RtlInitUnicodeString(&KeyName, L"ActiveService");
- ValueString = DeviceNode->ServiceName;
- if (!ValueString.Buffer)
- RtlInitUnicodeString(&ValueString, L"");
- Status = ZwSetValueKey(ControlHandle, &KeyName, 0, REG_SZ, ValueString.Buffer,
ValueString.Length + sizeof(UNICODE_NULL));
- // }
-
-ByeBye:
- if (ControlHandle != NULL)
- ZwClose(ControlHandle);
-
- if (InstanceHandle != NULL)
- ZwClose(InstanceHandle);
-
- return Status;
-}
-
-static
-NTSTATUS
-NTAPI
-IopQueryStopDevice(IN PDEVICE_OBJECT DeviceObject)
-{
- IO_STACK_LOCATION Stack;
- PVOID Dummy;
-
- RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
- Stack.MajorFunction = IRP_MJ_PNP;
- Stack.MinorFunction = IRP_MN_QUERY_STOP_DEVICE;
-
- return IopSynchronousCall(DeviceObject, &Stack, &Dummy);
-}
-
-static
-VOID
-NTAPI
-IopSendStopDevice(IN PDEVICE_OBJECT DeviceObject)
-{
- IO_STACK_LOCATION Stack;
- PVOID Dummy;
-
- RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
- Stack.MajorFunction = IRP_MJ_PNP;
- Stack.MinorFunction = IRP_MN_STOP_DEVICE;
-
- /* Drivers should never fail a IRP_MN_STOP_DEVICE request */
- IopSynchronousCall(DeviceObject, &Stack, &Dummy);
-}
-
-NTSTATUS
-IopStopDevice(
- PDEVICE_NODE DeviceNode)
-{
- NTSTATUS Status;
-
- DPRINT("Stopping device: %wZ\n", &DeviceNode->InstancePath);
-
- Status = IopQueryStopDevice(DeviceNode->PhysicalDeviceObject);
- if (NT_SUCCESS(Status))
- {
- IopSendStopDevice(DeviceNode->PhysicalDeviceObject);
-
- DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING);
- DeviceNode->Flags |= DNF_STOPPED;
-
- return STATUS_SUCCESS;
- }
-
- return Status;
+ return STATUS_SUCCESS;
}
/* PUBLIC FUNCTIONS **********************************************************/
@@ -2013,12 +1619,12 @@ IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
{
PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
- /* Drop all our state for this device in case it isn't really going away */
- DeviceNode->Flags &= DNF_ENUMERATED | DNF_PROCESSED;
+ ASSERT(DeviceNode->State == DeviceNodeAwaitingQueuedRemoval);
/* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
PiIrpSendRemoveCheckVpb(DeviceObject, IRP_MN_REMOVE_DEVICE);
+ PiSetDevNodeState(DeviceNode, DeviceNodeRemoved);
PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_REMOVE_COMPLETE, DeviceObject,
NULL);
LONG_PTR refCount = ObDereferenceObject(DeviceObject);
if (refCount != 0)
@@ -2072,6 +1678,7 @@ VOID
NTAPI
IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject)
{
+ ASSERT(IopGetDeviceNode(DeviceObject)->State == DeviceNodeAwaitingQueuedRemoval);
/* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */
PiIrpSendRemoveCheckVpb(DeviceObject, IRP_MN_SURPRISE_REMOVAL);
}
@@ -2200,6 +1807,7 @@ IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode, BOOLEAN
Force)
{
NextDeviceNode = ChildDeviceNode->Sibling;
KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
+ PiSetDevNodeState(ChildDeviceNode, DeviceNodeAwaitingQueuedRemoval);
Status = IopPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject,
Force);
if (!NT_SUCCESS(Status))
@@ -2344,65 +1952,35 @@ IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject, BOOLEAN
Force)
}
static
-VOID
-IopHandleDeviceRemoval(
- IN PDEVICE_NODE DeviceNode,
- IN PDEVICE_RELATIONS DeviceRelations)
+NTSTATUS
+IopRemoveDevice(PDEVICE_NODE DeviceNode)
{
- PDEVICE_NODE Child = DeviceNode->Child, NextChild;
- ULONG i;
- BOOLEAN Found;
-
- if (DeviceNode == IopRootDeviceNode)
- return;
-
- while (Child != NULL)
- {
- NextChild = Child->Sibling;
- Found = FALSE;
-
- for (i = 0; DeviceRelations && i < DeviceRelations->Count; i++)
- {
- if (IopGetDeviceNode(DeviceRelations->Objects[i]) == Child)
- {
- Found = TRUE;
- break;
- }
- }
+ NTSTATUS Status;
- if (!Found && !(Child->Flags & DNF_WILL_BE_REMOVED))
- {
- /* Send removal IRPs to all of its children */
- IopPrepareDeviceForRemoval(Child->PhysicalDeviceObject, TRUE);
+ // This function removes the device subtree, with the root in DeviceNode
+ // atm everyting is in fact done inside this function, which is completely wrong.
+ // The right implementation should have a separate removal worker thread and
+ // properly do device node state transitions
- /* Send the surprise removal IRP */
- IopSendSurpriseRemoval(Child->PhysicalDeviceObject);
+ DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath);
- /* Tell the user-mode PnP manager that a device was removed */
- IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
- &Child->InstancePath);
+ BOOLEAN surpriseRemoval = (_Bool)(DeviceNode->Flags & DNF_DEVICE_GONE);
- /* Send the remove device IRP */
- IopSendRemoveDevice(Child->PhysicalDeviceObject);
- }
+ Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject,
surpriseRemoval);
- Child = NextChild;
+ if (surpriseRemoval)
+ {
+ IopSendSurpriseRemoval(DeviceNode->PhysicalDeviceObject);
+ IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
&DeviceNode->InstancePath);
}
-}
-NTSTATUS
-IopRemoveDevice(PDEVICE_NODE DeviceNode)
-{
- NTSTATUS Status;
-
- DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath);
-
- Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject, FALSE);
if (NT_SUCCESS(Status))
{
IopSendRemoveDevice(DeviceNode->PhysicalDeviceObject);
- IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL,
- &DeviceNode->InstancePath);
+ if (surpriseRemoval)
+ {
+ IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL,
&DeviceNode->InstancePath);
+ }
return STATUS_SUCCESS;
}
@@ -2417,16 +1995,10 @@ NTAPI
IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject)
{
PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject);
- IO_STACK_LOCATION Stack;
- ULONG_PTR PnPFlags;
+ PNP_DEVICE_STATE PnPFlags;
NTSTATUS Status;
- IO_STATUS_BLOCK IoStatusBlock;
-
- RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
- Stack.MajorFunction = IRP_MJ_PNP;
- Stack.MinorFunction = IRP_MN_QUERY_PNP_DEVICE_STATE;
- Status = IopSynchronousCall(PhysicalDeviceObject, &Stack,
(PVOID*)&PnPFlags);
+ Status = PiIrpQueryPnPDeviceState(DeviceNode, &PnPFlags);
if (!NT_SUCCESS(Status))
{
if (Status != STATUS_NOT_SUPPORTED)
@@ -2450,20 +2022,16 @@ IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject)
((PnPFlags & PNP_DEVICE_FAILED) && !(PnPFlags &
PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)))
{
/* Flag it if it's failed */
- if (PnPFlags & PNP_DEVICE_FAILED) DeviceNode->Problem =
CM_PROB_FAILED_POST_START;
-
- /* Send removal IRPs to all of its children */
- IopPrepareDeviceForRemoval(PhysicalDeviceObject, TRUE);
-
- /* Send surprise removal */
- IopSendSurpriseRemoval(PhysicalDeviceObject);
-
- /* Tell the user-mode PnP manager that a device was removed */
- IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
- &DeviceNode->InstancePath);
+ if (PnPFlags & PNP_DEVICE_FAILED)
+ {
+ PiSetDevNodeProblem(DeviceNode, CM_PROB_FAILED_POST_START);
+ }
- IopSendRemoveDevice(PhysicalDeviceObject);
+ DeviceNode->Flags |= DNF_DEVICE_GONE;
+ PiSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedRemoval);
}
+ // it doesn't work anyway. A real resource rebalancing should be implemented
+#if 0
else if ((PnPFlags & PNP_DEVICE_FAILED) && (PnPFlags &
PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED))
{
/* Stop for resource rebalance */
@@ -2526,95 +2094,47 @@ IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject)
IopRemoveDevice(DeviceNode);
}
}
-}
-
-/*
- * IopInitializePnpServices
- *
- * Initialize services for discovered children
- *
- * Parameters
- * DeviceNode
- * Top device node to start initializing services.
- *
- * Return Value
- * Status
- */
-NTSTATUS
-IopInitializePnpServices(IN PDEVICE_NODE DeviceNode)
-{
- DEVICETREE_TRAVERSE_CONTEXT Context;
-
- DPRINT("IopInitializePnpServices(%p)\n", DeviceNode);
-
- IopInitDeviceTreeTraverseContext(
- &Context,
- DeviceNode,
- IopActionInitChildServices,
- DeviceNode);
-
- return IopTraverseDeviceTree(&Context);
+#endif
}
static
NTSTATUS
-PipEnumerateDevice(
+PiEnumerateDevice(
_In_ PDEVICE_NODE DeviceNode)
{
- DEVICETREE_TRAVERSE_CONTEXT Context;
- PDEVICE_RELATIONS DeviceRelations;
PDEVICE_OBJECT ChildDeviceObject;
- IO_STATUS_BLOCK IoStatusBlock;
PDEVICE_NODE ChildDeviceNode;
- IO_STACK_LOCATION Stack;
- NTSTATUS Status;
ULONG i;
- if (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY)
- {
- DeviceNode->Flags &= ~DNF_NEED_ENUMERATION_ONLY;
+ // bus relations are already obtained for this device node
- DPRINT("Sending GUID_DEVICE_ARRIVAL %wZ\n",
&DeviceNode->InstancePath);
- IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
- &DeviceNode->InstancePath);
- }
-
- DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
-
- Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
-
- Status = IopInitiatePnpIrp(
- DeviceNode->PhysicalDeviceObject,
- &IoStatusBlock,
- IRP_MN_QUERY_DEVICE_RELATIONS,
- &Stack);
- if (!NT_SUCCESS(Status))
+ if (!NT_SUCCESS(DeviceNode->CompletionStatus))
{
- DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
- return Status;
+ DPRINT("QDR request failed for %wZ, status %x\n",
+ &DeviceNode->InstancePath, DeviceNode->CompletionStatus);
+ // treat as if there are no child objects
}
- DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
+ PDEVICE_RELATIONS DeviceRelations = DeviceNode->OverUsed1.PendingDeviceRelations;
+ DeviceNode->OverUsed1.PendingDeviceRelations = NULL;
- /*
- * Send removal IRPs for devices that have disappeared
- * NOTE: This code handles the case where no relations are specified
- */
- IopHandleDeviceRemoval(DeviceNode, DeviceRelations);
-
- /* Now we bail if nothing was returned */
+ // it's acceptable not to have PDOs
if (!DeviceRelations)
{
- /* We're all done */
+ PiSetDevNodeState(DeviceNode, DeviceNodeStarted);
DPRINT("No PDOs\n");
return STATUS_SUCCESS;
}
- DPRINT("Got %u PDOs\n", DeviceRelations->Count);
+ // mark children nodes as non-present (those not returned in DR request will be
removed)
+ for (PDEVICE_NODE child = DeviceNode->Child; child != NULL; child =
child->Sibling)
+ {
+ child->Flags &= ~DNF_ENUMERATED;
+ }
- /*
- * Create device nodes for all discovered devices
- */
+ DPRINT("PiEnumerateDevice: enumerating %u children\n",
DeviceRelations->Count);
+
+ // create device nodes for all new children and set DNF_ENUMERATED back for old ones
for (i = 0; i < DeviceRelations->Count; i++)
{
ChildDeviceObject = DeviceRelations->Objects[i];
@@ -2638,7 +2158,7 @@ PipEnumerateDevice(
else
{
/* Ignore this DO */
- DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping
PDO %u\n", Status, i);
+ DPRINT1("PipAllocateDeviceNode() failed. Skipping PDO %u\n",
i);
ObDereferenceObject(ChildDeviceObject);
}
}
@@ -2651,49 +2171,18 @@ PipEnumerateDevice(
}
ExFreePool(DeviceRelations);
- /*
- * Retrieve information about all discovered children from the bus driver
- */
- IopInitDeviceTreeTraverseContext(
- &Context,
- DeviceNode,
- IopActionInterrogateDeviceStack,
- DeviceNode);
-
- Status = IopTraverseDeviceTree(&Context);
- if (!NT_SUCCESS(Status))
- {
- DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n",
Status);
- return Status;
- }
-
- /*
- * Retrieve configuration from the registry for discovered children
- */
- IopInitDeviceTreeTraverseContext(
- &Context,
- DeviceNode,
- IopActionConfigureChildServices,
- DeviceNode);
-
- Status = IopTraverseDeviceTree(&Context);
- if (!NT_SUCCESS(Status))
+ // time to remove non-reported devices
+ for (PDEVICE_NODE child = DeviceNode->Child; child != NULL; child =
child->Sibling)
{
- DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n",
Status);
- return Status;
- }
-
- /*
- * Initialize services for discovered children.
- */
- Status = IopInitializePnpServices(DeviceNode);
- if (!NT_SUCCESS(Status))
- {
- DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n",
Status);
- return Status;
+ if (!(child->Flags & (DNF_ENUMERATED|DNF_DEVICE_GONE)))
+ {
+ // this flag indicates that this is a surprise removal
+ child->Flags |= DNF_DEVICE_GONE;
+ PiSetDevNodeState(child, DeviceNodeAwaitingQueuedRemoval);
+ }
}
- DPRINT("IopEnumerateDevice() finished\n");
+ PiSetDevNodeState(DeviceNode, DeviceNodeStarted);
return STATUS_SUCCESS;
}
@@ -2787,7 +2276,7 @@ IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject)
}
else
{
- DeviceNode->Flags |= DNF_DISABLED;
+ // DeviceNode->Flags |= DNF_DISABLED;
}
IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT,
@@ -2801,54 +2290,180 @@ cleanup:
}
static
-NTSTATUS
-PipResetDevice(
- _In_ PDEVICE_NODE DeviceNode)
+VOID
+PiDevNodeStateMachine(
+ _In_ PDEVICE_NODE RootNode)
{
- NTSTATUS Status = STATUS_SUCCESS;
-
- ASSERT(DeviceNode->Flags & DNF_ENUMERATED);
- ASSERT(DeviceNode->Flags & DNF_PROCESSED);
+ NTSTATUS status;
+ BOOLEAN doProcessAgain;
+ PDEVICE_NODE currentNode = RootNode;
+ PDEVICE_OBJECT referencedObject;
- /* Check if there's already a driver loaded for this device */
- if (DeviceNode->Flags & DNF_ADDED)
+ do
{
- /* FIXME: our drivers do not handle device removal well enough */
-#if 0
- /* Remove the device node */
- Status = IopRemoveDevice(DeviceNode);
- if (NT_SUCCESS(Status))
+ doProcessAgain = FALSE;
+
+ // The device can be removed during processing, but we still need its Parent and
Sibling
+ // links to continue the tree traversal. So keep the link till the and of a
cycle
+ referencedObject = currentNode->PhysicalDeviceObject;
+ ObReferenceObject(referencedObject);
+
+ // Devices with problems are skipped (unless they are not being removed)
+ if (currentNode->Flags & DNF_HAS_PROBLEM &&
+ currentNode->State != DeviceNodeAwaitingQueuedRemoval)
{
- /* Invalidate device relations for the parent to reenumerate the device */
- DPRINT1("A new driver will be loaded for '%wZ' (FDO above
removed)\n", &DeviceNode->InstancePath);
- Status =
IoInvalidateDeviceRelations(DeviceNode->Parent->PhysicalDeviceObject,
BusRelations);
+ goto skipEnum;
}
- else
-#endif
+
+ switch (currentNode->State)
{
- /* A driver has already been loaded for this device */
- DPRINT("A reboot is required for the current driver for '%wZ' to
be replaced\n", &DeviceNode->InstancePath);
- DeviceNode->Problem = CM_PROB_NEED_RESTART;
- }
- }
- else
- {
- /* FIXME: What if the device really is disabled? */
- DeviceNode->Flags &= ~DNF_DISABLED;
- DeviceNode->Problem = 0;
+ case DeviceNodeUnspecified: // this state is not used
+ break;
+ case DeviceNodeUninitialized:
+ DPRINT("DeviceNodeUninitialized %wZ\n",
¤tNode->InstancePath);
+ status = PiInitializeDevNode(currentNode);
+ doProcessAgain = NT_SUCCESS(status);
+ break;
+ case DeviceNodeInitialized:
+ DPRINT("DeviceNodeInitialized %wZ\n",
¤tNode->InstancePath);
+ status = PiCallDriverAddDevice(currentNode, PnPBootDriversInitialized);
+ doProcessAgain = NT_SUCCESS(status);
+ break;
+ case DeviceNodeDriversAdded:
+ DPRINT("DeviceNodeDriversAdded %wZ\n",
¤tNode->InstancePath);
+ status = IopAssignDeviceResources(currentNode);
+ doProcessAgain = NT_SUCCESS(status);
+ break;
+ case DeviceNodeResourcesAssigned:
+ DPRINT("DeviceNodeResourcesAssigned %wZ\n",
¤tNode->InstancePath);
+ // send IRP_MN_START_DEVICE
+ PiIrpStartDevice(currentNode);
+
+ // skip DeviceNodeStartPending, it is probably used for an async
IRP_MN_START_DEVICE
+ PiSetDevNodeState(currentNode, DeviceNodeStartCompletion);
+ doProcessAgain = TRUE;
+ break;
+ case DeviceNodeStartPending: // skipped on XP/2003
+ break;
+ case DeviceNodeStartCompletion:
+ DPRINT("DeviceNodeStartCompletion %wZ\n",
¤tNode->InstancePath);
+ status = currentNode->CompletionStatus;
+ doProcessAgain = TRUE;
+ if (!NT_SUCCESS(status))
+ {
+ UINT32 problem = (status == STATUS_PNP_REBOOT_REQUIRED)
+ ? CM_PROB_NEED_RESTART
+ : CM_PROB_FAILED_START;
- /* Load service data from the registry */
- Status = IopActionConfigureChildServices(DeviceNode, DeviceNode->Parent);
+ PiSetDevNodeProblem(currentNode, problem);
+ PiSetDevNodeState(currentNode, DeviceNodeAwaitingQueuedRemoval);
+ }
+ else
+ {
+ // TODO: IopDoDeferredSetInterfaceState and
IopAllocateLegacyBootResources
+ // are called here too
- if (NT_SUCCESS(Status))
- {
- /* Start the service and begin PnP initialization of the device again */
- DPRINT("A new driver will be loaded for '%wZ' (no FDO
above)\n", &DeviceNode->InstancePath);
- Status = IopActionInitChildServices(DeviceNode, DeviceNode->Parent);
+ PiSetDevNodeState(currentNode, DeviceNodeStartPostWork);
+ }
+ break;
+ case DeviceNodeStartPostWork:
+ DPRINT("DeviceNodeStartPostWork %wZ\n",
¤tNode->InstancePath);
+ status = PiStartDeviceFinal(currentNode);
+ doProcessAgain = TRUE;
+ break;
+ case DeviceNodeStarted:
+ if (currentNode->Flags & DNF_REENUMERATE)
+ {
+ DPRINT("DeviceNodeStarted REENUMERATE %wZ\n",
¤tNode->InstancePath);
+ currentNode->Flags &= ~DNF_REENUMERATE;
+ status = PiIrpQueryDeviceRelations(currentNode, BusRelations);
+
+ // again, skip DeviceNodeEnumeratePending as with the starting
sequence
+ PiSetDevNodeState(currentNode, DeviceNodeEnumerateCompletion);
+ doProcessAgain = TRUE;
+ }
+ break;
+ case DeviceNodeQueryStopped:
+ // we're here after sending IRP_MN_QUERY_STOP_DEVICE
+ status = currentNode->CompletionStatus;
+ if (NT_SUCCESS(status))
+ {
+ PiSetDevNodeState(currentNode, DeviceNodeStopped);
+ }
+ else
+ {
+ PiIrpCancelStopDevice(currentNode);
+ PiSetDevNodeState(currentNode, DeviceNodeStarted);
+ }
+ break;
+ case DeviceNodeStopped:
+ // TODO: do resource rebalance (not implemented)
+ ASSERT(FALSE);
+ break;
+ case DeviceNodeRestartCompletion:
+ break;
+ case DeviceNodeEnumeratePending: // skipped on XP/2003
+ break;
+ case DeviceNodeEnumerateCompletion:
+ DPRINT("DeviceNodeEnumerateCompletion %wZ\n",
¤tNode->InstancePath);
+ status = PiEnumerateDevice(currentNode);
+ doProcessAgain = TRUE;
+ break;
+ case DeviceNodeAwaitingQueuedDeletion:
+ break;
+ case DeviceNodeAwaitingQueuedRemoval:
+ DPRINT("DeviceNodeAwaitingQueuedRemoval %wZ\n",
¤tNode->InstancePath);
+ status = IopRemoveDevice(currentNode);
+ break;
+ case DeviceNodeQueryRemoved:
+ break;
+ case DeviceNodeRemovePendingCloses:
+ break;
+ case DeviceNodeRemoved:
+ break;
+ case DeviceNodeDeletePendingCloses:
+ break;
+ case DeviceNodeDeleted:
+ break;
+ default:
+ break;
}
- }
- return Status;
+skipEnum:
+ if (!doProcessAgain)
+ {
+ KIRQL OldIrql;
+ KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
+ /* If we have a child, simply go down the tree */
+ if (currentNode->State != DeviceNodeRemoved &&
currentNode->Child != NULL)
+ {
+ ASSERT(currentNode->Child->Parent == currentNode);
+ currentNode = currentNode->Child;
+ }
+ else
+ {
+ while (currentNode != RootNode)
+ {
+ /* All children processed -- go sideways */
+ if (currentNode->Sibling != NULL)
+ {
+ ASSERT(currentNode->Sibling->Parent ==
currentNode->Parent);
+ currentNode = currentNode->Sibling;
+ break;
+ }
+ else
+ {
+ /* We're the last sibling -- go back up */
+ ASSERT(currentNode->Parent->LastChild == currentNode);
+ currentNode = currentNode->Parent;
+ }
+ /* We already visited the parent and all its children, so keep
looking */
+ }
+ }
+ KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
+ }
+ ObDereferenceObject(referencedObject);
+ } while (doProcessAgain || currentNode != RootNode);
}
#ifdef DBG
@@ -2904,11 +2519,14 @@ PipDeviceActionWorker(
{
case PiActionEnumRootDevices:
case PiActionEnumDeviceTree:
- status = PipEnumerateDevice(deviceNode);
+ deviceNode->Flags |= DNF_REENUMERATE;
+ PiDevNodeStateMachine(deviceNode);
break;
case PiActionResetDevice:
- status = PipResetDevice(deviceNode);
+ // TODO: the operation is a no-op for everything except removed nodes
+ // for removed nodes, it returns them back to DeviceNodeUninitialized
+ status = STATUS_SUCCESS;
break;
default:
diff --git a/ntoskrnl/io/pnpmgr/devnode.c b/ntoskrnl/io/pnpmgr/devnode.c
index 090419f18a9..f59a3ddaf7a 100644
--- a/ntoskrnl/io/pnpmgr/devnode.c
+++ b/ntoskrnl/io/pnpmgr/devnode.c
@@ -70,6 +70,8 @@ PipAllocateDeviceNode(
PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
}
+ DPRINT("Allocated devnode 0x%p\n", DeviceNode);
+
/* Return the node */
return DeviceNode;
}
@@ -98,6 +100,32 @@ PiInsertDevNode(
}
KeReleaseSpinLock(&IopDeviceTreeLock, oldIrql);
DeviceNode->Level = ParentNode->Level + 1;
+
+ DPRINT("Inserted devnode 0x%p to parent 0x%p\n", DeviceNode, ParentNode);
+}
+
+PNP_DEVNODE_STATE
+PiSetDevNodeState(
+ _In_ PDEVICE_NODE DeviceNode,
+ _In_ PNP_DEVNODE_STATE NewState)
+{
+ KIRQL oldIrql;
+
+ KeAcquireSpinLock(&IopDeviceTreeLock, &oldIrql);
+
+ PNP_DEVNODE_STATE prevState = DeviceNode->State;
+ if (prevState != NewState)
+ {
+ DeviceNode->State = NewState;
+ DeviceNode->PreviousState = prevState;
+ DeviceNode->StateHistory[DeviceNode->StateHistoryEntry++] = prevState;
+ DeviceNode->StateHistoryEntry %= DEVNODE_HISTORY_SIZE;
+ }
+
+ KeReleaseSpinLock(&IopDeviceTreeLock, oldIrql);
+
+ DPRINT("%wZ Changed state 0x%x => 0x%x\n",
&DeviceNode->InstancePath, prevState, NewState);
+ return prevState;
}
VOID
@@ -302,9 +330,11 @@ IopFreeDeviceNode(
KIRQL OldIrql;
PDEVICE_NODE PrevSibling = NULL;
- /* All children must be deleted before a parent is deleted */
- ASSERT(!DeviceNode->Child);
ASSERT(DeviceNode->PhysicalDeviceObject);
+ /* All children must be deleted before a parent is deleted */
+ ASSERT(DeviceNode->Child == NULL);
+ /* This is the only state where we are allowed to remove the node */
+ ASSERT(DeviceNode->State == DeviceNodeRemoved);
/* No notifications should be registered for this device */
ASSERT(IsListEmpty(&DeviceNode->TargetDeviceNotify));
diff --git a/ntoskrnl/io/pnpmgr/plugplay.c b/ntoskrnl/io/pnpmgr/plugplay.c
index 4f930e9bc55..66c1da7fde1 100644
--- a/ntoskrnl/io/pnpmgr/plugplay.c
+++ b/ntoskrnl/io/pnpmgr/plugplay.c
@@ -689,37 +689,54 @@ IopGetRelatedDevice(PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA
RelatedDeviceData)
return Status;
}
+static
+BOOLEAN
+PiIsDevNodeStarted(
+ _In_ PDEVICE_NODE DeviceNode)
+{
+ return (DeviceNode->State == DeviceNodeStartPending ||
+ DeviceNode->State == DeviceNodeStartCompletion ||
+ DeviceNode->State == DeviceNodeStartPostWork ||
+ DeviceNode->State == DeviceNodeStarted ||
+ DeviceNode->State == DeviceNodeQueryStopped ||
+ DeviceNode->State == DeviceNodeEnumeratePending ||
+ DeviceNode->State == DeviceNodeEnumerateCompletion ||
+ DeviceNode->State == DeviceNodeStopped ||
+ DeviceNode->State == DeviceNodeRestartCompletion);
+}
+
static ULONG
IopGetDeviceNodeStatus(PDEVICE_NODE DeviceNode)
{
- ULONG Output = 0;
+ ULONG Output = DN_NT_ENUMERATOR | DN_NT_DRIVER;
if (DeviceNode->Parent == IopRootDeviceNode)
Output |= DN_ROOT_ENUMERATED;
- if (DeviceNode->Flags & DNF_ADDED)
+ // FIXME: review for deleted and removed states
+ if (DeviceNode->State >= DeviceNodeDriversAdded)
Output |= DN_DRIVER_LOADED;
- /* FIXME: DN_ENUM_LOADED */
-
- if (DeviceNode->Flags & DNF_STARTED)
+ if (PiIsDevNodeStarted(DeviceNode))
Output |= DN_STARTED;
- /* FIXME: Manual */
+ if (DeviceNode->UserFlags & DNUF_WILL_BE_REMOVED)
+ Output |= DN_WILL_BE_REMOVED;
- if (!(DeviceNode->Flags & DNF_PROCESSED))
- Output |= DN_NEED_TO_ENUM;
-
- /* DN_NOT_FIRST_TIME is 9x only */
+ if (DeviceNode->Flags & DNF_HAS_PROBLEM)
+ Output |= DN_HAS_PROBLEM;
- /* FIXME: DN_HARDWARE_ENUM */
+ if (DeviceNode->Flags & DNF_HAS_PRIVATE_PROBLEM)
+ Output |= DN_PRIVATE_PROBLEM;
- /* DN_LIAR and DN_HAS_MARK are 9x only */
+ if (DeviceNode->Flags & DNF_DRIVER_BLOCKED)
+ Output |= DN_DRIVER_BLOCKED;
- if (DeviceNode->Problem != 0)
- Output |= DN_HAS_PROBLEM;
+ if (DeviceNode->Flags & DNF_CHILD_WITH_INVALID_ID)
+ Output |= DN_CHILD_WITH_INVALID_ID;
- /* FIXME: DN_FILTERED */
+ if (DeviceNode->Flags & DNF_HAS_PRIVATE_PROBLEM)
+ Output |= DN_PRIVATE_PROBLEM;
if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
Output |= DN_LEGACY_DRIVER;
@@ -730,10 +747,6 @@ IopGetDeviceNodeStatus(PDEVICE_NODE DeviceNode)
if (!(DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE))
Output |= DN_DISABLEABLE;
- /* FIXME: Implement the rest */
-
- Output |= DN_NT_ENUMERATOR | DN_NT_DRIVER;
-
return Output;
}
diff --git a/ntoskrnl/io/pnpmgr/pnpinit.c b/ntoskrnl/io/pnpmgr/pnpinit.c
index 0667fd72785..b189ac8280a 100644
--- a/ntoskrnl/io/pnpmgr/pnpinit.c
+++ b/ntoskrnl/io/pnpmgr/pnpinit.c
@@ -431,9 +431,8 @@ IopInitializePlugPlayServices(VOID)
IopRootDeviceNode = PipAllocateDeviceNode(Pdo);
/* Set flags */
- IopRootDeviceNode->Flags |= DNF_STARTED + DNF_PROCESSED + DNF_ENUMERATED +
- DNF_MADEUP + DNF_NO_RESOURCE_REQUIRED +
- DNF_ADDED;
+ IopRootDeviceNode->Flags |= DNF_MADEUP | DNF_ENUMERATED |
+ DNF_IDS_QUERIED | DNF_NO_RESOURCE_REQUIRED;
/* Create instance path */
RtlCreateUnicodeString(&IopRootDeviceNode->InstancePath,
@@ -443,19 +442,20 @@ IopInitializePlugPlayServices(VOID)
IopRootDriverObject->DriverExtension->AddDevice(IopRootDriverObject,
IopRootDeviceNode->PhysicalDeviceObject);
+ PiSetDevNodeState(IopRootDeviceNode, DeviceNodeStarted);
+
/* Initialize PnP-Event notification support */
Status = IopInitPlugPlayEvents();
if (!NT_SUCCESS(Status)) return Status;
- /* Report the device to the user-mode pnp manager */
- IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
- &IopRootDeviceNode->InstancePath);
-
/* Initialize the Bus Type GUID List */
PnpBusTypeGuidList = ExAllocatePool(PagedPool, sizeof(IO_BUS_TYPE_GUID_LIST));
RtlZeroMemory(PnpBusTypeGuidList, sizeof(IO_BUS_TYPE_GUID_LIST));
ExInitializeFastMutex(&PnpBusTypeGuidList->Lock);
+ /* Initialize PnP root relations (this is a syncronous operation) */
+ PiQueueDeviceAction(IopRootDeviceNode->PhysicalDeviceObject,
PiActionEnumRootDevices, NULL, NULL);
+
/* Launch the firmware mapper */
Status = IopUpdateRootKey();
if (!NT_SUCCESS(Status)) return Status;
diff --git a/ntoskrnl/io/pnpmgr/pnpirp.c b/ntoskrnl/io/pnpmgr/pnpirp.c
new file mode 100644
index 00000000000..03fc0d1aafc
--- /dev/null
+++ b/ntoskrnl/io/pnpmgr/pnpirp.c
@@ -0,0 +1,225 @@
+/*
+ * PROJECT: ReactOS Kernel
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Shortcuts for sending different IRP_MJ_PNP requests
+ * COPYRIGHT: Copyright 2010 Sir Richard <sir_richard(a)svn.reactos.org>
+ * Copyright 2020 Victor Perevertkin <victor.perevertkin(a)reactos.org>
+ */
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+NTSTATUS
+IopSynchronousCall(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIO_STACK_LOCATION IoStackLocation,
+ _Out_ PVOID *Information)
+{
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpStack;
+ IO_STATUS_BLOCK IoStatusBlock;
+ KEVENT Event;
+ NTSTATUS Status;
+ PDEVICE_OBJECT TopDeviceObject;
+ PAGED_CODE();
+
+ /* Call the top of the device stack */
+ TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
+
+ /* Allocate an IRP */
+ Irp = IoAllocateIrp(TopDeviceObject->StackSize, FALSE);
+ if (!Irp)
+ {
+ ObDereferenceObject(TopDeviceObject);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Initialize to failure */
+ Irp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
+ Irp->IoStatus.Information = IoStatusBlock.Information = 0;
+
+ /* Special case for IRP_MN_FILTER_RESOURCE_REQUIREMENTS */
+ if ((IoStackLocation->MajorFunction == IRP_MJ_PNP) &&
+ (IoStackLocation->MinorFunction == IRP_MN_FILTER_RESOURCE_REQUIREMENTS))
+ {
+ /* Copy the resource requirements list into the IOSB */
+ Irp->IoStatus.Information =
+ IoStatusBlock.Information =
(ULONG_PTR)IoStackLocation->Parameters.FilterResourceRequirements.IoResourceRequirementList;
+ }
+
+ /* Initialize the event */
+ KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
+
+ /* Set them up */
+ Irp->UserIosb = &IoStatusBlock;
+ Irp->UserEvent = &Event;
+
+ /* Queue the IRP */
+ Irp->Tail.Overlay.Thread = PsGetCurrentThread();
+ IoQueueThreadIrp(Irp);
+
+ /* Copy-in the stack */
+ IrpStack = IoGetNextIrpStackLocation(Irp);
+ *IrpStack = *IoStackLocation;
+
+ /* Call the driver */
+ Status = IoCallDriver(TopDeviceObject, Irp);
+ /* Otherwise we may get stuck here or have IoStatusBlock not populated */
+ ASSERT(!KeAreAllApcsDisabled());
+ if (Status == STATUS_PENDING)
+ {
+ /* Wait for it */
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ Status = IoStatusBlock.Status;
+ }
+
+ /* Remove the reference */
+ ObDereferenceObject(TopDeviceObject);
+
+ /* Return the information */
+ *Information = (PVOID)IoStatusBlock.Information;
+ return Status;
+}
+
+// IRP_MN_START_DEVICE (0x00)
+NTSTATUS
+PiIrpStartDevice(
+ _In_ PDEVICE_NODE DeviceNode)
+{
+ PAGED_CODE();
+
+ ASSERT(DeviceNode);
+ ASSERT(DeviceNode->State == DeviceNodeResourcesAssigned);
+
+ PVOID info;
+ IO_STACK_LOCATION stack = {
+ .MajorFunction = IRP_MJ_PNP,
+ .MinorFunction = IRP_MN_START_DEVICE,
+ .Parameters.StartDevice.AllocatedResources = DeviceNode->ResourceList,
+ .Parameters.StartDevice.AllocatedResourcesTranslated =
DeviceNode->ResourceListTranslated
+ };
+
+ // Vista+ does an asynchronous call
+ NTSTATUS status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack,
&info);
+ DeviceNode->CompletionStatus = status;
+ return status;
+}
+
+// IRP_MN_STOP_DEVICE (0x04)
+NTSTATUS
+PiIrpStopDevice(
+ _In_ PDEVICE_NODE DeviceNode)
+{
+ PAGED_CODE();
+
+ ASSERT(DeviceNode);
+ ASSERT(DeviceNode->State == DeviceNodeQueryStopped);
+
+ PVOID info;
+ IO_STACK_LOCATION stack = {
+ .MajorFunction = IRP_MJ_PNP,
+ .MinorFunction = IRP_MN_STOP_DEVICE
+ };
+
+ // Drivers should never fail a IRP_MN_STOP_DEVICE request
+ NTSTATUS status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack,
&info);
+ ASSERT(NT_SUCCESS(status));
+ return status;
+}
+
+// IRP_MN_QUERY_STOP_DEVICE (0x05)
+NTSTATUS
+PiIrpQueryStopDevice(
+ _In_ PDEVICE_NODE DeviceNode)
+{
+ PAGED_CODE();
+
+ ASSERT(DeviceNode);
+ ASSERT(DeviceNode->State == DeviceNodeStarted);
+
+ PVOID info;
+ IO_STACK_LOCATION stack = {
+ .MajorFunction = IRP_MJ_PNP,
+ .MinorFunction = IRP_MN_QUERY_STOP_DEVICE
+ };
+
+ NTSTATUS status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack,
&info);
+ DeviceNode->CompletionStatus = status;
+ return status;
+}
+
+// IRP_MN_CANCEL_STOP_DEVICE (0x06)
+NTSTATUS
+PiIrpCancelStopDevice(
+ _In_ PDEVICE_NODE DeviceNode)
+{
+ PAGED_CODE();
+
+ ASSERT(DeviceNode);
+ ASSERT(DeviceNode->State == DeviceNodeQueryStopped);
+
+ PVOID info;
+ IO_STACK_LOCATION stack = {
+ .MajorFunction = IRP_MJ_PNP,
+ .MinorFunction = IRP_MN_CANCEL_STOP_DEVICE
+ };
+
+ // in fact we don't care which status is returned here
+ NTSTATUS status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack,
&info);
+ ASSERT(NT_SUCCESS(status));
+ return status;
+}
+
+// IRP_MN_QUERY_DEVICE_RELATIONS (0x07)
+NTSTATUS
+PiIrpQueryDeviceRelations(
+ _In_ PDEVICE_NODE DeviceNode,
+ _In_ DEVICE_RELATION_TYPE Type)
+{
+ PAGED_CODE();
+
+ ASSERT(DeviceNode);
+ ASSERT(DeviceNode->State == DeviceNodeStarted);
+
+ IO_STACK_LOCATION stack = {
+ .MajorFunction = IRP_MJ_PNP,
+ .MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS,
+ .Parameters.QueryDeviceRelations.Type = Type
+ };
+
+ // Vista+ does an asynchronous call
+ NTSTATUS status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject,
+ &stack,
+
(PVOID)&DeviceNode->OverUsed1.PendingDeviceRelations);
+ DeviceNode->CompletionStatus = status;
+ return status;
+}
+
+// IRP_MN_QUERY_PNP_DEVICE_STATE (0x14)
+NTSTATUS
+PiIrpQueryPnPDeviceState(
+ _In_ PDEVICE_NODE DeviceNode,
+ _Out_ PPNP_DEVICE_STATE DeviceState)
+{
+ PAGED_CODE();
+
+ ASSERT(DeviceNode);
+ ASSERT(DeviceNode->State == DeviceNodeStartPostWork ||
+ DeviceNode->State == DeviceNodeStarted);
+
+ ULONG_PTR longState;
+ IO_STACK_LOCATION stack = {
+ .MajorFunction = IRP_MJ_PNP,
+ .MinorFunction = IRP_MN_QUERY_PNP_DEVICE_STATE
+ };
+
+ NTSTATUS status;
+ status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack,
(PVOID)&longState);
+ if (NT_SUCCESS(status))
+ {
+ *DeviceState = longState;
+ }
+
+ return status;
+}
diff --git a/ntoskrnl/io/pnpmgr/pnpmgr.c b/ntoskrnl/io/pnpmgr/pnpmgr.c
index 37290335cfd..d4f5cd97a19 100644
--- a/ntoskrnl/io/pnpmgr/pnpmgr.c
+++ b/ntoskrnl/io/pnpmgr/pnpmgr.c
@@ -475,82 +475,6 @@ Quickie:
return FoundIndex;
}
-NTSTATUS
-NTAPI
-IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject,
- IN PIO_STACK_LOCATION IoStackLocation,
- OUT PVOID *Information)
-{
- PIRP Irp;
- PIO_STACK_LOCATION IrpStack;
- IO_STATUS_BLOCK IoStatusBlock;
- KEVENT Event;
- NTSTATUS Status;
- PDEVICE_OBJECT TopDeviceObject;
- PAGED_CODE();
-
- /* Call the top of the device stack */
- TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
-
- /* Allocate an IRP */
- Irp = IoAllocateIrp(TopDeviceObject->StackSize, FALSE);
- if (!Irp)
- {
- ObDereferenceObject(TopDeviceObject);
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- /* Initialize to failure */
- Irp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
- Irp->IoStatus.Information = IoStatusBlock.Information = 0;
-
- /* Special case for IRP_MN_FILTER_RESOURCE_REQUIREMENTS */
- if ((IoStackLocation->MajorFunction == IRP_MJ_PNP) &&
- (IoStackLocation->MinorFunction == IRP_MN_FILTER_RESOURCE_REQUIREMENTS))
- {
- /* Copy the resource requirements list into the IOSB */
- Irp->IoStatus.Information =
- IoStatusBlock.Information =
(ULONG_PTR)IoStackLocation->Parameters.FilterResourceRequirements.IoResourceRequirementList;
- }
-
- /* Initialize the event */
- KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
-
- /* Set them up */
- Irp->UserIosb = &IoStatusBlock;
- Irp->UserEvent = &Event;
-
- /* Queue the IRP */
- Irp->Tail.Overlay.Thread = PsGetCurrentThread();
- IoQueueThreadIrp(Irp);
-
- /* Copy-in the stack */
- IrpStack = IoGetNextIrpStackLocation(Irp);
- *IrpStack = *IoStackLocation;
-
- /* Call the driver */
- Status = IoCallDriver(TopDeviceObject, Irp);
- /* Otherwise we may get stuck here or have IoStatusBlock not populated */
- ASSERT(!KeAreAllApcsDisabled());
- if (Status == STATUS_PENDING)
- {
- /* Wait for it */
- KeWaitForSingleObject(&Event,
- Executive,
- KernelMode,
- FALSE,
- NULL);
- Status = IoStatusBlock.Status;
- }
-
- /* Remove the reference */
- ObDereferenceObject(TopDeviceObject);
-
- /* Return the information */
- *Information = (PVOID)IoStatusBlock.Information;
- return Status;
-}
-
NTSTATUS
NTAPI
IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject,
diff --git a/ntoskrnl/io/pnpmgr/pnpreport.c b/ntoskrnl/io/pnpmgr/pnpreport.c
index 4c5e36cb147..8104a8f178b 100644
--- a/ntoskrnl/io/pnpmgr/pnpreport.c
+++ b/ntoskrnl/io/pnpmgr/pnpreport.c
@@ -28,10 +28,6 @@ NTSTATUS
IopSetDeviceInstanceData(HANDLE InstanceKey,
PDEVICE_NODE DeviceNode);
-NTSTATUS
-IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
- PVOID Context);
-
NTSTATUS
PpSetCustomTargetEvent(IN PDEVICE_OBJECT DeviceObject,
IN OUT PKEVENT SyncEvent OPTIONAL,
@@ -149,20 +145,20 @@ PpSetCustomTargetEvent(IN PDEVICE_OBJECT DeviceObject,
*/
NTSTATUS
NTAPI
-IoReportDetectedDevice(IN PDRIVER_OBJECT DriverObject,
- IN INTERFACE_TYPE LegacyBusType,
- IN ULONG BusNumber,
- IN ULONG SlotNumber,
- IN PCM_RESOURCE_LIST ResourceList,
- IN PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirements OPTIONAL,
- IN BOOLEAN ResourceAssigned,
- IN OUT PDEVICE_OBJECT *DeviceObject OPTIONAL)
+IoReportDetectedDevice(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ INTERFACE_TYPE LegacyBusType,
+ _In_ ULONG BusNumber,
+ _In_ ULONG SlotNumber,
+ _In_opt_ PCM_RESOURCE_LIST ResourceList,
+ _In_opt_ PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirements,
+ _In_ BOOLEAN ResourceAssigned,
+ _Inout_ PDEVICE_OBJECT *DeviceObject)
{
PDEVICE_NODE DeviceNode;
PDEVICE_OBJECT Pdo;
NTSTATUS Status;
HANDLE InstanceKey;
- ULONG RequiredLength;
UNICODE_STRING ValueName, ServiceLongName, ServiceName;
WCHAR HardwareId[256];
PWCHAR IfString;
@@ -223,6 +219,7 @@ IoReportDetectedDevice(IN PDRIVER_OBJECT DriverObject,
}
/* We use the caller's PDO if they supplied one */
+ UNICODE_STRING instancePath;
if (DeviceObject && *DeviceObject)
{
Pdo = *DeviceObject;
@@ -230,10 +227,7 @@ IoReportDetectedDevice(IN PDRIVER_OBJECT DriverObject,
else
{
/* Create the PDO */
- Status = PnpRootCreateDevice(&ServiceName,
- NULL,
- &Pdo,
- NULL);
+ Status = PnpRootCreateDevice(&ServiceName, NULL, &Pdo,
&instancePath);
if (!NT_SUCCESS(Status))
{
DPRINT("PnpRootCreateDevice() failed (Status 0x%08lx)\n", Status);
@@ -249,28 +243,7 @@ IoReportDetectedDevice(IN PDRIVER_OBJECT DriverObject,
return STATUS_INSUFFICIENT_RESOURCES;
}
- PiInsertDevNode(DeviceNode, IopRootDeviceNode);
-
- /* We're enumerated already */
- IopDeviceNodeSetFlag(DeviceNode, DNF_ENUMERATED);
-
- /* We don't call AddDevice for devices reported this way */
- IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
-
- /* We don't send IRP_MN_START_DEVICE */
- IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
-
- /* We need to get device IDs */
-#if 0
- IopDeviceNodeSetFlag(DeviceNode, DNF_NEED_QUERY_IDS);
-#endif
-
- /* This is a legacy driver for this device */
- IopDeviceNodeSetFlag(DeviceNode, DNF_LEGACY_DRIVER);
-
- /* Perform a manual configuration of our device */
- IopActionInterrogateDeviceStack(DeviceNode, DeviceNode->Parent);
- IopActionConfigureChildServices(DeviceNode, DeviceNode->Parent);
+ Status = RtlDuplicateUnicodeString(0, &instancePath,
&DeviceNode->InstancePath);
/* Open a handle to the instance path key */
Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath,
REG_OPTION_NON_VOLATILE, &InstanceKey);
@@ -321,30 +294,6 @@ IoReportDetectedDevice(IN PDRIVER_OBJECT DriverObject,
return Status;
}
- /* Add a hardware ID if the driver didn't report one */
- RtlInitUnicodeString(&ValueName, L"HardwareID");
- if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0,
&RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
- {
- /* Just use our most specific compatible ID */
- IdLength = 0;
- IdLength += swprintf(&HardwareId[IdLength],
- L"DETECTED%ls\\%wZ",
- IfString,
- &ServiceName);
- IdLength++;
-
- HardwareId[IdLength++] = UNICODE_NULL;
-
- /* Write the value to the registry */
- Status = ZwSetValueKey(InstanceKey, &ValueName, 0, REG_MULTI_SZ, HardwareId,
IdLength * sizeof(WCHAR));
- if (!NT_SUCCESS(Status))
- {
- DPRINT("Failed to write the hardware ID: 0x%x\n", Status);
- ZwClose(InstanceKey);
- return Status;
- }
- }
-
/* Assign the resources to the device node */
DeviceNode->BootResources = ResourceList;
DeviceNode->ResourceRequirements = ResourceRequirements;
@@ -380,13 +329,11 @@ IoReportDetectedDevice(IN PDRIVER_OBJECT DriverObject,
if (DeviceObject && *DeviceObject)
PnpRootRegisterDevice(*DeviceObject);
- /* Report the device's enumeration to umpnpmgr */
- IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
- &DeviceNode->InstancePath);
+ PiInsertDevNode(DeviceNode, IopRootDeviceNode);
+ DeviceNode->Flags |= DNF_MADEUP | DNF_ENUMERATED;
- /* Report the device's arrival to umpnpmgr */
- IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
- &DeviceNode->InstancePath);
+ // we still need to query IDs, send events and reenumerate this node
+ PiSetDevNodeState(DeviceNode, DeviceNodeStartPostWork);
DPRINT("Reported device: %S (%wZ)\n", HardwareId,
&DeviceNode->InstancePath);
diff --git a/ntoskrnl/io/pnpmgr/pnpres.c b/ntoskrnl/io/pnpmgr/pnpres.c
index 11e7b1b43bf..f8a47975c03 100644
--- a/ntoskrnl/io/pnpmgr/pnpres.c
+++ b/ntoskrnl/io/pnpmgr/pnpres.c
@@ -698,7 +698,7 @@ ByeBye:
// Hacked, because after fixing resource list parsing
// we actually detect resource conflicts
- return Silent ? Result : FALSE; // Result;
+ return Silent ? Result : FALSE; // Result;
}
static
@@ -1109,20 +1109,17 @@ IopAssignDeviceResources(
NTSTATUS Status;
ULONG ListSize;
- IopDeviceNodeSetFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
-
Status = IopFilterResourceRequirements(DeviceNode);
if (!NT_SUCCESS(Status))
goto ByeBye;
if (!DeviceNode->BootResources && !DeviceNode->ResourceRequirements)
{
- DeviceNode->Flags |= DNF_NO_RESOURCE_REQUIRED;
- DeviceNode->Flags &= ~DNF_ASSIGNING_RESOURCES;
-
/* No resource needed for this device */
DeviceNode->ResourceList = NULL;
DeviceNode->ResourceListTranslated = NULL;
+ PiSetDevNodeState(DeviceNode, DeviceNodeResourcesAssigned);
+ DeviceNode->Flags |= DNF_NO_RESOURCE_REQUIRED;
return STATUS_SUCCESS;
}
@@ -1191,9 +1188,7 @@ Finish:
if (!NT_SUCCESS(Status))
goto ByeBye;
- IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_ASSIGNED);
-
- IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
+ PiSetDevNodeState(DeviceNode, DeviceNodeResourcesAssigned);
return STATUS_SUCCESS;
@@ -1206,8 +1201,6 @@ ByeBye:
DeviceNode->ResourceListTranslated = NULL;
- IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
-
return Status;
}
diff --git a/ntoskrnl/ntos.cmake b/ntoskrnl/ntos.cmake
index 7b1c0f93cde..b815c62565a 100644
--- a/ntoskrnl/ntos.cmake
+++ b/ntoskrnl/ntos.cmake
@@ -157,6 +157,7 @@ list(APPEND SOURCE
${REACTOS_SOURCE_DIR}/ntoskrnl/io/pnpmgr/plugplay.c
${REACTOS_SOURCE_DIR}/ntoskrnl/io/pnpmgr/pnpdma.c
${REACTOS_SOURCE_DIR}/ntoskrnl/io/pnpmgr/pnpinit.c
+ ${REACTOS_SOURCE_DIR}/ntoskrnl/io/pnpmgr/pnpirp.c
${REACTOS_SOURCE_DIR}/ntoskrnl/io/pnpmgr/pnpmgr.c
${REACTOS_SOURCE_DIR}/ntoskrnl/io/pnpmgr/pnpnotify.c
${REACTOS_SOURCE_DIR}/ntoskrnl/io/pnpmgr/pnpreport.c
diff --git a/sdk/include/ndk/iotypes.h b/sdk/include/ndk/iotypes.h
index 84cf6c17143..ace4d6fc7a2 100644
--- a/sdk/include/ndk/iotypes.h
+++ b/sdk/include/ndk/iotypes.h
@@ -164,44 +164,53 @@ extern POBJECT_TYPE NTSYSAPI IoDriverObjectType;
//
// Device Node Flags
//
-#define DNF_PROCESSED 0x00000001
-#define DNF_STARTED 0x00000002
-#define DNF_START_FAILED 0x00000004
-#define DNF_ENUMERATED 0x00000008
-#define DNF_DELETED 0x00000010
-#define DNF_MADEUP 0x00000020
-#define DNF_START_REQUEST_PENDING 0x00000040
-#define DNF_NO_RESOURCE_REQUIRED 0x00000080
-#define DNF_INSUFFICIENT_RESOURCES 0x00000100
-#define DNF_RESOURCE_ASSIGNED 0x00000200
-#define DNF_RESOURCE_REPORTED 0x00000400
-#define DNF_HAL_NODE 0x00000800 // ???
-#define DNF_ADDED 0x00001000
-#define DNF_ADD_FAILED 0x00002000
-#define DNF_LEGACY_DRIVER 0x00004000
-#define DNF_STOPPED 0x00008000
-#define DNF_WILL_BE_REMOVED 0x00010000
+
+// this set of flags is relevant for w2k3 and newer
+// w2k has a completely different set of flags
+#define DNF_MADEUP 0x00000001
+#define DNF_DUPLICATE 0x00000002
+#define DNF_HAL_NODE 0x00000004
+#define DNF_REENUMERATE 0x00000008
+#define DNF_ENUMERATED 0x00000010
+#define DNF_IDS_QUERIED 0x00000020
+#define DNF_HAS_BOOT_CONFIG 0x00000040
+#define DNF_BOOT_CONFIG_RESERVED 0x00000080
+#define DNF_NO_RESOURCE_REQUIRED 0x00000100
+#define DNF_RESOURCE_REQUIREMENTS_NEED_FILTERED 0x00000200
+#define DNF_RESOURCE_REQUIREMENTS_CHANGED 0x00000400
+#define DNF_NON_STOPPED_REBALANCE 0x00000800
+#define DNF_LEGACY_DRIVER 0x00001000
+#define DNF_HAS_PROBLEM 0x00002000
+#define DNF_HAS_PRIVATE_PROBLEM 0x00004000
+#define DNF_HARDWARE_VERIFICATION 0x00008000
+#define DNF_DEVICE_GONE 0x00010000
#define DNF_LEGACY_RESOURCE_DEVICENODE 0x00020000
-#define DNF_NOT_CONFIGURED 0x00040000
-#define DNF_REINSTALL 0x00080000
-#define DNF_RESOURCE_REQUIREMENTS_NEED_FILTERED 0x00100000 // ???
-#define DNF_DISABLED 0x00200000
-#define DNF_RESTART_OK 0x00400000
-#define DNF_NEED_RESTART 0x00800000
-#define DNF_VISITED 0x01000000
-#define DNF_ASSIGNING_RESOURCES 0x02000000
-#define DNF_BEEING_ENUMERATED 0x04000000
-#define DNF_NEED_ENUMERATION_ONLY 0x08000000
-#define DNF_LOCKED 0x10000000
-#define DNF_HAS_BOOT_CONFIG 0x20000000
-#define DNF_BOOT_CONFIG_RESERVED 0x40000000
-#define DNF_HAS_PROBLEM 0x80000000 // ???
+#define DNF_NEEDS_REBALANCE 0x00040000
+#define DNF_LOCKED_FOR_EJECT 0x00080000
+#define DNF_DRIVER_BLOCKED 0x00100000
+#define DNF_CHILD_WITH_INVALID_ID 0x00200000
+
+// these flags were added in Vista or later
+#define DNF_ASYNC_START_NOT_SUPPORTED 0x00400000
+#define DNF_ASYNC_ENUMERATION_NOT_SUPPORTED 0x00800000
+#define DNF_LOCKED_FOR_REBALANCE 0x01000000
+#define DNF_UNINSTALLED 0x02000000
+#define DNF_NO_LOWER_DEVICE_FILTERS 0x04000000
+#define DNF_NO_LOWER_CLASS_FILTERS 0x08000000
+#define DNF_NO_SERVICE 0x10000000
+#define DNF_NO_UPPER_DEVICE_FILTERS 0x20000000
+#define DNF_NO_UPPER_CLASS_FILTERS 0x40000000
+#define DNF_WAITING_FOR_FDO 0x80000000
//
// Device Node User Flags
//
+#define DNUF_WILL_BE_REMOVED 0x0001
#define DNUF_DONT_SHOW_IN_UI 0x0002
+#define DNUF_NEED_RESTART 0x0004
#define DNUF_NOT_DISABLEABLE 0x0008
+#define DNUF_SHUTDOWN_QUERIED 0x0010
+#define DNUF_SHUTDOWN_SUBTREE_DONE 0x0020
//
// Internal Option Flags
@@ -815,6 +824,8 @@ typedef struct _IO_CLIENT_EXTENSION
PVOID ClientIdentificationAddress;
} IO_CLIENT_EXTENSION, *PIO_CLIENT_EXTENSION;
+#define DEVNODE_HISTORY_SIZE 20
+
//
// Device Node
//
@@ -829,7 +840,7 @@ typedef struct _DEVICE_NODE
PO_IRP_MANAGER PoIrpManager;
PNP_DEVNODE_STATE State;
PNP_DEVNODE_STATE PreviousState;
- PNP_DEVNODE_STATE StateHistory[20];
+ PNP_DEVNODE_STATE StateHistory[DEVNODE_HISTORY_SIZE];
ULONG StateHistoryEntry;
NTSTATUS CompletionStatus;
PIRP PendingIrp;