xref: /reactos/ntoskrnl/io/pnpmgr/pnpmgr.c (revision 1734f297)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * COPYRIGHT:       GPL - See COPYING in the top level directory
4  * FILE:            ntoskrnl/io/pnpmgr/pnpmgr.c
5  * PURPOSE:         Initializes the PnP manager
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 ERESOURCE PpRegistryDeviceResource;
19 KGUARDED_MUTEX PpDeviceReferenceTableLock;
20 RTL_AVL_TABLE PpDeviceReferenceTable;
21 
22 extern ULONG ExpInitializationPhase;
23 
24 /* DATA **********************************************************************/
25 
26 PDRIVER_OBJECT IopRootDriverObject;
27 PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList = NULL;
28 
29 /* FUNCTIONS *****************************************************************/
30 
31 VOID
32 IopFixupDeviceId(PWCHAR String)
33 {
34     SIZE_T Length = wcslen(String), i;
35 
36     for (i = 0; i < Length; i++)
37     {
38         if (String[i] == L'\\')
39             String[i] = L'#';
40     }
41 }
42 
43 VOID
44 NTAPI
45 IopInstallCriticalDevice(PDEVICE_NODE DeviceNode)
46 {
47     NTSTATUS Status;
48     HANDLE CriticalDeviceKey, InstanceKey;
49     OBJECT_ATTRIBUTES ObjectAttributes;
50     UNICODE_STRING CriticalDeviceKeyU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CriticalDeviceDatabase");
51     UNICODE_STRING CompatibleIdU = RTL_CONSTANT_STRING(L"CompatibleIDs");
52     UNICODE_STRING HardwareIdU = RTL_CONSTANT_STRING(L"HardwareID");
53     UNICODE_STRING ServiceU = RTL_CONSTANT_STRING(L"Service");
54     UNICODE_STRING ClassGuidU = RTL_CONSTANT_STRING(L"ClassGUID");
55     PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
56     ULONG HidLength = 0, CidLength = 0, BufferLength;
57     PWCHAR IdBuffer, OriginalIdBuffer;
58 
59     /* Open the device instance key */
60     Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey);
61     if (Status != STATUS_SUCCESS)
62         return;
63 
64     Status = ZwQueryValueKey(InstanceKey,
65                              &HardwareIdU,
66                              KeyValuePartialInformation,
67                              NULL,
68                              0,
69                              &HidLength);
70     if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
71     {
72         ZwClose(InstanceKey);
73         return;
74     }
75 
76     Status = ZwQueryValueKey(InstanceKey,
77                              &CompatibleIdU,
78                              KeyValuePartialInformation,
79                              NULL,
80                              0,
81                              &CidLength);
82     if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
83     {
84         CidLength = 0;
85     }
86 
87     BufferLength = HidLength + CidLength;
88     BufferLength -= (((CidLength != 0) ? 2 : 1) * FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data));
89 
90     /* Allocate a buffer to hold data from both */
91     OriginalIdBuffer = IdBuffer = ExAllocatePool(PagedPool, BufferLength);
92     if (!IdBuffer)
93     {
94         ZwClose(InstanceKey);
95         return;
96     }
97 
98     /* Compute the buffer size */
99     if (HidLength > CidLength)
100         BufferLength = HidLength;
101     else
102         BufferLength = CidLength;
103 
104     PartialInfo = ExAllocatePool(PagedPool, BufferLength);
105     if (!PartialInfo)
106     {
107         ZwClose(InstanceKey);
108         ExFreePool(OriginalIdBuffer);
109         return;
110     }
111 
112     Status = ZwQueryValueKey(InstanceKey,
113                              &HardwareIdU,
114                              KeyValuePartialInformation,
115                              PartialInfo,
116                              HidLength,
117                              &HidLength);
118     if (Status != STATUS_SUCCESS)
119     {
120         ExFreePool(PartialInfo);
121         ExFreePool(OriginalIdBuffer);
122         ZwClose(InstanceKey);
123         return;
124     }
125 
126     /* Copy in HID info first (without 2nd terminating NULL if CID is present) */
127     HidLength = PartialInfo->DataLength - ((CidLength != 0) ? sizeof(WCHAR) : 0);
128     RtlCopyMemory(IdBuffer, PartialInfo->Data, HidLength);
129 
130     if (CidLength != 0)
131     {
132         Status = ZwQueryValueKey(InstanceKey,
133                                  &CompatibleIdU,
134                                  KeyValuePartialInformation,
135                                  PartialInfo,
136                                  CidLength,
137                                  &CidLength);
138         if (Status != STATUS_SUCCESS)
139         {
140             ExFreePool(PartialInfo);
141             ExFreePool(OriginalIdBuffer);
142             ZwClose(InstanceKey);
143             return;
144         }
145 
146         /* Copy CID next */
147         CidLength = PartialInfo->DataLength;
148         RtlCopyMemory(((PUCHAR)IdBuffer) + HidLength, PartialInfo->Data, CidLength);
149     }
150 
151     /* Free our temp buffer */
152     ExFreePool(PartialInfo);
153 
154     InitializeObjectAttributes(&ObjectAttributes,
155                                &CriticalDeviceKeyU,
156                                OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
157                                NULL,
158                                NULL);
159     Status = ZwOpenKey(&CriticalDeviceKey,
160                        KEY_ENUMERATE_SUB_KEYS,
161                        &ObjectAttributes);
162     if (!NT_SUCCESS(Status))
163     {
164         /* The critical device database doesn't exist because
165          * we're probably in 1st stage setup, but it's ok */
166         ExFreePool(OriginalIdBuffer);
167         ZwClose(InstanceKey);
168         return;
169     }
170 
171     while (*IdBuffer)
172     {
173         USHORT StringLength = (USHORT)wcslen(IdBuffer) + 1, Index;
174 
175         IopFixupDeviceId(IdBuffer);
176 
177         /* Look through all subkeys for a match */
178         for (Index = 0; TRUE; Index++)
179         {
180             ULONG NeededLength;
181             PKEY_BASIC_INFORMATION BasicInfo;
182 
183             Status = ZwEnumerateKey(CriticalDeviceKey,
184                                     Index,
185                                     KeyBasicInformation,
186                                     NULL,
187                                     0,
188                                     &NeededLength);
189             if (Status == STATUS_NO_MORE_ENTRIES)
190                 break;
191             else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
192             {
193                 UNICODE_STRING ChildIdNameU, RegKeyNameU;
194 
195                 BasicInfo = ExAllocatePool(PagedPool, NeededLength);
196                 if (!BasicInfo)
197                 {
198                     /* No memory */
199                     ExFreePool(OriginalIdBuffer);
200                     ZwClose(CriticalDeviceKey);
201                     ZwClose(InstanceKey);
202                     return;
203                 }
204 
205                 Status = ZwEnumerateKey(CriticalDeviceKey,
206                                         Index,
207                                         KeyBasicInformation,
208                                         BasicInfo,
209                                         NeededLength,
210                                         &NeededLength);
211                 if (Status != STATUS_SUCCESS)
212                 {
213                     /* This shouldn't happen */
214                     ExFreePool(BasicInfo);
215                     continue;
216                 }
217 
218                 ChildIdNameU.Buffer = IdBuffer;
219                 ChildIdNameU.MaximumLength = ChildIdNameU.Length = (StringLength - 1) * sizeof(WCHAR);
220                 RegKeyNameU.Buffer = BasicInfo->Name;
221                 RegKeyNameU.MaximumLength = RegKeyNameU.Length = (USHORT)BasicInfo->NameLength;
222 
223                 if (RtlEqualUnicodeString(&ChildIdNameU, &RegKeyNameU, TRUE))
224                 {
225                     HANDLE ChildKeyHandle;
226 
227                     InitializeObjectAttributes(&ObjectAttributes,
228                                                &ChildIdNameU,
229                                                OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
230                                                CriticalDeviceKey,
231                                                NULL);
232 
233                     Status = ZwOpenKey(&ChildKeyHandle,
234                                        KEY_QUERY_VALUE,
235                                        &ObjectAttributes);
236                     if (Status != STATUS_SUCCESS)
237                     {
238                         ExFreePool(BasicInfo);
239                         continue;
240                     }
241 
242                     /* Check if there's already a driver installed */
243                     Status = ZwQueryValueKey(InstanceKey,
244                                              &ClassGuidU,
245                                              KeyValuePartialInformation,
246                                              NULL,
247                                              0,
248                                              &NeededLength);
249                     if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
250                     {
251                         ExFreePool(BasicInfo);
252                         continue;
253                     }
254 
255                     Status = ZwQueryValueKey(ChildKeyHandle,
256                                              &ClassGuidU,
257                                              KeyValuePartialInformation,
258                                              NULL,
259                                              0,
260                                              &NeededLength);
261                     if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
262                     {
263                         ExFreePool(BasicInfo);
264                         continue;
265                     }
266 
267                     PartialInfo = ExAllocatePool(PagedPool, NeededLength);
268                     if (!PartialInfo)
269                     {
270                         ExFreePool(OriginalIdBuffer);
271                         ExFreePool(BasicInfo);
272                         ZwClose(InstanceKey);
273                         ZwClose(ChildKeyHandle);
274                         ZwClose(CriticalDeviceKey);
275                         return;
276                     }
277 
278                     /* Read ClassGUID entry in the CDDB */
279                     Status = ZwQueryValueKey(ChildKeyHandle,
280                                              &ClassGuidU,
281                                              KeyValuePartialInformation,
282                                              PartialInfo,
283                                              NeededLength,
284                                              &NeededLength);
285                     if (Status != STATUS_SUCCESS)
286                     {
287                         ExFreePool(BasicInfo);
288                         continue;
289                     }
290 
291                     /* Write it to the ENUM key */
292                     Status = ZwSetValueKey(InstanceKey,
293                                            &ClassGuidU,
294                                            0,
295                                            REG_SZ,
296                                            PartialInfo->Data,
297                                            PartialInfo->DataLength);
298                     if (Status != STATUS_SUCCESS)
299                     {
300                         ExFreePool(BasicInfo);
301                         ExFreePool(PartialInfo);
302                         ZwClose(ChildKeyHandle);
303                         continue;
304                     }
305 
306                     Status = ZwQueryValueKey(ChildKeyHandle,
307                                              &ServiceU,
308                                              KeyValuePartialInformation,
309                                              NULL,
310                                              0,
311                                              &NeededLength);
312                     if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
313                     {
314                         ExFreePool(PartialInfo);
315                         PartialInfo = ExAllocatePool(PagedPool, NeededLength);
316                         if (!PartialInfo)
317                         {
318                             ExFreePool(OriginalIdBuffer);
319                             ExFreePool(BasicInfo);
320                             ZwClose(InstanceKey);
321                             ZwClose(ChildKeyHandle);
322                             ZwClose(CriticalDeviceKey);
323                             return;
324                         }
325 
326                         /* Read the service entry from the CDDB */
327                         Status = ZwQueryValueKey(ChildKeyHandle,
328                                                  &ServiceU,
329                                                  KeyValuePartialInformation,
330                                                  PartialInfo,
331                                                  NeededLength,
332                                                  &NeededLength);
333                         if (Status != STATUS_SUCCESS)
334                         {
335                             ExFreePool(BasicInfo);
336                             ExFreePool(PartialInfo);
337                             ZwClose(ChildKeyHandle);
338                             continue;
339                         }
340 
341                         /* Write it to the ENUM key */
342                         Status = ZwSetValueKey(InstanceKey,
343                                                &ServiceU,
344                                                0,
345                                                REG_SZ,
346                                                PartialInfo->Data,
347                                                PartialInfo->DataLength);
348                         if (Status != STATUS_SUCCESS)
349                         {
350                             ExFreePool(BasicInfo);
351                             ExFreePool(PartialInfo);
352                             ZwClose(ChildKeyHandle);
353                             continue;
354                         }
355 
356                         DPRINT("Installed service '%S' for critical device '%wZ'\n", PartialInfo->Data, &ChildIdNameU);
357                     }
358                     else
359                     {
360                         DPRINT1("Installed NULL service for critical device '%wZ'\n", &ChildIdNameU);
361                     }
362 
363                     ExFreePool(OriginalIdBuffer);
364                     ExFreePool(PartialInfo);
365                     ExFreePool(BasicInfo);
366                     ZwClose(InstanceKey);
367                     ZwClose(ChildKeyHandle);
368                     ZwClose(CriticalDeviceKey);
369 
370                     /* That's it */
371                     return;
372                 }
373 
374                 ExFreePool(BasicInfo);
375             }
376             else
377             {
378                 /* Umm, not sure what happened here */
379                 continue;
380             }
381         }
382 
383         /* Advance to the next ID */
384         IdBuffer += StringLength;
385     }
386 
387     ExFreePool(OriginalIdBuffer);
388     ZwClose(InstanceKey);
389     ZwClose(CriticalDeviceKey);
390 }
391 
392 NTSTATUS
393 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
394 {
395     KIRQL OldIrql;
396 
397     if (PopSystemPowerDeviceNode)
398     {
399         KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
400         *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject;
401         KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
402 
403         return STATUS_SUCCESS;
404     }
405 
406     return STATUS_UNSUCCESSFUL;
407 }
408 
409 USHORT
410 NTAPI
411 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
412 {
413     USHORT i = 0, FoundIndex = 0xFFFF;
414     ULONG NewSize;
415     PVOID NewList;
416 
417     /* Acquire the lock */
418     ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
419 
420     /* Loop all entries */
421     while (i < PnpBusTypeGuidList->GuidCount)
422     {
423          /* Try to find a match */
424          if (RtlCompareMemory(BusTypeGuid,
425                               &PnpBusTypeGuidList->Guids[i],
426                               sizeof(GUID)) == sizeof(GUID))
427          {
428               /* Found it */
429               FoundIndex = i;
430               goto Quickie;
431          }
432          i++;
433     }
434 
435     /* Check if we have to grow the list */
436     if (PnpBusTypeGuidList->GuidCount)
437     {
438         /* Calculate the new size */
439         NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) +
440                  (sizeof(GUID) * PnpBusTypeGuidList->GuidCount);
441 
442         /* Allocate the new copy */
443         NewList = ExAllocatePool(PagedPool, NewSize);
444 
445         if (!NewList)
446         {
447             /* Fail */
448             ExFreePool(PnpBusTypeGuidList);
449             goto Quickie;
450         }
451 
452         /* Now copy them, decrease the size too */
453         NewSize -= sizeof(GUID);
454         RtlCopyMemory(NewList, PnpBusTypeGuidList, NewSize);
455 
456         /* Free the old list */
457         ExFreePool(PnpBusTypeGuidList);
458 
459         /* Use the new buffer */
460         PnpBusTypeGuidList = NewList;
461     }
462 
463     /* Copy the new GUID */
464     RtlCopyMemory(&PnpBusTypeGuidList->Guids[PnpBusTypeGuidList->GuidCount],
465                   BusTypeGuid,
466                   sizeof(GUID));
467 
468     /* The new entry is the index */
469     FoundIndex = (USHORT)PnpBusTypeGuidList->GuidCount;
470     PnpBusTypeGuidList->GuidCount++;
471 
472 Quickie:
473     ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
474     return FoundIndex;
475 }
476 
477 NTSTATUS
478 NTAPI
479 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject,
480                   IN OUT PIO_STATUS_BLOCK IoStatusBlock,
481                   IN UCHAR MinorFunction,
482                   IN PIO_STACK_LOCATION Stack OPTIONAL)
483 {
484     IO_STACK_LOCATION IoStackLocation;
485 
486     /* Fill out the stack information */
487     RtlZeroMemory(&IoStackLocation, sizeof(IO_STACK_LOCATION));
488     IoStackLocation.MajorFunction = IRP_MJ_PNP;
489     IoStackLocation.MinorFunction = MinorFunction;
490     if (Stack)
491     {
492         /* Copy the rest */
493         RtlCopyMemory(&IoStackLocation.Parameters,
494                       &Stack->Parameters,
495                       sizeof(Stack->Parameters));
496     }
497 
498     /* Do the PnP call */
499     IoStatusBlock->Status = IopSynchronousCall(DeviceObject,
500                                                &IoStackLocation,
501                                                (PVOID)&IoStatusBlock->Information);
502     return IoStatusBlock->Status;
503 }
504 
505 /*
506  * IopCreateDeviceKeyPath
507  *
508  * Creates a registry key
509  *
510  * Parameters
511  *    RegistryPath
512  *        Name of the key to be created.
513  *    Handle
514  *        Handle to the newly created key
515  *
516  * Remarks
517  *     This method can create nested trees, so parent of RegistryPath can
518  *     be not existant, and will be created if needed.
519  */
520 NTSTATUS
521 NTAPI
522 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
523                        IN ULONG CreateOptions,
524                        OUT PHANDLE Handle)
525 {
526     UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
527     HANDLE hParent = NULL, hKey;
528     OBJECT_ATTRIBUTES ObjectAttributes;
529     UNICODE_STRING KeyName;
530     PCWSTR Current, Last;
531     USHORT Length;
532     NTSTATUS Status;
533 
534     /* Assume failure */
535     *Handle = NULL;
536 
537     /* Open root key for device instances */
538     Status = IopOpenRegistryKeyEx(&hParent, NULL, &EnumU, KEY_CREATE_SUB_KEY);
539     if (!NT_SUCCESS(Status))
540     {
541         DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
542         return Status;
543     }
544 
545     Current = KeyName.Buffer = RegistryPath->Buffer;
546     Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)];
547 
548     /* Go up to the end of the string */
549     while (Current <= Last)
550     {
551         if (Current != Last && *Current != L'\\')
552         {
553             /* Not the end of the string and not a separator */
554             Current++;
555             continue;
556         }
557 
558         /* Prepare relative key name */
559         Length = (USHORT)((ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer);
560         KeyName.MaximumLength = KeyName.Length = Length;
561         DPRINT("Create '%wZ'\n", &KeyName);
562 
563         /* Open key */
564         InitializeObjectAttributes(&ObjectAttributes,
565                                    &KeyName,
566                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
567                                    hParent,
568                                    NULL);
569         Status = ZwCreateKey(&hKey,
570                              Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY,
571                              &ObjectAttributes,
572                              0,
573                              NULL,
574                              CreateOptions,
575                              NULL);
576 
577         /* Close parent key handle, we don't need it anymore */
578         if (hParent)
579             ZwClose(hParent);
580 
581         /* Key opening/creating failed? */
582         if (!NT_SUCCESS(Status))
583         {
584             DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status);
585             return Status;
586         }
587 
588         /* Check if it is the end of the string */
589         if (Current == Last)
590         {
591             /* Yes, return success */
592             *Handle = hKey;
593             return STATUS_SUCCESS;
594         }
595 
596         /* Start with this new parent key */
597         hParent = hKey;
598         Current++;
599         KeyName.Buffer = (PWSTR)Current;
600     }
601 
602     return STATUS_UNSUCCESSFUL;
603 }
604 
605 NTSTATUS
606 IopSetDeviceInstanceData(HANDLE InstanceKey,
607                          PDEVICE_NODE DeviceNode)
608 {
609     OBJECT_ATTRIBUTES ObjectAttributes;
610     UNICODE_STRING KeyName;
611     HANDLE LogConfKey, ControlKey, DeviceParamsKey;
612     ULONG ResCount;
613     ULONG ResultLength;
614     NTSTATUS Status;
615 
616     DPRINT("IopSetDeviceInstanceData() called\n");
617 
618     /* Create the 'LogConf' key */
619     RtlInitUnicodeString(&KeyName, L"LogConf");
620     InitializeObjectAttributes(&ObjectAttributes,
621                                &KeyName,
622                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
623                                InstanceKey,
624                                NULL);
625     Status = ZwCreateKey(&LogConfKey,
626                          KEY_ALL_ACCESS,
627                          &ObjectAttributes,
628                          0,
629                          NULL,
630                          // FIXME? In r53694 it was silently turned from non-volatile into this,
631                          // without any extra warning. Is this still needed??
632                          REG_OPTION_VOLATILE,
633                          NULL);
634     if (NT_SUCCESS(Status))
635     {
636         /* Set 'BootConfig' value */
637         if (DeviceNode->BootResources != NULL)
638         {
639             ResCount = DeviceNode->BootResources->Count;
640             if (ResCount != 0)
641             {
642                 RtlInitUnicodeString(&KeyName, L"BootConfig");
643                 Status = ZwSetValueKey(LogConfKey,
644                                        &KeyName,
645                                        0,
646                                        REG_RESOURCE_LIST,
647                                        DeviceNode->BootResources,
648                                        PnpDetermineResourceListSize(DeviceNode->BootResources));
649             }
650         }
651 
652         /* Set 'BasicConfigVector' value */
653         if (DeviceNode->ResourceRequirements != NULL &&
654             DeviceNode->ResourceRequirements->ListSize != 0)
655         {
656             RtlInitUnicodeString(&KeyName, L"BasicConfigVector");
657             Status = ZwSetValueKey(LogConfKey,
658                                    &KeyName,
659                                    0,
660                                    REG_RESOURCE_REQUIREMENTS_LIST,
661                                    DeviceNode->ResourceRequirements,
662                                    DeviceNode->ResourceRequirements->ListSize);
663         }
664 
665         ZwClose(LogConfKey);
666     }
667 
668     /* Set the 'ConfigFlags' value */
669     RtlInitUnicodeString(&KeyName, L"ConfigFlags");
670     Status = ZwQueryValueKey(InstanceKey,
671                              &KeyName,
672                              KeyValueBasicInformation,
673                              NULL,
674                              0,
675                              &ResultLength);
676     if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
677     {
678         /* Write the default value */
679         ULONG DefaultConfigFlags = 0;
680         Status = ZwSetValueKey(InstanceKey,
681                                &KeyName,
682                                0,
683                                REG_DWORD,
684                                &DefaultConfigFlags,
685                                sizeof(DefaultConfigFlags));
686     }
687 
688     /* Create the 'Control' key */
689     RtlInitUnicodeString(&KeyName, L"Control");
690     InitializeObjectAttributes(&ObjectAttributes,
691                                &KeyName,
692                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
693                                InstanceKey,
694                                NULL);
695     Status = ZwCreateKey(&ControlKey,
696                          0,
697                          &ObjectAttributes,
698                          0,
699                          NULL,
700                          REG_OPTION_VOLATILE,
701                          NULL);
702     if (NT_SUCCESS(Status))
703         ZwClose(ControlKey);
704 
705     /* Create the 'Device Parameters' key and set the 'FirmwareIdentified' value for all ACPI-enumerated devices */
706     if (_wcsnicmp(DeviceNode->InstancePath.Buffer, L"ACPI\\", 5) == 0)
707     {
708         RtlInitUnicodeString(&KeyName, L"Device Parameters");
709         InitializeObjectAttributes(&ObjectAttributes,
710                                    &KeyName,
711                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
712                                    InstanceKey,
713                                    NULL);
714         Status = ZwCreateKey(&DeviceParamsKey,
715                              0,
716                              &ObjectAttributes,
717                              0,
718                              NULL,
719                              REG_OPTION_NON_VOLATILE,
720                              NULL);
721         if (NT_SUCCESS(Status))
722         {
723             ULONG FirmwareIdentified = 1;
724             RtlInitUnicodeString(&KeyName, L"FirmwareIdentified");
725             Status = ZwSetValueKey(DeviceParamsKey,
726                                    &KeyName,
727                                    0,
728                                    REG_DWORD,
729                                    &FirmwareIdentified,
730                                    sizeof(FirmwareIdentified));
731 
732             ZwClose(DeviceParamsKey);
733         }
734     }
735 
736     DPRINT("IopSetDeviceInstanceData() done\n");
737 
738     return Status;
739 }
740 
741 /*
742  * IopGetParentIdPrefix
743  *
744  * Retrieve (or create) a string which identifies a device.
745  *
746  * Parameters
747  *    DeviceNode
748  *        Pointer to device node.
749  *    ParentIdPrefix
750  *        Pointer to the string where is returned the parent node identifier
751  *
752  * Remarks
753  *     If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
754  *     valid and its Buffer field is NULL-terminated. The caller needs to
755  *     to free the string with RtlFreeUnicodeString when it is no longer
756  *     needed.
757  */
758 
759 NTSTATUS
760 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
761                      PUNICODE_STRING ParentIdPrefix)
762 {
763     const UNICODE_STRING EnumKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
764     ULONG KeyNameBufferLength;
765     PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
766     UNICODE_STRING KeyName = {0, 0, NULL};
767     UNICODE_STRING KeyValue;
768     UNICODE_STRING ValueName;
769     HANDLE hKey = NULL;
770     ULONG crc32;
771     NTSTATUS Status;
772 
773     /* HACK: As long as some devices have a NULL device
774      * instance path, the following test is required :(
775      */
776     if (DeviceNode->Parent->InstancePath.Length == 0)
777     {
778         DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
779                 &DeviceNode->InstancePath);
780         return STATUS_UNSUCCESSFUL;
781     }
782 
783     /* 1. Try to retrieve ParentIdPrefix from registry */
784     KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(L"12345678&12345678");
785     ParentIdPrefixInformation = ExAllocatePoolWithTag(PagedPool,
786                                                       KeyNameBufferLength + sizeof(UNICODE_NULL),
787                                                       TAG_IO);
788     if (!ParentIdPrefixInformation)
789     {
790         return STATUS_INSUFFICIENT_RESOURCES;
791     }
792 
793     KeyName.Length = 0;
794     KeyName.MaximumLength = EnumKeyPath.Length +
795                             DeviceNode->Parent->InstancePath.Length +
796                             sizeof(UNICODE_NULL);
797     KeyName.Buffer = ExAllocatePoolWithTag(PagedPool,
798                                            KeyName.MaximumLength,
799                                            TAG_IO);
800     if (!KeyName.Buffer)
801     {
802         Status = STATUS_INSUFFICIENT_RESOURCES;
803         goto cleanup;
804     }
805 
806     RtlCopyUnicodeString(&KeyName, &EnumKeyPath);
807     RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath);
808 
809     Status = IopOpenRegistryKeyEx(&hKey, NULL, &KeyName, KEY_QUERY_VALUE | KEY_SET_VALUE);
810     if (!NT_SUCCESS(Status))
811     {
812         goto cleanup;
813     }
814     RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
815     Status = ZwQueryValueKey(hKey,
816                              &ValueName,
817                              KeyValuePartialInformation,
818                              ParentIdPrefixInformation,
819                              KeyNameBufferLength,
820                              &KeyNameBufferLength);
821     if (NT_SUCCESS(Status))
822     {
823         if (ParentIdPrefixInformation->Type != REG_SZ)
824         {
825             Status = STATUS_UNSUCCESSFUL;
826         }
827         else
828         {
829             KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
830             KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
831             KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
832             ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
833         }
834         goto cleanup;
835     }
836     if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
837     {
838         /* FIXME how do we get here and why is ParentIdPrefixInformation valid? */
839         KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
840         KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
841         KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
842         ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
843         goto cleanup;
844     }
845 
846     /* 2. Create the ParentIdPrefix value */
847     crc32 = RtlComputeCrc32(0,
848                             (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
849                             DeviceNode->Parent->InstancePath.Length);
850 
851     RtlStringCbPrintfW((PWSTR)ParentIdPrefixInformation,
852                        KeyNameBufferLength,
853                        L"%lx&%lx",
854                        DeviceNode->Parent->Level,
855                        crc32);
856     RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation);
857 
858     /* 3. Try to write the ParentIdPrefix to registry */
859     Status = ZwSetValueKey(hKey,
860                            &ValueName,
861                            0,
862                            REG_SZ,
863                            KeyValue.Buffer,
864                            ((ULONG)wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
865 
866 cleanup:
867     if (NT_SUCCESS(Status))
868     {
869         /* Duplicate the string to return it */
870         Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
871                                            &KeyValue,
872                                            ParentIdPrefix);
873     }
874     ExFreePoolWithTag(ParentIdPrefixInformation, TAG_IO);
875     RtlFreeUnicodeString(&KeyName);
876     if (hKey != NULL)
877     {
878         ZwClose(hKey);
879     }
880     return Status;
881 }
882 
883 static
884 CODE_SEG("INIT")
885 NTSTATUS
886 IopEnumerateDetectedDevices(
887    IN HANDLE hBaseKey,
888    IN PUNICODE_STRING RelativePath OPTIONAL,
889    IN HANDLE hRootKey,
890    IN BOOLEAN EnumerateSubKeys,
891    IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
892    IN ULONG ParentBootResourcesLength)
893 {
894    UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
895    UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
896    UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
897    UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
898    UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
899    OBJECT_ATTRIBUTES ObjectAttributes;
900    HANDLE hDevicesKey = NULL;
901    HANDLE hDeviceKey = NULL;
902    HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
903    UNICODE_STRING Level2NameU;
904    WCHAR Level2Name[5];
905    ULONG IndexDevice = 0;
906    ULONG IndexSubKey;
907    PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
908    ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
909    PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
910    ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
911    UNICODE_STRING DeviceName, ValueName;
912    ULONG RequiredSize;
913    PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
914    ULONG BootResourcesLength;
915    NTSTATUS Status;
916 
917    const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
918    UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
919    static ULONG DeviceIndexSerial = 0;
920    const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
921    UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
922    static ULONG DeviceIndexKeyboard = 0;
923    const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
924    /* FIXME: IopEnumerateDetectedDevices() should be rewritten.
925     * The PnP identifiers can either be hardcoded or parsed from a LegacyXlate
926     * sections of driver INF files.
927     */
928 #if defined(SARCH_PC98)
929    UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*nEC1F00\0");
930 #else
931    UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
932 #endif
933    static ULONG DeviceIndexMouse = 0;
934    const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController");
935    UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0");
936    static ULONG DeviceIndexParallel = 0;
937    const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral");
938    UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0");
939    static ULONG DeviceIndexFloppy = 0;
940    UNICODE_STRING HardwareIdKey;
941    PUNICODE_STRING pHardwareId;
942    ULONG DeviceIndex = 0;
943    PUCHAR CmResourceList;
944    ULONG ListCount;
945 
946     if (RelativePath)
947     {
948         Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
949         if (!NT_SUCCESS(Status))
950         {
951             DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
952             goto cleanup;
953         }
954     }
955     else
956         hDevicesKey = hBaseKey;
957 
958    pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
959    if (!pDeviceInformation)
960    {
961       DPRINT("ExAllocatePool() failed\n");
962       Status = STATUS_NO_MEMORY;
963       goto cleanup;
964    }
965 
966    pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
967    if (!pValueInformation)
968    {
969       DPRINT("ExAllocatePool() failed\n");
970       Status = STATUS_NO_MEMORY;
971       goto cleanup;
972    }
973 
974    while (TRUE)
975    {
976       Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
977       if (Status == STATUS_NO_MORE_ENTRIES)
978          break;
979       else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
980       {
981          ExFreePool(pDeviceInformation);
982          DeviceInfoLength = RequiredSize;
983          pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
984          if (!pDeviceInformation)
985          {
986             DPRINT("ExAllocatePool() failed\n");
987             Status = STATUS_NO_MEMORY;
988             goto cleanup;
989          }
990          Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
991       }
992       if (!NT_SUCCESS(Status))
993       {
994          DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
995          goto cleanup;
996       }
997       IndexDevice++;
998 
999       /* Open device key */
1000       DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
1001       DeviceName.Buffer = pDeviceInformation->Name;
1002 
1003       Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
1004           KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
1005       if (!NT_SUCCESS(Status))
1006       {
1007          DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
1008          goto cleanup;
1009       }
1010 
1011       /* Read boot resources, and add then to parent ones */
1012       Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
1013       if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
1014       {
1015          ExFreePool(pValueInformation);
1016          ValueInfoLength = RequiredSize;
1017          pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
1018          if (!pValueInformation)
1019          {
1020             DPRINT("ExAllocatePool() failed\n");
1021             ZwDeleteKey(hLevel2Key);
1022             Status = STATUS_NO_MEMORY;
1023             goto cleanup;
1024          }
1025          Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
1026       }
1027       if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1028       {
1029          BootResources = ParentBootResources;
1030          BootResourcesLength = ParentBootResourcesLength;
1031       }
1032       else if (!NT_SUCCESS(Status))
1033       {
1034          DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
1035          goto nextdevice;
1036       }
1037       else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
1038       {
1039          DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
1040          goto nextdevice;
1041       }
1042       else
1043       {
1044          static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
1045 
1046          /* Concatenate current resources and parent ones */
1047          if (ParentBootResourcesLength == 0)
1048             BootResourcesLength = pValueInformation->DataLength;
1049          else
1050             BootResourcesLength = ParentBootResourcesLength
1051             + pValueInformation->DataLength
1052                - Header;
1053          BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
1054          if (!BootResources)
1055          {
1056             DPRINT("ExAllocatePool() failed\n");
1057             goto nextdevice;
1058          }
1059          if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
1060          {
1061             RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
1062          }
1063          else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
1064          {
1065             RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
1066             RtlCopyMemory(
1067                (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
1068                (PVOID)((ULONG_PTR)ParentBootResources + Header),
1069                ParentBootResourcesLength - Header);
1070             BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
1071          }
1072          else
1073          {
1074             RtlCopyMemory(BootResources, pValueInformation->Data, Header);
1075             RtlCopyMemory(
1076                (PVOID)((ULONG_PTR)BootResources + Header),
1077                (PVOID)((ULONG_PTR)ParentBootResources + Header),
1078                ParentBootResourcesLength - Header);
1079             RtlCopyMemory(
1080                (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
1081                pValueInformation->Data + Header,
1082                pValueInformation->DataLength - Header);
1083             BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
1084          }
1085       }
1086 
1087       if (EnumerateSubKeys)
1088       {
1089          IndexSubKey = 0;
1090          while (TRUE)
1091          {
1092             Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
1093             if (Status == STATUS_NO_MORE_ENTRIES)
1094                break;
1095             else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
1096             {
1097                ExFreePool(pDeviceInformation);
1098                DeviceInfoLength = RequiredSize;
1099                pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
1100                if (!pDeviceInformation)
1101                {
1102                   DPRINT("ExAllocatePool() failed\n");
1103                   Status = STATUS_NO_MEMORY;
1104                   goto cleanup;
1105                }
1106                Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
1107             }
1108             if (!NT_SUCCESS(Status))
1109             {
1110                DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
1111                goto cleanup;
1112             }
1113             IndexSubKey++;
1114             DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
1115             DeviceName.Buffer = pDeviceInformation->Name;
1116 
1117             Status = IopEnumerateDetectedDevices(
1118                hDeviceKey,
1119                &DeviceName,
1120                hRootKey,
1121                TRUE,
1122                BootResources,
1123                BootResourcesLength);
1124             if (!NT_SUCCESS(Status))
1125                goto cleanup;
1126          }
1127       }
1128 
1129       /* Read identifier */
1130       Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
1131       if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
1132       {
1133          ExFreePool(pValueInformation);
1134          ValueInfoLength = RequiredSize;
1135          pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
1136          if (!pValueInformation)
1137          {
1138             DPRINT("ExAllocatePool() failed\n");
1139             Status = STATUS_NO_MEMORY;
1140             goto cleanup;
1141          }
1142          Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
1143       }
1144       if (!NT_SUCCESS(Status))
1145       {
1146          if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
1147          {
1148             DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
1149             goto nextdevice;
1150          }
1151          ValueName.Length = ValueName.MaximumLength = 0;
1152       }
1153       else if (pValueInformation->Type != REG_SZ)
1154       {
1155          DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
1156          goto nextdevice;
1157       }
1158       else
1159       {
1160          /* Assign hardware id to this device */
1161          ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
1162          ValueName.Buffer = (PWCHAR)pValueInformation->Data;
1163          if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
1164             ValueName.Length -= sizeof(WCHAR);
1165       }
1166 
1167       if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
1168       {
1169          pHardwareId = &HardwareIdSerial;
1170          DeviceIndex = DeviceIndexSerial++;
1171       }
1172       else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
1173       {
1174          pHardwareId = &HardwareIdKeyboard;
1175          DeviceIndex = DeviceIndexKeyboard++;
1176       }
1177       else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
1178       {
1179          pHardwareId = &HardwareIdMouse;
1180          DeviceIndex = DeviceIndexMouse++;
1181       }
1182       else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0)
1183       {
1184          pHardwareId = &HardwareIdParallel;
1185          DeviceIndex = DeviceIndexParallel++;
1186       }
1187       else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0)
1188       {
1189          pHardwareId = &HardwareIdFloppy;
1190          DeviceIndex = DeviceIndexFloppy++;
1191       }
1192       else
1193       {
1194          /* Unknown key path */
1195          DPRINT("Unknown key path '%wZ'\n", RelativePath);
1196          goto nextdevice;
1197       }
1198 
1199       /* Prepare hardware id key (hardware id value without final \0) */
1200       HardwareIdKey = *pHardwareId;
1201       HardwareIdKey.Length -= sizeof(UNICODE_NULL);
1202 
1203       /* Add the detected device to Root key */
1204       InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
1205       Status = ZwCreateKey(
1206          &hLevel1Key,
1207          KEY_CREATE_SUB_KEY,
1208          &ObjectAttributes,
1209          0,
1210          NULL,
1211          REG_OPTION_NON_VOLATILE,
1212          NULL);
1213       if (!NT_SUCCESS(Status))
1214       {
1215          DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
1216          goto nextdevice;
1217       }
1218       swprintf(Level2Name, L"%04lu", DeviceIndex);
1219       RtlInitUnicodeString(&Level2NameU, Level2Name);
1220       InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
1221       Status = ZwCreateKey(
1222          &hLevel2Key,
1223          KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
1224          &ObjectAttributes,
1225          0,
1226          NULL,
1227          REG_OPTION_NON_VOLATILE,
1228          NULL);
1229       ZwClose(hLevel1Key);
1230       if (!NT_SUCCESS(Status))
1231       {
1232          DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
1233          goto nextdevice;
1234       }
1235       DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
1236       Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
1237       if (!NT_SUCCESS(Status))
1238       {
1239          DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
1240          ZwDeleteKey(hLevel2Key);
1241          goto nextdevice;
1242       }
1243       /* Create 'LogConf' subkey */
1244       InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
1245       Status = ZwCreateKey(
1246          &hLogConf,
1247          KEY_SET_VALUE,
1248          &ObjectAttributes,
1249          0,
1250          NULL,
1251          REG_OPTION_VOLATILE,
1252          NULL);
1253       if (!NT_SUCCESS(Status))
1254       {
1255          DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
1256          ZwDeleteKey(hLevel2Key);
1257          goto nextdevice;
1258       }
1259       if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
1260       {
1261          CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG));
1262          if (!CmResourceList)
1263          {
1264             ZwClose(hLogConf);
1265             ZwDeleteKey(hLevel2Key);
1266             goto nextdevice;
1267          }
1268 
1269          /* Add the list count (1st member of CM_RESOURCE_LIST) */
1270          ListCount = 1;
1271          RtlCopyMemory(CmResourceList,
1272                        &ListCount,
1273                        sizeof(ULONG));
1274 
1275          /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
1276          RtlCopyMemory(CmResourceList + sizeof(ULONG),
1277                        BootResources,
1278                        BootResourcesLength);
1279 
1280          /* Save boot resources to 'LogConf\BootConfig' */
1281          Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG));
1282          if (!NT_SUCCESS(Status))
1283          {
1284             DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
1285             ZwClose(hLogConf);
1286             ZwDeleteKey(hLevel2Key);
1287             goto nextdevice;
1288          }
1289       }
1290       ZwClose(hLogConf);
1291 
1292 nextdevice:
1293       if (BootResources && BootResources != ParentBootResources)
1294       {
1295          ExFreePool(BootResources);
1296          BootResources = NULL;
1297       }
1298       if (hLevel2Key)
1299       {
1300          ZwClose(hLevel2Key);
1301          hLevel2Key = NULL;
1302       }
1303       if (hDeviceKey)
1304       {
1305          ZwClose(hDeviceKey);
1306          hDeviceKey = NULL;
1307       }
1308    }
1309 
1310    Status = STATUS_SUCCESS;
1311 
1312 cleanup:
1313    if (hDevicesKey && hDevicesKey != hBaseKey)
1314       ZwClose(hDevicesKey);
1315    if (hDeviceKey)
1316       ZwClose(hDeviceKey);
1317    if (pDeviceInformation)
1318       ExFreePool(pDeviceInformation);
1319    if (pValueInformation)
1320       ExFreePool(pValueInformation);
1321    return Status;
1322 }
1323 
1324 static
1325 CODE_SEG("INIT")
1326 BOOLEAN
1327 IopIsFirmwareMapperDisabled(VOID)
1328 {
1329     UNICODE_STRING KeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
1330     UNICODE_STRING KeyNameU = RTL_CONSTANT_STRING(L"DisableFirmwareMapper");
1331     OBJECT_ATTRIBUTES ObjectAttributes;
1332     HANDLE hPnpKey;
1333     PKEY_VALUE_PARTIAL_INFORMATION KeyInformation;
1334     ULONG DesiredLength, Length;
1335     ULONG KeyValue = 0;
1336     NTSTATUS Status;
1337 
1338     InitializeObjectAttributes(&ObjectAttributes, &KeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
1339     Status = ZwOpenKey(&hPnpKey, KEY_QUERY_VALUE, &ObjectAttributes);
1340     if (NT_SUCCESS(Status))
1341     {
1342         Status = ZwQueryValueKey(hPnpKey,
1343                                  &KeyNameU,
1344                                  KeyValuePartialInformation,
1345                                  NULL,
1346                                  0,
1347                                  &DesiredLength);
1348         if ((Status == STATUS_BUFFER_TOO_SMALL) ||
1349             (Status == STATUS_BUFFER_OVERFLOW))
1350         {
1351             Length = DesiredLength;
1352             KeyInformation = ExAllocatePool(PagedPool, Length);
1353             if (KeyInformation)
1354             {
1355                 Status = ZwQueryValueKey(hPnpKey,
1356                                          &KeyNameU,
1357                                          KeyValuePartialInformation,
1358                                          KeyInformation,
1359                                          Length,
1360                                          &DesiredLength);
1361                 if (NT_SUCCESS(Status) && KeyInformation->DataLength == sizeof(ULONG))
1362                 {
1363                     KeyValue = (ULONG)(*KeyInformation->Data);
1364                 }
1365                 else
1366                 {
1367                     DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU, &KeyNameU);
1368                 }
1369 
1370                 ExFreePool(KeyInformation);
1371             }
1372             else
1373             {
1374                 DPRINT1("Failed to allocate memory for registry query\n");
1375             }
1376         }
1377         else
1378         {
1379             DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU, &KeyNameU, Status);
1380         }
1381 
1382         ZwClose(hPnpKey);
1383     }
1384     else
1385     {
1386         DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU, Status);
1387     }
1388 
1389     DPRINT("Firmware mapper is %s\n", KeyValue != 0 ? "disabled" : "enabled");
1390 
1391     return (KeyValue != 0) ? TRUE : FALSE;
1392 }
1393 
1394 CODE_SEG("INIT")
1395 NTSTATUS
1396 NTAPI
1397 IopUpdateRootKey(VOID)
1398 {
1399     UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
1400     UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root");
1401     UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
1402     OBJECT_ATTRIBUTES ObjectAttributes;
1403     HANDLE hEnum, hRoot;
1404     NTSTATUS Status;
1405 
1406     InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
1407     Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
1408     if (!NT_SUCCESS(Status))
1409     {
1410         DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
1411         return Status;
1412     }
1413 
1414     InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL);
1415     Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
1416     ZwClose(hEnum);
1417     if (!NT_SUCCESS(Status))
1418     {
1419         DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
1420         return Status;
1421     }
1422 
1423     if (!IopIsFirmwareMapperDisabled())
1424     {
1425         Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS);
1426         if (!NT_SUCCESS(Status))
1427         {
1428             /* Nothing to do, don't return with an error status */
1429             DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
1430             ZwClose(hRoot);
1431             return STATUS_SUCCESS;
1432         }
1433         Status = IopEnumerateDetectedDevices(
1434             hEnum,
1435             NULL,
1436             hRoot,
1437             TRUE,
1438             NULL,
1439             0);
1440         ZwClose(hEnum);
1441     }
1442     else
1443     {
1444         /* Enumeration is disabled */
1445         Status = STATUS_SUCCESS;
1446     }
1447 
1448     ZwClose(hRoot);
1449 
1450     return Status;
1451 }
1452 
1453 NTSTATUS
1454 NTAPI
1455 IopOpenRegistryKeyEx(PHANDLE KeyHandle,
1456                      HANDLE ParentKey,
1457                      PUNICODE_STRING Name,
1458                      ACCESS_MASK DesiredAccess)
1459 {
1460     OBJECT_ATTRIBUTES ObjectAttributes;
1461     NTSTATUS Status;
1462 
1463     PAGED_CODE();
1464 
1465     *KeyHandle = NULL;
1466 
1467     InitializeObjectAttributes(&ObjectAttributes,
1468         Name,
1469         OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1470         ParentKey,
1471         NULL);
1472 
1473     Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
1474 
1475     return Status;
1476 }
1477 
1478 NTSTATUS
1479 NTAPI
1480 IopCreateRegistryKeyEx(OUT PHANDLE Handle,
1481                        IN HANDLE RootHandle OPTIONAL,
1482                        IN PUNICODE_STRING KeyName,
1483                        IN ACCESS_MASK DesiredAccess,
1484                        IN ULONG CreateOptions,
1485                        OUT PULONG Disposition OPTIONAL)
1486 {
1487     OBJECT_ATTRIBUTES ObjectAttributes;
1488     ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0;
1489     USHORT Length;
1490     HANDLE HandleArray[2];
1491     BOOLEAN Recursing = TRUE;
1492     PWCHAR pp, p, p1;
1493     UNICODE_STRING KeyString;
1494     NTSTATUS Status = STATUS_SUCCESS;
1495     PAGED_CODE();
1496 
1497     /* P1 is start, pp is end */
1498     p1 = KeyName->Buffer;
1499     pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length);
1500 
1501     /* Create the target key */
1502     InitializeObjectAttributes(&ObjectAttributes,
1503                                KeyName,
1504                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1505                                RootHandle,
1506                                NULL);
1507     Status = ZwCreateKey(&HandleArray[i],
1508                          DesiredAccess,
1509                          &ObjectAttributes,
1510                          0,
1511                          NULL,
1512                          CreateOptions,
1513                          &KeyDisposition);
1514 
1515     /* Now we check if this failed */
1516     if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle))
1517     {
1518         /* Target key failed, so we'll need to create its parent. Setup array */
1519         HandleArray[0] = NULL;
1520         HandleArray[1] = RootHandle;
1521 
1522         /* Keep recursing for each missing parent */
1523         while (Recursing)
1524         {
1525             /* And if we're deep enough, close the last handle */
1526             if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
1527 
1528             /* We're setup to ping-pong between the two handle array entries */
1529             RootHandleIndex = i;
1530             i = (i + 1) & 1;
1531 
1532             /* Clear the one we're attempting to open now */
1533             HandleArray[i] = NULL;
1534 
1535             /* Process the parent key name */
1536             for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++);
1537             Length = (USHORT)(p - p1) * sizeof(WCHAR);
1538 
1539             /* Is there a parent name? */
1540             if (Length)
1541             {
1542                 /* Build the unicode string for it */
1543                 KeyString.Buffer = p1;
1544                 KeyString.Length = KeyString.MaximumLength = Length;
1545 
1546                 /* Now try opening the parent */
1547                 InitializeObjectAttributes(&ObjectAttributes,
1548                                            &KeyString,
1549                                            OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1550                                            HandleArray[RootHandleIndex],
1551                                            NULL);
1552                 Status = ZwCreateKey(&HandleArray[i],
1553                                      DesiredAccess,
1554                                      &ObjectAttributes,
1555                                      0,
1556                                      NULL,
1557                                      CreateOptions,
1558                                      &KeyDisposition);
1559                 if (NT_SUCCESS(Status))
1560                 {
1561                     /* It worked, we have one more handle */
1562                     NestedCloseLevel++;
1563                 }
1564                 else
1565                 {
1566                     /* Parent key creation failed, abandon loop */
1567                     Recursing = FALSE;
1568                     continue;
1569                 }
1570             }
1571             else
1572             {
1573                 /* We don't have a parent name, probably corrupted key name */
1574                 Status = STATUS_INVALID_PARAMETER;
1575                 Recursing = FALSE;
1576                 continue;
1577             }
1578 
1579             /* Now see if there's more parents to create */
1580             p1 = p + 1;
1581             if ((p == pp) || (p1 == pp))
1582             {
1583                 /* We're done, hopefully successfully, so stop */
1584                 Recursing = FALSE;
1585             }
1586         }
1587 
1588         /* Outer loop check for handle nesting that requires closing the top handle */
1589         if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
1590     }
1591 
1592     /* Check if we broke out of the loop due to success */
1593     if (NT_SUCCESS(Status))
1594     {
1595         /* Return the target handle (we closed all the parent ones) and disposition */
1596         *Handle = HandleArray[i];
1597         if (Disposition) *Disposition = KeyDisposition;
1598     }
1599 
1600     /* Return the success state */
1601     return Status;
1602 }
1603 
1604 NTSTATUS
1605 NTAPI
1606 IopGetRegistryValue(IN HANDLE Handle,
1607                     IN PWSTR ValueName,
1608                     OUT PKEY_VALUE_FULL_INFORMATION *Information)
1609 {
1610     UNICODE_STRING ValueString;
1611     NTSTATUS Status;
1612     PKEY_VALUE_FULL_INFORMATION FullInformation;
1613     ULONG Size;
1614     PAGED_CODE();
1615 
1616     RtlInitUnicodeString(&ValueString, ValueName);
1617 
1618     Status = ZwQueryValueKey(Handle,
1619                              &ValueString,
1620                              KeyValueFullInformation,
1621                              NULL,
1622                              0,
1623                              &Size);
1624     if ((Status != STATUS_BUFFER_OVERFLOW) &&
1625         (Status != STATUS_BUFFER_TOO_SMALL))
1626     {
1627         return Status;
1628     }
1629 
1630     FullInformation = ExAllocatePool(NonPagedPool, Size);
1631     if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES;
1632 
1633     Status = ZwQueryValueKey(Handle,
1634                              &ValueString,
1635                              KeyValueFullInformation,
1636                              FullInformation,
1637                              Size,
1638                              &Size);
1639     if (!NT_SUCCESS(Status))
1640     {
1641         ExFreePool(FullInformation);
1642         return Status;
1643     }
1644 
1645     *Information = FullInformation;
1646     return STATUS_SUCCESS;
1647 }
1648 
1649 RTL_GENERIC_COMPARE_RESULTS
1650 NTAPI
1651 PiCompareInstancePath(IN PRTL_AVL_TABLE Table,
1652                       IN PVOID FirstStruct,
1653                       IN PVOID SecondStruct)
1654 {
1655     /* FIXME: TODO */
1656     ASSERT(FALSE);
1657     return 0;
1658 }
1659 
1660 //
1661 //  The allocation function is called by the generic table package whenever
1662 //  it needs to allocate memory for the table.
1663 //
1664 
1665 PVOID
1666 NTAPI
1667 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table,
1668                             IN CLONG ByteSize)
1669 {
1670     /* FIXME: TODO */
1671     ASSERT(FALSE);
1672     return NULL;
1673 }
1674 
1675 VOID
1676 NTAPI
1677 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table,
1678                         IN PVOID Buffer)
1679 {
1680     /* FIXME: TODO */
1681     ASSERT(FALSE);
1682 }
1683 
1684 VOID
1685 NTAPI
1686 PpInitializeDeviceReferenceTable(VOID)
1687 {
1688     /* Setup the guarded mutex and AVL table */
1689     KeInitializeGuardedMutex(&PpDeviceReferenceTableLock);
1690     RtlInitializeGenericTableAvl(
1691         &PpDeviceReferenceTable,
1692         (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath,
1693         (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry,
1694         (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry,
1695         NULL);
1696 }
1697 
1698 BOOLEAN
1699 NTAPI
1700 PiInitPhase0(VOID)
1701 {
1702     /* Initialize the resource when accessing device registry data */
1703     ExInitializeResourceLite(&PpRegistryDeviceResource);
1704 
1705     /* Setup the device reference AVL table */
1706     PpInitializeDeviceReferenceTable();
1707     return TRUE;
1708 }
1709 
1710 BOOLEAN
1711 NTAPI
1712 PpInitSystem(VOID)
1713 {
1714     /* Check the initialization phase */
1715     switch (ExpInitializationPhase)
1716     {
1717     case 0:
1718 
1719         /* Do Phase 0 */
1720         return PiInitPhase0();
1721 
1722     case 1:
1723 
1724         /* Do Phase 1 */
1725         return TRUE;
1726         //return PiInitPhase1();
1727 
1728     default:
1729 
1730         /* Don't know any other phase! Bugcheck! */
1731         KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
1732         return FALSE;
1733     }
1734 }
1735 
1736 /* PUBLIC FUNCTIONS **********************************************************/
1737 
1738 NTSTATUS
1739 NTAPI
1740 PnpBusTypeGuidGet(IN USHORT Index,
1741                   IN LPGUID BusTypeGuid)
1742 {
1743     NTSTATUS Status = STATUS_SUCCESS;
1744 
1745     /* Acquire the lock */
1746     ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
1747 
1748     /* Validate size */
1749     if (Index < PnpBusTypeGuidList->GuidCount)
1750     {
1751         /* Copy the data */
1752         RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID));
1753     }
1754     else
1755     {
1756         /* Failure path */
1757         Status = STATUS_OBJECT_NAME_NOT_FOUND;
1758     }
1759 
1760     /* Release lock and return status */
1761     ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
1762     return Status;
1763 }
1764 
1765 NTSTATUS
1766 NTAPI
1767 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject,
1768                                 IN PHANDLE DeviceInstanceHandle,
1769                                 IN ACCESS_MASK DesiredAccess)
1770 {
1771     NTSTATUS Status;
1772     HANDLE KeyHandle;
1773     PDEVICE_NODE DeviceNode;
1774     UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
1775     PAGED_CODE();
1776 
1777     /* Open the enum key */
1778     Status = IopOpenRegistryKeyEx(&KeyHandle,
1779                                   NULL,
1780                                   &KeyName,
1781                                   KEY_READ);
1782     if (!NT_SUCCESS(Status)) return Status;
1783 
1784     /* Make sure we have an instance path */
1785     DeviceNode = IopGetDeviceNode(DeviceObject);
1786     if ((DeviceNode) && (DeviceNode->InstancePath.Length))
1787     {
1788         /* Get the instance key */
1789         Status = IopOpenRegistryKeyEx(DeviceInstanceHandle,
1790                                       KeyHandle,
1791                                       &DeviceNode->InstancePath,
1792                                       DesiredAccess);
1793     }
1794     else
1795     {
1796         /* Fail */
1797         Status = STATUS_INVALID_DEVICE_REQUEST;
1798     }
1799 
1800     /* Close the handle and return status */
1801     ZwClose(KeyHandle);
1802     return Status;
1803 }
1804 
1805 ULONG
1806 NTAPI
1807 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList)
1808 {
1809     ULONG FinalSize, PartialSize, EntrySize, i, j;
1810     PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
1811     PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
1812 
1813     /* If we don't have one, that's easy */
1814     if (!ResourceList) return 0;
1815 
1816     /* Start with the minimum size possible */
1817     FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
1818 
1819     /* Loop each full descriptor */
1820     FullDescriptor = ResourceList->List;
1821     for (i = 0; i < ResourceList->Count; i++)
1822     {
1823         /* Start with the minimum size possible */
1824         PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
1825         FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors);
1826 
1827         /* Loop each partial descriptor */
1828         PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors;
1829         for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++)
1830         {
1831             /* Start with the minimum size possible */
1832             EntrySize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1833 
1834             /* Check if there is extra data */
1835             if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
1836             {
1837                 /* Add that data */
1838                 EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize;
1839             }
1840 
1841             /* The size of partial descriptors is bigger */
1842             PartialSize += EntrySize;
1843 
1844             /* Go to the next partial descriptor */
1845             PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize);
1846         }
1847 
1848         /* The size of full descriptors is bigger */
1849         FinalSize += PartialSize;
1850 
1851         /* Go to the next full descriptor */
1852         FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize);
1853     }
1854 
1855     /* Return the final size */
1856     return FinalSize;
1857 }
1858 
1859 NTSTATUS
1860 NTAPI
1861 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject,
1862                             IN ULONG ValueType,
1863                             IN PWSTR ValueName,
1864                             IN PWSTR KeyName,
1865                             OUT PVOID Buffer,
1866                             IN PULONG BufferLength)
1867 {
1868     NTSTATUS Status;
1869     HANDLE KeyHandle, SubHandle;
1870     UNICODE_STRING KeyString;
1871     PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL;
1872     ULONG Length;
1873     PAGED_CODE();
1874 
1875     /* Find the instance key */
1876     Status = PnpDeviceObjectToDeviceInstance(DeviceObject, &KeyHandle, KEY_READ);
1877     if (NT_SUCCESS(Status))
1878     {
1879         /* Check for name given by caller */
1880         if (KeyName)
1881         {
1882             /* Open this key */
1883             RtlInitUnicodeString(&KeyString, KeyName);
1884             Status = IopOpenRegistryKeyEx(&SubHandle,
1885                                           KeyHandle,
1886                                           &KeyString,
1887                                           KEY_READ);
1888             if (NT_SUCCESS(Status))
1889             {
1890                 /* And use this handle instead */
1891                 ZwClose(KeyHandle);
1892                 KeyHandle = SubHandle;
1893             }
1894         }
1895 
1896         /* Check if sub-key handle succeeded (or no-op if no key name given) */
1897         if (NT_SUCCESS(Status))
1898         {
1899             /* Now get the size of the property */
1900             Status = IopGetRegistryValue(KeyHandle,
1901                                          ValueName,
1902                                          &KeyValueInfo);
1903         }
1904 
1905         /* Close the key */
1906         ZwClose(KeyHandle);
1907     }
1908 
1909     /* Fail if any of the registry operations failed */
1910     if (!NT_SUCCESS(Status)) return Status;
1911 
1912     /* Check how much data we have to copy */
1913     Length = KeyValueInfo->DataLength;
1914     if (*BufferLength >= Length)
1915     {
1916         /* Check for a match in the value type */
1917         if (KeyValueInfo->Type == ValueType)
1918         {
1919             /* Copy the data */
1920             RtlCopyMemory(Buffer,
1921                           (PVOID)((ULONG_PTR)KeyValueInfo +
1922                           KeyValueInfo->DataOffset),
1923                           Length);
1924         }
1925         else
1926         {
1927             /* Invalid registry property type, fail */
1928            Status = STATUS_INVALID_PARAMETER_2;
1929         }
1930     }
1931     else
1932     {
1933         /* Buffer is too small to hold data */
1934         Status = STATUS_BUFFER_TOO_SMALL;
1935     }
1936 
1937     /* Return the required buffer length, free the buffer, and return status */
1938     *BufferLength = Length;
1939     ExFreePool(KeyValueInfo);
1940     return Status;
1941 }
1942 
1943 #define PIP_RETURN_DATA(x, y)   {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
1944 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
1945 #define PIP_UNIMPLEMENTED()     {UNIMPLEMENTED_DBGBREAK(); break;}
1946 
1947 /*
1948  * @implemented
1949  */
1950 NTSTATUS
1951 NTAPI
1952 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
1953                     IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
1954                     IN ULONG BufferLength,
1955                     OUT PVOID PropertyBuffer,
1956                     OUT PULONG ResultLength)
1957 {
1958     PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
1959     DEVICE_CAPABILITIES DeviceCaps;
1960     ULONG ReturnLength = 0, Length = 0, ValueType;
1961     PWCHAR ValueName = NULL, EnumeratorNameEnd, DeviceInstanceName;
1962     PVOID Data = NULL;
1963     NTSTATUS Status = STATUS_BUFFER_TOO_SMALL;
1964     GUID BusTypeGuid;
1965     POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
1966     BOOLEAN NullTerminate = FALSE;
1967     DEVICE_REMOVAL_POLICY Policy;
1968 
1969     DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
1970 
1971     /* Assume failure */
1972     *ResultLength = 0;
1973 
1974     /* Only PDOs can call this */
1975     if (!DeviceNode) return STATUS_INVALID_DEVICE_REQUEST;
1976 
1977     /* Handle all properties */
1978     switch (DeviceProperty)
1979     {
1980         case DevicePropertyBusTypeGuid:
1981 
1982             /* Get the GUID from the internal cache */
1983             Status = PnpBusTypeGuidGet(DeviceNode->ChildBusTypeIndex, &BusTypeGuid);
1984             if (!NT_SUCCESS(Status)) return Status;
1985 
1986             /* This is the format of the returned data */
1987             PIP_RETURN_DATA(sizeof(GUID), &BusTypeGuid);
1988 
1989         case DevicePropertyLegacyBusType:
1990 
1991             /* Validate correct interface type */
1992             if (DeviceNode->ChildInterfaceType == InterfaceTypeUndefined)
1993                 return STATUS_OBJECT_NAME_NOT_FOUND;
1994 
1995             /* This is the format of the returned data */
1996             PIP_RETURN_DATA(sizeof(INTERFACE_TYPE), &DeviceNode->ChildInterfaceType);
1997 
1998         case DevicePropertyBusNumber:
1999 
2000             /* Validate correct bus number */
2001             if ((DeviceNode->ChildBusNumber & 0x80000000) == 0x80000000)
2002                 return STATUS_OBJECT_NAME_NOT_FOUND;
2003 
2004             /* This is the format of the returned data */
2005             PIP_RETURN_DATA(sizeof(ULONG), &DeviceNode->ChildBusNumber);
2006 
2007         case DevicePropertyEnumeratorName:
2008 
2009             /* Get the instance path */
2010             DeviceInstanceName = DeviceNode->InstancePath.Buffer;
2011 
2012             /* Sanity checks */
2013             ASSERT((BufferLength & 1) == 0);
2014             ASSERT(DeviceInstanceName != NULL);
2015 
2016             /* Get the name from the path */
2017             EnumeratorNameEnd = wcschr(DeviceInstanceName, OBJ_NAME_PATH_SEPARATOR);
2018             ASSERT(EnumeratorNameEnd);
2019 
2020             /* This string needs to be NULL-terminated */
2021             NullTerminate = TRUE;
2022 
2023             /* This is the format of the returned data */
2024             PIP_RETURN_DATA((ULONG)(EnumeratorNameEnd - DeviceInstanceName) * sizeof(WCHAR),
2025                             DeviceInstanceName);
2026 
2027         case DevicePropertyAddress:
2028 
2029             /* Query the device caps */
2030             Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps);
2031             if (!NT_SUCCESS(Status) || (DeviceCaps.Address == MAXULONG))
2032                 return STATUS_OBJECT_NAME_NOT_FOUND;
2033 
2034             /* This is the format of the returned data */
2035             PIP_RETURN_DATA(sizeof(ULONG), &DeviceCaps.Address);
2036 
2037         case DevicePropertyBootConfigurationTranslated:
2038 
2039             /* Validate we have resources */
2040             if (!DeviceNode->BootResources)
2041 //            if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
2042             {
2043                 /* No resources will still fake success, but with 0 bytes */
2044                 *ResultLength = 0;
2045                 return STATUS_SUCCESS;
2046             }
2047 
2048             /* This is the format of the returned data */
2049             PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode->BootResources), // FIXFIX: Should use BootResourcesTranslated
2050                             DeviceNode->BootResources); // FIXFIX: Should use BootResourcesTranslated
2051 
2052         case DevicePropertyPhysicalDeviceObjectName:
2053 
2054             /* Sanity check for Unicode-sized string */
2055             ASSERT((BufferLength & 1) == 0);
2056 
2057             /* Allocate name buffer */
2058             Length = BufferLength + sizeof(OBJECT_NAME_INFORMATION);
2059             ObjectNameInfo = ExAllocatePool(PagedPool, Length);
2060             if (!ObjectNameInfo) return STATUS_INSUFFICIENT_RESOURCES;
2061 
2062             /* Query the PDO name */
2063             Status = ObQueryNameString(DeviceObject,
2064                                        ObjectNameInfo,
2065                                        Length,
2066                                        ResultLength);
2067             if (Status == STATUS_INFO_LENGTH_MISMATCH)
2068             {
2069                 /* It's up to the caller to try again */
2070                 Status = STATUS_BUFFER_TOO_SMALL;
2071             }
2072 
2073             /* This string needs to be NULL-terminated */
2074             NullTerminate = TRUE;
2075 
2076             /* Return if successful */
2077             if (NT_SUCCESS(Status)) PIP_RETURN_DATA(ObjectNameInfo->Name.Length,
2078                                                     ObjectNameInfo->Name.Buffer);
2079 
2080             /* Let the caller know how big the name is */
2081             *ResultLength -= sizeof(OBJECT_NAME_INFORMATION);
2082             break;
2083 
2084         case DevicePropertyRemovalPolicy:
2085 
2086             Policy = DeviceNode->RemovalPolicy;
2087             PIP_RETURN_DATA(sizeof(Policy), &Policy);
2088 
2089         /* Handle the registry-based properties */
2090         case DevicePropertyUINumber:
2091             PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER, REG_DWORD);
2092         case DevicePropertyLocationInformation:
2093             PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION, REG_SZ);
2094         case DevicePropertyDeviceDescription:
2095             PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC, REG_SZ);
2096         case DevicePropertyHardwareID:
2097             PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID, REG_MULTI_SZ);
2098         case DevicePropertyCompatibleIDs:
2099             PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS, REG_MULTI_SZ);
2100         case DevicePropertyBootConfiguration:
2101             PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG, REG_RESOURCE_LIST);
2102         case DevicePropertyClassName:
2103             PIP_REGISTRY_DATA(REGSTR_VAL_CLASS, REG_SZ);
2104         case DevicePropertyClassGuid:
2105             PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID, REG_SZ);
2106         case DevicePropertyDriverKeyName:
2107             PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER, REG_SZ);
2108         case DevicePropertyManufacturer:
2109             PIP_REGISTRY_DATA(REGSTR_VAL_MFG, REG_SZ);
2110         case DevicePropertyFriendlyName:
2111             PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME, REG_SZ);
2112         case DevicePropertyContainerID:
2113             //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
2114             PIP_UNIMPLEMENTED();
2115             break;
2116         case DevicePropertyInstallState:
2117             PIP_REGISTRY_DATA(REGSTR_VAL_CONFIGFLAGS, REG_DWORD);
2118             break;
2119         case DevicePropertyResourceRequirements:
2120             PIP_UNIMPLEMENTED();
2121         case DevicePropertyAllocatedResources:
2122             PIP_UNIMPLEMENTED();
2123         default:
2124             return STATUS_INVALID_PARAMETER_2;
2125     }
2126 
2127     /* Having a registry value name implies registry data */
2128     if (ValueName)
2129     {
2130         /* We know up-front how much data to expect */
2131         *ResultLength = BufferLength;
2132 
2133         /* Go get the data, use the LogConf subkey if necessary */
2134         Status = PiGetDeviceRegistryProperty(DeviceObject,
2135                                              ValueType,
2136                                              ValueName,
2137                                              (DeviceProperty ==
2138                                               DevicePropertyBootConfiguration) ?
2139                                              L"LogConf":  NULL,
2140                                              PropertyBuffer,
2141                                              ResultLength);
2142     }
2143     else if (NT_SUCCESS(Status))
2144     {
2145         /* We know up-front how much data to expect, check the caller's buffer */
2146         *ResultLength = ReturnLength + (NullTerminate ? sizeof(UNICODE_NULL) : 0);
2147         if (*ResultLength <= BufferLength)
2148         {
2149             /* Buffer is all good, copy the data */
2150             RtlCopyMemory(PropertyBuffer, Data, ReturnLength);
2151 
2152             /* Check if we need to NULL-terminate the string */
2153             if (NullTerminate)
2154             {
2155                 /* Terminate the string */
2156                 ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL;
2157             }
2158 
2159             /* This is the success path */
2160             Status = STATUS_SUCCESS;
2161         }
2162         else
2163         {
2164             /* Failure path */
2165             Status = STATUS_BUFFER_TOO_SMALL;
2166         }
2167     }
2168 
2169     /* Free any allocation we may have made, and return the status code */
2170     if (ObjectNameInfo) ExFreePool(ObjectNameInfo);
2171     return Status;
2172 }
2173 
2174 /**
2175  * @name IoOpenDeviceRegistryKey
2176  *
2177  * Open a registry key unique for a specified driver or device instance.
2178  *
2179  * @param DeviceObject   Device to get the registry key for.
2180  * @param DevInstKeyType Type of the key to return.
2181  * @param DesiredAccess  Access mask (eg. KEY_READ | KEY_WRITE).
2182  * @param DevInstRegKey  Handle to the opened registry key on
2183  *                       successful return.
2184  *
2185  * @return Status.
2186  *
2187  * @implemented
2188  */
2189 NTSTATUS
2190 NTAPI
2191 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject,
2192                         IN ULONG DevInstKeyType,
2193                         IN ACCESS_MASK DesiredAccess,
2194                         OUT PHANDLE DevInstRegKey)
2195 {
2196     static WCHAR RootKeyName[] =
2197         L"\\Registry\\Machine\\System\\CurrentControlSet\\";
2198     static WCHAR ProfileKeyName[] =
2199         L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
2200     static WCHAR ClassKeyName[] = L"Control\\Class\\";
2201     static WCHAR EnumKeyName[] = L"Enum\\";
2202     static WCHAR DeviceParametersKeyName[] = L"Device Parameters";
2203     ULONG KeyNameLength;
2204     PWSTR KeyNameBuffer;
2205     UNICODE_STRING KeyName;
2206     ULONG DriverKeyLength;
2207     OBJECT_ATTRIBUTES ObjectAttributes;
2208     PDEVICE_NODE DeviceNode = NULL;
2209     NTSTATUS Status;
2210 
2211     DPRINT("IoOpenDeviceRegistryKey() called\n");
2212 
2213     if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0)
2214     {
2215         DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting...\n");
2216         return STATUS_INVALID_PARAMETER;
2217     }
2218 
2219     if (!IopIsValidPhysicalDeviceObject(DeviceObject))
2220         return STATUS_INVALID_DEVICE_REQUEST;
2221     DeviceNode = IopGetDeviceNode(DeviceObject);
2222 
2223     /*
2224      * Calculate the length of the base key name. This is the full
2225      * name for driver key or the name excluding "Device Parameters"
2226      * subkey for device key.
2227      */
2228 
2229     KeyNameLength = sizeof(RootKeyName);
2230     if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
2231         KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
2232     if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
2233     {
2234         KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
2235         Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
2236                                      0, NULL, &DriverKeyLength);
2237         if (Status != STATUS_BUFFER_TOO_SMALL)
2238             return Status;
2239         KeyNameLength += DriverKeyLength;
2240     }
2241     else
2242     {
2243         KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
2244                          DeviceNode->InstancePath.Length;
2245     }
2246 
2247     /*
2248      * Now allocate the buffer for the key name...
2249      */
2250 
2251     KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
2252     if (KeyNameBuffer == NULL)
2253         return STATUS_INSUFFICIENT_RESOURCES;
2254 
2255     KeyName.Length = 0;
2256     KeyName.MaximumLength = (USHORT)KeyNameLength;
2257     KeyName.Buffer = KeyNameBuffer;
2258 
2259     /*
2260      * ...and build the key name.
2261      */
2262 
2263     KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
2264     RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
2265 
2266     if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
2267         RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
2268 
2269     if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
2270     {
2271         RtlAppendUnicodeToString(&KeyName, ClassKeyName);
2272         Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
2273                                      DriverKeyLength, KeyNameBuffer +
2274                                      (KeyName.Length / sizeof(WCHAR)),
2275                                      &DriverKeyLength);
2276         if (!NT_SUCCESS(Status))
2277         {
2278             DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status);
2279             ExFreePool(KeyNameBuffer);
2280             return Status;
2281         }
2282         KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL);
2283     }
2284     else
2285     {
2286         RtlAppendUnicodeToString(&KeyName, EnumKeyName);
2287         Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath);
2288         if (DeviceNode->InstancePath.Length == 0)
2289         {
2290             ExFreePool(KeyNameBuffer);
2291             return Status;
2292         }
2293     }
2294 
2295     /*
2296      * Open the base key.
2297      */
2298     Status = IopOpenRegistryKeyEx(DevInstRegKey, NULL, &KeyName, DesiredAccess);
2299     if (!NT_SUCCESS(Status))
2300     {
2301         DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status);
2302         ExFreePool(KeyNameBuffer);
2303         return Status;
2304     }
2305     ExFreePool(KeyNameBuffer);
2306 
2307     /*
2308      * For driver key we're done now.
2309      */
2310 
2311     if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
2312         return Status;
2313 
2314     /*
2315      * Let's go further. For device key we must open "Device Parameters"
2316      * subkey and create it if it doesn't exist yet.
2317      */
2318 
2319     RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
2320     InitializeObjectAttributes(&ObjectAttributes,
2321                                &KeyName,
2322                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2323                                *DevInstRegKey,
2324                                NULL);
2325     Status = ZwCreateKey(DevInstRegKey,
2326                          DesiredAccess,
2327                          &ObjectAttributes,
2328                          0,
2329                          NULL,
2330                          REG_OPTION_NON_VOLATILE,
2331                          NULL);
2332     ZwClose(ObjectAttributes.RootDirectory);
2333 
2334     return Status;
2335 }
2336 
2337 /*
2338  * @implemented
2339  */
2340 VOID
2341 NTAPI
2342 IoInvalidateDeviceRelations(
2343     IN PDEVICE_OBJECT DeviceObject,
2344     IN DEVICE_RELATION_TYPE Type)
2345 {
2346     if (!IopIsValidPhysicalDeviceObject(DeviceObject))
2347     {
2348         KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 0x2, (ULONG_PTR)DeviceObject, 0, 0);
2349     }
2350 
2351     switch (Type)
2352     {
2353         case BusRelations:
2354             /* Enumerate the device */
2355             PiQueueDeviceAction(DeviceObject, PiActionEnumDeviceTree, NULL, NULL);
2356             break;
2357         default:
2358             /* Everything else is not implemented */
2359             break;
2360     }
2361 }
2362 
2363 /*
2364  * @implemented
2365  */
2366 NTSTATUS
2367 NTAPI
2368 IoSynchronousInvalidateDeviceRelations(
2369     IN PDEVICE_OBJECT DeviceObject,
2370     IN DEVICE_RELATION_TYPE Type)
2371 {
2372     PAGED_CODE();
2373 
2374     if (!IopIsValidPhysicalDeviceObject(DeviceObject))
2375     {
2376         KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 0x2, (ULONG_PTR)DeviceObject, 0, 0);
2377     }
2378 
2379     switch (Type)
2380     {
2381         case BusRelations:
2382             /* Enumerate the device */
2383             return PiPerformSyncDeviceAction(DeviceObject, PiActionEnumDeviceTree);
2384         case PowerRelations:
2385              /* Not handled yet */
2386              return STATUS_NOT_IMPLEMENTED;
2387         case TargetDeviceRelation:
2388             /* Nothing to do */
2389             return STATUS_SUCCESS;
2390         default:
2391             /* Ejection relations are not supported */
2392             return STATUS_NOT_SUPPORTED;
2393     }
2394 }
2395 
2396 /*
2397  * @implemented
2398  */
2399 BOOLEAN
2400 NTAPI
2401 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
2402                       IN ULONG BusNumber,
2403                       IN PHYSICAL_ADDRESS BusAddress,
2404                       IN OUT PULONG AddressSpace,
2405                       OUT PPHYSICAL_ADDRESS TranslatedAddress)
2406 {
2407     /* FIXME: Notify the resource arbiter */
2408 
2409     return HalTranslateBusAddress(InterfaceType,
2410                                   BusNumber,
2411                                   BusAddress,
2412                                   AddressSpace,
2413                                   TranslatedAddress);
2414 }
2415 
2416 VOID
2417 NTAPI
2418 IoInvalidateDeviceState(
2419     IN PDEVICE_OBJECT DeviceObject)
2420 {
2421     if (!IopIsValidPhysicalDeviceObject(DeviceObject))
2422     {
2423         KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 0x2, (ULONG_PTR)DeviceObject, 0, 0);
2424     }
2425 
2426     PiQueueDeviceAction(DeviceObject, PiActionQueryState, NULL, NULL);
2427 }
2428