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 PDEVICE_NODE IopRootDeviceNode; 19 KSPIN_LOCK IopDeviceTreeLock; 20 ERESOURCE PpRegistryDeviceResource; 21 KGUARDED_MUTEX PpDeviceReferenceTableLock; 22 RTL_AVL_TABLE PpDeviceReferenceTable; 23 24 extern ERESOURCE IopDriverLoadResource; 25 extern ULONG ExpInitializationPhase; 26 extern BOOLEAN PnpSystemInit; 27 28 #define MAX_DEVICE_ID_LEN 200 29 #define MAX_SEPARATORS_INSTANCEID 0 30 #define MAX_SEPARATORS_DEVICEID 1 31 32 /* DATA **********************************************************************/ 33 34 PDRIVER_OBJECT IopRootDriverObject; 35 PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList = NULL; 36 LIST_ENTRY IopDeviceActionRequestList; 37 WORK_QUEUE_ITEM IopDeviceActionWorkItem; 38 BOOLEAN IopDeviceActionInProgress; 39 KSPIN_LOCK IopDeviceActionLock; 40 41 typedef struct _DEVICE_ACTION_DATA 42 { 43 LIST_ENTRY RequestListEntry; 44 PDEVICE_OBJECT DeviceObject; 45 DEVICE_RELATION_TYPE Type; 46 } DEVICE_ACTION_DATA, *PDEVICE_ACTION_DATA; 47 48 /* FUNCTIONS *****************************************************************/ 49 NTSTATUS 50 NTAPI 51 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath, 52 IN ULONG CreateOptions, 53 OUT PHANDLE Handle); 54 55 VOID 56 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject); 57 58 NTSTATUS 59 IopPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject, BOOLEAN Force); 60 61 PDEVICE_OBJECT 62 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance); 63 64 PDEVICE_NODE 65 FASTCALL 66 IopGetDeviceNode(PDEVICE_OBJECT DeviceObject) 67 { 68 return ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode; 69 } 70 71 VOID 72 IopFixupDeviceId(PWCHAR String) 73 { 74 SIZE_T Length = wcslen(String), i; 75 76 for (i = 0; i < Length; i++) 77 { 78 if (String[i] == L'\\') 79 String[i] = L'#'; 80 } 81 } 82 83 VOID 84 NTAPI 85 IopInstallCriticalDevice(PDEVICE_NODE DeviceNode) 86 { 87 NTSTATUS Status; 88 HANDLE CriticalDeviceKey, InstanceKey; 89 OBJECT_ATTRIBUTES ObjectAttributes; 90 UNICODE_STRING CriticalDeviceKeyU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CriticalDeviceDatabase"); 91 UNICODE_STRING CompatibleIdU = RTL_CONSTANT_STRING(L"CompatibleIDs"); 92 UNICODE_STRING HardwareIdU = RTL_CONSTANT_STRING(L"HardwareID"); 93 UNICODE_STRING ServiceU = RTL_CONSTANT_STRING(L"Service"); 94 UNICODE_STRING ClassGuidU = RTL_CONSTANT_STRING(L"ClassGUID"); 95 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo; 96 ULONG HidLength = 0, CidLength = 0, BufferLength; 97 PWCHAR IdBuffer, OriginalIdBuffer; 98 99 /* Open the device instance key */ 100 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey); 101 if (Status != STATUS_SUCCESS) 102 return; 103 104 Status = ZwQueryValueKey(InstanceKey, 105 &HardwareIdU, 106 KeyValuePartialInformation, 107 NULL, 108 0, 109 &HidLength); 110 if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL) 111 { 112 ZwClose(InstanceKey); 113 return; 114 } 115 116 Status = ZwQueryValueKey(InstanceKey, 117 &CompatibleIdU, 118 KeyValuePartialInformation, 119 NULL, 120 0, 121 &CidLength); 122 if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL) 123 { 124 CidLength = 0; 125 } 126 127 BufferLength = HidLength + CidLength; 128 BufferLength -= (((CidLength != 0) ? 2 : 1) * FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)); 129 130 /* Allocate a buffer to hold data from both */ 131 OriginalIdBuffer = IdBuffer = ExAllocatePool(PagedPool, BufferLength); 132 if (!IdBuffer) 133 { 134 ZwClose(InstanceKey); 135 return; 136 } 137 138 /* Compute the buffer size */ 139 if (HidLength > CidLength) 140 BufferLength = HidLength; 141 else 142 BufferLength = CidLength; 143 144 PartialInfo = ExAllocatePool(PagedPool, BufferLength); 145 if (!PartialInfo) 146 { 147 ZwClose(InstanceKey); 148 ExFreePool(OriginalIdBuffer); 149 return; 150 } 151 152 Status = ZwQueryValueKey(InstanceKey, 153 &HardwareIdU, 154 KeyValuePartialInformation, 155 PartialInfo, 156 HidLength, 157 &HidLength); 158 if (Status != STATUS_SUCCESS) 159 { 160 ExFreePool(PartialInfo); 161 ExFreePool(OriginalIdBuffer); 162 ZwClose(InstanceKey); 163 return; 164 } 165 166 /* Copy in HID info first (without 2nd terminating NULL if CID is present) */ 167 HidLength = PartialInfo->DataLength - ((CidLength != 0) ? sizeof(WCHAR) : 0); 168 RtlCopyMemory(IdBuffer, PartialInfo->Data, HidLength); 169 170 if (CidLength != 0) 171 { 172 Status = ZwQueryValueKey(InstanceKey, 173 &CompatibleIdU, 174 KeyValuePartialInformation, 175 PartialInfo, 176 CidLength, 177 &CidLength); 178 if (Status != STATUS_SUCCESS) 179 { 180 ExFreePool(PartialInfo); 181 ExFreePool(OriginalIdBuffer); 182 ZwClose(InstanceKey); 183 return; 184 } 185 186 /* Copy CID next */ 187 CidLength = PartialInfo->DataLength; 188 RtlCopyMemory(((PUCHAR)IdBuffer) + HidLength, PartialInfo->Data, CidLength); 189 } 190 191 /* Free our temp buffer */ 192 ExFreePool(PartialInfo); 193 194 InitializeObjectAttributes(&ObjectAttributes, 195 &CriticalDeviceKeyU, 196 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 197 NULL, 198 NULL); 199 Status = ZwOpenKey(&CriticalDeviceKey, 200 KEY_ENUMERATE_SUB_KEYS, 201 &ObjectAttributes); 202 if (!NT_SUCCESS(Status)) 203 { 204 /* The critical device database doesn't exist because 205 * we're probably in 1st stage setup, but it's ok */ 206 ExFreePool(OriginalIdBuffer); 207 ZwClose(InstanceKey); 208 return; 209 } 210 211 while (*IdBuffer) 212 { 213 USHORT StringLength = (USHORT)wcslen(IdBuffer) + 1, Index; 214 215 IopFixupDeviceId(IdBuffer); 216 217 /* Look through all subkeys for a match */ 218 for (Index = 0; TRUE; Index++) 219 { 220 ULONG NeededLength; 221 PKEY_BASIC_INFORMATION BasicInfo; 222 223 Status = ZwEnumerateKey(CriticalDeviceKey, 224 Index, 225 KeyBasicInformation, 226 NULL, 227 0, 228 &NeededLength); 229 if (Status == STATUS_NO_MORE_ENTRIES) 230 break; 231 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 232 { 233 UNICODE_STRING ChildIdNameU, RegKeyNameU; 234 235 BasicInfo = ExAllocatePool(PagedPool, NeededLength); 236 if (!BasicInfo) 237 { 238 /* No memory */ 239 ExFreePool(OriginalIdBuffer); 240 ZwClose(CriticalDeviceKey); 241 ZwClose(InstanceKey); 242 return; 243 } 244 245 Status = ZwEnumerateKey(CriticalDeviceKey, 246 Index, 247 KeyBasicInformation, 248 BasicInfo, 249 NeededLength, 250 &NeededLength); 251 if (Status != STATUS_SUCCESS) 252 { 253 /* This shouldn't happen */ 254 ExFreePool(BasicInfo); 255 continue; 256 } 257 258 ChildIdNameU.Buffer = IdBuffer; 259 ChildIdNameU.MaximumLength = ChildIdNameU.Length = (StringLength - 1) * sizeof(WCHAR); 260 RegKeyNameU.Buffer = BasicInfo->Name; 261 RegKeyNameU.MaximumLength = RegKeyNameU.Length = (USHORT)BasicInfo->NameLength; 262 263 if (RtlEqualUnicodeString(&ChildIdNameU, &RegKeyNameU, TRUE)) 264 { 265 HANDLE ChildKeyHandle; 266 267 InitializeObjectAttributes(&ObjectAttributes, 268 &ChildIdNameU, 269 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 270 CriticalDeviceKey, 271 NULL); 272 273 Status = ZwOpenKey(&ChildKeyHandle, 274 KEY_QUERY_VALUE, 275 &ObjectAttributes); 276 if (Status != STATUS_SUCCESS) 277 { 278 ExFreePool(BasicInfo); 279 continue; 280 } 281 282 /* Check if there's already a driver installed */ 283 Status = ZwQueryValueKey(InstanceKey, 284 &ClassGuidU, 285 KeyValuePartialInformation, 286 NULL, 287 0, 288 &NeededLength); 289 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 290 { 291 ExFreePool(BasicInfo); 292 continue; 293 } 294 295 Status = ZwQueryValueKey(ChildKeyHandle, 296 &ClassGuidU, 297 KeyValuePartialInformation, 298 NULL, 299 0, 300 &NeededLength); 301 if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL) 302 { 303 ExFreePool(BasicInfo); 304 continue; 305 } 306 307 PartialInfo = ExAllocatePool(PagedPool, NeededLength); 308 if (!PartialInfo) 309 { 310 ExFreePool(OriginalIdBuffer); 311 ExFreePool(BasicInfo); 312 ZwClose(InstanceKey); 313 ZwClose(ChildKeyHandle); 314 ZwClose(CriticalDeviceKey); 315 return; 316 } 317 318 /* Read ClassGUID entry in the CDDB */ 319 Status = ZwQueryValueKey(ChildKeyHandle, 320 &ClassGuidU, 321 KeyValuePartialInformation, 322 PartialInfo, 323 NeededLength, 324 &NeededLength); 325 if (Status != STATUS_SUCCESS) 326 { 327 ExFreePool(BasicInfo); 328 continue; 329 } 330 331 /* Write it to the ENUM key */ 332 Status = ZwSetValueKey(InstanceKey, 333 &ClassGuidU, 334 0, 335 REG_SZ, 336 PartialInfo->Data, 337 PartialInfo->DataLength); 338 if (Status != STATUS_SUCCESS) 339 { 340 ExFreePool(BasicInfo); 341 ExFreePool(PartialInfo); 342 ZwClose(ChildKeyHandle); 343 continue; 344 } 345 346 Status = ZwQueryValueKey(ChildKeyHandle, 347 &ServiceU, 348 KeyValuePartialInformation, 349 NULL, 350 0, 351 &NeededLength); 352 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 353 { 354 ExFreePool(PartialInfo); 355 PartialInfo = ExAllocatePool(PagedPool, NeededLength); 356 if (!PartialInfo) 357 { 358 ExFreePool(OriginalIdBuffer); 359 ExFreePool(BasicInfo); 360 ZwClose(InstanceKey); 361 ZwClose(ChildKeyHandle); 362 ZwClose(CriticalDeviceKey); 363 return; 364 } 365 366 /* Read the service entry from the CDDB */ 367 Status = ZwQueryValueKey(ChildKeyHandle, 368 &ServiceU, 369 KeyValuePartialInformation, 370 PartialInfo, 371 NeededLength, 372 &NeededLength); 373 if (Status != STATUS_SUCCESS) 374 { 375 ExFreePool(BasicInfo); 376 ExFreePool(PartialInfo); 377 ZwClose(ChildKeyHandle); 378 continue; 379 } 380 381 /* Write it to the ENUM key */ 382 Status = ZwSetValueKey(InstanceKey, 383 &ServiceU, 384 0, 385 REG_SZ, 386 PartialInfo->Data, 387 PartialInfo->DataLength); 388 if (Status != STATUS_SUCCESS) 389 { 390 ExFreePool(BasicInfo); 391 ExFreePool(PartialInfo); 392 ZwClose(ChildKeyHandle); 393 continue; 394 } 395 396 DPRINT("Installed service '%S' for critical device '%wZ'\n", PartialInfo->Data, &ChildIdNameU); 397 } 398 else 399 { 400 DPRINT1("Installed NULL service for critical device '%wZ'\n", &ChildIdNameU); 401 } 402 403 ExFreePool(OriginalIdBuffer); 404 ExFreePool(PartialInfo); 405 ExFreePool(BasicInfo); 406 ZwClose(InstanceKey); 407 ZwClose(ChildKeyHandle); 408 ZwClose(CriticalDeviceKey); 409 410 /* That's it */ 411 return; 412 } 413 414 ExFreePool(BasicInfo); 415 } 416 else 417 { 418 /* Umm, not sure what happened here */ 419 continue; 420 } 421 } 422 423 /* Advance to the next ID */ 424 IdBuffer += StringLength; 425 } 426 427 ExFreePool(OriginalIdBuffer); 428 ZwClose(InstanceKey); 429 ZwClose(CriticalDeviceKey); 430 } 431 432 NTSTATUS 433 FASTCALL 434 IopInitializeDevice(PDEVICE_NODE DeviceNode, 435 PDRIVER_OBJECT DriverObject) 436 { 437 PDEVICE_OBJECT Fdo; 438 NTSTATUS Status; 439 440 if (!DriverObject) 441 { 442 /* Special case for bus driven devices */ 443 DeviceNode->Flags |= DNF_ADDED; 444 return STATUS_SUCCESS; 445 } 446 447 if (!DriverObject->DriverExtension->AddDevice) 448 { 449 DeviceNode->Flags |= DNF_LEGACY_DRIVER; 450 } 451 452 if (DeviceNode->Flags & DNF_LEGACY_DRIVER) 453 { 454 DeviceNode->Flags |= (DNF_ADDED | DNF_STARTED); 455 return STATUS_SUCCESS; 456 } 457 458 /* This is a Plug and Play driver */ 459 DPRINT("Plug and Play driver found\n"); 460 ASSERT(DeviceNode->PhysicalDeviceObject); 461 462 DPRINT("Calling %wZ->AddDevice(%wZ)\n", 463 &DriverObject->DriverName, 464 &DeviceNode->InstancePath); 465 Status = DriverObject->DriverExtension->AddDevice(DriverObject, 466 DeviceNode->PhysicalDeviceObject); 467 if (!NT_SUCCESS(Status)) 468 { 469 DPRINT1("%wZ->AddDevice(%wZ) failed with status 0x%x\n", 470 &DriverObject->DriverName, 471 &DeviceNode->InstancePath, 472 Status); 473 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); 474 DeviceNode->Problem = CM_PROB_FAILED_ADD; 475 return Status; 476 } 477 478 Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject); 479 480 /* Check if we have a ACPI device (needed for power management) */ 481 if (Fdo->DeviceType == FILE_DEVICE_ACPI) 482 { 483 static BOOLEAN SystemPowerDeviceNodeCreated = FALSE; 484 485 /* There can be only one system power device */ 486 if (!SystemPowerDeviceNodeCreated) 487 { 488 PopSystemPowerDeviceNode = DeviceNode; 489 ObReferenceObject(PopSystemPowerDeviceNode->PhysicalDeviceObject); 490 SystemPowerDeviceNodeCreated = TRUE; 491 } 492 } 493 494 ObDereferenceObject(Fdo); 495 496 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED); 497 498 return STATUS_SUCCESS; 499 } 500 501 static 502 NTSTATUS 503 NTAPI 504 IopSendEject(IN PDEVICE_OBJECT DeviceObject) 505 { 506 IO_STACK_LOCATION Stack; 507 PVOID Dummy; 508 509 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 510 Stack.MajorFunction = IRP_MJ_PNP; 511 Stack.MinorFunction = IRP_MN_EJECT; 512 513 return IopSynchronousCall(DeviceObject, &Stack, &Dummy); 514 } 515 516 static 517 VOID 518 NTAPI 519 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject) 520 { 521 IO_STACK_LOCATION Stack; 522 PVOID Dummy; 523 524 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 525 Stack.MajorFunction = IRP_MJ_PNP; 526 Stack.MinorFunction = IRP_MN_SURPRISE_REMOVAL; 527 528 /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */ 529 IopSynchronousCall(DeviceObject, &Stack, &Dummy); 530 } 531 532 static 533 NTSTATUS 534 NTAPI 535 IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject) 536 { 537 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 538 IO_STACK_LOCATION Stack; 539 PVOID Dummy; 540 NTSTATUS Status; 541 542 ASSERT(DeviceNode); 543 544 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING, 545 &DeviceNode->InstancePath); 546 547 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 548 Stack.MajorFunction = IRP_MJ_PNP; 549 Stack.MinorFunction = IRP_MN_QUERY_REMOVE_DEVICE; 550 551 Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy); 552 553 IopNotifyPlugPlayNotification(DeviceObject, 554 EventCategoryTargetDeviceChange, 555 &GUID_TARGET_DEVICE_QUERY_REMOVE, 556 NULL, 557 NULL); 558 559 if (!NT_SUCCESS(Status)) 560 { 561 DPRINT1("Removal vetoed by %wZ\n", &DeviceNode->InstancePath); 562 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED, 563 &DeviceNode->InstancePath); 564 } 565 566 return Status; 567 } 568 569 static 570 NTSTATUS 571 NTAPI 572 IopQueryStopDevice(IN PDEVICE_OBJECT DeviceObject) 573 { 574 IO_STACK_LOCATION Stack; 575 PVOID Dummy; 576 577 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 578 Stack.MajorFunction = IRP_MJ_PNP; 579 Stack.MinorFunction = IRP_MN_QUERY_STOP_DEVICE; 580 581 return IopSynchronousCall(DeviceObject, &Stack, &Dummy); 582 } 583 584 static 585 VOID 586 NTAPI 587 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject) 588 { 589 IO_STACK_LOCATION Stack; 590 PVOID Dummy; 591 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 592 593 /* Drop all our state for this device in case it isn't really going away */ 594 DeviceNode->Flags &= DNF_ENUMERATED | DNF_PROCESSED; 595 596 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 597 Stack.MajorFunction = IRP_MJ_PNP; 598 Stack.MinorFunction = IRP_MN_REMOVE_DEVICE; 599 600 /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */ 601 IopSynchronousCall(DeviceObject, &Stack, &Dummy); 602 603 IopNotifyPlugPlayNotification(DeviceObject, 604 EventCategoryTargetDeviceChange, 605 &GUID_TARGET_DEVICE_REMOVE_COMPLETE, 606 NULL, 607 NULL); 608 ObDereferenceObject(DeviceObject); 609 } 610 611 static 612 VOID 613 NTAPI 614 IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject) 615 { 616 IO_STACK_LOCATION Stack; 617 PVOID Dummy; 618 619 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 620 Stack.MajorFunction = IRP_MJ_PNP; 621 Stack.MinorFunction = IRP_MN_CANCEL_REMOVE_DEVICE; 622 623 /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */ 624 IopSynchronousCall(DeviceObject, &Stack, &Dummy); 625 626 IopNotifyPlugPlayNotification(DeviceObject, 627 EventCategoryTargetDeviceChange, 628 &GUID_TARGET_DEVICE_REMOVE_CANCELLED, 629 NULL, 630 NULL); 631 } 632 633 static 634 VOID 635 NTAPI 636 IopSendStopDevice(IN PDEVICE_OBJECT DeviceObject) 637 { 638 IO_STACK_LOCATION Stack; 639 PVOID Dummy; 640 641 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 642 Stack.MajorFunction = IRP_MJ_PNP; 643 Stack.MinorFunction = IRP_MN_STOP_DEVICE; 644 645 /* Drivers should never fail a IRP_MN_STOP_DEVICE request */ 646 IopSynchronousCall(DeviceObject, &Stack, &Dummy); 647 } 648 649 static 650 NTSTATUS 651 IopSetServiceEnumData(PDEVICE_NODE DeviceNode) 652 { 653 UNICODE_STRING ServicesKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); 654 UNICODE_STRING ServiceKeyName; 655 UNICODE_STRING EnumKeyName; 656 UNICODE_STRING ValueName; 657 PKEY_VALUE_FULL_INFORMATION KeyValueInformation; 658 HANDLE ServiceKey = NULL, ServiceEnumKey = NULL; 659 ULONG Disposition; 660 ULONG Count = 0, NextInstance = 0; 661 WCHAR ValueBuffer[6]; 662 NTSTATUS Status = STATUS_SUCCESS; 663 664 DPRINT("IopSetServiceEnumData(%p)\n", DeviceNode); 665 DPRINT("Instance: %wZ\n", &DeviceNode->InstancePath); 666 DPRINT("Service: %wZ\n", &DeviceNode->ServiceName); 667 668 if (DeviceNode->ServiceName.Buffer == NULL) 669 { 670 DPRINT1("No service!\n"); 671 return STATUS_SUCCESS; 672 } 673 674 ServiceKeyName.MaximumLength = ServicesKeyPath.Length + DeviceNode->ServiceName.Length + sizeof(UNICODE_NULL); 675 ServiceKeyName.Length = 0; 676 ServiceKeyName.Buffer = ExAllocatePool(PagedPool, ServiceKeyName.MaximumLength); 677 if (ServiceKeyName.Buffer == NULL) 678 { 679 DPRINT1("No ServiceKeyName.Buffer!\n"); 680 return STATUS_INSUFFICIENT_RESOURCES; 681 } 682 683 RtlAppendUnicodeStringToString(&ServiceKeyName, &ServicesKeyPath); 684 RtlAppendUnicodeStringToString(&ServiceKeyName, &DeviceNode->ServiceName); 685 686 DPRINT("ServiceKeyName: %wZ\n", &ServiceKeyName); 687 688 Status = IopOpenRegistryKeyEx(&ServiceKey, NULL, &ServiceKeyName, KEY_CREATE_SUB_KEY); 689 if (!NT_SUCCESS(Status)) 690 { 691 goto done; 692 } 693 694 RtlInitUnicodeString(&EnumKeyName, L"Enum"); 695 Status = IopCreateRegistryKeyEx(&ServiceEnumKey, 696 ServiceKey, 697 &EnumKeyName, 698 KEY_SET_VALUE, 699 REG_OPTION_VOLATILE, 700 &Disposition); 701 if (NT_SUCCESS(Status)) 702 { 703 if (Disposition == REG_OPENED_EXISTING_KEY) 704 { 705 /* Read the NextInstance value */ 706 Status = IopGetRegistryValue(ServiceEnumKey, 707 L"Count", 708 &KeyValueInformation); 709 if (!NT_SUCCESS(Status)) 710 goto done; 711 712 if ((KeyValueInformation->Type == REG_DWORD) && 713 (KeyValueInformation->DataLength)) 714 { 715 /* Read it */ 716 Count = *(PULONG)((ULONG_PTR)KeyValueInformation + 717 KeyValueInformation->DataOffset); 718 } 719 720 ExFreePool(KeyValueInformation); 721 KeyValueInformation = NULL; 722 723 /* Read the NextInstance value */ 724 Status = IopGetRegistryValue(ServiceEnumKey, 725 L"NextInstance", 726 &KeyValueInformation); 727 if (!NT_SUCCESS(Status)) 728 goto done; 729 730 if ((KeyValueInformation->Type == REG_DWORD) && 731 (KeyValueInformation->DataLength)) 732 { 733 NextInstance = *(PULONG)((ULONG_PTR)KeyValueInformation + 734 KeyValueInformation->DataOffset); 735 } 736 737 ExFreePool(KeyValueInformation); 738 KeyValueInformation = NULL; 739 } 740 741 /* Set the instance path */ 742 swprintf(ValueBuffer, L"%lu", NextInstance); 743 RtlInitUnicodeString(&ValueName, ValueBuffer); 744 Status = ZwSetValueKey(ServiceEnumKey, 745 &ValueName, 746 0, 747 REG_SZ, 748 DeviceNode->InstancePath.Buffer, 749 DeviceNode->InstancePath.MaximumLength); 750 if (!NT_SUCCESS(Status)) 751 goto done; 752 753 /* Increment Count and NextInstance */ 754 Count++; 755 NextInstance++; 756 757 /* Set the new Count value */ 758 RtlInitUnicodeString(&ValueName, L"Count"); 759 Status = ZwSetValueKey(ServiceEnumKey, 760 &ValueName, 761 0, 762 REG_DWORD, 763 &Count, 764 sizeof(Count)); 765 if (!NT_SUCCESS(Status)) 766 goto done; 767 768 /* Set the new NextInstance value */ 769 RtlInitUnicodeString(&ValueName, L"NextInstance"); 770 Status = ZwSetValueKey(ServiceEnumKey, 771 &ValueName, 772 0, 773 REG_DWORD, 774 &NextInstance, 775 sizeof(NextInstance)); 776 } 777 778 done: 779 if (ServiceEnumKey != NULL) 780 ZwClose(ServiceEnumKey); 781 782 if (ServiceKey != NULL) 783 ZwClose(ServiceKey); 784 785 ExFreePool(ServiceKeyName.Buffer); 786 787 return Status; 788 } 789 790 VOID 791 NTAPI 792 IopStartDevice2(IN PDEVICE_OBJECT DeviceObject) 793 { 794 IO_STACK_LOCATION Stack; 795 PDEVICE_NODE DeviceNode; 796 NTSTATUS Status; 797 PVOID Dummy; 798 DEVICE_CAPABILITIES DeviceCapabilities; 799 800 /* Get the device node */ 801 DeviceNode = IopGetDeviceNode(DeviceObject); 802 803 ASSERT(!(DeviceNode->Flags & DNF_DISABLED)); 804 805 /* Build the I/O stack location */ 806 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 807 Stack.MajorFunction = IRP_MJ_PNP; 808 Stack.MinorFunction = IRP_MN_START_DEVICE; 809 810 Stack.Parameters.StartDevice.AllocatedResources = 811 DeviceNode->ResourceList; 812 Stack.Parameters.StartDevice.AllocatedResourcesTranslated = 813 DeviceNode->ResourceListTranslated; 814 815 /* Do the call */ 816 Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy); 817 if (!NT_SUCCESS(Status)) 818 { 819 /* Send an IRP_MN_REMOVE_DEVICE request */ 820 IopRemoveDevice(DeviceNode); 821 822 /* Set the appropriate flag */ 823 DeviceNode->Flags |= DNF_START_FAILED; 824 DeviceNode->Problem = CM_PROB_FAILED_START; 825 826 DPRINT1("Warning: PnP Start failed (%wZ) [Status: 0x%x]\n", &DeviceNode->InstancePath, Status); 827 return; 828 } 829 830 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n"); 831 832 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities); 833 if (!NT_SUCCESS(Status)) 834 { 835 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status); 836 } 837 838 /* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */ 839 IoInvalidateDeviceState(DeviceObject); 840 841 /* Otherwise, mark us as started */ 842 DeviceNode->Flags |= DNF_STARTED; 843 DeviceNode->Flags &= ~DNF_STOPPED; 844 845 /* We now need enumeration */ 846 DeviceNode->Flags |= DNF_NEED_ENUMERATION_ONLY; 847 } 848 849 NTSTATUS 850 NTAPI 851 IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode) 852 { 853 PDEVICE_OBJECT DeviceObject; 854 NTSTATUS Status; 855 PAGED_CODE(); 856 857 /* Sanity check */ 858 ASSERT((DeviceNode->Flags & DNF_ADDED)); 859 ASSERT((DeviceNode->Flags & (DNF_RESOURCE_ASSIGNED | 860 DNF_RESOURCE_REPORTED | 861 DNF_NO_RESOURCE_REQUIRED))); 862 863 /* Get the device object */ 864 DeviceObject = DeviceNode->PhysicalDeviceObject; 865 866 /* Check if we're not started yet */ 867 if (!(DeviceNode->Flags & DNF_STARTED)) 868 { 869 /* Start us */ 870 IopStartDevice2(DeviceObject); 871 } 872 873 /* Do we need to query IDs? This happens in the case of manual reporting */ 874 #if 0 875 if (DeviceNode->Flags & DNF_NEED_QUERY_IDS) 876 { 877 DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n"); 878 /* And that case shouldn't happen yet */ 879 ASSERT(FALSE); 880 } 881 #endif 882 883 IopSetServiceEnumData(DeviceNode); 884 885 /* Make sure we're started, and check if we need enumeration */ 886 if ((DeviceNode->Flags & DNF_STARTED) && 887 (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY)) 888 { 889 /* Enumerate us */ 890 IoSynchronousInvalidateDeviceRelations(DeviceObject, BusRelations); 891 Status = STATUS_SUCCESS; 892 } 893 else 894 { 895 /* Nothing to do */ 896 Status = STATUS_SUCCESS; 897 } 898 899 /* Return */ 900 return Status; 901 } 902 903 NTSTATUS 904 IopStopDevice( 905 PDEVICE_NODE DeviceNode) 906 { 907 NTSTATUS Status; 908 909 DPRINT("Stopping device: %wZ\n", &DeviceNode->InstancePath); 910 911 Status = IopQueryStopDevice(DeviceNode->PhysicalDeviceObject); 912 if (NT_SUCCESS(Status)) 913 { 914 IopSendStopDevice(DeviceNode->PhysicalDeviceObject); 915 916 DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING); 917 DeviceNode->Flags |= DNF_STOPPED; 918 919 return STATUS_SUCCESS; 920 } 921 922 return Status; 923 } 924 925 NTSTATUS 926 IopStartDevice( 927 PDEVICE_NODE DeviceNode) 928 { 929 NTSTATUS Status; 930 HANDLE InstanceHandle = NULL, ControlHandle = NULL; 931 UNICODE_STRING KeyName, ValueString; 932 OBJECT_ATTRIBUTES ObjectAttributes; 933 934 if (DeviceNode->Flags & DNF_DISABLED) 935 return STATUS_SUCCESS; 936 937 Status = IopAssignDeviceResources(DeviceNode); 938 if (!NT_SUCCESS(Status)) 939 goto ByeBye; 940 941 /* New PnP ABI */ 942 IopStartAndEnumerateDevice(DeviceNode); 943 944 /* FIX: Should be done in new device instance code */ 945 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceHandle); 946 if (!NT_SUCCESS(Status)) 947 goto ByeBye; 948 949 /* FIX: Should be done in IoXxxPrepareDriverLoading */ 950 // { 951 RtlInitUnicodeString(&KeyName, L"Control"); 952 InitializeObjectAttributes(&ObjectAttributes, 953 &KeyName, 954 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 955 InstanceHandle, 956 NULL); 957 Status = ZwCreateKey(&ControlHandle, 958 KEY_SET_VALUE, 959 &ObjectAttributes, 960 0, 961 NULL, 962 REG_OPTION_VOLATILE, 963 NULL); 964 if (!NT_SUCCESS(Status)) 965 goto ByeBye; 966 967 RtlInitUnicodeString(&KeyName, L"ActiveService"); 968 ValueString = DeviceNode->ServiceName; 969 if (!ValueString.Buffer) 970 RtlInitUnicodeString(&ValueString, L""); 971 Status = ZwSetValueKey(ControlHandle, &KeyName, 0, REG_SZ, ValueString.Buffer, ValueString.Length + sizeof(UNICODE_NULL)); 972 // } 973 974 ByeBye: 975 if (ControlHandle != NULL) 976 ZwClose(ControlHandle); 977 978 if (InstanceHandle != NULL) 979 ZwClose(InstanceHandle); 980 981 return Status; 982 } 983 984 NTSTATUS 985 NTAPI 986 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode, 987 PDEVICE_CAPABILITIES DeviceCaps) 988 { 989 IO_STATUS_BLOCK StatusBlock; 990 IO_STACK_LOCATION Stack; 991 NTSTATUS Status; 992 HANDLE InstanceKey; 993 UNICODE_STRING ValueName; 994 995 /* Set up the Header */ 996 RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES)); 997 DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES); 998 DeviceCaps->Version = 1; 999 DeviceCaps->Address = -1; 1000 DeviceCaps->UINumber = -1; 1001 1002 /* Set up the Stack */ 1003 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 1004 Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps; 1005 1006 /* Send the IRP */ 1007 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 1008 &StatusBlock, 1009 IRP_MN_QUERY_CAPABILITIES, 1010 &Stack); 1011 if (!NT_SUCCESS(Status)) 1012 { 1013 if (Status != STATUS_NOT_SUPPORTED) 1014 { 1015 DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%lx\n", Status); 1016 } 1017 return Status; 1018 } 1019 1020 DeviceNode->CapabilityFlags = *(PULONG)((ULONG_PTR)&DeviceCaps->Version + sizeof(DeviceCaps->Version)); 1021 1022 if (DeviceCaps->NoDisplayInUI) 1023 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI; 1024 else 1025 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI; 1026 1027 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey); 1028 if (NT_SUCCESS(Status)) 1029 { 1030 /* Set 'Capabilities' value */ 1031 RtlInitUnicodeString(&ValueName, L"Capabilities"); 1032 Status = ZwSetValueKey(InstanceKey, 1033 &ValueName, 1034 0, 1035 REG_DWORD, 1036 &DeviceNode->CapabilityFlags, 1037 sizeof(ULONG)); 1038 1039 /* Set 'UINumber' value */ 1040 if (DeviceCaps->UINumber != MAXULONG) 1041 { 1042 RtlInitUnicodeString(&ValueName, L"UINumber"); 1043 Status = ZwSetValueKey(InstanceKey, 1044 &ValueName, 1045 0, 1046 REG_DWORD, 1047 &DeviceCaps->UINumber, 1048 sizeof(ULONG)); 1049 } 1050 1051 ZwClose(InstanceKey); 1052 } 1053 1054 return Status; 1055 } 1056 1057 static 1058 VOID 1059 NTAPI 1060 IopDeviceActionWorker( 1061 _In_ PVOID Context) 1062 { 1063 PLIST_ENTRY ListEntry; 1064 PDEVICE_ACTION_DATA Data; 1065 KIRQL OldIrql; 1066 1067 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql); 1068 while (!IsListEmpty(&IopDeviceActionRequestList)) 1069 { 1070 ListEntry = RemoveHeadList(&IopDeviceActionRequestList); 1071 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); 1072 Data = CONTAINING_RECORD(ListEntry, 1073 DEVICE_ACTION_DATA, 1074 RequestListEntry); 1075 1076 IoSynchronousInvalidateDeviceRelations(Data->DeviceObject, 1077 Data->Type); 1078 1079 ObDereferenceObject(Data->DeviceObject); 1080 ExFreePoolWithTag(Data, TAG_IO); 1081 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql); 1082 } 1083 IopDeviceActionInProgress = FALSE; 1084 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); 1085 } 1086 1087 NTSTATUS 1088 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject) 1089 { 1090 KIRQL OldIrql; 1091 1092 if (PopSystemPowerDeviceNode) 1093 { 1094 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 1095 *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject; 1096 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 1097 1098 return STATUS_SUCCESS; 1099 } 1100 1101 return STATUS_UNSUCCESSFUL; 1102 } 1103 1104 USHORT 1105 NTAPI 1106 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid) 1107 { 1108 USHORT i = 0, FoundIndex = 0xFFFF; 1109 ULONG NewSize; 1110 PVOID NewList; 1111 1112 /* Acquire the lock */ 1113 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock); 1114 1115 /* Loop all entries */ 1116 while (i < PnpBusTypeGuidList->GuidCount) 1117 { 1118 /* Try to find a match */ 1119 if (RtlCompareMemory(BusTypeGuid, 1120 &PnpBusTypeGuidList->Guids[i], 1121 sizeof(GUID)) == sizeof(GUID)) 1122 { 1123 /* Found it */ 1124 FoundIndex = i; 1125 goto Quickie; 1126 } 1127 i++; 1128 } 1129 1130 /* Check if we have to grow the list */ 1131 if (PnpBusTypeGuidList->GuidCount) 1132 { 1133 /* Calculate the new size */ 1134 NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) + 1135 (sizeof(GUID) * PnpBusTypeGuidList->GuidCount); 1136 1137 /* Allocate the new copy */ 1138 NewList = ExAllocatePool(PagedPool, NewSize); 1139 1140 if (!NewList) 1141 { 1142 /* Fail */ 1143 ExFreePool(PnpBusTypeGuidList); 1144 goto Quickie; 1145 } 1146 1147 /* Now copy them, decrease the size too */ 1148 NewSize -= sizeof(GUID); 1149 RtlCopyMemory(NewList, PnpBusTypeGuidList, NewSize); 1150 1151 /* Free the old list */ 1152 ExFreePool(PnpBusTypeGuidList); 1153 1154 /* Use the new buffer */ 1155 PnpBusTypeGuidList = NewList; 1156 } 1157 1158 /* Copy the new GUID */ 1159 RtlCopyMemory(&PnpBusTypeGuidList->Guids[PnpBusTypeGuidList->GuidCount], 1160 BusTypeGuid, 1161 sizeof(GUID)); 1162 1163 /* The new entry is the index */ 1164 FoundIndex = (USHORT)PnpBusTypeGuidList->GuidCount; 1165 PnpBusTypeGuidList->GuidCount++; 1166 1167 Quickie: 1168 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock); 1169 return FoundIndex; 1170 } 1171 1172 /* 1173 * DESCRIPTION 1174 * Creates a device node 1175 * 1176 * ARGUMENTS 1177 * ParentNode = Pointer to parent device node 1178 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL 1179 * to have the root device node create one 1180 * (eg. for legacy drivers) 1181 * DeviceNode = Pointer to storage for created device node 1182 * 1183 * RETURN VALUE 1184 * Status 1185 */ 1186 NTSTATUS 1187 IopCreateDeviceNode(PDEVICE_NODE ParentNode, 1188 PDEVICE_OBJECT PhysicalDeviceObject, 1189 PUNICODE_STRING ServiceName, 1190 PDEVICE_NODE *DeviceNode) 1191 { 1192 PDEVICE_NODE Node; 1193 NTSTATUS Status; 1194 KIRQL OldIrql; 1195 UNICODE_STRING FullServiceName; 1196 UNICODE_STRING LegacyPrefix = RTL_CONSTANT_STRING(L"LEGACY_"); 1197 UNICODE_STRING UnknownDeviceName = RTL_CONSTANT_STRING(L"UNKNOWN"); 1198 UNICODE_STRING KeyName, ClassName; 1199 PUNICODE_STRING ServiceName1; 1200 ULONG LegacyValue; 1201 UNICODE_STRING ClassGUID; 1202 HANDLE InstanceHandle; 1203 1204 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n", 1205 ParentNode, PhysicalDeviceObject, ServiceName); 1206 1207 Node = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_NODE), TAG_IO_DEVNODE); 1208 if (!Node) 1209 { 1210 return STATUS_INSUFFICIENT_RESOURCES; 1211 } 1212 1213 RtlZeroMemory(Node, sizeof(DEVICE_NODE)); 1214 1215 if (!ServiceName) 1216 ServiceName1 = &UnknownDeviceName; 1217 else 1218 ServiceName1 = ServiceName; 1219 1220 if (!PhysicalDeviceObject) 1221 { 1222 FullServiceName.MaximumLength = LegacyPrefix.Length + ServiceName1->Length + sizeof(UNICODE_NULL); 1223 FullServiceName.Length = 0; 1224 FullServiceName.Buffer = ExAllocatePool(PagedPool, FullServiceName.MaximumLength); 1225 if (!FullServiceName.Buffer) 1226 { 1227 ExFreePoolWithTag(Node, TAG_IO_DEVNODE); 1228 return STATUS_INSUFFICIENT_RESOURCES; 1229 } 1230 1231 RtlAppendUnicodeStringToString(&FullServiceName, &LegacyPrefix); 1232 RtlAppendUnicodeStringToString(&FullServiceName, ServiceName1); 1233 RtlUpcaseUnicodeString(&FullServiceName, &FullServiceName, FALSE); 1234 1235 Status = PnpRootCreateDevice(&FullServiceName, NULL, &PhysicalDeviceObject, &Node->InstancePath); 1236 if (!NT_SUCCESS(Status)) 1237 { 1238 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status); 1239 ExFreePool(FullServiceName.Buffer); 1240 ExFreePoolWithTag(Node, TAG_IO_DEVNODE); 1241 return Status; 1242 } 1243 1244 /* Create the device key for legacy drivers */ 1245 Status = IopCreateDeviceKeyPath(&Node->InstancePath, REG_OPTION_VOLATILE, &InstanceHandle); 1246 if (!NT_SUCCESS(Status)) 1247 { 1248 ExFreePool(FullServiceName.Buffer); 1249 ExFreePoolWithTag(Node, TAG_IO_DEVNODE); 1250 return Status; 1251 } 1252 1253 Node->ServiceName.MaximumLength = ServiceName1->Length + sizeof(UNICODE_NULL); 1254 Node->ServiceName.Length = 0; 1255 Node->ServiceName.Buffer = ExAllocatePool(PagedPool, Node->ServiceName.MaximumLength); 1256 if (!Node->ServiceName.Buffer) 1257 { 1258 ZwClose(InstanceHandle); 1259 ExFreePool(FullServiceName.Buffer); 1260 ExFreePoolWithTag(Node, TAG_IO_DEVNODE); 1261 return Status; 1262 } 1263 1264 RtlCopyUnicodeString(&Node->ServiceName, ServiceName1); 1265 1266 if (ServiceName) 1267 { 1268 RtlInitUnicodeString(&KeyName, L"Service"); 1269 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ServiceName->Buffer, ServiceName->Length + sizeof(UNICODE_NULL)); 1270 } 1271 1272 if (NT_SUCCESS(Status)) 1273 { 1274 RtlInitUnicodeString(&KeyName, L"Legacy"); 1275 LegacyValue = 1; 1276 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_DWORD, &LegacyValue, sizeof(LegacyValue)); 1277 1278 RtlInitUnicodeString(&KeyName, L"ConfigFlags"); 1279 LegacyValue = 0; 1280 ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_DWORD, &LegacyValue, sizeof(LegacyValue)); 1281 1282 if (NT_SUCCESS(Status)) 1283 { 1284 RtlInitUnicodeString(&KeyName, L"Class"); 1285 RtlInitUnicodeString(&ClassName, L"LegacyDriver"); 1286 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassName.Buffer, ClassName.Length + sizeof(UNICODE_NULL)); 1287 if (NT_SUCCESS(Status)) 1288 { 1289 RtlInitUnicodeString(&KeyName, L"ClassGUID"); 1290 RtlInitUnicodeString(&ClassGUID, L"{8ECC055D-047F-11D1-A537-0000F8753ED1}"); 1291 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassGUID.Buffer, ClassGUID.Length + sizeof(UNICODE_NULL)); 1292 if (NT_SUCCESS(Status)) 1293 { 1294 // FIXME: Retrieve the real "description" by looking at the "DisplayName" string 1295 // of the corresponding CurrentControlSet\Services\xxx entry for this driver. 1296 RtlInitUnicodeString(&KeyName, L"DeviceDesc"); 1297 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ServiceName1->Buffer, ServiceName1->Length + sizeof(UNICODE_NULL)); 1298 } 1299 } 1300 } 1301 } 1302 1303 ZwClose(InstanceHandle); 1304 ExFreePool(FullServiceName.Buffer); 1305 1306 if (!NT_SUCCESS(Status)) 1307 { 1308 ExFreePool(Node->ServiceName.Buffer); 1309 ExFreePoolWithTag(Node, TAG_IO_DEVNODE); 1310 return Status; 1311 } 1312 1313 IopDeviceNodeSetFlag(Node, DNF_LEGACY_DRIVER); 1314 IopDeviceNodeSetFlag(Node, DNF_PROCESSED); 1315 IopDeviceNodeSetFlag(Node, DNF_ADDED); 1316 IopDeviceNodeSetFlag(Node, DNF_STARTED); 1317 } 1318 1319 Node->PhysicalDeviceObject = PhysicalDeviceObject; 1320 1321 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = Node; 1322 1323 if (ParentNode) 1324 { 1325 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 1326 Node->Parent = ParentNode; 1327 Node->Sibling = NULL; 1328 if (ParentNode->LastChild == NULL) 1329 { 1330 ParentNode->Child = Node; 1331 ParentNode->LastChild = Node; 1332 } 1333 else 1334 { 1335 ParentNode->LastChild->Sibling = Node; 1336 ParentNode->LastChild = Node; 1337 } 1338 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 1339 Node->Level = ParentNode->Level + 1; 1340 } 1341 1342 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 1343 1344 *DeviceNode = Node; 1345 1346 return STATUS_SUCCESS; 1347 } 1348 1349 NTSTATUS 1350 IopFreeDeviceNode(PDEVICE_NODE DeviceNode) 1351 { 1352 KIRQL OldIrql; 1353 PDEVICE_NODE PrevSibling = NULL; 1354 1355 /* All children must be deleted before a parent is deleted */ 1356 ASSERT(!DeviceNode->Child); 1357 ASSERT(DeviceNode->PhysicalDeviceObject); 1358 1359 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 1360 1361 /* Get previous sibling */ 1362 if (DeviceNode->Parent && DeviceNode->Parent->Child != DeviceNode) 1363 { 1364 PrevSibling = DeviceNode->Parent->Child; 1365 while (PrevSibling->Sibling != DeviceNode) 1366 PrevSibling = PrevSibling->Sibling; 1367 } 1368 1369 /* Unlink from parent if it exists */ 1370 if (DeviceNode->Parent) 1371 { 1372 if (DeviceNode->Parent->LastChild == DeviceNode) 1373 { 1374 DeviceNode->Parent->LastChild = PrevSibling; 1375 if (PrevSibling) 1376 PrevSibling->Sibling = NULL; 1377 } 1378 if (DeviceNode->Parent->Child == DeviceNode) 1379 DeviceNode->Parent->Child = DeviceNode->Sibling; 1380 } 1381 1382 /* Unlink from sibling list */ 1383 if (PrevSibling) 1384 PrevSibling->Sibling = DeviceNode->Sibling; 1385 1386 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 1387 1388 RtlFreeUnicodeString(&DeviceNode->InstancePath); 1389 1390 RtlFreeUnicodeString(&DeviceNode->ServiceName); 1391 1392 if (DeviceNode->ResourceList) 1393 { 1394 ExFreePool(DeviceNode->ResourceList); 1395 } 1396 1397 if (DeviceNode->ResourceListTranslated) 1398 { 1399 ExFreePool(DeviceNode->ResourceListTranslated); 1400 } 1401 1402 if (DeviceNode->ResourceRequirements) 1403 { 1404 ExFreePool(DeviceNode->ResourceRequirements); 1405 } 1406 1407 if (DeviceNode->BootResources) 1408 { 1409 ExFreePool(DeviceNode->BootResources); 1410 } 1411 1412 ((PEXTENDED_DEVOBJ_EXTENSION)DeviceNode->PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = NULL; 1413 ExFreePoolWithTag(DeviceNode, TAG_IO_DEVNODE); 1414 1415 return STATUS_SUCCESS; 1416 } 1417 1418 NTSTATUS 1419 NTAPI 1420 IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject, 1421 IN PIO_STACK_LOCATION IoStackLocation, 1422 OUT PVOID *Information) 1423 { 1424 PIRP Irp; 1425 PIO_STACK_LOCATION IrpStack; 1426 IO_STATUS_BLOCK IoStatusBlock; 1427 KEVENT Event; 1428 NTSTATUS Status; 1429 PDEVICE_OBJECT TopDeviceObject; 1430 PAGED_CODE(); 1431 1432 /* Call the top of the device stack */ 1433 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject); 1434 1435 /* Allocate an IRP */ 1436 Irp = IoAllocateIrp(TopDeviceObject->StackSize, FALSE); 1437 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES; 1438 1439 /* Initialize to failure */ 1440 Irp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED; 1441 Irp->IoStatus.Information = IoStatusBlock.Information = 0; 1442 1443 /* Special case for IRP_MN_FILTER_RESOURCE_REQUIREMENTS */ 1444 if ((IoStackLocation->MajorFunction == IRP_MJ_PNP) && 1445 (IoStackLocation->MinorFunction == IRP_MN_FILTER_RESOURCE_REQUIREMENTS)) 1446 { 1447 /* Copy the resource requirements list into the IOSB */ 1448 Irp->IoStatus.Information = 1449 IoStatusBlock.Information = (ULONG_PTR)IoStackLocation->Parameters.FilterResourceRequirements.IoResourceRequirementList; 1450 } 1451 1452 /* Initialize the event */ 1453 KeInitializeEvent(&Event, SynchronizationEvent, FALSE); 1454 1455 /* Set them up */ 1456 Irp->UserIosb = &IoStatusBlock; 1457 Irp->UserEvent = &Event; 1458 1459 /* Queue the IRP */ 1460 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 1461 IoQueueThreadIrp(Irp); 1462 1463 /* Copy-in the stack */ 1464 IrpStack = IoGetNextIrpStackLocation(Irp); 1465 *IrpStack = *IoStackLocation; 1466 1467 /* Call the driver */ 1468 Status = IoCallDriver(TopDeviceObject, Irp); 1469 if (Status == STATUS_PENDING) 1470 { 1471 /* Wait for it */ 1472 KeWaitForSingleObject(&Event, 1473 Executive, 1474 KernelMode, 1475 FALSE, 1476 NULL); 1477 Status = IoStatusBlock.Status; 1478 } 1479 1480 /* Remove the reference */ 1481 ObDereferenceObject(TopDeviceObject); 1482 1483 /* Return the information */ 1484 *Information = (PVOID)IoStatusBlock.Information; 1485 return Status; 1486 } 1487 1488 NTSTATUS 1489 NTAPI 1490 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject, 1491 IN OUT PIO_STATUS_BLOCK IoStatusBlock, 1492 IN UCHAR MinorFunction, 1493 IN PIO_STACK_LOCATION Stack OPTIONAL) 1494 { 1495 IO_STACK_LOCATION IoStackLocation; 1496 1497 /* Fill out the stack information */ 1498 RtlZeroMemory(&IoStackLocation, sizeof(IO_STACK_LOCATION)); 1499 IoStackLocation.MajorFunction = IRP_MJ_PNP; 1500 IoStackLocation.MinorFunction = MinorFunction; 1501 if (Stack) 1502 { 1503 /* Copy the rest */ 1504 RtlCopyMemory(&IoStackLocation.Parameters, 1505 &Stack->Parameters, 1506 sizeof(Stack->Parameters)); 1507 } 1508 1509 /* Do the PnP call */ 1510 IoStatusBlock->Status = IopSynchronousCall(DeviceObject, 1511 &IoStackLocation, 1512 (PVOID)&IoStatusBlock->Information); 1513 return IoStatusBlock->Status; 1514 } 1515 1516 NTSTATUS 1517 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context) 1518 { 1519 PDEVICE_NODE ParentDeviceNode; 1520 PDEVICE_NODE ChildDeviceNode; 1521 PDEVICE_NODE NextDeviceNode; 1522 NTSTATUS Status; 1523 1524 /* Copy context data so we don't overwrite it in subsequent calls to this function */ 1525 ParentDeviceNode = Context->DeviceNode; 1526 1527 /* HACK: Keep a reference to the PDO so we can keep traversing the tree 1528 * if the device is deleted. In a perfect world, children would have to be 1529 * deleted before their parents, and we'd restart the traversal after 1530 * deleting a device node. */ 1531 ObReferenceObject(ParentDeviceNode->PhysicalDeviceObject); 1532 1533 /* Call the action routine */ 1534 Status = (Context->Action)(ParentDeviceNode, Context->Context); 1535 if (!NT_SUCCESS(Status)) 1536 { 1537 ObDereferenceObject(ParentDeviceNode->PhysicalDeviceObject); 1538 return Status; 1539 } 1540 1541 /* Traversal of all children nodes */ 1542 for (ChildDeviceNode = ParentDeviceNode->Child; 1543 ChildDeviceNode != NULL; 1544 ChildDeviceNode = NextDeviceNode) 1545 { 1546 /* HACK: We need this reference to ensure we can get Sibling below. */ 1547 ObReferenceObject(ChildDeviceNode->PhysicalDeviceObject); 1548 1549 /* Pass the current device node to the action routine */ 1550 Context->DeviceNode = ChildDeviceNode; 1551 1552 Status = IopTraverseDeviceTreeNode(Context); 1553 if (!NT_SUCCESS(Status)) 1554 { 1555 ObDereferenceObject(ChildDeviceNode->PhysicalDeviceObject); 1556 ObDereferenceObject(ParentDeviceNode->PhysicalDeviceObject); 1557 return Status; 1558 } 1559 1560 NextDeviceNode = ChildDeviceNode->Sibling; 1561 ObDereferenceObject(ChildDeviceNode->PhysicalDeviceObject); 1562 } 1563 1564 ObDereferenceObject(ParentDeviceNode->PhysicalDeviceObject); 1565 return Status; 1566 } 1567 1568 1569 NTSTATUS 1570 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context) 1571 { 1572 NTSTATUS Status; 1573 1574 DPRINT("Context 0x%p\n", Context); 1575 1576 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %p Context 0x%p)\n", 1577 Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context); 1578 1579 /* Start from the specified device node */ 1580 Context->DeviceNode = Context->FirstDeviceNode; 1581 1582 /* Recursively traverse the device tree */ 1583 Status = IopTraverseDeviceTreeNode(Context); 1584 if (Status == STATUS_UNSUCCESSFUL) 1585 { 1586 /* The action routine just wanted to terminate the traversal with status 1587 code STATUS_SUCCESS */ 1588 Status = STATUS_SUCCESS; 1589 } 1590 1591 return Status; 1592 } 1593 1594 1595 /* 1596 * IopCreateDeviceKeyPath 1597 * 1598 * Creates a registry key 1599 * 1600 * Parameters 1601 * RegistryPath 1602 * Name of the key to be created. 1603 * Handle 1604 * Handle to the newly created key 1605 * 1606 * Remarks 1607 * This method can create nested trees, so parent of RegistryPath can 1608 * be not existant, and will be created if needed. 1609 */ 1610 NTSTATUS 1611 NTAPI 1612 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath, 1613 IN ULONG CreateOptions, 1614 OUT PHANDLE Handle) 1615 { 1616 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT); 1617 HANDLE hParent = NULL, hKey; 1618 OBJECT_ATTRIBUTES ObjectAttributes; 1619 UNICODE_STRING KeyName; 1620 PCWSTR Current, Last; 1621 USHORT Length; 1622 NTSTATUS Status; 1623 1624 /* Assume failure */ 1625 *Handle = NULL; 1626 1627 /* Open root key for device instances */ 1628 Status = IopOpenRegistryKeyEx(&hParent, NULL, &EnumU, KEY_CREATE_SUB_KEY); 1629 if (!NT_SUCCESS(Status)) 1630 { 1631 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status); 1632 return Status; 1633 } 1634 1635 Current = KeyName.Buffer = RegistryPath->Buffer; 1636 Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)]; 1637 1638 /* Go up to the end of the string */ 1639 while (Current <= Last) 1640 { 1641 if (Current != Last && *Current != L'\\') 1642 { 1643 /* Not the end of the string and not a separator */ 1644 Current++; 1645 continue; 1646 } 1647 1648 /* Prepare relative key name */ 1649 Length = (USHORT)((ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer); 1650 KeyName.MaximumLength = KeyName.Length = Length; 1651 DPRINT("Create '%wZ'\n", &KeyName); 1652 1653 /* Open key */ 1654 InitializeObjectAttributes(&ObjectAttributes, 1655 &KeyName, 1656 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 1657 hParent, 1658 NULL); 1659 Status = ZwCreateKey(&hKey, 1660 Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY, 1661 &ObjectAttributes, 1662 0, 1663 NULL, 1664 CreateOptions, 1665 NULL); 1666 1667 /* Close parent key handle, we don't need it anymore */ 1668 if (hParent) 1669 ZwClose(hParent); 1670 1671 /* Key opening/creating failed? */ 1672 if (!NT_SUCCESS(Status)) 1673 { 1674 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status); 1675 return Status; 1676 } 1677 1678 /* Check if it is the end of the string */ 1679 if (Current == Last) 1680 { 1681 /* Yes, return success */ 1682 *Handle = hKey; 1683 return STATUS_SUCCESS; 1684 } 1685 1686 /* Start with this new parent key */ 1687 hParent = hKey; 1688 Current++; 1689 KeyName.Buffer = (PWSTR)Current; 1690 } 1691 1692 return STATUS_UNSUCCESSFUL; 1693 } 1694 1695 NTSTATUS 1696 IopSetDeviceInstanceData(HANDLE InstanceKey, 1697 PDEVICE_NODE DeviceNode) 1698 { 1699 OBJECT_ATTRIBUTES ObjectAttributes; 1700 UNICODE_STRING KeyName; 1701 HANDLE LogConfKey, ControlKey, DeviceParamsKey; 1702 ULONG ResCount; 1703 ULONG ResultLength; 1704 NTSTATUS Status; 1705 1706 DPRINT("IopSetDeviceInstanceData() called\n"); 1707 1708 /* Create the 'LogConf' key */ 1709 RtlInitUnicodeString(&KeyName, L"LogConf"); 1710 InitializeObjectAttributes(&ObjectAttributes, 1711 &KeyName, 1712 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 1713 InstanceKey, 1714 NULL); 1715 Status = ZwCreateKey(&LogConfKey, 1716 KEY_ALL_ACCESS, 1717 &ObjectAttributes, 1718 0, 1719 NULL, 1720 // FIXME? In r53694 it was silently turned from non-volatile into this, 1721 // without any extra warning. Is this still needed?? 1722 REG_OPTION_VOLATILE, 1723 NULL); 1724 if (NT_SUCCESS(Status)) 1725 { 1726 /* Set 'BootConfig' value */ 1727 if (DeviceNode->BootResources != NULL) 1728 { 1729 ResCount = DeviceNode->BootResources->Count; 1730 if (ResCount != 0) 1731 { 1732 RtlInitUnicodeString(&KeyName, L"BootConfig"); 1733 Status = ZwSetValueKey(LogConfKey, 1734 &KeyName, 1735 0, 1736 REG_RESOURCE_LIST, 1737 DeviceNode->BootResources, 1738 PnpDetermineResourceListSize(DeviceNode->BootResources)); 1739 } 1740 } 1741 1742 /* Set 'BasicConfigVector' value */ 1743 if (DeviceNode->ResourceRequirements != NULL && 1744 DeviceNode->ResourceRequirements->ListSize != 0) 1745 { 1746 RtlInitUnicodeString(&KeyName, L"BasicConfigVector"); 1747 Status = ZwSetValueKey(LogConfKey, 1748 &KeyName, 1749 0, 1750 REG_RESOURCE_REQUIREMENTS_LIST, 1751 DeviceNode->ResourceRequirements, 1752 DeviceNode->ResourceRequirements->ListSize); 1753 } 1754 1755 ZwClose(LogConfKey); 1756 } 1757 1758 /* Set the 'ConfigFlags' value */ 1759 RtlInitUnicodeString(&KeyName, L"ConfigFlags"); 1760 Status = ZwQueryValueKey(InstanceKey, 1761 &KeyName, 1762 KeyValueBasicInformation, 1763 NULL, 1764 0, 1765 &ResultLength); 1766 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 1767 { 1768 /* Write the default value */ 1769 ULONG DefaultConfigFlags = 0; 1770 Status = ZwSetValueKey(InstanceKey, 1771 &KeyName, 1772 0, 1773 REG_DWORD, 1774 &DefaultConfigFlags, 1775 sizeof(DefaultConfigFlags)); 1776 } 1777 1778 /* Create the 'Control' key */ 1779 RtlInitUnicodeString(&KeyName, L"Control"); 1780 InitializeObjectAttributes(&ObjectAttributes, 1781 &KeyName, 1782 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 1783 InstanceKey, 1784 NULL); 1785 Status = ZwCreateKey(&ControlKey, 1786 0, 1787 &ObjectAttributes, 1788 0, 1789 NULL, 1790 REG_OPTION_VOLATILE, 1791 NULL); 1792 if (NT_SUCCESS(Status)) 1793 ZwClose(ControlKey); 1794 1795 /* Create the 'Device Parameters' key and set the 'FirmwareIdentified' value for all ACPI-enumerated devices */ 1796 if (_wcsnicmp(DeviceNode->InstancePath.Buffer, L"ACPI\\", 5) == 0) 1797 { 1798 RtlInitUnicodeString(&KeyName, L"Device Parameters"); 1799 InitializeObjectAttributes(&ObjectAttributes, 1800 &KeyName, 1801 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 1802 InstanceKey, 1803 NULL); 1804 Status = ZwCreateKey(&DeviceParamsKey, 1805 0, 1806 &ObjectAttributes, 1807 0, 1808 NULL, 1809 REG_OPTION_NON_VOLATILE, 1810 NULL); 1811 if (NT_SUCCESS(Status)) 1812 { 1813 ULONG FirmwareIdentified = 1; 1814 RtlInitUnicodeString(&KeyName, L"FirmwareIdentified"); 1815 Status = ZwSetValueKey(DeviceParamsKey, 1816 &KeyName, 1817 0, 1818 REG_DWORD, 1819 &FirmwareIdentified, 1820 sizeof(FirmwareIdentified)); 1821 1822 ZwClose(DeviceParamsKey); 1823 } 1824 } 1825 1826 DPRINT("IopSetDeviceInstanceData() done\n"); 1827 1828 return Status; 1829 } 1830 1831 /* 1832 * IopGetParentIdPrefix 1833 * 1834 * Retrieve (or create) a string which identifies a device. 1835 * 1836 * Parameters 1837 * DeviceNode 1838 * Pointer to device node. 1839 * ParentIdPrefix 1840 * Pointer to the string where is returned the parent node identifier 1841 * 1842 * Remarks 1843 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is 1844 * valid and its Buffer field is NULL-terminated. The caller needs to 1845 * to free the string with RtlFreeUnicodeString when it is no longer 1846 * needed. 1847 */ 1848 1849 NTSTATUS 1850 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode, 1851 PUNICODE_STRING ParentIdPrefix) 1852 { 1853 const UNICODE_STRING EnumKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\"); 1854 ULONG KeyNameBufferLength; 1855 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL; 1856 UNICODE_STRING KeyName = {0, 0, NULL}; 1857 UNICODE_STRING KeyValue; 1858 UNICODE_STRING ValueName; 1859 HANDLE hKey = NULL; 1860 ULONG crc32; 1861 NTSTATUS Status; 1862 1863 /* HACK: As long as some devices have a NULL device 1864 * instance path, the following test is required :( 1865 */ 1866 if (DeviceNode->Parent->InstancePath.Length == 0) 1867 { 1868 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n", 1869 &DeviceNode->InstancePath); 1870 return STATUS_UNSUCCESSFUL; 1871 } 1872 1873 /* 1. Try to retrieve ParentIdPrefix from registry */ 1874 KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(L"12345678&12345678"); 1875 ParentIdPrefixInformation = ExAllocatePoolWithTag(PagedPool, 1876 KeyNameBufferLength + sizeof(UNICODE_NULL), 1877 TAG_IO); 1878 if (!ParentIdPrefixInformation) 1879 { 1880 return STATUS_INSUFFICIENT_RESOURCES; 1881 } 1882 1883 KeyName.Length = 0; 1884 KeyName.MaximumLength = EnumKeyPath.Length + 1885 DeviceNode->Parent->InstancePath.Length + 1886 sizeof(UNICODE_NULL); 1887 KeyName.Buffer = ExAllocatePoolWithTag(PagedPool, 1888 KeyName.MaximumLength, 1889 TAG_IO); 1890 if (!KeyName.Buffer) 1891 { 1892 Status = STATUS_INSUFFICIENT_RESOURCES; 1893 goto cleanup; 1894 } 1895 1896 RtlCopyUnicodeString(&KeyName, &EnumKeyPath); 1897 RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath); 1898 1899 Status = IopOpenRegistryKeyEx(&hKey, NULL, &KeyName, KEY_QUERY_VALUE | KEY_SET_VALUE); 1900 if (!NT_SUCCESS(Status)) 1901 { 1902 goto cleanup; 1903 } 1904 RtlInitUnicodeString(&ValueName, L"ParentIdPrefix"); 1905 Status = ZwQueryValueKey(hKey, 1906 &ValueName, 1907 KeyValuePartialInformation, 1908 ParentIdPrefixInformation, 1909 KeyNameBufferLength, 1910 &KeyNameBufferLength); 1911 if (NT_SUCCESS(Status)) 1912 { 1913 if (ParentIdPrefixInformation->Type != REG_SZ) 1914 { 1915 Status = STATUS_UNSUCCESSFUL; 1916 } 1917 else 1918 { 1919 KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength; 1920 KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL); 1921 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data; 1922 ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL); 1923 } 1924 goto cleanup; 1925 } 1926 if (Status != STATUS_OBJECT_NAME_NOT_FOUND) 1927 { 1928 /* FIXME how do we get here and why is ParentIdPrefixInformation valid? */ 1929 KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength; 1930 KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL); 1931 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data; 1932 ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL); 1933 goto cleanup; 1934 } 1935 1936 /* 2. Create the ParentIdPrefix value */ 1937 crc32 = RtlComputeCrc32(0, 1938 (PUCHAR)DeviceNode->Parent->InstancePath.Buffer, 1939 DeviceNode->Parent->InstancePath.Length); 1940 1941 RtlStringCbPrintfW((PWSTR)ParentIdPrefixInformation, 1942 KeyNameBufferLength, 1943 L"%lx&%lx", 1944 DeviceNode->Parent->Level, 1945 crc32); 1946 RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation); 1947 1948 /* 3. Try to write the ParentIdPrefix to registry */ 1949 Status = ZwSetValueKey(hKey, 1950 &ValueName, 1951 0, 1952 REG_SZ, 1953 KeyValue.Buffer, 1954 ((ULONG)wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR)); 1955 1956 cleanup: 1957 if (NT_SUCCESS(Status)) 1958 { 1959 /* Duplicate the string to return it */ 1960 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 1961 &KeyValue, 1962 ParentIdPrefix); 1963 } 1964 ExFreePoolWithTag(ParentIdPrefixInformation, TAG_IO); 1965 RtlFreeUnicodeString(&KeyName); 1966 if (hKey != NULL) 1967 { 1968 ZwClose(hKey); 1969 } 1970 return Status; 1971 } 1972 1973 static 1974 BOOLEAN 1975 IopValidateID( 1976 _In_ PWCHAR Id, 1977 _In_ BUS_QUERY_ID_TYPE QueryType) 1978 { 1979 PWCHAR PtrChar; 1980 PWCHAR StringEnd; 1981 WCHAR Char; 1982 ULONG SeparatorsCount = 0; 1983 PWCHAR PtrPrevChar = NULL; 1984 ULONG MaxSeparators; 1985 BOOLEAN IsMultiSz; 1986 1987 PAGED_CODE(); 1988 1989 switch (QueryType) 1990 { 1991 case BusQueryDeviceID: 1992 MaxSeparators = MAX_SEPARATORS_DEVICEID; 1993 IsMultiSz = FALSE; 1994 break; 1995 case BusQueryInstanceID: 1996 MaxSeparators = MAX_SEPARATORS_INSTANCEID; 1997 IsMultiSz = FALSE; 1998 break; 1999 2000 case BusQueryHardwareIDs: 2001 case BusQueryCompatibleIDs: 2002 MaxSeparators = MAX_SEPARATORS_DEVICEID; 2003 IsMultiSz = TRUE; 2004 break; 2005 2006 default: 2007 DPRINT1("IopValidateID: Not handled QueryType - %x\n", QueryType); 2008 return FALSE; 2009 } 2010 2011 StringEnd = Id + MAX_DEVICE_ID_LEN; 2012 2013 for (PtrChar = Id; PtrChar < StringEnd; PtrChar++) 2014 { 2015 Char = *PtrChar; 2016 2017 if (Char == UNICODE_NULL) 2018 { 2019 if (!IsMultiSz || (PtrPrevChar && PtrChar == PtrPrevChar + 1)) 2020 { 2021 if (MaxSeparators == SeparatorsCount || IsMultiSz) 2022 { 2023 return TRUE; 2024 } 2025 2026 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n", 2027 SeparatorsCount, MaxSeparators); 2028 goto ErrorExit; 2029 } 2030 2031 StringEnd = PtrChar + MAX_DEVICE_ID_LEN + 1; 2032 PtrPrevChar = PtrChar; 2033 SeparatorsCount = 0; 2034 } 2035 else if (Char < ' ' || Char > 0x7F || Char == ',') 2036 { 2037 DPRINT1("IopValidateID: Invalid character - %04X\n", Char); 2038 goto ErrorExit; 2039 } 2040 else if (Char == ' ') 2041 { 2042 *PtrChar = '_'; 2043 } 2044 else if (Char == '\\') 2045 { 2046 SeparatorsCount++; 2047 2048 if (SeparatorsCount > MaxSeparators) 2049 { 2050 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n", 2051 SeparatorsCount, MaxSeparators); 2052 goto ErrorExit; 2053 } 2054 } 2055 } 2056 2057 DPRINT1("IopValidateID: Not terminated ID\n"); 2058 2059 ErrorExit: 2060 // FIXME logging 2061 return FALSE; 2062 } 2063 2064 NTSTATUS 2065 IopQueryHardwareIds(PDEVICE_NODE DeviceNode, 2066 HANDLE InstanceKey) 2067 { 2068 IO_STACK_LOCATION Stack; 2069 IO_STATUS_BLOCK IoStatusBlock; 2070 PWSTR Ptr; 2071 UNICODE_STRING ValueName; 2072 NTSTATUS Status; 2073 ULONG Length, TotalLength; 2074 BOOLEAN IsValidID; 2075 2076 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n"); 2077 2078 RtlZeroMemory(&Stack, sizeof(Stack)); 2079 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs; 2080 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 2081 &IoStatusBlock, 2082 IRP_MN_QUERY_ID, 2083 &Stack); 2084 if (NT_SUCCESS(Status)) 2085 { 2086 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryHardwareIDs); 2087 2088 if (!IsValidID) 2089 { 2090 DPRINT1("Invalid HardwareIDs. DeviceNode - %p\n", DeviceNode); 2091 } 2092 2093 TotalLength = 0; 2094 2095 Ptr = (PWSTR)IoStatusBlock.Information; 2096 DPRINT("Hardware IDs:\n"); 2097 while (*Ptr) 2098 { 2099 DPRINT(" %S\n", Ptr); 2100 Length = (ULONG)wcslen(Ptr) + 1; 2101 2102 Ptr += Length; 2103 TotalLength += Length; 2104 } 2105 DPRINT("TotalLength: %hu\n", TotalLength); 2106 DPRINT("\n"); 2107 2108 RtlInitUnicodeString(&ValueName, L"HardwareID"); 2109 Status = ZwSetValueKey(InstanceKey, 2110 &ValueName, 2111 0, 2112 REG_MULTI_SZ, 2113 (PVOID)IoStatusBlock.Information, 2114 (TotalLength + 1) * sizeof(WCHAR)); 2115 if (!NT_SUCCESS(Status)) 2116 { 2117 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status); 2118 } 2119 } 2120 else 2121 { 2122 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status); 2123 } 2124 2125 return Status; 2126 } 2127 2128 NTSTATUS 2129 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode, 2130 HANDLE InstanceKey) 2131 { 2132 IO_STACK_LOCATION Stack; 2133 IO_STATUS_BLOCK IoStatusBlock; 2134 PWSTR Ptr; 2135 UNICODE_STRING ValueName; 2136 NTSTATUS Status; 2137 ULONG Length, TotalLength; 2138 BOOLEAN IsValidID; 2139 2140 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n"); 2141 2142 RtlZeroMemory(&Stack, sizeof(Stack)); 2143 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs; 2144 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 2145 &IoStatusBlock, 2146 IRP_MN_QUERY_ID, 2147 &Stack); 2148 if (NT_SUCCESS(Status) && IoStatusBlock.Information) 2149 { 2150 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryCompatibleIDs); 2151 2152 if (!IsValidID) 2153 { 2154 DPRINT1("Invalid CompatibleIDs. DeviceNode - %p\n", DeviceNode); 2155 } 2156 2157 TotalLength = 0; 2158 2159 Ptr = (PWSTR)IoStatusBlock.Information; 2160 DPRINT("Compatible IDs:\n"); 2161 while (*Ptr) 2162 { 2163 DPRINT(" %S\n", Ptr); 2164 Length = (ULONG)wcslen(Ptr) + 1; 2165 2166 Ptr += Length; 2167 TotalLength += Length; 2168 } 2169 DPRINT("TotalLength: %hu\n", TotalLength); 2170 DPRINT("\n"); 2171 2172 RtlInitUnicodeString(&ValueName, L"CompatibleIDs"); 2173 Status = ZwSetValueKey(InstanceKey, 2174 &ValueName, 2175 0, 2176 REG_MULTI_SZ, 2177 (PVOID)IoStatusBlock.Information, 2178 (TotalLength + 1) * sizeof(WCHAR)); 2179 if (!NT_SUCCESS(Status)) 2180 { 2181 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status); 2182 } 2183 } 2184 else 2185 { 2186 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status); 2187 } 2188 2189 return Status; 2190 } 2191 2192 NTSTATUS 2193 IopCreateDeviceInstancePath( 2194 _In_ PDEVICE_NODE DeviceNode, 2195 _Out_ PUNICODE_STRING InstancePath) 2196 { 2197 IO_STATUS_BLOCK IoStatusBlock; 2198 UNICODE_STRING DeviceId; 2199 UNICODE_STRING InstanceId; 2200 IO_STACK_LOCATION Stack; 2201 NTSTATUS Status; 2202 UNICODE_STRING ParentIdPrefix = { 0, 0, NULL }; 2203 DEVICE_CAPABILITIES DeviceCapabilities; 2204 BOOLEAN IsValidID; 2205 2206 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n"); 2207 2208 Stack.Parameters.QueryId.IdType = BusQueryDeviceID; 2209 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 2210 &IoStatusBlock, 2211 IRP_MN_QUERY_ID, 2212 &Stack); 2213 if (!NT_SUCCESS(Status)) 2214 { 2215 DPRINT1("IopInitiatePnpIrp(BusQueryDeviceID) failed (Status %x)\n", Status); 2216 return Status; 2217 } 2218 2219 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryDeviceID); 2220 2221 if (!IsValidID) 2222 { 2223 DPRINT1("Invalid DeviceID. DeviceNode - %p\n", DeviceNode); 2224 } 2225 2226 /* Save the device id string */ 2227 RtlInitUnicodeString(&DeviceId, (PWSTR)IoStatusBlock.Information); 2228 2229 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n"); 2230 2231 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities); 2232 if (!NT_SUCCESS(Status)) 2233 { 2234 DPRINT1("IopQueryDeviceCapabilities() failed (Status 0x%08lx)\n", Status); 2235 RtlFreeUnicodeString(&DeviceId); 2236 return Status; 2237 } 2238 2239 /* This bit is only check after enumeration */ 2240 if (DeviceCapabilities.HardwareDisabled) 2241 { 2242 /* FIXME: Cleanup device */ 2243 DeviceNode->Flags |= DNF_DISABLED; 2244 RtlFreeUnicodeString(&DeviceId); 2245 return STATUS_PLUGPLAY_NO_DEVICE; 2246 } 2247 else 2248 { 2249 DeviceNode->Flags &= ~DNF_DISABLED; 2250 } 2251 2252 if (!DeviceCapabilities.UniqueID) 2253 { 2254 /* Device has not a unique ID. We need to prepend parent bus unique identifier */ 2255 DPRINT("Instance ID is not unique\n"); 2256 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix); 2257 if (!NT_SUCCESS(Status)) 2258 { 2259 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status); 2260 RtlFreeUnicodeString(&DeviceId); 2261 return Status; 2262 } 2263 } 2264 2265 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n"); 2266 2267 Stack.Parameters.QueryId.IdType = BusQueryInstanceID; 2268 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 2269 &IoStatusBlock, 2270 IRP_MN_QUERY_ID, 2271 &Stack); 2272 if (!NT_SUCCESS(Status)) 2273 { 2274 DPRINT("IopInitiatePnpIrp(BusQueryInstanceID) failed (Status %lx)\n", Status); 2275 ASSERT(IoStatusBlock.Information == 0); 2276 } 2277 2278 if (IoStatusBlock.Information) 2279 { 2280 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryInstanceID); 2281 2282 if (!IsValidID) 2283 { 2284 DPRINT1("Invalid InstanceID. DeviceNode - %p\n", DeviceNode); 2285 } 2286 } 2287 2288 RtlInitUnicodeString(&InstanceId, 2289 (PWSTR)IoStatusBlock.Information); 2290 2291 InstancePath->Length = 0; 2292 InstancePath->MaximumLength = DeviceId.Length + sizeof(WCHAR) + 2293 ParentIdPrefix.Length + 2294 InstanceId.Length + 2295 sizeof(UNICODE_NULL); 2296 if (ParentIdPrefix.Length && InstanceId.Length) 2297 { 2298 InstancePath->MaximumLength += sizeof(WCHAR); 2299 } 2300 2301 InstancePath->Buffer = ExAllocatePoolWithTag(PagedPool, 2302 InstancePath->MaximumLength, 2303 TAG_IO); 2304 if (!InstancePath->Buffer) 2305 { 2306 RtlFreeUnicodeString(&InstanceId); 2307 RtlFreeUnicodeString(&ParentIdPrefix); 2308 RtlFreeUnicodeString(&DeviceId); 2309 return STATUS_INSUFFICIENT_RESOURCES; 2310 } 2311 2312 /* Start with the device id */ 2313 RtlCopyUnicodeString(InstancePath, &DeviceId); 2314 RtlAppendUnicodeToString(InstancePath, L"\\"); 2315 2316 /* Add information from parent bus device to InstancePath */ 2317 RtlAppendUnicodeStringToString(InstancePath, &ParentIdPrefix); 2318 if (ParentIdPrefix.Length && InstanceId.Length) 2319 { 2320 RtlAppendUnicodeToString(InstancePath, L"&"); 2321 } 2322 2323 /* Finally, add the id returned by the driver stack */ 2324 RtlAppendUnicodeStringToString(InstancePath, &InstanceId); 2325 2326 /* 2327 * FIXME: Check for valid characters, if there is invalid characters 2328 * then bugcheck 2329 */ 2330 2331 RtlFreeUnicodeString(&InstanceId); 2332 RtlFreeUnicodeString(&DeviceId); 2333 RtlFreeUnicodeString(&ParentIdPrefix); 2334 2335 return STATUS_SUCCESS; 2336 } 2337 2338 /* 2339 * IopActionInterrogateDeviceStack 2340 * 2341 * Retrieve information for all (direct) child nodes of a parent node. 2342 * 2343 * Parameters 2344 * DeviceNode 2345 * Pointer to device node. 2346 * Context 2347 * Pointer to parent node to retrieve child node information for. 2348 * 2349 * Remarks 2350 * Any errors that occur are logged instead so that all child services have a chance 2351 * of being interrogated. 2352 */ 2353 2354 NTSTATUS 2355 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode, 2356 PVOID Context) 2357 { 2358 IO_STATUS_BLOCK IoStatusBlock; 2359 PWSTR DeviceDescription; 2360 PWSTR LocationInformation; 2361 PDEVICE_NODE ParentDeviceNode; 2362 IO_STACK_LOCATION Stack; 2363 NTSTATUS Status; 2364 ULONG RequiredLength; 2365 LCID LocaleId; 2366 HANDLE InstanceKey = NULL; 2367 UNICODE_STRING ValueName; 2368 UNICODE_STRING InstancePathU; 2369 PDEVICE_OBJECT OldDeviceObject; 2370 2371 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context); 2372 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject); 2373 2374 ParentDeviceNode = (PDEVICE_NODE)Context; 2375 2376 /* 2377 * We are called for the parent too, but we don't need to do special 2378 * handling for this node 2379 */ 2380 if (DeviceNode == ParentDeviceNode) 2381 { 2382 DPRINT("Success\n"); 2383 return STATUS_SUCCESS; 2384 } 2385 2386 /* 2387 * Make sure this device node is a direct child of the parent device node 2388 * that is given as an argument 2389 */ 2390 if (DeviceNode->Parent != ParentDeviceNode) 2391 { 2392 DPRINT("Skipping 2+ level child\n"); 2393 return STATUS_SUCCESS; 2394 } 2395 2396 /* Skip processing if it was already completed before */ 2397 if (DeviceNode->Flags & DNF_PROCESSED) 2398 { 2399 /* Nothing to do */ 2400 return STATUS_SUCCESS; 2401 } 2402 2403 /* Get Locale ID */ 2404 Status = ZwQueryDefaultLocale(FALSE, &LocaleId); 2405 if (!NT_SUCCESS(Status)) 2406 { 2407 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status); 2408 return Status; 2409 } 2410 2411 /* 2412 * FIXME: For critical errors, cleanup and disable device, but always 2413 * return STATUS_SUCCESS. 2414 */ 2415 2416 Status = IopCreateDeviceInstancePath(DeviceNode, &InstancePathU); 2417 if (!NT_SUCCESS(Status)) 2418 { 2419 if (Status != STATUS_PLUGPLAY_NO_DEVICE) 2420 { 2421 DPRINT1("IopCreateDeviceInstancePath() failed with status 0x%lx\n", Status); 2422 } 2423 2424 /* We have to return success otherwise we abort the traverse operation */ 2425 return STATUS_SUCCESS; 2426 } 2427 2428 /* Verify that this is not a duplicate */ 2429 OldDeviceObject = IopGetDeviceObjectFromDeviceInstance(&InstancePathU); 2430 if (OldDeviceObject != NULL) 2431 { 2432 PDEVICE_NODE OldDeviceNode = IopGetDeviceNode(OldDeviceObject); 2433 2434 DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU); 2435 DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode->Parent->InstancePath); 2436 DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode->Parent->InstancePath); 2437 2438 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 2439 0x01, 2440 (ULONG_PTR)DeviceNode->PhysicalDeviceObject, 2441 (ULONG_PTR)OldDeviceObject, 2442 0); 2443 } 2444 2445 DeviceNode->InstancePath = InstancePathU; 2446 2447 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer); 2448 2449 /* 2450 * Create registry key for the instance id, if it doesn't exist yet 2451 */ 2452 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey); 2453 if (!NT_SUCCESS(Status)) 2454 { 2455 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status); 2456 2457 /* We have to return success otherwise we abort the traverse operation */ 2458 return STATUS_SUCCESS; 2459 } 2460 2461 IopQueryHardwareIds(DeviceNode, InstanceKey); 2462 2463 IopQueryCompatibleIds(DeviceNode, InstanceKey); 2464 2465 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n"); 2466 2467 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription; 2468 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId; 2469 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 2470 &IoStatusBlock, 2471 IRP_MN_QUERY_DEVICE_TEXT, 2472 &Stack); 2473 DeviceDescription = NT_SUCCESS(Status) ? (PWSTR)IoStatusBlock.Information 2474 : NULL; 2475 /* This key is mandatory, so even if the Irp fails, we still write it */ 2476 RtlInitUnicodeString(&ValueName, L"DeviceDesc"); 2477 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND) 2478 { 2479 if (DeviceDescription && 2480 *DeviceDescription != UNICODE_NULL) 2481 { 2482 /* This key is overriden when a driver is installed. Don't write the 2483 * new description if another one already exists */ 2484 Status = ZwSetValueKey(InstanceKey, 2485 &ValueName, 2486 0, 2487 REG_SZ, 2488 DeviceDescription, 2489 ((ULONG)wcslen(DeviceDescription) + 1) * sizeof(WCHAR)); 2490 } 2491 else 2492 { 2493 UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device"); 2494 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status); 2495 2496 Status = ZwSetValueKey(InstanceKey, 2497 &ValueName, 2498 0, 2499 REG_SZ, 2500 DeviceDesc.Buffer, 2501 DeviceDesc.MaximumLength); 2502 if (!NT_SUCCESS(Status)) 2503 { 2504 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status); 2505 } 2506 2507 } 2508 } 2509 2510 if (DeviceDescription) 2511 { 2512 ExFreePoolWithTag(DeviceDescription, 0); 2513 } 2514 2515 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n"); 2516 2517 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation; 2518 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId; 2519 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 2520 &IoStatusBlock, 2521 IRP_MN_QUERY_DEVICE_TEXT, 2522 &Stack); 2523 if (NT_SUCCESS(Status) && IoStatusBlock.Information) 2524 { 2525 LocationInformation = (PWSTR)IoStatusBlock.Information; 2526 DPRINT("LocationInformation: %S\n", LocationInformation); 2527 RtlInitUnicodeString(&ValueName, L"LocationInformation"); 2528 Status = ZwSetValueKey(InstanceKey, 2529 &ValueName, 2530 0, 2531 REG_SZ, 2532 LocationInformation, 2533 ((ULONG)wcslen(LocationInformation) + 1) * sizeof(WCHAR)); 2534 if (!NT_SUCCESS(Status)) 2535 { 2536 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status); 2537 } 2538 2539 ExFreePoolWithTag(LocationInformation, 0); 2540 } 2541 else 2542 { 2543 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); 2544 } 2545 2546 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n"); 2547 2548 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 2549 &IoStatusBlock, 2550 IRP_MN_QUERY_BUS_INFORMATION, 2551 NULL); 2552 if (NT_SUCCESS(Status) && IoStatusBlock.Information) 2553 { 2554 PPNP_BUS_INFORMATION BusInformation = (PPNP_BUS_INFORMATION)IoStatusBlock.Information; 2555 2556 DeviceNode->ChildBusNumber = BusInformation->BusNumber; 2557 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType; 2558 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid); 2559 ExFreePoolWithTag(BusInformation, 0); 2560 } 2561 else 2562 { 2563 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); 2564 2565 DeviceNode->ChildBusNumber = 0xFFFFFFF0; 2566 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined; 2567 DeviceNode->ChildBusTypeIndex = -1; 2568 } 2569 2570 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n"); 2571 2572 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 2573 &IoStatusBlock, 2574 IRP_MN_QUERY_RESOURCES, 2575 NULL); 2576 if (NT_SUCCESS(Status) && IoStatusBlock.Information) 2577 { 2578 DeviceNode->BootResources = (PCM_RESOURCE_LIST)IoStatusBlock.Information; 2579 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG); 2580 } 2581 else 2582 { 2583 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); 2584 DeviceNode->BootResources = NULL; 2585 } 2586 2587 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n"); 2588 2589 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 2590 &IoStatusBlock, 2591 IRP_MN_QUERY_RESOURCE_REQUIREMENTS, 2592 NULL); 2593 if (NT_SUCCESS(Status)) 2594 { 2595 DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information; 2596 } 2597 else 2598 { 2599 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status); 2600 DeviceNode->ResourceRequirements = NULL; 2601 } 2602 2603 if (InstanceKey != NULL) 2604 { 2605 IopSetDeviceInstanceData(InstanceKey, DeviceNode); 2606 } 2607 2608 ZwClose(InstanceKey); 2609 2610 IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED); 2611 2612 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER)) 2613 { 2614 /* Report the device to the user-mode pnp manager */ 2615 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED, 2616 &DeviceNode->InstancePath); 2617 } 2618 2619 return STATUS_SUCCESS; 2620 } 2621 2622 static 2623 VOID 2624 IopHandleDeviceRemoval( 2625 IN PDEVICE_NODE DeviceNode, 2626 IN PDEVICE_RELATIONS DeviceRelations) 2627 { 2628 PDEVICE_NODE Child = DeviceNode->Child, NextChild; 2629 ULONG i; 2630 BOOLEAN Found; 2631 2632 if (DeviceNode == IopRootDeviceNode) 2633 return; 2634 2635 while (Child != NULL) 2636 { 2637 NextChild = Child->Sibling; 2638 Found = FALSE; 2639 2640 for (i = 0; DeviceRelations && i < DeviceRelations->Count; i++) 2641 { 2642 if (IopGetDeviceNode(DeviceRelations->Objects[i]) == Child) 2643 { 2644 Found = TRUE; 2645 break; 2646 } 2647 } 2648 2649 if (!Found && !(Child->Flags & DNF_WILL_BE_REMOVED)) 2650 { 2651 /* Send removal IRPs to all of its children */ 2652 IopPrepareDeviceForRemoval(Child->PhysicalDeviceObject, TRUE); 2653 2654 /* Send the surprise removal IRP */ 2655 IopSendSurpriseRemoval(Child->PhysicalDeviceObject); 2656 2657 /* Tell the user-mode PnP manager that a device was removed */ 2658 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL, 2659 &Child->InstancePath); 2660 2661 /* Send the remove device IRP */ 2662 IopSendRemoveDevice(Child->PhysicalDeviceObject); 2663 } 2664 2665 Child = NextChild; 2666 } 2667 } 2668 2669 NTSTATUS 2670 IopEnumerateDevice( 2671 IN PDEVICE_OBJECT DeviceObject) 2672 { 2673 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 2674 DEVICETREE_TRAVERSE_CONTEXT Context; 2675 PDEVICE_RELATIONS DeviceRelations; 2676 PDEVICE_OBJECT ChildDeviceObject; 2677 IO_STATUS_BLOCK IoStatusBlock; 2678 PDEVICE_NODE ChildDeviceNode; 2679 IO_STACK_LOCATION Stack; 2680 NTSTATUS Status; 2681 ULONG i; 2682 2683 DPRINT("DeviceObject 0x%p\n", DeviceObject); 2684 2685 if (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY) 2686 { 2687 DeviceNode->Flags &= ~DNF_NEED_ENUMERATION_ONLY; 2688 2689 DPRINT("Sending GUID_DEVICE_ARRIVAL\n"); 2690 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, 2691 &DeviceNode->InstancePath); 2692 } 2693 2694 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n"); 2695 2696 Stack.Parameters.QueryDeviceRelations.Type = BusRelations; 2697 2698 Status = IopInitiatePnpIrp( 2699 DeviceObject, 2700 &IoStatusBlock, 2701 IRP_MN_QUERY_DEVICE_RELATIONS, 2702 &Stack); 2703 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING) 2704 { 2705 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 2706 return Status; 2707 } 2708 2709 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 2710 2711 /* 2712 * Send removal IRPs for devices that have disappeared 2713 * NOTE: This code handles the case where no relations are specified 2714 */ 2715 IopHandleDeviceRemoval(DeviceNode, DeviceRelations); 2716 2717 /* Now we bail if nothing was returned */ 2718 if (!DeviceRelations) 2719 { 2720 /* We're all done */ 2721 DPRINT("No PDOs\n"); 2722 return STATUS_SUCCESS; 2723 } 2724 2725 DPRINT("Got %u PDOs\n", DeviceRelations->Count); 2726 2727 /* 2728 * Create device nodes for all discovered devices 2729 */ 2730 for (i = 0; i < DeviceRelations->Count; i++) 2731 { 2732 ChildDeviceObject = DeviceRelations->Objects[i]; 2733 ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0); 2734 2735 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject); 2736 if (!ChildDeviceNode) 2737 { 2738 /* One doesn't exist, create it */ 2739 Status = IopCreateDeviceNode( 2740 DeviceNode, 2741 ChildDeviceObject, 2742 NULL, 2743 &ChildDeviceNode); 2744 if (NT_SUCCESS(Status)) 2745 { 2746 /* Mark the node as enumerated */ 2747 ChildDeviceNode->Flags |= DNF_ENUMERATED; 2748 2749 /* Mark the DO as bus enumerated */ 2750 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE; 2751 } 2752 else 2753 { 2754 /* Ignore this DO */ 2755 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i); 2756 ObDereferenceObject(ChildDeviceObject); 2757 } 2758 } 2759 else 2760 { 2761 /* Mark it as enumerated */ 2762 ChildDeviceNode->Flags |= DNF_ENUMERATED; 2763 ObDereferenceObject(ChildDeviceObject); 2764 } 2765 } 2766 ExFreePool(DeviceRelations); 2767 2768 /* 2769 * Retrieve information about all discovered children from the bus driver 2770 */ 2771 IopInitDeviceTreeTraverseContext( 2772 &Context, 2773 DeviceNode, 2774 IopActionInterrogateDeviceStack, 2775 DeviceNode); 2776 2777 Status = IopTraverseDeviceTree(&Context); 2778 if (!NT_SUCCESS(Status)) 2779 { 2780 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status); 2781 return Status; 2782 } 2783 2784 /* 2785 * Retrieve configuration from the registry for discovered children 2786 */ 2787 IopInitDeviceTreeTraverseContext( 2788 &Context, 2789 DeviceNode, 2790 IopActionConfigureChildServices, 2791 DeviceNode); 2792 2793 Status = IopTraverseDeviceTree(&Context); 2794 if (!NT_SUCCESS(Status)) 2795 { 2796 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status); 2797 return Status; 2798 } 2799 2800 /* 2801 * Initialize services for discovered children. 2802 */ 2803 Status = IopInitializePnpServices(DeviceNode); 2804 if (!NT_SUCCESS(Status)) 2805 { 2806 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status); 2807 return Status; 2808 } 2809 2810 DPRINT("IopEnumerateDevice() finished\n"); 2811 return STATUS_SUCCESS; 2812 } 2813 2814 2815 /* 2816 * IopActionConfigureChildServices 2817 * 2818 * Retrieve configuration for all (direct) child nodes of a parent node. 2819 * 2820 * Parameters 2821 * DeviceNode 2822 * Pointer to device node. 2823 * Context 2824 * Pointer to parent node to retrieve child node configuration for. 2825 * 2826 * Remarks 2827 * Any errors that occur are logged instead so that all child services have a chance of beeing 2828 * configured. 2829 */ 2830 2831 NTSTATUS 2832 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode, 2833 PVOID Context) 2834 { 2835 RTL_QUERY_REGISTRY_TABLE QueryTable[3]; 2836 PDEVICE_NODE ParentDeviceNode; 2837 PUNICODE_STRING Service; 2838 UNICODE_STRING ClassGUID; 2839 NTSTATUS Status; 2840 DEVICE_CAPABILITIES DeviceCaps; 2841 2842 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context); 2843 2844 ParentDeviceNode = (PDEVICE_NODE)Context; 2845 2846 /* 2847 * We are called for the parent too, but we don't need to do special 2848 * handling for this node 2849 */ 2850 if (DeviceNode == ParentDeviceNode) 2851 { 2852 DPRINT("Success\n"); 2853 return STATUS_SUCCESS; 2854 } 2855 2856 /* 2857 * Make sure this device node is a direct child of the parent device node 2858 * that is given as an argument 2859 */ 2860 2861 if (DeviceNode->Parent != ParentDeviceNode) 2862 { 2863 DPRINT("Skipping 2+ level child\n"); 2864 return STATUS_SUCCESS; 2865 } 2866 2867 if (!(DeviceNode->Flags & DNF_PROCESSED)) 2868 { 2869 DPRINT1("Child not ready to be configured\n"); 2870 return STATUS_SUCCESS; 2871 } 2872 2873 if (!(DeviceNode->Flags & (DNF_DISABLED | DNF_STARTED | DNF_ADDED))) 2874 { 2875 UNICODE_STRING RegKey; 2876 2877 /* Install the service for this if it's in the CDDB */ 2878 IopInstallCriticalDevice(DeviceNode); 2879 2880 /* 2881 * Retrieve configuration from Enum key 2882 */ 2883 2884 Service = &DeviceNode->ServiceName; 2885 2886 RtlZeroMemory(QueryTable, sizeof(QueryTable)); 2887 RtlInitUnicodeString(Service, NULL); 2888 RtlInitUnicodeString(&ClassGUID, NULL); 2889 2890 QueryTable[0].Name = L"Service"; 2891 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 2892 QueryTable[0].EntryContext = Service; 2893 2894 QueryTable[1].Name = L"ClassGUID"; 2895 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT; 2896 QueryTable[1].EntryContext = &ClassGUID; 2897 QueryTable[1].DefaultType = REG_SZ; 2898 QueryTable[1].DefaultData = L""; 2899 QueryTable[1].DefaultLength = 0; 2900 2901 RegKey.Length = 0; 2902 RegKey.MaximumLength = sizeof(ENUM_ROOT) + sizeof(WCHAR) + DeviceNode->InstancePath.Length; 2903 RegKey.Buffer = ExAllocatePoolWithTag(PagedPool, 2904 RegKey.MaximumLength, 2905 TAG_IO); 2906 if (RegKey.Buffer == NULL) 2907 { 2908 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); 2909 return STATUS_INSUFFICIENT_RESOURCES; 2910 } 2911 2912 RtlAppendUnicodeToString(&RegKey, ENUM_ROOT); 2913 RtlAppendUnicodeToString(&RegKey, L"\\"); 2914 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath); 2915 2916 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 2917 RegKey.Buffer, QueryTable, NULL, NULL); 2918 ExFreePoolWithTag(RegKey.Buffer, TAG_IO); 2919 2920 if (!NT_SUCCESS(Status)) 2921 { 2922 /* FIXME: Log the error */ 2923 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n", 2924 &DeviceNode->InstancePath, Status); 2925 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); 2926 return STATUS_SUCCESS; 2927 } 2928 2929 if (Service->Buffer == NULL) 2930 { 2931 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) && 2932 DeviceCaps.RawDeviceOK) 2933 { 2934 DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName); 2935 RtlInitEmptyUnicodeString(&DeviceNode->ServiceName, NULL, 0); 2936 } 2937 else if (ClassGUID.Length != 0) 2938 { 2939 /* Device has a ClassGUID value, but no Service value. 2940 * Suppose it is using the NULL driver, so state the 2941 * device is started */ 2942 DPRINT("%wZ is using NULL driver\n", &DeviceNode->InstancePath); 2943 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED); 2944 } 2945 else 2946 { 2947 DeviceNode->Problem = CM_PROB_FAILED_INSTALL; 2948 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); 2949 } 2950 return STATUS_SUCCESS; 2951 } 2952 2953 DPRINT("Got Service %S\n", Service->Buffer); 2954 } 2955 2956 return STATUS_SUCCESS; 2957 } 2958 2959 /* 2960 * IopActionInitChildServices 2961 * 2962 * Initialize the service for all (direct) child nodes of a parent node 2963 * 2964 * Parameters 2965 * DeviceNode 2966 * Pointer to device node. 2967 * Context 2968 * Pointer to parent node to initialize child node services for. 2969 * 2970 * Remarks 2971 * If the driver image for a service is not loaded and initialized 2972 * it is done here too. Any errors that occur are logged instead so 2973 * that all child services have a chance of being initialized. 2974 */ 2975 2976 NTSTATUS 2977 IopActionInitChildServices(PDEVICE_NODE DeviceNode, 2978 PVOID Context) 2979 { 2980 PDEVICE_NODE ParentDeviceNode; 2981 NTSTATUS Status; 2982 BOOLEAN BootDrivers = !PnpSystemInit; 2983 2984 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context); 2985 2986 ParentDeviceNode = Context; 2987 2988 /* 2989 * We are called for the parent too, but we don't need to do special 2990 * handling for this node 2991 */ 2992 if (DeviceNode == ParentDeviceNode) 2993 { 2994 DPRINT("Success\n"); 2995 return STATUS_SUCCESS; 2996 } 2997 2998 /* 2999 * We don't want to check for a direct child because 3000 * this function is called during boot to reinitialize 3001 * devices with drivers that couldn't load yet due to 3002 * stage 0 limitations (ie can't load from disk yet). 3003 */ 3004 3005 if (!(DeviceNode->Flags & DNF_PROCESSED)) 3006 { 3007 DPRINT1("Child not ready to be added\n"); 3008 return STATUS_SUCCESS; 3009 } 3010 3011 if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) || 3012 IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) || 3013 IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED)) 3014 return STATUS_SUCCESS; 3015 3016 if (DeviceNode->ServiceName.Buffer == NULL) 3017 { 3018 /* We don't need to worry about loading the driver because we're 3019 * being driven in raw mode so our parent must be loaded to get here */ 3020 Status = IopInitializeDevice(DeviceNode, NULL); 3021 if (NT_SUCCESS(Status)) 3022 { 3023 Status = IopStartDevice(DeviceNode); 3024 if (!NT_SUCCESS(Status)) 3025 { 3026 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n", 3027 &DeviceNode->InstancePath, Status); 3028 } 3029 } 3030 } 3031 else 3032 { 3033 PLDR_DATA_TABLE_ENTRY ModuleObject; 3034 PDRIVER_OBJECT DriverObject; 3035 3036 KeEnterCriticalRegion(); 3037 ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE); 3038 /* Get existing DriverObject pointer (in case the driver has 3039 already been loaded and initialized) */ 3040 Status = IopGetDriverObject( 3041 &DriverObject, 3042 &DeviceNode->ServiceName, 3043 FALSE); 3044 3045 if (!NT_SUCCESS(Status)) 3046 { 3047 /* Driver is not initialized, try to load it */ 3048 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject); 3049 3050 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED) 3051 { 3052 /* Initialize the driver */ 3053 Status = IopInitializeDriverModule(DeviceNode, ModuleObject, 3054 &DeviceNode->ServiceName, FALSE, &DriverObject); 3055 if (!NT_SUCCESS(Status)) DeviceNode->Problem = CM_PROB_FAILED_DRIVER_ENTRY; 3056 } 3057 else if (Status == STATUS_DRIVER_UNABLE_TO_LOAD) 3058 { 3059 DPRINT1("Service '%wZ' is disabled\n", &DeviceNode->ServiceName); 3060 DeviceNode->Problem = CM_PROB_DISABLED_SERVICE; 3061 } 3062 else 3063 { 3064 DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n", 3065 &DeviceNode->ServiceName, Status); 3066 if (!BootDrivers) DeviceNode->Problem = CM_PROB_DRIVER_FAILED_LOAD; 3067 } 3068 } 3069 ExReleaseResourceLite(&IopDriverLoadResource); 3070 KeLeaveCriticalRegion(); 3071 3072 /* Driver is loaded and initialized at this point */ 3073 if (NT_SUCCESS(Status)) 3074 { 3075 /* Initialize the device, including all filters */ 3076 Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject); 3077 3078 /* Remove the extra reference */ 3079 ObDereferenceObject(DriverObject); 3080 } 3081 else 3082 { 3083 /* 3084 * Don't disable when trying to load only boot drivers 3085 */ 3086 if (!BootDrivers) 3087 { 3088 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); 3089 } 3090 } 3091 } 3092 3093 return STATUS_SUCCESS; 3094 } 3095 3096 /* 3097 * IopInitializePnpServices 3098 * 3099 * Initialize services for discovered children 3100 * 3101 * Parameters 3102 * DeviceNode 3103 * Top device node to start initializing services. 3104 * 3105 * Return Value 3106 * Status 3107 */ 3108 NTSTATUS 3109 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode) 3110 { 3111 DEVICETREE_TRAVERSE_CONTEXT Context; 3112 3113 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode); 3114 3115 IopInitDeviceTreeTraverseContext( 3116 &Context, 3117 DeviceNode, 3118 IopActionInitChildServices, 3119 DeviceNode); 3120 3121 return IopTraverseDeviceTree(&Context); 3122 } 3123 3124 static 3125 INIT_FUNCTION 3126 NTSTATUS 3127 IopEnumerateDetectedDevices( 3128 IN HANDLE hBaseKey, 3129 IN PUNICODE_STRING RelativePath OPTIONAL, 3130 IN HANDLE hRootKey, 3131 IN BOOLEAN EnumerateSubKeys, 3132 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources, 3133 IN ULONG ParentBootResourcesLength) 3134 { 3135 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier"); 3136 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID"); 3137 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data"); 3138 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig"); 3139 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf"); 3140 OBJECT_ATTRIBUTES ObjectAttributes; 3141 HANDLE hDevicesKey = NULL; 3142 HANDLE hDeviceKey = NULL; 3143 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf; 3144 UNICODE_STRING Level2NameU; 3145 WCHAR Level2Name[5]; 3146 ULONG IndexDevice = 0; 3147 ULONG IndexSubKey; 3148 PKEY_BASIC_INFORMATION pDeviceInformation = NULL; 3149 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR); 3150 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL; 3151 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR); 3152 UNICODE_STRING DeviceName, ValueName; 3153 ULONG RequiredSize; 3154 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL; 3155 ULONG BootResourcesLength; 3156 NTSTATUS Status; 3157 3158 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController"); 3159 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0"); 3160 static ULONG DeviceIndexSerial = 0; 3161 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController"); 3162 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0"); 3163 static ULONG DeviceIndexKeyboard = 0; 3164 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController"); 3165 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0"); 3166 static ULONG DeviceIndexMouse = 0; 3167 const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController"); 3168 UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0"); 3169 static ULONG DeviceIndexParallel = 0; 3170 const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral"); 3171 UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0"); 3172 static ULONG DeviceIndexFloppy = 0; 3173 UNICODE_STRING HardwareIdKey; 3174 PUNICODE_STRING pHardwareId; 3175 ULONG DeviceIndex = 0; 3176 PUCHAR CmResourceList; 3177 ULONG ListCount; 3178 3179 if (RelativePath) 3180 { 3181 Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS); 3182 if (!NT_SUCCESS(Status)) 3183 { 3184 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status); 3185 goto cleanup; 3186 } 3187 } 3188 else 3189 hDevicesKey = hBaseKey; 3190 3191 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength); 3192 if (!pDeviceInformation) 3193 { 3194 DPRINT("ExAllocatePool() failed\n"); 3195 Status = STATUS_NO_MEMORY; 3196 goto cleanup; 3197 } 3198 3199 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength); 3200 if (!pValueInformation) 3201 { 3202 DPRINT("ExAllocatePool() failed\n"); 3203 Status = STATUS_NO_MEMORY; 3204 goto cleanup; 3205 } 3206 3207 while (TRUE) 3208 { 3209 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize); 3210 if (Status == STATUS_NO_MORE_ENTRIES) 3211 break; 3212 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 3213 { 3214 ExFreePool(pDeviceInformation); 3215 DeviceInfoLength = RequiredSize; 3216 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength); 3217 if (!pDeviceInformation) 3218 { 3219 DPRINT("ExAllocatePool() failed\n"); 3220 Status = STATUS_NO_MEMORY; 3221 goto cleanup; 3222 } 3223 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize); 3224 } 3225 if (!NT_SUCCESS(Status)) 3226 { 3227 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status); 3228 goto cleanup; 3229 } 3230 IndexDevice++; 3231 3232 /* Open device key */ 3233 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength; 3234 DeviceName.Buffer = pDeviceInformation->Name; 3235 3236 Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName, 3237 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0)); 3238 if (!NT_SUCCESS(Status)) 3239 { 3240 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status); 3241 goto cleanup; 3242 } 3243 3244 /* Read boot resources, and add then to parent ones */ 3245 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize); 3246 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 3247 { 3248 ExFreePool(pValueInformation); 3249 ValueInfoLength = RequiredSize; 3250 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength); 3251 if (!pValueInformation) 3252 { 3253 DPRINT("ExAllocatePool() failed\n"); 3254 ZwDeleteKey(hLevel2Key); 3255 Status = STATUS_NO_MEMORY; 3256 goto cleanup; 3257 } 3258 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize); 3259 } 3260 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 3261 { 3262 BootResources = ParentBootResources; 3263 BootResourcesLength = ParentBootResourcesLength; 3264 } 3265 else if (!NT_SUCCESS(Status)) 3266 { 3267 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status); 3268 goto nextdevice; 3269 } 3270 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR) 3271 { 3272 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR); 3273 goto nextdevice; 3274 } 3275 else 3276 { 3277 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors); 3278 3279 /* Concatenate current resources and parent ones */ 3280 if (ParentBootResourcesLength == 0) 3281 BootResourcesLength = pValueInformation->DataLength; 3282 else 3283 BootResourcesLength = ParentBootResourcesLength 3284 + pValueInformation->DataLength 3285 - Header; 3286 BootResources = ExAllocatePool(PagedPool, BootResourcesLength); 3287 if (!BootResources) 3288 { 3289 DPRINT("ExAllocatePool() failed\n"); 3290 goto nextdevice; 3291 } 3292 if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) 3293 { 3294 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength); 3295 } 3296 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific) 3297 { 3298 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength); 3299 RtlCopyMemory( 3300 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength), 3301 (PVOID)((ULONG_PTR)ParentBootResources + Header), 3302 ParentBootResourcesLength - Header); 3303 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count; 3304 } 3305 else 3306 { 3307 RtlCopyMemory(BootResources, pValueInformation->Data, Header); 3308 RtlCopyMemory( 3309 (PVOID)((ULONG_PTR)BootResources + Header), 3310 (PVOID)((ULONG_PTR)ParentBootResources + Header), 3311 ParentBootResourcesLength - Header); 3312 RtlCopyMemory( 3313 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength), 3314 pValueInformation->Data + Header, 3315 pValueInformation->DataLength - Header); 3316 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count; 3317 } 3318 } 3319 3320 if (EnumerateSubKeys) 3321 { 3322 IndexSubKey = 0; 3323 while (TRUE) 3324 { 3325 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize); 3326 if (Status == STATUS_NO_MORE_ENTRIES) 3327 break; 3328 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 3329 { 3330 ExFreePool(pDeviceInformation); 3331 DeviceInfoLength = RequiredSize; 3332 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength); 3333 if (!pDeviceInformation) 3334 { 3335 DPRINT("ExAllocatePool() failed\n"); 3336 Status = STATUS_NO_MEMORY; 3337 goto cleanup; 3338 } 3339 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize); 3340 } 3341 if (!NT_SUCCESS(Status)) 3342 { 3343 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status); 3344 goto cleanup; 3345 } 3346 IndexSubKey++; 3347 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength; 3348 DeviceName.Buffer = pDeviceInformation->Name; 3349 3350 Status = IopEnumerateDetectedDevices( 3351 hDeviceKey, 3352 &DeviceName, 3353 hRootKey, 3354 TRUE, 3355 BootResources, 3356 BootResourcesLength); 3357 if (!NT_SUCCESS(Status)) 3358 goto cleanup; 3359 } 3360 } 3361 3362 /* Read identifier */ 3363 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize); 3364 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 3365 { 3366 ExFreePool(pValueInformation); 3367 ValueInfoLength = RequiredSize; 3368 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength); 3369 if (!pValueInformation) 3370 { 3371 DPRINT("ExAllocatePool() failed\n"); 3372 Status = STATUS_NO_MEMORY; 3373 goto cleanup; 3374 } 3375 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize); 3376 } 3377 if (!NT_SUCCESS(Status)) 3378 { 3379 if (Status != STATUS_OBJECT_NAME_NOT_FOUND) 3380 { 3381 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status); 3382 goto nextdevice; 3383 } 3384 ValueName.Length = ValueName.MaximumLength = 0; 3385 } 3386 else if (pValueInformation->Type != REG_SZ) 3387 { 3388 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ); 3389 goto nextdevice; 3390 } 3391 else 3392 { 3393 /* Assign hardware id to this device */ 3394 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength; 3395 ValueName.Buffer = (PWCHAR)pValueInformation->Data; 3396 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL) 3397 ValueName.Length -= sizeof(WCHAR); 3398 } 3399 3400 if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0) 3401 { 3402 pHardwareId = &HardwareIdSerial; 3403 DeviceIndex = DeviceIndexSerial++; 3404 } 3405 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0) 3406 { 3407 pHardwareId = &HardwareIdKeyboard; 3408 DeviceIndex = DeviceIndexKeyboard++; 3409 } 3410 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0) 3411 { 3412 pHardwareId = &HardwareIdMouse; 3413 DeviceIndex = DeviceIndexMouse++; 3414 } 3415 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0) 3416 { 3417 pHardwareId = &HardwareIdParallel; 3418 DeviceIndex = DeviceIndexParallel++; 3419 } 3420 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0) 3421 { 3422 pHardwareId = &HardwareIdFloppy; 3423 DeviceIndex = DeviceIndexFloppy++; 3424 } 3425 else 3426 { 3427 /* Unknown key path */ 3428 DPRINT("Unknown key path '%wZ'\n", RelativePath); 3429 goto nextdevice; 3430 } 3431 3432 /* Prepare hardware id key (hardware id value without final \0) */ 3433 HardwareIdKey = *pHardwareId; 3434 HardwareIdKey.Length -= sizeof(UNICODE_NULL); 3435 3436 /* Add the detected device to Root key */ 3437 InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL); 3438 Status = ZwCreateKey( 3439 &hLevel1Key, 3440 KEY_CREATE_SUB_KEY, 3441 &ObjectAttributes, 3442 0, 3443 NULL, 3444 REG_OPTION_NON_VOLATILE, 3445 NULL); 3446 if (!NT_SUCCESS(Status)) 3447 { 3448 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status); 3449 goto nextdevice; 3450 } 3451 swprintf(Level2Name, L"%04lu", DeviceIndex); 3452 RtlInitUnicodeString(&Level2NameU, Level2Name); 3453 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL); 3454 Status = ZwCreateKey( 3455 &hLevel2Key, 3456 KEY_SET_VALUE | KEY_CREATE_SUB_KEY, 3457 &ObjectAttributes, 3458 0, 3459 NULL, 3460 REG_OPTION_NON_VOLATILE, 3461 NULL); 3462 ZwClose(hLevel1Key); 3463 if (!NT_SUCCESS(Status)) 3464 { 3465 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status); 3466 goto nextdevice; 3467 } 3468 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey); 3469 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength); 3470 if (!NT_SUCCESS(Status)) 3471 { 3472 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status); 3473 ZwDeleteKey(hLevel2Key); 3474 goto nextdevice; 3475 } 3476 /* Create 'LogConf' subkey */ 3477 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL); 3478 Status = ZwCreateKey( 3479 &hLogConf, 3480 KEY_SET_VALUE, 3481 &ObjectAttributes, 3482 0, 3483 NULL, 3484 REG_OPTION_VOLATILE, 3485 NULL); 3486 if (!NT_SUCCESS(Status)) 3487 { 3488 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status); 3489 ZwDeleteKey(hLevel2Key); 3490 goto nextdevice; 3491 } 3492 if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) 3493 { 3494 CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG)); 3495 if (!CmResourceList) 3496 { 3497 ZwClose(hLogConf); 3498 ZwDeleteKey(hLevel2Key); 3499 goto nextdevice; 3500 } 3501 3502 /* Add the list count (1st member of CM_RESOURCE_LIST) */ 3503 ListCount = 1; 3504 RtlCopyMemory(CmResourceList, 3505 &ListCount, 3506 sizeof(ULONG)); 3507 3508 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */ 3509 RtlCopyMemory(CmResourceList + sizeof(ULONG), 3510 BootResources, 3511 BootResourcesLength); 3512 3513 /* Save boot resources to 'LogConf\BootConfig' */ 3514 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG)); 3515 if (!NT_SUCCESS(Status)) 3516 { 3517 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status); 3518 ZwClose(hLogConf); 3519 ZwDeleteKey(hLevel2Key); 3520 goto nextdevice; 3521 } 3522 } 3523 ZwClose(hLogConf); 3524 3525 nextdevice: 3526 if (BootResources && BootResources != ParentBootResources) 3527 { 3528 ExFreePool(BootResources); 3529 BootResources = NULL; 3530 } 3531 if (hLevel2Key) 3532 { 3533 ZwClose(hLevel2Key); 3534 hLevel2Key = NULL; 3535 } 3536 if (hDeviceKey) 3537 { 3538 ZwClose(hDeviceKey); 3539 hDeviceKey = NULL; 3540 } 3541 } 3542 3543 Status = STATUS_SUCCESS; 3544 3545 cleanup: 3546 if (hDevicesKey && hDevicesKey != hBaseKey) 3547 ZwClose(hDevicesKey); 3548 if (hDeviceKey) 3549 ZwClose(hDeviceKey); 3550 if (pDeviceInformation) 3551 ExFreePool(pDeviceInformation); 3552 if (pValueInformation) 3553 ExFreePool(pValueInformation); 3554 return Status; 3555 } 3556 3557 static 3558 INIT_FUNCTION 3559 BOOLEAN 3560 IopIsFirmwareMapperDisabled(VOID) 3561 { 3562 UNICODE_STRING KeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp"); 3563 UNICODE_STRING KeyNameU = RTL_CONSTANT_STRING(L"DisableFirmwareMapper"); 3564 OBJECT_ATTRIBUTES ObjectAttributes; 3565 HANDLE hPnpKey; 3566 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation; 3567 ULONG DesiredLength, Length; 3568 ULONG KeyValue = 0; 3569 NTSTATUS Status; 3570 3571 InitializeObjectAttributes(&ObjectAttributes, &KeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); 3572 Status = ZwOpenKey(&hPnpKey, KEY_QUERY_VALUE, &ObjectAttributes); 3573 if (NT_SUCCESS(Status)) 3574 { 3575 Status = ZwQueryValueKey(hPnpKey, 3576 &KeyNameU, 3577 KeyValuePartialInformation, 3578 NULL, 3579 0, 3580 &DesiredLength); 3581 if ((Status == STATUS_BUFFER_TOO_SMALL) || 3582 (Status == STATUS_BUFFER_OVERFLOW)) 3583 { 3584 Length = DesiredLength; 3585 KeyInformation = ExAllocatePool(PagedPool, Length); 3586 if (KeyInformation) 3587 { 3588 Status = ZwQueryValueKey(hPnpKey, 3589 &KeyNameU, 3590 KeyValuePartialInformation, 3591 KeyInformation, 3592 Length, 3593 &DesiredLength); 3594 if (NT_SUCCESS(Status) && KeyInformation->DataLength == sizeof(ULONG)) 3595 { 3596 KeyValue = (ULONG)(*KeyInformation->Data); 3597 } 3598 else 3599 { 3600 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU, &KeyNameU); 3601 } 3602 3603 ExFreePool(KeyInformation); 3604 } 3605 else 3606 { 3607 DPRINT1("Failed to allocate memory for registry query\n"); 3608 } 3609 } 3610 else 3611 { 3612 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU, &KeyNameU, Status); 3613 } 3614 3615 ZwClose(hPnpKey); 3616 } 3617 else 3618 { 3619 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU, Status); 3620 } 3621 3622 DPRINT("Firmware mapper is %s\n", KeyValue != 0 ? "disabled" : "enabled"); 3623 3624 return (KeyValue != 0) ? TRUE : FALSE; 3625 } 3626 3627 INIT_FUNCTION 3628 NTSTATUS 3629 NTAPI 3630 IopUpdateRootKey(VOID) 3631 { 3632 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum"); 3633 UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root"); 3634 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"); 3635 OBJECT_ATTRIBUTES ObjectAttributes; 3636 HANDLE hEnum, hRoot; 3637 NTSTATUS Status; 3638 3639 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); 3640 Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL); 3641 if (!NT_SUCCESS(Status)) 3642 { 3643 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status); 3644 return Status; 3645 } 3646 3647 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL); 3648 Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL); 3649 ZwClose(hEnum); 3650 if (!NT_SUCCESS(Status)) 3651 { 3652 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status); 3653 return Status; 3654 } 3655 3656 if (!IopIsFirmwareMapperDisabled()) 3657 { 3658 Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS); 3659 if (!NT_SUCCESS(Status)) 3660 { 3661 /* Nothing to do, don't return with an error status */ 3662 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status); 3663 ZwClose(hRoot); 3664 return STATUS_SUCCESS; 3665 } 3666 Status = IopEnumerateDetectedDevices( 3667 hEnum, 3668 NULL, 3669 hRoot, 3670 TRUE, 3671 NULL, 3672 0); 3673 ZwClose(hEnum); 3674 } 3675 else 3676 { 3677 /* Enumeration is disabled */ 3678 Status = STATUS_SUCCESS; 3679 } 3680 3681 ZwClose(hRoot); 3682 3683 return Status; 3684 } 3685 3686 NTSTATUS 3687 NTAPI 3688 IopOpenRegistryKeyEx(PHANDLE KeyHandle, 3689 HANDLE ParentKey, 3690 PUNICODE_STRING Name, 3691 ACCESS_MASK DesiredAccess) 3692 { 3693 OBJECT_ATTRIBUTES ObjectAttributes; 3694 NTSTATUS Status; 3695 3696 PAGED_CODE(); 3697 3698 *KeyHandle = NULL; 3699 3700 InitializeObjectAttributes(&ObjectAttributes, 3701 Name, 3702 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 3703 ParentKey, 3704 NULL); 3705 3706 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes); 3707 3708 return Status; 3709 } 3710 3711 NTSTATUS 3712 NTAPI 3713 IopCreateRegistryKeyEx(OUT PHANDLE Handle, 3714 IN HANDLE RootHandle OPTIONAL, 3715 IN PUNICODE_STRING KeyName, 3716 IN ACCESS_MASK DesiredAccess, 3717 IN ULONG CreateOptions, 3718 OUT PULONG Disposition OPTIONAL) 3719 { 3720 OBJECT_ATTRIBUTES ObjectAttributes; 3721 ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0; 3722 USHORT Length; 3723 HANDLE HandleArray[2]; 3724 BOOLEAN Recursing = TRUE; 3725 PWCHAR pp, p, p1; 3726 UNICODE_STRING KeyString; 3727 NTSTATUS Status = STATUS_SUCCESS; 3728 PAGED_CODE(); 3729 3730 /* P1 is start, pp is end */ 3731 p1 = KeyName->Buffer; 3732 pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length); 3733 3734 /* Create the target key */ 3735 InitializeObjectAttributes(&ObjectAttributes, 3736 KeyName, 3737 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 3738 RootHandle, 3739 NULL); 3740 Status = ZwCreateKey(&HandleArray[i], 3741 DesiredAccess, 3742 &ObjectAttributes, 3743 0, 3744 NULL, 3745 CreateOptions, 3746 &KeyDisposition); 3747 3748 /* Now we check if this failed */ 3749 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle)) 3750 { 3751 /* Target key failed, so we'll need to create its parent. Setup array */ 3752 HandleArray[0] = NULL; 3753 HandleArray[1] = RootHandle; 3754 3755 /* Keep recursing for each missing parent */ 3756 while (Recursing) 3757 { 3758 /* And if we're deep enough, close the last handle */ 3759 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]); 3760 3761 /* We're setup to ping-pong between the two handle array entries */ 3762 RootHandleIndex = i; 3763 i = (i + 1) & 1; 3764 3765 /* Clear the one we're attempting to open now */ 3766 HandleArray[i] = NULL; 3767 3768 /* Process the parent key name */ 3769 for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++); 3770 Length = (USHORT)(p - p1) * sizeof(WCHAR); 3771 3772 /* Is there a parent name? */ 3773 if (Length) 3774 { 3775 /* Build the unicode string for it */ 3776 KeyString.Buffer = p1; 3777 KeyString.Length = KeyString.MaximumLength = Length; 3778 3779 /* Now try opening the parent */ 3780 InitializeObjectAttributes(&ObjectAttributes, 3781 &KeyString, 3782 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 3783 HandleArray[RootHandleIndex], 3784 NULL); 3785 Status = ZwCreateKey(&HandleArray[i], 3786 DesiredAccess, 3787 &ObjectAttributes, 3788 0, 3789 NULL, 3790 CreateOptions, 3791 &KeyDisposition); 3792 if (NT_SUCCESS(Status)) 3793 { 3794 /* It worked, we have one more handle */ 3795 NestedCloseLevel++; 3796 } 3797 else 3798 { 3799 /* Parent key creation failed, abandon loop */ 3800 Recursing = FALSE; 3801 continue; 3802 } 3803 } 3804 else 3805 { 3806 /* We don't have a parent name, probably corrupted key name */ 3807 Status = STATUS_INVALID_PARAMETER; 3808 Recursing = FALSE; 3809 continue; 3810 } 3811 3812 /* Now see if there's more parents to create */ 3813 p1 = p + 1; 3814 if ((p == pp) || (p1 == pp)) 3815 { 3816 /* We're done, hopefully successfully, so stop */ 3817 Recursing = FALSE; 3818 } 3819 } 3820 3821 /* Outer loop check for handle nesting that requires closing the top handle */ 3822 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]); 3823 } 3824 3825 /* Check if we broke out of the loop due to success */ 3826 if (NT_SUCCESS(Status)) 3827 { 3828 /* Return the target handle (we closed all the parent ones) and disposition */ 3829 *Handle = HandleArray[i]; 3830 if (Disposition) *Disposition = KeyDisposition; 3831 } 3832 3833 /* Return the success state */ 3834 return Status; 3835 } 3836 3837 NTSTATUS 3838 NTAPI 3839 IopGetRegistryValue(IN HANDLE Handle, 3840 IN PWSTR ValueName, 3841 OUT PKEY_VALUE_FULL_INFORMATION *Information) 3842 { 3843 UNICODE_STRING ValueString; 3844 NTSTATUS Status; 3845 PKEY_VALUE_FULL_INFORMATION FullInformation; 3846 ULONG Size; 3847 PAGED_CODE(); 3848 3849 RtlInitUnicodeString(&ValueString, ValueName); 3850 3851 Status = ZwQueryValueKey(Handle, 3852 &ValueString, 3853 KeyValueFullInformation, 3854 NULL, 3855 0, 3856 &Size); 3857 if ((Status != STATUS_BUFFER_OVERFLOW) && 3858 (Status != STATUS_BUFFER_TOO_SMALL)) 3859 { 3860 return Status; 3861 } 3862 3863 FullInformation = ExAllocatePool(NonPagedPool, Size); 3864 if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES; 3865 3866 Status = ZwQueryValueKey(Handle, 3867 &ValueString, 3868 KeyValueFullInformation, 3869 FullInformation, 3870 Size, 3871 &Size); 3872 if (!NT_SUCCESS(Status)) 3873 { 3874 ExFreePool(FullInformation); 3875 return Status; 3876 } 3877 3878 *Information = FullInformation; 3879 return STATUS_SUCCESS; 3880 } 3881 3882 RTL_GENERIC_COMPARE_RESULTS 3883 NTAPI 3884 PiCompareInstancePath(IN PRTL_AVL_TABLE Table, 3885 IN PVOID FirstStruct, 3886 IN PVOID SecondStruct) 3887 { 3888 /* FIXME: TODO */ 3889 ASSERT(FALSE); 3890 return 0; 3891 } 3892 3893 // 3894 // The allocation function is called by the generic table package whenever 3895 // it needs to allocate memory for the table. 3896 // 3897 3898 PVOID 3899 NTAPI 3900 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table, 3901 IN CLONG ByteSize) 3902 { 3903 /* FIXME: TODO */ 3904 ASSERT(FALSE); 3905 return NULL; 3906 } 3907 3908 VOID 3909 NTAPI 3910 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table, 3911 IN PVOID Buffer) 3912 { 3913 /* FIXME: TODO */ 3914 ASSERT(FALSE); 3915 } 3916 3917 VOID 3918 NTAPI 3919 PpInitializeDeviceReferenceTable(VOID) 3920 { 3921 /* Setup the guarded mutex and AVL table */ 3922 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock); 3923 RtlInitializeGenericTableAvl( 3924 &PpDeviceReferenceTable, 3925 (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath, 3926 (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry, 3927 (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry, 3928 NULL); 3929 } 3930 3931 BOOLEAN 3932 NTAPI 3933 PiInitPhase0(VOID) 3934 { 3935 /* Initialize the resource when accessing device registry data */ 3936 ExInitializeResourceLite(&PpRegistryDeviceResource); 3937 3938 /* Setup the device reference AVL table */ 3939 PpInitializeDeviceReferenceTable(); 3940 return TRUE; 3941 } 3942 3943 BOOLEAN 3944 NTAPI 3945 PpInitSystem(VOID) 3946 { 3947 /* Check the initialization phase */ 3948 switch (ExpInitializationPhase) 3949 { 3950 case 0: 3951 3952 /* Do Phase 0 */ 3953 return PiInitPhase0(); 3954 3955 case 1: 3956 3957 /* Do Phase 1 */ 3958 return TRUE; 3959 //return PiInitPhase1(); 3960 3961 default: 3962 3963 /* Don't know any other phase! Bugcheck! */ 3964 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL); 3965 return FALSE; 3966 } 3967 } 3968 3969 LONG IopNumberDeviceNodes; 3970 3971 PDEVICE_NODE 3972 NTAPI 3973 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject) 3974 { 3975 PDEVICE_NODE DeviceNode; 3976 PAGED_CODE(); 3977 3978 /* Allocate it */ 3979 DeviceNode = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_NODE), TAG_IO_DEVNODE); 3980 if (!DeviceNode) return DeviceNode; 3981 3982 /* Statistics */ 3983 InterlockedIncrement(&IopNumberDeviceNodes); 3984 3985 /* Set it up */ 3986 RtlZeroMemory(DeviceNode, sizeof(DEVICE_NODE)); 3987 DeviceNode->InterfaceType = InterfaceTypeUndefined; 3988 DeviceNode->BusNumber = -1; 3989 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined; 3990 DeviceNode->ChildBusNumber = -1; 3991 DeviceNode->ChildBusTypeIndex = -1; 3992 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE); 3993 InitializeListHead(&DeviceNode->DeviceArbiterList); 3994 InitializeListHead(&DeviceNode->DeviceTranslatorList); 3995 InitializeListHead(&DeviceNode->TargetDeviceNotify); 3996 InitializeListHead(&DeviceNode->DockInfo.ListEntry); 3997 InitializeListHead(&DeviceNode->PendedSetInterfaceState); 3998 3999 /* Check if there is a PDO */ 4000 if (PhysicalDeviceObject) 4001 { 4002 /* Link it and remove the init flag */ 4003 DeviceNode->PhysicalDeviceObject = PhysicalDeviceObject; 4004 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = DeviceNode; 4005 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 4006 } 4007 4008 /* Return the node */ 4009 return DeviceNode; 4010 } 4011 4012 /* PUBLIC FUNCTIONS **********************************************************/ 4013 4014 NTSTATUS 4015 NTAPI 4016 PnpBusTypeGuidGet(IN USHORT Index, 4017 IN LPGUID BusTypeGuid) 4018 { 4019 NTSTATUS Status = STATUS_SUCCESS; 4020 4021 /* Acquire the lock */ 4022 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock); 4023 4024 /* Validate size */ 4025 if (Index < PnpBusTypeGuidList->GuidCount) 4026 { 4027 /* Copy the data */ 4028 RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID)); 4029 } 4030 else 4031 { 4032 /* Failure path */ 4033 Status = STATUS_OBJECT_NAME_NOT_FOUND; 4034 } 4035 4036 /* Release lock and return status */ 4037 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock); 4038 return Status; 4039 } 4040 4041 NTSTATUS 4042 NTAPI 4043 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject, 4044 IN PHANDLE DeviceInstanceHandle, 4045 IN ACCESS_MASK DesiredAccess) 4046 { 4047 NTSTATUS Status; 4048 HANDLE KeyHandle; 4049 PDEVICE_NODE DeviceNode; 4050 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM"); 4051 PAGED_CODE(); 4052 4053 /* Open the enum key */ 4054 Status = IopOpenRegistryKeyEx(&KeyHandle, 4055 NULL, 4056 &KeyName, 4057 KEY_READ); 4058 if (!NT_SUCCESS(Status)) return Status; 4059 4060 /* Make sure we have an instance path */ 4061 DeviceNode = IopGetDeviceNode(DeviceObject); 4062 if ((DeviceNode) && (DeviceNode->InstancePath.Length)) 4063 { 4064 /* Get the instance key */ 4065 Status = IopOpenRegistryKeyEx(DeviceInstanceHandle, 4066 KeyHandle, 4067 &DeviceNode->InstancePath, 4068 DesiredAccess); 4069 } 4070 else 4071 { 4072 /* Fail */ 4073 Status = STATUS_INVALID_DEVICE_REQUEST; 4074 } 4075 4076 /* Close the handle and return status */ 4077 ZwClose(KeyHandle); 4078 return Status; 4079 } 4080 4081 ULONG 4082 NTAPI 4083 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList) 4084 { 4085 ULONG FinalSize, PartialSize, EntrySize, i, j; 4086 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor; 4087 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; 4088 4089 /* If we don't have one, that's easy */ 4090 if (!ResourceList) return 0; 4091 4092 /* Start with the minimum size possible */ 4093 FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List); 4094 4095 /* Loop each full descriptor */ 4096 FullDescriptor = ResourceList->List; 4097 for (i = 0; i < ResourceList->Count; i++) 4098 { 4099 /* Start with the minimum size possible */ 4100 PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) + 4101 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors); 4102 4103 /* Loop each partial descriptor */ 4104 PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors; 4105 for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++) 4106 { 4107 /* Start with the minimum size possible */ 4108 EntrySize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR); 4109 4110 /* Check if there is extra data */ 4111 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific) 4112 { 4113 /* Add that data */ 4114 EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize; 4115 } 4116 4117 /* The size of partial descriptors is bigger */ 4118 PartialSize += EntrySize; 4119 4120 /* Go to the next partial descriptor */ 4121 PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize); 4122 } 4123 4124 /* The size of full descriptors is bigger */ 4125 FinalSize += PartialSize; 4126 4127 /* Go to the next full descriptor */ 4128 FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize); 4129 } 4130 4131 /* Return the final size */ 4132 return FinalSize; 4133 } 4134 4135 NTSTATUS 4136 NTAPI 4137 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject, 4138 IN ULONG ValueType, 4139 IN PWSTR ValueName, 4140 IN PWSTR KeyName, 4141 OUT PVOID Buffer, 4142 IN PULONG BufferLength) 4143 { 4144 NTSTATUS Status; 4145 HANDLE KeyHandle, SubHandle; 4146 UNICODE_STRING KeyString; 4147 PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL; 4148 ULONG Length; 4149 PAGED_CODE(); 4150 4151 /* Find the instance key */ 4152 Status = PnpDeviceObjectToDeviceInstance(DeviceObject, &KeyHandle, KEY_READ); 4153 if (NT_SUCCESS(Status)) 4154 { 4155 /* Check for name given by caller */ 4156 if (KeyName) 4157 { 4158 /* Open this key */ 4159 RtlInitUnicodeString(&KeyString, KeyName); 4160 Status = IopOpenRegistryKeyEx(&SubHandle, 4161 KeyHandle, 4162 &KeyString, 4163 KEY_READ); 4164 if (NT_SUCCESS(Status)) 4165 { 4166 /* And use this handle instead */ 4167 ZwClose(KeyHandle); 4168 KeyHandle = SubHandle; 4169 } 4170 } 4171 4172 /* Check if sub-key handle succeeded (or no-op if no key name given) */ 4173 if (NT_SUCCESS(Status)) 4174 { 4175 /* Now get the size of the property */ 4176 Status = IopGetRegistryValue(KeyHandle, 4177 ValueName, 4178 &KeyValueInfo); 4179 } 4180 4181 /* Close the key */ 4182 ZwClose(KeyHandle); 4183 } 4184 4185 /* Fail if any of the registry operations failed */ 4186 if (!NT_SUCCESS(Status)) return Status; 4187 4188 /* Check how much data we have to copy */ 4189 Length = KeyValueInfo->DataLength; 4190 if (*BufferLength >= Length) 4191 { 4192 /* Check for a match in the value type */ 4193 if (KeyValueInfo->Type == ValueType) 4194 { 4195 /* Copy the data */ 4196 RtlCopyMemory(Buffer, 4197 (PVOID)((ULONG_PTR)KeyValueInfo + 4198 KeyValueInfo->DataOffset), 4199 Length); 4200 } 4201 else 4202 { 4203 /* Invalid registry property type, fail */ 4204 Status = STATUS_INVALID_PARAMETER_2; 4205 } 4206 } 4207 else 4208 { 4209 /* Buffer is too small to hold data */ 4210 Status = STATUS_BUFFER_TOO_SMALL; 4211 } 4212 4213 /* Return the required buffer length, free the buffer, and return status */ 4214 *BufferLength = Length; 4215 ExFreePool(KeyValueInfo); 4216 return Status; 4217 } 4218 4219 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;} 4220 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;} 4221 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED_DBGBREAK(); break;} 4222 4223 /* 4224 * @implemented 4225 */ 4226 NTSTATUS 4227 NTAPI 4228 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject, 4229 IN DEVICE_REGISTRY_PROPERTY DeviceProperty, 4230 IN ULONG BufferLength, 4231 OUT PVOID PropertyBuffer, 4232 OUT PULONG ResultLength) 4233 { 4234 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 4235 DEVICE_CAPABILITIES DeviceCaps; 4236 ULONG ReturnLength = 0, Length = 0, ValueType; 4237 PWCHAR ValueName = NULL, EnumeratorNameEnd, DeviceInstanceName; 4238 PVOID Data = NULL; 4239 NTSTATUS Status = STATUS_BUFFER_TOO_SMALL; 4240 GUID BusTypeGuid; 4241 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL; 4242 BOOLEAN NullTerminate = FALSE; 4243 DEVICE_REMOVAL_POLICY Policy; 4244 4245 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty); 4246 4247 /* Assume failure */ 4248 *ResultLength = 0; 4249 4250 /* Only PDOs can call this */ 4251 if (!DeviceNode) return STATUS_INVALID_DEVICE_REQUEST; 4252 4253 /* Handle all properties */ 4254 switch (DeviceProperty) 4255 { 4256 case DevicePropertyBusTypeGuid: 4257 4258 /* Get the GUID from the internal cache */ 4259 Status = PnpBusTypeGuidGet(DeviceNode->ChildBusTypeIndex, &BusTypeGuid); 4260 if (!NT_SUCCESS(Status)) return Status; 4261 4262 /* This is the format of the returned data */ 4263 PIP_RETURN_DATA(sizeof(GUID), &BusTypeGuid); 4264 4265 case DevicePropertyLegacyBusType: 4266 4267 /* Validate correct interface type */ 4268 if (DeviceNode->ChildInterfaceType == InterfaceTypeUndefined) 4269 return STATUS_OBJECT_NAME_NOT_FOUND; 4270 4271 /* This is the format of the returned data */ 4272 PIP_RETURN_DATA(sizeof(INTERFACE_TYPE), &DeviceNode->ChildInterfaceType); 4273 4274 case DevicePropertyBusNumber: 4275 4276 /* Validate correct bus number */ 4277 if ((DeviceNode->ChildBusNumber & 0x80000000) == 0x80000000) 4278 return STATUS_OBJECT_NAME_NOT_FOUND; 4279 4280 /* This is the format of the returned data */ 4281 PIP_RETURN_DATA(sizeof(ULONG), &DeviceNode->ChildBusNumber); 4282 4283 case DevicePropertyEnumeratorName: 4284 4285 /* Get the instance path */ 4286 DeviceInstanceName = DeviceNode->InstancePath.Buffer; 4287 4288 /* Sanity checks */ 4289 ASSERT((BufferLength & 1) == 0); 4290 ASSERT(DeviceInstanceName != NULL); 4291 4292 /* Get the name from the path */ 4293 EnumeratorNameEnd = wcschr(DeviceInstanceName, OBJ_NAME_PATH_SEPARATOR); 4294 ASSERT(EnumeratorNameEnd); 4295 4296 /* This string needs to be NULL-terminated */ 4297 NullTerminate = TRUE; 4298 4299 /* This is the format of the returned data */ 4300 PIP_RETURN_DATA((ULONG)(EnumeratorNameEnd - DeviceInstanceName) * sizeof(WCHAR), 4301 DeviceInstanceName); 4302 4303 case DevicePropertyAddress: 4304 4305 /* Query the device caps */ 4306 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps); 4307 if (!NT_SUCCESS(Status) || (DeviceCaps.Address == MAXULONG)) 4308 return STATUS_OBJECT_NAME_NOT_FOUND; 4309 4310 /* This is the format of the returned data */ 4311 PIP_RETURN_DATA(sizeof(ULONG), &DeviceCaps.Address); 4312 4313 case DevicePropertyBootConfigurationTranslated: 4314 4315 /* Validate we have resources */ 4316 if (!DeviceNode->BootResources) 4317 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field 4318 { 4319 /* No resources will still fake success, but with 0 bytes */ 4320 *ResultLength = 0; 4321 return STATUS_SUCCESS; 4322 } 4323 4324 /* This is the format of the returned data */ 4325 PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode->BootResources), // FIXFIX: Should use BootResourcesTranslated 4326 DeviceNode->BootResources); // FIXFIX: Should use BootResourcesTranslated 4327 4328 case DevicePropertyPhysicalDeviceObjectName: 4329 4330 /* Sanity check for Unicode-sized string */ 4331 ASSERT((BufferLength & 1) == 0); 4332 4333 /* Allocate name buffer */ 4334 Length = BufferLength + sizeof(OBJECT_NAME_INFORMATION); 4335 ObjectNameInfo = ExAllocatePool(PagedPool, Length); 4336 if (!ObjectNameInfo) return STATUS_INSUFFICIENT_RESOURCES; 4337 4338 /* Query the PDO name */ 4339 Status = ObQueryNameString(DeviceObject, 4340 ObjectNameInfo, 4341 Length, 4342 ResultLength); 4343 if (Status == STATUS_INFO_LENGTH_MISMATCH) 4344 { 4345 /* It's up to the caller to try again */ 4346 Status = STATUS_BUFFER_TOO_SMALL; 4347 } 4348 4349 /* This string needs to be NULL-terminated */ 4350 NullTerminate = TRUE; 4351 4352 /* Return if successful */ 4353 if (NT_SUCCESS(Status)) PIP_RETURN_DATA(ObjectNameInfo->Name.Length, 4354 ObjectNameInfo->Name.Buffer); 4355 4356 /* Let the caller know how big the name is */ 4357 *ResultLength -= sizeof(OBJECT_NAME_INFORMATION); 4358 break; 4359 4360 case DevicePropertyRemovalPolicy: 4361 4362 Policy = DeviceNode->RemovalPolicy; 4363 PIP_RETURN_DATA(sizeof(Policy), &Policy); 4364 4365 /* Handle the registry-based properties */ 4366 case DevicePropertyUINumber: 4367 PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER, REG_DWORD); 4368 case DevicePropertyLocationInformation: 4369 PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION, REG_SZ); 4370 case DevicePropertyDeviceDescription: 4371 PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC, REG_SZ); 4372 case DevicePropertyHardwareID: 4373 PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID, REG_MULTI_SZ); 4374 case DevicePropertyCompatibleIDs: 4375 PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS, REG_MULTI_SZ); 4376 case DevicePropertyBootConfiguration: 4377 PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG, REG_RESOURCE_LIST); 4378 case DevicePropertyClassName: 4379 PIP_REGISTRY_DATA(REGSTR_VAL_CLASS, REG_SZ); 4380 case DevicePropertyClassGuid: 4381 PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID, REG_SZ); 4382 case DevicePropertyDriverKeyName: 4383 PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER, REG_SZ); 4384 case DevicePropertyManufacturer: 4385 PIP_REGISTRY_DATA(REGSTR_VAL_MFG, REG_SZ); 4386 case DevicePropertyFriendlyName: 4387 PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME, REG_SZ); 4388 case DevicePropertyContainerID: 4389 //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7 4390 PIP_UNIMPLEMENTED(); 4391 break; 4392 case DevicePropertyInstallState: 4393 PIP_REGISTRY_DATA(REGSTR_VAL_CONFIGFLAGS, REG_DWORD); 4394 break; 4395 case DevicePropertyResourceRequirements: 4396 PIP_UNIMPLEMENTED(); 4397 case DevicePropertyAllocatedResources: 4398 PIP_UNIMPLEMENTED(); 4399 default: 4400 return STATUS_INVALID_PARAMETER_2; 4401 } 4402 4403 /* Having a registry value name implies registry data */ 4404 if (ValueName) 4405 { 4406 /* We know up-front how much data to expect */ 4407 *ResultLength = BufferLength; 4408 4409 /* Go get the data, use the LogConf subkey if necessary */ 4410 Status = PiGetDeviceRegistryProperty(DeviceObject, 4411 ValueType, 4412 ValueName, 4413 (DeviceProperty == 4414 DevicePropertyBootConfiguration) ? 4415 L"LogConf": NULL, 4416 PropertyBuffer, 4417 ResultLength); 4418 } 4419 else if (NT_SUCCESS(Status)) 4420 { 4421 /* We know up-front how much data to expect, check the caller's buffer */ 4422 *ResultLength = ReturnLength + (NullTerminate ? sizeof(UNICODE_NULL) : 0); 4423 if (*ResultLength <= BufferLength) 4424 { 4425 /* Buffer is all good, copy the data */ 4426 RtlCopyMemory(PropertyBuffer, Data, ReturnLength); 4427 4428 /* Check if we need to NULL-terminate the string */ 4429 if (NullTerminate) 4430 { 4431 /* Terminate the string */ 4432 ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL; 4433 } 4434 4435 /* This is the success path */ 4436 Status = STATUS_SUCCESS; 4437 } 4438 else 4439 { 4440 /* Failure path */ 4441 Status = STATUS_BUFFER_TOO_SMALL; 4442 } 4443 } 4444 4445 /* Free any allocation we may have made, and return the status code */ 4446 if (ObjectNameInfo) ExFreePool(ObjectNameInfo); 4447 return Status; 4448 } 4449 4450 /* 4451 * @implemented 4452 */ 4453 VOID 4454 NTAPI 4455 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject) 4456 { 4457 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject); 4458 IO_STACK_LOCATION Stack; 4459 ULONG PnPFlags; 4460 NTSTATUS Status; 4461 IO_STATUS_BLOCK IoStatusBlock; 4462 4463 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 4464 Stack.MajorFunction = IRP_MJ_PNP; 4465 Stack.MinorFunction = IRP_MN_QUERY_PNP_DEVICE_STATE; 4466 4467 Status = IopSynchronousCall(PhysicalDeviceObject, &Stack, (PVOID*)&PnPFlags); 4468 if (!NT_SUCCESS(Status)) 4469 { 4470 if (Status != STATUS_NOT_SUPPORTED) 4471 { 4472 DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%lx\n", Status); 4473 } 4474 return; 4475 } 4476 4477 if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE) 4478 DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE; 4479 else 4480 DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE; 4481 4482 if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI) 4483 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI; 4484 else 4485 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI; 4486 4487 if ((PnPFlags & PNP_DEVICE_REMOVED) || 4488 ((PnPFlags & PNP_DEVICE_FAILED) && !(PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED))) 4489 { 4490 /* Flag it if it's failed */ 4491 if (PnPFlags & PNP_DEVICE_FAILED) DeviceNode->Problem = CM_PROB_FAILED_POST_START; 4492 4493 /* Send removal IRPs to all of its children */ 4494 IopPrepareDeviceForRemoval(PhysicalDeviceObject, TRUE); 4495 4496 /* Send surprise removal */ 4497 IopSendSurpriseRemoval(PhysicalDeviceObject); 4498 4499 /* Tell the user-mode PnP manager that a device was removed */ 4500 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL, 4501 &DeviceNode->InstancePath); 4502 4503 IopSendRemoveDevice(PhysicalDeviceObject); 4504 } 4505 else if ((PnPFlags & PNP_DEVICE_FAILED) && (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)) 4506 { 4507 /* Stop for resource rebalance */ 4508 Status = IopStopDevice(DeviceNode); 4509 if (!NT_SUCCESS(Status)) 4510 { 4511 DPRINT1("Failed to stop device for rebalancing\n"); 4512 4513 /* Stop failed so don't rebalance */ 4514 PnPFlags &= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED; 4515 } 4516 } 4517 4518 /* Resource rebalance */ 4519 if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED) 4520 { 4521 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n"); 4522 4523 Status = IopInitiatePnpIrp(PhysicalDeviceObject, 4524 &IoStatusBlock, 4525 IRP_MN_QUERY_RESOURCES, 4526 NULL); 4527 if (NT_SUCCESS(Status) && IoStatusBlock.Information) 4528 { 4529 DeviceNode->BootResources = 4530 (PCM_RESOURCE_LIST)IoStatusBlock.Information; 4531 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG); 4532 } 4533 else 4534 { 4535 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); 4536 DeviceNode->BootResources = NULL; 4537 } 4538 4539 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n"); 4540 4541 Status = IopInitiatePnpIrp(PhysicalDeviceObject, 4542 &IoStatusBlock, 4543 IRP_MN_QUERY_RESOURCE_REQUIREMENTS, 4544 NULL); 4545 if (NT_SUCCESS(Status)) 4546 { 4547 DeviceNode->ResourceRequirements = 4548 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information; 4549 } 4550 else 4551 { 4552 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status); 4553 DeviceNode->ResourceRequirements = NULL; 4554 } 4555 4556 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */ 4557 if (IopStartDevice(DeviceNode) != STATUS_SUCCESS) 4558 { 4559 DPRINT1("Restart after resource rebalance failed\n"); 4560 4561 DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING); 4562 DeviceNode->Flags |= DNF_START_FAILED; 4563 4564 IopRemoveDevice(DeviceNode); 4565 } 4566 } 4567 } 4568 4569 /** 4570 * @name IoOpenDeviceRegistryKey 4571 * 4572 * Open a registry key unique for a specified driver or device instance. 4573 * 4574 * @param DeviceObject Device to get the registry key for. 4575 * @param DevInstKeyType Type of the key to return. 4576 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE). 4577 * @param DevInstRegKey Handle to the opened registry key on 4578 * successful return. 4579 * 4580 * @return Status. 4581 * 4582 * @implemented 4583 */ 4584 NTSTATUS 4585 NTAPI 4586 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject, 4587 IN ULONG DevInstKeyType, 4588 IN ACCESS_MASK DesiredAccess, 4589 OUT PHANDLE DevInstRegKey) 4590 { 4591 static WCHAR RootKeyName[] = 4592 L"\\Registry\\Machine\\System\\CurrentControlSet\\"; 4593 static WCHAR ProfileKeyName[] = 4594 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\"; 4595 static WCHAR ClassKeyName[] = L"Control\\Class\\"; 4596 static WCHAR EnumKeyName[] = L"Enum\\"; 4597 static WCHAR DeviceParametersKeyName[] = L"Device Parameters"; 4598 ULONG KeyNameLength; 4599 PWSTR KeyNameBuffer; 4600 UNICODE_STRING KeyName; 4601 ULONG DriverKeyLength; 4602 OBJECT_ATTRIBUTES ObjectAttributes; 4603 PDEVICE_NODE DeviceNode = NULL; 4604 NTSTATUS Status; 4605 4606 DPRINT("IoOpenDeviceRegistryKey() called\n"); 4607 4608 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0) 4609 { 4610 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n"); 4611 return STATUS_INVALID_PARAMETER; 4612 } 4613 4614 if (!IopIsValidPhysicalDeviceObject(DeviceObject)) 4615 return STATUS_INVALID_DEVICE_REQUEST; 4616 DeviceNode = IopGetDeviceNode(DeviceObject); 4617 4618 /* 4619 * Calculate the length of the base key name. This is the full 4620 * name for driver key or the name excluding "Device Parameters" 4621 * subkey for device key. 4622 */ 4623 4624 KeyNameLength = sizeof(RootKeyName); 4625 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE) 4626 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL); 4627 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER) 4628 { 4629 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL); 4630 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName, 4631 0, NULL, &DriverKeyLength); 4632 if (Status != STATUS_BUFFER_TOO_SMALL) 4633 return Status; 4634 KeyNameLength += DriverKeyLength; 4635 } 4636 else 4637 { 4638 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) + 4639 DeviceNode->InstancePath.Length; 4640 } 4641 4642 /* 4643 * Now allocate the buffer for the key name... 4644 */ 4645 4646 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength); 4647 if (KeyNameBuffer == NULL) 4648 return STATUS_INSUFFICIENT_RESOURCES; 4649 4650 KeyName.Length = 0; 4651 KeyName.MaximumLength = (USHORT)KeyNameLength; 4652 KeyName.Buffer = KeyNameBuffer; 4653 4654 /* 4655 * ...and build the key name. 4656 */ 4657 4658 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL); 4659 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length); 4660 4661 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE) 4662 RtlAppendUnicodeToString(&KeyName, ProfileKeyName); 4663 4664 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER) 4665 { 4666 RtlAppendUnicodeToString(&KeyName, ClassKeyName); 4667 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName, 4668 DriverKeyLength, KeyNameBuffer + 4669 (KeyName.Length / sizeof(WCHAR)), 4670 &DriverKeyLength); 4671 if (!NT_SUCCESS(Status)) 4672 { 4673 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status); 4674 ExFreePool(KeyNameBuffer); 4675 return Status; 4676 } 4677 KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL); 4678 } 4679 else 4680 { 4681 RtlAppendUnicodeToString(&KeyName, EnumKeyName); 4682 Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath); 4683 if (DeviceNode->InstancePath.Length == 0) 4684 { 4685 ExFreePool(KeyNameBuffer); 4686 return Status; 4687 } 4688 } 4689 4690 /* 4691 * Open the base key. 4692 */ 4693 Status = IopOpenRegistryKeyEx(DevInstRegKey, NULL, &KeyName, DesiredAccess); 4694 if (!NT_SUCCESS(Status)) 4695 { 4696 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status); 4697 ExFreePool(KeyNameBuffer); 4698 return Status; 4699 } 4700 ExFreePool(KeyNameBuffer); 4701 4702 /* 4703 * For driver key we're done now. 4704 */ 4705 4706 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER) 4707 return Status; 4708 4709 /* 4710 * Let's go further. For device key we must open "Device Parameters" 4711 * subkey and create it if it doesn't exist yet. 4712 */ 4713 4714 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName); 4715 InitializeObjectAttributes(&ObjectAttributes, 4716 &KeyName, 4717 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 4718 *DevInstRegKey, 4719 NULL); 4720 Status = ZwCreateKey(DevInstRegKey, 4721 DesiredAccess, 4722 &ObjectAttributes, 4723 0, 4724 NULL, 4725 REG_OPTION_NON_VOLATILE, 4726 NULL); 4727 ZwClose(ObjectAttributes.RootDirectory); 4728 4729 return Status; 4730 } 4731 4732 static 4733 NTSTATUS 4734 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode, BOOLEAN Force) 4735 { 4736 PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice; 4737 NTSTATUS Status; 4738 KIRQL OldIrql; 4739 4740 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4741 ChildDeviceNode = ParentDeviceNode->Child; 4742 while (ChildDeviceNode != NULL) 4743 { 4744 NextDeviceNode = ChildDeviceNode->Sibling; 4745 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4746 4747 Status = IopPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject, Force); 4748 if (!NT_SUCCESS(Status)) 4749 { 4750 FailedRemoveDevice = ChildDeviceNode; 4751 goto cleanup; 4752 } 4753 4754 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4755 ChildDeviceNode = NextDeviceNode; 4756 } 4757 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4758 4759 return STATUS_SUCCESS; 4760 4761 cleanup: 4762 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4763 ChildDeviceNode = ParentDeviceNode->Child; 4764 while (ChildDeviceNode != NULL) 4765 { 4766 NextDeviceNode = ChildDeviceNode->Sibling; 4767 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4768 4769 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject); 4770 4771 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device 4772 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */ 4773 if (ChildDeviceNode == FailedRemoveDevice) 4774 return Status; 4775 4776 ChildDeviceNode = NextDeviceNode; 4777 4778 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4779 } 4780 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4781 4782 return Status; 4783 } 4784 4785 static 4786 VOID 4787 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode) 4788 { 4789 PDEVICE_NODE ChildDeviceNode, NextDeviceNode; 4790 KIRQL OldIrql; 4791 4792 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4793 ChildDeviceNode = ParentDeviceNode->Child; 4794 while (ChildDeviceNode != NULL) 4795 { 4796 NextDeviceNode = ChildDeviceNode->Sibling; 4797 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4798 4799 IopSendRemoveDevice(ChildDeviceNode->PhysicalDeviceObject); 4800 4801 ChildDeviceNode = NextDeviceNode; 4802 4803 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4804 } 4805 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4806 } 4807 4808 static 4809 VOID 4810 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode) 4811 { 4812 PDEVICE_NODE ChildDeviceNode, NextDeviceNode; 4813 KIRQL OldIrql; 4814 4815 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4816 ChildDeviceNode = ParentDeviceNode->Child; 4817 while (ChildDeviceNode != NULL) 4818 { 4819 NextDeviceNode = ChildDeviceNode->Sibling; 4820 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4821 4822 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject); 4823 4824 ChildDeviceNode = NextDeviceNode; 4825 4826 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4827 } 4828 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4829 } 4830 4831 static 4832 NTSTATUS 4833 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations, BOOLEAN Force) 4834 { 4835 /* This function DOES NOT dereference the device objects on SUCCESS 4836 * but it DOES dereference device objects on FAILURE */ 4837 4838 ULONG i, j; 4839 NTSTATUS Status; 4840 4841 for (i = 0; i < DeviceRelations->Count; i++) 4842 { 4843 Status = IopPrepareDeviceForRemoval(DeviceRelations->Objects[i], Force); 4844 if (!NT_SUCCESS(Status)) 4845 { 4846 j = i; 4847 goto cleanup; 4848 } 4849 } 4850 4851 return STATUS_SUCCESS; 4852 4853 cleanup: 4854 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device 4855 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */ 4856 for (i = 0; i <= j; i++) 4857 { 4858 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]); 4859 ObDereferenceObject(DeviceRelations->Objects[i]); 4860 DeviceRelations->Objects[i] = NULL; 4861 } 4862 for (; i < DeviceRelations->Count; i++) 4863 { 4864 ObDereferenceObject(DeviceRelations->Objects[i]); 4865 DeviceRelations->Objects[i] = NULL; 4866 } 4867 ExFreePool(DeviceRelations); 4868 4869 return Status; 4870 } 4871 4872 static 4873 VOID 4874 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations) 4875 { 4876 /* This function DOES dereference the device objects in all cases */ 4877 4878 ULONG i; 4879 4880 for (i = 0; i < DeviceRelations->Count; i++) 4881 { 4882 IopSendRemoveDevice(DeviceRelations->Objects[i]); 4883 DeviceRelations->Objects[i] = NULL; 4884 } 4885 4886 ExFreePool(DeviceRelations); 4887 } 4888 4889 static 4890 VOID 4891 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations) 4892 { 4893 /* This function DOES dereference the device objects in all cases */ 4894 4895 ULONG i; 4896 4897 for (i = 0; i < DeviceRelations->Count; i++) 4898 { 4899 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]); 4900 ObDereferenceObject(DeviceRelations->Objects[i]); 4901 DeviceRelations->Objects[i] = NULL; 4902 } 4903 4904 ExFreePool(DeviceRelations); 4905 } 4906 4907 VOID 4908 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject) 4909 { 4910 IO_STACK_LOCATION Stack; 4911 IO_STATUS_BLOCK IoStatusBlock; 4912 PDEVICE_RELATIONS DeviceRelations; 4913 NTSTATUS Status; 4914 4915 IopCancelRemoveDevice(DeviceObject); 4916 4917 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations; 4918 4919 Status = IopInitiatePnpIrp(DeviceObject, 4920 &IoStatusBlock, 4921 IRP_MN_QUERY_DEVICE_RELATIONS, 4922 &Stack); 4923 if (!NT_SUCCESS(Status)) 4924 { 4925 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 4926 DeviceRelations = NULL; 4927 } 4928 else 4929 { 4930 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 4931 } 4932 4933 if (DeviceRelations) 4934 IopCancelRemoveDeviceRelations(DeviceRelations); 4935 } 4936 4937 NTSTATUS 4938 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject, BOOLEAN Force) 4939 { 4940 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 4941 IO_STACK_LOCATION Stack; 4942 IO_STATUS_BLOCK IoStatusBlock; 4943 PDEVICE_RELATIONS DeviceRelations; 4944 NTSTATUS Status; 4945 4946 if ((DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE) && !Force) 4947 { 4948 DPRINT1("Removal not allowed for %wZ\n", &DeviceNode->InstancePath); 4949 return STATUS_UNSUCCESSFUL; 4950 } 4951 4952 if (!Force && IopQueryRemoveDevice(DeviceObject) != STATUS_SUCCESS) 4953 { 4954 DPRINT1("Removal vetoed by failing the query remove request\n"); 4955 4956 IopCancelRemoveDevice(DeviceObject); 4957 4958 return STATUS_UNSUCCESSFUL; 4959 } 4960 4961 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations; 4962 4963 Status = IopInitiatePnpIrp(DeviceObject, 4964 &IoStatusBlock, 4965 IRP_MN_QUERY_DEVICE_RELATIONS, 4966 &Stack); 4967 if (!NT_SUCCESS(Status)) 4968 { 4969 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 4970 DeviceRelations = NULL; 4971 } 4972 else 4973 { 4974 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 4975 } 4976 4977 if (DeviceRelations) 4978 { 4979 Status = IopQueryRemoveDeviceRelations(DeviceRelations, Force); 4980 if (!NT_SUCCESS(Status)) 4981 return Status; 4982 } 4983 4984 Status = IopQueryRemoveChildDevices(DeviceNode, Force); 4985 if (!NT_SUCCESS(Status)) 4986 { 4987 if (DeviceRelations) 4988 IopCancelRemoveDeviceRelations(DeviceRelations); 4989 return Status; 4990 } 4991 4992 if (DeviceRelations) 4993 IopSendRemoveDeviceRelations(DeviceRelations); 4994 IopSendRemoveChildDevices(DeviceNode); 4995 4996 return STATUS_SUCCESS; 4997 } 4998 4999 NTSTATUS 5000 IopRemoveDevice(PDEVICE_NODE DeviceNode) 5001 { 5002 NTSTATUS Status; 5003 5004 DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath); 5005 5006 Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject, FALSE); 5007 if (NT_SUCCESS(Status)) 5008 { 5009 IopSendRemoveDevice(DeviceNode->PhysicalDeviceObject); 5010 IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL, 5011 &DeviceNode->InstancePath); 5012 return STATUS_SUCCESS; 5013 } 5014 5015 return Status; 5016 } 5017 5018 /* 5019 * @implemented 5020 */ 5021 VOID 5022 NTAPI 5023 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject) 5024 { 5025 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject); 5026 PDEVICE_RELATIONS DeviceRelations; 5027 IO_STATUS_BLOCK IoStatusBlock; 5028 IO_STACK_LOCATION Stack; 5029 DEVICE_CAPABILITIES Capabilities; 5030 NTSTATUS Status; 5031 5032 IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT, 5033 &DeviceNode->InstancePath); 5034 5035 if (IopQueryDeviceCapabilities(DeviceNode, &Capabilities) != STATUS_SUCCESS) 5036 { 5037 goto cleanup; 5038 } 5039 5040 Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations; 5041 5042 Status = IopInitiatePnpIrp(PhysicalDeviceObject, 5043 &IoStatusBlock, 5044 IRP_MN_QUERY_DEVICE_RELATIONS, 5045 &Stack); 5046 if (!NT_SUCCESS(Status)) 5047 { 5048 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 5049 DeviceRelations = NULL; 5050 } 5051 else 5052 { 5053 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 5054 } 5055 5056 if (DeviceRelations) 5057 { 5058 Status = IopQueryRemoveDeviceRelations(DeviceRelations, FALSE); 5059 if (!NT_SUCCESS(Status)) 5060 goto cleanup; 5061 } 5062 5063 Status = IopQueryRemoveChildDevices(DeviceNode, FALSE); 5064 if (!NT_SUCCESS(Status)) 5065 { 5066 if (DeviceRelations) 5067 IopCancelRemoveDeviceRelations(DeviceRelations); 5068 goto cleanup; 5069 } 5070 5071 if (IopPrepareDeviceForRemoval(PhysicalDeviceObject, FALSE) != STATUS_SUCCESS) 5072 { 5073 if (DeviceRelations) 5074 IopCancelRemoveDeviceRelations(DeviceRelations); 5075 IopCancelRemoveChildDevices(DeviceNode); 5076 goto cleanup; 5077 } 5078 5079 if (DeviceRelations) 5080 IopSendRemoveDeviceRelations(DeviceRelations); 5081 IopSendRemoveChildDevices(DeviceNode); 5082 5083 DeviceNode->Problem = CM_PROB_HELD_FOR_EJECT; 5084 if (Capabilities.EjectSupported) 5085 { 5086 if (IopSendEject(PhysicalDeviceObject) != STATUS_SUCCESS) 5087 { 5088 goto cleanup; 5089 } 5090 } 5091 else 5092 { 5093 DeviceNode->Flags |= DNF_DISABLED; 5094 } 5095 5096 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT, 5097 &DeviceNode->InstancePath); 5098 5099 return; 5100 5101 cleanup: 5102 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED, 5103 &DeviceNode->InstancePath); 5104 } 5105 5106 /* 5107 * @implemented 5108 */ 5109 VOID 5110 NTAPI 5111 IoInvalidateDeviceRelations( 5112 IN PDEVICE_OBJECT DeviceObject, 5113 IN DEVICE_RELATION_TYPE Type) 5114 { 5115 PDEVICE_ACTION_DATA Data; 5116 KIRQL OldIrql; 5117 5118 Data = ExAllocatePoolWithTag(NonPagedPool, 5119 sizeof(DEVICE_ACTION_DATA), 5120 TAG_IO); 5121 if (!Data) 5122 return; 5123 5124 ObReferenceObject(DeviceObject); 5125 Data->DeviceObject = DeviceObject; 5126 Data->Type = Type; 5127 5128 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql); 5129 InsertTailList(&IopDeviceActionRequestList, &Data->RequestListEntry); 5130 if (IopDeviceActionInProgress) 5131 { 5132 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); 5133 return; 5134 } 5135 IopDeviceActionInProgress = TRUE; 5136 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); 5137 5138 ExInitializeWorkItem(&IopDeviceActionWorkItem, 5139 IopDeviceActionWorker, 5140 NULL); 5141 ExQueueWorkItem(&IopDeviceActionWorkItem, 5142 DelayedWorkQueue); 5143 } 5144 5145 /* 5146 * @implemented 5147 */ 5148 NTSTATUS 5149 NTAPI 5150 IoSynchronousInvalidateDeviceRelations( 5151 IN PDEVICE_OBJECT DeviceObject, 5152 IN DEVICE_RELATION_TYPE Type) 5153 { 5154 PAGED_CODE(); 5155 5156 switch (Type) 5157 { 5158 case BusRelations: 5159 /* Enumerate the device */ 5160 return IopEnumerateDevice(DeviceObject); 5161 case PowerRelations: 5162 /* Not handled yet */ 5163 return STATUS_NOT_IMPLEMENTED; 5164 case TargetDeviceRelation: 5165 /* Nothing to do */ 5166 return STATUS_SUCCESS; 5167 default: 5168 /* Ejection relations are not supported */ 5169 return STATUS_NOT_SUPPORTED; 5170 } 5171 } 5172 5173 /* 5174 * @implemented 5175 */ 5176 BOOLEAN 5177 NTAPI 5178 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType, 5179 IN ULONG BusNumber, 5180 IN PHYSICAL_ADDRESS BusAddress, 5181 IN OUT PULONG AddressSpace, 5182 OUT PPHYSICAL_ADDRESS TranslatedAddress) 5183 { 5184 /* FIXME: Notify the resource arbiter */ 5185 5186 return HalTranslateBusAddress(InterfaceType, 5187 BusNumber, 5188 BusAddress, 5189 AddressSpace, 5190 TranslatedAddress); 5191 } 5192