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