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