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