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 IopQueueTargetDeviceEvent(&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 static 1506 NTSTATUS 1507 PiStartDeviceFinal( 1508 _In_ PDEVICE_NODE DeviceNode) 1509 { 1510 DEVICE_CAPABILITIES DeviceCapabilities; 1511 NTSTATUS Status; 1512 1513 if (!(DeviceNode->Flags & DNF_IDS_QUERIED)) 1514 { 1515 // query ids (for reported devices) 1516 UNICODE_STRING enumRoot = RTL_CONSTANT_STRING(ENUM_ROOT); 1517 HANDLE enumRootHandle, instanceHandle; 1518 1519 // open the enumeration root key 1520 Status = IopOpenRegistryKeyEx(&enumRootHandle, NULL, &enumRoot, KEY_READ); 1521 if (!NT_SUCCESS(Status)) 1522 { 1523 DPRINT1("IopOpenRegistryKeyEx() failed for \"%wZ\" (status %x)\n", &enumRoot, Status); 1524 return Status; 1525 } 1526 1527 // open an instance subkey 1528 Status = IopOpenRegistryKeyEx(&instanceHandle, enumRootHandle, &DeviceNode->InstancePath, KEY_READ); 1529 ZwClose(enumRootHandle); 1530 if (!NT_SUCCESS(Status)) 1531 { 1532 DPRINT1("Failed to open a devnode instance key for \"%wZ\" (status %x)\n", 1533 &DeviceNode->InstancePath, Status); 1534 return Status; 1535 } 1536 1537 IopQueryHardwareIds(DeviceNode, instanceHandle); 1538 IopQueryCompatibleIds(DeviceNode, instanceHandle); 1539 1540 DeviceNode->Flags |= DNF_IDS_QUERIED; 1541 ZwClose(instanceHandle); 1542 } 1543 1544 // we're about to start - needs enumeration 1545 DeviceNode->Flags |= DNF_REENUMERATE; 1546 1547 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n"); 1548 1549 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities); 1550 if (!NT_SUCCESS(Status)) 1551 { 1552 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status); 1553 } 1554 1555 // Query the device state (IRP_MN_QUERY_PNP_DEVICE_STATE) 1556 PiQueueDeviceAction(DeviceNode->PhysicalDeviceObject, PiActionQueryState, NULL, NULL); 1557 1558 DPRINT("Sending GUID_DEVICE_ARRIVAL %wZ\n", &DeviceNode->InstancePath); 1559 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, &DeviceNode->InstancePath); 1560 1561 PiSetDevNodeState(DeviceNode, DeviceNodeStarted); 1562 1563 return STATUS_SUCCESS; 1564 } 1565 1566 /* PUBLIC FUNCTIONS **********************************************************/ 1567 1568 /** 1569 * @brief Sends one of the remove IRPs to the device stack 1570 * 1571 * If there is a mounted VPB attached to a one of the stack devices, the IRP 1572 * should be send to a VPB's DeviceObject first (which belongs to a FS driver). 1573 * FS driver will then forward it down to the volume device. 1574 * While walking the device stack, the function sets (or unsets) VPB_REMOVE_PENDING flag 1575 * thus blocking all further mounts on a soon-to-be-removed devices 1576 */ 1577 static 1578 NTSTATUS 1579 PiIrpSendRemoveCheckVpb( 1580 _In_ PDEVICE_OBJECT DeviceObject, 1581 _In_ UCHAR MinorFunction) 1582 { 1583 KIRQL oldIrql; 1584 1585 ASSERT(MinorFunction == IRP_MN_QUERY_REMOVE_DEVICE || 1586 MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE || 1587 MinorFunction == IRP_MN_SURPRISE_REMOVAL || 1588 MinorFunction == IRP_MN_REMOVE_DEVICE); 1589 1590 PDEVICE_OBJECT vpbDevObj = DeviceObject, targetDevice = DeviceObject; 1591 1592 // walk the device stack down, stop on a first mounted device 1593 do 1594 { 1595 if (vpbDevObj->Vpb) 1596 { 1597 // two locks are needed here 1598 KeWaitForSingleObject(&vpbDevObj->DeviceLock, Executive, KernelMode, FALSE, NULL); 1599 IoAcquireVpbSpinLock(&oldIrql); 1600 1601 if (MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE) 1602 { 1603 vpbDevObj->Vpb->Flags &= ~VPB_REMOVE_PENDING; 1604 } 1605 else 1606 { 1607 vpbDevObj->Vpb->Flags |= VPB_REMOVE_PENDING; 1608 } 1609 1610 BOOLEAN isMounted = (_Bool)(vpbDevObj->Vpb->Flags & VPB_MOUNTED); 1611 1612 if (isMounted) 1613 { 1614 targetDevice = vpbDevObj->Vpb->DeviceObject; 1615 } 1616 1617 IoReleaseVpbSpinLock(oldIrql); 1618 KeSetEvent(&vpbDevObj->DeviceLock, IO_NO_INCREMENT, FALSE); 1619 1620 if (isMounted) 1621 { 1622 break; 1623 } 1624 } 1625 1626 oldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock); 1627 vpbDevObj = vpbDevObj->AttachedDevice; 1628 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, oldIrql); 1629 } while (vpbDevObj); 1630 1631 ASSERT(targetDevice); 1632 1633 PVOID info; 1634 IO_STACK_LOCATION stack = {.MajorFunction = IRP_MJ_PNP, .MinorFunction = MinorFunction}; 1635 1636 return IopSynchronousCall(targetDevice, &stack, &info); 1637 } 1638 1639 NTSTATUS 1640 IopUpdateResourceMapForPnPDevice( 1641 IN PDEVICE_NODE DeviceNode); 1642 1643 static 1644 VOID 1645 NTAPI 1646 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject) 1647 { 1648 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 1649 1650 ASSERT(DeviceNode->State == DeviceNodeAwaitingQueuedRemoval); 1651 1652 /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */ 1653 PiIrpSendRemoveCheckVpb(DeviceObject, IRP_MN_REMOVE_DEVICE); 1654 1655 /* Start of HACK: update resources stored in registry, so IopDetectResourceConflict works */ 1656 if (DeviceNode->ResourceList) 1657 { 1658 ASSERT(DeviceNode->ResourceListTranslated); 1659 DeviceNode->ResourceList->Count = 0; 1660 DeviceNode->ResourceListTranslated->Count = 0; 1661 IopUpdateResourceMapForPnPDevice(DeviceNode); 1662 } 1663 /* End of HACK */ 1664 1665 PiSetDevNodeState(DeviceNode, DeviceNodeRemoved); 1666 PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_REMOVE_COMPLETE, DeviceObject, NULL); 1667 LONG_PTR refCount = ObDereferenceObject(DeviceObject); 1668 if (refCount != 0) 1669 { 1670 DPRINT1("Leaking device %wZ, refCount = %d\n", &DeviceNode->InstancePath, (INT32)refCount); 1671 } 1672 } 1673 1674 static 1675 VOID 1676 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations) 1677 { 1678 /* This function DOES dereference the device objects in all cases */ 1679 1680 ULONG i; 1681 1682 for (i = 0; i < DeviceRelations->Count; i++) 1683 { 1684 IopSendRemoveDevice(DeviceRelations->Objects[i]); 1685 DeviceRelations->Objects[i] = NULL; 1686 } 1687 1688 ExFreePool(DeviceRelations); 1689 } 1690 1691 static 1692 VOID 1693 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode) 1694 { 1695 PDEVICE_NODE ChildDeviceNode, NextDeviceNode; 1696 KIRQL OldIrql; 1697 1698 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 1699 ChildDeviceNode = ParentDeviceNode->Child; 1700 while (ChildDeviceNode != NULL) 1701 { 1702 NextDeviceNode = ChildDeviceNode->Sibling; 1703 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 1704 1705 IopSendRemoveDevice(ChildDeviceNode->PhysicalDeviceObject); 1706 1707 ChildDeviceNode = NextDeviceNode; 1708 1709 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 1710 } 1711 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 1712 } 1713 1714 static 1715 VOID 1716 NTAPI 1717 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject) 1718 { 1719 ASSERT(IopGetDeviceNode(DeviceObject)->State == DeviceNodeAwaitingQueuedRemoval); 1720 /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */ 1721 PiIrpSendRemoveCheckVpb(DeviceObject, IRP_MN_SURPRISE_REMOVAL); 1722 } 1723 1724 static 1725 VOID 1726 NTAPI 1727 IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject) 1728 { 1729 /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */ 1730 PiIrpSendRemoveCheckVpb(DeviceObject, IRP_MN_CANCEL_REMOVE_DEVICE); 1731 1732 PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_REMOVE_CANCELLED, DeviceObject, NULL); 1733 } 1734 1735 static 1736 VOID 1737 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode) 1738 { 1739 PDEVICE_NODE ChildDeviceNode, NextDeviceNode; 1740 KIRQL OldIrql; 1741 1742 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 1743 ChildDeviceNode = ParentDeviceNode->Child; 1744 while (ChildDeviceNode != NULL) 1745 { 1746 NextDeviceNode = ChildDeviceNode->Sibling; 1747 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 1748 1749 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject); 1750 1751 ChildDeviceNode = NextDeviceNode; 1752 1753 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 1754 } 1755 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 1756 } 1757 1758 static 1759 VOID 1760 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations) 1761 { 1762 /* This function DOES dereference the device objects in all cases */ 1763 1764 ULONG i; 1765 1766 for (i = 0; i < DeviceRelations->Count; i++) 1767 { 1768 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]); 1769 ObDereferenceObject(DeviceRelations->Objects[i]); 1770 DeviceRelations->Objects[i] = NULL; 1771 } 1772 1773 ExFreePool(DeviceRelations); 1774 } 1775 1776 static 1777 VOID 1778 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject) 1779 { 1780 IO_STACK_LOCATION Stack; 1781 IO_STATUS_BLOCK IoStatusBlock; 1782 PDEVICE_RELATIONS DeviceRelations; 1783 NTSTATUS Status; 1784 1785 IopCancelRemoveDevice(DeviceObject); 1786 1787 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations; 1788 1789 Status = IopInitiatePnpIrp(DeviceObject, 1790 &IoStatusBlock, 1791 IRP_MN_QUERY_DEVICE_RELATIONS, 1792 &Stack); 1793 if (!NT_SUCCESS(Status)) 1794 { 1795 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 1796 DeviceRelations = NULL; 1797 } 1798 else 1799 { 1800 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 1801 } 1802 1803 if (DeviceRelations) 1804 IopCancelRemoveDeviceRelations(DeviceRelations); 1805 } 1806 1807 static 1808 NTSTATUS 1809 NTAPI 1810 IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject) 1811 { 1812 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 1813 NTSTATUS Status; 1814 1815 ASSERT(DeviceNode); 1816 1817 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING, 1818 &DeviceNode->InstancePath); 1819 1820 Status = PiIrpSendRemoveCheckVpb(DeviceObject, IRP_MN_QUERY_REMOVE_DEVICE); 1821 1822 PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_QUERY_REMOVE, DeviceObject, NULL); 1823 1824 if (!NT_SUCCESS(Status)) 1825 { 1826 DPRINT1("Removal vetoed by %wZ\n", &DeviceNode->InstancePath); 1827 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED, 1828 &DeviceNode->InstancePath); 1829 } 1830 1831 return Status; 1832 } 1833 1834 static 1835 NTSTATUS 1836 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode, BOOLEAN Force) 1837 { 1838 PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice; 1839 NTSTATUS Status; 1840 KIRQL OldIrql; 1841 1842 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 1843 ChildDeviceNode = ParentDeviceNode->Child; 1844 while (ChildDeviceNode != NULL) 1845 { 1846 NextDeviceNode = ChildDeviceNode->Sibling; 1847 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 1848 PiSetDevNodeState(ChildDeviceNode, DeviceNodeAwaitingQueuedRemoval); 1849 1850 Status = IopPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject, Force); 1851 if (!NT_SUCCESS(Status)) 1852 { 1853 FailedRemoveDevice = ChildDeviceNode; 1854 goto cleanup; 1855 } 1856 1857 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 1858 ChildDeviceNode = NextDeviceNode; 1859 } 1860 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 1861 1862 return STATUS_SUCCESS; 1863 1864 cleanup: 1865 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 1866 ChildDeviceNode = ParentDeviceNode->Child; 1867 while (ChildDeviceNode != NULL) 1868 { 1869 NextDeviceNode = ChildDeviceNode->Sibling; 1870 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 1871 1872 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject); 1873 1874 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device 1875 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */ 1876 if (ChildDeviceNode == FailedRemoveDevice) 1877 return Status; 1878 1879 ChildDeviceNode = NextDeviceNode; 1880 1881 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 1882 } 1883 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 1884 1885 return Status; 1886 } 1887 1888 static 1889 NTSTATUS 1890 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations, BOOLEAN Force) 1891 { 1892 /* This function DOES NOT dereference the device objects on SUCCESS 1893 * but it DOES dereference device objects on FAILURE */ 1894 1895 ULONG i, j; 1896 NTSTATUS Status; 1897 1898 for (i = 0; i < DeviceRelations->Count; i++) 1899 { 1900 Status = IopPrepareDeviceForRemoval(DeviceRelations->Objects[i], Force); 1901 if (!NT_SUCCESS(Status)) 1902 { 1903 j = i; 1904 goto cleanup; 1905 } 1906 } 1907 1908 return STATUS_SUCCESS; 1909 1910 cleanup: 1911 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device 1912 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */ 1913 for (i = 0; i <= j; i++) 1914 { 1915 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]); 1916 ObDereferenceObject(DeviceRelations->Objects[i]); 1917 DeviceRelations->Objects[i] = NULL; 1918 } 1919 for (; i < DeviceRelations->Count; i++) 1920 { 1921 ObDereferenceObject(DeviceRelations->Objects[i]); 1922 DeviceRelations->Objects[i] = NULL; 1923 } 1924 ExFreePool(DeviceRelations); 1925 1926 return Status; 1927 } 1928 1929 static 1930 NTSTATUS 1931 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject, BOOLEAN Force) 1932 { 1933 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 1934 IO_STACK_LOCATION Stack; 1935 IO_STATUS_BLOCK IoStatusBlock; 1936 PDEVICE_RELATIONS DeviceRelations; 1937 NTSTATUS Status; 1938 1939 if ((DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE) && !Force) 1940 { 1941 DPRINT1("Removal not allowed for %wZ\n", &DeviceNode->InstancePath); 1942 return STATUS_UNSUCCESSFUL; 1943 } 1944 1945 if (!Force && IopQueryRemoveDevice(DeviceObject) != STATUS_SUCCESS) 1946 { 1947 DPRINT1("Removal vetoed by failing the query remove request\n"); 1948 1949 IopCancelRemoveDevice(DeviceObject); 1950 1951 return STATUS_UNSUCCESSFUL; 1952 } 1953 1954 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations; 1955 1956 Status = IopInitiatePnpIrp(DeviceObject, 1957 &IoStatusBlock, 1958 IRP_MN_QUERY_DEVICE_RELATIONS, 1959 &Stack); 1960 if (!NT_SUCCESS(Status)) 1961 { 1962 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 1963 DeviceRelations = NULL; 1964 } 1965 else 1966 { 1967 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 1968 } 1969 1970 if (DeviceRelations) 1971 { 1972 Status = IopQueryRemoveDeviceRelations(DeviceRelations, Force); 1973 if (!NT_SUCCESS(Status)) 1974 return Status; 1975 } 1976 1977 Status = IopQueryRemoveChildDevices(DeviceNode, Force); 1978 if (!NT_SUCCESS(Status)) 1979 { 1980 if (DeviceRelations) 1981 IopCancelRemoveDeviceRelations(DeviceRelations); 1982 return Status; 1983 } 1984 1985 if (DeviceRelations) 1986 IopSendRemoveDeviceRelations(DeviceRelations); 1987 IopSendRemoveChildDevices(DeviceNode); 1988 1989 return STATUS_SUCCESS; 1990 } 1991 1992 static 1993 NTSTATUS 1994 IopRemoveDevice(PDEVICE_NODE DeviceNode) 1995 { 1996 NTSTATUS Status; 1997 1998 // This function removes the device subtree, with the root in DeviceNode 1999 // atm everyting is in fact done inside this function, which is completely wrong. 2000 // The right implementation should have a separate removal worker thread and 2001 // properly do device node state transitions 2002 2003 DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath); 2004 2005 BOOLEAN surpriseRemoval = (_Bool)(DeviceNode->Flags & DNF_DEVICE_GONE); 2006 2007 Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject, surpriseRemoval); 2008 2009 if (surpriseRemoval) 2010 { 2011 IopSendSurpriseRemoval(DeviceNode->PhysicalDeviceObject); 2012 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL, &DeviceNode->InstancePath); 2013 } 2014 2015 if (NT_SUCCESS(Status)) 2016 { 2017 IopSendRemoveDevice(DeviceNode->PhysicalDeviceObject); 2018 if (surpriseRemoval) 2019 { 2020 IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL, &DeviceNode->InstancePath); 2021 } 2022 return STATUS_SUCCESS; 2023 } 2024 2025 return Status; 2026 } 2027 2028 /** 2029 * @brief Processes the IoInvalidateDeviceState request 2030 * 2031 * Sends IRP_MN_QUERY_PNP_DEVICE_STATE request and sets device node's flags 2032 * according to the result. 2033 * Tree reenumeration should be started upon a successful return of the function. 2034 * 2035 * @todo Do not return STATUS_SUCCESS if nothing is changed. 2036 */ 2037 static 2038 NTSTATUS 2039 PiUpdateDeviceState( 2040 _In_ PDEVICE_NODE DeviceNode) 2041 { 2042 PNP_DEVICE_STATE PnPFlags; 2043 NTSTATUS Status; 2044 2045 Status = PiIrpQueryPnPDeviceState(DeviceNode, &PnPFlags); 2046 if (!NT_SUCCESS(Status)) 2047 { 2048 return Status; 2049 } 2050 2051 if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE) 2052 DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE; 2053 else 2054 DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE; 2055 2056 if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI) 2057 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI; 2058 else 2059 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI; 2060 2061 if (PnPFlags & PNP_DEVICE_REMOVED || PnPFlags & PNP_DEVICE_DISABLED) 2062 { 2063 PiSetDevNodeProblem(DeviceNode, 2064 PnPFlags & PNP_DEVICE_DISABLED 2065 ? CM_PROB_HARDWARE_DISABLED 2066 : CM_PROB_DEVICE_NOT_THERE); 2067 2068 PiSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedRemoval); 2069 } 2070 else if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED) 2071 { 2072 // Query resource rebalance 2073 2074 if (PnPFlags & PNP_DEVICE_FAILED) 2075 DeviceNode->Flags &= DNF_NON_STOPPED_REBALANCE; 2076 else 2077 DeviceNode->Flags |= DNF_NON_STOPPED_REBALANCE; 2078 2079 // Clear DNF_NO_RESOURCE_REQUIRED just in case (will be set back if needed) 2080 DeviceNode->Flags &= ~DNF_NO_RESOURCE_REQUIRED; 2081 2082 // This will be caught up later by enumeration 2083 DeviceNode->Flags |= DNF_RESOURCE_REQUIREMENTS_CHANGED; 2084 } 2085 else if (PnPFlags & PNP_DEVICE_FAILED) 2086 { 2087 PiSetDevNodeProblem(DeviceNode, CM_PROB_FAILED_POST_START); 2088 PiSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedRemoval); 2089 } 2090 2091 return STATUS_SUCCESS; 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 status = PiStartDeviceFinal(currentNode); 2390 doProcessAgain = TRUE; 2391 break; 2392 case DeviceNodeStarted: 2393 if (currentNode->Flags & DNF_REENUMERATE) 2394 { 2395 DPRINT("DeviceNodeStarted REENUMERATE %wZ\n", ¤tNode->InstancePath); 2396 currentNode->Flags &= ~DNF_REENUMERATE; 2397 status = PiIrpQueryDeviceRelations(currentNode, BusRelations); 2398 2399 // again, skip DeviceNodeEnumeratePending as with the starting sequence 2400 PiSetDevNodeState(currentNode, DeviceNodeEnumerateCompletion); 2401 doProcessAgain = TRUE; 2402 } 2403 else if (currentNode->Flags & DNF_RESOURCE_REQUIREMENTS_CHANGED) 2404 { 2405 if (currentNode->Flags & DNF_NON_STOPPED_REBALANCE) 2406 { 2407 PiFakeResourceRebalance(currentNode); 2408 currentNode->Flags &= ~DNF_NON_STOPPED_REBALANCE; 2409 } 2410 else 2411 { 2412 PiIrpQueryStopDevice(currentNode); 2413 PiSetDevNodeState(currentNode, DeviceNodeQueryStopped); 2414 } 2415 2416 doProcessAgain = TRUE; 2417 } 2418 break; 2419 case DeviceNodeQueryStopped: 2420 // we're here after sending IRP_MN_QUERY_STOP_DEVICE 2421 status = currentNode->CompletionStatus; 2422 if (NT_SUCCESS(status)) 2423 { 2424 PiIrpStopDevice(currentNode); 2425 PiSetDevNodeState(currentNode, DeviceNodeStopped); 2426 } 2427 else 2428 { 2429 PiIrpCancelStopDevice(currentNode); 2430 PiSetDevNodeState(currentNode, DeviceNodeStarted); 2431 } 2432 doProcessAgain = TRUE; 2433 break; 2434 case DeviceNodeStopped: 2435 // TODO: do resource rebalance (not implemented) 2436 PiFakeResourceRebalance(currentNode); 2437 2438 PiSetDevNodeState(currentNode, DeviceNodeDriversAdded); 2439 doProcessAgain = TRUE; 2440 break; 2441 case DeviceNodeRestartCompletion: 2442 break; 2443 case DeviceNodeEnumeratePending: // skipped on XP/2003 2444 break; 2445 case DeviceNodeEnumerateCompletion: 2446 DPRINT("DeviceNodeEnumerateCompletion %wZ\n", ¤tNode->InstancePath); 2447 status = PiEnumerateDevice(currentNode); 2448 doProcessAgain = TRUE; 2449 break; 2450 case DeviceNodeAwaitingQueuedDeletion: 2451 break; 2452 case DeviceNodeAwaitingQueuedRemoval: 2453 DPRINT("DeviceNodeAwaitingQueuedRemoval %wZ\n", ¤tNode->InstancePath); 2454 status = IopRemoveDevice(currentNode); 2455 break; 2456 case DeviceNodeQueryRemoved: 2457 break; 2458 case DeviceNodeRemovePendingCloses: 2459 break; 2460 case DeviceNodeRemoved: 2461 break; 2462 case DeviceNodeDeletePendingCloses: 2463 break; 2464 case DeviceNodeDeleted: 2465 break; 2466 default: 2467 break; 2468 } 2469 2470 skipEnum: 2471 if (!doProcessAgain) 2472 { 2473 KIRQL OldIrql; 2474 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 2475 /* If we have a child, simply go down the tree */ 2476 if (currentNode->State != DeviceNodeRemoved && currentNode->Child != NULL) 2477 { 2478 ASSERT(currentNode->Child->Parent == currentNode); 2479 currentNode = currentNode->Child; 2480 } 2481 else 2482 { 2483 while (currentNode != RootNode) 2484 { 2485 /* All children processed -- go sideways */ 2486 if (currentNode->Sibling != NULL) 2487 { 2488 ASSERT(currentNode->Sibling->Parent == currentNode->Parent); 2489 currentNode = currentNode->Sibling; 2490 break; 2491 } 2492 else 2493 { 2494 /* We're the last sibling -- go back up */ 2495 ASSERT(currentNode->Parent->LastChild == currentNode); 2496 currentNode = currentNode->Parent; 2497 } 2498 /* We already visited the parent and all its children, so keep looking */ 2499 } 2500 } 2501 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 2502 } 2503 ObDereferenceObject(referencedObject); 2504 } while (doProcessAgain || currentNode != RootNode); 2505 } 2506 2507 #ifdef DBG 2508 static 2509 PCSTR 2510 ActionToStr( 2511 _In_ DEVICE_ACTION Action) 2512 { 2513 switch (Action) 2514 { 2515 case PiActionEnumDeviceTree: 2516 return "PiActionEnumDeviceTree"; 2517 case PiActionEnumRootDevices: 2518 return "PiActionEnumRootDevices"; 2519 case PiActionResetDevice: 2520 return "PiActionResetDevice"; 2521 case PiActionAddBootDevices: 2522 return "PiActionAddBootDevices"; 2523 case PiActionStartDevice: 2524 return "PiActionStartDevice"; 2525 case PiActionQueryState: 2526 return "PiActionQueryState"; 2527 default: 2528 return "(request unknown)"; 2529 } 2530 } 2531 #endif 2532 2533 static 2534 VOID 2535 NTAPI 2536 PipDeviceActionWorker( 2537 _In_opt_ PVOID Context) 2538 { 2539 PLIST_ENTRY ListEntry; 2540 PDEVICE_ACTION_REQUEST Request; 2541 KIRQL OldIrql; 2542 PDEVICE_NODE deviceNode; 2543 NTSTATUS status; 2544 2545 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql); 2546 while (!IsListEmpty(&IopDeviceActionRequestList)) 2547 { 2548 ListEntry = RemoveHeadList(&IopDeviceActionRequestList); 2549 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); 2550 Request = CONTAINING_RECORD(ListEntry, DEVICE_ACTION_REQUEST, RequestListEntry); 2551 2552 ASSERT(Request->DeviceObject); 2553 2554 deviceNode = IopGetDeviceNode(Request->DeviceObject); 2555 ASSERT(deviceNode); 2556 2557 status = STATUS_SUCCESS; 2558 2559 DPRINT("Processing PnP request %p: DeviceObject - %p, Action - %s\n", 2560 Request, Request->DeviceObject, ActionToStr(Request->Action)); 2561 2562 switch (Request->Action) 2563 { 2564 case PiActionAddBootDevices: 2565 { 2566 if (deviceNode->State == DeviceNodeInitialized && 2567 !(deviceNode->Flags & DNF_HAS_PROBLEM)) 2568 { 2569 status = PiCallDriverAddDevice(deviceNode, PnPBootDriversInitialized); 2570 } 2571 break; 2572 } 2573 case PiActionEnumRootDevices: 2574 case PiActionEnumDeviceTree: 2575 deviceNode->Flags |= DNF_REENUMERATE; 2576 PiDevNodeStateMachine(deviceNode); 2577 break; 2578 2579 case PiActionResetDevice: 2580 // TODO: the operation is a no-op for everything except removed nodes 2581 // for removed nodes, it returns them back to DeviceNodeUninitialized 2582 status = STATUS_SUCCESS; 2583 break; 2584 2585 case PiActionStartDevice: 2586 // This action is triggered from usermode, when a driver is installed 2587 // for a non-critical PDO 2588 if (deviceNode->State == DeviceNodeInitialized && 2589 !(deviceNode->Flags & DNF_HAS_PROBLEM)) 2590 { 2591 PiDevNodeStateMachine(deviceNode); 2592 } 2593 else 2594 { 2595 DPRINT1("NOTE: attempt to start an already started/uninitialized device %wZ\n", 2596 &deviceNode->InstancePath); 2597 status = STATUS_UNSUCCESSFUL; 2598 } 2599 break; 2600 2601 case PiActionQueryState: 2602 // First, do a IRP_MN_QUERY_PNP_DEVICE_STATE request, 2603 // it will update node's flags and then do enumeration if something changed 2604 status = PiUpdateDeviceState(deviceNode); 2605 if (NT_SUCCESS(status)) 2606 { 2607 PiDevNodeStateMachine(deviceNode); 2608 } 2609 break; 2610 2611 default: 2612 DPRINT1("Unimplemented device action %u\n", Request->Action); 2613 status = STATUS_NOT_IMPLEMENTED; 2614 break; 2615 } 2616 2617 if (Request->CompletionStatus) 2618 { 2619 *Request->CompletionStatus = status; 2620 } 2621 2622 if (Request->CompletionEvent) 2623 { 2624 KeSetEvent(Request->CompletionEvent, IO_NO_INCREMENT, FALSE); 2625 } 2626 2627 DPRINT("Finished processing PnP request %p\n", Request); 2628 ObDereferenceObject(Request->DeviceObject); 2629 ExFreePoolWithTag(Request, TAG_IO); 2630 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql); 2631 } 2632 IopDeviceActionInProgress = FALSE; 2633 KeSetEvent(&PiEnumerationFinished, IO_NO_INCREMENT, FALSE); 2634 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); 2635 } 2636 2637 /** 2638 * @brief Queue a device operation to a worker thread. 2639 * 2640 * @param[in] DeviceObject The device object 2641 * @param[in] Action The action 2642 * @param[in] CompletionEvent The completion event object (optional) 2643 * @param[out] CompletionStatus Status returned be the action will be written here 2644 */ 2645 2646 VOID 2647 PiQueueDeviceAction( 2648 _In_ PDEVICE_OBJECT DeviceObject, 2649 _In_ DEVICE_ACTION Action, 2650 _In_opt_ PKEVENT CompletionEvent, 2651 _Out_opt_ NTSTATUS *CompletionStatus) 2652 { 2653 PDEVICE_ACTION_REQUEST Request; 2654 KIRQL OldIrql; 2655 2656 Request = ExAllocatePoolWithTag(NonPagedPoolMustSucceed, sizeof(*Request), TAG_IO); 2657 2658 DPRINT("PiQueueDeviceAction: DeviceObject - %p, Request - %p, Action - %s\n", 2659 DeviceObject, Request, ActionToStr(Action)); 2660 2661 ObReferenceObject(DeviceObject); 2662 2663 Request->DeviceObject = DeviceObject; 2664 Request->Action = Action; 2665 Request->CompletionEvent = CompletionEvent; 2666 Request->CompletionStatus = CompletionStatus; 2667 2668 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql); 2669 InsertTailList(&IopDeviceActionRequestList, &Request->RequestListEntry); 2670 2671 if (Action == PiActionEnumRootDevices || Action == PiActionAddBootDevices) 2672 { 2673 ASSERT(!IopDeviceActionInProgress); 2674 2675 IopDeviceActionInProgress = TRUE; 2676 KeClearEvent(&PiEnumerationFinished); 2677 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); 2678 2679 PipDeviceActionWorker(NULL); 2680 return; 2681 } 2682 2683 if (IopDeviceActionInProgress || !PnPBootDriversLoaded) 2684 { 2685 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); 2686 return; 2687 } 2688 IopDeviceActionInProgress = TRUE; 2689 KeClearEvent(&PiEnumerationFinished); 2690 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); 2691 2692 ExInitializeWorkItem(&IopDeviceActionWorkItem, PipDeviceActionWorker, NULL); 2693 ExQueueWorkItem(&IopDeviceActionWorkItem, DelayedWorkQueue); 2694 } 2695 2696 /** 2697 * @brief Perfom a device operation synchronously via PiQueueDeviceAction 2698 * 2699 * @param[in] DeviceObject The device object 2700 * @param[in] Action The action 2701 * 2702 * @return Status of the operation 2703 */ 2704 2705 NTSTATUS 2706 PiPerformSyncDeviceAction( 2707 _In_ PDEVICE_OBJECT DeviceObject, 2708 _In_ DEVICE_ACTION Action) 2709 { 2710 KEVENT opFinished; 2711 NTSTATUS status; 2712 2713 KeInitializeEvent(&opFinished, SynchronizationEvent, FALSE); 2714 PiQueueDeviceAction(DeviceObject, Action, &opFinished, &status); 2715 KeWaitForSingleObject(&opFinished, Executive, KernelMode, FALSE, NULL); 2716 2717 return status; 2718 } 2719