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