[NTOS:IO] Create non volatile registry keys for root devices (as for other devices)
[reactos.git] / ntoskrnl / io / pnpmgr / pnproot.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnproot.c
5 * PURPOSE: PnP manager root device
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Copyright 2007 Herv? Poussineau (hpoussin@reactos.org)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 #define ENUM_NAME_ROOT L"Root"
19
20 /* DATA **********************************************************************/
21
22 typedef struct _PNPROOT_DEVICE
23 {
24 // Entry on device list
25 LIST_ENTRY ListEntry;
26 // Physical Device Object of device
27 PDEVICE_OBJECT Pdo;
28 // Device ID
29 UNICODE_STRING DeviceID;
30 // Instance ID
31 UNICODE_STRING InstanceID;
32 // Device description
33 UNICODE_STRING DeviceDescription;
34 // Resource requirement list
35 PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirementsList;
36 // Associated resource list
37 PCM_RESOURCE_LIST ResourceList;
38 ULONG ResourceListSize;
39 } PNPROOT_DEVICE, *PPNPROOT_DEVICE;
40
41 typedef enum
42 {
43 dsStopped,
44 dsStarted,
45 dsPaused,
46 dsRemoved,
47 dsSurpriseRemoved
48 } PNPROOT_DEVICE_STATE;
49
50 typedef struct _PNPROOT_COMMON_DEVICE_EXTENSION
51 {
52 // Wether this device extension is for an FDO or PDO
53 BOOLEAN IsFDO;
54 } PNPROOT_COMMON_DEVICE_EXTENSION, *PPNPROOT_COMMON_DEVICE_EXTENSION;
55
56 /* Physical Device Object device extension for a child device */
57 typedef struct _PNPROOT_PDO_DEVICE_EXTENSION
58 {
59 // Common device data
60 PNPROOT_COMMON_DEVICE_EXTENSION Common;
61 // Informations about the device
62 PPNPROOT_DEVICE DeviceInfo;
63 } PNPROOT_PDO_DEVICE_EXTENSION, *PPNPROOT_PDO_DEVICE_EXTENSION;
64
65 /* Physical Device Object device extension for the Root bus device object */
66 typedef struct _PNPROOT_FDO_DEVICE_EXTENSION
67 {
68 // Common device data
69 PNPROOT_COMMON_DEVICE_EXTENSION Common;
70 // Lower device object
71 PDEVICE_OBJECT Ldo;
72 // Current state of the driver
73 PNPROOT_DEVICE_STATE State;
74 // Namespace device list
75 LIST_ENTRY DeviceListHead;
76 // Number of (not removed) devices in device list
77 ULONG DeviceListCount;
78 // Lock for namespace device list
79 KGUARDED_MUTEX DeviceListLock;
80 } PNPROOT_FDO_DEVICE_EXTENSION, *PPNPROOT_FDO_DEVICE_EXTENSION;
81
82 typedef struct _BUFFER
83 {
84 PVOID *Data;
85 PULONG Length;
86 } BUFFER, *PBUFFER;
87
88 static PDEVICE_OBJECT PnpRootDeviceObject = NULL;
89
90 /* FUNCTIONS *****************************************************************/
91
92 static NTSTATUS
93 LocateChildDevice(
94 IN PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension,
95 IN PCUNICODE_STRING DeviceId,
96 IN PCWSTR InstanceId,
97 OUT PPNPROOT_DEVICE* ChildDevice)
98 {
99 PPNPROOT_DEVICE Device;
100 UNICODE_STRING InstanceIdU;
101 PLIST_ENTRY NextEntry;
102
103 /* Initialize the string to compare */
104 RtlInitUnicodeString(&InstanceIdU, InstanceId);
105
106 /* Start looping */
107 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
108 NextEntry != &DeviceExtension->DeviceListHead;
109 NextEntry = NextEntry->Flink)
110 {
111 /* Get the entry */
112 Device = CONTAINING_RECORD(NextEntry, PNPROOT_DEVICE, ListEntry);
113
114 /* See if the strings match */
115 if (RtlEqualUnicodeString(DeviceId, &Device->DeviceID, TRUE) &&
116 RtlEqualUnicodeString(&InstanceIdU, &Device->InstanceID, TRUE))
117 {
118 /* They do, so set the pointer and return success */
119 *ChildDevice = Device;
120 return STATUS_SUCCESS;
121 }
122 }
123
124 /* No device found */
125 return STATUS_NO_SUCH_DEVICE;
126 }
127
128 NTSTATUS
129 PnpRootRegisterDevice(
130 IN PDEVICE_OBJECT DeviceObject)
131 {
132 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension = PnpRootDeviceObject->DeviceExtension;
133 PPNPROOT_DEVICE Device;
134 PDEVICE_NODE DeviceNode;
135 PWSTR InstancePath;
136 UNICODE_STRING InstancePathCopy;
137
138 Device = ExAllocatePoolWithTag(PagedPool, sizeof(PNPROOT_DEVICE), TAG_PNP_ROOT);
139 if (!Device) return STATUS_NO_MEMORY;
140
141 DeviceNode = IopGetDeviceNode(DeviceObject);
142 if (!RtlCreateUnicodeString(&InstancePathCopy, DeviceNode->InstancePath.Buffer))
143 {
144 ExFreePoolWithTag(Device, TAG_PNP_ROOT);
145 return STATUS_NO_MEMORY;
146 }
147
148 InstancePath = wcsrchr(InstancePathCopy.Buffer, L'\\');
149 ASSERT(InstancePath);
150
151 if (!RtlCreateUnicodeString(&Device->InstanceID, InstancePath + 1))
152 {
153 RtlFreeUnicodeString(&InstancePathCopy);
154 ExFreePoolWithTag(Device, TAG_PNP_ROOT);
155 return STATUS_NO_MEMORY;
156 }
157
158 InstancePath[0] = UNICODE_NULL;
159
160 if (!RtlCreateUnicodeString(&Device->DeviceID, InstancePathCopy.Buffer))
161 {
162 RtlFreeUnicodeString(&InstancePathCopy);
163 RtlFreeUnicodeString(&Device->InstanceID);
164 ExFreePoolWithTag(Device, TAG_PNP_ROOT);
165 return STATUS_NO_MEMORY;
166 }
167
168 InstancePath[0] = L'\\';
169
170 Device->Pdo = DeviceObject;
171
172 KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
173 InsertTailList(&DeviceExtension->DeviceListHead,
174 &Device->ListEntry);
175 DeviceExtension->DeviceListCount++;
176 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
177
178 RtlFreeUnicodeString(&InstancePathCopy);
179
180 return STATUS_SUCCESS;
181 }
182
183 /* Creates a new PnP device for a legacy driver */
184 NTSTATUS
185 PnpRootCreateDevice(
186 IN PUNICODE_STRING ServiceName,
187 IN OPTIONAL PDRIVER_OBJECT DriverObject,
188 OUT PDEVICE_OBJECT *PhysicalDeviceObject,
189 OUT OPTIONAL PUNICODE_STRING FullInstancePath)
190 {
191 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
192 PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension;
193 UNICODE_STRING DevicePath;
194 WCHAR InstancePath[5];
195 PPNPROOT_DEVICE Device = NULL;
196 NTSTATUS Status;
197 UNICODE_STRING PathSep = RTL_CONSTANT_STRING(L"\\");
198 ULONG NextInstance;
199 UNICODE_STRING EnumKeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\" REGSTR_PATH_SYSTEMENUM);
200 HANDLE EnumHandle, DeviceKeyHandle = NULL, InstanceKeyHandle;
201 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
202 OBJECT_ATTRIBUTES ObjectAttributes;
203
204 DeviceExtension = PnpRootDeviceObject->DeviceExtension;
205 KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
206
207 DPRINT("Creating a PnP root device for service '%wZ'\n", ServiceName);
208
209 DevicePath.Length = 0;
210 DevicePath.MaximumLength = sizeof(REGSTR_KEY_ROOTENUM) + sizeof(L'\\') + ServiceName->Length;
211 DevicePath.Buffer = ExAllocatePoolWithTag(PagedPool,
212 DevicePath.MaximumLength,
213 TAG_PNP_ROOT);
214 if (DevicePath.Buffer == NULL)
215 {
216 DPRINT1("ExAllocatePoolWithTag() failed\n");
217 Status = STATUS_NO_MEMORY;
218 goto cleanup;
219 }
220 RtlAppendUnicodeToString(&DevicePath, REGSTR_KEY_ROOTENUM L"\\");
221 RtlAppendUnicodeStringToString(&DevicePath, ServiceName);
222
223 /* Initialize a PNPROOT_DEVICE structure */
224 Device = ExAllocatePoolWithTag(PagedPool, sizeof(PNPROOT_DEVICE), TAG_PNP_ROOT);
225 if (!Device)
226 {
227 DPRINT("ExAllocatePoolWithTag() failed\n");
228 Status = STATUS_NO_MEMORY;
229 goto cleanup;
230 }
231 RtlZeroMemory(Device, sizeof(PNPROOT_DEVICE));
232 Device->DeviceID = DevicePath;
233 RtlInitEmptyUnicodeString(&DevicePath, NULL, 0);
234
235 Status = IopOpenRegistryKeyEx(&EnumHandle, NULL, &EnumKeyName, KEY_READ);
236 if (NT_SUCCESS(Status))
237 {
238 InitializeObjectAttributes(&ObjectAttributes,
239 &Device->DeviceID,
240 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
241 EnumHandle,
242 NULL);
243 Status = ZwCreateKey(&DeviceKeyHandle, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
244 ObCloseHandle(EnumHandle, KernelMode);
245 }
246
247 if (!NT_SUCCESS(Status))
248 {
249 DPRINT1("Failed to open registry key\n");
250 goto cleanup;
251 }
252
253 tryagain:
254 RtlZeroMemory(QueryTable, sizeof(QueryTable));
255 QueryTable[0].Name = L"NextInstance";
256 QueryTable[0].EntryContext = &NextInstance;
257 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
258
259 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
260 (PWSTR)DeviceKeyHandle,
261 QueryTable,
262 NULL,
263 NULL);
264 if (!NT_SUCCESS(Status))
265 {
266 for (NextInstance = 0; NextInstance <= 9999; NextInstance++)
267 {
268 _snwprintf(InstancePath, sizeof(InstancePath) / sizeof(WCHAR), L"%04lu", NextInstance);
269 Status = LocateChildDevice(DeviceExtension, &Device->DeviceID, InstancePath, &Device);
270 if (Status == STATUS_NO_SUCH_DEVICE)
271 break;
272 }
273
274 if (NextInstance > 9999)
275 {
276 DPRINT1("Too many legacy devices reported for service '%wZ'\n", ServiceName);
277 Status = STATUS_INSUFFICIENT_RESOURCES;
278 goto cleanup;
279 }
280 }
281
282 _snwprintf(InstancePath, sizeof(InstancePath) / sizeof(WCHAR), L"%04lu", NextInstance);
283 Status = LocateChildDevice(DeviceExtension, &Device->DeviceID, InstancePath, &Device);
284 if (Status != STATUS_NO_SUCH_DEVICE || NextInstance > 9999)
285 {
286 DPRINT1("NextInstance value is corrupt! (%lu)\n", NextInstance);
287 RtlDeleteRegistryValue(RTL_REGISTRY_HANDLE,
288 (PWSTR)DeviceKeyHandle,
289 L"NextInstance");
290 goto tryagain;
291 }
292
293 NextInstance++;
294 Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,
295 (PWSTR)DeviceKeyHandle,
296 L"NextInstance",
297 REG_DWORD,
298 &NextInstance,
299 sizeof(NextInstance));
300 if (!NT_SUCCESS(Status))
301 {
302 DPRINT1("Failed to write new NextInstance value! (0x%x)\n", Status);
303 goto cleanup;
304 }
305
306 if (!RtlCreateUnicodeString(&Device->InstanceID, InstancePath))
307 {
308 Status = STATUS_NO_MEMORY;
309 goto cleanup;
310 }
311
312 /* Finish creating the instance path in the registry */
313 InitializeObjectAttributes(&ObjectAttributes,
314 &Device->InstanceID,
315 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
316 DeviceKeyHandle,
317 NULL);
318 Status = ZwCreateKey(&InstanceKeyHandle, KEY_QUERY_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
319 if (!NT_SUCCESS(Status))
320 {
321 DPRINT1("Failed to create instance path (0x%x)\n", Status);
322 goto cleanup;
323 }
324
325 /* Just close the handle */
326 ObCloseHandle(InstanceKeyHandle, KernelMode);
327
328 if (FullInstancePath)
329 {
330 FullInstancePath->MaximumLength = Device->DeviceID.Length + PathSep.Length + Device->InstanceID.Length;
331 FullInstancePath->Length = 0;
332 FullInstancePath->Buffer = ExAllocatePool(PagedPool, FullInstancePath->MaximumLength);
333 if (!FullInstancePath->Buffer)
334 {
335 Status = STATUS_NO_MEMORY;
336 goto cleanup;
337 }
338
339 RtlAppendUnicodeStringToString(FullInstancePath, &Device->DeviceID);
340 RtlAppendUnicodeStringToString(FullInstancePath, &PathSep);
341 RtlAppendUnicodeStringToString(FullInstancePath, &Device->InstanceID);
342 }
343
344 /* Initialize a device object */
345 Status = IoCreateDevice(
346 DriverObject ? DriverObject : PnpRootDeviceObject->DriverObject,
347 sizeof(PNPROOT_PDO_DEVICE_EXTENSION),
348 NULL,
349 FILE_DEVICE_CONTROLLER,
350 FILE_AUTOGENERATED_DEVICE_NAME,
351 FALSE,
352 &Device->Pdo);
353 if (!NT_SUCCESS(Status))
354 {
355 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
356 Status = STATUS_NO_MEMORY;
357 goto cleanup;
358 }
359
360 PdoDeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;
361 RtlZeroMemory(PdoDeviceExtension, sizeof(PNPROOT_PDO_DEVICE_EXTENSION));
362 PdoDeviceExtension->Common.IsFDO = FALSE;
363 PdoDeviceExtension->DeviceInfo = Device;
364
365 Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
366 Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
367
368 InsertTailList(
369 &DeviceExtension->DeviceListHead,
370 &Device->ListEntry);
371 DeviceExtension->DeviceListCount++;
372
373 *PhysicalDeviceObject = Device->Pdo;
374 DPRINT("Created PDO %p (%wZ\\%wZ)\n", *PhysicalDeviceObject, &Device->DeviceID, &Device->InstanceID);
375 Device = NULL;
376 Status = STATUS_SUCCESS;
377
378 cleanup:
379 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
380 if (Device)
381 {
382 if (Device->Pdo)
383 IoDeleteDevice(Device->Pdo);
384 RtlFreeUnicodeString(&Device->DeviceID);
385 RtlFreeUnicodeString(&Device->InstanceID);
386 ExFreePoolWithTag(Device, TAG_PNP_ROOT);
387 }
388 RtlFreeUnicodeString(&DevicePath);
389 if (DeviceKeyHandle != NULL)
390 ObCloseHandle(DeviceKeyHandle, KernelMode);
391 return Status;
392 }
393
394 static NTSTATUS NTAPI
395 QueryStringCallback(
396 IN PWSTR ValueName,
397 IN ULONG ValueType,
398 IN PVOID ValueData,
399 IN ULONG ValueLength,
400 IN PVOID Context,
401 IN PVOID EntryContext)
402 {
403 PUNICODE_STRING Destination = (PUNICODE_STRING)EntryContext;
404 UNICODE_STRING Source;
405
406 if (ValueType != REG_SZ || ValueLength == 0 || ValueLength % sizeof(WCHAR) != 0)
407 {
408 Destination->Length = 0;
409 Destination->MaximumLength = 0;
410 Destination->Buffer = NULL;
411 return STATUS_SUCCESS;
412 }
413
414 Source.MaximumLength = Source.Length = (USHORT)ValueLength;
415 Source.Buffer = ValueData;
416
417 return RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &Source, Destination);
418 }
419
420 static NTSTATUS NTAPI
421 QueryBinaryValueCallback(
422 IN PWSTR ValueName,
423 IN ULONG ValueType,
424 IN PVOID ValueData,
425 IN ULONG ValueLength,
426 IN PVOID Context,
427 IN PVOID EntryContext)
428 {
429 PBUFFER Buffer = (PBUFFER)EntryContext;
430 PVOID BinaryValue;
431
432 if (ValueLength == 0)
433 {
434 *Buffer->Data = NULL;
435 return STATUS_SUCCESS;
436 }
437
438 BinaryValue = ExAllocatePoolWithTag(PagedPool, ValueLength, TAG_PNP_ROOT);
439 if (BinaryValue == NULL)
440 return STATUS_NO_MEMORY;
441 RtlCopyMemory(BinaryValue, ValueData, ValueLength);
442 *Buffer->Data = BinaryValue;
443 if (Buffer->Length) *Buffer->Length = ValueLength;
444 return STATUS_SUCCESS;
445 }
446
447 static
448 NTSTATUS
449 CreateDeviceFromRegistry(
450 _Inout_ PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension,
451 _Inout_ PUNICODE_STRING DevicePath,
452 _In_ PCWSTR InstanceId,
453 _In_ HANDLE SubKeyHandle)
454 {
455 NTSTATUS Status;
456 PPNPROOT_DEVICE Device;
457 HANDLE DeviceKeyHandle = NULL;
458 RTL_QUERY_REGISTRY_TABLE QueryTable[4];
459 BUFFER Buffer1, Buffer2;
460
461 /* If the device already exists, there's nothing to do */
462 Status = LocateChildDevice(DeviceExtension, DevicePath, InstanceId, &Device);
463 if (Status != STATUS_NO_SUCH_DEVICE)
464 {
465 return STATUS_SUCCESS;
466 }
467
468 /* Create a PPNPROOT_DEVICE object, and add it to the list of known devices */
469 Device = ExAllocatePoolWithTag(PagedPool, sizeof(PNPROOT_DEVICE), TAG_PNP_ROOT);
470 if (!Device)
471 {
472 DPRINT("ExAllocatePoolWithTag() failed\n");
473 Status = STATUS_NO_MEMORY;
474 goto cleanup;
475 }
476 RtlZeroMemory(Device, sizeof(PNPROOT_DEVICE));
477
478 /* Fill device ID and instance ID */
479 Device->DeviceID = *DevicePath;
480 RtlInitEmptyUnicodeString(DevicePath, NULL, 0);
481 if (!RtlCreateUnicodeString(&Device->InstanceID, InstanceId))
482 {
483 DPRINT1("RtlCreateUnicodeString() failed\n");
484 Status = STATUS_NO_MEMORY;
485 goto cleanup;
486 }
487
488 /* Open registry key to fill other informations */
489 Status = IopOpenRegistryKeyEx(&DeviceKeyHandle, SubKeyHandle, &Device->InstanceID, KEY_READ);
490 if (!NT_SUCCESS(Status))
491 {
492 /* If our key disappeared, let the caller go on */
493 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
494 &Device->InstanceID, Status);
495 Status = STATUS_SUCCESS;
496 goto cleanup;
497 }
498
499 /* Fill information from the device instance key */
500 RtlZeroMemory(QueryTable, sizeof(QueryTable));
501 QueryTable[0].QueryRoutine = QueryStringCallback;
502 QueryTable[0].Name = L"DeviceDesc";
503 QueryTable[0].EntryContext = &Device->DeviceDescription;
504
505 RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
506 (PCWSTR)DeviceKeyHandle,
507 QueryTable,
508 NULL,
509 NULL);
510
511 /* Fill information from the LogConf subkey */
512 Buffer1.Data = (PVOID *)&Device->ResourceRequirementsList;
513 Buffer1.Length = NULL;
514 Buffer2.Data = (PVOID *)&Device->ResourceList;
515 Buffer2.Length = &Device->ResourceListSize;
516 RtlZeroMemory(QueryTable, sizeof(QueryTable));
517 QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
518 QueryTable[0].Name = L"LogConf";
519 QueryTable[1].QueryRoutine = QueryBinaryValueCallback;
520 QueryTable[1].Name = L"BasicConfigVector";
521 QueryTable[1].EntryContext = &Buffer1;
522 QueryTable[2].QueryRoutine = QueryBinaryValueCallback;
523 QueryTable[2].Name = L"BootConfig";
524 QueryTable[2].EntryContext = &Buffer2;
525
526 if (!NT_SUCCESS(RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
527 (PCWSTR)DeviceKeyHandle,
528 QueryTable,
529 NULL,
530 NULL)))
531 {
532 /* Non-fatal error */
533 DPRINT1("Failed to read the LogConf key for %wZ\\%S\n", &Device->DeviceID, InstanceId);
534 }
535
536 /* Insert the newly created device into the list */
537 InsertTailList(&DeviceExtension->DeviceListHead,
538 &Device->ListEntry);
539 DeviceExtension->DeviceListCount++;
540 Device = NULL;
541
542 cleanup:
543 if (DeviceKeyHandle != NULL)
544 {
545 ZwClose(DeviceKeyHandle);
546 }
547 if (Device != NULL)
548 {
549 /* We have a device that has not been added to device list. We need to clean it up */
550 RtlFreeUnicodeString(&Device->DeviceID);
551 RtlFreeUnicodeString(&Device->InstanceID);
552 ExFreePoolWithTag(Device, TAG_PNP_ROOT);
553 }
554 return Status;
555 }
556
557 static NTSTATUS
558 EnumerateDevices(
559 IN PDEVICE_OBJECT DeviceObject)
560 {
561 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
562 PKEY_BASIC_INFORMATION KeyInfo = NULL, SubKeyInfo = NULL;
563 UNICODE_STRING LegacyU = RTL_CONSTANT_STRING(L"LEGACY_");
564 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\" REGSTR_PATH_SYSTEMENUM L"\\" REGSTR_KEY_ROOTENUM);
565 UNICODE_STRING SubKeyName;
566 UNICODE_STRING DevicePath;
567 HANDLE KeyHandle = NULL;
568 HANDLE SubKeyHandle = NULL;
569 ULONG KeyInfoSize, SubKeyInfoSize;
570 ULONG ResultSize;
571 ULONG Index1, Index2;
572 NTSTATUS Status = STATUS_UNSUCCESSFUL;
573
574 DPRINT("EnumerateDevices(FDO %p)\n", DeviceObject);
575
576 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
577 KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
578
579 /* Should hold most key names, but we reallocate below if it's too small */
580 KeyInfoSize = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name) + 64 * sizeof(WCHAR);
581 KeyInfo = ExAllocatePoolWithTag(PagedPool,
582 KeyInfoSize + sizeof(UNICODE_NULL),
583 TAG_PNP_ROOT);
584 if (!KeyInfo)
585 {
586 DPRINT("ExAllocatePoolWithTag() failed\n");
587 Status = STATUS_NO_MEMORY;
588 goto cleanup;
589 }
590 SubKeyInfoSize = KeyInfoSize;
591 SubKeyInfo = ExAllocatePoolWithTag(PagedPool,
592 SubKeyInfoSize + sizeof(UNICODE_NULL),
593 TAG_PNP_ROOT);
594 if (!SubKeyInfo)
595 {
596 DPRINT("ExAllocatePoolWithTag() failed\n");
597 Status = STATUS_NO_MEMORY;
598 goto cleanup;
599 }
600
601 Status = IopOpenRegistryKeyEx(&KeyHandle, NULL, &KeyName, KEY_ENUMERATE_SUB_KEYS);
602 if (!NT_SUCCESS(Status))
603 {
604 DPRINT("IopOpenRegistryKeyEx(%wZ) failed with status 0x%08lx\n", &KeyName, Status);
605 goto cleanup;
606 }
607
608 /* Devices are sub-sub-keys of 'KeyName'. KeyName is already opened as
609 * KeyHandle. We'll first do a first enumeration to have first level keys,
610 * and an inner one to have the real devices list.
611 */
612 Index1 = 0;
613 while (TRUE)
614 {
615 Status = ZwEnumerateKey(
616 KeyHandle,
617 Index1,
618 KeyBasicInformation,
619 KeyInfo,
620 KeyInfoSize,
621 &ResultSize);
622 if (Status == STATUS_NO_MORE_ENTRIES)
623 {
624 Status = STATUS_SUCCESS;
625 break;
626 }
627 else if (Status == STATUS_BUFFER_OVERFLOW ||
628 Status == STATUS_BUFFER_TOO_SMALL)
629 {
630 ASSERT(KeyInfoSize < ResultSize);
631 KeyInfoSize = ResultSize;
632 ExFreePoolWithTag(KeyInfo, TAG_PNP_ROOT);
633 KeyInfo = ExAllocatePoolWithTag(PagedPool,
634 KeyInfoSize + sizeof(UNICODE_NULL),
635 TAG_PNP_ROOT);
636 if (!KeyInfo)
637 {
638 DPRINT1("ExAllocatePoolWithTag(%lu) failed\n", KeyInfoSize);
639 Status = STATUS_NO_MEMORY;
640 goto cleanup;
641 }
642 continue;
643 }
644 else if (!NT_SUCCESS(Status))
645 {
646 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
647 goto cleanup;
648 }
649
650 /* Terminate the string */
651 KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = 0;
652
653 /* Check if it is a legacy driver */
654 RtlInitUnicodeString(&SubKeyName, KeyInfo->Name);
655 if (RtlPrefixUnicodeString(&LegacyU, &SubKeyName, FALSE))
656 {
657 DPRINT("Ignoring legacy driver '%wZ'\n", &SubKeyName);
658 Index1++;
659 continue;
660 }
661
662 /* Open the key */
663 Status = IopOpenRegistryKeyEx(&SubKeyHandle, KeyHandle, &SubKeyName, KEY_ENUMERATE_SUB_KEYS);
664 if (!NT_SUCCESS(Status))
665 {
666 DPRINT("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
667 &SubKeyName, Status);
668 break;
669 }
670
671 /* Enumerate the sub-keys */
672 Index2 = 0;
673 while (TRUE)
674 {
675 Status = ZwEnumerateKey(
676 SubKeyHandle,
677 Index2,
678 KeyBasicInformation,
679 SubKeyInfo,
680 SubKeyInfoSize,
681 &ResultSize);
682 if (Status == STATUS_NO_MORE_ENTRIES)
683 {
684 break;
685 }
686 else if (Status == STATUS_BUFFER_OVERFLOW ||
687 Status == STATUS_BUFFER_TOO_SMALL)
688 {
689 ASSERT(SubKeyInfoSize < ResultSize);
690 SubKeyInfoSize = ResultSize;
691 ExFreePoolWithTag(SubKeyInfo, TAG_PNP_ROOT);
692 SubKeyInfo = ExAllocatePoolWithTag(PagedPool,
693 SubKeyInfoSize + sizeof(UNICODE_NULL),
694 TAG_PNP_ROOT);
695 if (!SubKeyInfo)
696 {
697 DPRINT1("ExAllocatePoolWithTag(%lu) failed\n", SubKeyInfoSize);
698 Status = STATUS_NO_MEMORY;
699 goto cleanup;
700 }
701 continue;
702 }
703 else if (!NT_SUCCESS(Status))
704 {
705 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
706 break;
707 }
708
709 /* Terminate the string */
710 SubKeyInfo->Name[SubKeyInfo->NameLength / sizeof(WCHAR)] = 0;
711
712 /* Compute device ID */
713 DevicePath.Length = 0;
714 DevicePath.MaximumLength = sizeof(REGSTR_KEY_ROOTENUM) + sizeof(L'\\') + SubKeyName.Length;
715 DevicePath.Buffer = ExAllocatePoolWithTag(PagedPool,
716 DevicePath.MaximumLength,
717 TAG_PNP_ROOT);
718 if (DevicePath.Buffer == NULL)
719 {
720 DPRINT1("ExAllocatePoolWithTag() failed\n");
721 Status = STATUS_NO_MEMORY;
722 goto cleanup;
723 }
724
725 RtlAppendUnicodeToString(&DevicePath, REGSTR_KEY_ROOTENUM L"\\");
726 RtlAppendUnicodeStringToString(&DevicePath, &SubKeyName);
727 DPRINT("Found device %wZ\\%S!\n", &DevicePath, SubKeyInfo->Name);
728 Status = CreateDeviceFromRegistry(DeviceExtension,
729 &DevicePath,
730 SubKeyInfo->Name,
731 SubKeyHandle);
732
733 /* If CreateDeviceFromRegistry didn't take ownership and zero this,
734 * we need to free it
735 */
736 RtlFreeUnicodeString(&DevicePath);
737
738 if (!NT_SUCCESS(Status))
739 {
740 goto cleanup;
741 }
742
743 Index2++;
744 }
745
746 ZwClose(SubKeyHandle);
747 SubKeyHandle = NULL;
748 Index1++;
749 }
750
751 cleanup:
752 if (SubKeyHandle != NULL)
753 ZwClose(SubKeyHandle);
754 if (KeyHandle != NULL)
755 ZwClose(KeyHandle);
756 if (KeyInfo)
757 ExFreePoolWithTag(KeyInfo, TAG_PNP_ROOT);
758 if (SubKeyInfo)
759 ExFreePoolWithTag(SubKeyInfo, TAG_PNP_ROOT);
760 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
761 return Status;
762 }
763
764 /* FUNCTION: Handle IRP_MN_QUERY_DEVICE_RELATIONS IRPs for the root bus device object
765 * ARGUMENTS:
766 * DeviceObject = Pointer to functional device object of the root bus driver
767 * Irp = Pointer to IRP that should be handled
768 * RETURNS:
769 * Status
770 */
771 static NTSTATUS
772 PnpRootQueryDeviceRelations(
773 IN PDEVICE_OBJECT DeviceObject,
774 IN PIRP Irp)
775 {
776 PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension;
777 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
778 PDEVICE_RELATIONS Relations = NULL, OtherRelations = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
779 PPNPROOT_DEVICE Device = NULL;
780 ULONG Size;
781 NTSTATUS Status;
782 PLIST_ENTRY NextEntry;
783
784 DPRINT("PnpRootQueryDeviceRelations(FDO %p, Irp %p)\n", DeviceObject, Irp);
785
786 Status = EnumerateDevices(DeviceObject);
787 if (!NT_SUCCESS(Status))
788 {
789 DPRINT("EnumerateDevices() failed with status 0x%08lx\n", Status);
790 return Status;
791 }
792
793 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
794
795 Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) + sizeof(PDEVICE_OBJECT) * DeviceExtension->DeviceListCount;
796 if (OtherRelations)
797 {
798 /* Another bus driver has already created a DEVICE_RELATIONS
799 * structure so we must merge this structure with our own */
800
801 Size += sizeof(PDEVICE_OBJECT) * OtherRelations->Count;
802 }
803 Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size);
804 if (!Relations)
805 {
806 DPRINT("ExAllocatePoolWithTag() failed\n");
807 Status = STATUS_NO_MEMORY;
808 goto cleanup;
809 }
810 RtlZeroMemory(Relations, Size);
811 if (OtherRelations)
812 {
813 Relations->Count = OtherRelations->Count;
814 RtlCopyMemory(Relations->Objects, OtherRelations->Objects, sizeof(PDEVICE_OBJECT) * OtherRelations->Count);
815 }
816
817 KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
818
819 /* Start looping */
820 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
821 NextEntry != &DeviceExtension->DeviceListHead;
822 NextEntry = NextEntry->Flink)
823 {
824 /* Get the entry */
825 Device = CONTAINING_RECORD(NextEntry, PNPROOT_DEVICE, ListEntry);
826
827 if (!Device->Pdo)
828 {
829 /* Create a physical device object for the
830 * device as it does not already have one */
831 Status = IoCreateDevice(
832 DeviceObject->DriverObject,
833 sizeof(PNPROOT_PDO_DEVICE_EXTENSION),
834 NULL,
835 FILE_DEVICE_CONTROLLER,
836 FILE_AUTOGENERATED_DEVICE_NAME,
837 FALSE,
838 &Device->Pdo);
839 if (!NT_SUCCESS(Status))
840 {
841 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
842 break;
843 }
844
845 PdoDeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;
846 RtlZeroMemory(PdoDeviceExtension, sizeof(PNPROOT_PDO_DEVICE_EXTENSION));
847 PdoDeviceExtension->Common.IsFDO = FALSE;
848 PdoDeviceExtension->DeviceInfo = Device;
849
850 Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
851 Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
852 }
853
854 /* Reference the physical device object. The PnP manager
855 will dereference it again when it is no longer needed */
856 ObReferenceObject(Device->Pdo);
857
858 Relations->Objects[Relations->Count++] = Device->Pdo;
859 }
860 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
861
862 Irp->IoStatus.Information = (ULONG_PTR)Relations;
863
864 cleanup:
865 if (!NT_SUCCESS(Status))
866 {
867 if (OtherRelations)
868 ExFreePool(OtherRelations);
869 if (Relations)
870 ExFreePool(Relations);
871 if (Device && Device->Pdo)
872 {
873 IoDeleteDevice(Device->Pdo);
874 Device->Pdo = NULL;
875 }
876 }
877
878 return Status;
879 }
880
881 /*
882 * FUNCTION: Handle Plug and Play IRPs for the root bus device object
883 * ARGUMENTS:
884 * DeviceObject = Pointer to functional device object of the root bus driver
885 * Irp = Pointer to IRP that should be handled
886 * RETURNS:
887 * Status
888 */
889 static NTSTATUS
890 PnpRootFdoPnpControl(
891 IN PDEVICE_OBJECT DeviceObject,
892 IN PIRP Irp)
893 {
894 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
895 PIO_STACK_LOCATION IrpSp;
896 NTSTATUS Status;
897
898 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
899 Status = Irp->IoStatus.Status;
900 IrpSp = IoGetCurrentIrpStackLocation(Irp);
901
902 switch (IrpSp->MinorFunction)
903 {
904 case IRP_MN_QUERY_DEVICE_RELATIONS:
905 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS\n");
906 Status = PnpRootQueryDeviceRelations(DeviceObject, Irp);
907 break;
908
909 case IRP_MN_START_DEVICE:
910 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
911 if (!IoForwardIrpSynchronously(DeviceExtension->Ldo, Irp))
912 Status = STATUS_UNSUCCESSFUL;
913 else
914 {
915 Status = Irp->IoStatus.Status;
916 if (NT_SUCCESS(Status))
917 DeviceExtension->State = dsStarted;
918 }
919
920 Irp->IoStatus.Status = Status;
921 IoCompleteRequest(Irp, IO_NO_INCREMENT);
922 return Status;
923
924 case IRP_MN_STOP_DEVICE:
925 DPRINT("IRP_MJ_PNP / IRP_MN_STOP_DEVICE\n");
926 /* Root device cannot be stopped */
927 Irp->IoStatus.Status = Status = STATUS_INVALID_DEVICE_REQUEST;
928 IoCompleteRequest(Irp, IO_NO_INCREMENT);
929 return Status;
930
931 default:
932 DPRINT("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp->MinorFunction);
933 break;
934 }
935
936 if (Status != STATUS_PENDING)
937 {
938 Irp->IoStatus.Status = Status;
939 IoCompleteRequest(Irp, IO_NO_INCREMENT);
940 }
941
942 return Status;
943 }
944
945 static NTSTATUS
946 PdoQueryDeviceRelations(
947 IN PDEVICE_OBJECT DeviceObject,
948 IN PIRP Irp,
949 IN PIO_STACK_LOCATION IrpSp)
950 {
951 PDEVICE_RELATIONS Relations;
952 NTSTATUS Status = Irp->IoStatus.Status;
953
954 if (IrpSp->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
955 return Status;
956
957 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / TargetDeviceRelation\n");
958 Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
959 if (!Relations)
960 {
961 DPRINT("ExAllocatePoolWithTag() failed\n");
962 Status = STATUS_NO_MEMORY;
963 }
964 else
965 {
966 ObReferenceObject(DeviceObject);
967 Relations->Count = 1;
968 Relations->Objects[0] = DeviceObject;
969 Status = STATUS_SUCCESS;
970 Irp->IoStatus.Information = (ULONG_PTR)Relations;
971 }
972
973 return Status;
974 }
975
976 static NTSTATUS
977 PdoQueryCapabilities(
978 IN PDEVICE_OBJECT DeviceObject,
979 IN PIRP Irp,
980 IN PIO_STACK_LOCATION IrpSp)
981 {
982 PDEVICE_CAPABILITIES DeviceCapabilities;
983
984 DeviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities;
985
986 if (DeviceCapabilities->Version != 1)
987 return STATUS_REVISION_MISMATCH;
988
989 DeviceCapabilities->UniqueID = TRUE;
990 /* FIXME: Fill other fields */
991
992 return STATUS_SUCCESS;
993 }
994
995 static NTSTATUS
996 PdoQueryResources(
997 IN PDEVICE_OBJECT DeviceObject,
998 IN PIRP Irp,
999 IN PIO_STACK_LOCATION IrpSp)
1000 {
1001 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
1002 PCM_RESOURCE_LIST ResourceList;
1003
1004 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1005
1006 if (DeviceExtension->DeviceInfo->ResourceList)
1007 {
1008 /* Copy existing resource requirement list */
1009 ResourceList = ExAllocatePool(
1010 PagedPool,
1011 DeviceExtension->DeviceInfo->ResourceListSize);
1012 if (!ResourceList)
1013 return STATUS_NO_MEMORY;
1014
1015 RtlCopyMemory(
1016 ResourceList,
1017 DeviceExtension->DeviceInfo->ResourceList,
1018 DeviceExtension->DeviceInfo->ResourceListSize);
1019
1020 Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
1021
1022 return STATUS_SUCCESS;
1023 }
1024 else
1025 {
1026 /* No resources so just return without changing the status */
1027 return Irp->IoStatus.Status;
1028 }
1029 }
1030
1031 static NTSTATUS
1032 PdoQueryResourceRequirements(
1033 IN PDEVICE_OBJECT DeviceObject,
1034 IN PIRP Irp,
1035 IN PIO_STACK_LOCATION IrpSp)
1036 {
1037 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
1038 PIO_RESOURCE_REQUIREMENTS_LIST ResourceList;
1039
1040 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1041
1042 if (DeviceExtension->DeviceInfo->ResourceRequirementsList)
1043 {
1044 /* Copy existing resource requirement list */
1045 ResourceList = ExAllocatePool(PagedPool, DeviceExtension->DeviceInfo->ResourceRequirementsList->ListSize);
1046 if (!ResourceList)
1047 return STATUS_NO_MEMORY;
1048
1049 RtlCopyMemory(
1050 ResourceList,
1051 DeviceExtension->DeviceInfo->ResourceRequirementsList,
1052 DeviceExtension->DeviceInfo->ResourceRequirementsList->ListSize);
1053
1054 Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
1055
1056 return STATUS_SUCCESS;
1057 }
1058 else
1059 {
1060 /* No resource requirements so just return without changing the status */
1061 return Irp->IoStatus.Status;
1062 }
1063 }
1064
1065 static NTSTATUS
1066 PdoQueryDeviceText(
1067 IN PDEVICE_OBJECT DeviceObject,
1068 IN PIRP Irp,
1069 IN PIO_STACK_LOCATION IrpSp)
1070 {
1071 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
1072 DEVICE_TEXT_TYPE DeviceTextType;
1073 NTSTATUS Status = Irp->IoStatus.Status;
1074
1075 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1076 DeviceTextType = IrpSp->Parameters.QueryDeviceText.DeviceTextType;
1077
1078 switch (DeviceTextType)
1079 {
1080 case DeviceTextDescription:
1081 {
1082 UNICODE_STRING String;
1083 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription\n");
1084
1085 if (DeviceExtension->DeviceInfo->DeviceDescription.Buffer != NULL)
1086 {
1087 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1088 &DeviceExtension->DeviceInfo->DeviceDescription,
1089 &String);
1090 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
1091 }
1092 break;
1093 }
1094
1095 case DeviceTextLocationInformation:
1096 {
1097 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextLocationInformation\n");
1098 break;
1099 }
1100
1101 default:
1102 {
1103 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown query id type 0x%lx\n", DeviceTextType);
1104 }
1105 }
1106
1107 return Status;
1108 }
1109
1110 static NTSTATUS
1111 PdoQueryId(
1112 IN PDEVICE_OBJECT DeviceObject,
1113 IN PIRP Irp,
1114 IN PIO_STACK_LOCATION IrpSp)
1115 {
1116 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
1117 BUS_QUERY_ID_TYPE IdType;
1118 NTSTATUS Status = Irp->IoStatus.Status;
1119
1120 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1121 IdType = IrpSp->Parameters.QueryId.IdType;
1122
1123 switch (IdType)
1124 {
1125 case BusQueryDeviceID:
1126 {
1127 UNICODE_STRING String;
1128 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
1129
1130 Status = RtlDuplicateUnicodeString(
1131 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1132 &DeviceExtension->DeviceInfo->DeviceID,
1133 &String);
1134 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
1135 break;
1136 }
1137
1138 case BusQueryHardwareIDs:
1139 case BusQueryCompatibleIDs:
1140 {
1141 /* Optional, do nothing */
1142 break;
1143 }
1144
1145 case BusQueryInstanceID:
1146 {
1147 UNICODE_STRING String;
1148 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
1149
1150 Status = RtlDuplicateUnicodeString(
1151 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1152 &DeviceExtension->DeviceInfo->InstanceID,
1153 &String);
1154 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
1155 break;
1156 }
1157
1158 default:
1159 {
1160 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType);
1161 }
1162 }
1163
1164 return Status;
1165 }
1166
1167 static NTSTATUS
1168 PdoQueryBusInformation(
1169 IN PDEVICE_OBJECT DeviceObject,
1170 IN PIRP Irp,
1171 IN PIO_STACK_LOCATION IrpSp)
1172 {
1173 PPNP_BUS_INFORMATION BusInfo;
1174 NTSTATUS Status;
1175
1176 BusInfo = (PPNP_BUS_INFORMATION)ExAllocatePoolWithTag(PagedPool, sizeof(PNP_BUS_INFORMATION), TAG_PNP_ROOT);
1177 if (!BusInfo)
1178 Status = STATUS_NO_MEMORY;
1179 else
1180 {
1181 RtlCopyMemory(
1182 &BusInfo->BusTypeGuid,
1183 &GUID_BUS_TYPE_INTERNAL,
1184 sizeof(BusInfo->BusTypeGuid));
1185 BusInfo->LegacyBusType = PNPBus;
1186 /* We're the only root bus enumerator on the computer */
1187 BusInfo->BusNumber = 0;
1188 Irp->IoStatus.Information = (ULONG_PTR)BusInfo;
1189 Status = STATUS_SUCCESS;
1190 }
1191
1192 return Status;
1193 }
1194
1195 /*
1196 * FUNCTION: Handle Plug and Play IRPs for the child device
1197 * ARGUMENTS:
1198 * DeviceObject = Pointer to physical device object of the child device
1199 * Irp = Pointer to IRP that should be handled
1200 * RETURNS:
1201 * Status
1202 */
1203 static NTSTATUS
1204 PnpRootPdoPnpControl(
1205 IN PDEVICE_OBJECT DeviceObject,
1206 IN PIRP Irp)
1207 {
1208 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
1209 PPNPROOT_FDO_DEVICE_EXTENSION FdoDeviceExtension;
1210 PIO_STACK_LOCATION IrpSp;
1211 NTSTATUS Status;
1212
1213 DeviceExtension = DeviceObject->DeviceExtension;
1214 FdoDeviceExtension = PnpRootDeviceObject->DeviceExtension;
1215 Status = Irp->IoStatus.Status;
1216 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1217
1218 switch (IrpSp->MinorFunction)
1219 {
1220 case IRP_MN_START_DEVICE: /* 0x00 */
1221 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
1222 Status = STATUS_SUCCESS;
1223 break;
1224
1225 case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x07 */
1226 Status = PdoQueryDeviceRelations(DeviceObject, Irp, IrpSp);
1227 break;
1228
1229 case IRP_MN_QUERY_CAPABILITIES: /* 0x09 */
1230 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
1231 Status = PdoQueryCapabilities(DeviceObject, Irp, IrpSp);
1232 break;
1233
1234 case IRP_MN_QUERY_RESOURCES: /* 0x0a */
1235 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n");
1236 Status = PdoQueryResources(DeviceObject, Irp, IrpSp);
1237 break;
1238
1239 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: /* 0x0b */
1240 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
1241 Status = PdoQueryResourceRequirements(DeviceObject, Irp, IrpSp);
1242 break;
1243
1244 case IRP_MN_QUERY_DEVICE_TEXT: /* 0x0c */
1245 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
1246 Status = PdoQueryDeviceText(DeviceObject, Irp, IrpSp);
1247 break;
1248
1249 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0x0d */
1250 DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
1251 break;
1252
1253 case IRP_MN_REMOVE_DEVICE:
1254 /* Remove the device from the device list and decrement the device count*/
1255 KeAcquireGuardedMutex(&FdoDeviceExtension->DeviceListLock);
1256 RemoveEntryList(&DeviceExtension->DeviceInfo->ListEntry);
1257 FdoDeviceExtension->DeviceListCount--;
1258 KeReleaseGuardedMutex(&FdoDeviceExtension->DeviceListLock);
1259
1260 /* Free some strings we created */
1261 RtlFreeUnicodeString(&DeviceExtension->DeviceInfo->DeviceDescription);
1262 RtlFreeUnicodeString(&DeviceExtension->DeviceInfo->DeviceID);
1263 RtlFreeUnicodeString(&DeviceExtension->DeviceInfo->InstanceID);
1264
1265 /* Free the resource requirements list */
1266 if (DeviceExtension->DeviceInfo->ResourceRequirementsList != NULL)
1267 ExFreePool(DeviceExtension->DeviceInfo->ResourceRequirementsList);
1268
1269 /* Free the boot resources list */
1270 if (DeviceExtension->DeviceInfo->ResourceList != NULL)
1271 ExFreePool(DeviceExtension->DeviceInfo->ResourceList);
1272
1273 /* Free the device info */
1274 ExFreePool(DeviceExtension->DeviceInfo);
1275
1276 /* Finally, delete the device object */
1277 IoDeleteDevice(DeviceObject);
1278
1279 /* Return success */
1280 Status = STATUS_SUCCESS;
1281 break;
1282
1283 case IRP_MN_QUERY_ID: /* 0x13 */
1284 Status = PdoQueryId(DeviceObject, Irp, IrpSp);
1285 break;
1286
1287 case IRP_MN_QUERY_PNP_DEVICE_STATE: /* 0x14 */
1288 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_PNP_DEVICE_STATE\n");
1289 break;
1290
1291 case IRP_MN_QUERY_BUS_INFORMATION: /* 0x15 */
1292 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_BUS_INFORMATION\n");
1293 Status = PdoQueryBusInformation(DeviceObject, Irp, IrpSp);
1294 break;
1295
1296 default:
1297 DPRINT1("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp->MinorFunction);
1298 break;
1299 }
1300
1301 if (Status != STATUS_PENDING)
1302 {
1303 Irp->IoStatus.Status = Status;
1304 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1305 }
1306
1307 return Status;
1308 }
1309
1310 /*
1311 * FUNCTION: Handle Plug and Play IRPs
1312 * ARGUMENTS:
1313 * DeviceObject = Pointer to PDO or FDO
1314 * Irp = Pointer to IRP that should be handled
1315 * RETURNS:
1316 * Status
1317 */
1318 static NTSTATUS NTAPI
1319 PnpRootPnpControl(
1320 IN PDEVICE_OBJECT DeviceObject,
1321 IN PIRP Irp)
1322 {
1323 PPNPROOT_COMMON_DEVICE_EXTENSION DeviceExtension;
1324 NTSTATUS Status;
1325
1326 DeviceExtension = (PPNPROOT_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1327
1328 if (DeviceExtension->IsFDO)
1329 Status = PnpRootFdoPnpControl(DeviceObject, Irp);
1330 else
1331 Status = PnpRootPdoPnpControl(DeviceObject, Irp);
1332
1333 return Status;
1334 }
1335
1336 /*
1337 * FUNCTION: Handle Power IRPs
1338 * ARGUMENTS:
1339 * DeviceObject = Pointer to PDO or FDO
1340 * Irp = Pointer to IRP that should be handled
1341 * RETURNS:
1342 * Status
1343 */
1344 static NTSTATUS NTAPI
1345 PnpRootPowerControl(
1346 IN PDEVICE_OBJECT DeviceObject,
1347 IN PIRP Irp)
1348 {
1349 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
1350 PIO_STACK_LOCATION IrpSp;
1351 NTSTATUS Status;
1352
1353 DeviceExtension = DeviceObject->DeviceExtension;
1354 Status = Irp->IoStatus.Status;
1355 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1356
1357 if (DeviceExtension->Common.IsFDO)
1358 {
1359 ASSERT(!DeviceExtension->Common.IsFDO);
1360 PoStartNextPowerIrp(Irp);
1361 IoCopyCurrentIrpStackLocationToNext(Irp);
1362 Status = PoCallDriver(DeviceExtension->Ldo, Irp);
1363 }
1364 else
1365 {
1366 switch (IrpSp->MinorFunction)
1367 {
1368 case IRP_MN_QUERY_POWER:
1369 case IRP_MN_SET_POWER:
1370 Status = STATUS_SUCCESS;
1371 break;
1372 }
1373 Irp->IoStatus.Status = Status;
1374 PoStartNextPowerIrp(Irp);
1375 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1376 }
1377
1378 return Status;
1379 }
1380
1381 NTSTATUS
1382 NTAPI
1383 PnpRootAddDevice(
1384 IN PDRIVER_OBJECT DriverObject,
1385 IN PDEVICE_OBJECT PhysicalDeviceObject)
1386 {
1387 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
1388 NTSTATUS Status;
1389
1390 DPRINT("PnpRootAddDevice(DriverObject %p, Pdo %p)\n", DriverObject, PhysicalDeviceObject);
1391
1392 if (!PhysicalDeviceObject)
1393 {
1394 DPRINT("PhysicalDeviceObject 0x%p\n", PhysicalDeviceObject);
1395 Status = STATUS_INSUFFICIENT_RESOURCES;
1396 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
1397 }
1398
1399 Status = IoCreateDevice(
1400 DriverObject,
1401 sizeof(PNPROOT_FDO_DEVICE_EXTENSION),
1402 NULL,
1403 FILE_DEVICE_BUS_EXTENDER,
1404 FILE_DEVICE_SECURE_OPEN,
1405 TRUE,
1406 &PnpRootDeviceObject);
1407 if (!NT_SUCCESS(Status))
1408 {
1409 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
1410 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
1411 }
1412 DPRINT("Created FDO %p\n", PnpRootDeviceObject);
1413
1414 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)PnpRootDeviceObject->DeviceExtension;
1415 RtlZeroMemory(DeviceExtension, sizeof(PNPROOT_FDO_DEVICE_EXTENSION));
1416
1417 DeviceExtension->Common.IsFDO = TRUE;
1418 DeviceExtension->State = dsStopped;
1419 InitializeListHead(&DeviceExtension->DeviceListHead);
1420 DeviceExtension->DeviceListCount = 0;
1421 KeInitializeGuardedMutex(&DeviceExtension->DeviceListLock);
1422
1423 Status = IoAttachDeviceToDeviceStackSafe(
1424 PnpRootDeviceObject,
1425 PhysicalDeviceObject,
1426 &DeviceExtension->Ldo);
1427 if (!NT_SUCCESS(Status))
1428 {
1429 DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
1430 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
1431 }
1432
1433 PnpRootDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1434
1435 DPRINT("Done AddDevice()\n");
1436
1437 return STATUS_SUCCESS;
1438 }
1439
1440 #if MI_TRACE_PFNS
1441 PDEVICE_OBJECT IopPfnDumpDeviceObject;
1442
1443 NTSTATUS NTAPI
1444 PnpRootCreateClose(
1445 _In_ PDEVICE_OBJECT DeviceObject,
1446 _In_ PIRP Irp)
1447 {
1448 PIO_STACK_LOCATION IoStack;
1449
1450 if (DeviceObject != IopPfnDumpDeviceObject)
1451 {
1452 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
1453 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1454 return STATUS_INVALID_DEVICE_REQUEST;
1455 }
1456
1457 IoStack = IoGetCurrentIrpStackLocation(Irp);
1458 if (IoStack->MajorFunction == IRP_MJ_CREATE)
1459 {
1460 MmDumpArmPfnDatabase(TRUE);
1461 }
1462
1463 Irp->IoStatus.Status = STATUS_SUCCESS;
1464 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1465 return STATUS_SUCCESS;
1466 }
1467 #endif
1468
1469 NTSTATUS NTAPI
1470 PnpRootDriverEntry(
1471 IN PDRIVER_OBJECT DriverObject,
1472 IN PUNICODE_STRING RegistryPath)
1473 {
1474 #if MI_TRACE_PFNS
1475 NTSTATUS Status;
1476 UNICODE_STRING PfnDumpDeviceName = RTL_CONSTANT_STRING(L"\\Device\\PfnDump");
1477 #endif
1478
1479 DPRINT("PnpRootDriverEntry(%p %wZ)\n", DriverObject, RegistryPath);
1480
1481 IopRootDriverObject = DriverObject;
1482
1483 DriverObject->DriverExtension->AddDevice = PnpRootAddDevice;
1484
1485 #if MI_TRACE_PFNS
1486 DriverObject->MajorFunction[IRP_MJ_CREATE] = PnpRootCreateClose;
1487 DriverObject->MajorFunction[IRP_MJ_CLOSE] = PnpRootCreateClose;
1488 #endif
1489 DriverObject->MajorFunction[IRP_MJ_PNP] = PnpRootPnpControl;
1490 DriverObject->MajorFunction[IRP_MJ_POWER] = PnpRootPowerControl;
1491
1492 #if MI_TRACE_PFNS
1493 Status = IoCreateDevice(DriverObject,
1494 0,
1495 &PfnDumpDeviceName,
1496 FILE_DEVICE_UNKNOWN,
1497 0,
1498 FALSE,
1499 &IopPfnDumpDeviceObject);
1500 if (!NT_SUCCESS(Status))
1501 {
1502 DPRINT1("Creating PFN Dump device failed with %lx\n", Status);
1503 }
1504 else
1505 {
1506 IopPfnDumpDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1507 }
1508 #endif
1509
1510 return STATUS_SUCCESS;
1511 }