1 /*++ 2 3 4 Copyright (c) Microsoft. All rights reserved. 5 6 Module Name: 7 8 FxPkgPnp.cpp 9 10 Abstract: 11 12 This module implements the pnp IRP handlers for the driver framework. 13 14 Author: 15 16 17 18 Environment: 19 20 Both kernel and user mode 21 22 Revision History: 23 24 25 26 27 28 --*/ 29 30 #include "pnppriv.hpp" 31 32 #include <initguid.h> 33 #include <wdmguid.h> 34 35 extern "C" { 36 37 #if defined(EVENT_TRACING) 38 #include "FxPkgPnp.tmh" 39 #endif 40 41 } 42 43 /* dc7a8e51-49b3-4a3a-9e81-625205e7d729 */ 44 const GUID FxPkgPnp::GUID_POWER_THREAD_INTERFACE = { 45 0xdc7a8e51, 0x49b3, 0x4a3a, { 0x9e, 0x81, 0x62, 0x52, 0x05, 0xe7, 0xd7, 0x29 } 46 }; 47 48 FxPkgPnp::FxPkgPnp( 49 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 50 __in CfxDevice* Device, 51 __in WDFTYPE Type 52 ) : 53 FxPackage(FxDriverGlobals, Device, Type) 54 { 55 ULONG i; 56 57 m_DmaEnablerList = NULL; 58 m_RemovalDeviceList = NULL; 59 m_UsageDependentDeviceList = NULL; 60 61 // 62 // Initialize the structures to the default state and then override the 63 // non WDF std default values to the unsupported / off values. 64 // 65 m_PnpStateAndCaps.Value = 66 FxPnpStateDisabledUseDefault | 67 FxPnpStateDontDisplayInUIUseDefault | 68 FxPnpStateFailedUseDefault | 69 FxPnpStateNotDisableableUseDefault | 70 FxPnpStateRemovedUseDefault | 71 FxPnpStateResourcesChangedUseDefault | 72 73 FxPnpCapLockSupportedUseDefault | 74 FxPnpCapEjectSupportedUseDefault | 75 FxPnpCapRemovableUseDefault | 76 FxPnpCapDockDeviceUseDefault | 77 FxPnpCapUniqueIDUseDefault | 78 FxPnpCapSilentInstallUseDefault | 79 FxPnpCapSurpriseRemovalOKUseDefault | 80 FxPnpCapHardwareDisabledUseDefault | 81 FxPnpCapNoDisplayInUIUseDefault 82 ; 83 84 m_PnpCapsAddress = (ULONG) -1; 85 m_PnpCapsUINumber = (ULONG) -1; 86 87 RtlZeroMemory(&m_PowerCaps, sizeof(m_PowerCaps)); 88 m_PowerCaps.Caps = 89 FxPowerCapDeviceD1UseDefault | 90 FxPowerCapDeviceD2UseDefault | 91 FxPowerCapWakeFromD0UseDefault | 92 FxPowerCapWakeFromD1UseDefault | 93 FxPowerCapWakeFromD2UseDefault | 94 FxPowerCapWakeFromD3UseDefault 95 ; 96 97 m_PowerCaps.DeviceWake = PowerDeviceMaximum; 98 m_PowerCaps.SystemWake = PowerSystemMaximum; 99 100 m_PowerCaps.D1Latency = (ULONG) -1; 101 m_PowerCaps.D2Latency = (ULONG) -1; 102 m_PowerCaps.D3Latency = (ULONG) -1; 103 104 m_PowerCaps.States = 0; 105 for (i = 0; i < PowerSystemMaximum; i++) { 106 _SetPowerCapState(i, PowerDeviceMaximum, &m_PowerCaps.States); 107 } 108 109 RtlZeroMemory(&m_D3ColdInterface, sizeof(m_D3ColdInterface)); 110 RtlZeroMemory(&m_SpecialSupport[0], sizeof(m_SpecialSupport)); 111 RtlZeroMemory(&m_SpecialFileCount[0], sizeof(m_SpecialFileCount)); 112 113 m_PowerThreadInterface.Interface.Size = sizeof(m_PowerThreadInterface); 114 m_PowerThreadInterface.Interface.Version = 1; 115 m_PowerThreadInterface.Interface.Context = this; 116 m_PowerThreadInterface.Interface.InterfaceReference = &FxPkgPnp::_PowerThreadInterfaceReference; 117 m_PowerThreadInterface.Interface.InterfaceDereference = &FxPkgPnp::_PowerThreadInterfaceDereference; 118 m_PowerThreadInterface.PowerThreadEnqueue = &FxPkgPnp::_PowerThreadEnqueue; 119 m_PowerThread = NULL; 120 m_HasPowerThread = FALSE; 121 m_PowerThreadInterfaceReferenceCount = 1; 122 m_PowerThreadEvent = NULL; 123 124 m_DeviceStopCount = 0; 125 m_CapsQueried = FALSE; 126 m_InternalFailure = FALSE; 127 m_FailedAction = WdfDeviceFailedUndefined; 128 129 // 130 // We only set the pending child count to 1 once we know we have successfully 131 // created an FxDevice and initialized it fully. If we delete an FxDevice 132 // which is half baked, it cannot have any FxChildLists which have any 133 // pending children on them. 134 // 135 m_PendingChildCount = 0; 136 137 m_QueryInterfaceHead.Next = NULL; 138 139 m_DeviceInterfaceHead.Next = NULL; 140 m_DeviceInterfacesCanBeEnabled = FALSE; 141 142 m_Failed = FALSE; 143 m_SetDeviceRemoveProcessed = FALSE; 144 145 m_SystemPowerState = PowerSystemWorking; 146 m_DevicePowerState = WdfPowerDeviceD3Final; 147 m_DevicePowerStateOld = WdfPowerDeviceD3Final; 148 149 m_PendingPnPIrp = NULL; 150 m_PendingSystemPowerIrp = NULL; 151 m_PendingDevicePowerIrp = NULL; 152 m_SystemPowerAction = (UCHAR) PowerActionNone; 153 154 m_PnpStateCallbacks = NULL; 155 m_PowerStateCallbacks = NULL; 156 m_PowerPolicyStateCallbacks = NULL; 157 158 m_SelfManagedIoMachine = NULL; 159 160 m_EnumInfo = NULL; 161 162 m_Resources = NULL; 163 m_ResourcesRaw = NULL; 164 165 InitializeListHead(&m_InterruptListHead); 166 m_InterruptObjectCount = 0; 167 m_WakeInterruptCount = 0; 168 m_WakeInterruptPendingAckCount = 0; 169 m_SystemWokenByWakeInterrupt = FALSE; 170 m_WakeInterruptsKeepConnected = FALSE; 171 m_AchievedStart = FALSE; 172 173 m_SharedPower.m_WaitWakeIrp = NULL; 174 m_SharedPower.m_WaitWakeOwner = FALSE; 175 m_SharedPower.m_ExtendWatchDogTimer = FALSE; 176 177 m_DeviceRemoveProcessed = NULL; 178 179 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) 180 // 181 // Interrupt APIs for Vista and forward 182 // 183 m_IoConnectInterruptEx = FxLibraryGlobals.IoConnectInterruptEx; 184 m_IoDisconnectInterruptEx = FxLibraryGlobals.IoDisconnectInterruptEx; 185 186 // 187 // Interrupt APIs for Windows 8 and forward 188 // 189 m_IoReportInterruptActive = FxLibraryGlobals.IoReportInterruptActive; 190 m_IoReportInterruptInactive = FxLibraryGlobals.IoReportInterruptInactive; 191 192 #endif 193 194 m_ReleaseHardwareAfterDescendantsOnFailure = FALSE; 195 196 MarkDisposeOverride(ObjectDoNotLock); 197 } 198 199 FxPkgPnp::~FxPkgPnp() 200 { 201 PSINGLE_LIST_ENTRY ple; 202 203 Mx::MxAssert(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); 204 205 // 206 // We should either have zero pending children or we never made it out of 207 // the init state during a failed WDFDEVICE create or failed EvtDriverDeviceAdd 208 // 209 Mx::MxAssert(m_PendingChildCount == 0 || 210 m_Device->GetDevicePnpState() == WdfDevStatePnpInit); 211 212 213 ple = m_DeviceInterfaceHead.Next; 214 while (ple != NULL) { 215 FxDeviceInterface* pDI; 216 217 pDI = FxDeviceInterface::_FromEntry(ple); 218 219 // 220 // Advance to the next before deleting the current 221 // 222 ple = ple->Next; 223 224 // 225 // No longer in the list 226 // 227 pDI->m_Entry.Next = NULL; 228 229 delete pDI; 230 } 231 m_DeviceInterfaceHead.Next = NULL; 232 233 if (m_DmaEnablerList != NULL) { 234 delete m_DmaEnablerList; 235 m_DmaEnablerList = NULL; 236 } 237 238 if (m_RemovalDeviceList != NULL) { 239 delete m_RemovalDeviceList; 240 m_RemovalDeviceList = NULL; 241 } 242 243 if (m_UsageDependentDeviceList != NULL) { 244 delete m_UsageDependentDeviceList; 245 m_UsageDependentDeviceList = NULL; 246 } 247 248 if (m_PnpStateCallbacks != NULL) { 249 delete m_PnpStateCallbacks; 250 } 251 252 if (m_PowerStateCallbacks != NULL) { 253 delete m_PowerStateCallbacks; 254 } 255 256 if (m_PowerPolicyStateCallbacks != NULL) { 257 delete m_PowerPolicyStateCallbacks; 258 } 259 260 if (m_SelfManagedIoMachine != NULL) { 261 delete m_SelfManagedIoMachine; 262 m_SelfManagedIoMachine = NULL; 263 } 264 265 if (m_EnumInfo != NULL) { 266 delete m_EnumInfo; 267 m_EnumInfo = NULL; 268 } 269 270 if (m_Resources != NULL) { 271 m_Resources->RELEASE(this); 272 m_Resources = NULL; 273 } 274 275 if (m_ResourcesRaw != NULL) { 276 m_ResourcesRaw->RELEASE(this); 277 m_ResourcesRaw = NULL; 278 } 279 280 ASSERT(IsListEmpty(&m_InterruptListHead)); 281 } 282 283 BOOLEAN 284 FxPkgPnp::Dispose( 285 VOID 286 ) 287 { 288 PSINGLE_LIST_ENTRY ple; 289 290 // 291 // All of the interrupts were freed during this object's dispose path. This 292 // is because all of the interrupts were attached as children to this object. 293 // 294 // It is safe to just reinitialize the list head. 295 // 296 InitializeListHead(&m_InterruptListHead); 297 298 m_QueryInterfaceLock.AcquireLock(GetDriverGlobals()); 299 300 // 301 // A derived class can insert an embedded FxQueryInterface into the QI list, 302 // so clear out the list before the destructor chain runs. (The derived 303 // class will be destructed first, as such, the embedded FxQueryInterface 304 // will also destruct first and complain it is still in a list. 305 // 306 ple = m_QueryInterfaceHead.Next; 307 308 // 309 // Clear out the head while holding the lock so that we synchronize against 310 // processing a QI while deleting the list. 311 // 312 m_QueryInterfaceHead.Next = NULL; 313 314 m_QueryInterfaceLock.ReleaseLock(GetDriverGlobals()); 315 316 while (ple != NULL) { 317 FxQueryInterface* pQI; 318 319 pQI = FxQueryInterface::_FromEntry(ple); 320 321 // 322 // Advance before we potentiall free the structure 323 // 324 ple = ple->Next; 325 326 // 327 // FxQueryInterface's destructor requires Next be NULL 328 // 329 pQI->m_Entry.Next = NULL; 330 331 if (pQI->m_EmbeddedInterface == FALSE) { 332 delete pQI; 333 } 334 } 335 336 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) 337 DropD3ColdInterface(); 338 #endif 339 340 // 341 // Call up the hierarchy 342 // 343 return FxPackage::Dispose(); // __super call 344 } 345 346 347 _Must_inspect_result_ 348 NTSTATUS 349 FxPkgPnp::Initialize( 350 __in PWDFDEVICE_INIT DeviceInit 351 ) 352 353 /*++ 354 355 Routine Description: 356 357 This function initializes state associated with an instance of FxPkgPnp. 358 This differs from the constructor because it can do operations which 359 will fail, and can return failure. (Constructors can't fail, they can 360 only throw exceptions, which we can't deal with in this kernel mode 361 environment.) 362 363 Arguments: 364 365 DeviceInit - Struct that the driver initialized that contains defaults. 366 367 Returns: 368 369 NTSTATUS 370 371 --*/ 372 373 { 374 PFX_DRIVER_GLOBALS pFxDriverGlobals; 375 NTSTATUS status; 376 377 pFxDriverGlobals = GetDriverGlobals(); 378 379 m_ReleaseHardwareAfterDescendantsOnFailure = (DeviceInit->ReleaseHardwareOrderOnFailure == 380 WdfReleaseHardwareOrderOnFailureAfterDescendants); 381 382 status = m_QueryInterfaceLock.Initialize(); 383 if (!NT_SUCCESS(status)) { 384 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, 385 TRACINGPNP, 386 "Could not initialize QueryInterfaceLock for " 387 "WDFDEVICE %p, %!STATUS!", 388 m_Device->GetHandle(), status); 389 return status; 390 } 391 392 status = m_DeviceInterfaceLock.Initialize(); 393 if (!NT_SUCCESS(status)) { 394 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, 395 TRACINGPNP, 396 "Could not initialize DeviceInterfaceLock for " 397 "WDFDEVICE %p, %!STATUS!", 398 m_Device->GetHandle(), status); 399 return status; 400 } 401 402 // 403 // Initialize preallocated events for UM 404 // (For KM, events allocated on stack are used since event initialization 405 // doesn't fail in KM) 406 // 407 #if (FX_CORE_MODE==FX_CORE_USER_MODE) 408 409 status = m_CleanupEventUm.Initialize(); 410 if (!NT_SUCCESS(status)) { 411 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, 412 TRACINGPNP, 413 "Could not initialize cleanup event for " 414 "WDFDEVICE %p, %!STATUS!", 415 m_Device->GetHandle(), status); 416 return status; 417 } 418 419 status = m_RemoveEventUm.Initialize(SynchronizationEvent, FALSE); 420 if (!NT_SUCCESS(status)) { 421 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, 422 TRACINGPNP, 423 "Could not initialize remove event for " 424 "WDFDEVICE %p, %!STATUS!", 425 m_Device->GetHandle(), status); 426 return status; 427 } 428 #endif 429 430 if (DeviceInit->IsPwrPolOwner()) { 431 m_PowerPolicyMachine.m_Owner = new (pFxDriverGlobals) 432 FxPowerPolicyOwnerSettings(this); 433 434 if (m_PowerPolicyMachine.m_Owner == NULL) { 435 return STATUS_INSUFFICIENT_RESOURCES; 436 } 437 438 status = m_PowerPolicyMachine.m_Owner->Init(); 439 if (!NT_SUCCESS(status)) { 440 return status; 441 } 442 443 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) 444 QueryForD3ColdInterface(); 445 #endif 446 } 447 448 // 449 // we will change the access flags on the object later on when we build up 450 // the list from the wdm resources 451 // 452 status = FxCmResList::_CreateAndInit(&m_Resources, 453 pFxDriverGlobals, 454 m_Device, 455 WDF_NO_OBJECT_ATTRIBUTES, 456 FxResourceNoAccess); 457 if (!NT_SUCCESS(status)) { 458 return status; 459 } 460 461 status = m_Resources->Commit(WDF_NO_OBJECT_ATTRIBUTES, 462 WDF_NO_HANDLE, 463 m_Device); 464 465 // 466 // This should never fail 467 // 468 ASSERT(NT_SUCCESS(status)); 469 if (!NT_SUCCESS(status)) { 470 m_Resources->DeleteFromFailedCreate(); 471 m_Resources = NULL; 472 return status; 473 } 474 475 m_Resources->ADDREF(this); 476 477 // 478 // we will change the access flags on the object later on when we build up 479 // the list from the wdm resources 480 // 481 status = FxCmResList::_CreateAndInit(&m_ResourcesRaw, 482 pFxDriverGlobals, 483 m_Device, 484 WDF_NO_OBJECT_ATTRIBUTES, 485 FxResourceNoAccess); 486 if (!NT_SUCCESS(status)) { 487 return status; 488 } 489 490 status = m_ResourcesRaw->Commit(WDF_NO_OBJECT_ATTRIBUTES, 491 WDF_NO_HANDLE, 492 m_Device); 493 494 // 495 // This should never fail 496 // 497 ASSERT(NT_SUCCESS(status)); 498 if (!NT_SUCCESS(status)) { 499 m_ResourcesRaw->DeleteFromFailedCreate(); 500 m_ResourcesRaw = NULL; 501 return status; 502 } 503 504 m_ResourcesRaw->ADDREF(this); 505 506 status = RegisterCallbacks(&DeviceInit->PnpPower.PnpPowerEventCallbacks); 507 if (!NT_SUCCESS(status)) { 508 return status; 509 } 510 511 if (IsPowerPolicyOwner()) { 512 RegisterPowerPolicyCallbacks(&DeviceInit->PnpPower.PolicyEventCallbacks); 513 } 514 515 return status; 516 } 517 518 _Must_inspect_result_ 519 NTSTATUS 520 FxPkgPnp::Dispatch( 521 __in MdIrp Irp 522 ) 523 524 /*++ 525 526 Routine Description: 527 528 This is the main dispatch handler for the pnp package. This method is 529 called by the framework manager when a PNP or Power IRP enters the driver. 530 This function will dispatch the IRP to a function designed to handle the 531 specific IRP. 532 533 Arguments: 534 535 Device - a pointer to the FxDevice 536 537 Irp - a pointer to the FxIrp 538 539 Returns: 540 541 NTSTATUS 542 543 --*/ 544 545 { 546 NTSTATUS status; 547 FxIrp irp(Irp); 548 549 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) 550 FX_TRACK_DRIVER(GetDriverGlobals()); 551 #endif 552 553 if (irp.GetMajorFunction() == IRP_MJ_PNP) { 554 555 switch (irp.GetMinorFunction()) { 556 case IRP_MN_START_DEVICE: 557 case IRP_MN_QUERY_REMOVE_DEVICE: 558 case IRP_MN_REMOVE_DEVICE: 559 case IRP_MN_CANCEL_REMOVE_DEVICE: 560 case IRP_MN_STOP_DEVICE: 561 case IRP_MN_QUERY_STOP_DEVICE: 562 case IRP_MN_CANCEL_STOP_DEVICE: 563 case IRP_MN_SURPRISE_REMOVAL: 564 case IRP_MN_EJECT: 565 case IRP_MN_QUERY_PNP_DEVICE_STATE: 566 DoTraceLevelMessage( 567 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 568 "WDFDEVICE 0x%p !devobj 0x%p, IRP_MJ_PNP, %!pnpmn! IRP 0x%p", 569 m_Device->GetHandle(), 570 m_Device->GetDeviceObject(), 571 irp.GetMinorFunction(), irp.GetIrp()); 572 break; 573 574 case IRP_MN_QUERY_DEVICE_RELATIONS: 575 DoTraceLevelMessage( 576 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 577 "WDFDEVICE 0x%p !devobj 0x%p, IRP_MJ_PNP, %!pnpmn! " 578 "type %!DEVICE_RELATION_TYPE! IRP 0x%p", 579 m_Device->GetHandle(), 580 m_Device->GetDeviceObject(), 581 irp.GetMinorFunction(), 582 irp.GetParameterQDRType(), irp.GetIrp()); 583 break; 584 585 default: 586 DoTraceLevelMessage( 587 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 588 "WDFDEVICE 0x%p !devobj 0x%p, IRP_MJ_PNP, %!pnpmn! IRP 0x%p", 589 m_Device->GetHandle(), 590 m_Device->GetDeviceObject(), 591 irp.GetMinorFunction(), irp.GetIrp()); 592 break; 593 } 594 595 if (irp.GetMinorFunction() <= IRP_MN_SURPRISE_REMOVAL) { 596 status = (*GetDispatchPnp()[irp.GetMinorFunction()])(this, &irp); 597 } 598 else { 599 // 600 // For Pnp IRPs we don't understand, just forget about them 601 // 602 status = FireAndForgetIrp(&irp); 603 } 604 } 605 else { 606 // 607 // If this isn't a PnP Irp, it must be a power irp. 608 // 609 switch (irp.GetMinorFunction()) { 610 case IRP_MN_WAIT_WAKE: 611 case IRP_MN_SET_POWER: 612 if (irp.GetParameterPowerType() == SystemPowerState) { 613 DoTraceLevelMessage( 614 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 615 "WDFDEVICE 0x%p !devobj 0x%p IRP_MJ_POWER, %!pwrmn! " 616 "IRP 0x%p for %!SYSTEM_POWER_STATE! (S%d)", 617 m_Device->GetHandle(), 618 m_Device->GetDeviceObject(), 619 irp.GetMinorFunction(), irp.GetIrp(), 620 irp.GetParameterPowerStateSystemState(), 621 irp.GetParameterPowerStateSystemState() - 1); 622 } 623 else { 624 DoTraceLevelMessage( 625 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 626 "WDFDEVICE 0x%p !devobj 0x%p IRP_MJ_POWER, %!pwrmn! " 627 "IRP 0x%p for %!DEVICE_POWER_STATE!", 628 m_Device->GetHandle(), 629 m_Device->GetDeviceObject(), 630 irp.GetMinorFunction(), irp.GetIrp(), 631 irp.GetParameterPowerStateDeviceState()); 632 } 633 break; 634 635 default: 636 DoTraceLevelMessage( 637 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 638 "WDFDEVICE 0x%p !devobj 0x%p IRP_MJ_POWER, %!pwrmn! IRP 0x%p", 639 m_Device->GetHandle(), 640 m_Device->GetDeviceObject(), 641 irp.GetMinorFunction(), irp.GetIrp()); 642 break; 643 } 644 645 Mx::MxAssert(irp.GetMajorFunction() == IRP_MJ_POWER); 646 647 if (irp.GetMinorFunction() <= IRP_MN_QUERY_POWER) { 648 status = (*GetDispatchPower()[irp.GetMinorFunction()])(this, &irp); 649 } 650 else { 651 // 652 // For Power IRPs we don't understand, just forget about them 653 // 654 status = FireAndForgetIrp(&irp); 655 } 656 } 657 658 return status; 659 } 660 661 PNP_DEVICE_STATE 662 FxPkgPnp::HandleQueryPnpDeviceState( 663 __in PNP_DEVICE_STATE PnpDeviceState 664 ) 665 666 /*++ 667 668 Routine Description: 669 670 This function handled IRP_MN_QUERY_DEVICE_STATE. Most of the bits are 671 just copied from internal Framework state. 672 673 Arguments: 674 675 PnpDeviceState - Bitfield that will be returned to the sender of the IRP. 676 677 Returns: 678 679 NTSTATUS 680 681 --*/ 682 683 { 684 LONG state; 685 686 state = GetPnpStateInternal(); 687 688 // 689 // Return device state set by driver. 690 // 691 SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState, 692 PNP_DEVICE_DISABLED, 693 state, 694 Disabled); 695 SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState, 696 PNP_DEVICE_DONT_DISPLAY_IN_UI, 697 state, 698 DontDisplayInUI); 699 SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState, 700 PNP_DEVICE_FAILED, 701 state, 702 Failed); 703 SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState, 704 PNP_DEVICE_NOT_DISABLEABLE, 705 state, 706 NotDisableable); 707 SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState, 708 PNP_DEVICE_REMOVED, 709 state, 710 Removed); 711 SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState, 712 PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED, 713 state, 714 ResourcesChanged); 715 716 if ((state & FxPnpStateDontDisplayInUIMask) == FxPnpStateDontDisplayInUIUseDefault) { 717 LONG caps; 718 719 // 720 // Mask off all caps except for NoDispalyInUI 721 // 722 caps = GetPnpCapsInternal() & FxPnpCapNoDisplayInUIMask; 723 724 // 725 // If the driver didn't specify pnp state, see if they specified no 726 // display as a capability. For raw PDOs and just usability, it is not 727 // always clear to the driver writer that they must set both the pnp cap 728 // and the pnp state for the no display in UI property to stick after 729 // the device has been started. 730 // 731 if (caps == FxPnpCapNoDisplayInUITrue) { 732 PnpDeviceState |= PNP_DEVICE_DONT_DISPLAY_IN_UI; 733 } 734 else if (caps == FxPnpCapNoDisplayInUIFalse) { 735 PnpDeviceState &= ~PNP_DEVICE_DONT_DISPLAY_IN_UI; 736 } 737 } 738 739 // 740 // Return device state maintained by frameworks. 741 // 742 if (IsInSpecialUse()) { 743 PnpDeviceState |= PNP_DEVICE_NOT_DISABLEABLE; 744 } 745 746 // 747 // If there is an internal failure, then indicate that up to pnp. 748 // 749 if (m_InternalFailure || m_Failed) { 750 PnpDeviceState |= PNP_DEVICE_FAILED; 751 } 752 753 return PnpDeviceState; 754 } 755 756 _Must_inspect_result_ 757 NTSTATUS 758 FxPkgPnp::HandleQueryBusRelations( 759 __inout FxIrp* Irp 760 ) 761 /*++ 762 763 Routine Description: 764 Handles a query device relations for the bus relations type (all other types 765 are handled by HandleQueryDeviceRelations). This function will call into 766 each of the device's FxChildList objects to process the request. 767 768 Arguments: 769 Irp - the request contain the query device relations 770 771 Return Value: 772 NTSTATUS 773 774 --*/ 775 { 776 FxWaitLockTransactionedList* pList; 777 PDEVICE_RELATIONS pRelations; 778 FxTransactionedEntry* ple; 779 NTSTATUS status, listStatus; 780 BOOLEAN changed; 781 782 // 783 // Before we do anything, callback into the driver 784 // 785 m_DeviceRelationsQuery.Invoke(m_Device->GetHandle(), BusRelations); 786 787 // 788 // Default to success unless list processing fails 789 // 790 status = STATUS_SUCCESS; 791 792 // 793 // Keep track of changes made by any list object. If anything changes, 794 // remember it for post-processing. 795 // 796 changed = FALSE; 797 798 pRelations = (PDEVICE_RELATIONS) Irp->GetInformation(); 799 800 if (m_EnumInfo != NULL) { 801 pList = &m_EnumInfo->m_ChildListList; 802 803 pList->LockForEnum(GetDriverGlobals()); 804 } 805 else { 806 pList = NULL; 807 } 808 809 ple = NULL; 810 while (pList != NULL && (ple = pList->GetNextEntry(ple)) != NULL) { 811 FxChildList* pChildList; 812 813 pChildList = FxChildList::_FromEntry(ple); 814 815 // 816 // ProcessBusRelations will free and reallocate pRelations if necessary 817 // 818 listStatus = pChildList->ProcessBusRelations(&pRelations); 819 820 // 821 // STATUS_NOT_SUPPORTED is a special value. It indicates that the call 822 // to ProcessBusRelations did not modify pRelations in any way. 823 // 824 if (listStatus == STATUS_NOT_SUPPORTED) { 825 continue; 826 } 827 828 829 if (!NT_SUCCESS(listStatus)) { 830 DoTraceLevelMessage( 831 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 832 "WDFDEVICE %p, WDFCHILDLIST %p returned %!STATUS! from " 833 "processing bus relations", 834 m_Device->GetHandle(), pChildList->GetHandle(), listStatus); 835 status = listStatus; 836 break; 837 } 838 839 // 840 // We updated pRelations, change the status later 841 // 842 changed = TRUE; 843 } 844 845 // 846 // By checking for NT_SUCCESS(status) below we account for 847 // both the cases - list changed, as well as list unchanged but possibly 848 // children being reported missing (that doesn't involve list change). 849 // 850 if (NT_SUCCESS(status)) { 851 852 ple = NULL; 853 while (pList != NULL && (ple = pList->GetNextEntry(ple)) != NULL) { 854 FxChildList* pChildList; 855 856 pChildList = FxChildList::_FromEntry(ple); 857 858 // 859 // invoke the ReportedMissing callback for for children that are 860 // being reporte missing 861 // 862 pChildList->InvokeReportedMissingCallback(); 863 } 864 } 865 866 if (pList != NULL) { 867 pList->UnlockFromEnum(GetDriverGlobals()); 868 } 869 870 if (NT_SUCCESS(status) && changed == FALSE) { 871 // 872 // Went through the entire list of FxChildList objects, but no object 873 // modified the pRelations, so restore the caller's NTSTATUS. 874 // 875 status = Irp->GetStatus(); 876 } 877 878 // 879 // Re-set the relations into the structure so that any changes that any call 880 // to FxChildList::ProcessBusRelations takes effect and is reported. 881 // 882 Irp->SetInformation((ULONG_PTR) pRelations); 883 Irp->SetStatus(status); 884 885 DoTraceLevelMessage( 886 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 887 "WDFDEVICE %p, returning %!STATUS! from processing bus relations", 888 m_Device->GetHandle(), status 889 ); 890 891 if (NT_SUCCESS(status) && pRelations != NULL) { 892 ULONG i; 893 894 DoTraceLevelMessage( 895 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 896 "WDFDEVICE %p returning %d devices in relations %p", 897 m_Device->GetHandle(), pRelations->Count, pRelations 898 ); 899 900 // 901 // Try to not consume an IFR entry per DO reported. Instead, report up 902 // to 4 at a time. 903 // 904 for (i = 0; i < pRelations->Count && GetDriverGlobals()->FxVerboseOn; i += 4) { 905 if (i + 3 < pRelations->Count) { 906 DoTraceLevelMessage( 907 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 908 "PDO %p PDO %p PDO %p PDO %p", 909 pRelations->Objects[i], 910 pRelations->Objects[i+1], 911 pRelations->Objects[i+2], 912 pRelations->Objects[i+3] 913 ); 914 } 915 else if (i + 2 < pRelations->Count) { 916 DoTraceLevelMessage( 917 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 918 "PDO %p PDO %p PDO %p", 919 pRelations->Objects[i], 920 pRelations->Objects[i+1], 921 pRelations->Objects[i+2] 922 ); 923 } 924 else if (i + 1 < pRelations->Count) { 925 DoTraceLevelMessage( 926 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 927 "PDO %p PDO %p", 928 pRelations->Objects[i], 929 pRelations->Objects[i+1] 930 ); 931 } 932 else { 933 DoTraceLevelMessage( 934 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 935 "PDO %p", 936 pRelations->Objects[i] 937 ); 938 } 939 } 940 } 941 942 return status; 943 } 944 945 _Must_inspect_result_ 946 NTSTATUS 947 FxPkgPnp::HandleQueryBusInformation( 948 __inout FxIrp* Irp 949 ) 950 { 951 NTSTATUS status; 952 953 // 954 // Probably is a better check then this to see if the driver set the bus 955 // information 956 // 957 if (m_BusInformation.BusTypeGuid.Data1 != 0x0) { 958 PPNP_BUS_INFORMATION pBusInformation; 959 PFX_DRIVER_GLOBALS pFxDriverGlobals; 960 961 pFxDriverGlobals = GetDriverGlobals(); 962 pBusInformation = (PPNP_BUS_INFORMATION) MxMemory::MxAllocatePoolWithTag( 963 PagedPool, sizeof(PNP_BUS_INFORMATION), pFxDriverGlobals->Tag); 964 965 if (pBusInformation != NULL) { 966 // 967 // Initialize the PNP_BUS_INFORMATION structure with the data 968 // from PDO properties. 969 // 970 RtlCopyMemory(pBusInformation, 971 &m_BusInformation, 972 sizeof(PNP_BUS_INFORMATION)); 973 974 Irp->SetInformation((ULONG_PTR) pBusInformation); 975 status = STATUS_SUCCESS; 976 } 977 else { 978 Irp->SetInformation(NULL); 979 status = STATUS_INSUFFICIENT_RESOURCES; 980 981 DoTraceLevelMessage( 982 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 983 "WDFDEVICE %p could not allocate PNP_BUS_INFORMATION string, " 984 " %!STATUS!", m_Device->GetHandle(), status); 985 } 986 } 987 else { 988 status = Irp->GetStatus(); 989 } 990 991 return status; 992 } 993 994 _Must_inspect_result_ 995 NTSTATUS 996 FxPkgPnp::HandleQueryDeviceRelations( 997 __inout FxIrp* Irp, 998 __inout FxRelatedDeviceList* List 999 ) 1000 /*++ 1001 1002 Routine Description: 1003 Handles the query device relations request for all relation types *except* 1004 for bus relations (HandleQueryBusRelations handles that type exclusively). 1005 1006 This function will allocate a PDEVICE_RELATIONS structure if the passed in 1007 FxRelatedDeviceList contains any devices to add to the relations list. 1008 1009 Arguments: 1010 Irp - the request 1011 1012 List - list containing devices to report in the relations 1013 1014 Return Value: 1015 NTSTATUS 1016 1017 --*/ 1018 { 1019 PDEVICE_RELATIONS pPriorRelations, pNewRelations; 1020 FxRelatedDevice* entry; 1021 DEVICE_RELATION_TYPE type; 1022 ULONG count; 1023 size_t size; 1024 NTSTATUS status; 1025 BOOLEAN retry; 1026 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1027 1028 if (List == NULL) { 1029 // 1030 // Indicate that we didn't modify the irp at all since we have no list 1031 // 1032 return STATUS_NOT_SUPPORTED; 1033 } 1034 1035 pFxDriverGlobals = GetDriverGlobals(); 1036 type = Irp->GetParameterQDRType(); 1037 status = STATUS_SUCCESS; 1038 1039 // 1040 // Notify driver that he should re-scan for device relations. 1041 // 1042 m_DeviceRelationsQuery.Invoke(m_Device->GetHandle(), type); 1043 1044 pPriorRelations = (PDEVICE_RELATIONS) Irp->GetInformation(); 1045 retry = FALSE; 1046 1047 count = 0; 1048 1049 List->LockForEnum(pFxDriverGlobals); 1050 1051 // 1052 // Count how many entries there are in the list 1053 // 1054 for (entry = NULL; (entry = List->GetNextEntry(entry)) != NULL; count++) { 1055 DO_NOTHING(); 1056 } 1057 1058 // 1059 // If we have 1060 // 1) no devices in the list AND 1061 // a) we have nothing to report OR 1062 // b) we have something to report and there are previous relations (which 1063 // if left unchanged will be used to report our missing devices) 1064 // 1065 // THEN we have nothing else to do, just return 1066 // 1067 if (count == 0 && 1068 (List->m_NeedReportMissing == 0 || pPriorRelations != NULL)) { 1069 List->UnlockFromEnum(pFxDriverGlobals); 1070 return STATUS_NOT_SUPPORTED; 1071 } 1072 1073 if (pPriorRelations != NULL) { 1074 // 1075 // Looks like another driver in the stack has already added some 1076 // entries. Make sure we allocate space for these additional entries. 1077 // 1078 count += pPriorRelations->Count; 1079 } 1080 1081 // 1082 // Allocate space for the device relations structure (which includes 1083 // space for one PDEVICE_OBJECT, and then allocate enough additional 1084 // space for the extra PDEVICE_OBJECTS we need. 1085 // 1086 // (While no FxChildList objects are used in this function, this static 1087 // function from the class computes what we need.) 1088 // 1089 size = FxChildList::_ComputeRelationsSize(count); 1090 1091 pNewRelations = (PDEVICE_RELATIONS) MxMemory::MxAllocatePoolWithTag( 1092 PagedPool, size, pFxDriverGlobals->Tag); 1093 1094 if (pNewRelations == NULL) { 1095 // 1096 // Dereference any previously reported relations before exiting. They 1097 // are dereferenced here because the PNP manager will see error and not 1098 // do anything while the driver which added these objects expects the 1099 // pnp manager to do the dereference. Since this device is changing the 1100 // status, it must act like the pnp manager. 1101 // 1102 if (pPriorRelations != NULL) { 1103 ULONG i; 1104 1105 for (i = 0; i < pPriorRelations->Count; i++) { 1106 Mx::MxDereferenceObject(pPriorRelations->Objects[i]); 1107 } 1108 } 1109 1110 if (List->IncrementRetries() < 3) { 1111 retry = TRUE; 1112 } 1113 1114 status = STATUS_INSUFFICIENT_RESOURCES; 1115 1116 DoTraceLevelMessage( 1117 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 1118 "WDFDEVICE %p could not allocate device relations for type %d string, " 1119 " %!STATUS!", m_Device->GetHandle(), type, status); 1120 1121 goto Done; 1122 } 1123 1124 RtlZeroMemory(pNewRelations, size); 1125 1126 // 1127 // If there was an existing device relations structure, copy 1128 // the entries to the new structure. 1129 // 1130 if (pPriorRelations != NULL && pPriorRelations->Count > 0) { 1131 RtlCopyMemory( 1132 pNewRelations, 1133 pPriorRelations, 1134 FxChildList::_ComputeRelationsSize(pPriorRelations->Count) 1135 ); 1136 } 1137 1138 // 1139 // Walk the list and return the relations here 1140 // 1141 for (entry = NULL; 1142 (entry = List->GetNextEntry(entry)) != NULL; 1143 pNewRelations->Count++) { 1144 MdDeviceObject pdo; 1145 1146 pdo = entry->GetDevice(); 1147 1148 if (entry->m_State == RelatedDeviceStateNeedsReportPresent) { 1149 entry->m_State = RelatedDeviceStateReportedPresent; 1150 } 1151 1152 // 1153 // Add it to the DEVICE_RELATIONS structure. Pnp dictates that each 1154 // PDO in the list be referenced. 1155 // 1156 pNewRelations->Objects[pNewRelations->Count] = reinterpret_cast<PDEVICE_OBJECT>(pdo); 1157 Mx::MxReferenceObject(pdo); 1158 } 1159 1160 Done: 1161 if (NT_SUCCESS(status)) { 1162 List->ZeroRetries(); 1163 } 1164 1165 List->UnlockFromEnum(GetDriverGlobals()); 1166 1167 if (pPriorRelations != NULL) { 1168 MxMemory::MxFreePool(pPriorRelations); 1169 } 1170 1171 if (retry) { 1172 MxDeviceObject physicalDeviceObject( 1173 m_Device->GetPhysicalDevice() 1174 ); 1175 1176 physicalDeviceObject.InvalidateDeviceRelations(type); 1177 } 1178 1179 Irp->SetStatus(status); 1180 Irp->SetInformation((ULONG_PTR) pNewRelations); 1181 1182 return status; 1183 } 1184 1185 _Must_inspect_result_ 1186 NTSTATUS 1187 FxPkgPnp::PostCreateDeviceInitialize( 1188 VOID 1189 ) 1190 1191 /*++ 1192 1193 Routine Description: 1194 1195 This function does any initialization to this object which must be done 1196 after the underlying device object has been attached to the device stack, 1197 i.e. you can send IRPs down this stack now. 1198 1199 Arguments: 1200 1201 none 1202 1203 Returns: 1204 1205 NTSTATUS 1206 1207 --*/ 1208 1209 { 1210 NTSTATUS status; 1211 1212 status = m_PnpMachine.Init(this, &FxPkgPnp::_PnpProcessEventInner); 1213 if (!NT_SUCCESS(status)) { 1214 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1215 "PnP State Machine init failed, %!STATUS!", 1216 status); 1217 return status; 1218 } 1219 1220 status = m_PowerMachine.Init(this, &FxPkgPnp::_PowerProcessEventInner); 1221 if (!NT_SUCCESS(status)) { 1222 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1223 "Power State Machine init failed, %!STATUS!", 1224 status); 1225 return status; 1226 } 1227 1228 status = m_PowerPolicyMachine.Init(this, &FxPkgPnp::_PowerPolicyProcessEventInner); 1229 if (!NT_SUCCESS(status)) { 1230 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1231 "Power Policy State Machine init failed, %!STATUS!", 1232 status); 1233 return status; 1234 } 1235 1236 return status; 1237 } 1238 1239 VOID 1240 FxPkgPnp::FinishInitialize( 1241 __inout PWDFDEVICE_INIT DeviceInit 1242 ) 1243 /*++ 1244 1245 Routine Description: 1246 Finish initializing the object. All initialization up until this point 1247 could fail. This function cannot fail, so all it can do is assign field 1248 values and take allocations from DeviceInit. 1249 1250 Arguments: 1251 DeviceInit - device initialization structure that the driver writer has 1252 initialized 1253 1254 Return Value: 1255 None 1256 1257 --*/ 1258 1259 { 1260 // 1261 // Reassign the state callback arrays away from the init struct. 1262 // Set the init field to NULL so that it does not attempt to free the array 1263 // when it is destroyed. 1264 // 1265 m_PnpStateCallbacks = DeviceInit->PnpPower.PnpStateCallbacks; 1266 DeviceInit->PnpPower.PnpStateCallbacks = NULL; 1267 1268 m_PowerStateCallbacks = DeviceInit->PnpPower.PowerStateCallbacks; 1269 DeviceInit->PnpPower.PowerStateCallbacks = NULL; 1270 1271 m_PowerPolicyStateCallbacks = DeviceInit->PnpPower.PowerPolicyStateCallbacks; 1272 DeviceInit->PnpPower.PowerPolicyStateCallbacks = NULL; 1273 1274 // 1275 // Bias the count towards one so that we can optimize the synchronous 1276 // cleanup case when the device is being destroyed. 1277 // 1278 m_PendingChildCount = 1; 1279 1280 // 1281 // Now "Add" this device in the terms that the PnP state machine uses. This 1282 // will be in the context of an actual AddDevice function for FDOs, and 1283 // something very much like it for PDOs. 1284 // 1285 // Important that the posting of the event is after setting of the state 1286 // callback arrays so that we can guarantee that any state transition 1287 // callback will be made. 1288 // 1289 PnpProcessEvent(PnpEventAddDevice); 1290 } 1291 1292 VOID 1293 FxPkgPnp::ProcessDelayedDeletion( 1294 VOID 1295 ) 1296 { 1297 DoTraceLevelMessage( 1298 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 1299 "WDFDEVICE %p, !devobj %p processing delayed deletion from pnp state " 1300 "machine", m_Device->GetHandle(), m_Device->GetDeviceObject()); 1301 1302 CleanupStateMachines(FALSE); 1303 DeleteDevice(); 1304 } 1305 1306 VOID 1307 FxPkgPnp::SetSpecialFileSupport( 1308 __in WDF_SPECIAL_FILE_TYPE FileType, 1309 __in BOOLEAN Supported 1310 ) 1311 1312 /*++ 1313 1314 Routine Description: 1315 1316 This function marks the device as capable of handling the paging path, 1317 hibernation or crashdumps. Any device that is necessary for one of these 1318 three things will get notification. It is then responsible for forwarding 1319 the notification to its parent. The Framework handles that. This 1320 function just allows a driver to tell the Framework how to respond. 1321 1322 1323 Arguments: 1324 1325 FileType - identifies which of the special paths the device is in 1326 Supported - Yes or No 1327 1328 Returns: 1329 1330 void 1331 1332 --*/ 1333 1334 { 1335 switch (FileType) { 1336 case WdfSpecialFilePaging: 1337 case WdfSpecialFileHibernation: 1338 case WdfSpecialFileDump: 1339 case WdfSpecialFileBoot: 1340 SetUsageSupport(_SpecialTypeToUsage(FileType), Supported); 1341 break; 1342 1343 default: 1344 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1345 "Invalid special file type %x", FileType); 1346 } 1347 } 1348 1349 _Must_inspect_result_ 1350 NTSTATUS 1351 PnpPassThroughQI( 1352 __in CfxDevice* Device, 1353 __inout FxIrp* Irp 1354 ) 1355 1356 /*++ 1357 1358 Routine Description: 1359 1360 This driver may be sent IRP_MN_QUERY_INTERFACE, which is a way of getting 1361 a direct-call table from some driver in a device stack. In some cases, the 1362 right response is to turn around and send a similar query to the device's 1363 parent. This function does that. 1364 1365 1366 Arguments: 1367 1368 Device - This WDFDEVICE. 1369 Irp - The IRP that was sent to us. 1370 1371 Returns: 1372 1373 NTSTATUS 1374 1375 --*/ 1376 1377 { 1378 MdIrp pFwdIrp; 1379 NTSTATUS status; 1380 NTSTATUS prevStatus; 1381 MxDeviceObject pTopOfStack; 1382 1383 prevStatus = Irp->GetStatus(); 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 pTopOfStack.SetObject(Device->m_ParentDevice->GetAttachedDeviceReference()); 1397 1398 pFwdIrp = FxIrp::AllocateIrp(pTopOfStack.GetStackSize()); 1399 1400 if (pFwdIrp != NULL) { 1401 FxAutoIrp fxFwdIrp(pFwdIrp); 1402 1403 // 1404 // The worker routine copies stack parameters to forward-Irp, sends it 1405 // down the stack synchronously, then copies back the stack parameters 1406 // from forward-irp to original-irp 1407 // 1408 PnpPassThroughQIWorker(&pTopOfStack, Irp, &fxFwdIrp); 1409 1410 if (fxFwdIrp.GetStatus() != STATUS_NOT_SUPPORTED) { 1411 status = fxFwdIrp.GetStatus(); 1412 } 1413 else { 1414 status = prevStatus; 1415 } 1416 1417 Irp->SetStatus(status); 1418 Irp->SetInformation(fxFwdIrp.GetInformation()); 1419 } 1420 else { 1421 status = STATUS_INSUFFICIENT_RESOURCES; 1422 1423 DoTraceLevelMessage( 1424 Device->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1425 "WDFDEVICE %p could not allocate IRP to send QI to parent !devobj " 1426 "%p, %!STATUS!", Device->GetHandle(), pTopOfStack.GetObject(), 1427 status); 1428 } 1429 1430 pTopOfStack.DereferenceObject(); 1431 1432 return status; 1433 } 1434 1435 _Must_inspect_result_ 1436 NTSTATUS 1437 FxPkgPnp::HandleQueryInterfaceForPowerThread( 1438 __inout FxIrp* Irp, 1439 __out PBOOLEAN CompleteRequest 1440 ) 1441 { 1442 NTSTATUS status; 1443 1444 *CompleteRequest = TRUE; 1445 1446 // 1447 // Send the request down the stack first. If someone lower handles it 1448 // or failed trying to, just return their status 1449 // 1450 status = SendIrpSynchronously(Irp); 1451 1452 if (NT_SUCCESS(status) || status != STATUS_NOT_SUPPORTED) { 1453 // 1454 // Success or failure trying to handle it 1455 // 1456 return status; 1457 } 1458 1459 // 1460 // The semantic of this QI is that it sent down while processing start or 1461 // a device usage notification on the way *up* the stack. That means that 1462 // by the time the QI gets to the lower part of the stack, the power thread 1463 // will have already been allocated and exported. 1464 // 1465 ASSERT(HasPowerThread()); 1466 1467 if (Irp->GetParameterQueryInterfaceVersion() == 1 && 1468 Irp->GetParameterQueryInterfaceSize() >= 1469 m_PowerThreadInterface.Interface.Size) { 1470 // 1471 // Expose the interface to the requesting driver. 1472 // 1473 CopyQueryInterfaceToIrpStack(&m_PowerThreadInterface, Irp); 1474 1475 status = STATUS_SUCCESS; 1476 1477 // 1478 // Caller assumes a reference has been taken. 1479 // 1480 m_PowerThreadInterface.Interface.InterfaceReference( 1481 m_PowerThreadInterface.Interface.Context 1482 ); 1483 } 1484 else { 1485 status = STATUS_INVALID_BUFFER_SIZE; 1486 } 1487 1488 return status; 1489 } 1490 1491 _Must_inspect_result_ 1492 NTSTATUS 1493 FxPkgPnp::HandleQueryInterface( 1494 __inout FxIrp* Irp, 1495 __out PBOOLEAN CompleteRequest 1496 ) 1497 1498 /*++ 1499 1500 Routine Description: 1501 1502 This driver may be sent IRP_MN_QUERY_INTERFACE, which is a way of getting 1503 a direct-call table from some driver in a device stack. This function 1504 looks into a list of interfaces that the driver has registered and, if 1505 the interface that is being sought is present, it answers the IRP. 1506 1507 Arguments: 1508 1509 Irp - The IRP that was sent to us. 1510 CompleteRequest - tells the caller whether the IRP should be completed 1511 1512 Returns: 1513 1514 NTSTATUS 1515 1516 --*/ 1517 1518 { 1519 FxDeviceProcessQueryInterfaceRequest callback; 1520 const GUID* pInterfaceType; 1521 PSINGLE_LIST_ENTRY ple; 1522 FxQueryInterface *pQI; 1523 PVOID pFound; 1524 PINTERFACE pExposedInterface; 1525 PVOID pExposedInterfaceSpecificData; 1526 BOOLEAN sendToParent; 1527 1528 NTSTATUS status; 1529 1530 *CompleteRequest = FALSE; 1531 1532 pFound = NULL; 1533 pQI = NULL; 1534 pExposedInterface = NULL; 1535 pExposedInterfaceSpecificData = NULL; 1536 sendToParent = FALSE; 1537 1538 pInterfaceType = Irp->GetParameterQueryInterfaceType(); 1539 // 1540 // The power thread is special cased because it has a different semantic 1541 // then the usual QI irp that we expose to the driver writer. In this case, 1542 // we want to fill in the interface if the lower stack does not support it. 1543 // 1544 if (FxIsEqualGuid(pInterfaceType, &GUID_POWER_THREAD_INTERFACE)) { 1545 return HandleQueryInterfaceForPowerThread(Irp, CompleteRequest); 1546 } 1547 else if (FxIsEqualGuid(pInterfaceType, &GUID_REENUMERATE_SELF_INTERFACE_STANDARD)) { 1548 if (m_Device->IsPdo()) { 1549 return ((FxPkgPdo*) this)->HandleQueryInterfaceForReenumerate( 1550 Irp, CompleteRequest); 1551 } 1552 } 1553 1554 status = Irp->GetStatus(); 1555 1556 // 1557 // Walk the interface collection and return the appropriate interface. 1558 // 1559 m_QueryInterfaceLock.AcquireLock(GetDriverGlobals()); 1560 1561 for (ple = m_QueryInterfaceHead.Next; ple != NULL; ple = ple->Next) { 1562 pQI = FxQueryInterface::_FromEntry(ple); 1563 1564 if (FxIsEqualGuid(Irp->GetParameterQueryInterfaceType(), 1565 &pQI->m_InterfaceType)) { 1566 1567 pExposedInterface = Irp->GetParameterQueryInterfaceInterface(); 1568 pExposedInterfaceSpecificData = 1569 Irp->GetParameterQueryInterfaceInterfaceSpecificData(); 1570 1571 if (pQI->m_Interface != NULL) { 1572 // 1573 // NOTE: If a driver has exposed the same interface GUID with 1574 // different sizes as a ways of versioning, then the driver 1575 // writer can specify the minimum size and version number 1576 // and then fill in the remaining fields in the callback 1577 // below. 1578 // 1579 if (pQI->m_Interface->Size <= Irp->GetParameterQueryInterfaceSize() && 1580 pQI->m_Interface->Version <= Irp->GetParameterQueryInterfaceVersion()) { 1581 1582 if (pQI->m_ImportInterface == FALSE) { 1583 // 1584 // Expose the interface to the requesting driver. 1585 // 1586 RtlCopyMemory(pExposedInterface, 1587 pQI->m_Interface, 1588 pQI->m_Interface->Size); 1589 } 1590 else { 1591 // 1592 // The interface contains data which the driver wants 1593 // before copying over its information, so don't do a 1594 // copy and let the event callback do the copy 1595 // 1596 DO_NOTHING(); 1597 } 1598 } 1599 else { 1600 status = STATUS_INVALID_BUFFER_SIZE; 1601 break; 1602 } 1603 } 1604 1605 callback.m_Method = pQI->m_ProcessRequest.m_Method; 1606 sendToParent = pQI->m_SendQueryToParentStack; 1607 pFound = pQI; 1608 1609 status = STATUS_SUCCESS; 1610 break; 1611 } 1612 } 1613 1614 m_QueryInterfaceLock.ReleaseLock(GetDriverGlobals()); 1615 1616 if (!NT_SUCCESS(status) || pFound == NULL) { 1617 goto Done; 1618 } 1619 1620 // 1621 // Let the driver see the interface before it is handed out. 1622 // 1623 status = callback.Invoke(m_Device->GetHandle(), 1624 (LPGUID) Irp->GetParameterQueryInterfaceType(), 1625 pExposedInterface, 1626 pExposedInterfaceSpecificData); 1627 1628 // 1629 // STATUS_NOT_SUPPORTED is a special cased error code which indicates that 1630 // the QI should travel down the rest of the stack. 1631 // 1632 if (!NT_SUCCESS(status) && status != STATUS_NOT_SUPPORTED) { 1633 goto Done; 1634 } 1635 1636 // 1637 // If it is meant for the parent, send it down the parent stack 1638 // 1639 if (sendToParent) { 1640 status = PnpPassThroughQI(m_Device, Irp); 1641 goto Done; 1642 } 1643 1644 // 1645 // Reference the interface before returning it to the requesting driver. 1646 // If this is an import interface, the event callback is free to not fill 1647 // in the InterfaceReference function pointer. 1648 // 1649 if (pExposedInterface->InterfaceReference != NULL) { 1650 pExposedInterface->InterfaceReference(pExposedInterface->Context); 1651 } 1652 1653 // 1654 // If we are not a PDO in the stack, then send the fully formatted QI request 1655 // down the stack to allow others to filter the interface. 1656 // 1657 if (m_Device->IsPdo() == FALSE) { 1658 ASSERT(NT_SUCCESS(status) || status == STATUS_NOT_SUPPORTED); 1659 1660 Irp->SetStatus(status); 1661 Irp->CopyCurrentIrpStackLocationToNext(); 1662 status = Irp->SendIrpSynchronously(m_Device->GetAttachedDevice()); 1663 } 1664 1665 Done: 1666 if (pFound != NULL) { 1667 *CompleteRequest = TRUE; 1668 } 1669 1670 return status; 1671 } 1672 1673 _Must_inspect_result_ 1674 NTSTATUS 1675 FxPkgPnp::QueryForCapabilities( 1676 VOID 1677 ) 1678 { 1679 STACK_DEVICE_CAPABILITIES caps; 1680 NTSTATUS status; 1681 1682 MxDeviceObject deviceObject; 1683 1684 deviceObject.SetObject(m_Device->GetDeviceObject()); 1685 1686 status = GetStackCapabilities(GetDriverGlobals(), 1687 &deviceObject, 1688 &m_D3ColdInterface, 1689 &caps); 1690 1691 if (NT_SUCCESS(status)) { 1692 ULONG states, i; 1693 1694 ASSERT(caps.DeviceCaps.DeviceWake <= 0xFF && caps.DeviceCaps.SystemWake <= 0xFF); 1695 1696 m_SystemWake = (BYTE) caps.DeviceCaps.SystemWake; 1697 1698 // 1699 // Initialize the array of wakeable D-states to say that all system 1700 // states down to the one identified in the caps can generate wake. 1701 // This will be overridden below if the BIOS supplied more information. 1702 // 1703 // Compatibility Note: Non-ACPI bus drivers (root-enumerated drivers) 1704 // or other bus drivers that haven't set the power settings correctly 1705 // for their PDO may end up with a valid value for DeviceWake in the 1706 // device capabilities but a value of PowerSystemUnspecified for 1707 // SystemWake, in which case a call to WdfDeviceAssignS0IdleSettings or 1708 // WdfDeviceAssignSxWakeSettings DDIs will fail on 1.11+ resulting in 1709 // device compat issues. The failure is expected and right thing to do 1710 // but has compatibility implications - drivers that worked earlier now 1711 // fail on 1.11. Note that earlier versions of WDF did not have 1712 // m_DeviceWake as an array and stored just the capabilities->DeviceWake 1713 // value without regard to the SystemWake but the current implementation 1714 // introduces dependency on systemWake value). So for compat reasons, 1715 // for pre-1.11 compiled drivers we initilaize the array with DeviceWake 1716 // value ignoring SystemWake, removing any dependency of DeviceWake 1717 // on SystemWake value and thus preserving previous behavior for 1718 // pre-1.11 compiled drivers. 1719 // 1720 if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(1,11)) { 1721 1722 RtlFillMemory(m_DeviceWake, DeviceWakeStates, DeviceWakeDepthNotWakeable); 1723 1724 for (i = PowerSystemWorking; i <= m_SystemWake; i++) { 1725 1726 // 1727 // Note that this cast is hiding a conversion between two slightly 1728 // incompatible types. DeviceWake is in terms of DEVICE_POWER_STATE 1729 // which is defined this way: 1730 // 1731 // typedef enum _DEVICE_POWER_STATE { 1732 // PowerDeviceUnspecified = 0, 1733 // PowerDeviceD0, 1734 // PowerDeviceD1, 1735 // PowerDeviceD2, 1736 // PowerDeviceD3, 1737 // PowerDeviceMaximum 1738 // } DEVICE_POWER_STATE, *PDEVICE_POWER_STATE; 1739 // 1740 // m_DeviceWake is defined in terms of DEVICE_WAKE_DEPTH which is 1741 // defined this way: 1742 // 1743 // typedef enum _DEVICE_WAKE_DEPTH { 1744 // DeviceWakeDepthNotWakeable = 0, 1745 // DeviceWakeDepthD0, 1746 // DeviceWakeDepthD1, 1747 // DeviceWakeDepthD2, 1748 // DeviceWakeDepthD3hot, 1749 // DeviceWakeDepthD3cold, 1750 // DeviceWakeDepthMaximum 1751 // } DEVICE_WAKE_DEPTH, *PDEVICE_WAKE_DEPTH; 1752 // 1753 // The result is that the conversion below will map D3 onto D3hot, 1754 // which is a safe assumption to start with, one which may be 1755 // overridden later. 1756 // 1757 C_ASSERT(PowerDeviceD0 == static_cast<DEVICE_POWER_STATE>(DeviceWakeDepthD0)); 1758 m_DeviceWake[i - PowerSystemWorking] = (BYTE) caps.DeviceCaps.DeviceWake; 1759 } 1760 } 1761 else { 1762 // 1763 // See comments above for information on mapping of device power 1764 // state to device wake depth. 1765 // 1766 RtlFillMemory(m_DeviceWake, 1767 DeviceWakeStates, 1768 (BYTE) caps.DeviceCaps.DeviceWake); 1769 } 1770 1771 // 1772 // Capture the S -> D state mapping table as a ULONG for use in the 1773 // power policy owner state machine when the machine moves into Sx and 1774 // the device is not armed for wake and has set an IdealDxStateForSx 1775 // value 1776 // 1777 states = 0x0; 1778 1779 for (i = 0; i < ARRAY_SIZE(caps.DeviceCaps.DeviceState); i++) { 1780 _SetPowerCapState(i, caps.DeviceCaps.DeviceState[i], &states); 1781 } 1782 1783 m_PowerPolicyMachine.m_Owner->m_SystemToDeviceStateMap = states; 1784 1785 // 1786 // Query for the D3cold support interface. If present, it will tell 1787 // us specifically which D-states will work for generating wake signals 1788 // from specific S-states. 1789 // 1790 // Earlier versions of WDF didn't make this query, so for compatibility, 1791 // we only make it now if the driver was built against WDF 1.11 or 1792 // later. In truth, this just shifts the failure from initialization 1793 // time to run time, because the information that we're presumably 1794 // getting from the BIOS with this interrogation is saying that the 1795 // code in earlier verisions of WDF would have blindly enabled a device 1796 // for wake which simply wasn't capable of generating its wake signal 1797 // from the chosen D-state. Thus the device would have been put into 1798 // a low power state and then failed to resume in response to its wake 1799 // signal. 1800 // 1801 1802 if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(1,11)) { 1803 1804 // 1805 // Cycle through all the system states that this device can wake 1806 // from. There's no need to look at deeper sleep states than 1807 // m_SystemWake because the driver will not arm for wake in 1808 // those states. 1809 // 1810 for (i = PowerSystemWorking; i <= m_SystemWake; i++) { 1811 if (caps.DeepestWakeableDstate[i] != DeviceWakeDepthMaximum) { 1812 m_DeviceWake[i - PowerSystemWorking] = (BYTE)caps.DeepestWakeableDstate[i]; 1813 } 1814 } 1815 } 1816 } 1817 1818 return status; 1819 } 1820 1821 _Must_inspect_result_ 1822 NTSTATUS 1823 FxPkgPnp::_PnpStartDevice( 1824 __inout FxPkgPnp* This, 1825 __inout FxIrp *Irp 1826 ) 1827 /*++ 1828 1829 Routine Description: 1830 This method is called in response to a PnP StartDevice IRP coming down the 1831 stack. 1832 1833 Arguments: 1834 This - device instance 1835 Irp - a pointer to the FxIrp 1836 1837 Returns: 1838 STATUS_PENDING 1839 1840 --*/ 1841 { 1842 This->SetPendingPnpIrp(Irp); 1843 This->PnpProcessEvent(PnpEventStartDevice); 1844 1845 return STATUS_PENDING; 1846 } 1847 1848 _Must_inspect_result_ 1849 NTSTATUS 1850 FxPkgPnp::_PnpQueryStopDevice( 1851 __inout FxPkgPnp* This, 1852 __inout FxIrp *Irp 1853 ) 1854 1855 /*++ 1856 1857 Routine Description: 1858 1859 Pnp callback querying to see if the device can be stopped. 1860 1861 The Framework philosophy surrounding Query Stop (and Query Remove) is that 1862 it's impossible to really know if you can stop unless you've tried to stop. 1863 This may not always be true, but it's hard to find a general strategy that 1864 works that is less conservative. Furthermore, I couldn't find good examples 1865 of drivers that would really benefit from continuing to handle requests 1866 until the actual Stop IRP arrived, particularly when you consider that 1867 most QueryStops are followed immediately by Stops. 1868 1869 So this function sends an event to the PnP State machine that begins the 1870 stopping process. If it is successful, then ultimately the QueryStop IRP 1871 will be successfully completed. 1872 1873 Arguments: 1874 1875 This - a pointer to the PnP package 1876 1877 Irp - a pointer to the FxIrp 1878 1879 Return Value: 1880 1881 STATUS_PENDING 1882 1883 --*/ 1884 1885 { 1886 // 1887 // Keep this IRP around, since we're going to deal with it later. 1888 // 1889 This->SetPendingPnpIrp(Irp); 1890 1891 // 1892 // Now run the state machine on this thread. 1893 // 1894 This->PnpProcessEvent(PnpEventQueryStop); 1895 1896 return STATUS_PENDING; 1897 } 1898 1899 _Must_inspect_result_ 1900 NTSTATUS 1901 FxPkgPnp::_PnpCancelStopDevice( 1902 __inout FxPkgPnp* This, 1903 __inout FxIrp *Irp 1904 ) 1905 /*++ 1906 1907 Routine Description: 1908 1909 This routine is invoked in response to a query stop failing, somewhere in 1910 the stack. Note that we can receive a cancel stop without being in the 1911 query stop state if a driver above us in the stack failed the query stop. 1912 1913 Again, this function just exists to bridge the gap between the WDM IRPs 1914 and the PnP state machine. This function does little more than send an 1915 event to the machine. 1916 1917 Arguments: 1918 1919 This - the package 1920 1921 Irp - a pointer to the FxIrp 1922 1923 Returns: 1924 1925 STATUS_PENDING 1926 1927 --*/ 1928 { 1929 // 1930 // Seed the irp with success 1931 // 1932 Irp->SetStatus(STATUS_SUCCESS); 1933 1934 // 1935 // Pend it and transition the state machine 1936 // 1937 This->SetPendingPnpIrp(Irp); 1938 This->PnpProcessEvent(PnpEventCancelStop); 1939 1940 return STATUS_PENDING; 1941 } 1942 1943 _Must_inspect_result_ 1944 NTSTATUS 1945 FxPkgPnp::_PnpStopDevice( 1946 __inout FxPkgPnp* This, 1947 __inout FxIrp *Irp 1948 ) 1949 /*++ 1950 1951 Routine Description: 1952 1953 This method is invoked in response to a Pnp StopDevice IRP. 1954 1955 Arguments: 1956 1957 Irp - a pointer to the FxIrp 1958 1959 Returns: 1960 1961 STATUS_PENDING 1962 1963 --*/ 1964 { 1965 // 1966 // Seed the irp with success 1967 // 1968 Irp->SetStatus(STATUS_SUCCESS); 1969 1970 // 1971 // Pend and transition the state machine 1972 // 1973 This->SetPendingPnpIrp(Irp); 1974 This->PnpProcessEvent(PnpEventStop); 1975 1976 return STATUS_PENDING; 1977 } 1978 1979 _Must_inspect_result_ 1980 NTSTATUS 1981 FxPkgPnp::_PnpQueryRemoveDevice( 1982 __inout FxPkgPnp* This, 1983 __inout FxIrp *Irp 1984 ) 1985 /*++ 1986 1987 Routine Description: 1988 1989 Again, the Framework handles QueryRemove by stopping everything going on 1990 related to the device and then asking the driver whether it can be 1991 removed. This function just kicks the state machine. Final completion 1992 of the IRP will come (much) later. 1993 1994 Arguments: 1995 1996 This - the package 1997 1998 Irp - a pointer to the FxIrp 1999 2000 Returns: 2001 2002 STATUS_PENDING 2003 2004 --*/ 2005 { 2006 // 2007 // By default we handle this state. 2008 // 2009 Irp->SetStatus(STATUS_SUCCESS); 2010 2011 // 2012 // Keep this IRP around, since we're going to deal with it later. 2013 // 2014 This->SetPendingPnpIrp(Irp); 2015 2016 // 2017 // Now run the state machine on this thread. 2018 // 2019 This->PnpProcessEvent(PnpEventQueryRemove); 2020 2021 return STATUS_PENDING; 2022 } 2023 2024 _Must_inspect_result_ 2025 NTSTATUS 2026 FxPkgPnp::_PnpCancelRemoveDevice( 2027 __inout FxPkgPnp* This, 2028 __inout FxIrp *Irp 2029 ) 2030 2031 /*++ 2032 2033 Routine Description: 2034 2035 Notification of a previous remove being canceled. Kick the state machine. 2036 2037 Arguments: 2038 2039 This - the package 2040 2041 Irp - FxIrp representing the notification 2042 2043 Return Value: 2044 2045 STATUS_PENDING 2046 2047 --*/ 2048 2049 { 2050 // 2051 // Seed the irp with success 2052 // 2053 Irp->SetStatus(STATUS_SUCCESS); 2054 2055 // 2056 // Pend it and transition the state machine 2057 // 2058 2059 This->SetPendingPnpIrp(Irp); 2060 This->PnpProcessEvent(PnpEventCancelRemove); 2061 2062 return STATUS_PENDING; 2063 } 2064 2065 VOID 2066 FxPkgPnp::CleanupStateMachines( 2067 __in BOOLEAN CleanupPnp 2068 ) 2069 { 2070 #if (FX_CORE_MODE==FX_CORE_USER_MODE) 2071 FxCREvent * event = m_CleanupEventUm.GetSelfPointer(); 2072 #else 2073 FxCREvent eventOnStack; 2074 eventOnStack.Initialize(); 2075 FxCREvent * event = eventOnStack.GetSelfPointer(); 2076 #endif 2077 2078 // 2079 // Order of shutdown is important here. 2080 // o Pnp initiates events to power policy. 2081 // o Power policy initiates events to power and device-power-requirement 2082 // o Power does not initiate any events 2083 // o Device-power-requirement does not initiate any events 2084 // 2085 // By shutting them down in the order in which they send events, we can 2086 // guarantee that no new events will be posted into the subsidiary state 2087 // machines. 2088 // 2089 2090 // 2091 // This will shut off the pnp state machine and synchronize any outstanding 2092 // threads of execution. 2093 // 2094 if (CleanupPnp && m_PnpMachine.SetFinished( 2095 event 2096 ) == FALSE) { 2097 DoTraceLevelMessage( 2098 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 2099 "WDFDEVICE %p, !devobj %p waiting for pnp state machine to finish", 2100 m_Device->GetHandle(), m_Device->GetDeviceObject()); 2101 2102 // 2103 // Process the event *before* completing the irp so that this event is in 2104 // the queue before the device remove event which will be processed 2105 // right after the start irp has been completed. 2106 // 2107 event->EnterCRAndWaitAndLeave(); 2108 } 2109 2110 // 2111 // Even though event is a SynchronizationEvent, so we need to reset it for 2112 // the next wait because SetFinished will set it if even if the transition 2113 // to the finished state is immediate 2114 // 2115 event->Clear(); 2116 2117 if (m_PowerPolicyMachine.SetFinished(event) == FALSE) { 2118 DoTraceLevelMessage( 2119 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 2120 "WDFDEVICE %p, !devobj %p waiting for pwr pol state machine to finish", 2121 m_Device->GetHandle(), m_Device->GetDeviceObject()); 2122 2123 event->EnterCRAndWaitAndLeave(); 2124 } 2125 2126 // 2127 // See previous comment about why we Clear() 2128 // 2129 event->Clear(); 2130 2131 if (m_PowerMachine.SetFinished(event) == FALSE) { 2132 DoTraceLevelMessage( 2133 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 2134 "WDFDEVICE %p, !devobj %p waiting for pwr state machine to finish", 2135 m_Device->GetHandle(), m_Device->GetDeviceObject()); 2136 2137 event->EnterCRAndWaitAndLeave(); 2138 } 2139 2140 if (IsPowerPolicyOwner()) { 2141 // 2142 // See previous comment about why we Clear() 2143 // 2144 event->Clear(); 2145 2146 if (NULL != m_PowerPolicyMachine.m_Owner->m_PoxInterface. 2147 m_DevicePowerRequirementMachine) { 2148 2149 if (FALSE == m_PowerPolicyMachine.m_Owner->m_PoxInterface. 2150 m_DevicePowerRequirementMachine->SetFinished(event)) { 2151 2152 DoTraceLevelMessage( 2153 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 2154 "WDFDEVICE %p, !devobj %p waiting for device power " 2155 "requirement state machine to finish", 2156 m_Device->GetHandle(), 2157 m_Device->GetDeviceObject()); 2158 2159 event->EnterCRAndWaitAndLeave(); 2160 } 2161 } 2162 2163 m_PowerPolicyMachine.m_Owner->CleanupPowerCallback(); 2164 } 2165 2166 // 2167 // Release the power thread if we have one either through creation or query. 2168 // Since the power policy state machine is off, we should no longer need 2169 // a dedicated thread. 2170 // 2171 // *** NOTE *** 2172 // The power thread must be released *BEFORE* sending the irp down the stack 2173 // because this can happen 2174 // 1) this driver is not the power thread owner, but the last client 2175 // 2) we send the pnp irp first 2176 // 3) the power thread owner waits on this thread for all the clients to go 2177 // away, but this device still has a reference on it 2178 // 4) this device will not release the reference b/c the owner is waiting 2179 // in the same thread. 2180 // 2181 ReleasePowerThread(); 2182 2183 // 2184 // Deref the reenumeration interface 2185 // 2186 ReleaseReenumerationInterface(); 2187 } 2188 2189 VOID 2190 FxPkgPnp::CleanupDeviceFromFailedCreate( 2191 __in MxEvent * WaitEvent 2192 ) 2193 /*++ 2194 2195 Routine Description: 2196 The device failed creation in some stage. It is assumed that the device has 2197 enough state that it can survive a transition through the pnp state machine 2198 (which means that pointers like m_PkgIo are valid and != NULL). When this 2199 function returns, it will have deleted the owning FxDevice. 2200 2201 Arguments: 2202 WaitEvent - Event on which RemoveProcessed wait will be performed 2203 2204 We can't initialize this event on stack as the initialization 2205 can fail in user-mode. We can't have Initialize method 2206 preinitailize this event either as this function may get called 2207 before initialize (or in case of initialization failure). 2208 2209 Hence the caller preallocates the event and passes to this 2210 function. 2211 2212 Caller must initialize this event as SynchronizationEvent 2213 and it must be unsignalled. 2214 Return Value: 2215 None 2216 2217 --*/ 2218 { 2219 Mx::MxAssert(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); 2220 2221 // 2222 // Caller must initialize the event as Synchronization event and it should 2223 // be passed as non-signalled. But we Clear it just to be sure. 2224 // 2225 WaitEvent->Clear(); 2226 2227 ADDREF(WaitEvent); 2228 2229 ASSERT(m_DeviceRemoveProcessed == NULL); 2230 m_DeviceRemoveProcessed = WaitEvent; 2231 2232 // 2233 // Simulate a remove event coming to the device. After this call returns 2234 // m_Device is still valid and must be deleted. 2235 // 2236 PnpProcessEvent(PnpEventRemove); 2237 2238 // 2239 // No need to wait in a critical region because we are in the context of a 2240 // pnp request which is in the system context. 2241 // 2242 WaitEvent->WaitFor(Executive, KernelMode, FALSE, NULL); 2243 m_DeviceRemoveProcessed = NULL; 2244 2245 RELEASE(WaitEvent); 2246 } 2247 2248 VOID 2249 FxPkgPnp::DeleteDevice( 2250 VOID 2251 ) 2252 /*++ 2253 2254 Routine Description: 2255 This routine will detach and delete the device object and free the memory 2256 for the device if there are no other references to it. Before calling this 2257 routine, the state machines should have been cleaned up and the power thread 2258 released. 2259 2260 --*/ 2261 { 2262 // 2263 // This will detach and delete the device object 2264 // 2265 m_Device->Destroy(); 2266 2267 // 2268 // If this is the last reference, this will free the memory for the device 2269 // 2270 m_Device->DeleteObject(); 2271 } 2272 2273 _Must_inspect_result_ 2274 NTSTATUS 2275 FxPkgPnp::_PnpRemoveDevice( 2276 __inout FxPkgPnp* This, 2277 __inout FxIrp *Irp 2278 ) 2279 2280 /*++ 2281 2282 Routine Description: 2283 2284 Notification of a remove. Kick the state machine. 2285 2286 Arguments: 2287 2288 This - the package 2289 2290 Irp - FxIrp representing the notification 2291 2292 Return Value: 2293 2294 status 2295 2296 --*/ 2297 2298 { 2299 #if (FX_CORE_MODE==FX_CORE_USER_MODE) 2300 MxEvent * event = This->m_RemoveEventUm.GetSelfPointer(); 2301 #else 2302 MxEvent eventOnStack; 2303 eventOnStack.Initialize(SynchronizationEvent, FALSE); 2304 MxEvent * event = eventOnStack.GetSelfPointer(); 2305 #endif 2306 2307 NTSTATUS status; 2308 2309 status = Mx::MxAcquireRemoveLock( 2310 This->m_Device->GetRemoveLock(), 2311 Irp->GetIrp()); 2312 2313 #if DBG 2314 ASSERT(NT_SUCCESS(status)); 2315 #else 2316 UNREFERENCED_PARAMETER(status); 2317 #endif 2318 2319 // 2320 // Keep this object around after m_Device has RELEASE'ed its reference to 2321 // this package. 2322 // 2323 This->ADDREF(Irp); 2324 2325 // 2326 // Removes are always success 2327 // 2328 Irp->SetStatus(STATUS_SUCCESS); 2329 2330 ASSERT(This->m_DeviceRemoveProcessed == NULL); 2331 This->m_DeviceRemoveProcessed = event; 2332 2333 // 2334 // Post the event and wait for the FxDevice to destroy itself or determine 2335 // it has not been reported missing yet (for PDOs and bus filters). 2336 // 2337 This->PnpProcessEvent(PnpEventRemove); 2338 2339 DoTraceLevelMessage( 2340 This->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 2341 "WDFDEVICE %p, !devobj %p waiting for remove event to finish processing", 2342 This->m_Device->GetHandle(), This->m_Device->GetDeviceObject()); 2343 2344 // 2345 // No need to wait in a critical region because we are in the context of a 2346 // pnp request which is in the system context. 2347 // 2348 event->WaitFor(Executive, KernelMode, FALSE, NULL); 2349 2350 This->m_DeviceRemoveProcessed = NULL; 2351 2352 status = This->ProcessRemoveDeviceOverload(Irp); 2353 2354 // 2355 // Release the reference added at the top. This is most likely going to be 2356 // the last reference on the package for KMDF. For UMDF, host manages the 2357 // lifetime of FxDevice so this may not be the last release for UMDF. 2358 // 2359 This->RELEASE(Irp); 2360 2361 return status; 2362 } 2363 2364 _Must_inspect_result_ 2365 NTSTATUS 2366 FxPkgPnp::PnpSurpriseRemoval( 2367 __inout FxIrp* Irp 2368 ) 2369 2370 /*++ 2371 2372 Routine Description: 2373 2374 Notification that the device has been surprise removed. Kick the state 2375 machine. 2376 2377 Arguments: 2378 2379 Irp - pointer to FxIrp representing this notification 2380 2381 Return Value: 2382 2383 STATUS_PENDING 2384 2385 --*/ 2386 2387 { 2388 // 2389 // Package specific handling 2390 // 2391 Irp->SetStatus(STATUS_SUCCESS); 2392 SetPendingPnpIrp(Irp); 2393 PnpProcessEvent(PnpEventSurpriseRemove); 2394 2395 return STATUS_PENDING; 2396 } 2397 2398 _Must_inspect_result_ 2399 NTSTATUS 2400 FxPkgPnp::_DispatchWaitWake( 2401 __inout FxPkgPnp* This, 2402 __inout FxIrp *Irp 2403 ) 2404 2405 /*++ 2406 2407 Routine Description: 2408 2409 This the first-level dispatch routine for IRP_MN_WAIT_WAKE. What one 2410 does with a WaitWake IRP depends very much on whether one is an FDO, a PDO 2411 or a filter. So dispatch immediately to a subclassable function. 2412 2413 Arguments: 2414 2415 This - the package 2416 2417 Irp - pointer to FxIrp representing this notification 2418 2419 Return Value: 2420 2421 status 2422 2423 --*/ 2424 2425 { 2426 return This->DispatchWaitWake(Irp); 2427 } 2428 2429 _Must_inspect_result_ 2430 NTSTATUS 2431 FxPkgPnp::DispatchWaitWake( 2432 __inout FxIrp *Irp 2433 ) 2434 /*++ 2435 2436 Routine Description: 2437 2438 Handles wait wake requests in a generic fashion 2439 2440 Arguments: 2441 2442 2443 Return Value: 2444 2445 --*/ 2446 { 2447 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); 2448 NTSTATUS status; 2449 PIRP oldIrp; 2450 KIRQL irql; 2451 2452 if (IsPowerPolicyOwner()) { 2453 if (m_PowerPolicyMachine.m_Owner->m_RequestedWaitWakeIrp == FALSE) { 2454 // 2455 // A power irp arrived, but we did not request it. log and bugcheck 2456 // 2457 DoTraceLevelMessage( 2458 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 2459 "Received wait wake power irp %p on device %p, but the irp was " 2460 "not requested by the device (the power policy owner)", 2461 Irp->GetIrp(), m_Device->GetDeviceObject()); 2462 2463 FxVerifierBugCheck(GetDriverGlobals(), // globals 2464 WDF_POWER_MULTIPLE_PPO, // specific type 2465 (ULONG_PTR)m_Device->GetDeviceObject(), //parm 2 2466 (ULONG_PTR)Irp->GetIrp()); // parm 3 2467 2468 /* NOTREACHED */ 2469 } 2470 2471 // 2472 // We are no longer requesting a power irp because we received the one 2473 // we requested. 2474 // 2475 m_PowerPolicyMachine.m_Owner->m_RequestedWaitWakeIrp = FALSE; 2476 } 2477 2478 // 2479 // The Framework has the concept of a "Wait/Wake Owner." This is the layer 2480 // in the stack that is enabling and disabling wake at the bus level. This 2481 // is probably the PDO or a bus filter like ACPI.sys. This is distinct 2482 // from being the "Power Policy Owner," which would mean that this driver 2483 // is deciding what D-state is appropriate for the device, and also 2484 // sending Wait/Wake IRPs. 2485 // 2486 2487 if (m_SharedPower.m_WaitWakeOwner) { 2488 m_PowerMachine.m_WaitWakeLock.Acquire(&irql); 2489 2490 if (m_SharedPower.m_WaitWakeIrp != NULL) { 2491 // 2492 // We only allow one pended wait wake irp in the stack at a time. 2493 // Fail this secondary wait wake request. 2494 // 2495 status = STATUS_INVALID_DEVICE_STATE; 2496 2497 DoTraceLevelMessage( 2498 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 2499 "Failing wait wake irp %p with %!STATUS! because wait wake irp " 2500 "%p already pended", 2501 Irp->GetIrp(), status, m_SharedPower.m_WaitWakeIrp); 2502 } 2503 else { 2504 MdCancelRoutine pRoutine; 2505 2506 // 2507 // No wait wake irp is currently in the stack, so attempt to set 2508 // a cancel routine and transition the power state machine into a 2509 // a state where it can arm the device at the bus level for this 2510 // child. 2511 // 2512 // The power state machine expects the wait wake irp to have a cancel 2513 // routine set in all states. For those states which require a 2514 // non cancelable irp, those states clear the cancel routine as 2515 // appropriate. 2516 // 2517 pRoutine = Irp->SetCancelRoutine(_PowerWaitWakeCancelRoutine); 2518 #if DBG 2519 ASSERT(pRoutine == NULL); 2520 #else 2521 UNREFERENCED_PARAMETER(pRoutine); 2522 #endif 2523 status = STATUS_PENDING; 2524 2525 if (Irp->IsCanceled()) { 2526 DoTraceLevelMessage(GetDriverGlobals(), 2527 TRACE_LEVEL_ERROR, TRACINGPNP, 2528 "wait wake irp %p already canceled", Irp->GetIrp()); 2529 2530 // 2531 // This IRP has already been cancelled, we must clear the cancel 2532 // routine before completing the IRP. 2533 // 2534 pRoutine = Irp->SetCancelRoutine(NULL); 2535 2536 if (pRoutine != NULL) { 2537 // 2538 // Our cancel routine will not be called 2539 // 2540 #if DBG 2541 ASSERT(pRoutine == _PowerWaitWakeCancelRoutine); 2542 #else 2543 UNREFERENCED_PARAMETER(pRoutine); 2544 #endif 2545 Irp->SetStatus(STATUS_CANCELLED); 2546 status = STATUS_CANCELLED; 2547 } 2548 } 2549 2550 if (status == STATUS_PENDING) { 2551 // 2552 // Either we successfully set the cancel routine or the irp 2553 // was canceled and the cancel routine is about to run when 2554 // we drop the lock. If the routine is about to run, we still 2555 // need to setup m_SharedPower to values that it expects. 2556 // 2557 Irp->MarkIrpPending(); 2558 m_SharedPower.m_WaitWakeIrp = Irp->GetIrp(); 2559 } 2560 } 2561 m_PowerMachine.m_WaitWakeLock.Release(irql); 2562 2563 if (NT_SUCCESS(status)) { 2564 // 2565 // Post to the appropriate matchines 2566 // 2567 PowerProcessEvent(PowerWakeArrival); 2568 2569 if (IsPowerPolicyOwner()) { 2570 PowerPolicyProcessEvent(PwrPolWakeArrived); 2571 } 2572 } 2573 else { 2574 CompletePowerRequest(Irp, status); 2575 } 2576 2577 return status; 2578 } 2579 else if (IsPowerPolicyOwner()) { 2580 // 2581 // Try to set m_WaitWakeIrp to the new IRP value only if the current 2582 // value of m_WaitWakeIrp is NULL because there can only be one 2583 // active wait wake irp in the stack at a time. Since the power policy 2584 // state machine never sends more then one, this is really a guard 2585 // against some other device in the stack sending a wait wake irp to 2586 // this device in the wrong state. 2587 // 2588 oldIrp = (PIRP) InterlockedCompareExchangePointer( 2589 (PVOID*) &m_SharedPower.m_WaitWakeIrp, 2590 Irp->GetIrp(), 2591 NULL 2592 ); 2593 2594 // 2595 // If oldIrp is NULL then there was no previous irp and we successfully 2596 // exchanged the new PIRP value into m_WaitWakeIrp 2597 // 2598 if (oldIrp == NULL) { 2599 m_PowerPolicyMachine.SetWaitWakeUnclaimed(); 2600 2601 // 2602 // NOTE: There is a built in race condition here that WDF cannot 2603 // solve with the given WDM primitives. After arming the 2604 // device for wake, there is a window where the wait wake irp 2605 // has not yet been processed by the wait wake owner. Until 2606 // the wake request is processed, wake events could be generated 2607 // and lost. There is nothing we can do about this until we 2608 // have synchronous "goto Dx and arm" command available. 2609 // 2610 Irp->CopyCurrentIrpStackLocationToNext(); 2611 Irp->SetCompletionRoutineEx(m_Device->GetDeviceObject(), 2612 _PowerPolicyWaitWakeCompletionRoutine, 2613 this); 2614 2615 // 2616 // Technically, there should be a PDO vs FDO overload here which 2617 // does the right thing w/regard to this request and if it is at the 2618 // bottom of the stack or not. But, by design, we check for 2619 // m_WaitWakeOwner first which has the direct side affect of making 2620 // it impossible for a PDO to get to this point. 2621 // 2622 ASSERT(m_Device->IsFdo()); 2623 2624 status = Irp->PoCallDriver(m_Device->GetAttachedDevice()); 2625 2626 // 2627 // Send the wake arrived after sending the request as commented above. 2628 // This window between sending the request and sending the event to 2629 // the state machine allows the wait owner to complete the request 2630 // immediately. When completed synchronously, it has an effect on 2631 // both wake scenarios: 2632 // 2633 // 1) wake from S0: the device never transitions to Dx and the idle 2634 // timer is resumed if no i/o is present 2635 // 2636 // 2) wake from sx: the device is disarmed for wake from Sx and 2637 // put into Dx with being armed for wake. 2638 // 2639 PowerPolicyProcessEvent(PwrPolWakeArrived); 2640 } 2641 else { 2642 status = STATUS_POWER_STATE_INVALID; 2643 2644 DoTraceLevelMessage( 2645 FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, 2646 "already have a ww irp %p, failing new ww irp %p with %!STATUS!", 2647 oldIrp, Irp->GetIrp(), status); 2648 2649 CompletePowerRequest(Irp, status); 2650 } 2651 } 2652 else { 2653 // 2654 // Not the power policy owner, not the wait wake irp owner, ignore the 2655 // irp 2656 // 2657 // This will release the remove lock. 2658 // 2659 status = FireAndForgetIrp(Irp); 2660 } 2661 2662 return status; 2663 } 2664 2665 _Must_inspect_result_ 2666 NTSTATUS 2667 FxPkgPnp::RegisterCallbacks( 2668 __in PWDF_PNPPOWER_EVENT_CALLBACKS DispatchTable 2669 ) 2670 { 2671 NTSTATUS status; 2672 2673 // 2674 // Update the callback table. 2675 // 2676 m_DeviceD0Entry.m_Method = DispatchTable->EvtDeviceD0Entry; 2677 m_DeviceD0EntryPostInterruptsEnabled.m_Method = 2678 DispatchTable->EvtDeviceD0EntryPostInterruptsEnabled; 2679 m_DeviceD0ExitPreInterruptsDisabled.m_Method = 2680 DispatchTable->EvtDeviceD0ExitPreInterruptsDisabled; 2681 m_DeviceD0Exit.m_Method = DispatchTable->EvtDeviceD0Exit; 2682 2683 m_DevicePrepareHardware.m_Method = DispatchTable->EvtDevicePrepareHardware; 2684 m_DeviceReleaseHardware.m_Method = DispatchTable->EvtDeviceReleaseHardware; 2685 2686 m_DeviceQueryStop.m_Method = DispatchTable->EvtDeviceQueryStop; 2687 m_DeviceQueryRemove.m_Method = DispatchTable->EvtDeviceQueryRemove; 2688 2689 m_DeviceSurpriseRemoval.m_Method = DispatchTable->EvtDeviceSurpriseRemoval; 2690 2691 m_DeviceUsageNotification.m_Method = DispatchTable->EvtDeviceUsageNotification; 2692 m_DeviceUsageNotificationEx.m_Method = DispatchTable->EvtDeviceUsageNotificationEx; 2693 m_DeviceRelationsQuery.m_Method = DispatchTable->EvtDeviceRelationsQuery; 2694 2695 if (DispatchTable->EvtDeviceSelfManagedIoCleanup != NULL || 2696 DispatchTable->EvtDeviceSelfManagedIoFlush != NULL || 2697 DispatchTable->EvtDeviceSelfManagedIoInit != NULL || 2698 DispatchTable->EvtDeviceSelfManagedIoSuspend != NULL || 2699 DispatchTable->EvtDeviceSelfManagedIoRestart != NULL) { 2700 2701 status = FxSelfManagedIoMachine::_CreateAndInit(&m_SelfManagedIoMachine, 2702 this); 2703 2704 if (!NT_SUCCESS(status)) { 2705 return status; 2706 } 2707 2708 m_SelfManagedIoMachine->InitializeMachine(DispatchTable); 2709 } 2710 2711 return STATUS_SUCCESS; 2712 } 2713 2714 VOID 2715 FxPkgPnp::RegisterPowerPolicyCallbacks( 2716 __in PWDF_POWER_POLICY_EVENT_CALLBACKS Callbacks 2717 ) 2718 { 2719 m_PowerPolicyMachine.m_Owner->m_DeviceArmWakeFromS0.m_Method = 2720 Callbacks->EvtDeviceArmWakeFromS0; 2721 m_PowerPolicyMachine.m_Owner->m_DeviceArmWakeFromSx.m_Method = 2722 Callbacks->EvtDeviceArmWakeFromSx; 2723 m_PowerPolicyMachine.m_Owner->m_DeviceArmWakeFromSx.m_MethodWithReason = 2724 Callbacks->EvtDeviceArmWakeFromSxWithReason; 2725 2726 m_PowerPolicyMachine.m_Owner->m_DeviceDisarmWakeFromS0.m_Method = 2727 Callbacks->EvtDeviceDisarmWakeFromS0; 2728 m_PowerPolicyMachine.m_Owner->m_DeviceDisarmWakeFromSx.m_Method = 2729 Callbacks->EvtDeviceDisarmWakeFromSx; 2730 2731 m_PowerPolicyMachine.m_Owner->m_DeviceWakeFromS0Triggered.m_Method = 2732 Callbacks->EvtDeviceWakeFromS0Triggered; 2733 m_PowerPolicyMachine.m_Owner->m_DeviceWakeFromSxTriggered.m_Method = 2734 Callbacks->EvtDeviceWakeFromSxTriggered; 2735 } 2736 2737 NTSTATUS 2738 FxPkgPnp::RegisterPowerPolicyWmiInstance( 2739 __in const GUID* Guid, 2740 __in FxWmiInstanceInternalCallbacks* Callbacks, 2741 __out FxWmiInstanceInternal** Instance 2742 ) 2743 { 2744 // WDF_WMI_PROVIDER_CONFIG config; 2745 // NTSTATUS status; 2746 2747 // WDF_WMI_PROVIDER_CONFIG_INIT(&config, Guid); 2748 2749 // // 2750 // // We are assuming we are registering either for the wait wake or device 2751 // // timeout GUIDs which both operate on BOOLEANs. If we expand this API in 2752 // // the future, have the caller pass in a config structure for the provider 2753 // // GUID. 2754 // // 2755 // config.MinInstanceBufferSize = sizeof(BOOLEAN); 2756 2757 // status = m_Device->m_PkgWmi->AddPowerPolicyProviderAndInstance( 2758 // &config, 2759 // Callbacks, 2760 // Instance); 2761 2762 // if (status == STATUS_OBJECT_NAME_COLLISION) { 2763 // status = STATUS_SUCCESS; 2764 // } 2765 2766 // if (!NT_SUCCESS(status)) { 2767 // DoTraceLevelMessage( 2768 // GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 2769 // "Failed to register WMI power GUID %!STATUS!", status); 2770 // } 2771 // 2772 // return status; 2773 ROSWDFNOTIMPLEMENTED; 2774 return STATUS_SUCCESS; 2775 } 2776 2777 NTSTATUS 2778 FxPkgPnp::PowerPolicySetS0IdleSettings( 2779 __in PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS Settings 2780 ) 2781 /*++ 2782 2783 Routine Description: 2784 2785 Updates the S0 Idle settings for the device and then posts an update event 2786 to the power policy state machine. The first this function is called, the 2787 ability to allow the user to control this setting is set. 2788 2789 Arguments: 2790 2791 Settings - The settings to apply. 2792 2793 Return Value: 2794 2795 NTSTATUS 2796 2797 --*/ 2798 { 2799 DEVICE_POWER_STATE dxState; 2800 ULONG idleTimeout; 2801 NTSTATUS status; 2802 BOOLEAN enabled, s0Capable, overridable, firstTime; 2803 WDF_TRI_STATE powerUpOnSystemWake; 2804 const LONGLONG negliblySmallIdleTimeout = -1; // 100 nanoseconds 2805 2806 s0Capable = FALSE; 2807 dxState = PowerDeviceD3; 2808 overridable = FALSE; 2809 firstTime = TRUE; 2810 2811 if (Settings->Enabled == WdfTrue) { 2812 enabled = TRUE; 2813 2814 } else if (Settings->Enabled == WdfUseDefault) { 2815 enabled = TRUE; 2816 2817 if (Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { 2818 DECLARE_CONST_UNICODE_STRING(valueName, WDF_S0_IDLE_DEFAULT_VALUE_NAME); 2819 2820 // 2821 // Read registry. If registry value is not found, the value of "enabled" 2822 // remains unchanged 2823 // 2824 ReadRegistryS0Idle(&valueName, &enabled); 2825 } 2826 else { 2827 DoTraceLevelMessage( 2828 GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP, 2829 "If registry value WdfDefaultIdleInWorkingState was present, " 2830 "it was not read because DDI WdfDeviceAssignS0IdleSettings " 2831 "was not called at PASSIVE_LEVEL"); 2832 } 2833 } 2834 else { 2835 enabled = FALSE; 2836 } 2837 2838 if (m_PowerPolicyMachine.m_Owner->m_IdleSettings.Set) { 2839 firstTime = FALSE; 2840 } 2841 2842 if (m_CapsQueried == FALSE && Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { 2843 status = QueryForCapabilities(); 2844 if (!NT_SUCCESS(status)) { 2845 return status; 2846 } 2847 2848 // 2849 // Do not set m_CapsQueried to TRUE yet because we will do that once we 2850 // know the entire stack has been built we will do the query again. 2851 // 2852 } 2853 2854 switch (Settings->IdleCaps) { 2855 case IdleUsbSelectiveSuspend: 2856 case IdleCanWakeFromS0: 2857 s0Capable = TRUE; 2858 2859 if (Settings->DxState == PowerDeviceMaximum) { 2860 dxState = PowerPolicyGetDeviceDeepestDeviceWakeState(PowerSystemWorking); 2861 2862 // 2863 // Some bus drivers 2864 2865 // incorrectly report DeviceWake=D0 to 2866 // indicate that it does not support wake instead of specifying 2867 // PowerDeviceUnspecified and KMDF ends up requesting 2868 // a D0 irp when going to Dx. The check prevents this bug. 2869 // 2870 if (dxState < PowerDeviceD1 || 2871 dxState > PowerDeviceD3 || 2872 (dxState > PowerDeviceD2 && Settings->IdleCaps == IdleUsbSelectiveSuspend) 2873 ) { 2874 status = STATUS_POWER_STATE_INVALID; 2875 2876 DoTraceLevelMessage( 2877 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 2878 "DeviceWake power state reported in device capabilities " 2879 "%!DEVICE_POWER_STATE! indicates that device can not signal" 2880 " a wake event, %!STATUS!", 2881 dxState, status); 2882 return status; 2883 } 2884 } 2885 else { 2886 DEVICE_POWER_STATE dxDeepest; 2887 2888 dxState = Settings->DxState; 2889 dxDeepest = PowerPolicyGetDeviceDeepestDeviceWakeState(PowerSystemWorking); 2890 2891 if (dxState > dxDeepest) { 2892 status = STATUS_POWER_STATE_INVALID; 2893 2894 DoTraceLevelMessage( 2895 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 2896 "DxState specified by driver %!DEVICE_POWER_STATE! cannot " 2897 "be lighter than lightest available device wake state" 2898 " %!DEVICE_POWER_STATE!, %!STATUS!", dxState, 2899 dxDeepest, status); 2900 return status; 2901 } 2902 2903 // 2904 // Can only perform wait wake from D2 on a USB device 2905 // 2906 if (dxState > PowerDeviceD2 && 2907 Settings->IdleCaps == IdleUsbSelectiveSuspend) { 2908 status = STATUS_POWER_STATE_INVALID; 2909 2910 DoTraceLevelMessage( 2911 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 2912 "DxState specified by driver %!DEVICE_POWER_STATE! cannot " 2913 "be lighter than PowerDeviceD2 for USB selective suspend " 2914 "%!STATUS!", 2915 dxState, status); 2916 return status; 2917 } 2918 } 2919 2920 if (Settings->IdleCaps == IdleUsbSelectiveSuspend) { 2921 status = m_PowerPolicyMachine.InitUsbSS(); 2922 2923 if (!NT_SUCCESS(status)) { 2924 DoTraceLevelMessage( 2925 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 2926 "Failed to initialize USB selective suspend %!STATUS!", 2927 status); 2928 return status; 2929 } 2930 } 2931 2932 break; 2933 2934 case IdleCannotWakeFromS0: 2935 s0Capable = FALSE; 2936 2937 if (Settings->DxState == PowerDeviceMaximum) { 2938 dxState = PowerDeviceD3; 2939 } 2940 else { 2941 dxState = Settings->DxState; 2942 } 2943 2944 break; 2945 2946 default: 2947 ASSERT(FALSE); 2948 break; 2949 } 2950 2951 if (Settings->IdleTimeout == IdleTimeoutDefaultValue) { 2952 idleTimeout = FxPowerPolicyDefaultTimeout; 2953 } 2954 else { 2955 idleTimeout = Settings->IdleTimeout; 2956 } 2957 2958 if (Settings->UserControlOfIdleSettings == IdleAllowUserControl) { 2959 2960 // status = UpdateWmiInstanceForS0Idle(AddInstance); 2961 // if (!NT_SUCCESS(status)) { 2962 // return status; 2963 // } __REACTOS__ 2964 2965 if (Settings->Enabled == WdfUseDefault) { 2966 // 2967 // Read the registry entry for idle enabled if it's the first time. 2968 // 2969 if (firstTime && Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { 2970 DECLARE_CONST_UNICODE_STRING(valueName, WDF_S0_IDLE_ENABLED_VALUE_NAME); 2971 2972 // 2973 // Read registry. If registry value is not found, the value of 2974 // "enabled" remains unchanged 2975 // 2976 ReadRegistryS0Idle(&valueName, &enabled); 2977 } 2978 else { 2979 // 2980 // Use the saved value for idle enabled. 2981 // 2982 enabled = m_PowerPolicyMachine.m_Owner->m_IdleSettings.Enabled; 2983 } 2984 } 2985 2986 overridable = TRUE; 2987 } 2988 else if (Settings->UserControlOfIdleSettings == IdleDoNotAllowUserControl) { 2989 // 2990 // No user control 2991 // 2992 overridable = FALSE; 2993 2994 // (void) UpdateWmiInstanceForS0Idle(RemoveInstance); __REACTOS__ 2995 } 2996 2997 // 2998 // !!!! DO NOT INTRODUCE FAILURES BEYOND THIS POINT !!!! 2999 // 3000 // We should not introduce any failures that are not due to driver errors 3001 // beyond this point. This is because we are going to commit the driver's 3002 // S0-idle settings now and any failure in the midst of that could leave us 3003 // in a bad state. Therefore, all failable code where the failure is beyond 3004 // the driver's control should be placed above this point. 3005 // 3006 // For example, a driver may want wake-from-S0 support, but the device may 3007 // not support it. We already checked for that failure above, before we 3008 // started committing any of the driver's S0-idle settings. 3009 // 3010 // Any failures below this point should only be due to driver errors, i.e. 3011 // the driver incorrectly calling the AssignS0IdleSettings DDI. 3012 // 3013 3014 if (firstTime) { 3015 m_PowerPolicyMachine.m_Owner->m_IdleSettings.Set = TRUE; 3016 m_PowerPolicyMachine.m_Owner->m_IdleSettings.Overridable = overridable; 3017 } 3018 3019 // 3020 // IdleTimeoutType is available only on > 1.9 3021 // 3022 #ifndef __REACTOS__ 3023 if (Settings->Size > sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9)) { 3024 if (firstTime) { 3025 if ((SystemManagedIdleTimeout == Settings->IdleTimeoutType) || 3026 (SystemManagedIdleTimeoutWithHint == 3027 Settings->IdleTimeoutType)) { 3028 // 3029 // This is the first time S0-idle policy is being specified and 3030 // the caller has asked for the idle timeout to be determined 3031 // by the power manager. 3032 // 3033 status = m_PowerPolicyMachine.m_Owner->m_IdleSettings. 3034 m_TimeoutMgmt.UseSystemManagedIdleTimeout( 3035 GetDriverGlobals() 3036 ); 3037 if (!NT_SUCCESS(status)) { 3038 return status; 3039 } 3040 } 3041 } else { 3042 // 3043 // This is not the first time S0-idle policy is being specified. 3044 // Verify that the caller is not trying to change their mind about 3045 // whether the idle timeout is determined by the power manager. 3046 // 3047 BOOLEAN currentlyUsingSystemManagedIdleTimeout; 3048 BOOLEAN callerWantsSystemManagedIdleTimeout; 3049 3050 currentlyUsingSystemManagedIdleTimeout = 3051 m_PowerPolicyMachine.m_Owner->m_IdleSettings.m_TimeoutMgmt. 3052 UsingSystemManagedIdleTimeout(); 3053 callerWantsSystemManagedIdleTimeout = 3054 ((SystemManagedIdleTimeout == Settings->IdleTimeoutType) || 3055 (SystemManagedIdleTimeoutWithHint == Settings->IdleTimeoutType)); 3056 3057 // 3058 // UMDF currently does not implement 3059 // IdleTimeoutManagement::_SystemManagedIdleTimeoutAvailable. So 3060 // that method must be called only as part of the second check in 3061 // the "if" statement below. Since UMDF currently does not support 3062 // system managed idle timeout, the first check will always evaluate 3063 // to 'FALSE', so the second check never gets executed for UMDF. 3064 // 3065 if ((callerWantsSystemManagedIdleTimeout != 3066 currentlyUsingSystemManagedIdleTimeout) 3067 && 3068 (IdleTimeoutManagement::_SystemManagedIdleTimeoutAvailable()) 3069 ) { 3070 3071 status = STATUS_INVALID_DEVICE_REQUEST; 3072 DoTraceLevelMessage( 3073 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3074 "A previous call to assign S0-idle policy specified that " 3075 "the idle timeout %s be determined by the power manager. " 3076 "This decision cannot be changed. %!STATUS!", 3077 currentlyUsingSystemManagedIdleTimeout ? 3078 "should" : 3079 "should not", 3080 status); 3081 FxVerifierDbgBreakPoint(GetDriverGlobals()); 3082 return status; 3083 } 3084 } 3085 } 3086 #endif 3087 3088 if (Settings->IdleCaps == IdleCannotWakeFromS0) { 3089 // 3090 // PowerUpIdleDeviceOnSystemWake field added after v1.7. 3091 // By default KMDF uses an optimization where the device is not powered 3092 // up when resuming from Sx if it is idle. The field 3093 // PowerUpIdleDeviceOnSystemWake is used to turn off this optimization and allow 3094 // device to power up when resuming from Sx. Note that this optimization 3095 // is applicable only for IdleCannotWakeFromS0. In other cases the 3096 // device is always powered up in order to arm for wake. 3097 // 3098 powerUpOnSystemWake = 3099 (Settings->Size > sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7)) ? 3100 Settings->PowerUpIdleDeviceOnSystemWake : 3101 WdfUseDefault; 3102 3103 switch(powerUpOnSystemWake) { 3104 case WdfTrue: 3105 m_PowerPolicyMachine.m_Owner->m_IdleSettings.PowerUpIdleDeviceOnSystemWake = TRUE; 3106 DoTraceLevelMessage( 3107 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 3108 "Driver turned off S0Idle optimization. Device will be " 3109 "powered up on resume from Sx even when it is idle"); 3110 break; 3111 case WdfFalse: 3112 m_PowerPolicyMachine.m_Owner->m_IdleSettings.PowerUpIdleDeviceOnSystemWake = FALSE; 3113 DoTraceLevelMessage( 3114 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 3115 "Driver turned on S0Idle optimization. Device will remain " 3116 "powered off if idle when resuming from Sx"); 3117 break; 3118 case WdfUseDefault: 3119 DO_NOTHING(); 3120 break; 3121 default: 3122 break; 3123 } 3124 } 3125 3126 if (FALSE == 3127 m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapabilityKnown) 3128 { 3129 if (Settings->IdleCaps == IdleUsbSelectiveSuspend) { 3130 m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapable = TRUE; 3131 m_PowerPolicyMachine.m_Owner-> 3132 m_IdleSettings.UsbSSCapabilityKnown = TRUE; 3133 3134 } else if (Settings->IdleCaps == IdleCanWakeFromS0) { 3135 3136 m_PowerPolicyMachine.m_Owner-> 3137 m_IdleSettings.UsbSSCapabilityKnown = TRUE; 3138 } 3139 } 3140 3141 // 3142 // Wake FromS0Capable is set every time because we want to allow the driver 3143 // to swap between idle wake capable and idle not wake capable. This should 3144 // be allowed so that a scenario similar to the following can be implemented: 3145 // 3146 // a) when the device has an outstanding open, the device should arm itself 3147 // for wake when idle 3148 // 3149 // b) when the device does not have an outstanding open, the device should 3150 // be off and not armed. 3151 // 3152 // The only way to be off is to assign S0 wake settings, so the 3153 // WakeFromS0Capable field must change on each DDI call. This is not a 3154 // problem for the power policy state machine because it evaluates 3155 // WakeFromS0Capable state before enabling of idle. If we are not 3156 // WakeFromS0Capable and USB SS capable (ie a have a torn/unsynchronized 3157 // state) in m_IdleSettings, we will recover from it when processing 3158 // PwrPolS0IdlePolicyChanged in the state machine (b/c this event causes 3159 // both fields to be reevaluated). 3160 // 3161 m_PowerPolicyMachine.m_Owner->m_IdleSettings.WakeFromS0Capable = s0Capable; 3162 3163 m_PowerPolicyMachine.m_Owner->m_IdleSettings.DxState = dxState; 3164 3165 if (m_PowerPolicyMachine.m_Owner-> 3166 m_IdleSettings.m_TimeoutMgmt.UsingSystemManagedIdleTimeout()) { 3167 // 3168 // With system managed idle timeout, we don't want to apply an idle 3169 // timeout of our own on top of that. Effectively, our idle timeout is 3170 // 0. 3171 // But we apply a negligibly small timeout value as this allows us to 3172 // keep the same logic in the idle state machine, regardless of whether 3173 // we're using system-managed idle timeout or driver-managed idle 3174 // timeout. 3175 // 3176 if (firstTime) { 3177 m_PowerPolicyMachine.m_Owner-> 3178 m_PowerIdleMachine.m_PowerTimeout.QuadPart = 3179 negliblySmallIdleTimeout; 3180 } 3181 3182 if (SystemManagedIdleTimeoutWithHint == Settings->IdleTimeoutType) { 3183 // 3184 // We save the idle timeout hint, but we don't provide the hint to 3185 // the power framework immediately. This is because currently we may 3186 // or may not be registered with the power framework. Note that 3187 // WdfDeviceAssignS0IdleSettings might get called even when we are 3188 // not registered with the power framework. 3189 // 3190 // Therefore, we provide the hint to the power framework only when 3191 // we get to the WdfDevStatePwrPolStartingDecideS0Wake state. This 3192 // state is a good choice for providing the hint because: 3193 // 1. We know we would be registered with the power framework when 3194 // we are in this state. 3195 // 2. Any change in S0-idle settings causes us to go through this 3196 // state. 3197 // 3198 m_PowerPolicyMachine.m_Owner->m_PoxInterface.m_NextIdleTimeoutHint = 3199 idleTimeout; 3200 } 3201 3202 } else { 3203 m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.m_PowerTimeout.QuadPart 3204 = WDF_REL_TIMEOUT_IN_MS(idleTimeout); 3205 } 3206 3207 // 3208 // If the driver is 1.11 or later, update the bus drivers with the client's 3209 // choice on the topic of D3hot or D3cold. 3210 // 3211 if ((Settings->Size > sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9)) && 3212 (Settings->ExcludeD3Cold != WdfUseDefault)) { 3213 MxDeviceObject deviceObject; 3214 BOOLEAN enableD3Cold; 3215 3216 deviceObject.SetObject(m_Device->GetDeviceObject()); 3217 3218 switch (Settings->ExcludeD3Cold) { 3219 case WdfFalse: 3220 enableD3Cold = TRUE; 3221 break; 3222 default: 3223 DoTraceLevelMessage( 3224 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3225 "Invalid tri-state value for ExcludeD3Cold %d", 3226 Settings->ExcludeD3Cold); 3227 __fallthrough; 3228 case WdfTrue: 3229 enableD3Cold = FALSE; 3230 break; 3231 } 3232 3233 SetD3ColdSupport(GetDriverGlobals(), 3234 &deviceObject, 3235 &m_D3ColdInterface, 3236 enableD3Cold); 3237 } 3238 3239 PowerPolicySetS0IdleState(enabled); 3240 3241 return STATUS_SUCCESS; 3242 } 3243 3244 NTSTATUS 3245 FxPkgPnp::PowerPolicySetSxWakeSettings( 3246 __in PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS Settings, 3247 __in BOOLEAN ArmForWakeIfChildrenAreArmedForWake, 3248 __in BOOLEAN IndicateChildWakeOnParentWake 3249 ) 3250 /*++ 3251 3252 Routine Description: 3253 3254 Updates the Sx wake settings for the device. No event is posted to the 3255 state machine because this setting is statically checked when the machine 3256 is entering an Sx state (unlike S0 idle which can be checked at any time). 3257 3258 The first this function is called, the ability to allow the user to control 3259 this setting is set. 3260 3261 Arguments: 3262 3263 Settings - the new settings to apply 3264 3265 ArmForWakeIfChildrenAreArmedForWake - Inidicates whether the device 3266 should arm for wake when one or more children are armed for wake 3267 3268 IndicateChildWakeOnParentWake - Indicates whether the device should 3269 propagate the wake status to its children 3270 3271 Return Value: 3272 3273 NTSTATUS 3274 3275 --*/ 3276 { 3277 DEVICE_POWER_STATE dxState; 3278 NTSTATUS status; 3279 BOOLEAN overridable, firstTime, enabled; 3280 3281 dxState = PowerDeviceD3; 3282 overridable = FALSE; 3283 firstTime = TRUE; 3284 3285 if (Settings->Enabled == WdfTrue) { 3286 enabled = TRUE; 3287 3288 } 3289 else if (Settings->Enabled == WdfUseDefault) { 3290 enabled = TRUE; 3291 3292 if (Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { 3293 DECLARE_CONST_UNICODE_STRING(valueName, WDF_SX_WAKE_DEFAULT_VALUE_NAME); 3294 3295 // 3296 // Read registry. If registry value is not found, the value of "enabled" 3297 // remains unchanged 3298 // 3299 ReadRegistrySxWake(&valueName, &enabled); 3300 } 3301 else { 3302 DoTraceLevelMessage( 3303 GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP, 3304 "If registry value WdfDefaultWakeFromSleepState was present, " 3305 "it was not read because DDI WdfDeviceAssignSxWakeSettings " 3306 "was not called at PASSIVE_LEVEL"); 3307 } 3308 } 3309 else { 3310 enabled = FALSE; 3311 } 3312 3313 if (m_PowerPolicyMachine.m_Owner->m_WakeSettings.Set) { 3314 firstTime = FALSE; 3315 } 3316 3317 if (m_CapsQueried == FALSE && Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { 3318 status = QueryForCapabilities(); 3319 if (!NT_SUCCESS(status)) { 3320 return status; 3321 } 3322 3323 // 3324 // Do not set m_CapsQueried to TRUE yet because we will do that once we 3325 // know the entire stack has been built we will do the query again. 3326 // 3327 } 3328 3329 if (Settings->DxState == PowerDeviceMaximum) { 3330 dxState = PowerPolicyGetDeviceDeepestDeviceWakeState((SYSTEM_POWER_STATE)m_SystemWake); 3331 3332 // 3333 // Some bus drivers 3334 3335 // incorrectly report DeviceWake=D0 to 3336 // indicate that it does not support wake instead of specifying 3337 // PowerDeviceUnspecified and KMDF ends up requesting 3338 // a D0 irp when going to Dx. The check prevents this bug. 3339 // 3340 if (dxState < PowerDeviceD1 || dxState > PowerDeviceD3) { 3341 status = STATUS_POWER_STATE_INVALID; 3342 3343 DoTraceLevelMessage( 3344 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3345 "DeviceWake power state reported in device capabilities " 3346 "%!DEVICE_POWER_STATE! indicates that device can not signal a " 3347 "wake event, %!STATUS!", 3348 dxState, status); 3349 return status; 3350 } 3351 } 3352 else { 3353 DEVICE_POWER_STATE dxDeepest; 3354 3355 dxState = Settings->DxState; 3356 dxDeepest = PowerPolicyGetDeviceDeepestDeviceWakeState((SYSTEM_POWER_STATE)m_SystemWake); 3357 3358 if (dxState > dxDeepest) { 3359 status = STATUS_POWER_STATE_INVALID; 3360 DoTraceLevelMessage( 3361 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3362 "DxState specified by driver %!DEVICE_POWER_STATE! cannot be" 3363 " lighter than lightest available device wake state " 3364 "%!DEVICE_POWER_STATE!, %!STATUS!", dxState, 3365 dxDeepest, status); 3366 return status; 3367 } 3368 } 3369 3370 if (Settings->UserControlOfWakeSettings == WakeAllowUserControl) { 3371 3372 // status = UpdateWmiInstanceForSxWake(AddInstance); __REACTOS__ 3373 3374 // if (!NT_SUCCESS(status)) { 3375 // return status; 3376 // } 3377 3378 if (Settings->Enabled == WdfUseDefault) { 3379 // 3380 // Read the registry entry for wake enabled if it's the first time. 3381 // 3382 if (firstTime && Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { 3383 DECLARE_CONST_UNICODE_STRING(valueName, WDF_SX_WAKE_ENABLED_VALUE_NAME); 3384 3385 // 3386 // Read registry. If registry value is not found, the value of 3387 // "enabled" remains unchanged 3388 // 3389 ReadRegistrySxWake(&valueName, &enabled); 3390 } 3391 else { 3392 // 3393 // Use the saved value for wake enabled. 3394 // 3395 enabled = m_PowerPolicyMachine.m_Owner->m_WakeSettings.Enabled; 3396 } 3397 } 3398 3399 overridable = TRUE; 3400 } 3401 else if (Settings->UserControlOfWakeSettings == WakeDoNotAllowUserControl) { 3402 // 3403 // No user control, just set to enabled 3404 // 3405 overridable = FALSE; 3406 3407 // (void) UpdateWmiInstanceForSxWake(RemoveInstance); __REACTOS__ 3408 } 3409 3410 if (firstTime) { 3411 m_PowerPolicyMachine.m_Owner->m_WakeSettings.Set = TRUE; 3412 m_PowerPolicyMachine.m_Owner->m_WakeSettings.Overridable = overridable; 3413 3414 // 3415 // If ArmForWakeIfChildrenAreArmedForWake setting is set to FALSE, 3416 // then we use the legacy framework behavior which did not depend 3417 // on the child device being capable of arming for wake or not. 3418 // 3419 m_PowerPolicyMachine.m_Owner->m_WakeSettings.ArmForWakeIfChildrenAreArmedForWake = 3420 ArmForWakeIfChildrenAreArmedForWake; 3421 3422 // 3423 // If IndicateChildWakeOnParentWake setting is set to FALSE, then 3424 // we use the legacy framework behavior wherein the wake status 3425 // is not propagated from the parent device to the child device. 3426 // 3427 m_PowerPolicyMachine.m_Owner->m_WakeSettings.IndicateChildWakeOnParentWake = 3428 IndicateChildWakeOnParentWake; 3429 } 3430 3431 m_PowerPolicyMachine.m_Owner->m_WakeSettings.DxState = dxState; 3432 3433 PowerPolicySetSxWakeState(enabled); 3434 3435 return STATUS_SUCCESS; 3436 } 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 NTSTATUS 3455 FxPkgPnp::_S0IdleQueryInstance( 3456 __in CfxDevice* Device, 3457 __in FxWmiInstanceInternal* /* Instance */, 3458 __in ULONG /* OutBufferSize */, 3459 __out PVOID OutBuffer, 3460 __out PULONG BufferUsed 3461 ) 3462 { 3463 *((BOOLEAN*) OutBuffer) = 3464 (Device->m_PkgPnp)->m_PowerPolicyMachine.m_Owner->m_IdleSettings.Enabled; 3465 *BufferUsed = sizeof(BOOLEAN); 3466 3467 return STATUS_SUCCESS; 3468 } 3469 3470 NTSTATUS 3471 FxPkgPnp::_S0IdleSetInstance( 3472 __in CfxDevice* Device, 3473 __in FxWmiInstanceInternal* /* Instance */, 3474 __in ULONG /* InBufferSize */, 3475 __in PVOID InBuffer 3476 ) 3477 { 3478 BOOLEAN value; 3479 3480 3481 // 3482 // FxWmiIrpHandler makes sure the buffer is at least one byte big, so we 3483 // don't check the buffer size. 3484 // 3485 3486 value = *(PBOOLEAN) InBuffer; 3487 3488 (Device->m_PkgPnp)->PowerPolicySetS0IdleState(value); 3489 3490 return STATUS_SUCCESS; 3491 } 3492 3493 NTSTATUS 3494 FxPkgPnp::_S0IdleSetItem( 3495 __in CfxDevice* Device, 3496 __in FxWmiInstanceInternal* /* Instance */, 3497 __in ULONG DataItemId, 3498 __in ULONG InBufferSize, 3499 __in PVOID InBuffer 3500 ) 3501 { 3502 BOOLEAN value; 3503 3504 if (DataItemId != 0) { 3505 return STATUS_INVALID_DEVICE_REQUEST; 3506 } 3507 3508 if (InBufferSize < sizeof(BOOLEAN)) { 3509 return STATUS_BUFFER_TOO_SMALL; 3510 } 3511 3512 value = *(BOOLEAN*) InBuffer; 3513 (Device->m_PkgPnp)->PowerPolicySetS0IdleState(value); 3514 3515 return STATUS_SUCCESS; 3516 } 3517 3518 NTSTATUS 3519 FxPkgPnp::_SxWakeQueryInstance( 3520 __in CfxDevice* Device, 3521 __in FxWmiInstanceInternal* /* Instance */, 3522 __in ULONG /* OutBufferSize */, 3523 __out PVOID OutBuffer, 3524 __out PULONG BufferUsed 3525 ) 3526 { 3527 *((BOOLEAN*) OutBuffer) = 3528 (Device->m_PkgPnp)->m_PowerPolicyMachine.m_Owner->m_WakeSettings.Enabled; 3529 *BufferUsed = sizeof(BOOLEAN); 3530 3531 return STATUS_SUCCESS; 3532 } 3533 3534 NTSTATUS 3535 FxPkgPnp::_SxWakeSetInstance( 3536 __in CfxDevice* Device, 3537 __in FxWmiInstanceInternal* /* Instance */, 3538 __in ULONG /* InBufferSize */, 3539 __in PVOID InBuffer 3540 ) 3541 { 3542 BOOLEAN value; 3543 3544 // 3545 // FxWmiIrpHandler makes sure that the buffer is at least one byte big, so 3546 // we don't check the buffer size 3547 // 3548 value = *(PBOOLEAN) InBuffer; 3549 3550 (Device->m_PkgPnp)->PowerPolicySetSxWakeState(value); 3551 3552 return STATUS_SUCCESS; 3553 } 3554 3555 NTSTATUS 3556 FxPkgPnp::_SxWakeSetItem( 3557 __in CfxDevice* Device, 3558 __in FxWmiInstanceInternal* /* Instance */, 3559 __in ULONG DataItemId, 3560 __in ULONG InBufferSize, 3561 __in PVOID InBuffer 3562 ) 3563 { 3564 BOOLEAN value; 3565 3566 if (DataItemId != 0) { 3567 return STATUS_INVALID_DEVICE_REQUEST; 3568 } 3569 3570 if (InBufferSize < sizeof(BOOLEAN)) { 3571 return STATUS_BUFFER_TOO_SMALL; 3572 } 3573 3574 value = *(BOOLEAN*) InBuffer; 3575 (Device->m_PkgPnp)->PowerPolicySetSxWakeState(value); 3576 3577 return STATUS_SUCCESS; 3578 } 3579 3580 _Must_inspect_result_ 3581 NTSTATUS 3582 FxPkgPnp::PowerPolicyHandleSystemQueryPower( 3583 __in SYSTEM_POWER_STATE QueryState 3584 ) 3585 /*++ 3586 3587 Framework Philosophy Discussion: 3588 3589 WDM sends IRP_MN_QUERY_POWER for system power states (where system power 3590 states are S0-working, S1-light-sleep, S2-deeper-sleep, S3-deepest-sleep, 3591 S4-hibernation, S5-soft-off.) The idea is that, if a driver can't support 3592 a particular state, it fails the query. The problem is that this idea is 3593 horribly broken. 3594 3595 The first problem is that WDM doesn't always send these IRPs. In some 3596 situations, (very low battery, system getting critically hot) WDM will 3597 attempt to preserve user data by sleeping or hibernating, rather than just 3598 crashing. This is good, but it makes a driver writer's life very difficult, 3599 since it means that you have to deal with being told to go to a particular 3600 state even if you think that your device won't be able to deal well with 3601 that state. 3602 3603 The second problem is that, by the time the system is going to sleep, the 3604 user probably isn't still looking at the screen. This is especially true 3605 for laptop computers, as the system is very likely sleeping because the 3606 user closed the clamshell lid. So any attempt to ask the user how to 3607 resolve a situation where a driver doesn't want to go to a low power state 3608 is futile. Furthermore, even when the screen is still available, users 3609 dislike it when they push the sleep button or the power button on their 3610 machines and the machines don't do what they were told to do. 3611 3612 The third problem is related to the second. While there may be completely 3613 legitimate reasons for the driver to want to delay or even to veto a 3614 transition into a sleep state, (an example of a valid scenario would be one 3615 in which the driver was involved in burning a CD, an operation which can't 3616 be interrupted,) there isn't any good way for a driver to interact with a 3617 user anyhow. (Which desktop is the right one to send messages to? What 3618 should the UI for problem resolution look like? How does a driver put up 3619 UI anyhow?) 3620 3621 All the driver really knows is that it will or won't be able to maintain 3622 device state, and it will or won't be able to get enough power to arm 3623 any wake events that it might want to deliver (like PME#.) 3624 3625 Consequently, the designers of the PnP/Power model in the Framework have 3626 decided that all QueryPower-Sx IRPs will be completed successfully 3627 except if the device cannot maintain enough power to trigger its wake 3628 signal *AND* if the system supports lighter sleep states than the 3629 one that is currently being queried. (If it does, then the kernel's power 3630 manager will turn right around and query for those, next.) 3631 3632 This story usually brings up a few objections: 3633 3634 1) My device is important! When it's operating, I don't want 3635 the machine to just fall asleep. I need to fail QueryPower-Sx to 3636 prevent that. 3637 3638 This objection is an unfortunate consequence of the existing DDK. There 3639 is a perfectly good API that allows a driver to say that the machine 3640 shouldn't just fall asleep. (See PoSetSystemState.) If a user presses 3641 a button telling the machine to go to sleep, then the driver has a 3642 responsibility to do that. 3643 3644 2) There are certain operations that just can't be interrupted! 3645 3646 While that's true, those operations started somewhere, probably in user- 3647 mode. Those same user-mode components would be much, much better suited 3648 toward negotiating with the user or with other components to figure out 3649 what to do when the uninterruptable must be interrupted. User-mode 3650 components get notification that the system is going to sleep and they 3651 can delay or veto the transition. Get over the idea that your driver 3652 needs to be involved, too. 3653 3654 Routine Description: 3655 3656 Determines if for the passed in System state, if we can wake the machine 3657 from it. If the query state is the machine's minimum system state, then 3658 we always succeed it because we want the machine to go to at least some 3659 sleeping state. We always succeed hibernate and system off requests as well. 3660 3661 Arguments: 3662 3663 QueryState - The proposed system state 3664 3665 Return Value: 3666 3667 NT_SUCCESS if the queried state should be allowed, !NT_SUCCESS otherwise 3668 3669 --*/ 3670 { 3671 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); 3672 NTSTATUS status; 3673 3674 if (QueryState >= PowerSystemHibernate || 3675 PowerPolicyCanWakeFromSystemState(QueryState)) { 3676 // 3677 // If the query is for the machine's minimum S state or we going into 3678 // hibernate or off, always succeed it. 3679 // 3680 status = STATUS_SUCCESS; 3681 } 3682 else { 3683 3684 // 3685 // On Windows Vista and above, its OK to return a failure status code 3686 // if the system is going into an S state at which the device cannot 3687 // wake the system. 3688 // 3689 ASSERT(FxLibraryGlobals.OsVersionInfo.dwMajorVersion >= 6); 3690 3691 // 3692 // The S state the machine is going into is one where we can't 3693 // wake it up because our D state is too low for this S state. 3694 // Since this isn't the minimum S state the machine is capable 3695 // of, reject the current query. 3696 // 3697 DoTraceLevelMessage( 3698 FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGPNP, 3699 "failing system query power because the device cannot wake the " 3700 "machine from S%d", 3701 QueryState - 1); 3702 3703 status = STATUS_POWER_STATE_INVALID; 3704 } 3705 3706 return status; 3707 } 3708 3709 VOID 3710 FxPkgPnp::PowerPolicySetS0IdleState( 3711 __in BOOLEAN State 3712 ) 3713 { 3714 m_PowerPolicyMachine.m_Owner->m_IdleSettings.Enabled = State ? TRUE : FALSE; 3715 m_PowerPolicyMachine.m_Owner->m_IdleSettings.Dirty = TRUE; 3716 PowerPolicyProcessEvent(PwrPolS0IdlePolicyChanged); 3717 } 3718 3719 VOID 3720 FxPkgPnp::PowerPolicySetSxWakeState( 3721 __in BOOLEAN State 3722 ) 3723 /*++ 3724 3725 Routine Description: 3726 Sets the wake from Sx state 3727 3728 No need to post an event to the power policy state machine because we 3729 will not change any active due to a change in this setting. We only 3730 evaluate this state when going into Sx and once in this state we will not 3731 change our behavior until the next Sx, which will then evaluate this state. 3732 3733 Arguments: 3734 State - New state 3735 3736 Return Value: 3737 VOID 3738 3739 --*/ 3740 { 3741 m_PowerPolicyMachine.m_Owner->m_WakeSettings.Enabled = State ? TRUE : FALSE; 3742 m_PowerPolicyMachine.m_Owner->m_WakeSettings.Dirty = TRUE; 3743 3744 // 3745 // Since we are not posting an event to the power policy state machine, try 3746 // to write out the value now, otherwise it will be written when we 3747 // transition 3748 // 3749 if (Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { 3750 NTSTATUS status; 3751 LONGLONG timeout; 3752 3753 timeout = 0; 3754 3755 // 3756 // If the lock is already acquired on this thread, this will fail, which 3757 // is OK. 3758 // 3759 status = m_PowerPolicyMachine.m_StateMachineLock.AcquireLock( 3760 GetDriverGlobals(), 3761 &timeout 3762 ); 3763 3764 if (FxWaitLockInternal::IsLockAcquired(status)) { 3765 SaveState(TRUE); 3766 3767 m_PowerPolicyMachine.m_StateMachineLock.ReleaseLock( 3768 GetDriverGlobals() 3769 ); 3770 } 3771 } 3772 } 3773 3774 VOID 3775 FxPkgPnp::SetDeviceFailed( 3776 __in WDF_DEVICE_FAILED_ACTION FailedAction 3777 ) 3778 /*++ 3779 3780 Routine Description: 3781 Marks the device as a victim of catastrophic failure, either in software 3782 or in hardware. 3783 3784 If AttemptToRestart is TRUE, then we should try to get the stack re-built 3785 after it has been torn down. This would typically be the case the failure 3786 was in the software, and possibly not be the case if the failure was in 3787 the hardware. 3788 3789 Arguments: 3790 FailedAction - action to take once the stack has been removed 3791 3792 Return Value: 3793 None 3794 3795 --*/ 3796 { 3797 NTSTATUS status; 3798 MdDeviceObject pdo; 3799 3800 #if (FX_CORE_MODE == FX_CORE_USER_MODE) 3801 if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(2, 15) == FALSE && 3802 FailedAction == WdfDeviceFailedAttemptRestart) { 3803 3804 FailedAction = WdfDeviceFailedNoRestart; 3805 DoTraceLevelMessage( 3806 GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGDEVICE, 3807 "WdfDeviceFailedAttemptRestart is only available for UMDF 2.15 " 3808 "and later drivers. Reverting to WdfDeviceFailedNoRestart."); 3809 } 3810 #endif 3811 3812 m_FailedAction = (BYTE) FailedAction; 3813 3814 // 3815 // This will cause the PnP manager to tear down this stack, even if 3816 // the PDO can't be surprise-removed. 3817 // 3818 m_Failed = TRUE; 3819 3820 if (FailedAction == WdfDeviceFailedAttemptRestart) { 3821 // 3822 // Attempt to get the PDO surprise-removed. 3823 // 3824 status = AskParentToRemoveAndReenumerate(); 3825 3826 if (NT_SUCCESS(status)) { 3827 return; 3828 } 3829 } 3830 3831 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 3832 // 3833 // In between creating a PDO WDFDEVICE and it starting, if this DDI is called, 3834 // we will not have a valid PDO. Make sure it is valid before we proceed. 3835 // 3836 pdo = m_Device->GetSafePhysicalDevice(); 3837 3838 if (pdo != NULL) { 3839 // 3840 // Now tell the PnP manager to re-query us for our state. 3841 // 3842 MxDeviceObject physicalDeviceObject(pdo); 3843 3844 physicalDeviceObject.InvalidateDeviceState( 3845 m_Device->GetDeviceObject() 3846 ); 3847 } 3848 #else // USER_MODE 3849 m_Device->GetMxDeviceObject()->InvalidateDeviceState( 3850 m_Device->GetDeviceObject()); 3851 UNREFERENCED_PARAMETER(pdo); 3852 #endif 3853 } 3854 3855 _Must_inspect_result_ 3856 NTSTATUS 3857 FxPkgPnp::_PnpDeviceUsageNotification( 3858 __inout FxPkgPnp* This, 3859 __inout FxIrp *Irp 3860 ) 3861 { 3862 return This->PnpDeviceUsageNotification(Irp); 3863 } 3864 3865 _Must_inspect_result_ 3866 NTSTATUS 3867 FxPkgPnp::PnpDeviceUsageNotification( 3868 __inout FxIrp* Irp 3869 ) 3870 { 3871 FxRelatedDeviceList* pList; 3872 FxRelatedDevice *pDependent; 3873 FxAutoIrp relatedIrp(NULL), parentIrp(NULL); 3874 MxDeviceObject topOfParentStack; 3875 DEVICE_USAGE_NOTIFICATION_TYPE type; 3876 NTSTATUS status; 3877 MxDeviceObject pAttached; 3878 MdIrp pNewIrp; 3879 CCHAR maxStack; 3880 BOOLEAN inPath, supported; 3881 ULONG oldFlags; 3882 MxAutoWorkItem workItem; 3883 3884 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 3885 "Entering DeviceUsageNotification handler"); 3886 3887 status = STATUS_SUCCESS; 3888 3889 type = Irp->GetParameterUsageNotificationType(); 3890 inPath = Irp->GetParameterUsageNotificationInPath(); 3891 supported = FALSE; 3892 3893 DoTraceLevelMessage( 3894 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 3895 "type %x, in path %x, can support paging %x, dump file %x, " 3896 "hiber file %x, boot file %x", 3897 type, inPath, 3898 IsUsageSupported(_SpecialTypeToUsage(WdfSpecialFilePaging)), 3899 IsUsageSupported(_SpecialTypeToUsage(WdfSpecialFileDump)), 3900 IsUsageSupported(_SpecialTypeToUsage(WdfSpecialFileHibernation)), 3901 IsUsageSupported(_SpecialTypeToUsage(WdfSpecialFileBoot))); 3902 3903 3904 if (type >= static_cast<DEVICE_USAGE_NOTIFICATION_TYPE>(WdfSpecialFilePaging) 3905 && type < static_cast<DEVICE_USAGE_NOTIFICATION_TYPE>(WdfSpecialFileMax)) { 3906 if (inPath) { 3907 if (m_Device->IsFilter()) { 3908 // 3909 // Filters always support usage notifications 3910 // 3911 supported = TRUE; 3912 } 3913 else { 3914 supported = IsUsageSupported(type); 3915 } 3916 } 3917 else { 3918 // 3919 // We always handle notifications where we are out of the path 3920 // 3921 supported = TRUE; 3922 } 3923 } 3924 3925 if (supported == FALSE) { 3926 status = STATUS_NOT_IMPLEMENTED; 3927 3928 DoTraceLevelMessage( 3929 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 3930 "Usage type %x not supported, %!STATUS!", type, status); 3931 3932 return CompletePnpRequest(Irp, status); 3933 } 3934 3935 // 3936 // Usage notification IRP gets forwarded to parent stack or to 3937 // dependent stack. Since in such cases (with deep device tree) the stack 3938 // may run out quickly, ensure there is enough stack, otherwise use a 3939 // workitem. 3940 // 3941 if (Mx::MxHasEnoughRemainingThreadStack() == FALSE && 3942 (m_Device->IsPdo() || 3943 m_UsageDependentDeviceList != NULL)) { 3944 3945 status = workItem.Allocate(m_Device->GetDeviceObject()); 3946 if (!NT_SUCCESS(status)) { 3947 DoTraceLevelMessage( 3948 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3949 "WDFDEVICE %p !devobj %p could not allocate workitem " 3950 "to send usage notification type %d, inpath %d, %!STATUS!", 3951 m_Device->GetHandle(), 3952 m_Device->GetDeviceObject(), 3953 type, inPath, status); 3954 3955 return CompletePnpRequest(Irp, status); 3956 } 3957 } 3958 3959 // 3960 // Usage notification is supported. Set the flags on the device object 3961 // before processing this any further and save the current flags on the 3962 // device object. 3963 // 3964 oldFlags = SetUsageNotificationFlags(type, inPath); 3965 3966 if (m_Device->IsPdo()) { 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 topOfParentStack.SetObject( 3980 m_Device->m_ParentDevice->GetAttachedDeviceReference()); 3981 3982 pNewIrp = FxIrp::AllocateIrp(topOfParentStack.GetStackSize()); 3983 if (pNewIrp != NULL) { 3984 parentIrp.SetIrp(pNewIrp); 3985 3986 // 3987 // parentIrp now owns the irp 3988 // 3989 pNewIrp = NULL; 3990 3991 status = SendDeviceUsageNotification(&topOfParentStack, 3992 &parentIrp, 3993 &workItem, 3994 Irp, 3995 FALSE); 3996 } 3997 else { 3998 status = STATUS_INSUFFICIENT_RESOURCES; 3999 4000 DoTraceLevelMessage( 4001 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 4002 "WDFDEVICE %p could not allocate PIRP for parent !devobj %p to " 4003 "send usage notification type %d, inpath %d, %!STATUS!", 4004 m_Device->GetHandle(), topOfParentStack.GetObject(), 4005 type, inPath, status); 4006 } 4007 topOfParentStack.DereferenceObject(); 4008 topOfParentStack.SetObject(NULL); 4009 4010 if (!NT_SUCCESS(status)) { 4011 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 4012 "Exit %!STATUS!", status); 4013 4014 RevertUsageNotificationFlags(type, inPath, oldFlags); 4015 return CompletePnpRequest(Irp, status); 4016 } 4017 } 4018 4019 maxStack = 0; 4020 pDependent = NULL; 4021 4022 // 4023 // If the driver supports the given special file, lets notify dependent 4024 // stacks. 4025 // 4026 4027 // 4028 // LockForEnum will lock out new changes to the list until we unlock the list. 4029 // We remain at passive level once we are locked. 4030 // 4031 if (m_UsageDependentDeviceList != NULL) { 4032 // 4033 // We capture the m_UsageDependentDeviceList pointer value so that we 4034 // always use the same pointer value and that we have matched actions 4035 // (lock for enum / unlock from enum). What we are trying to avoid is 4036 // this: 4037 // 1) we do not lock for enum because m_UsageDependentDeviceList == NULL 4038 // 2) in the middle of this function, m_UsageDependentDeviceList is 4039 // assigned a pointer value 4040 // 3) we try to unlock from enum later (or iterate, thinking the enum 4041 // lock is held) by checking m_UsageDependentDeviceList for NULL, and 4042 // now that is != NULL, use it. 4043 // 4044 // By capturing the pointer now, we either have a list or not and we don't 4045 // hit situations 2 or 3. So, the rule is every subseqeunt time we need 4046 // to check if there is valid m_UsageDependentDeviceList pointer, we 4047 // use pList, but when we use the list, we can use m_UsageDependentDeviceList 4048 // directly. 4049 // 4050 pList = m_UsageDependentDeviceList; 4051 4052 m_UsageDependentDeviceList->LockForEnum(GetDriverGlobals()); 4053 4054 while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) { 4055 4056 MxDeviceObject deviceObject(pDependent->GetDevice()); 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 pAttached.SetObject(deviceObject.GetAttachedDeviceReference()); 4071 4072 if (pAttached.GetStackSize() > maxStack) { 4073 maxStack = pAttached.GetStackSize(); 4074 } 4075 4076 pAttached.DereferenceObject(); 4077 } 4078 } 4079 else { 4080 pList = NULL; 4081 } 4082 4083 if (maxStack > 0) { 4084 // 4085 // If we have a maxStack size, we have a list as well 4086 // 4087 ASSERT(m_UsageDependentDeviceList != NULL); 4088 4089 // 4090 // Allocate one irp for all the stacks so that we don't have an 4091 // allocation later. This way, once we have the irp, we can send the 4092 // usage notification to all stacks reliably, as well as the reverting 4093 // of the notification if we encounter failure. 4094 // 4095 pNewIrp = FxIrp::AllocateIrp(maxStack); 4096 if (pNewIrp == NULL) { 4097 status = STATUS_INSUFFICIENT_RESOURCES; 4098 4099 DoTraceLevelMessage( 4100 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 4101 "WDFDEVICE %p could not allocate IRP to send usage notifications" 4102 " to related stacks, type %d, inpath %d, status %!STATUS!", 4103 m_Device->GetHandle(), type, inPath, status); 4104 } 4105 else { 4106 MxDeviceObject dependentDevice; 4107 4108 // 4109 // relatedIrp will free the irp when it goes out of scope 4110 // 4111 relatedIrp.SetIrp(pNewIrp); 4112 4113 // 4114 // Walk our collection of dependent device stacks, and notify 4115 // each stack of the device notification. If any fail, notify 4116 // the stacks who already were told of the reverted behavior. 4117 // 4118 pDependent = NULL; 4119 while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) { 4120 dependentDevice.SetObject(pDependent->GetDevice()); 4121 status = SendDeviceUsageNotification(&dependentDevice, 4122 &relatedIrp, 4123 &workItem, 4124 Irp, 4125 FALSE); 4126 4127 if (!NT_SUCCESS(status)) { 4128 FxRelatedDevice* pDependent2; 4129 4130 pDependent2 = NULL; 4131 4132 // 4133 // A device failed the device usage notification request. 4134 // Notify the stacks that didn't fail, so they can unwind 4135 // the operation. 4136 // 4137 while ((pDependent2 = m_UsageDependentDeviceList->GetNextEntry(pDependent2)) != NULL && 4138 pDependent2 != pDependent) { 4139 dependentDevice.SetObject(pDependent2->GetDevice()); 4140 4141 // 4142 // We're already in a failure path. We can't do anything 4143 // about yet another failure. So we ignore the return 4144 // value. 4145 // 4146 (void) SendDeviceUsageNotification(&dependentDevice, 4147 &relatedIrp, 4148 &workItem, 4149 Irp, 4150 TRUE); 4151 } 4152 4153 // 4154 // Now break out of our outter loop. 4155 // 4156 break; 4157 } 4158 } 4159 } 4160 } 4161 4162 // 4163 // If we are successful to this point, then send the IRP down the 4164 // stack. 4165 // 4166 if (NT_SUCCESS(status)) { 4167 BOOLEAN referenceSucceeded, sendDown; 4168 4169 referenceSucceeded = FALSE; 4170 sendDown = TRUE; 4171 4172 // 4173 // Make sure the stack is in D0 before sending down the request. This 4174 // will at least guarantee that all devices below this one are in D0 4175 // when the make the transition from power pageable to non or vice versa. 4176 // 4177 if (IsPowerPolicyOwner()) { 4178 status = PowerReference(TRUE); 4179 4180 if (NT_SUCCESS(status)) { 4181 referenceSucceeded = TRUE; 4182 } 4183 else { 4184 Irp->SetStatus(status); 4185 sendDown = FALSE; 4186 } 4187 } 4188 4189 if (sendDown) { 4190 // 4191 // If we supported the usage, set the status to success, otherwise we 4192 // keep the status in the irp as it arrived to this device 4193 // 4194 if (supported) { 4195 Irp->SetStatus(status); 4196 } 4197 status = SendIrpSynchronously(Irp); 4198 } 4199 4200 // 4201 // Transitioning from a thread which was power pagable to non power 4202 // pagable. We now need a power thread for the stack, ask for it. 4203 // Note that there is no need for power thread in case of "boot" 4204 // notification since boot notification doesn't require clearing device's 4205 // DO_POWER_PAGABLE flag (power thread is required when handling power 4206 // irp at dispatch level which can happen if the DO_POWER_PAGABLE flag 4207 // is cleared). 4208 // 4209 // NOTE: Once we have a power thread, we never go back to using work 4210 // items even though the stack may revert to power pagable. 4211 // This is an acceptable tradeoff between resource usage and 4212 // WDF complexity. 4213 // 4214 // 4215 if (NT_SUCCESS(status) && 4216 inPath && 4217 (HasPowerThread() == FALSE) && 4218 type != static_cast<DEVICE_USAGE_NOTIFICATION_TYPE>(WdfSpecialFileBoot) 4219 ) { 4220 status = QueryForPowerThread(); 4221 4222 if (!NT_SUCCESS(status)) { 4223 // 4224 // Keep status the same through out so we can set it back in 4225 // the irp when we are done. 4226 // 4227 if (m_Device->IsPdo()) { 4228 // 4229 // need to revert our parent's stack 4230 // 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 topOfParentStack.SetObject( 4244 m_Device->m_ParentDevice->GetAttachedDeviceReference()); 4245 4246 // 4247 // Ignore the status because we can't do anything on failure 4248 // 4249 (void) SendDeviceUsageNotification(&topOfParentStack, 4250 &parentIrp, 4251 &workItem, 4252 Irp, 4253 TRUE); 4254 4255 topOfParentStack.DereferenceObject(); 4256 } 4257 else { 4258 // 4259 // Notify the stack below us 4260 // 4261 Irp->CopyCurrentIrpStackLocationToNext(); 4262 Irp->SetParameterUsageNotificationInPath(FALSE); 4263 4264 // 4265 // Required for pnp irps 4266 // 4267 Irp->SetStatus(STATUS_NOT_SUPPORTED); 4268 4269 // 4270 // Ignore the status because we can't do anything on failure 4271 // 4272 (void) Irp->SendIrpSynchronously(m_Device->GetAttachedDevice()); 4273 } 4274 4275 Irp->SetStatus(status); 4276 } 4277 } 4278 4279 // 4280 // Now check whether the lower devices succeeded or failed. If they 4281 // failed, back out our changes and propogate the failure. 4282 // 4283 if (!NT_SUCCESS(status)) { 4284 // 4285 // Revert the flags set on the device object. 4286 // 4287 RevertUsageNotificationFlags(type, inPath, oldFlags); 4288 4289 // 4290 // Notify dependent stacks of the failure. 4291 // 4292 pDependent = NULL; 4293 4294 // 4295 // See pList initiatilazation as to why we compare pList for != NULL 4296 // and not m_UsageDependentDeviceList. 4297 // 4298 if (pList != NULL) { 4299 MxDeviceObject dependentDevice; 4300 4301 while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) { 4302 dependentDevice.SetObject(pDependent->GetDevice()); 4303 4304 // 4305 // We're already in a failure path. We can't do anything 4306 // about yet another failure. So we ignore the return value. 4307 // 4308 (void) SendDeviceUsageNotification(&dependentDevice, 4309 &relatedIrp, 4310 &workItem, 4311 Irp, 4312 TRUE); 4313 } 4314 } 4315 } 4316 4317 // 4318 // By this point, we have propagated the notification to dependent devices 4319 // and lower stack, and if anyone failed during that time, we also 4320 // propagated failure to dependent stacks and lower stack. 4321 // If status is success at this point, invoke the driver's callback. 4322 // 4323 if (NT_SUCCESS(status)) { 4324 // 4325 // Invoke callback. Note that only one of the callbacks 4326 // DeviceUsageNotification or DeviceUsgeNotificationEx will get 4327 // invoked since only one of the callbacks at a time is supported. 4328 // We ensured that during registration of the callback. 4329 // Note that Ex callback will return success if driver did not 4330 // supply any callback. 4331 // 4332 m_DeviceUsageNotification.Invoke(m_Device->GetHandle(), 4333 _UsageToSpecialType(type), 4334 inPath); 4335 4336 status = m_DeviceUsageNotificationEx.Invoke( 4337 m_Device->GetHandle(), 4338 _UsageToSpecialType(type), 4339 inPath 4340 ); 4341 4342 if (!NT_SUCCESS(status)) { 4343 // 4344 // Driver's callback returned failure. We need to propagate 4345 // failure to lower stack and dependent stacks. 4346 // 4347 // 4348 // Keep status the same through out so we can set it back in 4349 // the irp when we are done. 4350 // 4351 if (m_Device->IsPdo()) { 4352 // 4353 // need to revert our parent's stack 4354 // 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 topOfParentStack.SetObject( 4368 m_Device->m_ParentDevice->GetAttachedDeviceReference()); 4369 4370 // 4371 // Ignore the status because we can't do anything on failure 4372 // 4373 (void) SendDeviceUsageNotification(&topOfParentStack, 4374 &parentIrp, 4375 &workItem, 4376 Irp, 4377 TRUE); 4378 4379 topOfParentStack.DereferenceObject(); 4380 } 4381 else { 4382 // 4383 // Notify the stack below us 4384 // 4385 Irp->CopyCurrentIrpStackLocationToNext(); 4386 Irp->SetParameterUsageNotificationInPath(FALSE); 4387 4388 // 4389 // Required for pnp irps 4390 // 4391 Irp->SetStatus(STATUS_NOT_SUPPORTED); 4392 4393 // 4394 // Ignore the status because we can't do anything on failure 4395 // 4396 (void) Irp->SendIrpSynchronously(m_Device->GetAttachedDevice()); 4397 } 4398 4399 Irp->SetStatus(status); 4400 4401 // 4402 // Revert the flags set on the device object. 4403 // 4404 RevertUsageNotificationFlags(type, inPath, oldFlags); 4405 4406 // 4407 // Notify dependent stacks of the failure. 4408 // 4409 pDependent = NULL; 4410 4411 // 4412 // See pList initiatilazation as to why we compare pList for != NULL 4413 // and not m_UsageDependentDeviceList. 4414 // 4415 if (pList != NULL) { 4416 MxDeviceObject dependentDevice; 4417 4418 while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) { 4419 dependentDevice.SetObject(pDependent->GetDevice()); 4420 4421 // 4422 // We're already in a failure path. We can't do anything 4423 // about yet another failure. So we ignore the return value. 4424 // 4425 (void) SendDeviceUsageNotification(&dependentDevice, 4426 &relatedIrp, 4427 &workItem, 4428 Irp, 4429 TRUE); 4430 } 4431 } 4432 } 4433 4434 if (NT_SUCCESS(status)) { 4435 4436 CommitUsageNotification(type, oldFlags); 4437 4438 // 4439 // If we are in the dump file path, we cannot idle out because we 4440 // can experience a crash dump at any time. 4441 // 4442 if (IsPowerPolicyOwner() && type == DeviceUsageTypeDumpFile) { 4443 // 4444 // Add a reference everytime we are notified of being in the 4445 // path, no need to match the first inPath notification and the 4446 // last !inPath notification. 4447 // 4448 if (inPath) { 4449 NTSTATUS refStatus; 4450 4451 ASSERT(GetUsageCount(type) > 0); 4452 4453 // 4454 // Since our previous synchronous power reference succeeded, 4455 // an addtional reference while we are powered up should 4456 // never fail. 4457 // 4458 refStatus = PowerReference(FALSE); 4459 #if DBG 4460 ASSERT(NT_SUCCESS(refStatus)); 4461 #else 4462 UNREFERENCED_PARAMETER(refStatus); 4463 #endif 4464 } 4465 else { 4466 ASSERT(GetUsageCount(type) >= 0); 4467 PowerDereference(); 4468 } 4469 } 4470 } 4471 } 4472 4473 // 4474 // We no longer need to be in D0 if we don't have to be. 4475 // 4476 if (referenceSucceeded) { 4477 ASSERT(IsPowerPolicyOwner()); 4478 PowerDereference(); 4479 } 4480 } 4481 4482 // 4483 // See pList initiatilazation as to why we compare pList for != NULL 4484 // and not m_UsageDependentDeviceList. 4485 // 4486 if (pList != NULL) { 4487 m_UsageDependentDeviceList->UnlockFromEnum(GetDriverGlobals()); 4488 } 4489 4490 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 4491 "Exit %!STATUS!", status); 4492 4493 return CompletePnpRequest(Irp, status); 4494 } 4495 4496 ULONG 4497 FxPkgPnp::SetUsageNotificationFlags( 4498 __in DEVICE_USAGE_NOTIFICATION_TYPE Type, 4499 __in BOOLEAN InPath 4500 ) 4501 /*++ 4502 4503 Routine Description: 4504 4505 This routine sets the usage notification flags on the device object (for 4506 non-boot usages) and updates the special file usage count . 4507 4508 Arguments: 4509 4510 Type - the special file type - paging, hibernate, dump or boot file. 4511 4512 InPath - indicates whether the system is creating or removing the special 4513 file on the device. 4514 4515 Return Value: 4516 4517 Returns the old flags on the device object. 4518 4519 --*/ 4520 { 4521 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); 4522 ULONG oldFlags, newFlags; 4523 4524 oldFlags = m_Device->GetDeviceObjectFlags(); 4525 4526 // 4527 4528 // 4529 DoTraceLevelMessage( 4530 FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, 4531 "Before: type %d, in path %d, special count %d, flags 0x%x, " 4532 "device %p (WDFDEVICE %p), is pageable capable %d", 4533 Type, InPath, GetUsageCount(Type), oldFlags, 4534 m_Device->GetDeviceObject(), m_Device->GetHandle(), 4535 m_Device->IsPowerPageableCapable()); 4536 4537 // 4538 // Adjust our "special file count". 4539 // 4540 AdjustUsageCount(Type, InPath); 4541 4542 // 4543 // Boot notification doesn't require updating device flags. 4544 // 4545 if (Type == static_cast<DEVICE_USAGE_NOTIFICATION_TYPE>(WdfSpecialFileBoot)) { 4546 return oldFlags; 4547 } 4548 4549 if (m_Device->IsFilter()) { 4550 // 4551 // Clear the previous flags and reset them to the attached 4552 // device's flags 4553 // 4554 newFlags = oldFlags & ~(DO_POWER_PAGABLE | DO_POWER_INRUSH); 4555 newFlags |= m_Device->GetAttachedDeviceObjectFlags() & 4556 (DO_POWER_PAGABLE | DO_POWER_INRUSH); 4557 m_Device->SetDeviceObjectFlags(newFlags); 4558 } 4559 else { 4560 if (InPath) { 4561 m_Device->SetDeviceObjectFlags( 4562 m_Device->GetDeviceObjectFlags() & ~DO_POWER_PAGABLE 4563 ); 4564 } 4565 else { 4566 if (m_Device->IsPowerPageableCapable() && IsInSpecialUse() == FALSE) { 4567 m_Device->SetDeviceObjectFlags( 4568 m_Device->GetDeviceObjectFlags() | DO_POWER_PAGABLE 4569 ); 4570 } 4571 } 4572 } 4573 4574 return oldFlags; 4575 } 4576 4577 VOID 4578 FxPkgPnp::RevertUsageNotificationFlags( 4579 __in DEVICE_USAGE_NOTIFICATION_TYPE Type, 4580 __in BOOLEAN InPath, 4581 __in ULONG OldFlags 4582 ) 4583 /*++ 4584 4585 Routine Description: 4586 4587 This routine reverts the usage notification flags to the old flags on 4588 the device object and updates the special file usage count. 4589 4590 Arguments: 4591 4592 Type - the special file type - paging, hibernate or dump file. 4593 4594 InPath - indicates whether the system is creating or removing the special 4595 file on the device. 4596 4597 OldFlags - the previous flags on the device object. 4598 4599 --*/ 4600 { 4601 // 4602 // Re-adjust our "special file count". 4603 // 4604 InPath = !InPath; 4605 AdjustUsageCount(Type, InPath); 4606 4607 // 4608 // Restore the flags on the device object. 4609 // 4610 m_Device->SetDeviceObjectFlags(OldFlags); 4611 } 4612 4613 VOID 4614 FxPkgPnp::CommitUsageNotification( 4615 __in DEVICE_USAGE_NOTIFICATION_TYPE Type, 4616 __in ULONG OldFlags 4617 ) 4618 /*++ 4619 4620 Routine Description: 4621 4622 This routine commits the usage notification flags on the device object 4623 and invokes the usage notification callbacks. If the current flags on 4624 the device object indicates that there was a transition from power-pagable 4625 to non power-pagable, or vice-versa, then an event is posted to the power 4626 state machine to notify it of the change. After this routine is called 4627 the PNP manager will no longer be able to disable the device. 4628 4629 Arguments: 4630 4631 Type - the special file type - paging, hibernation or crash dump file. 4632 4633 InPath - indicates whether the system is creating or removing the special 4634 file on the device. 4635 4636 OldFlags - the previous flags on the device object. 4637 4638 --*/ 4639 { 4640 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); 4641 ULONG newFlags; 4642 4643 newFlags = m_Device->GetDeviceObjectFlags(); 4644 4645 if ((OldFlags & DO_POWER_PAGABLE) == DO_POWER_PAGABLE && 4646 (newFlags & DO_POWER_PAGABLE) == 0) { 4647 // 4648 // We transitioned from a power pageable to a non power pageable 4649 // device. Move the power state machine to the appropriate 4650 // state. 4651 // 4652 PowerProcessEvent(PowerMarkNonpageable); 4653 } 4654 4655 if ((OldFlags & DO_POWER_PAGABLE) == 0 && 4656 (newFlags & DO_POWER_PAGABLE) == DO_POWER_PAGABLE) { 4657 // 4658 // We transitioned from a non power pageable to a power pageable 4659 // device. Move the power state machine to the appropriate 4660 // state. 4661 // 4662 PowerProcessEvent(PowerMarkPageable); 4663 } 4664 4665 // 4666 // Notify PNP that it should no longer be able 4667 // to disable this device. 4668 // 4669 MxDeviceObject physicalDeviceObject( 4670 m_Device->GetPhysicalDevice() 4671 ); 4672 physicalDeviceObject.InvalidateDeviceState( 4673 m_Device->GetDeviceObject() 4674 ); 4675 4676 DoTraceLevelMessage( 4677 FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, 4678 "After: special count %d, flags 0x%x, device %p (WDFDEVICE %p)", 4679 GetUsageCount(Type), newFlags, 4680 m_Device->GetDeviceObject(), m_Device->GetHandle()); 4681 } 4682 4683 _Must_inspect_result_ 4684 NTSTATUS 4685 FxPkgPnp::AddUsageDevice( 4686 __in MdDeviceObject DependentDevice 4687 ) 4688 { 4689 FxRelatedDevice* pRelated; 4690 NTSTATUS status; 4691 4692 if (m_UsageDependentDeviceList == NULL) { 4693 KIRQL irql; 4694 4695 Lock(&irql); 4696 if (m_UsageDependentDeviceList == NULL) { 4697 m_UsageDependentDeviceList = new (GetDriverGlobals()) FxRelatedDeviceList(); 4698 4699 if (m_UsageDependentDeviceList != NULL) { 4700 status = STATUS_SUCCESS; 4701 } 4702 else { 4703 status = STATUS_INSUFFICIENT_RESOURCES; 4704 4705 DoTraceLevelMessage( 4706 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 4707 "Could not allocate usage device list for WDFDEVICE %p, " 4708 "%!STATUS!", m_Device->GetHandle(), status); 4709 } 4710 4711 } 4712 else { 4713 // 4714 // another thread allocated the list already 4715 // 4716 status = STATUS_SUCCESS; 4717 } 4718 Unlock(irql); 4719 4720 if (!NT_SUCCESS(status)) { 4721 return status; 4722 } 4723 } 4724 4725 pRelated = new(GetDriverGlobals()) 4726 FxRelatedDevice(DependentDevice, GetDriverGlobals()); 4727 4728 if (pRelated == NULL) { 4729 return STATUS_INSUFFICIENT_RESOURCES; 4730 } 4731 4732 status = m_UsageDependentDeviceList->Add(GetDriverGlobals(), pRelated); 4733 4734 if (!NT_SUCCESS(status)) { 4735 pRelated->DeleteFromFailedCreate(); 4736 } 4737 4738 return status; 4739 } 4740 4741 VOID 4742 FxPkgPnp::RemoveUsageDevice( 4743 __in MdDeviceObject DependentDevice 4744 ) 4745 { 4746 if (m_UsageDependentDeviceList != NULL) { 4747 m_UsageDependentDeviceList->Remove(GetDriverGlobals(), DependentDevice); 4748 } 4749 } 4750 4751 _Must_inspect_result_ 4752 NTSTATUS 4753 FxPkgPnp::AddRemovalDevice( 4754 __in MdDeviceObject DependentDevice 4755 ) 4756 { 4757 FxRelatedDevice* pRelated; 4758 NTSTATUS status; 4759 4760 if (m_RemovalDeviceList == NULL) { 4761 KIRQL irql; 4762 4763 Lock(&irql); 4764 if (m_RemovalDeviceList == NULL) { 4765 m_RemovalDeviceList = new (GetDriverGlobals()) FxRelatedDeviceList(); 4766 4767 if (m_RemovalDeviceList != NULL) { 4768 status = STATUS_SUCCESS; 4769 } 4770 else { 4771 status = STATUS_INSUFFICIENT_RESOURCES; 4772 4773 DoTraceLevelMessage( 4774 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 4775 "Could not allocate removal device list for WDFDEVICE %p, " 4776 "%!STATUS!", m_Device->GetHandle(), status); 4777 } 4778 } 4779 else { 4780 // 4781 // another thread allocated the list already 4782 // 4783 status = STATUS_SUCCESS; 4784 } 4785 Unlock(irql); 4786 4787 if (!NT_SUCCESS(status)) { 4788 return status; 4789 } 4790 } 4791 4792 pRelated = new(GetDriverGlobals()) 4793 FxRelatedDevice(DependentDevice, GetDriverGlobals()); 4794 if (pRelated == NULL) { 4795 return STATUS_INSUFFICIENT_RESOURCES; 4796 } 4797 4798 status = m_RemovalDeviceList->Add(GetDriverGlobals(), pRelated); 4799 4800 if (NT_SUCCESS(status)) { 4801 // 4802 // RemovalRelations are queried automatically by PnP when the device is 4803 // going to be query removed. No need to tell pnp that the list changed 4804 // until it needs to query for it. 4805 // 4806 DO_NOTHING(); 4807 } 4808 else { 4809 pRelated->DeleteFromFailedCreate(); 4810 } 4811 4812 return status; 4813 } 4814 4815 VOID 4816 FxPkgPnp::RemoveRemovalDevice( 4817 __in MdDeviceObject DependentDevice 4818 ) 4819 { 4820 if (m_RemovalDeviceList != NULL) { 4821 m_RemovalDeviceList->Remove(GetDriverGlobals(), DependentDevice); 4822 } 4823 4824 // 4825 // RemovalRelations are queried automatically by PnP when the device is 4826 // going to be query removed. No need to tell pnp that the list changed 4827 // until it needs to query for it. 4828 // 4829 } 4830 4831 VOID 4832 FxPkgPnp::ClearRemovalDevicesList( 4833 VOID 4834 ) 4835 { 4836 FxRelatedDevice* pEntry; 4837 4838 if (m_RemovalDeviceList == NULL) { 4839 return; 4840 } 4841 4842 m_RemovalDeviceList->LockForEnum(GetDriverGlobals()); 4843 while ((pEntry = m_RemovalDeviceList->GetNextEntry(NULL)) != NULL) { 4844 m_RemovalDeviceList->Remove(GetDriverGlobals(), pEntry->GetDevice()); 4845 } 4846 m_RemovalDeviceList->UnlockFromEnum(GetDriverGlobals()); 4847 4848 // 4849 // RemovalRelations are queried automatically by PnP when the device is 4850 // going to be query removed. No need to tell pnp that the list changed 4851 // until it needs to query for it. 4852 // 4853 } 4854 4855 VOID 4856 FxPkgPnp::SetInternalFailure( 4857 VOID 4858 ) 4859 /*++ 4860 4861 Routine Description: 4862 Sets the failure field and then optionally invalidates the device state. 4863 4864 Arguments: 4865 InvalidateState - If TRUE, the state is invalidated 4866 4867 Return Value: 4868 None 4869 4870 --*/ 4871 { 4872 m_InternalFailure = TRUE; 4873 4874 MxDeviceObject physicalDeviceObject( 4875 m_Device->GetPhysicalDevice() 4876 ); 4877 physicalDeviceObject.InvalidateDeviceState( 4878 m_Device->GetDeviceObject() 4879 ); 4880 } 4881 4882 VOID 4883 FxPkgPnp::SetPendingPnpIrp( 4884 __inout FxIrp* Irp, 4885 __in BOOLEAN MarkIrpPending 4886 ) 4887 { 4888 if (m_PendingPnPIrp != NULL ) { 4889 FxIrp pendingIrp(m_PendingPnPIrp); 4890 4891 // 4892 // A state changing pnp irp is already pended. If we don't bugcheck 4893 // the pended pnp irp will be overwritten with new pnp irp and the old 4894 // one may never get completed, which may have drastic implications ( 4895 // unresponsive system, power manager not sending Sx Irp etc.) 4896 // 4897 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 4898 "A new state changing pnp irp %!pnpmn! IRP %p arrived while another " 4899 "pnp irp %!pnpmn! IRP %p is still pending WDFDEVICE %p\n", 4900 Irp->GetMinorFunction(), Irp->GetIrp(), 4901 pendingIrp.GetMinorFunction(),pendingIrp.GetIrp(), 4902 m_Device->GetHandle()); 4903 4904 FxVerifierBugCheck(GetDriverGlobals(), // globals 4905 WDF_PNP_FATAL_ERROR, // specific type 4906 (ULONG_PTR)m_Device->GetHandle(), //parm 2 4907 (ULONG_PTR)Irp->GetIrp()); // parm 3 4908 4909 /* NOTREACHED */ 4910 return; 4911 } 4912 if (MarkIrpPending) { 4913 Irp->MarkIrpPending(); 4914 } 4915 m_PendingPnPIrp = Irp->GetIrp(); 4916 } 4917 4918 _Must_inspect_result_ 4919 NTSTATUS 4920 FxPkgPnp::AllocateEnumInfo( 4921 VOID 4922 ) 4923 { 4924 KIRQL irql; 4925 NTSTATUS status; 4926 4927 if (m_EnumInfo != NULL) { 4928 return STATUS_SUCCESS; 4929 } 4930 4931 Lock(&irql); 4932 if (m_EnumInfo == NULL) { 4933 m_EnumInfo = new (GetDriverGlobals()) FxEnumerationInfo(GetDriverGlobals()); 4934 4935 if (m_EnumInfo != NULL) { 4936 status = m_EnumInfo->Initialize(); 4937 4938 if (!NT_SUCCESS(status)) { 4939 delete m_EnumInfo; 4940 m_EnumInfo = NULL; 4941 4942 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, 4943 TRACINGPNP, 4944 "Could not initialize enum info for " 4945 "WDFDEVICE %p, %!STATUS!", 4946 m_Device->GetHandle(), status); 4947 } 4948 4949 } 4950 else { 4951 status = STATUS_INSUFFICIENT_RESOURCES; 4952 4953 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 4954 "Could not allocate enum info for WDFDEVICE %p, " 4955 "%!STATUS!", m_Device->GetHandle(), status); 4956 } 4957 } 4958 else { 4959 // 4960 // another thread allocated the list already 4961 // 4962 status = STATUS_SUCCESS; 4963 } 4964 Unlock(irql); 4965 4966 return status; 4967 } 4968 4969 VOID 4970 FxPkgPnp::AddChildList( 4971 __in FxChildList* List 4972 ) 4973 { 4974 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 4975 "Adding FxChildList %p, WDFCHILDLIST %p", List, 4976 List->GetHandle()); 4977 4978 m_EnumInfo->m_ChildListList.Add(GetDriverGlobals(), 4979 &List->m_TransactionLink); 4980 } 4981 4982 VOID 4983 FxPkgPnp::RemoveChildList( 4984 __in FxChildList* List 4985 ) 4986 { 4987 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 4988 "Removing FxChildList %p, WDFCHILDLIST %p", List, 4989 List->GetHandle()); 4990 4991 m_EnumInfo->m_ChildListList.Remove(GetDriverGlobals(), &List->m_TransactionLink); 4992 4993 // 4994 4995 // 4996 } 4997 4998 VOID 4999 FxPkgPnp::ChildListNotifyRemove( 5000 __inout PLONG PendingCount 5001 ) 5002 { 5003 FxTransactionedEntry* ple; 5004 5005 ple = NULL; 5006 5007 if (m_EnumInfo != NULL) { 5008 m_EnumInfo->m_ChildListList.LockForEnum(GetDriverGlobals()); 5009 while ((ple = m_EnumInfo->m_ChildListList.GetNextEntry(ple)) != NULL) { 5010 FxChildList::_FromEntry(ple)->NotifyDeviceRemove(PendingCount); 5011 } 5012 m_EnumInfo->m_ChildListList.UnlockFromEnum(GetDriverGlobals()); 5013 } 5014 } 5015 5016 VOID 5017 FxPkgPnp::AddQueryInterface( 5018 __in FxQueryInterface* QI, 5019 __in BOOLEAN Lock 5020 ) 5021 /*++ 5022 5023 Routine Description: 5024 Add a query interface structure to the list of interfaces supported 5025 5026 Arguments: 5027 QI - the interface to add 5028 5029 Lock - indication of the list lock should be acquired or not 5030 5031 Return Value: 5032 None 5033 5034 --*/ 5035 { 5036 SINGLE_LIST_ENTRY **ppPrev, *pCur; 5037 5038 if (Lock) { 5039 m_QueryInterfaceLock.AcquireLock(GetDriverGlobals()); 5040 } 5041 5042 ASSERT(QI->m_Entry.Next == NULL); 5043 5044 // 5045 // Iterate until we find the end of the list and then append the new 5046 // structure. ppPrev is the pointer to the Next pointer value. When we 5047 // get to the end, ppPrev will be equal to the Next field which points to NULL. 5048 // 5049 ppPrev = &m_QueryInterfaceHead.Next; 5050 pCur = m_QueryInterfaceHead.Next; 5051 5052 while (pCur != NULL) { 5053 ppPrev = &pCur->Next; 5054 pCur = pCur->Next; 5055 } 5056 5057 *ppPrev = &QI->m_Entry; 5058 5059 if (Lock) { 5060 m_QueryInterfaceLock.ReleaseLock(GetDriverGlobals()); 5061 } 5062 } 5063 5064 __drv_maxIRQL(DISPATCH_LEVEL) 5065 __drv_minIRQL(DISPATCH_LEVEL) 5066 __drv_requiresIRQL(DISPATCH_LEVEL) 5067 __drv_sameIRQL 5068 VOID 5069 FxWatchdog::_WatchdogDpc( 5070 __in PKDPC Dpc, 5071 __in_opt PVOID Context, 5072 __in_opt PVOID SystemArgument1, 5073 __in_opt PVOID SystemArgument2 5074 ) 5075 /*++ 5076 5077 Routine Description: 5078 5079 This routine's job is to crash the machine, attempting to get some data 5080 into the crashdump file (or minidump) about why the machine stopped 5081 responding during an attempt to put the machine to sleep. 5082 5083 Arguments: 5084 5085 This - the instance of FxPkgPnp 5086 5087 Return Value: 5088 5089 this routine never returns 5090 5091 --*/ 5092 { 5093 WDF_POWER_ROUTINE_TIMED_OUT_DATA data; 5094 FxWatchdog* pThis; 5095 CfxDevice* pDevice; 5096 5097 UNREFERENCED_PARAMETER(Dpc); 5098 UNREFERENCED_PARAMETER(SystemArgument1); 5099 UNREFERENCED_PARAMETER(SystemArgument2); 5100 5101 pThis = (FxWatchdog*) Context; 5102 pDevice = pThis->m_PkgPnp->GetDevice(); 5103 5104 DoTraceLevelMessage(pDevice->GetDriverGlobals(), 5105 TRACE_LEVEL_ERROR, TRACINGPNP, 5106 "The driver failed to return from a callback routine " 5107 "in a reasonable period of time. This prevented the " 5108 "machine from going to sleep or from hibernating. The " 5109 "machine crashed because that was the best way to get " 5110 "data about the cause of the crash into a minidump file."); 5111 5112 data.PowerState = pDevice->GetDevicePowerState(); 5113 data.PowerPolicyState = pDevice->GetDevicePowerPolicyState(); 5114 data.DeviceObject = reinterpret_cast<PDEVICE_OBJECT>(pDevice->GetDeviceObject()); 5115 data.Device = pDevice->GetHandle(); 5116 data.TimedOutThread = reinterpret_cast<PKTHREAD>(pThis->m_CallingThread); 5117 5118 FxVerifierBugCheck(pDevice->GetDriverGlobals(), 5119 WDF_POWER_ROUTINE_TIMED_OUT, 5120 (ULONG_PTR) &data); 5121 } 5122 5123 _Must_inspect_result_ 5124 NTSTATUS 5125 FxPkgPnp::CreatePowerThread( 5126 VOID 5127 ) 5128 /*++ 5129 5130 Routine Description: 5131 Creates a power thread for the device node. This thread is share among all 5132 the devices in the stack through the POWER_THREAD_INTERFACE structure and 5133 PnP query interface. 5134 5135 Arguments: 5136 None 5137 5138 Return Value: 5139 NTSTATUS 5140 5141 --*/ 5142 { 5143 FxSystemThread *pThread, *pOld; 5144 NTSTATUS status; 5145 5146 status = FxSystemThread::_CreateAndInit( 5147 &pThread, 5148 GetDriverGlobals(), 5149 m_Device->GetHandle(), 5150 m_Device->GetDeviceObject()); 5151 5152 if (!NT_SUCCESS(status)) { 5153 return status; 5154 } 5155 5156 // 5157 // Simple locking logic in case N requests are conncurrent. (The requests 5158 // never should be concurrent, but in the case that there are 2 usage 5159 // notifications coming in from two different sources, it could 5160 // theoritically happen.) 5161 // 5162 pOld = (FxSystemThread*) InterlockedCompareExchangePointer( 5163 (PVOID*) &m_PowerThread, pThread, NULL); 5164 5165 if (pOld != NULL) { 5166 // 5167 // Someone also set the thread pointer value at the same time, free 5168 // our new one here. 5169 // 5170 pThread->ExitThread(); 5171 pThread->DeleteObject(); 5172 } 5173 5174 m_HasPowerThread = TRUE; 5175 5176 return STATUS_SUCCESS; 5177 } 5178 5179 VOID 5180 FxPkgPnp::ReleasePowerThread( 5181 VOID 5182 ) 5183 /*++ 5184 5185 Routine Description: 5186 If this device is the owner of the power thread, it kills the thread. 5187 Otherwise, if this device has acquired the thread from a lower device, 5188 release the reference now. 5189 5190 Arguments: 5191 None 5192 5193 Return Value: 5194 None 5195 5196 --*/ 5197 { 5198 BOOLEAN hadThread; 5199 5200 hadThread = m_HasPowerThread; 5201 5202 // 5203 // Set to FALSE before cleaning up the reference or thread itself in case 5204 // there is some other context trying to enqueue. The only way that could 5205 // be happening is if the power policy owner is not WDF and sends power irps 5206 // after query remove or surprise remove. 5207 // 5208 m_HasPowerThread = FALSE; 5209 5210 // 5211 // Check for ownership 5212 // 5213 if (m_PowerThread != NULL) { 5214 5215 FxCREvent event; 5216 5217 // 5218 // Event on stack is used, which is fine since this code is invoked 5219 // only in KM. Verify this assumption. 5220 // 5221 // If this code is ever needed for UM, m_PowerThreadEvent should be 5222 // pre-initialized (simlar to the way m_RemoveEventUm is used) 5223 // 5224 WDF_VERIFY_KM_ONLY_CODE(); 5225 5226 ASSERT(m_PowerThreadEvent == NULL); 5227 m_PowerThreadEvent = event.GetSelfPointer(); 5228 5229 if (InterlockedDecrement(&m_PowerThreadInterfaceReferenceCount) > 0) { 5230 // 5231 // Wait for all references to go away before exitting the thread. 5232 // A reference will be taken for every device in the stack above this 5233 // one which queried for the interface. 5234 // 5235 event.EnterCRAndWaitAndLeave(); 5236 } 5237 5238 m_PowerThreadEvent = NULL; 5239 5240 // 5241 // Wait for the thread to exit and then delete it. Since we have 5242 // turned off the power policy state machine, we can safely do this here. 5243 // Any upper level clients will have also turned off their power policy 5244 // state machines. 5245 // 5246 m_PowerThread->ExitThread(); 5247 m_PowerThread->DeleteObject(); 5248 5249 m_PowerThread = NULL; 5250 } 5251 else if (hadThread) { 5252 // 5253 // Release our reference 5254 // 5255 m_PowerThreadInterface.Interface.InterfaceDereference( 5256 m_PowerThreadInterface.Interface.Context 5257 ); 5258 } 5259 } 5260 5261 VOID 5262 FxPkgPnp::_PowerThreadInterfaceReference( 5263 __inout PVOID Context 5264 ) 5265 /*++ 5266 5267 Routine Description: 5268 Increments the ref count on the thread interface. 5269 5270 Arguments: 5271 Context - FxPkgPnp* 5272 5273 Return Value: 5274 None 5275 5276 --*/ 5277 { 5278 LONG count; 5279 5280 count = InterlockedIncrement( 5281 &((FxPkgPnp*) Context)->m_PowerThreadInterfaceReferenceCount 5282 ); 5283 5284 #if DBG 5285 ASSERT(count >= 2); 5286 #else 5287 UNREFERENCED_PARAMETER(count); 5288 #endif 5289 } 5290 5291 VOID 5292 FxPkgPnp::_PowerThreadInterfaceDereference( 5293 __inout PVOID Context 5294 ) 5295 /*++ 5296 5297 Routine Description: 5298 Interface deref for the thread interface. If this is the last reference 5299 released, an event is set so that the thread which waiting for the last ref 5300 to go away can unblock. 5301 5302 Arguments: 5303 Context - FxPkgPnp* 5304 5305 Return Value: 5306 None 5307 5308 --*/ 5309 5310 { 5311 FxPkgPnp* pThis; 5312 5313 pThis = (FxPkgPnp*) Context; 5314 5315 if (InterlockedDecrement(&pThis->m_PowerThreadInterfaceReferenceCount) == 0) { 5316 pThis->m_PowerThreadEvent->Set(); 5317 } 5318 } 5319 5320 _Must_inspect_result_ 5321 NTSTATUS 5322 FxPkgPnp::PnpPowerReferenceSelf( 5323 VOID 5324 ) 5325 /*++ 5326 5327 Routine Description: 5328 Take a power reference during a query pnp transition. 5329 5330 Arguments: 5331 None 5332 5333 Return Value: 5334 None 5335 5336 --*/ 5337 { 5338 if (IsPowerPolicyOwner()) { 5339 // 5340 // We want to synchronously wait to move into D0 5341 // 5342 return PowerReference(TRUE); 5343 } 5344 else { 5345 return STATUS_SUCCESS; 5346 } 5347 } 5348 5349 _Must_inspect_result_ 5350 NTSTATUS 5351 FxPkgPnp::PnpPowerReferenceDuringQueryPnp( 5352 VOID 5353 ) 5354 /*++ 5355 5356 Routine Description: 5357 Take a power reference during a query pnp transition. 5358 5359 Arguments: 5360 None 5361 5362 Return Value: 5363 None 5364 5365 --*/ 5366 { 5367 if (IsPowerPolicyOwner()) { 5368 // 5369 // We want to synchronously wait to move into D0 5370 // 5371 return m_PowerPolicyMachine.m_Owner-> 5372 m_PowerIdleMachine.PowerReferenceWithFlags( 5373 FxPowerReferenceSendPnpPowerUpEvent 5374 ); 5375 } 5376 else { 5377 return STATUS_SUCCESS; 5378 } 5379 } 5380 5381 VOID 5382 FxPkgPnp::PnpPowerDereferenceSelf( 5383 VOID 5384 ) 5385 /*++ 5386 5387 Routine Description: 5388 Release the power reference taken during a query pnp transition 5389 5390 Arguments: 5391 None 5392 5393 Return Value: 5394 None 5395 5396 --*/ 5397 { 5398 if (IsPowerPolicyOwner()) { 5399 PowerDereference(); 5400 } 5401 } 5402 5403 NTSTATUS 5404 FxPkgPnp::CompletePowerRequest( 5405 __inout FxIrp* Irp, 5406 __in NTSTATUS Status 5407 ) 5408 { 5409 MdIrp irp; 5410 5411 // 5412 // Once we call CompleteRequest, 2 things happen 5413 // 1) this object may go away 5414 // 2) Irp->m_Irp will be cleared 5415 // 5416 // As such, we capture the underlying WDM objects so that we can use them 5417 // to release the remove lock and use the PIRP *value* as a tag to release 5418 // the remlock. 5419 // 5420 irp = Irp->GetIrp(); 5421 5422 Irp->SetStatus(Status); 5423 Irp->StartNextPowerIrp(); 5424 Irp->CompleteRequest(IO_NO_INCREMENT); 5425 5426 Mx::MxReleaseRemoveLock(m_Device->GetRemoveLock(), 5427 irp); 5428 5429 return Status; 5430 } 5431 5432 LONG 5433 FxPkgPnp::GetPnpStateInternal( 5434 VOID 5435 ) 5436 /*++ 5437 5438 Routine Description: 5439 Returns the pnp device state encoded into a ULONG. This state is the state 5440 that is reported to PNp via IRP_MN_QUERY_PNP_DEVICE_STATE after it has been 5441 decoded into the bits pnp expects 5442 5443 Arguments: 5444 None 5445 5446 Return Value: 5447 the current state bits 5448 5449 --*/ 5450 { 5451 LONG state; 5452 KIRQL irql; 5453 5454 // 5455 // State is shared with the caps bits. Use a lock to guard against 5456 // corruption of the value between these 2 values 5457 // 5458 Lock(&irql); 5459 state = m_PnpStateAndCaps.Value & FxPnpStateMask; 5460 Unlock(irql); 5461 5462 return state; 5463 } 5464 5465 LONG 5466 FxPkgPnp::GetPnpCapsInternal( 5467 VOID 5468 ) 5469 /*++ 5470 5471 Routine Description: 5472 Returns the pnp device capabilities encoded into a LONG. This state is used 5473 in reporting device capabilities via IRP_MN_QUERY_CAPABILITIES and filling 5474 in the PDEVICE_CAPABILITIES structure. 5475 5476 Arguments: 5477 None 5478 5479 Return Value: 5480 the current pnp cap bits 5481 5482 --*/ 5483 { 5484 LONG caps; 5485 KIRQL irql; 5486 5487 Lock(&irql); 5488 caps = m_PnpStateAndCaps.Value & FxPnpCapMask; 5489 Unlock(irql); 5490 5491 return caps; 5492 } 5493 5494 5495 VOID 5496 FxPkgPnp::SetPnpCaps( 5497 __in PWDF_DEVICE_PNP_CAPABILITIES PnpCapabilities 5498 ) 5499 /*++ 5500 5501 Routine Description: 5502 Encode the driver provided pnp capabilities into our internal capabilities 5503 bit field and store the result. 5504 5505 Arguments: 5506 PnpCapabilities - capabilities as reported by the driver writer 5507 5508 Return Value: 5509 None 5510 5511 --*/ 5512 { 5513 LONG pnpCaps; 5514 KIRQL irql; 5515 5516 pnpCaps = 0; 5517 pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, LockSupported); 5518 pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, EjectSupported); 5519 pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, Removable); 5520 pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, DockDevice); 5521 pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, UniqueID); 5522 pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, SilentInstall); 5523 pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, SurpriseRemovalOK); 5524 pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, HardwareDisabled); 5525 pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, NoDisplayInUI); 5526 5527 // 5528 // Since the caller of IRP_MN_QUERY_CAPABILITIES sets these 2 values to -1, 5529 // we can reuse the -1 as the default/no override value since the associated 5530 // PDEVICE_CAPAPBILITIES structure will have been predisposed to these values 5531 // 5532 if (PnpCapabilities->Address != (ULONG) -1) { 5533 m_PnpCapsAddress = PnpCapabilities->Address; 5534 } 5535 if (PnpCapabilities->UINumber != (ULONG) -1) { 5536 m_PnpCapsUINumber = PnpCapabilities->UINumber; 5537 } 5538 5539 // 5540 // Use the FxPnpStateMask to keep the state mask while applying the new 5541 // pnp capabilities. 5542 // 5543 Lock(&irql); 5544 m_PnpStateAndCaps.Value = (m_PnpStateAndCaps.Value & FxPnpStateMask) | pnpCaps; 5545 Unlock(irql); 5546 } 5547 5548 VOID 5549 FxPkgPnp::GetPnpState( 5550 __out PWDF_DEVICE_STATE State 5551 ) 5552 /*++ 5553 5554 Routine Description: 5555 Decodes our internal pnp state bitfield into the external WDF_DEVICE_STATE 5556 structure 5557 5558 Arguments: 5559 State - the structure to decode into 5560 5561 Return Value: 5562 None 5563 5564 --*/ 5565 { 5566 LONG state; 5567 5568 state = GetPnpStateInternal(); 5569 5570 SET_TRI_STATE_FROM_STATE_BITS(state, State, Disabled); 5571 SET_TRI_STATE_FROM_STATE_BITS(state, State, DontDisplayInUI); 5572 SET_TRI_STATE_FROM_STATE_BITS(state, State, Failed); 5573 SET_TRI_STATE_FROM_STATE_BITS(state, State, NotDisableable); 5574 SET_TRI_STATE_FROM_STATE_BITS(state, State, Removed); 5575 SET_TRI_STATE_FROM_STATE_BITS(state, State, ResourcesChanged); 5576 } 5577 5578 VOID 5579 FxPkgPnp::SetPnpState( 5580 __in PWDF_DEVICE_STATE State 5581 ) 5582 /*++ 5583 5584 Routine Description: 5585 Encodes the driver writer provided state into our internal bit field. 5586 5587 Arguments: 5588 State - the states to encode 5589 5590 Return Value: 5591 None 5592 5593 --*/ 5594 { 5595 LONG pnpState; 5596 KIRQL irql; 5597 5598 pnpState = 0x0; 5599 pnpState |= GET_PNP_STATE_BITS_FROM_STRUCT(State, Disabled); 5600 pnpState |= GET_PNP_STATE_BITS_FROM_STRUCT(State, DontDisplayInUI); 5601 pnpState |= GET_PNP_STATE_BITS_FROM_STRUCT(State, Failed); 5602 pnpState |= GET_PNP_STATE_BITS_FROM_STRUCT(State, NotDisableable); 5603 pnpState |= GET_PNP_STATE_BITS_FROM_STRUCT(State, Removed); 5604 pnpState |= GET_PNP_STATE_BITS_FROM_STRUCT(State, ResourcesChanged); 5605 5606 // 5607 // Mask off FxPnpCapMask to keep the capabilities part of the bitfield 5608 // the same while change the pnp state. 5609 // 5610 Lock(&irql); 5611 m_PnpStateAndCaps.Value = (m_PnpStateAndCaps.Value & FxPnpCapMask) | pnpState; 5612 Unlock(irql); 5613 } 5614 5615 VOID 5616 FxPkgPnp::_SetPowerCapState( 5617 __in ULONG Index, 5618 __in DEVICE_POWER_STATE State, 5619 __out PULONG Result 5620 ) 5621 /*++ 5622 5623 Routine Description: 5624 Encodes the given device power state (State) into Result at the given Index. 5625 States are encoded in nibbles (4 bit chunks), starting at the bottom of the 5626 result and moving upward 5627 5628 Arguments: 5629 Index - zero based index into the number of nibbles to encode the value 5630 5631 State - State to encode 5632 5633 Result - pointer to where the encoding will take place 5634 5635 Return Value: 5636 None 5637 5638 --*/ 5639 { 5640 // 5641 // We store off state in 4 bits, starting at the lowest byte 5642 // 5643 ASSERT(Index < 8); 5644 5645 // 5646 // Erase the old value 5647 // 5648 *Result &= ~(0xF << (Index * 4)); 5649 5650 // 5651 // Write in the new one 5652 // 5653 *Result |= (0xF & State) << (Index * 4); 5654 } 5655 5656 DEVICE_POWER_STATE 5657 FxPkgPnp::_GetPowerCapState( 5658 __in ULONG Index, 5659 __in ULONG State 5660 ) 5661 /*++ 5662 5663 Routine Description: 5664 Decodes our internal device state encoding and returns a normalized device 5665 power state for the given index. 5666 5667 Arguments: 5668 Index - nibble (4 bit chunk) index into the State 5669 5670 State - value which has the device states encoded into it 5671 5672 Return Value: 5673 device power state for the given Index 5674 5675 --*/ 5676 { 5677 ASSERT(Index < 8); 5678 // isolate the value and normalize it 5679 return (DEVICE_POWER_STATE) ((State & (0xF << (Index * 4))) >> (Index * 4)); 5680 } 5681 5682 VOID 5683 FxPkgPnp::SetPowerCaps( 5684 __in PWDF_DEVICE_POWER_CAPABILITIES PowerCapabilities 5685 ) 5686 /*++ 5687 5688 Routine Description: 5689 Encodes the driver provided power capabilities into the object. The device 5690 power states are encoded into one ULONG while the other power caps are 5691 encoded into their own distinct fields. 5692 5693 Arguments: 5694 PowerCapabilities - the power caps reported by the driver writer 5695 5696 Return Value: 5697 None 5698 5699 --*/ 5700 { 5701 ULONG states, i; 5702 USHORT powerCaps; 5703 5704 states = 0x0; 5705 5706 // 5707 // Build up the device power state encoding into a temp var so that if we are 5708 // retrieving the encoding in another thread, we don't get a partial view 5709 // 5710 for (i = 0; i < ARRAY_SIZE(PowerCapabilities->DeviceState); i++) { 5711 _SetPowerCapState(i, PowerCapabilities->DeviceState[i], &states); 5712 } 5713 5714 m_PowerCaps.States = states; 5715 5716 // 5717 // Same idea. Build up the caps locally first so that when we assign them 5718 // into the object, it is assigned as a whole. 5719 // 5720 powerCaps = 0x0; 5721 powerCaps |= GET_POWER_CAP_BITS_FROM_STRUCT(PowerCapabilities, DeviceD1); 5722 powerCaps |= GET_POWER_CAP_BITS_FROM_STRUCT(PowerCapabilities, DeviceD2); 5723 powerCaps |= GET_POWER_CAP_BITS_FROM_STRUCT(PowerCapabilities, WakeFromD0); 5724 powerCaps |= GET_POWER_CAP_BITS_FROM_STRUCT(PowerCapabilities, WakeFromD1); 5725 powerCaps |= GET_POWER_CAP_BITS_FROM_STRUCT(PowerCapabilities, WakeFromD2); 5726 powerCaps |= GET_POWER_CAP_BITS_FROM_STRUCT(PowerCapabilities, WakeFromD3); 5727 5728 m_PowerCaps.Caps = powerCaps; 5729 5730 if (PowerCapabilities->DeviceWake != PowerDeviceMaximum) { 5731 m_PowerCaps.DeviceWake = (BYTE) PowerCapabilities->DeviceWake; 5732 } 5733 if (PowerCapabilities->SystemWake != PowerSystemMaximum) { 5734 m_PowerCaps.SystemWake = (BYTE) PowerCapabilities->SystemWake; 5735 } 5736 5737 m_PowerCaps.D1Latency = PowerCapabilities->D1Latency; 5738 m_PowerCaps.D2Latency = PowerCapabilities->D2Latency; 5739 m_PowerCaps.D3Latency = PowerCapabilities->D3Latency; 5740 5741 if (PowerCapabilities->IdealDxStateForSx != PowerDeviceMaximum) { 5742 // 5743 // Caller has already validated that IdealDxStateForSx is only set if 5744 // they device is the power policy owner. 5745 // 5746 m_PowerPolicyMachine.m_Owner->m_IdealDxStateForSx = (BYTE) 5747 PowerCapabilities->IdealDxStateForSx; 5748 } 5749 } 5750 5751 NTSTATUS 5752 FxPkgPnp::CompletePnpRequest( 5753 __inout FxIrp* Irp, 5754 __in NTSTATUS Status 5755 ) 5756 { 5757 MdIrp pIrp = Irp->GetIrp(); 5758 5759 Irp->SetStatus(Status); 5760 Irp->CompleteRequest(IO_NO_INCREMENT); 5761 5762 Mx::MxReleaseRemoveLock(m_Device->GetRemoveLock(), 5763 pIrp); 5764 5765 return Status; 5766 } 5767 5768 BOOLEAN 5769 FxPkgPnp::PowerPolicyIsWakeEnabled( 5770 VOID 5771 ) 5772 { 5773 if (IsPowerPolicyOwner() && PowerPolicyGetCurrentWakeReason() != 0x0) { 5774 return TRUE; 5775 } 5776 else { 5777 return FALSE; 5778 } 5779 } 5780 5781 ULONG 5782 FxPkgPnp::PowerPolicyGetCurrentWakeReason( 5783 VOID 5784 ) 5785 /*++ 5786 5787 Routine Description: 5788 This routine determines the reasons for whether wake should be enabled or 5789 not. Wake could be enabled because it is explicitly enabled for the device 5790 in the wake policy settings or, because the device opted to depend on its 5791 children being armed for wake. 5792 5793 Arguments: 5794 None 5795 5796 Return Value: 5797 Returns a combination of FxPowerPolicySxWakeChildrenArmedFlag, to indicate 5798 that wake can be enabled because of more than one children being armed for 5799 wake, and FxPowerPolicySxWakeDeviceEnabledFlag, to indicate that wake can 5800 be enabled because the device was explicitly enabled in the wake policy 5801 settings. 5802 5803 Returns Zero to indicate that wake is currently disabled for the device. 5804 5805 --*/ 5806 { 5807 ULONG wakeReason; 5808 5809 wakeReason = 0x0; 5810 5811 if (m_PowerPolicyMachine.m_Owner->m_WakeSettings.ArmForWakeIfChildrenAreArmedForWake && 5812 m_PowerPolicyMachine.m_Owner->m_ChildrenArmedCount > 0) { 5813 // 5814 // Wake settings depends on children and one or more children are 5815 // armed for wake. 5816 // 5817 wakeReason |= FxPowerPolicySxWakeChildrenArmedFlag; 5818 } 5819 5820 if (m_PowerPolicyMachine.m_Owner->m_WakeSettings.Enabled) { 5821 // 5822 // Wake settings is explicitly enabled. 5823 // 5824 wakeReason |= FxPowerPolicySxWakeDeviceEnabledFlag; 5825 } 5826 5827 return wakeReason; 5828 } 5829 5830 VOID 5831 FxPkgPnp::SaveState( 5832 __in BOOLEAN UseCanSaveState 5833 ) 5834 /*++ 5835 5836 Routine Description: 5837 Saves any permanent state of the device out to the registry 5838 5839 Arguments: 5840 None 5841 5842 Return Value: 5843 None 5844 5845 --*/ 5846 5847 { 5848 UNICODE_STRING name; 5849 FxAutoRegKey hKey; 5850 NTSTATUS status; 5851 ULONG value; 5852 5853 // 5854 // We only have settings to save if we are the power policy owner 5855 // 5856 if (IsPowerPolicyOwner() == FALSE) { 5857 return; 5858 } 5859 5860 if (UseCanSaveState && 5861 m_PowerPolicyMachine.m_Owner->m_CanSaveState == FALSE) { 5862 DoTraceLevelMessage( 5863 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 5864 "Not saving wake settings for WDFDEVICE %p due to system power " 5865 "transition", m_Device->GetHandle()); 5866 return; 5867 } 5868 5869 // 5870 // Check to see if there is anything to write out 5871 // 5872 if (m_PowerPolicyMachine.m_Owner->m_IdleSettings.Dirty == FALSE && 5873 m_PowerPolicyMachine.m_Owner->m_WakeSettings.Dirty == FALSE) { 5874 return; 5875 } 5876 5877 // 5878 // No need to write out if user control is not enabled 5879 // 5880 if (m_PowerPolicyMachine.m_Owner->m_IdleSettings.Overridable == FALSE && 5881 m_PowerPolicyMachine.m_Owner->m_WakeSettings.Overridable == FALSE) { 5882 return; 5883 } 5884 5885 // 5886 // If the device is in paging path we should not be touching registry during 5887 // power up because it may incur page fault which won't be satisfied if the 5888 // device is still not powered up, blocking power Irp. User control state 5889 // change will not get written if any at this time but will be flushed out 5890 // to registry during device disable/remove in the remove path. 5891 // 5892 if (IsUsageSupported(DeviceUsageTypePaging) && IsDevicePowerUpIrpPending()) { 5893 return; 5894 } 5895 5896 #if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) 5897 5898 status = m_Device->OpenSettingsKey(&hKey.m_Key, STANDARD_RIGHTS_WRITE); 5899 if (!NT_SUCCESS(status)) { 5900 return; 5901 } 5902 #else 5903 status = STATUS_SUCCESS; 5904 #endif 5905 5906 if (m_PowerPolicyMachine.m_Owner->m_IdleSettings.Overridable && 5907 m_PowerPolicyMachine.m_Owner->m_IdleSettings.Dirty) { 5908 RtlInitUnicodeString(&name, WDF_S0_IDLE_ENABLED_VALUE_NAME); 5909 value = m_PowerPolicyMachine.m_Owner->m_IdleSettings.Enabled; 5910 5911 WriteStateToRegistry(hKey.m_Key, &name, value); 5912 5913 m_PowerPolicyMachine.m_Owner->m_IdleSettings.Dirty = FALSE; 5914 } 5915 5916 if (m_PowerPolicyMachine.m_Owner->m_WakeSettings.Overridable && 5917 m_PowerPolicyMachine.m_Owner->m_WakeSettings.Dirty) { 5918 RtlInitUnicodeString(&name, WDF_SX_WAKE_ENABLED_VALUE_NAME); 5919 value = m_PowerPolicyMachine.m_Owner->m_WakeSettings.Enabled; 5920 5921 WriteStateToRegistry(hKey.m_Key, &name, value); 5922 5923 m_PowerPolicyMachine.m_Owner->m_WakeSettings.Dirty = FALSE; 5924 } 5925 } 5926 5927 VOID 5928 FxPkgPnp::AddInterruptObject( 5929 __in FxInterrupt* Interrupt 5930 ) 5931 /*++ 5932 5933 Routine Description: 5934 5935 This routine adds a WDFINTERRUPT object onto the list of interrupts 5936 which are attached to this device. This list is used in response to 5937 several IRPs. 5938 5939 Note: 5940 5941 It shouldn't be necessary to lock this list, since the driver will add or 5942 remove interrupt objects only in callbacks that are effectively serialized 5943 by the PnP manager. 5944 5945 Further note: 5946 5947 This list must remain sorted by order of interrupt object creation. E.g. 5948 the first interrupt object created must be first in this list. 5949 5950 Arguments: 5951 5952 Interrupt - a Framework interrupt object 5953 5954 Return Value: 5955 5956 VOID 5957 5958 --*/ 5959 { 5960 m_InterruptObjectCount++; 5961 InsertTailList(&m_InterruptListHead, &Interrupt->m_PnpList); 5962 } 5963 5964 VOID 5965 FxPkgPnp::RemoveInterruptObject( 5966 __in FxInterrupt* Interrupt 5967 ) 5968 /*++ 5969 5970 Routine Description: 5971 This routine removes a WDFINTERRUPT object onto the list of interrupts 5972 which are attached to this device. This list is used in response to 5973 several IRPs. 5974 5975 Arguments: 5976 5977 Interrupt - a Framework interrupt object 5978 5979 Return Value: 5980 5981 VOID 5982 5983 --*/ 5984 { 5985 m_InterruptObjectCount--; 5986 RemoveEntryList(&Interrupt->m_PnpList); 5987 } 5988 5989 VOID 5990 FxPkgPnp::NotifyResourceobjectsToReleaseResources( 5991 VOID 5992 ) 5993 /*++ 5994 5995 Routine Description: 5996 5997 This routine traverses all resource objects and tells them that their 5998 resources are no longer valid. 5999 6000 Arguments: 6001 6002 none 6003 6004 Return Value: 6005 6006 VOID 6007 6008 --*/ 6009 { 6010 FxInterrupt* interruptInstance; 6011 PLIST_ENTRY intListEntry; 6012 6013 // 6014 // Revoke each of the interrupts. 6015 // 6016 6017 intListEntry = m_InterruptListHead.Flink; 6018 6019 while (intListEntry != &m_InterruptListHead) { 6020 6021 // 6022 // Disconnect interrupts and then tell them that they no longer 6023 // own their resources. 6024 // 6025 6026 interruptInstance = CONTAINING_RECORD(intListEntry, FxInterrupt, m_PnpList); 6027 interruptInstance->RevokeResources(); 6028 intListEntry = intListEntry->Flink; 6029 } 6030 6031 // 6032 // Now revoke each of the DMA enablers (only system-mode enablers 6033 // will be affected by this) 6034 // 6035 6036 if (m_DmaEnablerList != NULL) { 6037 FxTransactionedEntry* listEntry; 6038 6039 m_DmaEnablerList->LockForEnum(GetDriverGlobals()); 6040 6041 for (listEntry = m_DmaEnablerList->GetNextEntry(NULL); 6042 listEntry != NULL; 6043 listEntry = m_DmaEnablerList->GetNextEntry(listEntry)) { 6044 RevokeDmaEnablerResources( 6045 (FxDmaEnabler *) listEntry->GetTransactionedObject() 6046 ); 6047 } 6048 6049 m_DmaEnablerList->UnlockFromEnum(GetDriverGlobals()); 6050 } 6051 } 6052 6053 _Must_inspect_result_ 6054 NTSTATUS 6055 FxPkgPnp::NotifyResourceObjectsD0( 6056 __in ULONG NotifyFlags 6057 ) 6058 /*++ 6059 6060 Routine Description: 6061 6062 This routine traverses all resource objects and tells them that the device 6063 is entering D0. If an error is encountered, the walking of the list is 6064 halted. 6065 6066 Arguments: 6067 6068 none 6069 6070 Return Value: 6071 6072 VOID 6073 6074 --*/ 6075 { 6076 FxInterrupt* pInterrupt; 6077 PLIST_ENTRY ple; 6078 NTSTATUS status; 6079 6080 for (ple = m_InterruptListHead.Flink; 6081 ple != &m_InterruptListHead; 6082 ple = ple->Flink) { 6083 6084 // 6085 // Connect the interrupts 6086 // 6087 pInterrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList); 6088 6089 status = pInterrupt->Connect(NotifyFlags); 6090 6091 if (!NT_SUCCESS(status)) { 6092 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 6093 "WDFINTERRUPT %p failed to connect, %!STATUS!", 6094 pInterrupt->GetHandle(), status); 6095 6096 return status; 6097 } 6098 } 6099 6100 return STATUS_SUCCESS; 6101 } 6102 6103 NTSTATUS 6104 FxPkgPnp::NotifyResourceObjectsDx( 6105 __in ULONG NotifyFlags 6106 ) 6107 /*++ 6108 6109 Routine Description: 6110 This routine traverses all resource objects and tells them that the device 6111 is leaving D0. If there is an error, the remaining resources in the list 6112 are still notified of exitting D0. 6113 6114 Arguments: 6115 NotifyFlags - combination of values from the enum NotifyResourcesFlags 6116 6117 Return Value: 6118 None 6119 6120 --*/ 6121 { 6122 FxInterrupt* pInterrupt; 6123 PLIST_ENTRY ple; 6124 NTSTATUS status, finalStatus; 6125 6126 finalStatus = STATUS_SUCCESS; 6127 6128 // 6129 // Disconect in the reverse order in which we connected the interrupts 6130 // 6131 for (ple = m_InterruptListHead.Blink; 6132 ple != &m_InterruptListHead; 6133 ple = ple->Blink) { 6134 6135 // 6136 // Disconnect interrupts and then tell them that they no longer 6137 // own their resources. 6138 // 6139 pInterrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList); 6140 6141 status = pInterrupt->Disconnect(NotifyFlags); 6142 6143 if (!NT_SUCCESS(status)) { 6144 // 6145 // When we encounter an error we still disconnect the remaining 6146 // interrupts b/c we would just do it later during device tear down 6147 // (might as well do it now). 6148 // 6149 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 6150 "WDFINTERRUPT %p failed to disconnect, %!STATUS!", 6151 pInterrupt->GetHandle(), status); 6152 // 6153 // Overwriting a previous finalStatus is OK, we'll just report the 6154 // last one 6155 // 6156 finalStatus = status; 6157 } 6158 } 6159 6160 return finalStatus; 6161 } 6162 6163 VOID 6164 FxPkgPnp::SendEventToAllWakeInterrupts( 6165 __in FxWakeInterruptEvents WakeInterruptEvent 6166 ) 6167 /*++ 6168 6169 Routine Description: 6170 This routine traverses all interrupt objects and queues the 6171 given event into those interrupts that are marked as wake 6172 capable and have a state machine 6173 6174 Arguments: 6175 WakeInterruptEvent - Event to be queued in the wake interrupt 6176 state machines 6177 6178 Return Value: 6179 None 6180 6181 --*/ 6182 { 6183 FxInterrupt* pInterrupt; 6184 PLIST_ENTRY ple; 6185 6186 if (m_WakeInterruptCount == 0) { 6187 return; 6188 } 6189 6190 // 6191 // Initialize the pending count to the wake interrupt count 6192 // If the event needs an acknowledgement, this variable will 6193 // be decremented as the interrupt machines ack. 6194 // 6195 m_WakeInterruptPendingAckCount = m_WakeInterruptCount; 6196 6197 for (ple = m_InterruptListHead.Flink; 6198 ple != &m_InterruptListHead; 6199 ple = ple->Flink) { 6200 6201 pInterrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList); 6202 6203 if (pInterrupt->IsWakeCapable()) { 6204 pInterrupt->ProcessWakeInterruptEvent(WakeInterruptEvent); 6205 } 6206 6207 } 6208 } 6209 6210 VOID 6211 FxPkgPnp::AckPendingWakeInterruptOperation( 6212 __in BOOLEAN ProcessPowerEventOnDifferentThread 6213 ) 6214 /*++ 6215 6216 Routine Description: 6217 This routine is invoked by the interrupt wake machine to acknowledge 6218 back an event that was queued into it. When the last interrupt machine 6219 acknowledges, an event is queued back into the Pnp/power state machine 6220 6221 Arguments: 6222 6223 ProcessPowerEventOnDifferentThread - Once all wake interrupts for the device 6224 have acknowledged the operation, if this is TRUE, the power state 6225 machine will process the PowerWakeInterruptCompleteTransition event on a 6226 seperate thread. 6227 6228 Return Value: 6229 None 6230 6231 --*/ 6232 { 6233 if (InterlockedDecrement((LONG *)&m_WakeInterruptPendingAckCount) == 0) { 6234 PowerProcessEvent( 6235 PowerWakeInterruptCompleteTransition, 6236 ProcessPowerEventOnDifferentThread 6237 ); 6238 } 6239 } 6240 6241 6242 NTSTATUS 6243 FxPkgPnp::AssignPowerFrameworkSettings( 6244 __in PWDF_POWER_FRAMEWORK_SETTINGS PowerFrameworkSettings 6245 ) 6246 { 6247 // NTSTATUS status; 6248 // PPO_FX_COMPONENT_IDLE_STATE idleStates = NULL; 6249 // ULONG idleStatesSize = 0; 6250 // PPO_FX_COMPONENT component = NULL; 6251 // ULONG componentSize = 0; 6252 // PPOX_SETTINGS poxSettings = NULL; 6253 // ULONG poxSettingsSize = 0; 6254 // BYTE * buffer = NULL; 6255 6256 // if (FALSE==(IdleTimeoutManagement::_SystemManagedIdleTimeoutAvailable())) { 6257 // // 6258 // // If system-managed idle timeout is not available on this OS, then 6259 // // there is nothing to do. 6260 // // 6261 // DoTraceLevelMessage( 6262 // GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 6263 // "WDFDEVICE %p !devobj %p Power framework is not supported on the " 6264 // "current OS. Therefore, the power framework settings will not take " 6265 // "effect.", 6266 // m_Device->GetHandle(), 6267 // m_Device->GetDeviceObject() 6268 // ); 6269 // return STATUS_SUCCESS; 6270 // } 6271 6272 // if (NULL != PowerFrameworkSettings->Component) { 6273 // // 6274 // // Caller should ensure that IdleStateCount is not zero 6275 // // 6276 // ASSERT(0 != PowerFrameworkSettings->Component->IdleStateCount); 6277 6278 // // 6279 // // Compute buffer size needed for storing F-states 6280 // // 6281 // status = RtlULongMult( 6282 // PowerFrameworkSettings->Component->IdleStateCount, 6283 // sizeof(*(PowerFrameworkSettings->Component->IdleStates)), 6284 // &idleStatesSize 6285 // ); 6286 // if (FALSE == NT_SUCCESS(status)) { 6287 // DoTraceLevelMessage( 6288 // GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 6289 // "WDFDEVICE %p !devobj %p Unable to compute length of buffer " 6290 // "required to store F-states. RtlULongMult failed with " 6291 // "%!STATUS!", 6292 // m_Device->GetHandle(), 6293 // m_Device->GetDeviceObject(), 6294 // status 6295 // ); 6296 // goto exit; 6297 // } 6298 6299 // // 6300 // // Compute buffer size needed for storing component information 6301 // // (including F-states) 6302 // // 6303 // status = RtlULongAdd(idleStatesSize, 6304 // sizeof(*component), 6305 // &componentSize); 6306 // if (FALSE == NT_SUCCESS(status)) { 6307 // DoTraceLevelMessage( 6308 // GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 6309 // "WDFDEVICE %p !devobj %p Unable to compute length of buffer " 6310 // "required to store driver's component information. RtlULongAdd " 6311 // "failed with %!STATUS!", 6312 // m_Device->GetHandle(), 6313 // m_Device->GetDeviceObject(), 6314 // status 6315 // ); 6316 // goto exit; 6317 // } 6318 // } 6319 6320 // // 6321 // // Compute total buffer size needed for power framework settings 6322 // // 6323 // status = RtlULongAdd(componentSize, 6324 // sizeof(*poxSettings), 6325 // &poxSettingsSize); 6326 // if (FALSE == NT_SUCCESS(status)) { 6327 // DoTraceLevelMessage( 6328 // GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 6329 // "WDFDEVICE %p !devobj %p Unable to compute length of buffer " 6330 // "required to store driver's power framework settings. RtlULongAdd " 6331 // "failed with %!STATUS!", 6332 // m_Device->GetHandle(), 6333 // m_Device->GetDeviceObject(), 6334 // status 6335 // ); 6336 // goto exit; 6337 // } 6338 6339 // // 6340 // // Allocate memory to copy the settings 6341 // // 6342 // buffer = (BYTE *) MxMemory::MxAllocatePoolWithTag(NonPagedPool, 6343 // poxSettingsSize, 6344 // GetDriverGlobals()->Tag); 6345 // if (NULL == buffer) { 6346 // status = STATUS_INSUFFICIENT_RESOURCES; 6347 // DoTraceLevelMessage( 6348 // GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 6349 // "WDFDEVICE %p !devobj %p Unable to allocate buffer required to " 6350 // "store F-states. %!STATUS!", 6351 // m_Device->GetHandle(), 6352 // m_Device->GetDeviceObject(), 6353 // status 6354 // ); 6355 // goto exit; 6356 // } 6357 6358 // // 6359 // // Set our pointers to point to appropriate locations in the buffer. 6360 // // 6361 // // NOTES: 6362 // // - The array of F-states comes first because it has ULONGLONG members 6363 // // because of which it has the biggest alignment requirement. 6364 // // - The logic below works even if the client driver did not specify any 6365 // // component information. In that case idleStatesSize and componentSize 6366 // // are both 0 and 'poxSettings' points to the beginning of the allocated 6367 // // buffer 6368 // // 6369 // idleStates = (PPO_FX_COMPONENT_IDLE_STATE) buffer; 6370 // component = (PPO_FX_COMPONENT) (buffer + idleStatesSize); 6371 // poxSettings = (PPOX_SETTINGS) (buffer + componentSize); 6372 6373 // // 6374 // // Copy the relevant parts of the settings buffer 6375 // // 6376 // poxSettings->EvtDeviceWdmPostPoFxRegisterDevice = 6377 // PowerFrameworkSettings->EvtDeviceWdmPostPoFxRegisterDevice; 6378 // poxSettings->EvtDeviceWdmPrePoFxUnregisterDevice = 6379 // PowerFrameworkSettings->EvtDeviceWdmPrePoFxUnregisterDevice; 6380 // poxSettings->Component = PowerFrameworkSettings->Component; 6381 // poxSettings->ComponentActiveConditionCallback = 6382 // PowerFrameworkSettings->ComponentActiveConditionCallback; 6383 // poxSettings->ComponentIdleConditionCallback = 6384 // PowerFrameworkSettings->ComponentIdleConditionCallback; 6385 // poxSettings->ComponentIdleStateCallback = 6386 // PowerFrameworkSettings->ComponentIdleStateCallback; 6387 // poxSettings->PowerControlCallback = 6388 // PowerFrameworkSettings->PowerControlCallback; 6389 // poxSettings->PoFxDeviceContext = PowerFrameworkSettings->PoFxDeviceContext; 6390 6391 // if (NULL != PowerFrameworkSettings->Component) { 6392 // // 6393 // // Copy the component information 6394 // // 6395 // poxSettings->Component = component; 6396 // RtlCopyMemory(poxSettings->Component, 6397 // PowerFrameworkSettings->Component, 6398 // sizeof(*component)); 6399 6400 // // 6401 // // Caller should ensure that IdleStates is not NULL 6402 // // 6403 // ASSERT(NULL != PowerFrameworkSettings->Component->IdleStates); 6404 6405 // // 6406 // // Copy the F-states 6407 // // 6408 // poxSettings->Component->IdleStates = idleStates; 6409 // RtlCopyMemory(poxSettings->Component->IdleStates, 6410 // PowerFrameworkSettings->Component->IdleStates, 6411 // idleStatesSize); 6412 // } 6413 6414 // // 6415 // // Commit these settings 6416 // // 6417 // status = m_PowerPolicyMachine.m_Owner-> 6418 // m_IdleSettings.m_TimeoutMgmt.CommitPowerFrameworkSettings( 6419 // GetDriverGlobals(), 6420 // poxSettings 6421 // ); 6422 // if (FALSE == NT_SUCCESS(status)) { 6423 // goto exit; 6424 // } 6425 6426 // status = STATUS_SUCCESS; 6427 6428 // exit: 6429 // if (FALSE == NT_SUCCESS(status)) { 6430 // if (NULL != buffer) { 6431 // MxMemory::MxFreePool(buffer); 6432 // } 6433 // } 6434 // return status; 6435 ROSWDFNOTIMPLEMENTED; 6436 return STATUS_SUCCESS; 6437 } 6438 6439 DEVICE_POWER_STATE 6440 FxPkgPnp::PowerPolicyGetDeviceDeepestDeviceWakeState( 6441 __in SYSTEM_POWER_STATE SystemState 6442 ) 6443 { 6444 DEVICE_POWER_STATE dxState; 6445 6446 // 6447 // Earlier versions of WDF (pre-1.11) did not take into account SystemState 6448 // in figuring out the deepest wake state. So for compatibility we restrict 6449 // this to drivers compiled for 1.11 or newer. See comments in the 6450 // FxPkgPnp::QueryForCapabilities function for more information on 6451 // compatibility risk. 6452 // 6453 if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(1,11)) { 6454 if ((SystemState < PowerSystemWorking) || 6455 (SystemState > PowerSystemHibernate)) { 6456 dxState = PowerDeviceD0; 6457 } else { 6458 dxState = MapWakeDepthToDstate( 6459 (DEVICE_WAKE_DEPTH)m_DeviceWake[SystemState - PowerSystemWorking] 6460 ); 6461 } 6462 } 6463 else { 6464 // 6465 // For pre-1.11 drivers, all of m_DeviceWake array is populated with 6466 // the same DeviceWake value obtained from device capabilities so we 6467 // just use the first one (index 0). 6468 // 6469 dxState = MapWakeDepthToDstate((DEVICE_WAKE_DEPTH)m_DeviceWake[0]); 6470 } 6471 6472 // 6473 // Per WDM docs DeviceWake and SystemWake must be non-zero to support 6474 // wake. We warn about the violation. Ideally, a verifier check would have 6475 // been better but we want to avoid that because some drivers may 6476 // intentionally call this DDI and do not treat the DDI failure as fatal ( 6477 // because they are aware that DDI may succeed in some cases), and a verifier 6478 // breakpoint would force them to avoid the verifier failure by not enabling 6479 // verifier. 6480 // 6481 if (dxState == PowerDeviceUnspecified || 6482 m_SystemWake == PowerSystemUnspecified) { 6483 DoTraceLevelMessage( 6484 GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP, 6485 "SystemWake %!SYSTEM_POWER_STATE! and DeviceWake " 6486 "%!DEVICE_POWER_STATE! power state reported in device " 6487 "capabilities do not support wake. Both the SystemWake and " 6488 "DeviceWake members should be nonzero to support wake-up on " 6489 "this system.", m_SystemWake, dxState); 6490 } 6491 6492 return dxState; 6493 } 6494 6495