1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: PnP manager device manipulation functions 5 * COPYRIGHT: Casper S. Hornstrup (chorns@users.sourceforge.net) 6 * 2007 Hervé Poussineau (hpoussin@reactos.org) 7 * 2014-2017 Thomas Faber (thomas.faber@reactos.org) 8 * 2020 Victor Perevertkin (victor.perevertkin@reactos.org) 9 */ 10 11 /* Device tree is a resource shared among all system services: hal, kernel, drivers etc. 12 * Thus all code which interacts with the tree needs to be synchronized. 13 * Here it's done via a list of DEVICE_ACTION_REQUEST structures, which represents 14 * the device action queue. It is being processed exclusively by the PipDeviceActionWorker. 15 * 16 * Operation queuing can be done with the PiQueueDeviceAction function or with 17 * the PiPerfomSyncDeviceAction for synchronous operations. 18 * All device manipulation like starting, removing, enumeration (see DEVICE_ACTION enum) 19 * have to be done with the PiQueueDeviceAction in order to avoid race conditions. 20 * 21 * Note: there is one special operation here - PiActionEnumRootDevices. It is meant to be done 22 * during initialization process (and be the first device tree operation executed) and 23 * is always executed synchronously. 24 */ 25 26 /* INCLUDES ******************************************************************/ 27 28 #include <ntoskrnl.h> 29 #define NDEBUG 30 #include <debug.h> 31 32 /* GLOBALS *******************************************************************/ 33 34 extern ERESOURCE IopDriverLoadResource; 35 extern BOOLEAN PnpSystemInit; 36 extern PDEVICE_NODE IopRootDeviceNode; 37 extern BOOLEAN PnPBootDriversLoaded; 38 extern BOOLEAN PnPBootDriversInitialized; 39 40 #define MAX_DEVICE_ID_LEN 200 41 #define MAX_SEPARATORS_INSTANCEID 0 42 #define MAX_SEPARATORS_DEVICEID 1 43 44 /* DATA **********************************************************************/ 45 46 LIST_ENTRY IopDeviceActionRequestList; 47 WORK_QUEUE_ITEM IopDeviceActionWorkItem; 48 BOOLEAN IopDeviceActionInProgress; 49 KSPIN_LOCK IopDeviceActionLock; 50 KEVENT PiEnumerationFinished; 51 static const WCHAR ServicesKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"; 52 53 /* TYPES *********************************************************************/ 54 55 typedef struct _DEVICE_ACTION_REQUEST 56 { 57 LIST_ENTRY RequestListEntry; 58 PDEVICE_OBJECT DeviceObject; 59 PKEVENT CompletionEvent; 60 NTSTATUS *CompletionStatus; 61 DEVICE_ACTION Action; 62 } DEVICE_ACTION_REQUEST, *PDEVICE_ACTION_REQUEST; 63 64 typedef enum _ADD_DEV_DRIVER_TYPE 65 { 66 LowerFilter, 67 LowerClassFilter, 68 DeviceDriver, 69 UpperFilter, 70 UpperClassFilter 71 } ADD_DEV_DRIVER_TYPE; 72 73 typedef struct _ADD_DEV_DRIVERS_LIST 74 { 75 LIST_ENTRY ListEntry; 76 PDRIVER_OBJECT DriverObject; 77 ADD_DEV_DRIVER_TYPE DriverType; 78 } ADD_DEV_DRIVERS_LIST, *PADD_DEV_DRIVERS_LIST; 79 80 typedef struct _ATTACH_FILTER_DRIVERS_CONTEXT 81 { 82 ADD_DEV_DRIVER_TYPE DriverType; 83 PDEVICE_NODE DeviceNode; 84 PLIST_ENTRY DriversListHead; 85 } ATTACH_FILTER_DRIVERS_CONTEXT, *PATTACH_FILTER_DRIVERS_CONTEXT; 86 87 /* FUNCTIONS *****************************************************************/ 88 89 PDEVICE_OBJECT 90 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance); 91 92 NTSTATUS 93 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode, PUNICODE_STRING ParentIdPrefix); 94 95 USHORT 96 NTAPI 97 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid); 98 99 NTSTATUS 100 IopSetDeviceInstanceData(HANDLE InstanceKey, PDEVICE_NODE DeviceNode); 101 102 VOID 103 NTAPI 104 IopInstallCriticalDevice(PDEVICE_NODE DeviceNode); 105 106 static 107 VOID 108 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject); 109 110 static 111 NTSTATUS 112 IopPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject, BOOLEAN Force); 113 114 static 115 NTSTATUS 116 IopSetServiceEnumData( 117 _In_ PDEVICE_NODE DeviceNode, 118 _In_ HANDLE InstanceHandle); 119 120 static 121 BOOLEAN 122 IopValidateID( 123 _In_ PWCHAR Id, 124 _In_ BUS_QUERY_ID_TYPE QueryType) 125 { 126 PWCHAR PtrChar; 127 PWCHAR StringEnd; 128 WCHAR Char; 129 ULONG SeparatorsCount = 0; 130 PWCHAR PtrPrevChar = NULL; 131 ULONG MaxSeparators; 132 BOOLEAN IsMultiSz; 133 134 PAGED_CODE(); 135 136 switch (QueryType) 137 { 138 case BusQueryDeviceID: 139 MaxSeparators = MAX_SEPARATORS_DEVICEID; 140 IsMultiSz = FALSE; 141 break; 142 case BusQueryInstanceID: 143 MaxSeparators = MAX_SEPARATORS_INSTANCEID; 144 IsMultiSz = FALSE; 145 break; 146 147 case BusQueryHardwareIDs: 148 case BusQueryCompatibleIDs: 149 MaxSeparators = MAX_SEPARATORS_DEVICEID; 150 IsMultiSz = TRUE; 151 break; 152 153 default: 154 DPRINT1("IopValidateID: Not handled QueryType - %x\n", QueryType); 155 return FALSE; 156 } 157 158 StringEnd = Id + MAX_DEVICE_ID_LEN; 159 160 for (PtrChar = Id; PtrChar < StringEnd; PtrChar++) 161 { 162 Char = *PtrChar; 163 164 if (Char == UNICODE_NULL) 165 { 166 if (!IsMultiSz || (PtrPrevChar && PtrChar == PtrPrevChar + 1)) 167 { 168 if (MaxSeparators == SeparatorsCount || IsMultiSz) 169 { 170 return TRUE; 171 } 172 173 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n", 174 SeparatorsCount, MaxSeparators); 175 goto ErrorExit; 176 } 177 178 StringEnd = PtrChar + MAX_DEVICE_ID_LEN + 1; 179 PtrPrevChar = PtrChar; 180 SeparatorsCount = 0; 181 } 182 else if (Char < ' ' || Char > 0x7F || Char == ',') 183 { 184 DPRINT1("IopValidateID: Invalid character - %04X\n", Char); 185 goto ErrorExit; 186 } 187 else if (Char == ' ') 188 { 189 *PtrChar = '_'; 190 } 191 else if (Char == '\\') 192 { 193 SeparatorsCount++; 194 195 if (SeparatorsCount > MaxSeparators) 196 { 197 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n", 198 SeparatorsCount, MaxSeparators); 199 goto ErrorExit; 200 } 201 } 202 } 203 204 DPRINT1("IopValidateID: Not terminated ID\n"); 205 206 ErrorExit: 207 // FIXME logging 208 return FALSE; 209 } 210 211 static 212 NTSTATUS 213 IopCreateDeviceInstancePath( 214 _In_ PDEVICE_NODE DeviceNode, 215 _Out_ PUNICODE_STRING InstancePath) 216 { 217 IO_STATUS_BLOCK IoStatusBlock; 218 UNICODE_STRING DeviceId; 219 UNICODE_STRING InstanceId; 220 IO_STACK_LOCATION Stack; 221 NTSTATUS Status; 222 UNICODE_STRING ParentIdPrefix = { 0, 0, NULL }; 223 DEVICE_CAPABILITIES DeviceCapabilities; 224 BOOLEAN IsValidID; 225 226 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n"); 227 228 Stack.Parameters.QueryId.IdType = BusQueryDeviceID; 229 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 230 &IoStatusBlock, 231 IRP_MN_QUERY_ID, 232 &Stack); 233 if (!NT_SUCCESS(Status)) 234 { 235 DPRINT1("IopInitiatePnpIrp(BusQueryDeviceID) failed (Status %x)\n", Status); 236 return Status; 237 } 238 239 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryDeviceID); 240 241 if (!IsValidID) 242 { 243 DPRINT1("Invalid DeviceID. DeviceNode - %p\n", DeviceNode); 244 } 245 246 /* Save the device id string */ 247 RtlInitUnicodeString(&DeviceId, (PWSTR)IoStatusBlock.Information); 248 249 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n"); 250 251 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities); 252 if (!NT_SUCCESS(Status)) 253 { 254 if (Status != STATUS_NOT_SUPPORTED) 255 { 256 DPRINT1("IopQueryDeviceCapabilities() failed (Status 0x%08lx)\n", Status); 257 } 258 RtlFreeUnicodeString(&DeviceId); 259 return Status; 260 } 261 262 /* This bit is only check after enumeration */ 263 if (DeviceCapabilities.HardwareDisabled) 264 { 265 /* FIXME: Cleanup device */ 266 RtlFreeUnicodeString(&DeviceId); 267 return STATUS_PLUGPLAY_NO_DEVICE; 268 } 269 270 if (!DeviceCapabilities.UniqueID) 271 { 272 /* Device has not a unique ID. We need to prepend parent bus unique identifier */ 273 DPRINT("Instance ID is not unique\n"); 274 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix); 275 if (!NT_SUCCESS(Status)) 276 { 277 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status); 278 RtlFreeUnicodeString(&DeviceId); 279 return Status; 280 } 281 } 282 283 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n"); 284 285 Stack.Parameters.QueryId.IdType = BusQueryInstanceID; 286 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 287 &IoStatusBlock, 288 IRP_MN_QUERY_ID, 289 &Stack); 290 if (!NT_SUCCESS(Status)) 291 { 292 DPRINT("IopInitiatePnpIrp(BusQueryInstanceID) failed (Status %lx)\n", Status); 293 ASSERT(IoStatusBlock.Information == 0); 294 } 295 296 if (IoStatusBlock.Information) 297 { 298 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryInstanceID); 299 300 if (!IsValidID) 301 { 302 DPRINT1("Invalid InstanceID. DeviceNode - %p\n", DeviceNode); 303 } 304 } 305 306 RtlInitUnicodeString(&InstanceId, 307 (PWSTR)IoStatusBlock.Information); 308 309 InstancePath->Length = 0; 310 InstancePath->MaximumLength = DeviceId.Length + sizeof(WCHAR) + 311 ParentIdPrefix.Length + 312 InstanceId.Length + 313 sizeof(UNICODE_NULL); 314 if (ParentIdPrefix.Length && InstanceId.Length) 315 { 316 InstancePath->MaximumLength += sizeof(WCHAR); 317 } 318 319 InstancePath->Buffer = ExAllocatePoolWithTag(PagedPool, 320 InstancePath->MaximumLength, 321 TAG_IO); 322 if (!InstancePath->Buffer) 323 { 324 RtlFreeUnicodeString(&InstanceId); 325 RtlFreeUnicodeString(&ParentIdPrefix); 326 RtlFreeUnicodeString(&DeviceId); 327 return STATUS_INSUFFICIENT_RESOURCES; 328 } 329 330 /* Start with the device id */ 331 RtlCopyUnicodeString(InstancePath, &DeviceId); 332 RtlAppendUnicodeToString(InstancePath, L"\\"); 333 334 /* Add information from parent bus device to InstancePath */ 335 RtlAppendUnicodeStringToString(InstancePath, &ParentIdPrefix); 336 if (ParentIdPrefix.Length && InstanceId.Length) 337 { 338 RtlAppendUnicodeToString(InstancePath, L"&"); 339 } 340 341 /* Finally, add the id returned by the driver stack */ 342 RtlAppendUnicodeStringToString(InstancePath, &InstanceId); 343 344 /* 345 * FIXME: Check for valid characters, if there is invalid characters 346 * then bugcheck 347 */ 348 349 RtlFreeUnicodeString(&InstanceId); 350 RtlFreeUnicodeString(&DeviceId); 351 RtlFreeUnicodeString(&ParentIdPrefix); 352 353 return STATUS_SUCCESS; 354 } 355 356 /** 357 * @brief Loads and/or returns the driver associated with the registry entry if the driver 358 * is enabled. In case of an error, sets up a corresponding Problem to the DeviceNode 359 */ 360 static 361 NTSTATUS 362 NTAPI 363 PiAttachFilterDriversCallback( 364 PWSTR ValueName, 365 ULONG ValueType, 366 PVOID ValueData, 367 ULONG ValueLength, 368 PVOID Ctx, 369 PVOID EntryContext) 370 { 371 PATTACH_FILTER_DRIVERS_CONTEXT context = Ctx; 372 PDRIVER_OBJECT DriverObject; 373 NTSTATUS Status; 374 BOOLEAN loadDrivers = (BOOLEAN)(ULONG_PTR)EntryContext; 375 376 PAGED_CODE(); 377 378 // No filter value present 379 if (ValueType != REG_SZ) 380 return STATUS_SUCCESS; 381 382 if (ValueLength <= sizeof(WCHAR)) 383 return STATUS_OBJECT_NAME_NOT_FOUND; 384 385 // open the service registry key 386 UNICODE_STRING serviceName = { .Length = 0 }, servicesKeyName; 387 RtlInitUnicodeString(&serviceName, ValueData); 388 RtlInitUnicodeString(&servicesKeyName, ServicesKeyName); 389 390 HANDLE ccsServicesHandle, serviceHandle = NULL; 391 392 Status = IopOpenRegistryKeyEx(&ccsServicesHandle, NULL, &servicesKeyName, KEY_READ); 393 if (!NT_SUCCESS(Status)) 394 { 395 DPRINT1("Failed to open a registry key for \"%wZ\" (status %x)\n", &serviceName, Status); 396 return Status; 397 } 398 399 Status = IopOpenRegistryKeyEx(&serviceHandle, ccsServicesHandle, &serviceName, KEY_READ); 400 ZwClose(ccsServicesHandle); 401 if (!NT_SUCCESS(Status)) 402 { 403 DPRINT1("Failed to open a registry key for \"%wZ\" (status %x)\n", &serviceName, Status); 404 return Status; 405 } 406 407 PADD_DEV_DRIVERS_LIST driverEntry = ExAllocatePoolWithTag(PagedPool, 408 sizeof(*driverEntry), 409 TAG_PNP_DEVACTION); 410 411 if (!driverEntry) 412 { 413 DPRINT1("Failed to allocate driverEntry for \"%wZ\"\n", &serviceName); 414 ZwClose(serviceHandle); 415 return STATUS_INSUFFICIENT_RESOURCES; 416 } 417 418 // check if the driver is disabled 419 PKEY_VALUE_FULL_INFORMATION kvInfo; 420 SERVICE_LOAD_TYPE startType = DisableLoad; 421 422 Status = IopGetRegistryValue(serviceHandle, L"Start", &kvInfo); 423 if (NT_SUCCESS(Status)) 424 { 425 if (kvInfo->Type == REG_DWORD) 426 { 427 RtlMoveMemory(&startType, 428 (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset), 429 sizeof(startType)); 430 } 431 432 ExFreePool(kvInfo); 433 } 434 435 // TODO: take into account other start types (like SERVICE_DEMAND_START) 436 if (startType >= DisableLoad) 437 { 438 if (!(context->DeviceNode->Flags & DNF_HAS_PROBLEM)) 439 { 440 PiSetDevNodeProblem(context->DeviceNode, CM_PROB_DISABLED_SERVICE); 441 } 442 443 DPRINT("Service \"%wZ\" is disabled (start type %u)\n", &serviceName, startType); 444 Status = STATUS_UNSUCCESSFUL; 445 goto Cleanup; 446 } 447 448 // check if the driver is already loaded 449 UNICODE_STRING driverName; 450 Status = IopGetDriverNames(serviceHandle, &driverName, NULL); 451 if (!NT_SUCCESS(Status)) 452 { 453 DPRINT1("Unable to obtain the driver name for \"%wZ\"\n", &serviceName); 454 goto Cleanup; 455 } 456 457 // try to open it 458 Status = ObReferenceObjectByName(&driverName, 459 OBJ_OPENIF | OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 460 NULL, /* PassedAccessState */ 461 0, /* DesiredAccess */ 462 IoDriverObjectType, 463 KernelMode, 464 NULL, /* ParseContext */ 465 (PVOID*)&DriverObject); 466 RtlFreeUnicodeString(&driverName); 467 468 // the driver was not probably loaded, try to load 469 if (!NT_SUCCESS(Status)) 470 { 471 if (loadDrivers) 472 { 473 Status = IopLoadDriver(serviceHandle, &DriverObject); 474 } 475 else 476 { 477 DPRINT("Service \"%wZ\" will not be loaded now\n", &serviceName); 478 // return failure, the driver will be loaded later (in a subsequent call) 479 Status = STATUS_UNSUCCESSFUL; 480 goto Cleanup; 481 } 482 } 483 484 if (NT_SUCCESS(Status)) 485 { 486 driverEntry->DriverObject = DriverObject; 487 driverEntry->DriverType = context->DriverType; 488 InsertTailList(context->DriversListHead, &driverEntry->ListEntry); 489 ZwClose(serviceHandle); 490 return STATUS_SUCCESS; 491 } 492 else 493 { 494 if (!(context->DeviceNode->Flags & DNF_HAS_PROBLEM)) 495 { 496 switch (Status) 497 { 498 case STATUS_INSUFFICIENT_RESOURCES: 499 PiSetDevNodeProblem(context->DeviceNode, CM_PROB_OUT_OF_MEMORY); 500 break; 501 case STATUS_FAILED_DRIVER_ENTRY: 502 PiSetDevNodeProblem(context->DeviceNode, CM_PROB_FAILED_DRIVER_ENTRY); 503 break; 504 case STATUS_ILL_FORMED_SERVICE_ENTRY: 505 PiSetDevNodeProblem(context->DeviceNode, CM_PROB_DRIVER_SERVICE_KEY_INVALID); 506 break; 507 default: 508 PiSetDevNodeProblem(context->DeviceNode, CM_PROB_DRIVER_FAILED_LOAD); 509 break; 510 } 511 } 512 513 DPRINT1("Failed to load driver \"%wZ\" for %wZ (status %x)\n", 514 &serviceName, &context->DeviceNode->InstancePath, Status); 515 } 516 517 Cleanup: 518 ExFreePoolWithTag(driverEntry, TAG_PNP_DEVACTION); 519 if (serviceHandle) 520 { 521 ZwClose(serviceHandle); 522 } 523 return Status; 524 } 525 526 527 /** 528 * @brief Calls PiAttachFilterDriversCallback for filter drivers (if any) 529 */ 530 static 531 NTSTATUS 532 PiAttachFilterDrivers( 533 PLIST_ENTRY DriversListHead, 534 PDEVICE_NODE DeviceNode, 535 HANDLE EnumSubKey, 536 HANDLE ClassKey, 537 BOOLEAN Lower, 538 BOOLEAN LoadDrivers) 539 { 540 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = { { NULL, 0, NULL, NULL, 0, NULL, 0 }, }; 541 ATTACH_FILTER_DRIVERS_CONTEXT routineContext; 542 NTSTATUS Status; 543 544 PAGED_CODE(); 545 546 routineContext.DriversListHead = DriversListHead; 547 routineContext.DeviceNode = DeviceNode; 548 549 // First add device filters 550 routineContext.DriverType = Lower ? LowerFilter : UpperFilter; 551 QueryTable[0] = (RTL_QUERY_REGISTRY_TABLE){ 552 .QueryRoutine = PiAttachFilterDriversCallback, 553 .Name = Lower ? L"LowerFilters" : L"UpperFilters", 554 .DefaultType = REG_NONE, 555 .EntryContext = (PVOID)(ULONG_PTR)LoadDrivers 556 }; 557 558 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 559 (PWSTR)EnumSubKey, 560 QueryTable, 561 &routineContext, 562 NULL); 563 if (ClassKey == NULL) 564 { 565 return Status; 566 } 567 568 // Then add device class filters 569 routineContext.DriverType = Lower ? LowerClassFilter : UpperClassFilter; 570 QueryTable[0] = (RTL_QUERY_REGISTRY_TABLE){ 571 .QueryRoutine = PiAttachFilterDriversCallback, 572 .Name = Lower ? L"LowerFilters" : L"UpperFilters", 573 .DefaultType = REG_NONE, 574 .EntryContext = (PVOID)(ULONG_PTR)LoadDrivers 575 }; 576 577 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 578 (PWSTR)ClassKey, 579 QueryTable, 580 &routineContext, 581 NULL); 582 return Status; 583 } 584 585 /** 586 * @brief Loads all drivers for a device node (actual service and filters) 587 * and calls their AddDevice routine 588 * 589 * @param[in] DeviceNode The device node 590 * @param[in] LoadDrivers Whether to load drivers if they are not loaded yet 591 * (used when storage subsystem is not yet initialized) 592 */ 593 static 594 NTSTATUS 595 PiCallDriverAddDevice( 596 _In_ PDEVICE_NODE DeviceNode, 597 _In_ BOOLEAN LoadDrivers) 598 { 599 NTSTATUS Status; 600 HANDLE EnumRootKey, SubKey; 601 HANDLE ClassKey = NULL; 602 UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT); 603 static UNICODE_STRING ccsControlClass = 604 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class"); 605 PKEY_VALUE_FULL_INFORMATION kvInfo = NULL; 606 607 PAGED_CODE(); 608 609 // open the enumeration root key 610 Status = IopOpenRegistryKeyEx(&EnumRootKey, NULL, &EnumRoot, KEY_READ); 611 if (!NT_SUCCESS(Status)) 612 { 613 DPRINT1("IopOpenRegistryKeyEx() failed for \"%wZ\" (status %x)\n", &EnumRoot, Status); 614 return Status; 615 } 616 617 // open an instance subkey 618 Status = IopOpenRegistryKeyEx(&SubKey, EnumRootKey, &DeviceNode->InstancePath, KEY_READ); 619 ZwClose(EnumRootKey); 620 if (!NT_SUCCESS(Status)) 621 { 622 DPRINT1("Failed to open a devnode instance key for \"%wZ\" (status %x)\n", 623 &DeviceNode->InstancePath, Status); 624 return Status; 625 } 626 627 // try to get the class GUID of an instance and its registry key 628 Status = IopGetRegistryValue(SubKey, REGSTR_VAL_CLASSGUID, &kvInfo); 629 if (NT_SUCCESS(Status)) 630 { 631 if (kvInfo->Type == REG_SZ && kvInfo->DataLength > sizeof(WCHAR)) 632 { 633 UNICODE_STRING classGUID = { 634 .MaximumLength = kvInfo->DataLength, 635 .Length = kvInfo->DataLength - sizeof(UNICODE_NULL), 636 .Buffer = (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset) 637 }; 638 HANDLE ccsControlHandle; 639 640 Status = IopOpenRegistryKeyEx(&ccsControlHandle, NULL, &ccsControlClass, KEY_READ); 641 if (!NT_SUCCESS(Status)) 642 { 643 DPRINT1("IopOpenRegistryKeyEx() failed for \"%wZ\" (status %x)\n", 644 &ccsControlClass, Status); 645 } 646 else 647 { 648 // open the CCS\Control\Class\<ClassGUID> key 649 Status = IopOpenRegistryKeyEx(&ClassKey, ccsControlHandle, &classGUID, KEY_READ); 650 ZwClose(ccsControlHandle); 651 if (!NT_SUCCESS(Status)) 652 { 653 DPRINT1("Failed to open class key \"%wZ\" (status %x)\n", &classGUID, Status); 654 } 655 } 656 657 if (ClassKey) 658 { 659 // Check the Properties key of a class too 660 // Windows fills some device properties from this key (which is protected) 661 // TODO: add the device properties from this key 662 663 UNICODE_STRING properties = RTL_CONSTANT_STRING(REGSTR_KEY_DEVICE_PROPERTIES); 664 HANDLE propertiesHandle; 665 666 Status = IopOpenRegistryKeyEx(&propertiesHandle, ClassKey, &properties, KEY_READ); 667 if (!NT_SUCCESS(Status)) 668 { 669 DPRINT("Properties key failed to open for \"%wZ\" (status %x)\n", 670 &classGUID, Status); 671 } 672 else 673 { 674 ZwClose(propertiesHandle); 675 } 676 } 677 } 678 679 ExFreePool(kvInfo); 680 } 681 682 // the driver loading order: 683 // 1. LowerFilters 684 // 2. LowerClassFilters 685 // 3. Device driver (only one service!) 686 // 4. UpperFilters 687 // 5. UpperClassFilters 688 689 LIST_ENTRY drvListHead; 690 InitializeListHead(&drvListHead); 691 692 // lower (class) filters 693 Status = PiAttachFilterDrivers(&drvListHead, DeviceNode, SubKey, ClassKey, TRUE, LoadDrivers); 694 if (!NT_SUCCESS(Status)) 695 { 696 goto Cleanup; 697 } 698 699 ATTACH_FILTER_DRIVERS_CONTEXT routineContext = { 700 .DriversListHead = &drvListHead, 701 .DriverType = DeviceDriver, 702 .DeviceNode = DeviceNode 703 }; 704 705 RTL_QUERY_REGISTRY_TABLE queryTable[2] = {{ 706 .QueryRoutine = PiAttachFilterDriversCallback, 707 .Name = L"Service", 708 .Flags = RTL_QUERY_REGISTRY_REQUIRED, 709 .DefaultType = REG_SZ, // REG_MULTI_SZ is not allowed here 710 .DefaultData = L"", 711 .EntryContext = (PVOID)(ULONG_PTR)LoadDrivers 712 },}; 713 714 // device driver 715 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 716 (PWSTR)SubKey, 717 queryTable, 718 &routineContext, 719 NULL); 720 if (NT_SUCCESS(Status)) 721 { 722 // do nothing 723 } 724 // if a driver is not found, but a device allows raw access -> proceed 725 else if (Status == STATUS_OBJECT_NAME_NOT_FOUND && 726 (DeviceNode->CapabilityFlags & 0x00000040)) // CM_DEVCAP_RAWDEVICEOK 727 { 728 // add a dummy entry to the drivers list (need for later processing) 729 PADD_DEV_DRIVERS_LIST driverEntry = ExAllocatePoolZero(PagedPool, 730 sizeof(*driverEntry), 731 TAG_PNP_DEVACTION); 732 driverEntry->DriverType = DeviceDriver; 733 InsertTailList(&drvListHead, &driverEntry->ListEntry); 734 DPRINT("No service for \"%wZ\" (RawDeviceOK)\n", &DeviceNode->InstancePath); 735 } 736 else 737 { 738 if (Status == STATUS_OBJECT_TYPE_MISMATCH && !(DeviceNode->Flags & DNF_HAS_PROBLEM)) 739 { 740 PiSetDevNodeProblem(DeviceNode, CM_PROB_REGISTRY); 741 } 742 DPRINT("No service for \"%wZ\" (loadDrv: %u)\n", &DeviceNode->InstancePath, LoadDrivers); 743 goto Cleanup; 744 } 745 746 // upper (class) filters 747 Status = PiAttachFilterDrivers(&drvListHead, DeviceNode, SubKey, ClassKey, FALSE, LoadDrivers); 748 if (!NT_SUCCESS(Status)) 749 { 750 goto Cleanup; 751 } 752 753 // finally loop through the stack and call AddDevice for every driver 754 for (PLIST_ENTRY listEntry = drvListHead.Flink; 755 listEntry != &drvListHead; 756 listEntry = listEntry->Flink) 757 { 758 PADD_DEV_DRIVERS_LIST driverEntry; 759 driverEntry = CONTAINING_RECORD(listEntry, ADD_DEV_DRIVERS_LIST, ListEntry); 760 PDRIVER_OBJECT driverObject = driverEntry->DriverObject; 761 762 // FIXME: ReactOS is not quite ready for this assert 763 // (legacy drivers should not have AddDevice routine) 764 // ASSERT(!(DriverObject->Flags & DRVO_LEGACY_DRIVER)); 765 766 if (driverObject && driverObject->DriverExtension->AddDevice) 767 { 768 Status = driverObject->DriverExtension->AddDevice(driverEntry->DriverObject, 769 DeviceNode->PhysicalDeviceObject); 770 } 771 else if (driverObject == NULL) 772 { 773 // valid only for DeviceDriver 774 ASSERT(driverEntry->DriverType == DeviceDriver); 775 ASSERT(DeviceNode->CapabilityFlags & 0x00000040); // CM_DEVCAP_RAWDEVICEOK 776 Status = STATUS_SUCCESS; 777 } 778 else 779 { 780 // HACK: the driver doesn't have a AddDevice routine. We shouldn't be here, 781 // but ReactOS' PnP stack is not that correct yet 782 DeviceNode->Flags |= DNF_LEGACY_DRIVER; 783 Status = STATUS_UNSUCCESSFUL; 784 } 785 786 // for filter drivers we don't care about the AddDevice result 787 if (driverEntry->DriverType == DeviceDriver) 788 { 789 if (NT_SUCCESS(Status)) 790 { 791 PDEVICE_OBJECT fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject); 792 793 // HACK: Check if we have a ACPI device (needed for power management) 794 if (fdo->DeviceType == FILE_DEVICE_ACPI) 795 { 796 static BOOLEAN SystemPowerDeviceNodeCreated = FALSE; 797 798 // There can be only one system power device 799 if (!SystemPowerDeviceNodeCreated) 800 { 801 PopSystemPowerDeviceNode = DeviceNode; 802 ObReferenceObject(PopSystemPowerDeviceNode->PhysicalDeviceObject); 803 SystemPowerDeviceNodeCreated = TRUE; 804 } 805 } 806 807 ObDereferenceObject(fdo); 808 PiSetDevNodeState(DeviceNode, DeviceNodeDriversAdded); 809 } 810 else 811 { 812 // lower filters (if already started) will be removed upon this request 813 PiSetDevNodeProblem(DeviceNode, CM_PROB_FAILED_ADD); 814 PiSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedRemoval); 815 break; 816 } 817 } 818 819 #if DBG 820 PDEVICE_OBJECT attachedDO = IoGetAttachedDevice(DeviceNode->PhysicalDeviceObject); 821 if (attachedDO->Flags & DO_DEVICE_INITIALIZING) 822 { 823 DPRINT1("DO_DEVICE_INITIALIZING is not cleared on a device 0x%p!\n", attachedDO); 824 } 825 #endif 826 } 827 828 Cleanup: 829 while (!IsListEmpty(&drvListHead)) 830 { 831 PLIST_ENTRY listEntry = RemoveHeadList(&drvListHead); 832 PADD_DEV_DRIVERS_LIST driverEntry; 833 driverEntry = CONTAINING_RECORD(listEntry, ADD_DEV_DRIVERS_LIST, ListEntry); 834 835 // drivers which don't have any devices (in case of failure) will be cleaned up 836 if (driverEntry->DriverObject) 837 { 838 ObDereferenceObject(driverEntry->DriverObject); 839 } 840 ExFreePoolWithTag(driverEntry, TAG_PNP_DEVACTION); 841 } 842 843 ZwClose(SubKey); 844 if (ClassKey != NULL) 845 { 846 ZwClose(ClassKey); 847 } 848 849 return Status; 850 } 851 852 NTSTATUS 853 NTAPI 854 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode, 855 PDEVICE_CAPABILITIES DeviceCaps) 856 { 857 IO_STATUS_BLOCK StatusBlock; 858 IO_STACK_LOCATION Stack; 859 NTSTATUS Status; 860 HANDLE InstanceKey; 861 UNICODE_STRING ValueName; 862 863 /* Set up the Header */ 864 RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES)); 865 DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES); 866 DeviceCaps->Version = 1; 867 DeviceCaps->Address = -1; 868 DeviceCaps->UINumber = -1; 869 870 /* Set up the Stack */ 871 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 872 Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps; 873 874 /* Send the IRP */ 875 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 876 &StatusBlock, 877 IRP_MN_QUERY_CAPABILITIES, 878 &Stack); 879 if (!NT_SUCCESS(Status)) 880 { 881 if (Status != STATUS_NOT_SUPPORTED) 882 { 883 DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%lx\n", Status); 884 } 885 return Status; 886 } 887 888 /* Map device capabilities to capability flags */ 889 DeviceNode->CapabilityFlags = 0; 890 if (DeviceCaps->LockSupported) 891 DeviceNode->CapabilityFlags |= 0x00000001; // CM_DEVCAP_LOCKSUPPORTED 892 893 if (DeviceCaps->EjectSupported) 894 DeviceNode->CapabilityFlags |= 0x00000002; // CM_DEVCAP_EJECTSUPPORTED 895 896 if (DeviceCaps->Removable) 897 DeviceNode->CapabilityFlags |= 0x00000004; // CM_DEVCAP_REMOVABLE 898 899 if (DeviceCaps->DockDevice) 900 DeviceNode->CapabilityFlags |= 0x00000008; // CM_DEVCAP_DOCKDEVICE 901 902 if (DeviceCaps->UniqueID) 903 DeviceNode->CapabilityFlags |= 0x00000010; // CM_DEVCAP_UNIQUEID 904 905 if (DeviceCaps->SilentInstall) 906 DeviceNode->CapabilityFlags |= 0x00000020; // CM_DEVCAP_SILENTINSTALL 907 908 if (DeviceCaps->RawDeviceOK) 909 DeviceNode->CapabilityFlags |= 0x00000040; // CM_DEVCAP_RAWDEVICEOK 910 911 if (DeviceCaps->SurpriseRemovalOK) 912 DeviceNode->CapabilityFlags |= 0x00000080; // CM_DEVCAP_SURPRISEREMOVALOK 913 914 if (DeviceCaps->HardwareDisabled) 915 DeviceNode->CapabilityFlags |= 0x00000100; // CM_DEVCAP_HARDWAREDISABLED 916 917 if (DeviceCaps->NonDynamic) 918 DeviceNode->CapabilityFlags |= 0x00000200; // CM_DEVCAP_NONDYNAMIC 919 920 if (DeviceCaps->NoDisplayInUI) 921 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI; 922 else 923 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI; 924 925 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey); 926 if (NT_SUCCESS(Status)) 927 { 928 /* Set 'Capabilities' value */ 929 RtlInitUnicodeString(&ValueName, L"Capabilities"); 930 Status = ZwSetValueKey(InstanceKey, 931 &ValueName, 932 0, 933 REG_DWORD, 934 &DeviceNode->CapabilityFlags, 935 sizeof(ULONG)); 936 937 /* Set 'UINumber' value */ 938 if (DeviceCaps->UINumber != MAXULONG) 939 { 940 RtlInitUnicodeString(&ValueName, L"UINumber"); 941 Status = ZwSetValueKey(InstanceKey, 942 &ValueName, 943 0, 944 REG_DWORD, 945 &DeviceCaps->UINumber, 946 sizeof(ULONG)); 947 } 948 949 ZwClose(InstanceKey); 950 } 951 952 return Status; 953 } 954 955 static 956 NTSTATUS 957 IopQueryHardwareIds(PDEVICE_NODE DeviceNode, 958 HANDLE InstanceKey) 959 { 960 IO_STACK_LOCATION Stack; 961 IO_STATUS_BLOCK IoStatusBlock; 962 PWSTR Ptr; 963 UNICODE_STRING ValueName; 964 NTSTATUS Status; 965 ULONG Length, TotalLength; 966 BOOLEAN IsValidID; 967 968 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n"); 969 970 RtlZeroMemory(&Stack, sizeof(Stack)); 971 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs; 972 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 973 &IoStatusBlock, 974 IRP_MN_QUERY_ID, 975 &Stack); 976 if (NT_SUCCESS(Status)) 977 { 978 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryHardwareIDs); 979 980 if (!IsValidID) 981 { 982 DPRINT1("Invalid HardwareIDs. DeviceNode - %p\n", DeviceNode); 983 } 984 985 TotalLength = 0; 986 987 Ptr = (PWSTR)IoStatusBlock.Information; 988 DPRINT("Hardware IDs:\n"); 989 while (*Ptr) 990 { 991 DPRINT(" %S\n", Ptr); 992 Length = (ULONG)wcslen(Ptr) + 1; 993 994 Ptr += Length; 995 TotalLength += Length; 996 } 997 DPRINT("TotalLength: %hu\n", TotalLength); 998 DPRINT("\n"); 999 1000 RtlInitUnicodeString(&ValueName, L"HardwareID"); 1001 Status = ZwSetValueKey(InstanceKey, 1002 &ValueName, 1003 0, 1004 REG_MULTI_SZ, 1005 (PVOID)IoStatusBlock.Information, 1006 (TotalLength + 1) * sizeof(WCHAR)); 1007 if (!NT_SUCCESS(Status)) 1008 { 1009 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status); 1010 } 1011 } 1012 else 1013 { 1014 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status); 1015 } 1016 1017 return Status; 1018 } 1019 1020 static 1021 NTSTATUS 1022 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode, 1023 HANDLE InstanceKey) 1024 { 1025 IO_STACK_LOCATION Stack; 1026 IO_STATUS_BLOCK IoStatusBlock; 1027 PWSTR Ptr; 1028 UNICODE_STRING ValueName; 1029 NTSTATUS Status; 1030 ULONG Length, TotalLength; 1031 BOOLEAN IsValidID; 1032 1033 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n"); 1034 1035 RtlZeroMemory(&Stack, sizeof(Stack)); 1036 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs; 1037 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 1038 &IoStatusBlock, 1039 IRP_MN_QUERY_ID, 1040 &Stack); 1041 if (NT_SUCCESS(Status) && IoStatusBlock.Information) 1042 { 1043 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryCompatibleIDs); 1044 1045 if (!IsValidID) 1046 { 1047 DPRINT1("Invalid CompatibleIDs. DeviceNode - %p\n", DeviceNode); 1048 } 1049 1050 TotalLength = 0; 1051 1052 Ptr = (PWSTR)IoStatusBlock.Information; 1053 DPRINT("Compatible IDs:\n"); 1054 while (*Ptr) 1055 { 1056 DPRINT(" %S\n", Ptr); 1057 Length = (ULONG)wcslen(Ptr) + 1; 1058 1059 Ptr += Length; 1060 TotalLength += Length; 1061 } 1062 DPRINT("TotalLength: %hu\n", TotalLength); 1063 DPRINT("\n"); 1064 1065 RtlInitUnicodeString(&ValueName, L"CompatibleIDs"); 1066 Status = ZwSetValueKey(InstanceKey, 1067 &ValueName, 1068 0, 1069 REG_MULTI_SZ, 1070 (PVOID)IoStatusBlock.Information, 1071 (TotalLength + 1) * sizeof(WCHAR)); 1072 if (!NT_SUCCESS(Status)) 1073 { 1074 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status); 1075 } 1076 } 1077 else 1078 { 1079 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status); 1080 } 1081 1082 return Status; 1083 } 1084 1085 /** 1086 * @brief Sets the DeviceNode's DeviceDesc and LocationInformation registry values 1087 */ 1088 VOID 1089 PiSetDevNodeText( 1090 _In_ PDEVICE_NODE DeviceNode, 1091 _In_ HANDLE InstanceKey) 1092 { 1093 PAGED_CODE(); 1094 1095 LCID localeId; 1096 1097 // Get the Locale ID 1098 NTSTATUS status = ZwQueryDefaultLocale(FALSE, &localeId); 1099 if (!NT_SUCCESS(status)) 1100 { 1101 DPRINT1("ZwQueryDefaultLocale() failed with status %x\n", status); 1102 return; 1103 } 1104 1105 // Step 1: Write the DeviceDesc value if does not exist 1106 1107 UNICODE_STRING valDeviceDesc = RTL_CONSTANT_STRING(L"DeviceDesc"); 1108 ULONG len; 1109 1110 status = ZwQueryValueKey(InstanceKey, &valDeviceDesc, KeyValueBasicInformation, NULL, 0, &len); 1111 if (status == STATUS_OBJECT_NAME_NOT_FOUND) 1112 { 1113 PWSTR deviceDesc = NULL; 1114 status = PiIrpQueryDeviceText(DeviceNode, localeId, DeviceTextDescription, &deviceDesc); 1115 1116 if (deviceDesc && deviceDesc[0] != UNICODE_NULL) 1117 { 1118 status = ZwSetValueKey(InstanceKey, 1119 &valDeviceDesc, 1120 0, 1121 REG_SZ, 1122 deviceDesc, 1123 ((ULONG)wcslen(deviceDesc) + 1) * sizeof(WCHAR)); 1124 1125 if (!NT_SUCCESS(status)) 1126 { 1127 DPRINT1("ZwSetValueKey() failed (Status %x)\n", status); 1128 } 1129 } 1130 else 1131 { 1132 // This key is mandatory, so even if the Irp fails, we still write it 1133 UNICODE_STRING unknownDeviceDesc = RTL_CONSTANT_STRING(L"Unknown device"); 1134 DPRINT("Driver didn't return DeviceDesc (status %x)\n", status); 1135 1136 status = ZwSetValueKey(InstanceKey, 1137 &valDeviceDesc, 1138 0, 1139 REG_SZ, 1140 unknownDeviceDesc.Buffer, 1141 unknownDeviceDesc.MaximumLength); 1142 if (!NT_SUCCESS(status)) 1143 { 1144 DPRINT1("ZwSetValueKey() failed (Status %x)\n", status); 1145 } 1146 } 1147 1148 if (deviceDesc) 1149 { 1150 ExFreePoolWithTag(deviceDesc, 0); 1151 } 1152 } 1153 1154 // Step 2: LocaltionInformation is overwritten unconditionally 1155 1156 PWSTR deviceLocationInfo = NULL; 1157 status = PiIrpQueryDeviceText(DeviceNode, 1158 localeId, 1159 DeviceTextLocationInformation, 1160 &deviceLocationInfo); 1161 1162 if (deviceLocationInfo && deviceLocationInfo[0] != UNICODE_NULL) 1163 { 1164 UNICODE_STRING valLocationInfo = RTL_CONSTANT_STRING(L"LocationInformation"); 1165 1166 status = ZwSetValueKey(InstanceKey, 1167 &valLocationInfo, 1168 0, 1169 REG_SZ, 1170 deviceLocationInfo, 1171 ((ULONG)wcslen(deviceLocationInfo) + 1) * sizeof(WCHAR)); 1172 if (!NT_SUCCESS(status)) 1173 { 1174 DPRINT1("ZwSetValueKey() failed (Status %x)\n", status); 1175 } 1176 } 1177 1178 if (deviceLocationInfo) 1179 { 1180 ExFreePoolWithTag(deviceLocationInfo, 0); 1181 } 1182 else 1183 { 1184 DPRINT("Driver didn't return LocationInformation (status %x)\n", status); 1185 } 1186 } 1187 1188 static 1189 NTSTATUS 1190 PiInitializeDevNode( 1191 _In_ PDEVICE_NODE DeviceNode) 1192 { 1193 IO_STATUS_BLOCK IoStatusBlock; 1194 NTSTATUS Status; 1195 HANDLE InstanceKey = NULL; 1196 UNICODE_STRING InstancePathU; 1197 PDEVICE_OBJECT OldDeviceObject; 1198 1199 DPRINT("PiProcessNewDevNode(%p)\n", DeviceNode); 1200 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject); 1201 1202 /* 1203 * FIXME: For critical errors, cleanup and disable device, but always 1204 * return STATUS_SUCCESS. 1205 */ 1206 1207 Status = IopCreateDeviceInstancePath(DeviceNode, &InstancePathU); 1208 if (!NT_SUCCESS(Status)) 1209 { 1210 if (Status != STATUS_PLUGPLAY_NO_DEVICE) 1211 { 1212 DPRINT1("IopCreateDeviceInstancePath() failed with status 0x%lx\n", Status); 1213 } 1214 return Status; 1215 } 1216 1217 /* Verify that this is not a duplicate */ 1218 OldDeviceObject = IopGetDeviceObjectFromDeviceInstance(&InstancePathU); 1219 if (OldDeviceObject != NULL) 1220 { 1221 PDEVICE_NODE OldDeviceNode = IopGetDeviceNode(OldDeviceObject); 1222 1223 DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU); 1224 DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode->Parent->InstancePath); 1225 DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode->Parent->InstancePath); 1226 1227 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 1228 0x01, 1229 (ULONG_PTR)DeviceNode->PhysicalDeviceObject, 1230 (ULONG_PTR)OldDeviceObject, 1231 0); 1232 } 1233 1234 DeviceNode->InstancePath = InstancePathU; 1235 1236 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer); 1237 1238 /* 1239 * Create registry key for the instance id, if it doesn't exist yet 1240 */ 1241 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey); 1242 if (!NT_SUCCESS(Status)) 1243 { 1244 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status); 1245 1246 /* We have to return success otherwise we abort the traverse operation */ 1247 return STATUS_SUCCESS; 1248 } 1249 1250 IopQueryHardwareIds(DeviceNode, InstanceKey); 1251 1252 IopQueryCompatibleIds(DeviceNode, InstanceKey); 1253 1254 DeviceNode->Flags |= DNF_IDS_QUERIED; 1255 1256 // Set the device's DeviceDesc and LocationInformation fields 1257 PiSetDevNodeText(DeviceNode, InstanceKey); 1258 1259 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n"); 1260 1261 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 1262 &IoStatusBlock, 1263 IRP_MN_QUERY_BUS_INFORMATION, 1264 NULL); 1265 if (NT_SUCCESS(Status) && IoStatusBlock.Information) 1266 { 1267 PPNP_BUS_INFORMATION BusInformation = (PPNP_BUS_INFORMATION)IoStatusBlock.Information; 1268 1269 DeviceNode->ChildBusNumber = BusInformation->BusNumber; 1270 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType; 1271 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid); 1272 ExFreePoolWithTag(BusInformation, 0); 1273 } 1274 else 1275 { 1276 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); 1277 1278 DeviceNode->ChildBusNumber = 0xFFFFFFF0; 1279 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined; 1280 DeviceNode->ChildBusTypeIndex = -1; 1281 } 1282 1283 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n"); 1284 1285 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 1286 &IoStatusBlock, 1287 IRP_MN_QUERY_RESOURCES, 1288 NULL); 1289 if (NT_SUCCESS(Status) && IoStatusBlock.Information) 1290 { 1291 DeviceNode->BootResources = (PCM_RESOURCE_LIST)IoStatusBlock.Information; 1292 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG); 1293 } 1294 else 1295 { 1296 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); 1297 DeviceNode->BootResources = NULL; 1298 } 1299 1300 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n"); 1301 1302 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 1303 &IoStatusBlock, 1304 IRP_MN_QUERY_RESOURCE_REQUIREMENTS, 1305 NULL); 1306 if (NT_SUCCESS(Status)) 1307 { 1308 DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information; 1309 } 1310 else 1311 { 1312 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status); 1313 DeviceNode->ResourceRequirements = NULL; 1314 } 1315 1316 if (InstanceKey != NULL) 1317 { 1318 IopSetDeviceInstanceData(InstanceKey, DeviceNode); 1319 } 1320 1321 // Try installing a critical device, so its Service key is populated 1322 // then call IopSetServiceEnumData to populate service's Enum key. 1323 // That allows us to start devices during an early boot 1324 IopInstallCriticalDevice(DeviceNode); 1325 IopSetServiceEnumData(DeviceNode, InstanceKey); 1326 1327 ZwClose(InstanceKey); 1328 1329 PiSetDevNodeState(DeviceNode, DeviceNodeInitialized); 1330 1331 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER)) 1332 { 1333 /* Report the device to the user-mode pnp manager */ 1334 IopQueueDeviceInstallEvent(&GUID_DEVICE_ENUMERATED, 1335 &DeviceNode->InstancePath); 1336 } 1337 1338 return STATUS_SUCCESS; 1339 } 1340 1341 static 1342 NTSTATUS 1343 IopSetServiceEnumData( 1344 _In_ PDEVICE_NODE DeviceNode, 1345 _In_ HANDLE InstanceHandle) 1346 { 1347 UNICODE_STRING ServicesKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); 1348 UNICODE_STRING ServiceKeyName; 1349 UNICODE_STRING EnumKeyName; 1350 UNICODE_STRING ValueName; 1351 UNICODE_STRING ServiceName; 1352 PKEY_VALUE_FULL_INFORMATION KeyValueInformation, kvInfo2; 1353 HANDLE ServiceKey = NULL, ServiceEnumKey = NULL; 1354 ULONG Disposition; 1355 ULONG Count = 0, NextInstance = 0; 1356 WCHAR ValueBuffer[6]; 1357 NTSTATUS Status = STATUS_SUCCESS; 1358 1359 // obtain the device node's ServiceName 1360 Status = IopGetRegistryValue(InstanceHandle, L"Service", &kvInfo2); 1361 if (!NT_SUCCESS(Status)) 1362 { 1363 return Status; 1364 } 1365 1366 if (kvInfo2->Type != REG_SZ || kvInfo2->DataLength <= sizeof(WCHAR)) 1367 { 1368 ExFreePool(kvInfo2); 1369 return STATUS_UNSUCCESSFUL; 1370 } 1371 1372 ServiceName.MaximumLength = kvInfo2->DataLength; 1373 ServiceName.Length = kvInfo2->DataLength - sizeof(UNICODE_NULL); 1374 ServiceName.Buffer = (PVOID)((ULONG_PTR)kvInfo2 + kvInfo2->DataOffset); 1375 1376 DPRINT("IopSetServiceEnumData(%p)\n", DeviceNode); 1377 DPRINT("Instance: %wZ\n", &DeviceNode->InstancePath); 1378 DPRINT("Service: %wZ\n", &ServiceName); 1379 1380 ServiceKeyName.MaximumLength = ServicesKeyPath.Length + ServiceName.Length + sizeof(UNICODE_NULL); 1381 ServiceKeyName.Length = 0; 1382 ServiceKeyName.Buffer = ExAllocatePool(PagedPool, ServiceKeyName.MaximumLength); 1383 if (ServiceKeyName.Buffer == NULL) 1384 { 1385 DPRINT1("No ServiceKeyName.Buffer!\n"); 1386 return STATUS_INSUFFICIENT_RESOURCES; 1387 } 1388 1389 RtlAppendUnicodeStringToString(&ServiceKeyName, &ServicesKeyPath); 1390 RtlAppendUnicodeStringToString(&ServiceKeyName, &ServiceName); 1391 1392 DPRINT("ServiceKeyName: %wZ\n", &ServiceKeyName); 1393 1394 Status = IopOpenRegistryKeyEx(&ServiceKey, NULL, &ServiceKeyName, KEY_CREATE_SUB_KEY); 1395 if (!NT_SUCCESS(Status)) 1396 { 1397 goto done; 1398 } 1399 1400 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING, 1401 &ServiceName, 1402 &DeviceNode->ServiceName); 1403 if (!NT_SUCCESS(Status)) 1404 { 1405 goto done; 1406 } 1407 1408 RtlInitUnicodeString(&EnumKeyName, L"Enum"); 1409 Status = IopCreateRegistryKeyEx(&ServiceEnumKey, 1410 ServiceKey, 1411 &EnumKeyName, 1412 KEY_SET_VALUE, 1413 REG_OPTION_VOLATILE, 1414 &Disposition); 1415 if (NT_SUCCESS(Status)) 1416 { 1417 if (Disposition == REG_OPENED_EXISTING_KEY) 1418 { 1419 /* Read the NextInstance value */ 1420 Status = IopGetRegistryValue(ServiceEnumKey, 1421 L"Count", 1422 &KeyValueInformation); 1423 if (!NT_SUCCESS(Status)) 1424 goto done; 1425 1426 if ((KeyValueInformation->Type == REG_DWORD) && 1427 (KeyValueInformation->DataLength)) 1428 { 1429 /* Read it */ 1430 Count = *(PULONG)((ULONG_PTR)KeyValueInformation + 1431 KeyValueInformation->DataOffset); 1432 } 1433 1434 ExFreePool(KeyValueInformation); 1435 KeyValueInformation = NULL; 1436 1437 /* Read the NextInstance value */ 1438 Status = IopGetRegistryValue(ServiceEnumKey, 1439 L"NextInstance", 1440 &KeyValueInformation); 1441 if (!NT_SUCCESS(Status)) 1442 goto done; 1443 1444 if ((KeyValueInformation->Type == REG_DWORD) && 1445 (KeyValueInformation->DataLength)) 1446 { 1447 NextInstance = *(PULONG)((ULONG_PTR)KeyValueInformation + 1448 KeyValueInformation->DataOffset); 1449 } 1450 1451 ExFreePool(KeyValueInformation); 1452 KeyValueInformation = NULL; 1453 } 1454 1455 /* Set the instance path */ 1456 swprintf(ValueBuffer, L"%lu", NextInstance); 1457 RtlInitUnicodeString(&ValueName, ValueBuffer); 1458 Status = ZwSetValueKey(ServiceEnumKey, 1459 &ValueName, 1460 0, 1461 REG_SZ, 1462 DeviceNode->InstancePath.Buffer, 1463 DeviceNode->InstancePath.MaximumLength); 1464 if (!NT_SUCCESS(Status)) 1465 goto done; 1466 1467 /* Increment Count and NextInstance */ 1468 Count++; 1469 NextInstance++; 1470 1471 /* Set the new Count value */ 1472 RtlInitUnicodeString(&ValueName, L"Count"); 1473 Status = ZwSetValueKey(ServiceEnumKey, 1474 &ValueName, 1475 0, 1476 REG_DWORD, 1477 &Count, 1478 sizeof(Count)); 1479 if (!NT_SUCCESS(Status)) 1480 goto done; 1481 1482 /* Set the new NextInstance value */ 1483 RtlInitUnicodeString(&ValueName, L"NextInstance"); 1484 Status = ZwSetValueKey(ServiceEnumKey, 1485 &ValueName, 1486 0, 1487 REG_DWORD, 1488 &NextInstance, 1489 sizeof(NextInstance)); 1490 } 1491 1492 done: 1493 if (ServiceEnumKey != NULL) 1494 ZwClose(ServiceEnumKey); 1495 1496 if (ServiceKey != NULL) 1497 ZwClose(ServiceKey); 1498 1499 ExFreePool(ServiceKeyName.Buffer); 1500 ExFreePool(kvInfo2); 1501 1502 return Status; 1503 } 1504 1505 /** 1506 * @brief Processes the IoInvalidateDeviceState request 1507 * 1508 * Sends IRP_MN_QUERY_PNP_DEVICE_STATE request and sets device node's flags 1509 * according to the result. 1510 * Tree reenumeration should be started upon a successful return of the function. 1511 * 1512 * @todo Do not return STATUS_SUCCESS if nothing is changed. 1513 */ 1514 static 1515 NTSTATUS 1516 PiUpdateDeviceState( 1517 _In_ PDEVICE_NODE DeviceNode) 1518 { 1519 PNP_DEVICE_STATE PnPFlags; 1520 NTSTATUS Status; 1521 1522 Status = PiIrpQueryPnPDeviceState(DeviceNode, &PnPFlags); 1523 if (!NT_SUCCESS(Status)) 1524 { 1525 return Status; 1526 } 1527 1528 if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE) 1529 DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE; 1530 else 1531 DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE; 1532 1533 if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI) 1534 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI; 1535 else 1536 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI; 1537 1538 if (PnPFlags & PNP_DEVICE_REMOVED || PnPFlags & PNP_DEVICE_DISABLED) 1539 { 1540 PiSetDevNodeProblem(DeviceNode, 1541 PnPFlags & PNP_DEVICE_DISABLED 1542 ? CM_PROB_HARDWARE_DISABLED 1543 : CM_PROB_DEVICE_NOT_THERE); 1544 1545 PiSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedRemoval); 1546 } 1547 else if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED) 1548 { 1549 // Query resource rebalance 1550 1551 if (PnPFlags & PNP_DEVICE_FAILED) 1552 DeviceNode->Flags &= DNF_NON_STOPPED_REBALANCE; 1553 else 1554 DeviceNode->Flags |= DNF_NON_STOPPED_REBALANCE; 1555 1556 // Clear DNF_NO_RESOURCE_REQUIRED just in case (will be set back if needed) 1557 DeviceNode->Flags &= ~DNF_NO_RESOURCE_REQUIRED; 1558 1559 // This will be caught up later by enumeration 1560 DeviceNode->Flags |= DNF_RESOURCE_REQUIREMENTS_CHANGED; 1561 } 1562 else if (PnPFlags & PNP_DEVICE_FAILED) 1563 { 1564 PiSetDevNodeProblem(DeviceNode, CM_PROB_FAILED_POST_START); 1565 PiSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedRemoval); 1566 } 1567 1568 return STATUS_SUCCESS; 1569 } 1570 1571 static 1572 NTSTATUS 1573 PiStartDeviceFinal( 1574 _In_ PDEVICE_NODE DeviceNode) 1575 { 1576 DEVICE_CAPABILITIES DeviceCapabilities; 1577 NTSTATUS Status; 1578 1579 if (!(DeviceNode->Flags & DNF_IDS_QUERIED)) 1580 { 1581 // query ids (for reported devices) 1582 UNICODE_STRING enumRoot = RTL_CONSTANT_STRING(ENUM_ROOT); 1583 HANDLE enumRootHandle, instanceHandle; 1584 1585 // open the enumeration root key 1586 Status = IopOpenRegistryKeyEx(&enumRootHandle, NULL, &enumRoot, KEY_READ); 1587 if (!NT_SUCCESS(Status)) 1588 { 1589 DPRINT1("IopOpenRegistryKeyEx() failed for \"%wZ\" (status %x)\n", &enumRoot, Status); 1590 return Status; 1591 } 1592 1593 // open an instance subkey 1594 Status = IopOpenRegistryKeyEx(&instanceHandle, enumRootHandle, &DeviceNode->InstancePath, KEY_READ); 1595 ZwClose(enumRootHandle); 1596 if (!NT_SUCCESS(Status)) 1597 { 1598 DPRINT1("Failed to open a devnode instance key for \"%wZ\" (status %x)\n", 1599 &DeviceNode->InstancePath, Status); 1600 return Status; 1601 } 1602 1603 IopQueryHardwareIds(DeviceNode, instanceHandle); 1604 IopQueryCompatibleIds(DeviceNode, instanceHandle); 1605 1606 DeviceNode->Flags |= DNF_IDS_QUERIED; 1607 ZwClose(instanceHandle); 1608 } 1609 1610 // we're about to start - needs enumeration 1611 DeviceNode->Flags |= DNF_REENUMERATE; 1612 1613 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n"); 1614 1615 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities); 1616 if (!NT_SUCCESS(Status)) 1617 { 1618 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status); 1619 } 1620 1621 // Query the device state (IRP_MN_QUERY_PNP_DEVICE_STATE) 1622 PiUpdateDeviceState(DeviceNode); 1623 1624 DPRINT("Sending GUID_DEVICE_ARRIVAL %wZ\n", &DeviceNode->InstancePath); 1625 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, &DeviceNode->InstancePath); 1626 1627 PiSetDevNodeState(DeviceNode, DeviceNodeStarted); 1628 1629 return STATUS_SUCCESS; 1630 } 1631 1632 /* PUBLIC FUNCTIONS **********************************************************/ 1633 1634 /** 1635 * @brief Sends one of the remove IRPs to the device stack 1636 * 1637 * If there is a mounted VPB attached to a one of the stack devices, the IRP 1638 * should be send to a VPB's DeviceObject first (which belongs to a FS driver). 1639 * FS driver will then forward it down to the volume device. 1640 * While walking the device stack, the function sets (or unsets) VPB_REMOVE_PENDING flag 1641 * thus blocking all further mounts on a soon-to-be-removed devices 1642 */ 1643 static 1644 NTSTATUS 1645 PiIrpSendRemoveCheckVpb( 1646 _In_ PDEVICE_OBJECT DeviceObject, 1647 _In_ UCHAR MinorFunction) 1648 { 1649 KIRQL oldIrql; 1650 1651 ASSERT(MinorFunction == IRP_MN_QUERY_REMOVE_DEVICE || 1652 MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE || 1653 MinorFunction == IRP_MN_SURPRISE_REMOVAL || 1654 MinorFunction == IRP_MN_REMOVE_DEVICE); 1655 1656 PDEVICE_OBJECT vpbDevObj = DeviceObject, targetDevice = DeviceObject; 1657 1658 // walk the device stack down, stop on a first mounted device 1659 do 1660 { 1661 if (vpbDevObj->Vpb) 1662 { 1663 // two locks are needed here 1664 KeWaitForSingleObject(&vpbDevObj->DeviceLock, Executive, KernelMode, FALSE, NULL); 1665 IoAcquireVpbSpinLock(&oldIrql); 1666 1667 if (MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE) 1668 { 1669 vpbDevObj->Vpb->Flags &= ~VPB_REMOVE_PENDING; 1670 } 1671 else 1672 { 1673 vpbDevObj->Vpb->Flags |= VPB_REMOVE_PENDING; 1674 } 1675 1676 BOOLEAN isMounted = (_Bool)(vpbDevObj->Vpb->Flags & VPB_MOUNTED); 1677 1678 if (isMounted) 1679 { 1680 targetDevice = vpbDevObj->Vpb->DeviceObject; 1681 } 1682 1683 IoReleaseVpbSpinLock(oldIrql); 1684 KeSetEvent(&vpbDevObj->DeviceLock, IO_NO_INCREMENT, FALSE); 1685 1686 if (isMounted) 1687 { 1688 break; 1689 } 1690 } 1691 1692 oldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock); 1693 vpbDevObj = vpbDevObj->AttachedDevice; 1694 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, oldIrql); 1695 } while (vpbDevObj); 1696 1697 ASSERT(targetDevice); 1698 1699 PVOID info; 1700 IO_STACK_LOCATION stack = {.MajorFunction = IRP_MJ_PNP, .MinorFunction = MinorFunction}; 1701 1702 return IopSynchronousCall(targetDevice, &stack, &info); 1703 } 1704 1705 NTSTATUS 1706 IopUpdateResourceMapForPnPDevice( 1707 IN PDEVICE_NODE DeviceNode); 1708 1709 static 1710 VOID 1711 NTAPI 1712 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject) 1713 { 1714 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 1715 1716 ASSERT(DeviceNode->State == DeviceNodeAwaitingQueuedRemoval); 1717 1718 /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */ 1719 PiIrpSendRemoveCheckVpb(DeviceObject, IRP_MN_REMOVE_DEVICE); 1720 1721 /* Start of HACK: update resources stored in registry, so IopDetectResourceConflict works */ 1722 if (DeviceNode->ResourceList) 1723 { 1724 ASSERT(DeviceNode->ResourceListTranslated); 1725 DeviceNode->ResourceList->Count = 0; 1726 DeviceNode->ResourceListTranslated->Count = 0; 1727 IopUpdateResourceMapForPnPDevice(DeviceNode); 1728 } 1729 /* End of HACK */ 1730 1731 PiSetDevNodeState(DeviceNode, DeviceNodeRemoved); 1732 PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_REMOVE_COMPLETE, DeviceObject, NULL); 1733 LONG_PTR refCount = ObDereferenceObject(DeviceObject); 1734 if (refCount != 0) 1735 { 1736 DPRINT1("Leaking device %wZ, refCount = %d\n", &DeviceNode->InstancePath, (INT32)refCount); 1737 } 1738 } 1739 1740 static 1741 VOID 1742 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations) 1743 { 1744 /* This function DOES dereference the device objects in all cases */ 1745 1746 ULONG i; 1747 1748 for (i = 0; i < DeviceRelations->Count; i++) 1749 { 1750 IopSendRemoveDevice(DeviceRelations->Objects[i]); 1751 DeviceRelations->Objects[i] = NULL; 1752 } 1753 1754 ExFreePool(DeviceRelations); 1755 } 1756 1757 static 1758 VOID 1759 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode) 1760 { 1761 PDEVICE_NODE ChildDeviceNode, NextDeviceNode; 1762 KIRQL OldIrql; 1763 1764 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 1765 ChildDeviceNode = ParentDeviceNode->Child; 1766 while (ChildDeviceNode != NULL) 1767 { 1768 NextDeviceNode = ChildDeviceNode->Sibling; 1769 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 1770 1771 IopSendRemoveDevice(ChildDeviceNode->PhysicalDeviceObject); 1772 1773 ChildDeviceNode = NextDeviceNode; 1774 1775 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 1776 } 1777 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 1778 } 1779 1780 static 1781 VOID 1782 NTAPI 1783 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject) 1784 { 1785 ASSERT(IopGetDeviceNode(DeviceObject)->State == DeviceNodeAwaitingQueuedRemoval); 1786 /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */ 1787 PiIrpSendRemoveCheckVpb(DeviceObject, IRP_MN_SURPRISE_REMOVAL); 1788 } 1789 1790 static 1791 VOID 1792 NTAPI 1793 IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject) 1794 { 1795 /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */ 1796 PiIrpSendRemoveCheckVpb(DeviceObject, IRP_MN_CANCEL_REMOVE_DEVICE); 1797 1798 PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_REMOVE_CANCELLED, DeviceObject, NULL); 1799 } 1800 1801 static 1802 VOID 1803 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode) 1804 { 1805 PDEVICE_NODE ChildDeviceNode, NextDeviceNode; 1806 KIRQL OldIrql; 1807 1808 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 1809 ChildDeviceNode = ParentDeviceNode->Child; 1810 while (ChildDeviceNode != NULL) 1811 { 1812 NextDeviceNode = ChildDeviceNode->Sibling; 1813 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 1814 1815 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject); 1816 1817 ChildDeviceNode = NextDeviceNode; 1818 1819 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 1820 } 1821 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 1822 } 1823 1824 static 1825 VOID 1826 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations) 1827 { 1828 /* This function DOES dereference the device objects in all cases */ 1829 1830 ULONG i; 1831 1832 for (i = 0; i < DeviceRelations->Count; i++) 1833 { 1834 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]); 1835 ObDereferenceObject(DeviceRelations->Objects[i]); 1836 DeviceRelations->Objects[i] = NULL; 1837 } 1838 1839 ExFreePool(DeviceRelations); 1840 } 1841 1842 static 1843 VOID 1844 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject) 1845 { 1846 IO_STACK_LOCATION Stack; 1847 IO_STATUS_BLOCK IoStatusBlock; 1848 PDEVICE_RELATIONS DeviceRelations; 1849 NTSTATUS Status; 1850 1851 IopCancelRemoveDevice(DeviceObject); 1852 1853 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations; 1854 1855 Status = IopInitiatePnpIrp(DeviceObject, 1856 &IoStatusBlock, 1857 IRP_MN_QUERY_DEVICE_RELATIONS, 1858 &Stack); 1859 if (!NT_SUCCESS(Status)) 1860 { 1861 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 1862 DeviceRelations = NULL; 1863 } 1864 else 1865 { 1866 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 1867 } 1868 1869 if (DeviceRelations) 1870 IopCancelRemoveDeviceRelations(DeviceRelations); 1871 } 1872 1873 static 1874 NTSTATUS 1875 NTAPI 1876 IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject) 1877 { 1878 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 1879 NTSTATUS Status; 1880 1881 ASSERT(DeviceNode); 1882 1883 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING, 1884 &DeviceNode->InstancePath); 1885 1886 Status = PiIrpSendRemoveCheckVpb(DeviceObject, IRP_MN_QUERY_REMOVE_DEVICE); 1887 1888 PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_QUERY_REMOVE, DeviceObject, NULL); 1889 1890 if (!NT_SUCCESS(Status)) 1891 { 1892 DPRINT1("Removal vetoed by %wZ\n", &DeviceNode->InstancePath); 1893 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED, 1894 &DeviceNode->InstancePath); 1895 } 1896 1897 return Status; 1898 } 1899 1900 static 1901 NTSTATUS 1902 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode, BOOLEAN Force) 1903 { 1904 PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice; 1905 NTSTATUS Status; 1906 KIRQL OldIrql; 1907 1908 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 1909 ChildDeviceNode = ParentDeviceNode->Child; 1910 while (ChildDeviceNode != NULL) 1911 { 1912 NextDeviceNode = ChildDeviceNode->Sibling; 1913 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 1914 PiSetDevNodeState(ChildDeviceNode, DeviceNodeAwaitingQueuedRemoval); 1915 1916 Status = IopPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject, Force); 1917 if (!NT_SUCCESS(Status)) 1918 { 1919 FailedRemoveDevice = ChildDeviceNode; 1920 goto cleanup; 1921 } 1922 1923 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 1924 ChildDeviceNode = NextDeviceNode; 1925 } 1926 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 1927 1928 return STATUS_SUCCESS; 1929 1930 cleanup: 1931 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 1932 ChildDeviceNode = ParentDeviceNode->Child; 1933 while (ChildDeviceNode != NULL) 1934 { 1935 NextDeviceNode = ChildDeviceNode->Sibling; 1936 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 1937 1938 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject); 1939 1940 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device 1941 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */ 1942 if (ChildDeviceNode == FailedRemoveDevice) 1943 return Status; 1944 1945 ChildDeviceNode = NextDeviceNode; 1946 1947 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 1948 } 1949 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 1950 1951 return Status; 1952 } 1953 1954 static 1955 NTSTATUS 1956 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations, BOOLEAN Force) 1957 { 1958 /* This function DOES NOT dereference the device objects on SUCCESS 1959 * but it DOES dereference device objects on FAILURE */ 1960 1961 ULONG i, j; 1962 NTSTATUS Status; 1963 1964 for (i = 0; i < DeviceRelations->Count; i++) 1965 { 1966 Status = IopPrepareDeviceForRemoval(DeviceRelations->Objects[i], Force); 1967 if (!NT_SUCCESS(Status)) 1968 { 1969 j = i; 1970 goto cleanup; 1971 } 1972 } 1973 1974 return STATUS_SUCCESS; 1975 1976 cleanup: 1977 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device 1978 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */ 1979 for (i = 0; i <= j; i++) 1980 { 1981 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]); 1982 ObDereferenceObject(DeviceRelations->Objects[i]); 1983 DeviceRelations->Objects[i] = NULL; 1984 } 1985 for (; i < DeviceRelations->Count; i++) 1986 { 1987 ObDereferenceObject(DeviceRelations->Objects[i]); 1988 DeviceRelations->Objects[i] = NULL; 1989 } 1990 ExFreePool(DeviceRelations); 1991 1992 return Status; 1993 } 1994 1995 static 1996 NTSTATUS 1997 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject, BOOLEAN Force) 1998 { 1999 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 2000 IO_STACK_LOCATION Stack; 2001 IO_STATUS_BLOCK IoStatusBlock; 2002 PDEVICE_RELATIONS DeviceRelations; 2003 NTSTATUS Status; 2004 2005 if ((DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE) && !Force) 2006 { 2007 DPRINT1("Removal not allowed for %wZ\n", &DeviceNode->InstancePath); 2008 return STATUS_UNSUCCESSFUL; 2009 } 2010 2011 if (!Force && IopQueryRemoveDevice(DeviceObject) != STATUS_SUCCESS) 2012 { 2013 DPRINT1("Removal vetoed by failing the query remove request\n"); 2014 2015 IopCancelRemoveDevice(DeviceObject); 2016 2017 return STATUS_UNSUCCESSFUL; 2018 } 2019 2020 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations; 2021 2022 Status = IopInitiatePnpIrp(DeviceObject, 2023 &IoStatusBlock, 2024 IRP_MN_QUERY_DEVICE_RELATIONS, 2025 &Stack); 2026 if (!NT_SUCCESS(Status)) 2027 { 2028 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 2029 DeviceRelations = NULL; 2030 } 2031 else 2032 { 2033 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 2034 } 2035 2036 if (DeviceRelations) 2037 { 2038 Status = IopQueryRemoveDeviceRelations(DeviceRelations, Force); 2039 if (!NT_SUCCESS(Status)) 2040 return Status; 2041 } 2042 2043 Status = IopQueryRemoveChildDevices(DeviceNode, Force); 2044 if (!NT_SUCCESS(Status)) 2045 { 2046 if (DeviceRelations) 2047 IopCancelRemoveDeviceRelations(DeviceRelations); 2048 return Status; 2049 } 2050 2051 if (DeviceRelations) 2052 IopSendRemoveDeviceRelations(DeviceRelations); 2053 IopSendRemoveChildDevices(DeviceNode); 2054 2055 return STATUS_SUCCESS; 2056 } 2057 2058 static 2059 NTSTATUS 2060 IopRemoveDevice(PDEVICE_NODE DeviceNode) 2061 { 2062 NTSTATUS Status; 2063 2064 // This function removes the device subtree, with the root in DeviceNode 2065 // atm everyting is in fact done inside this function, which is completely wrong. 2066 // The right implementation should have a separate removal worker thread and 2067 // properly do device node state transitions 2068 2069 DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath); 2070 2071 BOOLEAN surpriseRemoval = (_Bool)(DeviceNode->Flags & DNF_DEVICE_GONE); 2072 2073 Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject, surpriseRemoval); 2074 2075 if (surpriseRemoval) 2076 { 2077 IopSendSurpriseRemoval(DeviceNode->PhysicalDeviceObject); 2078 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL, &DeviceNode->InstancePath); 2079 } 2080 2081 if (NT_SUCCESS(Status)) 2082 { 2083 IopSendRemoveDevice(DeviceNode->PhysicalDeviceObject); 2084 if (surpriseRemoval) 2085 { 2086 IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL, &DeviceNode->InstancePath); 2087 } 2088 return STATUS_SUCCESS; 2089 } 2090 2091 return Status; 2092 } 2093 2094 static 2095 NTSTATUS 2096 PiEnumerateDevice( 2097 _In_ PDEVICE_NODE DeviceNode) 2098 { 2099 PDEVICE_OBJECT ChildDeviceObject; 2100 PDEVICE_NODE ChildDeviceNode; 2101 ULONG i; 2102 2103 // bus relations are already obtained for this device node 2104 2105 if (!NT_SUCCESS(DeviceNode->CompletionStatus)) 2106 { 2107 DPRINT("QDR request failed for %wZ, status %x\n", 2108 &DeviceNode->InstancePath, DeviceNode->CompletionStatus); 2109 // treat as if there are no child objects 2110 } 2111 2112 PDEVICE_RELATIONS DeviceRelations = DeviceNode->OverUsed1.PendingDeviceRelations; 2113 DeviceNode->OverUsed1.PendingDeviceRelations = NULL; 2114 2115 // it's acceptable not to have PDOs 2116 if (!DeviceRelations) 2117 { 2118 PiSetDevNodeState(DeviceNode, DeviceNodeStarted); 2119 DPRINT("No PDOs\n"); 2120 return STATUS_SUCCESS; 2121 } 2122 2123 // mark children nodes as non-present (those not returned in DR request will be removed) 2124 for (PDEVICE_NODE child = DeviceNode->Child; child != NULL; child = child->Sibling) 2125 { 2126 child->Flags &= ~DNF_ENUMERATED; 2127 } 2128 2129 DPRINT("PiEnumerateDevice: enumerating %u children\n", DeviceRelations->Count); 2130 2131 // create device nodes for all new children and set DNF_ENUMERATED back for old ones 2132 for (i = 0; i < DeviceRelations->Count; i++) 2133 { 2134 ChildDeviceObject = DeviceRelations->Objects[i]; 2135 ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0); 2136 2137 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject); 2138 if (!ChildDeviceNode) 2139 { 2140 /* One doesn't exist, create it */ 2141 ChildDeviceNode = PipAllocateDeviceNode(ChildDeviceObject); 2142 if (ChildDeviceNode) 2143 { 2144 PiInsertDevNode(ChildDeviceNode, DeviceNode); 2145 2146 /* Mark the node as enumerated */ 2147 ChildDeviceNode->Flags |= DNF_ENUMERATED; 2148 2149 /* Mark the DO as bus enumerated */ 2150 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE; 2151 } 2152 else 2153 { 2154 /* Ignore this DO */ 2155 DPRINT1("PipAllocateDeviceNode() failed. Skipping PDO %u\n", i); 2156 ObDereferenceObject(ChildDeviceObject); 2157 } 2158 } 2159 else 2160 { 2161 /* Mark it as enumerated */ 2162 ChildDeviceNode->Flags |= DNF_ENUMERATED; 2163 ObDereferenceObject(ChildDeviceObject); 2164 } 2165 } 2166 ExFreePool(DeviceRelations); 2167 2168 // time to remove non-reported devices 2169 for (PDEVICE_NODE child = DeviceNode->Child; child != NULL; child = child->Sibling) 2170 { 2171 if (!(child->Flags & (DNF_ENUMERATED|DNF_DEVICE_GONE))) 2172 { 2173 // this flag indicates that this is a surprise removal 2174 child->Flags |= DNF_DEVICE_GONE; 2175 PiSetDevNodeState(child, DeviceNodeAwaitingQueuedRemoval); 2176 } 2177 } 2178 2179 PiSetDevNodeState(DeviceNode, DeviceNodeStarted); 2180 return STATUS_SUCCESS; 2181 } 2182 2183 static 2184 NTSTATUS 2185 NTAPI 2186 IopSendEject(IN PDEVICE_OBJECT DeviceObject) 2187 { 2188 IO_STACK_LOCATION Stack; 2189 PVOID Dummy; 2190 2191 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 2192 Stack.MajorFunction = IRP_MJ_PNP; 2193 Stack.MinorFunction = IRP_MN_EJECT; 2194 2195 return IopSynchronousCall(DeviceObject, &Stack, &Dummy); 2196 } 2197 2198 /* 2199 * @implemented 2200 */ 2201 VOID 2202 NTAPI 2203 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject) 2204 { 2205 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject); 2206 PDEVICE_RELATIONS DeviceRelations; 2207 IO_STATUS_BLOCK IoStatusBlock; 2208 IO_STACK_LOCATION Stack; 2209 DEVICE_CAPABILITIES Capabilities; 2210 NTSTATUS Status; 2211 2212 IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT, 2213 &DeviceNode->InstancePath); 2214 2215 if (IopQueryDeviceCapabilities(DeviceNode, &Capabilities) != STATUS_SUCCESS) 2216 { 2217 goto cleanup; 2218 } 2219 2220 Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations; 2221 2222 Status = IopInitiatePnpIrp(PhysicalDeviceObject, 2223 &IoStatusBlock, 2224 IRP_MN_QUERY_DEVICE_RELATIONS, 2225 &Stack); 2226 if (!NT_SUCCESS(Status)) 2227 { 2228 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 2229 DeviceRelations = NULL; 2230 } 2231 else 2232 { 2233 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 2234 } 2235 2236 if (DeviceRelations) 2237 { 2238 Status = IopQueryRemoveDeviceRelations(DeviceRelations, FALSE); 2239 if (!NT_SUCCESS(Status)) 2240 goto cleanup; 2241 } 2242 2243 Status = IopQueryRemoveChildDevices(DeviceNode, FALSE); 2244 if (!NT_SUCCESS(Status)) 2245 { 2246 if (DeviceRelations) 2247 IopCancelRemoveDeviceRelations(DeviceRelations); 2248 goto cleanup; 2249 } 2250 2251 if (IopPrepareDeviceForRemoval(PhysicalDeviceObject, FALSE) != STATUS_SUCCESS) 2252 { 2253 if (DeviceRelations) 2254 IopCancelRemoveDeviceRelations(DeviceRelations); 2255 IopCancelRemoveChildDevices(DeviceNode); 2256 goto cleanup; 2257 } 2258 2259 if (DeviceRelations) 2260 IopSendRemoveDeviceRelations(DeviceRelations); 2261 IopSendRemoveChildDevices(DeviceNode); 2262 2263 DeviceNode->Problem = CM_PROB_HELD_FOR_EJECT; 2264 if (Capabilities.EjectSupported) 2265 { 2266 if (IopSendEject(PhysicalDeviceObject) != STATUS_SUCCESS) 2267 { 2268 goto cleanup; 2269 } 2270 } 2271 else 2272 { 2273 // DeviceNode->Flags |= DNF_DISABLED; 2274 } 2275 2276 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT, 2277 &DeviceNode->InstancePath); 2278 2279 return; 2280 2281 cleanup: 2282 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED, 2283 &DeviceNode->InstancePath); 2284 } 2285 2286 static 2287 VOID 2288 PiFakeResourceRebalance( 2289 _In_ PDEVICE_NODE DeviceNode) 2290 { 2291 ASSERT(DeviceNode->Flags & DNF_RESOURCE_REQUIREMENTS_CHANGED); 2292 2293 PCM_RESOURCE_LIST bootConfig = NULL; 2294 PIO_RESOURCE_REQUIREMENTS_LIST resourceRequirements = NULL; 2295 2296 PiIrpQueryResources(DeviceNode, &bootConfig); 2297 PiIrpQueryResourceRequirements(DeviceNode, &resourceRequirements); 2298 2299 DeviceNode->BootResources = bootConfig; 2300 DeviceNode->ResourceRequirements = resourceRequirements; 2301 2302 if (bootConfig) 2303 { 2304 DeviceNode->Flags |= DNF_HAS_BOOT_CONFIG; 2305 } 2306 2307 DeviceNode->Flags &= ~DNF_RESOURCE_REQUIREMENTS_CHANGED; 2308 } 2309 2310 static 2311 VOID 2312 PiDevNodeStateMachine( 2313 _In_ PDEVICE_NODE RootNode) 2314 { 2315 NTSTATUS status; 2316 BOOLEAN doProcessAgain; 2317 PDEVICE_NODE currentNode = RootNode; 2318 PDEVICE_OBJECT referencedObject; 2319 2320 do 2321 { 2322 doProcessAgain = FALSE; 2323 2324 // The device can be removed during processing, but we still need its Parent and Sibling 2325 // links to continue the tree traversal. So keep the link till the and of a cycle 2326 referencedObject = currentNode->PhysicalDeviceObject; 2327 ObReferenceObject(referencedObject); 2328 2329 // Devices with problems are skipped (unless they are not being removed) 2330 if (currentNode->Flags & DNF_HAS_PROBLEM && 2331 currentNode->State != DeviceNodeAwaitingQueuedRemoval) 2332 { 2333 goto skipEnum; 2334 } 2335 2336 switch (currentNode->State) 2337 { 2338 case DeviceNodeUnspecified: // this state is not used 2339 break; 2340 case DeviceNodeUninitialized: 2341 DPRINT("DeviceNodeUninitialized %wZ\n", ¤tNode->InstancePath); 2342 status = PiInitializeDevNode(currentNode); 2343 doProcessAgain = NT_SUCCESS(status); 2344 break; 2345 case DeviceNodeInitialized: 2346 DPRINT("DeviceNodeInitialized %wZ\n", ¤tNode->InstancePath); 2347 status = PiCallDriverAddDevice(currentNode, PnPBootDriversInitialized); 2348 doProcessAgain = NT_SUCCESS(status); 2349 break; 2350 case DeviceNodeDriversAdded: 2351 DPRINT("DeviceNodeDriversAdded %wZ\n", ¤tNode->InstancePath); 2352 status = IopAssignDeviceResources(currentNode); 2353 doProcessAgain = NT_SUCCESS(status); 2354 break; 2355 case DeviceNodeResourcesAssigned: 2356 DPRINT("DeviceNodeResourcesAssigned %wZ\n", ¤tNode->InstancePath); 2357 // send IRP_MN_START_DEVICE 2358 PiIrpStartDevice(currentNode); 2359 2360 // skip DeviceNodeStartPending, it is probably used for an async IRP_MN_START_DEVICE 2361 PiSetDevNodeState(currentNode, DeviceNodeStartCompletion); 2362 doProcessAgain = TRUE; 2363 break; 2364 case DeviceNodeStartPending: // skipped on XP/2003 2365 break; 2366 case DeviceNodeStartCompletion: 2367 DPRINT("DeviceNodeStartCompletion %wZ\n", ¤tNode->InstancePath); 2368 status = currentNode->CompletionStatus; 2369 doProcessAgain = TRUE; 2370 if (!NT_SUCCESS(status)) 2371 { 2372 UINT32 problem = (status == STATUS_PNP_REBOOT_REQUIRED) 2373 ? CM_PROB_NEED_RESTART 2374 : CM_PROB_FAILED_START; 2375 2376 PiSetDevNodeProblem(currentNode, problem); 2377 PiSetDevNodeState(currentNode, DeviceNodeAwaitingQueuedRemoval); 2378 } 2379 else 2380 { 2381 // TODO: IopDoDeferredSetInterfaceState and IopAllocateLegacyBootResources 2382 // are called here too 2383 2384 PiSetDevNodeState(currentNode, DeviceNodeStartPostWork); 2385 } 2386 break; 2387 case DeviceNodeStartPostWork: 2388 DPRINT("DeviceNodeStartPostWork %wZ\n", ¤tNode->InstancePath); 2389 // TODO: inspect the status 2390 status = PiStartDeviceFinal(currentNode); 2391 doProcessAgain = TRUE; 2392 break; 2393 case DeviceNodeStarted: 2394 if (currentNode->Flags & DNF_REENUMERATE) 2395 { 2396 DPRINT("DeviceNodeStarted REENUMERATE %wZ\n", ¤tNode->InstancePath); 2397 currentNode->Flags &= ~DNF_REENUMERATE; 2398 status = PiIrpQueryDeviceRelations(currentNode, BusRelations); 2399 2400 // again, skip DeviceNodeEnumeratePending as with the starting sequence 2401 PiSetDevNodeState(currentNode, DeviceNodeEnumerateCompletion); 2402 doProcessAgain = TRUE; 2403 } 2404 else if (currentNode->Flags & DNF_RESOURCE_REQUIREMENTS_CHANGED) 2405 { 2406 if (currentNode->Flags & DNF_NON_STOPPED_REBALANCE) 2407 { 2408 PiFakeResourceRebalance(currentNode); 2409 currentNode->Flags &= ~DNF_NON_STOPPED_REBALANCE; 2410 } 2411 else 2412 { 2413 PiIrpQueryStopDevice(currentNode); 2414 PiSetDevNodeState(currentNode, DeviceNodeQueryStopped); 2415 } 2416 2417 doProcessAgain = TRUE; 2418 } 2419 break; 2420 case DeviceNodeQueryStopped: 2421 // we're here after sending IRP_MN_QUERY_STOP_DEVICE 2422 status = currentNode->CompletionStatus; 2423 if (NT_SUCCESS(status)) 2424 { 2425 PiIrpStopDevice(currentNode); 2426 PiSetDevNodeState(currentNode, DeviceNodeStopped); 2427 } 2428 else 2429 { 2430 PiIrpCancelStopDevice(currentNode); 2431 PiSetDevNodeState(currentNode, DeviceNodeStarted); 2432 } 2433 doProcessAgain = TRUE; 2434 break; 2435 case DeviceNodeStopped: 2436 // TODO: do resource rebalance (not implemented) 2437 PiFakeResourceRebalance(currentNode); 2438 2439 PiSetDevNodeState(currentNode, DeviceNodeDriversAdded); 2440 doProcessAgain = TRUE; 2441 break; 2442 case DeviceNodeRestartCompletion: 2443 break; 2444 case DeviceNodeEnumeratePending: // skipped on XP/2003 2445 break; 2446 case DeviceNodeEnumerateCompletion: 2447 DPRINT("DeviceNodeEnumerateCompletion %wZ\n", ¤tNode->InstancePath); 2448 status = PiEnumerateDevice(currentNode); 2449 doProcessAgain = TRUE; 2450 break; 2451 case DeviceNodeAwaitingQueuedDeletion: 2452 break; 2453 case DeviceNodeAwaitingQueuedRemoval: 2454 DPRINT("DeviceNodeAwaitingQueuedRemoval %wZ\n", ¤tNode->InstancePath); 2455 status = IopRemoveDevice(currentNode); 2456 break; 2457 case DeviceNodeQueryRemoved: 2458 break; 2459 case DeviceNodeRemovePendingCloses: 2460 break; 2461 case DeviceNodeRemoved: 2462 break; 2463 case DeviceNodeDeletePendingCloses: 2464 break; 2465 case DeviceNodeDeleted: 2466 break; 2467 default: 2468 break; 2469 } 2470 2471 skipEnum: 2472 if (!doProcessAgain) 2473 { 2474 KIRQL OldIrql; 2475 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 2476 /* If we have a child, simply go down the tree */ 2477 if (currentNode->State != DeviceNodeRemoved && currentNode->Child != NULL) 2478 { 2479 ASSERT(currentNode->Child->Parent == currentNode); 2480 currentNode = currentNode->Child; 2481 } 2482 else 2483 { 2484 while (currentNode != RootNode) 2485 { 2486 /* All children processed -- go sideways */ 2487 if (currentNode->Sibling != NULL) 2488 { 2489 ASSERT(currentNode->Sibling->Parent == currentNode->Parent); 2490 currentNode = currentNode->Sibling; 2491 break; 2492 } 2493 else 2494 { 2495 /* We're the last sibling -- go back up */ 2496 ASSERT(currentNode->Parent->LastChild == currentNode); 2497 currentNode = currentNode->Parent; 2498 } 2499 /* We already visited the parent and all its children, so keep looking */ 2500 } 2501 } 2502 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 2503 } 2504 ObDereferenceObject(referencedObject); 2505 } while (doProcessAgain || currentNode != RootNode); 2506 } 2507 2508 #ifdef DBG 2509 static 2510 PCSTR 2511 ActionToStr( 2512 _In_ DEVICE_ACTION Action) 2513 { 2514 switch (Action) 2515 { 2516 case PiActionEnumDeviceTree: 2517 return "PiActionEnumDeviceTree"; 2518 case PiActionEnumRootDevices: 2519 return "PiActionEnumRootDevices"; 2520 case PiActionResetDevice: 2521 return "PiActionResetDevice"; 2522 case PiActionAddBootDevices: 2523 return "PiActionAddBootDevices"; 2524 case PiActionStartDevice: 2525 return "PiActionStartDevice"; 2526 case PiActionQueryState: 2527 return "PiActionQueryState"; 2528 default: 2529 return "(request unknown)"; 2530 } 2531 } 2532 #endif 2533 2534 static 2535 VOID 2536 NTAPI 2537 PipDeviceActionWorker( 2538 _In_opt_ PVOID Context) 2539 { 2540 PLIST_ENTRY ListEntry; 2541 PDEVICE_ACTION_REQUEST Request; 2542 KIRQL OldIrql; 2543 PDEVICE_NODE deviceNode; 2544 NTSTATUS status; 2545 2546 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql); 2547 while (!IsListEmpty(&IopDeviceActionRequestList)) 2548 { 2549 ListEntry = RemoveHeadList(&IopDeviceActionRequestList); 2550 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); 2551 Request = CONTAINING_RECORD(ListEntry, DEVICE_ACTION_REQUEST, RequestListEntry); 2552 2553 ASSERT(Request->DeviceObject); 2554 2555 deviceNode = IopGetDeviceNode(Request->DeviceObject); 2556 ASSERT(deviceNode); 2557 2558 status = STATUS_SUCCESS; 2559 2560 DPRINT("Processing PnP request %p: DeviceObject - %p, Action - %s\n", 2561 Request, Request->DeviceObject, ActionToStr(Request->Action)); 2562 2563 switch (Request->Action) 2564 { 2565 case PiActionAddBootDevices: 2566 { 2567 if (deviceNode->State == DeviceNodeInitialized && 2568 !(deviceNode->Flags & DNF_HAS_PROBLEM)) 2569 { 2570 status = PiCallDriverAddDevice(deviceNode, PnPBootDriversInitialized); 2571 } 2572 break; 2573 } 2574 case PiActionEnumRootDevices: 2575 case PiActionEnumDeviceTree: 2576 deviceNode->Flags |= DNF_REENUMERATE; 2577 PiDevNodeStateMachine(deviceNode); 2578 break; 2579 2580 case PiActionResetDevice: 2581 // TODO: the operation is a no-op for everything except removed nodes 2582 // for removed nodes, it returns them back to DeviceNodeUninitialized 2583 if (deviceNode->State == DeviceNodeRemoved) 2584 { 2585 deviceNode->State = DeviceNodeUninitialized; 2586 } 2587 status = STATUS_SUCCESS; 2588 break; 2589 2590 case PiActionStartDevice: 2591 // This action is triggered from usermode, when a driver is installed 2592 // for a non-critical PDO 2593 if (deviceNode->State == DeviceNodeInitialized && 2594 !(deviceNode->Flags & DNF_HAS_PROBLEM)) 2595 { 2596 PiDevNodeStateMachine(deviceNode); 2597 } 2598 else 2599 { 2600 DPRINT1("NOTE: attempt to start an already started/uninitialized device %wZ\n", 2601 &deviceNode->InstancePath); 2602 status = STATUS_UNSUCCESSFUL; 2603 } 2604 break; 2605 2606 case PiActionQueryState: 2607 // This action is only valid for started devices. If the device is not yet 2608 // started, the PnP manager issues IRP_MN_QUERY_PNP_DEVICE_STATE by itself. 2609 if (deviceNode->State == DeviceNodeStarted) 2610 { 2611 // Issue a IRP_MN_QUERY_PNP_DEVICE_STATE request: it will update node's flags 2612 // and then do enumeration if something has changed 2613 status = PiUpdateDeviceState(deviceNode); 2614 if (NT_SUCCESS(status)) 2615 { 2616 PiDevNodeStateMachine(deviceNode); 2617 } 2618 } 2619 // TODO: Windows may return STATUS_DELETE_PENDING here 2620 status = STATUS_SUCCESS; 2621 break; 2622 2623 default: 2624 DPRINT1("Unimplemented device action %u\n", Request->Action); 2625 status = STATUS_NOT_IMPLEMENTED; 2626 break; 2627 } 2628 2629 if (Request->CompletionStatus) 2630 { 2631 *Request->CompletionStatus = status; 2632 } 2633 2634 if (Request->CompletionEvent) 2635 { 2636 KeSetEvent(Request->CompletionEvent, IO_NO_INCREMENT, FALSE); 2637 } 2638 2639 DPRINT("Finished processing PnP request %p\n", Request); 2640 ObDereferenceObject(Request->DeviceObject); 2641 ExFreePoolWithTag(Request, TAG_IO); 2642 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql); 2643 } 2644 IopDeviceActionInProgress = FALSE; 2645 KeSetEvent(&PiEnumerationFinished, IO_NO_INCREMENT, FALSE); 2646 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); 2647 } 2648 2649 /** 2650 * @brief Queue a device operation to a worker thread. 2651 * 2652 * @param[in] DeviceObject The device object 2653 * @param[in] Action The action 2654 * @param[in] CompletionEvent The completion event object (optional) 2655 * @param[out] CompletionStatus Status returned be the action will be written here 2656 */ 2657 2658 VOID 2659 PiQueueDeviceAction( 2660 _In_ PDEVICE_OBJECT DeviceObject, 2661 _In_ DEVICE_ACTION Action, 2662 _In_opt_ PKEVENT CompletionEvent, 2663 _Out_opt_ NTSTATUS *CompletionStatus) 2664 { 2665 PDEVICE_ACTION_REQUEST Request; 2666 KIRQL OldIrql; 2667 2668 Request = ExAllocatePoolWithTag(NonPagedPoolMustSucceed, sizeof(*Request), TAG_IO); 2669 2670 DPRINT("PiQueueDeviceAction: DeviceObject - %p, Request - %p, Action - %s\n", 2671 DeviceObject, Request, ActionToStr(Action)); 2672 2673 ObReferenceObject(DeviceObject); 2674 2675 Request->DeviceObject = DeviceObject; 2676 Request->Action = Action; 2677 Request->CompletionEvent = CompletionEvent; 2678 Request->CompletionStatus = CompletionStatus; 2679 2680 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql); 2681 InsertTailList(&IopDeviceActionRequestList, &Request->RequestListEntry); 2682 2683 if (Action == PiActionEnumRootDevices || Action == PiActionAddBootDevices) 2684 { 2685 ASSERT(!IopDeviceActionInProgress); 2686 2687 IopDeviceActionInProgress = TRUE; 2688 KeClearEvent(&PiEnumerationFinished); 2689 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); 2690 2691 PipDeviceActionWorker(NULL); 2692 return; 2693 } 2694 2695 if (IopDeviceActionInProgress || !PnPBootDriversLoaded) 2696 { 2697 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); 2698 return; 2699 } 2700 IopDeviceActionInProgress = TRUE; 2701 KeClearEvent(&PiEnumerationFinished); 2702 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); 2703 2704 ExInitializeWorkItem(&IopDeviceActionWorkItem, PipDeviceActionWorker, NULL); 2705 ExQueueWorkItem(&IopDeviceActionWorkItem, DelayedWorkQueue); 2706 } 2707 2708 /** 2709 * @brief Perfom a device operation synchronously via PiQueueDeviceAction 2710 * 2711 * @param[in] DeviceObject The device object 2712 * @param[in] Action The action 2713 * 2714 * @return Status of the operation 2715 */ 2716 2717 NTSTATUS 2718 PiPerformSyncDeviceAction( 2719 _In_ PDEVICE_OBJECT DeviceObject, 2720 _In_ DEVICE_ACTION Action) 2721 { 2722 KEVENT opFinished; 2723 NTSTATUS status; 2724 2725 KeInitializeEvent(&opFinished, SynchronizationEvent, FALSE); 2726 PiQueueDeviceAction(DeviceObject, Action, &opFinished, &status); 2727 KeWaitForSingleObject(&opFinished, Executive, KernelMode, FALSE, NULL); 2728 2729 return status; 2730 } 2731