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 IopBusTypeGuidList
= 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
);
53 IopTranslateDeviceResources(
54 IN PDEVICE_NODE DeviceNode
,
55 IN ULONG RequiredSize
);
59 IopGetDeviceNode(PDEVICE_OBJECT DeviceObject
)
61 return ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceObject
->DeviceObjectExtension
)->DeviceNode
;
66 IopInitializeDevice(PDEVICE_NODE DeviceNode
,
67 PDRIVER_OBJECT DriverObject
)
72 if (!DriverObject
->DriverExtension
->AddDevice
)
73 return STATUS_SUCCESS
;
75 /* This is a Plug and Play driver */
76 DPRINT("Plug and Play driver found\n");
77 ASSERT(DeviceNode
->PhysicalDeviceObject
);
79 /* Check if this plug-and-play driver is used as a legacy one for this device node */
80 if (IopDeviceNodeHasFlag(DeviceNode
, DNF_LEGACY_DRIVER
))
82 IopDeviceNodeSetFlag(DeviceNode
, DNF_ADDED
);
83 return STATUS_SUCCESS
;
86 DPRINT("Calling %wZ->AddDevice(%wZ)\n",
87 &DriverObject
->DriverName
,
88 &DeviceNode
->InstancePath
);
89 Status
= DriverObject
->DriverExtension
->AddDevice(
90 DriverObject
, DeviceNode
->PhysicalDeviceObject
);
91 if (!NT_SUCCESS(Status
))
93 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
97 /* Check if driver added a FDO above the PDO */
98 Fdo
= IoGetAttachedDeviceReference(DeviceNode
->PhysicalDeviceObject
);
99 if (Fdo
== DeviceNode
->PhysicalDeviceObject
)
101 /* FIXME: What do we do? Unload the driver or just disable the device? */
102 DPRINT1("An FDO was not attached\n");
103 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
104 return STATUS_UNSUCCESSFUL
;
107 /* Check if we have a ACPI device (needed for power management) */
108 if (Fdo
->DeviceType
== FILE_DEVICE_ACPI
)
110 static BOOLEAN SystemPowerDeviceNodeCreated
= FALSE
;
112 /* There can be only one system power device */
113 if (!SystemPowerDeviceNodeCreated
)
115 PopSystemPowerDeviceNode
= DeviceNode
;
116 ObReferenceObject(PopSystemPowerDeviceNode
);
117 SystemPowerDeviceNodeCreated
= TRUE
;
121 ObDereferenceObject(Fdo
);
123 IopDeviceNodeSetFlag(DeviceNode
, DNF_ADDED
);
124 IopDeviceNodeSetFlag(DeviceNode
, DNF_NEED_ENUMERATION_ONLY
);
126 return STATUS_SUCCESS
;
131 PDEVICE_NODE DeviceNode
)
133 IO_STATUS_BLOCK IoStatusBlock
;
134 IO_STACK_LOCATION Stack
;
135 ULONG RequiredLength
;
138 IopDeviceNodeSetFlag(DeviceNode
, DNF_ASSIGNING_RESOURCES
);
139 DPRINT("Sending IRP_MN_FILTER_RESOURCE_REQUIREMENTS to device stack\n");
140 Stack
.Parameters
.FilterResourceRequirements
.IoResourceRequirementList
= DeviceNode
->ResourceRequirements
;
141 Status
= IopInitiatePnpIrp(
142 DeviceNode
->PhysicalDeviceObject
,
144 IRP_MN_FILTER_RESOURCE_REQUIREMENTS
,
146 if (!NT_SUCCESS(Status
) && Status
!= STATUS_NOT_SUPPORTED
)
148 DPRINT("IopInitiatePnpIrp(IRP_MN_FILTER_RESOURCE_REQUIREMENTS) failed\n");
151 DeviceNode
->ResourceRequirements
= Stack
.Parameters
.FilterResourceRequirements
.IoResourceRequirementList
;
153 Status
= IopAssignDeviceResources(DeviceNode
, &RequiredLength
);
154 if (NT_SUCCESS(Status
))
156 Status
= IopTranslateDeviceResources(DeviceNode
, RequiredLength
);
157 if (NT_SUCCESS(Status
))
159 IopDeviceNodeSetFlag(DeviceNode
, DNF_RESOURCE_ASSIGNED
);
163 DPRINT("IopTranslateDeviceResources() failed (Status 0x%08lx)\n", Status
);
168 DPRINT("IopAssignDeviceResources() failed (Status 0x%08lx)\n", Status
);
170 IopDeviceNodeClearFlag(DeviceNode
, DNF_ASSIGNING_RESOURCES
);
172 DPRINT("Sending IRP_MN_START_DEVICE to driver\n");
173 Stack
.Parameters
.StartDevice
.AllocatedResources
= DeviceNode
->ResourceList
;
174 Stack
.Parameters
.StartDevice
.AllocatedResourcesTranslated
= DeviceNode
->ResourceListTranslated
;
177 * Windows NT Drivers receive IRP_MN_START_DEVICE in a critical region and
178 * actually _depend_ on this!. This is because NT will lock the Device Node
179 * with an ERESOURCE, which of course requires APCs to be disabled.
181 KeEnterCriticalRegion();
183 Status
= IopInitiatePnpIrp(
184 DeviceNode
->PhysicalDeviceObject
,
189 KeLeaveCriticalRegion();
191 if (!NT_SUCCESS(Status
))
193 DPRINT("IopInitiatePnpIrp() failed\n");
197 if (IopDeviceNodeHasFlag(DeviceNode
, DNF_NEED_ENUMERATION_ONLY
))
199 DPRINT("Device needs enumeration, invalidating bus relations\n");
200 /* Invalidate device relations synchronously
201 (otherwise there will be dirty read of DeviceNode) */
202 IopEnumerateDevice(DeviceNode
->PhysicalDeviceObject
);
203 IopDeviceNodeClearFlag(DeviceNode
, DNF_NEED_ENUMERATION_ONLY
);
207 if (NT_SUCCESS(Status
))
208 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
215 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode
,
216 PDEVICE_CAPABILITIES DeviceCaps
)
218 IO_STATUS_BLOCK StatusBlock
;
219 IO_STACK_LOCATION Stack
;
221 /* Set up the Header */
222 RtlZeroMemory(DeviceCaps
, sizeof(DEVICE_CAPABILITIES
));
223 DeviceCaps
->Size
= sizeof(DEVICE_CAPABILITIES
);
224 DeviceCaps
->Version
= 1;
225 DeviceCaps
->Address
= -1;
226 DeviceCaps
->UINumber
= -1;
228 /* Set up the Stack */
229 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
230 Stack
.Parameters
.DeviceCapabilities
.Capabilities
= DeviceCaps
;
233 return IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
235 IRP_MN_QUERY_CAPABILITIES
,
240 IopAsynchronousInvalidateDeviceRelations(
241 IN PDEVICE_OBJECT DeviceObject
,
242 IN PVOID InvalidateContext
)
244 PINVALIDATE_DEVICE_RELATION_DATA Data
= InvalidateContext
;
246 IoSynchronousInvalidateDeviceRelations(
250 ObDereferenceObject(Data
->DeviceObject
);
251 IoFreeWorkItem(Data
->WorkItem
);
256 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT
*DeviceObject
)
260 if (PopSystemPowerDeviceNode
)
262 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
263 *DeviceObject
= PopSystemPowerDeviceNode
->PhysicalDeviceObject
;
264 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
266 return STATUS_SUCCESS
;
269 return STATUS_UNSUCCESSFUL
;
274 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid
)
276 USHORT i
= 0, FoundIndex
= 0xFFFF;
280 /* Acquire the lock */
281 ExAcquireFastMutex(&IopBusTypeGuidList
->Lock
);
283 /* Loop all entries */
284 while (i
< IopBusTypeGuidList
->GuidCount
)
286 /* Try to find a match */
287 if (RtlCompareMemory(BusTypeGuid
,
288 &IopBusTypeGuidList
->Guids
[i
],
289 sizeof(GUID
)) == sizeof(GUID
))
298 /* Check if we have to grow the list */
299 if (IopBusTypeGuidList
->GuidCount
)
301 /* Calculate the new size */
302 NewSize
= sizeof(IO_BUS_TYPE_GUID_LIST
) +
303 (sizeof(GUID
) * IopBusTypeGuidList
->GuidCount
);
305 /* Allocate the new copy */
306 NewList
= ExAllocatePool(PagedPool
, NewSize
);
308 /* Now copy them, decrease the size too */
309 NewSize
-= sizeof(GUID
);
310 RtlCopyMemory(NewList
, IopBusTypeGuidList
, NewSize
);
312 /* Free the old list */
313 ExFreePool(IopBusTypeGuidList
);
315 /* Use the new buffer */
316 IopBusTypeGuidList
= NewList
;
319 /* Copy the new GUID */
320 RtlCopyMemory(&IopBusTypeGuidList
->Guids
[IopBusTypeGuidList
->GuidCount
],
324 /* The new entry is the index */
325 FoundIndex
= (USHORT
)IopBusTypeGuidList
->GuidCount
;
326 IopBusTypeGuidList
->GuidCount
++;
329 ExReleaseFastMutex(&IopBusTypeGuidList
->Lock
);
335 * Creates a device node
338 * ParentNode = Pointer to parent device node
339 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
340 * to have the root device node create one
341 * (eg. for legacy drivers)
342 * DeviceNode = Pointer to storage for created device node
348 IopCreateDeviceNode(PDEVICE_NODE ParentNode
,
349 PDEVICE_OBJECT PhysicalDeviceObject
,
350 PUNICODE_STRING ServiceName
,
351 PDEVICE_NODE
*DeviceNode
)
357 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
358 ParentNode
, PhysicalDeviceObject
, ServiceName
);
360 Node
= (PDEVICE_NODE
)ExAllocatePool(NonPagedPool
, sizeof(DEVICE_NODE
));
363 return STATUS_INSUFFICIENT_RESOURCES
;
366 RtlZeroMemory(Node
, sizeof(DEVICE_NODE
));
368 if (!PhysicalDeviceObject
)
370 Status
= PnpRootCreateDevice(ServiceName
, &PhysicalDeviceObject
);
371 if (!NT_SUCCESS(Status
))
373 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status
);
378 /* This is for drivers passed on the command line to ntoskrnl.exe */
379 IopDeviceNodeSetFlag(Node
, DNF_STARTED
);
380 IopDeviceNodeSetFlag(Node
, DNF_LEGACY_DRIVER
);
383 Node
->PhysicalDeviceObject
= PhysicalDeviceObject
;
385 ((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= Node
;
389 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
390 Node
->Parent
= ParentNode
;
391 Node
->Sibling
= ParentNode
->Child
;
392 ParentNode
->Child
= Node
;
393 if (ParentNode
->LastChild
== NULL
)
394 ParentNode
->LastChild
= Node
;
395 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
396 Node
->Level
= ParentNode
->Level
+ 1;
399 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
403 return STATUS_SUCCESS
;
407 IopFreeDeviceNode(PDEVICE_NODE DeviceNode
)
410 PDEVICE_NODE PrevSibling
= NULL
;
412 /* All children must be deleted before a parent is deleted */
413 ASSERT(!DeviceNode
->Child
);
415 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
417 ASSERT(DeviceNode
->PhysicalDeviceObject
);
419 ObDereferenceObject(DeviceNode
->PhysicalDeviceObject
);
421 /* Get previous sibling */
422 if (DeviceNode
->Parent
&& DeviceNode
->Parent
->Child
!= DeviceNode
)
424 PrevSibling
= DeviceNode
->Parent
->Child
;
425 while (PrevSibling
->Sibling
!= DeviceNode
)
426 PrevSibling
= PrevSibling
->Sibling
;
429 /* Unlink from parent if it exists */
430 if (DeviceNode
->Parent
)
432 if (DeviceNode
->Parent
->LastChild
== DeviceNode
)
434 DeviceNode
->Parent
->LastChild
= PrevSibling
;
436 PrevSibling
->Sibling
= NULL
;
438 if (DeviceNode
->Parent
->Child
== DeviceNode
)
439 DeviceNode
->Parent
->Child
= DeviceNode
->Sibling
;
442 /* Unlink from sibling list */
444 PrevSibling
->Sibling
= DeviceNode
->Sibling
;
446 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
448 RtlFreeUnicodeString(&DeviceNode
->InstancePath
);
450 RtlFreeUnicodeString(&DeviceNode
->ServiceName
);
452 if (DeviceNode
->ResourceList
)
454 ExFreePool(DeviceNode
->ResourceList
);
457 if (DeviceNode
->ResourceListTranslated
)
459 ExFreePool(DeviceNode
->ResourceListTranslated
);
462 if (DeviceNode
->ResourceRequirements
)
464 ExFreePool(DeviceNode
->ResourceRequirements
);
467 if (DeviceNode
->BootResources
)
469 ExFreePool(DeviceNode
->BootResources
);
472 ExFreePool(DeviceNode
);
474 return STATUS_SUCCESS
;
478 IopInitiatePnpIrp(PDEVICE_OBJECT DeviceObject
,
479 PIO_STATUS_BLOCK IoStatusBlock
,
481 PIO_STACK_LOCATION Stack OPTIONAL
)
483 PDEVICE_OBJECT TopDeviceObject
;
484 PIO_STACK_LOCATION IrpSp
;
489 /* Always call the top of the device stack */
490 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
497 Irp
= IoBuildSynchronousFsdRequest(
506 /* PNP IRPs are initialized with a status code of STATUS_NOT_SUPPORTED */
507 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
508 Irp
->IoStatus
.Information
= 0;
510 IrpSp
= IoGetNextIrpStackLocation(Irp
);
511 IrpSp
->MinorFunction
= (UCHAR
)MinorFunction
;
515 RtlCopyMemory(&IrpSp
->Parameters
,
517 sizeof(Stack
->Parameters
));
520 Status
= IoCallDriver(TopDeviceObject
, Irp
);
521 if (Status
== STATUS_PENDING
)
523 KeWaitForSingleObject(&Event
,
528 Status
= IoStatusBlock
->Status
;
531 ObDereferenceObject(TopDeviceObject
);
538 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context
)
540 PDEVICE_NODE ParentDeviceNode
;
541 PDEVICE_NODE ChildDeviceNode
;
544 /* Copy context data so we don't overwrite it in subsequent calls to this function */
545 ParentDeviceNode
= Context
->DeviceNode
;
547 /* Call the action routine */
548 Status
= (Context
->Action
)(ParentDeviceNode
, Context
->Context
);
549 if (!NT_SUCCESS(Status
))
554 /* Traversal of all children nodes */
555 for (ChildDeviceNode
= ParentDeviceNode
->Child
;
556 ChildDeviceNode
!= NULL
;
557 ChildDeviceNode
= ChildDeviceNode
->Sibling
)
559 /* Pass the current device node to the action routine */
560 Context
->DeviceNode
= ChildDeviceNode
;
562 Status
= IopTraverseDeviceTreeNode(Context
);
563 if (!NT_SUCCESS(Status
))
574 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context
)
578 DPRINT("Context 0x%p\n", Context
);
580 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %x Context 0x%p)\n",
581 Context
->DeviceNode
, Context
->FirstDeviceNode
, Context
->Action
, Context
->Context
);
583 /* Start from the specified device node */
584 Context
->DeviceNode
= Context
->FirstDeviceNode
;
586 /* Recursively traverse the device tree */
587 Status
= IopTraverseDeviceTreeNode(Context
);
588 if (Status
== STATUS_UNSUCCESSFUL
)
590 /* The action routine just wanted to terminate the traversal with status
591 code STATUS_SUCCESS */
592 Status
= STATUS_SUCCESS
;
600 * IopCreateDeviceKeyPath
602 * Creates a registry key
606 * Name of the key to be created.
608 * Handle to the newly created key
611 * This method can create nested trees, so parent of RegistryPath can
612 * be not existant, and will be created if needed.
616 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath
,
619 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(ENUM_ROOT
);
620 HANDLE hParent
= NULL
, hKey
;
621 OBJECT_ATTRIBUTES ObjectAttributes
;
622 UNICODE_STRING KeyName
;
623 LPCWSTR Current
, Last
;
630 /* Open root key for device instances */
631 Status
= IopOpenRegistryKeyEx(&hParent
, NULL
, &EnumU
, KEY_CREATE_SUB_KEY
);
632 if (!NT_SUCCESS(Status
))
634 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU
, Status
);
638 Current
= KeyName
.Buffer
= RegistryPath
->Buffer
;
639 Last
= &RegistryPath
->Buffer
[RegistryPath
->Length
/ sizeof(WCHAR
)];
641 /* Go up to the end of the string */
642 while (Current
<= Last
)
644 if (Current
!= Last
&& *Current
!= '\\')
646 /* Not the end of the string and not a separator */
651 /* Prepare relative key name */
652 dwLength
= (ULONG_PTR
)Current
- (ULONG_PTR
)KeyName
.Buffer
;
653 KeyName
.MaximumLength
= KeyName
.Length
= dwLength
;
654 DPRINT("Create '%wZ'\n", &KeyName
);
657 InitializeObjectAttributes(&ObjectAttributes
,
659 OBJ_CASE_INSENSITIVE
,
662 Status
= ZwCreateKey(&hKey
,
663 Current
== Last
? KEY_ALL_ACCESS
: KEY_CREATE_SUB_KEY
,
670 /* Close parent key handle, we don't need it anymore */
674 /* Key opening/creating failed? */
675 if (!NT_SUCCESS(Status
))
677 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName
, Status
);
681 /* Check if it is the end of the string */
684 /* Yes, return success */
686 return STATUS_SUCCESS
;
689 /* Start with this new parent key */
692 KeyName
.Buffer
= (LPWSTR
)Current
;
695 return STATUS_UNSUCCESSFUL
;
701 IopSetDeviceInstanceData(HANDLE InstanceKey
,
702 PDEVICE_NODE DeviceNode
)
704 OBJECT_ATTRIBUTES ObjectAttributes
;
705 UNICODE_STRING KeyName
;
708 ULONG ListSize
, ResultLength
;
711 DPRINT("IopSetDeviceInstanceData() called\n");
713 /* Create the 'LogConf' key */
714 RtlInitUnicodeString(&KeyName
, L
"LogConf");
715 InitializeObjectAttributes(&ObjectAttributes
,
717 OBJ_CASE_INSENSITIVE
,
720 Status
= ZwCreateKey(&LogConfKey
,
727 if (NT_SUCCESS(Status
))
729 /* Set 'BootConfig' value */
730 if (DeviceNode
->BootResources
!= NULL
)
732 ResCount
= DeviceNode
->BootResources
->Count
;
735 ListSize
= CM_RESOURCE_LIST_SIZE(DeviceNode
->BootResources
);
737 RtlInitUnicodeString(&KeyName
, L
"BootConfig");
738 Status
= ZwSetValueKey(LogConfKey
,
742 &DeviceNode
->BootResources
,
747 /* Set 'BasicConfigVector' value */
748 if (DeviceNode
->ResourceRequirements
!= NULL
&&
749 DeviceNode
->ResourceRequirements
->ListSize
!= 0)
751 RtlInitUnicodeString(&KeyName
, L
"BasicConfigVector");
752 Status
= ZwSetValueKey(LogConfKey
,
755 REG_RESOURCE_REQUIREMENTS_LIST
,
756 DeviceNode
->ResourceRequirements
,
757 DeviceNode
->ResourceRequirements
->ListSize
);
763 /* Set the 'ConfigFlags' value */
764 RtlInitUnicodeString(&KeyName
, L
"ConfigFlags");
765 Status
= ZwQueryValueKey(InstanceKey
,
767 KeyValueBasicInformation
,
771 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
773 /* Write the default value */
774 ULONG DefaultConfigFlags
= 0;
775 Status
= ZwSetValueKey(InstanceKey
,
780 sizeof(DefaultConfigFlags
));
783 DPRINT("IopSetDeviceInstanceData() done\n");
785 return STATUS_SUCCESS
;
790 IopAssignDeviceResources(
791 IN PDEVICE_NODE DeviceNode
,
792 OUT ULONG
*pRequiredSize
)
794 PIO_RESOURCE_LIST ResourceList
;
795 PIO_RESOURCE_DESCRIPTOR ResourceDescriptor
;
796 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw
;
797 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList
;
798 ULONG NumberOfResources
= 0;
803 if (!DeviceNode
->BootResources
&& !DeviceNode
->ResourceRequirements
)
805 /* No resource needed for this device */
806 DeviceNode
->ResourceList
= NULL
;
808 return STATUS_SUCCESS
;
811 /* Fill DeviceNode->ResourceList
812 * FIXME: the PnP arbiter should go there!
813 * Actually, use the BootResources if provided, else the resource list #0
816 if (DeviceNode
->BootResources
)
818 /* Browse the boot resources to know if we have some custom structures */
819 Size
= FIELD_OFFSET(CM_RESOURCE_LIST
, List
);
820 for (i
= 0; i
< DeviceNode
->BootResources
->Count
; i
++)
822 pPartialResourceList
= &DeviceNode
->BootResources
->List
[i
].PartialResourceList
;
823 Size
+= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
)
824 + pPartialResourceList
->Count
* sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
825 for (j
= 0; j
< pPartialResourceList
->Count
; j
++)
827 if (pPartialResourceList
->PartialDescriptors
[j
].Type
== CmResourceTypeDeviceSpecific
)
828 Size
+= pPartialResourceList
->PartialDescriptors
[j
].u
.DeviceSpecificData
.DataSize
;
832 DeviceNode
->ResourceList
= ExAllocatePool(PagedPool
, Size
);
833 if (!DeviceNode
->ResourceList
)
835 Status
= STATUS_NO_MEMORY
;
838 RtlCopyMemory(DeviceNode
->ResourceList
, DeviceNode
->BootResources
, Size
);
840 *pRequiredSize
= Size
;
841 return STATUS_SUCCESS
;
844 /* Ok, here, we have to use the device requirement list */
845 ResourceList
= &DeviceNode
->ResourceRequirements
->List
[0];
846 if (ResourceList
->Version
!= 1 || ResourceList
->Revision
!= 1)
848 Status
= STATUS_REVISION_MISMATCH
;
852 Size
= sizeof(CM_RESOURCE_LIST
) + ResourceList
->Count
* sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
853 DeviceNode
->ResourceList
= ExAllocatePool(PagedPool
, Size
);
854 if (!DeviceNode
->ResourceList
)
856 Status
= STATUS_NO_MEMORY
;
860 DeviceNode
->ResourceList
->Count
= 1;
861 DeviceNode
->ResourceList
->List
[0].InterfaceType
= DeviceNode
->ResourceRequirements
->InterfaceType
;
862 DeviceNode
->ResourceList
->List
[0].BusNumber
= DeviceNode
->ResourceRequirements
->BusNumber
;
863 DeviceNode
->ResourceList
->List
[0].PartialResourceList
.Version
= 1;
864 DeviceNode
->ResourceList
->List
[0].PartialResourceList
.Revision
= 1;
866 for (i
= 0; i
< ResourceList
->Count
; i
++)
868 ResourceDescriptor
= &ResourceList
->Descriptors
[i
];
870 if (ResourceDescriptor
->Option
== 0 || ResourceDescriptor
->Option
== IO_RESOURCE_PREFERRED
)
872 DescriptorRaw
= &DeviceNode
->ResourceList
->List
[0].PartialResourceList
.PartialDescriptors
[NumberOfResources
];
875 /* Copy ResourceDescriptor to DescriptorRaw and DescriptorTranslated */
876 DescriptorRaw
->Type
= ResourceDescriptor
->Type
;
877 DescriptorRaw
->ShareDisposition
= ResourceDescriptor
->ShareDisposition
;
878 DescriptorRaw
->Flags
= ResourceDescriptor
->Flags
;
879 switch (ResourceDescriptor
->Type
)
881 case CmResourceTypePort
:
883 DescriptorRaw
->u
.Port
.Start
= ResourceDescriptor
->u
.Port
.MinimumAddress
;
884 DescriptorRaw
->u
.Port
.Length
= ResourceDescriptor
->u
.Port
.Length
;
887 case CmResourceTypeInterrupt
:
889 INTERFACE_TYPE BusType
;
894 DescriptorRaw
->u
.Interrupt
.Level
= 0;
895 DescriptorRaw
->u
.Interrupt
.Vector
= ResourceDescriptor
->u
.Interrupt
.MinimumVector
;
896 /* FIXME: HACK: if we have a PCI device, we try
897 * to keep the IRQ assigned by the BIOS */
898 if (NT_SUCCESS(IoGetDeviceProperty(
899 DeviceNode
->PhysicalDeviceObject
,
900 DevicePropertyLegacyBusType
,
901 sizeof(INTERFACE_TYPE
),
903 &ret
)) && BusType
== PCIBus
)
905 /* We have a PCI bus */
906 if (NT_SUCCESS(IoGetDeviceProperty(
907 DeviceNode
->PhysicalDeviceObject
,
908 DevicePropertyAddress
,
911 &ret
)) && SlotNumber
> 0)
913 /* We have a good slot number */
914 ret
= HalGetBusDataByOffset(PCIConfiguration
,
915 DeviceNode
->ResourceRequirements
->BusNumber
,
918 0x3c /* PCI_INTERRUPT_LINE */,
920 if (ret
!= 0 && ret
!= 2
921 && ResourceDescriptor
->u
.Interrupt
.MinimumVector
<= Irq
922 && ResourceDescriptor
->u
.Interrupt
.MaximumVector
>= Irq
)
924 /* The device already has an assigned IRQ */
925 DescriptorRaw
->u
.Interrupt
.Vector
= Irq
;
929 DPRINT1("Trying to assign IRQ 0x%lx to %wZ\n",
930 DescriptorRaw
->u
.Interrupt
.Vector
,
931 &DeviceNode
->InstancePath
);
932 Irq
= (UCHAR
)DescriptorRaw
->u
.Interrupt
.Vector
;
933 ret
= HalSetBusDataByOffset(PCIConfiguration
,
934 DeviceNode
->ResourceRequirements
->BusNumber
,
937 0x3c /* PCI_INTERRUPT_LINE */,
939 if (ret
== 0 || ret
== 2)
946 case CmResourceTypeMemory
:
948 DescriptorRaw
->u
.Memory
.Start
= ResourceDescriptor
->u
.Memory
.MinimumAddress
;
949 DescriptorRaw
->u
.Memory
.Length
= ResourceDescriptor
->u
.Memory
.Length
;
952 case CmResourceTypeDma
:
954 DescriptorRaw
->u
.Dma
.Channel
= ResourceDescriptor
->u
.Dma
.MinimumChannel
;
955 DescriptorRaw
->u
.Dma
.Port
= 0; /* FIXME */
956 DescriptorRaw
->u
.Dma
.Reserved1
= 0;
959 case CmResourceTypeBusNumber
:
961 DescriptorRaw
->u
.BusNumber
.Start
= ResourceDescriptor
->u
.BusNumber
.MinBusNumber
;
962 DescriptorRaw
->u
.BusNumber
.Length
= ResourceDescriptor
->u
.BusNumber
.Length
;
963 DescriptorRaw
->u
.BusNumber
.Reserved
= ResourceDescriptor
->u
.BusNumber
.Reserved
;
966 /*CmResourceTypeDevicePrivate:
967 case CmResourceTypePcCardConfig:
968 case CmResourceTypeMfCardConfig:
971 &DescriptorRaw->u.DevicePrivate,
972 &ResourceDescriptor->u.DevicePrivate,
973 sizeof(ResourceDescriptor->u.DevicePrivate));
975 &DescriptorTranslated->u.DevicePrivate,
976 &ResourceDescriptor->u.DevicePrivate,
977 sizeof(ResourceDescriptor->u.DevicePrivate));
981 DPRINT1("IopAssignDeviceResources(): unknown resource descriptor type 0x%x\n", ResourceDescriptor
->Type
);
988 DeviceNode
->ResourceList
->List
[0].PartialResourceList
.Count
= NumberOfResources
;
990 *pRequiredSize
= Size
;
991 return STATUS_SUCCESS
;
994 if (DeviceNode
->ResourceList
)
996 ExFreePool(DeviceNode
->ResourceList
);
997 DeviceNode
->ResourceList
= NULL
;
1005 IopTranslateDeviceResources(
1006 IN PDEVICE_NODE DeviceNode
,
1007 IN ULONG RequiredSize
)
1009 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList
;
1010 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw
, DescriptorTranslated
;
1014 if (!DeviceNode
->ResourceList
)
1016 DeviceNode
->ResourceListTranslated
= NULL
;
1017 return STATUS_SUCCESS
;
1020 /* That's easy to translate a resource list. Just copy the
1021 * untranslated one and change few fields in the copy
1023 DeviceNode
->ResourceListTranslated
= ExAllocatePool(PagedPool
, RequiredSize
);
1024 if (!DeviceNode
->ResourceListTranslated
)
1026 Status
=STATUS_NO_MEMORY
;
1029 RtlCopyMemory(DeviceNode
->ResourceListTranslated
, DeviceNode
->ResourceList
, RequiredSize
);
1031 for (i
= 0; i
< DeviceNode
->ResourceList
->Count
; i
++)
1033 pPartialResourceList
= &DeviceNode
->ResourceList
->List
[i
].PartialResourceList
;
1034 for (j
= 0; j
< pPartialResourceList
->Count
; j
++)
1036 DescriptorRaw
= &pPartialResourceList
->PartialDescriptors
[j
];
1037 DescriptorTranslated
= &DeviceNode
->ResourceListTranslated
->List
[i
].PartialResourceList
.PartialDescriptors
[j
];
1038 switch (DescriptorRaw
->Type
)
1040 case CmResourceTypePort
:
1042 ULONG AddressSpace
= 0; /* IO space */
1043 if (!HalTranslateBusAddress(
1044 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
1045 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
1046 DescriptorRaw
->u
.Port
.Start
,
1048 &DescriptorTranslated
->u
.Port
.Start
))
1050 Status
= STATUS_UNSUCCESSFUL
;
1055 case CmResourceTypeInterrupt
:
1057 DescriptorTranslated
->u
.Interrupt
.Vector
= HalGetInterruptVector(
1058 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
1059 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
1060 DescriptorRaw
->u
.Interrupt
.Level
,
1061 DescriptorRaw
->u
.Interrupt
.Vector
,
1062 (PKIRQL
)&DescriptorTranslated
->u
.Interrupt
.Level
,
1063 &DescriptorRaw
->u
.Interrupt
.Affinity
);
1066 case CmResourceTypeMemory
:
1068 ULONG AddressSpace
= 1; /* Memory space */
1069 if (!HalTranslateBusAddress(
1070 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
1071 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
1072 DescriptorRaw
->u
.Memory
.Start
,
1074 &DescriptorTranslated
->u
.Memory
.Start
))
1076 Status
= STATUS_UNSUCCESSFUL
;
1081 case CmResourceTypeDma
:
1082 case CmResourceTypeBusNumber
:
1083 case CmResourceTypeDeviceSpecific
:
1087 DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw
->Type
);
1088 Status
= STATUS_NOT_IMPLEMENTED
;
1093 return STATUS_SUCCESS
;
1096 /* Yes! Also delete ResourceList because ResourceList and
1097 * ResourceListTranslated should be a pair! */
1098 ExFreePool(DeviceNode
->ResourceList
);
1099 DeviceNode
->ResourceList
= NULL
;
1100 if (DeviceNode
->ResourceListTranslated
)
1102 ExFreePool(DeviceNode
->ResourceListTranslated
);
1103 DeviceNode
->ResourceList
= NULL
;
1110 * IopGetParentIdPrefix
1112 * Retrieve (or create) a string which identifies a device.
1116 * Pointer to device node.
1118 * Pointer to the string where is returned the parent node identifier
1121 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1122 * valid and its Buffer field is NULL-terminated. The caller needs to
1123 * to free the string with RtlFreeUnicodeString when it is no longer
1128 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode
,
1129 PUNICODE_STRING ParentIdPrefix
)
1131 ULONG KeyNameBufferLength
;
1132 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation
= NULL
;
1133 UNICODE_STRING KeyName
;
1134 UNICODE_STRING KeyValue
;
1135 UNICODE_STRING ValueName
;
1140 /* HACK: As long as some devices have a NULL device
1141 * instance path, the following test is required :(
1143 if (DeviceNode
->Parent
->InstancePath
.Length
== 0)
1145 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
1146 &DeviceNode
->InstancePath
);
1147 return STATUS_UNSUCCESSFUL
;
1150 /* 1. Try to retrieve ParentIdPrefix from registry */
1151 KeyNameBufferLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + MAX_PATH
* sizeof(WCHAR
);
1152 ParentIdPrefixInformation
= ExAllocatePool(PagedPool
, KeyNameBufferLength
+ sizeof(WCHAR
));
1153 if (!ParentIdPrefixInformation
)
1155 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1160 KeyName
.Buffer
= ExAllocatePool(PagedPool
, (49 * sizeof(WCHAR
)) + DeviceNode
->Parent
->InstancePath
.Length
);
1161 if (!KeyName
.Buffer
)
1163 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1167 KeyName
.MaximumLength
= (49 * sizeof(WCHAR
)) + DeviceNode
->Parent
->InstancePath
.Length
;
1169 RtlAppendUnicodeToString(&KeyName
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1170 RtlAppendUnicodeStringToString(&KeyName
, &DeviceNode
->Parent
->InstancePath
);
1172 Status
= IopOpenRegistryKeyEx(&hKey
, NULL
, &KeyName
, KEY_QUERY_VALUE
| KEY_SET_VALUE
);
1173 if (!NT_SUCCESS(Status
))
1175 RtlInitUnicodeString(&ValueName
, L
"ParentIdPrefix");
1176 Status
= ZwQueryValueKey(
1178 KeyValuePartialInformation
, ParentIdPrefixInformation
,
1179 KeyNameBufferLength
, &KeyNameBufferLength
);
1180 if (NT_SUCCESS(Status
))
1182 if (ParentIdPrefixInformation
->Type
!= REG_SZ
)
1183 Status
= STATUS_UNSUCCESSFUL
;
1186 KeyValue
.Length
= KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1187 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1191 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
1193 KeyValue
.Length
= KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1194 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1198 /* 2. Create the ParentIdPrefix value */
1199 crc32
= RtlComputeCrc32(0,
1200 (PUCHAR
)DeviceNode
->Parent
->InstancePath
.Buffer
,
1201 DeviceNode
->Parent
->InstancePath
.Length
);
1203 swprintf((PWSTR
)ParentIdPrefixInformation
->Data
, L
"%lx&%lx", DeviceNode
->Parent
->Level
, crc32
);
1204 RtlInitUnicodeString(&KeyValue
, (PWSTR
)ParentIdPrefixInformation
->Data
);
1206 /* 3. Try to write the ParentIdPrefix to registry */
1207 Status
= ZwSetValueKey(hKey
,
1211 (PVOID
)KeyValue
.Buffer
,
1212 (wcslen(KeyValue
.Buffer
) + 1) * sizeof(WCHAR
));
1215 if (NT_SUCCESS(Status
))
1217 /* Duplicate the string to return it */
1218 Status
= RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
, &KeyValue
, ParentIdPrefix
);
1220 ExFreePool(ParentIdPrefixInformation
);
1221 RtlFreeUnicodeString(&KeyName
);
1229 * IopActionInterrogateDeviceStack
1231 * Retrieve information for all (direct) child nodes of a parent node.
1235 * Pointer to device node.
1237 * Pointer to parent node to retrieve child node information for.
1240 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
1241 * when we reach a device node which is not a direct child of the device
1242 * node for which we retrieve information of child nodes for. Any errors
1243 * that occur is logged instead so that all child services have a chance
1244 * of being interrogated.
1248 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode
,
1251 IO_STATUS_BLOCK IoStatusBlock
;
1252 PDEVICE_NODE ParentDeviceNode
;
1253 WCHAR InstancePath
[MAX_PATH
];
1254 IO_STACK_LOCATION Stack
;
1259 ULONG RequiredLength
;
1261 HANDLE InstanceKey
= NULL
;
1262 UNICODE_STRING ValueName
;
1263 UNICODE_STRING ParentIdPrefix
= { 0 };
1264 DEVICE_CAPABILITIES DeviceCapabilities
;
1266 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode
, Context
);
1267 DPRINT("PDO 0x%p\n", DeviceNode
->PhysicalDeviceObject
);
1269 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
1272 * We are called for the parent too, but we don't need to do special
1273 * handling for this node
1276 if (DeviceNode
== ParentDeviceNode
)
1278 DPRINT("Success\n");
1279 return STATUS_SUCCESS
;
1283 * Make sure this device node is a direct child of the parent device node
1284 * that is given as an argument
1287 if (DeviceNode
->Parent
!= ParentDeviceNode
)
1289 /* Stop the traversal immediately and indicate successful operation */
1291 return STATUS_UNSUCCESSFUL
;
1295 Status
= ZwQueryDefaultLocale(FALSE
, &LocaleId
);
1296 if (!NT_SUCCESS(Status
))
1298 DPRINT("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status
);
1303 * FIXME: For critical errors, cleanup and disable device, but always
1304 * return STATUS_SUCCESS.
1307 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
1309 Stack
.Parameters
.QueryId
.IdType
= BusQueryDeviceID
;
1310 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1314 if (NT_SUCCESS(Status
))
1316 /* Copy the device id string */
1317 wcscpy(InstancePath
, (PWSTR
)IoStatusBlock
.Information
);
1320 * FIXME: Check for valid characters, if there is invalid characters
1326 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1329 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack\n");
1331 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
1332 if (!NT_SUCCESS(Status
))
1334 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
1337 DeviceNode
->CapabilityFlags
= *(PULONG
)((ULONG_PTR
)&DeviceCapabilities
+ 4);
1339 if (!DeviceCapabilities
.UniqueID
)
1341 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
1342 DPRINT("Instance ID is not unique\n");
1343 Status
= IopGetParentIdPrefix(DeviceNode
, &ParentIdPrefix
);
1344 if (!NT_SUCCESS(Status
))
1346 DPRINT("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status
);
1350 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
1352 Stack
.Parameters
.QueryId
.IdType
= BusQueryInstanceID
;
1353 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1357 if (NT_SUCCESS(Status
))
1359 /* Append the instance id string */
1360 wcscat(InstancePath
, L
"\\");
1361 if (ParentIdPrefix
.Length
> 0)
1363 /* Add information from parent bus device to InstancePath */
1364 wcscat(InstancePath
, ParentIdPrefix
.Buffer
);
1365 if (IoStatusBlock
.Information
&& *(PWSTR
)IoStatusBlock
.Information
)
1366 wcscat(InstancePath
, L
"&");
1368 if (IoStatusBlock
.Information
)
1369 wcscat(InstancePath
, (PWSTR
)IoStatusBlock
.Information
);
1372 * FIXME: Check for valid characters, if there is invalid characters
1378 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1380 RtlFreeUnicodeString(&ParentIdPrefix
);
1382 if (!RtlCreateUnicodeString(&DeviceNode
->InstancePath
, InstancePath
))
1384 DPRINT("No resources\n");
1385 /* FIXME: Cleanup and disable device */
1388 DPRINT("InstancePath is %S\n", DeviceNode
->InstancePath
.Buffer
);
1391 * Create registry key for the instance id, if it doesn't exist yet
1393 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, &InstanceKey
);
1394 if (!NT_SUCCESS(Status
))
1396 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status
);
1400 /* Set 'Capabilities' value */
1401 RtlInitUnicodeString(&ValueName
, L
"Capabilities");
1402 Status
= ZwSetValueKey(InstanceKey
,
1406 (PVOID
)&DeviceNode
->CapabilityFlags
,
1409 /* Set 'UINumber' value */
1410 if (DeviceCapabilities
.UINumber
!= (ULONG
)-1)
1412 RtlInitUnicodeString(&ValueName
, L
"UINumber");
1413 Status
= ZwSetValueKey(InstanceKey
,
1417 &DeviceCapabilities
.UINumber
,
1422 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1424 Stack
.Parameters
.QueryId
.IdType
= BusQueryHardwareIDs
;
1425 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1429 if (NT_SUCCESS(Status
))
1432 * FIXME: Check for valid characters, if there is invalid characters
1436 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
1437 DPRINT("Hardware IDs:\n");
1440 DPRINT(" %S\n", Ptr
);
1441 Length
= wcslen(Ptr
) + 1;
1444 TotalLength
+= Length
;
1446 DPRINT("TotalLength: %hu\n", TotalLength
);
1449 RtlInitUnicodeString(&ValueName
, L
"HardwareID");
1450 Status
= ZwSetValueKey(InstanceKey
,
1454 (PVOID
)IoStatusBlock
.Information
,
1455 (TotalLength
+ 1) * sizeof(WCHAR
));
1456 if (!NT_SUCCESS(Status
))
1458 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
1463 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1466 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1468 Stack
.Parameters
.QueryId
.IdType
= BusQueryCompatibleIDs
;
1469 Status
= IopInitiatePnpIrp(
1470 DeviceNode
->PhysicalDeviceObject
,
1474 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
1477 * FIXME: Check for valid characters, if there is invalid characters
1481 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
1482 DPRINT("Compatible IDs:\n");
1485 DPRINT(" %S\n", Ptr
);
1486 Length
= wcslen(Ptr
) + 1;
1489 TotalLength
+= Length
;
1491 DPRINT("TotalLength: %hu\n", TotalLength
);
1494 RtlInitUnicodeString(&ValueName
, L
"CompatibleIDs");
1495 Status
= ZwSetValueKey(InstanceKey
,
1499 (PVOID
)IoStatusBlock
.Information
,
1500 (TotalLength
+ 1) * sizeof(WCHAR
));
1501 if (!NT_SUCCESS(Status
))
1503 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status
);
1508 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1511 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
1513 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextDescription
;
1514 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
1515 Status
= IopInitiatePnpIrp(
1516 DeviceNode
->PhysicalDeviceObject
,
1518 IRP_MN_QUERY_DEVICE_TEXT
,
1520 /* This key is mandatory, so even if the Irp fails, we still write it */
1521 RtlInitUnicodeString(&ValueName
, L
"DeviceDesc");
1522 if (ZwQueryValueKey(InstanceKey
, &ValueName
, KeyValueBasicInformation
, NULL
, 0, &RequiredLength
) == STATUS_OBJECT_NAME_NOT_FOUND
)
1524 if (NT_SUCCESS(Status
) &&
1525 IoStatusBlock
.Information
&&
1526 (*(PWSTR
)IoStatusBlock
.Information
!= 0))
1528 /* This key is overriden when a driver is installed. Don't write the
1529 * new description if another one already exists */
1530 Status
= ZwSetValueKey(InstanceKey
,
1534 (PVOID
)IoStatusBlock
.Information
,
1535 (wcslen((PWSTR
)IoStatusBlock
.Information
) + 1) * sizeof(WCHAR
));
1539 UNICODE_STRING DeviceDesc
= RTL_CONSTANT_STRING(L
"Unknown device");
1540 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status
);
1542 Status
= ZwSetValueKey(InstanceKey
,
1547 DeviceDesc
.MaximumLength
);
1549 if (!NT_SUCCESS(Status
))
1551 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status
);
1557 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
1559 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextLocationInformation
;
1560 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
1561 Status
= IopInitiatePnpIrp(
1562 DeviceNode
->PhysicalDeviceObject
,
1564 IRP_MN_QUERY_DEVICE_TEXT
,
1566 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
1568 DPRINT("LocationInformation: %S\n", (PWSTR
)IoStatusBlock
.Information
);
1569 RtlInitUnicodeString(&ValueName
, L
"LocationInformation");
1570 Status
= ZwSetValueKey(InstanceKey
,
1574 (PVOID
)IoStatusBlock
.Information
,
1575 (wcslen((PWSTR
)IoStatusBlock
.Information
) + 1) * sizeof(WCHAR
));
1576 if (!NT_SUCCESS(Status
))
1578 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
1583 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
1586 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
1588 Status
= IopInitiatePnpIrp(
1589 DeviceNode
->PhysicalDeviceObject
,
1591 IRP_MN_QUERY_BUS_INFORMATION
,
1593 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
1595 PPNP_BUS_INFORMATION BusInformation
=
1596 (PPNP_BUS_INFORMATION
)IoStatusBlock
.Information
;
1598 DeviceNode
->ChildBusNumber
= BusInformation
->BusNumber
;
1599 DeviceNode
->ChildInterfaceType
= BusInformation
->LegacyBusType
;
1600 DeviceNode
->ChildBusTypeIndex
= IopGetBusTypeGuidIndex(&BusInformation
->BusTypeGuid
);
1601 ExFreePool(BusInformation
);
1605 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
1607 DeviceNode
->ChildBusNumber
= 0xFFFFFFF0;
1608 DeviceNode
->ChildInterfaceType
= InterfaceTypeUndefined
;
1609 DeviceNode
->ChildBusTypeIndex
= -1;
1612 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
1614 Status
= IopInitiatePnpIrp(
1615 DeviceNode
->PhysicalDeviceObject
,
1617 IRP_MN_QUERY_RESOURCES
,
1619 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
1621 DeviceNode
->BootResources
=
1622 (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
1623 DeviceNode
->Flags
|= DNF_HAS_BOOT_CONFIG
;
1627 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
1628 DeviceNode
->BootResources
= NULL
;
1631 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
1633 Status
= IopInitiatePnpIrp(
1634 DeviceNode
->PhysicalDeviceObject
,
1636 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
1638 if (NT_SUCCESS(Status
))
1640 DeviceNode
->ResourceRequirements
=
1641 (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
1642 if (IoStatusBlock
.Information
)
1643 IopDeviceNodeSetFlag(DeviceNode
, DNF_RESOURCE_REPORTED
);
1645 IopDeviceNodeSetFlag(DeviceNode
, DNF_NO_RESOURCE_REQUIRED
);
1649 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status
);
1650 DeviceNode
->ResourceRequirements
= NULL
;
1654 if (InstanceKey
!= NULL
)
1656 IopSetDeviceInstanceData(InstanceKey
, DeviceNode
);
1659 ZwClose(InstanceKey
);
1661 IopDeviceNodeSetFlag(DeviceNode
, DNF_PROCESSED
);
1663 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_LEGACY_DRIVER
))
1665 /* Report the device to the user-mode pnp manager */
1666 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED
,
1667 &DeviceNode
->InstancePath
);
1670 return STATUS_SUCCESS
;
1676 IN PDEVICE_OBJECT DeviceObject
)
1678 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
1679 DEVICETREE_TRAVERSE_CONTEXT Context
;
1680 PDEVICE_RELATIONS DeviceRelations
;
1681 PDEVICE_OBJECT ChildDeviceObject
;
1682 IO_STATUS_BLOCK IoStatusBlock
;
1683 PDEVICE_NODE ChildDeviceNode
;
1684 IO_STACK_LOCATION Stack
;
1688 DPRINT("DeviceObject 0x%p\n", DeviceObject
);
1690 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
1692 /* Report the device to the user-mode pnp manager */
1693 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL
,
1694 &DeviceNode
->InstancePath
);
1696 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
1698 Stack
.Parameters
.QueryDeviceRelations
.Type
= BusRelations
;
1700 Status
= IopInitiatePnpIrp(
1703 IRP_MN_QUERY_DEVICE_RELATIONS
,
1705 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
1707 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
1711 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
1713 if (!DeviceRelations
)
1715 DPRINT("No PDOs\n");
1716 return STATUS_UNSUCCESSFUL
;
1719 DPRINT("Got %u PDOs\n", DeviceRelations
->Count
);
1722 * Create device nodes for all discovered devices
1724 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
1726 ChildDeviceObject
= DeviceRelations
->Objects
[i
];
1727 ASSERT((ChildDeviceObject
->Flags
& DO_DEVICE_INITIALIZING
) == 0);
1729 ChildDeviceNode
= IopGetDeviceNode(ChildDeviceObject
);
1730 if (!ChildDeviceNode
)
1732 /* One doesn't exist, create it */
1733 Status
= IopCreateDeviceNode(
1738 if (NT_SUCCESS(Status
))
1740 /* Mark the node as enumerated */
1741 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
1743 /* Mark the DO as bus enumerated */
1744 ChildDeviceObject
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
1748 /* Ignore this DO */
1749 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status
, i
);
1750 ObDereferenceObject(ChildDeviceNode
);
1755 /* Mark it as enumerated */
1756 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
1757 ObDereferenceObject(ChildDeviceObject
);
1760 ExFreePool(DeviceRelations
);
1763 * Retrieve information about all discovered children from the bus driver
1765 IopInitDeviceTreeTraverseContext(
1768 IopActionInterrogateDeviceStack
,
1771 Status
= IopTraverseDeviceTree(&Context
);
1772 if (!NT_SUCCESS(Status
))
1774 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
1779 * Retrieve configuration from the registry for discovered children
1781 IopInitDeviceTreeTraverseContext(
1784 IopActionConfigureChildServices
,
1787 Status
= IopTraverseDeviceTree(&Context
);
1788 if (!NT_SUCCESS(Status
))
1790 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
1795 * Initialize services for discovered children.
1797 Status
= IopInitializePnpServices(DeviceNode
);
1798 if (!NT_SUCCESS(Status
))
1800 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status
);
1804 DPRINT("IopEnumerateDevice() finished\n");
1805 return STATUS_SUCCESS
;
1810 * IopActionConfigureChildServices
1812 * Retrieve configuration for all (direct) child nodes of a parent node.
1816 * Pointer to device node.
1818 * Pointer to parent node to retrieve child node configuration for.
1821 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
1822 * when we reach a device node which is not a direct child of the device
1823 * node for which we configure child services for. Any errors that occur is
1824 * logged instead so that all child services have a chance of beeing
1829 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode
,
1832 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1833 PDEVICE_NODE ParentDeviceNode
;
1834 PUNICODE_STRING Service
;
1835 UNICODE_STRING ClassGUID
;
1838 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode
, Context
);
1840 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
1843 * We are called for the parent too, but we don't need to do special
1844 * handling for this node
1846 if (DeviceNode
== ParentDeviceNode
)
1848 DPRINT("Success\n");
1849 return STATUS_SUCCESS
;
1853 * Make sure this device node is a direct child of the parent device node
1854 * that is given as an argument
1856 if (DeviceNode
->Parent
!= ParentDeviceNode
)
1858 /* Stop the traversal immediately and indicate successful operation */
1860 return STATUS_UNSUCCESSFUL
;
1863 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
))
1865 WCHAR RegKeyBuffer
[MAX_PATH
];
1866 UNICODE_STRING RegKey
;
1869 RegKey
.MaximumLength
= sizeof(RegKeyBuffer
);
1870 RegKey
.Buffer
= RegKeyBuffer
;
1873 * Retrieve configuration from Enum key
1876 Service
= &DeviceNode
->ServiceName
;
1878 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1879 RtlInitUnicodeString(Service
, NULL
);
1880 RtlInitUnicodeString(&ClassGUID
, NULL
);
1882 QueryTable
[0].Name
= L
"Service";
1883 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1884 QueryTable
[0].EntryContext
= Service
;
1886 QueryTable
[1].Name
= L
"ClassGUID";
1887 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1888 QueryTable
[1].EntryContext
= &ClassGUID
;
1889 QueryTable
[1].DefaultType
= REG_SZ
;
1890 QueryTable
[1].DefaultData
= L
"";
1891 QueryTable
[1].DefaultLength
= 0;
1893 RtlAppendUnicodeToString(&RegKey
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1894 RtlAppendUnicodeStringToString(&RegKey
, &DeviceNode
->InstancePath
);
1896 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1897 RegKey
.Buffer
, QueryTable
, NULL
, NULL
);
1899 if (!NT_SUCCESS(Status
))
1901 /* FIXME: Log the error */
1902 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
1903 &DeviceNode
->InstancePath
, Status
);
1904 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
1905 return STATUS_SUCCESS
;
1908 if (Service
->Buffer
== NULL
)
1910 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
1912 if (ClassGUID
.Length
!= 0)
1914 /* Device has a ClassGUID value, but no Service value.
1915 * Suppose it is using the NULL driver, so state the
1916 * device is started */
1917 DPRINT1("%wZ is using NULL driver\n", &DeviceNode
->InstancePath
);
1918 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
1920 return STATUS_SUCCESS
;
1923 DPRINT("Got Service %S\n", Service
->Buffer
);
1926 return STATUS_SUCCESS
;
1930 * IopActionInitChildServices
1932 * Initialize the service for all (direct) child nodes of a parent node
1936 * Pointer to device node.
1938 * Pointer to parent node to initialize child node services for.
1941 * If the driver image for a service is not loaded and initialized
1942 * it is done here too. We only return a status code indicating an
1943 * error (STATUS_UNSUCCESSFUL) when we reach a device node which is
1944 * not a direct child of the device node for which we initialize
1945 * child services for. Any errors that occur is logged instead so
1946 * that all child services have a chance of being initialized.
1950 IopActionInitChildServices(PDEVICE_NODE DeviceNode
,
1953 PDEVICE_NODE ParentDeviceNode
;
1955 BOOLEAN BootDrivers
= !PnpSystemInit
;
1957 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode
, Context
);
1959 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
1962 * We are called for the parent too, but we don't need to do special
1963 * handling for this node
1965 if (DeviceNode
== ParentDeviceNode
)
1967 DPRINT("Success\n");
1968 return STATUS_SUCCESS
;
1972 * Make sure this device node is a direct child of the parent device node
1973 * that is given as an argument
1976 if (DeviceNode
->Parent
!= ParentDeviceNode
)
1979 * Stop the traversal immediately and indicate unsuccessful operation
1982 return STATUS_UNSUCCESSFUL
;
1986 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
) &&
1987 !IopDeviceNodeHasFlag(DeviceNode
, DNF_ADDED
) &&
1988 !IopDeviceNodeHasFlag(DeviceNode
, DNF_STARTED
))
1990 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1991 PDRIVER_OBJECT DriverObject
;
1993 /* Get existing DriverObject pointer (in case the driver has
1994 already been loaded and initialized) */
1995 Status
= IopGetDriverObject(
1997 &DeviceNode
->ServiceName
,
2000 if (!NT_SUCCESS(Status
))
2002 /* Driver is not initialized, try to load it */
2003 Status
= IopLoadServiceModule(&DeviceNode
->ServiceName
, &ModuleObject
);
2005 if (NT_SUCCESS(Status
) || Status
== STATUS_IMAGE_ALREADY_LOADED
)
2007 /* STATUS_IMAGE_ALREADY_LOADED means this driver
2008 was loaded by the bootloader */
2009 if ((Status
!= STATUS_IMAGE_ALREADY_LOADED
) ||
2010 (Status
== STATUS_IMAGE_ALREADY_LOADED
&& !DriverObject
))
2012 /* Initialize the driver */
2013 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
2014 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
2018 Status
= STATUS_SUCCESS
;
2023 DPRINT1("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2024 &DeviceNode
->ServiceName
, Status
);
2028 /* Driver is loaded and initialized at this point */
2029 if (NT_SUCCESS(Status
))
2031 /* Attach lower level filter drivers. */
2032 IopAttachFilterDrivers(DeviceNode
, TRUE
);
2033 /* Initialize the function driver for the device node */
2034 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
2036 if (NT_SUCCESS(Status
))
2038 /* Attach upper level filter drivers. */
2039 IopAttachFilterDrivers(DeviceNode
, FALSE
);
2040 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
2042 Status
= IopStartDevice(DeviceNode
);
2046 DPRINT1("IopInitializeDevice(%wZ) failed with status 0x%08x\n",
2047 &DeviceNode
->InstancePath
, Status
);
2053 * Don't disable when trying to load only boot drivers
2057 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2058 IopDeviceNodeSetFlag(DeviceNode
, DNF_START_FAILED
);
2059 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
2060 DPRINT1("Initialization of service %S failed (Status %x)\n",
2061 DeviceNode
->ServiceName
.Buffer
, Status
);
2067 DPRINT("Device %wZ is disabled or already initialized\n",
2068 &DeviceNode
->InstancePath
);
2071 return STATUS_SUCCESS
;
2075 * IopInitializePnpServices
2077 * Initialize services for discovered children
2081 * Top device node to start initializing services.
2087 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode
)
2089 DEVICETREE_TRAVERSE_CONTEXT Context
;
2091 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode
);
2093 IopInitDeviceTreeTraverseContext(
2096 IopActionInitChildServices
,
2099 return IopTraverseDeviceTree(&Context
);
2102 static NTSTATUS INIT_FUNCTION
2103 IopEnumerateDetectedDevices(
2105 IN PUNICODE_STRING RelativePath OPTIONAL
,
2107 IN BOOLEAN EnumerateSubKeys
,
2108 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources
,
2109 IN ULONG ParentBootResourcesLength
)
2111 UNICODE_STRING IdentifierU
= RTL_CONSTANT_STRING(L
"Identifier");
2112 UNICODE_STRING DeviceDescU
= RTL_CONSTANT_STRING(L
"DeviceDesc");
2113 UNICODE_STRING HardwareIDU
= RTL_CONSTANT_STRING(L
"HardwareID");
2114 UNICODE_STRING ConfigurationDataU
= RTL_CONSTANT_STRING(L
"Configuration Data");
2115 UNICODE_STRING BootConfigU
= RTL_CONSTANT_STRING(L
"BootConfig");
2116 UNICODE_STRING LogConfU
= RTL_CONSTANT_STRING(L
"LogConf");
2117 OBJECT_ATTRIBUTES ObjectAttributes
;
2118 HANDLE hDevicesKey
= NULL
;
2119 HANDLE hDeviceKey
= NULL
;
2120 HANDLE hLevel1Key
, hLevel2Key
= NULL
, hLogConf
;
2121 UNICODE_STRING Level2NameU
;
2122 WCHAR Level2Name
[5];
2123 ULONG IndexDevice
= 0;
2125 PKEY_BASIC_INFORMATION pDeviceInformation
= NULL
;
2126 ULONG DeviceInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + 50 * sizeof(WCHAR
);
2127 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation
= NULL
;
2128 ULONG ValueInfoLength
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 50 * sizeof(WCHAR
);
2129 UNICODE_STRING DeviceName
, ValueName
;
2131 PCM_FULL_RESOURCE_DESCRIPTOR BootResources
= NULL
;
2132 ULONG BootResourcesLength
;
2135 const UNICODE_STRING IdentifierPci
= RTL_CONSTANT_STRING(L
"PCI");
2136 UNICODE_STRING HardwareIdPci
= RTL_CONSTANT_STRING(L
"*PNP0A03\0");
2137 static ULONG DeviceIndexPci
= 0;
2139 const UNICODE_STRING IdentifierAcpi
= RTL_CONSTANT_STRING(L
"ACPI BIOS");
2140 UNICODE_STRING HardwareIdAcpi
= RTL_CONSTANT_STRING(L
"*PNP0C08\0");
2141 static ULONG DeviceIndexAcpi
= 0;
2143 const UNICODE_STRING IdentifierSerial
= RTL_CONSTANT_STRING(L
"SerialController");
2144 UNICODE_STRING HardwareIdSerial
= RTL_CONSTANT_STRING(L
"*PNP0501\0");
2145 static ULONG DeviceIndexSerial
= 0;
2146 const UNICODE_STRING IdentifierKeyboard
= RTL_CONSTANT_STRING(L
"KeyboardController");
2147 UNICODE_STRING HardwareIdKeyboard
= RTL_CONSTANT_STRING(L
"*PNP0303\0");
2148 static ULONG DeviceIndexKeyboard
= 0;
2149 const UNICODE_STRING IdentifierMouse
= RTL_CONSTANT_STRING(L
"PointerController");
2150 UNICODE_STRING HardwareIdMouse
= RTL_CONSTANT_STRING(L
"*PNP0F13\0");
2151 static ULONG DeviceIndexMouse
= 0;
2152 UNICODE_STRING HardwareIdKey
;
2153 PUNICODE_STRING pHardwareId
;
2154 ULONG DeviceIndex
= 0;
2158 Status
= IopOpenRegistryKeyEx(&hDevicesKey
, hBaseKey
, RelativePath
, KEY_ENUMERATE_SUB_KEYS
);
2159 if (!NT_SUCCESS(Status
))
2161 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2166 hDevicesKey
= hBaseKey
;
2168 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2169 if (!pDeviceInformation
)
2171 DPRINT("ExAllocatePool() failed\n");
2172 Status
= STATUS_NO_MEMORY
;
2176 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2177 if (!pValueInformation
)
2179 DPRINT("ExAllocatePool() failed\n");
2180 Status
= STATUS_NO_MEMORY
;
2186 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2187 if (Status
== STATUS_NO_MORE_ENTRIES
)
2189 else if (Status
== STATUS_BUFFER_OVERFLOW
)
2191 ExFreePool(pDeviceInformation
);
2192 DeviceInfoLength
= RequiredSize
;
2193 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2194 if (!pDeviceInformation
)
2196 DPRINT("ExAllocatePool() failed\n");
2197 Status
= STATUS_NO_MEMORY
;
2200 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2202 if (!NT_SUCCESS(Status
))
2204 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
2209 /* Open device key */
2210 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
2211 DeviceName
.Buffer
= pDeviceInformation
->Name
;
2213 Status
= IopOpenRegistryKeyEx(&hDeviceKey
, hDevicesKey
, &DeviceName
,
2214 KEY_QUERY_VALUE
+ (EnumerateSubKeys
? KEY_ENUMERATE_SUB_KEYS
: 0));
2215 if (!NT_SUCCESS(Status
))
2217 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2221 /* Read boot resources, and add then to parent ones */
2222 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2223 if (Status
== STATUS_BUFFER_OVERFLOW
)
2225 ExFreePool(pValueInformation
);
2226 ValueInfoLength
= RequiredSize
;
2227 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2228 if (!pValueInformation
)
2230 DPRINT("ExAllocatePool() failed\n");
2231 ZwDeleteKey(hLevel2Key
);
2232 Status
= STATUS_NO_MEMORY
;
2235 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2237 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
2239 BootResources
= ParentBootResources
;
2240 BootResourcesLength
= ParentBootResourcesLength
;
2242 else if (!NT_SUCCESS(Status
))
2244 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
2247 else if (pValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
)
2249 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_FULL_RESOURCE_DESCRIPTOR
);
2254 static const ULONG Header
= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
);
2256 /* Concatenate current resources and parent ones */
2257 if (ParentBootResourcesLength
== 0)
2258 BootResourcesLength
= pValueInformation
->DataLength
;
2260 BootResourcesLength
= ParentBootResourcesLength
2261 + pValueInformation
->DataLength
2263 BootResources
= ExAllocatePool(PagedPool
, BootResourcesLength
);
2266 DPRINT("ExAllocatePool() failed\n");
2269 if (ParentBootResourcesLength
== 0)
2271 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
2273 else if (ParentBootResources
->PartialResourceList
.PartialDescriptors
[ParentBootResources
->PartialResourceList
.Count
- 1].Type
== CmResourceTypeDeviceSpecific
)
2275 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
2277 (PVOID
)((ULONG_PTR
)BootResources
+ pValueInformation
->DataLength
),
2278 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
2279 ParentBootResourcesLength
- Header
);
2280 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
2284 RtlCopyMemory(BootResources
, pValueInformation
->Data
, Header
);
2286 (PVOID
)((ULONG_PTR
)BootResources
+ Header
),
2287 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
2288 ParentBootResourcesLength
- Header
);
2290 (PVOID
)((ULONG_PTR
)BootResources
+ ParentBootResourcesLength
),
2291 pValueInformation
->Data
+ Header
,
2292 pValueInformation
->DataLength
- Header
);
2293 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
2297 if (EnumerateSubKeys
)
2302 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2303 if (Status
== STATUS_NO_MORE_ENTRIES
)
2305 else if (Status
== STATUS_BUFFER_OVERFLOW
)
2307 ExFreePool(pDeviceInformation
);
2308 DeviceInfoLength
= RequiredSize
;
2309 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2310 if (!pDeviceInformation
)
2312 DPRINT("ExAllocatePool() failed\n");
2313 Status
= STATUS_NO_MEMORY
;
2316 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2318 if (!NT_SUCCESS(Status
))
2320 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
2324 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
2325 DeviceName
.Buffer
= pDeviceInformation
->Name
;
2327 Status
= IopEnumerateDetectedDevices(
2333 BootResourcesLength
);
2334 if (!NT_SUCCESS(Status
))
2339 /* Read identifier */
2340 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2341 if (Status
== STATUS_BUFFER_OVERFLOW
)
2343 ExFreePool(pValueInformation
);
2344 ValueInfoLength
= RequiredSize
;
2345 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2346 if (!pValueInformation
)
2348 DPRINT("ExAllocatePool() failed\n");
2349 Status
= STATUS_NO_MEMORY
;
2352 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2354 if (!NT_SUCCESS(Status
))
2356 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
2358 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
2361 ValueName
.Length
= ValueName
.MaximumLength
= 0;
2363 else if (pValueInformation
->Type
!= REG_SZ
)
2365 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_SZ
);
2370 /* Assign hardware id to this device */
2371 ValueName
.Length
= ValueName
.MaximumLength
= (USHORT
)pValueInformation
->DataLength
;
2372 ValueName
.Buffer
= (PWCHAR
)pValueInformation
->Data
;
2373 if (ValueName
.Length
>= sizeof(WCHAR
) && ValueName
.Buffer
[ValueName
.Length
/ sizeof(WCHAR
) - 1] == UNICODE_NULL
)
2374 ValueName
.Length
-= sizeof(WCHAR
);
2377 if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierSerial
, FALSE
) == 0)
2379 pHardwareId
= &HardwareIdSerial
;
2380 DeviceIndex
= DeviceIndexSerial
++;
2382 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierKeyboard
, FALSE
) == 0)
2384 pHardwareId
= &HardwareIdKeyboard
;
2385 DeviceIndex
= DeviceIndexKeyboard
++;
2387 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierMouse
, FALSE
) == 0)
2389 pHardwareId
= &HardwareIdMouse
;
2390 DeviceIndex
= DeviceIndexMouse
++;
2392 else if (NT_SUCCESS(Status
))
2394 /* Try to also match the device identifier */
2395 if (RtlCompareUnicodeString(&ValueName
, &IdentifierPci
, FALSE
) == 0)
2397 pHardwareId
= &HardwareIdPci
;
2398 DeviceIndex
= DeviceIndexPci
++;
2401 else if (RtlCompareUnicodeString(&ValueName
, &IdentifierAcpi
, FALSE
) == 0)
2403 pHardwareId
= &HardwareIdAcpi
;
2404 DeviceIndex
= DeviceIndexAcpi
++;
2409 /* Unknown device */
2410 DPRINT("Unknown device '%wZ'\n", &ValueName
);
2416 /* Unknown key path */
2417 DPRINT("Unknown key path '%wZ'\n", RelativePath
);
2421 /* Prepare hardware id key (hardware id value without final \0) */
2422 HardwareIdKey
= *pHardwareId
;
2423 HardwareIdKey
.Length
-= sizeof(UNICODE_NULL
);
2425 /* Add the detected device to Root key */
2426 InitializeObjectAttributes(&ObjectAttributes
, &HardwareIdKey
, OBJ_KERNEL_HANDLE
, hRootKey
, NULL
);
2427 Status
= ZwCreateKey(
2433 REG_OPTION_NON_VOLATILE
,
2435 if (!NT_SUCCESS(Status
))
2437 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
2440 swprintf(Level2Name
, L
"%04lu", DeviceIndex
);
2441 RtlInitUnicodeString(&Level2NameU
, Level2Name
);
2442 InitializeObjectAttributes(&ObjectAttributes
, &Level2NameU
, OBJ_KERNEL_HANDLE
, hLevel1Key
, NULL
);
2443 Status
= ZwCreateKey(
2445 KEY_SET_VALUE
| KEY_CREATE_SUB_KEY
,
2449 REG_OPTION_NON_VOLATILE
,
2451 ZwClose(hLevel1Key
);
2452 if (!NT_SUCCESS(Status
))
2454 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
2457 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName
, DeviceIndex
, &HardwareIdKey
);
2458 Status
= ZwSetValueKey(hLevel2Key
, &DeviceDescU
, 0, REG_SZ
, ValueName
.Buffer
, ValueName
.MaximumLength
);
2459 if (!NT_SUCCESS(Status
))
2461 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
2462 ZwDeleteKey(hLevel2Key
);
2465 Status
= ZwSetValueKey(hLevel2Key
, &HardwareIDU
, 0, REG_MULTI_SZ
, pHardwareId
->Buffer
, pHardwareId
->MaximumLength
);
2466 if (!NT_SUCCESS(Status
))
2468 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
2469 ZwDeleteKey(hLevel2Key
);
2472 /* Create 'LogConf' subkey */
2473 InitializeObjectAttributes(&ObjectAttributes
, &LogConfU
, OBJ_KERNEL_HANDLE
, hLevel2Key
, NULL
);
2474 Status
= ZwCreateKey(
2480 REG_OPTION_VOLATILE
,
2482 if (!NT_SUCCESS(Status
))
2484 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
2485 ZwDeleteKey(hLevel2Key
);
2488 if (BootResourcesLength
> 0)
2490 /* Save boot resources to 'LogConf\BootConfig' */
2491 Status
= ZwSetValueKey(hLogConf
, &BootConfigU
, 0, REG_FULL_RESOURCE_DESCRIPTOR
, BootResources
, BootResourcesLength
);
2492 if (!NT_SUCCESS(Status
))
2494 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
2496 ZwDeleteKey(hLevel2Key
);
2503 if (BootResources
&& BootResources
!= ParentBootResources
)
2504 ExFreePool(BootResources
);
2507 ZwClose(hLevel2Key
);
2512 ZwClose(hDeviceKey
);
2517 Status
= STATUS_SUCCESS
;
2520 if (hDevicesKey
&& hDevicesKey
!= hBaseKey
)
2521 ZwClose(hDevicesKey
);
2523 ZwClose(hDeviceKey
);
2524 if (pDeviceInformation
)
2525 ExFreePool(pDeviceInformation
);
2526 if (pValueInformation
)
2527 ExFreePool(pValueInformation
);
2531 static BOOLEAN INIT_FUNCTION
2532 IopIsAcpiComputer(VOID
)
2537 UNICODE_STRING MultiKeyPathU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
2538 UNICODE_STRING IdentifierU
= RTL_CONSTANT_STRING(L
"Identifier");
2539 UNICODE_STRING AcpiBiosIdentifier
= RTL_CONSTANT_STRING(L
"ACPI BIOS");
2540 OBJECT_ATTRIBUTES ObjectAttributes
;
2541 PKEY_BASIC_INFORMATION pDeviceInformation
= NULL
;
2542 ULONG DeviceInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + 50 * sizeof(WCHAR
);
2543 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation
= NULL
;
2544 ULONG ValueInfoLength
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 50 * sizeof(WCHAR
);
2546 ULONG IndexDevice
= 0;
2547 UNICODE_STRING DeviceName
, ValueName
;
2548 HANDLE hDevicesKey
= NULL
;
2549 HANDLE hDeviceKey
= NULL
;
2551 BOOLEAN ret
= FALSE
;
2553 InitializeObjectAttributes(&ObjectAttributes
, &MultiKeyPathU
, OBJ_KERNEL_HANDLE
, NULL
, NULL
);
2554 Status
= ZwOpenKey(&hDevicesKey
, KEY_ENUMERATE_SUB_KEYS
, &ObjectAttributes
);
2555 if (!NT_SUCCESS(Status
))
2557 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2561 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2562 if (!pDeviceInformation
)
2564 DPRINT("ExAllocatePool() failed\n");
2565 Status
= STATUS_NO_MEMORY
;
2569 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2570 if (!pDeviceInformation
)
2572 DPRINT("ExAllocatePool() failed\n");
2573 Status
= STATUS_NO_MEMORY
;
2579 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2580 if (Status
== STATUS_NO_MORE_ENTRIES
)
2582 else if (Status
== STATUS_BUFFER_OVERFLOW
)
2584 ExFreePool(pDeviceInformation
);
2585 DeviceInfoLength
= RequiredSize
;
2586 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2587 if (!pDeviceInformation
)
2589 DPRINT("ExAllocatePool() failed\n");
2590 Status
= STATUS_NO_MEMORY
;
2593 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2595 if (!NT_SUCCESS(Status
))
2597 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
2602 /* Open device key */
2603 DeviceName
.Length
= DeviceName
.MaximumLength
= pDeviceInformation
->NameLength
;
2604 DeviceName
.Buffer
= pDeviceInformation
->Name
;
2605 InitializeObjectAttributes(&ObjectAttributes
, &DeviceName
, OBJ_KERNEL_HANDLE
, hDevicesKey
, NULL
);
2610 if (!NT_SUCCESS(Status
))
2612 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2616 /* Read identifier */
2617 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2618 if (Status
== STATUS_BUFFER_OVERFLOW
)
2620 ExFreePool(pValueInformation
);
2621 ValueInfoLength
= RequiredSize
;
2622 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2623 if (!pValueInformation
)
2625 DPRINT("ExAllocatePool() failed\n");
2626 Status
= STATUS_NO_MEMORY
;
2629 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2631 if (!NT_SUCCESS(Status
))
2633 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
2636 else if (pValueInformation
->Type
!= REG_SZ
)
2638 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_SZ
);
2642 ValueName
.Length
= ValueName
.MaximumLength
= pValueInformation
->DataLength
;
2643 ValueName
.Buffer
= (PWCHAR
)pValueInformation
->Data
;
2644 if (ValueName
.Length
>= sizeof(WCHAR
) && ValueName
.Buffer
[ValueName
.Length
/ sizeof(WCHAR
) - 1] == UNICODE_NULL
)
2645 ValueName
.Length
-= sizeof(WCHAR
);
2646 if (RtlCompareUnicodeString(&ValueName
, &AcpiBiosIdentifier
, FALSE
) == 0)
2648 DPRINT("Found ACPI BIOS\n");
2654 ZwClose(hDeviceKey
);
2659 if (pDeviceInformation
)
2660 ExFreePool(pDeviceInformation
);
2661 if (pValueInformation
)
2662 ExFreePool(pValueInformation
);
2664 ZwClose(hDevicesKey
);
2666 ZwClose(hDeviceKey
);
2671 static NTSTATUS INIT_FUNCTION
2672 IopUpdateRootKey(VOID
)
2674 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
2675 UNICODE_STRING RootPathU
= RTL_CONSTANT_STRING(L
"Root");
2676 UNICODE_STRING MultiKeyPathU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
2677 UNICODE_STRING DeviceDescU
= RTL_CONSTANT_STRING(L
"DeviceDesc");
2678 UNICODE_STRING HardwareIDU
= RTL_CONSTANT_STRING(L
"HardwareID");
2679 UNICODE_STRING LogConfU
= RTL_CONSTANT_STRING(L
"LogConf");
2680 UNICODE_STRING HalAcpiDevice
= RTL_CONSTANT_STRING(L
"ACPI_HAL");
2681 UNICODE_STRING HalAcpiId
= RTL_CONSTANT_STRING(L
"0000");
2682 UNICODE_STRING HalAcpiDeviceDesc
= RTL_CONSTANT_STRING(L
"HAL ACPI");
2683 UNICODE_STRING HalAcpiHardwareID
= RTL_CONSTANT_STRING(L
"*PNP0C08\0");
2684 OBJECT_ATTRIBUTES ObjectAttributes
;
2685 HANDLE hEnum
, hRoot
, hHalAcpiDevice
, hHalAcpiId
, hLogConf
;
2688 InitializeObjectAttributes(&ObjectAttributes
, &EnumU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
2689 Status
= ZwCreateKey(&hEnum
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
, 0, NULL
, 0, NULL
);
2690 if (!NT_SUCCESS(Status
))
2692 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status
);
2696 InitializeObjectAttributes(&ObjectAttributes
, &RootPathU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, hEnum
, NULL
);
2697 Status
= ZwCreateKey(&hRoot
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
, 0, NULL
, 0, NULL
);
2699 if (!NT_SUCCESS(Status
))
2701 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2705 if (IopIsAcpiComputer())
2707 InitializeObjectAttributes(&ObjectAttributes
, &HalAcpiDevice
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, hRoot
, NULL
);
2708 Status
= ZwCreateKey(&hHalAcpiDevice
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
2710 if (!NT_SUCCESS(Status
))
2712 InitializeObjectAttributes(&ObjectAttributes
, &HalAcpiId
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, hHalAcpiDevice
, NULL
);
2713 Status
= ZwCreateKey(&hHalAcpiId
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
2714 ZwClose(hHalAcpiDevice
);
2715 if (!NT_SUCCESS(Status
))
2717 Status
= ZwSetValueKey(hHalAcpiId
, &DeviceDescU
, 0, REG_SZ
, HalAcpiDeviceDesc
.Buffer
, HalAcpiDeviceDesc
.MaximumLength
);
2718 if (NT_SUCCESS(Status
))
2719 Status
= ZwSetValueKey(hHalAcpiId
, &HardwareIDU
, 0, REG_MULTI_SZ
, HalAcpiHardwareID
.Buffer
, HalAcpiHardwareID
.MaximumLength
);
2720 if (NT_SUCCESS(Status
))
2722 InitializeObjectAttributes(&ObjectAttributes
, &LogConfU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, hHalAcpiId
, NULL
);
2723 Status
= ZwCreateKey(&hLogConf
, 0, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
2724 if (NT_SUCCESS(Status
))
2727 ZwClose(hHalAcpiId
);
2732 Status
= IopOpenRegistryKeyEx(&hEnum
, NULL
, &MultiKeyPathU
, KEY_ENUMERATE_SUB_KEYS
);
2733 if (!NT_SUCCESS(Status
))
2735 /* Nothing to do, don't return with an error status */
2736 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2738 return STATUS_SUCCESS
;
2740 Status
= IopEnumerateDetectedDevices(
2755 IopOpenRegistryKeyEx(PHANDLE KeyHandle
,
2757 PUNICODE_STRING Name
,
2758 ACCESS_MASK DesiredAccess
)
2760 OBJECT_ATTRIBUTES ObjectAttributes
;
2767 InitializeObjectAttributes(&ObjectAttributes
,
2769 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2773 Status
= ZwOpenKey(KeyHandle
, DesiredAccess
, &ObjectAttributes
);
2780 IopGetRegistryValue(IN HANDLE Handle
,
2782 OUT PKEY_VALUE_FULL_INFORMATION
*Information
)
2784 UNICODE_STRING ValueString
;
2786 PKEY_VALUE_FULL_INFORMATION FullInformation
;
2790 RtlInitUnicodeString(&ValueString
, ValueName
);
2792 Status
= ZwQueryValueKey(Handle
,
2794 KeyValueFullInformation
,
2798 if ((Status
!= STATUS_BUFFER_OVERFLOW
) &&
2799 (Status
!= STATUS_BUFFER_TOO_SMALL
))
2804 FullInformation
= ExAllocatePool(NonPagedPool
, Size
);
2805 if (!FullInformation
) return STATUS_INSUFFICIENT_RESOURCES
;
2807 Status
= ZwQueryValueKey(Handle
,
2809 KeyValueFullInformation
,
2813 if (!NT_SUCCESS(Status
))
2815 ExFreePool(FullInformation
);
2819 *Information
= FullInformation
;
2820 return STATUS_SUCCESS
;
2823 static NTSTATUS INIT_FUNCTION
2825 PnpDriverInitializeEmpty(IN
struct _DRIVER_OBJECT
*DriverObject
, IN PUNICODE_STRING RegistryPath
)
2827 return STATUS_SUCCESS
;
2836 DPRINT("PnpInit()\n");
2838 KeInitializeSpinLock(&IopDeviceTreeLock
);
2840 /* Initialize the Bus Type GUID List */
2841 IopBusTypeGuidList
= ExAllocatePool(PagedPool
, sizeof(IO_BUS_TYPE_GUID_LIST
));
2842 RtlZeroMemory(IopBusTypeGuidList
, sizeof(IO_BUS_TYPE_GUID_LIST
));
2843 ExInitializeFastMutex(&IopBusTypeGuidList
->Lock
);
2845 /* Initialize PnP-Event notification support */
2846 Status
= IopInitPlugPlayEvents();
2847 if (!NT_SUCCESS(Status
))
2849 DPRINT1("IopInitPlugPlayEvents() failed\n");
2850 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
2854 * Create root device node
2857 Status
= IopCreateDriver(NULL
, PnpDriverInitializeEmpty
, NULL
, 0, 0, &IopRootDriverObject
);
2858 if (!NT_SUCCESS(Status
))
2860 DPRINT1("IoCreateDriverObject() failed\n");
2861 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
2864 Status
= IoCreateDevice(IopRootDriverObject
, 0, NULL
, FILE_DEVICE_CONTROLLER
,
2866 if (!NT_SUCCESS(Status
))
2868 DPRINT1("IoCreateDevice() failed\n");
2869 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
2872 Status
= IopCreateDeviceNode(NULL
, Pdo
, NULL
, &IopRootDeviceNode
);
2873 if (!NT_SUCCESS(Status
))
2875 DPRINT1("Insufficient resources\n");
2876 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
2879 if (!RtlCreateUnicodeString(&IopRootDeviceNode
->InstancePath
,
2882 DPRINT1("Failed to create the instance path!\n");
2883 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED
, STATUS_NO_MEMORY
, 0, 0, 0);
2886 /* Report the device to the user-mode pnp manager */
2887 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL
,
2888 &IopRootDeviceNode
->InstancePath
);
2890 IopRootDeviceNode
->PhysicalDeviceObject
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
2891 PnpRootDriverEntry(IopRootDriverObject
, NULL
);
2892 IopRootDeviceNode
->PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
2893 IopRootDriverObject
->DriverExtension
->AddDevice(
2894 IopRootDriverObject
,
2895 IopRootDeviceNode
->PhysicalDeviceObject
);
2897 /* Move information about devices detected by Freeloader to SYSTEM\CurrentControlSet\Root\ */
2898 Status
= IopUpdateRootKey();
2899 if (!NT_SUCCESS(Status
))
2901 DPRINT1("IopUpdateRootKey() failed\n");
2902 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
2906 RTL_GENERIC_COMPARE_RESULTS
2908 PiCompareInstancePath(IN PRTL_AVL_TABLE Table
,
2909 IN PVOID FirstStruct
,
2910 IN PVOID SecondStruct
)
2918 // The allocation function is called by the generic table package whenever
2919 // it needs to allocate memory for the table.
2924 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table
,
2934 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table
,
2943 PpInitializeDeviceReferenceTable(VOID
)
2945 /* Setup the guarded mutex and AVL table */
2946 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock
);
2947 RtlInitializeGenericTableAvl(
2948 &PpDeviceReferenceTable
,
2949 (PRTL_AVL_COMPARE_ROUTINE
)PiCompareInstancePath
,
2950 (PRTL_AVL_ALLOCATE_ROUTINE
)PiAllocateGenericTableEntry
,
2951 (PRTL_AVL_FREE_ROUTINE
)PiFreeGenericTableEntry
,
2959 /* Initialize the resource when accessing device registry data */
2960 ExInitializeResourceLite(&PpRegistryDeviceResource
);
2962 /* Setup the device reference AVL table */
2963 PpInitializeDeviceReferenceTable();
2971 /* Check the initialization phase */
2972 switch (ExpInitializationPhase
)
2977 return PiInitPhase0();
2983 //return PiInitPhase1();
2987 /* Don't know any other phase! Bugcheck! */
2988 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL
);
2993 /* PUBLIC FUNCTIONS **********************************************************/
3000 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject
,
3001 IN DEVICE_REGISTRY_PROPERTY DeviceProperty
,
3002 IN ULONG BufferLength
,
3003 OUT PVOID PropertyBuffer
,
3004 OUT PULONG ResultLength
)
3006 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
3007 DEVICE_CAPABILITIES DeviceCaps
;
3013 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject
, DeviceProperty
);
3017 if (DeviceNode
== NULL
)
3018 return STATUS_INVALID_DEVICE_REQUEST
;
3020 switch (DeviceProperty
)
3022 case DevicePropertyBusNumber
:
3023 Length
= sizeof(ULONG
);
3024 Data
= &DeviceNode
->ChildBusNumber
;
3027 /* Complete, untested */
3028 case DevicePropertyBusTypeGuid
:
3030 if ((DeviceNode
->ChildBusTypeIndex
!= 0xFFFF) &&
3031 (DeviceNode
->ChildBusTypeIndex
< IopBusTypeGuidList
->GuidCount
))
3033 /* Return the GUID */
3034 *ResultLength
= sizeof(GUID
);
3036 /* Check if the buffer given was large enough */
3037 if (BufferLength
< *ResultLength
)
3039 return STATUS_BUFFER_TOO_SMALL
;
3043 RtlCopyMemory(PropertyBuffer
,
3044 &(IopBusTypeGuidList
->Guids
[DeviceNode
->ChildBusTypeIndex
]),
3046 return STATUS_SUCCESS
;
3050 return STATUS_OBJECT_NAME_NOT_FOUND
;
3054 case DevicePropertyLegacyBusType
:
3055 Length
= sizeof(INTERFACE_TYPE
);
3056 Data
= &DeviceNode
->ChildInterfaceType
;
3059 case DevicePropertyAddress
:
3060 /* Query the device caps */
3061 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCaps
);
3062 if (NT_SUCCESS(Status
) && (DeviceCaps
.Address
!= (ULONG
)-1))
3065 *ResultLength
= sizeof(ULONG
);
3067 /* Check if the buffer given was large enough */
3068 if (BufferLength
< *ResultLength
)
3070 return STATUS_BUFFER_TOO_SMALL
;
3073 /* Return address */
3074 *(PULONG
)PropertyBuffer
= DeviceCaps
.Address
;
3075 return STATUS_SUCCESS
;
3079 return STATUS_OBJECT_NAME_NOT_FOUND
;
3083 // case DevicePropertyUINumber:
3084 // if (DeviceNode->CapabilityFlags == NULL)
3085 // return STATUS_INVALID_DEVICE_REQUEST;
3086 // Length = sizeof(ULONG);
3087 // Data = &DeviceNode->CapabilityFlags->UINumber;
3090 case DevicePropertyClassName
:
3091 case DevicePropertyClassGuid
:
3092 case DevicePropertyDriverKeyName
:
3093 case DevicePropertyManufacturer
:
3094 case DevicePropertyFriendlyName
:
3095 case DevicePropertyHardwareID
:
3096 case DevicePropertyCompatibleIDs
:
3097 case DevicePropertyDeviceDescription
:
3098 case DevicePropertyLocationInformation
:
3099 case DevicePropertyUINumber
:
3101 LPCWSTR RegistryPropertyName
;
3102 UNICODE_STRING EnumRoot
= RTL_CONSTANT_STRING(ENUM_ROOT
);
3103 UNICODE_STRING ValueName
;
3104 KEY_VALUE_PARTIAL_INFORMATION
*ValueInformation
;
3105 ULONG ValueInformationLength
;
3106 HANDLE KeyHandle
, EnumRootHandle
;
3109 switch (DeviceProperty
)
3111 case DevicePropertyClassName
:
3112 RegistryPropertyName
= L
"Class"; break;
3113 case DevicePropertyClassGuid
:
3114 RegistryPropertyName
= L
"ClassGuid"; break;
3115 case DevicePropertyDriverKeyName
:
3116 RegistryPropertyName
= L
"Driver"; break;
3117 case DevicePropertyManufacturer
:
3118 RegistryPropertyName
= L
"Mfg"; break;
3119 case DevicePropertyFriendlyName
:
3120 RegistryPropertyName
= L
"FriendlyName"; break;
3121 case DevicePropertyHardwareID
:
3122 RegistryPropertyName
= L
"HardwareID"; break;
3123 case DevicePropertyCompatibleIDs
:
3124 RegistryPropertyName
= L
"CompatibleIDs"; break;
3125 case DevicePropertyDeviceDescription
:
3126 RegistryPropertyName
= L
"DeviceDesc"; break;
3127 case DevicePropertyLocationInformation
:
3128 RegistryPropertyName
= L
"LocationInformation"; break;
3129 case DevicePropertyUINumber
:
3130 RegistryPropertyName
= L
"UINumber"; break;
3132 /* Should not happen */
3134 return STATUS_UNSUCCESSFUL
;
3137 DPRINT("Registry property %S\n", RegistryPropertyName
);
3140 Status
= IopOpenRegistryKeyEx(&EnumRootHandle
, NULL
,
3141 &EnumRoot
, KEY_READ
);
3142 if (!NT_SUCCESS(Status
))
3144 DPRINT1("Error opening ENUM_ROOT, Status=0x%08x\n", Status
);
3148 /* Open instance key */
3149 Status
= IopOpenRegistryKeyEx(&KeyHandle
, EnumRootHandle
,
3150 &DeviceNode
->InstancePath
, KEY_READ
);
3151 if (!NT_SUCCESS(Status
))
3153 DPRINT1("Error opening InstancePath, Status=0x%08x\n", Status
);
3154 ZwClose(EnumRootHandle
);
3158 /* Allocate buffer to read as much data as required by the caller */
3159 ValueInformationLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
,
3160 Data
[0]) + BufferLength
;
3161 ValueInformation
= ExAllocatePool(PagedPool
, ValueInformationLength
);
3162 if (!ValueInformation
)
3165 return STATUS_INSUFFICIENT_RESOURCES
;
3168 /* Read the value */
3169 RtlInitUnicodeString(&ValueName
, RegistryPropertyName
);
3170 Status
= ZwQueryValueKey(KeyHandle
, &ValueName
,
3171 KeyValuePartialInformation
, ValueInformation
,
3172 ValueInformationLength
,
3173 &ValueInformationLength
);
3177 *ResultLength
= ValueInformation
->DataLength
;
3179 if (!NT_SUCCESS(Status
))
3181 ExFreePool(ValueInformation
);
3182 if (Status
== STATUS_BUFFER_OVERFLOW
)
3183 return STATUS_BUFFER_TOO_SMALL
;
3184 DPRINT1("Problem: Status=0x%08x, ResultLength = %d\n", Status
, *ResultLength
);
3188 /* FIXME: Verify the value (NULL-terminated, correct format). */
3189 RtlCopyMemory(PropertyBuffer
, ValueInformation
->Data
,
3190 ValueInformation
->DataLength
);
3191 ExFreePool(ValueInformation
);
3193 return STATUS_SUCCESS
;
3196 case DevicePropertyBootConfiguration
:
3198 if (DeviceNode
->BootResources
->Count
!= 0)
3200 Length
= CM_RESOURCE_LIST_SIZE(DeviceNode
->BootResources
);
3202 Data
= &DeviceNode
->BootResources
;
3205 /* FIXME: use a translated boot configuration instead */
3206 case DevicePropertyBootConfigurationTranslated
:
3208 if (DeviceNode
->BootResources
->Count
!= 0)
3210 Length
= CM_RESOURCE_LIST_SIZE(DeviceNode
->BootResources
);
3212 Data
= &DeviceNode
->BootResources
;
3215 case DevicePropertyEnumeratorName
:
3216 /* A buffer overflow can't happen here, since InstancePath
3217 * always contains the enumerator name followed by \\ */
3218 Ptr
= wcschr(DeviceNode
->InstancePath
.Buffer
, L
'\\');
3220 Length
= (Ptr
- DeviceNode
->InstancePath
.Buffer
+ 1) * sizeof(WCHAR
);
3221 Data
= DeviceNode
->InstancePath
.Buffer
;
3224 case DevicePropertyPhysicalDeviceObjectName
:
3225 /* InstancePath buffer is NULL terminated, so we can do this */
3226 Length
= DeviceNode
->InstancePath
.MaximumLength
;
3227 Data
= DeviceNode
->InstancePath
.Buffer
;
3231 return STATUS_INVALID_PARAMETER_2
;
3234 /* Prepare returned values */
3235 *ResultLength
= Length
;
3236 if (BufferLength
< Length
)
3237 return STATUS_BUFFER_TOO_SMALL
;
3238 RtlCopyMemory(PropertyBuffer
, Data
, Length
);
3240 /* NULL terminate the string (if required) */
3241 if (DeviceProperty
== DevicePropertyEnumeratorName
)
3242 ((LPWSTR
)PropertyBuffer
)[Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3244 return STATUS_SUCCESS
;
3252 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject
)
3258 * @name IoOpenDeviceRegistryKey
3260 * Open a registry key unique for a specified driver or device instance.
3262 * @param DeviceObject Device to get the registry key for.
3263 * @param DevInstKeyType Type of the key to return.
3264 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
3265 * @param DevInstRegKey Handle to the opened registry key on
3266 * successful return.
3274 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject
,
3275 IN ULONG DevInstKeyType
,
3276 IN ACCESS_MASK DesiredAccess
,
3277 OUT PHANDLE DevInstRegKey
)
3279 static WCHAR RootKeyName
[] =
3280 L
"\\Registry\\Machine\\System\\CurrentControlSet\\";
3281 static WCHAR ProfileKeyName
[] =
3282 L
"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
3283 static WCHAR ClassKeyName
[] = L
"Control\\Class\\";
3284 static WCHAR EnumKeyName
[] = L
"Enum\\";
3285 static WCHAR DeviceParametersKeyName
[] = L
"Device Parameters";
3286 ULONG KeyNameLength
;
3287 LPWSTR KeyNameBuffer
;
3288 UNICODE_STRING KeyName
;
3289 ULONG DriverKeyLength
;
3290 OBJECT_ATTRIBUTES ObjectAttributes
;
3291 PDEVICE_NODE DeviceNode
= NULL
;
3294 DPRINT("IoOpenDeviceRegistryKey() called\n");
3296 if ((DevInstKeyType
& (PLUGPLAY_REGKEY_DEVICE
| PLUGPLAY_REGKEY_DRIVER
)) == 0)
3298 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
3299 return STATUS_INVALID_PARAMETER
;
3303 * Calculate the length of the base key name. This is the full
3304 * name for driver key or the name excluding "Device Parameters"
3305 * subkey for device key.
3308 KeyNameLength
= sizeof(RootKeyName
);
3309 if (DevInstKeyType
& PLUGPLAY_REGKEY_CURRENT_HWPROFILE
)
3310 KeyNameLength
+= sizeof(ProfileKeyName
) - sizeof(UNICODE_NULL
);
3311 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
3313 KeyNameLength
+= sizeof(ClassKeyName
) - sizeof(UNICODE_NULL
);
3314 Status
= IoGetDeviceProperty(DeviceObject
, DevicePropertyDriverKeyName
,
3315 0, NULL
, &DriverKeyLength
);
3316 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
3318 KeyNameLength
+= DriverKeyLength
;
3322 DeviceNode
= IopGetDeviceNode(DeviceObject
);
3323 KeyNameLength
+= sizeof(EnumKeyName
) - sizeof(UNICODE_NULL
) +
3324 DeviceNode
->InstancePath
.Length
;
3328 * Now allocate the buffer for the key name...
3331 KeyNameBuffer
= ExAllocatePool(PagedPool
, KeyNameLength
);
3332 if (KeyNameBuffer
== NULL
)
3333 return STATUS_INSUFFICIENT_RESOURCES
;
3336 KeyName
.MaximumLength
= (USHORT
)KeyNameLength
;
3337 KeyName
.Buffer
= KeyNameBuffer
;
3340 * ...and build the key name.
3343 KeyName
.Length
+= sizeof(RootKeyName
) - sizeof(UNICODE_NULL
);
3344 RtlCopyMemory(KeyNameBuffer
, RootKeyName
, KeyName
.Length
);
3346 if (DevInstKeyType
& PLUGPLAY_REGKEY_CURRENT_HWPROFILE
)
3347 RtlAppendUnicodeToString(&KeyName
, ProfileKeyName
);
3349 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
3351 RtlAppendUnicodeToString(&KeyName
, ClassKeyName
);
3352 Status
= IoGetDeviceProperty(DeviceObject
, DevicePropertyDriverKeyName
,
3353 DriverKeyLength
, KeyNameBuffer
+
3354 (KeyName
.Length
/ sizeof(WCHAR
)),
3356 if (!NT_SUCCESS(Status
))
3358 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status
);
3359 ExFreePool(KeyNameBuffer
);
3362 KeyName
.Length
+= (USHORT
)DriverKeyLength
- sizeof(UNICODE_NULL
);
3366 RtlAppendUnicodeToString(&KeyName
, EnumKeyName
);
3367 Status
= RtlAppendUnicodeStringToString(&KeyName
, &DeviceNode
->InstancePath
);
3368 if (DeviceNode
->InstancePath
.Length
== 0)
3370 ExFreePool(KeyNameBuffer
);
3376 * Open the base key.
3378 Status
= IopOpenRegistryKeyEx(DevInstRegKey
, NULL
, &KeyName
, DesiredAccess
);
3379 if (!NT_SUCCESS(Status
))
3381 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName
, Status
);
3382 ExFreePool(KeyNameBuffer
);
3385 ExFreePool(KeyNameBuffer
);
3388 * For driver key we're done now.
3391 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
3395 * Let's go further. For device key we must open "Device Parameters"
3396 * subkey and create it if it doesn't exist yet.
3399 RtlInitUnicodeString(&KeyName
, DeviceParametersKeyName
);
3400 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
,
3401 OBJ_CASE_INSENSITIVE
, *DevInstRegKey
, NULL
);
3402 Status
= ZwCreateKey(DevInstRegKey
, DesiredAccess
, &ObjectAttributes
,
3403 0, NULL
, REG_OPTION_NON_VOLATILE
, NULL
);
3404 ZwClose(ObjectAttributes
.RootDirectory
);
3414 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject
)
3424 IoInvalidateDeviceRelations(
3425 IN PDEVICE_OBJECT DeviceObject
,
3426 IN DEVICE_RELATION_TYPE Type
)
3428 PIO_WORKITEM WorkItem
;
3429 PINVALIDATE_DEVICE_RELATION_DATA Data
;
3431 Data
= ExAllocatePool(PagedPool
, sizeof(INVALIDATE_DEVICE_RELATION_DATA
));
3434 WorkItem
= IoAllocateWorkItem(DeviceObject
);
3441 ObReferenceObject(DeviceObject
);
3442 Data
->DeviceObject
= DeviceObject
;
3444 Data
->WorkItem
= WorkItem
;
3448 IopAsynchronousInvalidateDeviceRelations
,
3458 IoSynchronousInvalidateDeviceRelations(
3459 IN PDEVICE_OBJECT DeviceObject
,
3460 IN DEVICE_RELATION_TYPE Type
)
3467 /* Enumerate the device */
3468 return IopEnumerateDevice(DeviceObject
);
3469 case PowerRelations
:
3470 /* Not handled yet */
3471 return STATUS_NOT_IMPLEMENTED
;
3472 case TargetDeviceRelation
:
3474 return STATUS_SUCCESS
;
3476 /* Ejection relations are not supported */
3477 return STATUS_NOT_SUPPORTED
;