xref: /reactos/ntoskrnl/io/pnpmgr/pnpinit.c (revision 8a978a17)
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 */
612