1 /* $Id: pnpmgr.c,v 1.37 2004/10/11 19:07:25 ekohl 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
,
698 OBJECT_ATTRIBUTES ObjectAttributes
;
699 WCHAR KeyBuffer
[MAX_PATH
];
700 UNICODE_STRING KeyName
;
708 if (_wcsnicmp(Path
, L
"\\Registry\\", 10) != 0)
710 return STATUS_INVALID_PARAMETER
;
713 wcsncpy (KeyBuffer
, Path
, MAX_PATH
-1);
714 RtlInitUnicodeString (&KeyName
, KeyBuffer
);
716 /* Skip \\Registry\\ */
717 Current
= KeyName
.Buffer
;
718 Current
= wcschr (Current
, '\\') + 1;
719 Current
= wcschr (Current
, '\\') + 1;
723 Next
= wcschr (Current
, '\\');
733 InitializeObjectAttributes (&ObjectAttributes
,
735 OBJ_CASE_INSENSITIVE
,
739 DPRINT("Create '%S'\n", KeyName
.Buffer
);
741 Status
= NtCreateKey (&KeyHandle
,
748 if (!NT_SUCCESS (Status
))
750 DPRINT ("NtCreateKey() failed with status %x\n", Status
);
757 return STATUS_SUCCESS
;
768 return STATUS_UNSUCCESSFUL
;
773 IopSetDeviceInstanceData(HANDLE InstanceKey
,
774 PDEVICE_NODE DeviceNode
)
776 OBJECT_ATTRIBUTES ObjectAttributes
;
777 UNICODE_STRING KeyName
;
783 DPRINT("IopSetDeviceInstanceData() called\n");
785 RtlInitUnicodeString(&KeyName
,
787 Status
= NtSetValueKey(InstanceKey
,
791 DeviceNode
->CompatibleIDs
.Buffer
,
792 DeviceNode
->CompatibleIDs
.MaximumLength
);
794 RtlInitUnicodeString(&KeyName
,
796 Status
= NtSetValueKey(InstanceKey
,
800 DeviceNode
->HardwareIDs
.Buffer
,
801 DeviceNode
->HardwareIDs
.MaximumLength
);
803 /* Set 'DeviceDesc' value */
804 RtlInitUnicodeString(&KeyName
,
806 Status
= NtSetValueKey(InstanceKey
,
810 DeviceNode
->DeviceText
.Buffer
,
811 DeviceNode
->DeviceText
.MaximumLength
);
813 /* Set 'LocationInformation' value */
814 DPRINT("LocationInformation: %wZ\n", &DeviceNode
->DeviceTextLocation
);
815 RtlInitUnicodeString(&KeyName
,
816 L
"LocationInformation");
817 Status
= NtSetValueKey(InstanceKey
,
821 DeviceNode
->DeviceTextLocation
.Buffer
,
822 DeviceNode
->DeviceTextLocation
.MaximumLength
);
824 /* Set 'Capabilities' value */
825 RtlInitUnicodeString(&KeyName
,
827 Status
= NtSetValueKey(InstanceKey
,
831 (PVOID
)((ULONG_PTR
)&DeviceNode
->CapabilityFlags
+ 4),
834 /* Set 'UINumber' value */
835 if (DeviceNode
->CapabilityFlags
->UINumber
!= (ULONG
)-1)
837 RtlInitUnicodeString(&KeyName
,
839 Status
= NtSetValueKey(InstanceKey
,
843 &DeviceNode
->CapabilityFlags
->UINumber
,
847 /* Create the 'LogConf' key */
848 RtlInitUnicodeString(&KeyName
,
850 InitializeObjectAttributes(&ObjectAttributes
,
852 OBJ_CASE_INSENSITIVE
,
855 Status
= NtCreateKey(&LogConfKey
,
862 if (NT_SUCCESS(Status
))
864 /* Set 'BootConfig' value */
865 if (DeviceNode
->BootResourcesList
!= NULL
)
867 ResCount
= DeviceNode
->BootResourcesList
->List
[0].PartialResourceList
.Count
;
870 ListSize
= sizeof(CM_RESOURCE_LIST
) +
871 ((ResCount
- 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
));
873 RtlInitUnicodeString(&KeyName
,
875 Status
= NtSetValueKey(LogConfKey
,
879 &DeviceNode
->BootResourcesList
,
884 /* Set 'BasicConfigVector' value */
885 if (DeviceNode
->ResourceRequirementsList
!= NULL
&&
886 DeviceNode
->ResourceRequirementsList
->ListSize
!= 0)
888 RtlInitUnicodeString(&KeyName
,
889 L
"BasicConfigVector");
890 Status
= NtSetValueKey(LogConfKey
,
893 REG_RESOURCE_REQUIREMENTS_LIST
,
894 &DeviceNode
->ResourceRequirementsList
,
895 DeviceNode
->ResourceRequirementsList
->ListSize
);
901 DPRINT("IopSetDeviceInstanceData() done\n");
903 return STATUS_SUCCESS
;
908 * IopActionInterrogateDeviceStack
910 * Retrieve information for all (direct) child nodes of a parent node.
914 * Pointer to device node.
916 * Pointer to parent node to retrieve child node information for.
919 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
920 * when we reach a device node which is not a direct child of the device
921 * node for which we retrieve information of child nodes for. Any errors
922 * that occur is logged instead so that all child services have a chance
923 * of being interrogated.
927 IopActionInterrogateDeviceStack(
928 PDEVICE_NODE DeviceNode
,
931 IO_STATUS_BLOCK IoStatusBlock
;
932 PDEVICE_NODE ParentDeviceNode
;
933 WCHAR InstancePath
[MAX_PATH
];
934 IO_STACK_LOCATION Stack
;
940 HANDLE InstanceKey
= NULL
;
942 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode
, Context
);
943 DPRINT("PDO %x\n", DeviceNode
->Pdo
);
945 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
948 * We are called for the parent too, but we don't need to do special
949 * handling for this node
952 if (DeviceNode
== ParentDeviceNode
)
955 return STATUS_SUCCESS
;
959 * Make sure this device node is a direct child of the parent device node
960 * that is given as an argument
963 if (DeviceNode
->Parent
!= ParentDeviceNode
)
965 /* Stop the traversal immediately and indicate successful operation */
967 return STATUS_UNSUCCESSFUL
;
971 * FIXME: For critical errors, cleanup and disable device, but always
972 * return STATUS_SUCCESS.
975 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
977 Stack
.Parameters
.QueryId
.IdType
= BusQueryDeviceID
;
978 Status
= IopInitiatePnpIrp(
983 if (NT_SUCCESS(Status
))
985 RtlInitUnicodeString(
986 &DeviceNode
->DeviceID
,
987 (PWSTR
)IoStatusBlock
.Information
);
990 * FIXME: Check for valid characters, if there is invalid characters
996 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
997 RtlInitUnicodeString(&DeviceNode
->DeviceID
, NULL
);
1000 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
1002 Stack
.Parameters
.QueryId
.IdType
= BusQueryInstanceID
;
1003 Status
= IopInitiatePnpIrp(
1008 if (NT_SUCCESS(Status
))
1010 RtlInitUnicodeString(
1011 &DeviceNode
->InstanceID
,
1012 (PWSTR
)IoStatusBlock
.Information
);
1015 * FIXME: Check for valid characters, if there is invalid characters
1021 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1022 RtlInitUnicodeString(&DeviceNode
->InstanceID
, NULL
);
1025 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1027 Stack
.Parameters
.QueryId
.IdType
= BusQueryHardwareIDs
;
1028 Status
= IopInitiatePnpIrp(
1033 if (NT_SUCCESS(Status
))
1036 * FIXME: Check for valid characters, if there is invalid characters
1040 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
1041 DPRINT("Hardware IDs:\n");
1044 DPRINT(" %S\n", Ptr
);
1045 Length
= wcslen(Ptr
) + 1;
1048 TotalLength
+= Length
;
1050 DPRINT("TotalLength: %hu\n", TotalLength
);
1053 DeviceNode
->HardwareIDs
.Length
= TotalLength
* sizeof(WCHAR
);
1054 DeviceNode
->HardwareIDs
.MaximumLength
= DeviceNode
->HardwareIDs
.Length
+ sizeof(WCHAR
);
1055 DeviceNode
->HardwareIDs
.Buffer
= (PWSTR
)IoStatusBlock
.Information
;
1059 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1060 RtlInitUnicodeString(&DeviceNode
->HardwareIDs
, NULL
);
1063 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1065 Stack
.Parameters
.QueryId
.IdType
= BusQueryCompatibleIDs
;
1066 Status
= IopInitiatePnpIrp(
1071 if (NT_SUCCESS(Status
))
1074 * FIXME: Check for valid characters, if there is invalid characters
1078 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
1079 DPRINT("Compatible IDs:\n");
1082 DPRINT(" %S\n", Ptr
);
1083 Length
= wcslen(Ptr
) + 1;
1086 TotalLength
+= Length
;
1088 DPRINT("TotalLength: %hu\n", TotalLength
);
1091 DeviceNode
->CompatibleIDs
.Length
= TotalLength
* sizeof(WCHAR
);
1092 DeviceNode
->CompatibleIDs
.MaximumLength
= DeviceNode
->CompatibleIDs
.Length
+ sizeof(WCHAR
);
1093 DeviceNode
->CompatibleIDs
.Buffer
= (PWSTR
)IoStatusBlock
.Information
;
1097 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1098 RtlInitUnicodeString(&DeviceNode
->CompatibleIDs
, NULL
);
1101 Status
= IopQueryCapabilities(DeviceNode
->Pdo
, &DeviceNode
->CapabilityFlags
);
1102 if (NT_SUCCESS(Status
))
1109 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
1111 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextDescription
;
1112 Stack
.Parameters
.QueryDeviceText
.LocaleId
= 0; /* FIXME */
1113 Status
= IopInitiatePnpIrp(
1116 IRP_MN_QUERY_DEVICE_TEXT
,
1118 if (NT_SUCCESS(Status
))
1120 RtlInitUnicodeString(
1121 &DeviceNode
->DeviceText
,
1122 (PWSTR
)IoStatusBlock
.Information
);
1126 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1127 RtlInitUnicodeString(&DeviceNode
->DeviceText
, NULL
);
1130 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
1132 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextLocationInformation
;
1133 Stack
.Parameters
.QueryDeviceText
.LocaleId
= 0; // FIXME
1134 Status
= IopInitiatePnpIrp(
1137 IRP_MN_QUERY_DEVICE_TEXT
,
1139 if (NT_SUCCESS(Status
))
1141 RtlInitUnicodeString(
1142 &DeviceNode
->DeviceTextLocation
,
1143 (PWSTR
)IoStatusBlock
.Information
);
1147 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1148 RtlInitUnicodeString(&DeviceNode
->DeviceTextLocation
, NULL
);
1151 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
1153 Status
= IopInitiatePnpIrp(
1156 IRP_MN_QUERY_BUS_INFORMATION
,
1158 if (NT_SUCCESS(Status
))
1160 DeviceNode
->BusInformation
=
1161 (PPNP_BUS_INFORMATION
)IoStatusBlock
.Information
;
1165 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1166 DeviceNode
->BusInformation
= NULL
;
1169 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
1171 Status
= IopInitiatePnpIrp(
1174 IRP_MN_QUERY_RESOURCES
,
1176 if (NT_SUCCESS(Status
))
1178 DeviceNode
->BootResourcesList
=
1179 (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
1180 DeviceNode
->Flags
|= DNF_HAS_BOOT_CONFIG
;
1184 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1185 DeviceNode
->BootResourcesList
= NULL
;
1188 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
1190 Status
= IopInitiatePnpIrp(
1193 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
1195 if (NT_SUCCESS(Status
))
1197 DeviceNode
->ResourceRequirementsList
=
1198 (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
1202 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1203 DeviceNode
->ResourceRequirementsList
= NULL
;
1207 * Assemble the instance path for the device
1210 wcscpy(InstancePath
, DeviceNode
->DeviceID
.Buffer
);
1211 wcscat(InstancePath
, L
"\\");
1212 wcscat(InstancePath
, DeviceNode
->InstanceID
.Buffer
);
1214 if (!DeviceNode
->CapabilityFlags
->UniqueID
)
1216 DPRINT("Instance ID is not unique\n");
1217 /* FIXME: Add information from parent bus driver to InstancePath */
1220 if (!IopCreateUnicodeString(&DeviceNode
->InstancePath
, InstancePath
, PagedPool
))
1222 DPRINT("No resources\n");
1223 /* FIXME: Cleanup and disable device */
1226 DPRINT("InstancePath is %S\n", DeviceNode
->InstancePath
.Buffer
);
1229 * Create registry key for the instance id, if it doesn't exist yet
1232 KeyBuffer
= ExAllocatePool(
1234 (49 * sizeof(WCHAR
)) + DeviceNode
->InstancePath
.Length
);
1235 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1236 wcscat(KeyBuffer
, DeviceNode
->InstancePath
.Buffer
);
1237 Status
= IopCreateDeviceKeyPath(KeyBuffer
,
1239 ExFreePool(KeyBuffer
);
1241 if (InstanceKey
!= NULL
)
1243 IopSetDeviceInstanceData(InstanceKey
, DeviceNode
);
1244 NtClose(InstanceKey
);
1247 DeviceNode
->Flags
|= DNF_PROCESSED
;
1249 return STATUS_SUCCESS
;
1253 * IopActionConfigureChildServices
1255 * Retrieve configuration for all (direct) child nodes of a parent node.
1259 * Pointer to device node.
1261 * Pointer to parent node to retrieve child node configuration for.
1264 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
1265 * when we reach a device node which is not a direct child of the device
1266 * node for which we configure child services for. Any errors that occur is
1267 * logged instead so that all child services have a chance of beeing
1272 IopActionConfigureChildServices(
1273 PDEVICE_NODE DeviceNode
,
1276 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1277 PDEVICE_NODE ParentDeviceNode
;
1278 PUNICODE_STRING Service
;
1281 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode
, Context
);
1283 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
1286 * We are called for the parent too, but we don't need to do special
1287 * handling for this node
1289 if (DeviceNode
== ParentDeviceNode
)
1291 DPRINT("Success\n");
1292 return STATUS_SUCCESS
;
1296 * Make sure this device node is a direct child of the parent device node
1297 * that is given as an argument
1299 if (DeviceNode
->Parent
!= ParentDeviceNode
)
1301 /* Stop the traversal immediately and indicate successful operation */
1303 return STATUS_UNSUCCESSFUL
;
1306 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
))
1309 * Retrieve configuration from Enum key
1312 Service
= &DeviceNode
->ServiceName
;
1314 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1315 RtlInitUnicodeString(Service
, NULL
);
1317 QueryTable
[0].Name
= L
"Service";
1318 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1319 QueryTable
[0].EntryContext
= Service
;
1321 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ENUM
,
1322 DeviceNode
->InstancePath
.Buffer
, QueryTable
, NULL
, NULL
);
1324 if (!NT_SUCCESS(Status
))
1326 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1327 /* FIXME: Log the error */
1328 CPRINT("Could not retrieve configuration for device %S (Status %x)\n",
1329 DeviceNode
->InstancePath
.Buffer
, Status
);
1330 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
1331 return STATUS_SUCCESS
;
1334 if (Service
->Buffer
== NULL
)
1336 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
1337 return STATUS_SUCCESS
;
1340 DPRINT("Got Service %S\n", Service
->Buffer
);
1343 return STATUS_SUCCESS
;
1347 * IopActionInitChildServices
1349 * Initialize the service for all (direct) child nodes of a parent node
1353 * Pointer to device node.
1355 * Pointer to parent node to initialize child node services for.
1357 * Load only driver marked as boot start.
1360 * If the driver image for a service is not loaded and initialized
1361 * it is done here too. We only return a status code indicating an
1362 * error (STATUS_UNSUCCESSFUL) when we reach a device node which is
1363 * not a direct child of the device node for which we initialize
1364 * child services for. Any errors that occur is logged instead so
1365 * that all child services have a chance of being initialized.
1369 IopActionInitChildServices(
1370 PDEVICE_NODE DeviceNode
,
1372 BOOLEAN BootDrivers
)
1374 PDEVICE_NODE ParentDeviceNode
;
1377 DPRINT("IopActionInitChildServices(%p, %p, %d)\n", DeviceNode
, Context
,
1380 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
1383 * We are called for the parent too, but we don't need to do special
1384 * handling for this node
1386 if (DeviceNode
== ParentDeviceNode
)
1388 DPRINT("Success\n");
1389 return STATUS_SUCCESS
;
1393 * Make sure this device node is a direct child of the parent device node
1394 * that is given as an argument
1397 if (DeviceNode
->Parent
!= ParentDeviceNode
)
1400 * Stop the traversal immediately and indicate unsuccessful operation
1403 return STATUS_UNSUCCESSFUL
;
1407 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
) &&
1408 !IopDeviceNodeHasFlag(DeviceNode
, DNF_ADDED
) &&
1409 !IopDeviceNodeHasFlag(DeviceNode
, DNF_STARTED
))
1411 PMODULE_OBJECT ModuleObject
;
1412 PDRIVER_OBJECT DriverObject
;
1414 Status
= IopLoadServiceModule(&DeviceNode
->ServiceName
, &ModuleObject
);
1415 if (NT_SUCCESS(Status
))
1417 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, FALSE
, &DriverObject
);
1418 if (NT_SUCCESS(Status
))
1420 /* Attach lower level filter drivers. */
1421 IopAttachFilterDrivers(DeviceNode
, TRUE
);
1422 /* Initialize the function driver for the device node */
1423 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
1424 if (NT_SUCCESS(Status
))
1426 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
1427 /* Attach upper level filter drivers. */
1428 IopAttachFilterDrivers(DeviceNode
, FALSE
);
1435 * Don't disable when trying to load only boot drivers
1439 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
1440 IopDeviceNodeSetFlag(DeviceNode
, DNF_START_FAILED
);
1442 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
1443 CPRINT("Initialization of service %S failed (Status %x)\n",
1444 DeviceNode
->ServiceName
.Buffer
, Status
);
1448 DPRINT("Service %S is disabled or already initialized\n",
1449 DeviceNode
->ServiceName
.Buffer
);
1452 return STATUS_SUCCESS
;
1456 * IopActionInitAllServices
1458 * Initialize the service for all (direct) child nodes of a parent node. This
1459 * function just calls IopActionInitChildServices with BootDrivers = FALSE.
1463 IopActionInitAllServices(
1464 PDEVICE_NODE DeviceNode
,
1467 return IopActionInitChildServices(DeviceNode
, Context
, FALSE
);
1471 * IopActionInitBootServices
1473 * Initialize the boot start services for all (direct) child nodes of a
1474 * parent node. This function just calls IopActionInitChildServices with
1475 * BootDrivers = TRUE.
1479 IopActionInitBootServices(
1480 PDEVICE_NODE DeviceNode
,
1483 return IopActionInitChildServices(DeviceNode
, Context
, TRUE
);
1487 * IopInitializePnpServices
1489 * Initialize services for discovered children
1493 * Top device node to start initializing services.
1496 * When set to TRUE, only drivers marked as boot start will
1497 * be loaded. Otherwise, all drivers will be loaded.
1504 IopInitializePnpServices(
1505 IN PDEVICE_NODE DeviceNode
,
1506 IN BOOLEAN BootDrivers
)
1508 DEVICETREE_TRAVERSE_CONTEXT Context
;
1510 DPRINT("IopInitializePnpServices(%p, %d)\n", DeviceNode
, BootDrivers
);
1514 IopInitDeviceTreeTraverseContext(
1517 IopActionInitBootServices
,
1521 IopInitDeviceTreeTraverseContext(
1524 IopActionInitAllServices
,
1528 return IopTraverseDeviceTree(&Context
);
1533 IopInvalidateDeviceRelations(
1534 IN PDEVICE_NODE DeviceNode
,
1535 IN DEVICE_RELATION_TYPE Type
)
1537 DEVICETREE_TRAVERSE_CONTEXT Context
;
1538 PDEVICE_RELATIONS DeviceRelations
;
1539 IO_STATUS_BLOCK IoStatusBlock
;
1540 PDEVICE_NODE ChildDeviceNode
;
1541 IO_STACK_LOCATION Stack
;
1543 OBJECT_ATTRIBUTES ObjectAttributes
;
1544 UNICODE_STRING LinkName
;
1549 DPRINT("DeviceNode %x\n", DeviceNode
);
1551 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
1553 Stack
.Parameters
.QueryDeviceRelations
.Type
= Type
/*BusRelations*/;
1555 Status
= IopInitiatePnpIrp(
1558 IRP_MN_QUERY_DEVICE_RELATIONS
,
1560 if (!NT_SUCCESS(Status
))
1562 DPRINT("IopInitiatePnpIrp() failed\n");
1566 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
1568 if ((!DeviceRelations
) || (DeviceRelations
->Count
<= 0))
1570 DPRINT("No PDOs\n");
1571 if (DeviceRelations
)
1573 ExFreePool(DeviceRelations
);
1575 return STATUS_SUCCESS
;
1578 DPRINT("Got %d PDOs\n", DeviceRelations
->Count
);
1581 * Create device nodes for all discovered devices
1584 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
1586 Status
= IopCreateDeviceNode(
1588 DeviceRelations
->Objects
[i
],
1590 DeviceNode
->Flags
|= DNF_ENUMERATED
;
1591 if (!NT_SUCCESS(Status
))
1593 DPRINT("No resources\n");
1594 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
1595 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
1596 ExFreePool(DeviceRelations
);
1597 return STATUS_INSUFFICIENT_RESOURCES
;
1600 ExFreePool(DeviceRelations
);
1603 * Retrieve information about all discovered children from the bus driver
1606 IopInitDeviceTreeTraverseContext(
1609 IopActionInterrogateDeviceStack
,
1612 Status
= IopTraverseDeviceTree(&Context
);
1613 if (!NT_SUCCESS(Status
))
1615 DPRINT("IopTraverseDeviceTree() failed with status (%x)\n", Status
);
1620 * Retrieve configuration from the registry for discovered children
1623 IopInitDeviceTreeTraverseContext(
1626 IopActionConfigureChildServices
,
1629 Status
= IopTraverseDeviceTree(&Context
);
1630 if (!NT_SUCCESS(Status
))
1632 DPRINT("IopTraverseDeviceTree() failed with status (%x)\n", Status
);
1637 * Get the state of the system boot. If the \\SystemRoot link isn't
1638 * created yet, we will assume that it's possible to load only boot
1642 RtlInitUnicodeString(&LinkName
, L
"\\SystemRoot");
1644 InitializeObjectAttributes(
1651 Status
= NtOpenFile(
1659 BootDrivers
= NT_SUCCESS(Status
) ? FALSE
: TRUE
;
1664 * Initialize services for discovered children. Only boot drivers will
1665 * be loaded from boot driver!
1668 Status
= IopInitializePnpServices(DeviceNode
, BootDrivers
);
1669 if (!NT_SUCCESS(Status
))
1671 DPRINT("IopInitializePnpServices() failed with status (%x)\n", Status
);
1675 return STATUS_SUCCESS
;
1685 DPRINT("PnpInit()\n");
1687 KeInitializeSpinLock(&IopDeviceTreeLock
);
1690 * Create root device node
1693 Status
= IopCreateDriverObject(&IopRootDriverObject
, NULL
, FALSE
, NULL
, 0);
1694 if (!NT_SUCCESS(Status
))
1696 CPRINT("IoCreateDriverObject() failed\n");
1697 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
1700 Status
= IoCreateDevice(IopRootDriverObject
, 0, NULL
, FILE_DEVICE_CONTROLLER
,
1702 if (!NT_SUCCESS(Status
))
1704 CPRINT("IoCreateDevice() failed\n");
1705 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
1708 Status
= IopCreateDeviceNode(NULL
, Pdo
, &IopRootDeviceNode
);
1709 if (!NT_SUCCESS(Status
))
1711 CPRINT("Insufficient resources\n");
1712 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
1715 IopRootDeviceNode
->Pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
1716 PnpRootDriverEntry(IopRootDriverObject
, NULL
);
1717 IopRootDriverObject
->DriverExtension
->AddDevice(
1718 IopRootDriverObject
,
1719 IopRootDeviceNode
->Pdo
);