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