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