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 IsMultiSz = TRUE; 1797 break; 1798 1799 default: 1800 DPRINT1("IopValidateID: Not handled QueryType - %x\n", QueryType); 1801 return FALSE; 1802 } 1803 1804 StringEnd = Id + MAX_DEVICE_ID_LEN; 1805 1806 for (PtrChar = Id; PtrChar < StringEnd; PtrChar++) 1807 { 1808 Char = *PtrChar; 1809 1810 if (Char == UNICODE_NULL) 1811 { 1812 if (!IsMultiSz || (PtrPrevChar && PtrChar == PtrPrevChar + 1)) 1813 { 1814 if (MaxSeparators == SeparatorsCount || IsMultiSz) 1815 { 1816 return TRUE; 1817 } 1818 1819 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n", 1820 SeparatorsCount, MaxSeparators); 1821 goto ErrorExit; 1822 } 1823 1824 StringEnd = PtrChar + MAX_DEVICE_ID_LEN + 1; 1825 PtrPrevChar = PtrChar; 1826 } 1827 else if (Char < ' ' || Char > 0x7F || Char == ',') 1828 { 1829 DPRINT1("IopValidateID: Invalid character - %04X\n", Char); 1830 goto ErrorExit; 1831 } 1832 else if (Char == ' ') 1833 { 1834 *PtrChar = '_'; 1835 } 1836 else if (Char == '\\') 1837 { 1838 SeparatorsCount++; 1839 1840 if (SeparatorsCount > MaxSeparators) 1841 { 1842 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n", 1843 SeparatorsCount, MaxSeparators); 1844 goto ErrorExit; 1845 } 1846 } 1847 } 1848 1849 DPRINT1("IopValidateID: Not terminated ID\n"); 1850 1851 ErrorExit: 1852 // FIXME logging 1853 return FALSE; 1854 } 1855 1856 NTSTATUS 1857 IopQueryHardwareIds(PDEVICE_NODE DeviceNode, 1858 HANDLE InstanceKey) 1859 { 1860 IO_STACK_LOCATION Stack; 1861 IO_STATUS_BLOCK IoStatusBlock; 1862 PWSTR Ptr; 1863 UNICODE_STRING ValueName; 1864 NTSTATUS Status; 1865 ULONG Length, TotalLength; 1866 BOOLEAN IsValidID; 1867 1868 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n"); 1869 1870 RtlZeroMemory(&Stack, sizeof(Stack)); 1871 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs; 1872 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 1873 &IoStatusBlock, 1874 IRP_MN_QUERY_ID, 1875 &Stack); 1876 if (NT_SUCCESS(Status)) 1877 { 1878 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryHardwareIDs); 1879 1880 if (!IsValidID) 1881 { 1882 DPRINT1("Invalid HardwareIDs. DeviceNode - %p\n", DeviceNode); 1883 } 1884 1885 TotalLength = 0; 1886 1887 Ptr = (PWSTR)IoStatusBlock.Information; 1888 DPRINT("Hardware IDs:\n"); 1889 while (*Ptr) 1890 { 1891 DPRINT(" %S\n", Ptr); 1892 Length = (ULONG)wcslen(Ptr) + 1; 1893 1894 Ptr += Length; 1895 TotalLength += Length; 1896 } 1897 DPRINT("TotalLength: %hu\n", TotalLength); 1898 DPRINT("\n"); 1899 1900 RtlInitUnicodeString(&ValueName, L"HardwareID"); 1901 Status = ZwSetValueKey(InstanceKey, 1902 &ValueName, 1903 0, 1904 REG_MULTI_SZ, 1905 (PVOID)IoStatusBlock.Information, 1906 (TotalLength + 1) * sizeof(WCHAR)); 1907 if (!NT_SUCCESS(Status)) 1908 { 1909 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status); 1910 } 1911 } 1912 else 1913 { 1914 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status); 1915 } 1916 1917 return Status; 1918 } 1919 1920 NTSTATUS 1921 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode, 1922 HANDLE InstanceKey) 1923 { 1924 IO_STACK_LOCATION Stack; 1925 IO_STATUS_BLOCK IoStatusBlock; 1926 PWSTR Ptr; 1927 UNICODE_STRING ValueName; 1928 NTSTATUS Status; 1929 ULONG Length, TotalLength; 1930 BOOLEAN IsValidID; 1931 1932 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n"); 1933 1934 RtlZeroMemory(&Stack, sizeof(Stack)); 1935 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs; 1936 Status = IopInitiatePnpIrp( 1937 DeviceNode->PhysicalDeviceObject, 1938 &IoStatusBlock, 1939 IRP_MN_QUERY_ID, 1940 &Stack); 1941 if (NT_SUCCESS(Status) && IoStatusBlock.Information) 1942 { 1943 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryCompatibleIDs); 1944 1945 if (!IsValidID) 1946 { 1947 DPRINT1("Invalid CompatibleIDs. DeviceNode - %p\n", DeviceNode); 1948 } 1949 1950 TotalLength = 0; 1951 1952 Ptr = (PWSTR)IoStatusBlock.Information; 1953 DPRINT("Compatible IDs:\n"); 1954 while (*Ptr) 1955 { 1956 DPRINT(" %S\n", Ptr); 1957 Length = (ULONG)wcslen(Ptr) + 1; 1958 1959 Ptr += Length; 1960 TotalLength += Length; 1961 } 1962 DPRINT("TotalLength: %hu\n", TotalLength); 1963 DPRINT("\n"); 1964 1965 RtlInitUnicodeString(&ValueName, L"CompatibleIDs"); 1966 Status = ZwSetValueKey(InstanceKey, 1967 &ValueName, 1968 0, 1969 REG_MULTI_SZ, 1970 (PVOID)IoStatusBlock.Information, 1971 (TotalLength + 1) * sizeof(WCHAR)); 1972 if (!NT_SUCCESS(Status)) 1973 { 1974 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status); 1975 } 1976 } 1977 else 1978 { 1979 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status); 1980 } 1981 1982 return Status; 1983 } 1984 1985 NTSTATUS 1986 IopCreateDeviceInstancePath( 1987 _In_ PDEVICE_NODE DeviceNode, 1988 _Out_ PUNICODE_STRING InstancePath) 1989 { 1990 IO_STATUS_BLOCK IoStatusBlock; 1991 UNICODE_STRING DeviceId; 1992 UNICODE_STRING InstanceId; 1993 IO_STACK_LOCATION Stack; 1994 NTSTATUS Status; 1995 UNICODE_STRING ParentIdPrefix = { 0, 0, NULL }; 1996 DEVICE_CAPABILITIES DeviceCapabilities; 1997 BOOLEAN IsValidID; 1998 1999 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n"); 2000 2001 Stack.Parameters.QueryId.IdType = BusQueryDeviceID; 2002 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 2003 &IoStatusBlock, 2004 IRP_MN_QUERY_ID, 2005 &Stack); 2006 if (!NT_SUCCESS(Status)) 2007 { 2008 DPRINT1("IopInitiatePnpIrp(BusQueryDeviceID) failed (Status %x)\n", Status); 2009 return Status; 2010 } 2011 2012 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryDeviceID); 2013 2014 if (!IsValidID) 2015 { 2016 DPRINT1("Invalid DeviceID. DeviceNode - %p\n", DeviceNode); 2017 } 2018 2019 /* Save the device id string */ 2020 RtlInitUnicodeString(&DeviceId, (PWSTR)IoStatusBlock.Information); 2021 2022 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n"); 2023 2024 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities); 2025 if (!NT_SUCCESS(Status)) 2026 { 2027 DPRINT1("IopQueryDeviceCapabilities() failed (Status 0x%08lx)\n", Status); 2028 RtlFreeUnicodeString(&DeviceId); 2029 return Status; 2030 } 2031 2032 /* This bit is only check after enumeration */ 2033 if (DeviceCapabilities.HardwareDisabled) 2034 { 2035 /* FIXME: Cleanup device */ 2036 DeviceNode->Flags |= DNF_DISABLED; 2037 RtlFreeUnicodeString(&DeviceId); 2038 return STATUS_PLUGPLAY_NO_DEVICE; 2039 } 2040 else 2041 { 2042 DeviceNode->Flags &= ~DNF_DISABLED; 2043 } 2044 2045 if (!DeviceCapabilities.UniqueID) 2046 { 2047 /* Device has not a unique ID. We need to prepend parent bus unique identifier */ 2048 DPRINT("Instance ID is not unique\n"); 2049 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix); 2050 if (!NT_SUCCESS(Status)) 2051 { 2052 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status); 2053 RtlFreeUnicodeString(&DeviceId); 2054 return Status; 2055 } 2056 } 2057 2058 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n"); 2059 2060 Stack.Parameters.QueryId.IdType = BusQueryInstanceID; 2061 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 2062 &IoStatusBlock, 2063 IRP_MN_QUERY_ID, 2064 &Stack); 2065 if (!NT_SUCCESS(Status)) 2066 { 2067 DPRINT("IopInitiatePnpIrp(BusQueryInstanceID) failed (Status %lx)\n", Status); 2068 ASSERT(IoStatusBlock.Information == 0); 2069 } 2070 2071 if (IoStatusBlock.Information) 2072 { 2073 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryInstanceID); 2074 2075 if (!IsValidID) 2076 { 2077 DPRINT1("Invalid InstanceID. DeviceNode - %p\n", DeviceNode); 2078 } 2079 } 2080 2081 RtlInitUnicodeString(&InstanceId, 2082 (PWSTR)IoStatusBlock.Information); 2083 2084 InstancePath->Length = 0; 2085 InstancePath->MaximumLength = DeviceId.Length + sizeof(WCHAR) + 2086 ParentIdPrefix.Length + 2087 InstanceId.Length + 2088 sizeof(UNICODE_NULL); 2089 if (ParentIdPrefix.Length && InstanceId.Length) 2090 { 2091 InstancePath->MaximumLength += sizeof(WCHAR); 2092 } 2093 2094 InstancePath->Buffer = ExAllocatePoolWithTag(PagedPool, 2095 InstancePath->MaximumLength, 2096 TAG_IO); 2097 if (!InstancePath->Buffer) 2098 { 2099 RtlFreeUnicodeString(&InstanceId); 2100 RtlFreeUnicodeString(&ParentIdPrefix); 2101 RtlFreeUnicodeString(&DeviceId); 2102 return STATUS_INSUFFICIENT_RESOURCES; 2103 } 2104 2105 /* Start with the device id */ 2106 RtlCopyUnicodeString(InstancePath, &DeviceId); 2107 RtlAppendUnicodeToString(InstancePath, L"\\"); 2108 2109 /* Add information from parent bus device to InstancePath */ 2110 RtlAppendUnicodeStringToString(InstancePath, &ParentIdPrefix); 2111 if (ParentIdPrefix.Length && InstanceId.Length) 2112 { 2113 RtlAppendUnicodeToString(InstancePath, L"&"); 2114 } 2115 2116 /* Finally, add the id returned by the driver stack */ 2117 RtlAppendUnicodeStringToString(InstancePath, &InstanceId); 2118 2119 /* 2120 * FIXME: Check for valid characters, if there is invalid characters 2121 * then bugcheck 2122 */ 2123 2124 RtlFreeUnicodeString(&InstanceId); 2125 RtlFreeUnicodeString(&DeviceId); 2126 RtlFreeUnicodeString(&ParentIdPrefix); 2127 2128 return STATUS_SUCCESS; 2129 } 2130 2131 /* 2132 * IopActionInterrogateDeviceStack 2133 * 2134 * Retrieve information for all (direct) child nodes of a parent node. 2135 * 2136 * Parameters 2137 * DeviceNode 2138 * Pointer to device node. 2139 * Context 2140 * Pointer to parent node to retrieve child node information for. 2141 * 2142 * Remarks 2143 * Any errors that occur are logged instead so that all child services have a chance 2144 * of being interrogated. 2145 */ 2146 2147 NTSTATUS 2148 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode, 2149 PVOID Context) 2150 { 2151 IO_STATUS_BLOCK IoStatusBlock; 2152 PWSTR DeviceDescription; 2153 PWSTR LocationInformation; 2154 PDEVICE_NODE ParentDeviceNode; 2155 IO_STACK_LOCATION Stack; 2156 NTSTATUS Status; 2157 ULONG RequiredLength; 2158 LCID LocaleId; 2159 HANDLE InstanceKey = NULL; 2160 UNICODE_STRING ValueName; 2161 UNICODE_STRING InstancePathU; 2162 PDEVICE_OBJECT OldDeviceObject; 2163 2164 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context); 2165 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject); 2166 2167 ParentDeviceNode = (PDEVICE_NODE)Context; 2168 2169 /* 2170 * We are called for the parent too, but we don't need to do special 2171 * handling for this node 2172 */ 2173 if (DeviceNode == ParentDeviceNode) 2174 { 2175 DPRINT("Success\n"); 2176 return STATUS_SUCCESS; 2177 } 2178 2179 /* 2180 * Make sure this device node is a direct child of the parent device node 2181 * that is given as an argument 2182 */ 2183 if (DeviceNode->Parent != ParentDeviceNode) 2184 { 2185 DPRINT("Skipping 2+ level child\n"); 2186 return STATUS_SUCCESS; 2187 } 2188 2189 /* Skip processing if it was already completed before */ 2190 if (DeviceNode->Flags & DNF_PROCESSED) 2191 { 2192 /* Nothing to do */ 2193 return STATUS_SUCCESS; 2194 } 2195 2196 /* Get Locale ID */ 2197 Status = ZwQueryDefaultLocale(FALSE, &LocaleId); 2198 if (!NT_SUCCESS(Status)) 2199 { 2200 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status); 2201 return Status; 2202 } 2203 2204 /* 2205 * FIXME: For critical errors, cleanup and disable device, but always 2206 * return STATUS_SUCCESS. 2207 */ 2208 2209 Status = IopCreateDeviceInstancePath(DeviceNode, &InstancePathU); 2210 if (!NT_SUCCESS(Status)) 2211 { 2212 if (Status != STATUS_PLUGPLAY_NO_DEVICE) 2213 { 2214 DPRINT1("IopCreateDeviceInstancePath() failed with status 0x%lx\n", Status); 2215 } 2216 2217 /* We have to return success otherwise we abort the traverse operation */ 2218 return STATUS_SUCCESS; 2219 } 2220 2221 /* Verify that this is not a duplicate */ 2222 OldDeviceObject = IopGetDeviceObjectFromDeviceInstance(&InstancePathU); 2223 if (OldDeviceObject != NULL) 2224 { 2225 PDEVICE_NODE OldDeviceNode = IopGetDeviceNode(OldDeviceObject); 2226 2227 DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU); 2228 DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode->Parent->InstancePath); 2229 DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode->Parent->InstancePath); 2230 2231 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 2232 0x01, 2233 (ULONG_PTR)DeviceNode->PhysicalDeviceObject, 2234 (ULONG_PTR)OldDeviceObject, 2235 0); 2236 } 2237 2238 DeviceNode->InstancePath = InstancePathU; 2239 2240 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer); 2241 2242 /* 2243 * Create registry key for the instance id, if it doesn't exist yet 2244 */ 2245 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceKey); 2246 if (!NT_SUCCESS(Status)) 2247 { 2248 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status); 2249 2250 /* We have to return success otherwise we abort the traverse operation */ 2251 return STATUS_SUCCESS; 2252 } 2253 2254 IopQueryHardwareIds(DeviceNode, InstanceKey); 2255 2256 IopQueryCompatibleIds(DeviceNode, InstanceKey); 2257 2258 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n"); 2259 2260 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription; 2261 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId; 2262 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 2263 &IoStatusBlock, 2264 IRP_MN_QUERY_DEVICE_TEXT, 2265 &Stack); 2266 DeviceDescription = NT_SUCCESS(Status) ? (PWSTR)IoStatusBlock.Information 2267 : NULL; 2268 /* This key is mandatory, so even if the Irp fails, we still write it */ 2269 RtlInitUnicodeString(&ValueName, L"DeviceDesc"); 2270 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND) 2271 { 2272 if (DeviceDescription && 2273 *DeviceDescription != UNICODE_NULL) 2274 { 2275 /* This key is overriden when a driver is installed. Don't write the 2276 * new description if another one already exists */ 2277 Status = ZwSetValueKey(InstanceKey, 2278 &ValueName, 2279 0, 2280 REG_SZ, 2281 DeviceDescription, 2282 ((ULONG)wcslen(DeviceDescription) + 1) * sizeof(WCHAR)); 2283 } 2284 else 2285 { 2286 UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device"); 2287 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status); 2288 2289 Status = ZwSetValueKey(InstanceKey, 2290 &ValueName, 2291 0, 2292 REG_SZ, 2293 DeviceDesc.Buffer, 2294 DeviceDesc.MaximumLength); 2295 if (!NT_SUCCESS(Status)) 2296 { 2297 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status); 2298 } 2299 2300 } 2301 } 2302 2303 if (DeviceDescription) 2304 { 2305 ExFreePoolWithTag(DeviceDescription, 0); 2306 } 2307 2308 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n"); 2309 2310 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation; 2311 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId; 2312 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 2313 &IoStatusBlock, 2314 IRP_MN_QUERY_DEVICE_TEXT, 2315 &Stack); 2316 if (NT_SUCCESS(Status) && IoStatusBlock.Information) 2317 { 2318 LocationInformation = (PWSTR)IoStatusBlock.Information; 2319 DPRINT("LocationInformation: %S\n", LocationInformation); 2320 RtlInitUnicodeString(&ValueName, L"LocationInformation"); 2321 Status = ZwSetValueKey(InstanceKey, 2322 &ValueName, 2323 0, 2324 REG_SZ, 2325 LocationInformation, 2326 ((ULONG)wcslen(LocationInformation) + 1) * sizeof(WCHAR)); 2327 if (!NT_SUCCESS(Status)) 2328 { 2329 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status); 2330 } 2331 2332 ExFreePoolWithTag(LocationInformation, 0); 2333 } 2334 else 2335 { 2336 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); 2337 } 2338 2339 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n"); 2340 2341 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 2342 &IoStatusBlock, 2343 IRP_MN_QUERY_BUS_INFORMATION, 2344 NULL); 2345 if (NT_SUCCESS(Status) && IoStatusBlock.Information) 2346 { 2347 PPNP_BUS_INFORMATION BusInformation = (PPNP_BUS_INFORMATION)IoStatusBlock.Information; 2348 2349 DeviceNode->ChildBusNumber = BusInformation->BusNumber; 2350 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType; 2351 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid); 2352 ExFreePoolWithTag(BusInformation, 0); 2353 } 2354 else 2355 { 2356 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); 2357 2358 DeviceNode->ChildBusNumber = 0xFFFFFFF0; 2359 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined; 2360 DeviceNode->ChildBusTypeIndex = -1; 2361 } 2362 2363 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n"); 2364 2365 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 2366 &IoStatusBlock, 2367 IRP_MN_QUERY_RESOURCES, 2368 NULL); 2369 if (NT_SUCCESS(Status) && IoStatusBlock.Information) 2370 { 2371 DeviceNode->BootResources = (PCM_RESOURCE_LIST)IoStatusBlock.Information; 2372 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG); 2373 } 2374 else 2375 { 2376 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); 2377 DeviceNode->BootResources = NULL; 2378 } 2379 2380 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n"); 2381 2382 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 2383 &IoStatusBlock, 2384 IRP_MN_QUERY_RESOURCE_REQUIREMENTS, 2385 NULL); 2386 if (NT_SUCCESS(Status)) 2387 { 2388 DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information; 2389 } 2390 else 2391 { 2392 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status); 2393 DeviceNode->ResourceRequirements = NULL; 2394 } 2395 2396 if (InstanceKey != NULL) 2397 { 2398 IopSetDeviceInstanceData(InstanceKey, DeviceNode); 2399 } 2400 2401 ZwClose(InstanceKey); 2402 2403 IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED); 2404 2405 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER)) 2406 { 2407 /* Report the device to the user-mode pnp manager */ 2408 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED, 2409 &DeviceNode->InstancePath); 2410 } 2411 2412 return STATUS_SUCCESS; 2413 } 2414 2415 static 2416 VOID 2417 IopHandleDeviceRemoval( 2418 IN PDEVICE_NODE DeviceNode, 2419 IN PDEVICE_RELATIONS DeviceRelations) 2420 { 2421 PDEVICE_NODE Child = DeviceNode->Child, NextChild; 2422 ULONG i; 2423 BOOLEAN Found; 2424 2425 if (DeviceNode == IopRootDeviceNode) 2426 return; 2427 2428 while (Child != NULL) 2429 { 2430 NextChild = Child->Sibling; 2431 Found = FALSE; 2432 2433 for (i = 0; DeviceRelations && i < DeviceRelations->Count; i++) 2434 { 2435 if (IopGetDeviceNode(DeviceRelations->Objects[i]) == Child) 2436 { 2437 Found = TRUE; 2438 break; 2439 } 2440 } 2441 2442 if (!Found && !(Child->Flags & DNF_WILL_BE_REMOVED)) 2443 { 2444 /* Send removal IRPs to all of its children */ 2445 IopPrepareDeviceForRemoval(Child->PhysicalDeviceObject, TRUE); 2446 2447 /* Send the surprise removal IRP */ 2448 IopSendSurpriseRemoval(Child->PhysicalDeviceObject); 2449 2450 /* Tell the user-mode PnP manager that a device was removed */ 2451 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL, 2452 &Child->InstancePath); 2453 2454 /* Send the remove device IRP */ 2455 IopSendRemoveDevice(Child->PhysicalDeviceObject); 2456 } 2457 2458 Child = NextChild; 2459 } 2460 } 2461 2462 NTSTATUS 2463 IopEnumerateDevice( 2464 IN PDEVICE_OBJECT DeviceObject) 2465 { 2466 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 2467 DEVICETREE_TRAVERSE_CONTEXT Context; 2468 PDEVICE_RELATIONS DeviceRelations; 2469 PDEVICE_OBJECT ChildDeviceObject; 2470 IO_STATUS_BLOCK IoStatusBlock; 2471 PDEVICE_NODE ChildDeviceNode; 2472 IO_STACK_LOCATION Stack; 2473 NTSTATUS Status; 2474 ULONG i; 2475 2476 DPRINT("DeviceObject 0x%p\n", DeviceObject); 2477 2478 if (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY) 2479 { 2480 DeviceNode->Flags &= ~DNF_NEED_ENUMERATION_ONLY; 2481 2482 DPRINT("Sending GUID_DEVICE_ARRIVAL\n"); 2483 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, 2484 &DeviceNode->InstancePath); 2485 } 2486 2487 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n"); 2488 2489 Stack.Parameters.QueryDeviceRelations.Type = BusRelations; 2490 2491 Status = IopInitiatePnpIrp( 2492 DeviceObject, 2493 &IoStatusBlock, 2494 IRP_MN_QUERY_DEVICE_RELATIONS, 2495 &Stack); 2496 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING) 2497 { 2498 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 2499 return Status; 2500 } 2501 2502 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 2503 2504 /* 2505 * Send removal IRPs for devices that have disappeared 2506 * NOTE: This code handles the case where no relations are specified 2507 */ 2508 IopHandleDeviceRemoval(DeviceNode, DeviceRelations); 2509 2510 /* Now we bail if nothing was returned */ 2511 if (!DeviceRelations) 2512 { 2513 /* We're all done */ 2514 DPRINT("No PDOs\n"); 2515 return STATUS_SUCCESS; 2516 } 2517 2518 DPRINT("Got %u PDOs\n", DeviceRelations->Count); 2519 2520 /* 2521 * Create device nodes for all discovered devices 2522 */ 2523 for (i = 0; i < DeviceRelations->Count; i++) 2524 { 2525 ChildDeviceObject = DeviceRelations->Objects[i]; 2526 ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0); 2527 2528 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject); 2529 if (!ChildDeviceNode) 2530 { 2531 /* One doesn't exist, create it */ 2532 Status = IopCreateDeviceNode( 2533 DeviceNode, 2534 ChildDeviceObject, 2535 NULL, 2536 &ChildDeviceNode); 2537 if (NT_SUCCESS(Status)) 2538 { 2539 /* Mark the node as enumerated */ 2540 ChildDeviceNode->Flags |= DNF_ENUMERATED; 2541 2542 /* Mark the DO as bus enumerated */ 2543 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE; 2544 } 2545 else 2546 { 2547 /* Ignore this DO */ 2548 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i); 2549 ObDereferenceObject(ChildDeviceObject); 2550 } 2551 } 2552 else 2553 { 2554 /* Mark it as enumerated */ 2555 ChildDeviceNode->Flags |= DNF_ENUMERATED; 2556 ObDereferenceObject(ChildDeviceObject); 2557 } 2558 } 2559 ExFreePool(DeviceRelations); 2560 2561 /* 2562 * Retrieve information about all discovered children from the bus driver 2563 */ 2564 IopInitDeviceTreeTraverseContext( 2565 &Context, 2566 DeviceNode, 2567 IopActionInterrogateDeviceStack, 2568 DeviceNode); 2569 2570 Status = IopTraverseDeviceTree(&Context); 2571 if (!NT_SUCCESS(Status)) 2572 { 2573 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status); 2574 return Status; 2575 } 2576 2577 /* 2578 * Retrieve configuration from the registry for discovered children 2579 */ 2580 IopInitDeviceTreeTraverseContext( 2581 &Context, 2582 DeviceNode, 2583 IopActionConfigureChildServices, 2584 DeviceNode); 2585 2586 Status = IopTraverseDeviceTree(&Context); 2587 if (!NT_SUCCESS(Status)) 2588 { 2589 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status); 2590 return Status; 2591 } 2592 2593 /* 2594 * Initialize services for discovered children. 2595 */ 2596 Status = IopInitializePnpServices(DeviceNode); 2597 if (!NT_SUCCESS(Status)) 2598 { 2599 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status); 2600 return Status; 2601 } 2602 2603 DPRINT("IopEnumerateDevice() finished\n"); 2604 return STATUS_SUCCESS; 2605 } 2606 2607 2608 /* 2609 * IopActionConfigureChildServices 2610 * 2611 * Retrieve configuration for all (direct) child nodes of a parent node. 2612 * 2613 * Parameters 2614 * DeviceNode 2615 * Pointer to device node. 2616 * Context 2617 * Pointer to parent node to retrieve child node configuration for. 2618 * 2619 * Remarks 2620 * Any errors that occur are logged instead so that all child services have a chance of beeing 2621 * configured. 2622 */ 2623 2624 NTSTATUS 2625 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode, 2626 PVOID Context) 2627 { 2628 RTL_QUERY_REGISTRY_TABLE QueryTable[3]; 2629 PDEVICE_NODE ParentDeviceNode; 2630 PUNICODE_STRING Service; 2631 UNICODE_STRING ClassGUID; 2632 NTSTATUS Status; 2633 DEVICE_CAPABILITIES DeviceCaps; 2634 2635 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context); 2636 2637 ParentDeviceNode = (PDEVICE_NODE)Context; 2638 2639 /* 2640 * We are called for the parent too, but we don't need to do special 2641 * handling for this node 2642 */ 2643 if (DeviceNode == ParentDeviceNode) 2644 { 2645 DPRINT("Success\n"); 2646 return STATUS_SUCCESS; 2647 } 2648 2649 /* 2650 * Make sure this device node is a direct child of the parent device node 2651 * that is given as an argument 2652 */ 2653 2654 if (DeviceNode->Parent != ParentDeviceNode) 2655 { 2656 DPRINT("Skipping 2+ level child\n"); 2657 return STATUS_SUCCESS; 2658 } 2659 2660 if (!(DeviceNode->Flags & DNF_PROCESSED)) 2661 { 2662 DPRINT1("Child not ready to be configured\n"); 2663 return STATUS_SUCCESS; 2664 } 2665 2666 if (!(DeviceNode->Flags & (DNF_DISABLED | DNF_STARTED | DNF_ADDED))) 2667 { 2668 WCHAR RegKeyBuffer[MAX_PATH]; 2669 UNICODE_STRING RegKey; 2670 2671 /* Install the service for this if it's in the CDDB */ 2672 IopInstallCriticalDevice(DeviceNode); 2673 2674 RegKey.Length = 0; 2675 RegKey.MaximumLength = sizeof(RegKeyBuffer); 2676 RegKey.Buffer = RegKeyBuffer; 2677 2678 /* 2679 * Retrieve configuration from Enum key 2680 */ 2681 2682 Service = &DeviceNode->ServiceName; 2683 2684 RtlZeroMemory(QueryTable, sizeof(QueryTable)); 2685 RtlInitUnicodeString(Service, NULL); 2686 RtlInitUnicodeString(&ClassGUID, NULL); 2687 2688 QueryTable[0].Name = L"Service"; 2689 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 2690 QueryTable[0].EntryContext = Service; 2691 2692 QueryTable[1].Name = L"ClassGUID"; 2693 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT; 2694 QueryTable[1].EntryContext = &ClassGUID; 2695 QueryTable[1].DefaultType = REG_SZ; 2696 QueryTable[1].DefaultData = L""; 2697 QueryTable[1].DefaultLength = 0; 2698 2699 RtlAppendUnicodeToString(&RegKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\"); 2700 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath); 2701 2702 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 2703 RegKey.Buffer, QueryTable, NULL, NULL); 2704 2705 if (!NT_SUCCESS(Status)) 2706 { 2707 /* FIXME: Log the error */ 2708 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n", 2709 &DeviceNode->InstancePath, Status); 2710 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); 2711 return STATUS_SUCCESS; 2712 } 2713 2714 if (Service->Buffer == NULL) 2715 { 2716 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) && 2717 DeviceCaps.RawDeviceOK) 2718 { 2719 DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName); 2720 2721 DeviceNode->ServiceName.Length = 0; 2722 DeviceNode->ServiceName.MaximumLength = 0; 2723 DeviceNode->ServiceName.Buffer = NULL; 2724 } 2725 else if (ClassGUID.Length != 0) 2726 { 2727 /* Device has a ClassGUID value, but no Service value. 2728 * Suppose it is using the NULL driver, so state the 2729 * device is started */ 2730 DPRINT("%wZ is using NULL driver\n", &DeviceNode->InstancePath); 2731 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED); 2732 } 2733 else 2734 { 2735 DeviceNode->Problem = CM_PROB_FAILED_INSTALL; 2736 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); 2737 } 2738 return STATUS_SUCCESS; 2739 } 2740 2741 DPRINT("Got Service %S\n", Service->Buffer); 2742 } 2743 2744 return STATUS_SUCCESS; 2745 } 2746 2747 /* 2748 * IopActionInitChildServices 2749 * 2750 * Initialize the service for all (direct) child nodes of a parent node 2751 * 2752 * Parameters 2753 * DeviceNode 2754 * Pointer to device node. 2755 * Context 2756 * Pointer to parent node to initialize child node services for. 2757 * 2758 * Remarks 2759 * If the driver image for a service is not loaded and initialized 2760 * it is done here too. Any errors that occur are logged instead so 2761 * that all child services have a chance of being initialized. 2762 */ 2763 2764 NTSTATUS 2765 IopActionInitChildServices(PDEVICE_NODE DeviceNode, 2766 PVOID Context) 2767 { 2768 PDEVICE_NODE ParentDeviceNode; 2769 NTSTATUS Status; 2770 BOOLEAN BootDrivers = !PnpSystemInit; 2771 2772 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context); 2773 2774 ParentDeviceNode = Context; 2775 2776 /* 2777 * We are called for the parent too, but we don't need to do special 2778 * handling for this node 2779 */ 2780 if (DeviceNode == ParentDeviceNode) 2781 { 2782 DPRINT("Success\n"); 2783 return STATUS_SUCCESS; 2784 } 2785 2786 /* 2787 * We don't want to check for a direct child because 2788 * this function is called during boot to reinitialize 2789 * devices with drivers that couldn't load yet due to 2790 * stage 0 limitations (ie can't load from disk yet). 2791 */ 2792 2793 if (!(DeviceNode->Flags & DNF_PROCESSED)) 2794 { 2795 DPRINT1("Child not ready to be added\n"); 2796 return STATUS_SUCCESS; 2797 } 2798 2799 if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) || 2800 IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) || 2801 IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED)) 2802 return STATUS_SUCCESS; 2803 2804 if (DeviceNode->ServiceName.Buffer == NULL) 2805 { 2806 /* We don't need to worry about loading the driver because we're 2807 * being driven in raw mode so our parent must be loaded to get here */ 2808 Status = IopInitializeDevice(DeviceNode, NULL); 2809 if (NT_SUCCESS(Status)) 2810 { 2811 Status = IopStartDevice(DeviceNode); 2812 if (!NT_SUCCESS(Status)) 2813 { 2814 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n", 2815 &DeviceNode->InstancePath, Status); 2816 } 2817 } 2818 } 2819 else 2820 { 2821 PLDR_DATA_TABLE_ENTRY ModuleObject; 2822 PDRIVER_OBJECT DriverObject; 2823 2824 KeEnterCriticalRegion(); 2825 ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE); 2826 /* Get existing DriverObject pointer (in case the driver has 2827 already been loaded and initialized) */ 2828 Status = IopGetDriverObject( 2829 &DriverObject, 2830 &DeviceNode->ServiceName, 2831 FALSE); 2832 2833 if (!NT_SUCCESS(Status)) 2834 { 2835 /* Driver is not initialized, try to load it */ 2836 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject); 2837 2838 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED) 2839 { 2840 /* Initialize the driver */ 2841 Status = IopInitializeDriverModule(DeviceNode, ModuleObject, 2842 &DeviceNode->ServiceName, FALSE, &DriverObject); 2843 if (!NT_SUCCESS(Status)) DeviceNode->Problem = CM_PROB_FAILED_DRIVER_ENTRY; 2844 } 2845 else if (Status == STATUS_DRIVER_UNABLE_TO_LOAD) 2846 { 2847 DPRINT1("Service '%wZ' is disabled\n", &DeviceNode->ServiceName); 2848 DeviceNode->Problem = CM_PROB_DISABLED_SERVICE; 2849 } 2850 else 2851 { 2852 DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n", 2853 &DeviceNode->ServiceName, Status); 2854 if (!BootDrivers) DeviceNode->Problem = CM_PROB_DRIVER_FAILED_LOAD; 2855 } 2856 } 2857 ExReleaseResourceLite(&IopDriverLoadResource); 2858 KeLeaveCriticalRegion(); 2859 2860 /* Driver is loaded and initialized at this point */ 2861 if (NT_SUCCESS(Status)) 2862 { 2863 /* Initialize the device, including all filters */ 2864 Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject); 2865 2866 /* Remove the extra reference */ 2867 ObDereferenceObject(DriverObject); 2868 } 2869 else 2870 { 2871 /* 2872 * Don't disable when trying to load only boot drivers 2873 */ 2874 if (!BootDrivers) 2875 { 2876 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); 2877 } 2878 } 2879 } 2880 2881 return STATUS_SUCCESS; 2882 } 2883 2884 /* 2885 * IopInitializePnpServices 2886 * 2887 * Initialize services for discovered children 2888 * 2889 * Parameters 2890 * DeviceNode 2891 * Top device node to start initializing services. 2892 * 2893 * Return Value 2894 * Status 2895 */ 2896 NTSTATUS 2897 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode) 2898 { 2899 DEVICETREE_TRAVERSE_CONTEXT Context; 2900 2901 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode); 2902 2903 IopInitDeviceTreeTraverseContext( 2904 &Context, 2905 DeviceNode, 2906 IopActionInitChildServices, 2907 DeviceNode); 2908 2909 return IopTraverseDeviceTree(&Context); 2910 } 2911 2912 static NTSTATUS INIT_FUNCTION 2913 IopEnumerateDetectedDevices( 2914 IN HANDLE hBaseKey, 2915 IN PUNICODE_STRING RelativePath OPTIONAL, 2916 IN HANDLE hRootKey, 2917 IN BOOLEAN EnumerateSubKeys, 2918 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources, 2919 IN ULONG ParentBootResourcesLength) 2920 { 2921 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier"); 2922 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID"); 2923 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data"); 2924 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig"); 2925 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf"); 2926 OBJECT_ATTRIBUTES ObjectAttributes; 2927 HANDLE hDevicesKey = NULL; 2928 HANDLE hDeviceKey = NULL; 2929 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf; 2930 UNICODE_STRING Level2NameU; 2931 WCHAR Level2Name[5]; 2932 ULONG IndexDevice = 0; 2933 ULONG IndexSubKey; 2934 PKEY_BASIC_INFORMATION pDeviceInformation = NULL; 2935 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR); 2936 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL; 2937 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR); 2938 UNICODE_STRING DeviceName, ValueName; 2939 ULONG RequiredSize; 2940 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL; 2941 ULONG BootResourcesLength; 2942 NTSTATUS Status; 2943 2944 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController"); 2945 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0"); 2946 static ULONG DeviceIndexSerial = 0; 2947 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController"); 2948 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0"); 2949 static ULONG DeviceIndexKeyboard = 0; 2950 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController"); 2951 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0"); 2952 static ULONG DeviceIndexMouse = 0; 2953 const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController"); 2954 UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0"); 2955 static ULONG DeviceIndexParallel = 0; 2956 const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral"); 2957 UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0"); 2958 static ULONG DeviceIndexFloppy = 0; 2959 UNICODE_STRING HardwareIdKey; 2960 PUNICODE_STRING pHardwareId; 2961 ULONG DeviceIndex = 0; 2962 PUCHAR CmResourceList; 2963 ULONG ListCount; 2964 2965 if (RelativePath) 2966 { 2967 Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS); 2968 if (!NT_SUCCESS(Status)) 2969 { 2970 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status); 2971 goto cleanup; 2972 } 2973 } 2974 else 2975 hDevicesKey = hBaseKey; 2976 2977 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength); 2978 if (!pDeviceInformation) 2979 { 2980 DPRINT("ExAllocatePool() failed\n"); 2981 Status = STATUS_NO_MEMORY; 2982 goto cleanup; 2983 } 2984 2985 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength); 2986 if (!pValueInformation) 2987 { 2988 DPRINT("ExAllocatePool() failed\n"); 2989 Status = STATUS_NO_MEMORY; 2990 goto cleanup; 2991 } 2992 2993 while (TRUE) 2994 { 2995 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize); 2996 if (Status == STATUS_NO_MORE_ENTRIES) 2997 break; 2998 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 2999 { 3000 ExFreePool(pDeviceInformation); 3001 DeviceInfoLength = RequiredSize; 3002 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength); 3003 if (!pDeviceInformation) 3004 { 3005 DPRINT("ExAllocatePool() failed\n"); 3006 Status = STATUS_NO_MEMORY; 3007 goto cleanup; 3008 } 3009 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize); 3010 } 3011 if (!NT_SUCCESS(Status)) 3012 { 3013 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status); 3014 goto cleanup; 3015 } 3016 IndexDevice++; 3017 3018 /* Open device key */ 3019 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength; 3020 DeviceName.Buffer = pDeviceInformation->Name; 3021 3022 Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName, 3023 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0)); 3024 if (!NT_SUCCESS(Status)) 3025 { 3026 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status); 3027 goto cleanup; 3028 } 3029 3030 /* Read boot resources, and add then to parent ones */ 3031 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize); 3032 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 3033 { 3034 ExFreePool(pValueInformation); 3035 ValueInfoLength = RequiredSize; 3036 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength); 3037 if (!pValueInformation) 3038 { 3039 DPRINT("ExAllocatePool() failed\n"); 3040 ZwDeleteKey(hLevel2Key); 3041 Status = STATUS_NO_MEMORY; 3042 goto cleanup; 3043 } 3044 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize); 3045 } 3046 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 3047 { 3048 BootResources = ParentBootResources; 3049 BootResourcesLength = ParentBootResourcesLength; 3050 } 3051 else if (!NT_SUCCESS(Status)) 3052 { 3053 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status); 3054 goto nextdevice; 3055 } 3056 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR) 3057 { 3058 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR); 3059 goto nextdevice; 3060 } 3061 else 3062 { 3063 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors); 3064 3065 /* Concatenate current resources and parent ones */ 3066 if (ParentBootResourcesLength == 0) 3067 BootResourcesLength = pValueInformation->DataLength; 3068 else 3069 BootResourcesLength = ParentBootResourcesLength 3070 + pValueInformation->DataLength 3071 - Header; 3072 BootResources = ExAllocatePool(PagedPool, BootResourcesLength); 3073 if (!BootResources) 3074 { 3075 DPRINT("ExAllocatePool() failed\n"); 3076 goto nextdevice; 3077 } 3078 if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) 3079 { 3080 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength); 3081 } 3082 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific) 3083 { 3084 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength); 3085 RtlCopyMemory( 3086 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength), 3087 (PVOID)((ULONG_PTR)ParentBootResources + Header), 3088 ParentBootResourcesLength - Header); 3089 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count; 3090 } 3091 else 3092 { 3093 RtlCopyMemory(BootResources, pValueInformation->Data, Header); 3094 RtlCopyMemory( 3095 (PVOID)((ULONG_PTR)BootResources + Header), 3096 (PVOID)((ULONG_PTR)ParentBootResources + Header), 3097 ParentBootResourcesLength - Header); 3098 RtlCopyMemory( 3099 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength), 3100 pValueInformation->Data + Header, 3101 pValueInformation->DataLength - Header); 3102 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count; 3103 } 3104 } 3105 3106 if (EnumerateSubKeys) 3107 { 3108 IndexSubKey = 0; 3109 while (TRUE) 3110 { 3111 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize); 3112 if (Status == STATUS_NO_MORE_ENTRIES) 3113 break; 3114 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 3115 { 3116 ExFreePool(pDeviceInformation); 3117 DeviceInfoLength = RequiredSize; 3118 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength); 3119 if (!pDeviceInformation) 3120 { 3121 DPRINT("ExAllocatePool() failed\n"); 3122 Status = STATUS_NO_MEMORY; 3123 goto cleanup; 3124 } 3125 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize); 3126 } 3127 if (!NT_SUCCESS(Status)) 3128 { 3129 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status); 3130 goto cleanup; 3131 } 3132 IndexSubKey++; 3133 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength; 3134 DeviceName.Buffer = pDeviceInformation->Name; 3135 3136 Status = IopEnumerateDetectedDevices( 3137 hDeviceKey, 3138 &DeviceName, 3139 hRootKey, 3140 TRUE, 3141 BootResources, 3142 BootResourcesLength); 3143 if (!NT_SUCCESS(Status)) 3144 goto cleanup; 3145 } 3146 } 3147 3148 /* Read identifier */ 3149 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize); 3150 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 3151 { 3152 ExFreePool(pValueInformation); 3153 ValueInfoLength = RequiredSize; 3154 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength); 3155 if (!pValueInformation) 3156 { 3157 DPRINT("ExAllocatePool() failed\n"); 3158 Status = STATUS_NO_MEMORY; 3159 goto cleanup; 3160 } 3161 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize); 3162 } 3163 if (!NT_SUCCESS(Status)) 3164 { 3165 if (Status != STATUS_OBJECT_NAME_NOT_FOUND) 3166 { 3167 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status); 3168 goto nextdevice; 3169 } 3170 ValueName.Length = ValueName.MaximumLength = 0; 3171 } 3172 else if (pValueInformation->Type != REG_SZ) 3173 { 3174 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ); 3175 goto nextdevice; 3176 } 3177 else 3178 { 3179 /* Assign hardware id to this device */ 3180 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength; 3181 ValueName.Buffer = (PWCHAR)pValueInformation->Data; 3182 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL) 3183 ValueName.Length -= sizeof(WCHAR); 3184 } 3185 3186 if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0) 3187 { 3188 pHardwareId = &HardwareIdSerial; 3189 DeviceIndex = DeviceIndexSerial++; 3190 } 3191 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0) 3192 { 3193 pHardwareId = &HardwareIdKeyboard; 3194 DeviceIndex = DeviceIndexKeyboard++; 3195 } 3196 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0) 3197 { 3198 pHardwareId = &HardwareIdMouse; 3199 DeviceIndex = DeviceIndexMouse++; 3200 } 3201 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0) 3202 { 3203 pHardwareId = &HardwareIdParallel; 3204 DeviceIndex = DeviceIndexParallel++; 3205 } 3206 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0) 3207 { 3208 pHardwareId = &HardwareIdFloppy; 3209 DeviceIndex = DeviceIndexFloppy++; 3210 } 3211 else 3212 { 3213 /* Unknown key path */ 3214 DPRINT("Unknown key path '%wZ'\n", RelativePath); 3215 goto nextdevice; 3216 } 3217 3218 /* Prepare hardware id key (hardware id value without final \0) */ 3219 HardwareIdKey = *pHardwareId; 3220 HardwareIdKey.Length -= sizeof(UNICODE_NULL); 3221 3222 /* Add the detected device to Root key */ 3223 InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL); 3224 Status = ZwCreateKey( 3225 &hLevel1Key, 3226 KEY_CREATE_SUB_KEY, 3227 &ObjectAttributes, 3228 0, 3229 NULL, 3230 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0, 3231 NULL); 3232 if (!NT_SUCCESS(Status)) 3233 { 3234 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status); 3235 goto nextdevice; 3236 } 3237 swprintf(Level2Name, L"%04lu", DeviceIndex); 3238 RtlInitUnicodeString(&Level2NameU, Level2Name); 3239 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL); 3240 Status = ZwCreateKey( 3241 &hLevel2Key, 3242 KEY_SET_VALUE | KEY_CREATE_SUB_KEY, 3243 &ObjectAttributes, 3244 0, 3245 NULL, 3246 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0, 3247 NULL); 3248 ZwClose(hLevel1Key); 3249 if (!NT_SUCCESS(Status)) 3250 { 3251 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status); 3252 goto nextdevice; 3253 } 3254 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey); 3255 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength); 3256 if (!NT_SUCCESS(Status)) 3257 { 3258 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status); 3259 ZwDeleteKey(hLevel2Key); 3260 goto nextdevice; 3261 } 3262 /* Create 'LogConf' subkey */ 3263 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL); 3264 Status = ZwCreateKey( 3265 &hLogConf, 3266 KEY_SET_VALUE, 3267 &ObjectAttributes, 3268 0, 3269 NULL, 3270 REG_OPTION_VOLATILE, 3271 NULL); 3272 if (!NT_SUCCESS(Status)) 3273 { 3274 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status); 3275 ZwDeleteKey(hLevel2Key); 3276 goto nextdevice; 3277 } 3278 if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) 3279 { 3280 CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG)); 3281 if (!CmResourceList) 3282 { 3283 ZwClose(hLogConf); 3284 ZwDeleteKey(hLevel2Key); 3285 goto nextdevice; 3286 } 3287 3288 /* Add the list count (1st member of CM_RESOURCE_LIST) */ 3289 ListCount = 1; 3290 RtlCopyMemory(CmResourceList, 3291 &ListCount, 3292 sizeof(ULONG)); 3293 3294 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */ 3295 RtlCopyMemory(CmResourceList + sizeof(ULONG), 3296 BootResources, 3297 BootResourcesLength); 3298 3299 /* Save boot resources to 'LogConf\BootConfig' */ 3300 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG)); 3301 if (!NT_SUCCESS(Status)) 3302 { 3303 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status); 3304 ZwClose(hLogConf); 3305 ZwDeleteKey(hLevel2Key); 3306 goto nextdevice; 3307 } 3308 } 3309 ZwClose(hLogConf); 3310 3311 nextdevice: 3312 if (BootResources && BootResources != ParentBootResources) 3313 { 3314 ExFreePool(BootResources); 3315 BootResources = NULL; 3316 } 3317 if (hLevel2Key) 3318 { 3319 ZwClose(hLevel2Key); 3320 hLevel2Key = NULL; 3321 } 3322 if (hDeviceKey) 3323 { 3324 ZwClose(hDeviceKey); 3325 hDeviceKey = NULL; 3326 } 3327 } 3328 3329 Status = STATUS_SUCCESS; 3330 3331 cleanup: 3332 if (hDevicesKey && hDevicesKey != hBaseKey) 3333 ZwClose(hDevicesKey); 3334 if (hDeviceKey) 3335 ZwClose(hDeviceKey); 3336 if (pDeviceInformation) 3337 ExFreePool(pDeviceInformation); 3338 if (pValueInformation) 3339 ExFreePool(pValueInformation); 3340 return Status; 3341 } 3342 3343 static BOOLEAN INIT_FUNCTION 3344 IopIsFirmwareMapperDisabled(VOID) 3345 { 3346 UNICODE_STRING KeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp"); 3347 UNICODE_STRING KeyNameU = RTL_CONSTANT_STRING(L"DisableFirmwareMapper"); 3348 OBJECT_ATTRIBUTES ObjectAttributes; 3349 HANDLE hPnpKey; 3350 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation; 3351 ULONG DesiredLength, Length; 3352 ULONG KeyValue = 0; 3353 NTSTATUS Status; 3354 3355 InitializeObjectAttributes(&ObjectAttributes, &KeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); 3356 Status = ZwOpenKey(&hPnpKey, KEY_QUERY_VALUE, &ObjectAttributes); 3357 if (NT_SUCCESS(Status)) 3358 { 3359 Status = ZwQueryValueKey(hPnpKey, 3360 &KeyNameU, 3361 KeyValuePartialInformation, 3362 NULL, 3363 0, 3364 &DesiredLength); 3365 if ((Status == STATUS_BUFFER_TOO_SMALL) || 3366 (Status == STATUS_BUFFER_OVERFLOW)) 3367 { 3368 Length = DesiredLength; 3369 KeyInformation = ExAllocatePool(PagedPool, Length); 3370 if (KeyInformation) 3371 { 3372 Status = ZwQueryValueKey(hPnpKey, 3373 &KeyNameU, 3374 KeyValuePartialInformation, 3375 KeyInformation, 3376 Length, 3377 &DesiredLength); 3378 if (NT_SUCCESS(Status) && KeyInformation->DataLength == sizeof(ULONG)) 3379 { 3380 KeyValue = (ULONG)(*KeyInformation->Data); 3381 } 3382 else 3383 { 3384 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU, &KeyNameU); 3385 } 3386 3387 ExFreePool(KeyInformation); 3388 } 3389 else 3390 { 3391 DPRINT1("Failed to allocate memory for registry query\n"); 3392 } 3393 } 3394 else 3395 { 3396 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU, &KeyNameU, Status); 3397 } 3398 3399 ZwClose(hPnpKey); 3400 } 3401 else 3402 { 3403 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU, Status); 3404 } 3405 3406 DPRINT("Firmware mapper is %s\n", KeyValue != 0 ? "disabled" : "enabled"); 3407 3408 return (KeyValue != 0) ? TRUE : FALSE; 3409 } 3410 3411 NTSTATUS 3412 NTAPI 3413 INIT_FUNCTION 3414 IopUpdateRootKey(VOID) 3415 { 3416 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum"); 3417 UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root"); 3418 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"); 3419 OBJECT_ATTRIBUTES ObjectAttributes; 3420 HANDLE hEnum, hRoot; 3421 NTSTATUS Status; 3422 3423 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); 3424 Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL); 3425 if (!NT_SUCCESS(Status)) 3426 { 3427 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status); 3428 return Status; 3429 } 3430 3431 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL); 3432 Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL); 3433 ZwClose(hEnum); 3434 if (!NT_SUCCESS(Status)) 3435 { 3436 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status); 3437 return Status; 3438 } 3439 3440 if (!IopIsFirmwareMapperDisabled()) 3441 { 3442 Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS); 3443 if (!NT_SUCCESS(Status)) 3444 { 3445 /* Nothing to do, don't return with an error status */ 3446 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status); 3447 ZwClose(hRoot); 3448 return STATUS_SUCCESS; 3449 } 3450 Status = IopEnumerateDetectedDevices( 3451 hEnum, 3452 NULL, 3453 hRoot, 3454 TRUE, 3455 NULL, 3456 0); 3457 ZwClose(hEnum); 3458 } 3459 else 3460 { 3461 /* Enumeration is disabled */ 3462 Status = STATUS_SUCCESS; 3463 } 3464 3465 ZwClose(hRoot); 3466 3467 return Status; 3468 } 3469 3470 NTSTATUS 3471 NTAPI 3472 IopOpenRegistryKeyEx(PHANDLE KeyHandle, 3473 HANDLE ParentKey, 3474 PUNICODE_STRING Name, 3475 ACCESS_MASK DesiredAccess) 3476 { 3477 OBJECT_ATTRIBUTES ObjectAttributes; 3478 NTSTATUS Status; 3479 3480 PAGED_CODE(); 3481 3482 *KeyHandle = NULL; 3483 3484 InitializeObjectAttributes(&ObjectAttributes, 3485 Name, 3486 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 3487 ParentKey, 3488 NULL); 3489 3490 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes); 3491 3492 return Status; 3493 } 3494 3495 NTSTATUS 3496 NTAPI 3497 IopCreateRegistryKeyEx(OUT PHANDLE Handle, 3498 IN HANDLE RootHandle OPTIONAL, 3499 IN PUNICODE_STRING KeyName, 3500 IN ACCESS_MASK DesiredAccess, 3501 IN ULONG CreateOptions, 3502 OUT PULONG Disposition OPTIONAL) 3503 { 3504 OBJECT_ATTRIBUTES ObjectAttributes; 3505 ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0; 3506 USHORT Length; 3507 HANDLE HandleArray[2]; 3508 BOOLEAN Recursing = TRUE; 3509 PWCHAR pp, p, p1; 3510 UNICODE_STRING KeyString; 3511 NTSTATUS Status = STATUS_SUCCESS; 3512 PAGED_CODE(); 3513 3514 /* P1 is start, pp is end */ 3515 p1 = KeyName->Buffer; 3516 pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length); 3517 3518 /* Create the target key */ 3519 InitializeObjectAttributes(&ObjectAttributes, 3520 KeyName, 3521 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 3522 RootHandle, 3523 NULL); 3524 Status = ZwCreateKey(&HandleArray[i], 3525 DesiredAccess, 3526 &ObjectAttributes, 3527 0, 3528 NULL, 3529 CreateOptions, 3530 &KeyDisposition); 3531 3532 /* Now we check if this failed */ 3533 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle)) 3534 { 3535 /* Target key failed, so we'll need to create its parent. Setup array */ 3536 HandleArray[0] = NULL; 3537 HandleArray[1] = RootHandle; 3538 3539 /* Keep recursing for each missing parent */ 3540 while (Recursing) 3541 { 3542 /* And if we're deep enough, close the last handle */ 3543 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]); 3544 3545 /* We're setup to ping-pong between the two handle array entries */ 3546 RootHandleIndex = i; 3547 i = (i + 1) & 1; 3548 3549 /* Clear the one we're attempting to open now */ 3550 HandleArray[i] = NULL; 3551 3552 /* Process the parent key name */ 3553 for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++); 3554 Length = (USHORT)(p - p1) * sizeof(WCHAR); 3555 3556 /* Is there a parent name? */ 3557 if (Length) 3558 { 3559 /* Build the unicode string for it */ 3560 KeyString.Buffer = p1; 3561 KeyString.Length = KeyString.MaximumLength = Length; 3562 3563 /* Now try opening the parent */ 3564 InitializeObjectAttributes(&ObjectAttributes, 3565 &KeyString, 3566 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 3567 HandleArray[RootHandleIndex], 3568 NULL); 3569 Status = ZwCreateKey(&HandleArray[i], 3570 DesiredAccess, 3571 &ObjectAttributes, 3572 0, 3573 NULL, 3574 CreateOptions, 3575 &KeyDisposition); 3576 if (NT_SUCCESS(Status)) 3577 { 3578 /* It worked, we have one more handle */ 3579 NestedCloseLevel++; 3580 } 3581 else 3582 { 3583 /* Parent key creation failed, abandon loop */ 3584 Recursing = FALSE; 3585 continue; 3586 } 3587 } 3588 else 3589 { 3590 /* We don't have a parent name, probably corrupted key name */ 3591 Status = STATUS_INVALID_PARAMETER; 3592 Recursing = FALSE; 3593 continue; 3594 } 3595 3596 /* Now see if there's more parents to create */ 3597 p1 = p + 1; 3598 if ((p == pp) || (p1 == pp)) 3599 { 3600 /* We're done, hopefully successfully, so stop */ 3601 Recursing = FALSE; 3602 } 3603 } 3604 3605 /* Outer loop check for handle nesting that requires closing the top handle */ 3606 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]); 3607 } 3608 3609 /* Check if we broke out of the loop due to success */ 3610 if (NT_SUCCESS(Status)) 3611 { 3612 /* Return the target handle (we closed all the parent ones) and disposition */ 3613 *Handle = HandleArray[i]; 3614 if (Disposition) *Disposition = KeyDisposition; 3615 } 3616 3617 /* Return the success state */ 3618 return Status; 3619 } 3620 3621 NTSTATUS 3622 NTAPI 3623 IopGetRegistryValue(IN HANDLE Handle, 3624 IN PWSTR ValueName, 3625 OUT PKEY_VALUE_FULL_INFORMATION *Information) 3626 { 3627 UNICODE_STRING ValueString; 3628 NTSTATUS Status; 3629 PKEY_VALUE_FULL_INFORMATION FullInformation; 3630 ULONG Size; 3631 PAGED_CODE(); 3632 3633 RtlInitUnicodeString(&ValueString, ValueName); 3634 3635 Status = ZwQueryValueKey(Handle, 3636 &ValueString, 3637 KeyValueFullInformation, 3638 NULL, 3639 0, 3640 &Size); 3641 if ((Status != STATUS_BUFFER_OVERFLOW) && 3642 (Status != STATUS_BUFFER_TOO_SMALL)) 3643 { 3644 return Status; 3645 } 3646 3647 FullInformation = ExAllocatePool(NonPagedPool, Size); 3648 if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES; 3649 3650 Status = ZwQueryValueKey(Handle, 3651 &ValueString, 3652 KeyValueFullInformation, 3653 FullInformation, 3654 Size, 3655 &Size); 3656 if (!NT_SUCCESS(Status)) 3657 { 3658 ExFreePool(FullInformation); 3659 return Status; 3660 } 3661 3662 *Information = FullInformation; 3663 return STATUS_SUCCESS; 3664 } 3665 3666 RTL_GENERIC_COMPARE_RESULTS 3667 NTAPI 3668 PiCompareInstancePath(IN PRTL_AVL_TABLE Table, 3669 IN PVOID FirstStruct, 3670 IN PVOID SecondStruct) 3671 { 3672 /* FIXME: TODO */ 3673 ASSERT(FALSE); 3674 return 0; 3675 } 3676 3677 // 3678 // The allocation function is called by the generic table package whenever 3679 // it needs to allocate memory for the table. 3680 // 3681 3682 PVOID 3683 NTAPI 3684 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table, 3685 IN CLONG ByteSize) 3686 { 3687 /* FIXME: TODO */ 3688 ASSERT(FALSE); 3689 return NULL; 3690 } 3691 3692 VOID 3693 NTAPI 3694 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table, 3695 IN PVOID Buffer) 3696 { 3697 /* FIXME: TODO */ 3698 ASSERT(FALSE); 3699 } 3700 3701 VOID 3702 NTAPI 3703 PpInitializeDeviceReferenceTable(VOID) 3704 { 3705 /* Setup the guarded mutex and AVL table */ 3706 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock); 3707 RtlInitializeGenericTableAvl( 3708 &PpDeviceReferenceTable, 3709 (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath, 3710 (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry, 3711 (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry, 3712 NULL); 3713 } 3714 3715 BOOLEAN 3716 NTAPI 3717 PiInitPhase0(VOID) 3718 { 3719 /* Initialize the resource when accessing device registry data */ 3720 ExInitializeResourceLite(&PpRegistryDeviceResource); 3721 3722 /* Setup the device reference AVL table */ 3723 PpInitializeDeviceReferenceTable(); 3724 return TRUE; 3725 } 3726 3727 BOOLEAN 3728 NTAPI 3729 PpInitSystem(VOID) 3730 { 3731 /* Check the initialization phase */ 3732 switch (ExpInitializationPhase) 3733 { 3734 case 0: 3735 3736 /* Do Phase 0 */ 3737 return PiInitPhase0(); 3738 3739 case 1: 3740 3741 /* Do Phase 1 */ 3742 return TRUE; 3743 //return PiInitPhase1(); 3744 3745 default: 3746 3747 /* Don't know any other phase! Bugcheck! */ 3748 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL); 3749 return FALSE; 3750 } 3751 } 3752 3753 LONG IopNumberDeviceNodes; 3754 3755 PDEVICE_NODE 3756 NTAPI 3757 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject) 3758 { 3759 PDEVICE_NODE DeviceNode; 3760 PAGED_CODE(); 3761 3762 /* Allocate it */ 3763 DeviceNode = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_NODE), TAG_IO_DEVNODE); 3764 if (!DeviceNode) return DeviceNode; 3765 3766 /* Statistics */ 3767 InterlockedIncrement(&IopNumberDeviceNodes); 3768 3769 /* Set it up */ 3770 RtlZeroMemory(DeviceNode, sizeof(DEVICE_NODE)); 3771 DeviceNode->InterfaceType = InterfaceTypeUndefined; 3772 DeviceNode->BusNumber = -1; 3773 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined; 3774 DeviceNode->ChildBusNumber = -1; 3775 DeviceNode->ChildBusTypeIndex = -1; 3776 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE); 3777 InitializeListHead(&DeviceNode->DeviceArbiterList); 3778 InitializeListHead(&DeviceNode->DeviceTranslatorList); 3779 InitializeListHead(&DeviceNode->TargetDeviceNotify); 3780 InitializeListHead(&DeviceNode->DockInfo.ListEntry); 3781 InitializeListHead(&DeviceNode->PendedSetInterfaceState); 3782 3783 /* Check if there is a PDO */ 3784 if (PhysicalDeviceObject) 3785 { 3786 /* Link it and remove the init flag */ 3787 DeviceNode->PhysicalDeviceObject = PhysicalDeviceObject; 3788 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = DeviceNode; 3789 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 3790 } 3791 3792 /* Return the node */ 3793 return DeviceNode; 3794 } 3795 3796 /* PUBLIC FUNCTIONS **********************************************************/ 3797 3798 NTSTATUS 3799 NTAPI 3800 PnpBusTypeGuidGet(IN USHORT Index, 3801 IN LPGUID BusTypeGuid) 3802 { 3803 NTSTATUS Status = STATUS_SUCCESS; 3804 3805 /* Acquire the lock */ 3806 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock); 3807 3808 /* Validate size */ 3809 if (Index < PnpBusTypeGuidList->GuidCount) 3810 { 3811 /* Copy the data */ 3812 RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID)); 3813 } 3814 else 3815 { 3816 /* Failure path */ 3817 Status = STATUS_OBJECT_NAME_NOT_FOUND; 3818 } 3819 3820 /* Release lock and return status */ 3821 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock); 3822 return Status; 3823 } 3824 3825 NTSTATUS 3826 NTAPI 3827 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject, 3828 IN PHANDLE DeviceInstanceHandle, 3829 IN ACCESS_MASK DesiredAccess) 3830 { 3831 NTSTATUS Status; 3832 HANDLE KeyHandle; 3833 PDEVICE_NODE DeviceNode; 3834 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM"); 3835 PAGED_CODE(); 3836 3837 /* Open the enum key */ 3838 Status = IopOpenRegistryKeyEx(&KeyHandle, 3839 NULL, 3840 &KeyName, 3841 KEY_READ); 3842 if (!NT_SUCCESS(Status)) return Status; 3843 3844 /* Make sure we have an instance path */ 3845 DeviceNode = IopGetDeviceNode(DeviceObject); 3846 if ((DeviceNode) && (DeviceNode->InstancePath.Length)) 3847 { 3848 /* Get the instance key */ 3849 Status = IopOpenRegistryKeyEx(DeviceInstanceHandle, 3850 KeyHandle, 3851 &DeviceNode->InstancePath, 3852 DesiredAccess); 3853 } 3854 else 3855 { 3856 /* Fail */ 3857 Status = STATUS_INVALID_DEVICE_REQUEST; 3858 } 3859 3860 /* Close the handle and return status */ 3861 ZwClose(KeyHandle); 3862 return Status; 3863 } 3864 3865 ULONG 3866 NTAPI 3867 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList) 3868 { 3869 ULONG FinalSize, PartialSize, EntrySize, i, j; 3870 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor; 3871 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; 3872 3873 /* If we don't have one, that's easy */ 3874 if (!ResourceList) return 0; 3875 3876 /* Start with the minimum size possible */ 3877 FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List); 3878 3879 /* Loop each full descriptor */ 3880 FullDescriptor = ResourceList->List; 3881 for (i = 0; i < ResourceList->Count; i++) 3882 { 3883 /* Start with the minimum size possible */ 3884 PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) + 3885 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors); 3886 3887 /* Loop each partial descriptor */ 3888 PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors; 3889 for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++) 3890 { 3891 /* Start with the minimum size possible */ 3892 EntrySize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR); 3893 3894 /* Check if there is extra data */ 3895 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific) 3896 { 3897 /* Add that data */ 3898 EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize; 3899 } 3900 3901 /* The size of partial descriptors is bigger */ 3902 PartialSize += EntrySize; 3903 3904 /* Go to the next partial descriptor */ 3905 PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize); 3906 } 3907 3908 /* The size of full descriptors is bigger */ 3909 FinalSize += PartialSize; 3910 3911 /* Go to the next full descriptor */ 3912 FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize); 3913 } 3914 3915 /* Return the final size */ 3916 return FinalSize; 3917 } 3918 3919 NTSTATUS 3920 NTAPI 3921 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject, 3922 IN ULONG ValueType, 3923 IN PWSTR ValueName, 3924 IN PWSTR KeyName, 3925 OUT PVOID Buffer, 3926 IN PULONG BufferLength) 3927 { 3928 NTSTATUS Status; 3929 HANDLE KeyHandle, SubHandle; 3930 UNICODE_STRING KeyString; 3931 PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL; 3932 ULONG Length; 3933 PAGED_CODE(); 3934 3935 /* Find the instance key */ 3936 Status = PnpDeviceObjectToDeviceInstance(DeviceObject, &KeyHandle, KEY_READ); 3937 if (NT_SUCCESS(Status)) 3938 { 3939 /* Check for name given by caller */ 3940 if (KeyName) 3941 { 3942 /* Open this key */ 3943 RtlInitUnicodeString(&KeyString, KeyName); 3944 Status = IopOpenRegistryKeyEx(&SubHandle, 3945 KeyHandle, 3946 &KeyString, 3947 KEY_READ); 3948 if (NT_SUCCESS(Status)) 3949 { 3950 /* And use this handle instead */ 3951 ZwClose(KeyHandle); 3952 KeyHandle = SubHandle; 3953 } 3954 } 3955 3956 /* Check if sub-key handle succeeded (or no-op if no key name given) */ 3957 if (NT_SUCCESS(Status)) 3958 { 3959 /* Now get the size of the property */ 3960 Status = IopGetRegistryValue(KeyHandle, 3961 ValueName, 3962 &KeyValueInfo); 3963 } 3964 3965 /* Close the key */ 3966 ZwClose(KeyHandle); 3967 } 3968 3969 /* Fail if any of the registry operations failed */ 3970 if (!NT_SUCCESS(Status)) return Status; 3971 3972 /* Check how much data we have to copy */ 3973 Length = KeyValueInfo->DataLength; 3974 if (*BufferLength >= Length) 3975 { 3976 /* Check for a match in the value type */ 3977 if (KeyValueInfo->Type == ValueType) 3978 { 3979 /* Copy the data */ 3980 RtlCopyMemory(Buffer, 3981 (PVOID)((ULONG_PTR)KeyValueInfo + 3982 KeyValueInfo->DataOffset), 3983 Length); 3984 } 3985 else 3986 { 3987 /* Invalid registry property type, fail */ 3988 Status = STATUS_INVALID_PARAMETER_2; 3989 } 3990 } 3991 else 3992 { 3993 /* Buffer is too small to hold data */ 3994 Status = STATUS_BUFFER_TOO_SMALL; 3995 } 3996 3997 /* Return the required buffer length, free the buffer, and return status */ 3998 *BufferLength = Length; 3999 ExFreePool(KeyValueInfo); 4000 return Status; 4001 } 4002 4003 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;} 4004 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;} 4005 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED_DBGBREAK(); break;} 4006 4007 /* 4008 * @implemented 4009 */ 4010 NTSTATUS 4011 NTAPI 4012 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject, 4013 IN DEVICE_REGISTRY_PROPERTY DeviceProperty, 4014 IN ULONG BufferLength, 4015 OUT PVOID PropertyBuffer, 4016 OUT PULONG ResultLength) 4017 { 4018 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 4019 DEVICE_CAPABILITIES DeviceCaps; 4020 ULONG ReturnLength = 0, Length = 0, ValueType; 4021 PWCHAR ValueName = NULL, EnumeratorNameEnd, DeviceInstanceName; 4022 PVOID Data = NULL; 4023 NTSTATUS Status = STATUS_BUFFER_TOO_SMALL; 4024 GUID BusTypeGuid; 4025 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL; 4026 BOOLEAN NullTerminate = FALSE; 4027 4028 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty); 4029 4030 /* Assume failure */ 4031 *ResultLength = 0; 4032 4033 /* Only PDOs can call this */ 4034 if (!DeviceNode) return STATUS_INVALID_DEVICE_REQUEST; 4035 4036 /* Handle all properties */ 4037 switch (DeviceProperty) 4038 { 4039 case DevicePropertyBusTypeGuid: 4040 4041 /* Get the GUID from the internal cache */ 4042 Status = PnpBusTypeGuidGet(DeviceNode->ChildBusTypeIndex, &BusTypeGuid); 4043 if (!NT_SUCCESS(Status)) return Status; 4044 4045 /* This is the format of the returned data */ 4046 PIP_RETURN_DATA(sizeof(GUID), &BusTypeGuid); 4047 4048 case DevicePropertyLegacyBusType: 4049 4050 /* Validate correct interface type */ 4051 if (DeviceNode->ChildInterfaceType == InterfaceTypeUndefined) 4052 return STATUS_OBJECT_NAME_NOT_FOUND; 4053 4054 /* This is the format of the returned data */ 4055 PIP_RETURN_DATA(sizeof(INTERFACE_TYPE), &DeviceNode->ChildInterfaceType); 4056 4057 case DevicePropertyBusNumber: 4058 4059 /* Validate correct bus number */ 4060 if ((DeviceNode->ChildBusNumber & 0x80000000) == 0x80000000) 4061 return STATUS_OBJECT_NAME_NOT_FOUND; 4062 4063 /* This is the format of the returned data */ 4064 PIP_RETURN_DATA(sizeof(ULONG), &DeviceNode->ChildBusNumber); 4065 4066 case DevicePropertyEnumeratorName: 4067 4068 /* Get the instance path */ 4069 DeviceInstanceName = DeviceNode->InstancePath.Buffer; 4070 4071 /* Sanity checks */ 4072 ASSERT((BufferLength & 1) == 0); 4073 ASSERT(DeviceInstanceName != NULL); 4074 4075 /* Get the name from the path */ 4076 EnumeratorNameEnd = wcschr(DeviceInstanceName, OBJ_NAME_PATH_SEPARATOR); 4077 ASSERT(EnumeratorNameEnd); 4078 4079 /* This string needs to be NULL-terminated */ 4080 NullTerminate = TRUE; 4081 4082 /* This is the format of the returned data */ 4083 PIP_RETURN_DATA((ULONG)(EnumeratorNameEnd - DeviceInstanceName) * sizeof(WCHAR), 4084 DeviceInstanceName); 4085 4086 case DevicePropertyAddress: 4087 4088 /* Query the device caps */ 4089 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps); 4090 if (!NT_SUCCESS(Status) || (DeviceCaps.Address == MAXULONG)) 4091 return STATUS_OBJECT_NAME_NOT_FOUND; 4092 4093 /* This is the format of the returned data */ 4094 PIP_RETURN_DATA(sizeof(ULONG), &DeviceCaps.Address); 4095 4096 case DevicePropertyBootConfigurationTranslated: 4097 4098 /* Validate we have resources */ 4099 if (!DeviceNode->BootResources) 4100 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field 4101 { 4102 /* No resources will still fake success, but with 0 bytes */ 4103 *ResultLength = 0; 4104 return STATUS_SUCCESS; 4105 } 4106 4107 /* This is the format of the returned data */ 4108 PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode->BootResources), // FIXFIX: Should use BootResourcesTranslated 4109 DeviceNode->BootResources); // FIXFIX: Should use BootResourcesTranslated 4110 4111 case DevicePropertyPhysicalDeviceObjectName: 4112 4113 /* Sanity check for Unicode-sized string */ 4114 ASSERT((BufferLength & 1) == 0); 4115 4116 /* Allocate name buffer */ 4117 Length = BufferLength + sizeof(OBJECT_NAME_INFORMATION); 4118 ObjectNameInfo = ExAllocatePool(PagedPool, Length); 4119 if (!ObjectNameInfo) return STATUS_INSUFFICIENT_RESOURCES; 4120 4121 /* Query the PDO name */ 4122 Status = ObQueryNameString(DeviceObject, 4123 ObjectNameInfo, 4124 Length, 4125 ResultLength); 4126 if (Status == STATUS_INFO_LENGTH_MISMATCH) 4127 { 4128 /* It's up to the caller to try again */ 4129 Status = STATUS_BUFFER_TOO_SMALL; 4130 } 4131 4132 /* This string needs to be NULL-terminated */ 4133 NullTerminate = TRUE; 4134 4135 /* Return if successful */ 4136 if (NT_SUCCESS(Status)) PIP_RETURN_DATA(ObjectNameInfo->Name.Length, 4137 ObjectNameInfo->Name.Buffer); 4138 4139 /* Let the caller know how big the name is */ 4140 *ResultLength -= sizeof(OBJECT_NAME_INFORMATION); 4141 break; 4142 4143 /* Handle the registry-based properties */ 4144 case DevicePropertyUINumber: 4145 PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER, REG_DWORD); 4146 case DevicePropertyLocationInformation: 4147 PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION, REG_SZ); 4148 case DevicePropertyDeviceDescription: 4149 PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC, REG_SZ); 4150 case DevicePropertyHardwareID: 4151 PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID, REG_MULTI_SZ); 4152 case DevicePropertyCompatibleIDs: 4153 PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS, REG_MULTI_SZ); 4154 case DevicePropertyBootConfiguration: 4155 PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG, REG_RESOURCE_LIST); 4156 case DevicePropertyClassName: 4157 PIP_REGISTRY_DATA(REGSTR_VAL_CLASS, REG_SZ); 4158 case DevicePropertyClassGuid: 4159 PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID, REG_SZ); 4160 case DevicePropertyDriverKeyName: 4161 PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER, REG_SZ); 4162 case DevicePropertyManufacturer: 4163 PIP_REGISTRY_DATA(REGSTR_VAL_MFG, REG_SZ); 4164 case DevicePropertyFriendlyName: 4165 PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME, REG_SZ); 4166 case DevicePropertyContainerID: 4167 //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7 4168 PIP_UNIMPLEMENTED(); 4169 case DevicePropertyRemovalPolicy: 4170 PIP_UNIMPLEMENTED(); 4171 break; 4172 case DevicePropertyInstallState: 4173 PIP_REGISTRY_DATA(REGSTR_VAL_CONFIGFLAGS, REG_DWORD); 4174 break; 4175 case DevicePropertyResourceRequirements: 4176 PIP_UNIMPLEMENTED(); 4177 case DevicePropertyAllocatedResources: 4178 PIP_UNIMPLEMENTED(); 4179 default: 4180 return STATUS_INVALID_PARAMETER_2; 4181 } 4182 4183 /* Having a registry value name implies registry data */ 4184 if (ValueName) 4185 { 4186 /* We know up-front how much data to expect */ 4187 *ResultLength = BufferLength; 4188 4189 /* Go get the data, use the LogConf subkey if necessary */ 4190 Status = PiGetDeviceRegistryProperty(DeviceObject, 4191 ValueType, 4192 ValueName, 4193 (DeviceProperty == 4194 DevicePropertyBootConfiguration) ? 4195 L"LogConf": NULL, 4196 PropertyBuffer, 4197 ResultLength); 4198 } 4199 else if (NT_SUCCESS(Status)) 4200 { 4201 /* We know up-front how much data to expect, check the caller's buffer */ 4202 *ResultLength = ReturnLength + (NullTerminate ? sizeof(UNICODE_NULL) : 0); 4203 if (*ResultLength <= BufferLength) 4204 { 4205 /* Buffer is all good, copy the data */ 4206 RtlCopyMemory(PropertyBuffer, Data, ReturnLength); 4207 4208 /* Check if we need to NULL-terminate the string */ 4209 if (NullTerminate) 4210 { 4211 /* Terminate the string */ 4212 ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL; 4213 } 4214 4215 /* This is the success path */ 4216 Status = STATUS_SUCCESS; 4217 } 4218 else 4219 { 4220 /* Failure path */ 4221 Status = STATUS_BUFFER_TOO_SMALL; 4222 } 4223 } 4224 4225 /* Free any allocation we may have made, and return the status code */ 4226 if (ObjectNameInfo) ExFreePool(ObjectNameInfo); 4227 return Status; 4228 } 4229 4230 /* 4231 * @implemented 4232 */ 4233 VOID 4234 NTAPI 4235 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject) 4236 { 4237 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject); 4238 IO_STACK_LOCATION Stack; 4239 ULONG PnPFlags; 4240 NTSTATUS Status; 4241 IO_STATUS_BLOCK IoStatusBlock; 4242 4243 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 4244 Stack.MajorFunction = IRP_MJ_PNP; 4245 Stack.MinorFunction = IRP_MN_QUERY_PNP_DEVICE_STATE; 4246 4247 Status = IopSynchronousCall(PhysicalDeviceObject, &Stack, (PVOID*)&PnPFlags); 4248 if (!NT_SUCCESS(Status)) 4249 { 4250 if (Status != STATUS_NOT_SUPPORTED) 4251 { 4252 DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%lx\n", Status); 4253 } 4254 return; 4255 } 4256 4257 if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE) 4258 DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE; 4259 else 4260 DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE; 4261 4262 if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI) 4263 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI; 4264 else 4265 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI; 4266 4267 if ((PnPFlags & PNP_DEVICE_REMOVED) || 4268 ((PnPFlags & PNP_DEVICE_FAILED) && !(PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED))) 4269 { 4270 /* Flag it if it's failed */ 4271 if (PnPFlags & PNP_DEVICE_FAILED) DeviceNode->Problem = CM_PROB_FAILED_POST_START; 4272 4273 /* Send removal IRPs to all of its children */ 4274 IopPrepareDeviceForRemoval(PhysicalDeviceObject, TRUE); 4275 4276 /* Send surprise removal */ 4277 IopSendSurpriseRemoval(PhysicalDeviceObject); 4278 4279 /* Tell the user-mode PnP manager that a device was removed */ 4280 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL, 4281 &DeviceNode->InstancePath); 4282 4283 IopSendRemoveDevice(PhysicalDeviceObject); 4284 } 4285 else if ((PnPFlags & PNP_DEVICE_FAILED) && (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)) 4286 { 4287 /* Stop for resource rebalance */ 4288 Status = IopStopDevice(DeviceNode); 4289 if (!NT_SUCCESS(Status)) 4290 { 4291 DPRINT1("Failed to stop device for rebalancing\n"); 4292 4293 /* Stop failed so don't rebalance */ 4294 PnPFlags &= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED; 4295 } 4296 } 4297 4298 /* Resource rebalance */ 4299 if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED) 4300 { 4301 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n"); 4302 4303 Status = IopInitiatePnpIrp(PhysicalDeviceObject, 4304 &IoStatusBlock, 4305 IRP_MN_QUERY_RESOURCES, 4306 NULL); 4307 if (NT_SUCCESS(Status) && IoStatusBlock.Information) 4308 { 4309 DeviceNode->BootResources = 4310 (PCM_RESOURCE_LIST)IoStatusBlock.Information; 4311 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG); 4312 } 4313 else 4314 { 4315 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); 4316 DeviceNode->BootResources = NULL; 4317 } 4318 4319 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n"); 4320 4321 Status = IopInitiatePnpIrp(PhysicalDeviceObject, 4322 &IoStatusBlock, 4323 IRP_MN_QUERY_RESOURCE_REQUIREMENTS, 4324 NULL); 4325 if (NT_SUCCESS(Status)) 4326 { 4327 DeviceNode->ResourceRequirements = 4328 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information; 4329 } 4330 else 4331 { 4332 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status); 4333 DeviceNode->ResourceRequirements = NULL; 4334 } 4335 4336 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */ 4337 if (IopStartDevice(DeviceNode) != STATUS_SUCCESS) 4338 { 4339 DPRINT1("Restart after resource rebalance failed\n"); 4340 4341 DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING); 4342 DeviceNode->Flags |= DNF_START_FAILED; 4343 4344 IopRemoveDevice(DeviceNode); 4345 } 4346 } 4347 } 4348 4349 /** 4350 * @name IoOpenDeviceRegistryKey 4351 * 4352 * Open a registry key unique for a specified driver or device instance. 4353 * 4354 * @param DeviceObject Device to get the registry key for. 4355 * @param DevInstKeyType Type of the key to return. 4356 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE). 4357 * @param DevInstRegKey Handle to the opened registry key on 4358 * successful return. 4359 * 4360 * @return Status. 4361 * 4362 * @implemented 4363 */ 4364 NTSTATUS 4365 NTAPI 4366 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject, 4367 IN ULONG DevInstKeyType, 4368 IN ACCESS_MASK DesiredAccess, 4369 OUT PHANDLE DevInstRegKey) 4370 { 4371 static WCHAR RootKeyName[] = 4372 L"\\Registry\\Machine\\System\\CurrentControlSet\\"; 4373 static WCHAR ProfileKeyName[] = 4374 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\"; 4375 static WCHAR ClassKeyName[] = L"Control\\Class\\"; 4376 static WCHAR EnumKeyName[] = L"Enum\\"; 4377 static WCHAR DeviceParametersKeyName[] = L"Device Parameters"; 4378 ULONG KeyNameLength; 4379 PWSTR KeyNameBuffer; 4380 UNICODE_STRING KeyName; 4381 ULONG DriverKeyLength; 4382 OBJECT_ATTRIBUTES ObjectAttributes; 4383 PDEVICE_NODE DeviceNode = NULL; 4384 NTSTATUS Status; 4385 4386 DPRINT("IoOpenDeviceRegistryKey() called\n"); 4387 4388 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0) 4389 { 4390 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n"); 4391 return STATUS_INVALID_PARAMETER; 4392 } 4393 4394 if (!IopIsValidPhysicalDeviceObject(DeviceObject)) 4395 return STATUS_INVALID_DEVICE_REQUEST; 4396 DeviceNode = IopGetDeviceNode(DeviceObject); 4397 4398 /* 4399 * Calculate the length of the base key name. This is the full 4400 * name for driver key or the name excluding "Device Parameters" 4401 * subkey for device key. 4402 */ 4403 4404 KeyNameLength = sizeof(RootKeyName); 4405 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE) 4406 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL); 4407 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER) 4408 { 4409 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL); 4410 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName, 4411 0, NULL, &DriverKeyLength); 4412 if (Status != STATUS_BUFFER_TOO_SMALL) 4413 return Status; 4414 KeyNameLength += DriverKeyLength; 4415 } 4416 else 4417 { 4418 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) + 4419 DeviceNode->InstancePath.Length; 4420 } 4421 4422 /* 4423 * Now allocate the buffer for the key name... 4424 */ 4425 4426 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength); 4427 if (KeyNameBuffer == NULL) 4428 return STATUS_INSUFFICIENT_RESOURCES; 4429 4430 KeyName.Length = 0; 4431 KeyName.MaximumLength = (USHORT)KeyNameLength; 4432 KeyName.Buffer = KeyNameBuffer; 4433 4434 /* 4435 * ...and build the key name. 4436 */ 4437 4438 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL); 4439 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length); 4440 4441 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE) 4442 RtlAppendUnicodeToString(&KeyName, ProfileKeyName); 4443 4444 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER) 4445 { 4446 RtlAppendUnicodeToString(&KeyName, ClassKeyName); 4447 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName, 4448 DriverKeyLength, KeyNameBuffer + 4449 (KeyName.Length / sizeof(WCHAR)), 4450 &DriverKeyLength); 4451 if (!NT_SUCCESS(Status)) 4452 { 4453 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status); 4454 ExFreePool(KeyNameBuffer); 4455 return Status; 4456 } 4457 KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL); 4458 } 4459 else 4460 { 4461 RtlAppendUnicodeToString(&KeyName, EnumKeyName); 4462 Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath); 4463 if (DeviceNode->InstancePath.Length == 0) 4464 { 4465 ExFreePool(KeyNameBuffer); 4466 return Status; 4467 } 4468 } 4469 4470 /* 4471 * Open the base key. 4472 */ 4473 Status = IopOpenRegistryKeyEx(DevInstRegKey, NULL, &KeyName, DesiredAccess); 4474 if (!NT_SUCCESS(Status)) 4475 { 4476 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status); 4477 ExFreePool(KeyNameBuffer); 4478 return Status; 4479 } 4480 ExFreePool(KeyNameBuffer); 4481 4482 /* 4483 * For driver key we're done now. 4484 */ 4485 4486 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER) 4487 return Status; 4488 4489 /* 4490 * Let's go further. For device key we must open "Device Parameters" 4491 * subkey and create it if it doesn't exist yet. 4492 */ 4493 4494 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName); 4495 InitializeObjectAttributes(&ObjectAttributes, 4496 &KeyName, 4497 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 4498 *DevInstRegKey, 4499 NULL); 4500 Status = ZwCreateKey(DevInstRegKey, DesiredAccess, &ObjectAttributes, 4501 0, NULL, ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0, NULL); 4502 ZwClose(ObjectAttributes.RootDirectory); 4503 4504 return Status; 4505 } 4506 4507 static 4508 NTSTATUS 4509 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode, BOOLEAN Force) 4510 { 4511 PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice; 4512 NTSTATUS Status; 4513 KIRQL OldIrql; 4514 4515 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4516 ChildDeviceNode = ParentDeviceNode->Child; 4517 while (ChildDeviceNode != NULL) 4518 { 4519 NextDeviceNode = ChildDeviceNode->Sibling; 4520 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4521 4522 Status = IopPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject, Force); 4523 if (!NT_SUCCESS(Status)) 4524 { 4525 FailedRemoveDevice = ChildDeviceNode; 4526 goto cleanup; 4527 } 4528 4529 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4530 ChildDeviceNode = NextDeviceNode; 4531 } 4532 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4533 4534 return STATUS_SUCCESS; 4535 4536 cleanup: 4537 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4538 ChildDeviceNode = ParentDeviceNode->Child; 4539 while (ChildDeviceNode != NULL) 4540 { 4541 NextDeviceNode = ChildDeviceNode->Sibling; 4542 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4543 4544 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject); 4545 4546 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device 4547 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */ 4548 if (ChildDeviceNode == FailedRemoveDevice) 4549 return Status; 4550 4551 ChildDeviceNode = NextDeviceNode; 4552 4553 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4554 } 4555 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4556 4557 return Status; 4558 } 4559 4560 static 4561 VOID 4562 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode) 4563 { 4564 PDEVICE_NODE ChildDeviceNode, NextDeviceNode; 4565 KIRQL OldIrql; 4566 4567 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4568 ChildDeviceNode = ParentDeviceNode->Child; 4569 while (ChildDeviceNode != NULL) 4570 { 4571 NextDeviceNode = ChildDeviceNode->Sibling; 4572 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4573 4574 IopSendRemoveDevice(ChildDeviceNode->PhysicalDeviceObject); 4575 4576 ChildDeviceNode = NextDeviceNode; 4577 4578 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4579 } 4580 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4581 } 4582 4583 static 4584 VOID 4585 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode) 4586 { 4587 PDEVICE_NODE ChildDeviceNode, NextDeviceNode; 4588 KIRQL OldIrql; 4589 4590 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4591 ChildDeviceNode = ParentDeviceNode->Child; 4592 while (ChildDeviceNode != NULL) 4593 { 4594 NextDeviceNode = ChildDeviceNode->Sibling; 4595 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4596 4597 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject); 4598 4599 ChildDeviceNode = NextDeviceNode; 4600 4601 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4602 } 4603 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4604 } 4605 4606 static 4607 NTSTATUS 4608 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations, BOOLEAN Force) 4609 { 4610 /* This function DOES NOT dereference the device objects on SUCCESS 4611 * but it DOES dereference device objects on FAILURE */ 4612 4613 ULONG i, j; 4614 NTSTATUS Status; 4615 4616 for (i = 0; i < DeviceRelations->Count; i++) 4617 { 4618 Status = IopPrepareDeviceForRemoval(DeviceRelations->Objects[i], Force); 4619 if (!NT_SUCCESS(Status)) 4620 { 4621 j = i; 4622 goto cleanup; 4623 } 4624 } 4625 4626 return STATUS_SUCCESS; 4627 4628 cleanup: 4629 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device 4630 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */ 4631 for (i = 0; i <= j; i++) 4632 { 4633 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]); 4634 ObDereferenceObject(DeviceRelations->Objects[i]); 4635 DeviceRelations->Objects[i] = NULL; 4636 } 4637 for (; i < DeviceRelations->Count; i++) 4638 { 4639 ObDereferenceObject(DeviceRelations->Objects[i]); 4640 DeviceRelations->Objects[i] = NULL; 4641 } 4642 ExFreePool(DeviceRelations); 4643 4644 return Status; 4645 } 4646 4647 static 4648 VOID 4649 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations) 4650 { 4651 /* This function DOES dereference the device objects in all cases */ 4652 4653 ULONG i; 4654 4655 for (i = 0; i < DeviceRelations->Count; i++) 4656 { 4657 IopSendRemoveDevice(DeviceRelations->Objects[i]); 4658 DeviceRelations->Objects[i] = NULL; 4659 } 4660 4661 ExFreePool(DeviceRelations); 4662 } 4663 4664 static 4665 VOID 4666 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations) 4667 { 4668 /* This function DOES dereference the device objects in all cases */ 4669 4670 ULONG i; 4671 4672 for (i = 0; i < DeviceRelations->Count; i++) 4673 { 4674 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]); 4675 ObDereferenceObject(DeviceRelations->Objects[i]); 4676 DeviceRelations->Objects[i] = NULL; 4677 } 4678 4679 ExFreePool(DeviceRelations); 4680 } 4681 4682 VOID 4683 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject) 4684 { 4685 IO_STACK_LOCATION Stack; 4686 IO_STATUS_BLOCK IoStatusBlock; 4687 PDEVICE_RELATIONS DeviceRelations; 4688 NTSTATUS Status; 4689 4690 IopCancelRemoveDevice(DeviceObject); 4691 4692 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations; 4693 4694 Status = IopInitiatePnpIrp(DeviceObject, 4695 &IoStatusBlock, 4696 IRP_MN_QUERY_DEVICE_RELATIONS, 4697 &Stack); 4698 if (!NT_SUCCESS(Status)) 4699 { 4700 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 4701 DeviceRelations = NULL; 4702 } 4703 else 4704 { 4705 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 4706 } 4707 4708 if (DeviceRelations) 4709 IopCancelRemoveDeviceRelations(DeviceRelations); 4710 } 4711 4712 NTSTATUS 4713 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject, BOOLEAN Force) 4714 { 4715 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 4716 IO_STACK_LOCATION Stack; 4717 IO_STATUS_BLOCK IoStatusBlock; 4718 PDEVICE_RELATIONS DeviceRelations; 4719 NTSTATUS Status; 4720 4721 if ((DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE) && !Force) 4722 { 4723 DPRINT1("Removal not allowed for %wZ\n", &DeviceNode->InstancePath); 4724 return STATUS_UNSUCCESSFUL; 4725 } 4726 4727 if (!Force && IopQueryRemoveDevice(DeviceObject) != STATUS_SUCCESS) 4728 { 4729 DPRINT1("Removal vetoed by failing the query remove request\n"); 4730 4731 IopCancelRemoveDevice(DeviceObject); 4732 4733 return STATUS_UNSUCCESSFUL; 4734 } 4735 4736 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations; 4737 4738 Status = IopInitiatePnpIrp(DeviceObject, 4739 &IoStatusBlock, 4740 IRP_MN_QUERY_DEVICE_RELATIONS, 4741 &Stack); 4742 if (!NT_SUCCESS(Status)) 4743 { 4744 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 4745 DeviceRelations = NULL; 4746 } 4747 else 4748 { 4749 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 4750 } 4751 4752 if (DeviceRelations) 4753 { 4754 Status = IopQueryRemoveDeviceRelations(DeviceRelations, Force); 4755 if (!NT_SUCCESS(Status)) 4756 return Status; 4757 } 4758 4759 Status = IopQueryRemoveChildDevices(DeviceNode, Force); 4760 if (!NT_SUCCESS(Status)) 4761 { 4762 if (DeviceRelations) 4763 IopCancelRemoveDeviceRelations(DeviceRelations); 4764 return Status; 4765 } 4766 4767 if (DeviceRelations) 4768 IopSendRemoveDeviceRelations(DeviceRelations); 4769 IopSendRemoveChildDevices(DeviceNode); 4770 4771 return STATUS_SUCCESS; 4772 } 4773 4774 NTSTATUS 4775 IopRemoveDevice(PDEVICE_NODE DeviceNode) 4776 { 4777 NTSTATUS Status; 4778 4779 DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath); 4780 4781 Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject, FALSE); 4782 if (NT_SUCCESS(Status)) 4783 { 4784 IopSendRemoveDevice(DeviceNode->PhysicalDeviceObject); 4785 IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL, 4786 &DeviceNode->InstancePath); 4787 return STATUS_SUCCESS; 4788 } 4789 4790 return Status; 4791 } 4792 4793 /* 4794 * @implemented 4795 */ 4796 VOID 4797 NTAPI 4798 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject) 4799 { 4800 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject); 4801 PDEVICE_RELATIONS DeviceRelations; 4802 IO_STATUS_BLOCK IoStatusBlock; 4803 IO_STACK_LOCATION Stack; 4804 DEVICE_CAPABILITIES Capabilities; 4805 NTSTATUS Status; 4806 4807 IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT, 4808 &DeviceNode->InstancePath); 4809 4810 if (IopQueryDeviceCapabilities(DeviceNode, &Capabilities) != STATUS_SUCCESS) 4811 { 4812 goto cleanup; 4813 } 4814 4815 Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations; 4816 4817 Status = IopInitiatePnpIrp(PhysicalDeviceObject, 4818 &IoStatusBlock, 4819 IRP_MN_QUERY_DEVICE_RELATIONS, 4820 &Stack); 4821 if (!NT_SUCCESS(Status)) 4822 { 4823 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 4824 DeviceRelations = NULL; 4825 } 4826 else 4827 { 4828 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 4829 } 4830 4831 if (DeviceRelations) 4832 { 4833 Status = IopQueryRemoveDeviceRelations(DeviceRelations, FALSE); 4834 if (!NT_SUCCESS(Status)) 4835 goto cleanup; 4836 } 4837 4838 Status = IopQueryRemoveChildDevices(DeviceNode, FALSE); 4839 if (!NT_SUCCESS(Status)) 4840 { 4841 if (DeviceRelations) 4842 IopCancelRemoveDeviceRelations(DeviceRelations); 4843 goto cleanup; 4844 } 4845 4846 if (IopPrepareDeviceForRemoval(PhysicalDeviceObject, FALSE) != STATUS_SUCCESS) 4847 { 4848 if (DeviceRelations) 4849 IopCancelRemoveDeviceRelations(DeviceRelations); 4850 IopCancelRemoveChildDevices(DeviceNode); 4851 goto cleanup; 4852 } 4853 4854 if (DeviceRelations) 4855 IopSendRemoveDeviceRelations(DeviceRelations); 4856 IopSendRemoveChildDevices(DeviceNode); 4857 4858 DeviceNode->Problem = CM_PROB_HELD_FOR_EJECT; 4859 if (Capabilities.EjectSupported) 4860 { 4861 if (IopSendEject(PhysicalDeviceObject) != STATUS_SUCCESS) 4862 { 4863 goto cleanup; 4864 } 4865 } 4866 else 4867 { 4868 DeviceNode->Flags |= DNF_DISABLED; 4869 } 4870 4871 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT, 4872 &DeviceNode->InstancePath); 4873 4874 return; 4875 4876 cleanup: 4877 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED, 4878 &DeviceNode->InstancePath); 4879 } 4880 4881 /* 4882 * @implemented 4883 */ 4884 VOID 4885 NTAPI 4886 IoInvalidateDeviceRelations( 4887 IN PDEVICE_OBJECT DeviceObject, 4888 IN DEVICE_RELATION_TYPE Type) 4889 { 4890 PINVALIDATE_DEVICE_RELATION_DATA Data; 4891 KIRQL OldIrql; 4892 4893 Data = ExAllocatePool(NonPagedPool, sizeof(INVALIDATE_DEVICE_RELATION_DATA)); 4894 if (!Data) 4895 return; 4896 4897 ObReferenceObject(DeviceObject); 4898 Data->DeviceObject = DeviceObject; 4899 Data->Type = Type; 4900 4901 KeAcquireSpinLock(&IopDeviceRelationsSpinLock, &OldIrql); 4902 InsertTailList(&IopDeviceRelationsRequestList, &Data->RequestListEntry); 4903 if (IopDeviceRelationsRequestInProgress) 4904 { 4905 KeReleaseSpinLock(&IopDeviceRelationsSpinLock, OldIrql); 4906 return; 4907 } 4908 IopDeviceRelationsRequestInProgress = TRUE; 4909 KeReleaseSpinLock(&IopDeviceRelationsSpinLock, OldIrql); 4910 4911 ExInitializeWorkItem(&IopDeviceRelationsWorkItem, 4912 IopDeviceRelationsWorker, 4913 NULL); 4914 ExQueueWorkItem(&IopDeviceRelationsWorkItem, 4915 DelayedWorkQueue); 4916 } 4917 4918 /* 4919 * @implemented 4920 */ 4921 NTSTATUS 4922 NTAPI 4923 IoSynchronousInvalidateDeviceRelations( 4924 IN PDEVICE_OBJECT DeviceObject, 4925 IN DEVICE_RELATION_TYPE Type) 4926 { 4927 PAGED_CODE(); 4928 4929 switch (Type) 4930 { 4931 case BusRelations: 4932 /* Enumerate the device */ 4933 return IopEnumerateDevice(DeviceObject); 4934 case PowerRelations: 4935 /* Not handled yet */ 4936 return STATUS_NOT_IMPLEMENTED; 4937 case TargetDeviceRelation: 4938 /* Nothing to do */ 4939 return STATUS_SUCCESS; 4940 default: 4941 /* Ejection relations are not supported */ 4942 return STATUS_NOT_SUPPORTED; 4943 } 4944 } 4945 4946 /* 4947 * @implemented 4948 */ 4949 BOOLEAN 4950 NTAPI 4951 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType, 4952 IN ULONG BusNumber, 4953 IN PHYSICAL_ADDRESS BusAddress, 4954 IN OUT PULONG AddressSpace, 4955 OUT PPHYSICAL_ADDRESS TranslatedAddress) 4956 { 4957 /* FIXME: Notify the resource arbiter */ 4958 4959 return HalTranslateBusAddress(InterfaceType, 4960 BusNumber, 4961 BusAddress, 4962 AddressSpace, 4963 TranslatedAddress); 4964 } 4965