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