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