xref: /reactos/ntoskrnl/io/pnpmgr/pnpmgr.c (revision fc3ccb39)
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     if (Status == STATUS_PENDING)
603     {
604         /* Wait for it */
605         KeWaitForSingleObject(&Event,
606                               Executive,
607                               KernelMode,
608                               FALSE,
609                               NULL);
610         Status = IoStatusBlock.Status;
611     }
612 
613     /* Remove the reference */
614     ObDereferenceObject(TopDeviceObject);
615 
616     /* Return the information */
617     *Information = (PVOID)IoStatusBlock.Information;
618     return Status;
619 }
620 
621 NTSTATUS
622 NTAPI
623 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject,
624                   IN OUT PIO_STATUS_BLOCK IoStatusBlock,
625                   IN UCHAR MinorFunction,
626                   IN PIO_STACK_LOCATION Stack OPTIONAL)
627 {
628     IO_STACK_LOCATION IoStackLocation;
629 
630     /* Fill out the stack information */
631     RtlZeroMemory(&IoStackLocation, sizeof(IO_STACK_LOCATION));
632     IoStackLocation.MajorFunction = IRP_MJ_PNP;
633     IoStackLocation.MinorFunction = MinorFunction;
634     if (Stack)
635     {
636         /* Copy the rest */
637         RtlCopyMemory(&IoStackLocation.Parameters,
638                       &Stack->Parameters,
639                       sizeof(Stack->Parameters));
640     }
641 
642     /* Do the PnP call */
643     IoStatusBlock->Status = IopSynchronousCall(DeviceObject,
644                                                &IoStackLocation,
645                                                (PVOID)&IoStatusBlock->Information);
646     return IoStatusBlock->Status;
647 }
648 
649 /*
650  * IopCreateDeviceKeyPath
651  *
652  * Creates a registry key
653  *
654  * Parameters
655  *    RegistryPath
656  *        Name of the key to be created.
657  *    Handle
658  *        Handle to the newly created key
659  *
660  * Remarks
661  *     This method can create nested trees, so parent of RegistryPath can
662  *     be not existant, and will be created if needed.
663  */
664 NTSTATUS
665 NTAPI
666 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
667                        IN ULONG CreateOptions,
668                        OUT PHANDLE Handle)
669 {
670     UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
671     HANDLE hParent = NULL, hKey;
672     OBJECT_ATTRIBUTES ObjectAttributes;
673     UNICODE_STRING KeyName;
674     PCWSTR Current, Last;
675     USHORT Length;
676     NTSTATUS Status;
677 
678     /* Assume failure */
679     *Handle = NULL;
680 
681     /* Open root key for device instances */
682     Status = IopOpenRegistryKeyEx(&hParent, NULL, &EnumU, KEY_CREATE_SUB_KEY);
683     if (!NT_SUCCESS(Status))
684     {
685         DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
686         return Status;
687     }
688 
689     Current = KeyName.Buffer = RegistryPath->Buffer;
690     Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)];
691 
692     /* Go up to the end of the string */
693     while (Current <= Last)
694     {
695         if (Current != Last && *Current != L'\\')
696         {
697             /* Not the end of the string and not a separator */
698             Current++;
699             continue;
700         }
701 
702         /* Prepare relative key name */
703         Length = (USHORT)((ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer);
704         KeyName.MaximumLength = KeyName.Length = Length;
705         DPRINT("Create '%wZ'\n", &KeyName);
706 
707         /* Open key */
708         InitializeObjectAttributes(&ObjectAttributes,
709                                    &KeyName,
710                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
711                                    hParent,
712                                    NULL);
713         Status = ZwCreateKey(&hKey,
714                              Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY,
715                              &ObjectAttributes,
716                              0,
717                              NULL,
718                              CreateOptions,
719                              NULL);
720 
721         /* Close parent key handle, we don't need it anymore */
722         if (hParent)
723             ZwClose(hParent);
724 
725         /* Key opening/creating failed? */
726         if (!NT_SUCCESS(Status))
727         {
728             DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status);
729             return Status;
730         }
731 
732         /* Check if it is the end of the string */
733         if (Current == Last)
734         {
735             /* Yes, return success */
736             *Handle = hKey;
737             return STATUS_SUCCESS;
738         }
739 
740         /* Start with this new parent key */
741         hParent = hKey;
742         Current++;
743         KeyName.Buffer = (PWSTR)Current;
744     }
745 
746     return STATUS_UNSUCCESSFUL;
747 }
748 
749 NTSTATUS
750 IopSetDeviceInstanceData(HANDLE InstanceKey,
751                          PDEVICE_NODE DeviceNode)
752 {
753     OBJECT_ATTRIBUTES ObjectAttributes;
754     UNICODE_STRING KeyName;
755     HANDLE LogConfKey, ControlKey, DeviceParamsKey;
756     ULONG ResCount;
757     ULONG ResultLength;
758     NTSTATUS Status;
759 
760     DPRINT("IopSetDeviceInstanceData() called\n");
761 
762     /* Create the 'LogConf' key */
763     RtlInitUnicodeString(&KeyName, L"LogConf");
764     InitializeObjectAttributes(&ObjectAttributes,
765                                &KeyName,
766                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
767                                InstanceKey,
768                                NULL);
769     Status = ZwCreateKey(&LogConfKey,
770                          KEY_ALL_ACCESS,
771                          &ObjectAttributes,
772                          0,
773                          NULL,
774                          // FIXME? In r53694 it was silently turned from non-volatile into this,
775                          // without any extra warning. Is this still needed??
776                          REG_OPTION_VOLATILE,
777                          NULL);
778     if (NT_SUCCESS(Status))
779     {
780         /* Set 'BootConfig' value */
781         if (DeviceNode->BootResources != NULL)
782         {
783             ResCount = DeviceNode->BootResources->Count;
784             if (ResCount != 0)
785             {
786                 RtlInitUnicodeString(&KeyName, L"BootConfig");
787                 Status = ZwSetValueKey(LogConfKey,
788                                        &KeyName,
789                                        0,
790                                        REG_RESOURCE_LIST,
791                                        DeviceNode->BootResources,
792                                        PnpDetermineResourceListSize(DeviceNode->BootResources));
793             }
794         }
795 
796         /* Set 'BasicConfigVector' value */
797         if (DeviceNode->ResourceRequirements != NULL &&
798             DeviceNode->ResourceRequirements->ListSize != 0)
799         {
800             RtlInitUnicodeString(&KeyName, L"BasicConfigVector");
801             Status = ZwSetValueKey(LogConfKey,
802                                    &KeyName,
803                                    0,
804                                    REG_RESOURCE_REQUIREMENTS_LIST,
805                                    DeviceNode->ResourceRequirements,
806                                    DeviceNode->ResourceRequirements->ListSize);
807         }
808 
809         ZwClose(LogConfKey);
810     }
811 
812     /* Set the 'ConfigFlags' value */
813     RtlInitUnicodeString(&KeyName, L"ConfigFlags");
814     Status = ZwQueryValueKey(InstanceKey,
815                              &KeyName,
816                              KeyValueBasicInformation,
817                              NULL,
818                              0,
819                              &ResultLength);
820     if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
821     {
822         /* Write the default value */
823         ULONG DefaultConfigFlags = 0;
824         Status = ZwSetValueKey(InstanceKey,
825                                &KeyName,
826                                0,
827                                REG_DWORD,
828                                &DefaultConfigFlags,
829                                sizeof(DefaultConfigFlags));
830     }
831 
832     /* Create the 'Control' key */
833     RtlInitUnicodeString(&KeyName, L"Control");
834     InitializeObjectAttributes(&ObjectAttributes,
835                                &KeyName,
836                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
837                                InstanceKey,
838                                NULL);
839     Status = ZwCreateKey(&ControlKey,
840                          0,
841                          &ObjectAttributes,
842                          0,
843                          NULL,
844                          REG_OPTION_VOLATILE,
845                          NULL);
846     if (NT_SUCCESS(Status))
847         ZwClose(ControlKey);
848 
849     /* Create the 'Device Parameters' key and set the 'FirmwareIdentified' value for all ACPI-enumerated devices */
850     if (_wcsnicmp(DeviceNode->InstancePath.Buffer, L"ACPI\\", 5) == 0)
851     {
852         RtlInitUnicodeString(&KeyName, L"Device Parameters");
853         InitializeObjectAttributes(&ObjectAttributes,
854                                    &KeyName,
855                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
856                                    InstanceKey,
857                                    NULL);
858         Status = ZwCreateKey(&DeviceParamsKey,
859                              0,
860                              &ObjectAttributes,
861                              0,
862                              NULL,
863                              REG_OPTION_NON_VOLATILE,
864                              NULL);
865         if (NT_SUCCESS(Status))
866         {
867             ULONG FirmwareIdentified = 1;
868             RtlInitUnicodeString(&KeyName, L"FirmwareIdentified");
869             Status = ZwSetValueKey(DeviceParamsKey,
870                                    &KeyName,
871                                    0,
872                                    REG_DWORD,
873                                    &FirmwareIdentified,
874                                    sizeof(FirmwareIdentified));
875 
876             ZwClose(DeviceParamsKey);
877         }
878     }
879 
880     DPRINT("IopSetDeviceInstanceData() done\n");
881 
882     return Status;
883 }
884 
885 /*
886  * IopGetParentIdPrefix
887  *
888  * Retrieve (or create) a string which identifies a device.
889  *
890  * Parameters
891  *    DeviceNode
892  *        Pointer to device node.
893  *    ParentIdPrefix
894  *        Pointer to the string where is returned the parent node identifier
895  *
896  * Remarks
897  *     If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
898  *     valid and its Buffer field is NULL-terminated. The caller needs to
899  *     to free the string with RtlFreeUnicodeString when it is no longer
900  *     needed.
901  */
902 
903 NTSTATUS
904 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
905                      PUNICODE_STRING ParentIdPrefix)
906 {
907     const UNICODE_STRING EnumKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
908     ULONG KeyNameBufferLength;
909     PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
910     UNICODE_STRING KeyName = {0, 0, NULL};
911     UNICODE_STRING KeyValue;
912     UNICODE_STRING ValueName;
913     HANDLE hKey = NULL;
914     ULONG crc32;
915     NTSTATUS Status;
916 
917     /* HACK: As long as some devices have a NULL device
918      * instance path, the following test is required :(
919      */
920     if (DeviceNode->Parent->InstancePath.Length == 0)
921     {
922         DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
923                 &DeviceNode->InstancePath);
924         return STATUS_UNSUCCESSFUL;
925     }
926 
927     /* 1. Try to retrieve ParentIdPrefix from registry */
928     KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(L"12345678&12345678");
929     ParentIdPrefixInformation = ExAllocatePoolWithTag(PagedPool,
930                                                       KeyNameBufferLength + sizeof(UNICODE_NULL),
931                                                       TAG_IO);
932     if (!ParentIdPrefixInformation)
933     {
934         return STATUS_INSUFFICIENT_RESOURCES;
935     }
936 
937     KeyName.Length = 0;
938     KeyName.MaximumLength = EnumKeyPath.Length +
939                             DeviceNode->Parent->InstancePath.Length +
940                             sizeof(UNICODE_NULL);
941     KeyName.Buffer = ExAllocatePoolWithTag(PagedPool,
942                                            KeyName.MaximumLength,
943                                            TAG_IO);
944     if (!KeyName.Buffer)
945     {
946         Status = STATUS_INSUFFICIENT_RESOURCES;
947         goto cleanup;
948     }
949 
950     RtlCopyUnicodeString(&KeyName, &EnumKeyPath);
951     RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath);
952 
953     Status = IopOpenRegistryKeyEx(&hKey, NULL, &KeyName, KEY_QUERY_VALUE | KEY_SET_VALUE);
954     if (!NT_SUCCESS(Status))
955     {
956         goto cleanup;
957     }
958     RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
959     Status = ZwQueryValueKey(hKey,
960                              &ValueName,
961                              KeyValuePartialInformation,
962                              ParentIdPrefixInformation,
963                              KeyNameBufferLength,
964                              &KeyNameBufferLength);
965     if (NT_SUCCESS(Status))
966     {
967         if (ParentIdPrefixInformation->Type != REG_SZ)
968         {
969             Status = STATUS_UNSUCCESSFUL;
970         }
971         else
972         {
973             KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
974             KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
975             KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
976             ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
977         }
978         goto cleanup;
979     }
980     if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
981     {
982         /* FIXME how do we get here and why is ParentIdPrefixInformation valid? */
983         KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
984         KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
985         KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
986         ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
987         goto cleanup;
988     }
989 
990     /* 2. Create the ParentIdPrefix value */
991     crc32 = RtlComputeCrc32(0,
992                             (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
993                             DeviceNode->Parent->InstancePath.Length);
994 
995     RtlStringCbPrintfW((PWSTR)ParentIdPrefixInformation,
996                        KeyNameBufferLength,
997                        L"%lx&%lx",
998                        DeviceNode->Parent->Level,
999                        crc32);
1000     RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation);
1001 
1002     /* 3. Try to write the ParentIdPrefix to registry */
1003     Status = ZwSetValueKey(hKey,
1004                            &ValueName,
1005                            0,
1006                            REG_SZ,
1007                            KeyValue.Buffer,
1008                            ((ULONG)wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
1009 
1010 cleanup:
1011     if (NT_SUCCESS(Status))
1012     {
1013         /* Duplicate the string to return it */
1014         Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1015                                            &KeyValue,
1016                                            ParentIdPrefix);
1017     }
1018     ExFreePoolWithTag(ParentIdPrefixInformation, TAG_IO);
1019     RtlFreeUnicodeString(&KeyName);
1020     if (hKey != NULL)
1021     {
1022         ZwClose(hKey);
1023     }
1024     return Status;
1025 }
1026 
1027 static
1028 CODE_SEG("INIT")
1029 NTSTATUS
1030 IopEnumerateDetectedDevices(
1031    IN HANDLE hBaseKey,
1032    IN PUNICODE_STRING RelativePath OPTIONAL,
1033    IN HANDLE hRootKey,
1034    IN BOOLEAN EnumerateSubKeys,
1035    IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
1036    IN ULONG ParentBootResourcesLength)
1037 {
1038    UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
1039    UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
1040    UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
1041    UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
1042    UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
1043    OBJECT_ATTRIBUTES ObjectAttributes;
1044    HANDLE hDevicesKey = NULL;
1045    HANDLE hDeviceKey = NULL;
1046    HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
1047    UNICODE_STRING Level2NameU;
1048    WCHAR Level2Name[5];
1049    ULONG IndexDevice = 0;
1050    ULONG IndexSubKey;
1051    PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
1052    ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
1053    PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
1054    ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
1055    UNICODE_STRING DeviceName, ValueName;
1056    ULONG RequiredSize;
1057    PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
1058    ULONG BootResourcesLength;
1059    NTSTATUS Status;
1060 
1061    const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
1062    UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
1063    static ULONG DeviceIndexSerial = 0;
1064    const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
1065    UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
1066    static ULONG DeviceIndexKeyboard = 0;
1067    const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
1068    /* FIXME: IopEnumerateDetectedDevices() should be rewritten.
1069     * The PnP identifiers can either be hardcoded or parsed from a LegacyXlate
1070     * sections of driver INF files.
1071     */
1072 #if defined(SARCH_PC98)
1073    UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*nEC1F00\0");
1074 #else
1075    UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
1076 #endif
1077    static ULONG DeviceIndexMouse = 0;
1078    const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController");
1079    UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0");
1080    static ULONG DeviceIndexParallel = 0;
1081    const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral");
1082    UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0");
1083    static ULONG DeviceIndexFloppy = 0;
1084    UNICODE_STRING HardwareIdKey;
1085    PUNICODE_STRING pHardwareId;
1086    ULONG DeviceIndex = 0;
1087    PUCHAR CmResourceList;
1088    ULONG ListCount;
1089 
1090     if (RelativePath)
1091     {
1092         Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
1093         if (!NT_SUCCESS(Status))
1094         {
1095             DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
1096             goto cleanup;
1097         }
1098     }
1099     else
1100         hDevicesKey = hBaseKey;
1101 
1102    pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
1103    if (!pDeviceInformation)
1104    {
1105       DPRINT("ExAllocatePool() failed\n");
1106       Status = STATUS_NO_MEMORY;
1107       goto cleanup;
1108    }
1109 
1110    pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
1111    if (!pValueInformation)
1112    {
1113       DPRINT("ExAllocatePool() failed\n");
1114       Status = STATUS_NO_MEMORY;
1115       goto cleanup;
1116    }
1117 
1118    while (TRUE)
1119    {
1120       Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
1121       if (Status == STATUS_NO_MORE_ENTRIES)
1122          break;
1123       else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
1124       {
1125          ExFreePool(pDeviceInformation);
1126          DeviceInfoLength = RequiredSize;
1127          pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
1128          if (!pDeviceInformation)
1129          {
1130             DPRINT("ExAllocatePool() failed\n");
1131             Status = STATUS_NO_MEMORY;
1132             goto cleanup;
1133          }
1134          Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
1135       }
1136       if (!NT_SUCCESS(Status))
1137       {
1138          DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
1139          goto cleanup;
1140       }
1141       IndexDevice++;
1142 
1143       /* Open device key */
1144       DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
1145       DeviceName.Buffer = pDeviceInformation->Name;
1146 
1147       Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
1148           KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
1149       if (!NT_SUCCESS(Status))
1150       {
1151          DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
1152          goto cleanup;
1153       }
1154 
1155       /* Read boot resources, and add then to parent ones */
1156       Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
1157       if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
1158       {
1159          ExFreePool(pValueInformation);
1160          ValueInfoLength = RequiredSize;
1161          pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
1162          if (!pValueInformation)
1163          {
1164             DPRINT("ExAllocatePool() failed\n");
1165             ZwDeleteKey(hLevel2Key);
1166             Status = STATUS_NO_MEMORY;
1167             goto cleanup;
1168          }
1169          Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
1170       }
1171       if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1172       {
1173          BootResources = ParentBootResources;
1174          BootResourcesLength = ParentBootResourcesLength;
1175       }
1176       else if (!NT_SUCCESS(Status))
1177       {
1178          DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
1179          goto nextdevice;
1180       }
1181       else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
1182       {
1183          DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
1184          goto nextdevice;
1185       }
1186       else
1187       {
1188          static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
1189 
1190          /* Concatenate current resources and parent ones */
1191          if (ParentBootResourcesLength == 0)
1192             BootResourcesLength = pValueInformation->DataLength;
1193          else
1194             BootResourcesLength = ParentBootResourcesLength
1195             + pValueInformation->DataLength
1196                - Header;
1197          BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
1198          if (!BootResources)
1199          {
1200             DPRINT("ExAllocatePool() failed\n");
1201             goto nextdevice;
1202          }
1203          if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
1204          {
1205             RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
1206          }
1207          else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
1208          {
1209             RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
1210             RtlCopyMemory(
1211                (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
1212                (PVOID)((ULONG_PTR)ParentBootResources + Header),
1213                ParentBootResourcesLength - Header);
1214             BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
1215          }
1216          else
1217          {
1218             RtlCopyMemory(BootResources, pValueInformation->Data, Header);
1219             RtlCopyMemory(
1220                (PVOID)((ULONG_PTR)BootResources + Header),
1221                (PVOID)((ULONG_PTR)ParentBootResources + Header),
1222                ParentBootResourcesLength - Header);
1223             RtlCopyMemory(
1224                (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
1225                pValueInformation->Data + Header,
1226                pValueInformation->DataLength - Header);
1227             BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
1228          }
1229       }
1230 
1231       if (EnumerateSubKeys)
1232       {
1233          IndexSubKey = 0;
1234          while (TRUE)
1235          {
1236             Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
1237             if (Status == STATUS_NO_MORE_ENTRIES)
1238                break;
1239             else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
1240             {
1241                ExFreePool(pDeviceInformation);
1242                DeviceInfoLength = RequiredSize;
1243                pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
1244                if (!pDeviceInformation)
1245                {
1246                   DPRINT("ExAllocatePool() failed\n");
1247                   Status = STATUS_NO_MEMORY;
1248                   goto cleanup;
1249                }
1250                Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
1251             }
1252             if (!NT_SUCCESS(Status))
1253             {
1254                DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
1255                goto cleanup;
1256             }
1257             IndexSubKey++;
1258             DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
1259             DeviceName.Buffer = pDeviceInformation->Name;
1260 
1261             Status = IopEnumerateDetectedDevices(
1262                hDeviceKey,
1263                &DeviceName,
1264                hRootKey,
1265                TRUE,
1266                BootResources,
1267                BootResourcesLength);
1268             if (!NT_SUCCESS(Status))
1269                goto cleanup;
1270          }
1271       }
1272 
1273       /* Read identifier */
1274       Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
1275       if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
1276       {
1277          ExFreePool(pValueInformation);
1278          ValueInfoLength = RequiredSize;
1279          pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
1280          if (!pValueInformation)
1281          {
1282             DPRINT("ExAllocatePool() failed\n");
1283             Status = STATUS_NO_MEMORY;
1284             goto cleanup;
1285          }
1286          Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
1287       }
1288       if (!NT_SUCCESS(Status))
1289       {
1290          if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
1291          {
1292             DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
1293             goto nextdevice;
1294          }
1295          ValueName.Length = ValueName.MaximumLength = 0;
1296       }
1297       else if (pValueInformation->Type != REG_SZ)
1298       {
1299          DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
1300          goto nextdevice;
1301       }
1302       else
1303       {
1304          /* Assign hardware id to this device */
1305          ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
1306          ValueName.Buffer = (PWCHAR)pValueInformation->Data;
1307          if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
1308             ValueName.Length -= sizeof(WCHAR);
1309       }
1310 
1311       if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
1312       {
1313          pHardwareId = &HardwareIdSerial;
1314          DeviceIndex = DeviceIndexSerial++;
1315       }
1316       else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
1317       {
1318          pHardwareId = &HardwareIdKeyboard;
1319          DeviceIndex = DeviceIndexKeyboard++;
1320       }
1321       else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
1322       {
1323          pHardwareId = &HardwareIdMouse;
1324          DeviceIndex = DeviceIndexMouse++;
1325       }
1326       else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0)
1327       {
1328          pHardwareId = &HardwareIdParallel;
1329          DeviceIndex = DeviceIndexParallel++;
1330       }
1331       else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0)
1332       {
1333          pHardwareId = &HardwareIdFloppy;
1334          DeviceIndex = DeviceIndexFloppy++;
1335       }
1336       else
1337       {
1338          /* Unknown key path */
1339          DPRINT("Unknown key path '%wZ'\n", RelativePath);
1340          goto nextdevice;
1341       }
1342 
1343       /* Prepare hardware id key (hardware id value without final \0) */
1344       HardwareIdKey = *pHardwareId;
1345       HardwareIdKey.Length -= sizeof(UNICODE_NULL);
1346 
1347       /* Add the detected device to Root key */
1348       InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
1349       Status = ZwCreateKey(
1350          &hLevel1Key,
1351          KEY_CREATE_SUB_KEY,
1352          &ObjectAttributes,
1353          0,
1354          NULL,
1355          REG_OPTION_NON_VOLATILE,
1356          NULL);
1357       if (!NT_SUCCESS(Status))
1358       {
1359          DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
1360          goto nextdevice;
1361       }
1362       swprintf(Level2Name, L"%04lu", DeviceIndex);
1363       RtlInitUnicodeString(&Level2NameU, Level2Name);
1364       InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
1365       Status = ZwCreateKey(
1366          &hLevel2Key,
1367          KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
1368          &ObjectAttributes,
1369          0,
1370          NULL,
1371          REG_OPTION_NON_VOLATILE,
1372          NULL);
1373       ZwClose(hLevel1Key);
1374       if (!NT_SUCCESS(Status))
1375       {
1376          DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
1377          goto nextdevice;
1378       }
1379       DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
1380       Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
1381       if (!NT_SUCCESS(Status))
1382       {
1383          DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
1384          ZwDeleteKey(hLevel2Key);
1385          goto nextdevice;
1386       }
1387       /* Create 'LogConf' subkey */
1388       InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
1389       Status = ZwCreateKey(
1390          &hLogConf,
1391          KEY_SET_VALUE,
1392          &ObjectAttributes,
1393          0,
1394          NULL,
1395          REG_OPTION_VOLATILE,
1396          NULL);
1397       if (!NT_SUCCESS(Status))
1398       {
1399          DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
1400          ZwDeleteKey(hLevel2Key);
1401          goto nextdevice;
1402       }
1403       if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
1404       {
1405          CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG));
1406          if (!CmResourceList)
1407          {
1408             ZwClose(hLogConf);
1409             ZwDeleteKey(hLevel2Key);
1410             goto nextdevice;
1411          }
1412 
1413          /* Add the list count (1st member of CM_RESOURCE_LIST) */
1414          ListCount = 1;
1415          RtlCopyMemory(CmResourceList,
1416                        &ListCount,
1417                        sizeof(ULONG));
1418 
1419          /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
1420          RtlCopyMemory(CmResourceList + sizeof(ULONG),
1421                        BootResources,
1422                        BootResourcesLength);
1423 
1424          /* Save boot resources to 'LogConf\BootConfig' */
1425          Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG));
1426          if (!NT_SUCCESS(Status))
1427          {
1428             DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
1429             ZwClose(hLogConf);
1430             ZwDeleteKey(hLevel2Key);
1431             goto nextdevice;
1432          }
1433       }
1434       ZwClose(hLogConf);
1435 
1436 nextdevice:
1437       if (BootResources && BootResources != ParentBootResources)
1438       {
1439          ExFreePool(BootResources);
1440          BootResources = NULL;
1441       }
1442       if (hLevel2Key)
1443       {
1444          ZwClose(hLevel2Key);
1445          hLevel2Key = NULL;
1446       }
1447       if (hDeviceKey)
1448       {
1449          ZwClose(hDeviceKey);
1450          hDeviceKey = NULL;
1451       }
1452    }
1453 
1454    Status = STATUS_SUCCESS;
1455 
1456 cleanup:
1457    if (hDevicesKey && hDevicesKey != hBaseKey)
1458       ZwClose(hDevicesKey);
1459    if (hDeviceKey)
1460       ZwClose(hDeviceKey);
1461    if (pDeviceInformation)
1462       ExFreePool(pDeviceInformation);
1463    if (pValueInformation)
1464       ExFreePool(pValueInformation);
1465    return Status;
1466 }
1467 
1468 static
1469 CODE_SEG("INIT")
1470 BOOLEAN
1471 IopIsFirmwareMapperDisabled(VOID)
1472 {
1473     UNICODE_STRING KeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
1474     UNICODE_STRING KeyNameU = RTL_CONSTANT_STRING(L"DisableFirmwareMapper");
1475     OBJECT_ATTRIBUTES ObjectAttributes;
1476     HANDLE hPnpKey;
1477     PKEY_VALUE_PARTIAL_INFORMATION KeyInformation;
1478     ULONG DesiredLength, Length;
1479     ULONG KeyValue = 0;
1480     NTSTATUS Status;
1481 
1482     InitializeObjectAttributes(&ObjectAttributes, &KeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
1483     Status = ZwOpenKey(&hPnpKey, KEY_QUERY_VALUE, &ObjectAttributes);
1484     if (NT_SUCCESS(Status))
1485     {
1486         Status = ZwQueryValueKey(hPnpKey,
1487                                  &KeyNameU,
1488                                  KeyValuePartialInformation,
1489                                  NULL,
1490                                  0,
1491                                  &DesiredLength);
1492         if ((Status == STATUS_BUFFER_TOO_SMALL) ||
1493             (Status == STATUS_BUFFER_OVERFLOW))
1494         {
1495             Length = DesiredLength;
1496             KeyInformation = ExAllocatePool(PagedPool, Length);
1497             if (KeyInformation)
1498             {
1499                 Status = ZwQueryValueKey(hPnpKey,
1500                                          &KeyNameU,
1501                                          KeyValuePartialInformation,
1502                                          KeyInformation,
1503                                          Length,
1504                                          &DesiredLength);
1505                 if (NT_SUCCESS(Status) && KeyInformation->DataLength == sizeof(ULONG))
1506                 {
1507                     KeyValue = (ULONG)(*KeyInformation->Data);
1508                 }
1509                 else
1510                 {
1511                     DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU, &KeyNameU);
1512                 }
1513 
1514                 ExFreePool(KeyInformation);
1515             }
1516             else
1517             {
1518                 DPRINT1("Failed to allocate memory for registry query\n");
1519             }
1520         }
1521         else
1522         {
1523             DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU, &KeyNameU, Status);
1524         }
1525 
1526         ZwClose(hPnpKey);
1527     }
1528     else
1529     {
1530         DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU, Status);
1531     }
1532 
1533     DPRINT("Firmware mapper is %s\n", KeyValue != 0 ? "disabled" : "enabled");
1534 
1535     return (KeyValue != 0) ? TRUE : FALSE;
1536 }
1537 
1538 CODE_SEG("INIT")
1539 NTSTATUS
1540 NTAPI
1541 IopUpdateRootKey(VOID)
1542 {
1543     UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
1544     UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root");
1545     UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
1546     OBJECT_ATTRIBUTES ObjectAttributes;
1547     HANDLE hEnum, hRoot;
1548     NTSTATUS Status;
1549 
1550     InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
1551     Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
1552     if (!NT_SUCCESS(Status))
1553     {
1554         DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
1555         return Status;
1556     }
1557 
1558     InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL);
1559     Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
1560     ZwClose(hEnum);
1561     if (!NT_SUCCESS(Status))
1562     {
1563         DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
1564         return Status;
1565     }
1566 
1567     if (!IopIsFirmwareMapperDisabled())
1568     {
1569         Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS);
1570         if (!NT_SUCCESS(Status))
1571         {
1572             /* Nothing to do, don't return with an error status */
1573             DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
1574             ZwClose(hRoot);
1575             return STATUS_SUCCESS;
1576         }
1577         Status = IopEnumerateDetectedDevices(
1578             hEnum,
1579             NULL,
1580             hRoot,
1581             TRUE,
1582             NULL,
1583             0);
1584         ZwClose(hEnum);
1585     }
1586     else
1587     {
1588         /* Enumeration is disabled */
1589         Status = STATUS_SUCCESS;
1590     }
1591 
1592     ZwClose(hRoot);
1593 
1594     return Status;
1595 }
1596 
1597 NTSTATUS
1598 NTAPI
1599 IopOpenRegistryKeyEx(PHANDLE KeyHandle,
1600                      HANDLE ParentKey,
1601                      PUNICODE_STRING Name,
1602                      ACCESS_MASK DesiredAccess)
1603 {
1604     OBJECT_ATTRIBUTES ObjectAttributes;
1605     NTSTATUS Status;
1606 
1607     PAGED_CODE();
1608 
1609     *KeyHandle = NULL;
1610 
1611     InitializeObjectAttributes(&ObjectAttributes,
1612         Name,
1613         OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1614         ParentKey,
1615         NULL);
1616 
1617     Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
1618 
1619     return Status;
1620 }
1621 
1622 NTSTATUS
1623 NTAPI
1624 IopCreateRegistryKeyEx(OUT PHANDLE Handle,
1625                        IN HANDLE RootHandle OPTIONAL,
1626                        IN PUNICODE_STRING KeyName,
1627                        IN ACCESS_MASK DesiredAccess,
1628                        IN ULONG CreateOptions,
1629                        OUT PULONG Disposition OPTIONAL)
1630 {
1631     OBJECT_ATTRIBUTES ObjectAttributes;
1632     ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0;
1633     USHORT Length;
1634     HANDLE HandleArray[2];
1635     BOOLEAN Recursing = TRUE;
1636     PWCHAR pp, p, p1;
1637     UNICODE_STRING KeyString;
1638     NTSTATUS Status = STATUS_SUCCESS;
1639     PAGED_CODE();
1640 
1641     /* P1 is start, pp is end */
1642     p1 = KeyName->Buffer;
1643     pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length);
1644 
1645     /* Create the target key */
1646     InitializeObjectAttributes(&ObjectAttributes,
1647                                KeyName,
1648                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1649                                RootHandle,
1650                                NULL);
1651     Status = ZwCreateKey(&HandleArray[i],
1652                          DesiredAccess,
1653                          &ObjectAttributes,
1654                          0,
1655                          NULL,
1656                          CreateOptions,
1657                          &KeyDisposition);
1658 
1659     /* Now we check if this failed */
1660     if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle))
1661     {
1662         /* Target key failed, so we'll need to create its parent. Setup array */
1663         HandleArray[0] = NULL;
1664         HandleArray[1] = RootHandle;
1665 
1666         /* Keep recursing for each missing parent */
1667         while (Recursing)
1668         {
1669             /* And if we're deep enough, close the last handle */
1670             if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
1671 
1672             /* We're setup to ping-pong between the two handle array entries */
1673             RootHandleIndex = i;
1674             i = (i + 1) & 1;
1675 
1676             /* Clear the one we're attempting to open now */
1677             HandleArray[i] = NULL;
1678 
1679             /* Process the parent key name */
1680             for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++);
1681             Length = (USHORT)(p - p1) * sizeof(WCHAR);
1682 
1683             /* Is there a parent name? */
1684             if (Length)
1685             {
1686                 /* Build the unicode string for it */
1687                 KeyString.Buffer = p1;
1688                 KeyString.Length = KeyString.MaximumLength = Length;
1689 
1690                 /* Now try opening the parent */
1691                 InitializeObjectAttributes(&ObjectAttributes,
1692                                            &KeyString,
1693                                            OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1694                                            HandleArray[RootHandleIndex],
1695                                            NULL);
1696                 Status = ZwCreateKey(&HandleArray[i],
1697                                      DesiredAccess,
1698                                      &ObjectAttributes,
1699                                      0,
1700                                      NULL,
1701                                      CreateOptions,
1702                                      &KeyDisposition);
1703                 if (NT_SUCCESS(Status))
1704                 {
1705                     /* It worked, we have one more handle */
1706                     NestedCloseLevel++;
1707                 }
1708                 else
1709                 {
1710                     /* Parent key creation failed, abandon loop */
1711                     Recursing = FALSE;
1712                     continue;
1713                 }
1714             }
1715             else
1716             {
1717                 /* We don't have a parent name, probably corrupted key name */
1718                 Status = STATUS_INVALID_PARAMETER;
1719                 Recursing = FALSE;
1720                 continue;
1721             }
1722 
1723             /* Now see if there's more parents to create */
1724             p1 = p + 1;
1725             if ((p == pp) || (p1 == pp))
1726             {
1727                 /* We're done, hopefully successfully, so stop */
1728                 Recursing = FALSE;
1729             }
1730         }
1731 
1732         /* Outer loop check for handle nesting that requires closing the top handle */
1733         if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
1734     }
1735 
1736     /* Check if we broke out of the loop due to success */
1737     if (NT_SUCCESS(Status))
1738     {
1739         /* Return the target handle (we closed all the parent ones) and disposition */
1740         *Handle = HandleArray[i];
1741         if (Disposition) *Disposition = KeyDisposition;
1742     }
1743 
1744     /* Return the success state */
1745     return Status;
1746 }
1747 
1748 NTSTATUS
1749 NTAPI
1750 IopGetRegistryValue(IN HANDLE Handle,
1751                     IN PWSTR ValueName,
1752                     OUT PKEY_VALUE_FULL_INFORMATION *Information)
1753 {
1754     UNICODE_STRING ValueString;
1755     NTSTATUS Status;
1756     PKEY_VALUE_FULL_INFORMATION FullInformation;
1757     ULONG Size;
1758     PAGED_CODE();
1759 
1760     RtlInitUnicodeString(&ValueString, ValueName);
1761 
1762     Status = ZwQueryValueKey(Handle,
1763                              &ValueString,
1764                              KeyValueFullInformation,
1765                              NULL,
1766                              0,
1767                              &Size);
1768     if ((Status != STATUS_BUFFER_OVERFLOW) &&
1769         (Status != STATUS_BUFFER_TOO_SMALL))
1770     {
1771         return Status;
1772     }
1773 
1774     FullInformation = ExAllocatePool(NonPagedPool, Size);
1775     if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES;
1776 
1777     Status = ZwQueryValueKey(Handle,
1778                              &ValueString,
1779                              KeyValueFullInformation,
1780                              FullInformation,
1781                              Size,
1782                              &Size);
1783     if (!NT_SUCCESS(Status))
1784     {
1785         ExFreePool(FullInformation);
1786         return Status;
1787     }
1788 
1789     *Information = FullInformation;
1790     return STATUS_SUCCESS;
1791 }
1792 
1793 RTL_GENERIC_COMPARE_RESULTS
1794 NTAPI
1795 PiCompareInstancePath(IN PRTL_AVL_TABLE Table,
1796                       IN PVOID FirstStruct,
1797                       IN PVOID SecondStruct)
1798 {
1799     /* FIXME: TODO */
1800     ASSERT(FALSE);
1801     return 0;
1802 }
1803 
1804 //
1805 //  The allocation function is called by the generic table package whenever
1806 //  it needs to allocate memory for the table.
1807 //
1808 
1809 PVOID
1810 NTAPI
1811 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table,
1812                             IN CLONG ByteSize)
1813 {
1814     /* FIXME: TODO */
1815     ASSERT(FALSE);
1816     return NULL;
1817 }
1818 
1819 VOID
1820 NTAPI
1821 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table,
1822                         IN PVOID Buffer)
1823 {
1824     /* FIXME: TODO */
1825     ASSERT(FALSE);
1826 }
1827 
1828 VOID
1829 NTAPI
1830 PpInitializeDeviceReferenceTable(VOID)
1831 {
1832     /* Setup the guarded mutex and AVL table */
1833     KeInitializeGuardedMutex(&PpDeviceReferenceTableLock);
1834     RtlInitializeGenericTableAvl(
1835         &PpDeviceReferenceTable,
1836         (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath,
1837         (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry,
1838         (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry,
1839         NULL);
1840 }
1841 
1842 BOOLEAN
1843 NTAPI
1844 PiInitPhase0(VOID)
1845 {
1846     /* Initialize the resource when accessing device registry data */
1847     ExInitializeResourceLite(&PpRegistryDeviceResource);
1848 
1849     /* Setup the device reference AVL table */
1850     PpInitializeDeviceReferenceTable();
1851     return TRUE;
1852 }
1853 
1854 BOOLEAN
1855 NTAPI
1856 PpInitSystem(VOID)
1857 {
1858     /* Check the initialization phase */
1859     switch (ExpInitializationPhase)
1860     {
1861     case 0:
1862 
1863         /* Do Phase 0 */
1864         return PiInitPhase0();
1865 
1866     case 1:
1867 
1868         /* Do Phase 1 */
1869         return TRUE;
1870         //return PiInitPhase1();
1871 
1872     default:
1873 
1874         /* Don't know any other phase! Bugcheck! */
1875         KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
1876         return FALSE;
1877     }
1878 }
1879 
1880 /* PUBLIC FUNCTIONS **********************************************************/
1881 
1882 NTSTATUS
1883 NTAPI
1884 PnpBusTypeGuidGet(IN USHORT Index,
1885                   IN LPGUID BusTypeGuid)
1886 {
1887     NTSTATUS Status = STATUS_SUCCESS;
1888 
1889     /* Acquire the lock */
1890     ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
1891 
1892     /* Validate size */
1893     if (Index < PnpBusTypeGuidList->GuidCount)
1894     {
1895         /* Copy the data */
1896         RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID));
1897     }
1898     else
1899     {
1900         /* Failure path */
1901         Status = STATUS_OBJECT_NAME_NOT_FOUND;
1902     }
1903 
1904     /* Release lock and return status */
1905     ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
1906     return Status;
1907 }
1908 
1909 NTSTATUS
1910 NTAPI
1911 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject,
1912                                 IN PHANDLE DeviceInstanceHandle,
1913                                 IN ACCESS_MASK DesiredAccess)
1914 {
1915     NTSTATUS Status;
1916     HANDLE KeyHandle;
1917     PDEVICE_NODE DeviceNode;
1918     UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
1919     PAGED_CODE();
1920 
1921     /* Open the enum key */
1922     Status = IopOpenRegistryKeyEx(&KeyHandle,
1923                                   NULL,
1924                                   &KeyName,
1925                                   KEY_READ);
1926     if (!NT_SUCCESS(Status)) return Status;
1927 
1928     /* Make sure we have an instance path */
1929     DeviceNode = IopGetDeviceNode(DeviceObject);
1930     if ((DeviceNode) && (DeviceNode->InstancePath.Length))
1931     {
1932         /* Get the instance key */
1933         Status = IopOpenRegistryKeyEx(DeviceInstanceHandle,
1934                                       KeyHandle,
1935                                       &DeviceNode->InstancePath,
1936                                       DesiredAccess);
1937     }
1938     else
1939     {
1940         /* Fail */
1941         Status = STATUS_INVALID_DEVICE_REQUEST;
1942     }
1943 
1944     /* Close the handle and return status */
1945     ZwClose(KeyHandle);
1946     return Status;
1947 }
1948 
1949 ULONG
1950 NTAPI
1951 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList)
1952 {
1953     ULONG FinalSize, PartialSize, EntrySize, i, j;
1954     PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
1955     PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
1956 
1957     /* If we don't have one, that's easy */
1958     if (!ResourceList) return 0;
1959 
1960     /* Start with the minimum size possible */
1961     FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
1962 
1963     /* Loop each full descriptor */
1964     FullDescriptor = ResourceList->List;
1965     for (i = 0; i < ResourceList->Count; i++)
1966     {
1967         /* Start with the minimum size possible */
1968         PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
1969         FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors);
1970 
1971         /* Loop each partial descriptor */
1972         PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors;
1973         for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++)
1974         {
1975             /* Start with the minimum size possible */
1976             EntrySize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1977 
1978             /* Check if there is extra data */
1979             if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
1980             {
1981                 /* Add that data */
1982                 EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize;
1983             }
1984 
1985             /* The size of partial descriptors is bigger */
1986             PartialSize += EntrySize;
1987 
1988             /* Go to the next partial descriptor */
1989             PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize);
1990         }
1991 
1992         /* The size of full descriptors is bigger */
1993         FinalSize += PartialSize;
1994 
1995         /* Go to the next full descriptor */
1996         FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize);
1997     }
1998 
1999     /* Return the final size */
2000     return FinalSize;
2001 }
2002 
2003 NTSTATUS
2004 NTAPI
2005 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject,
2006                             IN ULONG ValueType,
2007                             IN PWSTR ValueName,
2008                             IN PWSTR KeyName,
2009                             OUT PVOID Buffer,
2010                             IN PULONG BufferLength)
2011 {
2012     NTSTATUS Status;
2013     HANDLE KeyHandle, SubHandle;
2014     UNICODE_STRING KeyString;
2015     PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL;
2016     ULONG Length;
2017     PAGED_CODE();
2018 
2019     /* Find the instance key */
2020     Status = PnpDeviceObjectToDeviceInstance(DeviceObject, &KeyHandle, KEY_READ);
2021     if (NT_SUCCESS(Status))
2022     {
2023         /* Check for name given by caller */
2024         if (KeyName)
2025         {
2026             /* Open this key */
2027             RtlInitUnicodeString(&KeyString, KeyName);
2028             Status = IopOpenRegistryKeyEx(&SubHandle,
2029                                           KeyHandle,
2030                                           &KeyString,
2031                                           KEY_READ);
2032             if (NT_SUCCESS(Status))
2033             {
2034                 /* And use this handle instead */
2035                 ZwClose(KeyHandle);
2036                 KeyHandle = SubHandle;
2037             }
2038         }
2039 
2040         /* Check if sub-key handle succeeded (or no-op if no key name given) */
2041         if (NT_SUCCESS(Status))
2042         {
2043             /* Now get the size of the property */
2044             Status = IopGetRegistryValue(KeyHandle,
2045                                          ValueName,
2046                                          &KeyValueInfo);
2047         }
2048 
2049         /* Close the key */
2050         ZwClose(KeyHandle);
2051     }
2052 
2053     /* Fail if any of the registry operations failed */
2054     if (!NT_SUCCESS(Status)) return Status;
2055 
2056     /* Check how much data we have to copy */
2057     Length = KeyValueInfo->DataLength;
2058     if (*BufferLength >= Length)
2059     {
2060         /* Check for a match in the value type */
2061         if (KeyValueInfo->Type == ValueType)
2062         {
2063             /* Copy the data */
2064             RtlCopyMemory(Buffer,
2065                           (PVOID)((ULONG_PTR)KeyValueInfo +
2066                           KeyValueInfo->DataOffset),
2067                           Length);
2068         }
2069         else
2070         {
2071             /* Invalid registry property type, fail */
2072            Status = STATUS_INVALID_PARAMETER_2;
2073         }
2074     }
2075     else
2076     {
2077         /* Buffer is too small to hold data */
2078         Status = STATUS_BUFFER_TOO_SMALL;
2079     }
2080 
2081     /* Return the required buffer length, free the buffer, and return status */
2082     *BufferLength = Length;
2083     ExFreePool(KeyValueInfo);
2084     return Status;
2085 }
2086 
2087 #define PIP_RETURN_DATA(x, y)   {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
2088 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
2089 #define PIP_UNIMPLEMENTED()     {UNIMPLEMENTED_DBGBREAK(); break;}
2090 
2091 /*
2092  * @implemented
2093  */
2094 NTSTATUS
2095 NTAPI
2096 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
2097                     IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
2098                     IN ULONG BufferLength,
2099                     OUT PVOID PropertyBuffer,
2100                     OUT PULONG ResultLength)
2101 {
2102     PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
2103     DEVICE_CAPABILITIES DeviceCaps;
2104     ULONG ReturnLength = 0, Length = 0, ValueType;
2105     PWCHAR ValueName = NULL, EnumeratorNameEnd, DeviceInstanceName;
2106     PVOID Data = NULL;
2107     NTSTATUS Status = STATUS_BUFFER_TOO_SMALL;
2108     GUID BusTypeGuid;
2109     POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
2110     BOOLEAN NullTerminate = FALSE;
2111     DEVICE_REMOVAL_POLICY Policy;
2112 
2113     DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
2114 
2115     /* Assume failure */
2116     *ResultLength = 0;
2117 
2118     /* Only PDOs can call this */
2119     if (!DeviceNode) return STATUS_INVALID_DEVICE_REQUEST;
2120 
2121     /* Handle all properties */
2122     switch (DeviceProperty)
2123     {
2124         case DevicePropertyBusTypeGuid:
2125 
2126             /* Get the GUID from the internal cache */
2127             Status = PnpBusTypeGuidGet(DeviceNode->ChildBusTypeIndex, &BusTypeGuid);
2128             if (!NT_SUCCESS(Status)) return Status;
2129 
2130             /* This is the format of the returned data */
2131             PIP_RETURN_DATA(sizeof(GUID), &BusTypeGuid);
2132 
2133         case DevicePropertyLegacyBusType:
2134 
2135             /* Validate correct interface type */
2136             if (DeviceNode->ChildInterfaceType == InterfaceTypeUndefined)
2137                 return STATUS_OBJECT_NAME_NOT_FOUND;
2138 
2139             /* This is the format of the returned data */
2140             PIP_RETURN_DATA(sizeof(INTERFACE_TYPE), &DeviceNode->ChildInterfaceType);
2141 
2142         case DevicePropertyBusNumber:
2143 
2144             /* Validate correct bus number */
2145             if ((DeviceNode->ChildBusNumber & 0x80000000) == 0x80000000)
2146                 return STATUS_OBJECT_NAME_NOT_FOUND;
2147 
2148             /* This is the format of the returned data */
2149             PIP_RETURN_DATA(sizeof(ULONG), &DeviceNode->ChildBusNumber);
2150 
2151         case DevicePropertyEnumeratorName:
2152 
2153             /* Get the instance path */
2154             DeviceInstanceName = DeviceNode->InstancePath.Buffer;
2155 
2156             /* Sanity checks */
2157             ASSERT((BufferLength & 1) == 0);
2158             ASSERT(DeviceInstanceName != NULL);
2159 
2160             /* Get the name from the path */
2161             EnumeratorNameEnd = wcschr(DeviceInstanceName, OBJ_NAME_PATH_SEPARATOR);
2162             ASSERT(EnumeratorNameEnd);
2163 
2164             /* This string needs to be NULL-terminated */
2165             NullTerminate = TRUE;
2166 
2167             /* This is the format of the returned data */
2168             PIP_RETURN_DATA((ULONG)(EnumeratorNameEnd - DeviceInstanceName) * sizeof(WCHAR),
2169                             DeviceInstanceName);
2170 
2171         case DevicePropertyAddress:
2172 
2173             /* Query the device caps */
2174             Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps);
2175             if (!NT_SUCCESS(Status) || (DeviceCaps.Address == MAXULONG))
2176                 return STATUS_OBJECT_NAME_NOT_FOUND;
2177 
2178             /* This is the format of the returned data */
2179             PIP_RETURN_DATA(sizeof(ULONG), &DeviceCaps.Address);
2180 
2181         case DevicePropertyBootConfigurationTranslated:
2182 
2183             /* Validate we have resources */
2184             if (!DeviceNode->BootResources)
2185 //            if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
2186             {
2187                 /* No resources will still fake success, but with 0 bytes */
2188                 *ResultLength = 0;
2189                 return STATUS_SUCCESS;
2190             }
2191 
2192             /* This is the format of the returned data */
2193             PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode->BootResources), // FIXFIX: Should use BootResourcesTranslated
2194                             DeviceNode->BootResources); // FIXFIX: Should use BootResourcesTranslated
2195 
2196         case DevicePropertyPhysicalDeviceObjectName:
2197 
2198             /* Sanity check for Unicode-sized string */
2199             ASSERT((BufferLength & 1) == 0);
2200 
2201             /* Allocate name buffer */
2202             Length = BufferLength + sizeof(OBJECT_NAME_INFORMATION);
2203             ObjectNameInfo = ExAllocatePool(PagedPool, Length);
2204             if (!ObjectNameInfo) return STATUS_INSUFFICIENT_RESOURCES;
2205 
2206             /* Query the PDO name */
2207             Status = ObQueryNameString(DeviceObject,
2208                                        ObjectNameInfo,
2209                                        Length,
2210                                        ResultLength);
2211             if (Status == STATUS_INFO_LENGTH_MISMATCH)
2212             {
2213                 /* It's up to the caller to try again */
2214                 Status = STATUS_BUFFER_TOO_SMALL;
2215             }
2216 
2217             /* This string needs to be NULL-terminated */
2218             NullTerminate = TRUE;
2219 
2220             /* Return if successful */
2221             if (NT_SUCCESS(Status)) PIP_RETURN_DATA(ObjectNameInfo->Name.Length,
2222                                                     ObjectNameInfo->Name.Buffer);
2223 
2224             /* Let the caller know how big the name is */
2225             *ResultLength -= sizeof(OBJECT_NAME_INFORMATION);
2226             break;
2227 
2228         case DevicePropertyRemovalPolicy:
2229 
2230             Policy = DeviceNode->RemovalPolicy;
2231             PIP_RETURN_DATA(sizeof(Policy), &Policy);
2232 
2233         /* Handle the registry-based properties */
2234         case DevicePropertyUINumber:
2235             PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER, REG_DWORD);
2236         case DevicePropertyLocationInformation:
2237             PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION, REG_SZ);
2238         case DevicePropertyDeviceDescription:
2239             PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC, REG_SZ);
2240         case DevicePropertyHardwareID:
2241             PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID, REG_MULTI_SZ);
2242         case DevicePropertyCompatibleIDs:
2243             PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS, REG_MULTI_SZ);
2244         case DevicePropertyBootConfiguration:
2245             PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG, REG_RESOURCE_LIST);
2246         case DevicePropertyClassName:
2247             PIP_REGISTRY_DATA(REGSTR_VAL_CLASS, REG_SZ);
2248         case DevicePropertyClassGuid:
2249             PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID, REG_SZ);
2250         case DevicePropertyDriverKeyName:
2251             PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER, REG_SZ);
2252         case DevicePropertyManufacturer:
2253             PIP_REGISTRY_DATA(REGSTR_VAL_MFG, REG_SZ);
2254         case DevicePropertyFriendlyName:
2255             PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME, REG_SZ);
2256         case DevicePropertyContainerID:
2257             //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
2258             PIP_UNIMPLEMENTED();
2259             break;
2260         case DevicePropertyInstallState:
2261             PIP_REGISTRY_DATA(REGSTR_VAL_CONFIGFLAGS, REG_DWORD);
2262             break;
2263         case DevicePropertyResourceRequirements:
2264             PIP_UNIMPLEMENTED();
2265         case DevicePropertyAllocatedResources:
2266             PIP_UNIMPLEMENTED();
2267         default:
2268             return STATUS_INVALID_PARAMETER_2;
2269     }
2270 
2271     /* Having a registry value name implies registry data */
2272     if (ValueName)
2273     {
2274         /* We know up-front how much data to expect */
2275         *ResultLength = BufferLength;
2276 
2277         /* Go get the data, use the LogConf subkey if necessary */
2278         Status = PiGetDeviceRegistryProperty(DeviceObject,
2279                                              ValueType,
2280                                              ValueName,
2281                                              (DeviceProperty ==
2282                                               DevicePropertyBootConfiguration) ?
2283                                              L"LogConf":  NULL,
2284                                              PropertyBuffer,
2285                                              ResultLength);
2286     }
2287     else if (NT_SUCCESS(Status))
2288     {
2289         /* We know up-front how much data to expect, check the caller's buffer */
2290         *ResultLength = ReturnLength + (NullTerminate ? sizeof(UNICODE_NULL) : 0);
2291         if (*ResultLength <= BufferLength)
2292         {
2293             /* Buffer is all good, copy the data */
2294             RtlCopyMemory(PropertyBuffer, Data, ReturnLength);
2295 
2296             /* Check if we need to NULL-terminate the string */
2297             if (NullTerminate)
2298             {
2299                 /* Terminate the string */
2300                 ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL;
2301             }
2302 
2303             /* This is the success path */
2304             Status = STATUS_SUCCESS;
2305         }
2306         else
2307         {
2308             /* Failure path */
2309             Status = STATUS_BUFFER_TOO_SMALL;
2310         }
2311     }
2312 
2313     /* Free any allocation we may have made, and return the status code */
2314     if (ObjectNameInfo) ExFreePool(ObjectNameInfo);
2315     return Status;
2316 }
2317 
2318 /**
2319  * @name IoOpenDeviceRegistryKey
2320  *
2321  * Open a registry key unique for a specified driver or device instance.
2322  *
2323  * @param DeviceObject   Device to get the registry key for.
2324  * @param DevInstKeyType Type of the key to return.
2325  * @param DesiredAccess  Access mask (eg. KEY_READ | KEY_WRITE).
2326  * @param DevInstRegKey  Handle to the opened registry key on
2327  *                       successful return.
2328  *
2329  * @return Status.
2330  *
2331  * @implemented
2332  */
2333 NTSTATUS
2334 NTAPI
2335 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject,
2336                         IN ULONG DevInstKeyType,
2337                         IN ACCESS_MASK DesiredAccess,
2338                         OUT PHANDLE DevInstRegKey)
2339 {
2340     static WCHAR RootKeyName[] =
2341         L"\\Registry\\Machine\\System\\CurrentControlSet\\";
2342     static WCHAR ProfileKeyName[] =
2343         L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
2344     static WCHAR ClassKeyName[] = L"Control\\Class\\";
2345     static WCHAR EnumKeyName[] = L"Enum\\";
2346     static WCHAR DeviceParametersKeyName[] = L"Device Parameters";
2347     ULONG KeyNameLength;
2348     PWSTR KeyNameBuffer;
2349     UNICODE_STRING KeyName;
2350     ULONG DriverKeyLength;
2351     OBJECT_ATTRIBUTES ObjectAttributes;
2352     PDEVICE_NODE DeviceNode = NULL;
2353     NTSTATUS Status;
2354 
2355     DPRINT("IoOpenDeviceRegistryKey() called\n");
2356 
2357     if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0)
2358     {
2359         DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
2360         return STATUS_INVALID_PARAMETER;
2361     }
2362 
2363     if (!IopIsValidPhysicalDeviceObject(DeviceObject))
2364         return STATUS_INVALID_DEVICE_REQUEST;
2365     DeviceNode = IopGetDeviceNode(DeviceObject);
2366 
2367     /*
2368      * Calculate the length of the base key name. This is the full
2369      * name for driver key or the name excluding "Device Parameters"
2370      * subkey for device key.
2371      */
2372 
2373     KeyNameLength = sizeof(RootKeyName);
2374     if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
2375         KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
2376     if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
2377     {
2378         KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
2379         Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
2380                                      0, NULL, &DriverKeyLength);
2381         if (Status != STATUS_BUFFER_TOO_SMALL)
2382             return Status;
2383         KeyNameLength += DriverKeyLength;
2384     }
2385     else
2386     {
2387         KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
2388                          DeviceNode->InstancePath.Length;
2389     }
2390 
2391     /*
2392      * Now allocate the buffer for the key name...
2393      */
2394 
2395     KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
2396     if (KeyNameBuffer == NULL)
2397         return STATUS_INSUFFICIENT_RESOURCES;
2398 
2399     KeyName.Length = 0;
2400     KeyName.MaximumLength = (USHORT)KeyNameLength;
2401     KeyName.Buffer = KeyNameBuffer;
2402 
2403     /*
2404      * ...and build the key name.
2405      */
2406 
2407     KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
2408     RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
2409 
2410     if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
2411         RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
2412 
2413     if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
2414     {
2415         RtlAppendUnicodeToString(&KeyName, ClassKeyName);
2416         Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
2417                                      DriverKeyLength, KeyNameBuffer +
2418                                      (KeyName.Length / sizeof(WCHAR)),
2419                                      &DriverKeyLength);
2420         if (!NT_SUCCESS(Status))
2421         {
2422             DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status);
2423             ExFreePool(KeyNameBuffer);
2424             return Status;
2425         }
2426         KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL);
2427     }
2428     else
2429     {
2430         RtlAppendUnicodeToString(&KeyName, EnumKeyName);
2431         Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath);
2432         if (DeviceNode->InstancePath.Length == 0)
2433         {
2434             ExFreePool(KeyNameBuffer);
2435             return Status;
2436         }
2437     }
2438 
2439     /*
2440      * Open the base key.
2441      */
2442     Status = IopOpenRegistryKeyEx(DevInstRegKey, NULL, &KeyName, DesiredAccess);
2443     if (!NT_SUCCESS(Status))
2444     {
2445         DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status);
2446         ExFreePool(KeyNameBuffer);
2447         return Status;
2448     }
2449     ExFreePool(KeyNameBuffer);
2450 
2451     /*
2452      * For driver key we're done now.
2453      */
2454 
2455     if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
2456         return Status;
2457 
2458     /*
2459      * Let's go further. For device key we must open "Device Parameters"
2460      * subkey and create it if it doesn't exist yet.
2461      */
2462 
2463     RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
2464     InitializeObjectAttributes(&ObjectAttributes,
2465                                &KeyName,
2466                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2467                                *DevInstRegKey,
2468                                NULL);
2469     Status = ZwCreateKey(DevInstRegKey,
2470                          DesiredAccess,
2471                          &ObjectAttributes,
2472                          0,
2473                          NULL,
2474                          REG_OPTION_NON_VOLATILE,
2475                          NULL);
2476     ZwClose(ObjectAttributes.RootDirectory);
2477 
2478     return Status;
2479 }
2480 
2481 /*
2482  * @implemented
2483  */
2484 VOID
2485 NTAPI
2486 IoInvalidateDeviceRelations(
2487     IN PDEVICE_OBJECT DeviceObject,
2488     IN DEVICE_RELATION_TYPE Type)
2489 {
2490     if (!IopIsValidPhysicalDeviceObject(DeviceObject))
2491     {
2492         KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 0x2, (ULONG_PTR)DeviceObject, 0, 0);
2493     }
2494 
2495     switch (Type)
2496     {
2497         case BusRelations:
2498             /* Enumerate the device */
2499             PiQueueDeviceAction(DeviceObject, PiActionEnumDeviceTree, NULL, NULL);
2500             break;
2501         default:
2502             /* Everything else is not implemented */
2503             break;
2504     }
2505 }
2506 
2507 /*
2508  * @implemented
2509  */
2510 NTSTATUS
2511 NTAPI
2512 IoSynchronousInvalidateDeviceRelations(
2513     IN PDEVICE_OBJECT DeviceObject,
2514     IN DEVICE_RELATION_TYPE Type)
2515 {
2516     PAGED_CODE();
2517 
2518     if (!IopIsValidPhysicalDeviceObject(DeviceObject))
2519     {
2520         KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 0x2, (ULONG_PTR)DeviceObject, 0, 0);
2521     }
2522 
2523     switch (Type)
2524     {
2525         case BusRelations:
2526             /* Enumerate the device */
2527             return PiPerformSyncDeviceAction(DeviceObject, PiActionEnumDeviceTree);
2528         case PowerRelations:
2529              /* Not handled yet */
2530              return STATUS_NOT_IMPLEMENTED;
2531         case TargetDeviceRelation:
2532             /* Nothing to do */
2533             return STATUS_SUCCESS;
2534         default:
2535             /* Ejection relations are not supported */
2536             return STATUS_NOT_SUPPORTED;
2537     }
2538 }
2539 
2540 /*
2541  * @implemented
2542  */
2543 BOOLEAN
2544 NTAPI
2545 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
2546                       IN ULONG BusNumber,
2547                       IN PHYSICAL_ADDRESS BusAddress,
2548                       IN OUT PULONG AddressSpace,
2549                       OUT PPHYSICAL_ADDRESS TranslatedAddress)
2550 {
2551     /* FIXME: Notify the resource arbiter */
2552 
2553     return HalTranslateBusAddress(InterfaceType,
2554                                   BusNumber,
2555                                   BusAddress,
2556                                   AddressSpace,
2557                                   TranslatedAddress);
2558 }
2559