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