1 /* $Id: pnpmgr.c,v 1.36 2004/10/11 18:36:20 navaraf Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/pnpmgr/pnpmgr.c
6 * PURPOSE: Initializes the PnP manager
7 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
9 * 16/04/2001 CSH Created
12 /* INCLUDES ******************************************************************/
15 #include <ole32/guiddef.h>
17 DEFINE_GUID(GUID_CLASS_COMPORT
, 0x86e0d1e0L
, 0x8089, 0x11d0, 0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73);
18 DEFINE_GUID(GUID_SERENUM_BUS_ENUMERATOR
, 0x4D36E978L
, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18);
22 #include <internal/debug.h>
25 /* GLOBALS *******************************************************************/
27 PDEVICE_NODE IopRootDeviceNode
;
28 KSPIN_LOCK IopDeviceTreeLock
;
30 /* DATA **********************************************************************/
32 PDRIVER_OBJECT IopRootDriverObject
;
34 /* FUNCTIONS *****************************************************************/
41 IoAdjustPagingPathCount(
52 IoInvalidateDeviceRelations(
53 IN PDEVICE_OBJECT DeviceObject
,
54 IN DEVICE_RELATION_TYPE Type
)
60 PDEVICE_OBJECT DeviceObject
)
62 return DeviceObject
->DeviceObjectExtension
->DeviceNode
;
71 IN PDEVICE_OBJECT DeviceObject
,
72 IN DEVICE_REGISTRY_PROPERTY DeviceProperty
,
73 IN ULONG BufferLength
,
74 OUT PVOID PropertyBuffer
,
75 OUT PULONG ResultLength
)
77 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
81 DPRINT("IoGetDeviceProperty called\n");
83 if (DeviceNode
== NULL
)
84 return STATUS_INVALID_DEVICE_REQUEST
;
86 switch (DeviceProperty
)
88 case DevicePropertyBusNumber
:
89 if (DeviceNode
->BusInformation
== NULL
)
90 return STATUS_INVALID_DEVICE_REQUEST
;
91 Length
= sizeof(ULONG
);
92 Data
= &DeviceNode
->BusInformation
->BusNumber
;
95 /* Complete, untested */
96 case DevicePropertyBusTypeGuid
:
97 if (DeviceNode
->BusInformation
== NULL
)
98 return STATUS_INVALID_DEVICE_REQUEST
;
99 *ResultLength
= 39 * sizeof(WCHAR
);
100 if (BufferLength
< (39 * sizeof(WCHAR
)))
101 return STATUS_BUFFER_TOO_SMALL
;
102 swprintf((PWSTR
)PropertyBuffer
,
103 L
"{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
104 DeviceNode
->BusInformation
->BusTypeGuid
.Data1
,
105 DeviceNode
->BusInformation
->BusTypeGuid
.Data2
,
106 DeviceNode
->BusInformation
->BusTypeGuid
.Data3
,
107 DeviceNode
->BusInformation
->BusTypeGuid
.Data4
[0],
108 DeviceNode
->BusInformation
->BusTypeGuid
.Data4
[1],
109 DeviceNode
->BusInformation
->BusTypeGuid
.Data4
[2],
110 DeviceNode
->BusInformation
->BusTypeGuid
.Data4
[3],
111 DeviceNode
->BusInformation
->BusTypeGuid
.Data4
[4],
112 DeviceNode
->BusInformation
->BusTypeGuid
.Data4
[5],
113 DeviceNode
->BusInformation
->BusTypeGuid
.Data4
[6],
114 DeviceNode
->BusInformation
->BusTypeGuid
.Data4
[7]);
115 return STATUS_SUCCESS
;
117 case DevicePropertyLegacyBusType
:
118 if (DeviceNode
->BusInformation
== NULL
)
119 return STATUS_INVALID_DEVICE_REQUEST
;
120 Length
= sizeof(INTERFACE_TYPE
);
121 Data
= &DeviceNode
->BusInformation
->LegacyBusType
;
124 case DevicePropertyAddress
:
125 if (DeviceNode
->CapabilityFlags
== NULL
)
126 return STATUS_INVALID_DEVICE_REQUEST
;
127 Length
= sizeof(ULONG
);
128 Data
= &DeviceNode
->CapabilityFlags
->Address
;
131 case DevicePropertyUINumber
:
132 if (DeviceNode
->CapabilityFlags
== NULL
)
133 return STATUS_INVALID_DEVICE_REQUEST
;
134 Length
= sizeof(ULONG
);
135 Data
= &DeviceNode
->CapabilityFlags
->UINumber
;
138 case DevicePropertyClassName
:
139 case DevicePropertyClassGuid
:
140 case DevicePropertyDriverKeyName
:
141 case DevicePropertyManufacturer
:
142 case DevicePropertyFriendlyName
:
144 LPWSTR RegistryPropertyName
, KeyNameBuffer
;
145 UNICODE_STRING KeyName
, ValueName
;
146 OBJECT_ATTRIBUTES ObjectAttributes
;
147 KEY_VALUE_PARTIAL_INFORMATION
*ValueInformation
;
148 ULONG ValueInformationLength
;
152 switch (DeviceProperty
)
154 case DevicePropertyClassName
:
155 RegistryPropertyName
= L
"Class"; break;
156 case DevicePropertyClassGuid
:
157 RegistryPropertyName
= L
"ClassGuid"; break;
158 case DevicePropertyDriverKeyName
:
159 RegistryPropertyName
= L
"Driver"; break;
160 case DevicePropertyManufacturer
:
161 RegistryPropertyName
= L
"Mfg"; break;
162 case DevicePropertyFriendlyName
:
163 RegistryPropertyName
= L
"FriendlyName"; break;
165 RegistryPropertyName
= NULL
; break;
168 KeyNameBuffer
= ExAllocatePool(PagedPool
,
169 (49 * sizeof(WCHAR
)) + DeviceNode
->InstancePath
.Length
);
170 if (KeyNameBuffer
== NULL
)
171 return STATUS_INSUFFICIENT_RESOURCES
;
173 wcscpy(KeyNameBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
174 wcscat(KeyNameBuffer
, DeviceNode
->InstancePath
.Buffer
);
176 RtlInitUnicodeString(&KeyName
, KeyNameBuffer
);
177 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
,
178 OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
180 Status
= ZwOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
181 ExFreePool(KeyNameBuffer
);
182 if (!NT_SUCCESS(Status
))
185 RtlInitUnicodeString(&ValueName
, RegistryPropertyName
);
186 ValueInformationLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
,
187 Data
[0]) + BufferLength
;
188 ValueInformation
= ExAllocatePool(PagedPool
, ValueInformationLength
);
189 if (ValueInformation
== NULL
)
192 return STATUS_INSUFFICIENT_RESOURCES
;
195 Status
= ZwQueryValueKey(KeyHandle
, &ValueName
,
196 KeyValuePartialInformation
, ValueInformation
,
197 ValueInformationLength
,
198 &ValueInformationLength
);
199 *ResultLength
= ValueInformation
->DataLength
;
202 if (ValueInformation
->DataLength
> BufferLength
)
203 Status
= STATUS_BUFFER_TOO_SMALL
;
205 if (!NT_SUCCESS(Status
))
207 ExFreePool(ValueInformation
);
211 /* FIXME: Verify the value (NULL-terminated, correct format). */
213 RtlCopyMemory(PropertyBuffer
, ValueInformation
->Data
,
214 ValueInformation
->DataLength
);
215 ExFreePool(ValueInformation
);
217 return STATUS_SUCCESS
;
220 case DevicePropertyBootConfiguration
:
221 case DevicePropertyBootConfigurationTranslated
:
222 case DevicePropertyCompatibleIDs
:
223 case DevicePropertyDeviceDescription
:
224 case DevicePropertyEnumeratorName
:
225 case DevicePropertyHardwareID
:
226 case DevicePropertyLocationInformation
:
227 case DevicePropertyPhysicalDeviceObjectName
:
228 return STATUS_NOT_IMPLEMENTED
;
231 return STATUS_INVALID_PARAMETER_2
;
234 *ResultLength
= Length
;
235 if (BufferLength
< Length
)
236 return STATUS_BUFFER_TOO_SMALL
;
237 RtlCopyMemory(PropertyBuffer
, Data
, Length
);
239 return STATUS_SUCCESS
;
247 IoInvalidateDeviceState(
248 IN PDEVICE_OBJECT PhysicalDeviceObject
)
257 IoOpenDeviceRegistryKey(
258 IN PDEVICE_OBJECT DeviceObject
,
259 IN ULONG DevInstKeyType
,
260 IN ACCESS_MASK DesiredAccess
,
261 OUT PHANDLE DevInstRegKey
)
263 static const WCHAR ClassKeyName
[] = {
264 '\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
265 'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t',
266 'r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\',
267 'C','l','a','s','s','\\'};
268 LPWSTR KeyNameBuffer
;
269 UNICODE_STRING KeyName
;
270 ULONG DriverKeyLength
;
271 OBJECT_ATTRIBUTES ObjectAttributes
;
274 if (DevInstKeyType
== PLUGPLAY_REGKEY_DRIVER
)
276 Status
= IoGetDeviceProperty(DeviceObject
, DevicePropertyDriverKeyName
,
277 0, NULL
, &DriverKeyLength
);
278 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
281 KeyNameBuffer
= ExAllocatePool(PagedPool
, DriverKeyLength
+ sizeof(ClassKeyName
));
282 if (KeyNameBuffer
== NULL
)
283 return STATUS_INSUFFICIENT_RESOURCES
;
285 RtlCopyMemory(KeyNameBuffer
, ClassKeyName
, sizeof(ClassKeyName
));
286 Status
= IoGetDeviceProperty(DeviceObject
, DevicePropertyDriverKeyName
,
287 DriverKeyLength
, KeyNameBuffer
+
288 (sizeof(ClassKeyName
) / sizeof(WCHAR
)),
290 if (!NT_SUCCESS(Status
))
292 ExFreePool(KeyNameBuffer
);
296 RtlInitUnicodeString(&KeyName
, KeyNameBuffer
);
297 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
,
298 OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
299 Status
= ZwOpenKey(DevInstRegKey
, DesiredAccess
, &ObjectAttributes
);
300 ExFreePool(KeyNameBuffer
);
304 return STATUS_NOT_IMPLEMENTED
;
312 IoRequestDeviceEject(
313 IN PDEVICE_OBJECT PhysicalDeviceObject
321 IopCreateUnicodeString(
322 PUNICODE_STRING Destination
,
330 RtlInitUnicodeString(Destination
, NULL
);
334 Length
= (wcslen(Source
) + 1) * sizeof(WCHAR
);
336 Destination
->Buffer
= ExAllocatePool(PoolType
, Length
);
338 if (Destination
->Buffer
== NULL
)
343 RtlCopyMemory(Destination
->Buffer
, Source
, Length
);
345 Destination
->MaximumLength
= Length
;
347 Destination
->Length
= Length
- sizeof(WCHAR
);
353 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT
*DeviceObject
)
357 if (PopSystemPowerDeviceNode
)
359 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
360 *DeviceObject
= PopSystemPowerDeviceNode
->Pdo
;
361 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
363 return STATUS_SUCCESS
;
366 return STATUS_UNSUCCESSFUL
;
369 /**********************************************************************
371 * Creates a device node
374 * ParentNode = Pointer to parent device node
375 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
376 * to have the root device node create one
377 * (eg. for legacy drivers)
378 * DeviceNode = Pointer to storage for created device node
384 IopCreateDeviceNode(PDEVICE_NODE ParentNode
,
385 PDEVICE_OBJECT PhysicalDeviceObject
,
386 PDEVICE_NODE
*DeviceNode
)
392 DPRINT("ParentNode %x PhysicalDeviceObject %x\n",
393 ParentNode
, PhysicalDeviceObject
);
395 Node
= (PDEVICE_NODE
)ExAllocatePool(PagedPool
, sizeof(DEVICE_NODE
));
398 return STATUS_INSUFFICIENT_RESOURCES
;
401 RtlZeroMemory(Node
, sizeof(DEVICE_NODE
));
403 if (!PhysicalDeviceObject
)
405 Status
= PnpRootCreateDevice(&PhysicalDeviceObject
);
406 if (!NT_SUCCESS(Status
))
412 /* This is for drivers passed on the command line to ntoskrnl.exe */
413 IopDeviceNodeSetFlag(Node
, DNF_STARTED
);
414 IopDeviceNodeSetFlag(Node
, DNF_LEGACY_DRIVER
);
417 Node
->Pdo
= PhysicalDeviceObject
;
419 PhysicalDeviceObject
->DeviceObjectExtension
->DeviceNode
= Node
;
423 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
424 Node
->Parent
= ParentNode
;
425 Node
->NextSibling
= ParentNode
->Child
;
426 if (ParentNode
->Child
!= NULL
)
428 ParentNode
->Child
->PrevSibling
= Node
;
430 ParentNode
->Child
= Node
;
431 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
436 return STATUS_SUCCESS
;
440 IopFreeDeviceNode(PDEVICE_NODE DeviceNode
)
444 /* All children must be deleted before a parent is deleted */
445 assert(!DeviceNode
->Child
);
447 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
449 assert(DeviceNode
->Pdo
);
451 ObDereferenceObject(DeviceNode
->Pdo
);
453 /* Unlink from parent if it exists */
455 if ((DeviceNode
->Parent
) && (DeviceNode
->Parent
->Child
== DeviceNode
))
457 DeviceNode
->Parent
->Child
= DeviceNode
->NextSibling
;
460 /* Unlink from sibling list */
462 if (DeviceNode
->PrevSibling
)
464 DeviceNode
->PrevSibling
->NextSibling
= DeviceNode
->NextSibling
;
467 if (DeviceNode
->NextSibling
)
469 DeviceNode
->NextSibling
->PrevSibling
= DeviceNode
->PrevSibling
;
472 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
474 RtlFreeUnicodeString(&DeviceNode
->InstancePath
);
476 RtlFreeUnicodeString(&DeviceNode
->ServiceName
);
478 if (DeviceNode
->CapabilityFlags
)
480 ExFreePool(DeviceNode
->CapabilityFlags
);
483 if (DeviceNode
->CmResourceList
)
485 ExFreePool(DeviceNode
->CmResourceList
);
488 if (DeviceNode
->BootResourcesList
)
490 ExFreePool(DeviceNode
->BootResourcesList
);
493 if (DeviceNode
->ResourceRequirementsList
)
495 ExFreePool(DeviceNode
->ResourceRequirementsList
);
498 RtlFreeUnicodeString(&DeviceNode
->DeviceID
);
500 RtlFreeUnicodeString(&DeviceNode
->InstanceID
);
502 RtlFreeUnicodeString(&DeviceNode
->HardwareIDs
);
504 RtlFreeUnicodeString(&DeviceNode
->CompatibleIDs
);
506 RtlFreeUnicodeString(&DeviceNode
->DeviceText
);
508 RtlFreeUnicodeString(&DeviceNode
->DeviceTextLocation
);
510 if (DeviceNode
->BusInformation
)
512 ExFreePool(DeviceNode
->BusInformation
);
515 ExFreePool(DeviceNode
);
517 return STATUS_SUCCESS
;
522 PDEVICE_OBJECT DeviceObject
,
523 PIO_STATUS_BLOCK IoStatusBlock
,
525 PIO_STACK_LOCATION Stack OPTIONAL
)
527 PDEVICE_OBJECT TopDeviceObject
;
528 PIO_STACK_LOCATION IrpSp
;
533 /* Always call the top of the device stack */
534 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
541 /* PNP IRPs are always initialized with a status code of
542 STATUS_NOT_IMPLEMENTED */
543 IoStatusBlock
->Status
= STATUS_NOT_IMPLEMENTED
;
544 IoStatusBlock
->Information
= 0;
546 Irp
= IoBuildSynchronousFsdRequest(
555 IrpSp
= IoGetNextIrpStackLocation(Irp
);
556 IrpSp
->MinorFunction
= MinorFunction
;
563 sizeof(Stack
->Parameters
));
566 Status
= IoCallDriver(TopDeviceObject
, Irp
);
567 if (Status
== STATUS_PENDING
)
569 KeWaitForSingleObject(
575 Status
= IoStatusBlock
->Status
;
578 ObDereferenceObject(TopDeviceObject
);
585 IopQueryCapabilities(
587 PDEVICE_CAPABILITIES
*Capabilities
)
589 IO_STATUS_BLOCK IoStatusBlock
;
590 PDEVICE_CAPABILITIES Caps
;
591 IO_STACK_LOCATION Stack
;
594 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack\n");
596 *Capabilities
= NULL
;
598 Caps
= ExAllocatePool(PagedPool
, sizeof(DEVICE_CAPABILITIES
));
601 return STATUS_INSUFFICIENT_RESOURCES
;
604 RtlZeroMemory(Caps
, sizeof(DEVICE_CAPABILITIES
));
605 Caps
->Size
= sizeof(DEVICE_CAPABILITIES
);
610 Stack
.Parameters
.DeviceCapabilities
.Capabilities
= Caps
;
612 Status
= IopInitiatePnpIrp(
615 IRP_MN_QUERY_CAPABILITIES
,
617 if (NT_SUCCESS(Status
))
619 *Capabilities
= Caps
;
623 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
631 IopTraverseDeviceTreeNode(
632 PDEVICETREE_TRAVERSE_CONTEXT Context
)
634 PDEVICE_NODE ParentDeviceNode
;
635 PDEVICE_NODE ChildDeviceNode
;
638 /* Copy context data so we don't overwrite it in subsequent calls to this function */
639 ParentDeviceNode
= Context
->DeviceNode
;
641 /* Call the action routine */
642 Status
= (Context
->Action
)(ParentDeviceNode
, Context
->Context
);
643 if (!NT_SUCCESS(Status
))
648 /* Traversal of all children nodes */
649 for (ChildDeviceNode
= ParentDeviceNode
->Child
;
650 ChildDeviceNode
!= NULL
;
651 ChildDeviceNode
= ChildDeviceNode
->NextSibling
)
653 /* Pass the current device node to the action routine */
654 Context
->DeviceNode
= ChildDeviceNode
;
656 Status
= IopTraverseDeviceTreeNode(Context
);
657 if (!NT_SUCCESS(Status
))
668 IopTraverseDeviceTree(
669 PDEVICETREE_TRAVERSE_CONTEXT Context
)
673 DPRINT("Context %x\n", Context
);
675 DPRINT("IopTraverseDeviceTree(DeviceNode %x FirstDeviceNode %x Action %x Context %x)\n",
676 Context
->DeviceNode
, Context
->FirstDeviceNode
, Context
->Action
, Context
->Context
);
678 /* Start from the specified device node */
679 Context
->DeviceNode
= Context
->FirstDeviceNode
;
681 /* Recursively traverse the device tree */
682 Status
= IopTraverseDeviceTreeNode(Context
);
683 if (Status
== STATUS_UNSUCCESSFUL
)
685 /* The action routine just wanted to terminate the traversal with status
686 code STATUS_SUCCESS */
687 Status
= STATUS_SUCCESS
;
695 IopCreateDeviceKeyPath(PWSTR Path
)
697 OBJECT_ATTRIBUTES ObjectAttributes
;
698 WCHAR KeyBuffer
[MAX_PATH
];
699 UNICODE_STRING KeyName
;
705 if (_wcsnicmp(Path
, L
"\\Registry\\", 10) != 0)
707 return STATUS_INVALID_PARAMETER
;
710 wcsncpy (KeyBuffer
, Path
, MAX_PATH
-1);
711 RtlInitUnicodeString (&KeyName
, KeyBuffer
);
713 /* Skip \\Registry\\ */
714 Current
= KeyName
.Buffer
;
715 Current
= wcschr (Current
, '\\') + 1;
716 Current
= wcschr (Current
, '\\') + 1;
720 Next
= wcschr (Current
, '\\');
730 InitializeObjectAttributes (&ObjectAttributes
,
732 OBJ_CASE_INSENSITIVE
,
736 DPRINT("Create '%S'\n", KeyName
.Buffer
);
738 Status
= NtCreateKey (&KeyHandle
,
745 if (!NT_SUCCESS (Status
))
747 DPRINT ("NtCreateKey() failed with status %x\n", Status
);
760 while (Next
!= NULL
);
762 return STATUS_SUCCESS
;
767 * IopActionInterrogateDeviceStack
769 * Retrieve information for all (direct) child nodes of a parent node.
773 * Pointer to device node.
775 * Pointer to parent node to retrieve child node information for.
778 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
779 * when we reach a device node which is not a direct child of the device
780 * node for which we retrieve information of child nodes for. Any errors
781 * that occur is logged instead so that all child services have a chance
782 * of being interrogated.
786 IopActionInterrogateDeviceStack(
787 PDEVICE_NODE DeviceNode
,
790 IO_STATUS_BLOCK IoStatusBlock
;
791 PDEVICE_NODE ParentDeviceNode
;
792 WCHAR InstancePath
[MAX_PATH
];
793 IO_STACK_LOCATION Stack
;
800 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode
, Context
);
801 DPRINT("PDO %x\n", DeviceNode
->Pdo
);
803 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
806 * We are called for the parent too, but we don't need to do special
807 * handling for this node
810 if (DeviceNode
== ParentDeviceNode
)
813 return STATUS_SUCCESS
;
817 * Make sure this device node is a direct child of the parent device node
818 * that is given as an argument
821 if (DeviceNode
->Parent
!= ParentDeviceNode
)
823 /* Stop the traversal immediately and indicate successful operation */
825 return STATUS_UNSUCCESSFUL
;
829 * FIXME: For critical errors, cleanup and disable device, but always
830 * return STATUS_SUCCESS.
833 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
835 Stack
.Parameters
.QueryId
.IdType
= BusQueryDeviceID
;
836 Status
= IopInitiatePnpIrp(
841 if (NT_SUCCESS(Status
))
843 RtlInitUnicodeString(
844 &DeviceNode
->DeviceID
,
845 (PWSTR
)IoStatusBlock
.Information
);
848 * FIXME: Check for valid characters, if there is invalid characters
854 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
855 RtlInitUnicodeString(&DeviceNode
->DeviceID
, NULL
);
858 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
860 Stack
.Parameters
.QueryId
.IdType
= BusQueryInstanceID
;
861 Status
= IopInitiatePnpIrp(
866 if (NT_SUCCESS(Status
))
868 RtlInitUnicodeString(
869 &DeviceNode
->InstanceID
,
870 (PWSTR
)IoStatusBlock
.Information
);
873 * FIXME: Check for valid characters, if there is invalid characters
879 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
880 RtlInitUnicodeString(&DeviceNode
->InstanceID
, NULL
);
883 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
885 Stack
.Parameters
.QueryId
.IdType
= BusQueryHardwareIDs
;
886 Status
= IopInitiatePnpIrp(
891 if (NT_SUCCESS(Status
))
894 * FIXME: Check for valid characters, if there is invalid characters
898 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
899 DPRINT("Hardware IDs:\n");
902 DPRINT(" %S\n", Ptr
);
903 Length
= wcslen(Ptr
) + 1;
906 TotalLength
+= Length
;
908 DPRINT("TotalLength: %hu\n", TotalLength
);
911 DeviceNode
->HardwareIDs
.Length
= TotalLength
* sizeof(WCHAR
);
912 DeviceNode
->HardwareIDs
.MaximumLength
= DeviceNode
->HardwareIDs
.Length
+ sizeof(WCHAR
);
913 DeviceNode
->HardwareIDs
.Buffer
= (PWSTR
)IoStatusBlock
.Information
;
917 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
918 RtlInitUnicodeString(&DeviceNode
->HardwareIDs
, NULL
);
921 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
923 Stack
.Parameters
.QueryId
.IdType
= BusQueryCompatibleIDs
;
924 Status
= IopInitiatePnpIrp(
929 if (NT_SUCCESS(Status
))
932 * FIXME: Check for valid characters, if there is invalid characters
936 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
937 DPRINT("Compatible IDs:\n");
940 DPRINT(" %S\n", Ptr
);
941 Length
= wcslen(Ptr
) + 1;
944 TotalLength
+= Length
;
946 DPRINT("TotalLength: %hu\n", TotalLength
);
949 DeviceNode
->CompatibleIDs
.Length
= TotalLength
* sizeof(WCHAR
);
950 DeviceNode
->CompatibleIDs
.MaximumLength
= DeviceNode
->CompatibleIDs
.Length
+ sizeof(WCHAR
);
951 DeviceNode
->CompatibleIDs
.Buffer
= (PWSTR
)IoStatusBlock
.Information
;
955 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
956 RtlInitUnicodeString(&DeviceNode
->CompatibleIDs
, NULL
);
959 Status
= IopQueryCapabilities(DeviceNode
->Pdo
, &DeviceNode
->CapabilityFlags
);
960 if (NT_SUCCESS(Status
))
967 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
969 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextDescription
;
970 Stack
.Parameters
.QueryDeviceText
.LocaleId
= 0; /* FIXME */
971 Status
= IopInitiatePnpIrp(
974 IRP_MN_QUERY_DEVICE_TEXT
,
976 if (NT_SUCCESS(Status
))
978 RtlInitUnicodeString(
979 &DeviceNode
->DeviceText
,
980 (PWSTR
)IoStatusBlock
.Information
);
984 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
985 RtlInitUnicodeString(&DeviceNode
->DeviceText
, NULL
);
988 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
990 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextLocationInformation
;
991 Stack
.Parameters
.QueryDeviceText
.LocaleId
= 0; // FIXME
992 Status
= IopInitiatePnpIrp(
995 IRP_MN_QUERY_DEVICE_TEXT
,
997 if (NT_SUCCESS(Status
))
999 RtlInitUnicodeString(
1000 &DeviceNode
->DeviceTextLocation
,
1001 (PWSTR
)IoStatusBlock
.Information
);
1005 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1006 RtlInitUnicodeString(&DeviceNode
->DeviceTextLocation
, NULL
);
1009 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
1011 Status
= IopInitiatePnpIrp(
1014 IRP_MN_QUERY_BUS_INFORMATION
,
1016 if (NT_SUCCESS(Status
))
1018 DeviceNode
->BusInformation
=
1019 (PPNP_BUS_INFORMATION
)IoStatusBlock
.Information
;
1023 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1024 DeviceNode
->BusInformation
= NULL
;
1027 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
1029 Status
= IopInitiatePnpIrp(
1032 IRP_MN_QUERY_RESOURCES
,
1034 if (NT_SUCCESS(Status
))
1036 DeviceNode
->BootResourcesList
=
1037 (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
1038 DeviceNode
->Flags
|= DNF_HAS_BOOT_CONFIG
;
1042 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1043 DeviceNode
->BootResourcesList
= NULL
;
1046 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
1048 Status
= IopInitiatePnpIrp(
1051 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
1053 if (NT_SUCCESS(Status
))
1055 DeviceNode
->ResourceRequirementsList
=
1056 (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
1060 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1061 DeviceNode
->ResourceRequirementsList
= NULL
;
1065 * Assemble the instance path for the device
1068 wcscpy(InstancePath
, DeviceNode
->DeviceID
.Buffer
);
1069 wcscat(InstancePath
, L
"\\");
1070 wcscat(InstancePath
, DeviceNode
->InstanceID
.Buffer
);
1072 if (!DeviceNode
->CapabilityFlags
->UniqueID
)
1074 DPRINT("Instance ID is not unique\n");
1075 /* FIXME: Add information from parent bus driver to InstancePath */
1078 if (!IopCreateUnicodeString(&DeviceNode
->InstancePath
, InstancePath
, PagedPool
))
1080 DPRINT("No resources\n");
1081 /* FIXME: Cleanup and disable device */
1084 DPRINT("InstancePath is %S\n", DeviceNode
->InstancePath
.Buffer
);
1087 * Create registry key for the instance id, if it doesn't exist yet
1090 KeyBuffer
= ExAllocatePool(
1092 (49 * sizeof(WCHAR
)) + DeviceNode
->InstancePath
.Length
);
1093 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1094 wcscat(KeyBuffer
, DeviceNode
->InstancePath
.Buffer
);
1095 IopCreateDeviceKeyPath(KeyBuffer
);
1096 ExFreePool(KeyBuffer
);
1097 DeviceNode
->Flags
|= DNF_PROCESSED
;
1099 return STATUS_SUCCESS
;
1103 * IopActionConfigureChildServices
1105 * Retrieve configuration for all (direct) child nodes of a parent node.
1109 * Pointer to device node.
1111 * Pointer to parent node to retrieve child node configuration for.
1114 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
1115 * when we reach a device node which is not a direct child of the device
1116 * node for which we configure child services for. Any errors that occur is
1117 * logged instead so that all child services have a chance of beeing
1122 IopActionConfigureChildServices(
1123 PDEVICE_NODE DeviceNode
,
1126 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1127 PDEVICE_NODE ParentDeviceNode
;
1128 PUNICODE_STRING Service
;
1131 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode
, Context
);
1133 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
1136 * We are called for the parent too, but we don't need to do special
1137 * handling for this node
1139 if (DeviceNode
== ParentDeviceNode
)
1141 DPRINT("Success\n");
1142 return STATUS_SUCCESS
;
1146 * Make sure this device node is a direct child of the parent device node
1147 * that is given as an argument
1149 if (DeviceNode
->Parent
!= ParentDeviceNode
)
1151 /* Stop the traversal immediately and indicate successful operation */
1153 return STATUS_UNSUCCESSFUL
;
1156 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
))
1159 * Retrieve configuration from Enum key
1162 Service
= &DeviceNode
->ServiceName
;
1164 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1165 RtlInitUnicodeString(Service
, NULL
);
1167 QueryTable
[0].Name
= L
"Service";
1168 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1169 QueryTable
[0].EntryContext
= Service
;
1171 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ENUM
,
1172 DeviceNode
->InstancePath
.Buffer
, QueryTable
, NULL
, NULL
);
1174 if (!NT_SUCCESS(Status
))
1176 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1177 /* FIXME: Log the error */
1178 CPRINT("Could not retrieve configuration for device %S (Status %x)\n",
1179 DeviceNode
->InstancePath
.Buffer
, Status
);
1180 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
1181 return STATUS_SUCCESS
;
1184 if (Service
->Buffer
== NULL
)
1186 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
1187 return STATUS_SUCCESS
;
1190 DPRINT("Got Service %S\n", Service
->Buffer
);
1193 return STATUS_SUCCESS
;
1197 * IopActionInitChildServices
1199 * Initialize the service for all (direct) child nodes of a parent node
1203 * Pointer to device node.
1205 * Pointer to parent node to initialize child node services for.
1207 * Load only driver marked as boot start.
1210 * If the driver image for a service is not loaded and initialized
1211 * it is done here too. We only return a status code indicating an
1212 * error (STATUS_UNSUCCESSFUL) when we reach a device node which is
1213 * not a direct child of the device node for which we initialize
1214 * child services for. Any errors that occur is logged instead so
1215 * that all child services have a chance of being initialized.
1219 IopActionInitChildServices(
1220 PDEVICE_NODE DeviceNode
,
1222 BOOLEAN BootDrivers
)
1224 PDEVICE_NODE ParentDeviceNode
;
1227 DPRINT("IopActionInitChildServices(%p, %p, %d)\n", DeviceNode
, Context
,
1230 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
1233 * We are called for the parent too, but we don't need to do special
1234 * handling for this node
1236 if (DeviceNode
== ParentDeviceNode
)
1238 DPRINT("Success\n");
1239 return STATUS_SUCCESS
;
1243 * Make sure this device node is a direct child of the parent device node
1244 * that is given as an argument
1247 if (DeviceNode
->Parent
!= ParentDeviceNode
)
1250 * Stop the traversal immediately and indicate unsuccessful operation
1253 return STATUS_UNSUCCESSFUL
;
1257 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
) &&
1258 !IopDeviceNodeHasFlag(DeviceNode
, DNF_ADDED
) &&
1259 !IopDeviceNodeHasFlag(DeviceNode
, DNF_STARTED
))
1261 PMODULE_OBJECT ModuleObject
;
1262 PDRIVER_OBJECT DriverObject
;
1264 Status
= IopLoadServiceModule(&DeviceNode
->ServiceName
, &ModuleObject
);
1265 if (NT_SUCCESS(Status
))
1267 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, FALSE
, &DriverObject
);
1268 if (NT_SUCCESS(Status
))
1270 /* Attach lower level filter drivers. */
1271 IopAttachFilterDrivers(DeviceNode
, TRUE
);
1272 /* Initialize the function driver for the device node */
1273 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
1274 if (NT_SUCCESS(Status
))
1276 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
1277 /* Attach upper level filter drivers. */
1278 IopAttachFilterDrivers(DeviceNode
, FALSE
);
1285 * Don't disable when trying to load only boot drivers
1289 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
1290 IopDeviceNodeSetFlag(DeviceNode
, DNF_START_FAILED
);
1292 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
1293 CPRINT("Initialization of service %S failed (Status %x)\n",
1294 DeviceNode
->ServiceName
.Buffer
, Status
);
1298 DPRINT("Service %S is disabled or already initialized\n",
1299 DeviceNode
->ServiceName
.Buffer
);
1302 return STATUS_SUCCESS
;
1306 * IopActionInitAllServices
1308 * Initialize the service for all (direct) child nodes of a parent node. This
1309 * function just calls IopActionInitChildServices with BootDrivers = FALSE.
1313 IopActionInitAllServices(
1314 PDEVICE_NODE DeviceNode
,
1317 return IopActionInitChildServices(DeviceNode
, Context
, FALSE
);
1321 * IopActionInitBootServices
1323 * Initialize the boot start services for all (direct) child nodes of a
1324 * parent node. This function just calls IopActionInitChildServices with
1325 * BootDrivers = TRUE.
1329 IopActionInitBootServices(
1330 PDEVICE_NODE DeviceNode
,
1333 return IopActionInitChildServices(DeviceNode
, Context
, TRUE
);
1337 * IopInitializePnpServices
1339 * Initialize services for discovered children
1343 * Top device node to start initializing services.
1346 * When set to TRUE, only drivers marked as boot start will
1347 * be loaded. Otherwise, all drivers will be loaded.
1354 IopInitializePnpServices(
1355 IN PDEVICE_NODE DeviceNode
,
1356 IN BOOLEAN BootDrivers
)
1358 DEVICETREE_TRAVERSE_CONTEXT Context
;
1360 DPRINT("IopInitializePnpServices(%p, %d)\n", DeviceNode
, BootDrivers
);
1364 IopInitDeviceTreeTraverseContext(
1367 IopActionInitBootServices
,
1371 IopInitDeviceTreeTraverseContext(
1374 IopActionInitAllServices
,
1378 return IopTraverseDeviceTree(&Context
);
1383 IopInvalidateDeviceRelations(
1384 IN PDEVICE_NODE DeviceNode
,
1385 IN DEVICE_RELATION_TYPE Type
)
1387 DEVICETREE_TRAVERSE_CONTEXT Context
;
1388 PDEVICE_RELATIONS DeviceRelations
;
1389 IO_STATUS_BLOCK IoStatusBlock
;
1390 PDEVICE_NODE ChildDeviceNode
;
1391 IO_STACK_LOCATION Stack
;
1393 OBJECT_ATTRIBUTES ObjectAttributes
;
1394 UNICODE_STRING LinkName
;
1399 DPRINT("DeviceNode %x\n", DeviceNode
);
1401 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
1403 Stack
.Parameters
.QueryDeviceRelations
.Type
= Type
/*BusRelations*/;
1405 Status
= IopInitiatePnpIrp(
1408 IRP_MN_QUERY_DEVICE_RELATIONS
,
1410 if (!NT_SUCCESS(Status
))
1412 DPRINT("IopInitiatePnpIrp() failed\n");
1416 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
1418 if ((!DeviceRelations
) || (DeviceRelations
->Count
<= 0))
1420 DPRINT("No PDOs\n");
1421 if (DeviceRelations
)
1423 ExFreePool(DeviceRelations
);
1425 return STATUS_SUCCESS
;
1428 DPRINT("Got %d PDOs\n", DeviceRelations
->Count
);
1431 * Create device nodes for all discovered devices
1434 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
1436 Status
= IopCreateDeviceNode(
1438 DeviceRelations
->Objects
[i
],
1440 DeviceNode
->Flags
|= DNF_ENUMERATED
;
1441 if (!NT_SUCCESS(Status
))
1443 DPRINT("No resources\n");
1444 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
1445 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
1446 ExFreePool(DeviceRelations
);
1447 return STATUS_INSUFFICIENT_RESOURCES
;
1450 ExFreePool(DeviceRelations
);
1453 * Retrieve information about all discovered children from the bus driver
1456 IopInitDeviceTreeTraverseContext(
1459 IopActionInterrogateDeviceStack
,
1462 Status
= IopTraverseDeviceTree(&Context
);
1463 if (!NT_SUCCESS(Status
))
1465 DPRINT("IopTraverseDeviceTree() failed with status (%x)\n", Status
);
1470 * Retrieve configuration from the registry for discovered children
1473 IopInitDeviceTreeTraverseContext(
1476 IopActionConfigureChildServices
,
1479 Status
= IopTraverseDeviceTree(&Context
);
1480 if (!NT_SUCCESS(Status
))
1482 DPRINT("IopTraverseDeviceTree() failed with status (%x)\n", Status
);
1487 * Get the state of the system boot. If the \\SystemRoot link isn't
1488 * created yet, we will assume that it's possible to load only boot
1492 RtlInitUnicodeString(&LinkName
, L
"\\SystemRoot");
1494 InitializeObjectAttributes(
1501 Status
= NtOpenFile(
1509 BootDrivers
= NT_SUCCESS(Status
) ? FALSE
: TRUE
;
1514 * Initialize services for discovered children. Only boot drivers will
1515 * be loaded from boot driver!
1518 Status
= IopInitializePnpServices(DeviceNode
, BootDrivers
);
1519 if (!NT_SUCCESS(Status
))
1521 DPRINT("IopInitializePnpServices() failed with status (%x)\n", Status
);
1525 return STATUS_SUCCESS
;
1535 DPRINT("PnpInit()\n");
1537 KeInitializeSpinLock(&IopDeviceTreeLock
);
1540 * Create root device node
1543 Status
= IopCreateDriverObject(&IopRootDriverObject
, NULL
, FALSE
, NULL
, 0);
1544 if (!NT_SUCCESS(Status
))
1546 CPRINT("IoCreateDriverObject() failed\n");
1547 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
1550 Status
= IoCreateDevice(IopRootDriverObject
, 0, NULL
, FILE_DEVICE_CONTROLLER
,
1552 if (!NT_SUCCESS(Status
))
1554 CPRINT("IoCreateDevice() failed\n");
1555 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
1558 Status
= IopCreateDeviceNode(NULL
, Pdo
, &IopRootDeviceNode
);
1559 if (!NT_SUCCESS(Status
))
1561 CPRINT("Insufficient resources\n");
1562 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
1565 IopRootDeviceNode
->Pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
1566 PnpRootDriverEntry(IopRootDriverObject
, NULL
);
1567 IopRootDriverObject
->DriverExtension
->AddDevice(
1568 IopRootDriverObject
,
1569 IopRootDeviceNode
->Pdo
);