* Sync to trunk HEAD (r53318).
[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 ULONG 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 = 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 ULONG 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 = 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 i = -1, Count, Tag = 0;
166 UNICODE_STRING GroupString =
167 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet"
168 L"\\Control\\ServiceGroupOrder");
169
170 /* Open the key */
171 Status = IopOpenRegistryKeyEx(&KeyHandle, NULL, &GroupString, KEY_READ);
172 if (!NT_SUCCESS(Status)) goto Quickie;
173
174 /* Read the group */
175 Status = IopGetRegistryValue(ServiceHandle, L"Group", &KeyValueInformation);
176 if (!NT_SUCCESS(Status)) goto Quickie;
177
178 /* Make sure we have a group */
179 if ((KeyValueInformation->Type == REG_SZ) &&
180 (KeyValueInformation->DataLength))
181 {
182 /* Convert to unicode string */
183 Buffer = (PVOID)((ULONG_PTR)KeyValueInformation + KeyValueInformation->DataOffset);
184 PnpRegSzToString(Buffer, KeyValueInformation->DataLength, &Group.Length);
185 Group.MaximumLength = KeyValueInformation->DataLength;
186 Group.Buffer = Buffer;
187 }
188
189 /* Now read the tag */
190 Status = IopGetRegistryValue(ServiceHandle, L"Tag", &KeyValueInformationTag);
191 if (!NT_SUCCESS(Status)) goto Quickie;
192
193 /* Make sure we have a tag */
194 if ((KeyValueInformationTag->Type == REG_DWORD) &&
195 (KeyValueInformationTag->DataLength))
196 {
197 /* Read it */
198 Tag = *(PULONG)((ULONG_PTR)KeyValueInformationTag +
199 KeyValueInformationTag->DataOffset);
200 }
201
202 /* We can get rid of this now */
203 ExFreePool(KeyValueInformationTag);
204
205 /* Now let's read the group's tag order */
206 Status = IopGetRegistryValue(KeyHandle,
207 Group.Buffer,
208 &KeyValueInformationGroupOrderList);
209
210 /* We can get rid of this now */
211 Quickie:
212 if (KeyValueInformation) ExFreePool(KeyValueInformation);
213 if (KeyHandle) NtClose(KeyHandle);
214 if (!NT_SUCCESS(Status)) return -1;
215
216 /* We're on the success path -- validate the tag order*/
217 if ((KeyValueInformationGroupOrderList->Type == REG_BINARY) &&
218 (KeyValueInformationGroupOrderList->DataLength))
219 {
220 /* Get the order array */
221 GroupOrder = (PULONG)((ULONG_PTR)KeyValueInformationGroupOrderList +
222 KeyValueInformationGroupOrderList->DataOffset);
223
224 /* Get the count */
225 Count = *GroupOrder;
226 ASSERT(((Count + 1) * sizeof(ULONG)) <=
227 KeyValueInformationGroupOrderList->DataLength);
228
229 /* Now loop each tag */
230 GroupOrder++;
231 for (i = 1; i <= Count; i++)
232 {
233 /* If we found it, we're out */
234 if (Tag == *GroupOrder) break;
235
236 /* Try the next one */
237 GroupOrder++;
238 }
239 }
240
241 /* Last buffer to free */
242 ExFreePool(KeyValueInformationGroupOrderList);
243 return i;
244 }
245
246 NTSTATUS
247 NTAPI
248 PipCallDriverAddDevice(IN PDEVICE_NODE DeviceNode,
249 IN BOOLEAN LoadDriver,
250 IN PDRIVER_OBJECT DriverObject)
251 {
252 NTSTATUS Status;
253 HANDLE EnumRootKey, SubKey, ControlKey, ClassKey, PropertiesKey;
254 UNICODE_STRING ClassGuid, Properties;
255 UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
256 UNICODE_STRING ControlClass =
257 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
258 PKEY_VALUE_FULL_INFORMATION KeyValueInformation = NULL;
259 PWCHAR Buffer;
260
261 /* Open enumeration root key */
262 Status = IopOpenRegistryKeyEx(&EnumRootKey,
263 NULL,
264 &EnumRoot,
265 KEY_READ);
266 if (!NT_SUCCESS(Status))
267 {
268 DPRINT1("IopOpenRegistryKeyEx() failed with Status %08X\n", Status);
269 return Status;
270 }
271
272 /* Open instance subkey */
273 Status = IopOpenRegistryKeyEx(&SubKey,
274 EnumRootKey,
275 &DeviceNode->InstancePath,
276 KEY_READ);
277 if (!NT_SUCCESS(Status))
278 {
279 DPRINT1("IopOpenRegistryKeyEx() failed with Status %08X\n", Status);
280 ZwClose(EnumRootKey);
281 return Status;
282 }
283
284 /* Get class GUID */
285 Status = IopGetRegistryValue(SubKey,
286 REGSTR_VAL_CLASSGUID,
287 &KeyValueInformation);
288 if (NT_SUCCESS(Status))
289 {
290 /* Convert to unicode string */
291 Buffer = (PVOID)((ULONG_PTR)KeyValueInformation + KeyValueInformation->DataOffset);
292 PnpRegSzToString(Buffer, KeyValueInformation->DataLength, &ClassGuid.Length);
293 ClassGuid.MaximumLength = KeyValueInformation->DataLength;
294 ClassGuid.Buffer = Buffer;
295
296 /* Open the key */
297 Status = IopOpenRegistryKeyEx(&ControlKey,
298 NULL,
299 &ControlClass,
300 KEY_READ);
301 if (!NT_SUCCESS(Status))
302 {
303 /* No class key */
304 DPRINT1("IopOpenRegistryKeyEx() failed with Status %08X\n", Status);
305 ClassKey = NULL;
306 }
307 else
308 {
309 /* Open the class key */
310 Status = IopOpenRegistryKeyEx(&ClassKey,
311 ControlKey,
312 &ClassGuid,
313 KEY_READ);
314 ZwClose(ControlKey);
315 if (!NT_SUCCESS(Status))
316 {
317 /* No class key */
318 DPRINT1("IopOpenRegistryKeyEx() failed with Status %08X\n", Status);
319 ClassKey = NULL;
320 }
321 }
322
323 /* Check if we made it till here */
324 if (ClassKey)
325 {
326 /* Get the device properties */
327 RtlInitUnicodeString(&Properties, REGSTR_KEY_DEVICE_PROPERTIES);
328 Status = IopOpenRegistryKeyEx(&PropertiesKey,
329 ClassKey,
330 &Properties,
331 KEY_READ);
332 if (!NT_SUCCESS(Status))
333 {
334 /* No properties */
335 DPRINT("IopOpenRegistryKeyEx() failed with Status %08X\n", Status);
336 PropertiesKey = NULL;
337 }
338 }
339
340 /* Free the registry data */
341 ExFreePool(KeyValueInformation);
342 }
343
344 /* Do ReactOS-style setup */
345 IopAttachFilterDrivers(DeviceNode, TRUE);
346 Status = IopInitializeDevice(DeviceNode, DriverObject);
347 if (NT_SUCCESS(Status))
348 {
349 IopAttachFilterDrivers(DeviceNode, FALSE);
350 Status = IopStartDevice(DeviceNode);
351 }
352
353 /* Return status */
354 return Status;
355 }
356
357 NTSTATUS
358 NTAPI
359 INIT_FUNCTION
360 IopInitializePlugPlayServices(VOID)
361 {
362 NTSTATUS Status;
363 ULONG Disposition;
364 HANDLE KeyHandle, EnumHandle, ParentHandle, TreeHandle;
365 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET");
366 PDEVICE_OBJECT Pdo;
367
368 /* Initialize locks and such */
369 KeInitializeSpinLock(&IopDeviceTreeLock);
370
371 /* Get the default interface */
372 PnpDefaultInterfaceType = IopDetermineDefaultInterfaceType();
373
374 /* Initialize arbiters */
375 Status = IopInitializeArbiters();
376 if (!NT_SUCCESS(Status)) return Status;
377
378 /* Setup the group cache */
379 Status = PiInitCacheGroupInformation();
380 if (!NT_SUCCESS(Status)) return Status;
381
382 /* Open the current control set */
383 Status = IopOpenRegistryKeyEx(&KeyHandle,
384 NULL,
385 &KeyName,
386 KEY_ALL_ACCESS);
387 if (!NT_SUCCESS(Status)) return Status;
388
389 /* Create the enum key */
390 RtlInitUnicodeString(&KeyName, REGSTR_KEY_ENUM);
391 Status = IopCreateRegistryKeyEx(&EnumHandle,
392 KeyHandle,
393 &KeyName,
394 KEY_ALL_ACCESS,
395 REG_OPTION_NON_VOLATILE,
396 &Disposition);
397 if (!NT_SUCCESS(Status)) return Status;
398
399 /* Check if it's a new key */
400 if (Disposition == REG_CREATED_NEW_KEY)
401 {
402 /* FIXME: DACLs */
403 DPRINT1("Need to build DACL\n");
404 }
405
406 /* Create the root key */
407 ParentHandle = EnumHandle;
408 RtlInitUnicodeString(&KeyName, REGSTR_KEY_ROOTENUM);
409 Status = IopCreateRegistryKeyEx(&EnumHandle,
410 ParentHandle,
411 &KeyName,
412 KEY_ALL_ACCESS,
413 REG_OPTION_NON_VOLATILE,
414 &Disposition);
415 NtClose(ParentHandle);
416 if (!NT_SUCCESS(Status)) return Status;
417 NtClose(EnumHandle);
418
419 /* Open the root key now */
420 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
421 Status = IopOpenRegistryKeyEx(&EnumHandle,
422 NULL,
423 &KeyName,
424 KEY_ALL_ACCESS);
425 if (NT_SUCCESS(Status))
426 {
427 /* Create the root dev node */
428 RtlInitUnicodeString(&KeyName, REGSTR_VAL_ROOT_DEVNODE);
429 Status = IopCreateRegistryKeyEx(&TreeHandle,
430 EnumHandle,
431 &KeyName,
432 KEY_ALL_ACCESS,
433 REG_OPTION_NON_VOLATILE,
434 NULL);
435 NtClose(EnumHandle);
436 if (NT_SUCCESS(Status)) NtClose(TreeHandle);
437 }
438
439 /* Create the root driver */
440 Status = IoCreateDriver(NULL, PnpRootDriverEntry);
441 if (!NT_SUCCESS(Status))
442 {
443 DPRINT1("IoCreateDriverObject() failed\n");
444 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
445 }
446
447 /* Create the root PDO */
448 Status = IoCreateDevice(IopRootDriverObject,
449 sizeof(IOPNP_DEVICE_EXTENSION),
450 NULL,
451 FILE_DEVICE_CONTROLLER,
452 0,
453 FALSE,
454 &Pdo);
455 if (!NT_SUCCESS(Status))
456 {
457 DPRINT1("IoCreateDevice() failed\n");
458 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
459 }
460
461 /* This is a bus enumerated device */
462 Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
463
464 /* Create the root device node */
465 IopRootDeviceNode = PipAllocateDeviceNode(Pdo);
466
467 /* Set flags */
468 IopRootDeviceNode->Flags |= DNF_STARTED + DNF_PROCESSED + DNF_ENUMERATED +
469 DNF_MADEUP + DNF_NO_RESOURCE_REQUIRED +
470 DNF_ADDED;
471
472 /* Create instance path */
473 RtlCreateUnicodeString(&IopRootDeviceNode->InstancePath,
474 REGSTR_VAL_ROOT_DEVNODE);
475
476 /* Call the add device routine */
477 IopRootDriverObject->DriverExtension->AddDevice(IopRootDriverObject,
478 IopRootDeviceNode->PhysicalDeviceObject);
479
480 /* Initialize PnP-Event notification support */
481 Status = IopInitPlugPlayEvents();
482 if (!NT_SUCCESS(Status)) return Status;
483
484 /* Report the device to the user-mode pnp manager */
485 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
486 &IopRootDeviceNode->InstancePath);
487
488 /* Initialize the Bus Type GUID List */
489 PnpBusTypeGuidList = ExAllocatePool(PagedPool, sizeof(IO_BUS_TYPE_GUID_LIST));
490 RtlZeroMemory(PnpBusTypeGuidList, sizeof(IO_BUS_TYPE_GUID_LIST));
491 ExInitializeFastMutex(&PnpBusTypeGuidList->Lock);
492
493 /* Launch the firmware mapper */
494 Status = IopUpdateRootKey();
495 if (!NT_SUCCESS(Status)) return Status;
496
497 /* Close the handle to the control set */
498 NtClose(KeyHandle);
499
500 /* We made it */
501 return STATUS_SUCCESS;
502 }
503
504 /* EOF */