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