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 PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList
= NULL
;
34 #if defined (ALLOC_PRAGMA)
35 #pragma alloc_text(INIT, PnpInit)
36 #pragma alloc_text(INIT, PnpInit2)
39 typedef struct _INVALIDATE_DEVICE_RELATION_DATA
41 PDEVICE_OBJECT DeviceObject
;
42 DEVICE_RELATION_TYPE Type
;
43 PIO_WORKITEM WorkItem
;
44 } INVALIDATE_DEVICE_RELATION_DATA
, *PINVALIDATE_DEVICE_RELATION_DATA
;
46 /* FUNCTIONS *****************************************************************/
49 IopAssignDeviceResources(
50 IN PDEVICE_NODE DeviceNode
,
51 OUT ULONG
*pRequiredSize
);
54 IopTranslateDeviceResources(
55 IN PDEVICE_NODE DeviceNode
,
56 IN ULONG RequiredSize
);
59 IopUpdateResourceMapForPnPDevice(
60 IN PDEVICE_NODE DeviceNode
);
64 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath
,
65 IN ULONG CreateOptions
,
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 IopStartDevice2(IN PDEVICE_OBJECT DeviceObject
)
145 IO_STACK_LOCATION Stack
;
146 PDEVICE_NODE DeviceNode
;
150 /* Get the device node */
151 DeviceNode
= IopGetDeviceNode(DeviceObject
);
153 /* Build the I/O stack locaiton */
154 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
155 Stack
.MajorFunction
= IRP_MJ_PNP
;
156 Stack
.MinorFunction
= IRP_MN_START_DEVICE
;
158 /* Check if we didn't already report the resources */
159 // if (!DeviceNode->Flags & DNF_RESOURCE_REPORTED)
162 if (DeviceNode
->Flags
& DNF_RESOURCE_REPORTED
)
164 DPRINT1("Warning: Setting resource pointers even though DNF_RESOURCE_REPORTED is set\n");
166 Stack
.Parameters
.StartDevice
.AllocatedResources
=
167 DeviceNode
->ResourceList
;
168 Stack
.Parameters
.StartDevice
.AllocatedResourcesTranslated
=
169 DeviceNode
->ResourceListTranslated
;
172 /* I don't think we set this flag yet */
173 ASSERT(!(DeviceNode
->Flags
& DNF_STOPPED
));
176 Status
= IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
177 if (!NT_SUCCESS(Status
))
180 DPRINT1("Warning: PnP Start failed\n");
185 /* Otherwise, mark us as started */
186 DeviceNode
->Flags
|= DNF_STARTED
;
188 /* We now need enumeration */
189 DeviceNode
->Flags
|= DNF_NEED_ENUMERATION_ONLY
;
194 IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode
)
196 PDEVICE_OBJECT DeviceObject
;
201 // ASSERT((DeviceNode->Flags & DNF_ADDED));
202 if (!(DeviceNode
->Flags
& DNF_ADDED
)) DPRINT1("Warning: Starting a device node without DNF_ADDED\n");
203 ASSERT((DeviceNode
->Flags
& (DNF_RESOURCE_ASSIGNED
|
204 DNF_RESOURCE_REPORTED
|
205 DNF_NO_RESOURCE_REQUIRED
|
206 DNF_NO_RESOURCE_REQUIRED
)));
207 ASSERT((!(DeviceNode
->Flags
& (DNF_HAS_PROBLEM
|
209 DNF_START_REQUEST_PENDING
))));
211 /* Get the device object */
212 DeviceObject
= DeviceNode
->PhysicalDeviceObject
;
214 /* Check if we're not started yet */
215 //if (!DeviceNode->Flags & DNF_STARTED)
218 IopStartDevice2(DeviceObject
);
221 /* Do we need to query IDs? This happens in the case of manual reporting */
222 //if (DeviceNode->Flags & DNF_NEED_QUERY_IDS)
224 // DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n");
225 /* And that case shouldn't happen yet */
229 /* Make sure we're started, and check if we need enumeration */
230 if ((DeviceNode
->Flags
& DNF_STARTED
) &&
231 (DeviceNode
->Flags
& DNF_NEED_ENUMERATION_ONLY
))
234 //Status = IopEnumerateDevice(DeviceObject);
235 IoSynchronousInvalidateDeviceRelations(DeviceObject
, BusRelations
);
236 IopDeviceNodeClearFlag(DeviceNode
, DNF_NEED_ENUMERATION_ONLY
);
237 Status
= STATUS_SUCCESS
;
242 Status
= STATUS_SUCCESS
;
251 PDEVICE_NODE DeviceNode
)
253 IO_STATUS_BLOCK IoStatusBlock
;
254 IO_STACK_LOCATION Stack
;
255 ULONG RequiredLength
;
257 HANDLE InstanceHandle
= INVALID_HANDLE_VALUE
, ControlHandle
= INVALID_HANDLE_VALUE
;
258 UNICODE_STRING KeyName
;
259 OBJECT_ATTRIBUTES ObjectAttributes
;
261 IopDeviceNodeSetFlag(DeviceNode
, DNF_ASSIGNING_RESOURCES
);
262 DPRINT("Sending IRP_MN_FILTER_RESOURCE_REQUIREMENTS to device stack\n");
263 Stack
.Parameters
.FilterResourceRequirements
.IoResourceRequirementList
= DeviceNode
->ResourceRequirements
;
264 Status
= IopInitiatePnpIrp(
265 DeviceNode
->PhysicalDeviceObject
,
267 IRP_MN_FILTER_RESOURCE_REQUIREMENTS
,
269 if (!NT_SUCCESS(Status
) && Status
!= STATUS_NOT_SUPPORTED
)
271 DPRINT("IopInitiatePnpIrp(IRP_MN_FILTER_RESOURCE_REQUIREMENTS) failed\n");
272 IopDeviceNodeClearFlag(DeviceNode
, DNF_ASSIGNING_RESOURCES
);
275 else if (NT_SUCCESS(Status
))
277 DeviceNode
->ResourceRequirements
= (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
280 Status
= IopAssignDeviceResources(DeviceNode
, &RequiredLength
);
281 if (NT_SUCCESS(Status
))
283 Status
= IopTranslateDeviceResources(DeviceNode
, RequiredLength
);
284 if (NT_SUCCESS(Status
))
286 Status
= IopUpdateResourceMapForPnPDevice(DeviceNode
);
287 if (!NT_SUCCESS(Status
))
289 DPRINT("IopUpdateResourceMap() failed (Status 0x%08lx)\n", Status
);
294 DPRINT("IopTranslateDeviceResources() failed (Status 0x%08lx)\n", Status
);
299 DPRINT("IopAssignDeviceResources() failed (Status 0x%08lx)\n", Status
);
301 IopDeviceNodeClearFlag(DeviceNode
, DNF_ASSIGNING_RESOURCES
);
303 if (!NT_SUCCESS(Status
))
307 IopStartAndEnumerateDevice(DeviceNode
);
309 /* FIX: Should be done in new device instance code */
310 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceHandle
);
311 if (!NT_SUCCESS(Status
))
314 /* FIX: Should be done in IoXxxPrepareDriverLoading */
316 RtlInitUnicodeString(&KeyName
, L
"Control");
317 InitializeObjectAttributes(&ObjectAttributes
,
319 OBJ_CASE_INSENSITIVE
,
322 Status
= ZwCreateKey(&ControlHandle
, KEY_SET_VALUE
, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
323 if (!NT_SUCCESS(Status
))
326 RtlInitUnicodeString(&KeyName
, L
"ActiveService");
327 Status
= ZwSetValueKey(ControlHandle
, &KeyName
, 0, REG_SZ
, DeviceNode
->ServiceName
.Buffer
, DeviceNode
->ServiceName
.Length
);
330 /* FIX: Should be done somewhere in resoure code? */
331 if (NT_SUCCESS(Status
) && DeviceNode
->ResourceList
)
333 RtlInitUnicodeString(&KeyName
, L
"AllocConfig");
334 Status
= ZwSetValueKey(ControlHandle
, &KeyName
, 0, REG_RESOURCE_LIST
,
335 DeviceNode
->ResourceList
, CM_RESOURCE_LIST_SIZE(DeviceNode
->ResourceList
));
339 if (NT_SUCCESS(Status
))
340 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
342 IopDeviceNodeSetFlag(DeviceNode
, DNF_START_FAILED
);
344 if (ControlHandle
!= INVALID_HANDLE_VALUE
)
345 ZwClose(ControlHandle
);
347 if (InstanceHandle
!= INVALID_HANDLE_VALUE
)
348 ZwClose(InstanceHandle
);
355 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode
,
356 PDEVICE_CAPABILITIES DeviceCaps
)
358 IO_STATUS_BLOCK StatusBlock
;
359 IO_STACK_LOCATION Stack
;
361 /* Set up the Header */
362 RtlZeroMemory(DeviceCaps
, sizeof(DEVICE_CAPABILITIES
));
363 DeviceCaps
->Size
= sizeof(DEVICE_CAPABILITIES
);
364 DeviceCaps
->Version
= 1;
365 DeviceCaps
->Address
= -1;
366 DeviceCaps
->UINumber
= -1;
368 /* Set up the Stack */
369 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
370 Stack
.Parameters
.DeviceCapabilities
.Capabilities
= DeviceCaps
;
373 return IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
375 IRP_MN_QUERY_CAPABILITIES
,
380 IopAsynchronousInvalidateDeviceRelations(
381 IN PDEVICE_OBJECT DeviceObject
,
382 IN PVOID InvalidateContext
)
384 PINVALIDATE_DEVICE_RELATION_DATA Data
= InvalidateContext
;
386 IoSynchronousInvalidateDeviceRelations(
390 ObDereferenceObject(Data
->DeviceObject
);
391 IoFreeWorkItem(Data
->WorkItem
);
396 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT
*DeviceObject
)
400 if (PopSystemPowerDeviceNode
)
402 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
403 *DeviceObject
= PopSystemPowerDeviceNode
->PhysicalDeviceObject
;
404 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
406 return STATUS_SUCCESS
;
409 return STATUS_UNSUCCESSFUL
;
414 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid
)
416 USHORT i
= 0, FoundIndex
= 0xFFFF;
420 /* Acquire the lock */
421 ExAcquireFastMutex(&PnpBusTypeGuidList
->Lock
);
423 /* Loop all entries */
424 while (i
< PnpBusTypeGuidList
->GuidCount
)
426 /* Try to find a match */
427 if (RtlCompareMemory(BusTypeGuid
,
428 &PnpBusTypeGuidList
->Guids
[i
],
429 sizeof(GUID
)) == sizeof(GUID
))
438 /* Check if we have to grow the list */
439 if (PnpBusTypeGuidList
->GuidCount
)
441 /* Calculate the new size */
442 NewSize
= sizeof(IO_BUS_TYPE_GUID_LIST
) +
443 (sizeof(GUID
) * PnpBusTypeGuidList
->GuidCount
);
445 /* Allocate the new copy */
446 NewList
= ExAllocatePool(PagedPool
, NewSize
);
450 ExFreePool(PnpBusTypeGuidList
);
454 /* Now copy them, decrease the size too */
455 NewSize
-= sizeof(GUID
);
456 RtlCopyMemory(NewList
, PnpBusTypeGuidList
, NewSize
);
458 /* Free the old list */
459 ExFreePool(PnpBusTypeGuidList
);
461 /* Use the new buffer */
462 PnpBusTypeGuidList
= NewList
;
465 /* Copy the new GUID */
466 RtlCopyMemory(&PnpBusTypeGuidList
->Guids
[PnpBusTypeGuidList
->GuidCount
],
470 /* The new entry is the index */
471 FoundIndex
= (USHORT
)PnpBusTypeGuidList
->GuidCount
;
472 PnpBusTypeGuidList
->GuidCount
++;
475 ExReleaseFastMutex(&PnpBusTypeGuidList
->Lock
);
481 * Creates a device node
484 * ParentNode = Pointer to parent device node
485 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
486 * to have the root device node create one
487 * (eg. for legacy drivers)
488 * DeviceNode = Pointer to storage for created device node
494 IopCreateDeviceNode(PDEVICE_NODE ParentNode
,
495 PDEVICE_OBJECT PhysicalDeviceObject
,
496 PUNICODE_STRING ServiceName
,
497 PDEVICE_NODE
*DeviceNode
)
502 UNICODE_STRING FullServiceName
;
503 UNICODE_STRING LegacyPrefix
= RTL_CONSTANT_STRING(L
"LEGACY_");
504 UNICODE_STRING UnknownDeviceName
= RTL_CONSTANT_STRING(L
"UNKNOWN");
505 UNICODE_STRING KeyName
, ClassName
, ClassGUID
;
506 PUNICODE_STRING ServiceName1
;
508 HANDLE InstanceHandle
;
510 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
511 ParentNode
, PhysicalDeviceObject
, ServiceName
);
513 Node
= (PDEVICE_NODE
)ExAllocatePool(NonPagedPool
, sizeof(DEVICE_NODE
));
516 return STATUS_INSUFFICIENT_RESOURCES
;
519 RtlZeroMemory(Node
, sizeof(DEVICE_NODE
));
522 ServiceName1
= &UnknownDeviceName
;
524 ServiceName1
= ServiceName
;
526 if (!PhysicalDeviceObject
)
528 FullServiceName
.MaximumLength
= LegacyPrefix
.Length
+ ServiceName1
->Length
;
529 FullServiceName
.Length
= 0;
530 FullServiceName
.Buffer
= ExAllocatePool(PagedPool
, FullServiceName
.MaximumLength
);
531 if (!FullServiceName
.Buffer
)
534 return STATUS_INSUFFICIENT_RESOURCES
;
537 RtlAppendUnicodeStringToString(&FullServiceName
, &LegacyPrefix
);
538 RtlAppendUnicodeStringToString(&FullServiceName
, ServiceName1
);
540 Status
= PnpRootCreateDevice(&FullServiceName
, &PhysicalDeviceObject
, &Node
->InstancePath
);
541 if (!NT_SUCCESS(Status
))
543 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status
);
548 /* Create the device key for legacy drivers */
549 Status
= IopCreateDeviceKeyPath(&Node
->InstancePath
, REG_OPTION_VOLATILE
, &InstanceHandle
);
550 if (!NT_SUCCESS(Status
))
552 ZwClose(InstanceHandle
);
554 ExFreePool(FullServiceName
.Buffer
);
558 Node
->ServiceName
.Buffer
= ExAllocatePool(PagedPool
, ServiceName1
->Length
);
559 if (!Node
->ServiceName
.Buffer
)
561 ZwClose(InstanceHandle
);
563 ExFreePool(FullServiceName
.Buffer
);
567 Node
->ServiceName
.MaximumLength
= ServiceName1
->Length
;
568 Node
->ServiceName
.Length
= 0;
570 RtlAppendUnicodeStringToString(&Node
->ServiceName
, ServiceName1
);
574 RtlInitUnicodeString(&KeyName
, L
"Service");
575 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ServiceName
->Buffer
, ServiceName
->Length
);
578 if (NT_SUCCESS(Status
))
580 RtlInitUnicodeString(&KeyName
, L
"Legacy");
583 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_DWORD
, &LegacyValue
, sizeof(LegacyValue
));
584 if (NT_SUCCESS(Status
))
586 RtlInitUnicodeString(&KeyName
, L
"Class");
588 RtlInitUnicodeString(&ClassName
, L
"LegacyDriver");
589 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ClassName
.Buffer
, ClassName
.Length
);
590 if (NT_SUCCESS(Status
))
592 RtlInitUnicodeString(&KeyName
, L
"ClassGUID");
594 RtlInitUnicodeString(&ClassGUID
, L
"{8ECC055D-047F-11D1-A537-0000F8753ED1}");
595 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ClassGUID
.Buffer
, ClassGUID
.Length
);
600 ZwClose(InstanceHandle
);
601 ExFreePool(FullServiceName
.Buffer
);
603 if (!NT_SUCCESS(Status
))
609 /* This is for drivers passed on the command line to ntoskrnl.exe */
610 IopDeviceNodeSetFlag(Node
, DNF_LEGACY_DRIVER
);
613 Node
->PhysicalDeviceObject
= PhysicalDeviceObject
;
615 ((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= Node
;
619 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
620 Node
->Parent
= ParentNode
;
621 Node
->Sibling
= ParentNode
->Child
;
622 ParentNode
->Child
= Node
;
623 if (ParentNode
->LastChild
== NULL
)
624 ParentNode
->LastChild
= Node
;
625 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
626 Node
->Level
= ParentNode
->Level
+ 1;
629 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
633 return STATUS_SUCCESS
;
637 IopFreeDeviceNode(PDEVICE_NODE DeviceNode
)
640 PDEVICE_NODE PrevSibling
= NULL
;
642 /* All children must be deleted before a parent is deleted */
643 ASSERT(!DeviceNode
->Child
);
645 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
647 ASSERT(DeviceNode
->PhysicalDeviceObject
);
649 ObDereferenceObject(DeviceNode
->PhysicalDeviceObject
);
651 /* Get previous sibling */
652 if (DeviceNode
->Parent
&& DeviceNode
->Parent
->Child
!= DeviceNode
)
654 PrevSibling
= DeviceNode
->Parent
->Child
;
655 while (PrevSibling
->Sibling
!= DeviceNode
)
656 PrevSibling
= PrevSibling
->Sibling
;
659 /* Unlink from parent if it exists */
660 if (DeviceNode
->Parent
)
662 if (DeviceNode
->Parent
->LastChild
== DeviceNode
)
664 DeviceNode
->Parent
->LastChild
= PrevSibling
;
666 PrevSibling
->Sibling
= NULL
;
668 if (DeviceNode
->Parent
->Child
== DeviceNode
)
669 DeviceNode
->Parent
->Child
= DeviceNode
->Sibling
;
672 /* Unlink from sibling list */
674 PrevSibling
->Sibling
= DeviceNode
->Sibling
;
676 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
678 RtlFreeUnicodeString(&DeviceNode
->InstancePath
);
680 RtlFreeUnicodeString(&DeviceNode
->ServiceName
);
682 if (DeviceNode
->ResourceList
)
684 ExFreePool(DeviceNode
->ResourceList
);
687 if (DeviceNode
->ResourceListTranslated
)
689 ExFreePool(DeviceNode
->ResourceListTranslated
);
692 if (DeviceNode
->ResourceRequirements
)
694 ExFreePool(DeviceNode
->ResourceRequirements
);
697 if (DeviceNode
->BootResources
)
699 ExFreePool(DeviceNode
->BootResources
);
702 ExFreePool(DeviceNode
);
704 return STATUS_SUCCESS
;
709 IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject
,
710 IN PIO_STACK_LOCATION IoStackLocation
,
711 OUT PVOID
*Information
)
714 PIO_STACK_LOCATION IrpStack
;
715 IO_STATUS_BLOCK IoStatusBlock
;
718 PDEVICE_OBJECT TopDeviceObject
;
721 /* Call the top of the device stack */
722 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
724 /* Allocate an IRP */
725 Irp
= IoAllocateIrp(TopDeviceObject
->StackSize
, FALSE
);
726 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
728 /* Initialize to failure */
729 Irp
->IoStatus
.Status
= IoStatusBlock
.Status
= STATUS_NOT_SUPPORTED
;
730 Irp
->IoStatus
.Information
= IoStatusBlock
.Information
= 0;
732 /* Initialize the event */
733 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
736 Irp
->UserIosb
= &IoStatusBlock
;
737 Irp
->UserEvent
= &Event
;
740 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
741 IoQueueThreadIrp(Irp
);
743 /* Copy-in the stack */
744 IrpStack
= IoGetNextIrpStackLocation(Irp
);
745 *IrpStack
= *IoStackLocation
;
747 /* Call the driver */
748 Status
= IoCallDriver(TopDeviceObject
, Irp
);
749 if (Status
== STATUS_PENDING
)
752 KeWaitForSingleObject(&Event
,
757 Status
= IoStatusBlock
.Status
;
760 /* Return the information */
761 *Information
= (PVOID
)IoStatusBlock
.Information
;
767 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject
,
768 IN OUT PIO_STATUS_BLOCK IoStatusBlock
,
769 IN ULONG MinorFunction
,
770 IN PIO_STACK_LOCATION Stack OPTIONAL
)
772 IO_STACK_LOCATION IoStackLocation
;
774 /* Fill out the stack information */
775 RtlZeroMemory(&IoStackLocation
, sizeof(IO_STACK_LOCATION
));
776 IoStackLocation
.MajorFunction
= IRP_MJ_PNP
;
777 IoStackLocation
.MinorFunction
= MinorFunction
;
781 RtlCopyMemory(&IoStackLocation
.Parameters
,
783 sizeof(Stack
->Parameters
));
786 /* Do the PnP call */
787 IoStatusBlock
->Status
= IopSynchronousCall(DeviceObject
,
789 (PVOID
)&IoStatusBlock
->Information
);
790 return IoStatusBlock
->Status
;
794 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context
)
796 PDEVICE_NODE ParentDeviceNode
;
797 PDEVICE_NODE ChildDeviceNode
;
800 /* Copy context data so we don't overwrite it in subsequent calls to this function */
801 ParentDeviceNode
= Context
->DeviceNode
;
803 /* Call the action routine */
804 Status
= (Context
->Action
)(ParentDeviceNode
, Context
->Context
);
805 if (!NT_SUCCESS(Status
))
810 /* Traversal of all children nodes */
811 for (ChildDeviceNode
= ParentDeviceNode
->Child
;
812 ChildDeviceNode
!= NULL
;
813 ChildDeviceNode
= ChildDeviceNode
->Sibling
)
815 /* Pass the current device node to the action routine */
816 Context
->DeviceNode
= ChildDeviceNode
;
818 Status
= IopTraverseDeviceTreeNode(Context
);
819 if (!NT_SUCCESS(Status
))
830 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context
)
834 DPRINT("Context 0x%p\n", Context
);
836 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %x Context 0x%p)\n",
837 Context
->DeviceNode
, Context
->FirstDeviceNode
, Context
->Action
, Context
->Context
);
839 /* Start from the specified device node */
840 Context
->DeviceNode
= Context
->FirstDeviceNode
;
842 /* Recursively traverse the device tree */
843 Status
= IopTraverseDeviceTreeNode(Context
);
844 if (Status
== STATUS_UNSUCCESSFUL
)
846 /* The action routine just wanted to terminate the traversal with status
847 code STATUS_SUCCESS */
848 Status
= STATUS_SUCCESS
;
856 * IopCreateDeviceKeyPath
858 * Creates a registry key
862 * Name of the key to be created.
864 * Handle to the newly created key
867 * This method can create nested trees, so parent of RegistryPath can
868 * be not existant, and will be created if needed.
872 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath
,
873 IN ULONG CreateOptions
,
876 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(ENUM_ROOT
);
877 HANDLE hParent
= NULL
, hKey
;
878 OBJECT_ATTRIBUTES ObjectAttributes
;
879 UNICODE_STRING KeyName
;
880 LPCWSTR Current
, Last
;
887 /* Open root key for device instances */
888 Status
= IopOpenRegistryKeyEx(&hParent
, NULL
, &EnumU
, KEY_CREATE_SUB_KEY
);
889 if (!NT_SUCCESS(Status
))
891 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU
, Status
);
895 Current
= KeyName
.Buffer
= RegistryPath
->Buffer
;
896 Last
= &RegistryPath
->Buffer
[RegistryPath
->Length
/ sizeof(WCHAR
)];
898 /* Go up to the end of the string */
899 while (Current
<= Last
)
901 if (Current
!= Last
&& *Current
!= '\\')
903 /* Not the end of the string and not a separator */
908 /* Prepare relative key name */
909 dwLength
= (ULONG_PTR
)Current
- (ULONG_PTR
)KeyName
.Buffer
;
910 KeyName
.MaximumLength
= KeyName
.Length
= dwLength
;
911 DPRINT("Create '%wZ'\n", &KeyName
);
914 InitializeObjectAttributes(&ObjectAttributes
,
916 OBJ_CASE_INSENSITIVE
,
919 Status
= ZwCreateKey(&hKey
,
920 Current
== Last
? KEY_ALL_ACCESS
: KEY_CREATE_SUB_KEY
,
927 /* Close parent key handle, we don't need it anymore */
931 /* Key opening/creating failed? */
932 if (!NT_SUCCESS(Status
))
934 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName
, Status
);
938 /* Check if it is the end of the string */
941 /* Yes, return success */
943 return STATUS_SUCCESS
;
946 /* Start with this new parent key */
949 KeyName
.Buffer
= (LPWSTR
)Current
;
952 return STATUS_UNSUCCESSFUL
;
956 IopUpdateResourceMap(IN PDEVICE_NODE DeviceNode
, PWCHAR Level1Key
, PWCHAR Level2Key
)
960 HANDLE PnpMgrLevel1
, PnpMgrLevel2
, ResourceMapKey
;
961 UNICODE_STRING KeyName
;
962 OBJECT_ATTRIBUTES ObjectAttributes
;
964 RtlInitUnicodeString(&KeyName
,
965 L
"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
966 InitializeObjectAttributes(&ObjectAttributes
,
968 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
971 Status
= ZwCreateKey(&ResourceMapKey
,
978 if (!NT_SUCCESS(Status
))
981 RtlInitUnicodeString(&KeyName
, Level1Key
);
982 InitializeObjectAttributes(&ObjectAttributes
,
984 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
987 Status
= ZwCreateKey(&PnpMgrLevel1
,
994 ZwClose(ResourceMapKey
);
995 if (!NT_SUCCESS(Status
))
998 RtlInitUnicodeString(&KeyName
, Level2Key
);
999 InitializeObjectAttributes(&ObjectAttributes
,
1001 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
1004 Status
= ZwCreateKey(&PnpMgrLevel2
,
1009 REG_OPTION_VOLATILE
,
1011 ZwClose(PnpMgrLevel1
);
1012 if (!NT_SUCCESS(Status
))
1015 if (DeviceNode
->ResourceList
)
1017 WCHAR NameBuff
[256];
1018 UNICODE_STRING NameU
;
1019 UNICODE_STRING Suffix
;
1022 ASSERT(DeviceNode
->ResourceListTranslated
);
1024 NameU
.Buffer
= NameBuff
;
1026 NameU
.MaximumLength
= 256 * sizeof(WCHAR
);
1028 Status
= IoGetDeviceProperty(DeviceNode
->PhysicalDeviceObject
,
1029 DevicePropertyPhysicalDeviceObjectName
,
1030 NameU
.MaximumLength
,
1033 ASSERT(Status
== STATUS_SUCCESS
);
1035 NameU
.Length
= (USHORT
)OldLength
;
1037 RtlInitUnicodeString(&Suffix
, L
".Raw");
1038 RtlAppendUnicodeStringToString(&NameU
, &Suffix
);
1040 Status
= ZwSetValueKey(PnpMgrLevel2
,
1044 DeviceNode
->ResourceList
,
1045 CM_RESOURCE_LIST_SIZE(DeviceNode
->ResourceList
));
1046 if (!NT_SUCCESS(Status
))
1048 ZwClose(PnpMgrLevel2
);
1052 /* "Remove" the suffix by setting the length back to what it used to be */
1053 NameU
.Length
= (USHORT
)OldLength
;
1055 RtlInitUnicodeString(&Suffix
, L
".Translated");
1056 RtlAppendUnicodeStringToString(&NameU
, &Suffix
);
1058 Status
= ZwSetValueKey(PnpMgrLevel2
,
1062 DeviceNode
->ResourceListTranslated
,
1063 CM_RESOURCE_LIST_SIZE(DeviceNode
->ResourceListTranslated
));
1064 ZwClose(PnpMgrLevel2
);
1065 if (!NT_SUCCESS(Status
))
1070 ZwClose(PnpMgrLevel2
);
1073 IopDeviceNodeSetFlag(DeviceNode
, DNF_RESOURCE_ASSIGNED
);
1075 return STATUS_SUCCESS
;
1079 IopUpdateResourceMapForPnPDevice(IN PDEVICE_NODE DeviceNode
)
1081 return IopUpdateResourceMap(DeviceNode
, L
"PnP Manager", L
"PnpManager");
1085 IopSetDeviceInstanceData(HANDLE InstanceKey
,
1086 PDEVICE_NODE DeviceNode
)
1088 OBJECT_ATTRIBUTES ObjectAttributes
;
1089 UNICODE_STRING KeyName
;
1092 ULONG ListSize
, ResultLength
;
1094 HANDLE ControlHandle
;
1096 DPRINT("IopSetDeviceInstanceData() called\n");
1098 /* Create the 'LogConf' key */
1099 RtlInitUnicodeString(&KeyName
, L
"LogConf");
1100 InitializeObjectAttributes(&ObjectAttributes
,
1102 OBJ_CASE_INSENSITIVE
,
1105 Status
= ZwCreateKey(&LogConfKey
,
1112 if (NT_SUCCESS(Status
))
1114 /* Set 'BootConfig' value */
1115 if (DeviceNode
->BootResources
!= NULL
)
1117 ResCount
= DeviceNode
->BootResources
->Count
;
1120 ListSize
= CM_RESOURCE_LIST_SIZE(DeviceNode
->BootResources
);
1122 RtlInitUnicodeString(&KeyName
, L
"BootConfig");
1123 Status
= ZwSetValueKey(LogConfKey
,
1127 DeviceNode
->BootResources
,
1132 /* Set 'BasicConfigVector' value */
1133 if (DeviceNode
->ResourceRequirements
!= NULL
&&
1134 DeviceNode
->ResourceRequirements
->ListSize
!= 0)
1136 RtlInitUnicodeString(&KeyName
, L
"BasicConfigVector");
1137 Status
= ZwSetValueKey(LogConfKey
,
1140 REG_RESOURCE_REQUIREMENTS_LIST
,
1141 DeviceNode
->ResourceRequirements
,
1142 DeviceNode
->ResourceRequirements
->ListSize
);
1145 ZwClose(LogConfKey
);
1148 /* Set the 'ConfigFlags' value */
1149 RtlInitUnicodeString(&KeyName
, L
"ConfigFlags");
1150 Status
= ZwQueryValueKey(InstanceKey
,
1152 KeyValueBasicInformation
,
1156 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1158 /* Write the default value */
1159 ULONG DefaultConfigFlags
= 0;
1160 Status
= ZwSetValueKey(InstanceKey
,
1164 &DefaultConfigFlags
,
1165 sizeof(DefaultConfigFlags
));
1168 /* Create the 'Control' key */
1169 RtlInitUnicodeString(&KeyName
, L
"Control");
1170 InitializeObjectAttributes(&ObjectAttributes
,
1172 OBJ_CASE_INSENSITIVE
,
1175 Status
= ZwCreateKey(&ControlHandle
, 0, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
1177 if (NT_SUCCESS(Status
))
1178 ZwClose(ControlHandle
);
1180 DPRINT("IopSetDeviceInstanceData() done\n");
1186 IopCheckResourceDescriptor(
1187 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc
,
1188 IN PCM_RESOURCE_LIST ResourceList
,
1190 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
1193 BOOLEAN Result
= FALSE
;
1195 if (ResDesc
->ShareDisposition
== CmResourceShareShared
)
1198 for (i
= 0; i
< ResourceList
->Count
; i
++)
1200 PCM_PARTIAL_RESOURCE_LIST ResList
= &ResourceList
->List
[i
].PartialResourceList
;
1201 for (ii
= 0; ii
< ResList
->Count
; ii
++)
1203 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc2
= &ResList
->PartialDescriptors
[ii
];
1205 /* We don't care about shared resources */
1206 if (ResDesc
->ShareDisposition
== CmResourceShareShared
&&
1207 ResDesc2
->ShareDisposition
== CmResourceShareShared
)
1210 /* Make sure we're comparing the same types */
1211 if (ResDesc
->Type
!= ResDesc2
->Type
)
1214 switch (ResDesc
->Type
)
1216 case CmResourceTypeMemory
:
1217 if ((ResDesc
->u
.Memory
.Start
.QuadPart
< ResDesc2
->u
.Memory
.Start
.QuadPart
&&
1218 ResDesc
->u
.Memory
.Start
.QuadPart
+ ResDesc
->u
.Memory
.Length
>
1219 ResDesc2
->u
.Memory
.Start
.QuadPart
) || (ResDesc2
->u
.Memory
.Start
.QuadPart
<
1220 ResDesc
->u
.Memory
.Start
.QuadPart
&& ResDesc2
->u
.Memory
.Start
.QuadPart
+
1221 ResDesc2
->u
.Memory
.Length
> ResDesc
->u
.Memory
.Start
.QuadPart
))
1225 DPRINT1("Resource conflict: Memory (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
1226 ResDesc
->u
.Memory
.Start
.QuadPart
, ResDesc
->u
.Memory
.Start
.QuadPart
+
1227 ResDesc
->u
.Memory
.Length
, ResDesc2
->u
.Memory
.Start
.QuadPart
,
1228 ResDesc2
->u
.Memory
.Start
.QuadPart
+ ResDesc2
->u
.Memory
.Length
);
1237 case CmResourceTypePort
:
1238 if ((ResDesc
->u
.Port
.Start
.QuadPart
< ResDesc2
->u
.Port
.Start
.QuadPart
&&
1239 ResDesc
->u
.Port
.Start
.QuadPart
+ ResDesc
->u
.Port
.Length
>
1240 ResDesc2
->u
.Port
.Start
.QuadPart
) || (ResDesc2
->u
.Port
.Start
.QuadPart
<
1241 ResDesc
->u
.Port
.Start
.QuadPart
&& ResDesc2
->u
.Port
.Start
.QuadPart
+
1242 ResDesc2
->u
.Port
.Length
> ResDesc
->u
.Port
.Start
.QuadPart
))
1246 DPRINT1("Resource conflict: Port (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
1247 ResDesc
->u
.Port
.Start
.QuadPart
, ResDesc
->u
.Port
.Start
.QuadPart
+
1248 ResDesc
->u
.Port
.Length
, ResDesc2
->u
.Port
.Start
.QuadPart
,
1249 ResDesc2
->u
.Port
.Start
.QuadPart
+ ResDesc2
->u
.Port
.Length
);
1258 case CmResourceTypeInterrupt
:
1259 if (ResDesc
->u
.Interrupt
.Vector
== ResDesc2
->u
.Interrupt
.Vector
)
1263 DPRINT1("Resource conflict: IRQ (0x%x 0x%x vs. 0x%x 0x%x)\n",
1264 ResDesc
->u
.Interrupt
.Vector
, ResDesc
->u
.Interrupt
.Level
,
1265 ResDesc2
->u
.Interrupt
.Vector
, ResDesc2
->u
.Interrupt
.Level
);
1274 case CmResourceTypeBusNumber
:
1275 if ((ResDesc
->u
.BusNumber
.Start
< ResDesc2
->u
.BusNumber
.Start
&&
1276 ResDesc
->u
.BusNumber
.Start
+ ResDesc
->u
.BusNumber
.Length
>
1277 ResDesc2
->u
.BusNumber
.Start
) || (ResDesc2
->u
.BusNumber
.Start
<
1278 ResDesc
->u
.BusNumber
.Start
&& ResDesc2
->u
.BusNumber
.Start
+
1279 ResDesc2
->u
.BusNumber
.Length
> ResDesc
->u
.BusNumber
.Start
))
1283 DPRINT1("Resource conflict: Bus number (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
1284 ResDesc
->u
.BusNumber
.Start
, ResDesc
->u
.BusNumber
.Start
+
1285 ResDesc
->u
.BusNumber
.Length
, ResDesc2
->u
.BusNumber
.Start
,
1286 ResDesc2
->u
.BusNumber
.Start
+ ResDesc2
->u
.BusNumber
.Length
);
1295 case CmResourceTypeDma
:
1296 if (ResDesc
->u
.Dma
.Channel
== ResDesc2
->u
.Dma
.Channel
)
1300 DPRINT1("Resource conflict: Dma (0x%x 0x%x vs. 0x%x 0x%x)\n",
1301 ResDesc
->u
.Dma
.Channel
, ResDesc
->u
.Dma
.Port
,
1302 ResDesc2
->u
.Dma
.Channel
, ResDesc2
->u
.Dma
.Port
);
1316 if (Result
&& ConflictingDescriptor
)
1318 RtlCopyMemory(ConflictingDescriptor
,
1320 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
));
1328 IopCheckForResourceConflict(
1329 IN PCM_RESOURCE_LIST ResourceList1
,
1330 IN PCM_RESOURCE_LIST ResourceList2
,
1332 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
1335 BOOLEAN Result
= FALSE
;
1337 for (i
= 0; i
< ResourceList1
->Count
; i
++)
1339 PCM_PARTIAL_RESOURCE_LIST ResList
= &ResourceList1
->List
[i
].PartialResourceList
;
1340 for (ii
= 0; ii
< ResList
->Count
; ii
++)
1342 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc
= &ResList
->PartialDescriptors
[ii
];
1344 Result
= IopCheckResourceDescriptor(ResDesc
,
1347 ConflictingDescriptor
);
1348 if (Result
) goto ByeBye
;
1359 IopDetectResourceConflict(
1360 IN PCM_RESOURCE_LIST ResourceList
,
1362 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
1364 OBJECT_ATTRIBUTES ObjectAttributes
;
1365 UNICODE_STRING KeyName
;
1366 HANDLE ResourceMapKey
= INVALID_HANDLE_VALUE
, ChildKey2
= INVALID_HANDLE_VALUE
, ChildKey3
= INVALID_HANDLE_VALUE
;
1367 ULONG KeyInformationLength
, RequiredLength
, KeyValueInformationLength
, KeyNameInformationLength
;
1368 PKEY_BASIC_INFORMATION KeyInformation
;
1369 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
;
1370 PKEY_VALUE_BASIC_INFORMATION KeyNameInformation
;
1371 ULONG ChildKeyIndex1
= 0, ChildKeyIndex2
= 0, ChildKeyIndex3
= 0;
1374 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
1375 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, 0, NULL
);
1376 Status
= ZwOpenKey(&ResourceMapKey
, KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
1377 if (!NT_SUCCESS(Status
))
1379 /* The key is missing which means we are the first device */
1380 return STATUS_SUCCESS
;
1385 Status
= ZwEnumerateKey(ResourceMapKey
,
1387 KeyBasicInformation
,
1391 if (Status
== STATUS_NO_MORE_ENTRIES
)
1393 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
1395 KeyInformationLength
= RequiredLength
;
1396 KeyInformation
= ExAllocatePool(PagedPool
, KeyInformationLength
);
1397 if (!KeyInformation
)
1399 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1403 Status
= ZwEnumerateKey(ResourceMapKey
,
1405 KeyBasicInformation
,
1407 KeyInformationLength
,
1413 if (!NT_SUCCESS(Status
))
1416 KeyName
.Buffer
= KeyInformation
->Name
;
1417 KeyName
.MaximumLength
= KeyName
.Length
= KeyInformation
->NameLength
;
1418 InitializeObjectAttributes(&ObjectAttributes
,
1420 OBJ_CASE_INSENSITIVE
,
1423 Status
= ZwOpenKey(&ChildKey2
, KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
1424 ExFreePool(KeyInformation
);
1425 if (!NT_SUCCESS(Status
))
1430 Status
= ZwEnumerateKey(ChildKey2
,
1432 KeyBasicInformation
,
1436 if (Status
== STATUS_NO_MORE_ENTRIES
)
1438 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
1440 KeyInformationLength
= RequiredLength
;
1441 KeyInformation
= ExAllocatePool(PagedPool
, KeyInformationLength
);
1442 if (!KeyInformation
)
1444 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1448 Status
= ZwEnumerateKey(ChildKey2
,
1450 KeyBasicInformation
,
1452 KeyInformationLength
,
1458 if (!NT_SUCCESS(Status
))
1461 KeyName
.Buffer
= KeyInformation
->Name
;
1462 KeyName
.MaximumLength
= KeyName
.Length
= KeyInformation
->NameLength
;
1463 InitializeObjectAttributes(&ObjectAttributes
,
1465 OBJ_CASE_INSENSITIVE
,
1468 Status
= ZwOpenKey(&ChildKey3
, KEY_QUERY_VALUE
, &ObjectAttributes
);
1469 ExFreePool(KeyInformation
);
1470 if (!NT_SUCCESS(Status
))
1475 Status
= ZwEnumerateValueKey(ChildKey3
,
1477 KeyValuePartialInformation
,
1481 if (Status
== STATUS_NO_MORE_ENTRIES
)
1483 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
1485 KeyValueInformationLength
= RequiredLength
;
1486 KeyValueInformation
= ExAllocatePool(PagedPool
, KeyValueInformationLength
);
1487 if (!KeyValueInformation
)
1489 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1493 Status
= ZwEnumerateValueKey(ChildKey3
,
1495 KeyValuePartialInformation
,
1496 KeyValueInformation
,
1497 KeyValueInformationLength
,
1502 if (!NT_SUCCESS(Status
))
1505 Status
= ZwEnumerateValueKey(ChildKey3
,
1507 KeyValueBasicInformation
,
1511 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1513 KeyNameInformationLength
= RequiredLength
;
1514 KeyNameInformation
= ExAllocatePool(PagedPool
, KeyNameInformationLength
+ sizeof(WCHAR
));
1515 if (!KeyNameInformation
)
1517 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1521 Status
= ZwEnumerateValueKey(ChildKey3
,
1523 KeyValueBasicInformation
,
1525 KeyNameInformationLength
,
1533 if (!NT_SUCCESS(Status
))
1536 KeyNameInformation
->Name
[KeyNameInformation
->NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1538 /* Skip translated entries */
1539 if (wcsstr(KeyNameInformation
->Name
, L
".Translated"))
1541 ExFreePool(KeyNameInformation
);
1545 ExFreePool(KeyNameInformation
);
1547 if (IopCheckForResourceConflict(ResourceList
,
1548 (PCM_RESOURCE_LIST
)KeyValueInformation
->Data
,
1550 ConflictingDescriptor
))
1552 ExFreePool(KeyValueInformation
);
1553 Status
= STATUS_CONFLICTING_ADDRESSES
;
1557 ExFreePool(KeyValueInformation
);
1563 if (ResourceMapKey
!= INVALID_HANDLE_VALUE
)
1564 ZwClose(ResourceMapKey
);
1565 if (ChildKey2
!= INVALID_HANDLE_VALUE
)
1567 if (ChildKey3
!= INVALID_HANDLE_VALUE
)
1570 if (Status
== STATUS_NO_MORE_ENTRIES
)
1571 Status
= STATUS_SUCCESS
;
1577 IopCheckDescriptorForConflict(PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
, OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
1579 CM_RESOURCE_LIST CmList
;
1583 CmList
.List
[0].InterfaceType
= InterfaceTypeUndefined
;
1584 CmList
.List
[0].BusNumber
= 0;
1585 CmList
.List
[0].PartialResourceList
.Version
= 1;
1586 CmList
.List
[0].PartialResourceList
.Revision
= 1;
1587 CmList
.List
[0].PartialResourceList
.Count
= 1;
1588 CmList
.List
[0].PartialResourceList
.PartialDescriptors
[0] = *CmDesc
;
1590 Status
= IopDetectResourceConflict(&CmList
, TRUE
, ConflictingDescriptor
);
1591 if (Status
== STATUS_CONFLICTING_ADDRESSES
)
1598 IopFindBusNumberResource(
1599 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
1600 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
1603 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc
;
1605 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
1606 ASSERT(IoDesc
->Type
== CmResourceTypeBusNumber
);
1608 for (Start
= IoDesc
->u
.BusNumber
.MinBusNumber
;
1609 Start
< IoDesc
->u
.BusNumber
.MaxBusNumber
;
1612 CmDesc
->u
.BusNumber
.Length
= IoDesc
->u
.BusNumber
.Length
;
1613 CmDesc
->u
.BusNumber
.Start
= Start
;
1615 if (IopCheckDescriptorForConflict(CmDesc
, &ConflictingDesc
))
1617 Start
+= ConflictingDesc
.u
.BusNumber
.Start
+ ConflictingDesc
.u
.BusNumber
.Length
;
1629 IopFindMemoryResource(
1630 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
1631 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
1634 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc
;
1636 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
1637 ASSERT(IoDesc
->Type
== CmResourceTypeMemory
);
1639 for (Start
= IoDesc
->u
.Memory
.MinimumAddress
.QuadPart
;
1640 Start
< IoDesc
->u
.Memory
.MaximumAddress
.QuadPart
;
1643 CmDesc
->u
.Memory
.Length
= IoDesc
->u
.Memory
.Length
;
1644 CmDesc
->u
.Memory
.Start
.QuadPart
= Start
;
1646 if (IopCheckDescriptorForConflict(CmDesc
, &ConflictingDesc
))
1648 Start
+= ConflictingDesc
.u
.Memory
.Start
.QuadPart
+ ConflictingDesc
.u
.Memory
.Length
;
1660 IopFindPortResource(
1661 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
1662 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
1665 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc
;
1667 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
1668 ASSERT(IoDesc
->Type
== CmResourceTypePort
);
1670 for (Start
= IoDesc
->u
.Port
.MinimumAddress
.QuadPart
;
1671 Start
< IoDesc
->u
.Port
.MaximumAddress
.QuadPart
;
1674 CmDesc
->u
.Port
.Length
= IoDesc
->u
.Port
.Length
;
1675 CmDesc
->u
.Port
.Start
.QuadPart
= Start
;
1677 if (IopCheckDescriptorForConflict(CmDesc
, &ConflictingDesc
))
1679 Start
+= ConflictingDesc
.u
.Port
.Start
.QuadPart
+ ConflictingDesc
.u
.Port
.Length
;
1692 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
1693 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
1697 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
1698 ASSERT(IoDesc
->Type
== CmResourceTypeDma
);
1700 for (Channel
= IoDesc
->u
.Dma
.MinimumChannel
;
1701 Channel
< IoDesc
->u
.Dma
.MaximumChannel
;
1704 CmDesc
->u
.Dma
.Channel
= Channel
;
1705 CmDesc
->u
.Dma
.Port
= 0;
1707 if (!IopCheckDescriptorForConflict(CmDesc
, NULL
))
1715 IopFindInterruptResource(
1716 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
1717 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
1721 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
1722 ASSERT(IoDesc
->Type
== CmResourceTypeInterrupt
);
1724 for (Vector
= IoDesc
->u
.Interrupt
.MinimumVector
;
1725 Vector
< IoDesc
->u
.Interrupt
.MaximumVector
;
1728 CmDesc
->u
.Interrupt
.Vector
= Vector
;
1729 CmDesc
->u
.Interrupt
.Level
= Vector
;
1730 CmDesc
->u
.Interrupt
.Affinity
= (KAFFINITY
)-1;
1732 if (!IopCheckDescriptorForConflict(CmDesc
, NULL
))
1740 IopCreateResourceListFromRequirements(
1741 IN PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList
,
1742 OUT PCM_RESOURCE_LIST
*ResourceList
)
1745 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc
;
1747 Size
= FIELD_OFFSET(CM_RESOURCE_LIST
, List
);
1748 for (i
= 0; i
< RequirementsList
->AlternativeLists
; i
++)
1750 PIO_RESOURCE_LIST ResList
= &RequirementsList
->List
[i
];
1751 Size
+= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
)
1752 + ResList
->Count
* sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
1755 *ResourceList
= ExAllocatePool(PagedPool
, Size
);
1757 return STATUS_INSUFFICIENT_RESOURCES
;
1759 (*ResourceList
)->Count
= 1;
1760 (*ResourceList
)->List
[0].BusNumber
= RequirementsList
->BusNumber
;
1761 (*ResourceList
)->List
[0].InterfaceType
= RequirementsList
->InterfaceType
;
1762 (*ResourceList
)->List
[0].PartialResourceList
.Version
= 1;
1763 (*ResourceList
)->List
[0].PartialResourceList
.Revision
= 1;
1764 (*ResourceList
)->List
[0].PartialResourceList
.Count
= 0;
1766 ResDesc
= &(*ResourceList
)->List
[0].PartialResourceList
.PartialDescriptors
[0];
1768 for (i
= 0; i
< RequirementsList
->AlternativeLists
; i
++)
1770 PIO_RESOURCE_LIST ResList
= &RequirementsList
->List
[i
];
1771 for (ii
= 0; ii
< ResList
->Count
; ii
++)
1773 PIO_RESOURCE_DESCRIPTOR ReqDesc
= &ResList
->Descriptors
[ii
];
1775 /* FIXME: Handle alternate ranges */
1776 if (ReqDesc
->Option
== IO_RESOURCE_ALTERNATIVE
)
1779 ResDesc
->Type
= ReqDesc
->Type
;
1780 ResDesc
->Flags
= ReqDesc
->Flags
;
1781 ResDesc
->ShareDisposition
= ReqDesc
->ShareDisposition
;
1783 switch (ReqDesc
->Type
)
1785 case CmResourceTypeInterrupt
:
1786 if (!IopFindInterruptResource(ReqDesc
, ResDesc
))
1788 DPRINT1("Failed to find an available interrupt resource (0x%x to 0x%x)\n",
1789 ReqDesc
->u
.Interrupt
.MinimumVector
, ReqDesc
->u
.Interrupt
.MaximumVector
);
1791 if (ReqDesc
->Option
== 0)
1793 ExFreePool(*ResourceList
);
1794 return STATUS_CONFLICTING_ADDRESSES
;
1799 case CmResourceTypePort
:
1800 if (!IopFindPortResource(ReqDesc
, ResDesc
))
1802 DPRINT1("Failed to find an available port resource (0x%x to 0x%x length: 0x%x)\n",
1803 ReqDesc
->u
.Port
.MinimumAddress
.QuadPart
, ReqDesc
->u
.Port
.MaximumAddress
.QuadPart
,
1804 ReqDesc
->u
.Port
.Length
);
1806 if (ReqDesc
->Option
== 0)
1808 ExFreePool(*ResourceList
);
1809 return STATUS_CONFLICTING_ADDRESSES
;
1814 case CmResourceTypeMemory
:
1815 if (!IopFindMemoryResource(ReqDesc
, ResDesc
))
1817 DPRINT1("Failed to find an available memory resource (0x%x to 0x%x length: 0x%x)\n",
1818 ReqDesc
->u
.Memory
.MinimumAddress
.QuadPart
, ReqDesc
->u
.Memory
.MaximumAddress
.QuadPart
,
1819 ReqDesc
->u
.Memory
.Length
);
1821 if (ReqDesc
->Option
== 0)
1823 ExFreePool(*ResourceList
);
1824 return STATUS_CONFLICTING_ADDRESSES
;
1829 case CmResourceTypeBusNumber
:
1830 if (!IopFindBusNumberResource(ReqDesc
, ResDesc
))
1832 DPRINT1("Failed to find an available bus number resource (0x%x to 0x%x length: 0x%x)\n",
1833 ReqDesc
->u
.BusNumber
.MinBusNumber
, ReqDesc
->u
.BusNumber
.MaxBusNumber
,
1834 ReqDesc
->u
.BusNumber
.Length
);
1836 if (ReqDesc
->Option
== 0)
1838 ExFreePool(*ResourceList
);
1839 return STATUS_CONFLICTING_ADDRESSES
;
1844 case CmResourceTypeDma
:
1845 if (!IopFindDmaResource(ReqDesc
, ResDesc
))
1847 DPRINT1("Failed to find an available dma resource (0x%x to 0x%x)\n",
1848 ReqDesc
->u
.Dma
.MinimumChannel
, ReqDesc
->u
.Dma
.MaximumChannel
);
1850 if (ReqDesc
->Option
== 0)
1852 ExFreePool(*ResourceList
);
1853 return STATUS_CONFLICTING_ADDRESSES
;
1859 DPRINT1("Unsupported resource type: %x\n", ReqDesc
->Type
);
1863 (*ResourceList
)->List
[0].PartialResourceList
.Count
++;
1868 return STATUS_SUCCESS
;
1872 IopAssignDeviceResources(
1873 IN PDEVICE_NODE DeviceNode
,
1874 OUT ULONG
*pRequiredSize
)
1876 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList
;
1882 if (!DeviceNode
->BootResources
&& !DeviceNode
->ResourceRequirements
)
1884 /* No resource needed for this device */
1885 DeviceNode
->ResourceList
= NULL
;
1887 return STATUS_SUCCESS
;
1890 /* Fill DeviceNode->ResourceList
1891 * FIXME: the PnP arbiter should go there!
1892 * Actually, use the BootResources if provided, else the resource requirements
1895 if (DeviceNode
->BootResources
)
1897 /* Browse the boot resources to know if we have some custom structures */
1898 Size
= FIELD_OFFSET(CM_RESOURCE_LIST
, List
);
1899 for (i
= 0; i
< DeviceNode
->BootResources
->Count
; i
++)
1901 pPartialResourceList
= &DeviceNode
->BootResources
->List
[i
].PartialResourceList
;
1902 Size
+= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
) +
1903 pPartialResourceList
->Count
* sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
1904 for (j
= 0; j
< pPartialResourceList
->Count
; j
++)
1906 if (pPartialResourceList
->PartialDescriptors
[j
].Type
== CmResourceTypeDeviceSpecific
)
1907 Size
+= pPartialResourceList
->PartialDescriptors
[j
].u
.DeviceSpecificData
.DataSize
;
1911 DeviceNode
->ResourceList
= ExAllocatePool(PagedPool
, Size
);
1912 if (!DeviceNode
->ResourceList
)
1914 Status
= STATUS_NO_MEMORY
;
1917 RtlCopyMemory(DeviceNode
->ResourceList
, DeviceNode
->BootResources
, Size
);
1919 Status
= IopDetectResourceConflict(DeviceNode
->ResourceList
, FALSE
, NULL
);
1920 if (NT_SUCCESS(Status
) || !DeviceNode
->ResourceRequirements
)
1922 if (!NT_SUCCESS(Status
) && !DeviceNode
->ResourceRequirements
)
1924 DPRINT1("Using conflicting boot resources because no requirements were supplied!\n");
1927 *pRequiredSize
= Size
;
1928 return STATUS_SUCCESS
;
1932 DPRINT1("Boot resources for %wZ cause a resource conflict!\n", &DeviceNode
->InstancePath
);
1933 ExFreePool(DeviceNode
->ResourceList
);
1937 Status
= IopCreateResourceListFromRequirements(DeviceNode
->ResourceRequirements
,
1938 &DeviceNode
->ResourceList
);
1939 if (!NT_SUCCESS(Status
))
1942 Size
= FIELD_OFFSET(CM_RESOURCE_LIST
, List
);
1943 for (i
= 0; i
< DeviceNode
->ResourceList
->Count
; i
++)
1945 pPartialResourceList
= &DeviceNode
->ResourceList
->List
[i
].PartialResourceList
;
1946 Size
+= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
) +
1947 pPartialResourceList
->Count
* sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
1950 Status
= IopDetectResourceConflict(DeviceNode
->ResourceList
, FALSE
, NULL
);
1951 if (!NT_SUCCESS(Status
))
1954 *pRequiredSize
= Size
;
1955 return STATUS_SUCCESS
;
1958 if (DeviceNode
->ResourceList
)
1960 ExFreePool(DeviceNode
->ResourceList
);
1961 DeviceNode
->ResourceList
= NULL
;
1969 IopTranslateDeviceResources(
1970 IN PDEVICE_NODE DeviceNode
,
1971 IN ULONG RequiredSize
)
1973 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList
;
1974 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw
, DescriptorTranslated
;
1978 if (!DeviceNode
->ResourceList
)
1980 DeviceNode
->ResourceListTranslated
= NULL
;
1981 return STATUS_SUCCESS
;
1984 /* That's easy to translate a resource list. Just copy the
1985 * untranslated one and change few fields in the copy
1987 DeviceNode
->ResourceListTranslated
= ExAllocatePool(PagedPool
, RequiredSize
);
1988 if (!DeviceNode
->ResourceListTranslated
)
1990 Status
=STATUS_NO_MEMORY
;
1993 RtlCopyMemory(DeviceNode
->ResourceListTranslated
, DeviceNode
->ResourceList
, RequiredSize
);
1995 for (i
= 0; i
< DeviceNode
->ResourceList
->Count
; i
++)
1997 pPartialResourceList
= &DeviceNode
->ResourceList
->List
[i
].PartialResourceList
;
1998 for (j
= 0; j
< pPartialResourceList
->Count
; j
++)
2000 DescriptorRaw
= &pPartialResourceList
->PartialDescriptors
[j
];
2001 DescriptorTranslated
= &DeviceNode
->ResourceListTranslated
->List
[i
].PartialResourceList
.PartialDescriptors
[j
];
2002 switch (DescriptorRaw
->Type
)
2004 case CmResourceTypePort
:
2006 ULONG AddressSpace
= 1; /* IO space */
2007 if (!HalTranslateBusAddress(
2008 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
2009 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
2010 DescriptorRaw
->u
.Port
.Start
,
2012 &DescriptorTranslated
->u
.Port
.Start
))
2014 Status
= STATUS_UNSUCCESSFUL
;
2019 case CmResourceTypeInterrupt
:
2021 DescriptorTranslated
->u
.Interrupt
.Vector
= HalGetInterruptVector(
2022 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
2023 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
2024 DescriptorRaw
->u
.Interrupt
.Level
,
2025 DescriptorRaw
->u
.Interrupt
.Vector
,
2026 (PKIRQL
)&DescriptorTranslated
->u
.Interrupt
.Level
,
2027 &DescriptorRaw
->u
.Interrupt
.Affinity
);
2030 case CmResourceTypeMemory
:
2032 ULONG AddressSpace
= 0; /* Memory space */
2033 if (!HalTranslateBusAddress(
2034 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
2035 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
2036 DescriptorRaw
->u
.Memory
.Start
,
2038 &DescriptorTranslated
->u
.Memory
.Start
))
2040 Status
= STATUS_UNSUCCESSFUL
;
2045 case CmResourceTypeDma
:
2046 case CmResourceTypeBusNumber
:
2047 case CmResourceTypeDeviceSpecific
:
2051 DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw
->Type
);
2052 Status
= STATUS_NOT_IMPLEMENTED
;
2057 return STATUS_SUCCESS
;
2060 /* Yes! Also delete ResourceList because ResourceList and
2061 * ResourceListTranslated should be a pair! */
2062 ExFreePool(DeviceNode
->ResourceList
);
2063 DeviceNode
->ResourceList
= NULL
;
2064 if (DeviceNode
->ResourceListTranslated
)
2066 ExFreePool(DeviceNode
->ResourceListTranslated
);
2067 DeviceNode
->ResourceList
= NULL
;
2074 * IopGetParentIdPrefix
2076 * Retrieve (or create) a string which identifies a device.
2080 * Pointer to device node.
2082 * Pointer to the string where is returned the parent node identifier
2085 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
2086 * valid and its Buffer field is NULL-terminated. The caller needs to
2087 * to free the string with RtlFreeUnicodeString when it is no longer
2092 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode
,
2093 PUNICODE_STRING ParentIdPrefix
)
2095 ULONG KeyNameBufferLength
;
2096 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation
= NULL
;
2097 UNICODE_STRING KeyName
;
2098 UNICODE_STRING KeyValue
;
2099 UNICODE_STRING ValueName
;
2104 /* HACK: As long as some devices have a NULL device
2105 * instance path, the following test is required :(
2107 if (DeviceNode
->Parent
->InstancePath
.Length
== 0)
2109 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
2110 &DeviceNode
->InstancePath
);
2111 return STATUS_UNSUCCESSFUL
;
2114 /* 1. Try to retrieve ParentIdPrefix from registry */
2115 KeyNameBufferLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + MAX_PATH
* sizeof(WCHAR
);
2116 ParentIdPrefixInformation
= ExAllocatePool(PagedPool
, KeyNameBufferLength
+ sizeof(WCHAR
));
2117 if (!ParentIdPrefixInformation
)
2119 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2124 KeyName
.Buffer
= ExAllocatePool(PagedPool
, (49 * sizeof(WCHAR
)) + DeviceNode
->Parent
->InstancePath
.Length
);
2125 if (!KeyName
.Buffer
)
2127 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2131 KeyName
.MaximumLength
= (49 * sizeof(WCHAR
)) + DeviceNode
->Parent
->InstancePath
.Length
;
2133 RtlAppendUnicodeToString(&KeyName
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2134 RtlAppendUnicodeStringToString(&KeyName
, &DeviceNode
->Parent
->InstancePath
);
2136 Status
= IopOpenRegistryKeyEx(&hKey
, NULL
, &KeyName
, KEY_QUERY_VALUE
| KEY_SET_VALUE
);
2137 if (!NT_SUCCESS(Status
))
2139 RtlInitUnicodeString(&ValueName
, L
"ParentIdPrefix");
2140 Status
= ZwQueryValueKey(
2142 KeyValuePartialInformation
, ParentIdPrefixInformation
,
2143 KeyNameBufferLength
, &KeyNameBufferLength
);
2144 if (NT_SUCCESS(Status
))
2146 if (ParentIdPrefixInformation
->Type
!= REG_SZ
)
2147 Status
= STATUS_UNSUCCESSFUL
;
2150 KeyValue
.Length
= KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
2151 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
2155 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
2157 KeyValue
.Length
= KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
2158 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
2162 /* 2. Create the ParentIdPrefix value */
2163 crc32
= RtlComputeCrc32(0,
2164 (PUCHAR
)DeviceNode
->Parent
->InstancePath
.Buffer
,
2165 DeviceNode
->Parent
->InstancePath
.Length
);
2167 swprintf((PWSTR
)ParentIdPrefixInformation
->Data
, L
"%lx&%lx", DeviceNode
->Parent
->Level
, crc32
);
2168 RtlInitUnicodeString(&KeyValue
, (PWSTR
)ParentIdPrefixInformation
->Data
);
2170 /* 3. Try to write the ParentIdPrefix to registry */
2171 Status
= ZwSetValueKey(hKey
,
2175 (PVOID
)KeyValue
.Buffer
,
2176 (wcslen(KeyValue
.Buffer
) + 1) * sizeof(WCHAR
));
2179 if (NT_SUCCESS(Status
))
2181 /* Duplicate the string to return it */
2182 Status
= RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
, &KeyValue
, ParentIdPrefix
);
2184 ExFreePool(ParentIdPrefixInformation
);
2185 RtlFreeUnicodeString(&KeyName
);
2193 * IopActionInterrogateDeviceStack
2195 * Retrieve information for all (direct) child nodes of a parent node.
2199 * Pointer to device node.
2201 * Pointer to parent node to retrieve child node information for.
2204 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
2205 * when we reach a device node which is not a direct child of the device
2206 * node for which we retrieve information of child nodes for. Any errors
2207 * that occur is logged instead so that all child services have a chance
2208 * of being interrogated.
2212 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode
,
2215 IO_STATUS_BLOCK IoStatusBlock
;
2216 PDEVICE_NODE ParentDeviceNode
;
2217 WCHAR InstancePath
[MAX_PATH
];
2218 IO_STACK_LOCATION Stack
;
2223 ULONG RequiredLength
;
2225 HANDLE InstanceKey
= NULL
;
2226 UNICODE_STRING ValueName
;
2227 UNICODE_STRING ParentIdPrefix
= { 0, 0, NULL
};
2228 DEVICE_CAPABILITIES DeviceCapabilities
;
2230 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode
, Context
);
2231 DPRINT("PDO 0x%p\n", DeviceNode
->PhysicalDeviceObject
);
2233 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2236 * We are called for the parent too, but we don't need to do special
2237 * handling for this node
2240 if (DeviceNode
== ParentDeviceNode
)
2242 DPRINT("Success\n");
2243 return STATUS_SUCCESS
;
2247 * Make sure this device node is a direct child of the parent device node
2248 * that is given as an argument
2251 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2253 /* Stop the traversal immediately and indicate successful operation */
2255 return STATUS_UNSUCCESSFUL
;
2259 Status
= ZwQueryDefaultLocale(FALSE
, &LocaleId
);
2260 if (!NT_SUCCESS(Status
))
2262 DPRINT("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status
);
2267 * FIXME: For critical errors, cleanup and disable device, but always
2268 * return STATUS_SUCCESS.
2271 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
2273 Stack
.Parameters
.QueryId
.IdType
= BusQueryDeviceID
;
2274 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2278 if (NT_SUCCESS(Status
))
2280 /* Copy the device id string */
2281 wcscpy(InstancePath
, (PWSTR
)IoStatusBlock
.Information
);
2284 * FIXME: Check for valid characters, if there is invalid characters
2290 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
2293 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack\n");
2295 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
2296 if (!NT_SUCCESS(Status
))
2298 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
2301 DeviceNode
->CapabilityFlags
= *(PULONG
)((ULONG_PTR
)&DeviceCapabilities
+ 4);
2303 if (!DeviceCapabilities
.UniqueID
)
2305 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
2306 DPRINT("Instance ID is not unique\n");
2307 Status
= IopGetParentIdPrefix(DeviceNode
, &ParentIdPrefix
);
2308 if (!NT_SUCCESS(Status
))
2310 DPRINT("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status
);
2314 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
2316 Stack
.Parameters
.QueryId
.IdType
= BusQueryInstanceID
;
2317 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2321 if (NT_SUCCESS(Status
))
2323 /* Append the instance id string */
2324 wcscat(InstancePath
, L
"\\");
2325 if (ParentIdPrefix
.Length
> 0)
2327 /* Add information from parent bus device to InstancePath */
2328 wcscat(InstancePath
, ParentIdPrefix
.Buffer
);
2329 if (IoStatusBlock
.Information
&& *(PWSTR
)IoStatusBlock
.Information
)
2330 wcscat(InstancePath
, L
"&");
2332 if (IoStatusBlock
.Information
)
2333 wcscat(InstancePath
, (PWSTR
)IoStatusBlock
.Information
);
2336 * FIXME: Check for valid characters, if there is invalid characters
2342 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
2344 RtlFreeUnicodeString(&ParentIdPrefix
);
2346 if (!RtlCreateUnicodeString(&DeviceNode
->InstancePath
, InstancePath
))
2348 DPRINT("No resources\n");
2349 /* FIXME: Cleanup and disable device */
2352 DPRINT("InstancePath is %S\n", DeviceNode
->InstancePath
.Buffer
);
2355 * Create registry key for the instance id, if it doesn't exist yet
2357 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceKey
);
2358 if (!NT_SUCCESS(Status
))
2360 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status
);
2364 /* Set 'Capabilities' value */
2365 RtlInitUnicodeString(&ValueName
, L
"Capabilities");
2366 Status
= ZwSetValueKey(InstanceKey
,
2370 (PVOID
)&DeviceNode
->CapabilityFlags
,
2373 /* Set 'UINumber' value */
2374 if (DeviceCapabilities
.UINumber
!= MAXULONG
)
2376 RtlInitUnicodeString(&ValueName
, L
"UINumber");
2377 Status
= ZwSetValueKey(InstanceKey
,
2381 &DeviceCapabilities
.UINumber
,
2386 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
2388 Stack
.Parameters
.QueryId
.IdType
= BusQueryHardwareIDs
;
2389 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2393 if (NT_SUCCESS(Status
))
2396 * FIXME: Check for valid characters, if there is invalid characters
2400 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
2401 DPRINT("Hardware IDs:\n");
2404 DPRINT(" %S\n", Ptr
);
2405 Length
= wcslen(Ptr
) + 1;
2408 TotalLength
+= Length
;
2410 DPRINT("TotalLength: %hu\n", TotalLength
);
2413 RtlInitUnicodeString(&ValueName
, L
"HardwareID");
2414 Status
= ZwSetValueKey(InstanceKey
,
2418 (PVOID
)IoStatusBlock
.Information
,
2419 (TotalLength
+ 1) * sizeof(WCHAR
));
2420 if (!NT_SUCCESS(Status
))
2422 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
2427 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
2430 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
2432 Stack
.Parameters
.QueryId
.IdType
= BusQueryCompatibleIDs
;
2433 Status
= IopInitiatePnpIrp(
2434 DeviceNode
->PhysicalDeviceObject
,
2438 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2441 * FIXME: Check for valid characters, if there is invalid characters
2445 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
2446 DPRINT("Compatible IDs:\n");
2449 DPRINT(" %S\n", Ptr
);
2450 Length
= wcslen(Ptr
) + 1;
2453 TotalLength
+= Length
;
2455 DPRINT("TotalLength: %hu\n", TotalLength
);
2458 RtlInitUnicodeString(&ValueName
, L
"CompatibleIDs");
2459 Status
= ZwSetValueKey(InstanceKey
,
2463 (PVOID
)IoStatusBlock
.Information
,
2464 (TotalLength
+ 1) * sizeof(WCHAR
));
2465 if (!NT_SUCCESS(Status
))
2467 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status
);
2472 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
2475 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2477 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextDescription
;
2478 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
2479 Status
= IopInitiatePnpIrp(
2480 DeviceNode
->PhysicalDeviceObject
,
2482 IRP_MN_QUERY_DEVICE_TEXT
,
2484 /* This key is mandatory, so even if the Irp fails, we still write it */
2485 RtlInitUnicodeString(&ValueName
, L
"DeviceDesc");
2486 if (ZwQueryValueKey(InstanceKey
, &ValueName
, KeyValueBasicInformation
, NULL
, 0, &RequiredLength
) == STATUS_OBJECT_NAME_NOT_FOUND
)
2488 if (NT_SUCCESS(Status
) &&
2489 IoStatusBlock
.Information
&&
2490 (*(PWSTR
)IoStatusBlock
.Information
!= 0))
2492 /* This key is overriden when a driver is installed. Don't write the
2493 * new description if another one already exists */
2494 Status
= ZwSetValueKey(InstanceKey
,
2498 (PVOID
)IoStatusBlock
.Information
,
2499 (wcslen((PWSTR
)IoStatusBlock
.Information
) + 1) * sizeof(WCHAR
));
2503 UNICODE_STRING DeviceDesc
= RTL_CONSTANT_STRING(L
"Unknown device");
2504 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status
);
2506 Status
= ZwSetValueKey(InstanceKey
,
2511 DeviceDesc
.MaximumLength
);
2513 if (!NT_SUCCESS(Status
))
2515 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status
);
2521 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2523 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextLocationInformation
;
2524 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
2525 Status
= IopInitiatePnpIrp(
2526 DeviceNode
->PhysicalDeviceObject
,
2528 IRP_MN_QUERY_DEVICE_TEXT
,
2530 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2532 DPRINT("LocationInformation: %S\n", (PWSTR
)IoStatusBlock
.Information
);
2533 RtlInitUnicodeString(&ValueName
, L
"LocationInformation");
2534 Status
= ZwSetValueKey(InstanceKey
,
2538 (PVOID
)IoStatusBlock
.Information
,
2539 (wcslen((PWSTR
)IoStatusBlock
.Information
) + 1) * sizeof(WCHAR
));
2540 if (!NT_SUCCESS(Status
))
2542 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
2547 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2550 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2552 Status
= IopInitiatePnpIrp(
2553 DeviceNode
->PhysicalDeviceObject
,
2555 IRP_MN_QUERY_BUS_INFORMATION
,
2557 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2559 PPNP_BUS_INFORMATION BusInformation
=
2560 (PPNP_BUS_INFORMATION
)IoStatusBlock
.Information
;
2562 DeviceNode
->ChildBusNumber
= BusInformation
->BusNumber
;
2563 DeviceNode
->ChildInterfaceType
= BusInformation
->LegacyBusType
;
2564 DeviceNode
->ChildBusTypeIndex
= IopGetBusTypeGuidIndex(&BusInformation
->BusTypeGuid
);
2565 ExFreePool(BusInformation
);
2569 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2571 DeviceNode
->ChildBusNumber
= 0xFFFFFFF0;
2572 DeviceNode
->ChildInterfaceType
= InterfaceTypeUndefined
;
2573 DeviceNode
->ChildBusTypeIndex
= -1;
2576 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2578 Status
= IopInitiatePnpIrp(
2579 DeviceNode
->PhysicalDeviceObject
,
2581 IRP_MN_QUERY_RESOURCES
,
2583 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2585 DeviceNode
->BootResources
=
2586 (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
2587 IopDeviceNodeSetFlag(DeviceNode
, DNF_HAS_BOOT_CONFIG
);
2591 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2592 DeviceNode
->BootResources
= NULL
;
2595 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2597 Status
= IopInitiatePnpIrp(
2598 DeviceNode
->PhysicalDeviceObject
,
2600 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
2602 if (NT_SUCCESS(Status
))
2604 DeviceNode
->ResourceRequirements
=
2605 (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
2606 if (IoStatusBlock
.Information
)
2607 IopDeviceNodeSetFlag(DeviceNode
, DNF_RESOURCE_REPORTED
);
2609 IopDeviceNodeSetFlag(DeviceNode
, DNF_NO_RESOURCE_REQUIRED
);
2613 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status
);
2614 DeviceNode
->ResourceRequirements
= NULL
;
2618 if (InstanceKey
!= NULL
)
2620 IopSetDeviceInstanceData(InstanceKey
, DeviceNode
);
2623 ZwClose(InstanceKey
);
2625 IopDeviceNodeSetFlag(DeviceNode
, DNF_PROCESSED
);
2627 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_LEGACY_DRIVER
))
2629 /* Report the device to the user-mode pnp manager */
2630 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED
,
2631 &DeviceNode
->InstancePath
);
2634 return STATUS_SUCCESS
;
2640 IN PDEVICE_OBJECT DeviceObject
)
2642 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
2643 DEVICETREE_TRAVERSE_CONTEXT Context
;
2644 PDEVICE_RELATIONS DeviceRelations
;
2645 PDEVICE_OBJECT ChildDeviceObject
;
2646 IO_STATUS_BLOCK IoStatusBlock
;
2647 PDEVICE_NODE ChildDeviceNode
;
2648 IO_STACK_LOCATION Stack
;
2652 DPRINT("DeviceObject 0x%p\n", DeviceObject
);
2654 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2656 /* Report the device to the user-mode pnp manager */
2657 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL
,
2658 &DeviceNode
->InstancePath
);
2660 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2662 Stack
.Parameters
.QueryDeviceRelations
.Type
= BusRelations
;
2664 Status
= IopInitiatePnpIrp(
2667 IRP_MN_QUERY_DEVICE_RELATIONS
,
2669 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
2671 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
2675 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
2677 if (!DeviceRelations
)
2679 DPRINT("No PDOs\n");
2680 return STATUS_UNSUCCESSFUL
;
2683 DPRINT("Got %u PDOs\n", DeviceRelations
->Count
);
2686 * Create device nodes for all discovered devices
2688 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
2690 ChildDeviceObject
= DeviceRelations
->Objects
[i
];
2691 ASSERT((ChildDeviceObject
->Flags
& DO_DEVICE_INITIALIZING
) == 0);
2693 ChildDeviceNode
= IopGetDeviceNode(ChildDeviceObject
);
2694 if (!ChildDeviceNode
)
2696 /* One doesn't exist, create it */
2697 Status
= IopCreateDeviceNode(
2702 if (NT_SUCCESS(Status
))
2704 /* Mark the node as enumerated */
2705 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2707 /* Mark the DO as bus enumerated */
2708 ChildDeviceObject
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
2712 /* Ignore this DO */
2713 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status
, i
);
2714 ObDereferenceObject(ChildDeviceNode
);
2719 /* Mark it as enumerated */
2720 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2721 ObDereferenceObject(ChildDeviceObject
);
2724 ExFreePool(DeviceRelations
);
2727 * Retrieve information about all discovered children from the bus driver
2729 IopInitDeviceTreeTraverseContext(
2732 IopActionInterrogateDeviceStack
,
2735 Status
= IopTraverseDeviceTree(&Context
);
2736 if (!NT_SUCCESS(Status
))
2738 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
2743 * Retrieve configuration from the registry for discovered children
2745 IopInitDeviceTreeTraverseContext(
2748 IopActionConfigureChildServices
,
2751 Status
= IopTraverseDeviceTree(&Context
);
2752 if (!NT_SUCCESS(Status
))
2754 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
2759 * Initialize services for discovered children.
2761 Status
= IopInitializePnpServices(DeviceNode
);
2762 if (!NT_SUCCESS(Status
))
2764 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status
);
2768 DPRINT("IopEnumerateDevice() finished\n");
2769 return STATUS_SUCCESS
;
2774 * IopActionConfigureChildServices
2776 * Retrieve configuration for all (direct) child nodes of a parent node.
2780 * Pointer to device node.
2782 * Pointer to parent node to retrieve child node configuration for.
2785 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
2786 * when we reach a device node which is not a direct child of the device
2787 * node for which we configure child services for. Any errors that occur is
2788 * logged instead so that all child services have a chance of beeing
2793 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode
,
2796 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
2797 PDEVICE_NODE ParentDeviceNode
;
2798 PUNICODE_STRING Service
;
2799 UNICODE_STRING ClassGUID
;
2801 DEVICE_CAPABILITIES DeviceCaps
;
2803 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode
, Context
);
2805 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2808 * We are called for the parent too, but we don't need to do special
2809 * handling for this node
2811 if (DeviceNode
== ParentDeviceNode
)
2813 DPRINT("Success\n");
2814 return STATUS_SUCCESS
;
2818 * Make sure this device node is a direct child of the parent device node
2819 * that is given as an argument
2821 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2823 /* Stop the traversal immediately and indicate successful operation */
2825 return STATUS_UNSUCCESSFUL
;
2828 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
))
2830 WCHAR RegKeyBuffer
[MAX_PATH
];
2831 UNICODE_STRING RegKey
;
2834 RegKey
.MaximumLength
= sizeof(RegKeyBuffer
);
2835 RegKey
.Buffer
= RegKeyBuffer
;
2838 * Retrieve configuration from Enum key
2841 Service
= &DeviceNode
->ServiceName
;
2843 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
2844 RtlInitUnicodeString(Service
, NULL
);
2845 RtlInitUnicodeString(&ClassGUID
, NULL
);
2847 QueryTable
[0].Name
= L
"Service";
2848 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2849 QueryTable
[0].EntryContext
= Service
;
2851 QueryTable
[1].Name
= L
"ClassGUID";
2852 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2853 QueryTable
[1].EntryContext
= &ClassGUID
;
2854 QueryTable
[1].DefaultType
= REG_SZ
;
2855 QueryTable
[1].DefaultData
= L
"";
2856 QueryTable
[1].DefaultLength
= 0;
2858 RtlAppendUnicodeToString(&RegKey
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2859 RtlAppendUnicodeStringToString(&RegKey
, &DeviceNode
->InstancePath
);
2861 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
2862 RegKey
.Buffer
, QueryTable
, NULL
, NULL
);
2864 if (!NT_SUCCESS(Status
))
2866 /* FIXME: Log the error */
2867 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2868 &DeviceNode
->InstancePath
, Status
);
2869 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2870 return STATUS_SUCCESS
;
2873 if (Service
->Buffer
== NULL
)
2875 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode
, &DeviceCaps
)) &&
2876 DeviceCaps
.RawDeviceOK
)
2878 DPRINT1("%wZ is using parent bus driver (%wZ)\n", &DeviceNode
->InstancePath
, &ParentDeviceNode
->ServiceName
);
2880 DeviceNode
->ServiceName
.Length
= 0;
2881 DeviceNode
->ServiceName
.MaximumLength
= 0;
2882 DeviceNode
->ServiceName
.Buffer
= NULL
;
2884 else if (ClassGUID
.Length
!= 0)
2886 /* Device has a ClassGUID value, but no Service value.
2887 * Suppose it is using the NULL driver, so state the
2888 * device is started */
2889 DPRINT1("%wZ is using NULL driver\n", &DeviceNode
->InstancePath
);
2890 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
2894 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2896 return STATUS_SUCCESS
;
2899 DPRINT("Got Service %S\n", Service
->Buffer
);
2902 return STATUS_SUCCESS
;
2906 * IopActionInitChildServices
2908 * Initialize the service for all (direct) child nodes of a parent node
2912 * Pointer to device node.
2914 * Pointer to parent node to initialize child node services for.
2917 * If the driver image for a service is not loaded and initialized
2918 * it is done here too. We only return a status code indicating an
2919 * error (STATUS_UNSUCCESSFUL) when we reach a device node which is
2920 * not a direct child of the device node for which we initialize
2921 * child services for. Any errors that occur is logged instead so
2922 * that all child services have a chance of being initialized.
2926 IopActionInitChildServices(PDEVICE_NODE DeviceNode
,
2929 PDEVICE_NODE ParentDeviceNode
;
2931 BOOLEAN BootDrivers
= !PnpSystemInit
;
2933 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode
, Context
);
2935 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2938 * We are called for the parent too, but we don't need to do special
2939 * handling for this node
2941 if (DeviceNode
== ParentDeviceNode
)
2943 DPRINT("Success\n");
2944 return STATUS_SUCCESS
;
2948 * Make sure this device node is a direct child of the parent device node
2949 * that is given as an argument
2952 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2955 * Stop the traversal immediately and indicate unsuccessful operation
2958 return STATUS_UNSUCCESSFUL
;
2961 if (IopDeviceNodeHasFlag(DeviceNode
, DNF_STARTED
) ||
2962 IopDeviceNodeHasFlag(DeviceNode
, DNF_ADDED
) ||
2963 IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
))
2964 return STATUS_SUCCESS
;
2966 if (DeviceNode
->ServiceName
.Buffer
== NULL
)
2968 /* We don't need to worry about loading the driver because we're
2969 * being driven in raw mode so our parent must be loaded to get here */
2970 Status
= IopStartDevice(DeviceNode
);
2971 if (!NT_SUCCESS(Status
))
2973 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2974 &DeviceNode
->InstancePath
, Status
);
2979 PLDR_DATA_TABLE_ENTRY ModuleObject
;
2980 PDRIVER_OBJECT DriverObject
;
2982 /* Get existing DriverObject pointer (in case the driver has
2983 already been loaded and initialized) */
2984 Status
= IopGetDriverObject(
2986 &DeviceNode
->ServiceName
,
2989 if (!NT_SUCCESS(Status
))
2991 /* Driver is not initialized, try to load it */
2992 Status
= IopLoadServiceModule(&DeviceNode
->ServiceName
, &ModuleObject
);
2994 if (NT_SUCCESS(Status
) || Status
== STATUS_IMAGE_ALREADY_LOADED
)
2996 /* STATUS_IMAGE_ALREADY_LOADED means this driver
2997 was loaded by the bootloader */
2998 if ((Status
!= STATUS_IMAGE_ALREADY_LOADED
) ||
2999 (Status
== STATUS_IMAGE_ALREADY_LOADED
&& !DriverObject
))
3001 /* Initialize the driver */
3002 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
3003 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
3007 Status
= STATUS_SUCCESS
;
3012 DPRINT1("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
3013 &DeviceNode
->ServiceName
, Status
);
3017 /* Driver is loaded and initialized at this point */
3018 if (NT_SUCCESS(Status
))
3020 /* Initialize the device, including all filters */
3021 Status
= PipCallDriverAddDevice(DeviceNode
, FALSE
, DriverObject
);
3026 * Don't disable when trying to load only boot drivers
3030 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
3031 IopDeviceNodeSetFlag(DeviceNode
, DNF_START_FAILED
);
3032 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
3033 DPRINT1("Initialization of service %S failed (Status %x)\n",
3034 DeviceNode
->ServiceName
.Buffer
, Status
);
3039 return STATUS_SUCCESS
;
3043 * IopInitializePnpServices
3045 * Initialize services for discovered children
3049 * Top device node to start initializing services.
3055 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode
)
3057 DEVICETREE_TRAVERSE_CONTEXT Context
;
3059 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode
);
3061 IopInitDeviceTreeTraverseContext(
3064 IopActionInitChildServices
,
3067 return IopTraverseDeviceTree(&Context
);
3070 static NTSTATUS INIT_FUNCTION
3071 IopEnumerateDetectedDevices(
3073 IN PUNICODE_STRING RelativePath OPTIONAL
,
3075 IN BOOLEAN EnumerateSubKeys
,
3076 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources
,
3077 IN ULONG ParentBootResourcesLength
)
3079 UNICODE_STRING IdentifierU
= RTL_CONSTANT_STRING(L
"Identifier");
3080 UNICODE_STRING HardwareIDU
= RTL_CONSTANT_STRING(L
"HardwareID");
3081 UNICODE_STRING ConfigurationDataU
= RTL_CONSTANT_STRING(L
"Configuration Data");
3082 UNICODE_STRING BootConfigU
= RTL_CONSTANT_STRING(L
"BootConfig");
3083 UNICODE_STRING LogConfU
= RTL_CONSTANT_STRING(L
"LogConf");
3084 OBJECT_ATTRIBUTES ObjectAttributes
;
3085 HANDLE hDevicesKey
= NULL
;
3086 HANDLE hDeviceKey
= NULL
;
3087 HANDLE hLevel1Key
, hLevel2Key
= NULL
, hLogConf
;
3088 UNICODE_STRING Level2NameU
;
3089 WCHAR Level2Name
[5];
3090 ULONG IndexDevice
= 0;
3092 PKEY_BASIC_INFORMATION pDeviceInformation
= NULL
;
3093 ULONG DeviceInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + 50 * sizeof(WCHAR
);
3094 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation
= NULL
;
3095 ULONG ValueInfoLength
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 50 * sizeof(WCHAR
);
3096 UNICODE_STRING DeviceName
, ValueName
;
3098 PCM_FULL_RESOURCE_DESCRIPTOR BootResources
= NULL
;
3099 ULONG BootResourcesLength
;
3102 const UNICODE_STRING IdentifierPci
= RTL_CONSTANT_STRING(L
"PCI");
3103 UNICODE_STRING HardwareIdPci
= RTL_CONSTANT_STRING(L
"*PNP0A03\0");
3104 static ULONG DeviceIndexPci
= 0;
3105 const UNICODE_STRING IdentifierSerial
= RTL_CONSTANT_STRING(L
"SerialController");
3106 UNICODE_STRING HardwareIdSerial
= RTL_CONSTANT_STRING(L
"*PNP0501\0");
3107 static ULONG DeviceIndexSerial
= 0;
3108 const UNICODE_STRING IdentifierKeyboard
= RTL_CONSTANT_STRING(L
"KeyboardController");
3109 UNICODE_STRING HardwareIdKeyboard
= RTL_CONSTANT_STRING(L
"*PNP0303\0");
3110 static ULONG DeviceIndexKeyboard
= 0;
3111 const UNICODE_STRING IdentifierMouse
= RTL_CONSTANT_STRING(L
"PointerController");
3112 UNICODE_STRING HardwareIdMouse
= RTL_CONSTANT_STRING(L
"*PNP0F13\0");
3113 static ULONG DeviceIndexMouse
= 0;
3114 const UNICODE_STRING IdentifierParallel
= RTL_CONSTANT_STRING(L
"ParallelController");
3115 UNICODE_STRING HardwareIdParallel
= RTL_CONSTANT_STRING(L
"*PNP0400\0");
3116 static ULONG DeviceIndexParallel
= 0;
3117 const UNICODE_STRING IdentifierFloppy
= RTL_CONSTANT_STRING(L
"FloppyDiskPeripheral");
3118 UNICODE_STRING HardwareIdFloppy
= RTL_CONSTANT_STRING(L
"*PNP0700\0");
3119 static ULONG DeviceIndexFloppy
= 0;
3120 const UNICODE_STRING IdentifierIsa
= RTL_CONSTANT_STRING(L
"ISA");
3121 UNICODE_STRING HardwareIdIsa
= RTL_CONSTANT_STRING(L
"*PNP0A00\0");
3122 static ULONG DeviceIndexIsa
= 0;
3123 UNICODE_STRING HardwareIdKey
;
3124 PUNICODE_STRING pHardwareId
;
3125 ULONG DeviceIndex
= 0;
3126 PUCHAR CmResourceList
;
3131 Status
= IopOpenRegistryKeyEx(&hDevicesKey
, hBaseKey
, RelativePath
, KEY_ENUMERATE_SUB_KEYS
);
3132 if (!NT_SUCCESS(Status
))
3134 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3139 hDevicesKey
= hBaseKey
;
3141 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
3142 if (!pDeviceInformation
)
3144 DPRINT("ExAllocatePool() failed\n");
3145 Status
= STATUS_NO_MEMORY
;
3149 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
3150 if (!pValueInformation
)
3152 DPRINT("ExAllocatePool() failed\n");
3153 Status
= STATUS_NO_MEMORY
;
3159 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
3160 if (Status
== STATUS_NO_MORE_ENTRIES
)
3162 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
3164 ExFreePool(pDeviceInformation
);
3165 DeviceInfoLength
= RequiredSize
;
3166 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
3167 if (!pDeviceInformation
)
3169 DPRINT("ExAllocatePool() failed\n");
3170 Status
= STATUS_NO_MEMORY
;
3173 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
3175 if (!NT_SUCCESS(Status
))
3177 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
3182 /* Open device key */
3183 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
3184 DeviceName
.Buffer
= pDeviceInformation
->Name
;
3186 Status
= IopOpenRegistryKeyEx(&hDeviceKey
, hDevicesKey
, &DeviceName
,
3187 KEY_QUERY_VALUE
+ (EnumerateSubKeys
? KEY_ENUMERATE_SUB_KEYS
: 0));
3188 if (!NT_SUCCESS(Status
))
3190 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3194 /* Read boot resources, and add then to parent ones */
3195 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3196 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
3198 ExFreePool(pValueInformation
);
3199 ValueInfoLength
= RequiredSize
;
3200 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
3201 if (!pValueInformation
)
3203 DPRINT("ExAllocatePool() failed\n");
3204 ZwDeleteKey(hLevel2Key
);
3205 Status
= STATUS_NO_MEMORY
;
3208 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3210 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
3212 BootResources
= ParentBootResources
;
3213 BootResourcesLength
= ParentBootResourcesLength
;
3215 else if (!NT_SUCCESS(Status
))
3217 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
3220 else if (pValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
)
3222 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_FULL_RESOURCE_DESCRIPTOR
);
3227 static const ULONG Header
= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
);
3229 /* Concatenate current resources and parent ones */
3230 if (ParentBootResourcesLength
== 0)
3231 BootResourcesLength
= pValueInformation
->DataLength
;
3233 BootResourcesLength
= ParentBootResourcesLength
3234 + pValueInformation
->DataLength
3236 BootResources
= ExAllocatePool(PagedPool
, BootResourcesLength
);
3239 DPRINT("ExAllocatePool() failed\n");
3242 if (ParentBootResourcesLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
3244 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
3246 else if (ParentBootResources
->PartialResourceList
.PartialDescriptors
[ParentBootResources
->PartialResourceList
.Count
- 1].Type
== CmResourceTypeDeviceSpecific
)
3248 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
3250 (PVOID
)((ULONG_PTR
)BootResources
+ pValueInformation
->DataLength
),
3251 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
3252 ParentBootResourcesLength
- Header
);
3253 BootResources
->PartialResourceList
.Count
+