[NTOS:PNP] Rename IopDeviceRelations* to IopDeviceAction*. CORE-10456
[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 /* 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 */