[NTOS] Remove some hacks that are not needed anymore, since a real registry hive...
[reactos.git] / ntoskrnl / io / pnpmgr / pnpinit.c
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 /* 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 NTSTATUS
378 NTAPI
379 INIT_FUNCTION
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 */