2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpmgr.c
5 * PURPOSE: Initializes the PnP manager
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
10 /* INCLUDES ******************************************************************/
18 /* GLOBALS *******************************************************************/
20 PDEVICE_NODE IopRootDeviceNode
;
21 KSPIN_LOCK IopDeviceTreeLock
;
22 ERESOURCE PpRegistryDeviceResource
;
23 KGUARDED_MUTEX PpDeviceReferenceTableLock
;
24 RTL_AVL_TABLE PpDeviceReferenceTable
;
26 extern ULONG ExpInitializationPhase
;
27 extern BOOLEAN PnpSystemInit
;
29 /* DATA **********************************************************************/
31 PDRIVER_OBJECT IopRootDriverObject
;
32 FAST_MUTEX IopBusTypeGuidListLock
;
33 PIO_BUS_TYPE_GUID_LIST IopBusTypeGuidList
= NULL
;
35 #if defined (ALLOC_PRAGMA)
36 #pragma alloc_text(INIT, PnpInit)
37 #pragma alloc_text(INIT, PnpInit2)
40 typedef struct _INVALIDATE_DEVICE_RELATION_DATA
42 PDEVICE_OBJECT DeviceObject
;
43 DEVICE_RELATION_TYPE Type
;
44 PIO_WORKITEM WorkItem
;
45 } INVALIDATE_DEVICE_RELATION_DATA
, *PINVALIDATE_DEVICE_RELATION_DATA
;
47 /* FUNCTIONS *****************************************************************/
50 IopAssignDeviceResources(
51 IN PDEVICE_NODE DeviceNode
,
52 OUT ULONG
*pRequiredSize
);
55 IopTranslateDeviceResources(
56 IN PDEVICE_NODE DeviceNode
,
57 IN ULONG RequiredSize
);
60 IopUpdateResourceMapForPnPDevice(
61 IN PDEVICE_NODE DeviceNode
);
65 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath
,
70 IopGetDeviceNode(PDEVICE_OBJECT DeviceObject
)
72 return ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceObject
->DeviceObjectExtension
)->DeviceNode
;
77 IopInitializeDevice(PDEVICE_NODE DeviceNode
,
78 PDRIVER_OBJECT DriverObject
)
83 if (!DriverObject
->DriverExtension
->AddDevice
)
84 return STATUS_SUCCESS
;
86 /* This is a Plug and Play driver */
87 DPRINT("Plug and Play driver found\n");
88 ASSERT(DeviceNode
->PhysicalDeviceObject
);
90 /* Check if this plug-and-play driver is used as a legacy one for this device node */
91 if (IopDeviceNodeHasFlag(DeviceNode
, DNF_LEGACY_DRIVER
))
93 IopDeviceNodeSetFlag(DeviceNode
, DNF_ADDED
);
94 return STATUS_SUCCESS
;
97 DPRINT("Calling %wZ->AddDevice(%wZ)\n",
98 &DriverObject
->DriverName
,
99 &DeviceNode
->InstancePath
);
100 Status
= DriverObject
->DriverExtension
->AddDevice(
101 DriverObject
, DeviceNode
->PhysicalDeviceObject
);
102 if (!NT_SUCCESS(Status
))
104 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
108 /* Check if driver added a FDO above the PDO */
109 Fdo
= IoGetAttachedDeviceReference(DeviceNode
->PhysicalDeviceObject
);
110 if (Fdo
== DeviceNode
->PhysicalDeviceObject
)
112 /* FIXME: What do we do? Unload the driver or just disable the device? */
113 DPRINT1("An FDO was not attached\n");
114 ObDereferenceObject(Fdo
);
115 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
116 return STATUS_UNSUCCESSFUL
;
119 /* Check if we have a ACPI device (needed for power management) */
120 if (Fdo
->DeviceType
== FILE_DEVICE_ACPI
)
122 static BOOLEAN SystemPowerDeviceNodeCreated
= FALSE
;
124 /* There can be only one system power device */
125 if (!SystemPowerDeviceNodeCreated
)
127 PopSystemPowerDeviceNode
= DeviceNode
;
128 ObReferenceObject(PopSystemPowerDeviceNode
);
129 SystemPowerDeviceNodeCreated
= TRUE
;
133 ObDereferenceObject(Fdo
);
135 IopDeviceNodeSetFlag(DeviceNode
, DNF_ADDED
);
136 IopDeviceNodeSetFlag(DeviceNode
, DNF_NEED_ENUMERATION_ONLY
);
138 return STATUS_SUCCESS
;
143 PDEVICE_NODE DeviceNode
)
145 IO_STATUS_BLOCK IoStatusBlock
;
146 IO_STACK_LOCATION Stack
;
147 ULONG RequiredLength
;
149 HANDLE InstanceHandle
, ControlHandle
;
150 UNICODE_STRING KeyName
;
151 OBJECT_ATTRIBUTES ObjectAttributes
;
153 IopDeviceNodeSetFlag(DeviceNode
, DNF_ASSIGNING_RESOURCES
);
154 DPRINT("Sending IRP_MN_FILTER_RESOURCE_REQUIREMENTS to device stack\n");
155 Stack
.Parameters
.FilterResourceRequirements
.IoResourceRequirementList
= DeviceNode
->ResourceRequirements
;
156 Status
= IopInitiatePnpIrp(
157 DeviceNode
->PhysicalDeviceObject
,
159 IRP_MN_FILTER_RESOURCE_REQUIREMENTS
,
161 if (!NT_SUCCESS(Status
) && Status
!= STATUS_NOT_SUPPORTED
)
163 DPRINT("IopInitiatePnpIrp(IRP_MN_FILTER_RESOURCE_REQUIREMENTS) failed\n");
166 else if (NT_SUCCESS(Status
))
168 DeviceNode
->ResourceRequirements
= (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
171 Status
= IopAssignDeviceResources(DeviceNode
, &RequiredLength
);
172 if (NT_SUCCESS(Status
))
174 Status
= IopTranslateDeviceResources(DeviceNode
, RequiredLength
);
175 if (NT_SUCCESS(Status
))
177 Status
= IopUpdateResourceMapForPnPDevice(DeviceNode
);
178 if (!NT_SUCCESS(Status
))
180 DPRINT("IopUpdateResourceMap() failed (Status 0x%08lx)\n", Status
);
185 DPRINT("IopTranslateDeviceResources() failed (Status 0x%08lx)\n", Status
);
190 DPRINT("IopAssignDeviceResources() failed (Status 0x%08lx)\n", Status
);
192 IopDeviceNodeClearFlag(DeviceNode
, DNF_ASSIGNING_RESOURCES
);
194 DPRINT("Sending IRP_MN_START_DEVICE to driver\n");
195 Stack
.Parameters
.StartDevice
.AllocatedResources
= DeviceNode
->ResourceList
;
196 Stack
.Parameters
.StartDevice
.AllocatedResourcesTranslated
= DeviceNode
->ResourceListTranslated
;
199 * Windows NT Drivers receive IRP_MN_START_DEVICE in a critical region and
200 * actually _depend_ on this!. This is because NT will lock the Device Node
201 * with an ERESOURCE, which of course requires APCs to be disabled.
203 KeEnterCriticalRegion();
205 Status
= IopInitiatePnpIrp(
206 DeviceNode
->PhysicalDeviceObject
,
211 KeLeaveCriticalRegion();
213 if (!NT_SUCCESS(Status
))
215 DPRINT("IopInitiatePnpIrp() failed\n");
219 if (IopDeviceNodeHasFlag(DeviceNode
, DNF_NEED_ENUMERATION_ONLY
))
221 DPRINT("Device needs enumeration, invalidating bus relations\n");
222 /* Invalidate device relations synchronously
223 (otherwise there will be dirty read of DeviceNode) */
224 IopEnumerateDevice(DeviceNode
->PhysicalDeviceObject
);
225 IopDeviceNodeClearFlag(DeviceNode
, DNF_NEED_ENUMERATION_ONLY
);
229 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, &InstanceHandle
);
230 if (!NT_SUCCESS(Status
))
233 RtlInitUnicodeString(&KeyName
, L
"Control");
234 InitializeObjectAttributes(&ObjectAttributes
,
236 OBJ_CASE_INSENSITIVE
,
239 Status
= ZwCreateKey(&ControlHandle
, KEY_SET_VALUE
, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
240 if (!NT_SUCCESS(Status
))
242 ZwClose(InstanceHandle
);
246 RtlInitUnicodeString(&KeyName
, L
"ActiveService");
247 Status
= ZwSetValueKey(ControlHandle
, &KeyName
, 0, REG_SZ
, DeviceNode
->ServiceName
.Buffer
, DeviceNode
->ServiceName
.Length
);
249 if (NT_SUCCESS(Status
) && DeviceNode
->ResourceList
)
251 RtlInitUnicodeString(&KeyName
, L
"AllocConfig");
252 Status
= ZwSetValueKey(ControlHandle
, &KeyName
, 0, REG_RESOURCE_LIST
,
253 DeviceNode
->ResourceList
, CM_RESOURCE_LIST_SIZE(DeviceNode
->ResourceList
));
256 if (NT_SUCCESS(Status
))
257 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
259 ZwClose(ControlHandle
);
260 ZwClose(InstanceHandle
);
267 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode
,
268 PDEVICE_CAPABILITIES DeviceCaps
)
270 IO_STATUS_BLOCK StatusBlock
;
271 IO_STACK_LOCATION Stack
;
273 /* Set up the Header */
274 RtlZeroMemory(DeviceCaps
, sizeof(DEVICE_CAPABILITIES
));
275 DeviceCaps
->Size
= sizeof(DEVICE_CAPABILITIES
);
276 DeviceCaps
->Version
= 1;
277 DeviceCaps
->Address
= -1;
278 DeviceCaps
->UINumber
= -1;
280 /* Set up the Stack */
281 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
282 Stack
.Parameters
.DeviceCapabilities
.Capabilities
= DeviceCaps
;
285 return IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
287 IRP_MN_QUERY_CAPABILITIES
,
292 IopAsynchronousInvalidateDeviceRelations(
293 IN PDEVICE_OBJECT DeviceObject
,
294 IN PVOID InvalidateContext
)
296 PINVALIDATE_DEVICE_RELATION_DATA Data
= InvalidateContext
;
298 IoSynchronousInvalidateDeviceRelations(
302 ObDereferenceObject(Data
->DeviceObject
);
303 IoFreeWorkItem(Data
->WorkItem
);
308 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT
*DeviceObject
)
312 if (PopSystemPowerDeviceNode
)
314 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
315 *DeviceObject
= PopSystemPowerDeviceNode
->PhysicalDeviceObject
;
316 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
318 return STATUS_SUCCESS
;
321 return STATUS_UNSUCCESSFUL
;
326 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid
)
328 USHORT i
= 0, FoundIndex
= 0xFFFF;
332 /* Acquire the lock */
333 ExAcquireFastMutex(&IopBusTypeGuidListLock
);
335 /* Loop all entries */
336 while (i
< IopBusTypeGuidList
->GuidCount
)
338 /* Try to find a match */
339 if (RtlCompareMemory(BusTypeGuid
,
340 &IopBusTypeGuidList
->Guids
[i
],
341 sizeof(GUID
)) == sizeof(GUID
))
350 /* Check if we have to grow the list */
351 if (IopBusTypeGuidList
->GuidCount
)
353 /* Calculate the new size */
354 NewSize
= sizeof(IO_BUS_TYPE_GUID_LIST
) +
355 (sizeof(GUID
) * IopBusTypeGuidList
->GuidCount
);
357 /* Allocate the new copy */
358 NewList
= ExAllocatePool(PagedPool
, NewSize
);
362 ExFreePool(IopBusTypeGuidList
);
366 /* Now copy them, decrease the size too */
367 NewSize
-= sizeof(GUID
);
368 RtlCopyMemory(NewList
, IopBusTypeGuidList
, NewSize
);
370 /* Free the old list */
371 ExFreePool(IopBusTypeGuidList
);
373 /* Use the new buffer */
374 IopBusTypeGuidList
= NewList
;
377 /* Copy the new GUID */
378 RtlCopyMemory(&IopBusTypeGuidList
->Guids
[IopBusTypeGuidList
->GuidCount
],
382 /* The new entry is the index */
383 FoundIndex
= (USHORT
)IopBusTypeGuidList
->GuidCount
;
384 IopBusTypeGuidList
->GuidCount
++;
387 ExReleaseFastMutex(&IopBusTypeGuidListLock
);
393 * Creates a device node
396 * ParentNode = Pointer to parent device node
397 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
398 * to have the root device node create one
399 * (eg. for legacy drivers)
400 * DeviceNode = Pointer to storage for created device node
406 IopCreateDeviceNode(PDEVICE_NODE ParentNode
,
407 PDEVICE_OBJECT PhysicalDeviceObject
,
408 PUNICODE_STRING ServiceName
,
409 PDEVICE_NODE
*DeviceNode
)
414 UNICODE_STRING FullServiceName
;
415 UNICODE_STRING LegacyPrefix
= RTL_CONSTANT_STRING(L
"LEGACY_");
416 UNICODE_STRING UnknownDeviceName
= RTL_CONSTANT_STRING(L
"UNKNOWN");
419 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
420 ParentNode
, PhysicalDeviceObject
, ServiceName
);
422 Node
= (PDEVICE_NODE
)ExAllocatePool(NonPagedPool
, sizeof(DEVICE_NODE
));
425 return STATUS_INSUFFICIENT_RESOURCES
;
428 RtlZeroMemory(Node
, sizeof(DEVICE_NODE
));
431 ServiceName
= &UnknownDeviceName
;
433 if (!PhysicalDeviceObject
)
435 FullServiceName
.MaximumLength
= LegacyPrefix
.Length
+ ServiceName
->Length
;
436 FullServiceName
.Length
= 0;
437 FullServiceName
.Buffer
= ExAllocatePool(PagedPool
, FullServiceName
.MaximumLength
);
438 if (!FullServiceName
.Buffer
)
441 return STATUS_INSUFFICIENT_RESOURCES
;
444 RtlAppendUnicodeStringToString(&FullServiceName
, &LegacyPrefix
);
445 RtlAppendUnicodeStringToString(&FullServiceName
, ServiceName
);
447 Status
= PnpRootCreateDevice(&FullServiceName
, &PhysicalDeviceObject
, &Node
->InstancePath
);
448 if (!NT_SUCCESS(Status
))
450 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status
);
455 /* Create the device key for legacy drivers */
456 Status
= IopCreateDeviceKeyPath(&Node
->InstancePath
, &TempHandle
);
457 if (NT_SUCCESS(Status
))
460 ExFreePool(FullServiceName
.Buffer
);
462 /* This is for drivers passed on the command line to ntoskrnl.exe */
463 IopDeviceNodeSetFlag(Node
, DNF_STARTED
);
464 IopDeviceNodeSetFlag(Node
, DNF_LEGACY_DRIVER
);
467 Node
->PhysicalDeviceObject
= PhysicalDeviceObject
;
469 ((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= Node
;
473 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
474 Node
->Parent
= ParentNode
;
475 Node
->Sibling
= ParentNode
->Child
;
476 ParentNode
->Child
= Node
;
477 if (ParentNode
->LastChild
== NULL
)
478 ParentNode
->LastChild
= Node
;
479 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
480 Node
->Level
= ParentNode
->Level
+ 1;
483 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
487 return STATUS_SUCCESS
;
491 IopFreeDeviceNode(PDEVICE_NODE DeviceNode
)
494 PDEVICE_NODE PrevSibling
= NULL
;
496 /* All children must be deleted before a parent is deleted */
497 ASSERT(!DeviceNode
->Child
);
499 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
501 ASSERT(DeviceNode
->PhysicalDeviceObject
);
503 ObDereferenceObject(DeviceNode
->PhysicalDeviceObject
);
505 /* Get previous sibling */
506 if (DeviceNode
->Parent
&& DeviceNode
->Parent
->Child
!= DeviceNode
)
508 PrevSibling
= DeviceNode
->Parent
->Child
;
509 while (PrevSibling
->Sibling
!= DeviceNode
)
510 PrevSibling
= PrevSibling
->Sibling
;
513 /* Unlink from parent if it exists */
514 if (DeviceNode
->Parent
)
516 if (DeviceNode
->Parent
->LastChild
== DeviceNode
)
518 DeviceNode
->Parent
->LastChild
= PrevSibling
;
520 PrevSibling
->Sibling
= NULL
;
522 if (DeviceNode
->Parent
->Child
== DeviceNode
)
523 DeviceNode
->Parent
->Child
= DeviceNode
->Sibling
;
526 /* Unlink from sibling list */
528 PrevSibling
->Sibling
= DeviceNode
->Sibling
;
530 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
532 RtlFreeUnicodeString(&DeviceNode
->InstancePath
);
534 RtlFreeUnicodeString(&DeviceNode
->ServiceName
);
536 if (DeviceNode
->ResourceList
)
538 ExFreePool(DeviceNode
->ResourceList
);
541 if (DeviceNode
->ResourceListTranslated
)
543 ExFreePool(DeviceNode
->ResourceListTranslated
);
546 if (DeviceNode
->ResourceRequirements
)
548 ExFreePool(DeviceNode
->ResourceRequirements
);
551 if (DeviceNode
->BootResources
)
553 ExFreePool(DeviceNode
->BootResources
);
556 ExFreePool(DeviceNode
);
558 return STATUS_SUCCESS
;
562 IopInitiatePnpIrp(PDEVICE_OBJECT DeviceObject
,
563 PIO_STATUS_BLOCK IoStatusBlock
,
565 PIO_STACK_LOCATION Stack OPTIONAL
)
567 PDEVICE_OBJECT TopDeviceObject
;
568 PIO_STACK_LOCATION IrpSp
;
573 /* Always call the top of the device stack */
574 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
581 Irp
= IoBuildSynchronousFsdRequest(
590 /* PNP IRPs are initialized with a status code of STATUS_NOT_SUPPORTED */
591 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
592 Irp
->IoStatus
.Information
= 0;
594 if (MinorFunction
== IRP_MN_FILTER_RESOURCE_REQUIREMENTS
)
596 Irp
->IoStatus
.Information
= (ULONG_PTR
)Stack
->Parameters
.FilterResourceRequirements
.IoResourceRequirementList
;
599 IrpSp
= IoGetNextIrpStackLocation(Irp
);
600 IrpSp
->MinorFunction
= (UCHAR
)MinorFunction
;
604 RtlCopyMemory(&IrpSp
->Parameters
,
606 sizeof(Stack
->Parameters
));
609 Status
= IoCallDriver(TopDeviceObject
, Irp
);
610 if (Status
== STATUS_PENDING
)
612 KeWaitForSingleObject(&Event
,
617 Status
= IoStatusBlock
->Status
;
620 ObDereferenceObject(TopDeviceObject
);
627 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context
)
629 PDEVICE_NODE ParentDeviceNode
;
630 PDEVICE_NODE ChildDeviceNode
;
633 /* Copy context data so we don't overwrite it in subsequent calls to this function */
634 ParentDeviceNode
= Context
->DeviceNode
;
636 /* Call the action routine */
637 Status
= (Context
->Action
)(ParentDeviceNode
, Context
->Context
);
638 if (!NT_SUCCESS(Status
))
643 /* Traversal of all children nodes */
644 for (ChildDeviceNode
= ParentDeviceNode
->Child
;
645 ChildDeviceNode
!= NULL
;
646 ChildDeviceNode
= ChildDeviceNode
->Sibling
)
648 /* Pass the current device node to the action routine */
649 Context
->DeviceNode
= ChildDeviceNode
;
651 Status
= IopTraverseDeviceTreeNode(Context
);
652 if (!NT_SUCCESS(Status
))
663 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context
)
667 DPRINT("Context 0x%p\n", Context
);
669 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %x Context 0x%p)\n",
670 Context
->DeviceNode
, Context
->FirstDeviceNode
, Context
->Action
, Context
->Context
);
672 /* Start from the specified device node */
673 Context
->DeviceNode
= Context
->FirstDeviceNode
;
675 /* Recursively traverse the device tree */
676 Status
= IopTraverseDeviceTreeNode(Context
);
677 if (Status
== STATUS_UNSUCCESSFUL
)
679 /* The action routine just wanted to terminate the traversal with status
680 code STATUS_SUCCESS */
681 Status
= STATUS_SUCCESS
;
689 * IopCreateDeviceKeyPath
691 * Creates a registry key
695 * Name of the key to be created.
697 * Handle to the newly created key
700 * This method can create nested trees, so parent of RegistryPath can
701 * be not existant, and will be created if needed.
705 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath
,
708 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(ENUM_ROOT
);
709 HANDLE hParent
= NULL
, hKey
;
710 OBJECT_ATTRIBUTES ObjectAttributes
;
711 UNICODE_STRING KeyName
;
712 LPCWSTR Current
, Last
;
719 /* Open root key for device instances */
720 Status
= IopOpenRegistryKeyEx(&hParent
, NULL
, &EnumU
, KEY_CREATE_SUB_KEY
);
721 if (!NT_SUCCESS(Status
))
723 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU
, Status
);
727 Current
= KeyName
.Buffer
= RegistryPath
->Buffer
;
728 Last
= &RegistryPath
->Buffer
[RegistryPath
->Length
/ sizeof(WCHAR
)];
730 /* Go up to the end of the string */
731 while (Current
<= Last
)
733 if (Current
!= Last
&& *Current
!= '\\')
735 /* Not the end of the string and not a separator */
740 /* Prepare relative key name */
741 dwLength
= (ULONG_PTR
)Current
- (ULONG_PTR
)KeyName
.Buffer
;
742 KeyName
.MaximumLength
= KeyName
.Length
= dwLength
;
743 DPRINT("Create '%wZ'\n", &KeyName
);
746 InitializeObjectAttributes(&ObjectAttributes
,
748 OBJ_CASE_INSENSITIVE
,
751 Status
= ZwCreateKey(&hKey
,
752 Current
== Last
? KEY_ALL_ACCESS
: KEY_CREATE_SUB_KEY
,
759 /* Close parent key handle, we don't need it anymore */
763 /* Key opening/creating failed? */
764 if (!NT_SUCCESS(Status
))
766 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName
, Status
);
770 /* Check if it is the end of the string */
773 /* Yes, return success */
775 return STATUS_SUCCESS
;
778 /* Start with this new parent key */
781 KeyName
.Buffer
= (LPWSTR
)Current
;
784 return STATUS_UNSUCCESSFUL
;
788 IopUpdateResourceMap(IN PDEVICE_NODE DeviceNode
, PWCHAR Level1Key
, PWCHAR Level2Key
)
792 HANDLE PnpMgrLevel1
, PnpMgrLevel2
, ResourceMapKey
;
793 UNICODE_STRING KeyName
;
794 OBJECT_ATTRIBUTES ObjectAttributes
;
796 RtlInitUnicodeString(&KeyName
,
797 L
"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
798 InitializeObjectAttributes(&ObjectAttributes
,
800 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
803 Status
= ZwCreateKey(&ResourceMapKey
,
810 if (!NT_SUCCESS(Status
))
813 RtlInitUnicodeString(&KeyName
, Level1Key
);
814 InitializeObjectAttributes(&ObjectAttributes
,
816 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
819 Status
= ZwCreateKey(&PnpMgrLevel1
,
826 ZwClose(ResourceMapKey
);
827 if (!NT_SUCCESS(Status
))
830 RtlInitUnicodeString(&KeyName
, Level2Key
);
831 InitializeObjectAttributes(&ObjectAttributes
,
833 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
836 Status
= ZwCreateKey(&PnpMgrLevel2
,
843 ZwClose(PnpMgrLevel1
);
844 if (!NT_SUCCESS(Status
))
847 if (DeviceNode
->ResourceList
)
850 UNICODE_STRING NameU
;
851 UNICODE_STRING Suffix
;
854 ASSERT(DeviceNode
->ResourceListTranslated
);
856 NameU
.Buffer
= NameBuff
;
858 NameU
.MaximumLength
= 256 * sizeof(WCHAR
);
860 Status
= IoGetDeviceProperty(DeviceNode
->PhysicalDeviceObject
,
861 DevicePropertyPhysicalDeviceObjectName
,
865 ASSERT(Status
== STATUS_SUCCESS
);
867 NameU
.Length
= (USHORT
)OldLength
;
869 RtlInitUnicodeString(&Suffix
, L
".Raw");
870 RtlAppendUnicodeStringToString(&NameU
, &Suffix
);
872 Status
= ZwSetValueKey(PnpMgrLevel2
,
876 DeviceNode
->ResourceList
,
877 CM_RESOURCE_LIST_SIZE(DeviceNode
->ResourceList
));
878 if (!NT_SUCCESS(Status
))
880 ZwClose(PnpMgrLevel2
);
884 /* "Remove" the suffix by setting the length back to what it used to be */
885 NameU
.Length
= (USHORT
)OldLength
;
887 RtlInitUnicodeString(&Suffix
, L
".Translated");
888 RtlAppendUnicodeStringToString(&NameU
, &Suffix
);
890 Status
= ZwSetValueKey(PnpMgrLevel2
,
894 DeviceNode
->ResourceListTranslated
,
895 CM_RESOURCE_LIST_SIZE(DeviceNode
->ResourceListTranslated
));
896 ZwClose(PnpMgrLevel2
);
897 if (!NT_SUCCESS(Status
))
902 ZwClose(PnpMgrLevel2
);
905 IopDeviceNodeSetFlag(DeviceNode
, DNF_RESOURCE_ASSIGNED
);
907 return STATUS_SUCCESS
;
911 IopUpdateResourceMapForPnPDevice(IN PDEVICE_NODE DeviceNode
)
913 return IopUpdateResourceMap(DeviceNode
, L
"PnP Manager", L
"PnpManager");
917 IopSetDeviceInstanceData(HANDLE InstanceKey
,
918 PDEVICE_NODE DeviceNode
)
920 OBJECT_ATTRIBUTES ObjectAttributes
;
921 UNICODE_STRING KeyName
;
924 ULONG ListSize
, ResultLength
;
926 HANDLE ControlHandle
;
928 DPRINT("IopSetDeviceInstanceData() called\n");
930 /* Create the 'LogConf' key */
931 RtlInitUnicodeString(&KeyName
, L
"LogConf");
932 InitializeObjectAttributes(&ObjectAttributes
,
934 OBJ_CASE_INSENSITIVE
,
937 Status
= ZwCreateKey(&LogConfKey
,
944 if (NT_SUCCESS(Status
))
946 /* Set 'BootConfig' value */
947 if (DeviceNode
->BootResources
!= NULL
)
949 ResCount
= DeviceNode
->BootResources
->Count
;
952 ListSize
= CM_RESOURCE_LIST_SIZE(DeviceNode
->BootResources
);
954 RtlInitUnicodeString(&KeyName
, L
"BootConfig");
955 Status
= ZwSetValueKey(LogConfKey
,
959 DeviceNode
->BootResources
,
964 /* Set 'BasicConfigVector' value */
965 if (DeviceNode
->ResourceRequirements
!= NULL
&&
966 DeviceNode
->ResourceRequirements
->ListSize
!= 0)
968 RtlInitUnicodeString(&KeyName
, L
"BasicConfigVector");
969 Status
= ZwSetValueKey(LogConfKey
,
972 REG_RESOURCE_REQUIREMENTS_LIST
,
973 DeviceNode
->ResourceRequirements
,
974 DeviceNode
->ResourceRequirements
->ListSize
);
980 /* Set the 'ConfigFlags' value */
981 RtlInitUnicodeString(&KeyName
, L
"ConfigFlags");
982 Status
= ZwQueryValueKey(InstanceKey
,
984 KeyValueBasicInformation
,
988 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
990 /* Write the default value */
991 ULONG DefaultConfigFlags
= 0;
992 Status
= ZwSetValueKey(InstanceKey
,
997 sizeof(DefaultConfigFlags
));
1000 /* Create the 'Control' key */
1001 RtlInitUnicodeString(&KeyName
, L
"Control");
1002 InitializeObjectAttributes(&ObjectAttributes
,
1004 OBJ_CASE_INSENSITIVE
,
1007 Status
= ZwCreateKey(&ControlHandle
, 0, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
1009 if (NT_SUCCESS(Status
))
1010 ZwClose(ControlHandle
);
1012 DPRINT("IopSetDeviceInstanceData() done\n");
1018 IopCheckResourceDescriptor(
1019 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc
,
1020 IN PCM_RESOURCE_LIST ResourceList
,
1022 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
1025 BOOLEAN Result
= FALSE
;
1027 if (ResDesc
->ShareDisposition
== CmResourceShareShared
)
1030 for (i
= 0; i
< ResourceList
->Count
; i
++)
1032 PCM_PARTIAL_RESOURCE_LIST ResList
= &ResourceList
->List
[i
].PartialResourceList
;
1033 for (ii
= 0; ii
< ResList
->Count
; ii
++)
1035 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc2
= &ResList
->PartialDescriptors
[ii
];
1037 /* We don't care about shared resources */
1038 if (ResDesc
->ShareDisposition
== CmResourceShareShared
&&
1039 ResDesc2
->ShareDisposition
== CmResourceShareShared
)
1042 /* Make sure we're comparing the same types */
1043 if (ResDesc
->Type
!= ResDesc2
->Type
)
1046 switch (ResDesc
->Type
)
1048 case CmResourceTypeMemory
:
1049 if ((ResDesc
->u
.Memory
.Start
.QuadPart
< ResDesc2
->u
.Memory
.Start
.QuadPart
&&
1050 ResDesc
->u
.Memory
.Start
.QuadPart
+ ResDesc
->u
.Memory
.Length
>
1051 ResDesc2
->u
.Memory
.Start
.QuadPart
) || (ResDesc2
->u
.Memory
.Start
.QuadPart
<
1052 ResDesc
->u
.Memory
.Start
.QuadPart
&& ResDesc2
->u
.Memory
.Start
.QuadPart
+
1053 ResDesc2
->u
.Memory
.Length
> ResDesc
->u
.Memory
.Start
.QuadPart
))
1057 DPRINT1("Resource conflict: Memory (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
1058 ResDesc
->u
.Memory
.Start
.QuadPart
, ResDesc
->u
.Memory
.Start
.QuadPart
+
1059 ResDesc
->u
.Memory
.Length
, ResDesc2
->u
.Memory
.Start
.QuadPart
,
1060 ResDesc2
->u
.Memory
.Start
.QuadPart
+ ResDesc2
->u
.Memory
.Length
);
1069 case CmResourceTypePort
:
1070 if ((ResDesc
->u
.Port
.Start
.QuadPart
< ResDesc2
->u
.Port
.Start
.QuadPart
&&
1071 ResDesc
->u
.Port
.Start
.QuadPart
+ ResDesc
->u
.Port
.Length
>
1072 ResDesc2
->u
.Port
.Start
.QuadPart
) || (ResDesc2
->u
.Port
.Start
.QuadPart
<
1073 ResDesc
->u
.Port
.Start
.QuadPart
&& ResDesc2
->u
.Port
.Start
.QuadPart
+
1074 ResDesc2
->u
.Port
.Length
> ResDesc
->u
.Port
.Start
.QuadPart
))
1078 DPRINT1("Resource conflict: Port (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
1079 ResDesc
->u
.Port
.Start
.QuadPart
, ResDesc
->u
.Port
.Start
.QuadPart
+
1080 ResDesc
->u
.Port
.Length
, ResDesc2
->u
.Port
.Start
.QuadPart
,
1081 ResDesc2
->u
.Port
.Start
.QuadPart
+ ResDesc2
->u
.Port
.Length
);
1090 case CmResourceTypeInterrupt
:
1091 if (ResDesc
->u
.Interrupt
.Vector
== ResDesc2
->u
.Interrupt
.Vector
)
1095 DPRINT1("Resource conflict: IRQ (0x%x 0x%x vs. 0x%x 0x%x)\n",
1096 ResDesc
->u
.Interrupt
.Vector
, ResDesc
->u
.Interrupt
.Level
,
1097 ResDesc2
->u
.Interrupt
.Vector
, ResDesc2
->u
.Interrupt
.Level
);
1106 case CmResourceTypeBusNumber
:
1107 if ((ResDesc
->u
.BusNumber
.Start
< ResDesc2
->u
.BusNumber
.Start
&&
1108 ResDesc
->u
.BusNumber
.Start
+ ResDesc
->u
.BusNumber
.Length
>
1109 ResDesc2
->u
.BusNumber
.Start
) || (ResDesc2
->u
.BusNumber
.Start
<
1110 ResDesc
->u
.BusNumber
.Start
&& ResDesc2
->u
.BusNumber
.Start
+
1111 ResDesc2
->u
.BusNumber
.Length
> ResDesc
->u
.BusNumber
.Start
))
1115 DPRINT1("Resource conflict: Bus number (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
1116 ResDesc
->u
.BusNumber
.Start
, ResDesc
->u
.BusNumber
.Start
+
1117 ResDesc
->u
.BusNumber
.Length
, ResDesc2
->u
.BusNumber
.Start
,
1118 ResDesc2
->u
.BusNumber
.Start
+ ResDesc2
->u
.BusNumber
.Length
);
1127 case CmResourceTypeDma
:
1128 if (ResDesc
->u
.Dma
.Channel
== ResDesc2
->u
.Dma
.Channel
)
1132 DPRINT1("Resource conflict: Dma (0x%x 0x%x vs. 0x%x 0x%x)\n",
1133 ResDesc
->u
.Dma
.Channel
, ResDesc
->u
.Dma
.Port
,
1134 ResDesc2
->u
.Dma
.Channel
, ResDesc2
->u
.Dma
.Port
);
1148 if (Result
&& ConflictingDescriptor
)
1150 RtlCopyMemory(ConflictingDescriptor
,
1152 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
));
1160 IopCheckForResourceConflict(
1161 IN PCM_RESOURCE_LIST ResourceList1
,
1162 IN PCM_RESOURCE_LIST ResourceList2
,
1164 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
1167 BOOLEAN Result
= FALSE
;
1169 for (i
= 0; i
< ResourceList1
->Count
; i
++)
1171 PCM_PARTIAL_RESOURCE_LIST ResList
= &ResourceList1
->List
[i
].PartialResourceList
;
1172 for (ii
= 0; ii
< ResList
->Count
; ii
++)
1174 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc
= &ResList
->PartialDescriptors
[ii
];
1176 Result
= IopCheckResourceDescriptor(ResDesc
,
1179 ConflictingDescriptor
);
1180 if (Result
) goto ByeBye
;
1191 IopDetectResourceConflict(
1192 IN PCM_RESOURCE_LIST ResourceList
,
1194 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
1196 OBJECT_ATTRIBUTES ObjectAttributes
;
1197 UNICODE_STRING KeyName
;
1198 HANDLE ResourceMapKey
= INVALID_HANDLE_VALUE
, ChildKey2
= INVALID_HANDLE_VALUE
, ChildKey3
= INVALID_HANDLE_VALUE
;
1199 ULONG KeyInformationLength
, RequiredLength
, KeyValueInformationLength
, KeyNameInformationLength
;
1200 PKEY_BASIC_INFORMATION KeyInformation
;
1201 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
;
1202 PKEY_VALUE_BASIC_INFORMATION KeyNameInformation
;
1203 ULONG ChildKeyIndex1
= 0, ChildKeyIndex2
= 0, ChildKeyIndex3
= 0;
1206 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
1207 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, 0, NULL
);
1208 Status
= ZwOpenKey(&ResourceMapKey
, KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
1209 if (!NT_SUCCESS(Status
))
1211 /* The key is missing which means we are the first device */
1212 return STATUS_SUCCESS
;
1217 Status
= ZwEnumerateKey(ResourceMapKey
,
1219 KeyBasicInformation
,
1223 if (Status
== STATUS_NO_MORE_ENTRIES
)
1225 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
1227 KeyInformationLength
= RequiredLength
;
1228 KeyInformation
= ExAllocatePool(PagedPool
, KeyInformationLength
);
1229 if (!KeyInformation
)
1231 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1235 Status
= ZwEnumerateKey(ResourceMapKey
,
1237 KeyBasicInformation
,
1239 KeyInformationLength
,
1245 if (!NT_SUCCESS(Status
))
1248 KeyName
.Buffer
= KeyInformation
->Name
;
1249 KeyName
.MaximumLength
= KeyName
.Length
= KeyInformation
->NameLength
;
1250 InitializeObjectAttributes(&ObjectAttributes
,
1252 OBJ_CASE_INSENSITIVE
,
1255 Status
= ZwOpenKey(&ChildKey2
, KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
1256 ExFreePool(KeyInformation
);
1257 if (!NT_SUCCESS(Status
))
1262 Status
= ZwEnumerateKey(ChildKey2
,
1264 KeyBasicInformation
,
1268 if (Status
== STATUS_NO_MORE_ENTRIES
)
1270 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
1272 KeyInformationLength
= RequiredLength
;
1273 KeyInformation
= ExAllocatePool(PagedPool
, KeyInformationLength
);
1274 if (!KeyInformation
)
1276 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1280 Status
= ZwEnumerateKey(ChildKey2
,
1282 KeyBasicInformation
,
1284 KeyInformationLength
,
1290 if (!NT_SUCCESS(Status
))
1293 KeyName
.Buffer
= KeyInformation
->Name
;
1294 KeyName
.MaximumLength
= KeyName
.Length
= KeyInformation
->NameLength
;
1295 InitializeObjectAttributes(&ObjectAttributes
,
1297 OBJ_CASE_INSENSITIVE
,
1300 Status
= ZwOpenKey(&ChildKey3
, KEY_QUERY_VALUE
, &ObjectAttributes
);
1301 ExFreePool(KeyInformation
);
1302 if (!NT_SUCCESS(Status
))
1307 Status
= ZwEnumerateValueKey(ChildKey3
,
1309 KeyValuePartialInformation
,
1313 if (Status
== STATUS_NO_MORE_ENTRIES
)
1315 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
1317 KeyValueInformationLength
= RequiredLength
;
1318 KeyValueInformation
= ExAllocatePool(PagedPool
, KeyValueInformationLength
);
1319 if (!KeyValueInformation
)
1321 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1325 Status
= ZwEnumerateValueKey(ChildKey3
,
1327 KeyValuePartialInformation
,
1328 KeyValueInformation
,
1329 KeyValueInformationLength
,
1334 if (!NT_SUCCESS(Status
))
1337 Status
= ZwEnumerateValueKey(ChildKey3
,
1339 KeyValueBasicInformation
,
1343 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1345 KeyNameInformationLength
= RequiredLength
;
1346 KeyNameInformation
= ExAllocatePool(PagedPool
, KeyNameInformationLength
+ sizeof(WCHAR
));
1347 if (!KeyNameInformation
)
1349 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1353 Status
= ZwEnumerateValueKey(ChildKey3
,
1355 KeyValueBasicInformation
,
1357 KeyNameInformationLength
,
1365 if (!NT_SUCCESS(Status
))
1368 KeyNameInformation
->Name
[KeyNameInformation
->NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1370 /* Skip translated entries */
1371 if (wcsstr(KeyNameInformation
->Name
, L
".Translated"))
1373 ExFreePool(KeyNameInformation
);
1377 ExFreePool(KeyNameInformation
);
1379 if (IopCheckForResourceConflict(ResourceList
,
1380 (PCM_RESOURCE_LIST
)KeyValueInformation
->Data
,
1382 ConflictingDescriptor
))
1384 ExFreePool(KeyValueInformation
);
1385 Status
= STATUS_CONFLICTING_ADDRESSES
;
1389 ExFreePool(KeyValueInformation
);
1395 if (ResourceMapKey
!= INVALID_HANDLE_VALUE
)
1396 ZwClose(ResourceMapKey
);
1397 if (ChildKey2
!= INVALID_HANDLE_VALUE
)
1399 if (ChildKey3
!= INVALID_HANDLE_VALUE
)
1402 if (Status
== STATUS_NO_MORE_ENTRIES
)
1403 Status
= STATUS_SUCCESS
;
1409 IopCheckDescriptorForConflict(PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
, OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
1411 CM_RESOURCE_LIST CmList
;
1415 CmList
.List
[0].InterfaceType
= InterfaceTypeUndefined
;
1416 CmList
.List
[0].BusNumber
= 0;
1417 CmList
.List
[0].PartialResourceList
.Version
= 1;
1418 CmList
.List
[0].PartialResourceList
.Revision
= 1;
1419 CmList
.List
[0].PartialResourceList
.Count
= 1;
1420 CmList
.List
[0].PartialResourceList
.PartialDescriptors
[0] = *CmDesc
;
1422 Status
= IopDetectResourceConflict(&CmList
, TRUE
, ConflictingDescriptor
);
1423 if (Status
== STATUS_CONFLICTING_ADDRESSES
)
1430 IopFindBusNumberResource(
1431 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
1432 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
1435 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc
;
1437 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
1438 ASSERT(IoDesc
->Type
== CmResourceTypeBusNumber
);
1440 for (Start
= IoDesc
->u
.BusNumber
.MinBusNumber
;
1441 Start
< IoDesc
->u
.BusNumber
.MaxBusNumber
;
1444 CmDesc
->u
.BusNumber
.Length
= IoDesc
->u
.BusNumber
.Length
;
1445 CmDesc
->u
.BusNumber
.Start
= Start
;
1447 if (IopCheckDescriptorForConflict(CmDesc
, &ConflictingDesc
))
1449 Start
+= ConflictingDesc
.u
.BusNumber
.Start
+ ConflictingDesc
.u
.BusNumber
.Length
;
1461 IopFindMemoryResource(
1462 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
1463 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
1466 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc
;
1468 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
1469 ASSERT(IoDesc
->Type
== CmResourceTypeMemory
);
1471 for (Start
= IoDesc
->u
.Memory
.MinimumAddress
.QuadPart
;
1472 Start
< IoDesc
->u
.Memory
.MaximumAddress
.QuadPart
;
1475 CmDesc
->u
.Memory
.Length
= IoDesc
->u
.Memory
.Length
;
1476 CmDesc
->u
.Memory
.Start
.QuadPart
= Start
;
1478 if (IopCheckDescriptorForConflict(CmDesc
, &ConflictingDesc
))
1480 Start
+= ConflictingDesc
.u
.Memory
.Start
.QuadPart
+ ConflictingDesc
.u
.Memory
.Length
;
1492 IopFindPortResource(
1493 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
1494 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
1497 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc
;
1499 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
1500 ASSERT(IoDesc
->Type
== CmResourceTypePort
);
1502 for (Start
= IoDesc
->u
.Port
.MinimumAddress
.QuadPart
;
1503 Start
< IoDesc
->u
.Port
.MaximumAddress
.QuadPart
;
1506 CmDesc
->u
.Port
.Length
= IoDesc
->u
.Port
.Length
;
1507 CmDesc
->u
.Port
.Start
.QuadPart
= Start
;
1509 if (IopCheckDescriptorForConflict(CmDesc
, &ConflictingDesc
))
1511 Start
+= ConflictingDesc
.u
.Port
.Start
.QuadPart
+ ConflictingDesc
.u
.Port
.Length
;
1524 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
1525 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
1529 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
1530 ASSERT(IoDesc
->Type
== CmResourceTypeDma
);
1532 for (Channel
= IoDesc
->u
.Dma
.MinimumChannel
;
1533 Channel
< IoDesc
->u
.Dma
.MaximumChannel
;
1536 CmDesc
->u
.Dma
.Channel
= Channel
;
1537 CmDesc
->u
.Dma
.Port
= 0;
1539 if (!IopCheckDescriptorForConflict(CmDesc
, NULL
))
1547 IopFindInterruptResource(
1548 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
1549 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
1553 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
1554 ASSERT(IoDesc
->Type
== CmResourceTypeInterrupt
);
1556 for (Vector
= IoDesc
->u
.Interrupt
.MinimumVector
;
1557 Vector
< IoDesc
->u
.Interrupt
.MaximumVector
;
1560 CmDesc
->u
.Interrupt
.Vector
= Vector
;
1561 CmDesc
->u
.Interrupt
.Level
= Vector
;
1562 CmDesc
->u
.Interrupt
.Affinity
= (KAFFINITY
)-1;
1564 if (!IopCheckDescriptorForConflict(CmDesc
, NULL
))
1572 IopCreateResourceListFromRequirements(
1573 IN PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList
,
1574 OUT PCM_RESOURCE_LIST
*ResourceList
)
1577 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc
;
1579 Size
= FIELD_OFFSET(CM_RESOURCE_LIST
, List
);
1580 for (i
= 0; i
< RequirementsList
->AlternativeLists
; i
++)
1582 PIO_RESOURCE_LIST ResList
= &RequirementsList
->List
[i
];
1583 Size
+= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
)
1584 + ResList
->Count
* sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
1587 *ResourceList
= ExAllocatePool(PagedPool
, Size
);
1589 return STATUS_INSUFFICIENT_RESOURCES
;
1591 (*ResourceList
)->Count
= 1;
1592 (*ResourceList
)->List
[0].BusNumber
= RequirementsList
->BusNumber
;
1593 (*ResourceList
)->List
[0].InterfaceType
= RequirementsList
->InterfaceType
;
1594 (*ResourceList
)->List
[0].PartialResourceList
.Version
= 1;
1595 (*ResourceList
)->List
[0].PartialResourceList
.Revision
= 1;
1596 (*ResourceList
)->List
[0].PartialResourceList
.Count
= 0;
1598 ResDesc
= &(*ResourceList
)->List
[0].PartialResourceList
.PartialDescriptors
[0];
1600 for (i
= 0; i
< RequirementsList
->AlternativeLists
; i
++)
1602 PIO_RESOURCE_LIST ResList
= &RequirementsList
->List
[i
];
1603 for (ii
= 0; ii
< ResList
->Count
; ii
++)
1605 PIO_RESOURCE_DESCRIPTOR ReqDesc
= &ResList
->Descriptors
[ii
];
1607 /* FIXME: Handle alternate ranges */
1608 if (ReqDesc
->Option
== IO_RESOURCE_ALTERNATIVE
)
1611 ResDesc
->Type
= ReqDesc
->Type
;
1612 ResDesc
->Flags
= ReqDesc
->Flags
;
1613 ResDesc
->ShareDisposition
= ReqDesc
->ShareDisposition
;
1615 switch (ReqDesc
->Type
)
1617 case CmResourceTypeInterrupt
:
1618 if (!IopFindInterruptResource(ReqDesc
, ResDesc
))
1620 DPRINT1("Failed to find an available interrupt resource (0x%x to 0x%x)\n",
1621 ReqDesc
->u
.Interrupt
.MinimumVector
, ReqDesc
->u
.Interrupt
.MaximumVector
);
1623 if (ReqDesc
->Option
== 0)
1625 ExFreePool(*ResourceList
);
1626 return STATUS_CONFLICTING_ADDRESSES
;
1631 case CmResourceTypePort
:
1632 if (!IopFindPortResource(ReqDesc
, ResDesc
))
1634 DPRINT1("Failed to find an available port resource (0x%x to 0x%x length: 0x%x)\n",
1635 ReqDesc
->u
.Port
.MinimumAddress
.QuadPart
, ReqDesc
->u
.Port
.MaximumAddress
.QuadPart
,
1636 ReqDesc
->u
.Port
.Length
);
1638 if (ReqDesc
->Option
== 0)
1640 ExFreePool(*ResourceList
);
1641 return STATUS_CONFLICTING_ADDRESSES
;
1646 case CmResourceTypeMemory
:
1647 if (!IopFindMemoryResource(ReqDesc
, ResDesc
))
1649 DPRINT1("Failed to find an available memory resource (0x%x to 0x%x length: 0x%x)\n",
1650 ReqDesc
->u
.Memory
.MinimumAddress
.QuadPart
, ReqDesc
->u
.Memory
.MaximumAddress
.QuadPart
,
1651 ReqDesc
->u
.Memory
.Length
);
1653 if (ReqDesc
->Option
== 0)
1655 ExFreePool(*ResourceList
);
1656 return STATUS_CONFLICTING_ADDRESSES
;
1661 case CmResourceTypeBusNumber
:
1662 if (!IopFindBusNumberResource(ReqDesc
, ResDesc
))
1664 DPRINT1("Failed to find an available bus number resource (0x%x to 0x%x length: 0x%x)\n",
1665 ReqDesc
->u
.BusNumber
.MinBusNumber
, ReqDesc
->u
.BusNumber
.MaxBusNumber
,
1666 ReqDesc
->u
.BusNumber
.Length
);
1668 if (ReqDesc
->Option
== 0)
1670 ExFreePool(*ResourceList
);
1671 return STATUS_CONFLICTING_ADDRESSES
;
1676 case CmResourceTypeDma
:
1677 if (!IopFindDmaResource(ReqDesc
, ResDesc
))
1679 DPRINT1("Failed to find an available dma resource (0x%x to 0x%x)\n",
1680 ReqDesc
->u
.Dma
.MinimumChannel
, ReqDesc
->u
.Dma
.MaximumChannel
);
1682 if (ReqDesc
->Option
== 0)
1684 ExFreePool(*ResourceList
);
1685 return STATUS_CONFLICTING_ADDRESSES
;
1691 DPRINT1("Unsupported resource type: %x\n", ReqDesc
->Type
);
1695 (*ResourceList
)->List
[0].PartialResourceList
.Count
++;
1700 return STATUS_SUCCESS
;
1704 IopAssignDeviceResources(
1705 IN PDEVICE_NODE DeviceNode
,
1706 OUT ULONG
*pRequiredSize
)
1708 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList
;
1714 if (!DeviceNode
->BootResources
&& !DeviceNode
->ResourceRequirements
)
1716 /* No resource needed for this device */
1717 DeviceNode
->ResourceList
= NULL
;
1719 return STATUS_SUCCESS
;
1722 /* Fill DeviceNode->ResourceList
1723 * FIXME: the PnP arbiter should go there!
1724 * Actually, use the BootResources if provided, else the resource requirements
1727 if (DeviceNode
->BootResources
)
1729 /* Browse the boot resources to know if we have some custom structures */
1730 Size
= FIELD_OFFSET(CM_RESOURCE_LIST
, List
);
1731 for (i
= 0; i
< DeviceNode
->BootResources
->Count
; i
++)
1733 pPartialResourceList
= &DeviceNode
->BootResources
->List
[i
].PartialResourceList
;
1734 Size
+= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
)
1735 + pPartialResourceList
->Count
* sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
1736 for (j
= 0; j
< pPartialResourceList
->Count
; j
++)
1738 if (pPartialResourceList
->PartialDescriptors
[j
].Type
== CmResourceTypeDeviceSpecific
)
1739 Size
+= pPartialResourceList
->PartialDescriptors
[j
].u
.DeviceSpecificData
.DataSize
;
1743 DeviceNode
->ResourceList
= ExAllocatePool(PagedPool
, Size
);
1744 if (!DeviceNode
->ResourceList
)
1746 Status
= STATUS_NO_MEMORY
;
1749 RtlCopyMemory(DeviceNode
->ResourceList
, DeviceNode
->BootResources
, Size
);
1751 Status
= IopDetectResourceConflict(DeviceNode
->ResourceList
, FALSE
, NULL
);
1752 if (NT_SUCCESS(Status
) || !DeviceNode
->ResourceRequirements
)
1754 if (!NT_SUCCESS(Status
) && !DeviceNode
->ResourceRequirements
)
1756 DPRINT1("Using conflicting boot resources because no requirements were supplied!\n");
1759 *pRequiredSize
= Size
;
1760 return STATUS_SUCCESS
;
1764 DPRINT1("Boot resources for %wZ cause a resource conflict!\n", &DeviceNode
->InstancePath
);
1765 ExFreePool(DeviceNode
->ResourceList
);
1769 Status
= IopCreateResourceListFromRequirements(DeviceNode
->ResourceRequirements
,
1770 &DeviceNode
->ResourceList
);
1771 if (!NT_SUCCESS(Status
))
1774 Size
= FIELD_OFFSET(CM_RESOURCE_LIST
, List
);
1775 for (i
= 0; i
< DeviceNode
->ResourceList
->Count
; i
++)
1777 pPartialResourceList
= &DeviceNode
->ResourceList
->List
[i
].PartialResourceList
;
1778 Size
+= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
)
1779 + pPartialResourceList
->Count
* sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
1782 Status
= IopDetectResourceConflict(DeviceNode
->ResourceList
, FALSE
, NULL
);
1783 if (!NT_SUCCESS(Status
))
1786 *pRequiredSize
= Size
;
1787 return STATUS_SUCCESS
;
1790 if (DeviceNode
->ResourceList
)
1792 ExFreePool(DeviceNode
->ResourceList
);
1793 DeviceNode
->ResourceList
= NULL
;
1801 IopTranslateDeviceResources(
1802 IN PDEVICE_NODE DeviceNode
,
1803 IN ULONG RequiredSize
)
1805 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList
;
1806 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw
, DescriptorTranslated
;
1810 if (!DeviceNode
->ResourceList
)
1812 DeviceNode
->ResourceListTranslated
= NULL
;
1813 return STATUS_SUCCESS
;
1816 /* That's easy to translate a resource list. Just copy the
1817 * untranslated one and change few fields in the copy
1819 DeviceNode
->ResourceListTranslated
= ExAllocatePool(PagedPool
, RequiredSize
);
1820 if (!DeviceNode
->ResourceListTranslated
)
1822 Status
=STATUS_NO_MEMORY
;
1825 RtlCopyMemory(DeviceNode
->ResourceListTranslated
, DeviceNode
->ResourceList
, RequiredSize
);
1827 for (i
= 0; i
< DeviceNode
->ResourceList
->Count
; i
++)
1829 pPartialResourceList
= &DeviceNode
->ResourceList
->List
[i
].PartialResourceList
;
1830 for (j
= 0; j
< pPartialResourceList
->Count
; j
++)
1832 DescriptorRaw
= &pPartialResourceList
->PartialDescriptors
[j
];
1833 DescriptorTranslated
= &DeviceNode
->ResourceListTranslated
->List
[i
].PartialResourceList
.PartialDescriptors
[j
];
1834 switch (DescriptorRaw
->Type
)
1836 case CmResourceTypePort
:
1838 ULONG AddressSpace
= 1; /* IO space */
1839 if (!HalTranslateBusAddress(
1840 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
1841 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
1842 DescriptorRaw
->u
.Port
.Start
,
1844 &DescriptorTranslated
->u
.Port
.Start
))
1846 Status
= STATUS_UNSUCCESSFUL
;
1851 case CmResourceTypeInterrupt
:
1853 DescriptorTranslated
->u
.Interrupt
.Vector
= HalGetInterruptVector(
1854 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
1855 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
1856 DescriptorRaw
->u
.Interrupt
.Level
,
1857 DescriptorRaw
->u
.Interrupt
.Vector
,
1858 (PKIRQL
)&DescriptorTranslated
->u
.Interrupt
.Level
,
1859 &DescriptorRaw
->u
.Interrupt
.Affinity
);
1862 case CmResourceTypeMemory
:
1864 ULONG AddressSpace
= 0; /* Memory space */
1865 if (!HalTranslateBusAddress(
1866 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
1867 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
1868 DescriptorRaw
->u
.Memory
.Start
,
1870 &DescriptorTranslated
->u
.Memory
.Start
))
1872 Status
= STATUS_UNSUCCESSFUL
;
1877 case CmResourceTypeDma
:
1878 case CmResourceTypeBusNumber
:
1879 case CmResourceTypeDeviceSpecific
:
1883 DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw
->Type
);
1884 Status
= STATUS_NOT_IMPLEMENTED
;
1889 return STATUS_SUCCESS
;
1892 /* Yes! Also delete ResourceList because ResourceList and
1893 * ResourceListTranslated should be a pair! */
1894 ExFreePool(DeviceNode
->ResourceList
);
1895 DeviceNode
->ResourceList
= NULL
;
1896 if (DeviceNode
->ResourceListTranslated
)
1898 ExFreePool(DeviceNode
->ResourceListTranslated
);
1899 DeviceNode
->ResourceList
= NULL
;
1906 * IopGetParentIdPrefix
1908 * Retrieve (or create) a string which identifies a device.
1912 * Pointer to device node.
1914 * Pointer to the string where is returned the parent node identifier
1917 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1918 * valid and its Buffer field is NULL-terminated. The caller needs to
1919 * to free the string with RtlFreeUnicodeString when it is no longer
1924 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode
,
1925 PUNICODE_STRING ParentIdPrefix
)
1927 ULONG KeyNameBufferLength
;
1928 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation
= NULL
;
1929 UNICODE_STRING KeyName
;
1930 UNICODE_STRING KeyValue
;
1931 UNICODE_STRING ValueName
;
1936 /* HACK: As long as some devices have a NULL device
1937 * instance path, the following test is required :(
1939 if (DeviceNode
->Parent
->InstancePath
.Length
== 0)
1941 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
1942 &DeviceNode
->InstancePath
);
1943 return STATUS_UNSUCCESSFUL
;
1946 /* 1. Try to retrieve ParentIdPrefix from registry */
1947 KeyNameBufferLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + MAX_PATH
* sizeof(WCHAR
);
1948 ParentIdPrefixInformation
= ExAllocatePool(PagedPool
, KeyNameBufferLength
+ sizeof(WCHAR
));
1949 if (!ParentIdPrefixInformation
)
1951 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1956 KeyName
.Buffer
= ExAllocatePool(PagedPool
, (49 * sizeof(WCHAR
)) + DeviceNode
->Parent
->InstancePath
.Length
);
1957 if (!KeyName
.Buffer
)
1959 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1963 KeyName
.MaximumLength
= (49 * sizeof(WCHAR
)) + DeviceNode
->Parent
->InstancePath
.Length
;
1965 RtlAppendUnicodeToString(&KeyName
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1966 RtlAppendUnicodeStringToString(&KeyName
, &DeviceNode
->Parent
->InstancePath
);
1968 Status
= IopOpenRegistryKeyEx(&hKey
, NULL
, &KeyName
, KEY_QUERY_VALUE
| KEY_SET_VALUE
);
1969 if (!NT_SUCCESS(Status
))
1971 RtlInitUnicodeString(&ValueName
, L
"ParentIdPrefix");
1972 Status
= ZwQueryValueKey(
1974 KeyValuePartialInformation
, ParentIdPrefixInformation
,
1975 KeyNameBufferLength
, &KeyNameBufferLength
);
1976 if (NT_SUCCESS(Status
))
1978 if (ParentIdPrefixInformation
->Type
!= REG_SZ
)
1979 Status
= STATUS_UNSUCCESSFUL
;
1982 KeyValue
.Length
= KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1983 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1987 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
1989 KeyValue
.Length
= KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1990 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1994 /* 2. Create the ParentIdPrefix value */
1995 crc32
= RtlComputeCrc32(0,
1996 (PUCHAR
)DeviceNode
->Parent
->InstancePath
.Buffer
,
1997 DeviceNode
->Parent
->InstancePath
.Length
);
1999 swprintf((PWSTR
)ParentIdPrefixInformation
->Data
, L
"%lx&%lx", DeviceNode
->Parent
->Level
, crc32
);
2000 RtlInitUnicodeString(&KeyValue
, (PWSTR
)ParentIdPrefixInformation
->Data
);
2002 /* 3. Try to write the ParentIdPrefix to registry */
2003 Status
= ZwSetValueKey(hKey
,
2007 (PVOID
)KeyValue
.Buffer
,
2008 (wcslen(KeyValue
.Buffer
) + 1) * sizeof(WCHAR
));
2011 if (NT_SUCCESS(Status
))
2013 /* Duplicate the string to return it */
2014 Status
= RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
, &KeyValue
, ParentIdPrefix
);
2016 ExFreePool(ParentIdPrefixInformation
);
2017 RtlFreeUnicodeString(&KeyName
);
2025 * IopActionInterrogateDeviceStack
2027 * Retrieve information for all (direct) child nodes of a parent node.
2031 * Pointer to device node.
2033 * Pointer to parent node to retrieve child node information for.
2036 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
2037 * when we reach a device node which is not a direct child of the device
2038 * node for which we retrieve information of child nodes for. Any errors
2039 * that occur is logged instead so that all child services have a chance
2040 * of being interrogated.
2044 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode
,
2047 IO_STATUS_BLOCK IoStatusBlock
;
2048 PDEVICE_NODE ParentDeviceNode
;
2049 WCHAR InstancePath
[MAX_PATH
];
2050 IO_STACK_LOCATION Stack
;
2055 ULONG RequiredLength
;
2057 HANDLE InstanceKey
= NULL
;
2058 UNICODE_STRING ValueName
;
2059 UNICODE_STRING ParentIdPrefix
= { 0, 0, NULL
};
2060 DEVICE_CAPABILITIES DeviceCapabilities
;
2062 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode
, Context
);
2063 DPRINT("PDO 0x%p\n", DeviceNode
->PhysicalDeviceObject
);
2065 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2068 * We are called for the parent too, but we don't need to do special
2069 * handling for this node
2072 if (DeviceNode
== ParentDeviceNode
)
2074 DPRINT("Success\n");
2075 return STATUS_SUCCESS
;
2079 * Make sure this device node is a direct child of the parent device node
2080 * that is given as an argument
2083 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2085 /* Stop the traversal immediately and indicate successful operation */
2087 return STATUS_UNSUCCESSFUL
;
2091 Status
= ZwQueryDefaultLocale(FALSE
, &LocaleId
);
2092 if (!NT_SUCCESS(Status
))
2094 DPRINT("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status
);
2099 * FIXME: For critical errors, cleanup and disable device, but always
2100 * return STATUS_SUCCESS.
2103 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
2105 Stack
.Parameters
.QueryId
.IdType
= BusQueryDeviceID
;
2106 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2110 if (NT_SUCCESS(Status
))
2112 /* Copy the device id string */
2113 wcscpy(InstancePath
, (PWSTR
)IoStatusBlock
.Information
);
2116 * FIXME: Check for valid characters, if there is invalid characters
2122 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
2125 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack\n");
2127 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
2128 if (!NT_SUCCESS(Status
))
2130 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
2133 DeviceNode
->CapabilityFlags
= *(PULONG
)((ULONG_PTR
)&DeviceCapabilities
+ 4);
2135 if (!DeviceCapabilities
.UniqueID
)
2137 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
2138 DPRINT("Instance ID is not unique\n");
2139 Status
= IopGetParentIdPrefix(DeviceNode
, &ParentIdPrefix
);
2140 if (!NT_SUCCESS(Status
))
2142 DPRINT("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status
);
2146 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
2148 Stack
.Parameters
.QueryId
.IdType
= BusQueryInstanceID
;
2149 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2153 if (NT_SUCCESS(Status
))
2155 /* Append the instance id string */
2156 wcscat(InstancePath
, L
"\\");
2157 if (ParentIdPrefix
.Length
> 0)
2159 /* Add information from parent bus device to InstancePath */
2160 wcscat(InstancePath
, ParentIdPrefix
.Buffer
);
2161 if (IoStatusBlock
.Information
&& *(PWSTR
)IoStatusBlock
.Information
)
2162 wcscat(InstancePath
, L
"&");
2164 if (IoStatusBlock
.Information
)
2165 wcscat(InstancePath
, (PWSTR
)IoStatusBlock
.Information
);
2168 * FIXME: Check for valid characters, if there is invalid characters
2174 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
2176 RtlFreeUnicodeString(&ParentIdPrefix
);
2178 if (!RtlCreateUnicodeString(&DeviceNode
->InstancePath
, InstancePath
))
2180 DPRINT("No resources\n");
2181 /* FIXME: Cleanup and disable device */
2184 DPRINT("InstancePath is %S\n", DeviceNode
->InstancePath
.Buffer
);
2187 * Create registry key for the instance id, if it doesn't exist yet
2189 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, &InstanceKey
);
2190 if (!NT_SUCCESS(Status
))
2192 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status
);
2196 /* Set 'Capabilities' value */
2197 RtlInitUnicodeString(&ValueName
, L
"Capabilities");
2198 Status
= ZwSetValueKey(InstanceKey
,
2202 (PVOID
)&DeviceNode
->CapabilityFlags
,
2205 /* Set 'UINumber' value */
2206 if (DeviceCapabilities
.UINumber
!= MAXULONG
)
2208 RtlInitUnicodeString(&ValueName
, L
"UINumber");
2209 Status
= ZwSetValueKey(InstanceKey
,
2213 &DeviceCapabilities
.UINumber
,
2218 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
2220 Stack
.Parameters
.QueryId
.IdType
= BusQueryHardwareIDs
;
2221 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2225 if (NT_SUCCESS(Status
))
2228 * FIXME: Check for valid characters, if there is invalid characters
2232 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
2233 DPRINT("Hardware IDs:\n");
2236 DPRINT(" %S\n", Ptr
);
2237 Length
= wcslen(Ptr
) + 1;
2240 TotalLength
+= Length
;
2242 DPRINT("TotalLength: %hu\n", TotalLength
);
2245 RtlInitUnicodeString(&ValueName
, L
"HardwareID");
2246 Status
= ZwSetValueKey(InstanceKey
,
2250 (PVOID
)IoStatusBlock
.Information
,
2251 (TotalLength
+ 1) * sizeof(WCHAR
));
2252 if (!NT_SUCCESS(Status
))
2254 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
2259 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
2262 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
2264 Stack
.Parameters
.QueryId
.IdType
= BusQueryCompatibleIDs
;
2265 Status
= IopInitiatePnpIrp(
2266 DeviceNode
->PhysicalDeviceObject
,
2270 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2273 * FIXME: Check for valid characters, if there is invalid characters
2277 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
2278 DPRINT("Compatible IDs:\n");
2281 DPRINT(" %S\n", Ptr
);
2282 Length
= wcslen(Ptr
) + 1;
2285 TotalLength
+= Length
;
2287 DPRINT("TotalLength: %hu\n", TotalLength
);
2290 RtlInitUnicodeString(&ValueName
, L
"CompatibleIDs");
2291 Status
= ZwSetValueKey(InstanceKey
,
2295 (PVOID
)IoStatusBlock
.Information
,
2296 (TotalLength
+ 1) * sizeof(WCHAR
));
2297 if (!NT_SUCCESS(Status
))
2299 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status
);
2304 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
2307 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2309 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextDescription
;
2310 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
2311 Status
= IopInitiatePnpIrp(
2312 DeviceNode
->PhysicalDeviceObject
,
2314 IRP_MN_QUERY_DEVICE_TEXT
,
2316 /* This key is mandatory, so even if the Irp fails, we still write it */
2317 RtlInitUnicodeString(&ValueName
, L
"DeviceDesc");
2318 if (ZwQueryValueKey(InstanceKey
, &ValueName
, KeyValueBasicInformation
, NULL
, 0, &RequiredLength
) == STATUS_OBJECT_NAME_NOT_FOUND
)
2320 if (NT_SUCCESS(Status
) &&
2321 IoStatusBlock
.Information
&&
2322 (*(PWSTR
)IoStatusBlock
.Information
!= 0))
2324 /* This key is overriden when a driver is installed. Don't write the
2325 * new description if another one already exists */
2326 Status
= ZwSetValueKey(InstanceKey
,
2330 (PVOID
)IoStatusBlock
.Information
,
2331 (wcslen((PWSTR
)IoStatusBlock
.Information
) + 1) * sizeof(WCHAR
));
2335 UNICODE_STRING DeviceDesc
= RTL_CONSTANT_STRING(L
"Unknown device");
2336 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status
);
2338 Status
= ZwSetValueKey(InstanceKey
,
2343 DeviceDesc
.MaximumLength
);
2345 if (!NT_SUCCESS(Status
))
2347 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status
);
2353 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2355 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextLocationInformation
;
2356 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
2357 Status
= IopInitiatePnpIrp(
2358 DeviceNode
->PhysicalDeviceObject
,
2360 IRP_MN_QUERY_DEVICE_TEXT
,
2362 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2364 DPRINT("LocationInformation: %S\n", (PWSTR
)IoStatusBlock
.Information
);
2365 RtlInitUnicodeString(&ValueName
, L
"LocationInformation");
2366 Status
= ZwSetValueKey(InstanceKey
,
2370 (PVOID
)IoStatusBlock
.Information
,
2371 (wcslen((PWSTR
)IoStatusBlock
.Information
) + 1) * sizeof(WCHAR
));
2372 if (!NT_SUCCESS(Status
))
2374 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
2379 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2382 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2384 Status
= IopInitiatePnpIrp(
2385 DeviceNode
->PhysicalDeviceObject
,
2387 IRP_MN_QUERY_BUS_INFORMATION
,
2389 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2391 PPNP_BUS_INFORMATION BusInformation
=
2392 (PPNP_BUS_INFORMATION
)IoStatusBlock
.Information
;
2394 DeviceNode
->ChildBusNumber
= BusInformation
->BusNumber
;
2395 DeviceNode
->ChildInterfaceType
= BusInformation
->LegacyBusType
;
2396 DeviceNode
->ChildBusTypeIndex
= IopGetBusTypeGuidIndex(&BusInformation
->BusTypeGuid
);
2397 ExFreePool(BusInformation
);
2401 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2403 DeviceNode
->ChildBusNumber
= 0xFFFFFFF0;
2404 DeviceNode
->ChildInterfaceType
= InterfaceTypeUndefined
;
2405 DeviceNode
->ChildBusTypeIndex
= -1;
2408 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2410 Status
= IopInitiatePnpIrp(
2411 DeviceNode
->PhysicalDeviceObject
,
2413 IRP_MN_QUERY_RESOURCES
,
2415 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2417 DeviceNode
->BootResources
=
2418 (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
2419 DeviceNode
->Flags
|= DNF_HAS_BOOT_CONFIG
;
2423 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2424 DeviceNode
->BootResources
= NULL
;
2427 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2429 Status
= IopInitiatePnpIrp(
2430 DeviceNode
->PhysicalDeviceObject
,
2432 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
2434 if (NT_SUCCESS(Status
))
2436 DeviceNode
->ResourceRequirements
=
2437 (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
2438 if (IoStatusBlock
.Information
)
2439 IopDeviceNodeSetFlag(DeviceNode
, DNF_RESOURCE_REPORTED
);
2441 IopDeviceNodeSetFlag(DeviceNode
, DNF_NO_RESOURCE_REQUIRED
);
2445 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status
);
2446 DeviceNode
->ResourceRequirements
= NULL
;
2450 if (InstanceKey
!= NULL
)
2452 IopSetDeviceInstanceData(InstanceKey
, DeviceNode
);
2455 ZwClose(InstanceKey
);
2457 IopDeviceNodeSetFlag(DeviceNode
, DNF_PROCESSED
);
2459 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_LEGACY_DRIVER
))
2461 /* Report the device to the user-mode pnp manager */
2462 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED
,
2463 &DeviceNode
->InstancePath
);
2466 return STATUS_SUCCESS
;
2472 IN PDEVICE_OBJECT DeviceObject
)
2474 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
2475 DEVICETREE_TRAVERSE_CONTEXT Context
;
2476 PDEVICE_RELATIONS DeviceRelations
;
2477 PDEVICE_OBJECT ChildDeviceObject
;
2478 IO_STATUS_BLOCK IoStatusBlock
;
2479 PDEVICE_NODE ChildDeviceNode
;
2480 IO_STACK_LOCATION Stack
;
2484 DPRINT("DeviceObject 0x%p\n", DeviceObject
);
2486 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2488 /* Report the device to the user-mode pnp manager */
2489 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL
,
2490 &DeviceNode
->InstancePath
);
2492 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2494 Stack
.Parameters
.QueryDeviceRelations
.Type
= BusRelations
;
2496 Status
= IopInitiatePnpIrp(
2499 IRP_MN_QUERY_DEVICE_RELATIONS
,
2501 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
2503 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
2507 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
2509 if (!DeviceRelations
)
2511 DPRINT("No PDOs\n");
2512 return STATUS_UNSUCCESSFUL
;
2515 DPRINT("Got %u PDOs\n", DeviceRelations
->Count
);
2518 * Create device nodes for all discovered devices
2520 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
2522 ChildDeviceObject
= DeviceRelations
->Objects
[i
];
2523 ASSERT((ChildDeviceObject
->Flags
& DO_DEVICE_INITIALIZING
) == 0);
2525 ChildDeviceNode
= IopGetDeviceNode(ChildDeviceObject
);
2526 if (!ChildDeviceNode
)
2528 /* One doesn't exist, create it */
2529 Status
= IopCreateDeviceNode(
2534 if (NT_SUCCESS(Status
))
2536 /* Mark the node as enumerated */
2537 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2539 /* Mark the DO as bus enumerated */
2540 ChildDeviceObject
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
2544 /* Ignore this DO */
2545 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status
, i
);
2546 ObDereferenceObject(ChildDeviceNode
);
2551 /* Mark it as enumerated */
2552 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2553 ObDereferenceObject(ChildDeviceObject
);
2556 ExFreePool(DeviceRelations
);
2559 * Retrieve information about all discovered children from the bus driver
2561 IopInitDeviceTreeTraverseContext(
2564 IopActionInterrogateDeviceStack
,
2567 Status
= IopTraverseDeviceTree(&Context
);
2568 if (!NT_SUCCESS(Status
))
2570 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
2575 * Retrieve configuration from the registry for discovered children
2577 IopInitDeviceTreeTraverseContext(
2580 IopActionConfigureChildServices
,
2583 Status
= IopTraverseDeviceTree(&Context
);
2584 if (!NT_SUCCESS(Status
))
2586 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
2591 * Initialize services for discovered children.
2593 Status
= IopInitializePnpServices(DeviceNode
);
2594 if (!NT_SUCCESS(Status
))
2596 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status
);
2600 DPRINT("IopEnumerateDevice() finished\n");
2601 return STATUS_SUCCESS
;
2606 * IopActionConfigureChildServices
2608 * Retrieve configuration for all (direct) child nodes of a parent node.
2612 * Pointer to device node.
2614 * Pointer to parent node to retrieve child node configuration for.
2617 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
2618 * when we reach a device node which is not a direct child of the device
2619 * node for which we configure child services for. Any errors that occur is
2620 * logged instead so that all child services have a chance of beeing
2625 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode
,
2628 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
2629 PDEVICE_NODE ParentDeviceNode
;
2630 PUNICODE_STRING Service
;
2631 UNICODE_STRING ClassGUID
;
2633 DEVICE_CAPABILITIES DeviceCaps
;
2635 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode
, Context
);
2637 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2640 * We are called for the parent too, but we don't need to do special
2641 * handling for this node
2643 if (DeviceNode
== ParentDeviceNode
)
2645 DPRINT("Success\n");
2646 return STATUS_SUCCESS
;
2650 * Make sure this device node is a direct child of the parent device node
2651 * that is given as an argument
2653 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2655 /* Stop the traversal immediately and indicate successful operation */
2657 return STATUS_UNSUCCESSFUL
;
2660 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
))
2662 WCHAR RegKeyBuffer
[MAX_PATH
];
2663 UNICODE_STRING RegKey
;
2666 RegKey
.MaximumLength
= sizeof(RegKeyBuffer
);
2667 RegKey
.Buffer
= RegKeyBuffer
;
2670 * Retrieve configuration from Enum key
2673 Service
= &DeviceNode
->ServiceName
;
2675 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
2676 RtlInitUnicodeString(Service
, NULL
);
2677 RtlInitUnicodeString(&ClassGUID
, NULL
);
2679 QueryTable
[0].Name
= L
"Service";
2680 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2681 QueryTable
[0].EntryContext
= Service
;
2683 QueryTable
[1].Name
= L
"ClassGUID";
2684 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2685 QueryTable
[1].EntryContext
= &ClassGUID
;
2686 QueryTable
[1].DefaultType
= REG_SZ
;
2687 QueryTable
[1].DefaultData
= L
"";
2688 QueryTable
[1].DefaultLength
= 0;
2690 RtlAppendUnicodeToString(&RegKey
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2691 RtlAppendUnicodeStringToString(&RegKey
, &DeviceNode
->InstancePath
);
2693 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
2694 RegKey
.Buffer
, QueryTable
, NULL
, NULL
);
2696 if (!NT_SUCCESS(Status
))
2698 /* FIXME: Log the error */
2699 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2700 &DeviceNode
->InstancePath
, Status
);
2701 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2702 return STATUS_SUCCESS
;
2705 if (Service
->Buffer
== NULL
)
2707 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode
, &DeviceCaps
)) &&
2708 DeviceCaps
.RawDeviceOK
)
2710 DPRINT1("%wZ is using parent bus driver (%wZ)\n", &DeviceNode
->InstancePath
, &ParentDeviceNode
->ServiceName
);
2712 DeviceNode
->ServiceName
.Length
= 0;
2713 DeviceNode
->ServiceName
.MaximumLength
= ParentDeviceNode
->ServiceName
.MaximumLength
;
2714 DeviceNode
->ServiceName
.Buffer
= ExAllocatePool(PagedPool
, DeviceNode
->ServiceName
.MaximumLength
);
2715 if (!DeviceNode
->ServiceName
.Buffer
)
2716 return STATUS_SUCCESS
;
2718 RtlCopyUnicodeString(&DeviceNode
->ServiceName
, &ParentDeviceNode
->ServiceName
);
2720 IopDeviceNodeSetFlag(DeviceNode
, DNF_LEGACY_DRIVER
);
2722 else if (ClassGUID
.Length
!= 0)
2724 /* Device has a ClassGUID value, but no Service value.
2725 * Suppose it is using the NULL driver, so state the
2726 * device is started */
2727 DPRINT1("%wZ is using NULL driver\n", &DeviceNode
->InstancePath
);
2728 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
2732 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2734 return STATUS_SUCCESS
;
2737 DPRINT("Got Service %S\n", Service
->Buffer
);
2740 return STATUS_SUCCESS
;
2744 * IopActionInitChildServices
2746 * Initialize the service for all (direct) child nodes of a parent node
2750 * Pointer to device node.
2752 * Pointer to parent node to initialize child node services for.
2755 * If the driver image for a service is not loaded and initialized
2756 * it is done here too. We only return a status code indicating an
2757 * error (STATUS_UNSUCCESSFUL) when we reach a device node which is
2758 * not a direct child of the device node for which we initialize
2759 * child services for. Any errors that occur is logged instead so
2760 * that all child services have a chance of being initialized.
2764 IopActionInitChildServices(PDEVICE_NODE DeviceNode
,
2767 PDEVICE_NODE ParentDeviceNode
;
2769 BOOLEAN BootDrivers
= !PnpSystemInit
;
2771 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode
, Context
);
2773 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2776 * We are called for the parent too, but we don't need to do special
2777 * handling for this node
2779 if (DeviceNode
== ParentDeviceNode
)
2781 DPRINT("Success\n");
2782 return STATUS_SUCCESS
;
2786 * Make sure this device node is a direct child of the parent device node
2787 * that is given as an argument
2790 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2793 * Stop the traversal immediately and indicate unsuccessful operation
2796 return STATUS_UNSUCCESSFUL
;
2800 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
) &&
2801 !IopDeviceNodeHasFlag(DeviceNode
, DNF_ADDED
) &&
2802 !IopDeviceNodeHasFlag(DeviceNode
, DNF_STARTED
))
2804 PLDR_DATA_TABLE_ENTRY ModuleObject
;
2805 PDRIVER_OBJECT DriverObject
;
2807 /* Get existing DriverObject pointer (in case the driver has
2808 already been loaded and initialized) */
2809 Status
= IopGetDriverObject(
2811 &DeviceNode
->ServiceName
,
2814 if (!NT_SUCCESS(Status
))
2816 /* Driver is not initialized, try to load it */
2817 Status
= IopLoadServiceModule(&DeviceNode
->ServiceName
, &ModuleObject
);
2819 if (NT_SUCCESS(Status
) || Status
== STATUS_IMAGE_ALREADY_LOADED
)
2821 /* STATUS_IMAGE_ALREADY_LOADED means this driver
2822 was loaded by the bootloader */
2823 if ((Status
!= STATUS_IMAGE_ALREADY_LOADED
) ||
2824 (Status
== STATUS_IMAGE_ALREADY_LOADED
&& !DriverObject
))
2826 /* Initialize the driver */
2827 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
2828 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
2832 Status
= STATUS_SUCCESS
;
2837 DPRINT1("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2838 &DeviceNode
->ServiceName
, Status
);
2842 /* Driver is loaded and initialized at this point */
2843 if (NT_SUCCESS(Status
))
2845 /* Attach lower level filter drivers. */
2846 IopAttachFilterDrivers(DeviceNode
, TRUE
);
2847 /* Initialize the function driver for the device node */
2848 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
2850 if (NT_SUCCESS(Status
))
2852 /* Attach upper level filter drivers. */
2853 IopAttachFilterDrivers(DeviceNode
, FALSE
);
2854 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
2856 Status
= IopStartDevice(DeviceNode
);
2860 DPRINT1("IopInitializeDevice(%wZ) failed with status 0x%08x\n",
2861 &DeviceNode
->InstancePath
, Status
);
2867 * Don't disable when trying to load only boot drivers
2871 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2872 IopDeviceNodeSetFlag(DeviceNode
, DNF_START_FAILED
);
2873 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
2874 DPRINT1("Initialization of service %S failed (Status %x)\n",
2875 DeviceNode
->ServiceName
.Buffer
, Status
);
2881 DPRINT("Device %wZ is disabled or already initialized\n",
2882 &DeviceNode
->InstancePath
);
2885 return STATUS_SUCCESS
;
2889 * IopInitializePnpServices
2891 * Initialize services for discovered children
2895 * Top device node to start initializing services.
2901 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode
)
2903 DEVICETREE_TRAVERSE_CONTEXT Context
;
2905 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode
);
2907 IopInitDeviceTreeTraverseContext(
2910 IopActionInitChildServices
,
2913 return IopTraverseDeviceTree(&Context
);
2916 static NTSTATUS INIT_FUNCTION
2917 IopEnumerateDetectedDevices(
2919 IN PUNICODE_STRING RelativePath OPTIONAL
,
2921 IN BOOLEAN EnumerateSubKeys
,
2922 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources
,
2923 IN ULONG ParentBootResourcesLength
)
2925 UNICODE_STRING IdentifierU
= RTL_CONSTANT_STRING(L
"Identifier");
2926 UNICODE_STRING HardwareIDU
= RTL_CONSTANT_STRING(L
"HardwareID");
2927 UNICODE_STRING ConfigurationDataU
= RTL_CONSTANT_STRING(L
"Configuration Data");
2928 UNICODE_STRING BootConfigU
= RTL_CONSTANT_STRING(L
"BootConfig");
2929 UNICODE_STRING LogConfU
= RTL_CONSTANT_STRING(L
"LogConf");
2930 OBJECT_ATTRIBUTES ObjectAttributes
;
2931 HANDLE hDevicesKey
= NULL
;
2932 HANDLE hDeviceKey
= NULL
;
2933 HANDLE hLevel1Key
, hLevel2Key
= NULL
, hLogConf
;
2934 UNICODE_STRING Level2NameU
;
2935 WCHAR Level2Name
[5];
2936 ULONG IndexDevice
= 0;
2938 PKEY_BASIC_INFORMATION pDeviceInformation
= NULL
;
2939 ULONG DeviceInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + 50 * sizeof(WCHAR
);
2940 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation
= NULL
;
2941 ULONG ValueInfoLength
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 50 * sizeof(WCHAR
);
2942 UNICODE_STRING DeviceName
, ValueName
;
2944 PCM_FULL_RESOURCE_DESCRIPTOR BootResources
= NULL
;
2945 ULONG BootResourcesLength
;
2948 const UNICODE_STRING IdentifierPci
= RTL_CONSTANT_STRING(L
"PCI");
2949 UNICODE_STRING HardwareIdPci
= RTL_CONSTANT_STRING(L
"*PNP0A03\0");
2950 static ULONG DeviceIndexPci
= 0;
2951 const UNICODE_STRING IdentifierSerial
= RTL_CONSTANT_STRING(L
"SerialController");
2952 UNICODE_STRING HardwareIdSerial
= RTL_CONSTANT_STRING(L
"*PNP0501\0");
2953 static ULONG DeviceIndexSerial
= 0;
2954 const UNICODE_STRING IdentifierKeyboard
= RTL_CONSTANT_STRING(L
"KeyboardController");
2955 UNICODE_STRING HardwareIdKeyboard
= RTL_CONSTANT_STRING(L
"*PNP0303\0");
2956 static ULONG DeviceIndexKeyboard
= 0;
2957 const UNICODE_STRING IdentifierMouse
= RTL_CONSTANT_STRING(L
"PointerController");
2958 UNICODE_STRING HardwareIdMouse
= RTL_CONSTANT_STRING(L
"*PNP0F13\0");
2959 static ULONG DeviceIndexMouse
= 0;
2960 const UNICODE_STRING IdentifierParallel
= RTL_CONSTANT_STRING(L
"ParallelController");
2961 UNICODE_STRING HardwareIdParallel
= RTL_CONSTANT_STRING(L
"*PNP0400\0");
2962 static ULONG DeviceIndexParallel
= 0;
2963 const UNICODE_STRING IdentifierFloppy
= RTL_CONSTANT_STRING(L
"FloppyDiskPeripheral");
2964 UNICODE_STRING HardwareIdFloppy
= RTL_CONSTANT_STRING(L
"*PNP0700\0");
2965 static ULONG DeviceIndexFloppy
= 0;
2966 const UNICODE_STRING IdentifierIsa
= RTL_CONSTANT_STRING(L
"ISA");
2967 UNICODE_STRING HardwareIdIsa
= RTL_CONSTANT_STRING(L
"*PNP0A00\0");
2968 static ULONG DeviceIndexIsa
= 0;
2969 UNICODE_STRING HardwareIdKey
;
2970 PUNICODE_STRING pHardwareId
;
2971 ULONG DeviceIndex
= 0;
2972 PUCHAR CmResourceList
;
2977 Status
= IopOpenRegistryKeyEx(&hDevicesKey
, hBaseKey
, RelativePath
, KEY_ENUMERATE_SUB_KEYS
);
2978 if (!NT_SUCCESS(Status
))
2980 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2985 hDevicesKey
= hBaseKey
;
2987 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2988 if (!pDeviceInformation
)
2990 DPRINT("ExAllocatePool() failed\n");
2991 Status
= STATUS_NO_MEMORY
;
2995 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2996 if (!pValueInformation
)
2998 DPRINT("ExAllocatePool() failed\n");
2999 Status
= STATUS_NO_MEMORY
;
3005 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
3006 if (Status
== STATUS_NO_MORE_ENTRIES
)
3008 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
3010 ExFreePool(pDeviceInformation
);
3011 DeviceInfoLength
= RequiredSize
;
3012 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
3013 if (!pDeviceInformation
)
3015 DPRINT("ExAllocatePool() failed\n");
3016 Status
= STATUS_NO_MEMORY
;
3019 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
3021 if (!NT_SUCCESS(Status
))
3023 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
3028 /* Open device key */
3029 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
3030 DeviceName
.Buffer
= pDeviceInformation
->Name
;
3032 Status
= IopOpenRegistryKeyEx(&hDeviceKey
, hDevicesKey
, &DeviceName
,
3033 KEY_QUERY_VALUE
+ (EnumerateSubKeys
? KEY_ENUMERATE_SUB_KEYS
: 0));
3034 if (!NT_SUCCESS(Status
))
3036 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3040 /* Read boot resources, and add then to parent ones */
3041 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3042 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
3044 ExFreePool(pValueInformation
);
3045 ValueInfoLength
= RequiredSize
;
3046 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
3047 if (!pValueInformation
)
3049 DPRINT("ExAllocatePool() failed\n");
3050 ZwDeleteKey(hLevel2Key
);
3051 Status
= STATUS_NO_MEMORY
;
3054 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3056 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
3058 BootResources
= ParentBootResources
;
3059 BootResourcesLength
= ParentBootResourcesLength
;
3061 else if (!NT_SUCCESS(Status
))
3063 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
3066 else if (pValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
)
3068 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_FULL_RESOURCE_DESCRIPTOR
);
3073 static const ULONG Header
= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
);
3075 /* Concatenate current resources and parent ones */
3076 if (ParentBootResourcesLength
== 0)
3077 BootResourcesLength
= pValueInformation
->DataLength
;
3079 BootResourcesLength
= ParentBootResourcesLength
3080 + pValueInformation
->DataLength
3082 BootResources
= ExAllocatePool(PagedPool
, BootResourcesLength
);
3085 DPRINT("ExAllocatePool() failed\n");
3088 if (ParentBootResourcesLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
3090 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
3092 else if (ParentBootResources
->PartialResourceList
.PartialDescriptors
[ParentBootResources
->PartialResourceList
.Count
- 1].Type
== CmResourceTypeDeviceSpecific
)
3094 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
3096 (PVOID
)((ULONG_PTR
)BootResources
+ pValueInformation
->DataLength
),
3097 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
3098 ParentBootResourcesLength
- Header
);
3099 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
3103 RtlCopyMemory(BootResources
, pValueInformation
->Data
, Header
);
3105 (PVOID
)((ULONG_PTR
)BootResources
+ Header
),
3106 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
3107 ParentBootResourcesLength
- Header
);
3109 (PVOID
)((ULONG_PTR
)BootResources
+ ParentBootResourcesLength
),
3110 pValueInformation
->Data
+ Header
,
3111 pValueInformation
->DataLength
- Header
);
3112 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
3116 if (EnumerateSubKeys
)
3121 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
3122 if (Status
== STATUS_NO_MORE_ENTRIES
)
3124 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
3126 ExFreePool(pDeviceInformation
);
3127 DeviceInfoLength
= RequiredSize
;
3128 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
3129 if (!pDeviceInformation
)
3131 DPRINT("ExAllocatePool() failed\n");
3132 Status
= STATUS_NO_MEMORY
;
3135 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
3137 if (!NT_SUCCESS(Status
))
3139 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
3143 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
3144 DeviceName
.Buffer
= pDeviceInformation
->Name
;
3146 Status
= IopEnumerateDetectedDevices(
3152 BootResourcesLength
);
3153 if (!NT_SUCCESS(Status
))
3158 /* Read identifier */
3159 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3160 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
3162 ExFreePool(pValueInformation
);
3163 ValueInfoLength
= RequiredSize
;
3164 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
3165 if (!pValueInformation
)
3167 DPRINT("ExAllocatePool() failed\n");
3168 Status
= STATUS_NO_MEMORY
;
3171 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3173 if (!NT_SUCCESS(Status
))
3175 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
3177 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
3180 ValueName
.Length
= ValueName
.MaximumLength
= 0;
3182 else if (pValueInformation
->Type
!= REG_SZ
)
3184 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_SZ
);
3189 /* Assign hardware id to this device */
3190 ValueName
.Length
= ValueName
.MaximumLength
= (USHORT
)pValueInformation
->DataLength
;
3191 ValueName
.Buffer
= (PWCHAR
)pValueInformation
->Data
;
3192 if (ValueName
.Length
>= sizeof(WCHAR
) && ValueName
.Buffer
[ValueName
.Length
/ sizeof(WCHAR
) - 1] == UNICODE_NULL
)
3193 ValueName
.Length
-= sizeof(WCHAR
);
3196 if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierSerial
, FALSE
) == 0)
3198 pHardwareId
= &HardwareIdSerial
;
3199 DeviceIndex
= DeviceIndexSerial
++;
3201 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierKeyboard
, FALSE
) == 0)
3203 pHardwareId
= &HardwareIdKeyboard
;
3204 DeviceIndex
= DeviceIndexKeyboard
++;
3206 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierMouse
, FALSE
) == 0)
3208 pHardwareId
= &HardwareIdMouse
;
3209 DeviceIndex
= DeviceIndexMouse
++;
3211 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierParallel
, FALSE
) == 0)
3213 pHardwareId
= &HardwareIdParallel
;
3214 DeviceIndex
= DeviceIndexParallel
++;
3216 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierFloppy
, FALSE
) == 0)
3218 pHardwareId
= &HardwareIdFloppy
;
3219 DeviceIndex
= DeviceIndexFloppy
++;
3221 else if (NT_SUCCESS(Status
))
3223 /* Try to also match the device identifier */
3224 if (RtlCompareUnicodeString(&ValueName
, &IdentifierPci
, FALSE
) == 0)
3226 pHardwareId
= &HardwareIdPci
;
3227 DeviceIndex
= DeviceIndexPci
++;
3229 else if (RtlCompareUnicodeString(&ValueName
, &IdentifierIsa
, FALSE
) == 0)
3231 pHardwareId
= &HardwareIdIsa
;
3232 DeviceIndex
= DeviceIndexIsa
++;
3236 DPRINT("Unknown device '%wZ'\n", &ValueName
);