xref: /reactos/ntoskrnl/io/pnpmgr/pnpmgr.c (revision cce399e7)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * COPYRIGHT:       GPL - See COPYING in the top level directory
4  * FILE:            ntoskrnl/io/pnpmgr/pnpmgr.c
5  * PURPOSE:         Initializes the PnP manager
6  * PROGRAMMERS:     Casper S. Hornstrup (chorns@users.sourceforge.net)
7  *                  Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS *******************************************************************/
17 
18 ERESOURCE PpRegistryDeviceResource;
19 KGUARDED_MUTEX PpDeviceReferenceTableLock;
20 RTL_AVL_TABLE PpDeviceReferenceTable;
21 
22 extern ULONG ExpInitializationPhase;
23 
24 /* DATA **********************************************************************/
25 
26 PDRIVER_OBJECT IopRootDriverObject;
27 PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList = NULL;
28 
29 /* FUNCTIONS *****************************************************************/
30 
31 VOID
32 IopFixupDeviceId(PWCHAR String)
33 {
34     SIZE_T Length = wcslen(String), i;
35 
36     for (i = 0; i < Length; i++)
37     {
38         if (String[i] == L'\\')
39             String[i] = L'#';
40     }
41 }
42 
43 VOID
44 NTAPI
45 IopInstallCriticalDevice(PDEVICE_NODE DeviceNode)
46 {
47     NTSTATUS Status;
48     HANDLE CriticalDeviceKey, InstanceKey;
49     OBJECT_ATTRIBUTES ObjectAttributes;
50     UNICODE_STRING CriticalDeviceKeyU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CriticalDeviceDatabase");
51     UNICODE_STRING CompatibleIdU = RTL_CONSTANT_STRING(L"CompatibleIDs");
52     UNICODE_STRING HardwareIdU = RTL_CONSTANT_STRING(L"HardwareID");
53     UNICODE_STRING ServiceU = RTL_CONSTANT_STRING(L"Service");
54     UNICODE_STRING ClassGuidU = RTL_CONSTANT_STRING(L"ClassGUID");
55     PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
56     ULONG HidLength = 0, CidLength = 0, BufferLength;
57     PWCHAR IdBuffer, OriginalIdBuffer;
58 
59     /* Open the device instance key */
60     Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey);
61     if (Status != STATUS_SUCCESS)
62         return;
63 
64     Status = ZwQueryValueKey(InstanceKey,
65                              &HardwareIdU,
66                              KeyValuePartialInformation,
67                              NULL,
68                              0,
69                              &HidLength);
70     if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
71     {
72         ZwClose(InstanceKey);
73         return;
74     }
75 
76     Status = ZwQueryValueKey(InstanceKey,
77                              &CompatibleIdU,
78                              KeyValuePartialInformation,
79                              NULL,
80                              0,
81                              &CidLength);
82     if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
83     {
84         CidLength = 0;
85     }
86 
87     BufferLength = HidLength + CidLength;
88     BufferLength -= (((CidLength != 0) ? 2 : 1) * FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data));
89 
90     /* Allocate a buffer to hold data from both */
91     OriginalIdBuffer = IdBuffer = ExAllocatePool(PagedPool, BufferLength);
92     if (!IdBuffer)
93     {
94         ZwClose(InstanceKey);
95         return;
96     }
97 
98     /* Compute the buffer size */
99     if (HidLength > CidLength)
100         BufferLength = HidLength;
101     else
102         BufferLength = CidLength;
103 
104     PartialInfo = ExAllocatePool(PagedPool, BufferLength);
105     if (!PartialInfo)
106     {
107         ZwClose(InstanceKey);
108         ExFreePool(OriginalIdBuffer);
109         return;
110     }
111 
112     Status = ZwQueryValueKey(InstanceKey,
113                              &HardwareIdU,
114                              KeyValuePartialInformation,
115                              PartialInfo,
116                              HidLength,
117                              &HidLength);
118     if (Status != STATUS_SUCCESS)
119     {
120         ExFreePool(PartialInfo);
121         ExFreePool(OriginalIdBuffer);
122         ZwClose(InstanceKey);
123         return;
124     }
125 
126     /* Copy in HID info first (without 2nd terminating NULL if CID is present) */
127     HidLength = PartialInfo->DataLength - ((CidLength != 0) ? sizeof(WCHAR) : 0);
128     RtlCopyMemory(IdBuffer, PartialInfo->Data, HidLength);
129 
130     if (CidLength != 0)
131     {
132         Status = ZwQueryValueKey(InstanceKey,
133                                  &CompatibleIdU,
134                                  KeyValuePartialInformation,
135                                  PartialInfo,
136                                  CidLength,
137                                  &CidLength);
138         if (Status != STATUS_SUCCESS)
139         {
140             ExFreePool(PartialInfo);
141             ExFreePool(OriginalIdBuffer);
142             ZwClose(InstanceKey);
143             return;
144         }
145 
146         /* Copy CID next */
147         CidLength = PartialInfo->DataLength;
148         RtlCopyMemory(((PUCHAR)IdBuffer) + HidLength, PartialInfo->Data, CidLength);
149     }
150 
151     /* Free our temp buffer */
152     ExFreePool(PartialInfo);
153 
154     InitializeObjectAttributes(&ObjectAttributes,
155                                &CriticalDeviceKeyU,
156                                OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
157                                NULL,
158                                NULL);
159     Status = ZwOpenKey(&CriticalDeviceKey,
160                        KEY_ENUMERATE_SUB_KEYS,
161                        &ObjectAttributes);
162     if (!NT_SUCCESS(Status))
163     {
164         /* The critical device database doesn't exist because
165          * we're probably in 1st stage setup, but it's ok */
166         ExFreePool(OriginalIdBuffer);
167         ZwClose(InstanceKey);
168         return;
169     }
170 
171     while (*IdBuffer)
172     {
173         USHORT StringLength = (USHORT)wcslen(IdBuffer) + 1, Index;
174 
175         IopFixupDeviceId(IdBuffer);
176 
177         /* Look through all subkeys for a match */
178         for (Index = 0; TRUE; Index++)
179         {
180             ULONG NeededLength;
181             PKEY_BASIC_INFORMATION BasicInfo;
182 
183             Status = ZwEnumerateKey(CriticalDeviceKey,
184                                     Index,
185                                     KeyBasicInformation,
186                                     NULL,
187                                     0,
188                                     &NeededLength);
189             if (Status == STATUS_NO_MORE_ENTRIES)
190                 break;
191             else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
192             {
193                 UNICODE_STRING ChildIdNameU, RegKeyNameU;
194 
195                 BasicInfo = ExAllocatePool(PagedPool, NeededLength);
196                 if (!BasicInfo)
197                 {
198                     /* No memory */
199                     ExFreePool(OriginalIdBuffer);
200                     ZwClose(CriticalDeviceKey);
201                     ZwClose(InstanceKey);
202                     return;
203                 }
204 
205                 Status = ZwEnumerateKey(CriticalDeviceKey,
206                                         Index,
207                                         KeyBasicInformation,
208                                         BasicInfo,
209                                         NeededLength,
210                                         &NeededLength);
211                 if (Status != STATUS_SUCCESS)
212                 {
213                     /* This shouldn't happen */
214                     ExFreePool(BasicInfo);
215                     continue;
216                 }
217 
218                 ChildIdNameU.Buffer = IdBuffer;
219                 ChildIdNameU.MaximumLength = ChildIdNameU.Length = (StringLength - 1) * sizeof(WCHAR);
220                 RegKeyNameU.Buffer = BasicInfo->Name;
221                 RegKeyNameU.MaximumLength = RegKeyNameU.Length = (USHORT)BasicInfo->NameLength;
222 
223                 if (RtlEqualUnicodeString(&ChildIdNameU, &RegKeyNameU, TRUE))
224                 {
225                     HANDLE ChildKeyHandle;
226 
227                     InitializeObjectAttributes(&ObjectAttributes,
228                                                &ChildIdNameU,
229                                                OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
230                                                CriticalDeviceKey,
231                                                NULL);
232 
233                     Status = ZwOpenKey(&ChildKeyHandle,
234                                        KEY_QUERY_VALUE,
235                                        &ObjectAttributes);
236                     if (Status != STATUS_SUCCESS)
237                     {
238                         ExFreePool(BasicInfo);
239                         continue;
240                     }
241 
242                     /* Check if there's already a driver installed */
243                     Status = ZwQueryValueKey(InstanceKey,
244                                              &ClassGuidU,
245                                              KeyValuePartialInformation,
246                                              NULL,
247                                              0,
248                                              &NeededLength);
249                     if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
250                     {
251                         ExFreePool(BasicInfo);
252                         continue;
253                     }
254 
255                     Status = ZwQueryValueKey(ChildKeyHandle,
256                                              &ClassGuidU,
257                                              KeyValuePartialInformation,
258                                              NULL,
259                                              0,
260                                              &NeededLength);
261                     if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
262                     {
263                         ExFreePool(BasicInfo);
264                         continue;
265                     }
266 
267                     PartialInfo = ExAllocatePool(PagedPool, NeededLength);
268                     if (!PartialInfo)
269                     {
270                         ExFreePool(OriginalIdBuffer);
271                         ExFreePool(BasicInfo);
272                         ZwClose(InstanceKey);
273                         ZwClose(ChildKeyHandle);
274                         ZwClose(CriticalDeviceKey);
275                         return;
276                     }
277 
278                     /* Read ClassGUID entry in the CDDB */
279                     Status = ZwQueryValueKey(ChildKeyHandle,
280                                              &ClassGuidU,
281                                              KeyValuePartialInformation,
282                                              PartialInfo,
283                                              NeededLength,
284                                              &NeededLength);
285                     if (Status != STATUS_SUCCESS)
286                     {
287                         ExFreePool(BasicInfo);
288                         continue;
289                     }
290 
291                     /* Write it to the ENUM key */
292                     Status = ZwSetValueKey(InstanceKey,
293                                            &ClassGuidU,
294                                            0,
295                                            REG_SZ,
296                                            PartialInfo->Data,
297                                            PartialInfo->DataLength);
298                     if (Status != STATUS_SUCCESS)
299                     {
300                         ExFreePool(BasicInfo);
301                         ExFreePool(PartialInfo);
302                         ZwClose(ChildKeyHandle);
303                         continue;
304                     }
305 
306                     Status = ZwQueryValueKey(ChildKeyHandle,
307                                              &ServiceU,
308                                              KeyValuePartialInformation,
309                                              NULL,
310                                              0,
311                                              &NeededLength);
312                     if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
313                     {
314                         ExFreePool(PartialInfo);
315                         PartialInfo = ExAllocatePool(PagedPool, NeededLength);
316                         if (!PartialInfo)
317                         {
318                             ExFreePool(OriginalIdBuffer);
319                             ExFreePool(BasicInfo);
320                             ZwClose(InstanceKey);
321                             ZwClose(ChildKeyHandle);
322                             ZwClose(CriticalDeviceKey);
323                             return;
324                         }
325 
326                         /* Read the service entry from the CDDB */
327                         Status = ZwQueryValueKey(ChildKeyHandle,
328                                                  &ServiceU,
329                                                  KeyValuePartialInformation,
330                                                  PartialInfo,
331                                                  NeededLength,
332                                                  &NeededLength);
333                         if (Status != STATUS_SUCCESS)
334                         {
335                             ExFreePool(BasicInfo);
336                             ExFreePool(PartialInfo);
337                             ZwClose(ChildKeyHandle);
338                             continue;
339                         }
340 
341                         /* Write it to the ENUM key */
342                         Status = ZwSetValueKey(InstanceKey,
343                                                &ServiceU,
344                                                0,
345                                                REG_SZ,
346                                                PartialInfo->Data,
347                                                PartialInfo->DataLength);
348                         if (Status != STATUS_SUCCESS)
349                         {
350                             ExFreePool(BasicInfo);
351                             ExFreePool(PartialInfo);
352                             ZwClose(ChildKeyHandle);
353                             continue;
354                         }
355 
356                         DPRINT("Installed service '%S' for critical device '%wZ'\n", PartialInfo->Data, &ChildIdNameU);
357                     }
358                     else
359                     {
360                         DPRINT1("Installed NULL service for critical device '%wZ'\n", &ChildIdNameU);
361                     }
362 
363                     ExFreePool(OriginalIdBuffer);
364                     ExFreePool(PartialInfo);
365                     ExFreePool(BasicInfo);
366                     ZwClose(InstanceKey);
367                     ZwClose(ChildKeyHandle);
368                     ZwClose(CriticalDeviceKey);
369 
370                     /* That's it */
371                     return;
372                 }
373 
374                 ExFreePool(BasicInfo);
375             }
376             else
377             {
378                 /* Umm, not sure what happened here */
379                 continue;
380             }
381         }
382 
383         /* Advance to the next ID */
384         IdBuffer += StringLength;
385     }
386 
387     ExFreePool(OriginalIdBuffer);
388     ZwClose(InstanceKey);
389     ZwClose(CriticalDeviceKey);
390 }
391 
392 NTSTATUS
393 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
394 {
395     KIRQL OldIrql;
396 
397     if (PopSystemPowerDeviceNode)
398     {
399         KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
400         *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject;
401         KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
402 
403         return STATUS_SUCCESS;
404     }
405 
406     return STATUS_UNSUCCESSFUL;
407 }
408 
409 USHORT
410 NTAPI
411 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
412 {
413     USHORT i = 0, FoundIndex = 0xFFFF;
414     ULONG NewSize;
415     PVOID NewList;
416 
417     /* Acquire the lock */
418     ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
419 
420     /* Loop all entries */
421     while (i < PnpBusTypeGuidList->GuidCount)
422     {
423          /* Try to find a match */
424          if (RtlCompareMemory(BusTypeGuid,
425                               &PnpBusTypeGuidList->Guids[i],
426                               sizeof(GUID)) == sizeof(GUID))
427          {
428               /* Found it */
429               FoundIndex = i;
430               goto Quickie;
431          }
432          i++;
433     }
434 
435     /* Check if we have to grow the list */
436     if (PnpBusTypeGuidList->GuidCount)
437     {
438         /* Calculate the new size */
439         NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) +
440                  (sizeof(GUID) * PnpBusTypeGuidList->GuidCount);
441 
442         /* Allocate the new copy */
443         NewList = ExAllocatePool(PagedPool, NewSize);
444 
445         if (!NewList)
446         {
447             /* Fail */
448             ExFreePool(PnpBusTypeGuidList);
449             goto Quickie;
450         }
451 
452         /* Now copy them, decrease the size too */
453         NewSize -= sizeof(GUID);
454         RtlCopyMemory(NewList, PnpBusTypeGuidList, NewSize);
455 
456         /* Free the old list */
457         ExFreePool(PnpBusTypeGuidList);
458 
459         /* Use the new buffer */
460         PnpBusTypeGuidList = NewList;
461     }
462 
463     /* Copy the new GUID */
464     RtlCopyMemory(&PnpBusTypeGuidList->Guids[PnpBusTypeGuidList->GuidCount],
465                   BusTypeGuid,
466                   sizeof(GUID));
467 
468     /* The new entry is the index */
469     FoundIndex = (USHORT)PnpBusTypeGuidList->GuidCount;
470     PnpBusTypeGuidList->GuidCount++;
471 
472 Quickie:
473     ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
474     return FoundIndex;
475 }
476 
477 NTSTATUS
478 NTAPI
479 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject,
480                   IN OUT PIO_STATUS_BLOCK IoStatusBlock,
481                   IN UCHAR MinorFunction,
482                   IN PIO_STACK_LOCATION Stack OPTIONAL)
483 {
484     IO_STACK_LOCATION IoStackLocation;
485 
486     /* Fill out the stack information */
487     RtlZeroMemory(&IoStackLocation, sizeof(IO_STACK_LOCATION));
488     IoStackLocation.MajorFunction = IRP_MJ_PNP;
489     IoStackLocation.MinorFunction = MinorFunction;
490     if (Stack)
491     {
492         /* Copy the rest */
493         RtlCopyMemory(&IoStackLocation.Parameters,
494                       &Stack->Parameters,
495                       sizeof(Stack->Parameters));
496     }
497 
498     /* Do the PnP call */
499     IoStatusBlock->Status = IopSynchronousCall(DeviceObject,
500                                                &IoStackLocation,
501                                                (PVOID)&IoStatusBlock->Information);
502     return IoStatusBlock->Status;
503 }
504 
505 /*
506  * IopCreateDeviceKeyPath
507  *
508  * Creates a registry key
509  *
510  * Parameters
511  *    RegistryPath
512  *        Name of the key to be created.
513  *    Handle
514  *        Handle to the newly created key
515  *
516  * Remarks
517  *     This method can create nested trees, so parent of RegistryPath can
518  *     be not existant, and will be created if needed.
519  */
520 NTSTATUS
521 NTAPI
522 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
523                        IN ULONG CreateOptions,
524                        OUT PHANDLE Handle)
525 {
526     UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
527     HANDLE hParent = NULL, hKey;
528     OBJECT_ATTRIBUTES ObjectAttributes;
529     UNICODE_STRING KeyName;
530     PCWSTR Current, Last;
531     USHORT Length;
532     NTSTATUS Status;
533 
534     /* Assume failure */
535     *Handle = NULL;
536 
537     /* Open root key for device instances */
538     Status = IopOpenRegistryKeyEx(&hParent, NULL, &EnumU, KEY_CREATE_SUB_KEY);
539     if (!NT_SUCCESS(Status))
540     {
541         DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
542         return Status;
543     }
544 
545     Current = KeyName.Buffer = RegistryPath->Buffer;
546     Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)];
547 
548     /* Go up to the end of the string */
549     while (Current <= Last)
550     {
551         if (Current != Last && *Current != L'\\')
552         {
553             /* Not the end of the string and not a separator */
554             Current++;
555             continue;
556         }
557 
558         /* Prepare relative key name */
559         Length = (USHORT)((ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer);
560         KeyName.MaximumLength = KeyName.Length = Length;
561         DPRINT("Create '%wZ'\n", &KeyName);
562 
563         /* Open key */
564         InitializeObjectAttributes(&ObjectAttributes,
565                                    &KeyName,
566                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
567                                    hParent,
568                                    NULL);
569         Status = ZwCreateKey(&hKey,
570                              Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY,
571                              &ObjectAttributes,
572                              0,
573                              NULL,
574                              CreateOptions,
575                              NULL);
576 
577         /* Close parent key handle, we don't need it anymore */
578         if (hParent)
579             ZwClose(hParent);
580 
581         /* Key opening/creating failed? */
582         if (!NT_SUCCESS(Status))
583         {
584             DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status);
585             return Status;
586         }
587 
588         /* Check if it is the end of the string */
589         if (Current == Last)
590         {
591             /* Yes, return success */
592             *Handle = hKey;
593             return STATUS_SUCCESS;
594         }
595 
596         /* Start with this new parent key */
597         hParent = hKey;
598         Current++;
599         KeyName.Buffer = (PWSTR)Current;
600     }
601 
602     return STATUS_UNSUCCESSFUL;
603 }
604 
605 NTSTATUS
606 IopSetDeviceInstanceData(HANDLE InstanceKey,
607                          PDEVICE_NODE DeviceNode)
608 {
609     OBJECT_ATTRIBUTES ObjectAttributes;
610     UNICODE_STRING KeyName;
611     HANDLE LogConfKey, ControlKey, DeviceParamsKey;
612     ULONG ResCount;
613     ULONG ResultLength;
614     NTSTATUS Status;
615 
616     DPRINT("IopSetDeviceInstanceData() called\n");
617 
618     /* Create the 'LogConf' key */
619     RtlInitUnicodeString(&KeyName, L"LogConf");
620     InitializeObjectAttributes(&ObjectAttributes,
621                                &KeyName,
622                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
623                                InstanceKey,
624                                NULL);
625     Status = ZwCreateKey(&LogConfKey,
626                          KEY_ALL_ACCESS,
627                          &ObjectAttributes,
628                          0,
629                          NULL,
630                          // FIXME? In r53694 it was silently turned from non-volatile into this,
631                          // without any extra warning. Is this still needed??
632                          REG_OPTION_VOLATILE,
633                          NULL);
634     if (NT_SUCCESS(Status))
635     {
636         /* Set 'BootConfig' value */
637         if (DeviceNode->BootResources != NULL)
638         {
639             ResCount = DeviceNode->BootResources->Count;
640             if (ResCount != 0)
641             {
642                 RtlInitUnicodeString(&KeyName, L"BootConfig");
643                 Status = ZwSetValueKey(LogConfKey,
644                                        &KeyName,
645                                        0,
646                                        REG_RESOURCE_LIST,
647                                        DeviceNode->BootResources,
648                                        PnpDetermineResourceListSize(DeviceNode->BootResources));
649             }
650         }
651 
652         /* Set 'BasicConfigVector' value */
653         if (DeviceNode->ResourceRequirements != NULL &&
654             DeviceNode->ResourceRequirements->ListSize != 0)
655         {
656             RtlInitUnicodeString(&KeyName, L"BasicConfigVector");
657             Status = ZwSetValueKey(LogConfKey,
658                                    &KeyName,
659                                    0,
660                                    REG_RESOURCE_REQUIREMENTS_LIST,
661                                    DeviceNode->ResourceRequirements,
662                                    DeviceNode->ResourceRequirements->ListSize);
663         }
664 
665         ZwClose(LogConfKey);
666     }
667 
668     /* Set the 'ConfigFlags' value */
669     RtlInitUnicodeString(&KeyName, L"ConfigFlags");
670     Status = ZwQueryValueKey(InstanceKey,
671                              &KeyName,
672                              KeyValueBasicInformation,
673                              NULL,
674                              0,
675                              &ResultLength);
676     if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
677     {
678         /* Write the default value */
679         ULONG DefaultConfigFlags = 0;
680         Status = ZwSetValueKey(InstanceKey,
681                                &KeyName,
682                                0,
683                                REG_DWORD,
684                                &DefaultConfigFlags,
685                                sizeof(DefaultConfigFlags));
686     }
687 
688     /* Create the 'Control' key */
689     RtlInitUnicodeString(&KeyName, L"Control");
690     InitializeObjectAttributes(&ObjectAttributes,
691                                &KeyName,
692                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
693                                InstanceKey,
694                                NULL);
695     Status = ZwCreateKey(&ControlKey,
696                          0,
697                          &ObjectAttributes,
698                          0,
699                          NULL,
700                          REG_OPTION_VOLATILE,
701                          NULL);
702     if (NT_SUCCESS(Status))
703         ZwClose(ControlKey);
704 
705     /* Create the 'Device Parameters' key and set the 'FirmwareIdentified' value for all ACPI-enumerated devices */
706     if (_wcsnicmp(DeviceNode->InstancePath.Buffer, L"ACPI\\", 5) == 0)
707     {
708         RtlInitUnicodeString(&KeyName, L"Device Parameters");
709         InitializeObjectAttributes(&ObjectAttributes,
710                                    &KeyName,
711                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
712                                    InstanceKey,
713                                    NULL);
714         Status = ZwCreateKey(&DeviceParamsKey,
715                              0,
716                              &ObjectAttributes,
717                              0,
718                              NULL,
719                              REG_OPTION_NON_VOLATILE,
720                              NULL);
721         if (NT_SUCCESS(Status))
722         {
723             ULONG FirmwareIdentified = 1;
724             RtlInitUnicodeString(&KeyName, L"FirmwareIdentified");
725             Status = ZwSetValueKey(DeviceParamsKey,
726                                    &KeyName,
727                                    0,
728                                    REG_DWORD,
729                                    &FirmwareIdentified,
730                                    sizeof(FirmwareIdentified));
731 
732             ZwClose(DeviceParamsKey);
733         }
734     }
735 
736     DPRINT("IopSetDeviceInstanceData() done\n");
737 
738     return Status;
739 }
740 
741 /*
742  * IopGetParentIdPrefix
743  *
744  * Retrieve (or create) a string which identifies a device.
745  *
746  * Parameters
747  *    DeviceNode
748  *        Pointer to device node.
749  *    ParentIdPrefix
750  *        Pointer to the string where is returned the parent node identifier
751  *
752  * Remarks
753  *     If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
754  *     valid and its Buffer field is NULL-terminated. The caller needs to
755  *     to free the string with RtlFreeUnicodeString when it is no longer
756  *     needed.
757  */
758 
759 NTSTATUS
760 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
761                      PUNICODE_STRING ParentIdPrefix)
762 {
763     const UNICODE_STRING EnumKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
764     ULONG KeyNameBufferLength;
765     PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
766     UNICODE_STRING KeyName = {0, 0, NULL};
767     UNICODE_STRING KeyValue;
768     UNICODE_STRING ValueName;
769     HANDLE hKey = NULL;
770     ULONG crc32;
771     NTSTATUS Status;
772 
773     /* HACK: As long as some devices have a NULL device
774      * instance path, the following test is required :(
775      */
776     if (DeviceNode->Parent->InstancePath.Length == 0)
777     {
778         DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
779                 &DeviceNode->InstancePath);
780         return STATUS_UNSUCCESSFUL;
781     }
782 
783     /* 1. Try to retrieve ParentIdPrefix from registry */
784     KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(L"12345678&12345678");
785     ParentIdPrefixInformation = ExAllocatePoolWithTag(PagedPool,
786                                                       KeyNameBufferLength + sizeof(UNICODE_NULL),
787                                                       TAG_IO);
788     if (!ParentIdPrefixInformation)
789     {
790         return STATUS_INSUFFICIENT_RESOURCES;
791     }
792 
793     KeyName.Length = 0;
794     KeyName.MaximumLength = EnumKeyPath.Length +
795                             DeviceNode->Parent->InstancePath.Length +
796                             sizeof(UNICODE_NULL);
797     KeyName.Buffer = ExAllocatePoolWithTag(PagedPool,
798                                            KeyName.MaximumLength,
799                                            TAG_IO);
800     if (!KeyName.Buffer)
801     {
802         Status = STATUS_INSUFFICIENT_RESOURCES;
803         goto cleanup;
804     }
805 
806     RtlCopyUnicodeString(&KeyName, &EnumKeyPath);
807     RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath);
808 
809     Status = IopOpenRegistryKeyEx(&hKey, NULL, &KeyName, KEY_QUERY_VALUE | KEY_SET_VALUE);
810     if (!NT_SUCCESS(Status))
811     {
812         goto cleanup;
813     }
814     RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
815     Status = ZwQueryValueKey(hKey,
816                              &ValueName,
817                              KeyValuePartialInformation,
818                              ParentIdPrefixInformation,
819                              KeyNameBufferLength,
820                              &KeyNameBufferLength);
821     if (NT_SUCCESS(Status))
822     {
823         if (ParentIdPrefixInformation->Type != REG_SZ)
824         {
825             Status = STATUS_UNSUCCESSFUL;
826         }
827         else
828         {
829             KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
830             KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
831             KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
832             ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
833         }
834         goto cleanup;
835     }
836     if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
837     {
838         /* FIXME how do we get here and why is ParentIdPrefixInformation valid? */
839         KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
840         KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
841         KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
842         ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
843         goto cleanup;
844     }
845 
846     /* 2. Create the ParentIdPrefix value */
847     crc32 = RtlComputeCrc32(0,
848                             (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
849                             DeviceNode->Parent->InstancePath.Length);
850 
851     RtlStringCbPrintfW((PWSTR)ParentIdPrefixInformation,
852                        KeyNameBufferLength,
853                        L"%lx&%lx",
854                        DeviceNode->Parent->Level,
855                        crc32);
856     RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation);
857 
858     /* 3. Try to write the ParentIdPrefix to registry */
859     Status = ZwSetValueKey(hKey,
860                            &ValueName,
861                            0,
862                            REG_SZ,
863                            KeyValue.Buffer,
864                            ((ULONG)wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
865 
866 cleanup:
867     if (NT_SUCCESS(Status))
868     {
869         /* Duplicate the string to return it */
870         Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
871                                            &KeyValue,
872                                            ParentIdPrefix);
873     }
874     ExFreePoolWithTag(ParentIdPrefixInformation, TAG_IO);
875     RtlFreeUnicodeString(&KeyName);
876     if (hKey != NULL)
877     {
878         ZwClose(hKey);
879     }
880     return Status;
881 }
882 
883 NTSTATUS
884 NTAPI
885 IopOpenRegistryKeyEx(PHANDLE KeyHandle,
886                      HANDLE ParentKey,
887                      PUNICODE_STRING Name,
888                      ACCESS_MASK DesiredAccess)
889 {
890     OBJECT_ATTRIBUTES ObjectAttributes;
891     NTSTATUS Status;
892 
893     PAGED_CODE();
894 
895     *KeyHandle = NULL;
896 
897     InitializeObjectAttributes(&ObjectAttributes,
898         Name,
899         OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
900         ParentKey,
901         NULL);
902 
903     Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
904 
905     return Status;
906 }
907 
908 NTSTATUS
909 NTAPI
910 IopCreateRegistryKeyEx(OUT PHANDLE Handle,
911                        IN HANDLE RootHandle OPTIONAL,
912                        IN PUNICODE_STRING KeyName,
913                        IN ACCESS_MASK DesiredAccess,
914                        IN ULONG CreateOptions,
915                        OUT PULONG Disposition OPTIONAL)
916 {
917     OBJECT_ATTRIBUTES ObjectAttributes;
918     ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0;
919     USHORT Length;
920     HANDLE HandleArray[2];
921     BOOLEAN Recursing = TRUE;
922     PWCHAR pp, p, p1;
923     UNICODE_STRING KeyString;
924     NTSTATUS Status = STATUS_SUCCESS;
925     PAGED_CODE();
926 
927     /* P1 is start, pp is end */
928     p1 = KeyName->Buffer;
929     pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length);
930 
931     /* Create the target key */
932     InitializeObjectAttributes(&ObjectAttributes,
933                                KeyName,
934                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
935                                RootHandle,
936                                NULL);
937     Status = ZwCreateKey(&HandleArray[i],
938                          DesiredAccess,
939                          &ObjectAttributes,
940                          0,
941                          NULL,
942                          CreateOptions,
943                          &KeyDisposition);
944 
945     /* Now we check if this failed */
946     if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle))
947     {
948         /* Target key failed, so we'll need to create its parent. Setup array */
949         HandleArray[0] = NULL;
950         HandleArray[1] = RootHandle;
951 
952         /* Keep recursing for each missing parent */
953         while (Recursing)
954         {
955             /* And if we're deep enough, close the last handle */
956             if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
957 
958             /* We're setup to ping-pong between the two handle array entries */
959             RootHandleIndex = i;
960             i = (i + 1) & 1;
961 
962             /* Clear the one we're attempting to open now */
963             HandleArray[i] = NULL;
964 
965             /* Process the parent key name */
966             for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++);
967             Length = (USHORT)(p - p1) * sizeof(WCHAR);
968 
969             /* Is there a parent name? */
970             if (Length)
971             {
972                 /* Build the unicode string for it */
973                 KeyString.Buffer = p1;
974                 KeyString.Length = KeyString.MaximumLength = Length;
975 
976                 /* Now try opening the parent */
977                 InitializeObjectAttributes(&ObjectAttributes,
978                                            &KeyString,
979                                            OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
980                                            HandleArray[RootHandleIndex],
981                                            NULL);
982                 Status = ZwCreateKey(&HandleArray[i],
983                                      DesiredAccess,
984                                      &ObjectAttributes,
985                                      0,
986                                      NULL,
987                                      CreateOptions,
988                                      &KeyDisposition);
989                 if (NT_SUCCESS(Status))
990                 {
991                     /* It worked, we have one more handle */
992                     NestedCloseLevel++;
993                 }
994                 else
995                 {
996                     /* Parent key creation failed, abandon loop */
997                     Recursing = FALSE;
998                     continue;
999                 }
1000             }
1001             else
1002             {
1003                 /* We don't have a parent name, probably corrupted key name */
1004                 Status = STATUS_INVALID_PARAMETER;
1005                 Recursing = FALSE;
1006                 continue;
1007             }
1008 
1009             /* Now see if there's more parents to create */
1010             p1 = p + 1;
1011             if ((p == pp) || (p1 == pp))
1012             {
1013                 /* We're done, hopefully successfully, so stop */
1014                 Recursing = FALSE;
1015             }
1016         }
1017 
1018         /* Outer loop check for handle nesting that requires closing the top handle */
1019         if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
1020     }
1021 
1022     /* Check if we broke out of the loop due to success */
1023     if (NT_SUCCESS(Status))
1024     {
1025         /* Return the target handle (we closed all the parent ones) and disposition */
1026         *Handle = HandleArray[i];
1027         if (Disposition) *Disposition = KeyDisposition;
1028     }
1029 
1030     /* Return the success state */
1031     return Status;
1032 }
1033 
1034 NTSTATUS
1035 NTAPI
1036 IopGetRegistryValue(IN HANDLE Handle,
1037                     IN PWSTR ValueName,
1038                     OUT PKEY_VALUE_FULL_INFORMATION *Information)
1039 {
1040     UNICODE_STRING ValueString;
1041     NTSTATUS Status;
1042     PKEY_VALUE_FULL_INFORMATION FullInformation;
1043     ULONG Size;
1044     PAGED_CODE();
1045 
1046     RtlInitUnicodeString(&ValueString, ValueName);
1047 
1048     Status = ZwQueryValueKey(Handle,
1049                              &ValueString,
1050                              KeyValueFullInformation,
1051                              NULL,
1052                              0,
1053                              &Size);
1054     if ((Status != STATUS_BUFFER_OVERFLOW) &&
1055         (Status != STATUS_BUFFER_TOO_SMALL))
1056     {
1057         return Status;
1058     }
1059 
1060     FullInformation = ExAllocatePool(NonPagedPool, Size);
1061     if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES;
1062 
1063     Status = ZwQueryValueKey(Handle,
1064                              &ValueString,
1065                              KeyValueFullInformation,
1066                              FullInformation,
1067                              Size,
1068                              &Size);
1069     if (!NT_SUCCESS(Status))
1070     {
1071         ExFreePool(FullInformation);
1072         return Status;
1073     }
1074 
1075     *Information = FullInformation;
1076     return STATUS_SUCCESS;
1077 }
1078 
1079 RTL_GENERIC_COMPARE_RESULTS
1080 NTAPI
1081 PiCompareInstancePath(IN PRTL_AVL_TABLE Table,
1082                       IN PVOID FirstStruct,
1083                       IN PVOID SecondStruct)
1084 {
1085     /* FIXME: TODO */
1086     ASSERT(FALSE);
1087     return 0;
1088 }
1089 
1090 //
1091 //  The allocation function is called by the generic table package whenever
1092 //  it needs to allocate memory for the table.
1093 //
1094 
1095 PVOID
1096 NTAPI
1097 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table,
1098                             IN CLONG ByteSize)
1099 {
1100     /* FIXME: TODO */
1101     ASSERT(FALSE);
1102     return NULL;
1103 }
1104 
1105 VOID
1106 NTAPI
1107 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table,
1108                         IN PVOID Buffer)
1109 {
1110     /* FIXME: TODO */
1111     ASSERT(FALSE);
1112 }
1113 
1114 VOID
1115 NTAPI
1116 PpInitializeDeviceReferenceTable(VOID)
1117 {
1118     /* Setup the guarded mutex and AVL table */
1119     KeInitializeGuardedMutex(&PpDeviceReferenceTableLock);
1120     RtlInitializeGenericTableAvl(
1121         &PpDeviceReferenceTable,
1122         (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath,
1123         (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry,
1124         (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry,
1125         NULL);
1126 }
1127 
1128 BOOLEAN
1129 NTAPI
1130 PiInitPhase0(VOID)
1131 {
1132     /* Initialize the resource when accessing device registry data */
1133     ExInitializeResourceLite(&PpRegistryDeviceResource);
1134 
1135     /* Setup the device reference AVL table */
1136     PpInitializeDeviceReferenceTable();
1137     return TRUE;
1138 }
1139 
1140 BOOLEAN
1141 NTAPI
1142 PpInitSystem(VOID)
1143 {
1144     /* Check the initialization phase */
1145     switch (ExpInitializationPhase)
1146     {
1147     case 0:
1148 
1149         /* Do Phase 0 */
1150         return PiInitPhase0();
1151 
1152     case 1:
1153 
1154         /* Do Phase 1 */
1155         return TRUE;
1156         //return PiInitPhase1();
1157 
1158     default:
1159 
1160         /* Don't know any other phase! Bugcheck! */
1161         KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
1162         return FALSE;
1163     }
1164 }
1165 
1166 /* PUBLIC FUNCTIONS **********************************************************/
1167 
1168 NTSTATUS
1169 NTAPI
1170 PnpBusTypeGuidGet(IN USHORT Index,
1171                   IN LPGUID BusTypeGuid)
1172 {
1173     NTSTATUS Status = STATUS_SUCCESS;
1174 
1175     /* Acquire the lock */
1176     ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
1177 
1178     /* Validate size */
1179     if (Index < PnpBusTypeGuidList->GuidCount)
1180     {
1181         /* Copy the data */
1182         RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID));
1183     }
1184     else
1185     {
1186         /* Failure path */
1187         Status = STATUS_OBJECT_NAME_NOT_FOUND;
1188     }
1189 
1190     /* Release lock and return status */
1191     ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
1192     return Status;
1193 }
1194 
1195 NTSTATUS
1196 NTAPI
1197 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject,
1198                                 IN PHANDLE DeviceInstanceHandle,
1199                                 IN ACCESS_MASK DesiredAccess)
1200 {
1201     NTSTATUS Status;
1202     HANDLE KeyHandle;
1203     PDEVICE_NODE DeviceNode;
1204     UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
1205     PAGED_CODE();
1206 
1207     /* Open the enum key */
1208     Status = IopOpenRegistryKeyEx(&KeyHandle,
1209                                   NULL,
1210                                   &KeyName,
1211                                   KEY_READ);
1212     if (!NT_SUCCESS(Status)) return Status;
1213 
1214     /* Make sure we have an instance path */
1215     DeviceNode = IopGetDeviceNode(DeviceObject);
1216     if ((DeviceNode) && (DeviceNode->InstancePath.Length))
1217     {
1218         /* Get the instance key */
1219         Status = IopOpenRegistryKeyEx(DeviceInstanceHandle,
1220                                       KeyHandle,
1221                                       &DeviceNode->InstancePath,
1222                                       DesiredAccess);
1223     }
1224     else
1225     {
1226         /* Fail */
1227         Status = STATUS_INVALID_DEVICE_REQUEST;
1228     }
1229 
1230     /* Close the handle and return status */
1231     ZwClose(KeyHandle);
1232     return Status;
1233 }
1234 
1235 ULONG
1236 NTAPI
1237 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList)
1238 {
1239     ULONG FinalSize, PartialSize, EntrySize, i, j;
1240     PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
1241     PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
1242 
1243     /* If we don't have one, that's easy */
1244     if (!ResourceList) return 0;
1245 
1246     /* Start with the minimum size possible */
1247     FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
1248 
1249     /* Loop each full descriptor */
1250     FullDescriptor = ResourceList->List;
1251     for (i = 0; i < ResourceList->Count; i++)
1252     {
1253         /* Start with the minimum size possible */
1254         PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
1255         FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors);
1256 
1257         /* Loop each partial descriptor */
1258         PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors;
1259         for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++)
1260         {
1261             /* Start with the minimum size possible */
1262             EntrySize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1263 
1264             /* Check if there is extra data */
1265             if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
1266             {
1267                 /* Add that data */
1268                 EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize;
1269             }
1270 
1271             /* The size of partial descriptors is bigger */
1272             PartialSize += EntrySize;
1273 
1274             /* Go to the next partial descriptor */
1275             PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize);
1276         }
1277 
1278         /* The size of full descriptors is bigger */
1279         FinalSize += PartialSize;
1280 
1281         /* Go to the next full descriptor */
1282         FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize);
1283     }
1284 
1285     /* Return the final size */
1286     return FinalSize;
1287 }
1288 
1289 NTSTATUS
1290 NTAPI
1291 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject,
1292                             IN ULONG ValueType,
1293                             IN PWSTR ValueName,
1294                             IN PWSTR KeyName,
1295                             OUT PVOID Buffer,
1296                             IN PULONG BufferLength)
1297 {
1298     NTSTATUS Status;
1299     HANDLE KeyHandle, SubHandle;
1300     UNICODE_STRING KeyString;
1301     PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL;
1302     ULONG Length;
1303     PAGED_CODE();
1304 
1305     /* Find the instance key */
1306     Status = PnpDeviceObjectToDeviceInstance(DeviceObject, &KeyHandle, KEY_READ);
1307     if (NT_SUCCESS(Status))
1308     {
1309         /* Check for name given by caller */
1310         if (KeyName)
1311         {
1312             /* Open this key */
1313             RtlInitUnicodeString(&KeyString, KeyName);
1314             Status = IopOpenRegistryKeyEx(&SubHandle,
1315                                           KeyHandle,
1316                                           &KeyString,
1317                                           KEY_READ);
1318             if (NT_SUCCESS(Status))
1319             {
1320                 /* And use this handle instead */
1321                 ZwClose(KeyHandle);
1322                 KeyHandle = SubHandle;
1323             }
1324         }
1325 
1326         /* Check if sub-key handle succeeded (or no-op if no key name given) */
1327         if (NT_SUCCESS(Status))
1328         {
1329             /* Now get the size of the property */
1330             Status = IopGetRegistryValue(KeyHandle,
1331                                          ValueName,
1332                                          &KeyValueInfo);
1333         }
1334 
1335         /* Close the key */
1336         ZwClose(KeyHandle);
1337     }
1338 
1339     /* Fail if any of the registry operations failed */
1340     if (!NT_SUCCESS(Status)) return Status;
1341 
1342     /* Check how much data we have to copy */
1343     Length = KeyValueInfo->DataLength;
1344     if (*BufferLength >= Length)
1345     {
1346         /* Check for a match in the value type */
1347         if (KeyValueInfo->Type == ValueType)
1348         {
1349             /* Copy the data */
1350             RtlCopyMemory(Buffer,
1351                           (PVOID)((ULONG_PTR)KeyValueInfo +
1352                           KeyValueInfo->DataOffset),
1353                           Length);
1354         }
1355         else
1356         {
1357             /* Invalid registry property type, fail */
1358            Status = STATUS_INVALID_PARAMETER_2;
1359         }
1360     }
1361     else
1362     {
1363         /* Buffer is too small to hold data */
1364         Status = STATUS_BUFFER_TOO_SMALL;
1365     }
1366 
1367     /* Return the required buffer length, free the buffer, and return status */
1368     *BufferLength = Length;
1369     ExFreePool(KeyValueInfo);
1370     return Status;
1371 }
1372 
1373 #define PIP_RETURN_DATA(x, y)   {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
1374 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
1375 #define PIP_UNIMPLEMENTED()     {UNIMPLEMENTED_DBGBREAK(); break;}
1376 
1377 /*
1378  * @implemented
1379  */
1380 NTSTATUS
1381 NTAPI
1382 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
1383                     IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
1384                     IN ULONG BufferLength,
1385                     OUT PVOID PropertyBuffer,
1386                     OUT PULONG ResultLength)
1387 {
1388     PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
1389     DEVICE_CAPABILITIES DeviceCaps;
1390     ULONG ReturnLength = 0, Length = 0, ValueType;
1391     PWCHAR ValueName = NULL, EnumeratorNameEnd, DeviceInstanceName;
1392     PVOID Data = NULL;
1393     NTSTATUS Status = STATUS_BUFFER_TOO_SMALL;
1394     GUID BusTypeGuid;
1395     POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
1396     BOOLEAN NullTerminate = FALSE;
1397     DEVICE_REMOVAL_POLICY Policy;
1398 
1399     DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
1400 
1401     /* Assume failure */
1402     *ResultLength = 0;
1403 
1404     /* Only PDOs can call this */
1405     if (!DeviceNode) return STATUS_INVALID_DEVICE_REQUEST;
1406 
1407     /* Handle all properties */
1408     switch (DeviceProperty)
1409     {
1410         case DevicePropertyBusTypeGuid:
1411 
1412             /* Get the GUID from the internal cache */
1413             Status = PnpBusTypeGuidGet(DeviceNode->ChildBusTypeIndex, &BusTypeGuid);
1414             if (!NT_SUCCESS(Status)) return Status;
1415 
1416             /* This is the format of the returned data */
1417             PIP_RETURN_DATA(sizeof(GUID), &BusTypeGuid);
1418 
1419         case DevicePropertyLegacyBusType:
1420 
1421             /* Validate correct interface type */
1422             if (DeviceNode->ChildInterfaceType == InterfaceTypeUndefined)
1423                 return STATUS_OBJECT_NAME_NOT_FOUND;
1424 
1425             /* This is the format of the returned data */
1426             PIP_RETURN_DATA(sizeof(INTERFACE_TYPE), &DeviceNode->ChildInterfaceType);
1427 
1428         case DevicePropertyBusNumber:
1429 
1430             /* Validate correct bus number */
1431             if ((DeviceNode->ChildBusNumber & 0x80000000) == 0x80000000)
1432                 return STATUS_OBJECT_NAME_NOT_FOUND;
1433 
1434             /* This is the format of the returned data */
1435             PIP_RETURN_DATA(sizeof(ULONG), &DeviceNode->ChildBusNumber);
1436 
1437         case DevicePropertyEnumeratorName:
1438 
1439             /* Get the instance path */
1440             DeviceInstanceName = DeviceNode->InstancePath.Buffer;
1441 
1442             /* Sanity checks */
1443             ASSERT((BufferLength & 1) == 0);
1444             ASSERT(DeviceInstanceName != NULL);
1445 
1446             /* Get the name from the path */
1447             EnumeratorNameEnd = wcschr(DeviceInstanceName, OBJ_NAME_PATH_SEPARATOR);
1448             ASSERT(EnumeratorNameEnd);
1449 
1450             /* This string needs to be NULL-terminated */
1451             NullTerminate = TRUE;
1452 
1453             /* This is the format of the returned data */
1454             PIP_RETURN_DATA((ULONG)(EnumeratorNameEnd - DeviceInstanceName) * sizeof(WCHAR),
1455                             DeviceInstanceName);
1456 
1457         case DevicePropertyAddress:
1458 
1459             /* Query the device caps */
1460             Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps);
1461             if (!NT_SUCCESS(Status) || (DeviceCaps.Address == MAXULONG))
1462                 return STATUS_OBJECT_NAME_NOT_FOUND;
1463 
1464             /* This is the format of the returned data */
1465             PIP_RETURN_DATA(sizeof(ULONG), &DeviceCaps.Address);
1466 
1467         case DevicePropertyBootConfigurationTranslated:
1468 
1469             /* Validate we have resources */
1470             if (!DeviceNode->BootResources)
1471 //            if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
1472             {
1473                 /* No resources will still fake success, but with 0 bytes */
1474                 *ResultLength = 0;
1475                 return STATUS_SUCCESS;
1476             }
1477 
1478             /* This is the format of the returned data */
1479             PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode->BootResources), // FIXFIX: Should use BootResourcesTranslated
1480                             DeviceNode->BootResources); // FIXFIX: Should use BootResourcesTranslated
1481 
1482         case DevicePropertyPhysicalDeviceObjectName:
1483 
1484             /* Sanity check for Unicode-sized string */
1485             ASSERT((BufferLength & 1) == 0);
1486 
1487             /* Allocate name buffer */
1488             Length = BufferLength + sizeof(OBJECT_NAME_INFORMATION);
1489             ObjectNameInfo = ExAllocatePool(PagedPool, Length);
1490             if (!ObjectNameInfo) return STATUS_INSUFFICIENT_RESOURCES;
1491 
1492             /* Query the PDO name */
1493             Status = ObQueryNameString(DeviceObject,
1494                                        ObjectNameInfo,
1495                                        Length,
1496                                        ResultLength);
1497             if (Status == STATUS_INFO_LENGTH_MISMATCH)
1498             {
1499                 /* It's up to the caller to try again */
1500                 Status = STATUS_BUFFER_TOO_SMALL;
1501             }
1502 
1503             /* This string needs to be NULL-terminated */
1504             NullTerminate = TRUE;
1505 
1506             /* Return if successful */
1507             if (NT_SUCCESS(Status)) PIP_RETURN_DATA(ObjectNameInfo->Name.Length,
1508                                                     ObjectNameInfo->Name.Buffer);
1509 
1510             /* Let the caller know how big the name is */
1511             *ResultLength -= sizeof(OBJECT_NAME_INFORMATION);
1512             break;
1513 
1514         case DevicePropertyRemovalPolicy:
1515 
1516             Policy = DeviceNode->RemovalPolicy;
1517             PIP_RETURN_DATA(sizeof(Policy), &Policy);
1518 
1519         /* Handle the registry-based properties */
1520         case DevicePropertyUINumber:
1521             PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER, REG_DWORD);
1522         case DevicePropertyLocationInformation:
1523             PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION, REG_SZ);
1524         case DevicePropertyDeviceDescription:
1525             PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC, REG_SZ);
1526         case DevicePropertyHardwareID:
1527             PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID, REG_MULTI_SZ);
1528         case DevicePropertyCompatibleIDs:
1529             PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS, REG_MULTI_SZ);
1530         case DevicePropertyBootConfiguration:
1531             PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG, REG_RESOURCE_LIST);
1532         case DevicePropertyClassName:
1533             PIP_REGISTRY_DATA(REGSTR_VAL_CLASS, REG_SZ);
1534         case DevicePropertyClassGuid:
1535             PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID, REG_SZ);
1536         case DevicePropertyDriverKeyName:
1537             PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER, REG_SZ);
1538         case DevicePropertyManufacturer:
1539             PIP_REGISTRY_DATA(REGSTR_VAL_MFG, REG_SZ);
1540         case DevicePropertyFriendlyName:
1541             PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME, REG_SZ);
1542         case DevicePropertyContainerID:
1543             //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
1544             PIP_UNIMPLEMENTED();
1545             break;
1546         case DevicePropertyInstallState:
1547             PIP_REGISTRY_DATA(REGSTR_VAL_CONFIGFLAGS, REG_DWORD);
1548             break;
1549         case DevicePropertyResourceRequirements:
1550             PIP_UNIMPLEMENTED();
1551         case DevicePropertyAllocatedResources:
1552             PIP_UNIMPLEMENTED();
1553         default:
1554             return STATUS_INVALID_PARAMETER_2;
1555     }
1556 
1557     /* Having a registry value name implies registry data */
1558     if (ValueName)
1559     {
1560         /* We know up-front how much data to expect */
1561         *ResultLength = BufferLength;
1562 
1563         /* Go get the data, use the LogConf subkey if necessary */
1564         Status = PiGetDeviceRegistryProperty(DeviceObject,
1565                                              ValueType,
1566                                              ValueName,
1567                                              (DeviceProperty ==
1568                                               DevicePropertyBootConfiguration) ?
1569                                              L"LogConf":  NULL,
1570                                              PropertyBuffer,
1571                                              ResultLength);
1572     }
1573     else if (NT_SUCCESS(Status))
1574     {
1575         /* We know up-front how much data to expect, check the caller's buffer */
1576         *ResultLength = ReturnLength + (NullTerminate ? sizeof(UNICODE_NULL) : 0);
1577         if (*ResultLength <= BufferLength)
1578         {
1579             /* Buffer is all good, copy the data */
1580             RtlCopyMemory(PropertyBuffer, Data, ReturnLength);
1581 
1582             /* Check if we need to NULL-terminate the string */
1583             if (NullTerminate)
1584             {
1585                 /* Terminate the string */
1586                 ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL;
1587             }
1588 
1589             /* This is the success path */
1590             Status = STATUS_SUCCESS;
1591         }
1592         else
1593         {
1594             /* Failure path */
1595             Status = STATUS_BUFFER_TOO_SMALL;
1596         }
1597     }
1598 
1599     /* Free any allocation we may have made, and return the status code */
1600     if (ObjectNameInfo) ExFreePool(ObjectNameInfo);
1601     return Status;
1602 }
1603 
1604 /**
1605  * @name IoOpenDeviceRegistryKey
1606  *
1607  * Open a registry key unique for a specified driver or device instance.
1608  *
1609  * @param DeviceObject   Device to get the registry key for.
1610  * @param DevInstKeyType Type of the key to return.
1611  * @param DesiredAccess  Access mask (eg. KEY_READ | KEY_WRITE).
1612  * @param DevInstRegKey  Handle to the opened registry key on
1613  *                       successful return.
1614  *
1615  * @return Status.
1616  *
1617  * @implemented
1618  */
1619 NTSTATUS
1620 NTAPI
1621 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject,
1622                         IN ULONG DevInstKeyType,
1623                         IN ACCESS_MASK DesiredAccess,
1624                         OUT PHANDLE DevInstRegKey)
1625 {
1626     static WCHAR RootKeyName[] =
1627         L"\\Registry\\Machine\\System\\CurrentControlSet\\";
1628     static WCHAR ProfileKeyName[] =
1629         L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
1630     static WCHAR ClassKeyName[] = L"Control\\Class\\";
1631     static WCHAR EnumKeyName[] = L"Enum\\";
1632     static WCHAR DeviceParametersKeyName[] = L"Device Parameters";
1633     ULONG KeyNameLength;
1634     PWSTR KeyNameBuffer;
1635     UNICODE_STRING KeyName;
1636     ULONG DriverKeyLength;
1637     OBJECT_ATTRIBUTES ObjectAttributes;
1638     PDEVICE_NODE DeviceNode = NULL;
1639     NTSTATUS Status;
1640 
1641     DPRINT("IoOpenDeviceRegistryKey() called\n");
1642 
1643     if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0)
1644     {
1645         DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting...\n");
1646         return STATUS_INVALID_PARAMETER;
1647     }
1648 
1649     if (!IopIsValidPhysicalDeviceObject(DeviceObject))
1650         return STATUS_INVALID_DEVICE_REQUEST;
1651     DeviceNode = IopGetDeviceNode(DeviceObject);
1652 
1653     /*
1654      * Calculate the length of the base key name. This is the full
1655      * name for driver key or the name excluding "Device Parameters"
1656      * subkey for device key.
1657      */
1658 
1659     KeyNameLength = sizeof(RootKeyName);
1660     if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
1661         KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
1662     if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
1663     {
1664         KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
1665         Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
1666                                      0, NULL, &DriverKeyLength);
1667         if (Status != STATUS_BUFFER_TOO_SMALL)
1668             return Status;
1669         KeyNameLength += DriverKeyLength;
1670     }
1671     else
1672     {
1673         KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
1674                          DeviceNode->InstancePath.Length;
1675     }
1676 
1677     /*
1678      * Now allocate the buffer for the key name...
1679      */
1680 
1681     KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
1682     if (KeyNameBuffer == NULL)
1683         return STATUS_INSUFFICIENT_RESOURCES;
1684 
1685     KeyName.Length = 0;
1686     KeyName.MaximumLength = (USHORT)KeyNameLength;
1687     KeyName.Buffer = KeyNameBuffer;
1688 
1689     /*
1690      * ...and build the key name.
1691      */
1692 
1693     KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
1694     RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
1695 
1696     if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
1697         RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
1698 
1699     if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
1700     {
1701         RtlAppendUnicodeToString(&KeyName, ClassKeyName);
1702         Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
1703                                      DriverKeyLength, KeyNameBuffer +
1704                                      (KeyName.Length / sizeof(WCHAR)),
1705                                      &DriverKeyLength);
1706         if (!NT_SUCCESS(Status))
1707         {
1708             DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status);
1709             ExFreePool(KeyNameBuffer);
1710             return Status;
1711         }
1712         KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL);
1713     }
1714     else
1715     {
1716         RtlAppendUnicodeToString(&KeyName, EnumKeyName);
1717         Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath);
1718         if (DeviceNode->InstancePath.Length == 0)
1719         {
1720             ExFreePool(KeyNameBuffer);
1721             return Status;
1722         }
1723     }
1724 
1725     /*
1726      * Open the base key.
1727      */
1728     Status = IopOpenRegistryKeyEx(DevInstRegKey, NULL, &KeyName, DesiredAccess);
1729     if (!NT_SUCCESS(Status))
1730     {
1731         DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status);
1732         ExFreePool(KeyNameBuffer);
1733         return Status;
1734     }
1735     ExFreePool(KeyNameBuffer);
1736 
1737     /*
1738      * For driver key we're done now.
1739      */
1740 
1741     if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
1742         return Status;
1743 
1744     /*
1745      * Let's go further. For device key we must open "Device Parameters"
1746      * subkey and create it if it doesn't exist yet.
1747      */
1748 
1749     RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
1750     InitializeObjectAttributes(&ObjectAttributes,
1751                                &KeyName,
1752                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1753                                *DevInstRegKey,
1754                                NULL);
1755     Status = ZwCreateKey(DevInstRegKey,
1756                          DesiredAccess,
1757                          &ObjectAttributes,
1758                          0,
1759                          NULL,
1760                          REG_OPTION_NON_VOLATILE,
1761                          NULL);
1762     ZwClose(ObjectAttributes.RootDirectory);
1763 
1764     return Status;
1765 }
1766 
1767 /*
1768  * @implemented
1769  */
1770 VOID
1771 NTAPI
1772 IoInvalidateDeviceRelations(
1773     IN PDEVICE_OBJECT DeviceObject,
1774     IN DEVICE_RELATION_TYPE Type)
1775 {
1776     if (!IopIsValidPhysicalDeviceObject(DeviceObject))
1777     {
1778         KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 0x2, (ULONG_PTR)DeviceObject, 0, 0);
1779     }
1780 
1781     switch (Type)
1782     {
1783         case BusRelations:
1784             /* Enumerate the device */
1785             PiQueueDeviceAction(DeviceObject, PiActionEnumDeviceTree, NULL, NULL);
1786             break;
1787         default:
1788             /* Everything else is not implemented */
1789             break;
1790     }
1791 }
1792 
1793 /*
1794  * @implemented
1795  */
1796 NTSTATUS
1797 NTAPI
1798 IoSynchronousInvalidateDeviceRelations(
1799     IN PDEVICE_OBJECT DeviceObject,
1800     IN DEVICE_RELATION_TYPE Type)
1801 {
1802     PAGED_CODE();
1803 
1804     if (!IopIsValidPhysicalDeviceObject(DeviceObject))
1805     {
1806         KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 0x2, (ULONG_PTR)DeviceObject, 0, 0);
1807     }
1808 
1809     switch (Type)
1810     {
1811         case BusRelations:
1812             /* Enumerate the device */
1813             return PiPerformSyncDeviceAction(DeviceObject, PiActionEnumDeviceTree);
1814         case PowerRelations:
1815              /* Not handled yet */
1816              return STATUS_NOT_IMPLEMENTED;
1817         case TargetDeviceRelation:
1818             /* Nothing to do */
1819             return STATUS_SUCCESS;
1820         default:
1821             /* Ejection relations are not supported */
1822             return STATUS_NOT_SUPPORTED;
1823     }
1824 }
1825 
1826 /*
1827  * @implemented
1828  */
1829 BOOLEAN
1830 NTAPI
1831 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
1832                       IN ULONG BusNumber,
1833                       IN PHYSICAL_ADDRESS BusAddress,
1834                       IN OUT PULONG AddressSpace,
1835                       OUT PPHYSICAL_ADDRESS TranslatedAddress)
1836 {
1837     /* FIXME: Notify the resource arbiter */
1838 
1839     return HalTranslateBusAddress(InterfaceType,
1840                                   BusNumber,
1841                                   BusAddress,
1842                                   AddressSpace,
1843                                   TranslatedAddress);
1844 }
1845 
1846 VOID
1847 NTAPI
1848 IoInvalidateDeviceState(
1849     IN PDEVICE_OBJECT DeviceObject)
1850 {
1851     if (!IopIsValidPhysicalDeviceObject(DeviceObject))
1852     {
1853         KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 0x2, (ULONG_PTR)DeviceObject, 0, 0);
1854     }
1855 
1856     PiQueueDeviceAction(DeviceObject, PiActionQueryState, NULL, NULL);
1857 }
1858