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