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