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