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[0]) + MAX_PATH * sizeof(WCHAR); 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 WCHAR RegKeyBuffer[MAX_PATH]; 2858 UNICODE_STRING RegKey; 2859 2860 /* Install the service for this if it's in the CDDB */ 2861 IopInstallCriticalDevice(DeviceNode); 2862 2863 RegKey.Length = 0; 2864 RegKey.MaximumLength = sizeof(RegKeyBuffer); 2865 RegKey.Buffer = RegKeyBuffer; 2866 2867 /* 2868 * Retrieve configuration from Enum key 2869 */ 2870 2871 Service = &DeviceNode->ServiceName; 2872 2873 RtlZeroMemory(QueryTable, sizeof(QueryTable)); 2874 RtlInitUnicodeString(Service, NULL); 2875 RtlInitUnicodeString(&ClassGUID, NULL); 2876 2877 QueryTable[0].Name = L"Service"; 2878 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 2879 QueryTable[0].EntryContext = Service; 2880 2881 QueryTable[1].Name = L"ClassGUID"; 2882 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT; 2883 QueryTable[1].EntryContext = &ClassGUID; 2884 QueryTable[1].DefaultType = REG_SZ; 2885 QueryTable[1].DefaultData = L""; 2886 QueryTable[1].DefaultLength = 0; 2887 2888 RtlAppendUnicodeToString(&RegKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\"); 2889 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath); 2890 2891 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 2892 RegKey.Buffer, QueryTable, NULL, NULL); 2893 2894 if (!NT_SUCCESS(Status)) 2895 { 2896 /* FIXME: Log the error */ 2897 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n", 2898 &DeviceNode->InstancePath, Status); 2899 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); 2900 return STATUS_SUCCESS; 2901 } 2902 2903 if (Service->Buffer == NULL) 2904 { 2905 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) && 2906 DeviceCaps.RawDeviceOK) 2907 { 2908 DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName); 2909 RtlInitEmptyUnicodeString(&DeviceNode->ServiceName, NULL, 0); 2910 } 2911 else if (ClassGUID.Length != 0) 2912 { 2913 /* Device has a ClassGUID value, but no Service value. 2914 * Suppose it is using the NULL driver, so state the 2915 * device is started */ 2916 DPRINT("%wZ is using NULL driver\n", &DeviceNode->InstancePath); 2917 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED); 2918 } 2919 else 2920 { 2921 DeviceNode->Problem = CM_PROB_FAILED_INSTALL; 2922 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); 2923 } 2924 return STATUS_SUCCESS; 2925 } 2926 2927 DPRINT("Got Service %S\n", Service->Buffer); 2928 } 2929 2930 return STATUS_SUCCESS; 2931 } 2932 2933 /* 2934 * IopActionInitChildServices 2935 * 2936 * Initialize the service for all (direct) child nodes of a parent node 2937 * 2938 * Parameters 2939 * DeviceNode 2940 * Pointer to device node. 2941 * Context 2942 * Pointer to parent node to initialize child node services for. 2943 * 2944 * Remarks 2945 * If the driver image for a service is not loaded and initialized 2946 * it is done here too. Any errors that occur are logged instead so 2947 * that all child services have a chance of being initialized. 2948 */ 2949 2950 NTSTATUS 2951 IopActionInitChildServices(PDEVICE_NODE DeviceNode, 2952 PVOID Context) 2953 { 2954 PDEVICE_NODE ParentDeviceNode; 2955 NTSTATUS Status; 2956 BOOLEAN BootDrivers = !PnpSystemInit; 2957 2958 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context); 2959 2960 ParentDeviceNode = Context; 2961 2962 /* 2963 * We are called for the parent too, but we don't need to do special 2964 * handling for this node 2965 */ 2966 if (DeviceNode == ParentDeviceNode) 2967 { 2968 DPRINT("Success\n"); 2969 return STATUS_SUCCESS; 2970 } 2971 2972 /* 2973 * We don't want to check for a direct child because 2974 * this function is called during boot to reinitialize 2975 * devices with drivers that couldn't load yet due to 2976 * stage 0 limitations (ie can't load from disk yet). 2977 */ 2978 2979 if (!(DeviceNode->Flags & DNF_PROCESSED)) 2980 { 2981 DPRINT1("Child not ready to be added\n"); 2982 return STATUS_SUCCESS; 2983 } 2984 2985 if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) || 2986 IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) || 2987 IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED)) 2988 return STATUS_SUCCESS; 2989 2990 if (DeviceNode->ServiceName.Buffer == NULL) 2991 { 2992 /* We don't need to worry about loading the driver because we're 2993 * being driven in raw mode so our parent must be loaded to get here */ 2994 Status = IopInitializeDevice(DeviceNode, NULL); 2995 if (NT_SUCCESS(Status)) 2996 { 2997 Status = IopStartDevice(DeviceNode); 2998 if (!NT_SUCCESS(Status)) 2999 { 3000 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n", 3001 &DeviceNode->InstancePath, Status); 3002 } 3003 } 3004 } 3005 else 3006 { 3007 PLDR_DATA_TABLE_ENTRY ModuleObject; 3008 PDRIVER_OBJECT DriverObject; 3009 3010 KeEnterCriticalRegion(); 3011 ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE); 3012 /* Get existing DriverObject pointer (in case the driver has 3013 already been loaded and initialized) */ 3014 Status = IopGetDriverObject( 3015 &DriverObject, 3016 &DeviceNode->ServiceName, 3017 FALSE); 3018 3019 if (!NT_SUCCESS(Status)) 3020 { 3021 /* Driver is not initialized, try to load it */ 3022 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject); 3023 3024 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED) 3025 { 3026 /* Initialize the driver */ 3027 Status = IopInitializeDriverModule(DeviceNode, ModuleObject, 3028 &DeviceNode->ServiceName, FALSE, &DriverObject); 3029 if (!NT_SUCCESS(Status)) DeviceNode->Problem = CM_PROB_FAILED_DRIVER_ENTRY; 3030 } 3031 else if (Status == STATUS_DRIVER_UNABLE_TO_LOAD) 3032 { 3033 DPRINT1("Service '%wZ' is disabled\n", &DeviceNode->ServiceName); 3034 DeviceNode->Problem = CM_PROB_DISABLED_SERVICE; 3035 } 3036 else 3037 { 3038 DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n", 3039 &DeviceNode->ServiceName, Status); 3040 if (!BootDrivers) DeviceNode->Problem = CM_PROB_DRIVER_FAILED_LOAD; 3041 } 3042 } 3043 ExReleaseResourceLite(&IopDriverLoadResource); 3044 KeLeaveCriticalRegion(); 3045 3046 /* Driver is loaded and initialized at this point */ 3047 if (NT_SUCCESS(Status)) 3048 { 3049 /* Initialize the device, including all filters */ 3050 Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject); 3051 3052 /* Remove the extra reference */ 3053 ObDereferenceObject(DriverObject); 3054 } 3055 else 3056 { 3057 /* 3058 * Don't disable when trying to load only boot drivers 3059 */ 3060 if (!BootDrivers) 3061 { 3062 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); 3063 } 3064 } 3065 } 3066 3067 return STATUS_SUCCESS; 3068 } 3069 3070 /* 3071 * IopInitializePnpServices 3072 * 3073 * Initialize services for discovered children 3074 * 3075 * Parameters 3076 * DeviceNode 3077 * Top device node to start initializing services. 3078 * 3079 * Return Value 3080 * Status 3081 */ 3082 NTSTATUS 3083 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode) 3084 { 3085 DEVICETREE_TRAVERSE_CONTEXT Context; 3086 3087 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode); 3088 3089 IopInitDeviceTreeTraverseContext( 3090 &Context, 3091 DeviceNode, 3092 IopActionInitChildServices, 3093 DeviceNode); 3094 3095 return IopTraverseDeviceTree(&Context); 3096 } 3097 3098 static 3099 INIT_FUNCTION 3100 NTSTATUS 3101 IopEnumerateDetectedDevices( 3102 IN HANDLE hBaseKey, 3103 IN PUNICODE_STRING RelativePath OPTIONAL, 3104 IN HANDLE hRootKey, 3105 IN BOOLEAN EnumerateSubKeys, 3106 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources, 3107 IN ULONG ParentBootResourcesLength) 3108 { 3109 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier"); 3110 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID"); 3111 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data"); 3112 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig"); 3113 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf"); 3114 OBJECT_ATTRIBUTES ObjectAttributes; 3115 HANDLE hDevicesKey = NULL; 3116 HANDLE hDeviceKey = NULL; 3117 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf; 3118 UNICODE_STRING Level2NameU; 3119 WCHAR Level2Name[5]; 3120 ULONG IndexDevice = 0; 3121 ULONG IndexSubKey; 3122 PKEY_BASIC_INFORMATION pDeviceInformation = NULL; 3123 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR); 3124 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL; 3125 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR); 3126 UNICODE_STRING DeviceName, ValueName; 3127 ULONG RequiredSize; 3128 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL; 3129 ULONG BootResourcesLength; 3130 NTSTATUS Status; 3131 3132 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController"); 3133 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0"); 3134 static ULONG DeviceIndexSerial = 0; 3135 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController"); 3136 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0"); 3137 static ULONG DeviceIndexKeyboard = 0; 3138 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController"); 3139 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0"); 3140 static ULONG DeviceIndexMouse = 0; 3141 const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController"); 3142 UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0"); 3143 static ULONG DeviceIndexParallel = 0; 3144 const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral"); 3145 UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0"); 3146 static ULONG DeviceIndexFloppy = 0; 3147 UNICODE_STRING HardwareIdKey; 3148 PUNICODE_STRING pHardwareId; 3149 ULONG DeviceIndex = 0; 3150 PUCHAR CmResourceList; 3151 ULONG ListCount; 3152 3153 if (RelativePath) 3154 { 3155 Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS); 3156 if (!NT_SUCCESS(Status)) 3157 { 3158 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status); 3159 goto cleanup; 3160 } 3161 } 3162 else 3163 hDevicesKey = hBaseKey; 3164 3165 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength); 3166 if (!pDeviceInformation) 3167 { 3168 DPRINT("ExAllocatePool() failed\n"); 3169 Status = STATUS_NO_MEMORY; 3170 goto cleanup; 3171 } 3172 3173 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength); 3174 if (!pValueInformation) 3175 { 3176 DPRINT("ExAllocatePool() failed\n"); 3177 Status = STATUS_NO_MEMORY; 3178 goto cleanup; 3179 } 3180 3181 while (TRUE) 3182 { 3183 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize); 3184 if (Status == STATUS_NO_MORE_ENTRIES) 3185 break; 3186 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 3187 { 3188 ExFreePool(pDeviceInformation); 3189 DeviceInfoLength = RequiredSize; 3190 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength); 3191 if (!pDeviceInformation) 3192 { 3193 DPRINT("ExAllocatePool() failed\n"); 3194 Status = STATUS_NO_MEMORY; 3195 goto cleanup; 3196 } 3197 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize); 3198 } 3199 if (!NT_SUCCESS(Status)) 3200 { 3201 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status); 3202 goto cleanup; 3203 } 3204 IndexDevice++; 3205 3206 /* Open device key */ 3207 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength; 3208 DeviceName.Buffer = pDeviceInformation->Name; 3209 3210 Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName, 3211 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0)); 3212 if (!NT_SUCCESS(Status)) 3213 { 3214 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status); 3215 goto cleanup; 3216 } 3217 3218 /* Read boot resources, and add then to parent ones */ 3219 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize); 3220 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 3221 { 3222 ExFreePool(pValueInformation); 3223 ValueInfoLength = RequiredSize; 3224 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength); 3225 if (!pValueInformation) 3226 { 3227 DPRINT("ExAllocatePool() failed\n"); 3228 ZwDeleteKey(hLevel2Key); 3229 Status = STATUS_NO_MEMORY; 3230 goto cleanup; 3231 } 3232 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize); 3233 } 3234 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 3235 { 3236 BootResources = ParentBootResources; 3237 BootResourcesLength = ParentBootResourcesLength; 3238 } 3239 else if (!NT_SUCCESS(Status)) 3240 { 3241 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status); 3242 goto nextdevice; 3243 } 3244 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR) 3245 { 3246 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR); 3247 goto nextdevice; 3248 } 3249 else 3250 { 3251 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors); 3252 3253 /* Concatenate current resources and parent ones */ 3254 if (ParentBootResourcesLength == 0) 3255 BootResourcesLength = pValueInformation->DataLength; 3256 else 3257 BootResourcesLength = ParentBootResourcesLength 3258 + pValueInformation->DataLength 3259 - Header; 3260 BootResources = ExAllocatePool(PagedPool, BootResourcesLength); 3261 if (!BootResources) 3262 { 3263 DPRINT("ExAllocatePool() failed\n"); 3264 goto nextdevice; 3265 } 3266 if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) 3267 { 3268 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength); 3269 } 3270 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific) 3271 { 3272 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength); 3273 RtlCopyMemory( 3274 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength), 3275 (PVOID)((ULONG_PTR)ParentBootResources + Header), 3276 ParentBootResourcesLength - Header); 3277 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count; 3278 } 3279 else 3280 { 3281 RtlCopyMemory(BootResources, pValueInformation->Data, Header); 3282 RtlCopyMemory( 3283 (PVOID)((ULONG_PTR)BootResources + Header), 3284 (PVOID)((ULONG_PTR)ParentBootResources + Header), 3285 ParentBootResourcesLength - Header); 3286 RtlCopyMemory( 3287 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength), 3288 pValueInformation->Data + Header, 3289 pValueInformation->DataLength - Header); 3290 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count; 3291 } 3292 } 3293 3294 if (EnumerateSubKeys) 3295 { 3296 IndexSubKey = 0; 3297 while (TRUE) 3298 { 3299 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize); 3300 if (Status == STATUS_NO_MORE_ENTRIES) 3301 break; 3302 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 3303 { 3304 ExFreePool(pDeviceInformation); 3305 DeviceInfoLength = RequiredSize; 3306 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength); 3307 if (!pDeviceInformation) 3308 { 3309 DPRINT("ExAllocatePool() failed\n"); 3310 Status = STATUS_NO_MEMORY; 3311 goto cleanup; 3312 } 3313 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize); 3314 } 3315 if (!NT_SUCCESS(Status)) 3316 { 3317 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status); 3318 goto cleanup; 3319 } 3320 IndexSubKey++; 3321 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength; 3322 DeviceName.Buffer = pDeviceInformation->Name; 3323 3324 Status = IopEnumerateDetectedDevices( 3325 hDeviceKey, 3326 &DeviceName, 3327 hRootKey, 3328 TRUE, 3329 BootResources, 3330 BootResourcesLength); 3331 if (!NT_SUCCESS(Status)) 3332 goto cleanup; 3333 } 3334 } 3335 3336 /* Read identifier */ 3337 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize); 3338 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 3339 { 3340 ExFreePool(pValueInformation); 3341 ValueInfoLength = RequiredSize; 3342 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength); 3343 if (!pValueInformation) 3344 { 3345 DPRINT("ExAllocatePool() failed\n"); 3346 Status = STATUS_NO_MEMORY; 3347 goto cleanup; 3348 } 3349 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize); 3350 } 3351 if (!NT_SUCCESS(Status)) 3352 { 3353 if (Status != STATUS_OBJECT_NAME_NOT_FOUND) 3354 { 3355 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status); 3356 goto nextdevice; 3357 } 3358 ValueName.Length = ValueName.MaximumLength = 0; 3359 } 3360 else if (pValueInformation->Type != REG_SZ) 3361 { 3362 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ); 3363 goto nextdevice; 3364 } 3365 else 3366 { 3367 /* Assign hardware id to this device */ 3368 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength; 3369 ValueName.Buffer = (PWCHAR)pValueInformation->Data; 3370 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL) 3371 ValueName.Length -= sizeof(WCHAR); 3372 } 3373 3374 if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0) 3375 { 3376 pHardwareId = &HardwareIdSerial; 3377 DeviceIndex = DeviceIndexSerial++; 3378 } 3379 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0) 3380 { 3381 pHardwareId = &HardwareIdKeyboard; 3382 DeviceIndex = DeviceIndexKeyboard++; 3383 } 3384 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0) 3385 { 3386 pHardwareId = &HardwareIdMouse; 3387 DeviceIndex = DeviceIndexMouse++; 3388 } 3389 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0) 3390 { 3391 pHardwareId = &HardwareIdParallel; 3392 DeviceIndex = DeviceIndexParallel++; 3393 } 3394 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0) 3395 { 3396 pHardwareId = &HardwareIdFloppy; 3397 DeviceIndex = DeviceIndexFloppy++; 3398 } 3399 else 3400 { 3401 /* Unknown key path */ 3402 DPRINT("Unknown key path '%wZ'\n", RelativePath); 3403 goto nextdevice; 3404 } 3405 3406 /* Prepare hardware id key (hardware id value without final \0) */ 3407 HardwareIdKey = *pHardwareId; 3408 HardwareIdKey.Length -= sizeof(UNICODE_NULL); 3409 3410 /* Add the detected device to Root key */ 3411 InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL); 3412 Status = ZwCreateKey( 3413 &hLevel1Key, 3414 KEY_CREATE_SUB_KEY, 3415 &ObjectAttributes, 3416 0, 3417 NULL, 3418 REG_OPTION_NON_VOLATILE, 3419 NULL); 3420 if (!NT_SUCCESS(Status)) 3421 { 3422 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status); 3423 goto nextdevice; 3424 } 3425 swprintf(Level2Name, L"%04lu", DeviceIndex); 3426 RtlInitUnicodeString(&Level2NameU, Level2Name); 3427 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL); 3428 Status = ZwCreateKey( 3429 &hLevel2Key, 3430 KEY_SET_VALUE | KEY_CREATE_SUB_KEY, 3431 &ObjectAttributes, 3432 0, 3433 NULL, 3434 REG_OPTION_NON_VOLATILE, 3435 NULL); 3436 ZwClose(hLevel1Key); 3437 if (!NT_SUCCESS(Status)) 3438 { 3439 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status); 3440 goto nextdevice; 3441 } 3442 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey); 3443 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength); 3444 if (!NT_SUCCESS(Status)) 3445 { 3446 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status); 3447 ZwDeleteKey(hLevel2Key); 3448 goto nextdevice; 3449 } 3450 /* Create 'LogConf' subkey */ 3451 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL); 3452 Status = ZwCreateKey( 3453 &hLogConf, 3454 KEY_SET_VALUE, 3455 &ObjectAttributes, 3456 0, 3457 NULL, 3458 REG_OPTION_VOLATILE, 3459 NULL); 3460 if (!NT_SUCCESS(Status)) 3461 { 3462 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status); 3463 ZwDeleteKey(hLevel2Key); 3464 goto nextdevice; 3465 } 3466 if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) 3467 { 3468 CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG)); 3469 if (!CmResourceList) 3470 { 3471 ZwClose(hLogConf); 3472 ZwDeleteKey(hLevel2Key); 3473 goto nextdevice; 3474 } 3475 3476 /* Add the list count (1st member of CM_RESOURCE_LIST) */ 3477 ListCount = 1; 3478 RtlCopyMemory(CmResourceList, 3479 &ListCount, 3480 sizeof(ULONG)); 3481 3482 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */ 3483 RtlCopyMemory(CmResourceList + sizeof(ULONG), 3484 BootResources, 3485 BootResourcesLength); 3486 3487 /* Save boot resources to 'LogConf\BootConfig' */ 3488 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG)); 3489 if (!NT_SUCCESS(Status)) 3490 { 3491 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status); 3492 ZwClose(hLogConf); 3493 ZwDeleteKey(hLevel2Key); 3494 goto nextdevice; 3495 } 3496 } 3497 ZwClose(hLogConf); 3498 3499 nextdevice: 3500 if (BootResources && BootResources != ParentBootResources) 3501 { 3502 ExFreePool(BootResources); 3503 BootResources = NULL; 3504 } 3505 if (hLevel2Key) 3506 { 3507 ZwClose(hLevel2Key); 3508 hLevel2Key = NULL; 3509 } 3510 if (hDeviceKey) 3511 { 3512 ZwClose(hDeviceKey); 3513 hDeviceKey = NULL; 3514 } 3515 } 3516 3517 Status = STATUS_SUCCESS; 3518 3519 cleanup: 3520 if (hDevicesKey && hDevicesKey != hBaseKey) 3521 ZwClose(hDevicesKey); 3522 if (hDeviceKey) 3523 ZwClose(hDeviceKey); 3524 if (pDeviceInformation) 3525 ExFreePool(pDeviceInformation); 3526 if (pValueInformation) 3527 ExFreePool(pValueInformation); 3528 return Status; 3529 } 3530 3531 static 3532 INIT_FUNCTION 3533 BOOLEAN 3534 IopIsFirmwareMapperDisabled(VOID) 3535 { 3536 UNICODE_STRING KeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp"); 3537 UNICODE_STRING KeyNameU = RTL_CONSTANT_STRING(L"DisableFirmwareMapper"); 3538 OBJECT_ATTRIBUTES ObjectAttributes; 3539 HANDLE hPnpKey; 3540 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation; 3541 ULONG DesiredLength, Length; 3542 ULONG KeyValue = 0; 3543 NTSTATUS Status; 3544 3545 InitializeObjectAttributes(&ObjectAttributes, &KeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); 3546 Status = ZwOpenKey(&hPnpKey, KEY_QUERY_VALUE, &ObjectAttributes); 3547 if (NT_SUCCESS(Status)) 3548 { 3549 Status = ZwQueryValueKey(hPnpKey, 3550 &KeyNameU, 3551 KeyValuePartialInformation, 3552 NULL, 3553 0, 3554 &DesiredLength); 3555 if ((Status == STATUS_BUFFER_TOO_SMALL) || 3556 (Status == STATUS_BUFFER_OVERFLOW)) 3557 { 3558 Length = DesiredLength; 3559 KeyInformation = ExAllocatePool(PagedPool, Length); 3560 if (KeyInformation) 3561 { 3562 Status = ZwQueryValueKey(hPnpKey, 3563 &KeyNameU, 3564 KeyValuePartialInformation, 3565 KeyInformation, 3566 Length, 3567 &DesiredLength); 3568 if (NT_SUCCESS(Status) && KeyInformation->DataLength == sizeof(ULONG)) 3569 { 3570 KeyValue = (ULONG)(*KeyInformation->Data); 3571 } 3572 else 3573 { 3574 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU, &KeyNameU); 3575 } 3576 3577 ExFreePool(KeyInformation); 3578 } 3579 else 3580 { 3581 DPRINT1("Failed to allocate memory for registry query\n"); 3582 } 3583 } 3584 else 3585 { 3586 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU, &KeyNameU, Status); 3587 } 3588 3589 ZwClose(hPnpKey); 3590 } 3591 else 3592 { 3593 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU, Status); 3594 } 3595 3596 DPRINT("Firmware mapper is %s\n", KeyValue != 0 ? "disabled" : "enabled"); 3597 3598 return (KeyValue != 0) ? TRUE : FALSE; 3599 } 3600 3601 INIT_FUNCTION 3602 NTSTATUS 3603 NTAPI 3604 IopUpdateRootKey(VOID) 3605 { 3606 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum"); 3607 UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root"); 3608 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"); 3609 OBJECT_ATTRIBUTES ObjectAttributes; 3610 HANDLE hEnum, hRoot; 3611 NTSTATUS Status; 3612 3613 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); 3614 Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL); 3615 if (!NT_SUCCESS(Status)) 3616 { 3617 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status); 3618 return Status; 3619 } 3620 3621 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL); 3622 Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL); 3623 ZwClose(hEnum); 3624 if (!NT_SUCCESS(Status)) 3625 { 3626 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status); 3627 return Status; 3628 } 3629 3630 if (!IopIsFirmwareMapperDisabled()) 3631 { 3632 Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS); 3633 if (!NT_SUCCESS(Status)) 3634 { 3635 /* Nothing to do, don't return with an error status */ 3636 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status); 3637 ZwClose(hRoot); 3638 return STATUS_SUCCESS; 3639 } 3640 Status = IopEnumerateDetectedDevices( 3641 hEnum, 3642 NULL, 3643 hRoot, 3644 TRUE, 3645 NULL, 3646 0); 3647 ZwClose(hEnum); 3648 } 3649 else 3650 { 3651 /* Enumeration is disabled */ 3652 Status = STATUS_SUCCESS; 3653 } 3654 3655 ZwClose(hRoot); 3656 3657 return Status; 3658 } 3659 3660 NTSTATUS 3661 NTAPI 3662 IopOpenRegistryKeyEx(PHANDLE KeyHandle, 3663 HANDLE ParentKey, 3664 PUNICODE_STRING Name, 3665 ACCESS_MASK DesiredAccess) 3666 { 3667 OBJECT_ATTRIBUTES ObjectAttributes; 3668 NTSTATUS Status; 3669 3670 PAGED_CODE(); 3671 3672 *KeyHandle = NULL; 3673 3674 InitializeObjectAttributes(&ObjectAttributes, 3675 Name, 3676 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 3677 ParentKey, 3678 NULL); 3679 3680 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes); 3681 3682 return Status; 3683 } 3684 3685 NTSTATUS 3686 NTAPI 3687 IopCreateRegistryKeyEx(OUT PHANDLE Handle, 3688 IN HANDLE RootHandle OPTIONAL, 3689 IN PUNICODE_STRING KeyName, 3690 IN ACCESS_MASK DesiredAccess, 3691 IN ULONG CreateOptions, 3692 OUT PULONG Disposition OPTIONAL) 3693 { 3694 OBJECT_ATTRIBUTES ObjectAttributes; 3695 ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0; 3696 USHORT Length; 3697 HANDLE HandleArray[2]; 3698 BOOLEAN Recursing = TRUE; 3699 PWCHAR pp, p, p1; 3700 UNICODE_STRING KeyString; 3701 NTSTATUS Status = STATUS_SUCCESS; 3702 PAGED_CODE(); 3703 3704 /* P1 is start, pp is end */ 3705 p1 = KeyName->Buffer; 3706 pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length); 3707 3708 /* Create the target key */ 3709 InitializeObjectAttributes(&ObjectAttributes, 3710 KeyName, 3711 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 3712 RootHandle, 3713 NULL); 3714 Status = ZwCreateKey(&HandleArray[i], 3715 DesiredAccess, 3716 &ObjectAttributes, 3717 0, 3718 NULL, 3719 CreateOptions, 3720 &KeyDisposition); 3721 3722 /* Now we check if this failed */ 3723 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle)) 3724 { 3725 /* Target key failed, so we'll need to create its parent. Setup array */ 3726 HandleArray[0] = NULL; 3727 HandleArray[1] = RootHandle; 3728 3729 /* Keep recursing for each missing parent */ 3730 while (Recursing) 3731 { 3732 /* And if we're deep enough, close the last handle */ 3733 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]); 3734 3735 /* We're setup to ping-pong between the two handle array entries */ 3736 RootHandleIndex = i; 3737 i = (i + 1) & 1; 3738 3739 /* Clear the one we're attempting to open now */ 3740 HandleArray[i] = NULL; 3741 3742 /* Process the parent key name */ 3743 for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++); 3744 Length = (USHORT)(p - p1) * sizeof(WCHAR); 3745 3746 /* Is there a parent name? */ 3747 if (Length) 3748 { 3749 /* Build the unicode string for it */ 3750 KeyString.Buffer = p1; 3751 KeyString.Length = KeyString.MaximumLength = Length; 3752 3753 /* Now try opening the parent */ 3754 InitializeObjectAttributes(&ObjectAttributes, 3755 &KeyString, 3756 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 3757 HandleArray[RootHandleIndex], 3758 NULL); 3759 Status = ZwCreateKey(&HandleArray[i], 3760 DesiredAccess, 3761 &ObjectAttributes, 3762 0, 3763 NULL, 3764 CreateOptions, 3765 &KeyDisposition); 3766 if (NT_SUCCESS(Status)) 3767 { 3768 /* It worked, we have one more handle */ 3769 NestedCloseLevel++; 3770 } 3771 else 3772 { 3773 /* Parent key creation failed, abandon loop */ 3774 Recursing = FALSE; 3775 continue; 3776 } 3777 } 3778 else 3779 { 3780 /* We don't have a parent name, probably corrupted key name */ 3781 Status = STATUS_INVALID_PARAMETER; 3782 Recursing = FALSE; 3783 continue; 3784 } 3785 3786 /* Now see if there's more parents to create */ 3787 p1 = p + 1; 3788 if ((p == pp) || (p1 == pp)) 3789 { 3790 /* We're done, hopefully successfully, so stop */ 3791 Recursing = FALSE; 3792 } 3793 } 3794 3795 /* Outer loop check for handle nesting that requires closing the top handle */ 3796 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]); 3797 } 3798 3799 /* Check if we broke out of the loop due to success */ 3800 if (NT_SUCCESS(Status)) 3801 { 3802 /* Return the target handle (we closed all the parent ones) and disposition */ 3803 *Handle = HandleArray[i]; 3804 if (Disposition) *Disposition = KeyDisposition; 3805 } 3806 3807 /* Return the success state */ 3808 return Status; 3809 } 3810 3811 NTSTATUS 3812 NTAPI 3813 IopGetRegistryValue(IN HANDLE Handle, 3814 IN PWSTR ValueName, 3815 OUT PKEY_VALUE_FULL_INFORMATION *Information) 3816 { 3817 UNICODE_STRING ValueString; 3818 NTSTATUS Status; 3819 PKEY_VALUE_FULL_INFORMATION FullInformation; 3820 ULONG Size; 3821 PAGED_CODE(); 3822 3823 RtlInitUnicodeString(&ValueString, ValueName); 3824 3825 Status = ZwQueryValueKey(Handle, 3826 &ValueString, 3827 KeyValueFullInformation, 3828 NULL, 3829 0, 3830 &Size); 3831 if ((Status != STATUS_BUFFER_OVERFLOW) && 3832 (Status != STATUS_BUFFER_TOO_SMALL)) 3833 { 3834 return Status; 3835 } 3836 3837 FullInformation = ExAllocatePool(NonPagedPool, Size); 3838 if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES; 3839 3840 Status = ZwQueryValueKey(Handle, 3841 &ValueString, 3842 KeyValueFullInformation, 3843 FullInformation, 3844 Size, 3845 &Size); 3846 if (!NT_SUCCESS(Status)) 3847 { 3848 ExFreePool(FullInformation); 3849 return Status; 3850 } 3851 3852 *Information = FullInformation; 3853 return STATUS_SUCCESS; 3854 } 3855 3856 RTL_GENERIC_COMPARE_RESULTS 3857 NTAPI 3858 PiCompareInstancePath(IN PRTL_AVL_TABLE Table, 3859 IN PVOID FirstStruct, 3860 IN PVOID SecondStruct) 3861 { 3862 /* FIXME: TODO */ 3863 ASSERT(FALSE); 3864 return 0; 3865 } 3866 3867 // 3868 // The allocation function is called by the generic table package whenever 3869 // it needs to allocate memory for the table. 3870 // 3871 3872 PVOID 3873 NTAPI 3874 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table, 3875 IN CLONG ByteSize) 3876 { 3877 /* FIXME: TODO */ 3878 ASSERT(FALSE); 3879 return NULL; 3880 } 3881 3882 VOID 3883 NTAPI 3884 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table, 3885 IN PVOID Buffer) 3886 { 3887 /* FIXME: TODO */ 3888 ASSERT(FALSE); 3889 } 3890 3891 VOID 3892 NTAPI 3893 PpInitializeDeviceReferenceTable(VOID) 3894 { 3895 /* Setup the guarded mutex and AVL table */ 3896 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock); 3897 RtlInitializeGenericTableAvl( 3898 &PpDeviceReferenceTable, 3899 (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath, 3900 (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry, 3901 (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry, 3902 NULL); 3903 } 3904 3905 BOOLEAN 3906 NTAPI 3907 PiInitPhase0(VOID) 3908 { 3909 /* Initialize the resource when accessing device registry data */ 3910 ExInitializeResourceLite(&PpRegistryDeviceResource); 3911 3912 /* Setup the device reference AVL table */ 3913 PpInitializeDeviceReferenceTable(); 3914 return TRUE; 3915 } 3916 3917 BOOLEAN 3918 NTAPI 3919 PpInitSystem(VOID) 3920 { 3921 /* Check the initialization phase */ 3922 switch (ExpInitializationPhase) 3923 { 3924 case 0: 3925 3926 /* Do Phase 0 */ 3927 return PiInitPhase0(); 3928 3929 case 1: 3930 3931 /* Do Phase 1 */ 3932 return TRUE; 3933 //return PiInitPhase1(); 3934 3935 default: 3936 3937 /* Don't know any other phase! Bugcheck! */ 3938 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL); 3939 return FALSE; 3940 } 3941 } 3942 3943 LONG IopNumberDeviceNodes; 3944 3945 PDEVICE_NODE 3946 NTAPI 3947 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject) 3948 { 3949 PDEVICE_NODE DeviceNode; 3950 PAGED_CODE(); 3951 3952 /* Allocate it */ 3953 DeviceNode = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_NODE), TAG_IO_DEVNODE); 3954 if (!DeviceNode) return DeviceNode; 3955 3956 /* Statistics */ 3957 InterlockedIncrement(&IopNumberDeviceNodes); 3958 3959 /* Set it up */ 3960 RtlZeroMemory(DeviceNode, sizeof(DEVICE_NODE)); 3961 DeviceNode->InterfaceType = InterfaceTypeUndefined; 3962 DeviceNode->BusNumber = -1; 3963 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined; 3964 DeviceNode->ChildBusNumber = -1; 3965 DeviceNode->ChildBusTypeIndex = -1; 3966 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE); 3967 InitializeListHead(&DeviceNode->DeviceArbiterList); 3968 InitializeListHead(&DeviceNode->DeviceTranslatorList); 3969 InitializeListHead(&DeviceNode->TargetDeviceNotify); 3970 InitializeListHead(&DeviceNode->DockInfo.ListEntry); 3971 InitializeListHead(&DeviceNode->PendedSetInterfaceState); 3972 3973 /* Check if there is a PDO */ 3974 if (PhysicalDeviceObject) 3975 { 3976 /* Link it and remove the init flag */ 3977 DeviceNode->PhysicalDeviceObject = PhysicalDeviceObject; 3978 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = DeviceNode; 3979 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 3980 } 3981 3982 /* Return the node */ 3983 return DeviceNode; 3984 } 3985 3986 /* PUBLIC FUNCTIONS **********************************************************/ 3987 3988 NTSTATUS 3989 NTAPI 3990 PnpBusTypeGuidGet(IN USHORT Index, 3991 IN LPGUID BusTypeGuid) 3992 { 3993 NTSTATUS Status = STATUS_SUCCESS; 3994 3995 /* Acquire the lock */ 3996 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock); 3997 3998 /* Validate size */ 3999 if (Index < PnpBusTypeGuidList->GuidCount) 4000 { 4001 /* Copy the data */ 4002 RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID)); 4003 } 4004 else 4005 { 4006 /* Failure path */ 4007 Status = STATUS_OBJECT_NAME_NOT_FOUND; 4008 } 4009 4010 /* Release lock and return status */ 4011 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock); 4012 return Status; 4013 } 4014 4015 NTSTATUS 4016 NTAPI 4017 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject, 4018 IN PHANDLE DeviceInstanceHandle, 4019 IN ACCESS_MASK DesiredAccess) 4020 { 4021 NTSTATUS Status; 4022 HANDLE KeyHandle; 4023 PDEVICE_NODE DeviceNode; 4024 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM"); 4025 PAGED_CODE(); 4026 4027 /* Open the enum key */ 4028 Status = IopOpenRegistryKeyEx(&KeyHandle, 4029 NULL, 4030 &KeyName, 4031 KEY_READ); 4032 if (!NT_SUCCESS(Status)) return Status; 4033 4034 /* Make sure we have an instance path */ 4035 DeviceNode = IopGetDeviceNode(DeviceObject); 4036 if ((DeviceNode) && (DeviceNode->InstancePath.Length)) 4037 { 4038 /* Get the instance key */ 4039 Status = IopOpenRegistryKeyEx(DeviceInstanceHandle, 4040 KeyHandle, 4041 &DeviceNode->InstancePath, 4042 DesiredAccess); 4043 } 4044 else 4045 { 4046 /* Fail */ 4047 Status = STATUS_INVALID_DEVICE_REQUEST; 4048 } 4049 4050 /* Close the handle and return status */ 4051 ZwClose(KeyHandle); 4052 return Status; 4053 } 4054 4055 ULONG 4056 NTAPI 4057 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList) 4058 { 4059 ULONG FinalSize, PartialSize, EntrySize, i, j; 4060 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor; 4061 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; 4062 4063 /* If we don't have one, that's easy */ 4064 if (!ResourceList) return 0; 4065 4066 /* Start with the minimum size possible */ 4067 FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List); 4068 4069 /* Loop each full descriptor */ 4070 FullDescriptor = ResourceList->List; 4071 for (i = 0; i < ResourceList->Count; i++) 4072 { 4073 /* Start with the minimum size possible */ 4074 PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) + 4075 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors); 4076 4077 /* Loop each partial descriptor */ 4078 PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors; 4079 for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++) 4080 { 4081 /* Start with the minimum size possible */ 4082 EntrySize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR); 4083 4084 /* Check if there is extra data */ 4085 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific) 4086 { 4087 /* Add that data */ 4088 EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize; 4089 } 4090 4091 /* The size of partial descriptors is bigger */ 4092 PartialSize += EntrySize; 4093 4094 /* Go to the next partial descriptor */ 4095 PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize); 4096 } 4097 4098 /* The size of full descriptors is bigger */ 4099 FinalSize += PartialSize; 4100 4101 /* Go to the next full descriptor */ 4102 FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize); 4103 } 4104 4105 /* Return the final size */ 4106 return FinalSize; 4107 } 4108 4109 NTSTATUS 4110 NTAPI 4111 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject, 4112 IN ULONG ValueType, 4113 IN PWSTR ValueName, 4114 IN PWSTR KeyName, 4115 OUT PVOID Buffer, 4116 IN PULONG BufferLength) 4117 { 4118 NTSTATUS Status; 4119 HANDLE KeyHandle, SubHandle; 4120 UNICODE_STRING KeyString; 4121 PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL; 4122 ULONG Length; 4123 PAGED_CODE(); 4124 4125 /* Find the instance key */ 4126 Status = PnpDeviceObjectToDeviceInstance(DeviceObject, &KeyHandle, KEY_READ); 4127 if (NT_SUCCESS(Status)) 4128 { 4129 /* Check for name given by caller */ 4130 if (KeyName) 4131 { 4132 /* Open this key */ 4133 RtlInitUnicodeString(&KeyString, KeyName); 4134 Status = IopOpenRegistryKeyEx(&SubHandle, 4135 KeyHandle, 4136 &KeyString, 4137 KEY_READ); 4138 if (NT_SUCCESS(Status)) 4139 { 4140 /* And use this handle instead */ 4141 ZwClose(KeyHandle); 4142 KeyHandle = SubHandle; 4143 } 4144 } 4145 4146 /* Check if sub-key handle succeeded (or no-op if no key name given) */ 4147 if (NT_SUCCESS(Status)) 4148 { 4149 /* Now get the size of the property */ 4150 Status = IopGetRegistryValue(KeyHandle, 4151 ValueName, 4152 &KeyValueInfo); 4153 } 4154 4155 /* Close the key */ 4156 ZwClose(KeyHandle); 4157 } 4158 4159 /* Fail if any of the registry operations failed */ 4160 if (!NT_SUCCESS(Status)) return Status; 4161 4162 /* Check how much data we have to copy */ 4163 Length = KeyValueInfo->DataLength; 4164 if (*BufferLength >= Length) 4165 { 4166 /* Check for a match in the value type */ 4167 if (KeyValueInfo->Type == ValueType) 4168 { 4169 /* Copy the data */ 4170 RtlCopyMemory(Buffer, 4171 (PVOID)((ULONG_PTR)KeyValueInfo + 4172 KeyValueInfo->DataOffset), 4173 Length); 4174 } 4175 else 4176 { 4177 /* Invalid registry property type, fail */ 4178 Status = STATUS_INVALID_PARAMETER_2; 4179 } 4180 } 4181 else 4182 { 4183 /* Buffer is too small to hold data */ 4184 Status = STATUS_BUFFER_TOO_SMALL; 4185 } 4186 4187 /* Return the required buffer length, free the buffer, and return status */ 4188 *BufferLength = Length; 4189 ExFreePool(KeyValueInfo); 4190 return Status; 4191 } 4192 4193 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;} 4194 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;} 4195 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED_DBGBREAK(); break;} 4196 4197 /* 4198 * @implemented 4199 */ 4200 NTSTATUS 4201 NTAPI 4202 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject, 4203 IN DEVICE_REGISTRY_PROPERTY DeviceProperty, 4204 IN ULONG BufferLength, 4205 OUT PVOID PropertyBuffer, 4206 OUT PULONG ResultLength) 4207 { 4208 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 4209 DEVICE_CAPABILITIES DeviceCaps; 4210 ULONG ReturnLength = 0, Length = 0, ValueType; 4211 PWCHAR ValueName = NULL, EnumeratorNameEnd, DeviceInstanceName; 4212 PVOID Data = NULL; 4213 NTSTATUS Status = STATUS_BUFFER_TOO_SMALL; 4214 GUID BusTypeGuid; 4215 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL; 4216 BOOLEAN NullTerminate = FALSE; 4217 4218 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty); 4219 4220 /* Assume failure */ 4221 *ResultLength = 0; 4222 4223 /* Only PDOs can call this */ 4224 if (!DeviceNode) return STATUS_INVALID_DEVICE_REQUEST; 4225 4226 /* Handle all properties */ 4227 switch (DeviceProperty) 4228 { 4229 case DevicePropertyBusTypeGuid: 4230 4231 /* Get the GUID from the internal cache */ 4232 Status = PnpBusTypeGuidGet(DeviceNode->ChildBusTypeIndex, &BusTypeGuid); 4233 if (!NT_SUCCESS(Status)) return Status; 4234 4235 /* This is the format of the returned data */ 4236 PIP_RETURN_DATA(sizeof(GUID), &BusTypeGuid); 4237 4238 case DevicePropertyLegacyBusType: 4239 4240 /* Validate correct interface type */ 4241 if (DeviceNode->ChildInterfaceType == InterfaceTypeUndefined) 4242 return STATUS_OBJECT_NAME_NOT_FOUND; 4243 4244 /* This is the format of the returned data */ 4245 PIP_RETURN_DATA(sizeof(INTERFACE_TYPE), &DeviceNode->ChildInterfaceType); 4246 4247 case DevicePropertyBusNumber: 4248 4249 /* Validate correct bus number */ 4250 if ((DeviceNode->ChildBusNumber & 0x80000000) == 0x80000000) 4251 return STATUS_OBJECT_NAME_NOT_FOUND; 4252 4253 /* This is the format of the returned data */ 4254 PIP_RETURN_DATA(sizeof(ULONG), &DeviceNode->ChildBusNumber); 4255 4256 case DevicePropertyEnumeratorName: 4257 4258 /* Get the instance path */ 4259 DeviceInstanceName = DeviceNode->InstancePath.Buffer; 4260 4261 /* Sanity checks */ 4262 ASSERT((BufferLength & 1) == 0); 4263 ASSERT(DeviceInstanceName != NULL); 4264 4265 /* Get the name from the path */ 4266 EnumeratorNameEnd = wcschr(DeviceInstanceName, OBJ_NAME_PATH_SEPARATOR); 4267 ASSERT(EnumeratorNameEnd); 4268 4269 /* This string needs to be NULL-terminated */ 4270 NullTerminate = TRUE; 4271 4272 /* This is the format of the returned data */ 4273 PIP_RETURN_DATA((ULONG)(EnumeratorNameEnd - DeviceInstanceName) * sizeof(WCHAR), 4274 DeviceInstanceName); 4275 4276 case DevicePropertyAddress: 4277 4278 /* Query the device caps */ 4279 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps); 4280 if (!NT_SUCCESS(Status) || (DeviceCaps.Address == MAXULONG)) 4281 return STATUS_OBJECT_NAME_NOT_FOUND; 4282 4283 /* This is the format of the returned data */ 4284 PIP_RETURN_DATA(sizeof(ULONG), &DeviceCaps.Address); 4285 4286 case DevicePropertyBootConfigurationTranslated: 4287 4288 /* Validate we have resources */ 4289 if (!DeviceNode->BootResources) 4290 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field 4291 { 4292 /* No resources will still fake success, but with 0 bytes */ 4293 *ResultLength = 0; 4294 return STATUS_SUCCESS; 4295 } 4296 4297 /* This is the format of the returned data */ 4298 PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode->BootResources), // FIXFIX: Should use BootResourcesTranslated 4299 DeviceNode->BootResources); // FIXFIX: Should use BootResourcesTranslated 4300 4301 case DevicePropertyPhysicalDeviceObjectName: 4302 4303 /* Sanity check for Unicode-sized string */ 4304 ASSERT((BufferLength & 1) == 0); 4305 4306 /* Allocate name buffer */ 4307 Length = BufferLength + sizeof(OBJECT_NAME_INFORMATION); 4308 ObjectNameInfo = ExAllocatePool(PagedPool, Length); 4309 if (!ObjectNameInfo) return STATUS_INSUFFICIENT_RESOURCES; 4310 4311 /* Query the PDO name */ 4312 Status = ObQueryNameString(DeviceObject, 4313 ObjectNameInfo, 4314 Length, 4315 ResultLength); 4316 if (Status == STATUS_INFO_LENGTH_MISMATCH) 4317 { 4318 /* It's up to the caller to try again */ 4319 Status = STATUS_BUFFER_TOO_SMALL; 4320 } 4321 4322 /* This string needs to be NULL-terminated */ 4323 NullTerminate = TRUE; 4324 4325 /* Return if successful */ 4326 if (NT_SUCCESS(Status)) PIP_RETURN_DATA(ObjectNameInfo->Name.Length, 4327 ObjectNameInfo->Name.Buffer); 4328 4329 /* Let the caller know how big the name is */ 4330 *ResultLength -= sizeof(OBJECT_NAME_INFORMATION); 4331 break; 4332 4333 case DevicePropertyRemovalPolicy: 4334 PIP_RETURN_DATA(sizeof(UCHAR), &DeviceNode->RemovalPolicy); 4335 4336 /* Handle the registry-based properties */ 4337 case DevicePropertyUINumber: 4338 PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER, REG_DWORD); 4339 case DevicePropertyLocationInformation: 4340 PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION, REG_SZ); 4341 case DevicePropertyDeviceDescription: 4342 PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC, REG_SZ); 4343 case DevicePropertyHardwareID: 4344 PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID, REG_MULTI_SZ); 4345 case DevicePropertyCompatibleIDs: 4346 PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS, REG_MULTI_SZ); 4347 case DevicePropertyBootConfiguration: 4348 PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG, REG_RESOURCE_LIST); 4349 case DevicePropertyClassName: 4350 PIP_REGISTRY_DATA(REGSTR_VAL_CLASS, REG_SZ); 4351 case DevicePropertyClassGuid: 4352 PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID, REG_SZ); 4353 case DevicePropertyDriverKeyName: 4354 PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER, REG_SZ); 4355 case DevicePropertyManufacturer: 4356 PIP_REGISTRY_DATA(REGSTR_VAL_MFG, REG_SZ); 4357 case DevicePropertyFriendlyName: 4358 PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME, REG_SZ); 4359 case DevicePropertyContainerID: 4360 //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7 4361 PIP_UNIMPLEMENTED(); 4362 break; 4363 case DevicePropertyInstallState: 4364 PIP_REGISTRY_DATA(REGSTR_VAL_CONFIGFLAGS, REG_DWORD); 4365 break; 4366 case DevicePropertyResourceRequirements: 4367 PIP_UNIMPLEMENTED(); 4368 case DevicePropertyAllocatedResources: 4369 PIP_UNIMPLEMENTED(); 4370 default: 4371 return STATUS_INVALID_PARAMETER_2; 4372 } 4373 4374 /* Having a registry value name implies registry data */ 4375 if (ValueName) 4376 { 4377 /* We know up-front how much data to expect */ 4378 *ResultLength = BufferLength; 4379 4380 /* Go get the data, use the LogConf subkey if necessary */ 4381 Status = PiGetDeviceRegistryProperty(DeviceObject, 4382 ValueType, 4383 ValueName, 4384 (DeviceProperty == 4385 DevicePropertyBootConfiguration) ? 4386 L"LogConf": NULL, 4387 PropertyBuffer, 4388 ResultLength); 4389 } 4390 else if (NT_SUCCESS(Status)) 4391 { 4392 /* We know up-front how much data to expect, check the caller's buffer */ 4393 *ResultLength = ReturnLength + (NullTerminate ? sizeof(UNICODE_NULL) : 0); 4394 if (*ResultLength <= BufferLength) 4395 { 4396 /* Buffer is all good, copy the data */ 4397 RtlCopyMemory(PropertyBuffer, Data, ReturnLength); 4398 4399 /* Check if we need to NULL-terminate the string */ 4400 if (NullTerminate) 4401 { 4402 /* Terminate the string */ 4403 ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL; 4404 } 4405 4406 /* This is the success path */ 4407 Status = STATUS_SUCCESS; 4408 } 4409 else 4410 { 4411 /* Failure path */ 4412 Status = STATUS_BUFFER_TOO_SMALL; 4413 } 4414 } 4415 4416 /* Free any allocation we may have made, and return the status code */ 4417 if (ObjectNameInfo) ExFreePool(ObjectNameInfo); 4418 return Status; 4419 } 4420 4421 /* 4422 * @implemented 4423 */ 4424 VOID 4425 NTAPI 4426 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject) 4427 { 4428 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject); 4429 IO_STACK_LOCATION Stack; 4430 ULONG PnPFlags; 4431 NTSTATUS Status; 4432 IO_STATUS_BLOCK IoStatusBlock; 4433 4434 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 4435 Stack.MajorFunction = IRP_MJ_PNP; 4436 Stack.MinorFunction = IRP_MN_QUERY_PNP_DEVICE_STATE; 4437 4438 Status = IopSynchronousCall(PhysicalDeviceObject, &Stack, (PVOID*)&PnPFlags); 4439 if (!NT_SUCCESS(Status)) 4440 { 4441 if (Status != STATUS_NOT_SUPPORTED) 4442 { 4443 DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%lx\n", Status); 4444 } 4445 return; 4446 } 4447 4448 if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE) 4449 DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE; 4450 else 4451 DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE; 4452 4453 if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI) 4454 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI; 4455 else 4456 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI; 4457 4458 if ((PnPFlags & PNP_DEVICE_REMOVED) || 4459 ((PnPFlags & PNP_DEVICE_FAILED) && !(PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED))) 4460 { 4461 /* Flag it if it's failed */ 4462 if (PnPFlags & PNP_DEVICE_FAILED) DeviceNode->Problem = CM_PROB_FAILED_POST_START; 4463 4464 /* Send removal IRPs to all of its children */ 4465 IopPrepareDeviceForRemoval(PhysicalDeviceObject, TRUE); 4466 4467 /* Send surprise removal */ 4468 IopSendSurpriseRemoval(PhysicalDeviceObject); 4469 4470 /* Tell the user-mode PnP manager that a device was removed */ 4471 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL, 4472 &DeviceNode->InstancePath); 4473 4474 IopSendRemoveDevice(PhysicalDeviceObject); 4475 } 4476 else if ((PnPFlags & PNP_DEVICE_FAILED) && (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)) 4477 { 4478 /* Stop for resource rebalance */ 4479 Status = IopStopDevice(DeviceNode); 4480 if (!NT_SUCCESS(Status)) 4481 { 4482 DPRINT1("Failed to stop device for rebalancing\n"); 4483 4484 /* Stop failed so don't rebalance */ 4485 PnPFlags &= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED; 4486 } 4487 } 4488 4489 /* Resource rebalance */ 4490 if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED) 4491 { 4492 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n"); 4493 4494 Status = IopInitiatePnpIrp(PhysicalDeviceObject, 4495 &IoStatusBlock, 4496 IRP_MN_QUERY_RESOURCES, 4497 NULL); 4498 if (NT_SUCCESS(Status) && IoStatusBlock.Information) 4499 { 4500 DeviceNode->BootResources = 4501 (PCM_RESOURCE_LIST)IoStatusBlock.Information; 4502 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG); 4503 } 4504 else 4505 { 4506 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); 4507 DeviceNode->BootResources = NULL; 4508 } 4509 4510 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n"); 4511 4512 Status = IopInitiatePnpIrp(PhysicalDeviceObject, 4513 &IoStatusBlock, 4514 IRP_MN_QUERY_RESOURCE_REQUIREMENTS, 4515 NULL); 4516 if (NT_SUCCESS(Status)) 4517 { 4518 DeviceNode->ResourceRequirements = 4519 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information; 4520 } 4521 else 4522 { 4523 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status); 4524 DeviceNode->ResourceRequirements = NULL; 4525 } 4526 4527 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */ 4528 if (IopStartDevice(DeviceNode) != STATUS_SUCCESS) 4529 { 4530 DPRINT1("Restart after resource rebalance failed\n"); 4531 4532 DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING); 4533 DeviceNode->Flags |= DNF_START_FAILED; 4534 4535 IopRemoveDevice(DeviceNode); 4536 } 4537 } 4538 } 4539 4540 /** 4541 * @name IoOpenDeviceRegistryKey 4542 * 4543 * Open a registry key unique for a specified driver or device instance. 4544 * 4545 * @param DeviceObject Device to get the registry key for. 4546 * @param DevInstKeyType Type of the key to return. 4547 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE). 4548 * @param DevInstRegKey Handle to the opened registry key on 4549 * successful return. 4550 * 4551 * @return Status. 4552 * 4553 * @implemented 4554 */ 4555 NTSTATUS 4556 NTAPI 4557 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject, 4558 IN ULONG DevInstKeyType, 4559 IN ACCESS_MASK DesiredAccess, 4560 OUT PHANDLE DevInstRegKey) 4561 { 4562 static WCHAR RootKeyName[] = 4563 L"\\Registry\\Machine\\System\\CurrentControlSet\\"; 4564 static WCHAR ProfileKeyName[] = 4565 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\"; 4566 static WCHAR ClassKeyName[] = L"Control\\Class\\"; 4567 static WCHAR EnumKeyName[] = L"Enum\\"; 4568 static WCHAR DeviceParametersKeyName[] = L"Device Parameters"; 4569 ULONG KeyNameLength; 4570 PWSTR KeyNameBuffer; 4571 UNICODE_STRING KeyName; 4572 ULONG DriverKeyLength; 4573 OBJECT_ATTRIBUTES ObjectAttributes; 4574 PDEVICE_NODE DeviceNode = NULL; 4575 NTSTATUS Status; 4576 4577 DPRINT("IoOpenDeviceRegistryKey() called\n"); 4578 4579 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0) 4580 { 4581 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n"); 4582 return STATUS_INVALID_PARAMETER; 4583 } 4584 4585 if (!IopIsValidPhysicalDeviceObject(DeviceObject)) 4586 return STATUS_INVALID_DEVICE_REQUEST; 4587 DeviceNode = IopGetDeviceNode(DeviceObject); 4588 4589 /* 4590 * Calculate the length of the base key name. This is the full 4591 * name for driver key or the name excluding "Device Parameters" 4592 * subkey for device key. 4593 */ 4594 4595 KeyNameLength = sizeof(RootKeyName); 4596 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE) 4597 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL); 4598 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER) 4599 { 4600 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL); 4601 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName, 4602 0, NULL, &DriverKeyLength); 4603 if (Status != STATUS_BUFFER_TOO_SMALL) 4604 return Status; 4605 KeyNameLength += DriverKeyLength; 4606 } 4607 else 4608 { 4609 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) + 4610 DeviceNode->InstancePath.Length; 4611 } 4612 4613 /* 4614 * Now allocate the buffer for the key name... 4615 */ 4616 4617 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength); 4618 if (KeyNameBuffer == NULL) 4619 return STATUS_INSUFFICIENT_RESOURCES; 4620 4621 KeyName.Length = 0; 4622 KeyName.MaximumLength = (USHORT)KeyNameLength; 4623 KeyName.Buffer = KeyNameBuffer; 4624 4625 /* 4626 * ...and build the key name. 4627 */ 4628 4629 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL); 4630 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length); 4631 4632 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE) 4633 RtlAppendUnicodeToString(&KeyName, ProfileKeyName); 4634 4635 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER) 4636 { 4637 RtlAppendUnicodeToString(&KeyName, ClassKeyName); 4638 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName, 4639 DriverKeyLength, KeyNameBuffer + 4640 (KeyName.Length / sizeof(WCHAR)), 4641 &DriverKeyLength); 4642 if (!NT_SUCCESS(Status)) 4643 { 4644 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status); 4645 ExFreePool(KeyNameBuffer); 4646 return Status; 4647 } 4648 KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL); 4649 } 4650 else 4651 { 4652 RtlAppendUnicodeToString(&KeyName, EnumKeyName); 4653 Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath); 4654 if (DeviceNode->InstancePath.Length == 0) 4655 { 4656 ExFreePool(KeyNameBuffer); 4657 return Status; 4658 } 4659 } 4660 4661 /* 4662 * Open the base key. 4663 */ 4664 Status = IopOpenRegistryKeyEx(DevInstRegKey, NULL, &KeyName, DesiredAccess); 4665 if (!NT_SUCCESS(Status)) 4666 { 4667 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status); 4668 ExFreePool(KeyNameBuffer); 4669 return Status; 4670 } 4671 ExFreePool(KeyNameBuffer); 4672 4673 /* 4674 * For driver key we're done now. 4675 */ 4676 4677 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER) 4678 return Status; 4679 4680 /* 4681 * Let's go further. For device key we must open "Device Parameters" 4682 * subkey and create it if it doesn't exist yet. 4683 */ 4684 4685 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName); 4686 InitializeObjectAttributes(&ObjectAttributes, 4687 &KeyName, 4688 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 4689 *DevInstRegKey, 4690 NULL); 4691 Status = ZwCreateKey(DevInstRegKey, 4692 DesiredAccess, 4693 &ObjectAttributes, 4694 0, 4695 NULL, 4696 REG_OPTION_NON_VOLATILE, 4697 NULL); 4698 ZwClose(ObjectAttributes.RootDirectory); 4699 4700 return Status; 4701 } 4702 4703 static 4704 NTSTATUS 4705 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode, BOOLEAN Force) 4706 { 4707 PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice; 4708 NTSTATUS Status; 4709 KIRQL OldIrql; 4710 4711 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4712 ChildDeviceNode = ParentDeviceNode->Child; 4713 while (ChildDeviceNode != NULL) 4714 { 4715 NextDeviceNode = ChildDeviceNode->Sibling; 4716 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4717 4718 Status = IopPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject, Force); 4719 if (!NT_SUCCESS(Status)) 4720 { 4721 FailedRemoveDevice = ChildDeviceNode; 4722 goto cleanup; 4723 } 4724 4725 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4726 ChildDeviceNode = NextDeviceNode; 4727 } 4728 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4729 4730 return STATUS_SUCCESS; 4731 4732 cleanup: 4733 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4734 ChildDeviceNode = ParentDeviceNode->Child; 4735 while (ChildDeviceNode != NULL) 4736 { 4737 NextDeviceNode = ChildDeviceNode->Sibling; 4738 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4739 4740 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject); 4741 4742 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device 4743 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */ 4744 if (ChildDeviceNode == FailedRemoveDevice) 4745 return Status; 4746 4747 ChildDeviceNode = NextDeviceNode; 4748 4749 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4750 } 4751 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4752 4753 return Status; 4754 } 4755 4756 static 4757 VOID 4758 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode) 4759 { 4760 PDEVICE_NODE ChildDeviceNode, NextDeviceNode; 4761 KIRQL OldIrql; 4762 4763 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4764 ChildDeviceNode = ParentDeviceNode->Child; 4765 while (ChildDeviceNode != NULL) 4766 { 4767 NextDeviceNode = ChildDeviceNode->Sibling; 4768 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4769 4770 IopSendRemoveDevice(ChildDeviceNode->PhysicalDeviceObject); 4771 4772 ChildDeviceNode = NextDeviceNode; 4773 4774 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4775 } 4776 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4777 } 4778 4779 static 4780 VOID 4781 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode) 4782 { 4783 PDEVICE_NODE ChildDeviceNode, NextDeviceNode; 4784 KIRQL OldIrql; 4785 4786 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4787 ChildDeviceNode = ParentDeviceNode->Child; 4788 while (ChildDeviceNode != NULL) 4789 { 4790 NextDeviceNode = ChildDeviceNode->Sibling; 4791 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4792 4793 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject); 4794 4795 ChildDeviceNode = NextDeviceNode; 4796 4797 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 4798 } 4799 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 4800 } 4801 4802 static 4803 NTSTATUS 4804 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations, BOOLEAN Force) 4805 { 4806 /* This function DOES NOT dereference the device objects on SUCCESS 4807 * but it DOES dereference device objects on FAILURE */ 4808 4809 ULONG i, j; 4810 NTSTATUS Status; 4811 4812 for (i = 0; i < DeviceRelations->Count; i++) 4813 { 4814 Status = IopPrepareDeviceForRemoval(DeviceRelations->Objects[i], Force); 4815 if (!NT_SUCCESS(Status)) 4816 { 4817 j = i; 4818 goto cleanup; 4819 } 4820 } 4821 4822 return STATUS_SUCCESS; 4823 4824 cleanup: 4825 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device 4826 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */ 4827 for (i = 0; i <= j; i++) 4828 { 4829 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]); 4830 ObDereferenceObject(DeviceRelations->Objects[i]); 4831 DeviceRelations->Objects[i] = NULL; 4832 } 4833 for (; i < DeviceRelations->Count; i++) 4834 { 4835 ObDereferenceObject(DeviceRelations->Objects[i]); 4836 DeviceRelations->Objects[i] = NULL; 4837 } 4838 ExFreePool(DeviceRelations); 4839 4840 return Status; 4841 } 4842 4843 static 4844 VOID 4845 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations) 4846 { 4847 /* This function DOES dereference the device objects in all cases */ 4848 4849 ULONG i; 4850 4851 for (i = 0; i < DeviceRelations->Count; i++) 4852 { 4853 IopSendRemoveDevice(DeviceRelations->Objects[i]); 4854 DeviceRelations->Objects[i] = NULL; 4855 } 4856 4857 ExFreePool(DeviceRelations); 4858 } 4859 4860 static 4861 VOID 4862 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations) 4863 { 4864 /* This function DOES dereference the device objects in all cases */ 4865 4866 ULONG i; 4867 4868 for (i = 0; i < DeviceRelations->Count; i++) 4869 { 4870 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]); 4871 ObDereferenceObject(DeviceRelations->Objects[i]); 4872 DeviceRelations->Objects[i] = NULL; 4873 } 4874 4875 ExFreePool(DeviceRelations); 4876 } 4877 4878 VOID 4879 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject) 4880 { 4881 IO_STACK_LOCATION Stack; 4882 IO_STATUS_BLOCK IoStatusBlock; 4883 PDEVICE_RELATIONS DeviceRelations; 4884 NTSTATUS Status; 4885 4886 IopCancelRemoveDevice(DeviceObject); 4887 4888 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations; 4889 4890 Status = IopInitiatePnpIrp(DeviceObject, 4891 &IoStatusBlock, 4892 IRP_MN_QUERY_DEVICE_RELATIONS, 4893 &Stack); 4894 if (!NT_SUCCESS(Status)) 4895 { 4896 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 4897 DeviceRelations = NULL; 4898 } 4899 else 4900 { 4901 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 4902 } 4903 4904 if (DeviceRelations) 4905 IopCancelRemoveDeviceRelations(DeviceRelations); 4906 } 4907 4908 NTSTATUS 4909 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject, BOOLEAN Force) 4910 { 4911 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 4912 IO_STACK_LOCATION Stack; 4913 IO_STATUS_BLOCK IoStatusBlock; 4914 PDEVICE_RELATIONS DeviceRelations; 4915 NTSTATUS Status; 4916 4917 if ((DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE) && !Force) 4918 { 4919 DPRINT1("Removal not allowed for %wZ\n", &DeviceNode->InstancePath); 4920 return STATUS_UNSUCCESSFUL; 4921 } 4922 4923 if (!Force && IopQueryRemoveDevice(DeviceObject) != STATUS_SUCCESS) 4924 { 4925 DPRINT1("Removal vetoed by failing the query remove request\n"); 4926 4927 IopCancelRemoveDevice(DeviceObject); 4928 4929 return STATUS_UNSUCCESSFUL; 4930 } 4931 4932 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations; 4933 4934 Status = IopInitiatePnpIrp(DeviceObject, 4935 &IoStatusBlock, 4936 IRP_MN_QUERY_DEVICE_RELATIONS, 4937 &Stack); 4938 if (!NT_SUCCESS(Status)) 4939 { 4940 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 4941 DeviceRelations = NULL; 4942 } 4943 else 4944 { 4945 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 4946 } 4947 4948 if (DeviceRelations) 4949 { 4950 Status = IopQueryRemoveDeviceRelations(DeviceRelations, Force); 4951 if (!NT_SUCCESS(Status)) 4952 return Status; 4953 } 4954 4955 Status = IopQueryRemoveChildDevices(DeviceNode, Force); 4956 if (!NT_SUCCESS(Status)) 4957 { 4958 if (DeviceRelations) 4959 IopCancelRemoveDeviceRelations(DeviceRelations); 4960 return Status; 4961 } 4962 4963 if (DeviceRelations) 4964 IopSendRemoveDeviceRelations(DeviceRelations); 4965 IopSendRemoveChildDevices(DeviceNode); 4966 4967 return STATUS_SUCCESS; 4968 } 4969 4970 NTSTATUS 4971 IopRemoveDevice(PDEVICE_NODE DeviceNode) 4972 { 4973 NTSTATUS Status; 4974 4975 DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath); 4976 4977 Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject, FALSE); 4978 if (NT_SUCCESS(Status)) 4979 { 4980 IopSendRemoveDevice(DeviceNode->PhysicalDeviceObject); 4981 IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL, 4982 &DeviceNode->InstancePath); 4983 return STATUS_SUCCESS; 4984 } 4985 4986 return Status; 4987 } 4988 4989 /* 4990 * @implemented 4991 */ 4992 VOID 4993 NTAPI 4994 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject) 4995 { 4996 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject); 4997 PDEVICE_RELATIONS DeviceRelations; 4998 IO_STATUS_BLOCK IoStatusBlock; 4999 IO_STACK_LOCATION Stack; 5000 DEVICE_CAPABILITIES Capabilities; 5001 NTSTATUS Status; 5002 5003 IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT, 5004 &DeviceNode->InstancePath); 5005 5006 if (IopQueryDeviceCapabilities(DeviceNode, &Capabilities) != STATUS_SUCCESS) 5007 { 5008 goto cleanup; 5009 } 5010 5011 Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations; 5012 5013 Status = IopInitiatePnpIrp(PhysicalDeviceObject, 5014 &IoStatusBlock, 5015 IRP_MN_QUERY_DEVICE_RELATIONS, 5016 &Stack); 5017 if (!NT_SUCCESS(Status)) 5018 { 5019 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 5020 DeviceRelations = NULL; 5021 } 5022 else 5023 { 5024 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 5025 } 5026 5027 if (DeviceRelations) 5028 { 5029 Status = IopQueryRemoveDeviceRelations(DeviceRelations, FALSE); 5030 if (!NT_SUCCESS(Status)) 5031 goto cleanup; 5032 } 5033 5034 Status = IopQueryRemoveChildDevices(DeviceNode, FALSE); 5035 if (!NT_SUCCESS(Status)) 5036 { 5037 if (DeviceRelations) 5038 IopCancelRemoveDeviceRelations(DeviceRelations); 5039 goto cleanup; 5040 } 5041 5042 if (IopPrepareDeviceForRemoval(PhysicalDeviceObject, FALSE) != STATUS_SUCCESS) 5043 { 5044 if (DeviceRelations) 5045 IopCancelRemoveDeviceRelations(DeviceRelations); 5046 IopCancelRemoveChildDevices(DeviceNode); 5047 goto cleanup; 5048 } 5049 5050 if (DeviceRelations) 5051 IopSendRemoveDeviceRelations(DeviceRelations); 5052 IopSendRemoveChildDevices(DeviceNode); 5053 5054 DeviceNode->Problem = CM_PROB_HELD_FOR_EJECT; 5055 if (Capabilities.EjectSupported) 5056 { 5057 if (IopSendEject(PhysicalDeviceObject) != STATUS_SUCCESS) 5058 { 5059 goto cleanup; 5060 } 5061 } 5062 else 5063 { 5064 DeviceNode->Flags |= DNF_DISABLED; 5065 } 5066 5067 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT, 5068 &DeviceNode->InstancePath); 5069 5070 return; 5071 5072 cleanup: 5073 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED, 5074 &DeviceNode->InstancePath); 5075 } 5076 5077 /* 5078 * @implemented 5079 */ 5080 VOID 5081 NTAPI 5082 IoInvalidateDeviceRelations( 5083 IN PDEVICE_OBJECT DeviceObject, 5084 IN DEVICE_RELATION_TYPE Type) 5085 { 5086 PDEVICE_ACTION_DATA Data; 5087 KIRQL OldIrql; 5088 5089 Data = ExAllocatePoolWithTag(NonPagedPool, 5090 sizeof(DEVICE_ACTION_DATA), 5091 TAG_IO); 5092 if (!Data) 5093 return; 5094 5095 ObReferenceObject(DeviceObject); 5096 Data->DeviceObject = DeviceObject; 5097 Data->Type = Type; 5098 5099 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql); 5100 InsertTailList(&IopDeviceActionRequestList, &Data->RequestListEntry); 5101 if (IopDeviceActionInProgress) 5102 { 5103 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); 5104 return; 5105 } 5106 IopDeviceActionInProgress = TRUE; 5107 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); 5108 5109 ExInitializeWorkItem(&IopDeviceActionWorkItem, 5110 IopDeviceActionWorker, 5111 NULL); 5112 ExQueueWorkItem(&IopDeviceActionWorkItem, 5113 DelayedWorkQueue); 5114 } 5115 5116 /* 5117 * @implemented 5118 */ 5119 NTSTATUS 5120 NTAPI 5121 IoSynchronousInvalidateDeviceRelations( 5122 IN PDEVICE_OBJECT DeviceObject, 5123 IN DEVICE_RELATION_TYPE Type) 5124 { 5125 PAGED_CODE(); 5126 5127 switch (Type) 5128 { 5129 case BusRelations: 5130 /* Enumerate the device */ 5131 return IopEnumerateDevice(DeviceObject); 5132 case PowerRelations: 5133 /* Not handled yet */ 5134 return STATUS_NOT_IMPLEMENTED; 5135 case TargetDeviceRelation: 5136 /* Nothing to do */ 5137 return STATUS_SUCCESS; 5138 default: 5139 /* Ejection relations are not supported */ 5140 return STATUS_NOT_SUPPORTED; 5141 } 5142 } 5143 5144 /* 5145 * @implemented 5146 */ 5147 BOOLEAN 5148 NTAPI 5149 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType, 5150 IN ULONG BusNumber, 5151 IN PHYSICAL_ADDRESS BusAddress, 5152 IN OUT PULONG AddressSpace, 5153 OUT PPHYSICAL_ADDRESS TranslatedAddress) 5154 { 5155 /* FIXME: Notify the resource arbiter */ 5156 5157 return HalTranslateBusAddress(InterfaceType, 5158 BusNumber, 5159 BusAddress, 5160 AddressSpace, 5161 TranslatedAddress); 5162 } 5163