1 /* $Id: pnpmgr.c,v 1.29 2004/06/10 11:00:28 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 ******************************************************************/
14 #include <ddk/ntddk.h>
15 #include <reactos/bugcodes.h>
16 #include <internal/io.h>
17 #include <internal/po.h>
18 #include <internal/ldr.h>
19 #include <internal/module.h>
21 #include <ole32/guiddef.h>
22 //#include <ddk/pnpfuncs.h>
24 DEFINE_GUID(GUID_CLASS_COMPORT
, 0x86e0d1e0L
, 0x8089, 0x11d0, 0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73);
25 DEFINE_GUID(GUID_SERENUM_BUS_ENUMERATOR
, 0x4D36E978L
, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18);
29 #include <internal/debug.h>
32 /* GLOBALS *******************************************************************/
34 PDEVICE_NODE IopRootDeviceNode
;
35 KSPIN_LOCK IopDeviceTreeLock
;
37 /* DATA **********************************************************************/
39 PDRIVER_OBJECT IopRootDriverObject
;
41 /* FUNCTIONS *****************************************************************/
48 IoAdjustPagingPathCount(
59 IoInvalidateDeviceRelations(
60 IN PDEVICE_OBJECT DeviceObject
,
61 IN DEVICE_RELATION_TYPE Type
)
67 PDEVICE_OBJECT DeviceObject
)
69 return DeviceObject
->DeviceObjectExtension
->DeviceNode
;
78 IN PDEVICE_OBJECT DeviceObject
,
79 IN DEVICE_REGISTRY_PROPERTY DeviceProperty
,
80 IN ULONG BufferLength
,
81 OUT PVOID PropertyBuffer
,
82 OUT PULONG ResultLength
)
84 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
88 DPRINT("IoGetDeviceProperty called\n");
90 if (DeviceNode
== NULL
||
91 DeviceNode
->BusInformation
== NULL
||
92 DeviceNode
->CapabilityFlags
== NULL
)
94 return STATUS_INVALID_DEVICE_REQUEST
;
100 * IRP_MN_QUERY_BUS_INFORMATION
102 switch (DeviceProperty
)
104 case DevicePropertyBusNumber
:
105 Length
= sizeof(ULONG
);
106 Data
= &DeviceNode
->BusInformation
->BusNumber
;
109 /* Complete, untested */
110 case DevicePropertyBusTypeGuid
:
111 *ResultLength
= 39 * sizeof(WCHAR
);
112 if (BufferLength
< (39 * sizeof(WCHAR
)))
113 return STATUS_BUFFER_TOO_SMALL
;
114 swprintf((PWSTR
)PropertyBuffer
,
115 L
"{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
116 DeviceNode
->BusInformation
->BusTypeGuid
.Data1
,
117 DeviceNode
->BusInformation
->BusTypeGuid
.Data2
,
118 DeviceNode
->BusInformation
->BusTypeGuid
.Data3
,
119 DeviceNode
->BusInformation
->BusTypeGuid
.Data4
[0],
120 DeviceNode
->BusInformation
->BusTypeGuid
.Data4
[1],
121 DeviceNode
->BusInformation
->BusTypeGuid
.Data4
[2],
122 DeviceNode
->BusInformation
->BusTypeGuid
.Data4
[3],
123 DeviceNode
->BusInformation
->BusTypeGuid
.Data4
[4],
124 DeviceNode
->BusInformation
->BusTypeGuid
.Data4
[5],
125 DeviceNode
->BusInformation
->BusTypeGuid
.Data4
[6],
126 DeviceNode
->BusInformation
->BusTypeGuid
.Data4
[7]);
127 return STATUS_SUCCESS
;
129 case DevicePropertyLegacyBusType
:
130 Length
= sizeof(INTERFACE_TYPE
);
131 Data
= &DeviceNode
->BusInformation
->LegacyBusType
;
134 case DevicePropertyAddress
:
135 Length
= sizeof(ULONG
);
136 Data
= &DeviceNode
->CapabilityFlags
->Address
;
139 case DevicePropertyUINumber
:
140 Length
= sizeof(ULONG
);
141 Data
= &DeviceNode
->CapabilityFlags
->UINumber
;
144 case DevicePropertyBootConfiguration
:
145 case DevicePropertyBootConfigurationTranslated
:
146 case DevicePropertyClassGuid
:
147 case DevicePropertyClassName
:
148 case DevicePropertyCompatibleIDs
:
149 case DevicePropertyDeviceDescription
:
150 case DevicePropertyDriverKeyName
:
151 case DevicePropertyEnumeratorName
:
152 case DevicePropertyFriendlyName
:
153 case DevicePropertyHardwareID
:
154 case DevicePropertyLocationInformation
:
155 case DevicePropertyManufacturer
:
156 case DevicePropertyPhysicalDeviceObjectName
:
157 return STATUS_NOT_IMPLEMENTED
;
160 return STATUS_INVALID_PARAMETER_2
;
163 *ResultLength
= Length
;
164 if (BufferLength
< Length
)
165 return STATUS_BUFFER_TOO_SMALL
;
166 RtlCopyMemory(PropertyBuffer
, Data
, Length
);
168 return STATUS_SUCCESS
;
176 IoInvalidateDeviceState(
177 IN PDEVICE_OBJECT PhysicalDeviceObject
)
186 IoOpenDeviceRegistryKey(
187 IN PDEVICE_OBJECT DeviceObject
,
188 IN ULONG DevInstKeyType
,
189 IN ACCESS_MASK DesiredAccess
,
190 OUT PHANDLE DevInstRegKey
)
192 return STATUS_NOT_IMPLEMENTED
;
200 IoRequestDeviceEject(
201 IN PDEVICE_OBJECT PhysicalDeviceObject
)
207 IopCreateUnicodeString(
208 PUNICODE_STRING Destination
,
216 RtlInitUnicodeString(Destination
, NULL
);
220 Length
= (wcslen(Source
) + 1) * sizeof(WCHAR
);
222 Destination
->Buffer
= ExAllocatePool(PoolType
, Length
);
224 if (Destination
->Buffer
== NULL
)
229 RtlCopyMemory(Destination
->Buffer
, Source
, Length
);
231 Destination
->MaximumLength
= Length
;
233 Destination
->Length
= Length
- sizeof(WCHAR
);
239 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT
*DeviceObject
)
243 if (PopSystemPowerDeviceNode
)
245 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
246 *DeviceObject
= PopSystemPowerDeviceNode
->Pdo
;
247 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
249 return STATUS_SUCCESS
;
252 return STATUS_UNSUCCESSFUL
;
255 /**********************************************************************
257 * Creates a device node
260 * ParentNode = Pointer to parent device node
261 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
262 * to have the root device node create one
263 * (eg. for legacy drivers)
264 * DeviceNode = Pointer to storage for created device node
270 IopCreateDeviceNode(PDEVICE_NODE ParentNode
,
271 PDEVICE_OBJECT PhysicalDeviceObject
,
272 PDEVICE_NODE
*DeviceNode
)
278 DPRINT("ParentNode %x PhysicalDeviceObject %x\n",
279 ParentNode
, PhysicalDeviceObject
);
281 Node
= (PDEVICE_NODE
)ExAllocatePool(PagedPool
, sizeof(DEVICE_NODE
));
284 return STATUS_INSUFFICIENT_RESOURCES
;
287 RtlZeroMemory(Node
, sizeof(DEVICE_NODE
));
289 if (!PhysicalDeviceObject
)
291 Status
= PnpRootCreateDevice(&PhysicalDeviceObject
);
292 if (!NT_SUCCESS(Status
))
298 /* This is for drivers passed on the command line to ntoskrnl.exe */
299 IopDeviceNodeSetFlag(Node
, DNF_STARTED
);
300 IopDeviceNodeSetFlag(Node
, DNF_LEGACY_DRIVER
);
303 Node
->Pdo
= PhysicalDeviceObject
;
305 PhysicalDeviceObject
->DeviceObjectExtension
->DeviceNode
= Node
;
309 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
310 Node
->Parent
= ParentNode
;
311 Node
->NextSibling
= ParentNode
->Child
;
312 if (ParentNode
->Child
!= NULL
)
314 ParentNode
->Child
->PrevSibling
= Node
;
316 ParentNode
->Child
= Node
;
317 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
322 return STATUS_SUCCESS
;
326 IopFreeDeviceNode(PDEVICE_NODE DeviceNode
)
330 /* All children must be deleted before a parent is deleted */
331 assert(!DeviceNode
->Child
);
333 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
335 assert(DeviceNode
->Pdo
);
337 ObDereferenceObject(DeviceNode
->Pdo
);
339 /* Unlink from parent if it exists */
341 if ((DeviceNode
->Parent
) && (DeviceNode
->Parent
->Child
== DeviceNode
))
343 DeviceNode
->Parent
->Child
= DeviceNode
->NextSibling
;
346 /* Unlink from sibling list */
348 if (DeviceNode
->PrevSibling
)
350 DeviceNode
->PrevSibling
->NextSibling
= DeviceNode
->NextSibling
;
353 if (DeviceNode
->NextSibling
)
355 DeviceNode
->NextSibling
->PrevSibling
= DeviceNode
->PrevSibling
;
358 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
360 RtlFreeUnicodeString(&DeviceNode
->InstancePath
);
362 RtlFreeUnicodeString(&DeviceNode
->ServiceName
);
364 if (DeviceNode
->CapabilityFlags
)
366 ExFreePool(DeviceNode
->CapabilityFlags
);
369 if (DeviceNode
->CmResourceList
)
371 ExFreePool(DeviceNode
->CmResourceList
);
374 if (DeviceNode
->BootResourcesList
)
376 ExFreePool(DeviceNode
->BootResourcesList
);
379 if (DeviceNode
->ResourceRequirementsList
)
381 ExFreePool(DeviceNode
->ResourceRequirementsList
);
384 RtlFreeUnicodeString(&DeviceNode
->DeviceID
);
386 RtlFreeUnicodeString(&DeviceNode
->InstanceID
);
388 RtlFreeUnicodeString(&DeviceNode
->HardwareIDs
);
390 RtlFreeUnicodeString(&DeviceNode
->CompatibleIDs
);
392 RtlFreeUnicodeString(&DeviceNode
->DeviceText
);
394 RtlFreeUnicodeString(&DeviceNode
->DeviceTextLocation
);
396 if (DeviceNode
->BusInformation
)
398 ExFreePool(DeviceNode
->BusInformation
);
401 ExFreePool(DeviceNode
);
403 return STATUS_SUCCESS
;
408 PDEVICE_OBJECT DeviceObject
,
409 PIO_STATUS_BLOCK IoStatusBlock
,
411 PIO_STACK_LOCATION Stack OPTIONAL
)
413 PDEVICE_OBJECT TopDeviceObject
;
414 PIO_STACK_LOCATION IrpSp
;
419 /* Always call the top of the device stack */
420 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
427 /* PNP IRPs are always initialized with a status code of
428 STATUS_NOT_IMPLEMENTED */
429 IoStatusBlock
->Status
= STATUS_NOT_IMPLEMENTED
;
430 IoStatusBlock
->Information
= 0;
432 Irp
= IoBuildSynchronousFsdRequest(
441 IrpSp
= IoGetNextIrpStackLocation(Irp
);
442 IrpSp
->MinorFunction
= MinorFunction
;
449 sizeof(Stack
->Parameters
));
452 Status
= IoCallDriver(TopDeviceObject
, Irp
);
453 if (Status
== STATUS_PENDING
)
455 KeWaitForSingleObject(
461 Status
= IoStatusBlock
->Status
;
464 ObDereferenceObject(TopDeviceObject
);
471 IopQueryCapabilities(
473 PDEVICE_CAPABILITIES
*Capabilities
)
475 IO_STATUS_BLOCK IoStatusBlock
;
476 PDEVICE_CAPABILITIES Caps
;
477 IO_STACK_LOCATION Stack
;
480 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack\n");
482 *Capabilities
= NULL
;
484 Caps
= ExAllocatePool(PagedPool
, sizeof(DEVICE_CAPABILITIES
));
487 return STATUS_INSUFFICIENT_RESOURCES
;
490 RtlZeroMemory(Caps
, sizeof(DEVICE_CAPABILITIES
));
491 Caps
->Size
= sizeof(DEVICE_CAPABILITIES
);
496 Stack
.Parameters
.DeviceCapabilities
.Capabilities
= Caps
;
498 Status
= IopInitiatePnpIrp(
501 IRP_MN_QUERY_CAPABILITIES
,
503 if (NT_SUCCESS(Status
))
505 *Capabilities
= Caps
;
509 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
517 IopTraverseDeviceTreeNode(
518 PDEVICETREE_TRAVERSE_CONTEXT Context
)
520 PDEVICE_NODE ParentDeviceNode
;
521 PDEVICE_NODE ChildDeviceNode
;
524 /* Copy context data so we don't overwrite it in subsequent calls to this function */
525 ParentDeviceNode
= Context
->DeviceNode
;
527 /* Call the action routine */
528 Status
= (Context
->Action
)(ParentDeviceNode
, Context
->Context
);
529 if (!NT_SUCCESS(Status
))
534 /* Traversal of all children nodes */
535 for (ChildDeviceNode
= ParentDeviceNode
->Child
;
536 ChildDeviceNode
!= NULL
;
537 ChildDeviceNode
= ChildDeviceNode
->NextSibling
)
539 /* Pass the current device node to the action routine */
540 Context
->DeviceNode
= ChildDeviceNode
;
542 Status
= IopTraverseDeviceTreeNode(Context
);
543 if (!NT_SUCCESS(Status
))
554 IopTraverseDeviceTree(
555 PDEVICETREE_TRAVERSE_CONTEXT Context
)
559 DPRINT("Context %x\n", Context
);
561 DPRINT("IopTraverseDeviceTree(DeviceNode %x FirstDeviceNode %x Action %x Context %x)\n",
562 Context
->DeviceNode
, Context
->FirstDeviceNode
, Context
->Action
, Context
->Context
);
564 /* Start from the specified device node */
565 Context
->DeviceNode
= Context
->FirstDeviceNode
;
567 /* Recursively traverse the device tree */
568 Status
= IopTraverseDeviceTreeNode(Context
);
569 if (Status
== STATUS_UNSUCCESSFUL
)
571 /* The action routine just wanted to terminate the traversal with status
572 code STATUS_SUCCESS */
573 Status
= STATUS_SUCCESS
;
581 IopCreateDeviceKeyPath(PWSTR Path
)
583 OBJECT_ATTRIBUTES ObjectAttributes
;
584 WCHAR KeyBuffer
[MAX_PATH
];
585 UNICODE_STRING KeyName
;
591 if (_wcsnicmp(Path
, L
"\\Registry\\", 10) != 0)
593 return STATUS_INVALID_PARAMETER
;
596 wcsncpy (KeyBuffer
, Path
, MAX_PATH
-1);
597 RtlInitUnicodeString (&KeyName
, KeyBuffer
);
599 /* Skip \\Registry\\ */
600 Current
= KeyName
.Buffer
;
601 Current
= wcschr (Current
, '\\') + 1;
602 Current
= wcschr (Current
, '\\') + 1;
606 Next
= wcschr (Current
, '\\');
616 InitializeObjectAttributes (&ObjectAttributes
,
618 OBJ_CASE_INSENSITIVE
,
622 DPRINT("Create '%S'\n", KeyName
.Buffer
);
624 Status
= NtCreateKey (&KeyHandle
,
631 if (!NT_SUCCESS (Status
))
633 DPRINT ("NtCreateKey() failed with status %x\n", Status
);
646 while (Next
!= NULL
);
648 return STATUS_SUCCESS
;
653 * IopActionInterrogateDeviceStack
655 * Retrieve information for all (direct) child nodes of a parent node.
659 * Pointer to device node.
661 * Pointer to parent node to retrieve child node information for.
664 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
665 * when we reach a device node which is not a direct child of the device
666 * node for which we retrieve information of child nodes for. Any errors
667 * that occur is logged instead so that all child services have a chance
668 * of being interrogated.
672 IopActionInterrogateDeviceStack(
673 PDEVICE_NODE DeviceNode
,
676 IO_STATUS_BLOCK IoStatusBlock
;
677 PDEVICE_NODE ParentDeviceNode
;
678 WCHAR InstancePath
[MAX_PATH
];
679 IO_STACK_LOCATION Stack
;
686 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode
, Context
);
687 DPRINT("PDO %x\n", DeviceNode
->Pdo
);
689 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
692 * We are called for the parent too, but we don't need to do special
693 * handling for this node
696 if (DeviceNode
== ParentDeviceNode
)
699 return STATUS_SUCCESS
;
703 * Make sure this device node is a direct child of the parent device node
704 * that is given as an argument
707 if (DeviceNode
->Parent
!= ParentDeviceNode
)
709 /* Stop the traversal immediately and indicate successful operation */
711 return STATUS_UNSUCCESSFUL
;
715 * FIXME: For critical errors, cleanup and disable device, but always
716 * return STATUS_SUCCESS.
719 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
721 Stack
.Parameters
.QueryId
.IdType
= BusQueryDeviceID
;
722 Status
= IopInitiatePnpIrp(
727 if (NT_SUCCESS(Status
))
729 RtlInitUnicodeString(
730 &DeviceNode
->DeviceID
,
731 (PWSTR
)IoStatusBlock
.Information
);
734 * FIXME: Check for valid characters, if there is invalid characters
740 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
741 RtlInitUnicodeString(&DeviceNode
->DeviceID
, NULL
);
744 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
746 Stack
.Parameters
.QueryId
.IdType
= BusQueryInstanceID
;
747 Status
= IopInitiatePnpIrp(
752 if (NT_SUCCESS(Status
))
754 RtlInitUnicodeString(
755 &DeviceNode
->InstanceID
,
756 (PWSTR
)IoStatusBlock
.Information
);
759 * FIXME: Check for valid characters, if there is invalid characters
765 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
766 RtlInitUnicodeString(&DeviceNode
->InstanceID
, NULL
);
769 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
771 Stack
.Parameters
.QueryId
.IdType
= BusQueryHardwareIDs
;
772 Status
= IopInitiatePnpIrp(
777 if (NT_SUCCESS(Status
))
780 * FIXME: Check for valid characters, if there is invalid characters
784 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
785 DPRINT("Hardware IDs:\n");
788 DPRINT(" %S\n", Ptr
);
789 Length
= wcslen(Ptr
) + 1;
792 TotalLength
+= Length
;
794 DPRINT("TotalLength: %hu\n", TotalLength
);
797 DeviceNode
->HardwareIDs
.Length
= TotalLength
* sizeof(WCHAR
);
798 DeviceNode
->HardwareIDs
.MaximumLength
= DeviceNode
->HardwareIDs
.Length
+ sizeof(WCHAR
);
799 DeviceNode
->HardwareIDs
.Buffer
= (PWSTR
)IoStatusBlock
.Information
;
803 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
804 RtlInitUnicodeString(&DeviceNode
->HardwareIDs
, NULL
);
807 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
809 Stack
.Parameters
.QueryId
.IdType
= BusQueryCompatibleIDs
;
810 Status
= IopInitiatePnpIrp(
815 if (NT_SUCCESS(Status
))
818 * FIXME: Check for valid characters, if there is invalid characters
822 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
823 DPRINT("Compatible IDs:\n");
826 DPRINT(" %S\n", Ptr
);
827 Length
= wcslen(Ptr
) + 1;
830 TotalLength
+= Length
;
832 DPRINT("TotalLength: %hu\n", TotalLength
);
835 DeviceNode
->CompatibleIDs
.Length
= TotalLength
* sizeof(WCHAR
);
836 DeviceNode
->CompatibleIDs
.MaximumLength
= DeviceNode
->CompatibleIDs
.Length
+ sizeof(WCHAR
);
837 DeviceNode
->CompatibleIDs
.Buffer
= (PWSTR
)IoStatusBlock
.Information
;
841 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
842 RtlInitUnicodeString(&DeviceNode
->CompatibleIDs
, NULL
);
845 Status
= IopQueryCapabilities(DeviceNode
->Pdo
, &DeviceNode
->CapabilityFlags
);
846 if (NT_SUCCESS(Status
))
853 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
855 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextDescription
;
856 Stack
.Parameters
.QueryDeviceText
.LocaleId
= 0; /* FIXME */
857 Status
= IopInitiatePnpIrp(
860 IRP_MN_QUERY_DEVICE_TEXT
,
862 if (NT_SUCCESS(Status
))
864 RtlInitUnicodeString(
865 &DeviceNode
->DeviceText
,
866 (PWSTR
)IoStatusBlock
.Information
);
870 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
871 RtlInitUnicodeString(&DeviceNode
->DeviceText
, NULL
);
874 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
876 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextLocationInformation
;
877 Stack
.Parameters
.QueryDeviceText
.LocaleId
= 0; // FIXME
878 Status
= IopInitiatePnpIrp(
881 IRP_MN_QUERY_DEVICE_TEXT
,
883 if (NT_SUCCESS(Status
))
885 RtlInitUnicodeString(
886 &DeviceNode
->DeviceTextLocation
,
887 (PWSTR
)IoStatusBlock
.Information
);
891 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
892 RtlInitUnicodeString(&DeviceNode
->DeviceTextLocation
, NULL
);
895 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
897 Status
= IopInitiatePnpIrp(
900 IRP_MN_QUERY_BUS_INFORMATION
,
902 if (NT_SUCCESS(Status
))
904 DeviceNode
->BusInformation
=
905 (PPNP_BUS_INFORMATION
)IoStatusBlock
.Information
;
909 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
910 DeviceNode
->BusInformation
= NULL
;
913 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
915 Status
= IopInitiatePnpIrp(
918 IRP_MN_QUERY_RESOURCES
,
920 if (NT_SUCCESS(Status
))
922 DeviceNode
->BootResourcesList
=
923 (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
924 DeviceNode
->Flags
|= DNF_HAS_BOOT_CONFIG
;
928 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
929 DeviceNode
->BootResourcesList
= NULL
;
932 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
934 Status
= IopInitiatePnpIrp(
937 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
939 if (NT_SUCCESS(Status
))
941 DeviceNode
->ResourceRequirementsList
=
942 (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
946 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
947 DeviceNode
->ResourceRequirementsList
= NULL
;
951 * Assemble the instance path for the device
954 wcscpy(InstancePath
, DeviceNode
->DeviceID
.Buffer
);
955 wcscat(InstancePath
, L
"\\");
956 wcscat(InstancePath
, DeviceNode
->InstanceID
.Buffer
);
958 if (!DeviceNode
->CapabilityFlags
->UniqueID
)
960 DPRINT("Instance ID is not unique\n");
961 /* FIXME: Add information from parent bus driver to InstancePath */
964 if (!IopCreateUnicodeString(&DeviceNode
->InstancePath
, InstancePath
, PagedPool
))
966 DPRINT("No resources\n");
967 /* FIXME: Cleanup and disable device */
970 DPRINT("InstancePath is %S\n", DeviceNode
->InstancePath
.Buffer
);
973 * Create registry key for the instance id, if it doesn't exist yet
976 KeyBuffer
= ExAllocatePool(
978 (49 * sizeof(WCHAR
)) + DeviceNode
->InstancePath
.Length
);
979 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
980 wcscat(KeyBuffer
, DeviceNode
->InstancePath
.Buffer
);
981 IopCreateDeviceKeyPath(KeyBuffer
);
982 ExFreePool(KeyBuffer
);
983 DeviceNode
->Flags
|= DNF_PROCESSED
;
985 return STATUS_SUCCESS
;
989 * IopActionConfigureChildServices
991 * Retrieve configuration for all (direct) child nodes of a parent node.
995 * Pointer to device node.
997 * Pointer to parent node to retrieve child node configuration for.
1000 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
1001 * when we reach a device node which is not a direct child of the device
1002 * node for which we configure child services for. Any errors that occur is
1003 * logged instead so that all child services have a chance of beeing
1008 IopActionConfigureChildServices(
1009 PDEVICE_NODE DeviceNode
,
1012 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1013 PDEVICE_NODE ParentDeviceNode
;
1014 PUNICODE_STRING Service
;
1017 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode
, Context
);
1019 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
1022 * We are called for the parent too, but we don't need to do special
1023 * handling for this node
1025 if (DeviceNode
== ParentDeviceNode
)
1027 DPRINT("Success\n");
1028 return STATUS_SUCCESS
;
1032 * Make sure this device node is a direct child of the parent device node
1033 * that is given as an argument
1035 if (DeviceNode
->Parent
!= ParentDeviceNode
)
1037 /* Stop the traversal immediately and indicate successful operation */
1039 return STATUS_UNSUCCESSFUL
;
1042 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
))
1045 * Retrieve configuration from Enum key
1048 Service
= &DeviceNode
->ServiceName
;
1050 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1051 RtlInitUnicodeString(Service
, NULL
);
1053 QueryTable
[0].Name
= L
"Service";
1054 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1055 QueryTable
[0].EntryContext
= Service
;
1057 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ENUM
,
1058 DeviceNode
->InstancePath
.Buffer
, QueryTable
, NULL
, NULL
);
1060 if (!NT_SUCCESS(Status
))
1062 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1063 /* FIXME: Log the error */
1064 CPRINT("Could not retrieve configuration for device %S (Status %x)\n",
1065 DeviceNode
->InstancePath
.Buffer
, Status
);
1066 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
1067 return STATUS_SUCCESS
;
1070 if (Service
->Buffer
== NULL
)
1072 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
1073 return STATUS_SUCCESS
;
1076 DPRINT("Got Service %S\n", Service
->Buffer
);
1079 return STATUS_SUCCESS
;
1083 * IopActionInitChildServices
1085 * Initialize the service for all (direct) child nodes of a parent node
1089 * Pointer to device node.
1091 * Pointer to parent node to initialize child node services for.
1093 * Load only driver marked as boot start.
1096 * If the driver image for a service is not loaded and initialized
1097 * it is done here too. We only return a status code indicating an
1098 * error (STATUS_UNSUCCESSFUL) when we reach a device node which is
1099 * not a direct child of the device node for which we initialize
1100 * child services for. Any errors that occur is logged instead so
1101 * that all child services have a chance of being initialized.
1105 IopActionInitChildServices(
1106 PDEVICE_NODE DeviceNode
,
1108 BOOLEAN BootDrivers
)
1110 PDEVICE_NODE ParentDeviceNode
;
1113 DPRINT("IopActionInitChildServices(%p, %p, %d)\n", DeviceNode
, Context
,
1116 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
1119 * We are called for the parent too, but we don't need to do special
1120 * handling for this node
1122 if (DeviceNode
== ParentDeviceNode
)
1124 DPRINT("Success\n");
1125 return STATUS_SUCCESS
;
1129 * Make sure this device node is a direct child of the parent device node
1130 * that is given as an argument
1133 if (DeviceNode
->Parent
!= ParentDeviceNode
)
1136 * Stop the traversal immediately and indicate unsuccessful operation
1139 return STATUS_UNSUCCESSFUL
;
1143 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
) &&
1144 !IopDeviceNodeHasFlag(DeviceNode
, DNF_ADDED
) &&
1145 !IopDeviceNodeHasFlag(DeviceNode
, DNF_STARTED
))
1147 PMODULE_OBJECT ModuleObject
;
1148 PDRIVER_OBJECT DriverObject
;
1150 Status
= IopLoadServiceModule(&DeviceNode
->ServiceName
, &ModuleObject
);
1151 if (NT_SUCCESS(Status
))
1153 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, FALSE
, &DriverObject
);
1154 if (NT_SUCCESS(Status
))
1156 /* Attach lower level filter drivers. */
1157 IopAttachFilterDrivers(DeviceNode
, TRUE
);
1158 /* Initialize the function driver for the device node */
1159 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
1160 if (NT_SUCCESS(Status
))
1162 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
1163 /* Attach upper level filter drivers. */
1164 IopAttachFilterDrivers(DeviceNode
, FALSE
);
1171 * Don't disable when trying to load only boot drivers
1175 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
1176 IopDeviceNodeSetFlag(DeviceNode
, DNF_START_FAILED
);
1178 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
1179 CPRINT("Initialization of service %S failed (Status %x)\n",
1180 DeviceNode
->ServiceName
.Buffer
, Status
);
1184 DPRINT("Service %S is disabled or already initialized\n",
1185 DeviceNode
->ServiceName
.Buffer
);
1188 return STATUS_SUCCESS
;
1192 * IopActionInitAllServices
1194 * Initialize the service for all (direct) child nodes of a parent node. This
1195 * function just calls IopActionInitChildServices with BootDrivers = FALSE.
1199 IopActionInitAllServices(
1200 PDEVICE_NODE DeviceNode
,
1203 return IopActionInitChildServices(DeviceNode
, Context
, FALSE
);
1207 * IopActionInitBootServices
1209 * Initialize the boot start services for all (direct) child nodes of a
1210 * parent node. This function just calls IopActionInitChildServices with
1211 * BootDrivers = TRUE.
1215 IopActionInitBootServices(
1216 PDEVICE_NODE DeviceNode
,
1219 return IopActionInitChildServices(DeviceNode
, Context
, TRUE
);
1223 * IopInitializePnpServices
1225 * Initialize services for discovered children
1229 * Top device node to start initializing services.
1232 * When set to TRUE, only drivers marked as boot start will
1233 * be loaded. Otherwise, all drivers will be loaded.
1240 IopInitializePnpServices(
1241 IN PDEVICE_NODE DeviceNode
,
1242 IN BOOLEAN BootDrivers
)
1244 DEVICETREE_TRAVERSE_CONTEXT Context
;
1246 DPRINT("IopInitializePnpServices(%p, %d)\n", DeviceNode
, BootDrivers
);
1250 IopInitDeviceTreeTraverseContext(
1253 IopActionInitBootServices
,
1257 IopInitDeviceTreeTraverseContext(
1260 IopActionInitAllServices
,
1264 return IopTraverseDeviceTree(&Context
);
1269 IopInvalidateDeviceRelations(
1270 IN PDEVICE_NODE DeviceNode
,
1271 IN DEVICE_RELATION_TYPE Type
)
1273 DEVICETREE_TRAVERSE_CONTEXT Context
;
1274 PDEVICE_RELATIONS DeviceRelations
;
1275 IO_STATUS_BLOCK IoStatusBlock
;
1276 PDEVICE_NODE ChildDeviceNode
;
1277 IO_STACK_LOCATION Stack
;
1279 OBJECT_ATTRIBUTES ObjectAttributes
;
1280 UNICODE_STRING LinkName
;
1285 DPRINT("DeviceNode %x\n", DeviceNode
);
1287 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
1289 Stack
.Parameters
.QueryDeviceRelations
.Type
= Type
/*BusRelations*/;
1291 Status
= IopInitiatePnpIrp(
1294 IRP_MN_QUERY_DEVICE_RELATIONS
,
1296 if (!NT_SUCCESS(Status
))
1298 DPRINT("IopInitiatePnpIrp() failed\n");
1302 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
1304 if ((!DeviceRelations
) || (DeviceRelations
->Count
<= 0))
1306 DPRINT("No PDOs\n");
1307 if (DeviceRelations
)
1309 ExFreePool(DeviceRelations
);
1311 return STATUS_SUCCESS
;
1314 DPRINT("Got %d PDOs\n", DeviceRelations
->Count
);
1317 * Create device nodes for all discovered devices
1320 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
1322 Status
= IopCreateDeviceNode(
1324 DeviceRelations
->Objects
[i
],
1326 DeviceNode
->Flags
|= DNF_ENUMERATED
;
1327 if (!NT_SUCCESS(Status
))
1329 DPRINT("No resources\n");
1330 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
1331 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
1332 ExFreePool(DeviceRelations
);
1333 return STATUS_INSUFFICIENT_RESOURCES
;
1336 ExFreePool(DeviceRelations
);
1339 * Retrieve information about all discovered children from the bus driver
1342 IopInitDeviceTreeTraverseContext(
1345 IopActionInterrogateDeviceStack
,
1348 Status
= IopTraverseDeviceTree(&Context
);
1349 if (!NT_SUCCESS(Status
))
1351 DPRINT("IopTraverseDeviceTree() failed with status (%x)\n", Status
);
1356 * Retrieve configuration from the registry for discovered children
1359 IopInitDeviceTreeTraverseContext(
1362 IopActionConfigureChildServices
,
1365 Status
= IopTraverseDeviceTree(&Context
);
1366 if (!NT_SUCCESS(Status
))
1368 DPRINT("IopTraverseDeviceTree() failed with status (%x)\n", Status
);
1373 * Get the state of the system boot. If the \\SystemRoot link isn't
1374 * created yet, we will assume that it's possible to load only boot
1378 RtlInitUnicodeString(&LinkName
, L
"\\SystemRoot");
1380 InitializeObjectAttributes(
1387 Status
= NtOpenFile(
1395 BootDrivers
= NT_SUCCESS(Status
) ? FALSE
: TRUE
;
1400 * Initialize services for discovered children. Only boot drivers will
1401 * be loaded from boot driver!
1404 Status
= IopInitializePnpServices(DeviceNode
, BootDrivers
);
1405 if (!NT_SUCCESS(Status
))
1407 DPRINT("IopInitializePnpServices() failed with status (%x)\n", Status
);
1411 return STATUS_SUCCESS
;
1420 DPRINT("PnpInit()\n");
1422 KeInitializeSpinLock(&IopDeviceTreeLock
);
1425 * Create root device node
1428 Status
= IopCreateDriverObject(&IopRootDriverObject
, NULL
, FALSE
, NULL
, 0);
1429 if (!NT_SUCCESS(Status
))
1431 CPRINT("IoCreateDriverObject() failed\n");
1432 KEBUGCHECK(PHASE1_INITIALIZATION_FAILED
);
1435 Status
= IoCreateDevice(IopRootDriverObject
, 0, NULL
, FILE_DEVICE_CONTROLLER
,
1437 if (!NT_SUCCESS(Status
))
1439 CPRINT("IoCreateDevice() failed\n");
1440 KEBUGCHECK(PHASE1_INITIALIZATION_FAILED
);
1443 Status
= IopCreateDeviceNode(NULL
, Pdo
, &IopRootDeviceNode
);
1444 if (!NT_SUCCESS(Status
))
1446 CPRINT("Insufficient resources\n");
1447 KEBUGCHECK(PHASE1_INITIALIZATION_FAILED
);
1450 IopRootDeviceNode
->Pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
1451 PnpRootDriverEntry(IopRootDriverObject
, NULL
);
1452 IopRootDriverObject
->DriverExtension
->AddDevice(
1453 IopRootDriverObject
,
1454 IopRootDeviceNode
->Pdo
);