2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: PnP manager device manipulation functions
5 * COPYRIGHT: Casper S. Hornstrup (chorns@users.sourceforge.net)
6 * 2007 Hervé Poussineau (hpoussin@reactos.org)
7 * 2014-2017 Thomas Faber (thomas.faber@reactos.org)
8 * 2020 Victor Perevertkin (victor.perevertkin@reactos.org)
11 /* Device tree is a resource shared among all system services: hal, kernel, drivers etc.
12 * Thus all code which interacts with the tree needs to be synchronized.
13 * Here it's done via a list of DEVICE_ACTION_REQUEST structures, which represents
14 * the device action queue. It is being processed exclusively by the PipDeviceActionWorker.
16 * Operation queuing can be done with the PiQueueDeviceAction function or with
17 * the PiPerfomSyncDeviceAction for synchronous operations.
18 * All device manipulation like starting, removing, enumeration (see DEVICE_ACTION enum)
19 * have to be done with the PiQueueDeviceAction in order to avoid race conditions.
21 * Note: there is one special operation here - PiActionEnumRootDevices. It is meant to be done
22 * during initialization process (and be the first device tree operation executed) and
23 * is always executed synchronously.
26 /* INCLUDES ******************************************************************/
32 /* GLOBALS *******************************************************************/
34 extern ERESOURCE IopDriverLoadResource
;
35 extern BOOLEAN PnpSystemInit
;
36 extern PDEVICE_NODE IopRootDeviceNode
;
37 extern BOOLEAN PnPBootDriversLoaded
;
38 extern BOOLEAN PnPBootDriversInitialized
;
40 #define MAX_DEVICE_ID_LEN 200
41 #define MAX_SEPARATORS_INSTANCEID 0
42 #define MAX_SEPARATORS_DEVICEID 1
44 /* DATA **********************************************************************/
46 LIST_ENTRY IopDeviceActionRequestList
;
47 WORK_QUEUE_ITEM IopDeviceActionWorkItem
;
48 BOOLEAN IopDeviceActionInProgress
;
49 KSPIN_LOCK IopDeviceActionLock
;
50 KEVENT PiEnumerationFinished
;
51 static const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
53 #define TAG_PNP_DEVACTION 'aDpP'
55 /* TYPES *********************************************************************/
57 typedef struct _DEVICE_ACTION_REQUEST
59 LIST_ENTRY RequestListEntry
;
60 PDEVICE_OBJECT DeviceObject
;
61 PKEVENT CompletionEvent
;
62 NTSTATUS
*CompletionStatus
;
64 } DEVICE_ACTION_REQUEST
, *PDEVICE_ACTION_REQUEST
;
66 typedef enum _ADD_DEV_DRIVER_TYPE
73 } ADD_DEV_DRIVER_TYPE
;
75 typedef struct _ADD_DEV_DRIVERS_LIST
78 PDRIVER_OBJECT DriverObject
;
79 ADD_DEV_DRIVER_TYPE DriverType
;
80 } ADD_DEV_DRIVERS_LIST
, *PADD_DEV_DRIVERS_LIST
;
82 typedef struct _ATTACH_FILTER_DRIVERS_CONTEXT
84 ADD_DEV_DRIVER_TYPE DriverType
;
85 PDEVICE_NODE DeviceNode
;
86 PLIST_ENTRY DriversListHead
;
87 } ATTACH_FILTER_DRIVERS_CONTEXT
, *PATTACH_FILTER_DRIVERS_CONTEXT
;
89 /* FUNCTIONS *****************************************************************/
92 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance
);
95 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode
, PUNICODE_STRING ParentIdPrefix
);
99 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid
);
102 IopSetDeviceInstanceData(HANDLE InstanceKey
, PDEVICE_NODE DeviceNode
);
106 IopInstallCriticalDevice(PDEVICE_NODE DeviceNode
);
110 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject
);
114 IopPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject
, BOOLEAN Force
);
118 IopSetServiceEnumData(
119 _In_ PDEVICE_NODE DeviceNode
,
120 _In_ HANDLE InstanceHandle
);
126 _In_ BUS_QUERY_ID_TYPE QueryType
)
131 ULONG SeparatorsCount
= 0;
132 PWCHAR PtrPrevChar
= NULL
;
140 case BusQueryDeviceID
:
141 MaxSeparators
= MAX_SEPARATORS_DEVICEID
;
144 case BusQueryInstanceID
:
145 MaxSeparators
= MAX_SEPARATORS_INSTANCEID
;
149 case BusQueryHardwareIDs
:
150 case BusQueryCompatibleIDs
:
151 MaxSeparators
= MAX_SEPARATORS_DEVICEID
;
156 DPRINT1("IopValidateID: Not handled QueryType - %x\n", QueryType
);
160 StringEnd
= Id
+ MAX_DEVICE_ID_LEN
;
162 for (PtrChar
= Id
; PtrChar
< StringEnd
; PtrChar
++)
166 if (Char
== UNICODE_NULL
)
168 if (!IsMultiSz
|| (PtrPrevChar
&& PtrChar
== PtrPrevChar
+ 1))
170 if (MaxSeparators
== SeparatorsCount
|| IsMultiSz
)
175 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
176 SeparatorsCount
, MaxSeparators
);
180 StringEnd
= PtrChar
+ MAX_DEVICE_ID_LEN
+ 1;
181 PtrPrevChar
= PtrChar
;
184 else if (Char
< ' ' || Char
> 0x7F || Char
== ',')
186 DPRINT1("IopValidateID: Invalid character - %04X\n", Char
);
189 else if (Char
== ' ')
193 else if (Char
== '\\')
197 if (SeparatorsCount
> MaxSeparators
)
199 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
200 SeparatorsCount
, MaxSeparators
);
206 DPRINT1("IopValidateID: Not terminated ID\n");
215 IopCreateDeviceInstancePath(
216 _In_ PDEVICE_NODE DeviceNode
,
217 _Out_ PUNICODE_STRING InstancePath
)
219 IO_STATUS_BLOCK IoStatusBlock
;
220 UNICODE_STRING DeviceId
;
221 UNICODE_STRING InstanceId
;
222 IO_STACK_LOCATION Stack
;
224 UNICODE_STRING ParentIdPrefix
= { 0, 0, NULL
};
225 DEVICE_CAPABILITIES DeviceCapabilities
;
228 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
230 Stack
.Parameters
.QueryId
.IdType
= BusQueryDeviceID
;
231 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
235 if (!NT_SUCCESS(Status
))
237 DPRINT1("IopInitiatePnpIrp(BusQueryDeviceID) failed (Status %x)\n", Status
);
241 IsValidID
= IopValidateID((PWCHAR
)IoStatusBlock
.Information
, BusQueryDeviceID
);
245 DPRINT1("Invalid DeviceID. DeviceNode - %p\n", DeviceNode
);
248 /* Save the device id string */
249 RtlInitUnicodeString(&DeviceId
, (PWSTR
)IoStatusBlock
.Information
);
251 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
253 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
254 if (!NT_SUCCESS(Status
))
256 DPRINT1("IopQueryDeviceCapabilities() failed (Status 0x%08lx)\n", Status
);
257 RtlFreeUnicodeString(&DeviceId
);
261 /* This bit is only check after enumeration */
262 if (DeviceCapabilities
.HardwareDisabled
)
264 /* FIXME: Cleanup device */
265 RtlFreeUnicodeString(&DeviceId
);
266 return STATUS_PLUGPLAY_NO_DEVICE
;
269 if (!DeviceCapabilities
.UniqueID
)
271 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
272 DPRINT("Instance ID is not unique\n");
273 Status
= IopGetParentIdPrefix(DeviceNode
, &ParentIdPrefix
);
274 if (!NT_SUCCESS(Status
))
276 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status
);
277 RtlFreeUnicodeString(&DeviceId
);
282 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
284 Stack
.Parameters
.QueryId
.IdType
= BusQueryInstanceID
;
285 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
289 if (!NT_SUCCESS(Status
))
291 DPRINT("IopInitiatePnpIrp(BusQueryInstanceID) failed (Status %lx)\n", Status
);
292 ASSERT(IoStatusBlock
.Information
== 0);
295 if (IoStatusBlock
.Information
)
297 IsValidID
= IopValidateID((PWCHAR
)IoStatusBlock
.Information
, BusQueryInstanceID
);
301 DPRINT1("Invalid InstanceID. DeviceNode - %p\n", DeviceNode
);
305 RtlInitUnicodeString(&InstanceId
,
306 (PWSTR
)IoStatusBlock
.Information
);
308 InstancePath
->Length
= 0;
309 InstancePath
->MaximumLength
= DeviceId
.Length
+ sizeof(WCHAR
) +
310 ParentIdPrefix
.Length
+
312 sizeof(UNICODE_NULL
);
313 if (ParentIdPrefix
.Length
&& InstanceId
.Length
)
315 InstancePath
->MaximumLength
+= sizeof(WCHAR
);
318 InstancePath
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
319 InstancePath
->MaximumLength
,
321 if (!InstancePath
->Buffer
)
323 RtlFreeUnicodeString(&InstanceId
);
324 RtlFreeUnicodeString(&ParentIdPrefix
);
325 RtlFreeUnicodeString(&DeviceId
);
326 return STATUS_INSUFFICIENT_RESOURCES
;
329 /* Start with the device id */
330 RtlCopyUnicodeString(InstancePath
, &DeviceId
);
331 RtlAppendUnicodeToString(InstancePath
, L
"\\");
333 /* Add information from parent bus device to InstancePath */
334 RtlAppendUnicodeStringToString(InstancePath
, &ParentIdPrefix
);
335 if (ParentIdPrefix
.Length
&& InstanceId
.Length
)
337 RtlAppendUnicodeToString(InstancePath
, L
"&");
340 /* Finally, add the id returned by the driver stack */
341 RtlAppendUnicodeStringToString(InstancePath
, &InstanceId
);
344 * FIXME: Check for valid characters, if there is invalid characters
348 RtlFreeUnicodeString(&InstanceId
);
349 RtlFreeUnicodeString(&DeviceId
);
350 RtlFreeUnicodeString(&ParentIdPrefix
);
352 return STATUS_SUCCESS
;
356 * @brief Loads and/or returns the driver associated with the registry entry if the driver
357 * is enabled. In case of an error, sets up a corresponding Problem to the DeviceNode
362 PiAttachFilterDriversCallback(
370 PATTACH_FILTER_DRIVERS_CONTEXT context
= Ctx
;
371 PDRIVER_OBJECT DriverObject
;
373 BOOLEAN loadDrivers
= (BOOLEAN
)(ULONG_PTR
)EntryContext
;
377 // No filter value present
378 if (ValueType
!= REG_SZ
)
379 return STATUS_SUCCESS
;
381 if (ValueLength
<= sizeof(WCHAR
))
382 return STATUS_OBJECT_NAME_NOT_FOUND
;
384 // open the service registry key
385 UNICODE_STRING serviceName
= { .Length
= 0 }, servicesKeyName
;
386 RtlInitUnicodeString(&serviceName
, ValueData
);
387 RtlInitUnicodeString(&servicesKeyName
, ServicesKeyName
);
389 HANDLE ccsServicesHandle
, serviceHandle
= NULL
;
391 Status
= IopOpenRegistryKeyEx(&ccsServicesHandle
, NULL
, &servicesKeyName
, KEY_READ
);
392 if (!NT_SUCCESS(Status
))
394 DPRINT1("Failed to open a registry key for \"%wZ\" (status %x)\n", &serviceName
, Status
);
398 Status
= IopOpenRegistryKeyEx(&serviceHandle
, ccsServicesHandle
, &serviceName
, KEY_READ
);
399 ZwClose(ccsServicesHandle
);
400 if (!NT_SUCCESS(Status
))
402 DPRINT1("Failed to open a registry key for \"%wZ\" (status %x)\n", &serviceName
, Status
);
406 PADD_DEV_DRIVERS_LIST driverEntry
= ExAllocatePoolWithTag(PagedPool
,
407 sizeof(*driverEntry
),
412 DPRINT1("Failed to allocate driverEntry for \"%wZ\"\n", &serviceName
);
413 ZwClose(serviceHandle
);
414 return STATUS_INSUFFICIENT_RESOURCES
;
417 // check if the driver is disabled
418 PKEY_VALUE_FULL_INFORMATION kvInfo
;
419 SERVICE_LOAD_TYPE startType
= DisableLoad
;
421 Status
= IopGetRegistryValue(serviceHandle
, L
"Start", &kvInfo
);
422 if (NT_SUCCESS(Status
) && kvInfo
->Type
== REG_DWORD
)
424 RtlMoveMemory(&startType
,
425 (PVOID
)((ULONG_PTR
)kvInfo
+ kvInfo
->DataOffset
),
430 // TODO: take into account other start types (like SERVICE_DEMAND_START)
431 if (startType
>= DisableLoad
)
433 if (!(context
->DeviceNode
->Flags
& DNF_HAS_PROBLEM
))
435 PiSetDevNodeProblem(context
->DeviceNode
, CM_PROB_DISABLED_SERVICE
);
438 DPRINT("Service \"%wZ\" is disabled (start type %u)\n", &serviceName
, startType
);
439 Status
= STATUS_UNSUCCESSFUL
;
443 // check if the driver is already loaded
444 UNICODE_STRING driverName
;
445 Status
= IopGetDriverNames(serviceHandle
, &driverName
, NULL
);
446 if (!NT_SUCCESS(Status
))
448 DPRINT1("Unable to obtain the driver name for \"%wZ\"\n", &serviceName
);
453 Status
= ObReferenceObjectByName(&driverName
,
454 OBJ_OPENIF
| OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
455 NULL
, /* PassedAccessState */
456 0, /* DesiredAccess */
459 NULL
, /* ParseContext */
460 (PVOID
*)&DriverObject
);
461 RtlFreeUnicodeString(&driverName
);
463 // the driver was not probably loaded, try to load
464 if (!NT_SUCCESS(Status
))
468 Status
= IopLoadDriver(serviceHandle
, &DriverObject
);
472 DPRINT("Service \"%wZ\" will not be loaded now\n", &serviceName
);
473 // return failure, the driver will be loaded later (in a subsequent call)
474 Status
= STATUS_UNSUCCESSFUL
;
479 if (NT_SUCCESS(Status
))
481 driverEntry
->DriverObject
= DriverObject
;
482 driverEntry
->DriverType
= context
->DriverType
;
483 InsertTailList(context
->DriversListHead
, &driverEntry
->ListEntry
);
484 ZwClose(serviceHandle
);
485 return STATUS_SUCCESS
;
489 if (!(context
->DeviceNode
->Flags
& DNF_HAS_PROBLEM
))
493 case STATUS_INSUFFICIENT_RESOURCES
:
494 PiSetDevNodeProblem(context
->DeviceNode
, CM_PROB_OUT_OF_MEMORY
);
496 case STATUS_FAILED_DRIVER_ENTRY
:
497 PiSetDevNodeProblem(context
->DeviceNode
, CM_PROB_FAILED_DRIVER_ENTRY
);
499 case STATUS_ILL_FORMED_SERVICE_ENTRY
:
500 PiSetDevNodeProblem(context
->DeviceNode
, CM_PROB_DRIVER_SERVICE_KEY_INVALID
);
503 PiSetDevNodeProblem(context
->DeviceNode
, CM_PROB_DRIVER_FAILED_LOAD
);
508 DPRINT1("Failed to load driver \"%wZ\" for %wZ (status %x)\n",
509 &serviceName
, &context
->DeviceNode
->InstancePath
, Status
);
513 ExFreePoolWithTag(driverEntry
, TAG_PNP_DEVACTION
);
516 ZwClose(serviceHandle
);
523 * @brief Calls PiAttachFilterDriversCallback for filter drivers (if any)
527 PiAttachFilterDrivers(
528 PLIST_ENTRY DriversListHead
,
529 PDEVICE_NODE DeviceNode
,
535 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = { { NULL
, 0, NULL
, NULL
, 0, NULL
, 0 }, };
536 ATTACH_FILTER_DRIVERS_CONTEXT routineContext
;
541 routineContext
.DriversListHead
= DriversListHead
;
542 routineContext
.DeviceNode
= DeviceNode
;
544 // First add device filters
545 routineContext
.DriverType
= Lower
? LowerFilter
: UpperFilter
;
546 QueryTable
[0] = (RTL_QUERY_REGISTRY_TABLE
){
547 .QueryRoutine
= PiAttachFilterDriversCallback
,
548 .Name
= Lower
? L
"LowerFilters" : L
"UpperFilters",
549 .DefaultType
= REG_NONE
,
550 .EntryContext
= (PVOID
)(ULONG_PTR
)LoadDrivers
553 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
558 if (ClassKey
== NULL
)
563 // Then add device class filters
564 routineContext
.DriverType
= Lower
? LowerClassFilter
: UpperClassFilter
;
565 QueryTable
[0] = (RTL_QUERY_REGISTRY_TABLE
){
566 .QueryRoutine
= PiAttachFilterDriversCallback
,
567 .Name
= Lower
? L
"LowerFilters" : L
"UpperFilters",
568 .DefaultType
= REG_NONE
,
569 .EntryContext
= (PVOID
)(ULONG_PTR
)LoadDrivers
572 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
581 * @brief Loads all drivers for a device node (actual service and filters)
582 * and calls their AddDevice routine
584 * @param[in] DeviceNode The device node
585 * @param[in] LoadDrivers Whether to load drivers if they are not loaded yet
586 * (used when storage subsystem is not yet initialized)
590 PiCallDriverAddDevice(
591 _In_ PDEVICE_NODE DeviceNode
,
592 _In_ BOOLEAN LoadDrivers
)
595 HANDLE EnumRootKey
, SubKey
;
596 HANDLE ClassKey
= NULL
;
597 UNICODE_STRING EnumRoot
= RTL_CONSTANT_STRING(ENUM_ROOT
);
598 static UNICODE_STRING ccsControlClass
=
599 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
600 PKEY_VALUE_FULL_INFORMATION kvInfo
= NULL
;
604 // open the enumeration root key
605 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
, &EnumRoot
, KEY_READ
);
606 if (!NT_SUCCESS(Status
))
608 DPRINT1("IopOpenRegistryKeyEx() failed for \"%wZ\" (status %x)\n", &EnumRoot
, Status
);
612 // open an instance subkey
613 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
, &DeviceNode
->InstancePath
, KEY_READ
);
614 ZwClose(EnumRootKey
);
615 if (!NT_SUCCESS(Status
))
617 DPRINT1("Failed to open a devnode instance key for \"%wZ\" (status %x)\n",
618 &DeviceNode
->InstancePath
, Status
);
622 // try to get the class GUID of an instance and its registry key
623 Status
= IopGetRegistryValue(SubKey
, REGSTR_VAL_CLASSGUID
, &kvInfo
);
624 if (NT_SUCCESS(Status
) && kvInfo
->Type
== REG_SZ
&& kvInfo
->DataLength
> sizeof(WCHAR
))
626 UNICODE_STRING classGUID
= {
627 .MaximumLength
= kvInfo
->DataLength
,
628 .Length
= kvInfo
->DataLength
- sizeof(UNICODE_NULL
),
629 .Buffer
= (PVOID
)((ULONG_PTR
)kvInfo
+ kvInfo
->DataOffset
)
631 HANDLE ccsControlHandle
;
633 Status
= IopOpenRegistryKeyEx(&ccsControlHandle
, NULL
, &ccsControlClass
, KEY_READ
);
634 if (!NT_SUCCESS(Status
))
636 DPRINT1("IopOpenRegistryKeyEx() failed for \"%wZ\" (status %x)\n",
637 &ccsControlClass
, Status
);
641 // open the CCS\Control\Class\<ClassGUID> key
642 Status
= IopOpenRegistryKeyEx(&ClassKey
, ccsControlHandle
, &classGUID
, KEY_READ
);
643 ZwClose(ccsControlHandle
);
644 if (!NT_SUCCESS(Status
))
646 DPRINT1("Failed to open class key \"%wZ\" (status %x)\n", &classGUID
, Status
);
652 // Check the Properties key of a class too
653 // Windows fills some device properties from this key (which is protected)
654 // TODO: add the device properties from this key
656 UNICODE_STRING properties
= RTL_CONSTANT_STRING(REGSTR_KEY_DEVICE_PROPERTIES
);
657 HANDLE propertiesHandle
;
659 Status
= IopOpenRegistryKeyEx(&propertiesHandle
, ClassKey
, &properties
, KEY_READ
);
660 if (!NT_SUCCESS(Status
))
662 DPRINT("Properties key failed to open for \"%wZ\" (status %x)\n",
667 ZwClose(propertiesHandle
);
673 // the driver loading order:
675 // 2. LowerClassFilters
676 // 3. Device driver (only one service!)
678 // 5. UpperClassFilters
680 LIST_ENTRY drvListHead
;
681 InitializeListHead(&drvListHead
);
683 // lower (class) filters
684 Status
= PiAttachFilterDrivers(&drvListHead
, DeviceNode
, SubKey
, ClassKey
, TRUE
, LoadDrivers
);
685 if (!NT_SUCCESS(Status
))
690 ATTACH_FILTER_DRIVERS_CONTEXT routineContext
= {
691 .DriversListHead
= &drvListHead
,
692 .DriverType
= DeviceDriver
,
693 .DeviceNode
= DeviceNode
696 RTL_QUERY_REGISTRY_TABLE queryTable
[2] = {{
697 .QueryRoutine
= PiAttachFilterDriversCallback
,
699 .Flags
= RTL_QUERY_REGISTRY_REQUIRED
,
700 .DefaultType
= REG_SZ
, // REG_MULTI_SZ is not allowed here
702 .EntryContext
= (PVOID
)(ULONG_PTR
)LoadDrivers
706 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
711 if (NT_SUCCESS(Status
))
715 // if a driver is not found, but a device allows raw access -> proceed
716 else if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
&&
717 (DeviceNode
->CapabilityFlags
& 0x00000040)) // CM_DEVCAP_RAWDEVICEOK
719 // add a dummy entry to the drivers list (need for later processing)
720 PADD_DEV_DRIVERS_LIST driverEntry
= ExAllocatePoolZero(PagedPool
,
721 sizeof(*driverEntry
),
723 driverEntry
->DriverType
= DeviceDriver
;
724 InsertTailList(&drvListHead
, &driverEntry
->ListEntry
);
725 DPRINT("No service for \"%wZ\" (RawDeviceOK)\n", &DeviceNode
->InstancePath
);
729 if (Status
== STATUS_OBJECT_TYPE_MISMATCH
&& !(DeviceNode
->Flags
& DNF_HAS_PROBLEM
))
731 PiSetDevNodeProblem(DeviceNode
, CM_PROB_REGISTRY
);
733 DPRINT("No service for \"%wZ\" (loadDrv: %u)\n", &DeviceNode
->InstancePath
, LoadDrivers
);
737 // upper (class) filters
738 Status
= PiAttachFilterDrivers(&drvListHead
, DeviceNode
, SubKey
, ClassKey
, FALSE
, LoadDrivers
);
739 if (!NT_SUCCESS(Status
))
744 // finally loop through the stack and call AddDevice for every driver
745 for (PLIST_ENTRY listEntry
= drvListHead
.Flink
;
746 listEntry
!= &drvListHead
;
747 listEntry
= listEntry
->Flink
)
749 PADD_DEV_DRIVERS_LIST driverEntry
;
750 driverEntry
= CONTAINING_RECORD(listEntry
, ADD_DEV_DRIVERS_LIST
, ListEntry
);
751 PDRIVER_OBJECT driverObject
= driverEntry
->DriverObject
;
753 // FIXME: ReactOS is not quite ready for this assert
754 // (legacy drivers should not have AddDevice routine)
755 // ASSERT(!(DriverObject->Flags & DRVO_LEGACY_DRIVER));
757 if (driverObject
&& driverObject
->DriverExtension
->AddDevice
)
759 Status
= driverObject
->DriverExtension
->AddDevice(driverEntry
->DriverObject
,
760 DeviceNode
->PhysicalDeviceObject
);
762 else if (driverObject
== NULL
)
764 // valid only for DeviceDriver
765 ASSERT(driverEntry
->DriverType
== DeviceDriver
);
766 ASSERT(DeviceNode
->CapabilityFlags
& 0x00000040); // CM_DEVCAP_RAWDEVICEOK
767 Status
= STATUS_SUCCESS
;
771 // HACK: the driver doesn't have a AddDevice routine. We shouldn't be here,
772 // but ReactOS' PnP stack is not that correct yet
773 DeviceNode
->Flags
|= DNF_LEGACY_DRIVER
;
774 Status
= STATUS_UNSUCCESSFUL
;
777 // for filter drivers we don't care about the AddDevice result
778 if (driverEntry
->DriverType
== DeviceDriver
)
780 if (NT_SUCCESS(Status
))
782 PDEVICE_OBJECT fdo
= IoGetAttachedDeviceReference(DeviceNode
->PhysicalDeviceObject
);
784 // HACK: Check if we have a ACPI device (needed for power management)
785 if (fdo
->DeviceType
== FILE_DEVICE_ACPI
)
787 static BOOLEAN SystemPowerDeviceNodeCreated
= FALSE
;
789 // There can be only one system power device
790 if (!SystemPowerDeviceNodeCreated
)
792 PopSystemPowerDeviceNode
= DeviceNode
;
793 ObReferenceObject(PopSystemPowerDeviceNode
->PhysicalDeviceObject
);
794 SystemPowerDeviceNodeCreated
= TRUE
;
798 ObDereferenceObject(fdo
);
799 PiSetDevNodeState(DeviceNode
, DeviceNodeDriversAdded
);
803 // lower filters (if already started) will be removed upon this request
804 PiSetDevNodeProblem(DeviceNode
, CM_PROB_FAILED_ADD
);
805 PiSetDevNodeState(DeviceNode
, DeviceNodeAwaitingQueuedRemoval
);
811 PDEVICE_OBJECT attachedDO
= IoGetAttachedDevice(DeviceNode
->PhysicalDeviceObject
);
812 if (attachedDO
->Flags
& DO_DEVICE_INITIALIZING
)
814 DPRINT1("DO_DEVICE_INITIALIZING is not cleared on a device 0x%p!\n", attachedDO
);
820 while (!IsListEmpty(&drvListHead
))
822 PLIST_ENTRY listEntry
= RemoveHeadList(&drvListHead
);
823 PADD_DEV_DRIVERS_LIST driverEntry
;
824 driverEntry
= CONTAINING_RECORD(listEntry
, ADD_DEV_DRIVERS_LIST
, ListEntry
);
826 // drivers which don't have any devices (in case of failure) will be cleaned up
827 if (driverEntry
->DriverObject
)
829 ObDereferenceObject(driverEntry
->DriverObject
);
831 ExFreePoolWithTag(driverEntry
, TAG_PNP_DEVACTION
);
835 if (ClassKey
!= NULL
)
845 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode
,
846 PDEVICE_CAPABILITIES DeviceCaps
)
848 IO_STATUS_BLOCK StatusBlock
;
849 IO_STACK_LOCATION Stack
;
852 UNICODE_STRING ValueName
;
854 /* Set up the Header */
855 RtlZeroMemory(DeviceCaps
, sizeof(DEVICE_CAPABILITIES
));
856 DeviceCaps
->Size
= sizeof(DEVICE_CAPABILITIES
);
857 DeviceCaps
->Version
= 1;
858 DeviceCaps
->Address
= -1;
859 DeviceCaps
->UINumber
= -1;
861 /* Set up the Stack */
862 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
863 Stack
.Parameters
.DeviceCapabilities
.Capabilities
= DeviceCaps
;
866 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
868 IRP_MN_QUERY_CAPABILITIES
,
870 if (!NT_SUCCESS(Status
))
872 if (Status
!= STATUS_NOT_SUPPORTED
)
874 DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%lx\n", Status
);
879 /* Map device capabilities to capability flags */
880 DeviceNode
->CapabilityFlags
= 0;
881 if (DeviceCaps
->LockSupported
)
882 DeviceNode
->CapabilityFlags
|= 0x00000001; // CM_DEVCAP_LOCKSUPPORTED
884 if (DeviceCaps
->EjectSupported
)
885 DeviceNode
->CapabilityFlags
|= 0x00000002; // CM_DEVCAP_EJECTSUPPORTED
887 if (DeviceCaps
->Removable
)
888 DeviceNode
->CapabilityFlags
|= 0x00000004; // CM_DEVCAP_REMOVABLE
890 if (DeviceCaps
->DockDevice
)
891 DeviceNode
->CapabilityFlags
|= 0x00000008; // CM_DEVCAP_DOCKDEVICE
893 if (DeviceCaps
->UniqueID
)
894 DeviceNode
->CapabilityFlags
|= 0x00000010; // CM_DEVCAP_UNIQUEID
896 if (DeviceCaps
->SilentInstall
)
897 DeviceNode
->CapabilityFlags
|= 0x00000020; // CM_DEVCAP_SILENTINSTALL
899 if (DeviceCaps
->RawDeviceOK
)
900 DeviceNode
->CapabilityFlags
|= 0x00000040; // CM_DEVCAP_RAWDEVICEOK
902 if (DeviceCaps
->SurpriseRemovalOK
)
903 DeviceNode
->CapabilityFlags
|= 0x00000080; // CM_DEVCAP_SURPRISEREMOVALOK
905 if (DeviceCaps
->HardwareDisabled
)
906 DeviceNode
->CapabilityFlags
|= 0x00000100; // CM_DEVCAP_HARDWAREDISABLED
908 if (DeviceCaps
->NonDynamic
)
909 DeviceNode
->CapabilityFlags
|= 0x00000200; // CM_DEVCAP_NONDYNAMIC
911 if (DeviceCaps
->NoDisplayInUI
)
912 DeviceNode
->UserFlags
|= DNUF_DONT_SHOW_IN_UI
;
914 DeviceNode
->UserFlags
&= ~DNUF_DONT_SHOW_IN_UI
;
916 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, REG_OPTION_NON_VOLATILE
, &InstanceKey
);
917 if (NT_SUCCESS(Status
))
919 /* Set 'Capabilities' value */
920 RtlInitUnicodeString(&ValueName
, L
"Capabilities");
921 Status
= ZwSetValueKey(InstanceKey
,
925 &DeviceNode
->CapabilityFlags
,
928 /* Set 'UINumber' value */
929 if (DeviceCaps
->UINumber
!= MAXULONG
)
931 RtlInitUnicodeString(&ValueName
, L
"UINumber");
932 Status
= ZwSetValueKey(InstanceKey
,
936 &DeviceCaps
->UINumber
,
940 ZwClose(InstanceKey
);
948 IopQueryHardwareIds(PDEVICE_NODE DeviceNode
,
951 IO_STACK_LOCATION Stack
;
952 IO_STATUS_BLOCK IoStatusBlock
;
954 UNICODE_STRING ValueName
;
956 ULONG Length
, TotalLength
;
959 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
961 RtlZeroMemory(&Stack
, sizeof(Stack
));
962 Stack
.Parameters
.QueryId
.IdType
= BusQueryHardwareIDs
;
963 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
967 if (NT_SUCCESS(Status
))
969 IsValidID
= IopValidateID((PWCHAR
)IoStatusBlock
.Information
, BusQueryHardwareIDs
);
973 DPRINT1("Invalid HardwareIDs. DeviceNode - %p\n", DeviceNode
);
978 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
979 DPRINT("Hardware IDs:\n");
982 DPRINT(" %S\n", Ptr
);
983 Length
= (ULONG
)wcslen(Ptr
) + 1;
986 TotalLength
+= Length
;
988 DPRINT("TotalLength: %hu\n", TotalLength
);
991 RtlInitUnicodeString(&ValueName
, L
"HardwareID");
992 Status
= ZwSetValueKey(InstanceKey
,
996 (PVOID
)IoStatusBlock
.Information
,
997 (TotalLength
+ 1) * sizeof(WCHAR
));
998 if (!NT_SUCCESS(Status
))
1000 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
1005 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1013 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode
,
1016 IO_STACK_LOCATION Stack
;
1017 IO_STATUS_BLOCK IoStatusBlock
;
1019 UNICODE_STRING ValueName
;
1021 ULONG Length
, TotalLength
;
1024 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1026 RtlZeroMemory(&Stack
, sizeof(Stack
));
1027 Stack
.Parameters
.QueryId
.IdType
= BusQueryCompatibleIDs
;
1028 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1032 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
1034 IsValidID
= IopValidateID((PWCHAR
)IoStatusBlock
.Information
, BusQueryCompatibleIDs
);
1038 DPRINT1("Invalid CompatibleIDs. DeviceNode - %p\n", DeviceNode
);
1043 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
1044 DPRINT("Compatible IDs:\n");
1047 DPRINT(" %S\n", Ptr
);
1048 Length
= (ULONG
)wcslen(Ptr
) + 1;
1051 TotalLength
+= Length
;
1053 DPRINT("TotalLength: %hu\n", TotalLength
);
1056 RtlInitUnicodeString(&ValueName
, L
"CompatibleIDs");
1057 Status
= ZwSetValueKey(InstanceKey
,
1061 (PVOID
)IoStatusBlock
.Information
,
1062 (TotalLength
+ 1) * sizeof(WCHAR
));
1063 if (!NT_SUCCESS(Status
))
1065 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status
);
1070 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1078 PiInitializeDevNode(
1079 _In_ PDEVICE_NODE DeviceNode
)
1081 IO_STATUS_BLOCK IoStatusBlock
;
1082 PWSTR DeviceDescription
;
1083 PWSTR LocationInformation
;
1084 IO_STACK_LOCATION Stack
;
1086 ULONG RequiredLength
;
1088 HANDLE InstanceKey
= NULL
;
1089 UNICODE_STRING ValueName
;
1090 UNICODE_STRING InstancePathU
;
1091 PDEVICE_OBJECT OldDeviceObject
;
1093 DPRINT("PiProcessNewDevNode(%p)\n", DeviceNode
);
1094 DPRINT("PDO 0x%p\n", DeviceNode
->PhysicalDeviceObject
);
1097 Status
= ZwQueryDefaultLocale(FALSE
, &LocaleId
);
1098 if (!NT_SUCCESS(Status
))
1100 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status
);
1105 * FIXME: For critical errors, cleanup and disable device, but always
1106 * return STATUS_SUCCESS.
1109 Status
= IopCreateDeviceInstancePath(DeviceNode
, &InstancePathU
);
1110 if (!NT_SUCCESS(Status
))
1112 if (Status
!= STATUS_PLUGPLAY_NO_DEVICE
)
1114 DPRINT1("IopCreateDeviceInstancePath() failed with status 0x%lx\n", Status
);
1119 /* Verify that this is not a duplicate */
1120 OldDeviceObject
= IopGetDeviceObjectFromDeviceInstance(&InstancePathU
);
1121 if (OldDeviceObject
!= NULL
)
1123 PDEVICE_NODE OldDeviceNode
= IopGetDeviceNode(OldDeviceObject
);
1125 DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU
);
1126 DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode
->Parent
->InstancePath
);
1127 DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode
->Parent
->InstancePath
);
1129 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR
,
1131 (ULONG_PTR
)DeviceNode
->PhysicalDeviceObject
,
1132 (ULONG_PTR
)OldDeviceObject
,
1136 DeviceNode
->InstancePath
= InstancePathU
;
1138 DPRINT("InstancePath is %S\n", DeviceNode
->InstancePath
.Buffer
);
1141 * Create registry key for the instance id, if it doesn't exist yet
1143 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, REG_OPTION_NON_VOLATILE
, &InstanceKey
);
1144 if (!NT_SUCCESS(Status
))
1146 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status
);
1148 /* We have to return success otherwise we abort the traverse operation */
1149 return STATUS_SUCCESS
;
1152 IopQueryHardwareIds(DeviceNode
, InstanceKey
);
1154 IopQueryCompatibleIds(DeviceNode
, InstanceKey
);
1156 DeviceNode
->Flags
|= DNF_IDS_QUERIED
;
1158 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
1160 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextDescription
;
1161 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
1162 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1164 IRP_MN_QUERY_DEVICE_TEXT
,
1166 DeviceDescription
= NT_SUCCESS(Status
) ? (PWSTR
)IoStatusBlock
.Information
1168 /* This key is mandatory, so even if the Irp fails, we still write it */
1169 RtlInitUnicodeString(&ValueName
, L
"DeviceDesc");
1170 if (ZwQueryValueKey(InstanceKey
, &ValueName
, KeyValueBasicInformation
, NULL
, 0, &RequiredLength
) == STATUS_OBJECT_NAME_NOT_FOUND
)
1172 if (DeviceDescription
&&
1173 *DeviceDescription
!= UNICODE_NULL
)
1175 /* This key is overriden when a driver is installed. Don't write the
1176 * new description if another one already exists */
1177 Status
= ZwSetValueKey(InstanceKey
,
1182 ((ULONG
)wcslen(DeviceDescription
) + 1) * sizeof(WCHAR
));
1186 UNICODE_STRING DeviceDesc
= RTL_CONSTANT_STRING(L
"Unknown device");
1187 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status
);
1189 Status
= ZwSetValueKey(InstanceKey
,
1194 DeviceDesc
.MaximumLength
);
1195 if (!NT_SUCCESS(Status
))
1197 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status
);
1203 if (DeviceDescription
)
1205 ExFreePoolWithTag(DeviceDescription
, 0);
1208 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
1210 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextLocationInformation
;
1211 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
1212 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1214 IRP_MN_QUERY_DEVICE_TEXT
,
1216 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
1218 LocationInformation
= (PWSTR
)IoStatusBlock
.Information
;
1219 DPRINT("LocationInformation: %S\n", LocationInformation
);
1220 RtlInitUnicodeString(&ValueName
, L
"LocationInformation");
1221 Status
= ZwSetValueKey(InstanceKey
,
1225 LocationInformation
,
1226 ((ULONG
)wcslen(LocationInformation
) + 1) * sizeof(WCHAR
));
1227 if (!NT_SUCCESS(Status
))
1229 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
1232 ExFreePoolWithTag(LocationInformation
, 0);
1236 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
1239 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
1241 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1243 IRP_MN_QUERY_BUS_INFORMATION
,
1245 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
1247 PPNP_BUS_INFORMATION BusInformation
= (PPNP_BUS_INFORMATION
)IoStatusBlock
.Information
;
1249 DeviceNode
->ChildBusNumber
= BusInformation
->BusNumber
;
1250 DeviceNode
->ChildInterfaceType
= BusInformation
->LegacyBusType
;
1251 DeviceNode
->ChildBusTypeIndex
= IopGetBusTypeGuidIndex(&BusInformation
->BusTypeGuid
);
1252 ExFreePoolWithTag(BusInformation
, 0);
1256 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
1258 DeviceNode
->ChildBusNumber
= 0xFFFFFFF0;
1259 DeviceNode
->ChildInterfaceType
= InterfaceTypeUndefined
;
1260 DeviceNode
->ChildBusTypeIndex
= -1;
1263 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
1265 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1267 IRP_MN_QUERY_RESOURCES
,
1269 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
1271 DeviceNode
->BootResources
= (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
1272 IopDeviceNodeSetFlag(DeviceNode
, DNF_HAS_BOOT_CONFIG
);
1276 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
1277 DeviceNode
->BootResources
= NULL
;
1280 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
1282 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1284 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
1286 if (NT_SUCCESS(Status
))
1288 DeviceNode
->ResourceRequirements
= (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
1292 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status
);
1293 DeviceNode
->ResourceRequirements
= NULL
;
1296 if (InstanceKey
!= NULL
)
1298 IopSetDeviceInstanceData(InstanceKey
, DeviceNode
);
1301 // Try installing a critical device, so its Service key is populated
1302 // then call IopSetServiceEnumData to populate service's Enum key.
1303 // That allows us to start devices during an early boot
1304 IopInstallCriticalDevice(DeviceNode
);
1305 IopSetServiceEnumData(DeviceNode
, InstanceKey
);
1307 ZwClose(InstanceKey
);
1309 PiSetDevNodeState(DeviceNode
, DeviceNodeInitialized
);
1311 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_LEGACY_DRIVER
))
1313 /* Report the device to the user-mode pnp manager */
1314 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED
,
1315 &DeviceNode
->InstancePath
);
1318 return STATUS_SUCCESS
;
1323 IopSetServiceEnumData(
1324 _In_ PDEVICE_NODE DeviceNode
,
1325 _In_ HANDLE InstanceHandle
)
1327 UNICODE_STRING ServicesKeyPath
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
1328 UNICODE_STRING ServiceKeyName
;
1329 UNICODE_STRING EnumKeyName
;
1330 UNICODE_STRING ValueName
;
1331 UNICODE_STRING ServiceName
;
1332 PKEY_VALUE_FULL_INFORMATION KeyValueInformation
, kvInfo2
;
1333 HANDLE ServiceKey
= NULL
, ServiceEnumKey
= NULL
;
1335 ULONG Count
= 0, NextInstance
= 0;
1336 WCHAR ValueBuffer
[6];
1337 NTSTATUS Status
= STATUS_SUCCESS
;
1339 // obtain the device node's ServiceName
1340 Status
= IopGetRegistryValue(InstanceHandle
, L
"Service", &kvInfo2
);
1341 if (!NT_SUCCESS(Status
))
1346 if (kvInfo2
->Type
!= REG_SZ
|| kvInfo2
->DataLength
<= sizeof(WCHAR
))
1348 ExFreePool(kvInfo2
);
1349 return STATUS_UNSUCCESSFUL
;
1352 ServiceName
.MaximumLength
= kvInfo2
->DataLength
;
1353 ServiceName
.Length
= kvInfo2
->DataLength
- sizeof(UNICODE_NULL
);
1354 ServiceName
.Buffer
= (PVOID
)((ULONG_PTR
)kvInfo2
+ kvInfo2
->DataOffset
);
1356 DPRINT("IopSetServiceEnumData(%p)\n", DeviceNode
);
1357 DPRINT("Instance: %wZ\n", &DeviceNode
->InstancePath
);
1358 DPRINT("Service: %wZ\n", &ServiceName
);
1360 ServiceKeyName
.MaximumLength
= ServicesKeyPath
.Length
+ ServiceName
.Length
+ sizeof(UNICODE_NULL
);
1361 ServiceKeyName
.Length
= 0;
1362 ServiceKeyName
.Buffer
= ExAllocatePool(PagedPool
, ServiceKeyName
.MaximumLength
);
1363 if (ServiceKeyName
.Buffer
== NULL
)
1365 DPRINT1("No ServiceKeyName.Buffer!\n");
1366 return STATUS_INSUFFICIENT_RESOURCES
;
1369 RtlAppendUnicodeStringToString(&ServiceKeyName
, &ServicesKeyPath
);
1370 RtlAppendUnicodeStringToString(&ServiceKeyName
, &ServiceName
);
1372 DPRINT("ServiceKeyName: %wZ\n", &ServiceKeyName
);
1374 Status
= IopOpenRegistryKeyEx(&ServiceKey
, NULL
, &ServiceKeyName
, KEY_CREATE_SUB_KEY
);
1375 if (!NT_SUCCESS(Status
))
1380 RtlInitUnicodeString(&EnumKeyName
, L
"Enum");
1381 Status
= IopCreateRegistryKeyEx(&ServiceEnumKey
,
1385 REG_OPTION_VOLATILE
,
1387 if (NT_SUCCESS(Status
))
1389 if (Disposition
== REG_OPENED_EXISTING_KEY
)
1391 /* Read the NextInstance value */
1392 Status
= IopGetRegistryValue(ServiceEnumKey
,
1394 &KeyValueInformation
);
1395 if (!NT_SUCCESS(Status
))
1398 if ((KeyValueInformation
->Type
== REG_DWORD
) &&
1399 (KeyValueInformation
->DataLength
))
1402 Count
= *(PULONG
)((ULONG_PTR
)KeyValueInformation
+
1403 KeyValueInformation
->DataOffset
);
1406 ExFreePool(KeyValueInformation
);
1407 KeyValueInformation
= NULL
;
1409 /* Read the NextInstance value */
1410 Status
= IopGetRegistryValue(ServiceEnumKey
,
1412 &KeyValueInformation
);
1413 if (!NT_SUCCESS(Status
))
1416 if ((KeyValueInformation
->Type
== REG_DWORD
) &&
1417 (KeyValueInformation
->DataLength
))
1419 NextInstance
= *(PULONG
)((ULONG_PTR
)KeyValueInformation
+
1420 KeyValueInformation
->DataOffset
);
1423 ExFreePool(KeyValueInformation
);
1424 KeyValueInformation
= NULL
;
1427 /* Set the instance path */
1428 swprintf(ValueBuffer
, L
"%lu", NextInstance
);
1429 RtlInitUnicodeString(&ValueName
, ValueBuffer
);
1430 Status
= ZwSetValueKey(ServiceEnumKey
,
1434 DeviceNode
->InstancePath
.Buffer
,
1435 DeviceNode
->InstancePath
.MaximumLength
);
1436 if (!NT_SUCCESS(Status
))
1439 /* Increment Count and NextInstance */
1443 /* Set the new Count value */
1444 RtlInitUnicodeString(&ValueName
, L
"Count");
1445 Status
= ZwSetValueKey(ServiceEnumKey
,
1451 if (!NT_SUCCESS(Status
))
1454 /* Set the new NextInstance value */
1455 RtlInitUnicodeString(&ValueName
, L
"NextInstance");
1456 Status
= ZwSetValueKey(ServiceEnumKey
,
1461 sizeof(NextInstance
));
1464 RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING
,
1466 &DeviceNode
->ServiceName
);
1469 if (ServiceEnumKey
!= NULL
)
1470 ZwClose(ServiceEnumKey
);
1472 if (ServiceKey
!= NULL
)
1473 ZwClose(ServiceKey
);
1475 ExFreePool(ServiceKeyName
.Buffer
);
1476 ExFreePool(kvInfo2
);
1484 _In_ PDEVICE_NODE DeviceNode
)
1486 DEVICE_CAPABILITIES DeviceCapabilities
;
1489 if (!(DeviceNode
->Flags
& DNF_IDS_QUERIED
))
1491 // query ids (for reported devices)
1492 UNICODE_STRING enumRoot
= RTL_CONSTANT_STRING(ENUM_ROOT
);
1493 HANDLE enumRootHandle
, instanceHandle
;
1495 // open the enumeration root key
1496 Status
= IopOpenRegistryKeyEx(&enumRootHandle
, NULL
, &enumRoot
, KEY_READ
);
1497 if (!NT_SUCCESS(Status
))
1499 DPRINT1("IopOpenRegistryKeyEx() failed for \"%wZ\" (status %x)\n", &enumRoot
, Status
);
1503 // open an instance subkey
1504 Status
= IopOpenRegistryKeyEx(&instanceHandle
, enumRootHandle
, &DeviceNode
->InstancePath
, KEY_READ
);
1505 ZwClose(enumRootHandle
);
1506 if (!NT_SUCCESS(Status
))
1508 DPRINT1("Failed to open a devnode instance key for \"%wZ\" (status %x)\n",
1509 &DeviceNode
->InstancePath
, Status
);
1513 IopQueryHardwareIds(DeviceNode
, instanceHandle
);
1514 IopQueryCompatibleIds(DeviceNode
, instanceHandle
);
1516 DeviceNode
->Flags
|= DNF_IDS_QUERIED
;
1517 ZwClose(instanceHandle
);
1520 // we're about to start - needs enumeration
1521 DeviceNode
->Flags
|= DNF_REENUMERATE
;
1523 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n");
1525 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
1526 if (!NT_SUCCESS(Status
))
1528 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
1531 /* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */
1532 IoInvalidateDeviceState(DeviceNode
->PhysicalDeviceObject
);
1534 DPRINT("Sending GUID_DEVICE_ARRIVAL %wZ\n", &DeviceNode
->InstancePath
);
1535 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL
, &DeviceNode
->InstancePath
);
1537 PiSetDevNodeState(DeviceNode
, DeviceNodeStarted
);
1539 return STATUS_SUCCESS
;
1542 /* PUBLIC FUNCTIONS **********************************************************/
1545 * @brief Sends one of the remove IRPs to the device stack
1547 * If there is a mounted VPB attached to a one of the stack devices, the IRP
1548 * should be send to a VPB's DeviceObject first (which belongs to a FS driver).
1549 * FS driver will then forward it down to the volume device.
1550 * While walking the device stack, the function sets (or unsets) VPB_REMOVE_PENDING flag
1551 * thus blocking all further mounts on a soon-to-be-removed devices
1555 PiIrpSendRemoveCheckVpb(
1556 _In_ PDEVICE_OBJECT DeviceObject
,
1557 _In_ UCHAR MinorFunction
)
1561 ASSERT(MinorFunction
== IRP_MN_QUERY_REMOVE_DEVICE
||
1562 MinorFunction
== IRP_MN_CANCEL_REMOVE_DEVICE
||
1563 MinorFunction
== IRP_MN_SURPRISE_REMOVAL
||
1564 MinorFunction
== IRP_MN_REMOVE_DEVICE
);
1566 PDEVICE_OBJECT vpbDevObj
= DeviceObject
, targetDevice
= DeviceObject
;
1568 // walk the device stack down, stop on a first mounted device
1573 // two locks are needed here
1574 KeWaitForSingleObject(&vpbDevObj
->DeviceLock
, Executive
, KernelMode
, FALSE
, NULL
);
1575 IoAcquireVpbSpinLock(&oldIrql
);
1577 if (MinorFunction
== IRP_MN_CANCEL_REMOVE_DEVICE
)
1579 vpbDevObj
->Vpb
->Flags
&= ~VPB_REMOVE_PENDING
;
1583 vpbDevObj
->Vpb
->Flags
|= VPB_REMOVE_PENDING
;
1586 BOOLEAN isMounted
= (_Bool
)(vpbDevObj
->Vpb
->Flags
& VPB_MOUNTED
);
1590 targetDevice
= vpbDevObj
->Vpb
->DeviceObject
;
1593 IoReleaseVpbSpinLock(oldIrql
);
1594 KeSetEvent(&vpbDevObj
->DeviceLock
, IO_NO_INCREMENT
, FALSE
);
1602 oldIrql
= KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock
);
1603 vpbDevObj
= vpbDevObj
->AttachedDevice
;
1604 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock
, oldIrql
);
1605 } while (vpbDevObj
);
1607 ASSERT(targetDevice
);
1610 IO_STACK_LOCATION stack
= {.MajorFunction
= IRP_MJ_PNP
, .MinorFunction
= MinorFunction
};
1612 return IopSynchronousCall(targetDevice
, &stack
, &info
);
1618 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
1620 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
1622 ASSERT(DeviceNode
->State
== DeviceNodeAwaitingQueuedRemoval
);
1624 /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
1625 PiIrpSendRemoveCheckVpb(DeviceObject
, IRP_MN_REMOVE_DEVICE
);
1627 PiSetDevNodeState(DeviceNode
, DeviceNodeRemoved
);
1628 PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_REMOVE_COMPLETE
, DeviceObject
, NULL
);
1629 LONG_PTR refCount
= ObDereferenceObject(DeviceObject
);
1632 DPRINT1("Leaking device %wZ, refCount = %d\n", &DeviceNode
->InstancePath
, (INT32
)refCount
);
1638 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations
)
1640 /* This function DOES dereference the device objects in all cases */
1644 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
1646 IopSendRemoveDevice(DeviceRelations
->Objects
[i
]);
1647 DeviceRelations
->Objects
[i
] = NULL
;
1650 ExFreePool(DeviceRelations
);
1655 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
)
1657 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
;
1660 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1661 ChildDeviceNode
= ParentDeviceNode
->Child
;
1662 while (ChildDeviceNode
!= NULL
)
1664 NextDeviceNode
= ChildDeviceNode
->Sibling
;
1665 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1667 IopSendRemoveDevice(ChildDeviceNode
->PhysicalDeviceObject
);
1669 ChildDeviceNode
= NextDeviceNode
;
1671 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1673 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1679 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject
)
1681 ASSERT(IopGetDeviceNode(DeviceObject
)->State
== DeviceNodeAwaitingQueuedRemoval
);
1682 /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */
1683 PiIrpSendRemoveCheckVpb(DeviceObject
, IRP_MN_SURPRISE_REMOVAL
);
1689 IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
1691 /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */
1692 PiIrpSendRemoveCheckVpb(DeviceObject
, IRP_MN_CANCEL_REMOVE_DEVICE
);
1694 PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_REMOVE_CANCELLED
, DeviceObject
, NULL
);
1699 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
)
1701 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
;
1704 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1705 ChildDeviceNode
= ParentDeviceNode
->Child
;
1706 while (ChildDeviceNode
!= NULL
)
1708 NextDeviceNode
= ChildDeviceNode
->Sibling
;
1709 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1711 IopCancelPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
);
1713 ChildDeviceNode
= NextDeviceNode
;
1715 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1717 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1722 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations
)
1724 /* This function DOES dereference the device objects in all cases */
1728 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
1730 IopCancelPrepareDeviceForRemoval(DeviceRelations
->Objects
[i
]);
1731 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
1732 DeviceRelations
->Objects
[i
] = NULL
;
1735 ExFreePool(DeviceRelations
);
1740 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject
)
1742 IO_STACK_LOCATION Stack
;
1743 IO_STATUS_BLOCK IoStatusBlock
;
1744 PDEVICE_RELATIONS DeviceRelations
;
1747 IopCancelRemoveDevice(DeviceObject
);
1749 Stack
.Parameters
.QueryDeviceRelations
.Type
= RemovalRelations
;
1751 Status
= IopInitiatePnpIrp(DeviceObject
,
1753 IRP_MN_QUERY_DEVICE_RELATIONS
,
1755 if (!NT_SUCCESS(Status
))
1757 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
1758 DeviceRelations
= NULL
;
1762 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
1765 if (DeviceRelations
)
1766 IopCancelRemoveDeviceRelations(DeviceRelations
);
1772 IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
1774 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
1779 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING
,
1780 &DeviceNode
->InstancePath
);
1782 Status
= PiIrpSendRemoveCheckVpb(DeviceObject
, IRP_MN_QUERY_REMOVE_DEVICE
);
1784 PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_QUERY_REMOVE
, DeviceObject
, NULL
);
1786 if (!NT_SUCCESS(Status
))
1788 DPRINT1("Removal vetoed by %wZ\n", &DeviceNode
->InstancePath
);
1789 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED
,
1790 &DeviceNode
->InstancePath
);
1798 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
, BOOLEAN Force
)
1800 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
, FailedRemoveDevice
;
1804 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1805 ChildDeviceNode
= ParentDeviceNode
->Child
;
1806 while (ChildDeviceNode
!= NULL
)
1808 NextDeviceNode
= ChildDeviceNode
->Sibling
;
1809 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1810 PiSetDevNodeState(ChildDeviceNode
, DeviceNodeAwaitingQueuedRemoval
);
1812 Status
= IopPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
, Force
);
1813 if (!NT_SUCCESS(Status
))
1815 FailedRemoveDevice
= ChildDeviceNode
;
1819 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1820 ChildDeviceNode
= NextDeviceNode
;
1822 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1824 return STATUS_SUCCESS
;
1827 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1828 ChildDeviceNode
= ParentDeviceNode
->Child
;
1829 while (ChildDeviceNode
!= NULL
)
1831 NextDeviceNode
= ChildDeviceNode
->Sibling
;
1832 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1834 IopCancelPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
);
1836 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
1837 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
1838 if (ChildDeviceNode
== FailedRemoveDevice
)
1841 ChildDeviceNode
= NextDeviceNode
;
1843 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1845 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1852 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations
, BOOLEAN Force
)
1854 /* This function DOES NOT dereference the device objects on SUCCESS
1855 * but it DOES dereference device objects on FAILURE */
1860 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
1862 Status
= IopPrepareDeviceForRemoval(DeviceRelations
->Objects
[i
], Force
);
1863 if (!NT_SUCCESS(Status
))
1870 return STATUS_SUCCESS
;
1873 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
1874 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
1875 for (i
= 0; i
<= j
; i
++)
1877 IopCancelPrepareDeviceForRemoval(DeviceRelations
->Objects
[i
]);
1878 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
1879 DeviceRelations
->Objects
[i
] = NULL
;
1881 for (; i
< DeviceRelations
->Count
; i
++)
1883 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
1884 DeviceRelations
->Objects
[i
] = NULL
;
1886 ExFreePool(DeviceRelations
);
1893 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject
, BOOLEAN Force
)
1895 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
1896 IO_STACK_LOCATION Stack
;
1897 IO_STATUS_BLOCK IoStatusBlock
;
1898 PDEVICE_RELATIONS DeviceRelations
;
1901 if ((DeviceNode
->UserFlags
& DNUF_NOT_DISABLEABLE
) && !Force
)
1903 DPRINT1("Removal not allowed for %wZ\n", &DeviceNode
->InstancePath
);
1904 return STATUS_UNSUCCESSFUL
;
1907 if (!Force
&& IopQueryRemoveDevice(DeviceObject
) != STATUS_SUCCESS
)
1909 DPRINT1("Removal vetoed by failing the query remove request\n");
1911 IopCancelRemoveDevice(DeviceObject
);
1913 return STATUS_UNSUCCESSFUL
;
1916 Stack
.Parameters
.QueryDeviceRelations
.Type
= RemovalRelations
;
1918 Status
= IopInitiatePnpIrp(DeviceObject
,
1920 IRP_MN_QUERY_DEVICE_RELATIONS
,
1922 if (!NT_SUCCESS(Status
))
1924 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
1925 DeviceRelations
= NULL
;
1929 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
1932 if (DeviceRelations
)
1934 Status
= IopQueryRemoveDeviceRelations(DeviceRelations
, Force
);
1935 if (!NT_SUCCESS(Status
))
1939 Status
= IopQueryRemoveChildDevices(DeviceNode
, Force
);
1940 if (!NT_SUCCESS(Status
))
1942 if (DeviceRelations
)
1943 IopCancelRemoveDeviceRelations(DeviceRelations
);
1947 if (DeviceRelations
)
1948 IopSendRemoveDeviceRelations(DeviceRelations
);
1949 IopSendRemoveChildDevices(DeviceNode
);
1951 return STATUS_SUCCESS
;
1956 IopRemoveDevice(PDEVICE_NODE DeviceNode
)
1960 // This function removes the device subtree, with the root in DeviceNode
1961 // atm everyting is in fact done inside this function, which is completely wrong.
1962 // The right implementation should have a separate removal worker thread and
1963 // properly do device node state transitions
1965 DPRINT("Removing device: %wZ\n", &DeviceNode
->InstancePath
);
1967 BOOLEAN surpriseRemoval
= (_Bool
)(DeviceNode
->Flags
& DNF_DEVICE_GONE
);
1969 Status
= IopPrepareDeviceForRemoval(DeviceNode
->PhysicalDeviceObject
, surpriseRemoval
);
1971 if (surpriseRemoval
)
1973 IopSendSurpriseRemoval(DeviceNode
->PhysicalDeviceObject
);
1974 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL
, &DeviceNode
->InstancePath
);
1977 if (NT_SUCCESS(Status
))
1979 IopSendRemoveDevice(DeviceNode
->PhysicalDeviceObject
);
1980 if (surpriseRemoval
)
1982 IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL
, &DeviceNode
->InstancePath
);
1984 return STATUS_SUCCESS
;
1995 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject
)
1997 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(PhysicalDeviceObject
);
1998 PNP_DEVICE_STATE PnPFlags
;
2001 Status
= PiIrpQueryPnPDeviceState(DeviceNode
, &PnPFlags
);
2002 if (!NT_SUCCESS(Status
))
2004 if (Status
!= STATUS_NOT_SUPPORTED
)
2006 DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%lx\n", Status
);
2011 if (PnPFlags
& PNP_DEVICE_NOT_DISABLEABLE
)
2012 DeviceNode
->UserFlags
|= DNUF_NOT_DISABLEABLE
;
2014 DeviceNode
->UserFlags
&= ~DNUF_NOT_DISABLEABLE
;
2016 if (PnPFlags
& PNP_DEVICE_DONT_DISPLAY_IN_UI
)
2017 DeviceNode
->UserFlags
|= DNUF_DONT_SHOW_IN_UI
;
2019 DeviceNode
->UserFlags
&= ~DNUF_DONT_SHOW_IN_UI
;
2021 if ((PnPFlags
& PNP_DEVICE_REMOVED
) ||
2022 ((PnPFlags
& PNP_DEVICE_FAILED
) && !(PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
)))
2024 /* Flag it if it's failed */
2025 if (PnPFlags
& PNP_DEVICE_FAILED
)
2027 PiSetDevNodeProblem(DeviceNode
, CM_PROB_FAILED_POST_START
);
2030 DeviceNode
->Flags
|= DNF_DEVICE_GONE
;
2031 PiSetDevNodeState(DeviceNode
, DeviceNodeAwaitingQueuedRemoval
);
2033 // it doesn't work anyway. A real resource rebalancing should be implemented
2035 else if ((PnPFlags
& PNP_DEVICE_FAILED
) && (PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
))
2037 /* Stop for resource rebalance */
2038 Status
= IopStopDevice(DeviceNode
);
2039 if (!NT_SUCCESS(Status
))
2041 DPRINT1("Failed to stop device for rebalancing\n");
2043 /* Stop failed so don't rebalance */
2044 PnPFlags
&= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
;
2048 /* Resource rebalance */
2049 if (PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
)
2051 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2053 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
2055 IRP_MN_QUERY_RESOURCES
,
2057 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2059 DeviceNode
->BootResources
=
2060 (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
2061 IopDeviceNodeSetFlag(DeviceNode
, DNF_HAS_BOOT_CONFIG
);
2065 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2066 DeviceNode
->BootResources
= NULL
;
2069 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2071 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
2073 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
2075 if (NT_SUCCESS(Status
))
2077 DeviceNode
->ResourceRequirements
=
2078 (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
2082 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status
);
2083 DeviceNode
->ResourceRequirements
= NULL
;
2086 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */
2087 if (IopStartDevice(DeviceNode
) != STATUS_SUCCESS
)
2089 DPRINT1("Restart after resource rebalance failed\n");
2091 DeviceNode
->Flags
&= ~(DNF_STARTED
| DNF_START_REQUEST_PENDING
);
2092 DeviceNode
->Flags
|= DNF_START_FAILED
;
2094 IopRemoveDevice(DeviceNode
);
2103 _In_ PDEVICE_NODE DeviceNode
)
2105 PDEVICE_OBJECT ChildDeviceObject
;
2106 PDEVICE_NODE ChildDeviceNode
;
2109 // bus relations are already obtained for this device node
2111 if (!NT_SUCCESS(DeviceNode
->CompletionStatus
))
2113 DPRINT("QDR request failed for %wZ, status %x\n",
2114 &DeviceNode
->InstancePath
, DeviceNode
->CompletionStatus
);
2115 // treat as if there are no child objects
2118 PDEVICE_RELATIONS DeviceRelations
= DeviceNode
->OverUsed1
.PendingDeviceRelations
;
2119 DeviceNode
->OverUsed1
.PendingDeviceRelations
= NULL
;
2121 // it's acceptable not to have PDOs
2122 if (!DeviceRelations
)
2124 PiSetDevNodeState(DeviceNode
, DeviceNodeStarted
);
2125 DPRINT("No PDOs\n");
2126 return STATUS_SUCCESS
;
2129 // mark children nodes as non-present (those not returned in DR request will be removed)
2130 for (PDEVICE_NODE child
= DeviceNode
->Child
; child
!= NULL
; child
= child
->Sibling
)
2132 child
->Flags
&= ~DNF_ENUMERATED
;
2135 DPRINT("PiEnumerateDevice: enumerating %u children\n", DeviceRelations
->Count
);
2137 // create device nodes for all new children and set DNF_ENUMERATED back for old ones
2138 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
2140 ChildDeviceObject
= DeviceRelations
->Objects
[i
];
2141 ASSERT((ChildDeviceObject
->Flags
& DO_DEVICE_INITIALIZING
) == 0);
2143 ChildDeviceNode
= IopGetDeviceNode(ChildDeviceObject
);
2144 if (!ChildDeviceNode
)
2146 /* One doesn't exist, create it */
2147 ChildDeviceNode
= PipAllocateDeviceNode(ChildDeviceObject
);
2148 if (ChildDeviceNode
)
2150 PiInsertDevNode(ChildDeviceNode
, DeviceNode
);
2152 /* Mark the node as enumerated */
2153 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2155 /* Mark the DO as bus enumerated */
2156 ChildDeviceObject
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
2160 /* Ignore this DO */
2161 DPRINT1("PipAllocateDeviceNode() failed. Skipping PDO %u\n", i
);
2162 ObDereferenceObject(ChildDeviceObject
);
2167 /* Mark it as enumerated */
2168 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2169 ObDereferenceObject(ChildDeviceObject
);
2172 ExFreePool(DeviceRelations
);
2174 // time to remove non-reported devices
2175 for (PDEVICE_NODE child
= DeviceNode
->Child
; child
!= NULL
; child
= child
->Sibling
)
2177 if (!(child
->Flags
& (DNF_ENUMERATED
|DNF_DEVICE_GONE
)))
2179 // this flag indicates that this is a surprise removal
2180 child
->Flags
|= DNF_DEVICE_GONE
;
2181 PiSetDevNodeState(child
, DeviceNodeAwaitingQueuedRemoval
);
2185 PiSetDevNodeState(DeviceNode
, DeviceNodeStarted
);
2186 return STATUS_SUCCESS
;
2192 IopSendEject(IN PDEVICE_OBJECT DeviceObject
)
2194 IO_STACK_LOCATION Stack
;
2197 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
2198 Stack
.MajorFunction
= IRP_MJ_PNP
;
2199 Stack
.MinorFunction
= IRP_MN_EJECT
;
2201 return IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
2209 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject
)
2211 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(PhysicalDeviceObject
);
2212 PDEVICE_RELATIONS DeviceRelations
;
2213 IO_STATUS_BLOCK IoStatusBlock
;
2214 IO_STACK_LOCATION Stack
;
2215 DEVICE_CAPABILITIES Capabilities
;
2218 IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT
,
2219 &DeviceNode
->InstancePath
);
2221 if (IopQueryDeviceCapabilities(DeviceNode
, &Capabilities
) != STATUS_SUCCESS
)
2226 Stack
.Parameters
.QueryDeviceRelations
.Type
= EjectionRelations
;
2228 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
2230 IRP_MN_QUERY_DEVICE_RELATIONS
,
2232 if (!NT_SUCCESS(Status
))
2234 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
2235 DeviceRelations
= NULL
;
2239 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
2242 if (DeviceRelations
)
2244 Status
= IopQueryRemoveDeviceRelations(DeviceRelations
, FALSE
);
2245 if (!NT_SUCCESS(Status
))
2249 Status
= IopQueryRemoveChildDevices(DeviceNode
, FALSE
);
2250 if (!NT_SUCCESS(Status
))
2252 if (DeviceRelations
)
2253 IopCancelRemoveDeviceRelations(DeviceRelations
);
2257 if (IopPrepareDeviceForRemoval(PhysicalDeviceObject
, FALSE
) != STATUS_SUCCESS
)
2259 if (DeviceRelations
)
2260 IopCancelRemoveDeviceRelations(DeviceRelations
);
2261 IopCancelRemoveChildDevices(DeviceNode
);
2265 if (DeviceRelations
)
2266 IopSendRemoveDeviceRelations(DeviceRelations
);
2267 IopSendRemoveChildDevices(DeviceNode
);
2269 DeviceNode
->Problem
= CM_PROB_HELD_FOR_EJECT
;
2270 if (Capabilities
.EjectSupported
)
2272 if (IopSendEject(PhysicalDeviceObject
) != STATUS_SUCCESS
)
2279 // DeviceNode->Flags |= DNF_DISABLED;
2282 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT
,
2283 &DeviceNode
->InstancePath
);
2288 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED
,
2289 &DeviceNode
->InstancePath
);
2294 PiDevNodeStateMachine(
2295 _In_ PDEVICE_NODE RootNode
)
2298 BOOLEAN doProcessAgain
;
2299 PDEVICE_NODE currentNode
= RootNode
;
2300 PDEVICE_OBJECT referencedObject
;
2304 doProcessAgain
= FALSE
;
2306 // The device can be removed during processing, but we still need its Parent and Sibling
2307 // links to continue the tree traversal. So keep the link till the and of a cycle
2308 referencedObject
= currentNode
->PhysicalDeviceObject
;
2309 ObReferenceObject(referencedObject
);
2311 // Devices with problems are skipped (unless they are not being removed)
2312 if (currentNode
->Flags
& DNF_HAS_PROBLEM
&&
2313 currentNode
->State
!= DeviceNodeAwaitingQueuedRemoval
)
2318 switch (currentNode
->State
)
2320 case DeviceNodeUnspecified
: // this state is not used
2322 case DeviceNodeUninitialized
:
2323 DPRINT("DeviceNodeUninitialized %wZ\n", ¤tNode
->InstancePath
);
2324 status
= PiInitializeDevNode(currentNode
);
2325 doProcessAgain
= NT_SUCCESS(status
);
2327 case DeviceNodeInitialized
:
2328 DPRINT("DeviceNodeInitialized %wZ\n", ¤tNode
->InstancePath
);
2329 status
= PiCallDriverAddDevice(currentNode
, PnPBootDriversInitialized
);
2330 doProcessAgain
= NT_SUCCESS(status
);
2332 case DeviceNodeDriversAdded
:
2333 DPRINT("DeviceNodeDriversAdded %wZ\n", ¤tNode
->InstancePath
);
2334 status
= IopAssignDeviceResources(currentNode
);
2335 doProcessAgain
= NT_SUCCESS(status
);
2337 case DeviceNodeResourcesAssigned
:
2338 DPRINT("DeviceNodeResourcesAssigned %wZ\n", ¤tNode
->InstancePath
);
2339 // send IRP_MN_START_DEVICE
2340 PiIrpStartDevice(currentNode
);
2342 // skip DeviceNodeStartPending, it is probably used for an async IRP_MN_START_DEVICE
2343 PiSetDevNodeState(currentNode
, DeviceNodeStartCompletion
);
2344 doProcessAgain
= TRUE
;
2346 case DeviceNodeStartPending
: // skipped on XP/2003
2348 case DeviceNodeStartCompletion
:
2349 DPRINT("DeviceNodeStartCompletion %wZ\n", ¤tNode
->InstancePath
);
2350 status
= currentNode
->CompletionStatus
;
2351 doProcessAgain
= TRUE
;
2352 if (!NT_SUCCESS(status
))
2354 UINT32 problem
= (status
== STATUS_PNP_REBOOT_REQUIRED
)
2355 ? CM_PROB_NEED_RESTART
2356 : CM_PROB_FAILED_START
;
2358 PiSetDevNodeProblem(currentNode
, problem
);
2359 PiSetDevNodeState(currentNode
, DeviceNodeAwaitingQueuedRemoval
);
2363 // TODO: IopDoDeferredSetInterfaceState and IopAllocateLegacyBootResources
2364 // are called here too
2366 PiSetDevNodeState(currentNode
, DeviceNodeStartPostWork
);
2369 case DeviceNodeStartPostWork
:
2370 DPRINT("DeviceNodeStartPostWork %wZ\n", ¤tNode
->InstancePath
);
2371 status
= PiStartDeviceFinal(currentNode
);
2372 doProcessAgain
= TRUE
;
2374 case DeviceNodeStarted
:
2375 if (currentNode
->Flags
& DNF_REENUMERATE
)
2377 DPRINT("DeviceNodeStarted REENUMERATE %wZ\n", ¤tNode
->InstancePath
);
2378 currentNode
->Flags
&= ~DNF_REENUMERATE
;
2379 status
= PiIrpQueryDeviceRelations(currentNode
, BusRelations
);
2381 // again, skip DeviceNodeEnumeratePending as with the starting sequence
2382 PiSetDevNodeState(currentNode
, DeviceNodeEnumerateCompletion
);
2383 doProcessAgain
= TRUE
;
2386 case DeviceNodeQueryStopped
:
2387 // we're here after sending IRP_MN_QUERY_STOP_DEVICE
2388 status
= currentNode
->CompletionStatus
;
2389 if (NT_SUCCESS(status
))
2391 PiSetDevNodeState(currentNode
, DeviceNodeStopped
);
2395 PiIrpCancelStopDevice(currentNode
);
2396 PiSetDevNodeState(currentNode
, DeviceNodeStarted
);
2399 case DeviceNodeStopped
:
2400 // TODO: do resource rebalance (not implemented)
2403 case DeviceNodeRestartCompletion
:
2405 case DeviceNodeEnumeratePending
: // skipped on XP/2003
2407 case DeviceNodeEnumerateCompletion
:
2408 DPRINT("DeviceNodeEnumerateCompletion %wZ\n", ¤tNode
->InstancePath
);
2409 status
= PiEnumerateDevice(currentNode
);
2410 doProcessAgain
= TRUE
;
2412 case DeviceNodeAwaitingQueuedDeletion
:
2414 case DeviceNodeAwaitingQueuedRemoval
:
2415 DPRINT("DeviceNodeAwaitingQueuedRemoval %wZ\n", ¤tNode
->InstancePath
);
2416 status
= IopRemoveDevice(currentNode
);
2418 case DeviceNodeQueryRemoved
:
2420 case DeviceNodeRemovePendingCloses
:
2422 case DeviceNodeRemoved
:
2424 case DeviceNodeDeletePendingCloses
:
2426 case DeviceNodeDeleted
:
2433 if (!doProcessAgain
)
2436 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
2437 /* If we have a child, simply go down the tree */
2438 if (currentNode
->State
!= DeviceNodeRemoved
&& currentNode
->Child
!= NULL
)
2440 ASSERT(currentNode
->Child
->Parent
== currentNode
);
2441 currentNode
= currentNode
->Child
;
2445 while (currentNode
!= RootNode
)
2447 /* All children processed -- go sideways */
2448 if (currentNode
->Sibling
!= NULL
)
2450 ASSERT(currentNode
->Sibling
->Parent
== currentNode
->Parent
);
2451 currentNode
= currentNode
->Sibling
;
2456 /* We're the last sibling -- go back up */
2457 ASSERT(currentNode
->Parent
->LastChild
== currentNode
);
2458 currentNode
= currentNode
->Parent
;
2460 /* We already visited the parent and all its children, so keep looking */
2463 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
2465 ObDereferenceObject(referencedObject
);
2466 } while (doProcessAgain
|| currentNode
!= RootNode
);
2473 _In_ DEVICE_ACTION Action
)
2477 case PiActionEnumDeviceTree
:
2478 return "PiActionEnumDeviceTree";
2479 case PiActionEnumRootDevices
:
2480 return "PiActionEnumRootDevices";
2481 case PiActionResetDevice
:
2482 return "PiActionResetDevice";
2483 case PiActionAddBootDevices
:
2484 return "PiActionAddBootDevices";
2485 case PiActionStartDevice
:
2486 return "PiActionStartDevice";
2488 return "(request unknown)";
2496 PipDeviceActionWorker(
2497 _In_opt_ PVOID Context
)
2499 PLIST_ENTRY ListEntry
;
2500 PDEVICE_ACTION_REQUEST Request
;
2502 PDEVICE_NODE deviceNode
;
2505 KeAcquireSpinLock(&IopDeviceActionLock
, &OldIrql
);
2506 while (!IsListEmpty(&IopDeviceActionRequestList
))
2508 ListEntry
= RemoveHeadList(&IopDeviceActionRequestList
);
2509 KeReleaseSpinLock(&IopDeviceActionLock
, OldIrql
);
2510 Request
= CONTAINING_RECORD(ListEntry
, DEVICE_ACTION_REQUEST
, RequestListEntry
);
2512 ASSERT(Request
->DeviceObject
);
2514 deviceNode
= IopGetDeviceNode(Request
->DeviceObject
);
2517 status
= STATUS_SUCCESS
;
2519 DPRINT("Processing PnP request %p: DeviceObject - %p, Action - %s\n",
2520 Request
, Request
->DeviceObject
, ActionToStr(Request
->Action
));
2522 switch (Request
->Action
)
2524 case PiActionAddBootDevices
:
2526 if (deviceNode
->State
== DeviceNodeInitialized
&&
2527 !(deviceNode
->Flags
& DNF_HAS_PROBLEM
))
2529 status
= PiCallDriverAddDevice(deviceNode
, PnPBootDriversInitialized
);
2533 case PiActionEnumRootDevices
:
2534 case PiActionEnumDeviceTree
:
2535 deviceNode
->Flags
|= DNF_REENUMERATE
;
2536 PiDevNodeStateMachine(deviceNode
);
2539 case PiActionResetDevice
:
2540 // TODO: the operation is a no-op for everything except removed nodes
2541 // for removed nodes, it returns them back to DeviceNodeUninitialized
2542 status
= STATUS_SUCCESS
;
2545 case PiActionStartDevice
:
2546 // This action is triggered from usermode, when a driver is installed
2547 // for a non-critical PDO
2548 if (deviceNode
->State
== DeviceNodeInitialized
&&
2549 !(deviceNode
->Flags
& DNF_HAS_PROBLEM
))
2551 PiDevNodeStateMachine(deviceNode
);
2555 DPRINT1("NOTE: attempt to start an already started/uninitialized device %wZ\n",
2556 &deviceNode
->InstancePath
);
2557 status
= STATUS_UNSUCCESSFUL
;
2562 DPRINT1("Unimplemented device action %u\n", Request
->Action
);
2563 status
= STATUS_NOT_IMPLEMENTED
;
2567 if (Request
->CompletionStatus
)
2569 *Request
->CompletionStatus
= status
;
2572 if (Request
->CompletionEvent
)
2574 KeSetEvent(Request
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2577 DPRINT("Finished processing PnP request %p\n", Request
);
2578 ObDereferenceObject(Request
->DeviceObject
);
2579 ExFreePoolWithTag(Request
, TAG_IO
);
2580 KeAcquireSpinLock(&IopDeviceActionLock
, &OldIrql
);
2582 IopDeviceActionInProgress
= FALSE
;
2583 KeSetEvent(&PiEnumerationFinished
, IO_NO_INCREMENT
, FALSE
);
2584 KeReleaseSpinLock(&IopDeviceActionLock
, OldIrql
);
2588 * @brief Queue a device operation to a worker thread.
2590 * @param[in] DeviceObject The device object
2591 * @param[in] Action The action
2592 * @param[in] CompletionEvent The completion event object (optional)
2593 * @param[out] CompletionStatus Status returned be the action will be written here
2597 PiQueueDeviceAction(
2598 _In_ PDEVICE_OBJECT DeviceObject
,
2599 _In_ DEVICE_ACTION Action
,
2600 _In_opt_ PKEVENT CompletionEvent
,
2601 _Out_opt_ NTSTATUS
*CompletionStatus
)
2603 PDEVICE_ACTION_REQUEST Request
;
2606 Request
= ExAllocatePoolWithTag(NonPagedPoolMustSucceed
, sizeof(*Request
), TAG_IO
);
2608 DPRINT("PiQueueDeviceAction: DeviceObject - %p, Request - %p, Action - %s\n",
2609 DeviceObject
, Request
, ActionToStr(Action
));
2611 ObReferenceObject(DeviceObject
);
2613 Request
->DeviceObject
= DeviceObject
;
2614 Request
->Action
= Action
;
2615 Request
->CompletionEvent
= CompletionEvent
;
2616 Request
->CompletionStatus
= CompletionStatus
;
2618 KeAcquireSpinLock(&IopDeviceActionLock
, &OldIrql
);
2619 InsertTailList(&IopDeviceActionRequestList
, &Request
->RequestListEntry
);
2621 if (Action
== PiActionEnumRootDevices
|| Action
== PiActionAddBootDevices
)
2623 ASSERT(!IopDeviceActionInProgress
);
2625 IopDeviceActionInProgress
= TRUE
;
2626 KeClearEvent(&PiEnumerationFinished
);
2627 KeReleaseSpinLock(&IopDeviceActionLock
, OldIrql
);
2629 PipDeviceActionWorker(NULL
);
2633 if (IopDeviceActionInProgress
|| !PnPBootDriversLoaded
)
2635 KeReleaseSpinLock(&IopDeviceActionLock
, OldIrql
);
2638 IopDeviceActionInProgress
= TRUE
;
2639 KeClearEvent(&PiEnumerationFinished
);
2640 KeReleaseSpinLock(&IopDeviceActionLock
, OldIrql
);
2642 ExInitializeWorkItem(&IopDeviceActionWorkItem
, PipDeviceActionWorker
, NULL
);
2643 ExQueueWorkItem(&IopDeviceActionWorkItem
, DelayedWorkQueue
);
2647 * @brief Perfom a device operation synchronously via PiQueueDeviceAction
2649 * @param[in] DeviceObject The device object
2650 * @param[in] Action The action
2652 * @return Status of the operation
2656 PiPerformSyncDeviceAction(
2657 _In_ PDEVICE_OBJECT DeviceObject
,
2658 _In_ DEVICE_ACTION Action
)
2663 KeInitializeEvent(&opFinished
, SynchronizationEvent
, FALSE
);
2664 PiQueueDeviceAction(DeviceObject
, Action
, &opFinished
, &status
);
2665 KeWaitForSingleObject(&opFinished
, Executive
, KernelMode
, FALSE
, NULL
);