* Sync up to trunk head (r64921).
[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
389 /* Get the default interface */
390 PnpDefaultInterfaceType = IopDetermineDefaultInterfaceType();
391
392 /* Initialize arbiters */
393 Status = IopInitializeArbiters();
394 if (!NT_SUCCESS(Status)) return Status;
395
396 /* Setup the group cache */
397 Status = PiInitCacheGroupInformation();
398 if (!NT_SUCCESS(Status)) return Status;
399
400 /* Open the current control set */
401 Status = IopOpenRegistryKeyEx(&KeyHandle,
402 NULL,
403 &KeyName,
404 KEY_ALL_ACCESS);
405 if (!NT_SUCCESS(Status)) return Status;
406
407 /* Create the control key */
408 RtlInitUnicodeString(&KeyName, L"Control");
409 Status = IopCreateRegistryKeyEx(&ControlHandle,
410 KeyHandle,
411 &KeyName,
412 KEY_ALL_ACCESS,
413 REG_OPTION_NON_VOLATILE,
414 &Disposition);
415 if (!NT_SUCCESS(Status)) return Status;
416
417 /* Check if it's a new key */
418 if (Disposition == REG_CREATED_NEW_KEY)
419 {
420 HANDLE DeviceClassesHandle;
421
422 /* Create the device classes key */
423 RtlInitUnicodeString(&KeyName, L"DeviceClasses");
424 Status = IopCreateRegistryKeyEx(&DeviceClassesHandle,
425 ControlHandle,
426 &KeyName,
427 KEY_ALL_ACCESS,
428 REG_OPTION_NON_VOLATILE,
429 &Disposition);
430 if (!NT_SUCCESS(Status)) return Status;
431
432 ZwClose(DeviceClassesHandle);
433 }
434
435 ZwClose(ControlHandle);
436
437 /* Create the enum key */
438 RtlInitUnicodeString(&KeyName, REGSTR_KEY_ENUM);
439 Status = IopCreateRegistryKeyEx(&EnumHandle,
440 KeyHandle,
441 &KeyName,
442 KEY_ALL_ACCESS,
443 REG_OPTION_NON_VOLATILE,
444 &Disposition);
445 if (!NT_SUCCESS(Status)) return Status;
446
447 /* Check if it's a new key */
448 if (Disposition == REG_CREATED_NEW_KEY)
449 {
450 /* FIXME: DACLs */
451 DPRINT1("Need to build DACL\n");
452 }
453
454 /* Create the root key */
455 ParentHandle = EnumHandle;
456 RtlInitUnicodeString(&KeyName, REGSTR_KEY_ROOTENUM);
457 Status = IopCreateRegistryKeyEx(&EnumHandle,
458 ParentHandle,
459 &KeyName,
460 KEY_ALL_ACCESS,
461 REG_OPTION_NON_VOLATILE,
462 &Disposition);
463 NtClose(ParentHandle);
464 if (!NT_SUCCESS(Status)) return Status;
465 NtClose(EnumHandle);
466
467 /* Open the root key now */
468 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
469 Status = IopOpenRegistryKeyEx(&EnumHandle,
470 NULL,
471 &KeyName,
472 KEY_ALL_ACCESS);
473 if (NT_SUCCESS(Status))
474 {
475 /* Create the root dev node */
476 RtlInitUnicodeString(&KeyName, REGSTR_VAL_ROOT_DEVNODE);
477 Status = IopCreateRegistryKeyEx(&TreeHandle,
478 EnumHandle,
479 &KeyName,
480 KEY_ALL_ACCESS,
481 REG_OPTION_NON_VOLATILE,
482 NULL);
483 NtClose(EnumHandle);
484 if (NT_SUCCESS(Status)) NtClose(TreeHandle);
485 }
486
487 /* Create the root driver */
488 Status = IoCreateDriver(&PnpManagerDriverName, PnpRootDriverEntry);
489 if (!NT_SUCCESS(Status))
490 {
491 DPRINT1("IoCreateDriverObject() failed\n");
492 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
493 }
494
495 /* Create the root PDO */
496 Status = IoCreateDevice(IopRootDriverObject,
497 sizeof(IOPNP_DEVICE_EXTENSION),
498 NULL,
499 FILE_DEVICE_CONTROLLER,
500 0,
501 FALSE,
502 &Pdo);
503 if (!NT_SUCCESS(Status))
504 {
505 DPRINT1("IoCreateDevice() failed\n");
506 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
507 }
508
509 /* This is a bus enumerated device */
510 Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
511
512 /* Create the root device node */
513 IopRootDeviceNode = PipAllocateDeviceNode(Pdo);
514
515 /* Set flags */
516 IopRootDeviceNode->Flags |= DNF_STARTED + DNF_PROCESSED + DNF_ENUMERATED +
517 DNF_MADEUP + DNF_NO_RESOURCE_REQUIRED +
518 DNF_ADDED;
519
520 /* Create instance path */
521 RtlCreateUnicodeString(&IopRootDeviceNode->InstancePath,
522 REGSTR_VAL_ROOT_DEVNODE);
523
524 /* Call the add device routine */
525 IopRootDriverObject->DriverExtension->AddDevice(IopRootDriverObject,
526 IopRootDeviceNode->PhysicalDeviceObject);
527
528 /* Initialize PnP-Event notification support */
529 Status = IopInitPlugPlayEvents();
530 if (!NT_SUCCESS(Status)) return Status;
531
532 /* Report the device to the user-mode pnp manager */
533 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
534 &IopRootDeviceNode->InstancePath);
535
536 /* Initialize the Bus Type GUID List */
537 PnpBusTypeGuidList = ExAllocatePool(PagedPool, sizeof(IO_BUS_TYPE_GUID_LIST));
538 RtlZeroMemory(PnpBusTypeGuidList, sizeof(IO_BUS_TYPE_GUID_LIST));
539 ExInitializeFastMutex(&PnpBusTypeGuidList->Lock);
540
541 /* Launch the firmware mapper */
542 Status = IopUpdateRootKey();
543 if (!NT_SUCCESS(Status)) return Status;
544
545 /* Close the handle to the control set */
546 NtClose(KeyHandle);
547
548 /* We made it */
549 return STATUS_SUCCESS;
550 }
551
552 /* EOF */