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\ key + // open the CCS\Control\Class\ 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); - - if (DeviceNode->ServiceName.Buffer == NULL) + // obtain the device node's ServiceName + Status = IopGetRegistryValue(InstanceHandle, L"Service", &kvInfo2); + if (!NT_SUCCESS(Status)) { - DPRINT1("No service!\n"); - return STATUS_SUCCESS; + return Status; } - ServiceKeyName.MaximumLength = ServicesKeyPath.Length + DeviceNode->ServiceName.Length + sizeof(UNICODE_NULL); + if (kvInfo2->Type != REG_SZ || kvInfo2->DataLength <= sizeof(WCHAR)) + { + ExFreePool(kvInfo2); + return STATUS_UNSUCCESSFUL; + } + + 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; - - Stack.Parameters.StartDevice.AllocatedResources = - DeviceNode->ResourceList; - Stack.Parameters.StartDevice.AllocatedResourcesTranslated = - DeviceNode->ResourceListTranslated; - - /* Do the call */ - Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy); - if (!NT_SUCCESS(Status)) + if (!(DeviceNode->Flags & DNF_IDS_QUERIED)) { - /* Send an IRP_MN_REMOVE_DEVICE request */ - IopRemoveDevice(DeviceNode); + // query ids (for reported devices) + UNICODE_STRING enumRoot = RTL_CONSTANT_STRING(ENUM_ROOT); + HANDLE enumRootHandle, instanceHandle; - /* Set the appropriate flag */ - DeviceNode->Flags |= DNF_START_FAILED; - DeviceNode->Problem = CM_PROB_FAILED_START; + // 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; + } - DPRINT1("Warning: PnP Start failed (%wZ) [Status: 0x%x]\n", &DeviceNode->InstancePath, Status); - return; + // 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; + } + + IopQueryHardwareIds(DeviceNode, instanceHandle); + IopQueryCompatibleIds(DeviceNode, instanceHandle); + + 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) -{ - 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; - } - } - - if (!Found && !(Child->Flags & DNF_WILL_BE_REMOVED)) - { - /* Send removal IRPs to all of its children */ - IopPrepareDeviceForRemoval(Child->PhysicalDeviceObject, TRUE); - - /* Send the surprise removal IRP */ - IopSendSurpriseRemoval(Child->PhysicalDeviceObject); - - /* Tell the user-mode PnP manager that a device was removed */ - IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL, - &Child->InstancePath); - - /* Send the remove device IRP */ - IopSendRemoveDevice(Child->PhysicalDeviceObject); - } - - Child = NextChild; - } -} - NTSTATUS IopRemoveDevice(PDEVICE_NODE DeviceNode) { NTSTATUS Status; + // 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 + DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath); - Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject, FALSE); + BOOLEAN surpriseRemoval = (_Bool)(DeviceNode->Flags & DNF_DEVICE_GONE); + + Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject, surpriseRemoval); + + if (surpriseRemoval) + { + IopSendSurpriseRemoval(DeviceNode->PhysicalDeviceObject); + IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL, &DeviceNode->InstancePath); + } + 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; + if (PnPFlags & PNP_DEVICE_FAILED) + { + PiSetDevNodeProblem(DeviceNode, 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); - - 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); + if (!NT_SUCCESS(DeviceNode->CompletionStatus)) + { + DPRINT("QDR request failed for %wZ, status %x\n", + &DeviceNode->InstancePath, DeviceNode->CompletionStatus); + // treat as if there are no child objects } - DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n"); + PDEVICE_RELATIONS DeviceRelations = DeviceNode->OverUsed1.PendingDeviceRelations; + DeviceNode->OverUsed1.PendingDeviceRelations = NULL; - Stack.Parameters.QueryDeviceRelations.Type = BusRelations; - - Status = IopInitiatePnpIrp( - DeviceNode->PhysicalDeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_DEVICE_RELATIONS, - &Stack); - if (!NT_SUCCESS(Status)) - { - DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); - return Status; - } - - DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; - - /* - * 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)) + // 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; + 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); + } } - /* - * Retrieve configuration from the registry for discovered children - */ - IopInitDeviceTreeTraverseContext( - &Context, - DeviceNode, - IopActionConfigureChildServices, - DeviceNode); - - Status = IopTraverseDeviceTree(&Context); - if (!NT_SUCCESS(Status)) - { - 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; - } - - 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; + NTSTATUS status; + BOOLEAN doProcessAgain; + PDEVICE_NODE currentNode = RootNode; + PDEVICE_OBJECT referencedObject; - ASSERT(DeviceNode->Flags & DNF_ENUMERATED); - ASSERT(DeviceNode->Flags & DNF_PROCESSED); - - /* 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)) - { - /* 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); - } - else -#endif - { - /* 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; + doProcessAgain = FALSE; - /* Load service data from the registry */ - Status = IopActionConfigureChildServices(DeviceNode, DeviceNode->Parent); + // 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); - if (NT_SUCCESS(Status)) + // Devices with problems are skipped (unless they are not being removed) + if (currentNode->Flags & DNF_HAS_PROBLEM && + currentNode->State != DeviceNodeAwaitingQueuedRemoval) { - /* 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); + goto skipEnum; } - } - return Status; + switch (currentNode->State) + { + 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; + + PiSetDevNodeProblem(currentNode, problem); + PiSetDevNodeState(currentNode, DeviceNodeAwaitingQueuedRemoval); + } + else + { + // TODO: IopDoDeferredSetInterfaceState and IopAllocateLegacyBootResources + // are called here too + + 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; + } + +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 */ - - /* FIXME: DN_HARDWARE_ENUM */ - - /* DN_LIAR and DN_HAS_MARK are 9x only */ - - if (DeviceNode->Problem != 0) + if (DeviceNode->Flags & DNF_HAS_PROBLEM) Output |= DN_HAS_PROBLEM; - /* FIXME: DN_FILTERED */ + if (DeviceNode->Flags & DNF_HAS_PRIVATE_PROBLEM) + Output |= DN_PRIVATE_PROBLEM; + + if (DeviceNode->Flags & DNF_DRIVER_BLOCKED) + Output |= DN_DRIVER_BLOCKED; + + if (DeviceNode->Flags & DNF_CHILD_WITH_INVALID_ID) + Output |= DN_CHILD_WITH_INVALID_ID; + + 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 + * Copyright 2020 Victor Perevertkin + */ + +#include +#define NDEBUG +#include + +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;