2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpinit.c
5 * PURPOSE: PnP Initialization Code
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 /* GLOBALS ********************************************************************/
17 typedef struct _IOPNP_DEVICE_EXTENSION
19 PWCHAR CompatibleIdList
;
20 ULONG CompatibleIdListSize
;
21 } IOPNP_DEVICE_EXTENSION
, *PIOPNP_DEVICE_EXTENSION
;
23 PUNICODE_STRING PiInitGroupOrderTable
;
24 USHORT PiInitGroupOrderTableCount
;
25 INTERFACE_TYPE PnpDefaultInterfaceType
;
26 BOOLEAN PnPBootDriversLoaded
= FALSE
;
28 ARBITER_INSTANCE IopRootBusNumberArbiter
;
29 ARBITER_INSTANCE IopRootIrqArbiter
;
30 ARBITER_INSTANCE IopRootDmaArbiter
;
31 ARBITER_INSTANCE IopRootMemArbiter
;
32 ARBITER_INSTANCE IopRootPortArbiter
;
34 extern KEVENT PiEnumerationFinished
;
36 NTSTATUS NTAPI
IopPortInitialize(VOID
);
37 NTSTATUS NTAPI
IopMemInitialize(VOID
);
38 NTSTATUS NTAPI
IopDmaInitialize(VOID
);
39 NTSTATUS NTAPI
IopIrqInitialize(VOID
);
40 NTSTATUS NTAPI
IopBusNumberInitialize(VOID
);
42 /* FUNCTIONS ******************************************************************/
46 IopDetermineDefaultInterfaceType(VOID
)
48 /* FIXME: ReactOS doesn't support MicroChannel yet */
54 IopInitializeArbiters(VOID
)
58 Status
= IopPortInitialize();
59 if (!NT_SUCCESS(Status
))
61 DPRINT1("IopPortInitialize() return %X\n", Status
);
65 Status
= IopMemInitialize();
66 if (!NT_SUCCESS(Status
))
68 DPRINT1("IopMemInitialize() return %X\n", Status
);
72 Status
= IopDmaInitialize();
73 if (!NT_SUCCESS(Status
))
75 DPRINT1("IopDmaInitialize() return %X\n", Status
);
79 Status
= IopIrqInitialize();
80 if (!NT_SUCCESS(Status
))
82 DPRINT1("IopIrqInitialize() return %X\n", Status
);
86 Status
= IopBusNumberInitialize();
87 if (!NT_SUCCESS(Status
))
89 DPRINT1("IopBusNumberInitialize() return %X\n", Status
);
99 PiInitCacheGroupInformation(VOID
)
103 PKEY_VALUE_FULL_INFORMATION KeyValueInformation
;
104 PUNICODE_STRING GroupTable
;
106 UNICODE_STRING GroupString
=
107 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet"
108 L
"\\Control\\ServiceGroupOrder");
110 /* Open the registry key */
111 Status
= IopOpenRegistryKeyEx(&KeyHandle
,
115 if (NT_SUCCESS(Status
))
118 Status
= IopGetRegistryValue(KeyHandle
, L
"List", &KeyValueInformation
);
121 /* Make sure we got it */
122 if (NT_SUCCESS(Status
))
124 /* Make sure it's valid */
125 if ((KeyValueInformation
->Type
== REG_MULTI_SZ
) &&
126 (KeyValueInformation
->DataLength
))
128 /* Convert it to unicode strings */
129 Status
= PnpRegMultiSzToUnicodeStrings(KeyValueInformation
,
133 /* Cache it for later */
134 PiInitGroupOrderTable
= GroupTable
;
135 PiInitGroupOrderTableCount
= (USHORT
)Count
;
140 Status
= STATUS_UNSUCCESSFUL
;
143 /* Free the information */
144 ExFreePool(KeyValueInformation
);
154 PpInitGetGroupOrderIndex(IN HANDLE ServiceHandle
)
157 PKEY_VALUE_FULL_INFORMATION KeyValueInformation
;
160 UNICODE_STRING Group
;
163 /* Make sure we have a cache */
164 if (!PiInitGroupOrderTable
) return -1;
166 /* If we don't have a handle, the rest is easy -- return the count */
167 if (!ServiceHandle
) return PiInitGroupOrderTableCount
+ 1;
169 /* Otherwise, get the group value */
170 Status
= IopGetRegistryValue(ServiceHandle
, L
"Group", &KeyValueInformation
);
171 if (!NT_SUCCESS(Status
)) return PiInitGroupOrderTableCount
;
173 /* Make sure we have a valid string */
174 ASSERT(KeyValueInformation
->Type
== REG_SZ
);
175 ASSERT(KeyValueInformation
->DataLength
);
177 /* Convert to unicode string */
178 Buffer
= (PVOID
)((ULONG_PTR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
);
179 PnpRegSzToString(Buffer
, KeyValueInformation
->DataLength
, &Group
.Length
);
180 Group
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
181 Group
.Buffer
= Buffer
;
183 /* Loop the groups */
184 for (i
= 0; i
< PiInitGroupOrderTableCount
; i
++)
186 /* Try to find a match */
187 if (RtlEqualUnicodeString(&Group
, &PiInitGroupOrderTable
[i
], TRUE
)) break;
191 ExFreePool(KeyValueInformation
);
197 PipGetDriverTagPriority(IN HANDLE ServiceHandle
)
200 HANDLE KeyHandle
= NULL
;
201 PKEY_VALUE_FULL_INFORMATION KeyValueInformation
= NULL
;
202 PKEY_VALUE_FULL_INFORMATION KeyValueInformationTag
;
203 PKEY_VALUE_FULL_INFORMATION KeyValueInformationGroupOrderList
;
205 UNICODE_STRING Group
;
207 ULONG Count
, Tag
= 0;
209 UNICODE_STRING GroupString
=
210 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet"
211 L
"\\Control\\ServiceGroupOrder");
214 Status
= IopOpenRegistryKeyEx(&KeyHandle
, NULL
, &GroupString
, KEY_READ
);
215 if (!NT_SUCCESS(Status
)) goto Quickie
;
218 Status
= IopGetRegistryValue(ServiceHandle
, L
"Group", &KeyValueInformation
);
219 if (!NT_SUCCESS(Status
)) goto Quickie
;
221 /* Make sure we have a group */
222 if ((KeyValueInformation
->Type
== REG_SZ
) &&
223 (KeyValueInformation
->DataLength
))
225 /* Convert to unicode string */
226 Buffer
= (PVOID
)((ULONG_PTR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
);
227 PnpRegSzToString(Buffer
, KeyValueInformation
->DataLength
, &Group
.Length
);
228 Group
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
229 Group
.Buffer
= Buffer
;
232 /* Now read the tag */
233 Status
= IopGetRegistryValue(ServiceHandle
, L
"Tag", &KeyValueInformationTag
);
234 if (!NT_SUCCESS(Status
)) goto Quickie
;
236 /* Make sure we have a tag */
237 if ((KeyValueInformationTag
->Type
== REG_DWORD
) &&
238 (KeyValueInformationTag
->DataLength
))
241 Tag
= *(PULONG
)((ULONG_PTR
)KeyValueInformationTag
+
242 KeyValueInformationTag
->DataOffset
);
245 /* We can get rid of this now */
246 ExFreePool(KeyValueInformationTag
);
248 /* Now let's read the group's tag order */
249 Status
= IopGetRegistryValue(KeyHandle
,
251 &KeyValueInformationGroupOrderList
);
253 /* We can get rid of this now */
255 if (KeyValueInformation
) ExFreePool(KeyValueInformation
);
256 if (KeyHandle
) NtClose(KeyHandle
);
257 if (!NT_SUCCESS(Status
)) return -1;
259 /* We're on the success path -- validate the tag order*/
260 if ((KeyValueInformationGroupOrderList
->Type
== REG_BINARY
) &&
261 (KeyValueInformationGroupOrderList
->DataLength
))
263 /* Get the order array */
264 GroupOrder
= (PULONG
)((ULONG_PTR
)KeyValueInformationGroupOrderList
+
265 KeyValueInformationGroupOrderList
->DataOffset
);
269 ASSERT(((Count
+ 1) * sizeof(ULONG
)) <=
270 KeyValueInformationGroupOrderList
->DataLength
);
272 /* Now loop each tag */
274 for (i
= 1; i
<= Count
; i
++)
276 /* If we found it, we're out */
277 if (Tag
== *GroupOrder
) break;
279 /* Try the next one */
284 /* Last buffer to free */
285 ExFreePool(KeyValueInformationGroupOrderList
);
291 PipCallDriverAddDevice(IN PDEVICE_NODE DeviceNode
,
292 IN BOOLEAN LoadDriver
,
293 IN PDRIVER_OBJECT DriverObject
)
296 HANDLE EnumRootKey
, SubKey
;
297 HANDLE ControlKey
, ClassKey
= NULL
, PropertiesKey
;
298 UNICODE_STRING ClassGuid
, Properties
;
299 UNICODE_STRING EnumRoot
= RTL_CONSTANT_STRING(ENUM_ROOT
);
300 UNICODE_STRING ControlClass
=
301 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
302 PKEY_VALUE_FULL_INFORMATION KeyValueInformation
= NULL
;
305 /* Open enumeration root key */
306 Status
= IopOpenRegistryKeyEx(&EnumRootKey
,
310 if (!NT_SUCCESS(Status
))
312 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
317 /* Open instance subkey */
318 Status
= IopOpenRegistryKeyEx(&SubKey
,
320 &DeviceNode
->InstancePath
,
322 ZwClose(EnumRootKey
);
323 if (!NT_SUCCESS(Status
))
325 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
326 &DeviceNode
->InstancePath
, Status
);
331 Status
= IopGetRegistryValue(SubKey
,
332 REGSTR_VAL_CLASSGUID
,
333 &KeyValueInformation
);
334 if (NT_SUCCESS(Status
))
336 /* Convert to unicode string */
337 Buffer
= (PVOID
)((ULONG_PTR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
);
338 PnpRegSzToString(Buffer
, KeyValueInformation
->DataLength
, &ClassGuid
.Length
);
339 ClassGuid
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
340 ClassGuid
.Buffer
= Buffer
;
343 Status
= IopOpenRegistryKeyEx(&ControlKey
,
347 if (!NT_SUCCESS(Status
))
350 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
351 &ControlClass
, Status
);
355 /* Open the class key */
356 Status
= IopOpenRegistryKeyEx(&ClassKey
,
361 if (!NT_SUCCESS(Status
))
364 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
369 /* Check if we made it till here */
372 /* Get the device properties */
373 RtlInitUnicodeString(&Properties
, REGSTR_KEY_DEVICE_PROPERTIES
);
374 Status
= IopOpenRegistryKeyEx(&PropertiesKey
,
378 if (!NT_SUCCESS(Status
))
381 DPRINT("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
382 &Properties
, Status
);
383 PropertiesKey
= NULL
;
387 ZwClose(PropertiesKey
);
391 /* Free the registry data */
392 ExFreePool(KeyValueInformation
);
395 /* Do ReactOS-style setup */
396 Status
= IopAttachFilterDrivers(DeviceNode
, SubKey
, ClassKey
, TRUE
);
397 if (!NT_SUCCESS(Status
))
399 IopRemoveDevice(DeviceNode
);
403 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
404 if (!NT_SUCCESS(Status
))
409 Status
= IopAttachFilterDrivers(DeviceNode
, SubKey
, ClassKey
, FALSE
);
410 if (!NT_SUCCESS(Status
))
412 IopRemoveDevice(DeviceNode
);
416 Status
= IopStartDevice(DeviceNode
);
419 /* Close keys and return status */
421 if (ClassKey
!= NULL
)
431 IopInitializePlugPlayServices(VOID
)
435 HANDLE KeyHandle
, EnumHandle
, ParentHandle
, TreeHandle
, ControlHandle
;
436 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET");
437 UNICODE_STRING PnpManagerDriverName
= RTL_CONSTANT_STRING(DRIVER_ROOT_NAME L
"PnpManager");
440 /* Initialize locks and such */
441 KeInitializeSpinLock(&IopDeviceTreeLock
);
442 KeInitializeSpinLock(&IopDeviceActionLock
);
443 InitializeListHead(&IopDeviceActionRequestList
);
444 KeInitializeEvent(&PiEnumerationFinished
, NotificationEvent
, TRUE
);
446 /* Get the default interface */
447 PnpDefaultInterfaceType
= IopDetermineDefaultInterfaceType();
449 /* Initialize arbiters */
450 Status
= IopInitializeArbiters();
451 if (!NT_SUCCESS(Status
)) return Status
;
453 /* Setup the group cache */
454 Status
= PiInitCacheGroupInformation();
455 if (!NT_SUCCESS(Status
)) return Status
;
457 /* Open the current control set */
458 Status
= IopOpenRegistryKeyEx(&KeyHandle
,
462 if (!NT_SUCCESS(Status
)) return Status
;
464 /* Create the control key */
465 RtlInitUnicodeString(&KeyName
, L
"Control");
466 Status
= IopCreateRegistryKeyEx(&ControlHandle
,
470 REG_OPTION_NON_VOLATILE
,
472 if (!NT_SUCCESS(Status
)) return Status
;
474 /* Check if it's a new key */
475 if (Disposition
== REG_CREATED_NEW_KEY
)
477 HANDLE DeviceClassesHandle
;
479 /* Create the device classes key */
480 RtlInitUnicodeString(&KeyName
, L
"DeviceClasses");
481 Status
= IopCreateRegistryKeyEx(&DeviceClassesHandle
,
485 REG_OPTION_NON_VOLATILE
,
487 if (!NT_SUCCESS(Status
)) return Status
;
489 ZwClose(DeviceClassesHandle
);
492 ZwClose(ControlHandle
);
494 /* Create the enum key */
495 RtlInitUnicodeString(&KeyName
, REGSTR_KEY_ENUM
);
496 Status
= IopCreateRegistryKeyEx(&EnumHandle
,
500 REG_OPTION_NON_VOLATILE
,
502 if (!NT_SUCCESS(Status
)) return Status
;
504 /* Check if it's a new key */
505 if (Disposition
== REG_CREATED_NEW_KEY
)
510 /* Create the root key */
511 ParentHandle
= EnumHandle
;
512 RtlInitUnicodeString(&KeyName
, REGSTR_KEY_ROOTENUM
);
513 Status
= IopCreateRegistryKeyEx(&EnumHandle
,
517 REG_OPTION_NON_VOLATILE
,
519 NtClose(ParentHandle
);
520 if (!NT_SUCCESS(Status
)) return Status
;
523 /* Open the root key now */
524 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
525 Status
= IopOpenRegistryKeyEx(&EnumHandle
,
529 if (NT_SUCCESS(Status
))
531 /* Create the root dev node */
532 RtlInitUnicodeString(&KeyName
, REGSTR_VAL_ROOT_DEVNODE
);
533 Status
= IopCreateRegistryKeyEx(&TreeHandle
,
537 REG_OPTION_NON_VOLATILE
,
540 if (NT_SUCCESS(Status
)) NtClose(TreeHandle
);
543 /* Create the root driver */
544 Status
= IoCreateDriver(&PnpManagerDriverName
, PnpRootDriverEntry
);
545 if (!NT_SUCCESS(Status
))
547 DPRINT1("IoCreateDriverObject() failed\n");
548 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
551 /* Create the root PDO */
552 Status
= IoCreateDevice(IopRootDriverObject
,
553 sizeof(IOPNP_DEVICE_EXTENSION
),
555 FILE_DEVICE_CONTROLLER
,
559 if (!NT_SUCCESS(Status
))
561 DPRINT1("IoCreateDevice() failed\n");
562 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
565 /* This is a bus enumerated device */
566 Pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
568 /* Create the root device node */
569 IopRootDeviceNode
= PipAllocateDeviceNode(Pdo
);
572 IopRootDeviceNode
->Flags
|= DNF_STARTED
+ DNF_PROCESSED
+ DNF_ENUMERATED
+
573 DNF_MADEUP
+ DNF_NO_RESOURCE_REQUIRED
+
576 /* Create instance path */
577 RtlCreateUnicodeString(&IopRootDeviceNode
->InstancePath
,
578 REGSTR_VAL_ROOT_DEVNODE
);
580 /* Call the add device routine */
581 IopRootDriverObject
->DriverExtension
->AddDevice(IopRootDriverObject
,
582 IopRootDeviceNode
->PhysicalDeviceObject
);
584 /* Initialize PnP-Event notification support */
585 Status
= IopInitPlugPlayEvents();
586 if (!NT_SUCCESS(Status
)) return Status
;
588 /* Report the device to the user-mode pnp manager */
589 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL
,
590 &IopRootDeviceNode
->InstancePath
);
592 /* Initialize the Bus Type GUID List */
593 PnpBusTypeGuidList
= ExAllocatePool(PagedPool
, sizeof(IO_BUS_TYPE_GUID_LIST
));
594 RtlZeroMemory(PnpBusTypeGuidList
, sizeof(IO_BUS_TYPE_GUID_LIST
));
595 ExInitializeFastMutex(&PnpBusTypeGuidList
->Lock
);
597 /* Launch the firmware mapper */
598 Status
= IopUpdateRootKey();
599 if (!NT_SUCCESS(Status
)) return Status
;
601 /* Close the handle to the control set */
604 /* Initialize PnP root relations (this is a syncronous operation) */
605 PiQueueDeviceAction(IopRootDeviceNode
->PhysicalDeviceObject
, PiActionEnumRootDevices
, NULL
, NULL
);
608 return STATUS_SUCCESS
;