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