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