[REACTOS] Cleanup INIT and some PAGE section allocations
[reactos.git] / ntoskrnl / io / pnpmgr / pnpinit.c
1 /*
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
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 typedef struct _IOPNP_DEVICE_EXTENSION
18 {
19 PWCHAR CompatibleIdList;
20 ULONG CompatibleIdListSize;
21 } IOPNP_DEVICE_EXTENSION, *PIOPNP_DEVICE_EXTENSION;
22
23 PUNICODE_STRING PiInitGroupOrderTable;
24 USHORT PiInitGroupOrderTableCount;
25 INTERFACE_TYPE PnpDefaultInterfaceType;
26 BOOLEAN PnPBootDriversLoaded = FALSE;
27
28 ARBITER_INSTANCE IopRootBusNumberArbiter;
29 ARBITER_INSTANCE IopRootIrqArbiter;
30 ARBITER_INSTANCE IopRootDmaArbiter;
31 ARBITER_INSTANCE IopRootMemArbiter;
32 ARBITER_INSTANCE IopRootPortArbiter;
33
34 extern KEVENT PiEnumerationFinished;
35
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);
41
42 /* FUNCTIONS ******************************************************************/
43
44 INTERFACE_TYPE
45 NTAPI
46 IopDetermineDefaultInterfaceType(VOID)
47 {
48 /* FIXME: ReactOS doesn't support MicroChannel yet */
49 return Isa;
50 }
51
52 NTSTATUS
53 NTAPI
54 IopInitializeArbiters(VOID)
55 {
56 NTSTATUS Status;
57
58 Status = IopPortInitialize();
59 if (!NT_SUCCESS(Status))
60 {
61 DPRINT1("IopPortInitialize() return %X\n", Status);
62 return Status;
63 }
64
65 Status = IopMemInitialize();
66 if (!NT_SUCCESS(Status))
67 {
68 DPRINT1("IopMemInitialize() return %X\n", Status);
69 return Status;
70 }
71
72 Status = IopDmaInitialize();
73 if (!NT_SUCCESS(Status))
74 {
75 DPRINT1("IopDmaInitialize() return %X\n", Status);
76 return Status;
77 }
78
79 Status = IopIrqInitialize();
80 if (!NT_SUCCESS(Status))
81 {
82 DPRINT1("IopIrqInitialize() return %X\n", Status);
83 return Status;
84 }
85
86 Status = IopBusNumberInitialize();
87 if (!NT_SUCCESS(Status))
88 {
89 DPRINT1("IopBusNumberInitialize() return %X\n", Status);
90 }
91
92 return Status;
93 }
94
95
96 CODE_SEG("INIT")
97 NTSTATUS
98 NTAPI
99 PiInitCacheGroupInformation(VOID)
100 {
101 HANDLE KeyHandle;
102 NTSTATUS Status;
103 PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
104 PUNICODE_STRING GroupTable;
105 ULONG Count;
106 UNICODE_STRING GroupString =
107 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet"
108 L"\\Control\\ServiceGroupOrder");
109
110 /* Open the registry key */
111 Status = IopOpenRegistryKeyEx(&KeyHandle,
112 NULL,
113 &GroupString,
114 KEY_READ);
115 if (NT_SUCCESS(Status))
116 {
117 /* Get the list */
118 Status = IopGetRegistryValue(KeyHandle, L"List", &KeyValueInformation);
119 ZwClose(KeyHandle);
120
121 /* Make sure we got it */
122 if (NT_SUCCESS(Status))
123 {
124 /* Make sure it's valid */
125 if ((KeyValueInformation->Type == REG_MULTI_SZ) &&
126 (KeyValueInformation->DataLength))
127 {
128 /* Convert it to unicode strings */
129 Status = PnpRegMultiSzToUnicodeStrings(KeyValueInformation,
130 &GroupTable,
131 &Count);
132
133 /* Cache it for later */
134 PiInitGroupOrderTable = GroupTable;
135 PiInitGroupOrderTableCount = (USHORT)Count;
136 }
137 else
138 {
139 /* Fail */
140 Status = STATUS_UNSUCCESSFUL;
141 }
142
143 /* Free the information */
144 ExFreePool(KeyValueInformation);
145 }
146 }
147
148 /* Return status */
149 return Status;
150 }
151
152 USHORT
153 NTAPI
154 PpInitGetGroupOrderIndex(IN HANDLE ServiceHandle)
155 {
156 NTSTATUS Status;
157 PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
158 USHORT i;
159 PVOID Buffer;
160 UNICODE_STRING Group;
161 PAGED_CODE();
162
163 /* Make sure we have a cache */
164 if (!PiInitGroupOrderTable) return -1;
165
166 /* If we don't have a handle, the rest is easy -- return the count */
167 if (!ServiceHandle) return PiInitGroupOrderTableCount + 1;
168
169 /* Otherwise, get the group value */
170 Status = IopGetRegistryValue(ServiceHandle, L"Group", &KeyValueInformation);
171 if (!NT_SUCCESS(Status)) return PiInitGroupOrderTableCount;
172
173 /* Make sure we have a valid string */
174 ASSERT(KeyValueInformation->Type == REG_SZ);
175 ASSERT(KeyValueInformation->DataLength);
176
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;
182
183 /* Loop the groups */
184 for (i = 0; i < PiInitGroupOrderTableCount; i++)
185 {
186 /* Try to find a match */
187 if (RtlEqualUnicodeString(&Group, &PiInitGroupOrderTable[i], TRUE)) break;
188 }
189
190 /* We're done */
191 ExFreePool(KeyValueInformation);
192 return i;
193 }
194
195 USHORT
196 NTAPI
197 PipGetDriverTagPriority(IN HANDLE ServiceHandle)
198 {
199 NTSTATUS Status;
200 HANDLE KeyHandle = NULL;
201 PKEY_VALUE_FULL_INFORMATION KeyValueInformation = NULL;
202 PKEY_VALUE_FULL_INFORMATION KeyValueInformationTag;
203 PKEY_VALUE_FULL_INFORMATION KeyValueInformationGroupOrderList;
204 PVOID Buffer;
205 UNICODE_STRING Group;
206 PULONG GroupOrder;
207 ULONG Count, Tag = 0;
208 USHORT i = -1;
209 UNICODE_STRING GroupString =
210 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet"
211 L"\\Control\\ServiceGroupOrder");
212
213 /* Open the key */
214 Status = IopOpenRegistryKeyEx(&KeyHandle, NULL, &GroupString, KEY_READ);
215 if (!NT_SUCCESS(Status)) goto Quickie;
216
217 /* Read the group */
218 Status = IopGetRegistryValue(ServiceHandle, L"Group", &KeyValueInformation);
219 if (!NT_SUCCESS(Status)) goto Quickie;
220
221 /* Make sure we have a group */
222 if ((KeyValueInformation->Type == REG_SZ) &&
223 (KeyValueInformation->DataLength))
224 {
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;
230 }
231
232 /* Now read the tag */
233 Status = IopGetRegistryValue(ServiceHandle, L"Tag", &KeyValueInformationTag);
234 if (!NT_SUCCESS(Status)) goto Quickie;
235
236 /* Make sure we have a tag */
237 if ((KeyValueInformationTag->Type == REG_DWORD) &&
238 (KeyValueInformationTag->DataLength))
239 {
240 /* Read it */
241 Tag = *(PULONG)((ULONG_PTR)KeyValueInformationTag +
242 KeyValueInformationTag->DataOffset);
243 }
244
245 /* We can get rid of this now */
246 ExFreePool(KeyValueInformationTag);
247
248 /* Now let's read the group's tag order */
249 Status = IopGetRegistryValue(KeyHandle,
250 Group.Buffer,
251 &KeyValueInformationGroupOrderList);
252
253 /* We can get rid of this now */
254 Quickie:
255 if (KeyValueInformation) ExFreePool(KeyValueInformation);
256 if (KeyHandle) NtClose(KeyHandle);
257 if (!NT_SUCCESS(Status)) return -1;
258
259 /* We're on the success path -- validate the tag order*/
260 if ((KeyValueInformationGroupOrderList->Type == REG_BINARY) &&
261 (KeyValueInformationGroupOrderList->DataLength))
262 {
263 /* Get the order array */
264 GroupOrder = (PULONG)((ULONG_PTR)KeyValueInformationGroupOrderList +
265 KeyValueInformationGroupOrderList->DataOffset);
266
267 /* Get the count */
268 Count = *GroupOrder;
269 ASSERT(((Count + 1) * sizeof(ULONG)) <=
270 KeyValueInformationGroupOrderList->DataLength);
271
272 /* Now loop each tag */
273 GroupOrder++;
274 for (i = 1; i <= Count; i++)
275 {
276 /* If we found it, we're out */
277 if (Tag == *GroupOrder) break;
278
279 /* Try the next one */
280 GroupOrder++;
281 }
282 }
283
284 /* Last buffer to free */
285 ExFreePool(KeyValueInformationGroupOrderList);
286 return i;
287 }
288
289 NTSTATUS
290 NTAPI
291 PipCallDriverAddDevice(IN PDEVICE_NODE DeviceNode,
292 IN BOOLEAN LoadDriver,
293 IN PDRIVER_OBJECT DriverObject)
294 {
295 NTSTATUS Status;
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;
303 PWCHAR Buffer;
304
305 /* Open enumeration root key */
306 Status = IopOpenRegistryKeyEx(&EnumRootKey,
307 NULL,
308 &EnumRoot,
309 KEY_READ);
310 if (!NT_SUCCESS(Status))
311 {
312 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
313 &EnumRoot, Status);
314 return Status;
315 }
316
317 /* Open instance subkey */
318 Status = IopOpenRegistryKeyEx(&SubKey,
319 EnumRootKey,
320 &DeviceNode->InstancePath,
321 KEY_READ);
322 ZwClose(EnumRootKey);
323 if (!NT_SUCCESS(Status))
324 {
325 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
326 &DeviceNode->InstancePath, Status);
327 return Status;
328 }
329
330 /* Get class GUID */
331 Status = IopGetRegistryValue(SubKey,
332 REGSTR_VAL_CLASSGUID,
333 &KeyValueInformation);
334 if (NT_SUCCESS(Status))
335 {
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;
341
342 /* Open the key */
343 Status = IopOpenRegistryKeyEx(&ControlKey,
344 NULL,
345 &ControlClass,
346 KEY_READ);
347 if (!NT_SUCCESS(Status))
348 {
349 /* No class key */
350 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
351 &ControlClass, Status);
352 }
353 else
354 {
355 /* Open the class key */
356 Status = IopOpenRegistryKeyEx(&ClassKey,
357 ControlKey,
358 &ClassGuid,
359 KEY_READ);
360 ZwClose(ControlKey);
361 if (!NT_SUCCESS(Status))
362 {
363 /* No class key */
364 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
365 &ClassGuid, Status);
366 }
367 }
368
369 /* Check if we made it till here */
370 if (ClassKey)
371 {
372 /* Get the device properties */
373 RtlInitUnicodeString(&Properties, REGSTR_KEY_DEVICE_PROPERTIES);
374 Status = IopOpenRegistryKeyEx(&PropertiesKey,
375 ClassKey,
376 &Properties,
377 KEY_READ);
378 if (!NT_SUCCESS(Status))
379 {
380 /* No properties */
381 DPRINT("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
382 &Properties, Status);
383 PropertiesKey = NULL;
384 }
385 else
386 {
387 ZwClose(PropertiesKey);
388 }
389 }
390
391 /* Free the registry data */
392 ExFreePool(KeyValueInformation);
393 }
394
395 /* Do ReactOS-style setup */
396 Status = IopAttachFilterDrivers(DeviceNode, SubKey, ClassKey, TRUE);
397 if (!NT_SUCCESS(Status))
398 {
399 IopRemoveDevice(DeviceNode);
400 goto Exit;
401 }
402
403 Status = IopInitializeDevice(DeviceNode, DriverObject);
404 if (!NT_SUCCESS(Status))
405 {
406 goto Exit;
407 }
408
409 Status = IopAttachFilterDrivers(DeviceNode, SubKey, ClassKey, FALSE);
410 if (!NT_SUCCESS(Status))
411 {
412 IopRemoveDevice(DeviceNode);
413 goto Exit;
414 }
415
416 Status = IopStartDevice(DeviceNode);
417
418 Exit:
419 /* Close keys and return status */
420 ZwClose(SubKey);
421 if (ClassKey != NULL)
422 {
423 ZwClose(ClassKey);
424 }
425 return Status;
426 }
427
428 CODE_SEG("INIT")
429 NTSTATUS
430 NTAPI
431 IopInitializePlugPlayServices(VOID)
432 {
433 NTSTATUS Status;
434 ULONG Disposition;
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");
438 PDEVICE_OBJECT Pdo;
439
440 /* Initialize locks and such */
441 KeInitializeSpinLock(&IopDeviceTreeLock);
442 KeInitializeSpinLock(&IopDeviceActionLock);
443 InitializeListHead(&IopDeviceActionRequestList);
444 KeInitializeEvent(&PiEnumerationFinished, NotificationEvent, TRUE);
445
446 /* Get the default interface */
447 PnpDefaultInterfaceType = IopDetermineDefaultInterfaceType();
448
449 /* Initialize arbiters */
450 Status = IopInitializeArbiters();
451 if (!NT_SUCCESS(Status)) return Status;
452
453 /* Setup the group cache */
454 Status = PiInitCacheGroupInformation();
455 if (!NT_SUCCESS(Status)) return Status;
456
457 /* Open the current control set */
458 Status = IopOpenRegistryKeyEx(&KeyHandle,
459 NULL,
460 &KeyName,
461 KEY_ALL_ACCESS);
462 if (!NT_SUCCESS(Status)) return Status;
463
464 /* Create the control key */
465 RtlInitUnicodeString(&KeyName, L"Control");
466 Status = IopCreateRegistryKeyEx(&ControlHandle,
467 KeyHandle,
468 &KeyName,
469 KEY_ALL_ACCESS,
470 REG_OPTION_NON_VOLATILE,
471 &Disposition);
472 if (!NT_SUCCESS(Status)) return Status;
473
474 /* Check if it's a new key */
475 if (Disposition == REG_CREATED_NEW_KEY)
476 {
477 HANDLE DeviceClassesHandle;
478
479 /* Create the device classes key */
480 RtlInitUnicodeString(&KeyName, L"DeviceClasses");
481 Status = IopCreateRegistryKeyEx(&DeviceClassesHandle,
482 ControlHandle,
483 &KeyName,
484 KEY_ALL_ACCESS,
485 REG_OPTION_NON_VOLATILE,
486 &Disposition);
487 if (!NT_SUCCESS(Status)) return Status;
488
489 ZwClose(DeviceClassesHandle);
490 }
491
492 ZwClose(ControlHandle);
493
494 /* Create the enum key */
495 RtlInitUnicodeString(&KeyName, REGSTR_KEY_ENUM);
496 Status = IopCreateRegistryKeyEx(&EnumHandle,
497 KeyHandle,
498 &KeyName,
499 KEY_ALL_ACCESS,
500 REG_OPTION_NON_VOLATILE,
501 &Disposition);
502 if (!NT_SUCCESS(Status)) return Status;
503
504 /* Check if it's a new key */
505 if (Disposition == REG_CREATED_NEW_KEY)
506 {
507 /* FIXME: DACLs */
508 }
509
510 /* Create the root key */
511 ParentHandle = EnumHandle;
512 RtlInitUnicodeString(&KeyName, REGSTR_KEY_ROOTENUM);
513 Status = IopCreateRegistryKeyEx(&EnumHandle,
514 ParentHandle,
515 &KeyName,
516 KEY_ALL_ACCESS,
517 REG_OPTION_NON_VOLATILE,
518 &Disposition);
519 NtClose(ParentHandle);
520 if (!NT_SUCCESS(Status)) return Status;
521 NtClose(EnumHandle);
522
523 /* Open the root key now */
524 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
525 Status = IopOpenRegistryKeyEx(&EnumHandle,
526 NULL,
527 &KeyName,
528 KEY_ALL_ACCESS);
529 if (NT_SUCCESS(Status))
530 {
531 /* Create the root dev node */
532 RtlInitUnicodeString(&KeyName, REGSTR_VAL_ROOT_DEVNODE);
533 Status = IopCreateRegistryKeyEx(&TreeHandle,
534 EnumHandle,
535 &KeyName,
536 KEY_ALL_ACCESS,
537 REG_OPTION_NON_VOLATILE,
538 NULL);
539 NtClose(EnumHandle);
540 if (NT_SUCCESS(Status)) NtClose(TreeHandle);
541 }
542
543 /* Create the root driver */
544 Status = IoCreateDriver(&PnpManagerDriverName, PnpRootDriverEntry);
545 if (!NT_SUCCESS(Status))
546 {
547 DPRINT1("IoCreateDriverObject() failed\n");
548 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
549 }
550
551 /* Create the root PDO */
552 Status = IoCreateDevice(IopRootDriverObject,
553 sizeof(IOPNP_DEVICE_EXTENSION),
554 NULL,
555 FILE_DEVICE_CONTROLLER,
556 0,
557 FALSE,
558 &Pdo);
559 if (!NT_SUCCESS(Status))
560 {
561 DPRINT1("IoCreateDevice() failed\n");
562 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
563 }
564
565 /* This is a bus enumerated device */
566 Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
567
568 /* Create the root device node */
569 IopRootDeviceNode = PipAllocateDeviceNode(Pdo);
570
571 /* Set flags */
572 IopRootDeviceNode->Flags |= DNF_STARTED + DNF_PROCESSED + DNF_ENUMERATED +
573 DNF_MADEUP + DNF_NO_RESOURCE_REQUIRED +
574 DNF_ADDED;
575
576 /* Create instance path */
577 RtlCreateUnicodeString(&IopRootDeviceNode->InstancePath,
578 REGSTR_VAL_ROOT_DEVNODE);
579
580 /* Call the add device routine */
581 IopRootDriverObject->DriverExtension->AddDevice(IopRootDriverObject,
582 IopRootDeviceNode->PhysicalDeviceObject);
583
584 /* Initialize PnP-Event notification support */
585 Status = IopInitPlugPlayEvents();
586 if (!NT_SUCCESS(Status)) return Status;
587
588 /* Report the device to the user-mode pnp manager */
589 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
590 &IopRootDeviceNode->InstancePath);
591
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);
596
597 /* Launch the firmware mapper */
598 Status = IopUpdateRootKey();
599 if (!NT_SUCCESS(Status)) return Status;
600
601 /* Close the handle to the control set */
602 NtClose(KeyHandle);
603
604 /* Initialize PnP root relations (this is a syncronous operation) */
605 PiQueueDeviceAction(IopRootDeviceNode->PhysicalDeviceObject, PiActionEnumRootDevices, NULL, NULL);
606
607 /* We made it */
608 return STATUS_SUCCESS;
609 }
610
611 /* EOF */