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 DeviceNode
->ResourceRequirements
= (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
168 Status
= IopAssignDeviceResources(DeviceNode
, &RequiredLength
);
169 if (NT_SUCCESS(Status
))
171 Status
= IopTranslateDeviceResources(DeviceNode
, RequiredLength
);
172 if (NT_SUCCESS(Status
))
174 Status
= IopUpdateResourceMapForPnPDevice(DeviceNode
);
175 if (!NT_SUCCESS(Status
))
177 DPRINT("IopUpdateResourceMap() failed (Status 0x%08lx)\n", Status
);
182 DPRINT("IopTranslateDeviceResources() failed (Status 0x%08lx)\n", Status
);
187 DPRINT("IopAssignDeviceResources() failed (Status 0x%08lx)\n", Status
);
189 IopDeviceNodeClearFlag(DeviceNode
, DNF_ASSIGNING_RESOURCES
);
191 DPRINT("Sending IRP_MN_START_DEVICE to driver\n");
192 Stack
.Parameters
.StartDevice
.AllocatedResources
= DeviceNode
->ResourceList
;
193 Stack
.Parameters
.StartDevice
.AllocatedResourcesTranslated
= DeviceNode
->ResourceListTranslated
;
196 * Windows NT Drivers receive IRP_MN_START_DEVICE in a critical region and
197 * actually _depend_ on this!. This is because NT will lock the Device Node
198 * with an ERESOURCE, which of course requires APCs to be disabled.
200 KeEnterCriticalRegion();
202 Status
= IopInitiatePnpIrp(
203 DeviceNode
->PhysicalDeviceObject
,
208 KeLeaveCriticalRegion();
210 if (!NT_SUCCESS(Status
))
212 DPRINT("IopInitiatePnpIrp() failed\n");
216 if (IopDeviceNodeHasFlag(DeviceNode
, DNF_NEED_ENUMERATION_ONLY
))
218 DPRINT("Device needs enumeration, invalidating bus relations\n");
219 /* Invalidate device relations synchronously
220 (otherwise there will be dirty read of DeviceNode) */
221 IopEnumerateDevice(DeviceNode
->PhysicalDeviceObject
);
222 IopDeviceNodeClearFlag(DeviceNode
, DNF_NEED_ENUMERATION_ONLY
);
226 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, &InstanceHandle
);
227 if (!NT_SUCCESS(Status
))
230 RtlInitUnicodeString(&KeyName
, L
"Control");
231 InitializeObjectAttributes(&ObjectAttributes
,
233 OBJ_CASE_INSENSITIVE
,
236 Status
= ZwCreateKey(&ControlHandle
, KEY_SET_VALUE
, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
237 if (!NT_SUCCESS(Status
))
239 ZwClose(InstanceHandle
);
243 RtlInitUnicodeString(&KeyName
, L
"ActiveService");
244 Status
= ZwSetValueKey(ControlHandle
, &KeyName
, 0, REG_SZ
, DeviceNode
->ServiceName
.Buffer
, DeviceNode
->ServiceName
.Length
);
246 if (NT_SUCCESS(Status
))
247 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
249 ZwClose(ControlHandle
);
250 ZwClose(InstanceHandle
);
257 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode
,
258 PDEVICE_CAPABILITIES DeviceCaps
)
260 IO_STATUS_BLOCK StatusBlock
;
261 IO_STACK_LOCATION Stack
;
263 /* Set up the Header */
264 RtlZeroMemory(DeviceCaps
, sizeof(DEVICE_CAPABILITIES
));
265 DeviceCaps
->Size
= sizeof(DEVICE_CAPABILITIES
);
266 DeviceCaps
->Version
= 1;
267 DeviceCaps
->Address
= -1;
268 DeviceCaps
->UINumber
= -1;
270 /* Set up the Stack */
271 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
272 Stack
.Parameters
.DeviceCapabilities
.Capabilities
= DeviceCaps
;
275 return IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
277 IRP_MN_QUERY_CAPABILITIES
,
282 IopAsynchronousInvalidateDeviceRelations(
283 IN PDEVICE_OBJECT DeviceObject
,
284 IN PVOID InvalidateContext
)
286 PINVALIDATE_DEVICE_RELATION_DATA Data
= InvalidateContext
;
288 IoSynchronousInvalidateDeviceRelations(
292 ObDereferenceObject(Data
->DeviceObject
);
293 IoFreeWorkItem(Data
->WorkItem
);
298 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT
*DeviceObject
)
302 if (PopSystemPowerDeviceNode
)
304 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
305 *DeviceObject
= PopSystemPowerDeviceNode
->PhysicalDeviceObject
;
306 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
308 return STATUS_SUCCESS
;
311 return STATUS_UNSUCCESSFUL
;
316 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid
)
318 USHORT i
= 0, FoundIndex
= 0xFFFF;
322 /* Acquire the lock */
323 ExAcquireFastMutex(&IopBusTypeGuidListLock
);
325 /* Loop all entries */
326 while (i
< IopBusTypeGuidList
->GuidCount
)
328 /* Try to find a match */
329 if (RtlCompareMemory(BusTypeGuid
,
330 &IopBusTypeGuidList
->Guids
[i
],
331 sizeof(GUID
)) == sizeof(GUID
))
340 /* Check if we have to grow the list */
341 if (IopBusTypeGuidList
->GuidCount
)
343 /* Calculate the new size */
344 NewSize
= sizeof(IO_BUS_TYPE_GUID_LIST
) +
345 (sizeof(GUID
) * IopBusTypeGuidList
->GuidCount
);
347 /* Allocate the new copy */
348 NewList
= ExAllocatePool(PagedPool
, NewSize
);
352 ExFreePool(IopBusTypeGuidList
);
356 /* Now copy them, decrease the size too */
357 NewSize
-= sizeof(GUID
);
358 RtlCopyMemory(NewList
, IopBusTypeGuidList
, NewSize
);
360 /* Free the old list */
361 ExFreePool(IopBusTypeGuidList
);
363 /* Use the new buffer */
364 IopBusTypeGuidList
= NewList
;
367 /* Copy the new GUID */
368 RtlCopyMemory(&IopBusTypeGuidList
->Guids
[IopBusTypeGuidList
->GuidCount
],
372 /* The new entry is the index */
373 FoundIndex
= (USHORT
)IopBusTypeGuidList
->GuidCount
;
374 IopBusTypeGuidList
->GuidCount
++;
377 ExReleaseFastMutex(&IopBusTypeGuidListLock
);
383 * Creates a device node
386 * ParentNode = Pointer to parent device node
387 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
388 * to have the root device node create one
389 * (eg. for legacy drivers)
390 * DeviceNode = Pointer to storage for created device node
396 IopCreateDeviceNode(PDEVICE_NODE ParentNode
,
397 PDEVICE_OBJECT PhysicalDeviceObject
,
398 PUNICODE_STRING ServiceName
,
399 PDEVICE_NODE
*DeviceNode
)
404 UNICODE_STRING FullServiceName
;
405 UNICODE_STRING LegacyPrefix
= RTL_CONSTANT_STRING(L
"LEGACY_");
406 UNICODE_STRING UnknownDeviceName
= RTL_CONSTANT_STRING(L
"UNKNOWN");
409 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
410 ParentNode
, PhysicalDeviceObject
, ServiceName
);
412 Node
= (PDEVICE_NODE
)ExAllocatePool(NonPagedPool
, sizeof(DEVICE_NODE
));
415 return STATUS_INSUFFICIENT_RESOURCES
;
418 RtlZeroMemory(Node
, sizeof(DEVICE_NODE
));
421 ServiceName
= &UnknownDeviceName
;
423 if (!PhysicalDeviceObject
)
425 FullServiceName
.MaximumLength
= LegacyPrefix
.Length
+ ServiceName
->Length
;
426 FullServiceName
.Length
= 0;
427 FullServiceName
.Buffer
= ExAllocatePool(PagedPool
, FullServiceName
.MaximumLength
);
428 if (!FullServiceName
.Buffer
)
431 return STATUS_INSUFFICIENT_RESOURCES
;
434 RtlAppendUnicodeStringToString(&FullServiceName
, &LegacyPrefix
);
435 RtlAppendUnicodeStringToString(&FullServiceName
, ServiceName
);
437 Status
= PnpRootCreateDevice(&FullServiceName
, &PhysicalDeviceObject
, &Node
->InstancePath
);
438 if (!NT_SUCCESS(Status
))
440 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status
);
445 /* Create the device key for legacy drivers */
446 Status
= IopCreateDeviceKeyPath(&Node
->InstancePath
, &TempHandle
);
447 if (NT_SUCCESS(Status
))
450 ExFreePool(FullServiceName
.Buffer
);
452 /* This is for drivers passed on the command line to ntoskrnl.exe */
453 IopDeviceNodeSetFlag(Node
, DNF_STARTED
);
454 IopDeviceNodeSetFlag(Node
, DNF_LEGACY_DRIVER
);
457 Node
->PhysicalDeviceObject
= PhysicalDeviceObject
;
459 ((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= Node
;
463 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
464 Node
->Parent
= ParentNode
;
465 Node
->Sibling
= ParentNode
->Child
;
466 ParentNode
->Child
= Node
;
467 if (ParentNode
->LastChild
== NULL
)
468 ParentNode
->LastChild
= Node
;
469 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
470 Node
->Level
= ParentNode
->Level
+ 1;
473 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
477 return STATUS_SUCCESS
;
481 IopFreeDeviceNode(PDEVICE_NODE DeviceNode
)
484 PDEVICE_NODE PrevSibling
= NULL
;
486 /* All children must be deleted before a parent is deleted */
487 ASSERT(!DeviceNode
->Child
);
489 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
491 ASSERT(DeviceNode
->PhysicalDeviceObject
);
493 ObDereferenceObject(DeviceNode
->PhysicalDeviceObject
);
495 /* Get previous sibling */
496 if (DeviceNode
->Parent
&& DeviceNode
->Parent
->Child
!= DeviceNode
)
498 PrevSibling
= DeviceNode
->Parent
->Child
;
499 while (PrevSibling
->Sibling
!= DeviceNode
)
500 PrevSibling
= PrevSibling
->Sibling
;
503 /* Unlink from parent if it exists */
504 if (DeviceNode
->Parent
)
506 if (DeviceNode
->Parent
->LastChild
== DeviceNode
)
508 DeviceNode
->Parent
->LastChild
= PrevSibling
;
510 PrevSibling
->Sibling
= NULL
;
512 if (DeviceNode
->Parent
->Child
== DeviceNode
)
513 DeviceNode
->Parent
->Child
= DeviceNode
->Sibling
;
516 /* Unlink from sibling list */
518 PrevSibling
->Sibling
= DeviceNode
->Sibling
;
520 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
522 RtlFreeUnicodeString(&DeviceNode
->InstancePath
);
524 RtlFreeUnicodeString(&DeviceNode
->ServiceName
);
526 if (DeviceNode
->ResourceList
)
528 ExFreePool(DeviceNode
->ResourceList
);
531 if (DeviceNode
->ResourceListTranslated
)
533 ExFreePool(DeviceNode
->ResourceListTranslated
);
536 if (DeviceNode
->ResourceRequirements
)
538 ExFreePool(DeviceNode
->ResourceRequirements
);
541 if (DeviceNode
->BootResources
)
543 ExFreePool(DeviceNode
->BootResources
);
546 ExFreePool(DeviceNode
);
548 return STATUS_SUCCESS
;
552 IopInitiatePnpIrp(PDEVICE_OBJECT DeviceObject
,
553 PIO_STATUS_BLOCK IoStatusBlock
,
555 PIO_STACK_LOCATION Stack OPTIONAL
)
557 PDEVICE_OBJECT TopDeviceObject
;
558 PIO_STACK_LOCATION IrpSp
;
563 /* Always call the top of the device stack */
564 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
571 Irp
= IoBuildSynchronousFsdRequest(
580 /* PNP IRPs are initialized with a status code of STATUS_NOT_SUPPORTED */
581 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
582 Irp
->IoStatus
.Information
= 0;
584 if (MinorFunction
== IRP_MN_FILTER_RESOURCE_REQUIREMENTS
)
586 Irp
->IoStatus
.Information
= (ULONG_PTR
)Stack
->Parameters
.FilterResourceRequirements
.IoResourceRequirementList
;
589 IrpSp
= IoGetNextIrpStackLocation(Irp
);
590 IrpSp
->MinorFunction
= (UCHAR
)MinorFunction
;
594 RtlCopyMemory(&IrpSp
->Parameters
,
596 sizeof(Stack
->Parameters
));
599 Status
= IoCallDriver(TopDeviceObject
, Irp
);
600 if (Status
== STATUS_PENDING
)
602 KeWaitForSingleObject(&Event
,
607 Status
= IoStatusBlock
->Status
;
610 ObDereferenceObject(TopDeviceObject
);
617 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context
)
619 PDEVICE_NODE ParentDeviceNode
;
620 PDEVICE_NODE ChildDeviceNode
;
623 /* Copy context data so we don't overwrite it in subsequent calls to this function */
624 ParentDeviceNode
= Context
->DeviceNode
;
626 /* Call the action routine */
627 Status
= (Context
->Action
)(ParentDeviceNode
, Context
->Context
);
628 if (!NT_SUCCESS(Status
))
633 /* Traversal of all children nodes */
634 for (ChildDeviceNode
= ParentDeviceNode
->Child
;
635 ChildDeviceNode
!= NULL
;
636 ChildDeviceNode
= ChildDeviceNode
->Sibling
)
638 /* Pass the current device node to the action routine */
639 Context
->DeviceNode
= ChildDeviceNode
;
641 Status
= IopTraverseDeviceTreeNode(Context
);
642 if (!NT_SUCCESS(Status
))
653 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context
)
657 DPRINT("Context 0x%p\n", Context
);
659 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %x Context 0x%p)\n",
660 Context
->DeviceNode
, Context
->FirstDeviceNode
, Context
->Action
, Context
->Context
);
662 /* Start from the specified device node */
663 Context
->DeviceNode
= Context
->FirstDeviceNode
;
665 /* Recursively traverse the device tree */
666 Status
= IopTraverseDeviceTreeNode(Context
);
667 if (Status
== STATUS_UNSUCCESSFUL
)
669 /* The action routine just wanted to terminate the traversal with status
670 code STATUS_SUCCESS */
671 Status
= STATUS_SUCCESS
;
679 * IopCreateDeviceKeyPath
681 * Creates a registry key
685 * Name of the key to be created.
687 * Handle to the newly created key
690 * This method can create nested trees, so parent of RegistryPath can
691 * be not existant, and will be created if needed.
695 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath
,
698 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(ENUM_ROOT
);
699 HANDLE hParent
= NULL
, hKey
;
700 OBJECT_ATTRIBUTES ObjectAttributes
;
701 UNICODE_STRING KeyName
;
702 LPCWSTR Current
, Last
;
709 /* Open root key for device instances */
710 Status
= IopOpenRegistryKeyEx(&hParent
, NULL
, &EnumU
, KEY_CREATE_SUB_KEY
);
711 if (!NT_SUCCESS(Status
))
713 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU
, Status
);
717 Current
= KeyName
.Buffer
= RegistryPath
->Buffer
;
718 Last
= &RegistryPath
->Buffer
[RegistryPath
->Length
/ sizeof(WCHAR
)];
720 /* Go up to the end of the string */
721 while (Current
<= Last
)
723 if (Current
!= Last
&& *Current
!= '\\')
725 /* Not the end of the string and not a separator */
730 /* Prepare relative key name */
731 dwLength
= (ULONG_PTR
)Current
- (ULONG_PTR
)KeyName
.Buffer
;
732 KeyName
.MaximumLength
= KeyName
.Length
= dwLength
;
733 DPRINT("Create '%wZ'\n", &KeyName
);
736 InitializeObjectAttributes(&ObjectAttributes
,
738 OBJ_CASE_INSENSITIVE
,
741 Status
= ZwCreateKey(&hKey
,
742 Current
== Last
? KEY_ALL_ACCESS
: KEY_CREATE_SUB_KEY
,
749 /* Close parent key handle, we don't need it anymore */
753 /* Key opening/creating failed? */
754 if (!NT_SUCCESS(Status
))
756 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName
, Status
);
760 /* Check if it is the end of the string */
763 /* Yes, return success */
765 return STATUS_SUCCESS
;
768 /* Start with this new parent key */
771 KeyName
.Buffer
= (LPWSTR
)Current
;
774 return STATUS_UNSUCCESSFUL
;
778 IopUpdateResourceMap(IN PDEVICE_NODE DeviceNode
, PWCHAR Level1Key
, PWCHAR Level2Key
)
782 HANDLE PnpMgrLevel1
, PnpMgrLevel2
, ResourceMapKey
;
783 UNICODE_STRING KeyName
;
784 OBJECT_ATTRIBUTES ObjectAttributes
;
786 RtlInitUnicodeString(&KeyName
,
787 L
"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
788 InitializeObjectAttributes(&ObjectAttributes
,
790 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
793 Status
= ZwCreateKey(&ResourceMapKey
,
800 if (!NT_SUCCESS(Status
))
803 RtlInitUnicodeString(&KeyName
, Level1Key
);
804 InitializeObjectAttributes(&ObjectAttributes
,
806 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
809 Status
= ZwCreateKey(&PnpMgrLevel1
,
816 ZwClose(ResourceMapKey
);
817 if (!NT_SUCCESS(Status
))
820 RtlInitUnicodeString(&KeyName
, Level2Key
);
821 InitializeObjectAttributes(&ObjectAttributes
,
823 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
826 Status
= ZwCreateKey(&PnpMgrLevel2
,
833 ZwClose(PnpMgrLevel1
);
834 if (!NT_SUCCESS(Status
))
837 if (DeviceNode
->ResourceList
)
840 UNICODE_STRING NameU
;
841 UNICODE_STRING Suffix
;
844 ASSERT(DeviceNode
->ResourceListTranslated
);
846 NameU
.Buffer
= NameBuff
;
848 NameU
.MaximumLength
= 256 * sizeof(WCHAR
);
850 Status
= IoGetDeviceProperty(DeviceNode
->PhysicalDeviceObject
,
851 DevicePropertyPhysicalDeviceObjectName
,
855 ASSERT(Status
== STATUS_SUCCESS
);
857 NameU
.Length
= (USHORT
)OldLength
;
859 RtlInitUnicodeString(&Suffix
, L
".Raw");
860 RtlAppendUnicodeStringToString(&NameU
, &Suffix
);
862 Status
= ZwSetValueKey(PnpMgrLevel2
,
866 DeviceNode
->ResourceList
,
867 CM_RESOURCE_LIST_SIZE(DeviceNode
->ResourceList
));
868 if (!NT_SUCCESS(Status
))
870 ZwClose(PnpMgrLevel2
);
874 /* "Remove" the suffix by setting the length back to what it used to be */
875 NameU
.Length
= (USHORT
)OldLength
;
877 RtlInitUnicodeString(&Suffix
, L
".Translated");
878 RtlAppendUnicodeStringToString(&NameU
, &Suffix
);
880 Status
= ZwSetValueKey(PnpMgrLevel2
,
884 DeviceNode
->ResourceListTranslated
,
885 CM_RESOURCE_LIST_SIZE(DeviceNode
->ResourceListTranslated
));
886 ZwClose(PnpMgrLevel2
);
887 if (!NT_SUCCESS(Status
))
892 ZwClose(PnpMgrLevel2
);
895 IopDeviceNodeSetFlag(DeviceNode
, DNF_RESOURCE_ASSIGNED
);
897 return STATUS_SUCCESS
;
901 IopUpdateResourceMapForPnPDevice(IN PDEVICE_NODE DeviceNode
)
903 return IopUpdateResourceMap(DeviceNode
, L
"PnP Manager", L
"PnpManager");
907 IopSetDeviceInstanceData(HANDLE InstanceKey
,
908 PDEVICE_NODE DeviceNode
)
910 OBJECT_ATTRIBUTES ObjectAttributes
;
911 UNICODE_STRING KeyName
;
914 ULONG ListSize
, ResultLength
;
916 HANDLE ControlHandle
;
918 DPRINT("IopSetDeviceInstanceData() called\n");
920 /* Create the 'LogConf' key */
921 RtlInitUnicodeString(&KeyName
, L
"LogConf");
922 InitializeObjectAttributes(&ObjectAttributes
,
924 OBJ_CASE_INSENSITIVE
,
927 Status
= ZwCreateKey(&LogConfKey
,
934 if (NT_SUCCESS(Status
))
936 /* Set 'BootConfig' value */
937 if (DeviceNode
->BootResources
!= NULL
)
939 ResCount
= DeviceNode
->BootResources
->Count
;
942 ListSize
= CM_RESOURCE_LIST_SIZE(DeviceNode
->BootResources
);
944 RtlInitUnicodeString(&KeyName
, L
"BootConfig");
945 Status
= ZwSetValueKey(LogConfKey
,
949 DeviceNode
->BootResources
,
954 /* Set 'BasicConfigVector' value */
955 if (DeviceNode
->ResourceRequirements
!= NULL
&&
956 DeviceNode
->ResourceRequirements
->ListSize
!= 0)
958 RtlInitUnicodeString(&KeyName
, L
"BasicConfigVector");
959 Status
= ZwSetValueKey(LogConfKey
,
962 REG_RESOURCE_REQUIREMENTS_LIST
,
963 DeviceNode
->ResourceRequirements
,
964 DeviceNode
->ResourceRequirements
->ListSize
);
970 /* Set the 'ConfigFlags' value */
971 RtlInitUnicodeString(&KeyName
, L
"ConfigFlags");
972 Status
= ZwQueryValueKey(InstanceKey
,
974 KeyValueBasicInformation
,
978 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
980 /* Write the default value */
981 ULONG DefaultConfigFlags
= 0;
982 Status
= ZwSetValueKey(InstanceKey
,
987 sizeof(DefaultConfigFlags
));
990 /* Create the 'Control' key */
991 RtlInitUnicodeString(&KeyName
, L
"Control");
992 InitializeObjectAttributes(&ObjectAttributes
,
994 OBJ_CASE_INSENSITIVE
,
997 Status
= ZwCreateKey(&ControlHandle
, 0, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
999 if (NT_SUCCESS(Status
))
1000 ZwClose(ControlHandle
);
1002 DPRINT("IopSetDeviceInstanceData() done\n");
1008 IopCheckResourceDescriptor(
1009 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc
,
1010 IN PCM_RESOURCE_LIST ResourceList
,
1012 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
1015 BOOLEAN Result
= FALSE
;
1017 if (ResDesc
->ShareDisposition
== CmResourceShareShared
)
1020 for (i
= 0; i
< ResourceList
->Count
; i
++)
1022 PCM_PARTIAL_RESOURCE_LIST ResList
= &ResourceList
->List
[i
].PartialResourceList
;
1023 for (ii
= 0; ii
< ResList
->Count
; ii
++)
1025 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc2
= &ResList
->PartialDescriptors
[ii
];
1027 /* We don't care about shared resources */
1028 if (ResDesc
->ShareDisposition
== CmResourceShareShared
&&
1029 ResDesc2
->ShareDisposition
== CmResourceShareShared
)
1032 /* Make sure we're comparing the same types */
1033 if (ResDesc
->Type
!= ResDesc2
->Type
)
1036 switch (ResDesc
->Type
)
1038 case CmResourceTypeMemory
:
1039 if ((ResDesc
->u
.Memory
.Start
.QuadPart
< ResDesc2
->u
.Memory
.Start
.QuadPart
&&
1040 ResDesc
->u
.Memory
.Start
.QuadPart
+ ResDesc
->u
.Memory
.Length
>
1041 ResDesc2
->u
.Memory
.Start
.QuadPart
) || (ResDesc2
->u
.Memory
.Start
.QuadPart
<
1042 ResDesc
->u
.Memory
.Start
.QuadPart
&& ResDesc2
->u
.Memory
.Start
.QuadPart
+
1043 ResDesc2
->u
.Memory
.Length
> ResDesc
->u
.Memory
.Start
.QuadPart
))
1047 DPRINT1("Resource conflict: Memory (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
1048 ResDesc
->u
.Memory
.Start
.QuadPart
, ResDesc
->u
.Memory
.Start
.QuadPart
+
1049 ResDesc
->u
.Memory
.Length
, ResDesc2
->u
.Memory
.Start
.QuadPart
,
1050 ResDesc2
->u
.Memory
.Start
.QuadPart
+ ResDesc2
->u
.Memory
.Length
);
1059 case CmResourceTypePort
:
1060 if ((ResDesc
->u
.Port
.Start
.QuadPart
< ResDesc2
->u
.Port
.Start
.QuadPart
&&
1061 ResDesc
->u
.Port
.Start
.QuadPart
+ ResDesc
->u
.Port
.Length
>
1062 ResDesc2
->u
.Port
.Start
.QuadPart
) || (ResDesc2
->u
.Port
.Start
.QuadPart
<
1063 ResDesc
->u
.Port
.Start
.QuadPart
&& ResDesc2
->u
.Port
.Start
.QuadPart
+
1064 ResDesc2
->u
.Port
.Length
> ResDesc
->u
.Port
.Start
.QuadPart
))
1068 DPRINT1("Resource conflict: Port (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
1069 ResDesc
->u
.Port
.Start
.QuadPart
, ResDesc
->u
.Port
.Start
.QuadPart
+
1070 ResDesc
->u
.Port
.Length
, ResDesc2
->u
.Port
.Start
.QuadPart
,
1071 ResDesc2
->u
.Port
.Start
.QuadPart
+ ResDesc2
->u
.Port
.Length
);
1080 case CmResourceTypeInterrupt
:
1081 if (ResDesc
->u
.Interrupt
.Vector
== ResDesc2
->u
.Interrupt
.Vector
)
1085 DPRINT1("Resource conflict: IRQ (0x%x 0x%x vs. 0x%x 0x%x)\n",
1086 ResDesc
->u
.Interrupt
.Vector
, ResDesc
->u
.Interrupt
.Level
,
1087 ResDesc2
->u
.Interrupt
.Vector
, ResDesc2
->u
.Interrupt
.Level
);
1096 case CmResourceTypeBusNumber
:
1097 if ((ResDesc
->u
.BusNumber
.Start
< ResDesc2
->u
.BusNumber
.Start
&&
1098 ResDesc
->u
.BusNumber
.Start
+ ResDesc
->u
.BusNumber
.Length
>
1099 ResDesc2
->u
.BusNumber
.Start
) || (ResDesc2
->u
.BusNumber
.Start
<
1100 ResDesc
->u
.BusNumber
.Start
&& ResDesc2
->u
.BusNumber
.Start
+
1101 ResDesc2
->u
.BusNumber
.Length
> ResDesc
->u
.BusNumber
.Start
))
1105 DPRINT1("Resource conflict: Bus number (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
1106 ResDesc
->u
.BusNumber
.Start
, ResDesc
->u
.BusNumber
.Start
+
1107 ResDesc
->u
.BusNumber
.Length
, ResDesc2
->u
.BusNumber
.Start
,
1108 ResDesc2
->u
.BusNumber
.Start
+ ResDesc2
->u
.BusNumber
.Length
);
1117 case CmResourceTypeDma
:
1118 if (ResDesc
->u
.Dma
.Channel
== ResDesc2
->u
.Dma
.Channel
)
1122 DPRINT1("Resource conflict: Dma (0x%x 0x%x vs. 0x%x 0x%x)\n",
1123 ResDesc
->u
.Dma
.Channel
, ResDesc
->u
.Dma
.Port
,
1124 ResDesc2
->u
.Dma
.Channel
, ResDesc2
->u
.Dma
.Port
);
1138 if (Result
&& ConflictingDescriptor
)
1140 RtlCopyMemory(ConflictingDescriptor
,
1142 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
));
1150 IopCheckForResourceConflict(
1151 IN PCM_RESOURCE_LIST ResourceList1
,
1152 IN PCM_RESOURCE_LIST ResourceList2
,
1154 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
1157 BOOLEAN Result
= FALSE
;
1159 for (i
= 0; i
< ResourceList1
->Count
; i
++)
1161 PCM_PARTIAL_RESOURCE_LIST ResList
= &ResourceList1
->List
[i
].PartialResourceList
;
1162 for (ii
= 0; ii
< ResList
->Count
; ii
++)
1164 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc
= &ResList
->PartialDescriptors
[ii
];
1166 Result
= IopCheckResourceDescriptor(ResDesc
,
1169 ConflictingDescriptor
);
1170 if (Result
) goto ByeBye
;
1181 IopDetectResourceConflict(
1182 IN PCM_RESOURCE_LIST ResourceList
,
1184 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
1186 OBJECT_ATTRIBUTES ObjectAttributes
;
1187 UNICODE_STRING KeyName
;
1188 HANDLE ResourceMapKey
= INVALID_HANDLE_VALUE
, ChildKey2
= INVALID_HANDLE_VALUE
, ChildKey3
= INVALID_HANDLE_VALUE
;
1189 ULONG KeyInformationLength
, RequiredLength
, KeyValueInformationLength
, KeyNameInformationLength
;
1190 PKEY_BASIC_INFORMATION KeyInformation
;
1191 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
;
1192 PKEY_VALUE_BASIC_INFORMATION KeyNameInformation
;
1193 ULONG ChildKeyIndex1
= 0, ChildKeyIndex2
= 0, ChildKeyIndex3
= 0;
1196 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
1197 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, 0, NULL
);
1198 Status
= ZwOpenKey(&ResourceMapKey
, KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
1199 if (!NT_SUCCESS(Status
))
1201 /* The key is missing which means we are the first device */
1202 return STATUS_SUCCESS
;
1207 Status
= ZwEnumerateKey(ResourceMapKey
,
1209 KeyBasicInformation
,
1213 if (Status
== STATUS_NO_MORE_ENTRIES
)
1215 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
1217 KeyInformationLength
= RequiredLength
;
1218 KeyInformation
= ExAllocatePool(PagedPool
, KeyInformationLength
);
1219 if (!KeyInformation
)
1221 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1225 Status
= ZwEnumerateKey(ResourceMapKey
,
1227 KeyBasicInformation
,
1229 KeyInformationLength
,
1235 if (!NT_SUCCESS(Status
))
1238 KeyName
.Buffer
= KeyInformation
->Name
;
1239 KeyName
.MaximumLength
= KeyName
.Length
= KeyInformation
->NameLength
;
1240 InitializeObjectAttributes(&ObjectAttributes
,
1242 OBJ_CASE_INSENSITIVE
,
1245 Status
= ZwOpenKey(&ChildKey2
, KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
1246 ExFreePool(KeyInformation
);
1247 if (!NT_SUCCESS(Status
))
1252 Status
= ZwEnumerateKey(ChildKey2
,
1254 KeyBasicInformation
,
1258 if (Status
== STATUS_NO_MORE_ENTRIES
)
1260 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
1262 KeyInformationLength
= RequiredLength
;
1263 KeyInformation
= ExAllocatePool(PagedPool
, KeyInformationLength
);
1264 if (!KeyInformation
)
1266 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1270 Status
= ZwEnumerateKey(ChildKey2
,
1272 KeyBasicInformation
,
1274 KeyInformationLength
,
1280 if (!NT_SUCCESS(Status
))
1283 KeyName
.Buffer
= KeyInformation
->Name
;
1284 KeyName
.MaximumLength
= KeyName
.Length
= KeyInformation
->NameLength
;
1285 InitializeObjectAttributes(&ObjectAttributes
,
1287 OBJ_CASE_INSENSITIVE
,
1290 Status
= ZwOpenKey(&ChildKey3
, KEY_QUERY_VALUE
, &ObjectAttributes
);
1291 ExFreePool(KeyInformation
);
1292 if (!NT_SUCCESS(Status
))
1297 Status
= ZwEnumerateValueKey(ChildKey3
,
1299 KeyValuePartialInformation
,
1303 if (Status
== STATUS_NO_MORE_ENTRIES
)
1305 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
1307 KeyValueInformationLength
= RequiredLength
;
1308 KeyValueInformation
= ExAllocatePool(PagedPool
, KeyValueInformationLength
);
1309 if (!KeyValueInformation
)
1311 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1315 Status
= ZwEnumerateValueKey(ChildKey3
,
1317 KeyValuePartialInformation
,
1318 KeyValueInformation
,
1319 KeyValueInformationLength
,
1324 if (!NT_SUCCESS(Status
))
1327 Status
= ZwEnumerateValueKey(ChildKey3
,
1329 KeyValueBasicInformation
,
1333 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1335 KeyNameInformationLength
= RequiredLength
;
1336 KeyNameInformation
= ExAllocatePool(PagedPool
, KeyNameInformationLength
+ sizeof(WCHAR
));
1337 if (!KeyNameInformation
)
1339 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1343 Status
= ZwEnumerateValueKey(ChildKey3
,
1345 KeyValueBasicInformation
,
1347 KeyNameInformationLength
,
1355 if (!NT_SUCCESS(Status
))
1358 KeyNameInformation
->Name
[KeyNameInformation
->NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1360 /* Skip translated entries */
1361 if (wcsstr(KeyNameInformation
->Name
, L
".Translated"))
1363 ExFreePool(KeyNameInformation
);
1367 ExFreePool(KeyNameInformation
);
1369 if (IopCheckForResourceConflict(ResourceList
,
1370 (PCM_RESOURCE_LIST
)KeyValueInformation
->Data
,
1372 ConflictingDescriptor
))
1374 ExFreePool(KeyValueInformation
);
1375 Status
= STATUS_CONFLICTING_ADDRESSES
;
1379 ExFreePool(KeyValueInformation
);
1385 if (ResourceMapKey
!= INVALID_HANDLE_VALUE
)
1386 ZwClose(ResourceMapKey
);
1387 if (ChildKey2
!= INVALID_HANDLE_VALUE
)
1389 if (ChildKey3
!= INVALID_HANDLE_VALUE
)
1392 if (Status
== STATUS_NO_MORE_ENTRIES
)
1393 Status
= STATUS_SUCCESS
;
1399 IopCheckDescriptorForConflict(PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
, OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
1401 CM_RESOURCE_LIST CmList
;
1405 CmList
.List
[0].InterfaceType
= InterfaceTypeUndefined
;
1406 CmList
.List
[0].BusNumber
= 0;
1407 CmList
.List
[0].PartialResourceList
.Version
= 1;
1408 CmList
.List
[0].PartialResourceList
.Revision
= 1;
1409 CmList
.List
[0].PartialResourceList
.Count
= 1;
1410 CmList
.List
[0].PartialResourceList
.PartialDescriptors
[0] = *CmDesc
;
1412 Status
= IopDetectResourceConflict(&CmList
, TRUE
, ConflictingDescriptor
);
1413 if (Status
== STATUS_CONFLICTING_ADDRESSES
)
1420 IopFindBusNumberResource(
1421 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
1422 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
1425 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc
;
1427 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
1428 ASSERT(IoDesc
->Type
== CmResourceTypeBusNumber
);
1430 for (Start
= IoDesc
->u
.BusNumber
.MinBusNumber
;
1431 Start
< IoDesc
->u
.BusNumber
.MaxBusNumber
;
1434 CmDesc
->u
.BusNumber
.Length
= IoDesc
->u
.BusNumber
.Length
;
1435 CmDesc
->u
.BusNumber
.Start
= Start
;
1437 if (IopCheckDescriptorForConflict(CmDesc
, &ConflictingDesc
))
1439 Start
+= ConflictingDesc
.u
.BusNumber
.Start
+ ConflictingDesc
.u
.BusNumber
.Length
;
1451 IopFindMemoryResource(
1452 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
1453 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
1456 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc
;
1458 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
1459 ASSERT(IoDesc
->Type
== CmResourceTypeMemory
);
1461 for (Start
= IoDesc
->u
.Memory
.MinimumAddress
.QuadPart
;
1462 Start
< IoDesc
->u
.Memory
.MaximumAddress
.QuadPart
;
1465 CmDesc
->u
.Memory
.Length
= IoDesc
->u
.Memory
.Length
;
1466 CmDesc
->u
.Memory
.Start
.QuadPart
= Start
;
1468 if (IopCheckDescriptorForConflict(CmDesc
, &ConflictingDesc
))
1470 Start
+= ConflictingDesc
.u
.Memory
.Start
.QuadPart
+ ConflictingDesc
.u
.Memory
.Length
;
1482 IopFindPortResource(
1483 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
1484 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
1487 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc
;
1489 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
1490 ASSERT(IoDesc
->Type
== CmResourceTypePort
);
1492 for (Start
= IoDesc
->u
.Port
.MinimumAddress
.QuadPart
;
1493 Start
< IoDesc
->u
.Port
.MaximumAddress
.QuadPart
;
1496 CmDesc
->u
.Port
.Length
= IoDesc
->u
.Port
.Length
;
1497 CmDesc
->u
.Port
.Start
.QuadPart
= Start
;
1499 if (IopCheckDescriptorForConflict(CmDesc
, &ConflictingDesc
))
1501 Start
+= ConflictingDesc
.u
.Port
.Start
.QuadPart
+ ConflictingDesc
.u
.Port
.Length
;
1514 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
1515 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
1519 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
1520 ASSERT(IoDesc
->Type
== CmResourceTypeDma
);
1522 for (Channel
= IoDesc
->u
.Dma
.MinimumChannel
;
1523 Channel
< IoDesc
->u
.Dma
.MaximumChannel
;
1526 CmDesc
->u
.Dma
.Channel
= Channel
;
1527 CmDesc
->u
.Dma
.Port
= 0;
1529 if (!IopCheckDescriptorForConflict(CmDesc
, NULL
))
1537 IopFindInterruptResource(
1538 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
1539 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
1543 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
1544 ASSERT(IoDesc
->Type
== CmResourceTypeInterrupt
);
1546 for (Vector
= IoDesc
->u
.Interrupt
.MinimumVector
;
1547 Vector
< IoDesc
->u
.Interrupt
.MaximumVector
;
1550 CmDesc
->u
.Interrupt
.Vector
= Vector
;
1551 CmDesc
->u
.Interrupt
.Level
= Vector
;
1552 CmDesc
->u
.Interrupt
.Affinity
= (KAFFINITY
)-1;
1554 if (!IopCheckDescriptorForConflict(CmDesc
, NULL
))
1562 IopCreateResourceListFromRequirements(
1563 IN PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList
,
1564 OUT PCM_RESOURCE_LIST
*ResourceList
)
1567 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc
;
1569 Size
= FIELD_OFFSET(CM_RESOURCE_LIST
, List
);
1570 for (i
= 0; i
< RequirementsList
->AlternativeLists
; i
++)
1572 PIO_RESOURCE_LIST ResList
= &RequirementsList
->List
[i
];
1573 Size
+= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
)
1574 + ResList
->Count
* sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
1577 *ResourceList
= ExAllocatePool(PagedPool
, Size
);
1579 return STATUS_INSUFFICIENT_RESOURCES
;
1581 (*ResourceList
)->Count
= 1;
1582 (*ResourceList
)->List
[0].BusNumber
= RequirementsList
->BusNumber
;
1583 (*ResourceList
)->List
[0].InterfaceType
= RequirementsList
->InterfaceType
;
1584 (*ResourceList
)->List
[0].PartialResourceList
.Version
= 1;
1585 (*ResourceList
)->List
[0].PartialResourceList
.Revision
= 1;
1586 (*ResourceList
)->List
[0].PartialResourceList
.Count
= 0;
1588 ResDesc
= &(*ResourceList
)->List
[0].PartialResourceList
.PartialDescriptors
[0];
1590 for (i
= 0; i
< RequirementsList
->AlternativeLists
; i
++)
1592 PIO_RESOURCE_LIST ResList
= &RequirementsList
->List
[i
];
1593 for (ii
= 0; ii
< ResList
->Count
; ii
++)
1595 PIO_RESOURCE_DESCRIPTOR ReqDesc
= &ResList
->Descriptors
[ii
];
1597 /* FIXME: Handle alternate ranges */
1598 if (ReqDesc
->Option
== IO_RESOURCE_ALTERNATIVE
)
1601 ResDesc
->Type
= ReqDesc
->Type
;
1602 ResDesc
->Flags
= ReqDesc
->Flags
;
1603 ResDesc
->ShareDisposition
= ReqDesc
->ShareDisposition
;
1605 switch (ReqDesc
->Type
)
1607 case CmResourceTypeInterrupt
:
1608 if (!IopFindInterruptResource(ReqDesc
, ResDesc
))
1610 DPRINT1("Failed to find an available interrupt resource (0x%x to 0x%x)\n",
1611 ReqDesc
->u
.Interrupt
.MinimumVector
, ReqDesc
->u
.Interrupt
.MaximumVector
);
1613 if (ReqDesc
->Option
== 0)
1615 ExFreePool(*ResourceList
);
1616 return STATUS_CONFLICTING_ADDRESSES
;
1621 case CmResourceTypePort
:
1622 if (!IopFindPortResource(ReqDesc
, ResDesc
))
1624 DPRINT1("Failed to find an available port resource (0x%x to 0x%x length: 0x%x)\n",
1625 ReqDesc
->u
.Port
.MinimumAddress
.QuadPart
, ReqDesc
->u
.Port
.MaximumAddress
.QuadPart
,
1626 ReqDesc
->u
.Port
.Length
);
1628 if (ReqDesc
->Option
== 0)
1630 ExFreePool(*ResourceList
);
1631 return STATUS_CONFLICTING_ADDRESSES
;
1636 case CmResourceTypeMemory
:
1637 if (!IopFindMemoryResource(ReqDesc
, ResDesc
))
1639 DPRINT1("Failed to find an available memory resource (0x%x to 0x%x length: 0x%x)\n",
1640 ReqDesc
->u
.Memory
.MinimumAddress
.QuadPart
, ReqDesc
->u
.Memory
.MaximumAddress
.QuadPart
,
1641 ReqDesc
->u
.Memory
.Length
);
1643 if (ReqDesc
->Option
== 0)
1645 ExFreePool(*ResourceList
);
1646 return STATUS_CONFLICTING_ADDRESSES
;
1651 case CmResourceTypeBusNumber
:
1652 if (!IopFindBusNumberResource(ReqDesc
, ResDesc
))
1654 DPRINT1("Failed to find an available bus number resource (0x%x to 0x%x length: 0x%x)\n",
1655 ReqDesc
->u
.BusNumber
.MinBusNumber
, ReqDesc
->u
.BusNumber
.MaxBusNumber
,
1656 ReqDesc
->u
.BusNumber
.Length
);
1658 if (ReqDesc
->Option
== 0)
1660 ExFreePool(*ResourceList
);
1661 return STATUS_CONFLICTING_ADDRESSES
;
1666 case CmResourceTypeDma
:
1667 if (!IopFindDmaResource(ReqDesc
, ResDesc
))
1669 DPRINT1("Failed to find an available dma resource (0x%x to 0x%x)\n",
1670 ReqDesc
->u
.Dma
.MinimumChannel
, ReqDesc
->u
.Dma
.MaximumChannel
);
1672 if (ReqDesc
->Option
== 0)
1674 ExFreePool(*ResourceList
);
1675 return STATUS_CONFLICTING_ADDRESSES
;
1681 DPRINT1("Unsupported resource type: %x\n", ReqDesc
->Type
);
1685 (*ResourceList
)->List
[0].PartialResourceList
.Count
++;
1690 return STATUS_SUCCESS
;
1694 IopAssignDeviceResources(
1695 IN PDEVICE_NODE DeviceNode
,
1696 OUT ULONG
*pRequiredSize
)
1698 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList
;
1704 if (!DeviceNode
->BootResources
&& !DeviceNode
->ResourceRequirements
)
1706 /* No resource needed for this device */
1707 DeviceNode
->ResourceList
= NULL
;
1709 return STATUS_SUCCESS
;
1712 /* Fill DeviceNode->ResourceList
1713 * FIXME: the PnP arbiter should go there!
1714 * Actually, use the BootResources if provided, else the resource requirements
1717 if (DeviceNode
->BootResources
)
1719 /* Browse the boot resources to know if we have some custom structures */
1720 Size
= FIELD_OFFSET(CM_RESOURCE_LIST
, List
);
1721 for (i
= 0; i
< DeviceNode
->BootResources
->Count
; i
++)
1723 pPartialResourceList
= &DeviceNode
->BootResources
->List
[i
].PartialResourceList
;
1724 Size
+= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
)
1725 + pPartialResourceList
->Count
* sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
1726 for (j
= 0; j
< pPartialResourceList
->Count
; j
++)
1728 if (pPartialResourceList
->PartialDescriptors
[j
].Type
== CmResourceTypeDeviceSpecific
)
1729 Size
+= pPartialResourceList
->PartialDescriptors
[j
].u
.DeviceSpecificData
.DataSize
;
1733 DeviceNode
->ResourceList
= ExAllocatePool(PagedPool
, Size
);
1734 if (!DeviceNode
->ResourceList
)
1736 Status
= STATUS_NO_MEMORY
;
1739 RtlCopyMemory(DeviceNode
->ResourceList
, DeviceNode
->BootResources
, Size
);
1741 Status
= IopDetectResourceConflict(DeviceNode
->ResourceList
, FALSE
, NULL
);
1742 if (NT_SUCCESS(Status
) || !DeviceNode
->ResourceRequirements
)
1744 if (!NT_SUCCESS(Status
) && !DeviceNode
->ResourceRequirements
)
1746 DPRINT1("Using conflicting boot resources because no requirements were supplied!\n");
1749 *pRequiredSize
= Size
;
1750 return STATUS_SUCCESS
;
1754 DPRINT1("Boot resources for %wZ cause a resource conflict!\n", &DeviceNode
->InstancePath
);
1755 ExFreePool(DeviceNode
->ResourceList
);
1759 Status
= IopCreateResourceListFromRequirements(DeviceNode
->ResourceRequirements
,
1760 &DeviceNode
->ResourceList
);
1761 if (!NT_SUCCESS(Status
))
1764 Size
= FIELD_OFFSET(CM_RESOURCE_LIST
, List
);
1765 for (i
= 0; i
< DeviceNode
->ResourceList
->Count
; i
++)
1767 pPartialResourceList
= &DeviceNode
->ResourceList
->List
[i
].PartialResourceList
;
1768 Size
+= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
)
1769 + pPartialResourceList
->Count
* sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
1772 Status
= IopDetectResourceConflict(DeviceNode
->ResourceList
, FALSE
, NULL
);
1773 if (!NT_SUCCESS(Status
))
1776 *pRequiredSize
= Size
;
1777 return STATUS_SUCCESS
;
1780 if (DeviceNode
->ResourceList
)
1782 ExFreePool(DeviceNode
->ResourceList
);
1783 DeviceNode
->ResourceList
= NULL
;
1791 IopTranslateDeviceResources(
1792 IN PDEVICE_NODE DeviceNode
,
1793 IN ULONG RequiredSize
)
1795 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList
;
1796 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw
, DescriptorTranslated
;
1800 if (!DeviceNode
->ResourceList
)
1802 DeviceNode
->ResourceListTranslated
= NULL
;
1803 return STATUS_SUCCESS
;
1806 /* That's easy to translate a resource list. Just copy the
1807 * untranslated one and change few fields in the copy
1809 DeviceNode
->ResourceListTranslated
= ExAllocatePool(PagedPool
, RequiredSize
);
1810 if (!DeviceNode
->ResourceListTranslated
)
1812 Status
=STATUS_NO_MEMORY
;
1815 RtlCopyMemory(DeviceNode
->ResourceListTranslated
, DeviceNode
->ResourceList
, RequiredSize
);
1817 for (i
= 0; i
< DeviceNode
->ResourceList
->Count
; i
++)
1819 pPartialResourceList
= &DeviceNode
->ResourceList
->List
[i
].PartialResourceList
;
1820 for (j
= 0; j
< pPartialResourceList
->Count
; j
++)
1822 DescriptorRaw
= &pPartialResourceList
->PartialDescriptors
[j
];
1823 DescriptorTranslated
= &DeviceNode
->ResourceListTranslated
->List
[i
].PartialResourceList
.PartialDescriptors
[j
];
1824 switch (DescriptorRaw
->Type
)
1826 case CmResourceTypePort
:
1828 ULONG AddressSpace
= 1; /* IO space */
1829 if (!HalTranslateBusAddress(
1830 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
1831 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
1832 DescriptorRaw
->u
.Port
.Start
,
1834 &DescriptorTranslated
->u
.Port
.Start
))
1836 Status
= STATUS_UNSUCCESSFUL
;
1841 case CmResourceTypeInterrupt
:
1843 DescriptorTranslated
->u
.Interrupt
.Vector
= HalGetInterruptVector(
1844 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
1845 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
1846 DescriptorRaw
->u
.Interrupt
.Level
,
1847 DescriptorRaw
->u
.Interrupt
.Vector
,
1848 (PKIRQL
)&DescriptorTranslated
->u
.Interrupt
.Level
,
1849 &DescriptorRaw
->u
.Interrupt
.Affinity
);
1852 case CmResourceTypeMemory
:
1854 ULONG AddressSpace
= 0; /* Memory space */
1855 if (!HalTranslateBusAddress(
1856 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
1857 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
1858 DescriptorRaw
->u
.Memory
.Start
,
1860 &DescriptorTranslated
->u
.Memory
.Start
))
1862 Status
= STATUS_UNSUCCESSFUL
;
1867 case CmResourceTypeDma
:
1868 case CmResourceTypeBusNumber
:
1869 case CmResourceTypeDeviceSpecific
:
1873 DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw
->Type
);
1874 Status
= STATUS_NOT_IMPLEMENTED
;
1879 return STATUS_SUCCESS
;
1882 /* Yes! Also delete ResourceList because ResourceList and
1883 * ResourceListTranslated should be a pair! */
1884 ExFreePool(DeviceNode
->ResourceList
);
1885 DeviceNode
->ResourceList
= NULL
;
1886 if (DeviceNode
->ResourceListTranslated
)
1888 ExFreePool(DeviceNode
->ResourceListTranslated
);
1889 DeviceNode
->ResourceList
= NULL
;
1896 * IopGetParentIdPrefix
1898 * Retrieve (or create) a string which identifies a device.
1902 * Pointer to device node.
1904 * Pointer to the string where is returned the parent node identifier
1907 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1908 * valid and its Buffer field is NULL-terminated. The caller needs to
1909 * to free the string with RtlFreeUnicodeString when it is no longer
1914 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode
,
1915 PUNICODE_STRING ParentIdPrefix
)
1917 ULONG KeyNameBufferLength
;
1918 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation
= NULL
;
1919 UNICODE_STRING KeyName
;
1920 UNICODE_STRING KeyValue
;
1921 UNICODE_STRING ValueName
;
1926 /* HACK: As long as some devices have a NULL device
1927 * instance path, the following test is required :(
1929 if (DeviceNode
->Parent
->InstancePath
.Length
== 0)
1931 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
1932 &DeviceNode
->InstancePath
);
1933 return STATUS_UNSUCCESSFUL
;
1936 /* 1. Try to retrieve ParentIdPrefix from registry */
1937 KeyNameBufferLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + MAX_PATH
* sizeof(WCHAR
);
1938 ParentIdPrefixInformation
= ExAllocatePool(PagedPool
, KeyNameBufferLength
+ sizeof(WCHAR
));
1939 if (!ParentIdPrefixInformation
)
1941 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1946 KeyName
.Buffer
= ExAllocatePool(PagedPool
, (49 * sizeof(WCHAR
)) + DeviceNode
->Parent
->InstancePath
.Length
);
1947 if (!KeyName
.Buffer
)
1949 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1953 KeyName
.MaximumLength
= (49 * sizeof(WCHAR
)) + DeviceNode
->Parent
->InstancePath
.Length
;
1955 RtlAppendUnicodeToString(&KeyName
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1956 RtlAppendUnicodeStringToString(&KeyName
, &DeviceNode
->Parent
->InstancePath
);
1958 Status
= IopOpenRegistryKeyEx(&hKey
, NULL
, &KeyName
, KEY_QUERY_VALUE
| KEY_SET_VALUE
);
1959 if (!NT_SUCCESS(Status
))
1961 RtlInitUnicodeString(&ValueName
, L
"ParentIdPrefix");
1962 Status
= ZwQueryValueKey(
1964 KeyValuePartialInformation
, ParentIdPrefixInformation
,
1965 KeyNameBufferLength
, &KeyNameBufferLength
);
1966 if (NT_SUCCESS(Status
))
1968 if (ParentIdPrefixInformation
->Type
!= REG_SZ
)
1969 Status
= STATUS_UNSUCCESSFUL
;
1972 KeyValue
.Length
= KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1973 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1977 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
1979 KeyValue
.Length
= KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1980 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1984 /* 2. Create the ParentIdPrefix value */
1985 crc32
= RtlComputeCrc32(0,
1986 (PUCHAR
)DeviceNode
->Parent
->InstancePath
.Buffer
,
1987 DeviceNode
->Parent
->InstancePath
.Length
);
1989 swprintf((PWSTR
)ParentIdPrefixInformation
->Data
, L
"%lx&%lx", DeviceNode
->Parent
->Level
, crc32
);
1990 RtlInitUnicodeString(&KeyValue
, (PWSTR
)ParentIdPrefixInformation
->Data
);
1992 /* 3. Try to write the ParentIdPrefix to registry */
1993 Status
= ZwSetValueKey(hKey
,
1997 (PVOID
)KeyValue
.Buffer
,
1998 (wcslen(KeyValue
.Buffer
) + 1) * sizeof(WCHAR
));
2001 if (NT_SUCCESS(Status
))
2003 /* Duplicate the string to return it */
2004 Status
= RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
, &KeyValue
, ParentIdPrefix
);
2006 ExFreePool(ParentIdPrefixInformation
);
2007 RtlFreeUnicodeString(&KeyName
);
2015 * IopActionInterrogateDeviceStack
2017 * Retrieve information for all (direct) child nodes of a parent node.
2021 * Pointer to device node.
2023 * Pointer to parent node to retrieve child node information for.
2026 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
2027 * when we reach a device node which is not a direct child of the device
2028 * node for which we retrieve information of child nodes for. Any errors
2029 * that occur is logged instead so that all child services have a chance
2030 * of being interrogated.
2034 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode
,
2037 IO_STATUS_BLOCK IoStatusBlock
;
2038 PDEVICE_NODE ParentDeviceNode
;
2039 WCHAR InstancePath
[MAX_PATH
];
2040 IO_STACK_LOCATION Stack
;
2045 ULONG RequiredLength
;
2047 HANDLE InstanceKey
= NULL
;
2048 UNICODE_STRING ValueName
;
2049 UNICODE_STRING ParentIdPrefix
= { 0, 0, NULL
};
2050 DEVICE_CAPABILITIES DeviceCapabilities
;
2052 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode
, Context
);
2053 DPRINT("PDO 0x%p\n", DeviceNode
->PhysicalDeviceObject
);
2055 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2058 * We are called for the parent too, but we don't need to do special
2059 * handling for this node
2062 if (DeviceNode
== ParentDeviceNode
)
2064 DPRINT("Success\n");
2065 return STATUS_SUCCESS
;
2069 * Make sure this device node is a direct child of the parent device node
2070 * that is given as an argument
2073 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2075 /* Stop the traversal immediately and indicate successful operation */
2077 return STATUS_UNSUCCESSFUL
;
2081 Status
= ZwQueryDefaultLocale(FALSE
, &LocaleId
);
2082 if (!NT_SUCCESS(Status
))
2084 DPRINT("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status
);
2089 * FIXME: For critical errors, cleanup and disable device, but always
2090 * return STATUS_SUCCESS.
2093 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
2095 Stack
.Parameters
.QueryId
.IdType
= BusQueryDeviceID
;
2096 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2100 if (NT_SUCCESS(Status
))
2102 /* Copy the device id string */
2103 wcscpy(InstancePath
, (PWSTR
)IoStatusBlock
.Information
);
2106 * FIXME: Check for valid characters, if there is invalid characters
2112 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
2115 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack\n");
2117 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
2118 if (!NT_SUCCESS(Status
))
2120 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
2123 DeviceNode
->CapabilityFlags
= *(PULONG
)((ULONG_PTR
)&DeviceCapabilities
+ 4);
2125 if (!DeviceCapabilities
.UniqueID
)
2127 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
2128 DPRINT("Instance ID is not unique\n");
2129 Status
= IopGetParentIdPrefix(DeviceNode
, &ParentIdPrefix
);
2130 if (!NT_SUCCESS(Status
))
2132 DPRINT("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status
);
2136 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
2138 Stack
.Parameters
.QueryId
.IdType
= BusQueryInstanceID
;
2139 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2143 if (NT_SUCCESS(Status
))
2145 /* Append the instance id string */
2146 wcscat(InstancePath
, L
"\\");
2147 if (ParentIdPrefix
.Length
> 0)
2149 /* Add information from parent bus device to InstancePath */
2150 wcscat(InstancePath
, ParentIdPrefix
.Buffer
);
2151 if (IoStatusBlock
.Information
&& *(PWSTR
)IoStatusBlock
.Information
)
2152 wcscat(InstancePath
, L
"&");
2154 if (IoStatusBlock
.Information
)
2155 wcscat(InstancePath
, (PWSTR
)IoStatusBlock
.Information
);
2158 * FIXME: Check for valid characters, if there is invalid characters
2164 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
2166 RtlFreeUnicodeString(&ParentIdPrefix
);
2168 if (!RtlCreateUnicodeString(&DeviceNode
->InstancePath
, InstancePath
))
2170 DPRINT("No resources\n");
2171 /* FIXME: Cleanup and disable device */
2174 DPRINT("InstancePath is %S\n", DeviceNode
->InstancePath
.Buffer
);
2177 * Create registry key for the instance id, if it doesn't exist yet
2179 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, &InstanceKey
);
2180 if (!NT_SUCCESS(Status
))
2182 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status
);
2186 /* Set 'Capabilities' value */
2187 RtlInitUnicodeString(&ValueName
, L
"Capabilities");
2188 Status
= ZwSetValueKey(InstanceKey
,
2192 (PVOID
)&DeviceNode
->CapabilityFlags
,
2195 /* Set 'UINumber' value */
2196 if (DeviceCapabilities
.UINumber
!= MAXULONG
)
2198 RtlInitUnicodeString(&ValueName
, L
"UINumber");
2199 Status
= ZwSetValueKey(InstanceKey
,
2203 &DeviceCapabilities
.UINumber
,
2208 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
2210 Stack
.Parameters
.QueryId
.IdType
= BusQueryHardwareIDs
;
2211 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2215 if (NT_SUCCESS(Status
))
2218 * FIXME: Check for valid characters, if there is invalid characters
2222 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
2223 DPRINT("Hardware IDs:\n");
2226 DPRINT(" %S\n", Ptr
);
2227 Length
= wcslen(Ptr
) + 1;
2230 TotalLength
+= Length
;
2232 DPRINT("TotalLength: %hu\n", TotalLength
);
2235 RtlInitUnicodeString(&ValueName
, L
"HardwareID");
2236 Status
= ZwSetValueKey(InstanceKey
,
2240 (PVOID
)IoStatusBlock
.Information
,
2241 (TotalLength
+ 1) * sizeof(WCHAR
));
2242 if (!NT_SUCCESS(Status
))
2244 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
2249 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
2252 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
2254 Stack
.Parameters
.QueryId
.IdType
= BusQueryCompatibleIDs
;
2255 Status
= IopInitiatePnpIrp(
2256 DeviceNode
->PhysicalDeviceObject
,
2260 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2263 * FIXME: Check for valid characters, if there is invalid characters
2267 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
2268 DPRINT("Compatible IDs:\n");
2271 DPRINT(" %S\n", Ptr
);
2272 Length
= wcslen(Ptr
) + 1;
2275 TotalLength
+= Length
;
2277 DPRINT("TotalLength: %hu\n", TotalLength
);
2280 RtlInitUnicodeString(&ValueName
, L
"CompatibleIDs");
2281 Status
= ZwSetValueKey(InstanceKey
,
2285 (PVOID
)IoStatusBlock
.Information
,
2286 (TotalLength
+ 1) * sizeof(WCHAR
));
2287 if (!NT_SUCCESS(Status
))
2289 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status
);
2294 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
2297 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2299 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextDescription
;
2300 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
2301 Status
= IopInitiatePnpIrp(
2302 DeviceNode
->PhysicalDeviceObject
,
2304 IRP_MN_QUERY_DEVICE_TEXT
,
2306 /* This key is mandatory, so even if the Irp fails, we still write it */
2307 RtlInitUnicodeString(&ValueName
, L
"DeviceDesc");
2308 if (ZwQueryValueKey(InstanceKey
, &ValueName
, KeyValueBasicInformation
, NULL
, 0, &RequiredLength
) == STATUS_OBJECT_NAME_NOT_FOUND
)
2310 if (NT_SUCCESS(Status
) &&
2311 IoStatusBlock
.Information
&&
2312 (*(PWSTR
)IoStatusBlock
.Information
!= 0))
2314 /* This key is overriden when a driver is installed. Don't write the
2315 * new description if another one already exists */
2316 Status
= ZwSetValueKey(InstanceKey
,
2320 (PVOID
)IoStatusBlock
.Information
,
2321 (wcslen((PWSTR
)IoStatusBlock
.Information
) + 1) * sizeof(WCHAR
));
2325 UNICODE_STRING DeviceDesc
= RTL_CONSTANT_STRING(L
"Unknown device");
2326 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status
);
2328 Status
= ZwSetValueKey(InstanceKey
,
2333 DeviceDesc
.MaximumLength
);
2335 if (!NT_SUCCESS(Status
))
2337 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status
);
2343 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2345 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextLocationInformation
;
2346 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
2347 Status
= IopInitiatePnpIrp(
2348 DeviceNode
->PhysicalDeviceObject
,
2350 IRP_MN_QUERY_DEVICE_TEXT
,
2352 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2354 DPRINT("LocationInformation: %S\n", (PWSTR
)IoStatusBlock
.Information
);
2355 RtlInitUnicodeString(&ValueName
, L
"LocationInformation");
2356 Status
= ZwSetValueKey(InstanceKey
,
2360 (PVOID
)IoStatusBlock
.Information
,
2361 (wcslen((PWSTR
)IoStatusBlock
.Information
) + 1) * sizeof(WCHAR
));
2362 if (!NT_SUCCESS(Status
))
2364 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
2369 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2372 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2374 Status
= IopInitiatePnpIrp(
2375 DeviceNode
->PhysicalDeviceObject
,
2377 IRP_MN_QUERY_BUS_INFORMATION
,
2379 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2381 PPNP_BUS_INFORMATION BusInformation
=
2382 (PPNP_BUS_INFORMATION
)IoStatusBlock
.Information
;
2384 DeviceNode
->ChildBusNumber
= BusInformation
->BusNumber
;
2385 DeviceNode
->ChildInterfaceType
= BusInformation
->LegacyBusType
;
2386 DeviceNode
->ChildBusTypeIndex
= IopGetBusTypeGuidIndex(&BusInformation
->BusTypeGuid
);
2387 ExFreePool(BusInformation
);
2391 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2393 DeviceNode
->ChildBusNumber
= 0xFFFFFFF0;
2394 DeviceNode
->ChildInterfaceType
= InterfaceTypeUndefined
;
2395 DeviceNode
->ChildBusTypeIndex
= -1;
2398 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2400 Status
= IopInitiatePnpIrp(
2401 DeviceNode
->PhysicalDeviceObject
,
2403 IRP_MN_QUERY_RESOURCES
,
2405 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2407 DeviceNode
->BootResources
=
2408 (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
2409 DeviceNode
->Flags
|= DNF_HAS_BOOT_CONFIG
;
2413 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2414 DeviceNode
->BootResources
= NULL
;
2417 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2419 Status
= IopInitiatePnpIrp(
2420 DeviceNode
->PhysicalDeviceObject
,
2422 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
2424 if (NT_SUCCESS(Status
))
2426 DeviceNode
->ResourceRequirements
=
2427 (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
2428 if (IoStatusBlock
.Information
)
2429 IopDeviceNodeSetFlag(DeviceNode
, DNF_RESOURCE_REPORTED
);
2431 IopDeviceNodeSetFlag(DeviceNode
, DNF_NO_RESOURCE_REQUIRED
);
2435 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status
);
2436 DeviceNode
->ResourceRequirements
= NULL
;
2440 if (InstanceKey
!= NULL
)
2442 IopSetDeviceInstanceData(InstanceKey
, DeviceNode
);
2445 ZwClose(InstanceKey
);
2447 IopDeviceNodeSetFlag(DeviceNode
, DNF_PROCESSED
);
2449 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_LEGACY_DRIVER
))
2451 /* Report the device to the user-mode pnp manager */
2452 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED
,
2453 &DeviceNode
->InstancePath
);
2456 return STATUS_SUCCESS
;
2462 IN PDEVICE_OBJECT DeviceObject
)
2464 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
2465 DEVICETREE_TRAVERSE_CONTEXT Context
;
2466 PDEVICE_RELATIONS DeviceRelations
;
2467 PDEVICE_OBJECT ChildDeviceObject
;
2468 IO_STATUS_BLOCK IoStatusBlock
;
2469 PDEVICE_NODE ChildDeviceNode
;
2470 IO_STACK_LOCATION Stack
;
2474 DPRINT("DeviceObject 0x%p\n", DeviceObject
);
2476 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2478 /* Report the device to the user-mode pnp manager */
2479 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL
,
2480 &DeviceNode
->InstancePath
);
2482 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2484 Stack
.Parameters
.QueryDeviceRelations
.Type
= BusRelations
;
2486 Status
= IopInitiatePnpIrp(
2489 IRP_MN_QUERY_DEVICE_RELATIONS
,
2491 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
2493 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
2497 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
2499 if (!DeviceRelations
)
2501 DPRINT("No PDOs\n");
2502 return STATUS_UNSUCCESSFUL
;
2505 DPRINT("Got %u PDOs\n", DeviceRelations
->Count
);
2508 * Create device nodes for all discovered devices
2510 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
2512 ChildDeviceObject
= DeviceRelations
->Objects
[i
];
2513 ASSERT((ChildDeviceObject
->Flags
& DO_DEVICE_INITIALIZING
) == 0);
2515 ChildDeviceNode
= IopGetDeviceNode(ChildDeviceObject
);
2516 if (!ChildDeviceNode
)
2518 /* One doesn't exist, create it */
2519 Status
= IopCreateDeviceNode(
2524 if (NT_SUCCESS(Status
))
2526 /* Mark the node as enumerated */
2527 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2529 /* Mark the DO as bus enumerated */
2530 ChildDeviceObject
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
2534 /* Ignore this DO */
2535 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status
, i
);
2536 ObDereferenceObject(ChildDeviceNode
);
2541 /* Mark it as enumerated */
2542 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2543 ObDereferenceObject(ChildDeviceObject
);
2546 ExFreePool(DeviceRelations
);
2549 * Retrieve information about all discovered children from the bus driver
2551 IopInitDeviceTreeTraverseContext(
2554 IopActionInterrogateDeviceStack
,
2557 Status
= IopTraverseDeviceTree(&Context
);
2558 if (!NT_SUCCESS(Status
))
2560 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
2565 * Retrieve configuration from the registry for discovered children
2567 IopInitDeviceTreeTraverseContext(
2570 IopActionConfigureChildServices
,
2573 Status
= IopTraverseDeviceTree(&Context
);
2574 if (!NT_SUCCESS(Status
))
2576 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
2581 * Initialize services for discovered children.
2583 Status
= IopInitializePnpServices(DeviceNode
);
2584 if (!NT_SUCCESS(Status
))
2586 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status
);
2590 DPRINT("IopEnumerateDevice() finished\n");
2591 return STATUS_SUCCESS
;
2596 * IopActionConfigureChildServices
2598 * Retrieve configuration for all (direct) child nodes of a parent node.
2602 * Pointer to device node.
2604 * Pointer to parent node to retrieve child node configuration for.
2607 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
2608 * when we reach a device node which is not a direct child of the device
2609 * node for which we configure child services for. Any errors that occur is
2610 * logged instead so that all child services have a chance of beeing
2615 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode
,
2618 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
2619 PDEVICE_NODE ParentDeviceNode
;
2620 PUNICODE_STRING Service
;
2621 UNICODE_STRING ClassGUID
;
2623 DEVICE_CAPABILITIES DeviceCaps
;
2625 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode
, Context
);
2627 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2630 * We are called for the parent too, but we don't need to do special
2631 * handling for this node
2633 if (DeviceNode
== ParentDeviceNode
)
2635 DPRINT("Success\n");
2636 return STATUS_SUCCESS
;
2640 * Make sure this device node is a direct child of the parent device node
2641 * that is given as an argument
2643 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2645 /* Stop the traversal immediately and indicate successful operation */
2647 return STATUS_UNSUCCESSFUL
;
2650 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
))
2652 WCHAR RegKeyBuffer
[MAX_PATH
];
2653 UNICODE_STRING RegKey
;
2656 RegKey
.MaximumLength
= sizeof(RegKeyBuffer
);
2657 RegKey
.Buffer
= RegKeyBuffer
;
2660 * Retrieve configuration from Enum key
2663 Service
= &DeviceNode
->ServiceName
;
2665 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
2666 RtlInitUnicodeString(Service
, NULL
);
2667 RtlInitUnicodeString(&ClassGUID
, NULL
);
2669 QueryTable
[0].Name
= L
"Service";
2670 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2671 QueryTable
[0].EntryContext
= Service
;
2673 QueryTable
[1].Name
= L
"ClassGUID";
2674 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2675 QueryTable
[1].EntryContext
= &ClassGUID
;
2676 QueryTable
[1].DefaultType
= REG_SZ
;
2677 QueryTable
[1].DefaultData
= L
"";
2678 QueryTable
[1].DefaultLength
= 0;
2680 RtlAppendUnicodeToString(&RegKey
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2681 RtlAppendUnicodeStringToString(&RegKey
, &DeviceNode
->InstancePath
);
2683 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
2684 RegKey
.Buffer
, QueryTable
, NULL
, NULL
);
2686 if (!NT_SUCCESS(Status
))
2688 /* FIXME: Log the error */
2689 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2690 &DeviceNode
->InstancePath
, Status
);
2691 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2692 return STATUS_SUCCESS
;
2695 if (Service
->Buffer
== NULL
)
2697 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode
, &DeviceCaps
)) &&
2698 DeviceCaps
.RawDeviceOK
)
2700 DPRINT1("%wZ is using parent bus driver (%wZ)\n", &DeviceNode
->InstancePath
, &ParentDeviceNode
->ServiceName
);
2702 DeviceNode
->ServiceName
.Length
= 0;
2703 DeviceNode
->ServiceName
.MaximumLength
= ParentDeviceNode
->ServiceName
.MaximumLength
;
2704 DeviceNode
->ServiceName
.Buffer
= ExAllocatePool(PagedPool
, DeviceNode
->ServiceName
.MaximumLength
);
2705 if (!DeviceNode
->ServiceName
.Buffer
)
2706 return STATUS_SUCCESS
;
2708 RtlCopyUnicodeString(&DeviceNode
->ServiceName
, &ParentDeviceNode
->ServiceName
);
2710 IopDeviceNodeSetFlag(DeviceNode
, DNF_LEGACY_DRIVER
);
2712 else if (ClassGUID
.Length
!= 0)
2714 /* Device has a ClassGUID value, but no Service value.
2715 * Suppose it is using the NULL driver, so state the
2716 * device is started */
2717 DPRINT1("%wZ is using NULL driver\n", &DeviceNode
->InstancePath
);
2718 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
2722 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2724 return STATUS_SUCCESS
;
2727 DPRINT("Got Service %S\n", Service
->Buffer
);
2730 return STATUS_SUCCESS
;
2734 * IopActionInitChildServices
2736 * Initialize the service for all (direct) child nodes of a parent node
2740 * Pointer to device node.
2742 * Pointer to parent node to initialize child node services for.
2745 * If the driver image for a service is not loaded and initialized
2746 * it is done here too. We only return a status code indicating an
2747 * error (STATUS_UNSUCCESSFUL) when we reach a device node which is
2748 * not a direct child of the device node for which we initialize
2749 * child services for. Any errors that occur is logged instead so
2750 * that all child services have a chance of being initialized.
2754 IopActionInitChildServices(PDEVICE_NODE DeviceNode
,
2757 PDEVICE_NODE ParentDeviceNode
;
2759 BOOLEAN BootDrivers
= !PnpSystemInit
;
2761 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode
, Context
);
2763 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2766 * We are called for the parent too, but we don't need to do special
2767 * handling for this node
2769 if (DeviceNode
== ParentDeviceNode
)
2771 DPRINT("Success\n");
2772 return STATUS_SUCCESS
;
2776 * Make sure this device node is a direct child of the parent device node
2777 * that is given as an argument
2780 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2783 * Stop the traversal immediately and indicate unsuccessful operation
2786 return STATUS_UNSUCCESSFUL
;
2790 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
) &&
2791 !IopDeviceNodeHasFlag(DeviceNode
, DNF_ADDED
) &&
2792 !IopDeviceNodeHasFlag(DeviceNode
, DNF_STARTED
))
2794 PLDR_DATA_TABLE_ENTRY ModuleObject
;
2795 PDRIVER_OBJECT DriverObject
;
2797 /* Get existing DriverObject pointer (in case the driver has
2798 already been loaded and initialized) */
2799 Status
= IopGetDriverObject(
2801 &DeviceNode
->ServiceName
,
2804 if (!NT_SUCCESS(Status
))
2806 /* Driver is not initialized, try to load it */
2807 Status
= IopLoadServiceModule(&DeviceNode
->ServiceName
, &ModuleObject
);
2809 if (NT_SUCCESS(Status
) || Status
== STATUS_IMAGE_ALREADY_LOADED
)
2811 /* STATUS_IMAGE_ALREADY_LOADED means this driver
2812 was loaded by the bootloader */
2813 if ((Status
!= STATUS_IMAGE_ALREADY_LOADED
) ||
2814 (Status
== STATUS_IMAGE_ALREADY_LOADED
&& !DriverObject
))
2816 /* Initialize the driver */
2817 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
2818 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
2822 Status
= STATUS_SUCCESS
;
2827 DPRINT1("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2828 &DeviceNode
->ServiceName
, Status
);
2832 /* Driver is loaded and initialized at this point */
2833 if (NT_SUCCESS(Status
))
2835 /* Attach lower level filter drivers. */
2836 IopAttachFilterDrivers(DeviceNode
, TRUE
);
2837 /* Initialize the function driver for the device node */
2838 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
2840 if (NT_SUCCESS(Status
))
2842 /* Attach upper level filter drivers. */
2843 IopAttachFilterDrivers(DeviceNode
, FALSE
);
2844 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
2846 Status
= IopStartDevice(DeviceNode
);
2850 DPRINT1("IopInitializeDevice(%wZ) failed with status 0x%08x\n",
2851 &DeviceNode
->InstancePath
, Status
);
2857 * Don't disable when trying to load only boot drivers
2861 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2862 IopDeviceNodeSetFlag(DeviceNode
, DNF_START_FAILED
);
2863 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
2864 DPRINT1("Initialization of service %S failed (Status %x)\n",
2865 DeviceNode
->ServiceName
.Buffer
, Status
);
2871 DPRINT("Device %wZ is disabled or already initialized\n",
2872 &DeviceNode
->InstancePath
);
2875 return STATUS_SUCCESS
;
2879 * IopInitializePnpServices
2881 * Initialize services for discovered children
2885 * Top device node to start initializing services.
2891 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode
)
2893 DEVICETREE_TRAVERSE_CONTEXT Context
;
2895 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode
);
2897 IopInitDeviceTreeTraverseContext(
2900 IopActionInitChildServices
,
2903 return IopTraverseDeviceTree(&Context
);
2906 static NTSTATUS INIT_FUNCTION
2907 IopEnumerateDetectedDevices(
2909 IN PUNICODE_STRING RelativePath OPTIONAL
,
2911 IN BOOLEAN EnumerateSubKeys
,
2912 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources
,
2913 IN ULONG ParentBootResourcesLength
)
2915 UNICODE_STRING IdentifierU
= RTL_CONSTANT_STRING(L
"Identifier");
2916 UNICODE_STRING HardwareIDU
= RTL_CONSTANT_STRING(L
"HardwareID");
2917 UNICODE_STRING ConfigurationDataU
= RTL_CONSTANT_STRING(L
"Configuration Data");
2918 UNICODE_STRING BootConfigU
= RTL_CONSTANT_STRING(L
"BootConfig");
2919 UNICODE_STRING LogConfU
= RTL_CONSTANT_STRING(L
"LogConf");
2920 OBJECT_ATTRIBUTES ObjectAttributes
;
2921 HANDLE hDevicesKey
= NULL
;
2922 HANDLE hDeviceKey
= NULL
;
2923 HANDLE hLevel1Key
, hLevel2Key
= NULL
, hLogConf
;
2924 UNICODE_STRING Level2NameU
;
2925 WCHAR Level2Name
[5];
2926 ULONG IndexDevice
= 0;
2928 PKEY_BASIC_INFORMATION pDeviceInformation
= NULL
;
2929 ULONG DeviceInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + 50 * sizeof(WCHAR
);
2930 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation
= NULL
;
2931 ULONG ValueInfoLength
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 50 * sizeof(WCHAR
);
2932 UNICODE_STRING DeviceName
, ValueName
;
2934 PCM_FULL_RESOURCE_DESCRIPTOR BootResources
= NULL
;
2935 ULONG BootResourcesLength
;
2938 const UNICODE_STRING IdentifierPci
= RTL_CONSTANT_STRING(L
"PCI");
2939 UNICODE_STRING HardwareIdPci
= RTL_CONSTANT_STRING(L
"*PNP0A03\0");
2940 static ULONG DeviceIndexPci
= 0;
2941 const UNICODE_STRING IdentifierSerial
= RTL_CONSTANT_STRING(L
"SerialController");
2942 UNICODE_STRING HardwareIdSerial
= RTL_CONSTANT_STRING(L
"*PNP0501\0");
2943 static ULONG DeviceIndexSerial
= 0;
2944 const UNICODE_STRING IdentifierKeyboard
= RTL_CONSTANT_STRING(L
"KeyboardController");
2945 UNICODE_STRING HardwareIdKeyboard
= RTL_CONSTANT_STRING(L
"*PNP0303\0");
2946 static ULONG DeviceIndexKeyboard
= 0;
2947 const UNICODE_STRING IdentifierMouse
= RTL_CONSTANT_STRING(L
"PointerController");
2948 UNICODE_STRING HardwareIdMouse
= RTL_CONSTANT_STRING(L
"*PNP0F13\0");
2949 static ULONG DeviceIndexMouse
= 0;
2950 const UNICODE_STRING IdentifierParallel
= RTL_CONSTANT_STRING(L
"ParallelController");
2951 UNICODE_STRING HardwareIdParallel
= RTL_CONSTANT_STRING(L
"*PNP0400\0");
2952 static ULONG DeviceIndexParallel
= 0;
2953 const UNICODE_STRING IdentifierFloppy
= RTL_CONSTANT_STRING(L
"FloppyDiskPeripheral");
2954 UNICODE_STRING HardwareIdFloppy
= RTL_CONSTANT_STRING(L
"*PNP0700\0");
2955 static ULONG DeviceIndexFloppy
= 0;
2956 const UNICODE_STRING IdentifierIsa
= RTL_CONSTANT_STRING(L
"ISA");
2957 UNICODE_STRING HardwareIdIsa
= RTL_CONSTANT_STRING(L
"*PNP0A00\0");
2958 static ULONG DeviceIndexIsa
= 0;
2959 UNICODE_STRING HardwareIdKey
;
2960 PUNICODE_STRING pHardwareId
;
2961 ULONG DeviceIndex
= 0;
2962 PUCHAR CmResourceList
;
2967 Status
= IopOpenRegistryKeyEx(&hDevicesKey
, hBaseKey
, RelativePath
, KEY_ENUMERATE_SUB_KEYS
);
2968 if (!NT_SUCCESS(Status
))
2970 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2975 hDevicesKey
= hBaseKey
;
2977 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2978 if (!pDeviceInformation
)
2980 DPRINT("ExAllocatePool() failed\n");
2981 Status
= STATUS_NO_MEMORY
;
2985 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2986 if (!pValueInformation
)
2988 DPRINT("ExAllocatePool() failed\n");
2989 Status
= STATUS_NO_MEMORY
;
2995 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2996 if (Status
== STATUS_NO_MORE_ENTRIES
)
2998 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
3000 ExFreePool(pDeviceInformation
);
3001 DeviceInfoLength
= RequiredSize
;
3002 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
3003 if (!pDeviceInformation
)
3005 DPRINT("ExAllocatePool() failed\n");
3006 Status
= STATUS_NO_MEMORY
;
3009 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
3011 if (!NT_SUCCESS(Status
))
3013 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
3018 /* Open device key */
3019 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
3020 DeviceName
.Buffer
= pDeviceInformation
->Name
;
3022 Status
= IopOpenRegistryKeyEx(&hDeviceKey
, hDevicesKey
, &DeviceName
,
3023 KEY_QUERY_VALUE
+ (EnumerateSubKeys
? KEY_ENUMERATE_SUB_KEYS
: 0));
3024 if (!NT_SUCCESS(Status
))
3026 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3030 /* Read boot resources, and add then to parent ones */
3031 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3032 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
3034 ExFreePool(pValueInformation
);
3035 ValueInfoLength
= RequiredSize
;
3036 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
3037 if (!pValueInformation
)
3039 DPRINT("ExAllocatePool() failed\n");
3040 ZwDeleteKey(hLevel2Key
);
3041 Status
= STATUS_NO_MEMORY
;
3044 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3046 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
3048 BootResources
= ParentBootResources
;
3049 BootResourcesLength
= ParentBootResourcesLength
;
3051 else if (!NT_SUCCESS(Status
))
3053 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
3056 else if (pValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
)
3058 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_FULL_RESOURCE_DESCRIPTOR
);
3063 static const ULONG Header
= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
);
3065 /* Concatenate current resources and parent ones */
3066 if (ParentBootResourcesLength
== 0)
3067 BootResourcesLength
= pValueInformation
->DataLength
;
3069 BootResourcesLength
= ParentBootResourcesLength
3070 + pValueInformation
->DataLength
3072 BootResources
= ExAllocatePool(PagedPool
, BootResourcesLength
);
3075 DPRINT("ExAllocatePool() failed\n");
3078 if (ParentBootResourcesLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
3080 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
3082 else if (ParentBootResources
->PartialResourceList
.PartialDescriptors
[ParentBootResources
->PartialResourceList
.Count
- 1].Type
== CmResourceTypeDeviceSpecific
)
3084 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
3086 (PVOID
)((ULONG_PTR
)BootResources
+ pValueInformation
->DataLength
),
3087 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
3088 ParentBootResourcesLength
- Header
);
3089 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
3093 RtlCopyMemory(BootResources
, pValueInformation
->Data
, Header
);
3095 (PVOID
)((ULONG_PTR
)BootResources
+ Header
),
3096 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
3097 ParentBootResourcesLength
- Header
);
3099 (PVOID
)((ULONG_PTR
)BootResources
+ ParentBootResourcesLength
),
3100 pValueInformation
->Data
+ Header
,
3101 pValueInformation
->DataLength
- Header
);
3102 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
3106 if (EnumerateSubKeys
)
3111 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
3112 if (Status
== STATUS_NO_MORE_ENTRIES
)
3114 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
3116 ExFreePool(pDeviceInformation
);
3117 DeviceInfoLength
= RequiredSize
;
3118 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
3119 if (!pDeviceInformation
)
3121 DPRINT("ExAllocatePool() failed\n");
3122 Status
= STATUS_NO_MEMORY
;
3125 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
3127 if (!NT_SUCCESS(Status
))
3129 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
3133 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
3134 DeviceName
.Buffer
= pDeviceInformation
->Name
;
3136 Status
= IopEnumerateDetectedDevices(
3142 BootResourcesLength
);
3143 if (!NT_SUCCESS(Status
))
3148 /* Read identifier */
3149 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3150 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
3152 ExFreePool(pValueInformation
);
3153 ValueInfoLength
= RequiredSize
;
3154 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
3155 if (!pValueInformation
)
3157 DPRINT("ExAllocatePool() failed\n");
3158 Status
= STATUS_NO_MEMORY
;
3161 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3163 if (!NT_SUCCESS(Status
))
3165 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
3167 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
3170 ValueName
.Length
= ValueName
.MaximumLength
= 0;
3172 else if (pValueInformation
->Type
!= REG_SZ
)
3174 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_SZ
);
3179 /* Assign hardware id to this device */
3180 ValueName
.Length
= ValueName
.MaximumLength
= (USHORT
)pValueInformation
->DataLength
;
3181 ValueName
.Buffer
= (PWCHAR
)pValueInformation
->Data
;
3182 if (ValueName
.Length
>= sizeof(WCHAR
) && ValueName
.Buffer
[ValueName
.Length
/ sizeof(WCHAR
) - 1] == UNICODE_NULL
)
3183 ValueName
.Length
-= sizeof(WCHAR
);
3186 if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierSerial
, FALSE
) == 0)
3188 pHardwareId
= &HardwareIdSerial
;
3189 DeviceIndex
= DeviceIndexSerial
++;
3191 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierKeyboard
, FALSE
) == 0)
3193 pHardwareId
= &HardwareIdKeyboard
;
3194 DeviceIndex
= DeviceIndexKeyboard
++;
3196 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierMouse
, FALSE
) == 0)
3198 pHardwareId
= &HardwareIdMouse
;
3199 DeviceIndex
= DeviceIndexMouse
++;
3201 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierParallel
, FALSE
) == 0)
3203 pHardwareId
= &HardwareIdParallel
;
3204 DeviceIndex
= DeviceIndexParallel
++;
3206 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierFloppy
, FALSE
) == 0)
3208 pHardwareId
= &HardwareIdFloppy
;
3209 DeviceIndex
= DeviceIndexFloppy
++;
3211 else if (NT_SUCCESS(Status
))
3213 /* Try to also match the device identifier */
3214 if (RtlCompareUnicodeString(&ValueName
, &IdentifierPci
, FALSE
) == 0)
3216 pHardwareId
= &HardwareIdPci
;
3217 DeviceIndex
= DeviceIndexPci
++;
3219 else if (RtlCompareUnicodeString(&ValueName
, &IdentifierIsa
, FALSE
) == 0)
3221 pHardwareId
= &HardwareIdIsa
;
3222 DeviceIndex
= DeviceIndexIsa
++;
3226 DPRINT("Unknown device '%wZ'\n", &ValueName
);
3232 /* Unknown key path */
3233 DPRINT("Unknown key path '%wZ'\n", RelativePath
);
3237 /* Prepare hardware id key (hardware id value without final \0) */
3238 HardwareIdKey
= *pHardwareId
;
3239 HardwareIdKey
.Length
-= sizeof(UNICODE_NULL
);
3241 /* Add the detected device to Root key */