Sync with trunk r62529.
[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 if (!NT_SUCCESS(Status))
279 {
280 DPRINT1("IopOpenRegistryKeyEx() failed with Status %08X\n", Status);
281 ZwClose(EnumRootKey);
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 if (!NT_SUCCESS(Status))
334 {
335 /* No properties */
336 DPRINT("IopOpenRegistryKeyEx() failed with Status %08X\n", Status);
337 PropertiesKey = NULL;
338 }
339 }
340
341 /* Free the registry data */
342 ExFreePool(KeyValueInformation);
343 }
344
345 /* Do ReactOS-style setup */
346 IopAttachFilterDrivers(DeviceNode, TRUE);
347 Status = IopInitializeDevice(DeviceNode, DriverObject);
348 if (NT_SUCCESS(Status))
349 {
350 IopAttachFilterDrivers(DeviceNode, FALSE);
351 Status = IopStartDevice(DeviceNode);
352 }
353
354 /* Return status */
355 return Status;
356 }
357
358 NTSTATUS
359 NTAPI
360 INIT_FUNCTION
361 IopInitializePlugPlayServices(VOID)
362 {
363 NTSTATUS Status;
364 ULONG Disposition;
365 HANDLE KeyHandle, EnumHandle, ParentHandle, TreeHandle, ControlHandle;
366 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET");
367 UNICODE_STRING PnpManagerDriverName = RTL_CONSTANT_STRING(DRIVER_ROOT_NAME L"PnpManager");
368 PDEVICE_OBJECT Pdo;
369
370 /* Initialize locks and such */
371 KeInitializeSpinLock(&IopDeviceTreeLock);
372
373 /* Get the default interface */
374 PnpDefaultInterfaceType = IopDetermineDefaultInterfaceType();
375
376 /* Initialize arbiters */
377 Status = IopInitializeArbiters();
378 if (!NT_SUCCESS(Status)) return Status;
379
380 /* Setup the group cache */
381 Status = PiInitCacheGroupInformation();
382 if (!NT_SUCCESS(Status)) return Status;
383
384 /* Open the current control set */
385 Status = IopOpenRegistryKeyEx(&KeyHandle,
386 NULL,
387 &KeyName,
388 KEY_ALL_ACCESS);
389 if (!NT_SUCCESS(Status)) return Status;
390
391 /* Create the control key */
392 RtlInitUnicodeString(&KeyName, L"Control");
393 Status = IopCreateRegistryKeyEx(&ControlHandle,
394 KeyHandle,
395 &KeyName,
396 KEY_ALL_ACCESS,
397 REG_OPTION_NON_VOLATILE,
398 &Disposition);
399 if (!NT_SUCCESS(Status)) return Status;
400
401 /* Check if it's a new key */
402 if (Disposition == REG_CREATED_NEW_KEY)
403 {
404 HANDLE DeviceClassesHandle;
405
406 /* Create the device classes key */
407 RtlInitUnicodeString(&KeyName, L"DeviceClasses");
408 Status = IopCreateRegistryKeyEx(&DeviceClassesHandle,
409 ControlHandle,
410 &KeyName,
411 KEY_ALL_ACCESS,
412 REG_OPTION_NON_VOLATILE,
413 &Disposition);
414 if (!NT_SUCCESS(Status)) return Status;
415
416 ZwClose(DeviceClassesHandle);
417 }
418
419 ZwClose(ControlHandle);
420
421 /* Create the enum key */
422 RtlInitUnicodeString(&KeyName, REGSTR_KEY_ENUM);
423 Status = IopCreateRegistryKeyEx(&EnumHandle,
424 KeyHandle,
425 &KeyName,
426 KEY_ALL_ACCESS,
427 REG_OPTION_NON_VOLATILE,
428 &Disposition);
429 if (!NT_SUCCESS(Status)) return Status;
430
431 /* Check if it's a new key */
432 if (Disposition == REG_CREATED_NEW_KEY)
433 {
434 /* FIXME: DACLs */
435 DPRINT1("Need to build DACL\n");
436 }
437
438 /* Create the root key */
439 ParentHandle = EnumHandle;
440 RtlInitUnicodeString(&KeyName, REGSTR_KEY_ROOTENUM);
441 Status = IopCreateRegistryKeyEx(&EnumHandle,
442 ParentHandle,
443 &KeyName,
444 KEY_ALL_ACCESS,
445 REG_OPTION_NON_VOLATILE,
446 &Disposition);
447 NtClose(ParentHandle);
448 if (!NT_SUCCESS(Status)) return Status;
449 NtClose(EnumHandle);
450
451 /* Open the root key now */
452 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
453 Status = IopOpenRegistryKeyEx(&EnumHandle,
454 NULL,
455 &KeyName,
456 KEY_ALL_ACCESS);
457 if (NT_SUCCESS(Status))
458 {
459 /* Create the root dev node */
460 RtlInitUnicodeString(&KeyName, REGSTR_VAL_ROOT_DEVNODE);
461 Status = IopCreateRegistryKeyEx(&TreeHandle,
462 EnumHandle,
463 &KeyName,
464 KEY_ALL_ACCESS,
465 REG_OPTION_NON_VOLATILE,
466 NULL);
467 NtClose(EnumHandle);
468 if (NT_SUCCESS(Status)) NtClose(TreeHandle);
469 }
470
471 /* Create the root driver */
472 Status = IoCreateDriver(&PnpManagerDriverName, PnpRootDriverEntry);
473 if (!NT_SUCCESS(Status))
474 {
475 DPRINT1("IoCreateDriverObject() failed\n");
476 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
477 }
478
479 /* Create the root PDO */
480 Status = IoCreateDevice(IopRootDriverObject,
481 sizeof(IOPNP_DEVICE_EXTENSION),
482 NULL,
483 FILE_DEVICE_CONTROLLER,
484 0,
485 FALSE,
486 &Pdo);
487 if (!NT_SUCCESS(Status))
488 {
489 DPRINT1("IoCreateDevice() failed\n");
490 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
491 }
492
493 /* This is a bus enumerated device */
494 Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
495
496 /* Create the root device node */
497 IopRootDeviceNode = PipAllocateDeviceNode(Pdo);
498
499 /* Set flags */
500 IopRootDeviceNode->Flags |= DNF_STARTED + DNF_PROCESSED + DNF_ENUMERATED +
501 DNF_MADEUP + DNF_NO_RESOURCE_REQUIRED +
502 DNF_ADDED;
503
504 /* Create instance path */
505 RtlCreateUnicodeString(&IopRootDeviceNode->InstancePath,
506 REGSTR_VAL_ROOT_DEVNODE);
507
508 /* Call the add device routine */
509 IopRootDriverObject->DriverExtension->AddDevice(IopRootDriverObject,
510 IopRootDeviceNode->PhysicalDeviceObject);
511
512 /* Initialize PnP-Event notification support */
513 Status = IopInitPlugPlayEvents();
514 if (!NT_SUCCESS(Status)) return Status;
515
516 /* Report the device to the user-mode pnp manager */
517 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
518 &IopRootDeviceNode->InstancePath);
519
520 /* Initialize the Bus Type GUID List */
521 PnpBusTypeGuidList = ExAllocatePool(PagedPool, sizeof(IO_BUS_TYPE_GUID_LIST));
522 RtlZeroMemory(PnpBusTypeGuidList, sizeof(IO_BUS_TYPE_GUID_LIST));
523 ExInitializeFastMutex(&PnpBusTypeGuidList->Lock);
524
525 /* Launch the firmware mapper */
526 Status = IopUpdateRootKey();
527 if (!NT_SUCCESS(Status)) return Status;
528
529 /* Close the handle to the control set */
530 NtClose(KeyHandle);
531
532 /* We made it */
533 return STATUS_SUCCESS;
534 }
535
536 /* EOF */