[CLT2012]
[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;
366 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET");
367 PDEVICE_OBJECT Pdo;
368
369 /* Initialize locks and such */
370 KeInitializeSpinLock(&IopDeviceTreeLock);
371
372 /* Get the default interface */
373 PnpDefaultInterfaceType = IopDetermineDefaultInterfaceType();
374
375 /* Initialize arbiters */
376 Status = IopInitializeArbiters();
377 if (!NT_SUCCESS(Status)) return Status;
378
379 /* Setup the group cache */
380 Status = PiInitCacheGroupInformation();
381 if (!NT_SUCCESS(Status)) return Status;
382
383 /* Open the current control set */
384 Status = IopOpenRegistryKeyEx(&KeyHandle,
385 NULL,
386 &KeyName,
387 KEY_ALL_ACCESS);
388 if (!NT_SUCCESS(Status)) return Status;
389
390 /* Create the enum key */
391 RtlInitUnicodeString(&KeyName, REGSTR_KEY_ENUM);
392 Status = IopCreateRegistryKeyEx(&EnumHandle,
393 KeyHandle,
394 &KeyName,
395 KEY_ALL_ACCESS,
396 REG_OPTION_NON_VOLATILE,
397 &Disposition);
398 if (!NT_SUCCESS(Status)) return Status;
399
400 /* Check if it's a new key */
401 if (Disposition == REG_CREATED_NEW_KEY)
402 {
403 /* FIXME: DACLs */
404 DPRINT1("Need to build DACL\n");
405 }
406
407 /* Create the root key */
408 ParentHandle = EnumHandle;
409 RtlInitUnicodeString(&KeyName, REGSTR_KEY_ROOTENUM);
410 Status = IopCreateRegistryKeyEx(&EnumHandle,
411 ParentHandle,
412 &KeyName,
413 KEY_ALL_ACCESS,
414 REG_OPTION_NON_VOLATILE,
415 &Disposition);
416 NtClose(ParentHandle);
417 if (!NT_SUCCESS(Status)) return Status;
418 NtClose(EnumHandle);
419
420 /* Open the root key now */
421 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
422 Status = IopOpenRegistryKeyEx(&EnumHandle,
423 NULL,
424 &KeyName,
425 KEY_ALL_ACCESS);
426 if (NT_SUCCESS(Status))
427 {
428 /* Create the root dev node */
429 RtlInitUnicodeString(&KeyName, REGSTR_VAL_ROOT_DEVNODE);
430 Status = IopCreateRegistryKeyEx(&TreeHandle,
431 EnumHandle,
432 &KeyName,
433 KEY_ALL_ACCESS,
434 REG_OPTION_NON_VOLATILE,
435 NULL);
436 NtClose(EnumHandle);
437 if (NT_SUCCESS(Status)) NtClose(TreeHandle);
438 }
439
440 /* Create the root driver */
441 Status = IoCreateDriver(NULL, PnpRootDriverEntry);
442 if (!NT_SUCCESS(Status))
443 {
444 DPRINT1("IoCreateDriverObject() failed\n");
445 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
446 }
447
448 /* Create the root PDO */
449 Status = IoCreateDevice(IopRootDriverObject,
450 sizeof(IOPNP_DEVICE_EXTENSION),
451 NULL,
452 FILE_DEVICE_CONTROLLER,
453 0,
454 FALSE,
455 &Pdo);
456 if (!NT_SUCCESS(Status))
457 {
458 DPRINT1("IoCreateDevice() failed\n");
459 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
460 }
461
462 /* This is a bus enumerated device */
463 Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
464
465 /* Create the root device node */
466 IopRootDeviceNode = PipAllocateDeviceNode(Pdo);
467
468 /* Set flags */
469 IopRootDeviceNode->Flags |= DNF_STARTED + DNF_PROCESSED + DNF_ENUMERATED +
470 DNF_MADEUP + DNF_NO_RESOURCE_REQUIRED +
471 DNF_ADDED;
472
473 /* Create instance path */
474 RtlCreateUnicodeString(&IopRootDeviceNode->InstancePath,
475 REGSTR_VAL_ROOT_DEVNODE);
476
477 /* Call the add device routine */
478 IopRootDriverObject->DriverExtension->AddDevice(IopRootDriverObject,
479 IopRootDeviceNode->PhysicalDeviceObject);
480
481 /* Initialize PnP-Event notification support */
482 Status = IopInitPlugPlayEvents();
483 if (!NT_SUCCESS(Status)) return Status;
484
485 /* Report the device to the user-mode pnp manager */
486 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
487 &IopRootDeviceNode->InstancePath);
488
489 /* Initialize the Bus Type GUID List */
490 PnpBusTypeGuidList = ExAllocatePool(PagedPool, sizeof(IO_BUS_TYPE_GUID_LIST));
491 RtlZeroMemory(PnpBusTypeGuidList, sizeof(IO_BUS_TYPE_GUID_LIST));
492 ExInitializeFastMutex(&PnpBusTypeGuidList->Lock);
493
494 /* Launch the firmware mapper */
495 Status = IopUpdateRootKey();
496 if (!NT_SUCCESS(Status)) return Status;
497
498 /* Close the handle to the control set */
499 NtClose(KeyHandle);
500
501 /* We made it */
502 return STATUS_SUCCESS;
503 }
504
505 /* EOF */