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