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