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