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