mirror of
https://github.com/reactos/reactos.git
synced 2024-05-16 10:11:53 +00:00
8404 lines
254 KiB
C++
8404 lines
254 KiB
C++
/*++
|
|
|
|
Copyright (c) Microsoft. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
PowerPolicyStateMachine.cpp
|
|
|
|
Abstract:
|
|
|
|
This module implements the Power Policy state machine for the driver
|
|
framework. This code was split out from FxPkgPnp.cpp.
|
|
|
|
Author:
|
|
|
|
|
|
|
|
|
|
Environment:
|
|
|
|
Both kernel and user mode
|
|
|
|
Revision History:
|
|
|
|
|
|
|
|
--*/
|
|
|
|
#include "pnppriv.hpp"
|
|
|
|
#if FX_IS_KERNEL_MODE
|
|
#include <usbdrivr.h>
|
|
#endif
|
|
|
|
#include "fxusbidleinfo.hpp"
|
|
|
|
extern "C" {
|
|
#if defined(EVENT_TRACING)
|
|
#include "PowerPolicyStateMachine.tmh"
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// The Power Policy State Machine
|
|
//
|
|
// This state machine responds to the following events:
|
|
//
|
|
// PowerUp
|
|
// PowerDown
|
|
// PowerPolicyStart
|
|
// PowerPolicyStop
|
|
// IRP_MN_SET_POWER -- System State S0
|
|
// IRP_MN_SET_POWER -- System State Sx
|
|
// PowerTimeoutExpired
|
|
// IoPresent
|
|
// IRP_MN_WAIT_WAKE Complete
|
|
// IRP_MN_WAIT_WAKE Failed
|
|
//
|
|
|
|
#if FX_SUPER_DBG
|
|
#define ASSERT_PWR_POL_STATE(_This, _State) \
|
|
ASSERT((_This)->m_Device->GetDevicePowerPolicyState() == (_State))
|
|
#else
|
|
#define ASSERT_PWR_POL_STATE(_This, _State) (0)
|
|
#endif
|
|
|
|
#if FX_STATE_MACHINE_VERIFY
|
|
#define VALIDATE_PWR_POL_STATE(_CurrentState, _NewState) \
|
|
ValidatePwrPolStateEntryFunctionReturnValue((_CurrentState), (_NewState))
|
|
#else
|
|
#define VALIDATE_PWR_POL_STATE(_CurrentState, _NewState) (0)
|
|
#endif //FX_STATE_MACHINE_VERIFY
|
|
|
|
// @@SMVERIFY_SPLIT_BEGIN
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolObjectCreatedOtherStates[] =
|
|
{
|
|
{ PwrPolRemove, WdfDevStatePwrPolRemoved DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStartingOtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolStartingFailed DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStartedIdleCapableOtherStates[] =
|
|
{
|
|
{ PwrPolSx, WdfDevStatePwrPolStartedIdleCapableCancelTimerForSleep DEBUGGED_EVENT },
|
|
{ PwrPolStop, WdfDevStatePwrPolStoppingCancelTimer DEBUGGED_EVENT },
|
|
{ PwrPolSurpriseRemove,WdfDevStatePwrPolStoppingCancelTimer DEBUGGED_EVENT },
|
|
{ PwrPolS0IdlePolicyChanged, WdfDevStatePwrPolStartedCancelTimer DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolIdleCapableDeviceIdleOtherStates[] =
|
|
{
|
|
{ PwrPolSx, WdfDevStatePwrPolDeviceIdleSleeping DEBUGGED_EVENT },
|
|
{ PwrPolStop, WdfDevStatePwrPolDeviceIdleStopping DEBUGGED_EVENT },
|
|
{ PwrPolSurpriseRemove,WdfDevStatePwrPolDeviceIdleStopping DEBUGGED_EVENT },
|
|
{ PwrPolS0IdlePolicyChanged, WdfDevStatePwrPolDeviceIdleReturnToActive TRAP_ON_EVENT },
|
|
{ PwrPolIoPresent, WdfDevStatePwrPolDeviceIdleReturnToActive DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredNoWakeOtherStates[] =
|
|
{
|
|
{ PwrPolPowerDown, WdfDevStatePwrPolTimerExpiredNoWakePowerDownNotProcessed TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredNoWakeCompletePowerDownOtherStates[] =
|
|
{
|
|
{ PwrPolPowerDownFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolWaitingUnarmedOtherStates[] =
|
|
{
|
|
{ PwrPolSx, WdfDevStatePwrPolSystemSleepFromDeviceWaitingUnarmed DEBUGGED_EVENT },
|
|
{ PwrPolStop, WdfDevStatePwrPolStoppingResetDevice DEBUGGED_EVENT },
|
|
{ PwrPolSurpriseRemove, WdfDevStatePwrPolStoppingCancelTimer DEBUGGED_EVENT },
|
|
{ PwrPolS0IdlePolicyChanged, WdfDevStatePwrPolS0NoWakePowerUp DEBUGGED_EVENT },
|
|
{ PwrPolDevicePowerRequired, WdfDevStatePwrPolS0NoWakePowerUp DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolS0NoWakePowerUpOtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT },
|
|
{ PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolS0NoWakeCompletePowerUpOtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemSleepNeedWakeOtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolSystemSleepPowerRequestFailed DEBUGGED_EVENT },
|
|
{ PwrPolPowerUpNotSeen, WdfDevStatePwrPolPowerUpForSystemSleepNotSeen TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemSleepNeedWakeCompletePowerUpOtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolSystemSleepPowerRequestFailed DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemAsleepWakeArmedOtherStates[] =
|
|
{
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolSystemWakeDeviceWakeTriggered DEBUGGED_EVENT },
|
|
{ PwrPolWakeInterruptFired, WdfDevStatePwrPolSystemWakeDeviceWakeInterruptFired DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemAsleepWakeArmedNPOtherStates[] =
|
|
{
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredNP DEBUGGED_EVENT },
|
|
{ PwrPolWakeInterruptFired, WdfDevStatePwrPolSystemWakeDeviceWakeInterruptFiredNP TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceToD0OtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT },
|
|
{ PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceToD0CompletePowerUpOtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStartedWakeCapableOtherStates[] =
|
|
{
|
|
{ PwrPolSx, WdfDevStatePwrPolStartedWakeCapableCancelTimerForSleep DEBUGGED_EVENT },
|
|
{ PwrPolStop, WdfDevStatePwrPolStoppingCancelTimer DEBUGGED_EVENT },
|
|
{ PwrPolSurpriseRemove, WdfDevStatePwrPolStoppingCancelTimer DEBUGGED_EVENT },
|
|
{ PwrPolS0IdlePolicyChanged, WdfDevStatePwrPolStartedCancelTimer DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolWakeCapableDeviceIdleOtherStates[] =
|
|
{
|
|
{ PwrPolSx, WdfDevStatePwrPolDeviceIdleSleeping DEBUGGED_EVENT },
|
|
{ PwrPolStop, WdfDevStatePwrPolDeviceIdleStopping TRAP_ON_EVENT },
|
|
{ PwrPolSurpriseRemove,WdfDevStatePwrPolDeviceIdleStopping DEBUGGED_EVENT },
|
|
{ PwrPolS0IdlePolicyChanged, WdfDevStatePwrPolDeviceIdleReturnToActive TRAP_ON_EVENT },
|
|
{ PwrPolIoPresent, WdfDevStatePwrPolDeviceIdleReturnToActive DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSleepingWakePowerDownOtherStates[] =
|
|
{
|
|
{ PwrPolPowerDown, WdfDevStatePwrPolSleepingPowerDownNotProcessed TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapablePowerDownOtherStates[] =
|
|
{
|
|
{ PwrPolPowerDown, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownNotProcessed TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapableSendWakeOtherStates[] =
|
|
{
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolTimerExpiredWakeCompletedDisarm DEBUGGED_EVENT },
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolTimerExpiredWakeSucceeded DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapableUsbSSOtherStates[] =
|
|
{
|
|
{ PwrPolSx, WdfDevStatePwrPolStartedWakeCapableSleepingUsbSS DEBUGGED_EVENT },
|
|
{ PwrPolStop, WdfDevStatePwrPolStoppingCancelUsbSS TRAP_ON_EVENT },
|
|
{ PwrPolSurpriseRemove, WdfDevStatePwrPolStoppingCancelUsbSS DEBUGGED_EVENT },
|
|
{ PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolWakeCapableUsbSSCompleted DEBUGGED_EVENT },
|
|
{ PwrPolS0IdlePolicyChanged, WdfDevStatePwrPolCancelUsbSS DEBUGGED_EVENT },
|
|
{ PwrPolIoPresent, WdfDevStatePwrPolCancelUsbSS DEBUGGED_EVENT },
|
|
{ PwrPolDevicePowerRequired, WdfDevStatePwrPolCancelUsbSS DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolWaitingArmedOtherStates[] =
|
|
{
|
|
{ PwrPolSx, WdfDevStatePwrPolCancelingUsbSSForSystemSleep DEBUGGED_EVENT },
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolWaitingArmedWakeSucceededCancelUsbSS DEBUGGED_EVENT },
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolWaitingArmedWakeFailedCancelUsbSS DEBUGGED_EVENT },
|
|
{ PwrPolStop, WdfDevStatePwrPolStoppingD0CancelUsbSS DEBUGGED_EVENT },
|
|
{ PwrPolSurpriseRemove, WdfDevStatePwrPolWaitingArmedStoppingCancelUsbSS DEBUGGED_EVENT },
|
|
{ PwrPolS0IdlePolicyChanged, WdfDevStatePwrPolWaitingArmedIoPresentCancelUsbSS DEBUGGED_EVENT },
|
|
{ PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolIoPresentArmed TRAP_ON_EVENT },
|
|
{ PwrPolDevicePowerRequired, WdfDevStatePwrPolWaitingArmedIoPresentCancelUsbSS DEBUGGED_EVENT },
|
|
{ PwrPolWakeInterruptFired, WdfDevStatePwrPolWaitingArmedWakeInterruptFired DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolDisarmingWakeForSystemSleepCompletePowerUpOtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolPowerUpForSystemSleepFailed DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolCancelingWakeForSystemSleepWakeCanceledOtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolPowerUpForSystemSleepFailed DEBUGGED_EVENT },
|
|
{ PwrPolPowerUpNotSeen, WdfDevStatePwrPolPowerUpForSystemSleepNotSeen TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolWokeFromS0OtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT },
|
|
{ PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStoppingResetDeviceOtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolStoppingResetDeviceFailed DEBUGGED_EVENT },
|
|
{ PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStoppingResetDeviceCompletePowerUpOtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolStoppingResetDeviceFailed DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStoppingD0OtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolStoppingD0Failed DEBUGGED_EVENT },
|
|
{ PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStoppingDisarmWakeOtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolStoppingD0Failed DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStoppingDisarmWakeCancelWakeOtherStates[] =
|
|
{
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolStoppingDisarmWakeWakeCanceled DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStartedOtherStates[] =
|
|
{
|
|
{ PwrPolStop, WdfDevStatePwrPolStopping DEBUGGED_EVENT },
|
|
{ PwrPolSurpriseRemove, WdfDevStatePwrPolStopping DEBUGGED_EVENT },
|
|
{ PwrPolS0IdlePolicyChanged, WdfDevStatePwrPolStartingDecideS0Wake DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStartedWaitForIdleTimeoutOtherStates[] =
|
|
{
|
|
{ PwrPolStop, WdfDevStatePwrPolStoppingWaitForIdleTimeout TRAP_ON_EVENT },
|
|
{ PwrPolSurpriseRemove, WdfDevStatePwrPolStoppingWaitForIdleTimeout TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolIoPresentArmedOtherStates[] =
|
|
{
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolIoPresentArmedWakeCanceled DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolIoPresentArmedWakeCanceledOtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT },
|
|
{ PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolS0WakeCompletePowerUpOtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapableWakeSucceededOtherStates[] =
|
|
{
|
|
{ PwrPolPowerDownFailed, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedUsbSS DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapableWakeFailedOtherStates[] =
|
|
{
|
|
{ PwrPolPowerDownFailed, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedUsbSS DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapablePowerDownFailedCancelWakeOtherStates[] =
|
|
{
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolCancelingWakeForSystemSleepOtherStates[] =
|
|
{
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolCancelingWakeForSystemSleepWakeCanceled DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapableWakeArrivedOtherStates[] =
|
|
{
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolTimerExpiredWakeCapableWakeSucceeded DEBUGGED_EVENT },
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolTimerExpiredWakeCapableWakeFailed DEBUGGED_EVENT },
|
|
{ PwrPolPowerDownFailed, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedCancelWake DEBUGGED_EVENT },
|
|
{ PwrPolWakeInterruptFired, WdfDevStatePwrPolTimerExpiredWakeCapableWakeInterruptArrived },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapableCancelWakeOtherStates[] =
|
|
{
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolTimerExpiredWakeCapableWakeCanceled DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCompletedPowerDownOtherStates[] =
|
|
{
|
|
{ PwrPolPowerDownFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCompletedPowerUpOtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT },
|
|
{ PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSleepingWakeWakeArrivedOtherStates[] =
|
|
{
|
|
{ PwrPolPowerDownFailed, WdfDevStatePwrPolSleepingWakePowerDownFailed DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceWakeTriggeredS0OtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT },
|
|
{ PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceWakeTriggeredS0NPOtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT },
|
|
{ PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceWakeCompletePowerUpOtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSleepingNoWakePowerDownOtherStates[] =
|
|
{
|
|
{ PwrPolPowerDown, WdfDevStatePwrPolSleepingPowerDownNotProcessed TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSleepingNoWakeCompletePowerDownOtherStates[] =
|
|
{
|
|
{ PwrPolPowerDownFailed, WdfDevStatePwrPolSystemSleepPowerRequestFailed DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSleepingSendWakeOtherStates[] =
|
|
{
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolSleepingNoWakeCompletePowerDown DEBUGGED_EVENT },
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolSleepingNoWakeCompletePowerDown DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSleepingWakeWakeArrivedNPOtherStates[] =
|
|
{
|
|
{ PwrPolPowerDownFailed, WdfDevStatePwrPolSleepingWakePowerDownFailed DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSleepingWakePowerDownFailedOtherStates[] =
|
|
{
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolSleepingWakePowerDownFailedWakeCanceled DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceWakeEnabledOtherStates[] =
|
|
{
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceled DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceWakeEnabledWakeCanceledOtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT },
|
|
{ PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceWakeEnabledNPOtherStates[] =
|
|
{
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceledNP DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceWakeEnabledWakeCanceledNPOtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT },
|
|
{ PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolDevicePowerRequestFailedOtherStates[] =
|
|
{
|
|
{ PwrPolSurpriseRemove, WdfDevStatePwrPolStopping DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStoppingOtherStates[] =
|
|
{
|
|
{ PwrPolPowerDownFailed, WdfDevStatePwrPolStoppingFailed DEBUGGED_EVENT },
|
|
{ PwrPolNull,WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStoppedOtherStates[] =
|
|
{
|
|
{ PwrPolRemove, WdfDevStatePwrPolStoppedRemoving DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolRestartingOtherStates[] =
|
|
{
|
|
{ PwrPolPowerUpFailed, WdfDevStatePwrPolRestartingFailed DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStoppingCancelWakeOtherStates[] =
|
|
{
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolStopping DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolCancelUsbSSOtherStates[] =
|
|
{
|
|
{ PwrPolStop, WdfDevStatePwrPolStoppingWaitForUsbSSCompletion TRAP_ON_EVENT },
|
|
{ PwrPolSurpriseRemove, WdfDevStatePwrPolStoppingWaitForUsbSSCompletion TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSleepingWakeRevertArmWakeOtherStates[] =
|
|
{
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolSleepingNoWakeCompletePowerDown DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSleepingWakeRevertArmWakeNPOtherStates[] =
|
|
{
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolSleepingNoWakeCompletePowerDown DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolRemovedOtherStates[] =
|
|
{
|
|
{ PwrPolRemove, WdfDevStatePwrPolRemoved DEBUGGED_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolWaitingArmedWakeInterruptFiredOtherStates[] =
|
|
{
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolWaitingArmedWakeSucceededCancelUsbSS TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceWakeInterruptFiredOtherStates[] =
|
|
{
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolSystemWakeDeviceWakeTriggered TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceWakeInterruptFiredNPOtherStates[] =
|
|
{
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredNP TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapableWakeInterruptArrivedOtherStates[] =
|
|
{
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolTimerExpiredWakeCapableWakeSucceeded TRAP_ON_EVENT },
|
|
{ PwrPolPowerDownFailed, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeInterruptArrived TRAP_ON_EVENT },
|
|
{ PwrPolPowerDown, WdfDevStatePwrPolWaitingArmedWakeInterruptFiredDuringPowerDown },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapablePowerDownFailedWakeInterruptArrivedOtherStates[] =
|
|
{
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolWaitingArmedWakeInterruptFiredDuringPowerDownOtherStates[] =
|
|
{
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolWaitingArmedWakeSucceededCancelUsbSS TRAP_ON_EVENT },
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
};
|
|
|
|
const POWER_POLICY_STATE_TABLE FxPkgPnp::m_WdfPowerPolicyStates[] =
|
|
{
|
|
// transition function,
|
|
// { first target state },
|
|
// other target states
|
|
// queue open,
|
|
|
|
// WdfDevStatePwrPolObjectCreated
|
|
{ NULL,
|
|
{ PwrPolStart, WdfDevStatePwrPolStarting DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolObjectCreatedOtherStates,
|
|
{ TRUE,
|
|
PwrPolS0 | // Sx -> S0 transition on a PDO which was enumerated and
|
|
// in the disabled state
|
|
|
|
PwrPolSx | // Sx transition right after enumeration
|
|
PwrPolS0IdlePolicyChanged },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStarting
|
|
{ FxPkgPnp::PowerPolStarting,
|
|
{ PwrPolPowerUp, WdfDevStatePwrPolStartingPoweredUp DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolStartingOtherStates,
|
|
{ FALSE,
|
|
PwrPolPowerUpFailed // If the power state machine fails D0 entry upon
|
|
// initial start, we will get this event here. The
|
|
// pnp s.m. will not rely on the pwr pol s.m. to
|
|
// power down the stack in this case.
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolStartingSucceeded
|
|
{ FxPkgPnp::PowerPolStartingSucceeded,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStartingFailed
|
|
{ FxPkgPnp::PowerPolStartingFailed,
|
|
{ PwrPolRemove, WdfDevStatePwrPolRemoved DEBUGGED_EVENT },
|
|
NULL,
|
|
{ TRUE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStartingDecideS0Wake
|
|
{ FxPkgPnp::PowerPolStartingDecideS0Wake,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull }, // transition out based on wake from S0 enabled
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStartedIdleCapable
|
|
{ FxPkgPnp::PowerPolStartedIdleCapable,
|
|
{ PwrPolPowerTimeoutExpired, WdfDevStatePwrPolIdleCapableDeviceIdle DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolStartedIdleCapableOtherStates,
|
|
{ TRUE,
|
|
PwrPolS0 | // If the machine send a query Sx and it fails, it will send
|
|
// an S0 while in the running state (w/out ever sending a true set Sx irp)
|
|
PwrPolWakeArrived | // If the wake request is failed by the bus in between WakeArrived
|
|
// being posted in TimerExpiredWakeCapapble and being
|
|
// processed, this event will show up in this state if the idle
|
|
// setting changed at this exact moment as well
|
|
PwrPolPowerUp | // posted by power when we are powering up the first time
|
|
PwrPolIoPresent | // posted by the idle state machine. If we return
|
|
// to idle this can happen
|
|
PwrPolDevicePowerNotRequired | // The device-power-not-required event arrived just after an
|
|
// I/O request or or an S0-idle policy change caused us to
|
|
// become active again. The event is ignored in this case.
|
|
PwrPolDevicePowerRequired // The device-power-required event arrived, but we had already
|
|
// powered-up the device proactively because we detected that
|
|
// power was needed. The event is ignored in this case.
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredNoWake
|
|
{ FxPkgPnp::PowerPolTimerExpiredNoWake,
|
|
{ PwrPolPowerDownIoStopped, WdfDevStatePwrPolTimerExpiredNoWakeCompletePowerDown DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolTimerExpiredNoWakeOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredNoWakeCompletePowerDown
|
|
{ FxPkgPnp::PowerPolTimerExpiredNoWakeCompletePowerDown,
|
|
// NOTE: see the comments PowerPolWaitingArmedUsbSS() about why we query the
|
|
// idle state instead of going directly to WdfDevStatePwrPolWaitingUnarmed
|
|
{ PwrPolPowerDown, WdfDevStatePwrPolTimerExpiredNoWakePoweredDownDisableIdleTimer DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolTimerExpiredNoWakeCompletePowerDownOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolWaitingUnarmed
|
|
{ NULL,
|
|
{ PwrPolIoPresent, WdfDevStatePwrPolWaitingUnarmedQueryIdle DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolWaitingUnarmedOtherStates,
|
|
{ TRUE,
|
|
PwrPolS0 | // If the machine send a query Sx and it fails, it will send
|
|
// an S0 while in the running state (w/out ever sending a true set Sx irp)
|
|
PwrPolDevicePowerNotRequired // When moving from Sx -> S0, we do not power up the
|
|
// device if:
|
|
// (UsingSystemManagedIdleTimeout == TRUE) and
|
|
// (IdleEnabled == TRUE) and
|
|
// (WakeFromS0Capable == FALSE) and
|
|
// (PowerUpIdleDeviceOnSystemWake == FALSE).
|
|
// In this situation, we declare to the active/idle
|
|
// state machine that we are idle, but ignore the
|
|
// device-power-not-required event, because we are
|
|
// already in Dx.
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolWaitingUnarmedQueryIdle
|
|
{ FxPkgPnp::PowerPolWaitingUnarmedQueryIdle,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolS0NoWakePowerUp
|
|
{ FxPkgPnp::PowerPolS0NoWakePowerUp,
|
|
{ PwrPolPowerUpHwStarted, WdfDevStatePwrPolS0NoWakeCompletePowerUp DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolS0NoWakePowerUpOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolS0NoWakeCompletePowerUp
|
|
{ FxPkgPnp::PowerPolS0NoWakeCompletePowerUp,
|
|
{ PwrPolPowerUp, WdfDevStatePwrPolStartingDecideS0Wake DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolS0NoWakeCompletePowerUpOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemSleepFromDeviceWaitingUnarmed
|
|
{ FxPkgPnp::PowerPolSystemSleepFromDeviceWaitingUnarmed,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull }, // transition out based on wake from Sx enabled
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemSleepNeedWake
|
|
{ FxPkgPnp::PowerPolSystemSleepNeedWake,
|
|
{ PwrPolPowerUpHwStarted, WdfDevStatePwrPolSystemSleepNeedWakeCompletePowerUp DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSystemSleepNeedWakeOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemSleepNeedWakeCompletePowerUp
|
|
{ FxPkgPnp::PowerPolSystemSleepNeedWakeCompletePowerUp,
|
|
{ PwrPolPowerUp, WdfDevStatePwrPolSleeping DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSystemSleepNeedWakeCompletePowerUpOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemSleepPowerRequestFailed
|
|
{ FxPkgPnp::PowerPolSystemSleepPowerRequestFailed,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0, },
|
|
},
|
|
|
|
// WdfDevStatePwrPolCheckPowerPageable
|
|
{ FxPkgPnp::PowerPolCheckPowerPageable,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull }, // transition out based on which DO_POWER_Xxx flags set on DO
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSleepingWakeWakeArrived
|
|
{ FxPkgPnp::PowerPolSleepingWakeWakeArrived,
|
|
{ PwrPolPowerDown, WdfDevStatePwrPolSystemAsleepWakeArmed DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSleepingWakeWakeArrivedOtherStates,
|
|
{ FALSE,
|
|
PwrPolWakeFailed | // wake completed before we could cancel
|
|
// the request, so the event may end up here
|
|
PwrPolWakeSuccess| // -do-
|
|
PwrPolWakeInterruptFired // Wake interrupt fired when during power
|
|
// down as part of system sleep transition
|
|
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolSleepingWakeRevertArmWake
|
|
{ FxPkgPnp::PowerPolSleepingWakeRevertArmWake,
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolSleepingNoWakeCompletePowerDown DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSleepingWakeRevertArmWakeOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemAsleepWakeArmed
|
|
{ FxPkgPnp::PowerPolSystemAsleepWakeArmed,
|
|
{ PwrPolS0, WdfDevStatePwrPolSystemWakeDeviceWakeEnabled DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSystemAsleepWakeArmedOtherStates,
|
|
{ TRUE,
|
|
PwrPolWakeFailed | // Wake failed while in Sx
|
|
PwrPolIoPresent | // IO arrived when the machine was going to Sx
|
|
PwrPolPowerTimeoutExpired | // we don't cancel the power timer when we goto
|
|
// sleep from an idleable state
|
|
PwrPolDevicePowerNotRequired // Upon receiving Sx, we simulated a device-power-
|
|
// not-required, so the device-power-requirement
|
|
// state machine sent us this event in response.
|
|
// We can drop it because we already powered down.
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemWakeDeviceWakeEnabled
|
|
{ FxPkgPnp::PowerPolSystemWakeDeviceWakeEnabled,
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceled DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSystemWakeDeviceWakeEnabledOtherStates,
|
|
{ FALSE,
|
|
PwrPolWakeInterruptFired // wake interrupt fired as we were waking the
|
|
// device on receiving S0 due to other reasons.
|
|
// This event can fire until the wake interrupt
|
|
// machine is notified of the power up.
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceled
|
|
{ FxPkgPnp::PowerPolSystemWakeDeviceWakeEnabledWakeCanceled,
|
|
{ PwrPolPowerUpHwStarted, WdfDevStatePwrPolSystemWakeDeviceWakeDisarm DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSystemWakeDeviceWakeEnabledWakeCanceledOtherStates,
|
|
{ FALSE,
|
|
PwrPolWakeInterruptFired // wake interrupt fired as we were waking the
|
|
// device on receiving S0 due to other reasons.
|
|
// This event can fire until the wake interrupt
|
|
// machine is notified of the power up.
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemWakeDeviceWakeDisarm
|
|
{ FxPkgPnp::PowerPolSystemWakeDeviceWakeDisarm,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemWakeDeviceWakeTriggered
|
|
{ NULL,
|
|
{ PwrPolS0, WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredS0 DEBUGGED_EVENT },
|
|
NULL,
|
|
{ TRUE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredS0
|
|
{ FxPkgPnp::PowerPolSystemWakeDeviceWakeTriggeredS0,
|
|
{ PwrPolPowerUpHwStarted, WdfDevStatePwrPolSystemWakeDeviceWokeDisarm DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSystemWakeDeviceWakeTriggeredS0OtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemWakeDeviceWokeDisarm
|
|
{ FxPkgPnp::PowerPolSystemWakeDeviceWokeDisarm,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSleepingWakeWakeArrivedNP,
|
|
{ FxPkgPnp::PowerPolSleepingWakeWakeArrivedNP,
|
|
{ PwrPolPowerDown, WdfDevStatePwrPolSystemAsleepWakeArmedNP DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSleepingWakeWakeArrivedNPOtherStates,
|
|
{ FALSE,
|
|
PwrPolWakeFailed | // wake completed before we could cancel
|
|
// the request, so the event may end up here
|
|
PwrPolWakeSuccess| // -do-
|
|
PwrPolWakeInterruptFired // Wake interrupt fired when during power
|
|
// down as part of system sleep transition
|
|
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolSleepingWakeRevertArmWakeNP,
|
|
{ FxPkgPnp::PowerPolSleepingWakeRevertArmWakeNP,
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolSleepingNoWakeCompletePowerDown DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSleepingWakeRevertArmWakeNPOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSleepingWakePowerDownFailed
|
|
{ FxPkgPnp::PowerPolSleepingWakePowerDownFailed,
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolSleepingWakePowerDownFailedWakeCanceled TRAP_ON_EVENT },
|
|
FxPkgPnp::m_PowerPolSleepingWakePowerDownFailedOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSleepingWakePowerDownFailedWakeCanceled
|
|
{ FxPkgPnp::PowerPolSleepingWakePowerDownFailedWakeCanceled,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemAsleepWakeArmedNP
|
|
{ FxPkgPnp::PowerPolSystemAsleepWakeArmedNP,
|
|
{ PwrPolS0, WdfDevStatePwrPolSystemWakeDeviceWakeEnabledNP DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSystemAsleepWakeArmedNPOtherStates,
|
|
{ TRUE,
|
|
PwrPolWakeFailed | // Wake failed while in Sx
|
|
PwrPolIoPresent | // IO arrived when the machine was going to Sx
|
|
PwrPolPowerTimeoutExpired // we don't cancel the power timer when we goto
|
|
// sleep from an idleable state
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemWakeDeviceWakeEnabledNP
|
|
{ FxPkgPnp::PowerPolSystemWakeDeviceWakeEnabledNP,
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceledNP DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSystemWakeDeviceWakeEnabledNPOtherStates,
|
|
{ FALSE,
|
|
PwrPolWakeInterruptFired // wake interrupt fired as we were waking the
|
|
// device on receiving S0 due to other reasons.
|
|
// This event can fire until the wake interrupt
|
|
// machine is notified of the power up.
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceledNP
|
|
{ FxPkgPnp::PowerPolSystemWakeDeviceWakeEnabledWakeCanceledNP,
|
|
{ PwrPolPowerUpHwStarted, WdfDevStatePwrPolSystemWakeDeviceWakeDisarmNP DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSystemWakeDeviceWakeEnabledWakeCanceledNPOtherStates,
|
|
{ FALSE,
|
|
PwrPolWakeSuccess | // wake succeeded and completed before we could cancel
|
|
// the request, so the event ends up here
|
|
|
|
PwrPolWakeInterruptFired // wake interrupt fired as we were waking the
|
|
// device on receiving S0 due to other reasons.
|
|
// This event can fire until the wake interrupt
|
|
// machine is notified of the power up.
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemWakeDeviceWakeDisarmNP
|
|
{ FxPkgPnp::PowerPolSystemWakeDeviceWakeDisarmNP,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredNP
|
|
{ NULL,
|
|
{ PwrPolS0, WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredS0NP DEBUGGED_EVENT },
|
|
NULL,
|
|
{ TRUE,
|
|
PwrPolIoPresent // I/O arrived before S0 arrival
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredS0NP
|
|
{ FxPkgPnp::PowerPolSystemWakeDeviceWakeTriggeredS0NP,
|
|
{ PwrPolPowerUpHwStarted, WdfDevStatePwrPolSystemWakeDeviceWokeDisarmNP DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSystemWakeDeviceWakeTriggeredS0NPOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemWakeDeviceWokeDisarmNP
|
|
{ FxPkgPnp::PowerPolSystemWakeDeviceWokeDisarmNP,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemWakeDeviceWakeCompletePowerUp
|
|
{ FxPkgPnp::PowerPolSystemWakeDeviceWakeCompletePowerUp,
|
|
{ PwrPolPowerUp, WdfDevStatePwrPolStartingDecideS0Wake DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSystemWakeDeviceWakeCompletePowerUpOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSleeping
|
|
{ FxPkgPnp::PowerPolSleeping,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSleepingNoWakePowerDown
|
|
{ FxPkgPnp::PowerPolSleepingNoWakePowerDown,
|
|
{ PwrPolPowerDownIoStopped, WdfDevStatePwrPolSleepingNoWakeCompletePowerDown DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSleepingNoWakePowerDownOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSleepingNoWakeCompletePowerDown
|
|
{ FxPkgPnp::PowerPolSleepingNoWakeCompletePowerDown,
|
|
{ PwrPolPowerDown, WdfDevStatePwrPolSystemAsleepNoWake DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSleepingNoWakeCompletePowerDownOtherStates,
|
|
{ FALSE,
|
|
PwrPolWakeArrived // wake arrived event posted after the ww irp
|
|
// completed from SleepingSendWake state. Ignore this
|
|
// event since wake is already trigged.
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolSleepingNoWakeDxRequestFailed
|
|
{ FxPkgPnp::PowerPolSleepingNoWakeDxRequestFailed,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSleepingWakePowerDown
|
|
{ FxPkgPnp::PowerPolSleepingWakePowerDown,
|
|
{ PwrPolPowerDownIoStopped, WdfDevStatePwrPolSleepingSendWake DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSleepingWakePowerDownOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSleepingSendWake
|
|
{ FxPkgPnp::PowerPolSleepingSendWake,
|
|
{ PwrPolWakeArrived, WdfDevStatePwrPolCheckPowerPageable DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSleepingSendWakeOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemAsleepNoWake
|
|
{ FxPkgPnp::PowerPolSystemAsleepNoWake,
|
|
{ PwrPolS0, WdfDevStatePwrPolSystemWakeDeviceWakeDisabled DEBUGGED_EVENT },
|
|
NULL,
|
|
{ TRUE,
|
|
PwrPolS0IdlePolicyChanged | // Policy changed while the device is in Dx
|
|
// because of Sx, we will reevaluate the idle
|
|
// settings when we return to S0 anyways
|
|
PwrPolWakeArrived | // If arming for wake from sx failed, the WakeArrived
|
|
// event that was a part of that arming is dequeued here
|
|
PwrPolIoPresent | // I/O showed up when going into Sx
|
|
PwrPolPowerTimeoutExpired |
|
|
PwrPolDevicePowerNotRequired // Upon receiving Sx, we simulated a device-power-
|
|
// not-required, so the device-power-requirement
|
|
// state machine sent us this event in response.
|
|
// We can drop it because we already powered down.
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemWakeDeviceWakeDisabled
|
|
{ FxPkgPnp::PowerPolSystemWakeDeviceWakeDisabled,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull }, // transition out based on wake from S0 enabled
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemWakeDeviceToD0
|
|
{ FxPkgPnp::PowerPolSystemWakeDeviceToD0,
|
|
{ PwrPolPowerUpHwStarted, WdfDevStatePwrPolSystemWakeDeviceToD0CompletePowerUp DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSystemWakeDeviceToD0OtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemWakeDeviceToD0CompletePowerUp
|
|
{ FxPkgPnp::PowerPolSystemWakeDeviceToD0CompletePowerUp,
|
|
{ PwrPolPowerUp, WdfDevStatePwrPolStartingDecideS0Wake DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolSystemWakeDeviceToD0CompletePowerUpOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemWakeQueryIdle
|
|
{ FxPkgPnp::PowerPolSystemWakeQueryIdle,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull}, // transition out based on timer expiration state
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStartedWakeCapable
|
|
{ FxPkgPnp::PowerPolStartedWakeCapable,
|
|
{ PwrPolPowerTimeoutExpired, WdfDevStatePwrPolWakeCapableDeviceIdle DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolStartedWakeCapableOtherStates,
|
|
{ TRUE,
|
|
PwrPolS0 | // If the machine send a query Sx and it fails, it will send
|
|
// an S0 while in the running state (w/out ever sending a true set Sx irp)
|
|
PwrPolPowerUp |
|
|
PwrPolWakeArrived | // If the wake request is failed by the bus in between WakeArrived
|
|
// being posted in TimerExpiredWakeCapapble and being
|
|
// processed, this event will show up in this state
|
|
|
|
PwrPolWakeSuccess | // wake succeeded while we were trying to cancel it
|
|
// while coming out of WaitingArmed b/c of io present
|
|
|
|
PwrPolWakeFailed | // wake request failed while we were trying to cancel it
|
|
// while coming out of WaitingArmed b/c of io present
|
|
|
|
PwrPolUsbSelectiveSuspendCallback |
|
|
PwrPolUsbSelectiveSuspendCompleted | // When returning from a success resume
|
|
// from USB SS, the completion of the irp will
|
|
// occur in the started state
|
|
|
|
PwrPolIoPresent | // posted by the idle state machine. If we return
|
|
// to idle this can happen
|
|
PwrPolDevicePowerNotRequired | // The device-power-not-required event arrived just after an
|
|
// I/O request or or an S0-idle policy change caused us to
|
|
// become active again. The event is ignored in this case.
|
|
PwrPolDevicePowerRequired // The device-power-required event arrived, but we had already
|
|
// powered-up the device proactively because we detected that
|
|
// power was needed. The event is ignored in this case.
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredDecideUsbSS
|
|
{ FxPkgPnp::PowerPolTimerExpiredDecideUsbSS,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCapablePowerDown
|
|
{ FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDown,
|
|
{ PwrPolPowerDownIoStopped, WdfDevStatePwrPolTimerExpiredWakeCapableSendWake DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolTimerExpiredWakeCapablePowerDownOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCapableSendWake
|
|
{ FxPkgPnp::PowerPolTimerExpiredWakeCapableSendWake,
|
|
{ PwrPolWakeArrived, WdfDevStatePwrPolTimerExpiredWakeCapableWakeArrived DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolTimerExpiredWakeCapableSendWakeOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCapableUsbSS
|
|
{ FxPkgPnp::PowerPolTimerExpiredWakeCapableUsbSS,
|
|
{ PwrPolUsbSelectiveSuspendCallback, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDown DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolTimerExpiredWakeCapableUsbSSOtherStates,
|
|
{ TRUE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCapableWakeArrived
|
|
{ FxPkgPnp::PowerPolTimerExpiredWakeCapableWakeArrived,
|
|
{ PwrPolPowerDown, WdfDevStatePwrPolWaitingArmedUsbSS DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolTimerExpiredWakeCapableWakeArrivedOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCapableCancelWake
|
|
{ FxPkgPnp::PowerPolTimerExpiredWakeCapableCancelWake,
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolTimerExpiredWakeCapableWakeCanceled TRAP_ON_EVENT },
|
|
FxPkgPnp::m_PowerPolTimerExpiredWakeCapableCancelWakeOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCapableWakeCanceled
|
|
{ FxPkgPnp::PowerPolTimerExpiredWakeCapableWakeCanceled,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCapableCleanup
|
|
{ FxPkgPnp::PowerPolTimerExpiredWakeCapableCleanup,
|
|
{ PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolTimerExpiredWakeCompletedPowerDown TRAP_ON_EVENT },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCapableDxAllocFailed
|
|
{ FxPkgPnp::PowerPolTimerExpiredWakeCapableDxAllocFailed,
|
|
{ PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolTimerExpiredWakeCapableUndoPowerDown TRAP_ON_EVENT },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCompletedPowerDown
|
|
{ FxPkgPnp::PowerPolTimerExpiredWakeCompletedPowerDown,
|
|
{ PwrPolPowerDown, WdfDevStatePwrPolTimerExpiredWakeCompletedPowerUp DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolTimerExpiredWakeCompletedPowerDownOtherStates,
|
|
{ FALSE,
|
|
PwrPolWakeSuccess | // arming callback failed while going into Dx armed for wake from S0
|
|
// but bus completed wake request with success
|
|
|
|
PwrPolWakeArrived // if the wake request completes before PwrPolWakeArrived
|
|
// can be processed in the PwrPolTimerExpiredWakeCapableSendWake
|
|
// state, it will show up here
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCompletedPowerUp
|
|
{ FxPkgPnp::PowerPolTimerExpiredWakeCompletedPowerUp,
|
|
{ PwrPolPowerUpHwStarted, WdfDevStatePwrPolTimerExpiredWakeCompletedHardwareStarted DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolTimerExpiredWakeCompletedPowerUpOtherStates,
|
|
{ FALSE,
|
|
PwrPolWakeSuccess | // arming callback failed while going into Dx armed for wake from S0
|
|
// but bus completed wake request with success
|
|
|
|
PwrPolWakeArrived // if the wake request completes before PwrPolWakeArrived
|
|
// can be processed in the WdfDevStatePwrPolTimerExpiredWakeCapableSendWake
|
|
// state, it will show up here
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolWaitingArmedUsbSS
|
|
{ FxPkgPnp::PowerPolWaitingArmedUsbSS,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolWaitingArmed
|
|
{ NULL,
|
|
{ PwrPolIoPresent, WdfDevStatePwrPolWaitingArmedQueryIdle DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolWaitingArmedOtherStates,
|
|
{ TRUE,
|
|
PwrPolS0 // If the machine send a query Sx and it fails, it will send
|
|
// an S0 while in the running state (w/out ever sending a true set Sx irp)
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolWaitingArmedQueryIdle
|
|
{ FxPkgPnp::PowerPolWaitingArmedQueryIdle,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolIoPresentArmed
|
|
{ FxPkgPnp::PowerPolIoPresentArmed,
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolIoPresentArmedWakeCanceled DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolIoPresentArmedOtherStates,
|
|
{ FALSE,
|
|
PwrPolWakeInterruptFired // wake interrupt fired as we were waking the
|
|
// device on receiving IO.This event can fire
|
|
// until the wake interrupt machine is notified
|
|
// of the power up.
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolIoPresentArmedWakeCanceled
|
|
{ FxPkgPnp::PowerPolIoPresentArmedWakeCanceled,
|
|
{ PwrPolPowerUpHwStarted, WdfDevStatePwrPolS0WakeDisarm DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolIoPresentArmedWakeCanceledOtherStates,
|
|
{ FALSE,
|
|
PwrPolWakeSuccess | // The wake status was already processed before entering
|
|
// this state - indicates that the client driver is
|
|
// probably propagating a duplicate wake status using
|
|
// the WdfDeviceIndicateWakeStatus ddi.
|
|
|
|
PwrPolWakeFailed | // The wake status was already processed before entering
|
|
// this state - indicates that the client driver is
|
|
// probably propagating a duplicate wake status using
|
|
// the WdfDeviceIndicateWakeStatus ddi.
|
|
|
|
PwrPolWakeInterruptFired // wake interrupt fired as we were waking the
|
|
// device on receiving IO.This event can fire
|
|
// until the wake interrupt machine is notified
|
|
// of the power up.
|
|
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolS0WakeDisarm,
|
|
{ FxPkgPnp::PowerPolS0WakeDisarm,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolS0WakeCompletePowerUp
|
|
{ FxPkgPnp::PowerPolS0WakeCompletePowerUp,
|
|
{ PwrPolPowerUp, WdfDevStatePwrPolStartingDecideS0Wake DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolS0WakeCompletePowerUpOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeSucceeded
|
|
{ FxPkgPnp::PowerPolTimerExpiredWakeSucceeded,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCompletedDisarm
|
|
{ FxPkgPnp::PowerPolTimerExpiredWakeCompletedDisarm,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCapableWakeSucceeded
|
|
{ NULL,
|
|
{ PwrPolPowerDown, WdfDevStatePwrPolWokeFromS0UsbSS DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolTimerExpiredWakeCapableWakeSucceededOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCapableWakeFailed
|
|
{ NULL,
|
|
{ PwrPolPowerDown, WdfDevStatePwrPolWakeFailedUsbSS DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolTimerExpiredWakeCapableWakeFailedOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolWakeFailedUsbSS
|
|
{ FxPkgPnp::PowerPolWakeFailedUsbSS,
|
|
{ PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolIoPresentArmedWakeCanceled TRAP_ON_EVENT },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedCancelWake
|
|
{ FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDownFailedCancelWake,
|
|
{ PwrPolWakeSuccess, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolTimerExpiredWakeCapablePowerDownFailedCancelWakeOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled
|
|
{ FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedUsbSS
|
|
{ FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDownFailedUsbSS,
|
|
{ PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolDevicePowerRequestFailed TRAP_ON_EVENT },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolCancelingWakeForSystemSleep
|
|
{ FxPkgPnp::PowerPolCancelingWakeForSystemSleep,
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolCancelingWakeForSystemSleepWakeCanceled DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolCancelingWakeForSystemSleepOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolCancelingWakeForSystemSleepWakeCanceled
|
|
{ FxPkgPnp::PowerPolCancelingWakeForSystemSleepWakeCanceled,
|
|
{ PwrPolPowerUpHwStarted, WdfDevStatePwrPolDisarmingWakeForSystemSleepCompletePowerUp DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolCancelingWakeForSystemSleepWakeCanceledOtherStates,
|
|
{ FALSE,
|
|
PwrPolWakeSuccess // Wake completed successfully right as the transition
|
|
// from WaitingArmed to goto Sx occurred
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolDisarmingWakeForSystemSleepCompletePowerUp
|
|
{ FxPkgPnp::PowerPolDisarmingWakeForSystemSleepCompletePowerUp,
|
|
{ PwrPolPowerUp, WdfDevStatePwrPolStartedWakeCapableCancelTimerForSleep DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolDisarmingWakeForSystemSleepCompletePowerUpOtherStates,
|
|
{ FALSE,
|
|
0, },
|
|
},
|
|
|
|
// WdfDevStatePwrPolPowerUpForSystemSleepFailed
|
|
{ FxPkgPnp::PowerPolPowerUpForSystemSleepFailed,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolWokeFromS0UsbSS
|
|
{ FxPkgPnp::PowerPolWokeFromS0UsbSS,
|
|
{ PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolWokeFromS0 DEBUGGED_EVENT },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolWokeFromS0
|
|
{ FxPkgPnp::PowerPolWokeFromS0,
|
|
{ PwrPolPowerUpHwStarted, WdfDevStatePwrPolWokeFromS0NotifyDriver DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolWokeFromS0OtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolWokeFromS0NotifyDriver
|
|
{ FxPkgPnp::PowerPolWokeFromS0NotifyDriver,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppingResetDevice
|
|
{ FxPkgPnp::PowerPolStoppingResetDevice,
|
|
{ PwrPolPowerUpHwStarted, WdfDevStatePwrPolStoppingResetDeviceCompletePowerUp DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolStoppingResetDeviceOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppingResetDeviceCompletePowerUp
|
|
{ FxPkgPnp::PowerPolStoppingResetDeviceCompletePowerUp,
|
|
{ PwrPolPowerUp, WdfDevStatePwrPolStopping DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolStoppingResetDeviceCompletePowerUpOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppingResetDeviceFailed
|
|
{ FxPkgPnp::PowerPolStoppingResetDeviceFailed,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppingD0
|
|
{ FxPkgPnp::PowerPolStoppingD0,
|
|
{ PwrPolPowerUpHwStarted, WdfDevStatePwrPolStoppingDisarmWake DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolStoppingD0OtherStates,
|
|
{ FALSE,
|
|
PwrPolWakeSuccess | // In the waiting armed state, the wake completed
|
|
// right after PwrPolStop arrived
|
|
PwrPolWakeFailed // wake completed before we could cancel
|
|
// the request, so the event may end up here
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppingD0Failed
|
|
{ FxPkgPnp::PowerPolStoppingD0Failed,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppingDisarmWake
|
|
{ FxPkgPnp::PowerPolStoppingDisarmWake,
|
|
{ PwrPolPowerUp, WdfDevStatePwrPolStoppingDisarmWakeCancelWake DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolStoppingDisarmWakeOtherStates,
|
|
{ FALSE,
|
|
PwrPolWakeFailed | // wake completed before we could cancel
|
|
// the request, so the event may end up here
|
|
PwrPolWakeSuccess // -do-
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppingDisarmWakeCancelWake
|
|
{ FxPkgPnp::PowerPolStoppingDisarmWakeCancelWake,
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolStoppingDisarmWakeWakeCanceled DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolStoppingDisarmWakeCancelWakeOtherStates,
|
|
{ FALSE,
|
|
PwrPolUsbSelectiveSuspendCompleted // pwr pol stopped from a usb SS device
|
|
// in Dx and the irp completed when the D0
|
|
// irp was sent
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppingDisarmWakeWakeCanceled
|
|
{ FxPkgPnp::PowerPolStoppingDisarmWakeWakeCanceled,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull}, // transition to Stopping occurs in function
|
|
NULL,
|
|
{ FALSE,
|
|
PwrPolUsbSelectiveSuspendCompleted // pwr pol stopped from a usb SS device
|
|
// in Dx and the irp completed when the D0
|
|
// irp was sent
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolStopping
|
|
{ FxPkgPnp::PowerPolStopping,
|
|
{ PwrPolPowerDown, WdfDevStatePwrPolStoppingSendStatus DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolStoppingOtherStates,
|
|
{ FALSE,
|
|
PwrPolUsbSelectiveSuspendCompleted // pwr pol stopped from a usb SS device
|
|
// in Dx and the irp completed when the D0
|
|
// irp was sent
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppingFailed
|
|
{ FxPkgPnp::PowerPolStoppingFailed,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppingSendStatus
|
|
{ FxPkgPnp::PowerPolStoppingSendStatus,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppingCancelTimer
|
|
{ FxPkgPnp::PowerPolStoppingCancelTimer,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppingWaitForIdleTimeout
|
|
{ NULL,
|
|
{ PwrPolPowerTimeoutExpired, WdfDevStatePwrPolStopping DEBUGGED_EVENT },
|
|
NULL,
|
|
{ TRUE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppingCancelUsbSS
|
|
{ FxPkgPnp::PowerPolStoppingCancelUsbSS,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppingWaitForUsbSSCompletion
|
|
{ NULL,
|
|
{ PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolStoppingCancelTimer DEBUGGED_EVENT },
|
|
NULL,
|
|
{ TRUE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppingCancelWake
|
|
{ FxPkgPnp::PowerPolStoppingCancelWake,
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolStopping DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolStoppingCancelWakeOtherStates,
|
|
{ TRUE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStopped
|
|
{ NULL,
|
|
{ PwrPolStart, WdfDevStatePwrPolRestarting DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolStoppedOtherStates,
|
|
{ TRUE,
|
|
PwrPolPowerTimeoutExpired | // idle timer fired right before stopping
|
|
// pwr policy and before pwr pol could process
|
|
// the timeout
|
|
PwrPolIoPresent | // I/O arrived while transitioning to the
|
|
// stopped state
|
|
PwrPolDevicePowerRequired // Due to a power-related failure, we declared our device state
|
|
// as failed and stopped the power policy state machine. But
|
|
// before stopping the power policy machine, we would have
|
|
// declared ourselves as powered-on (maybe fake) in order to
|
|
// move the power framework to a consistent state. Since we've
|
|
// already declared ourselves as powered-on, we can drop this.
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolCancelUsbSS
|
|
{ FxPkgPnp::PowerPolCancelUsbSS,
|
|
{ PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolStartedCancelTimer DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolCancelUsbSSOtherStates,
|
|
{ TRUE,
|
|
PwrPolIoPresent // I/O arrived while we were waiting for the USB idle notification IOCTL
|
|
// to be completed after we had canceled it. It is okay to drop this
|
|
// event because we are already in the process to returning to the powered-
|
|
// up state.
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolStarted
|
|
{ FxPkgPnp::PowerPolStarted,
|
|
{ PwrPolSx, WdfDevStatePwrPolSleeping DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolStartedOtherStates,
|
|
{ TRUE,
|
|
PwrPolS0 | // If the machine send a query Sx and it fails, it will send
|
|
// an S0 while in the running state (w/out ever sending a true set Sx irp)
|
|
PwrPolWakeArrived | // If the wake request is failed by the bus in between WakeArrived
|
|
// being posted in TimerExpiredWakeCapapble and being
|
|
// processed, this event will show up in this state if the idle
|
|
// setting changed at this exact moment as well
|
|
PwrPolWakeSuccess | // returning from Dx armed for wake from Sx, wake
|
|
// is completed w/success after S0 irp arrives
|
|
PwrPolPowerUp |
|
|
PwrPolUsbSelectiveSuspendCompleted | // sent when we move out of the armed
|
|
// & idle enabled state into the
|
|
// idle disabled state
|
|
PwrPolIoPresent |// This just indicates that I/O arrived, which is fine here
|
|
PwrPolPowerTimeoutExpired | // this can happen when idle timer is disabled
|
|
// due to policy change while powering up.
|
|
PwrPolDevicePowerRequired // idle policy changed when device was powered down
|
|
// due to S0-idle. The policy change caused us to power
|
|
// up. As part of powering up, the device-power-required
|
|
// event arrived. Can drop because we already powered-up.
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolStartedCancelTimer
|
|
{ FxPkgPnp::PowerPolStartedCancelTimer,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStartedWaitForIdleTimeout
|
|
{ NULL,
|
|
{ PwrPolPowerTimeoutExpired, WdfDevStatePwrPolStartingDecideS0Wake TRAP_ON_EVENT },
|
|
FxPkgPnp::m_PowerPolStartedWaitForIdleTimeoutOtherStates,
|
|
{ TRUE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStartedWakeCapableCancelTimerForSleep
|
|
{ FxPkgPnp::PowerPolStartedWakeCapableCancelTimerForSleep,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStartedWakeCapableWaitForIdleTimeout
|
|
{ NULL,
|
|
{ PwrPolPowerTimeoutExpired, WdfDevStatePwrPolSleeping TRAP_ON_EVENT },
|
|
NULL,
|
|
{ TRUE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStartedWakeCapableSleepingUsbSS
|
|
{ FxPkgPnp::PowerPolStartedWakeCapableSleepingUsbSS,
|
|
{ PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolSleeping DEBUGGED_EVENT },
|
|
NULL,
|
|
{ TRUE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStartedIdleCapableCancelTimerForSleep
|
|
{ FxPkgPnp::PowerPolStartedIdleCapableCancelTimerForSleep,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStartedIdleCapableWaitForIdleTimeout
|
|
{ NULL,
|
|
{ PwrPolPowerTimeoutExpired, WdfDevStatePwrPolSleeping TRAP_ON_EVENT },
|
|
NULL,
|
|
{ TRUE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolDeviceD0PowerRequestFailed
|
|
{ FxPkgPnp::PowerPolDeviceD0PowerRequestFailed,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull},
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolDevicePowerRequestFailed
|
|
{ FxPkgPnp::PowerPolDevicePowerRequestFailed,
|
|
{ PwrPolStop, WdfDevStatePwrPolStoppingCancelTimer DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolDevicePowerRequestFailedOtherStates,
|
|
{ TRUE,
|
|
PwrPolUsbSelectiveSuspendCompleted | // Device was suspened and surprise
|
|
// removed while in Dx
|
|
PwrPolS0 | // If the device failed D0Exit while the machine was going into
|
|
// Sx, then we will get this event when the machine comes back up
|
|
|
|
PwrPolWakeArrived | // wake was completed before PwrPolWakeArrived was
|
|
// sent. On immediate power down or up, the power
|
|
// operation failed
|
|
|
|
PwrPolWakeFailed | // If the device failed exit d0 after being armed, the
|
|
// this event will be processed in the failed state
|
|
PwrPolDevicePowerRequired | // We can drop because we already declared ourselves
|
|
// as being powered on (fake power-on in order to
|
|
// move the power framework to consistent state).
|
|
PwrPolIoPresent // We're being notified that we need to be powered-on because
|
|
// there is I/O to process, but the device is already in failed
|
|
// state and is about to be removed.
|
|
},
|
|
},
|
|
|
|
// State exists only for the non power policy owner state machine
|
|
// WdfDevStatePwrPolGotoDx
|
|
{ NULL,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ TRUE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolGotoDxInDx
|
|
{ NULL,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ TRUE,
|
|
0 },
|
|
},
|
|
|
|
// State exists only for the non power policy owner state machine
|
|
// WdfDevStatePwrPolDx
|
|
{ NULL,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ TRUE,
|
|
0 },
|
|
},
|
|
|
|
// State exists only for the non power policy owner state machine
|
|
// WdfDevStatePwrPolGotoD0
|
|
{ NULL,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ TRUE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolGotoD0InD0
|
|
{ NULL,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ TRUE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolFinal
|
|
{ NULL,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ TRUE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSleepingPowerDownNotProcessed
|
|
{ FxPkgPnp::PowerPolSleepingPowerDownNotProcessed,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownNotProcessed
|
|
{ FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDownNotProcessed,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredNoWakePowerDownNotProcessed
|
|
{ FxPkgPnp::PowerPolTimerExpiredNoWakePowerDownNotProcessed,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredNoWakePoweredDownDisableIdleTimer
|
|
{ FxPkgPnp::PowerPolTimerExpiredNoWakePoweredDownDisableIdleTimer,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppingWaitingForImplicitPowerDown
|
|
{ NULL,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppingPoweringUp
|
|
{ NULL,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppingPoweringDown
|
|
{ NULL,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolPowerUpForSystemSleepNotSeen
|
|
{ FxPkgPnp::PowerPolPowerUpForSystemSleepNotSeen,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolWaitingArmedStoppingCancelUsbSS
|
|
{ FxPkgPnp::PowerPolWaitingArmedStoppingCancelUsbSS,
|
|
{ PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolStoppingCancelWake DEBUGGED_EVENT },
|
|
NULL,
|
|
{ FALSE,
|
|
PwrPolWakeFailed | // wake completed before we could cancel
|
|
// the request, so the event may end up here
|
|
PwrPolWakeSuccess // -do-
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolWaitingArmedWakeFailedCancelUsbSS
|
|
{ FxPkgPnp::PowerPolWaitingArmedWakeFailedCancelUsbSS,
|
|
{ PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolIoPresentArmedWakeCanceled TRAP_ON_EVENT },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolWaitingArmedIoPresentCancelUsbSS
|
|
{ FxPkgPnp::PowerPolWaitingArmedIoPresentCancelUsbSS,
|
|
{ PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolIoPresentArmed DEBUGGED_EVENT },
|
|
NULL,
|
|
{ FALSE,
|
|
PwrPolWakeFailed | // wake completed before we could cancel
|
|
// the request, so the event may end up here
|
|
PwrPolWakeSuccess | // -do-
|
|
PwrPolWakeInterruptFired // wake interrupt fired as we were waking the
|
|
// device on receiving IO.This event can fire
|
|
// until the wake interrupt machine is notified
|
|
// of the power up.
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolWaitingArmedWakeSucceededCancelUsbSS
|
|
{ FxPkgPnp::PowerPolWaitingArmedWakeSucceededCancelUsbSS,
|
|
{ PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolWokeFromS0 DEBUGGED_EVENT },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolCancelingUsbSSForSystemSleep
|
|
{ FxPkgPnp::PowerPolCancelingUsbSSForSystemSleep,
|
|
{ PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolCancelingWakeForSystemSleep DEBUGGED_EVENT },
|
|
NULL,
|
|
{ FALSE,
|
|
PwrPolWakeFailed | // wake completed before we could cancel
|
|
// the request, so the event may end up here
|
|
PwrPolWakeSuccess // -do-
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppingD0CancelUsbSS
|
|
{ FxPkgPnp::PowerPolStoppingD0CancelUsbSS,
|
|
{ PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolStoppingD0 TRAP_ON_EVENT },
|
|
NULL,
|
|
{ FALSE,
|
|
PwrPolWakeFailed | // wake completed before we could cancel
|
|
// the request, so the event may end up here
|
|
PwrPolWakeSuccess // -do-
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolStartingPoweredUp
|
|
{ FxPkgPnp::PowerPolStartingPoweredUp,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolIdleCapableDeviceIdle
|
|
{ FxPkgPnp::PowerPolIdleCapableDeviceIdle,
|
|
{ PwrPolDevicePowerNotRequired, WdfDevStatePwrPolTimerExpiredNoWake DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolIdleCapableDeviceIdleOtherStates,
|
|
{ TRUE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolDeviceIdleReturnToActive
|
|
{ FxPkgPnp::PowerPolDeviceIdleReturnToActive,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolDeviceIdleSleeping
|
|
{ FxPkgPnp::PowerPolDeviceIdleSleeping,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolDeviceIdleStopping
|
|
{ FxPkgPnp::PowerPolDeviceIdleStopping,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredNoWakeUndoPowerDown
|
|
{ FxPkgPnp::PowerPolTimerExpiredNoWakeUndoPowerDown,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolWakeCapableDeviceIdle
|
|
{ FxPkgPnp::PowerPolWakeCapableDeviceIdle,
|
|
{ PwrPolDevicePowerNotRequired, WdfDevStatePwrPolTimerExpiredDecideUsbSS DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolWakeCapableDeviceIdleOtherStates,
|
|
{ TRUE,
|
|
PwrPolDevicePowerRequired // The device-power-required event arrived, but we had already
|
|
// powered-up the device proactively because we detected that
|
|
// power was needed. And after we powered up, we become idle
|
|
// again and arrived in our current state before the device-
|
|
// power-required event was received. The event is ignored in
|
|
// this case.
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolWakeCapableUsbSSCompleted
|
|
{ FxPkgPnp::PowerPolWakeCapableUsbSSCompleted,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCapableUndoPowerDown
|
|
{ FxPkgPnp::PowerPolTimerExpiredWakeCapableUndoPowerDown,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCompletedHardwareStarted
|
|
{ FxPkgPnp::PowerPolTimerExpiredWakeCompletedHardwareStarted,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStoppedRemoving
|
|
{ FxPkgPnp::PowerPolStoppedRemoving,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolRemoved
|
|
{ FxPkgPnp::PowerPolRemoved,
|
|
{ PwrPolStart, WdfDevStatePwrPolStarting DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolRemovedOtherStates,
|
|
{ TRUE,
|
|
PwrPolSx | // device is disabled (must be a PDO) and then the machine
|
|
// moves into an Sx state
|
|
PwrPolS0 | // driver failed power up when moving out of S0 Dx idle
|
|
// state and system resumed after failure
|
|
PwrPolS0IdlePolicyChanged // driver changes S0 idle settings while being
|
|
// removed
|
|
},
|
|
},
|
|
|
|
// WdfDevStatePwrPolRestarting
|
|
{ FxPkgPnp::PowerPolRestarting,
|
|
{ PwrPolPowerUp, WdfDevStatePwrPolStartingSucceeded DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolRestartingOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolRestartingFailed
|
|
{ FxPkgPnp::PowerPolRestartingFailed,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolStartingPoweredUpFailed
|
|
{ FxPkgPnp::PowerPolStartingPoweredUpFailed,
|
|
{ PwrPolPowerDown, WdfDevStatePwrPolStartingFailed DEBUGGED_EVENT },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredNoWakeReturnToActive
|
|
{ FxPkgPnp::PowerPolTimerExpiredNoWakeReturnToActive,
|
|
{ PwrPolNull, WdfDevStatePwrPolNull },
|
|
NULL,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolWaitingArmedWakeInterruptFired
|
|
{ FxPkgPnp::PowerPolWaitingArmedWakeInterruptFired,
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolWaitingArmedWakeSucceededCancelUsbSS DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolWaitingArmedWakeInterruptFiredOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemWakeDeviceWakeInterruptFired
|
|
{ FxPkgPnp::PowerPolSystemWakeDeviceWakeInterruptFired,
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolSystemWakeDeviceWakeTriggered TRAP_ON_EVENT },
|
|
FxPkgPnp::m_PowerPolSystemWakeDeviceWakeInterruptFiredOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolSystemWakeDeviceWakeInterruptFiredNP
|
|
{ FxPkgPnp::PowerPolSystemWakeDeviceWakeInterruptFiredNP,
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredNP TRAP_ON_EVENT },
|
|
FxPkgPnp::m_PowerPolSystemWakeDeviceWakeInterruptFiredNPOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCapableWakeInterruptArrived
|
|
{ FxPkgPnp::PowerPolTimerExpiredWakeCapableWakeInterruptArrived,
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolTimerExpiredWakeCapableWakeSucceeded DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolTimerExpiredWakeCapableWakeInterruptArrivedOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeInterruptArrived
|
|
{ NULL,
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolTimerExpiredWakeCapablePowerDownFailedWakeInterruptArrivedOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolWaitingArmedWakeInterruptFiredDuringPowerDown
|
|
{ NULL,
|
|
{ PwrPolWakeFailed, WdfDevStatePwrPolWaitingArmedWakeSucceededCancelUsbSS DEBUGGED_EVENT },
|
|
FxPkgPnp::m_PowerPolWaitingArmedWakeInterruptFiredDuringPowerDownOtherStates,
|
|
{ FALSE,
|
|
0 },
|
|
},
|
|
|
|
// WdfDevStatePwrPolNull
|
|
// *** no entry for this state ***
|
|
};
|
|
|
|
// @@SMVERIFY_SPLIT_END
|
|
|
|
VOID
|
|
FxPkgPnp::PowerPolicyCheckAssumptions(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine is never actually called by running code, it just has
|
|
WDFCASSERTs who upon failure, would not allow this file to be compiled.
|
|
|
|
DO NOT REMOVE THIS FUNCTION just because it is not callec by any running
|
|
code.
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
WDFCASSERT(sizeof(FxPwrPolStateInfo) == sizeof(ULONG));
|
|
|
|
WDFCASSERT((sizeof(m_WdfPowerPolicyStates)/sizeof(m_WdfPowerPolicyStates[0]))
|
|
==
|
|
(WdfDevStatePwrPolNull - WdfDevStatePwrPolObjectCreated));
|
|
|
|
// we assume these are the same length when we update the history index
|
|
WDFCASSERT((sizeof(m_PowerPolicyMachine.m_Queue)/
|
|
sizeof(m_PowerPolicyMachine.m_Queue[0]))
|
|
==
|
|
(sizeof(m_PowerPolicyMachine.m_States.History)/
|
|
sizeof(m_PowerPolicyMachine.m_States.History[0])));
|
|
}
|
|
|
|
CfxDevice *
|
|
IdleTimeoutManagement::GetDevice(
|
|
VOID
|
|
)
|
|
{
|
|
IdlePolicySettings * idlePolicySettings = NULL;
|
|
FxPowerPolicyOwnerSettings * ppoSettings = NULL;
|
|
FxPkgPnp * pPkgPnp = NULL;
|
|
|
|
idlePolicySettings = (IdlePolicySettings *) CONTAINING_RECORD(
|
|
this,
|
|
IdlePolicySettings,
|
|
m_TimeoutMgmt
|
|
);
|
|
ppoSettings = (FxPowerPolicyOwnerSettings *) CONTAINING_RECORD(
|
|
idlePolicySettings,
|
|
FxPowerPolicyOwnerSettings,
|
|
m_IdleSettings
|
|
);
|
|
pPkgPnp = ppoSettings->m_PkgPnp;
|
|
|
|
return pPkgPnp->GetDevice();
|
|
}
|
|
|
|
IdleTimeoutManagement::IdleTimeoutStatusUpdateResult
|
|
IdleTimeoutManagement::UpdateIdleTimeoutStatus(
|
|
__in IdleTimeoutManagement::IdleTimeoutStatusFlag Flag
|
|
)
|
|
{
|
|
LONG idleTimeoutStatusSnapshot;
|
|
LONG updatedIdleTimeoutStatus;
|
|
LONG preInterlockedIdleTimeoutStatus;
|
|
|
|
//
|
|
// Take a snapshot of the idle timeout management status
|
|
//
|
|
idleTimeoutStatusSnapshot = m_IdleTimeoutStatus;
|
|
|
|
//
|
|
// Verify that the flag we're trying to set is not already set
|
|
//
|
|
if (0 != (idleTimeoutStatusSnapshot & Flag)) {
|
|
return IdleTimeoutStatusFlagAlreadySet;
|
|
}
|
|
|
|
//
|
|
// Verify that the idle timeout management status is not already
|
|
// "frozen"
|
|
//
|
|
if (0 != (idleTimeoutStatusSnapshot & IdleTimeoutStatusFrozen)) {
|
|
//
|
|
// It was too late to set the flag. The flag value was already
|
|
// "frozen".
|
|
//
|
|
return IdleTimeoutStatusFlagsAlreadyFrozen;
|
|
}
|
|
|
|
//
|
|
// Try to set the flag
|
|
//
|
|
updatedIdleTimeoutStatus = idleTimeoutStatusSnapshot | Flag;
|
|
|
|
preInterlockedIdleTimeoutStatus = InterlockedCompareExchange(
|
|
&m_IdleTimeoutStatus,
|
|
updatedIdleTimeoutStatus,
|
|
idleTimeoutStatusSnapshot
|
|
);
|
|
if (preInterlockedIdleTimeoutStatus != idleTimeoutStatusSnapshot) {
|
|
|
|
if (0 != (preInterlockedIdleTimeoutStatus &
|
|
IdleTimeoutStatusFrozen)) {
|
|
//
|
|
// It was too late to set the flag. The flag value was already
|
|
// "frozen".
|
|
//
|
|
return IdleTimeoutStatusFlagsAlreadyFrozen;
|
|
}
|
|
else {
|
|
//
|
|
// Idle timeout management status is being changed by multiple
|
|
// threads in parallel. This is not supported.
|
|
//
|
|
return IdleTimeoutStatusFlagsUnexpected;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We have successfully set the flag
|
|
//
|
|
return IdleTimeoutStatusFlagsUpdated;
|
|
}
|
|
|
|
NTSTATUS
|
|
IdleTimeoutManagement::UseSystemManagedIdleTimeout(
|
|
__in PFX_DRIVER_GLOBALS DriverGlobals
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
IdleTimeoutStatusUpdateResult statusUpdateResult;
|
|
CfxDevice * device;
|
|
|
|
//
|
|
// First check if we are running on Windows 8 or above
|
|
//
|
|
if (_SystemManagedIdleTimeoutAvailable()) {
|
|
|
|
//
|
|
// Get the device object so we can use it for logging
|
|
//
|
|
device = GetDevice();
|
|
|
|
//
|
|
// Try to update the flag that specifies that the power framework should
|
|
// determine the idle timeout.
|
|
//
|
|
statusUpdateResult = UpdateIdleTimeoutStatus(IdleTimeoutSystemManaged);
|
|
|
|
switch (statusUpdateResult) {
|
|
case IdleTimeoutStatusFlagsAlreadyFrozen:
|
|
{
|
|
//
|
|
// Status is already frozen. Too late to update it.
|
|
//
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
DoTraceLevelMessage(
|
|
DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"WDFDEVICE %p !devobj %p If the power framework is made "
|
|
"responsible for determining the idle timeout, then the "
|
|
"first call to assign S0-idle policy must occur before the "
|
|
"first start IRP is completed. However, in this case, it "
|
|
"occurred after the first start IRP was completed. "
|
|
"%!STATUS!.",
|
|
device->GetHandle(),
|
|
device->GetDeviceObject(),
|
|
status
|
|
);
|
|
FxVerifierDbgBreakPoint(DriverGlobals);
|
|
}
|
|
break;
|
|
|
|
case IdleTimeoutStatusFlagsUnexpected:
|
|
{
|
|
//
|
|
// Status being updated from multiple threads in parallel. Not
|
|
// supported.
|
|
//
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
DoTraceLevelMessage(
|
|
DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"WDFDEVICE %p !devobj %p Calls to assign S0-idle settings "
|
|
"and to specify power framework settings are happening in "
|
|
"parallel. The driver needs to serialize these calls with "
|
|
"respect to each other. %!STATUS!.",
|
|
device->GetHandle(),
|
|
device->GetDeviceObject(),
|
|
status
|
|
);
|
|
FxVerifierDbgBreakPoint(DriverGlobals);
|
|
}
|
|
break;
|
|
|
|
case IdleTimeoutStatusFlagAlreadySet:
|
|
{
|
|
//
|
|
// Status flag was already set. This should never happen for the
|
|
// IdleTimeoutSystemManaged flag. The caller ensures this.
|
|
//
|
|
ASSERTMSG(
|
|
"IdleTimeoutManagement::UseSystemManagedIdleTimeout was "
|
|
"called more than once\n", FALSE);
|
|
}
|
|
|
|
//
|
|
// Fall through
|
|
//
|
|
// || || ||
|
|
// \/ \/ \/
|
|
//
|
|
case IdleTimeoutStatusFlagsUpdated:
|
|
{
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
ASSERTMSG("Unexpected IdleTimeoutStatusUpdateResult value\n",
|
|
FALSE);
|
|
status = STATUS_INTERNAL_ERROR;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// If we're not running on Windows 8 or above, then there is nothing to
|
|
// do.
|
|
//
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
IdleTimeoutManagement::FreezeIdleTimeoutManagementStatus(
|
|
__in PFX_DRIVER_GLOBALS DriverGlobals
|
|
)
|
|
{
|
|
LONG idleTimeoutSnapshot;
|
|
LONG idleTimeoutStatus;
|
|
LONG idleTimeoutPreviousStatus;
|
|
CfxDevice * device;
|
|
|
|
//
|
|
// Get the device object so we can use it for logging
|
|
//
|
|
device = GetDevice();
|
|
|
|
//
|
|
// Take a snapshot of the idle timeout management status
|
|
//
|
|
idleTimeoutSnapshot = m_IdleTimeoutStatus;
|
|
|
|
//
|
|
// Set the bit that freezes the status
|
|
//
|
|
idleTimeoutStatus = idleTimeoutSnapshot | IdleTimeoutStatusFrozen;
|
|
|
|
//
|
|
// Update the status
|
|
//
|
|
idleTimeoutPreviousStatus = InterlockedExchange(&m_IdleTimeoutStatus,
|
|
idleTimeoutStatus);
|
|
|
|
if (idleTimeoutPreviousStatus != idleTimeoutSnapshot) {
|
|
//
|
|
// An update of idle timeout status is racing with the freezing of idle
|
|
// timeout status
|
|
//
|
|
DoTraceLevelMessage(
|
|
DriverGlobals, TRACE_LEVEL_WARNING, TRACINGPNP,
|
|
"WDFDEVICE %p !devobj %p The driver's S0-idle settings and/or power"
|
|
" framework settings did not take effect because they were supplied"
|
|
" too late. The driver must ensure that the settings are provided "
|
|
"before the first start IRP is completed.",
|
|
device->GetHandle(),
|
|
device->GetDeviceObject()
|
|
);
|
|
FxVerifierDbgBreakPoint(DriverGlobals);
|
|
}
|
|
|
|
//
|
|
// If the driver has specified power framework settings and system managed
|
|
// idle timeout is available on this OS, then the driver must have opted for
|
|
// system managed idle timeout.
|
|
//
|
|
if ((0 != (idleTimeoutStatus & IdleTimeoutPoxSettingsSpecified)) &&
|
|
(_SystemManagedIdleTimeoutAvailable()) &&
|
|
(0 == (idleTimeoutStatus & IdleTimeoutSystemManaged))) {
|
|
DoTraceLevelMessage(
|
|
DriverGlobals, TRACE_LEVEL_WARNING, TRACINGPNP,
|
|
"WDFDEVICE %p !devobj %p The driver specified power framework "
|
|
"settings, but did not opt for system-managed idle timeout.",
|
|
device->GetHandle(),
|
|
device->GetDeviceObject()
|
|
);
|
|
FxVerifierDbgBreakPoint(DriverGlobals);
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
IdleTimeoutManagement::UsingSystemManagedIdleTimeout(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// If the value of this constant is changed, the debugger extension needs
|
|
// to be fixed as well.
|
|
//
|
|
C_ASSERT(0x2 == IdleTimeoutSystemManaged);
|
|
|
|
return (0 != (m_IdleTimeoutStatus & IdleTimeoutSystemManaged));
|
|
}
|
|
|
|
BOOLEAN
|
|
IdleTimeoutManagement::DriverSpecifiedPowerFrameworkSettings(
|
|
VOID
|
|
)
|
|
{
|
|
return (0 != (m_IdleTimeoutStatus & IdleTimeoutPoxSettingsSpecified));
|
|
}
|
|
|
|
NTSTATUS
|
|
IdleTimeoutManagement::CommitPowerFrameworkSettings(
|
|
__in PFX_DRIVER_GLOBALS DriverGlobals,
|
|
__in PPOX_SETTINGS PoxSettings
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
IdleTimeoutStatusUpdateResult statusUpdateResult;
|
|
PVOID oldPoxSettings = NULL;
|
|
BOOLEAN settingsSuccessfullySaved = FALSE;
|
|
CfxDevice * device;
|
|
|
|
//
|
|
// We should never get here if system-managed idle timeout is not available
|
|
//
|
|
ASSERT(_SystemManagedIdleTimeoutAvailable());
|
|
|
|
//
|
|
// Get the device object so we can use it for logging
|
|
//
|
|
device = GetDevice();
|
|
|
|
//
|
|
// Try to save the driver's power framework settings
|
|
//
|
|
oldPoxSettings = InterlockedCompareExchangePointer((PVOID*) &m_PoxSettings,
|
|
PoxSettings,
|
|
NULL // Comparand
|
|
);
|
|
if (NULL != oldPoxSettings) {
|
|
//
|
|
// The driver's power framework settings have already been specified
|
|
// earlier. The driver should not be attempting to specify them more
|
|
// than once.
|
|
//
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
DoTraceLevelMessage(
|
|
DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"WDFDEVICE %p !devobj %p The driver attempted to specify power "
|
|
"framework settings more than once. %!STATUS!.",
|
|
device->GetHandle(),
|
|
device->GetDeviceObject(),
|
|
status
|
|
);
|
|
FxVerifierDbgBreakPoint(DriverGlobals);
|
|
goto exit;
|
|
}
|
|
settingsSuccessfullySaved = TRUE;
|
|
|
|
//
|
|
// Try to update the flag that indicates that the client driver has
|
|
// specified settings that are to be used when we register with the power
|
|
// framework.
|
|
//
|
|
statusUpdateResult = UpdateIdleTimeoutStatus(
|
|
IdleTimeoutPoxSettingsSpecified
|
|
);
|
|
switch (statusUpdateResult) {
|
|
case IdleTimeoutStatusFlagsAlreadyFrozen:
|
|
{
|
|
//
|
|
// Status is already frozen. Too late to update it.
|
|
//
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
DoTraceLevelMessage(
|
|
DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"WDFDEVICE %p !devobj %p Power framework settings must be "
|
|
"specified before the first start IRP is completed. %!STATUS!.",
|
|
device->GetHandle(),
|
|
device->GetDeviceObject(),
|
|
status
|
|
);
|
|
FxVerifierDbgBreakPoint(DriverGlobals);
|
|
goto exit;
|
|
}
|
|
break;
|
|
|
|
case IdleTimeoutStatusFlagsUnexpected:
|
|
{
|
|
//
|
|
// Status being updated from multiple threads in parallel. Not
|
|
// supported.
|
|
//
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
DoTraceLevelMessage(
|
|
DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"WDFDEVICE %p !devobj %p Calls to assign S0-idle settings and "
|
|
"to specify power framework settings are happening in parallel."
|
|
" The driver needs to serialize these calls with respect to "
|
|
"each other. %!STATUS!.",
|
|
device->GetHandle(),
|
|
device->GetDeviceObject(),
|
|
status
|
|
);
|
|
FxVerifierDbgBreakPoint(DriverGlobals);
|
|
goto exit;
|
|
}
|
|
break;
|
|
|
|
case IdleTimeoutStatusFlagAlreadySet:
|
|
{
|
|
//
|
|
// Status flag was already set. This should never happen for the
|
|
// IdleTimeoutPoxSettingsSpecified flag because we have logic in the
|
|
// beginning of this function to ensure that only the first caller
|
|
// attempts to set this flag.
|
|
//
|
|
ASSERTMSG(
|
|
"Attempt to set the IdleTimeoutPoxSettingsSpecified flag more "
|
|
"than once\n", FALSE);
|
|
status = STATUS_INTERNAL_ERROR;
|
|
goto exit;
|
|
}
|
|
|
|
case IdleTimeoutStatusFlagsUpdated:
|
|
{
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
ASSERTMSG("Unexpected IdleTimeoutStatusUpdateResult value\n",
|
|
FALSE);
|
|
status = STATUS_INTERNAL_ERROR;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we get here, we must have a successful status
|
|
//
|
|
ASSERT(STATUS_SUCCESS == status);
|
|
|
|
exit:
|
|
if (FALSE == NT_SUCCESS(status)) {
|
|
if (settingsSuccessfullySaved) {
|
|
//
|
|
// Since a failure has occurred, we must reset the pointer to the
|
|
// power framework settings.
|
|
//
|
|
m_PoxSettings = NULL;
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
PolicySettings::~PolicySettings()
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
FxPowerPolicyMachine::FxPowerPolicyMachine(
|
|
VOID
|
|
) : FxThreadedEventQueue(FxPowerPolicyEventQueueDepth)
|
|
{
|
|
m_Owner = NULL;
|
|
|
|
RtlZeroMemory(&m_Queue[0], sizeof(m_Queue));
|
|
RtlZeroMemory(&m_States, sizeof(m_States));
|
|
|
|
m_States.History[IncrementHistoryIndex()] = WdfDevStatePwrPolObjectCreated;
|
|
|
|
m_SingularEventsPresent = 0x0;
|
|
}
|
|
|
|
FxPowerPolicyMachine::~FxPowerPolicyMachine(
|
|
VOID
|
|
)
|
|
{
|
|
if (m_Owner != NULL) {
|
|
delete m_Owner;
|
|
m_Owner = NULL;
|
|
}
|
|
}
|
|
|
|
_Must_inspect_result_
|
|
NTSTATUS
|
|
FxPowerPolicyMachine::InitUsbSS(
|
|
VOID
|
|
)
|
|
{
|
|
FxUsbIdleInfo* pInfo;
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// The field is already set, we are good to go
|
|
//
|
|
if (m_Owner->m_UsbIdle != NULL) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
pInfo = new (m_PkgPnp->GetDriverGlobals()) FxUsbIdleInfo(m_PkgPnp);
|
|
|
|
if (pInfo == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
status = pInfo->Initialize();
|
|
if (!NT_SUCCESS(status)) {
|
|
delete pInfo;
|
|
return status;
|
|
}
|
|
|
|
if (InterlockedCompareExchangePointer((PVOID*) &m_Owner->m_UsbIdle,
|
|
pInfo,
|
|
NULL) == NULL) {
|
|
//
|
|
// This thread was the one that set the field value.
|
|
//
|
|
DO_NOTHING();
|
|
}
|
|
else {
|
|
//
|
|
// Another thread raced in and beat this thread in setting the field,
|
|
// just delete our allocation and use the other allocated FxUsbIdleInfo.
|
|
//
|
|
delete pInfo;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
FxPowerPolicyOwnerSettings::FxPowerPolicyOwnerSettings(
|
|
__in FxPkgPnp* PkgPnp
|
|
) : m_PoxInterface(PkgPnp)
|
|
{
|
|
ULONG i;
|
|
|
|
m_UsbIdle = NULL;
|
|
|
|
m_PkgPnp = PkgPnp;
|
|
|
|
//
|
|
// Default every state to D3 except for system working which is D0 by
|
|
// default.
|
|
//
|
|
m_SystemToDeviceStateMap = 0x0;
|
|
|
|
for (i = 0; i < PowerSystemMaximum; i++) {
|
|
FxPkgPnp::_SetPowerCapState(i,
|
|
i == PowerSystemWorking ? PowerDeviceD0
|
|
: PowerDeviceD3,
|
|
&m_SystemToDeviceStateMap);
|
|
}
|
|
|
|
m_IdealDxStateForSx = PowerDeviceD3;
|
|
|
|
m_RequestedPowerUpIrp = FALSE;
|
|
m_RequestedPowerDownIrp = FALSE;
|
|
m_RequestedWaitWakeIrp = FALSE;
|
|
m_WakeCompletionEventDropped = FALSE;
|
|
m_PowerFailed = FALSE;
|
|
m_CanSaveState = TRUE;
|
|
|
|
m_ChildrenCanPowerUp = FALSE;
|
|
m_ChildrenPoweredOnCount = 0;
|
|
m_ChildrenArmedCount = 0;
|
|
|
|
m_WaitWakeStatus = STATUS_NOT_SUPPORTED;
|
|
m_SystemWakeSource = FALSE;
|
|
m_WaitWakeCancelCompletionOwnership = CancelOwnershipUnclaimed;
|
|
|
|
m_PowerCallbackObject = NULL;
|
|
m_PowerCallbackRegistration = NULL;
|
|
}
|
|
|
|
FxPowerPolicyOwnerSettings::~FxPowerPolicyOwnerSettings(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// There are paths which cleanup this object which do not go through the
|
|
// pnp state machine, so make sure the power object callback fields are
|
|
// freed. In these paths, we are guaranteed PASSIVE_LEVEL b/c there will
|
|
// be no dangling references which can cause deletion at a greater IRQL.
|
|
//
|
|
CleanupPowerCallback();
|
|
|
|
if (m_UsbIdle != NULL) {
|
|
delete m_UsbIdle;
|
|
m_UsbIdle = NULL;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
FxPowerPolicyOwnerSettings::CleanupPowerCallback(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Cleans up the power state callback registration for this object.
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if (m_PowerCallbackRegistration != NULL) {
|
|
Mx::UnregisterCallback(m_PowerCallbackRegistration);
|
|
m_PowerCallbackRegistration = NULL;
|
|
|
|
}
|
|
|
|
if (m_PowerCallbackObject != NULL) {
|
|
Mx::MxDereferenceObject(m_PowerCallbackObject);
|
|
m_PowerCallbackObject = NULL;
|
|
}
|
|
}
|
|
|
|
_Must_inspect_result_
|
|
NTSTATUS
|
|
FxPowerPolicyOwnerSettings::Init(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Initialize the object. We will try to register a power state callback so
|
|
that we can be informed of when the machine is changing S states. We are
|
|
interested in system state changes because we need to know when NOT to write
|
|
to the registry (to save wake settings) so that we don't cause a deadlock
|
|
in a non power pageable device while moving into Sx.
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
OBJECT_ATTRIBUTES oa;
|
|
UNICODE_STRING string;
|
|
NTSTATUS status;
|
|
|
|
RtlInitUnicodeString(&string, L"\\Callback\\PowerState");
|
|
InitializeObjectAttributes(
|
|
&oa,
|
|
&string,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Create a callback object, but we do not want to be the first ones
|
|
// to create it (it should be created way before we load in NTOS
|
|
// anyways)
|
|
//
|
|
status = Mx::CreateCallback(&m_PowerCallbackObject, &oa, FALSE, TRUE);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
m_PowerCallbackRegistration = Mx::RegisterCallback(
|
|
m_PowerCallbackObject,
|
|
_PowerStateCallback,
|
|
this
|
|
);
|
|
|
|
if (m_PowerCallbackRegistration == NULL) {
|
|
//
|
|
// Non-critical failure, so we'll free the callback object and keep
|
|
// going
|
|
//
|
|
Mx::MxDereferenceObject(m_PowerCallbackObject);
|
|
m_PowerCallbackObject = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Initialize FxPowerIdleMachine
|
|
//
|
|
status = m_PowerIdleMachine.Init();
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
FxPowerPolicyOwnerSettings::_PowerStateCallback(
|
|
__in PVOID Context,
|
|
__in_opt PVOID Argument1,
|
|
__in_opt PVOID Argument2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Callback invoked by the power subsystem when the system is changing S states
|
|
|
|
Arguments:
|
|
Context - FxPowerPolicyOwnerSettings pointer (the "this" pointer)
|
|
|
|
Argument1 - Reason why the callback was invoked, we only care about
|
|
PO_CB_SYSTEM_STATE_LOCK
|
|
|
|
Argument2 - State transition that is occurring
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
FxPowerPolicyOwnerSettings* pThis;
|
|
|
|
pThis = (FxPowerPolicyOwnerSettings*) Context;
|
|
|
|
if (Argument1 != (PVOID) PO_CB_SYSTEM_STATE_LOCK) {
|
|
return;
|
|
}
|
|
|
|
pThis->m_PkgPnp->m_PowerPolicyMachine.m_StateMachineLock.AcquireLock(
|
|
pThis->m_PkgPnp->GetDriverGlobals(),
|
|
NULL
|
|
);
|
|
|
|
if (Argument2 == (PVOID) 0) {
|
|
//
|
|
// Write out the state if necessary before we turn off the paging path.
|
|
//
|
|
pThis->m_PkgPnp->SaveState(TRUE);
|
|
|
|
//
|
|
// Exiting S0
|
|
//
|
|
pThis->m_CanSaveState = FALSE;
|
|
}
|
|
else if (Argument2 == (PVOID) 1) {
|
|
//
|
|
// We have reentered S0
|
|
//
|
|
pThis->m_CanSaveState = TRUE;
|
|
|
|
//
|
|
// Write out the state if necessary now that the paging path is back
|
|
//
|
|
pThis->m_PkgPnp->SaveState(TRUE);
|
|
}
|
|
|
|
pThis->m_PkgPnp->m_PowerPolicyMachine.m_StateMachineLock.ReleaseLock(
|
|
pThis->m_PkgPnp->GetDriverGlobals()
|
|
);
|
|
}
|
|
|
|
/*++
|
|
|
|
The locking model for the Power policy state machine requires that events be enqueued
|
|
possibly at DISPATCH_LEVEL. It also requires that the state machine be
|
|
runnable at PASSIVE_LEVEL. Consequently, we have two locks, one DISPATCH_LEVEL
|
|
lock that guards the event queue and one PASSIVE_LEVEL lock that guards the
|
|
state machine itself.
|
|
|
|
The Power policy state machine has a few constraints that the PnP state machine
|
|
doesn't. Sometimes it has to call some driver functions at PASSIVE_LEVEL, but
|
|
with the disks turned off. This means that these functions absolutely must not
|
|
page fault. You might think that this means that we should call the driver at
|
|
DISPATCH_LEVEL, and you'd be right if your only concern were for perfectly
|
|
safe code. The problem with that approach, though is that it will force much
|
|
of the rest of the driver to DISPATCH_LEVEL, which will only push the driver
|
|
writer into using lots of asynchronous work items, which will complicate their
|
|
code and make it unsafe in a new variety of ways. So we're going to go with
|
|
PASSIVE_LEVEL here and setting a timeout of 20 seconds. If the driver faults,
|
|
the timer will fire and log the failure. This also means that the driver must
|
|
complete these callbacks within 20 seconds. Even beyond that, it means that
|
|
the work items must be queued onto a special thread, one that once the machine
|
|
has started to go to sleep, never handles any work items that may fault.
|
|
|
|
Algorithm:
|
|
|
|
1) Acquire the Power policy queue lock.
|
|
2) Enqueue the event. events are put at the end of the queue.
|
|
3) Drop the Power policy queue lock.
|
|
4) If the thread is running at PASSIVE_LEVEL, skip to step 6.
|
|
5) Queue a work item onto the special power thread.
|
|
6) Attempt to acquire the state machine lock, with a zero-length timeout (*).
|
|
7) If successful, skip to step 9.
|
|
8) Queue a work item onto the special power thread.
|
|
9) Acquire the state machine lock.
|
|
10) Acquire the Power policy queue lock.
|
|
11) Attempt to dequeue an event.
|
|
12) Drop the Power policyqueue lock.
|
|
13) If there was no event to dequeue, drop the state machine lock and exit.
|
|
14) Execute the state handler. This may involve taking one of the other state
|
|
machine queue locks, briefly, to deliver an event.
|
|
15) Go to Step 10.
|
|
|
|
(*) zero length is different then NULL (infinite) being passed for the timeout
|
|
|
|
Implementing this algorithm requires three functions.
|
|
|
|
PowerPolicyProcessEvent -- Implements steps 1-8.
|
|
_PowerPolicyProcessEventInner -- Implements step 9.
|
|
PowerPolicyProcessEventInner -- Implements steps 10-15.
|
|
|
|
--*/
|
|
|
|
VOID
|
|
FxPkgPnp::PowerPolicyProcessEvent(
|
|
__in FxPowerPolicyEvent Event,
|
|
__in BOOLEAN ProcessOnDifferentThread
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function implements steps 1-8 of the algorithm described above.
|
|
|
|
Arguments:
|
|
Event - Current Power event
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
ULONG mask;
|
|
KIRQL irql;
|
|
|
|
//
|
|
// Take the lock, raising to DISPATCH_LEVEL.
|
|
//
|
|
m_PowerPolicyMachine.Lock(&irql);
|
|
|
|
//
|
|
// If the input Event is any of the events described by PowerSingularEventMask,
|
|
// then check whether it is already queued up. If so, then dont enqueue this
|
|
// Event.
|
|
//
|
|
if (Event & PowerPolSingularEventMask) {
|
|
if ((m_PowerPolicyMachine.m_SingularEventsPresent & Event) == 0x00) {
|
|
m_PowerPolicyMachine.m_SingularEventsPresent |= Event;
|
|
}
|
|
else {
|
|
DoTraceLevelMessage(
|
|
GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
|
|
"WDFDEVICE 0x%p !devobj 0x%p current pwr pol state "
|
|
"%!WDF_DEVICE_POWER_POLICY_STATE! dropping event "
|
|
"%!FxPowerPolicyEvent! because the Event is already enqueued.",
|
|
m_Device->GetHandle(),
|
|
m_Device->GetDeviceObject(),
|
|
m_Device->GetDevicePowerPolicyState(), Event);
|
|
|
|
m_PowerPolicyMachine.Unlock(irql);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (m_PowerPolicyMachine.IsFull()) {
|
|
//
|
|
// The queue is full. Bail.
|
|
//
|
|
m_PowerPolicyMachine.Unlock(irql);
|
|
|
|
ASSERT(!"The Power queue is full. This shouldn't be able to happen.");
|
|
return;
|
|
}
|
|
|
|
if (m_PowerPolicyMachine.IsClosedLocked()) {
|
|
DoTraceLevelMessage(
|
|
GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
|
|
"WDFDEVICE 0x%p !devobj 0x%p current pwr pol state "
|
|
"%!WDF_DEVICE_POWER_POLICY_STATE! dropping event "
|
|
"%!FxPowerPolicyEvent! because of a closed queue",
|
|
m_Device->GetHandle(),
|
|
m_Device->GetDeviceObject(),
|
|
m_Device->GetDevicePowerPolicyState(), Event);
|
|
|
|
//
|
|
// The queue is closed. Bail
|
|
//
|
|
m_PowerPolicyMachine.Unlock(irql);
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Enqueue the event. Whether the event goes on the front
|
|
// or the end of the queue depends on which event it is and if we are the
|
|
// PPO or not.
|
|
//
|
|
// Yes, mask could be a member variable of m_PowerPolicyMachine, but why
|
|
// waste 4 bytes when it is very easy to figure out?
|
|
//
|
|
mask = IsPowerPolicyOwner() ? PwrPolPriorityEventsMask
|
|
: PwrPolNotOwnerPriorityEventsMask;
|
|
|
|
if (Event & mask) {
|
|
//
|
|
// Stick it on the front of the queue, making it the next event that
|
|
// will be processed if, otherwise let these events go by.
|
|
//
|
|
m_PowerPolicyMachine.m_Queue[m_PowerPolicyMachine.InsertAtHead()] = Event;
|
|
}
|
|
else {
|
|
//
|
|
// Stick it on the end of the queue.
|
|
//
|
|
m_PowerPolicyMachine.m_Queue[m_PowerPolicyMachine.InsertAtTail()] = Event;
|
|
}
|
|
|
|
//
|
|
// Drop the lock.
|
|
//
|
|
m_PowerPolicyMachine.Unlock(irql);
|
|
|
|
//
|
|
// Now, if we are running at PASSIVE_LEVEL, attempt to run the state
|
|
// machine on this thread. If we can't do that, then queue a work item.
|
|
//
|
|
if (FALSE == ShouldProcessPowerPolicyEventOnDifferentThread(
|
|
irql,
|
|
ProcessOnDifferentThread
|
|
)) {
|
|
|
|
LONGLONG timeout = 0;
|
|
|
|
status = m_PowerPolicyMachine.m_StateMachineLock.AcquireLock(
|
|
GetDriverGlobals(), &timeout);
|
|
|
|
if (FxWaitLockInternal::IsLockAcquired(status)) {
|
|
FxPostProcessInfo info;
|
|
|
|
//
|
|
// We now hold the state machine lock. So call the function that
|
|
// dispatches the next state.
|
|
//
|
|
PowerPolicyProcessEventInner(&info);
|
|
|
|
//
|
|
// The pnp state machine should be the only one deleting the object
|
|
//
|
|
ASSERT(info.m_DeleteObject == FALSE);
|
|
|
|
m_PowerPolicyMachine.m_StateMachineLock.ReleaseLock(
|
|
GetDriverGlobals());
|
|
|
|
info.Evaluate(this);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The tag added above will be released when the work item runs
|
|
//
|
|
|
|
//
|
|
// For one reason or another, we couldn't run the state machine on this
|
|
// thread. So queue a work item to do it. If m_PnPWorkItemEnqueuing
|
|
// is non-zero, that means that the work item is already being enqueued
|
|
// on another thread. This is significant, since it means that we can't do
|
|
// anything with the work item on this thread, but it's okay, since the
|
|
// work item will pick up our work and do it.
|
|
//
|
|
m_PowerPolicyMachine.QueueToThread();
|
|
}
|
|
|
|
VOID
|
|
FxPkgPnp::_PowerPolicyProcessEventInner(
|
|
__inout FxPkgPnp* This,
|
|
__inout FxPostProcessInfo* Info,
|
|
__in PVOID Context
|
|
)
|
|
{
|
|
|
|
UNREFERENCED_PARAMETER(Context);
|
|
|
|
//
|
|
// Take the state machine lock.
|
|
//
|
|
This->m_PowerPolicyMachine.m_StateMachineLock.AcquireLock(
|
|
This->GetDriverGlobals()
|
|
);
|
|
|
|
//
|
|
// Call the function that will actually run the state machine.
|
|
//
|
|
This->PowerPolicyProcessEventInner(Info);
|
|
|
|
//
|
|
// We are being called from the work item and m_WorkItemRunning is > 0, so
|
|
// we cannot be deleted yet.
|
|
//
|
|
ASSERT(Info->SomethingToDo() == FALSE);
|
|
|
|
//
|
|
// Now release the lock
|
|
//
|
|
This->m_PowerPolicyMachine.m_StateMachineLock.ReleaseLock(
|
|
This->GetDriverGlobals()
|
|
);
|
|
}
|
|
|
|
VOID
|
|
FxPkgPnp::PowerPolicyProcessEventInner(
|
|
__inout FxPostProcessInfo* Info
|
|
)
|
|
{
|
|
WDF_DEVICE_POWER_POLICY_STATE newState;
|
|
FxPowerPolicyEvent event;
|
|
ULONG i;
|
|
KIRQL irql;
|
|
|
|
if (IsPowerPolicyOwner()) {
|
|
CPPOWER_POLICY_STATE_TABLE entry;
|
|
|
|
//
|
|
// Process as many events as we can.
|
|
//
|
|
for ( ; ; ) {
|
|
entry = GetPowerPolicyTableEntry(m_Device->GetDevicePowerPolicyState());
|
|
|
|
//
|
|
// Get an event from the queue.
|
|
//
|
|
m_PowerPolicyMachine.Lock(&irql);
|
|
|
|
if (m_PowerPolicyMachine.IsEmpty()) {
|
|
m_PowerPolicyMachine.GetFinishedState(Info);
|
|
|
|
//
|
|
// The queue is empty.
|
|
//
|
|
m_PowerPolicyMachine.Unlock(irql);
|
|
return;
|
|
}
|
|
|
|
event = m_PowerPolicyMachine.m_Queue[m_PowerPolicyMachine.GetHead()];
|
|
|
|
//
|
|
// At this point, we need to determine whether we can process this
|
|
// event.
|
|
//
|
|
if (event & PwrPolPriorityEventsMask) {
|
|
//
|
|
// These are always possible to handle.
|
|
//
|
|
DO_NOTHING();
|
|
}
|
|
else {
|
|
//
|
|
// Check to see if this state can handle new events, ie if this
|
|
// is a green dot (queue open) or red dot (queue *not* open) state.
|
|
//
|
|
if (entry->StateInfo.Bits.QueueOpen == FALSE) {
|
|
//
|
|
// This state can't handle new events.
|
|
//
|
|
m_PowerPolicyMachine.Unlock(irql);
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the event obtained from the queue was a singular event, then
|
|
// clear the flag to allow other similar events to be put into this
|
|
// queue for processing.
|
|
//
|
|
if (m_PowerPolicyMachine.m_SingularEventsPresent & event) {
|
|
m_PowerPolicyMachine.m_SingularEventsPresent &= ~event;
|
|
}
|
|
|
|
m_PowerPolicyMachine.IncrementHead();
|
|
m_PowerPolicyMachine.Unlock(irql);
|
|
|
|
//
|
|
// Find the entry in the power policy state table that corresponds
|
|
// to this event.
|
|
//
|
|
newState = WdfDevStatePwrPolNull;
|
|
|
|
if (entry->FirstTargetState.PowerPolicyEvent == event) {
|
|
newState = entry->FirstTargetState.TargetState;
|
|
|
|
DO_EVENT_TRAP(&entry->FirstTargetState);
|
|
}
|
|
else if (entry->OtherTargetStates != NULL) {
|
|
for (i = 0;
|
|
entry->OtherTargetStates[i].PowerPolicyEvent != PwrPolNull;
|
|
i++) {
|
|
if (entry->OtherTargetStates[i].PowerPolicyEvent == event) {
|
|
newState = entry->OtherTargetStates[i].TargetState;
|
|
DO_EVENT_TRAP(&entry->OtherTargetStates[i]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (newState == WdfDevStatePwrPolNull) {
|
|
//
|
|
// This state doesn't respond to the event. Just throw the event
|
|
// away.
|
|
//
|
|
DoTraceLevelMessage(
|
|
GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
|
"WDFDEVICE 0x%p !devobj 0x%p current pwr pol state "
|
|
"%!WDF_DEVICE_POWER_POLICY_STATE! dropping event "
|
|
"%!FxPowerPolicyEvent!", m_Device->GetHandle(),
|
|
m_Device->GetDeviceObject(),
|
|
m_Device->GetDevicePowerPolicyState(), event);
|
|
|
|
if ((entry->StateInfo.Bits.KnownDroppedEvents & event) == 0) {
|
|
COVERAGE_TRAP();
|
|
|
|
DoTraceLevelMessage(
|
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"WDFDEVICE 0x%p !devobj 0x%p current state "
|
|
"%!WDF_DEVICE_POWER_POLICY_STATE!, policy event "
|
|
"%!FxPowerPolicyEvent! is not a known dropped "
|
|
"event, known dropped events are %!FxPowerPolicyEvent!",
|
|
m_Device->GetHandle(), m_Device->GetDeviceObject(),
|
|
m_Device->GetDevicePowerPolicyState(),
|
|
event, entry->StateInfo.Bits.KnownDroppedEvents);
|
|
|
|
|
|
}
|
|
|
|
//
|
|
// Failsafes for events which have required processing in them.
|
|
//
|
|
switch (event) {
|
|
case PwrPolSx:
|
|
//
|
|
// The Sx handling code expects that the state machine
|
|
// complete the Sx irp. (S0 irps are never pended). Since
|
|
// we don't have a state to transition to that will complete
|
|
// the request, do so now.
|
|
//
|
|
// (This can legitimately happen if a PDO is disabled and
|
|
// the machines moves into an Sx state.)
|
|
//
|
|
PowerPolicyCompleteSystemPowerIrp();
|
|
break;
|
|
|
|
case PwrPolUsbSelectiveSuspendCompleted:
|
|
//
|
|
// This state did not handle the event and event got
|
|
// dropped. However some state is definitely going to wait
|
|
// for this event. That's why we need m_EventDropped flag.
|
|
// If we didn't have this flag there will be no way to know
|
|
// if the event got dropped and some state will end up
|
|
// waiting for it indefinitely.
|
|
//
|
|
m_PowerPolicyMachine.m_Owner->m_UsbIdle->m_EventDropped = TRUE;
|
|
break;
|
|
|
|
case PwrPolUsbSelectiveSuspendCallback:
|
|
m_PowerPolicyMachine.UsbSSCallbackProcessingComplete();
|
|
break;
|
|
|
|
case PwrPolWakeSuccess:
|
|
case PwrPolWakeFailed:
|
|
//
|
|
// This state did not handle the event and event got
|
|
// dropped. However some state is definitely going to wait
|
|
// for this event. That's why we need
|
|
// m_WakeCompletionEventDropped flag. If we didn't have this
|
|
// flag there will be no way to know if the event got
|
|
// dropped and some state will end up waiting for it
|
|
// indefinitely.
|
|
//
|
|
m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped = TRUE;
|
|
break;
|
|
|
|
default:
|
|
DO_NOTHING();
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// Now enter the new state.
|
|
//
|
|
PowerPolicyEnterNewState(newState);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// Process as many events as we can.
|
|
//
|
|
for ( ; ; ) {
|
|
CPNOT_POWER_POLICY_OWNER_STATE_TABLE entry;
|
|
|
|
#pragma prefast(suppress:__WARNING_DEREF_NULL_PTR, "The current power policy state will always be in the table so entry will never be NULL")
|
|
entry = GetNotPowerPolicyOwnerTableEntry(
|
|
m_Device->GetDevicePowerPolicyState()
|
|
);
|
|
|
|
//
|
|
// Get an event from the queue.
|
|
//
|
|
m_PowerPolicyMachine.Lock(&irql);
|
|
|
|
if (m_PowerPolicyMachine.IsEmpty()) {
|
|
//
|
|
// The queue is empty.
|
|
//
|
|
m_PowerPolicyMachine.Unlock(irql);
|
|
return;
|
|
}
|
|
|
|
event = m_PowerPolicyMachine.m_Queue[m_PowerPolicyMachine.GetHead()];
|
|
|
|
//
|
|
// At this point, we need to determine whether we can process this
|
|
// event.
|
|
//
|
|
if (event & PwrPolNotOwnerPriorityEventsMask) {
|
|
//
|
|
// These are always possible to handle.
|
|
//
|
|
DO_NOTHING();
|
|
}
|
|
else {
|
|
//
|
|
// Check to see if this state can handle new events, ie if this
|
|
// is a green dot (queue open) or red dot (queue *not* open) state.
|
|
//
|
|
if (entry->QueueOpen == FALSE) {
|
|
//
|
|
// This state can't handle new events.
|
|
//
|
|
m_PowerPolicyMachine.Unlock(irql);
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the event obtained from the queue was a singular event, then
|
|
// clear the flag to allow other similar events to be put into this
|
|
// queue for processing.
|
|
//
|
|
if (m_PowerPolicyMachine.m_SingularEventsPresent & event) {
|
|
m_PowerPolicyMachine.m_SingularEventsPresent &= ~event;
|
|
}
|
|
|
|
m_PowerPolicyMachine.IncrementHead();
|
|
m_PowerPolicyMachine.Unlock(irql);
|
|
|
|
if (entry != NULL && entry->TargetStatesCount > 0) {
|
|
for (i = 0; i < entry->TargetStatesCount; i++) {
|
|
if (event == entry->TargetStates[i].PowerPolicyEvent) {
|
|
DO_EVENT_TRAP(&entry->TargetStates[i]);
|
|
|
|
//
|
|
// Now enter the new state.
|
|
//
|
|
NotPowerPolicyOwnerEnterNewState(
|
|
entry->TargetStates[i].TargetState);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
FxPkgPnp::PowerPolicyEnterNewState(
|
|
__in WDF_DEVICE_POWER_POLICY_STATE NewState
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function looks up the handler for a state and then calls it.
|
|
|
|
Arguments:
|
|
Event - Current power plicy event
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
CPPOWER_POLICY_STATE_TABLE entry;
|
|
WDF_DEVICE_POWER_POLICY_STATE currentState, newState;
|
|
WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA data;
|
|
FxWatchdog watchdog(this);
|
|
|
|
currentState = m_Device->GetDevicePowerPolicyState();
|
|
newState = NewState;
|
|
|
|
while (newState != WdfDevStatePwrPolNull) {
|
|
DoTraceLevelMessage(
|
|
GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNPPOWERSTATES,
|
|
"WDFDEVICE 0x%p !devobj 0x%p entering power policy state "
|
|
"%!WDF_DEVICE_POWER_POLICY_STATE! from "
|
|
"%!WDF_DEVICE_POWER_POLICY_STATE!", m_Device->GetHandle(),
|
|
m_Device->GetDeviceObject(), newState, currentState);
|
|
|
|
if (m_PowerPolicyStateCallbacks != NULL) {
|
|
//
|
|
// Callback for leaving the old state
|
|
//
|
|
RtlZeroMemory(&data, sizeof(data));
|
|
|
|
data.Type = StateNotificationLeaveState;
|
|
data.Data.LeaveState.CurrentState = currentState;
|
|
data.Data.LeaveState.NewState = newState;
|
|
|
|
m_PowerPolicyStateCallbacks->Invoke(currentState,
|
|
StateNotificationLeaveState,
|
|
m_Device->GetHandle(),
|
|
&data);
|
|
}
|
|
|
|
m_PowerPolicyMachine.m_States.History[
|
|
m_PowerPolicyMachine.IncrementHistoryIndex()] = (USHORT) newState;
|
|
|
|
if (m_PowerPolicyStateCallbacks != NULL) {
|
|
//
|
|
// Callback for entering the new state
|
|
//
|
|
RtlZeroMemory(&data, sizeof(data));
|
|
|
|
data.Type = StateNotificationEnterState;
|
|
data.Data.EnterState.CurrentState = currentState;
|
|
data.Data.EnterState.NewState = newState;
|
|
|
|
m_PowerPolicyStateCallbacks->Invoke(newState,
|
|
StateNotificationEnterState,
|
|
m_Device->GetHandle(),
|
|
&data);
|
|
}
|
|
|
|
m_Device->SetDevicePowerPolicyState(newState);
|
|
currentState = newState;
|
|
|
|
entry = GetPowerPolicyTableEntry(currentState);
|
|
|
|
//
|
|
// And call the state handler, if there is one.
|
|
//
|
|
if (entry->StateFunc != NULL) {
|
|
watchdog.StartTimer(currentState);
|
|
newState = entry->StateFunc(this);
|
|
watchdog.CancelTimer(currentState);
|
|
|
|
//
|
|
// Validate the return value if FX_STATE_MACHINE_VERIFY is enabled
|
|
//
|
|
VALIDATE_PWR_POL_STATE(currentState, newState);
|
|
|
|
}
|
|
else {
|
|
newState = WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
if (m_PowerPolicyStateCallbacks != NULL) {
|
|
//
|
|
// Callback for post processing the new state
|
|
//
|
|
RtlZeroMemory(&data, sizeof(data));
|
|
|
|
data.Type = StateNotificationPostProcessState;
|
|
data.Data.PostProcessState.CurrentState = currentState;
|
|
|
|
m_PowerPolicyStateCallbacks->Invoke(currentState,
|
|
StateNotificationPostProcessState,
|
|
m_Device->GetHandle(),
|
|
&data);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
One of the goals of the Driver Framework is to make it really easy to write
|
|
a driver for a device which keeps the device in the lowest useful power state
|
|
at all times. This could (and often does) mean that the device remains in the
|
|
D0 state whenever the machine is running. Or it could mean that the device is
|
|
only in D0 when there are outstanding IRPs in its queues. Or it could mean
|
|
that the device is in D0 whenever the driver explicitly says that it has to be.
|
|
|
|
Consequently, the Power Policy state machine has a bunch of states that relate
|
|
only to managing the state of the device while the system is running, possibly
|
|
allowing the device to "idle-out" to low power states while it isn't being
|
|
heavily used. Once that idle-out process has begun, there needs to be some
|
|
way for the Framework I/O Package and the driver itself to tell the Power Policy
|
|
engine that the device must, for some time at least, be in the D0 (high-power,
|
|
working) state. The problem is made much harder by the fact that the driver
|
|
(or the Framework itself) probably has to stall some operation while the device
|
|
is brought back into the D0 state.
|
|
|
|
So we've created two operations, PowerReference and PowerDereference, which
|
|
tell the Power Policy state machine when a device needs to be in the D0 state.
|
|
The I/O Package uses these internally, and the driver may as well. We want
|
|
these operations to be as light-weight as possible, so that a driver never
|
|
experiences meaningful degradation in performance simply because it chose to
|
|
be a good electricity consumer and enabled idle-time power management.
|
|
Fortunately, the Framework I/O package can significantly reduce the number of
|
|
times that it needs to call these functions by only calling them when the
|
|
queue state transitions from empty to non-empty or back again. A caller within
|
|
the driver itself will need to be aware that their usage can be somewhat
|
|
expensive.
|
|
|
|
Furthermore, these functions need to be callable at both PASSIVE_LEVEL and
|
|
DISPATCH_LEVEL. This really necessitates two versions, as a PASSIVE_LEVEL
|
|
user within the driver probably would like us to block while the device is
|
|
moved into D0, while a DISPATCH_LEVEL user (or the Framework I/O package) would
|
|
prefer a much more asynchronous mode of use.
|
|
|
|
Dealing with these multiple modes involves a fairly complex locking scheme. Here
|
|
is a statement of algorithm.
|
|
|
|
Locks:
|
|
|
|
A) Idle Transition Spinlock - DISPATCH_LEVEL
|
|
B) Device in D0 Notification Event - PASSIVE_LEVEL
|
|
|
|
Device-wide variables:
|
|
|
|
I) Power Reference Count - number of outstanding reasons to be in D0.
|
|
II) Idle Timout -- value set by the driver which governs the idle timer
|
|
III) Transitioning -- boolean indicating whether we're in the process of
|
|
moving the device from Dx to D0.
|
|
|
|
PowerDecrement:
|
|
|
|
1) Take Idle Transition lock.
|
|
3) Decrement of the device-wide power reference count.
|
|
3) If that's not zero, drop the lock and exit.
|
|
4) Set the driver's Idle Timer.
|
|
5) Drop the Idle Transition lock.
|
|
|
|
PowerIncrement:
|
|
|
|
1) Take Idle Transition lock.
|
|
2) Increment of the device-wide power reference count.
|
|
3) If that's 1, then we're transitioning out of idle. Goto Step 6.
|
|
4) If Transitioning == TRUE, we need to wait, Goto Step 13.
|
|
5) Drop the Idle Transition lock. Exit.
|
|
6) Cancel the Idle Timer. If that was unsuccessful, then the timer was not
|
|
set, which means that the device has either moved out of D0 or it is moving
|
|
out of D0. Goto Step 8.
|
|
7) Drop the Idle Transition lock. Exit.
|
|
8) The timer was not succefully cancelled. This means that we have timed out
|
|
in the past and we need to put the device back in D0.
|
|
Set Transitioning = TRUE.
|
|
9) Drop Idle Transition lock.
|
|
10) Reset the D0 Notification Event.
|
|
11) Send IoPresent event to the Power Policy state machine.
|
|
12) If IRQL == DISPATCH_LEVEL goto Step 15.
|
|
13) Wait for the D0 Notification Event.
|
|
14) Exit.
|
|
15) Note that I/O needs to be restarted later.
|
|
16) Exit STATUS_PENDING.
|
|
|
|
--*/
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStarting(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStarting);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.Start();
|
|
|
|
This->PowerProcessEvent(PowerImplicitD0);
|
|
|
|
//
|
|
// Wait for the successful power up before starting any idle timers. If
|
|
// the power up fails, we will not send a power policy stop from the pnp
|
|
// engine.
|
|
//
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStartingPoweredUp(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The power state policy state machine has powered up. Tell the active/idle
|
|
state machine to initialize.
|
|
|
|
The device needs to be in D0 before the active/idle state machine registers
|
|
with the power framework. Therefore, we wait until the power state machine
|
|
has brought the device into D0 before we tell the active/idle state machine
|
|
to start. Moving the device into D0 allows us to touch hardware if needed
|
|
(for example, to determine the number of components in the device) before
|
|
registering with the power framework.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStartingPoweredUp);
|
|
|
|
//
|
|
// The decision regarding whether or not the power framework determines the
|
|
// idle timeout is now "frozen" and cannot be changed unless the device is
|
|
// stopped and restarted.
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_IdleSettings.m_TimeoutMgmt.FreezeIdleTimeoutManagementStatus(
|
|
This->GetDriverGlobals()
|
|
);
|
|
|
|
status = This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.InitializeComponents();
|
|
if (FALSE == NT_SUCCESS(status)) {
|
|
return WdfDevStatePwrPolStartingPoweredUpFailed;
|
|
}
|
|
|
|
return WdfDevStatePwrPolStartingSucceeded;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStartingPoweredUpFailed(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
We failed to initialize the device's components. We have already started the
|
|
power state machine, so ask it to run down before we tell the PNP state
|
|
machine to fail device start.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStartingPoweredUpFailed);
|
|
|
|
This->PowerProcessEvent(PowerImplicitD3);
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStartingSucceeded(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The power policy state machine has successfully started. Notify the pnp
|
|
state machine that this has occurred and then tell the active/idle state
|
|
machine to move to an active state.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolStartingDecideS0Wake
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStartingSucceeded);
|
|
|
|
This->PnpProcessEvent(PnpEventPwrPolStarted);
|
|
|
|
return WdfDevStatePwrPolStartingDecideS0Wake;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStartingFailed(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Attempting to bring the device into the D0 state failed. Report the status
|
|
to pnp.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
KIRQL irql;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStartingFailed);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.Stop();
|
|
|
|
//
|
|
// We raise IRQL to dispatch level so that pnp is forced onto its own thread
|
|
// to process the PwrPolStartFailed event. If pnp is on the power thread when
|
|
// it processes the event and it tries to delete the dedicated thread, it
|
|
// will deadlock waiting for the thread its on to exit.
|
|
//
|
|
Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql);
|
|
This->PnpProcessEvent(PnpEventPwrPolStartFailed);
|
|
Mx::MxLowerIrql(irql);
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStartingDecideS0Wake(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStartingDecideS0Wake);
|
|
|
|
This->PowerPolicyChildrenCanPowerUp();
|
|
|
|
//
|
|
// Save idle state if it is dirty. We check when deciding the S0 state
|
|
// because any change in the S0 idle settings will go through this state.
|
|
//
|
|
This->SaveState(TRUE);
|
|
|
|
//
|
|
// If necessary update the idle timeout hint to the power framework
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->m_PoxInterface.UpdateIdleTimeoutHint();
|
|
|
|
if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.Enabled) {
|
|
if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.WakeFromS0Capable) {
|
|
//
|
|
// We can idle out and wake from S0
|
|
//
|
|
return WdfDevStatePwrPolStartedWakeCapable;
|
|
}
|
|
else {
|
|
//
|
|
// We can idle out, but not wake from the idle state
|
|
//
|
|
return WdfDevStatePwrPolStartedIdleCapable;
|
|
}
|
|
}
|
|
|
|
return WdfDevStatePwrPolStarted;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStartedIdleCapable(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStartedIdleCapable);
|
|
|
|
//
|
|
// Enable the idle state machine. This will release any threads who are
|
|
// waiting for the device to return to D0.
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.EnableTimer();
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolIdleCapableDeviceIdle(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
We are now idle. Tell the active/idle state machine to move us to an idle
|
|
state.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN canPowerDown;
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolIdleCapableDeviceIdle);
|
|
|
|
canPowerDown = This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.DeclareComponentIdle();
|
|
|
|
//
|
|
// If we are using driver-managed idle timeout we can power down immediately
|
|
// and so we jump to the next state (that initiates power down) immediately.
|
|
// If we are using system-managed idle timeout, we wait in the current state
|
|
// for device-power-not-required notification.
|
|
//
|
|
return (canPowerDown ?
|
|
WdfDevStatePwrPolTimerExpiredNoWake :
|
|
WdfDevStatePwrPolNull);
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolDeviceIdleReturnToActive(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
We are idle, but still in D0. We need to return to an active state.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolDeviceIdleReturnToActive);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.RequestComponentActive();
|
|
|
|
return WdfDevStatePwrPolStartedCancelTimer;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolDeviceIdleSleeping(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
We are idle, but still in D0. System is going to a low power state.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolDeviceIdleSleeping);
|
|
|
|
//
|
|
// Normally we'd make the component active when we get the device-power-
|
|
// required notification. But we've not yet processed the device-power-not-
|
|
// required notification, so we will not be processing the device-power-
|
|
// required notification either. So let's activate the component before we
|
|
// process the Sx IRP.
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.RequestComponentActive();
|
|
|
|
return WdfDevStatePwrPolStartedIdleCapableCancelTimerForSleep;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolDeviceIdleStopping(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
We are idle, but still in D0. Power policy state machine is being stopped.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolDeviceIdleStopping);
|
|
|
|
//
|
|
// Normally we'd make the component active when we get the device-power-
|
|
// required notification. But we've not yet processed the device-power-not-
|
|
// required notification, so we will not be processing the device-power-
|
|
// required notification either. So let's activate the component before we
|
|
// process the stop/remove request.
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.RequestComponentActive();
|
|
|
|
return WdfDevStatePwrPolStoppingCancelTimer;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredNoWake(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
BOOLEAN poweredDown;
|
|
NTSTATUS notifyPowerDownStatus;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredNoWake);
|
|
|
|
//
|
|
// Notify the device power requirement state machine that we are about to
|
|
// power down.
|
|
//
|
|
notifyPowerDownStatus = This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.NotifyDevicePowerDown();
|
|
if (FALSE == NT_SUCCESS(notifyPowerDownStatus)) {
|
|
//
|
|
// We couldn't notify the device power requirement state machine that
|
|
// we are about to power down, because the "device-power-required"
|
|
// notification has already arrived. So we should not power down at this
|
|
// time. Revert back to the started state.
|
|
//
|
|
return WdfDevStatePwrPolTimerExpiredNoWakeReturnToActive;
|
|
}
|
|
|
|
poweredDown = This->PowerPolicyCanIdlePowerDown(
|
|
This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.DxState
|
|
);
|
|
|
|
if (poweredDown == FALSE) {
|
|
//
|
|
// Upon failure, revert back to the started state.
|
|
//
|
|
return WdfDevStatePwrPolTimerExpiredNoWakeUndoPowerDown;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredNoWakeCompletePowerDown(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device idled out and we sent the Dx request. The power state machine has
|
|
gone as far as stopping I/O is waiting to be notified to complete the Dx
|
|
process. Send the PowerCompleteDx event to move the device fully into Dx.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This,
|
|
WdfDevStatePwrPolTimerExpiredNoWakeCompletePowerDown);
|
|
|
|
This->PowerProcessEvent(PowerCompleteDx);
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolWaitingUnarmedQueryIdle(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device was in the WaitingUnarmed state and received a PwrPolIoPresent
|
|
event. Before committing the device to move back to D0, check to see if
|
|
the device has returned to an idle state. This can easily happen if the
|
|
driver causes a power reference in D0Exit accidentally and the power
|
|
reference is removed before exiting the function.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWaitingUnarmedQueryIdle);
|
|
|
|
//
|
|
// If QueryReturnToIdle returns TRUE, return to the waiting state
|
|
//
|
|
if (This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.QueryReturnToIdle()) {
|
|
return WdfDevStatePwrPolWaitingUnarmed;
|
|
}
|
|
else {
|
|
return WdfDevStatePwrPolS0NoWakePowerUp;
|
|
}
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolS0NoWakePowerUp(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolS0NoWakePowerUp);
|
|
|
|
//
|
|
// Attempt to get back to the D0 state
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.RequestComponentActive();
|
|
status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
COVERAGE_TRAP();
|
|
return WdfDevStatePwrPolDeviceD0PowerRequestFailed;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolS0NoWakeCompletePowerUp(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device was in a Dx unarmed for wake while in S0 and is now being brought
|
|
into the D0 state. The device is currently in a partial D0 state (HW
|
|
started), move it into the full D0 state by sending PowerCompleteD0 to the
|
|
power state machine.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolS0NoWakeCompletePowerUp);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.DeviceIsPoweredOn();
|
|
|
|
This->PowerProcessEvent(PowerCompleteD0);
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemSleepFromDeviceWaitingUnarmed(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
SYSTEM_POWER_STATE systemState;
|
|
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolSystemSleepFromDeviceWaitingUnarmed);
|
|
|
|
systemState = This->PowerPolicyGetPendingSystemState();
|
|
|
|
if (This->PowerPolicyIsWakeEnabled() &&
|
|
This->PowerPolicyCanWakeFromSystemState(systemState)) {
|
|
return WdfDevStatePwrPolSystemSleepNeedWake;
|
|
}
|
|
else {
|
|
return WdfDevStatePwrPolSystemAsleepNoWake;
|
|
}
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemSleepNeedWake(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
BOOLEAN result;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemSleepNeedWake);
|
|
|
|
result = This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer();
|
|
ASSERT(result);
|
|
UNREFERENCED_PARAMETER(result);
|
|
|
|
status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry);
|
|
|
|
//
|
|
// We are currently in Dx and not armed for wake. While the current Dx
|
|
// state may not be the same Dx state we would be for Sx, we can't get to
|
|
// D0 to arm ourselves for Sx wake so just leave ourselves as is.
|
|
//
|
|
if (!NT_SUCCESS(status)) {
|
|
DoTraceLevelMessage(
|
|
This->GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP,
|
|
"Failed to allocate D0 request to disarm from wake from S0 to allow "
|
|
"arm for wake from Sx, %!STATUS!", status);
|
|
|
|
COVERAGE_TRAP();
|
|
|
|
//
|
|
// If D0 IRP allocation fails, we don't treat that as an error. Instead,
|
|
// we just let the device remain in Dx without arming it for
|
|
// wake-from-Sx, even though the driver had enabled wake-from-Sx.
|
|
//
|
|
return WdfDevStatePwrPolSystemAsleepNoWake;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemSleepNeedWakeCompletePowerUp(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The machine is going into Sx while the device was in Dx. We have started
|
|
the D0 process. The power state machine has moved the device into the HW
|
|
working state and is waiting to be notified to complete the D0 process.
|
|
Send the PowerCompleteD0 event to complete it.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This,
|
|
WdfDevStatePwrPolSystemSleepNeedWakeCompletePowerUp);
|
|
|
|
This->PowerProcessEvent(PowerCompleteD0);
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemSleepPowerRequestFailed(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Power up failed in the power state machine. Complete the pending system
|
|
power irp with success (system ignores the results) even if the Dx irp
|
|
failed.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state WdfDevStatePwrPolDevicePowerRequestFailed
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemSleepPowerRequestFailed);
|
|
|
|
This->PowerPolicyCompleteSystemPowerIrp();
|
|
|
|
return WdfDevStatePwrPolDevicePowerRequestFailed;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolCheckPowerPageable(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Checks to see if the device should move down the power pagable wake path
|
|
or the NP path.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state
|
|
|
|
--*/
|
|
{
|
|
ULONG flags;
|
|
MxDeviceObject deviceObject;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolCheckPowerPageable);
|
|
|
|
deviceObject.SetObject(This->m_Device->GetDeviceObject());
|
|
flags = deviceObject.GetFlags();
|
|
|
|
if (flags & DO_POWER_PAGABLE) {
|
|
ASSERT((flags & DO_POWER_INRUSH) == 0);
|
|
|
|
return WdfDevStatePwrPolSleepingWakeWakeArrived;
|
|
}
|
|
else {
|
|
//
|
|
// DO_POWER_INRUSH also gets us to this state, but since it is mutually
|
|
// exclusive with DO_POWER_PAGABLE, we don't need to check for it
|
|
//
|
|
return WdfDevStatePwrPolSleepingWakeWakeArrivedNP;
|
|
}
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSleepingWakeWakeArrived(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device is in partial Dx (I/O has stopped) and will now be armed for wake.
|
|
Complete the going Dx transition by sending a PowerCompleteDx irp to the
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
ULONG wakeReason;
|
|
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolSleepingWakeWakeArrived);
|
|
|
|
ASSERT(This->PowerPolicyCanWakeFromSystemState(
|
|
This->PowerPolicyGetPendingSystemState()
|
|
));
|
|
|
|
wakeReason = This->PowerPolicyGetCurrentWakeReason();
|
|
|
|
status = This->m_PowerPolicyMachine.m_Owner->m_DeviceArmWakeFromSx.Invoke(
|
|
This->m_Device->GetHandle(),
|
|
FLAG_TO_BOOL(wakeReason, FxPowerPolicySxWakeDeviceEnabledFlag),
|
|
FLAG_TO_BOOL(wakeReason, FxPowerPolicySxWakeChildrenArmedFlag)
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
DoTraceLevelMessage(
|
|
This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"WDFDEVICE %p Failed to arm for wake from Sx, %!STATUS!",
|
|
This->m_Device->GetHandle(), status);
|
|
|
|
return WdfDevStatePwrPolSleepingWakeRevertArmWake;
|
|
}
|
|
|
|
//
|
|
// If the PDO is the Power Policy owner, then enable wake at bus, otherwise
|
|
// the power state machine will enable wake at bus.
|
|
//
|
|
if (This->m_Device->IsPdo()) {
|
|
status = This->PowerEnableWakeAtBusOverload();
|
|
if (!NT_SUCCESS(status)) {
|
|
DoTraceLevelMessage(
|
|
This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"WDFDEVICE %p Failed to Enable Wake at Bus, %!STATUS!",
|
|
This->m_Device->GetHandle(), status);
|
|
return WdfDevStatePwrPolSleepingWakeRevertArmWake;
|
|
}
|
|
}
|
|
|
|
This->PowerProcessEvent(PowerCompleteDx);
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSleepingWakeRevertArmWake(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolSleepingWakeRevertArmWake);
|
|
|
|
DoTraceLevelMessage(
|
|
This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"reverting arm for wake from Sx due to failure to allocate wait wake "
|
|
"request or wait wake request completed immeidately. Device will *NOT* "
|
|
"be armed for wake from Sx");
|
|
|
|
//
|
|
// Enable calls should be matched with Disable calls even in the failure
|
|
// cases. However, for the Enable wake at bus failure, we do not call the
|
|
// disable wake at bus method as we try to keep the failure behavior
|
|
// consistent with the Power State machine. Only the Device Disarm wake
|
|
// callback will be invoked here.
|
|
//
|
|
This->PowerPolicyDisarmWakeFromSx();
|
|
|
|
//
|
|
// attempt to cancel ww
|
|
//
|
|
if (This->PowerPolicyCancelWaitWake() == FALSE &&
|
|
This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
|
|
return WdfDevStatePwrPolSleepingNoWakeCompletePowerDown;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemAsleepWakeArmed(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemAsleepWakeArmed);
|
|
This->PowerPolicyCompleteSystemPowerIrp();
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemWakeDeviceWakeEnabled(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolSystemWakeDeviceWakeEnabled);
|
|
|
|
if (This->PowerPolicyCancelWaitWake() == FALSE &&
|
|
This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
|
|
return WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceled;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemWakeDeviceWakeInterruptFired(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolSystemWakeDeviceWakeInterruptFired);
|
|
|
|
//
|
|
// Make a note of the fact that system was woken by
|
|
// a wake interrupt of this device
|
|
//
|
|
This->m_SystemWokenByWakeInterrupt = TRUE;
|
|
|
|
if (This->PowerPolicyCancelWaitWake() == FALSE &&
|
|
This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
|
|
|
|
return WdfDevStatePwrPolSystemWakeDeviceWakeTriggered;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemWakeDeviceWakeEnabledWakeCanceled(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceled);
|
|
|
|
status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
COVERAGE_TRAP();
|
|
return WdfDevStatePwrPolDeviceD0PowerRequestFailed;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemWakeDeviceWakeDisarm(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolSystemWakeDeviceWakeDisarm);
|
|
|
|
//
|
|
// If the PDO is the Power Policy owner, then disable wake at bus, otherwise
|
|
// the power state machine will disable wake at bus.
|
|
//
|
|
if (This->m_Device->IsPdo()) {
|
|
This->PowerDisableWakeAtBusOverload();
|
|
}
|
|
|
|
This->PowerPolicyDisarmWakeFromSx();
|
|
|
|
return WdfDevStatePwrPolSystemWakeDeviceWakeCompletePowerUp;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemWakeDeviceWakeTriggeredS0(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredS0);
|
|
|
|
status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
COVERAGE_TRAP();
|
|
return WdfDevStatePwrPolDeviceD0PowerRequestFailed;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemWakeDeviceWokeDisarm(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolSystemWakeDeviceWokeDisarm);
|
|
|
|
//
|
|
// If the PDO is the Power Policy owner, then disable wake at bus, otherwise
|
|
// the power state machine will enable wake at bus.
|
|
//
|
|
if (This->m_Device->IsPdo()) {
|
|
This->PowerDisableWakeAtBusOverload();
|
|
}
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->m_DeviceWakeFromSxTriggered.Invoke(
|
|
This->m_Device->GetHandle()
|
|
);
|
|
|
|
This->PowerPolicyDisarmWakeFromSx();
|
|
|
|
return WdfDevStatePwrPolSystemWakeDeviceWakeCompletePowerUp;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSleepingWakeWakeArrivedNP(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device is in partial Dx (I/O has stopped) and will now be armed for wake.
|
|
Complete the going Dx transition by sending a PowerCompleteDx irp to the
|
|
power state machine.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
ULONG wakeReason;
|
|
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolSleepingWakeWakeArrivedNP);
|
|
|
|
ASSERT(This->PowerPolicyCanWakeFromSystemState(
|
|
This->PowerPolicyGetPendingSystemState()
|
|
));
|
|
|
|
wakeReason = This->PowerPolicyGetCurrentWakeReason();
|
|
|
|
status = This->m_PowerPolicyMachine.m_Owner->m_DeviceArmWakeFromSx.Invoke(
|
|
This->m_Device->GetHandle(),
|
|
FLAG_TO_BOOL(wakeReason, FxPowerPolicySxWakeDeviceEnabledFlag),
|
|
FLAG_TO_BOOL(wakeReason, FxPowerPolicySxWakeChildrenArmedFlag)
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
DoTraceLevelMessage(
|
|
This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"WDFDEVICE %p Failed to arm for wake from Sx, %!STATUS!",
|
|
This->m_Device->GetHandle(), status);
|
|
|
|
return WdfDevStatePwrPolSleepingWakeRevertArmWakeNP;
|
|
}
|
|
|
|
//
|
|
// If the PDO is the Power Policy owner, then enable wake at bus, otherwise
|
|
// the power state machine will enable wake at bus.
|
|
//
|
|
if (This->m_Device->IsPdo()) {
|
|
status = This->PowerEnableWakeAtBusOverload();
|
|
if (!NT_SUCCESS(status)) {
|
|
DoTraceLevelMessage(
|
|
This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"WDFDEVICE %p Failed to Enable Wake at Bus, %!STATUS!",
|
|
This->m_Device->GetHandle(), status);
|
|
return WdfDevStatePwrPolSleepingWakeRevertArmWakeNP;
|
|
}
|
|
}
|
|
|
|
This->PowerProcessEvent(PowerCompleteDx);
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSleepingWakeRevertArmWakeNP(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolSleepingWakeRevertArmWakeNP);
|
|
|
|
DoTraceLevelMessage(
|
|
This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"reverting arm for wake from Sx due to failure to allocate wait wake "
|
|
"request or wait wake request completed immeidately. Device will *NOT* "
|
|
"be armed for wake from Sx");
|
|
|
|
//
|
|
// Enable calls should be matched with Disable calls even in the failure
|
|
// cases. However, for the Enable wake at bus failure, we do not call the
|
|
// disable wake at bus method as we try to keep the failure behavior
|
|
// consistent with the Power State machine. Only the Device Disarm wake
|
|
// callback will be invoked here.
|
|
//
|
|
This->PowerPolicyDisarmWakeFromSx();
|
|
|
|
//
|
|
// attempt to cancel ww
|
|
//
|
|
if (This->PowerPolicyCancelWaitWake() == FALSE &&
|
|
This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
|
|
return WdfDevStatePwrPolSleepingNoWakeCompletePowerDown;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSleepingWakePowerDownFailed(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Power down failed in the power state machine. Cancel the wait wake irp
|
|
that was just sent down and revert the arming before moving to the failed
|
|
state.
|
|
|
|
Arguments:
|
|
This - instance of the state machine.
|
|
|
|
Return Value:
|
|
new state
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolSleepingWakePowerDownFailed);
|
|
|
|
if (This->PowerPolicyCancelWaitWake() == FALSE &&
|
|
This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
|
|
return WdfDevStatePwrPolSleepingWakePowerDownFailedWakeCanceled;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSleepingWakePowerDownFailedWakeCanceled(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Wait wake irp has been cancelled. Complete the Sx irp and goto the failed
|
|
state.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolSleepingWakePowerDownFailedWakeCanceled);
|
|
|
|
This->PowerPolicyCompleteSystemPowerIrp();
|
|
|
|
return WdfDevStatePwrPolDevicePowerRequestFailed;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemAsleepWakeArmedNP(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemAsleepWakeArmedNP);
|
|
|
|
This->PowerPolicyCompleteSystemPowerIrp();
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemWakeDeviceWakeEnabledNP(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemWakeDeviceWakeEnabledNP);
|
|
|
|
if (This->PowerPolicyCancelWaitWake() == FALSE &&
|
|
This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
|
|
return WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceledNP;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemWakeDeviceWakeInterruptFiredNP(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolSystemWakeDeviceWakeInterruptFiredNP);
|
|
|
|
//
|
|
// Make a notee of the fact that system was woken by
|
|
// a wake interrupt of this device
|
|
//
|
|
This->m_SystemWokenByWakeInterrupt = TRUE;
|
|
|
|
if (This->PowerPolicyCancelWaitWake() == FALSE &&
|
|
This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
|
|
return WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredNP;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemWakeDeviceWakeEnabledWakeCanceledNP(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceledNP);
|
|
|
|
status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
COVERAGE_TRAP();
|
|
return WdfDevStatePwrPolDeviceD0PowerRequestFailed;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemWakeDeviceWakeDisarmNP(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemWakeDeviceWakeDisarmNP);
|
|
|
|
//
|
|
// If the PDO is the Power Policy owner, then disable wake at bus, otherwise
|
|
// the power state machine will disable wake at bus.
|
|
//
|
|
if (This->m_Device->IsPdo()) {
|
|
This->PowerDisableWakeAtBusOverload();
|
|
}
|
|
|
|
This->PowerPolicyDisarmWakeFromSx();
|
|
|
|
return WdfDevStatePwrPolSystemWakeDeviceWakeCompletePowerUp;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemWakeDeviceWakeTriggeredS0NP(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredS0NP);
|
|
|
|
status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
COVERAGE_TRAP();
|
|
return WdfDevStatePwrPolDeviceD0PowerRequestFailed;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemWakeDeviceWokeDisarmNP(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemWakeDeviceWokeDisarmNP);
|
|
|
|
//
|
|
// If the PDO is the Power Policy owner, then disable wake at bus, otherwise
|
|
// the power state machine will disable wake at bus.
|
|
//
|
|
if (This->m_Device->IsPdo()) {
|
|
This->PowerDisableWakeAtBusOverload();
|
|
}
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->m_DeviceWakeFromSxTriggered.Invoke(
|
|
This->m_Device->GetHandle()
|
|
);
|
|
|
|
This->PowerPolicyDisarmWakeFromSx();
|
|
|
|
return WdfDevStatePwrPolSystemWakeDeviceWakeCompletePowerUp;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemWakeDeviceWakeCompletePowerUp(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The system went into Sx and the device was armed for wake. The system has
|
|
now returned to S0, the device has started the D0 transition, and the device
|
|
has been disarmed for wake. We must now complete the D0 transition by sending
|
|
PowerCompleteD0 to the power state machine.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This,
|
|
WdfDevStatePwrPolSystemWakeDeviceWakeCompletePowerUp);
|
|
|
|
//
|
|
// Simulate a device-power-required notification from the power framework.
|
|
// An S0-IRP is essentially equivalent to a device-power-required
|
|
// notification.
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.SimulateDevicePowerRequired();
|
|
|
|
//
|
|
// Notify the device-power-requirement state machine that we are powered on
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.DeviceIsPoweredOn();
|
|
|
|
This->PowerProcessEvent(PowerCompleteD0);
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSleeping(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The machine is going into Sx. Send a Dx irp to the stack. The "x" depends
|
|
on if the target system state is one which we can wake the system and
|
|
the device is enabled to wake from Sx.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS notifyPowerDownStatus;
|
|
SYSTEM_POWER_STATE systemState;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSleeping);
|
|
|
|
//
|
|
// If the bus/PDO is not in the hibernate path, then verify that all the
|
|
// children have powered down by now.
|
|
//
|
|
if (This->GetUsageCount(WdfSpecialFileHibernation) == 0 &&
|
|
This->m_PowerPolicyMachine.m_Owner->m_ChildrenPoweredOnCount > 0) {
|
|
DoTraceLevelMessage(
|
|
This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"WDFDEVICE %p powering down before child devices have powered down. "
|
|
"This usually indicates a faulty child device that completed the Sx "
|
|
"irp before sending the Dx irp",
|
|
This->m_Device->GetHandle());
|
|
|
|
FxVerifierBreakOnDeviceStateError(
|
|
This->m_Device->GetDriverGlobals());
|
|
}
|
|
|
|
//
|
|
// Simulate a device-power-not-required notification from the power
|
|
// framework. An Sx-IRP is essentially equivalent to a device-power-not-
|
|
// required notification.
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.SimulateDevicePowerNotRequired();
|
|
|
|
//
|
|
// Notify the device-power-requirement state machine that we are about to
|
|
// power down
|
|
//
|
|
notifyPowerDownStatus = This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.NotifyDevicePowerDown();
|
|
|
|
//
|
|
// We simulated a device-power-not-required notification before we notified
|
|
// the device-power-requirement state machine that we are powering down.
|
|
// Therefore, our notification should have succeeded.
|
|
//
|
|
ASSERT(NT_SUCCESS(notifyPowerDownStatus));
|
|
UNREFERENCED_PARAMETER(notifyPowerDownStatus);
|
|
|
|
systemState = This->PowerPolicyGetPendingSystemState();
|
|
|
|
if (This->PowerPolicyIsWakeEnabled() &&
|
|
This->PowerPolicyCanWakeFromSystemState(systemState)) {
|
|
return WdfDevStatePwrPolSleepingWakePowerDown;
|
|
}
|
|
else {
|
|
return WdfDevStatePwrPolSleepingNoWakePowerDown;
|
|
}
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSleepingNoWakePowerDown(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Machine is going into Sx and the device is not enabled to wake from Sx.
|
|
Request a D3 irp to put the device into a low power state.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
DEVICE_POWER_STATE dxState;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSleepingNoWakePowerDown);
|
|
|
|
dxState = (DEVICE_POWER_STATE)
|
|
This->m_PowerPolicyMachine.m_Owner->m_IdealDxStateForSx;
|
|
|
|
if (dxState != PowerDeviceD3) {
|
|
DEVICE_POWER_STATE dxMappedState;
|
|
|
|
//
|
|
// Get the lightest Dx state for this Sx state as reported by the
|
|
// device capabilities of the stack.
|
|
//
|
|
dxMappedState = _GetPowerCapState(
|
|
This->PowerPolicyGetPendingSystemState(),
|
|
This->m_PowerPolicyMachine.m_Owner->m_SystemToDeviceStateMap
|
|
);
|
|
|
|
//
|
|
// If the ideal desired state is lighter than what the S->D mapping says
|
|
// is the lightest supported D state, use the mapping value instead.
|
|
//
|
|
if (dxState < dxMappedState) {
|
|
dxState = dxMappedState;
|
|
}
|
|
}
|
|
|
|
ASSERT(dxState >= PowerDeviceD1 && dxState <= PowerDeviceD3);
|
|
|
|
status = This->PowerPolicyPowerDownForSx(dxState, Retry);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
COVERAGE_TRAP();
|
|
return WdfDevStatePwrPolSleepingNoWakeDxRequestFailed;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSleepingNoWakeCompletePowerDown(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The system has moved into Sx and the device is not armed for wake. The
|
|
device in partial Dx (I/O has stopped), transition the device into full
|
|
Dx by sending the PowerCompleteDx event to the power state machine.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This,
|
|
WdfDevStatePwrPolSleepingNoWakeCompletePowerDown);
|
|
|
|
This->PowerProcessEvent(PowerCompleteDx);
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSleepingNoWakeDxRequestFailed(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
COVERAGE_TRAP();
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSleepingNoWakeDxRequestFailed);
|
|
|
|
This->SetInternalFailure();
|
|
This->PowerPolicyCompleteSystemPowerIrp();
|
|
|
|
if (FALSE == This->m_ReleaseHardwareAfterDescendantsOnFailure) {
|
|
This->PnpProcessEvent(PnpEventPowerDownFailed);
|
|
}
|
|
|
|
return WdfDevStatePwrPolDevicePowerRequestFailed;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSleepingWakePowerDown(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The system is going into Sx and the device is set to arm itself for wake from
|
|
Sx. Start the power down process by requesting the Dx irp to stop I/O in
|
|
the power state machine.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSleepingWakePowerDown);
|
|
|
|
status = This->PowerPolicyPowerDownForSx(
|
|
This->m_PowerPolicyMachine.m_Owner->m_WakeSettings.DxState, NoRetry
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
COVERAGE_TRAP();
|
|
return WdfDevStatePwrPolSleepingNoWakePowerDown;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSleepingSendWake(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Machine is moving into an Sx state and the device is in a partial Dx (I/O
|
|
stopped) state. Send a wait wake request so that the device can be armed
|
|
for wake from Sx.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state
|
|
|
|
--*/
|
|
{
|
|
SYSTEM_POWER_STATE systemState;
|
|
NTSTATUS status;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSleepingSendWake);
|
|
|
|
//
|
|
// We are in a wake-enabled path, keep wake interrupts connected.
|
|
//
|
|
This->m_WakeInterruptsKeepConnected = TRUE;
|
|
|
|
//
|
|
// We use the deepest possible Sx state instead of the current Sx state so
|
|
// that we can handle the FastS4 case where PowerPolicyGetPendingSystemState
|
|
// would return, but we could possible goto S4. By using the deepest
|
|
// possible state, we can arm for any possible Sx state that we are capable
|
|
// of waking from.
|
|
//
|
|
systemState = This->PowerPolicyGetDeviceDeepestSystemWakeState();
|
|
|
|
status = This->PowerPolicySendWaitWakeRequest(systemState);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
DoTraceLevelMessage(
|
|
This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"Attempting to send wait wake request for EvtDeviceArmWakeFromSx() "
|
|
"failed, %!STATUS!", status);
|
|
|
|
COVERAGE_TRAP();
|
|
|
|
return WdfDevStatePwrPolSleepingNoWakeCompletePowerDown;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemAsleepNoWake(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemAsleepNoWake);
|
|
|
|
This->PowerPolicyCompleteSystemPowerIrp();
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemWakeDeviceWakeDisabled(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The machine is moving from Sx->S0 and the device was in Dx and not armed for
|
|
wake from Sx. Determine if the device should remain in Dx after the machine
|
|
has moved into S0.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemWakeDeviceWakeDisabled);
|
|
|
|
//
|
|
// We do not attempt to let the device remain in Dx if we are using system-
|
|
// managed idle timeout. This is because an S0 IRP is equivalent to a
|
|
// device-power-required notification from the power framework. In response
|
|
// to it, we need to power up the device and notify the power framework that
|
|
// the device is powered on.
|
|
//
|
|
if ((This->m_PowerPolicyMachine.m_Owner->
|
|
m_IdleSettings.m_TimeoutMgmt.UsingSystemManagedIdleTimeout() == FALSE)
|
|
&&
|
|
(This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.Enabled)
|
|
&&
|
|
(This->m_PowerPolicyMachine.m_Owner->
|
|
m_IdleSettings.WakeFromS0Capable == FALSE)
|
|
&&
|
|
(This->m_PowerPolicyMachine.m_Owner->
|
|
m_IdleSettings.PowerUpIdleDeviceOnSystemWake == FALSE)) {
|
|
|
|
return WdfDevStatePwrPolSystemWakeQueryIdle;
|
|
}
|
|
else {
|
|
return WdfDevStatePwrPolSystemWakeDeviceToD0;
|
|
}
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemWakeDeviceToD0(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemWakeDeviceToD0);
|
|
|
|
status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry);
|
|
if (!NT_SUCCESS(status)) {
|
|
COVERAGE_TRAP();
|
|
return WdfDevStatePwrPolDeviceD0PowerRequestFailed;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemWakeDeviceToD0CompletePowerUp(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The machine was in Sx and the device was not armed for wake from Sx. The
|
|
machine is moving back into S0 and the device is in partial D0 (HW has
|
|
started). Move the device into full D0 by sending the PowerCompleteD0
|
|
event to the power state machine.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolSystemWakeDeviceToD0CompletePowerUp);
|
|
|
|
//
|
|
// Simulate a device-power-not-required notification from the power
|
|
// framework. An S0-IRP is essentially equivalent to a device-power-required
|
|
// notification.
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.SimulateDevicePowerRequired();
|
|
|
|
//
|
|
// Notify the device-power-requirement state machine that we are powered on
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.DeviceIsPoweredOn();
|
|
|
|
This->PowerProcessEvent(PowerCompleteD0);
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSystemWakeQueryIdle(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemWakeQueryIdle);
|
|
|
|
//
|
|
// This state can be reached only if we are using driver-managed idle
|
|
// timeout.
|
|
//
|
|
ASSERT(
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_IdleSettings.m_TimeoutMgmt.UsingSystemManagedIdleTimeout() == FALSE
|
|
);
|
|
|
|
if (This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.QueryReturnToIdle()) {
|
|
return WdfDevStatePwrPolWaitingUnarmed;
|
|
}
|
|
else {
|
|
return WdfDevStatePwrPolSystemWakeDeviceToD0;
|
|
}
|
|
}
|
|
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStartedWakeCapable(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStartedWakeCapable);
|
|
|
|
//
|
|
// Enable the idle state machine. This will release any threads who are
|
|
// waiting for the device to return to D0.
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.EnableTimer();
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolWakeCapableDeviceIdle(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
We are now idle. Tell the active/idle state machine to move us to an idle
|
|
state.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN canPowerDown;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWakeCapableDeviceIdle);
|
|
|
|
canPowerDown = This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.DeclareComponentIdle();
|
|
|
|
//
|
|
// If we are using driver-managed idle timeout we can power down immediately
|
|
// and so we jump to the next state (that initiates power down) immediately.
|
|
// If we are using system-managed idle timeout, we wait in the current state
|
|
// for device-power-not-required notification.
|
|
//
|
|
return (canPowerDown ?
|
|
WdfDevStatePwrPolTimerExpiredDecideUsbSS :
|
|
WdfDevStatePwrPolNull);
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredDecideUsbSS(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Decides how to handle the idle timer firing. If the device is capable of
|
|
USB selective suspend, it will move the machine into that path. Otherwise,
|
|
the machine will be moved into the normal arm for wake while in D0 path.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolTimerExpiredWakeCapableUsbSS
|
|
or
|
|
WdfDevStatePwrPolTimerExpiredWakeCapable
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS notifyPowerDownStatus;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredDecideUsbSS);
|
|
|
|
//
|
|
// Notify the device power requirement state machine that we are about to
|
|
// power down.
|
|
//
|
|
notifyPowerDownStatus = This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.NotifyDevicePowerDown();
|
|
if (FALSE == NT_SUCCESS(notifyPowerDownStatus)) {
|
|
//
|
|
// We couldn't notify the device power requirement state machine that
|
|
// we are about to power down, because the "device-power-required"
|
|
// notification has already arrived. So we should not power down at this
|
|
// time. Revert back to the started state.
|
|
//
|
|
return WdfDevStatePwrPolDeviceIdleReturnToActive;
|
|
}
|
|
|
|
if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapable) {
|
|
return WdfDevStatePwrPolTimerExpiredWakeCapableUsbSS;
|
|
}
|
|
else {
|
|
return WdfDevStatePwrPolTimerExpiredWakeCapablePowerDown;
|
|
}
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDown(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device is enabled to be armed for wake from S0. The device just idled
|
|
out and is now about to transition into this state. The first step is to
|
|
move into a partial Dx state (I/O stopped), send the wake request, arm the
|
|
device, and then move into full Dx. This function starts the transition
|
|
by requesting a Dx irp.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN poweredDown;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDown);
|
|
|
|
poweredDown = This->PowerPolicyCanIdlePowerDown(
|
|
This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.DxState
|
|
);
|
|
|
|
if (poweredDown == FALSE) {
|
|
//
|
|
// Upon failure, revert back to the started state.
|
|
//
|
|
return WdfDevStatePwrPolTimerExpiredWakeCapableDxAllocFailed;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredWakeCapableSendWake(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolTimerExpiredWakeCapableSendWake);
|
|
|
|
//
|
|
// We are in a wake-enabled path, keep wake interrupts connected.
|
|
//
|
|
This->m_WakeInterruptsKeepConnected = TRUE;
|
|
|
|
status = This->PowerPolicySendWaitWakeRequest(PowerSystemWorking);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
DoTraceLevelMessage(
|
|
This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"Could not allocate wake request for wake from S0, revert arming,"
|
|
" %!STATUS!", status);
|
|
|
|
COVERAGE_TRAP();
|
|
|
|
return WdfDevStatePwrPolTimerExpiredWakeCapableCleanup;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredWakeCapableUsbSS(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Sends the selective suspend ready irp down to the USB parent
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredWakeCapableUsbSS);
|
|
|
|
This->PowerPolicySubmitUsbIdleNotification();
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolWakeCapableUsbSSCompleted(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
We've sent the USB idle notification, but the bus driver completed it even
|
|
before sending the USB idle callback.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWakeCapableUsbSSCompleted);
|
|
|
|
//
|
|
// We notified the device power requirement state machine that we are about
|
|
// to power down, but eventually we didn't power down. So notify the device
|
|
// power requirement state machine that the device should be considered
|
|
// powered on.
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.DeviceIsPoweredOn();
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.RequestComponentActive();
|
|
|
|
return WdfDevStatePwrPolStartedWakeCapable;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredWakeCapableWakeArrived(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device is has been armed for wake from S0. It is in a partial Dx state
|
|
(I/O stopped) and needs to transition to the total Dx state by sending
|
|
a PowerCompleteDx event to the power state machine.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolTimerExpiredWakeCapableWakeArrived);
|
|
|
|
status = This->m_PowerPolicyMachine.m_Owner->m_DeviceArmWakeFromS0.Invoke(
|
|
This->m_Device->GetHandle()
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return WdfDevStatePwrPolTimerExpiredWakeCapableCancelWake;
|
|
}
|
|
|
|
//
|
|
// If the PDO is the Power Policy owner, then enable wake at bus, otherwise
|
|
// the power state machine will enable wake at bus.
|
|
//
|
|
if (This->m_Device->IsPdo()) {
|
|
status = This->PowerEnableWakeAtBusOverload();
|
|
if (!NT_SUCCESS(status)) {
|
|
DoTraceLevelMessage(
|
|
This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"WDFDEVICE %p Failed to Enable Wake at Bus, %!STATUS!",
|
|
This->m_Device->GetHandle(), status);
|
|
|
|
return WdfDevStatePwrPolTimerExpiredWakeCapableCancelWake;
|
|
}
|
|
}
|
|
|
|
This->PowerProcessEvent(PowerCompleteDx);
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredWakeCapableCancelWake(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Device was attempting to enter Dx armed for wake from S0, but
|
|
EvtDeviceArmForWakeFromS0 returned failure. Cancel the wait wake irp and
|
|
move into Dx.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredWakeCapableCancelWake);
|
|
|
|
if (This->PowerPolicyCancelWaitWake() == FALSE) {
|
|
return WdfDevStatePwrPolTimerExpiredWakeCapableWakeCanceled;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredWakeCapableWakeCanceled(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device was put into a wake from S0 state and the arm failed. The wait
|
|
wake irp has been canceled, now complete the power down.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolTimerExpiredWakeCapableCleanup
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER(This);
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredWakeCapableWakeCanceled);
|
|
|
|
return WdfDevStatePwrPolTimerExpiredWakeCapableCleanup;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredWakeCapableCleanup(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
An attempt to arm the device for wake from S0 has failed. Decide if we need
|
|
to complete the USB SS callback or not before completely powering down so
|
|
that we can power back up again.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredWakeCapableCleanup);
|
|
|
|
if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapable) {
|
|
COVERAGE_TRAP();
|
|
This->m_PowerPolicyMachine.UsbSSCallbackProcessingComplete();
|
|
}
|
|
|
|
//
|
|
// Cancel UsbSS if present
|
|
//
|
|
if (This->PowerPolicyCancelUsbSSIfCapable()) {
|
|
//
|
|
// wait for Usbss completion event to move us from this state.
|
|
//
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
return WdfDevStatePwrPolTimerExpiredWakeCompletedPowerDown;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredWakeCapableDxAllocFailed(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device idled out and we attempted to allocate a Dx irp so that we could
|
|
be armed for wake from S0. The Dx irp allocation failed. Complete the
|
|
USB SS callback and move back into the working state.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolTimerExpiredWakeCapableUndoPowerDown
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolTimerExpiredWakeCapableDxAllocFailed);
|
|
|
|
if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapable) {
|
|
COVERAGE_TRAP();
|
|
This->m_PowerPolicyMachine.UsbSSCallbackProcessingComplete();
|
|
}
|
|
|
|
//
|
|
// cancel USB SS irp if capable
|
|
//
|
|
if (This->PowerPolicyCancelUsbSSIfCapable()) {
|
|
//
|
|
// wait for Usbss completion event to move us from this state.
|
|
//
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
return WdfDevStatePwrPolTimerExpiredWakeCapableUndoPowerDown;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredWakeCapableUndoPowerDown(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device idled out, but a failure occurred when we attempted to power
|
|
down. So we need to return to the active state now.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolDeviceIdleReturnToActive
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolTimerExpiredWakeCapableUndoPowerDown);
|
|
|
|
//
|
|
// We notified the device power requirement state machine that we are about
|
|
// to power down, but eventually we didn't power down. So notify the device
|
|
// power requirement state machine that the device should be considered
|
|
// powered on.
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.DeviceIsPoweredOn();
|
|
return WdfDevStatePwrPolDeviceIdleReturnToActive;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredWakeCompletedPowerDown(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Complete the Dx transition from Dx armed for S0 wake. Upon going into Dx,
|
|
we will move back into D0 since the wake completed already (or there was
|
|
an error in arming).
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolTimerExpiredWakeCompletedPowerDown);
|
|
|
|
This->PowerProcessEvent(PowerCompleteDx);
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredWakeCompletedPowerUp(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device was armed for wake from S0 and the wake completed immediately
|
|
(or there was a problem). We put the device into Dx and we are now trying
|
|
to bring it back into D0.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
BOOLEAN result;
|
|
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolTimerExpiredWakeCompletedPowerUp);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.RequestComponentActive();
|
|
|
|
//
|
|
// Disable the timer so that when we move back into D0, the timer is not
|
|
// automatically started. Since the timer has already fired, we should never
|
|
// get FALSE back (which indicates we should wait for the timer to fire).
|
|
//
|
|
result = This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer();
|
|
ASSERT(result);
|
|
UNREFERENCED_PARAMETER(result);
|
|
|
|
status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
//
|
|
// Couldn't allocate power irp, goto the failed state
|
|
//
|
|
COVERAGE_TRAP();
|
|
return WdfDevStatePwrPolDeviceD0PowerRequestFailed;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredWakeCompletedHardwareStarted(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
We went idle and were in the process of powering down, but the wait-wake IRP
|
|
completed even before we could arm the device for wake. We finished powering
|
|
down the device and we're now powering it back up due to the wait-wake
|
|
completion.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This,
|
|
WdfDevStatePwrPolTimerExpiredWakeCompletedHardwareStarted);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.DeviceIsPoweredOn();
|
|
|
|
return WdfDevStatePwrPolS0WakeCompletePowerUp;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolWaitingArmedUsbSS(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Complete the USB SS callback now tha the device is armed and in Dx
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolWaitingArmed
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN result;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWaitingArmedUsbSS);
|
|
|
|
if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapable) {
|
|
This->m_PowerPolicyMachine.UsbSSCallbackProcessingComplete();
|
|
}
|
|
|
|
//
|
|
// Disable the timer so that when we move back into D0, the timer is not
|
|
// automatically started. Since the timer has already fired, we should never
|
|
// get FALSE back (which indicates we should wait for the timer to fire).
|
|
//
|
|
result = This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer();
|
|
ASSERT(result);
|
|
UNREFERENCED_PARAMETER(result);
|
|
|
|
//
|
|
// PwrPolIoPresent can be sent before PwrPolPowerTimeoutExpired in the idle
|
|
// state machine if the idle s.m. attempts to cancel the timer after it has
|
|
// started running. That means the PwrPolIoPresent meant to wake up the
|
|
// device and resume from idle is lost. By first querying the idle s.m.
|
|
// after moving into Dx we can recover from the lost event.
|
|
//
|
|
return WdfDevStatePwrPolWaitingArmedQueryIdle;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolWaitingArmedQueryIdle(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device was in the WaitingArmed state and received a PwrPolIoPresent
|
|
event. Before committing the device to move back to D0, check to see if
|
|
the device has returned to an idle state. This can easily happen if the
|
|
driver causes a power reference in D0Exit accidentally and the power
|
|
reference is removed before exitting the function.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// If QueryReturnToIdle returns TRUE, return to the waiting state
|
|
//
|
|
if (This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.QueryReturnToIdle()) {
|
|
return WdfDevStatePwrPolWaitingArmed;
|
|
}
|
|
else {
|
|
return WdfDevStatePwrPolWaitingArmedIoPresentCancelUsbSS;
|
|
}
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolIoPresentArmed(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolIoPresentArmed);
|
|
|
|
if (This->PowerPolicyCancelWaitWake() == FALSE &&
|
|
This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
|
|
COVERAGE_TRAP();
|
|
return WdfDevStatePwrPolIoPresentArmedWakeCanceled;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolWaitingArmedWakeInterruptFired(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWaitingArmedWakeInterruptFired);
|
|
|
|
if (This->PowerPolicyCancelWaitWake() == FALSE &&
|
|
This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
|
|
return WdfDevStatePwrPolWaitingArmedWakeSucceededCancelUsbSS;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolIoPresentArmedWakeCanceled(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolIoPresentArmedWakeCanceled);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.RequestComponentActive();
|
|
|
|
status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
COVERAGE_TRAP();
|
|
return WdfDevStatePwrPolDeviceD0PowerRequestFailed;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolS0WakeDisarm(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolS0WakeDisarm);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.DeviceIsPoweredOn();
|
|
|
|
//
|
|
// If the PDO is the Power Policy owner, then disable wake at bus, otherwise
|
|
// the power state machine will disable wake at bus.
|
|
//
|
|
if (This->m_Device->IsPdo()) {
|
|
This->PowerDisableWakeAtBusOverload();
|
|
}
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->m_DeviceDisarmWakeFromS0.Invoke(
|
|
This->m_Device->GetHandle()
|
|
);
|
|
|
|
return WdfDevStatePwrPolS0WakeCompletePowerUp;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolS0WakeCompletePowerUp(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
We are moving back into D0 from being armed for wake from S0. The device
|
|
is in partial D0 (hw started) already, so complete the transition to D0
|
|
by posting the PowerCompleteD0 event to the power state machine.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolS0WakeCompletePowerUp);
|
|
|
|
This->PowerProcessEvent(PowerCompleteD0);
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredWakeSucceeded(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The wake irp succeeded synchronously when we sent it down the stack. Notify
|
|
the driver and move immediately back into the working state.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolStartingDecideS0Wake
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredWakeSucceeded);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->m_DeviceWakeFromS0Triggered.Invoke(
|
|
This->m_Device->GetHandle()
|
|
);
|
|
|
|
return WdfDevStatePwrPolTimerExpiredWakeCompletedDisarm;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredWakeCompletedDisarm(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device was armed for wake from Dx in S0. The wake irp completed
|
|
before the PwrPolPowerDown was processed. Disarm the device, move to Dx,
|
|
and then immediately back to D0.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolTimerExpiredWakeCapableCleanup
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredWakeCompletedDisarm);
|
|
|
|
//
|
|
// If the PDO is the Power Policy owner, then disable wake at bus, otherwise
|
|
// the power state machine will disable wake at bus.
|
|
//
|
|
if (This->m_Device->IsPdo()) {
|
|
This->PowerDisableWakeAtBusOverload();
|
|
}
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->m_DeviceDisarmWakeFromS0.Invoke(
|
|
This->m_Device->GetHandle()
|
|
);
|
|
|
|
return WdfDevStatePwrPolTimerExpiredWakeCapableCleanup;
|
|
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolWakeFailedUsbSS(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Wake failed before we got the Dx irp. Complete the SS calback and then
|
|
move to the WakeFailed state.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolIoPresentArmedWakeCanceled
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN result;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWakeFailedUsbSS);
|
|
|
|
if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapable) {
|
|
This->m_PowerPolicyMachine.UsbSSCallbackProcessingComplete();
|
|
}
|
|
|
|
//
|
|
// Disable the timer so that when we move back into D0, the timer is not
|
|
// automatically started. Since the timer has already fired, we should never
|
|
// get FALSE back (which indicates we should wait for the timer to fire).
|
|
//
|
|
result = This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer();
|
|
ASSERT(result);
|
|
UNREFERENCED_PARAMETER(result);
|
|
|
|
//
|
|
// cancel USB SS irp if capable
|
|
//
|
|
if (This->PowerPolicyCancelUsbSSIfCapable()) {
|
|
//
|
|
// wait for Usbss completion event to move us from this state.
|
|
//
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
return WdfDevStatePwrPolIoPresentArmedWakeCanceled;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDownFailedCancelWake(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
We sent the wake request, but the power state machine failed. Cancel the
|
|
wake request and then move to the failed state.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This,
|
|
WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedCancelWake);
|
|
|
|
if (This->PowerPolicyCancelWaitWake() == FALSE) {
|
|
return WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The wake request has been canceled. Move to the state where we will decide
|
|
if we need to complete the USB SS callback.
|
|
|
|
There is no need to disarm for wake from S0 because the failure here is for
|
|
the device to power down. We must assume the device is now in Dx and we
|
|
cannot touch hw in this state.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedDecideUsbSS
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER(This);
|
|
|
|
ASSERT_PWR_POL_STATE(
|
|
This,
|
|
WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled);
|
|
|
|
return WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedUsbSS;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDownFailedUsbSS(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Complete the USB SS callback if enabled and the move to the failed state
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state, WdfDevStatePwrPolDevicePowerRequestFailed
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedUsbSS);
|
|
|
|
if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapable) {
|
|
This->m_PowerPolicyMachine.UsbSSCallbackProcessingComplete();
|
|
}
|
|
|
|
if (This->PowerPolicyCancelUsbSSIfCapable()) {
|
|
//
|
|
// wait for Usbss completion event to move us from this state.
|
|
//
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
return WdfDevStatePwrPolDevicePowerRequestFailed;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolCancelingWakeForSystemSleep(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolCancelingWakeForSystemSleep);
|
|
|
|
if (This->PowerPolicyCancelWaitWake() == FALSE &&
|
|
This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
|
|
return WdfDevStatePwrPolCancelingWakeForSystemSleepWakeCanceled;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolCancelingWakeForSystemSleepWakeCanceled(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolCancelingWakeForSystemSleepWakeCanceled);
|
|
|
|
status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, NoRetry);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
COVERAGE_TRAP();
|
|
return WdfDevStatePwrPolPowerUpForSystemSleepNotSeen;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolDisarmingWakeForSystemSleepCompletePowerUp(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device was armed for wake from S0 and in Dx. The machine is now moving
|
|
into Sx. The device is currently in partial D0 (HW started). Disarm wake
|
|
from S0 and then move the device fully into D0 (I/0 started).
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolDisarmingWakeForSystemSleepCompletePowerUp);
|
|
|
|
//
|
|
// If the PDO is the Power Policy owner, then disable wake at bus, otherwise
|
|
// the power state machine will disable wake at bus.
|
|
//
|
|
if (This->m_Device->IsPdo()) {
|
|
This->PowerDisableWakeAtBusOverload();
|
|
}
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->m_DeviceDisarmWakeFromS0.Invoke(
|
|
This->m_Device->GetHandle()
|
|
);
|
|
|
|
This->PowerProcessEvent(PowerCompleteD0);
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolPowerUpForSystemSleepFailed(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The system is moving into an Sx state and the device was in a Dx armed for
|
|
wake from S0 state. Power up has failed (could not allocate the request,
|
|
actual power up path failed, etc). Complete the Sx irp and move into a
|
|
state where we can be removed when we return to S0.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolDevicePowerRequestFailed
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolPowerUpForSystemSleepFailed);
|
|
|
|
This->PowerPolicyCompleteSystemPowerIrp();
|
|
|
|
return WdfDevStatePwrPolDevicePowerRequestFailed;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolWokeFromS0UsbSS(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device successfully woke up before we got to the WaitingArmed state.
|
|
Complete the USB SS callback while we are in Dx.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolWokeFromS0
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN result;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWokeFromS0UsbSS);
|
|
|
|
if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapable) {
|
|
This->m_PowerPolicyMachine.UsbSSCallbackProcessingComplete();
|
|
}
|
|
|
|
//
|
|
// Disable the timer so that when we move back into D0, the timer is not
|
|
// automatically started. Since the timer has already fired, we should never
|
|
// get FALSE back (which indicates we should wait for the timer to fire).
|
|
//
|
|
result = This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer();
|
|
ASSERT(result);
|
|
UNREFERENCED_PARAMETER(result);
|
|
|
|
//
|
|
// Cancel USBSS irp if capable
|
|
//
|
|
if (This->PowerPolicyCancelUsbSSIfCapable()) {
|
|
//
|
|
// Usbss completion event will move us from this state.
|
|
//
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
return WdfDevStatePwrPolWokeFromS0;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolWokeFromS0(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWokeFromS0);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.RequestComponentActive();
|
|
|
|
status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry);
|
|
if (!NT_SUCCESS(status)) {
|
|
COVERAGE_TRAP();
|
|
return WdfDevStatePwrPolDeviceD0PowerRequestFailed;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolWokeFromS0NotifyDriver(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device was armed for wake from S0 and it successfully woke up and triggered
|
|
wake. Notify the driver of this on the way back up to D0.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolS0WakeDisarm
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWokeFromS0NotifyDriver);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->m_DeviceWakeFromS0Triggered.Invoke(
|
|
This->m_Device->GetHandle()
|
|
);
|
|
|
|
return WdfDevStatePwrPolS0WakeDisarm;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStoppingResetDevice(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device was in a Dx state, unarmed for wake. The device is not being
|
|
removed, so we must disable the idle timer and power up the device so that
|
|
we can implicitly power it down.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new state
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
BOOLEAN result;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingResetDevice);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.RequestComponentActive();
|
|
|
|
result = This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer();
|
|
ASSERT(result);
|
|
UNREFERENCED_PARAMETER(result);
|
|
|
|
status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
COVERAGE_TRAP();
|
|
return WdfDevStatePwrPolDeviceD0PowerRequestFailed;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStoppingResetDeviceCompletePowerUp(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device was idled out and in Dx (not armed for wake from S0). The power
|
|
policy state machine is being stopped and the device has been brought into
|
|
partial D0 (HW started). Complete the D0 transition by sending PowerCompleteD0
|
|
to the power state machine.
|
|
|
|
Arguments:
|
|
This - Instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolStoppingResetDeviceCompletePowerUp);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.DeviceIsPoweredOn();
|
|
|
|
This->PowerProcessEvent(PowerCompleteD0);
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStoppingResetDeviceFailed(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The attempt to power on a device in the idled out state so that we can stop
|
|
the power policy state machine failed. Record the error and continue down
|
|
the stop path.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolStopping
|
|
|
|
--*/
|
|
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingResetDeviceFailed);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->m_PowerFailed = TRUE;
|
|
|
|
//
|
|
// Notify the device power requirement state machine that the device should
|
|
// be considered powered on, although it is not. Doing this will ensure that
|
|
// component activation before device removal will succeed.
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.DeviceIsPoweredOn();
|
|
|
|
return WdfDevStatePwrPolStopping;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStoppingD0(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingD0);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.RequestComponentActive();
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer();
|
|
|
|
status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry);
|
|
if (!NT_SUCCESS(status)) {
|
|
COVERAGE_TRAP();
|
|
return WdfDevStatePwrPolDeviceD0PowerRequestFailed;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStoppingD0Failed(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
While attempting to stop the device and bring it into D0, power up failed.
|
|
Record the error and continue.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolStoppingDisarmWakeCancelWake
|
|
|
|
--*/
|
|
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingD0Failed);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->m_PowerFailed = TRUE;
|
|
|
|
//
|
|
// Notify the device power requirement state machine that the device should
|
|
// be considered powered on, although it is not. Doing this will ensure that
|
|
// component activation before device removal will succeed.
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.DeviceIsPoweredOn();
|
|
|
|
return WdfDevStatePwrPolStoppingDisarmWakeCancelWake;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStoppingDisarmWake(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingDisarmWake);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.DeviceIsPoweredOn();
|
|
|
|
//
|
|
// If the PDO is the Power Policy owner, then disable wake at bus, otherwise
|
|
// the power state machine will disable wake at bus.
|
|
//
|
|
if (This->m_Device->IsPdo()) {
|
|
This->PowerDisableWakeAtBusOverload();
|
|
}
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->m_DeviceDisarmWakeFromS0.Invoke(
|
|
This->m_Device->GetHandle()
|
|
);
|
|
|
|
This->PowerProcessEvent(PowerCompleteD0);
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStoppingDisarmWakeCancelWake(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingDisarmWakeCancelWake);
|
|
|
|
if (This->PowerPolicyCancelWaitWake() == FALSE &&
|
|
This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
|
|
return WdfDevStatePwrPolStoppingDisarmWakeWakeCanceled;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStoppingDisarmWakeWakeCanceled(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(This);
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingDisarmWakeWakeCanceled);
|
|
|
|
return WdfDevStatePwrPolStopping;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStopping(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStopping);
|
|
|
|
//
|
|
// Prevent any children from powering up. Technically this is not necessary
|
|
// because if we are getting to this point, all of our children have already
|
|
// been implicitly stopped as well, but this keeps the child power up state
|
|
// consistent with the power policy state.
|
|
//
|
|
This->PowerPolicyBlockChildrenPowerUp();
|
|
|
|
//
|
|
// This power change event does not need to be synchronous
|
|
//
|
|
This->PowerProcessEvent(PowerImplicitD3);
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStoppingFailed(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The attempt to move the power state machine into a Dx state failed. Report
|
|
the failure to pnp and move to the stopped state.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolStopped
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingFailed);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->m_PowerFailed = TRUE;
|
|
|
|
return WdfDevStatePwrPolStoppingSendStatus;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStoppingSendStatus(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The power policy machine is about to finish stopping. The final act of
|
|
stopping is notify the Pnp state machine of the final outcome. Do so, reset
|
|
state, and move to the stopped state.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolStopped
|
|
|
|
--*/
|
|
{
|
|
KIRQL irql;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingSendStatus);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.Stop();
|
|
|
|
//
|
|
// We raise IRQL to dispatch level so that pnp is forced onto its own thread
|
|
// to process the PwrPolStopped event. If pnp is on the power thread when
|
|
// it processes the event and it tries to delete the dedicated thread, it
|
|
// will deadlock waiting for the thread its on to exit.
|
|
//
|
|
Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql);
|
|
This->PnpProcessEvent(
|
|
This->m_PowerPolicyMachine.m_Owner->m_PowerFailed
|
|
? PnpEventPwrPolStopFailed
|
|
: PnpEventPwrPolStopped
|
|
);
|
|
Mx::MxLowerIrql(irql);
|
|
|
|
//
|
|
// Reset back to a non failed state
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->m_PowerFailed = FALSE;
|
|
|
|
return WdfDevStatePwrPolStopped;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStoppedRemoving(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device is being removed. Tell the active/idle state machine to
|
|
unregister with the power framework.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppedRemoving);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.UninitializeComponents();
|
|
|
|
return WdfDevStatePwrPolRemoved;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolRemoved(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The active/idle state machine has unregistered with the power framework.
|
|
Tell the PNP state machine that device removal can proceed.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
KIRQL irql;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolRemoved);
|
|
|
|
//
|
|
// We raise IRQL to dispatch level so that pnp is forced onto its own thread
|
|
// to process the PwrPolRemoved event. If pnp is on the power thread when
|
|
// it processes the event and it tries to delete the dedicated thread, it
|
|
// will deadlock waiting for the thread it is on to exit.
|
|
//
|
|
Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql);
|
|
This->PnpProcessEvent(PnpEventPwrPolRemoved);
|
|
Mx::MxLowerIrql(irql);
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolRestarting(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device is restarting after being stopped
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolRestarting);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.Start();
|
|
|
|
This->PowerProcessEvent(PowerImplicitD0);
|
|
|
|
//
|
|
// Wait for the successful power up before starting any idle timers. If
|
|
// the power up fails, we will not send a power policy stop from the pnp
|
|
// engine.
|
|
//
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolRestartingFailed(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Power up failed when restarting the device
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolStopped
|
|
|
|
--*/
|
|
{
|
|
KIRQL irql;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolRestartingFailed);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.Stop();
|
|
|
|
//
|
|
// We raise IRQL to dispatch level so that pnp is forced onto its own thread
|
|
// to process the PwrPolStartFailed event. If pnp is on the power thread
|
|
// when it processes the event and it tries to delete the dedicated thread,
|
|
// it will deadlock waiting for the thread it is on to exit.
|
|
//
|
|
Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql);
|
|
This->PnpProcessEvent(PnpEventPwrPolStartFailed);
|
|
Mx::MxLowerIrql(irql);
|
|
|
|
return WdfDevStatePwrPolStopped;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStoppingCancelTimer(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Moving to the stopping state. Need to cancel the idle timeout timer.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new power policy state
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingCancelTimer);
|
|
|
|
if (This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer()) {
|
|
return WdfDevStatePwrPolStopping;
|
|
}
|
|
else {
|
|
//
|
|
// Timer was not canceled, move to the state where we wait for the
|
|
// timeout event to be posted.
|
|
//
|
|
return WdfDevStatePwrPolStoppingWaitForIdleTimeout;
|
|
}
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStoppingCancelUsbSS(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Cancel the USB SS request because we are being stopped or surprise removed
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolStoppingWaitForUsbSSCompletion
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingCancelUsbSS);
|
|
|
|
//
|
|
// We notified the device power requirement state machine that we are about
|
|
// to power down, but eventually we didn't power down. So notify the device
|
|
// power requirement state machine that the device should be considered
|
|
// powered on.
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.DeviceIsPoweredOn();
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.RequestComponentActive();
|
|
|
|
if (This->PowerPolicyCancelUsbSSIfCapable() == FALSE) {
|
|
//
|
|
// UsbSS already canceled/completed
|
|
//
|
|
return WdfDevStatePwrPolStoppingCancelTimer;
|
|
}
|
|
|
|
return WdfDevStatePwrPolStoppingWaitForUsbSSCompletion;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStoppingCancelWake(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Cancels the pended wait wake in the case where we are surprise removed and
|
|
in a Dx state and armed for wake.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
If there was no request to cancel, WdfDevStatePwrPolStopping. If there was,
|
|
wait for the wait completion event to be posted before transitioning.
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingCancelWake);
|
|
|
|
if (This->PowerPolicyCancelWaitWake() == FALSE &&
|
|
This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
|
|
COVERAGE_TRAP();
|
|
return WdfDevStatePwrPolStopping;
|
|
}
|
|
else {
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolCancelUsbSS(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The S0 idle policy has changed. Cancel the idle notification so we can move
|
|
to another S0 started state
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolCancelUsbSS);
|
|
|
|
//
|
|
// We notified the device power requirement state machine that we are about
|
|
// to power down, but eventually we didn't power down. So notify the device
|
|
// power requirement state machine that the device should be considered
|
|
// powered on.
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.DeviceIsPoweredOn();
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.RequestComponentActive();
|
|
|
|
if (This->PowerPolicyCancelUsbSSIfCapable() == FALSE) {
|
|
//
|
|
// UsbSS has already been canceled/completed
|
|
//
|
|
return WdfDevStatePwrPolStartedCancelTimer;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStarted(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device is now in the started state (w/regard to power policy).
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStarted);
|
|
|
|
//
|
|
// We signal we are in D0 even though there is idling out in this state
|
|
// because we could have just come from a state which *was* idled out.
|
|
// For instance
|
|
// 1) We are in WaitingArmed and an io present event moved us out of this state
|
|
// 2) Immediately afterward, the s0 idle policy was changed
|
|
// 3) When we enter StartingDecideS0Wake, we will move into this state without
|
|
// first entering StartedWakeCapable.
|
|
// 4) The source of the io present event, if waiting synchronously needs to
|
|
// be unblocked.
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer();
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStartedCancelTimer(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Device is started and we need to cancel the idle timer
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new power policy state
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStartedCancelTimer);
|
|
|
|
if (This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer()) {
|
|
return WdfDevStatePwrPolStartingDecideS0Wake;
|
|
}
|
|
else {
|
|
COVERAGE_TRAP();
|
|
return WdfDevStatePwrPolStartedWaitForIdleTimeout;
|
|
}
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStartedWakeCapableCancelTimerForSleep(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Device is wake capable and enabled for idling out. Try to disable the
|
|
power idle state machine.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new power policy state
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolStartedWakeCapableCancelTimerForSleep);
|
|
|
|
if (This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer()) {
|
|
return WdfDevStatePwrPolSleeping;
|
|
}
|
|
else {
|
|
COVERAGE_TRAP();
|
|
return WdfDevStatePwrPolStartedWakeCapableWaitForIdleTimeout;
|
|
}
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStartedWakeCapableSleepingUsbSS(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The machine is going to sleep after we have submitted the USB SS request
|
|
but before USB has called us back on the go to idle callback. Cancel the
|
|
request and wait for its completion
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPol
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN result;
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStartedWakeCapableSleepingUsbSS);
|
|
|
|
result = This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer();
|
|
|
|
//
|
|
// Since the power timeout expired, the disable should not return FALSE
|
|
//
|
|
ASSERT(result);
|
|
UNREFERENCED_PARAMETER(result);
|
|
|
|
//
|
|
// Cancel USBSS irp
|
|
//
|
|
This->PowerPolicyCancelUsbSS();
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStartedIdleCapableCancelTimerForSleep(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Device is idle capable and enabled for idling out. Try to disable the
|
|
power idle state machine.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
new power policy state
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolStartedIdleCapableCancelTimerForSleep);
|
|
|
|
if (This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer()) {
|
|
return WdfDevStatePwrPolSleeping;
|
|
}
|
|
else {
|
|
COVERAGE_TRAP();
|
|
return WdfDevStatePwrPolStartedIdleCapableWaitForIdleTimeout;
|
|
}
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolDeviceD0PowerRequestFailed(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
A D0 request failed, notify pnp.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolDevicePowerRequestFailed
|
|
|
|
--*/
|
|
{
|
|
COVERAGE_TRAP();
|
|
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolDeviceD0PowerRequestFailed);
|
|
|
|
This->SetInternalFailure();
|
|
|
|
if (FALSE == This->m_ReleaseHardwareAfterDescendantsOnFailure) {
|
|
This->PnpProcessEvent(PnpEventPowerUpFailed);
|
|
}
|
|
|
|
return WdfDevStatePwrPolDevicePowerRequestFailed;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolDevicePowerRequestFailed(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Either we could not allocate a device power irp or the power state machine
|
|
reported failure. Mark the failure and then wait for pnp to send a stop
|
|
event.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolDevicePowerRequestFailed);
|
|
|
|
//
|
|
// In the failure path we still need to notify the children that they can
|
|
// power up so that they will unblock.
|
|
//
|
|
This->PowerPolicyChildrenCanPowerUp();
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->m_PowerFailed = TRUE;
|
|
|
|
//
|
|
// Notify the device power requirement state machine that the device should
|
|
// be considered powered on, although it may not be in reality. Doing this
|
|
// will ensure that component activation before device removal will succeed.
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.DeviceIsPoweredOn();
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolSleepingPowerDownNotProcessed(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
We requested a Dx irp but a driver layered above our device failed the
|
|
request without sending it down the stack. Queue a Tear down the stack and
|
|
then move into a state where we will complete the Sx irp.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolSystemSleepPowerRequestFailed
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSleepingPowerDownNotProcessed);
|
|
|
|
This->SetInternalFailure();
|
|
|
|
return WdfDevStatePwrPolSystemSleepPowerRequestFailed;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDownNotProcessed(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
We requested a Dx irp after idling out, but a driver layered above our device
|
|
failed the request without sending it down the stack. Queue a tear down the
|
|
stack and then move into a state where we can handle tear down.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolTimerExpiredWakeCapableDxAllocFailed
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownNotProcessed);
|
|
|
|
This->SetInternalFailure();
|
|
|
|
return WdfDevStatePwrPolTimerExpiredWakeCapableDxAllocFailed;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredNoWakePowerDownNotProcessed(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
We requested a Dx irp after idling out, but a driver layered above our device
|
|
failed the request without sending it down the stack. Queue a tear down the
|
|
stack and then move into a state where we can handle tear down.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolStartedIdleCapable
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolTimerExpiredNoWakePowerDownNotProcessed);
|
|
|
|
This->SetInternalFailure();
|
|
|
|
return WdfDevStatePwrPolTimerExpiredNoWakeUndoPowerDown;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredNoWakeUndoPowerDown(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device was idle and attempting to go to Dx (without wake-from-S0), but
|
|
a power down failure occurred.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolTimerExpiredNoWakeUndoPowerDown);
|
|
|
|
//
|
|
// We notified the device power requirement state machine that we are about
|
|
// to power down, but eventually we didn't power down. So notify the device
|
|
// power requirement state machine that the device should be considered
|
|
// powered on.
|
|
//
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.DeviceIsPoweredOn();
|
|
|
|
return WdfDevStatePwrPolTimerExpiredNoWakeReturnToActive;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredNoWakeReturnToActive(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device was idle and attempting to go to Dx (without wake-from-S0), but
|
|
eventually it did not go to Dx. This might have been because a power down
|
|
failure occurred or because we received the device power required
|
|
notification from the power framework before we could go to Dx.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolNull
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolTimerExpiredNoWakeReturnToActive);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->
|
|
m_PoxInterface.RequestComponentActive();
|
|
|
|
return WdfDevStatePwrPolStartedIdleCapable;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredNoWakePoweredDownDisableIdleTimer(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device has fully powered down. Disable the idle timer so that when we
|
|
we power up the idle timer will not start running immediately. Rather,
|
|
we should power up and only start the idle timer after being explicitly
|
|
enabled again.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolWaitingUnarmedQueryIdle
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN result;
|
|
|
|
ASSERT_PWR_POL_STATE(
|
|
This, WdfDevStatePwrPolTimerExpiredNoWakePoweredDownDisableIdleTimer);
|
|
|
|
//
|
|
// Disable the timer so that when we move back into D0, the timer is not
|
|
// automatically started. Since the timer has already fired, we should never
|
|
// get FALSE back (which indicates we should wait for the timer to fire).
|
|
//
|
|
result = This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer();
|
|
ASSERT(result);
|
|
UNREFERENCED_PARAMETER(result);
|
|
|
|
//
|
|
// Check to see if we should immediately power up
|
|
//
|
|
return WdfDevStatePwrPolWaitingUnarmedQueryIdle;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolPowerUpForSystemSleepNotSeen(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
PowerDeviceD0 request was not forwarded to this driver by upper driver even
|
|
though this driver requested it. Power completion routine detects this
|
|
condition, and causes transition to this state. Ensure that any pending
|
|
S-IRP is completed.
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolDeviceD0PowerRequestFailed
|
|
|
|
--*/
|
|
{
|
|
if (This->m_PendingSystemPowerIrp != NULL) {
|
|
This->PowerPolicyCompleteSystemPowerIrp();
|
|
}
|
|
|
|
return WdfDevStatePwrPolDeviceD0PowerRequestFailed;
|
|
}
|
|
|
|
__drv_sameIRQL
|
|
VOID
|
|
FxPkgPnp::_PowerPolDeviceWaitWakeComplete(
|
|
__in MdDeviceObject DeviceObject,
|
|
__in UCHAR MinorFunction,
|
|
__in POWER_STATE PowerState,
|
|
__in_opt PVOID Context,
|
|
__in PIO_STATUS_BLOCK IoStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Completion routine for a requested wait wake irp. Called once the wait wake
|
|
irp has traveled through the entire stack or when some driver in the stack
|
|
completes the wait wake irp. We feed the result of the wait wake operation
|
|
back into the power policy state machine through an event.
|
|
|
|
Arguments:
|
|
Context - instance of the state machine
|
|
IoStatus - pointer to the IO_STATUS_BLOCK structure for the completed IRP
|
|
All others ignored
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
FxPkgPnp* pThis;
|
|
|
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|
UNREFERENCED_PARAMETER(MinorFunction);
|
|
UNREFERENCED_PARAMETER(PowerState);
|
|
|
|
pThis = (FxPkgPnp*) Context;
|
|
pThis->m_PowerPolicyMachine.m_Owner->m_WaitWakeStatus = IoStatus->Status;
|
|
|
|
if (NT_SUCCESS(IoStatus->Status)) {
|
|
pThis->PowerPolicyProcessEvent(PwrPolWakeSuccess);
|
|
}
|
|
else {
|
|
pThis->PowerPolicyProcessEvent(PwrPolWakeFailed);
|
|
}
|
|
}
|
|
|
|
__drv_sameIRQL
|
|
VOID
|
|
FxPkgPnp::_PowerPolDevicePowerDownComplete(
|
|
__in MdDeviceObject DeviceObject,
|
|
__in UCHAR MinorFunction,
|
|
__in POWER_STATE PowerState,
|
|
__in_opt PVOID Context,
|
|
__in PIO_STATUS_BLOCK IoStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Completion routine for a requested power irp. Called once the power irp
|
|
has traveled through the entire stack. We feed the result of the power
|
|
operation back into the power policy state machine through an event.
|
|
|
|
Arguments:
|
|
Context - instance of the state machine
|
|
All others ignored
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
FxPkgPnp* pThis;
|
|
|
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|
UNREFERENCED_PARAMETER(MinorFunction);
|
|
UNREFERENCED_PARAMETER(PowerState);
|
|
UNREFERENCED_PARAMETER(IoStatus);
|
|
|
|
pThis = (FxPkgPnp*) Context;
|
|
|
|
//
|
|
// Note that we are ignoring IoStatus.Status intentionally. If we failed
|
|
// power down in this device, we have tracked that state via
|
|
// m_PowerDownFailure. If some other device failed power down, we are still
|
|
// in the state where we succeeded power down and we don't want to alter
|
|
// that yet.
|
|
//
|
|
// Note that the state machine also handles an upper filter completing the
|
|
// Dx irp before our device gets to process it (which would be a bug in the
|
|
// filter driver) by handling the PwrPolPowerDown from the appropriate
|
|
// state, as an example...
|
|
//
|
|
// a successful power down state transition looks like this
|
|
// 1) power policy state where we request a power irp
|
|
// 2) power sends a partial power down message (PwrPolPowerDownIoStopped)
|
|
// to power policy, moves to the partial power down state
|
|
// 3) power policy tells power to complete the power down
|
|
// 4) power completes the irp and we send the power down complete message
|
|
// (PwrPolPowerDown) moving from the partial power down state to the
|
|
// final power down state
|
|
//
|
|
// In the case where the top filter driver completes the PIRP without our
|
|
// driver seeing it, we will be in the state where we requested a power irp
|
|
// and process a power down complete event instead of the partial power down
|
|
// event and in this transition, we detect the error.
|
|
//
|
|
if (pThis->m_PowerMachine.m_PowerDownFailure) {
|
|
//
|
|
// Clear the faliure condition if we ever attempt to power off this
|
|
// device again (highly possible if it is a PDO).
|
|
//
|
|
pThis->m_PowerMachine.m_PowerDownFailure = FALSE;
|
|
|
|
//
|
|
// Power down failed, send ourself an even indicating that.
|
|
//
|
|
pThis->PowerPolicyProcessEvent(PwrPolPowerDownFailed);
|
|
|
|
//
|
|
// Inform pnp last so that all the other state machines are in the failed
|
|
// state by the time we transition the pnp state of the device.
|
|
//
|
|
if (FALSE == pThis->m_ReleaseHardwareAfterDescendantsOnFailure) {
|
|
pThis->PnpProcessEvent(PnpEventPowerDownFailed);
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// Power down succeeded, send ourself an even indicating that.
|
|
//
|
|
pThis->PowerPolicyProcessEvent(PwrPolPowerDown);
|
|
}
|
|
}
|
|
|
|
__drv_sameIRQL
|
|
VOID
|
|
FxPkgPnp::_PowerPolDevicePowerUpComplete(
|
|
__in MdDeviceObject DeviceObject,
|
|
__in UCHAR MinorFunction,
|
|
__in POWER_STATE PowerState,
|
|
__in_opt PVOID Context,
|
|
__in PIO_STATUS_BLOCK IoStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Completion routine for a requested power irp. Called once the power irp
|
|
has traveled through the entire stack. We feed the result of the power
|
|
operation back into the power policy state machine through an event.
|
|
|
|
Arguments:
|
|
Context - instance of the state machine
|
|
All others ignored
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
FxPkgPnp* pThis;
|
|
|
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|
UNREFERENCED_PARAMETER(MinorFunction);
|
|
UNREFERENCED_PARAMETER(PowerState);
|
|
UNREFERENCED_PARAMETER(IoStatus);
|
|
|
|
pThis = (FxPkgPnp*) Context;
|
|
|
|
//
|
|
// The state machine handles an upper filter completing the
|
|
// D0 irp before our device gets to process it (which would be a bug in the
|
|
// filter driver).
|
|
//
|
|
if (pThis->m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp) {
|
|
//
|
|
// We requested a Power Irp but that never arrived in dispatch routine.
|
|
// We know this because m_RequestedPowerUpIrp is still TRUE at the end of
|
|
// the power irp completion (it is set to false when it arrives in
|
|
// dispatch routine).
|
|
//
|
|
DoTraceLevelMessage(
|
|
pThis->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"PowerDeviceD0 requested by WDFDEVICE 0x%p !devobj 0x%p, "
|
|
"is being completed by upper driver without sending it to "
|
|
"driver that requested it",
|
|
pThis->m_Device->GetHandle(),
|
|
pThis->m_Device->GetDeviceObject());
|
|
|
|
//
|
|
// Power-up request not seen, send ourself an event indicating that.
|
|
//
|
|
pThis->PowerPolicyProcessEvent(PwrPolPowerUpNotSeen);
|
|
}
|
|
}
|
|
|
|
_Must_inspect_result_
|
|
NTSTATUS
|
|
FxPkgPnp::PowerPolicySendDevicePowerRequest(
|
|
__in DEVICE_POWER_STATE DeviceState,
|
|
__in SendDeviceRequestAction Action
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Attempts to send a D irp to the stack. The caller can specify if the
|
|
request allocation is retried in case of failure.
|
|
|
|
Design Notes:
|
|
The timeout and number of retries are somewhat magical numbers. They were
|
|
picked so that the total amount of time spent attempting to retry would be
|
|
under a minute. Any memory pressure the machine would be under after the
|
|
first failure should be over by the end of the minute; if not, there are
|
|
bigger problems.
|
|
|
|
If you look at each of the callers who specify Retry for the Action, nearly
|
|
each one transitions to the WdfDevStatePwrPolDevicePowerRequestFailed state
|
|
if the request cannot be allocated. This transition could be placed in this
|
|
function, but it is not for 2 reasons:
|
|
|
|
1) Keep this function simple
|
|
|
|
2) It makes the flow of the state transition function easier to understand;
|
|
all transitions out of the current state happen within top level
|
|
transition function
|
|
|
|
Arguments:
|
|
DeviceState - The new D state being request
|
|
|
|
Action - Whether to retry upon failure to allocate the request
|
|
|
|
Return Value:
|
|
NT_SUCCESS if the request was allocated, !NT_SUCCESS otherwise
|
|
|
|
--*/
|
|
{
|
|
MdRequestPowerComplete pCompletionRoutine;
|
|
LARGE_INTEGER interval;
|
|
NTSTATUS status;
|
|
POWER_STATE state;
|
|
ULONG i;
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
interval.QuadPart = WDF_REL_TIMEOUT_IN_MS(500);
|
|
state.DeviceState = DeviceState;
|
|
|
|
if (DeviceState == PowerDeviceD0) {
|
|
//
|
|
// We are powering up, we do not synchronize the completion of the D0 irp
|
|
// with a potential S0 irp. However we need to ensure that if an upper filter
|
|
// driver fails the power irp, we handle it gracefully rather than keep waiting
|
|
// for the power irp to arrive.
|
|
//
|
|
pCompletionRoutine = _PowerPolDevicePowerUpComplete;
|
|
}
|
|
else {
|
|
//
|
|
// We are powering down, we synchronize the completion of the Dx irp
|
|
// with a potential Sx irp. If there is no pending Sx irp, the state
|
|
// machine takes care of it.
|
|
//
|
|
pCompletionRoutine = _PowerPolDevicePowerDownComplete;
|
|
}
|
|
|
|
//
|
|
// We track when we request power irps to catch someone other then ourselves
|
|
// sending power irps to our own stack.
|
|
//
|
|
if (DeviceState == PowerDeviceD0) {
|
|
m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp = TRUE;
|
|
}
|
|
else {
|
|
m_PowerPolicyMachine.m_Owner->m_RequestedPowerDownIrp = TRUE;
|
|
}
|
|
|
|
for (i = 0; i < 100; i++) {
|
|
status = FxIrp::RequestPowerIrp(m_Device->GetDeviceObject(),
|
|
IRP_MN_SET_POWER,
|
|
state,
|
|
pCompletionRoutine,
|
|
this);
|
|
|
|
//
|
|
// If we are not retrying, we always break out
|
|
//
|
|
if (NT_SUCCESS(status) || Action == NoRetry) {
|
|
break;
|
|
}
|
|
|
|
Mx::MxDelayExecutionThread(KernelMode, FALSE, &interval);
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
//
|
|
// We are no longer requesting a power irp
|
|
//
|
|
if (DeviceState == PowerDeviceD0) {
|
|
m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp = FALSE;
|
|
}
|
|
else {
|
|
m_PowerPolicyMachine.m_Owner->m_RequestedPowerDownIrp = FALSE;
|
|
}
|
|
|
|
if (Action == Retry) {
|
|
COVERAGE_TRAP();
|
|
|
|
DoTraceLevelMessage(
|
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"Could not request D%d irp for device %p (WDFDEVICE %p), "
|
|
"%!STATUS!", DeviceState-1,
|
|
m_Device->GetDeviceObject(),
|
|
m_Device->GetHandle(), status);
|
|
}
|
|
}
|
|
|
|
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
|
"Requesting D%d irp, %!STATUS!",
|
|
DeviceState-1, status);
|
|
|
|
return status;
|
|
}
|
|
|
|
_Must_inspect_result_
|
|
NTSTATUS
|
|
FxPkgPnp::PowerPolicySendWaitWakeRequest(
|
|
__in SYSTEM_POWER_STATE SystemState
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
POWER_STATE state;
|
|
|
|
state.SystemState = SystemState;
|
|
|
|
//
|
|
// We track when we request power irps to catch someone other then ourselves
|
|
// sending power irps to our own stack.
|
|
//
|
|
m_PowerPolicyMachine.m_Owner->m_RequestedWaitWakeIrp = TRUE;
|
|
|
|
//
|
|
// Since we are sending a fresh wake, clear any state that was meant
|
|
// for the last wake IRP
|
|
//
|
|
m_SystemWokenByWakeInterrupt = FALSE;
|
|
|
|
//
|
|
// we are requesting new ww irp so re-initialize dropped event tracker.
|
|
//
|
|
m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped = FALSE;
|
|
|
|
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
|
"Requesting wait wake irp for S%d", SystemState-1);
|
|
|
|
status = FxIrp::RequestPowerIrp(m_Device->GetDeviceObject(),
|
|
IRP_MN_WAIT_WAKE,
|
|
state,
|
|
_PowerPolDeviceWaitWakeComplete,
|
|
this);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"Requesting wait wake irp for S%d failed, %!STATUS!",
|
|
SystemState-1, status);
|
|
|
|
//
|
|
// We are no longer requesting a power irp
|
|
//
|
|
m_PowerPolicyMachine.m_Owner->m_RequestedWaitWakeIrp = FALSE;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
FxPkgPnp::PowerPolicyCompleteSystemPowerIrp(
|
|
VOID
|
|
)
|
|
{
|
|
FxIrp irp(m_PendingSystemPowerIrp);
|
|
NTSTATUS status;
|
|
|
|
ASSERT(m_PendingSystemPowerIrp != NULL);
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
DoTraceLevelMessage(
|
|
GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
|
"Completing system power irp %p (S%d), %!STATUS!",
|
|
m_PendingSystemPowerIrp,
|
|
irp.GetParameterPowerStateSystemState()-1,
|
|
status);
|
|
|
|
m_PendingSystemPowerIrp = NULL;
|
|
|
|
CompletePowerRequest(&irp, STATUS_SUCCESS);
|
|
}
|
|
|
|
BOOLEAN
|
|
FxPkgPnp::PowerPolicyCancelWaitWake(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Completes or cancels a pending wait wake irp depending on if the irp is
|
|
present and if the device is the owner of the wait wake irp.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
MdIrp wwIrp;
|
|
BOOLEAN cancelled, result;
|
|
|
|
if (m_SharedPower.m_WaitWakeOwner) {
|
|
//
|
|
// This will complete the irp and then post the appropriate events to
|
|
// both the power and power policy state machines.
|
|
//
|
|
cancelled = PowerIndicateWaitWakeStatus(STATUS_CANCELLED);
|
|
}
|
|
else {
|
|
wwIrp = (MdIrp) InterlockedExchangePointer(
|
|
(PVOID*) &m_SharedPower.m_WaitWakeIrp, NULL);
|
|
|
|
if (wwIrp != NULL) {
|
|
FxIrp irp(wwIrp);
|
|
|
|
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
|
"Successfully got WaitWake irp %p for cancelling", wwIrp);
|
|
|
|
result = irp.Cancel();
|
|
|
|
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
|
"Cancel of irp %p returned %d", wwIrp, result);
|
|
|
|
|
|
if (m_PowerPolicyMachine.CanCompleteWaitWakeIrp()) {
|
|
CompletePowerRequest(&irp, irp.GetStatus());
|
|
}
|
|
else {
|
|
//
|
|
// Irp has been completed by the lower bus driver, that's OK
|
|
// because the completion of the request will trigger the
|
|
// same transition
|
|
//
|
|
DO_NOTHING();
|
|
}
|
|
|
|
cancelled = TRUE;
|
|
}
|
|
else {
|
|
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
|
"No WaitWake irp to cancel");
|
|
|
|
cancelled = FALSE;
|
|
}
|
|
}
|
|
|
|
return cancelled;
|
|
}
|
|
|
|
__drv_sameIRQL
|
|
NTSTATUS
|
|
FxPkgPnp::_PowerPolicyWaitWakeCompletionRoutine(
|
|
__in MdDeviceObject DeviceObject,
|
|
__in MdIrp OriginalIrp,
|
|
__in_xcount_opt("varies") PVOID Context
|
|
)
|
|
{
|
|
FxIrp originalIrp(OriginalIrp);
|
|
MdIrp pOldIrp;
|
|
FxPkgPnp *pThis;
|
|
NTSTATUS status;
|
|
|
|
pThis = (FxPkgPnp*) Context;
|
|
|
|
if (originalIrp.PendingReturned()) {
|
|
originalIrp.MarkIrpPending();
|
|
}
|
|
|
|
DoTraceLevelMessage(pThis->GetDriverGlobals(),
|
|
TRACE_LEVEL_INFORMATION, TRACINGPNP,
|
|
"WDFDEVICE %p !devobj %p Completion of WaitWake irp %p,"
|
|
" %!STATUS!", pThis->m_Device->GetHandle(),
|
|
DeviceObject, originalIrp.GetIrp(),
|
|
originalIrp.GetStatus());
|
|
|
|
if (NT_SUCCESS(originalIrp.GetStatus())) {
|
|
|
|
//
|
|
// Check to see if this device caused the machine to wake up
|
|
//
|
|
pThis->PowerPolicyUpdateSystemWakeSource(&originalIrp);
|
|
}
|
|
|
|
if (pThis->m_SystemWokenByWakeInterrupt) {
|
|
//
|
|
// If the system was woken by a wake interrupt, we need to mark this
|
|
// device as the wake source. Since we typically cancel the wait
|
|
// wake IRP in this path, it is expected that the completion
|
|
// status will not be success. We need to change this status code to
|
|
// success because power manager ignores the wake source information
|
|
// reported by a wait wake IRP that is not completed successfully.
|
|
//
|
|
pThis->_PowerSetSystemWakeSource(&originalIrp);
|
|
originalIrp.SetStatus(STATUS_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// Attempt to gain exclusive ownership of the irp from the cancel call site.
|
|
// If we do (indicated by the exchange returning a non-NULL pointer), we can
|
|
// complete the request w/out worrying about the cancel call site.
|
|
//
|
|
// If we can't, we must check to see if we can complete the wait wake irp
|
|
// (the cancel call site at least has the irp pointer value and has called
|
|
// IoCancelIrp on it).
|
|
//
|
|
pOldIrp = (MdIrp) InterlockedExchangePointer(
|
|
(PVOID*)&pThis->m_SharedPower.m_WaitWakeIrp, NULL);
|
|
|
|
ASSERT(pOldIrp == NULL || pOldIrp == originalIrp.GetIrp());
|
|
|
|
if (pOldIrp != NULL ||
|
|
pThis->m_PowerPolicyMachine.CanCompleteWaitWakeIrp()) {
|
|
DoTraceLevelMessage(pThis->GetDriverGlobals(),
|
|
TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
|
"Completion of WaitWake irp %p",
|
|
originalIrp.GetIrp());
|
|
|
|
originalIrp.StartNextPowerIrp();
|
|
|
|
status = STATUS_CONTINUE_COMPLETION;
|
|
|
|
Mx::MxReleaseRemoveLock(
|
|
&FxDevice::_GetFxWdmExtension(
|
|
DeviceObject)->IoRemoveLock,
|
|
originalIrp.GetIrp()
|
|
);
|
|
}
|
|
else {
|
|
//
|
|
// ************ WARNING *************
|
|
// By this time the IRP may have got completed by cancel call site, so
|
|
// don't touch irp *members* in this path (it is ok to use the IRP
|
|
// address though as in the log below).
|
|
//
|
|
DoTraceLevelMessage(
|
|
pThis->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
|
"Not completing WaitWake irp %p in completion routine",
|
|
originalIrp.GetIrp());
|
|
|
|
status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
__drv_sameIRQL
|
|
NTSTATUS
|
|
FxPkgPnp::_PowerPolicyUsbSelectiveSuspendCompletionRoutine(
|
|
__in MdDeviceObject DeviceObject,
|
|
__in MdIrp Irp,
|
|
__in_xcount_opt("varies") PVOID Context
|
|
)
|
|
{
|
|
FxPkgPnp* This;
|
|
FxIrp irp(Irp);
|
|
|
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|
|
|
This = (FxPkgPnp*) Context;
|
|
|
|
//
|
|
// Parameters DeviceObejct and Irp are always set to NULL in UMDF, so
|
|
// don't touch these in UMDF trace
|
|
//
|
|
#if FX_IS_KERNEL_MODE
|
|
DoTraceLevelMessage(This->GetDriverGlobals(),
|
|
TRACE_LEVEL_INFORMATION, TRACINGPNP,
|
|
"WDFDEVICE %p, !devobj %p Completion of UsbSS irp %p, %!STATUS!",
|
|
This->m_Device, This->m_Device->GetDeviceObject(),
|
|
irp.GetIrp(), irp.GetStatus());
|
|
|
|
#elif FX_IS_USER_MODE
|
|
UNREFERENCED_PARAMETER(irp);
|
|
|
|
DoTraceLevelMessage(This->GetDriverGlobals(),
|
|
TRACE_LEVEL_INFORMATION, TRACINGPNP,
|
|
"WDFDEVICE %p, !devobj %p Completion of UsbSS irp",
|
|
This->m_Device, This->m_Device->GetDeviceObject());
|
|
#endif
|
|
|
|
//
|
|
// Post an event indicating that the irp has been completed
|
|
//
|
|
This->PowerPolicyProcessEvent(
|
|
PwrPolUsbSelectiveSuspendCompleted
|
|
);
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
BOOLEAN
|
|
FxPkgPnp::PowerPolicyCanIdlePowerDown(
|
|
__in DEVICE_POWER_STATE DxState
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Attempts to send a Dx irp down the stack after this device has idled out.
|
|
Before the Dx can be set, we must check that no child devices have attempted
|
|
to power up in between the idle timer firing and the state machine
|
|
processing the event. After we have determined that no children are in
|
|
D0, we setup a guard so that any child which attempts to power up after this
|
|
point will pend the power up until this device has either powered all the
|
|
way down and back up or could not allocate a device power irp
|
|
|
|
Arguments:
|
|
DxState - the destination device state
|
|
|
|
Return Value:
|
|
TRUE if the device power irp was sent, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN powerDown;
|
|
|
|
//
|
|
// If we potentially have children, make sure that they are all in Dx before
|
|
// the parent powers down.
|
|
//
|
|
if (m_EnumInfo != NULL) {
|
|
m_EnumInfo->AcquireParentPowerStateLock(GetDriverGlobals());
|
|
if (m_PowerPolicyMachine.m_Owner->m_ChildrenPoweredOnCount == 0) {
|
|
//
|
|
// Setup a guard so that no children power up until we either fail
|
|
// this power down or power all the way down and back up.
|
|
//
|
|
m_PowerPolicyMachine.m_Owner->m_ChildrenCanPowerUp = FALSE;
|
|
powerDown = TRUE;
|
|
}
|
|
else {
|
|
DoTraceLevelMessage(
|
|
GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
|
|
"WDFDEVICE %p !devobj 0x%p not idling out because there are %d "
|
|
"children who are powered up", m_Device->GetHandle(),
|
|
m_Device->GetDeviceObject(),
|
|
m_PowerPolicyMachine.m_Owner->m_ChildrenPoweredOnCount);
|
|
powerDown = FALSE;
|
|
}
|
|
m_EnumInfo->ReleaseParentPowerStateLock(GetDriverGlobals());
|
|
}
|
|
else {
|
|
powerDown = TRUE;
|
|
}
|
|
|
|
if (powerDown) {
|
|
NTSTATUS status;
|
|
|
|
status = PowerPolicySendDevicePowerRequest(DxState, NoRetry);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
//
|
|
// This will set m_ChildrenCanPowerUp to TRUE and send a
|
|
// ParentMovesToD0 in case any children powered down in between
|
|
// determining if the parent can go idle and failing to do so.
|
|
//
|
|
PowerPolicyChildrenCanPowerUp();
|
|
|
|
powerDown = FALSE;
|
|
}
|
|
}
|
|
|
|
return powerDown;
|
|
}
|
|
|
|
VOID
|
|
FxPkgPnp::PowerPolicyPostParentToD0ToChildren(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Indicates to all of the children that the parent is in D0
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
FxTransactionedEntry* ple;
|
|
|
|
ASSERT(IsPowerPolicyOwner());
|
|
|
|
if (m_EnumInfo != NULL) {
|
|
m_EnumInfo->m_ChildListList.LockForEnum(GetDriverGlobals());
|
|
|
|
ple = NULL;
|
|
while ((ple = m_EnumInfo->m_ChildListList.GetNextEntry(ple)) != NULL) {
|
|
((FxChildList*) ple->GetTransactionedObject())->PostParentToD0();
|
|
}
|
|
|
|
m_EnumInfo->m_ChildListList.UnlockFromEnum(GetDriverGlobals());
|
|
}
|
|
}
|
|
|
|
VOID
|
|
FxPkgPnp::PowerPolicyChildrenCanPowerUp(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
After this function returns, any child devices rooted off of this parent
|
|
device can now move into D0.
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// This can be called for any PPO so we must check first if we have any
|
|
// possibility of children.
|
|
//
|
|
if (m_EnumInfo == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (IsPowerPolicyOwner()) {
|
|
m_EnumInfo->AcquireParentPowerStateLock(GetDriverGlobals());
|
|
|
|
//
|
|
// When the child attempts to power up, m_ChildrenPoweredOnCount can
|
|
// be incremented while the parent is in Dx. The important value
|
|
// here is the guard value, m_ChildrenCanPowerUp which must be
|
|
// FALSE.
|
|
//
|
|
// ASSERT (m_PowerPolicyMachine.m_Owner->m_ChildrenPoweredOnCount == 0);
|
|
|
|
//
|
|
// In the USB SS case, we can return to StartingDecideS0Wake without
|
|
// ever attempting to go into a Dx state state, so m_ChildrenCanPowerUp
|
|
// can be TRUE.
|
|
//
|
|
// ASSERT(m_PowerPolicyMachine.m_Owner->m_ChildrenCanPowerUp == FALSE);
|
|
|
|
m_PowerPolicyMachine.m_Owner->m_ChildrenCanPowerUp = TRUE;
|
|
m_EnumInfo->ReleaseParentPowerStateLock(GetDriverGlobals());
|
|
|
|
//
|
|
// Now that we have set the state of the parent, any child which checks
|
|
// the power state after we have released the lock will be able to
|
|
// power up immediately. We now need to unblock all children which
|
|
// checked the parent state before this function was called by posting
|
|
// a PowerParentToD0 event to each child (regardless of the PDO device
|
|
// power state).
|
|
//
|
|
PowerPolicyPostParentToD0ToChildren();
|
|
}
|
|
else {
|
|
//
|
|
// Since we are not the power policy owner for the parent device,
|
|
// we cannot make any guarantees about the child being in D0 while
|
|
// the parent is in D0 so we do not call PowerPostParentToD0ToChildren().
|
|
// Additionally in PowerPolicyCanChildPowerUp(), if the parent (this)
|
|
// device is not the PPO, we don't even check the parent D state before
|
|
// powering up the child.
|
|
//
|
|
DO_NOTHING();
|
|
}
|
|
}
|
|
|
|
VOID
|
|
__inline
|
|
FxPkgPnp::PowerPolicyDisarmWakeFromSx(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Calls into the client driver to disarm itself from wake and the clears the
|
|
flag which indicates that the device is a source of system wake. The disarm
|
|
callback is the last callback available to the driver to indicate the wake
|
|
status of its children and have the wake status propagate upwards to the
|
|
PDO's stack.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS wwStatus;
|
|
FxTransactionedEntry* ple;
|
|
|
|
m_PowerPolicyMachine.m_Owner->m_DeviceDisarmWakeFromSx.Invoke(
|
|
m_Device->GetHandle()
|
|
);
|
|
|
|
wwStatus = m_PowerPolicyMachine.m_Owner->m_WaitWakeStatus;
|
|
|
|
if (wwStatus != STATUS_CANCELLED &&
|
|
m_EnumInfo != NULL &&
|
|
PowerPolicyShouldPropagateWakeStatusToChildren()) {
|
|
m_EnumInfo->m_ChildListList.LockForEnum(GetDriverGlobals());
|
|
|
|
ple = NULL;
|
|
while ((ple = m_EnumInfo->m_ChildListList.GetNextEntry(ple)) != NULL) {
|
|
((FxChildList*) ple->GetTransactionedObject())->
|
|
IndicateWakeStatus(wwStatus);
|
|
}
|
|
|
|
m_EnumInfo->m_ChildListList.UnlockFromEnum(GetDriverGlobals());
|
|
}
|
|
|
|
m_PowerPolicyMachine.m_Owner->m_WaitWakeStatus = STATUS_NOT_SUPPORTED;
|
|
|
|
//
|
|
// Always set the wake source back to FALSE regardless of it previous value.
|
|
//
|
|
m_PowerPolicyMachine.m_Owner->m_SystemWakeSource = FALSE;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolWaitingArmedStoppingCancelUsbSS(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device is in Dx and surprise removed. Cancel the idle notification so
|
|
we can move to another state
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolStoppingCancelWake
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWaitingArmedStoppingCancelUsbSS);
|
|
|
|
This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer();
|
|
|
|
//
|
|
// Since we are in Dx and surprise removed, cancel the usb SS irp if it is
|
|
// there. Otherwise, the USB PDO will call us back after we have processed
|
|
// remove.
|
|
//
|
|
if (This->PowerPolicyCancelUsbSSIfCapable()) {
|
|
//
|
|
// Usbss completion event will move us from this state.
|
|
//
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
//
|
|
// If usbss irp was there it has already been canceled, so march on.
|
|
//
|
|
return WdfDevStatePwrPolStoppingCancelWake;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolWaitingArmedWakeFailedCancelUsbSS(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device is in Dx armed for wake and wait wake irp got failed.
|
|
Cancel the idle notification so we can move to another state
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolIoPresentArmedWakeCanceled
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWaitingArmedWakeFailedCancelUsbSS);
|
|
|
|
if (This->PowerPolicyCancelUsbSSIfCapable()) {
|
|
//
|
|
// Usbss completion event will move us from this state.
|
|
//
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
//
|
|
// If usbss irp was there it has already been canceled, so march on.
|
|
//
|
|
return WdfDevStatePwrPolIoPresentArmedWakeCanceled;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolWaitingArmedIoPresentCancelUsbSS(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device is in Dx armed for wake.
|
|
Cancel the idle notification so we can move to another state
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolIoPresentArmed
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWaitingArmedIoPresentCancelUsbSS);
|
|
|
|
if (This->PowerPolicyCancelUsbSSIfCapable()) {
|
|
//
|
|
// Usbss completion event will move us from this state.
|
|
//
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
//
|
|
// If usbss irp was there it has already been canceled, so march on.
|
|
//
|
|
return WdfDevStatePwrPolIoPresentArmed;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolWaitingArmedWakeSucceededCancelUsbSS(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The device woke from S0.
|
|
Cancel the idle notification so we can move to another state
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolWokeFromS0
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWaitingArmedWakeSucceededCancelUsbSS);
|
|
|
|
if (This->PowerPolicyCancelUsbSSIfCapable()) {
|
|
//
|
|
// Usbss completion event will move us from this state.
|
|
//
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
//
|
|
// If usbss irp was there it has already been canceled, so march on.
|
|
//
|
|
return WdfDevStatePwrPolWokeFromS0;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolCancelingUsbSSForSystemSleep(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The system is going to sleep..
|
|
Cancel the idle notification so we can move to another state
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolCancelingWakeForSystemSleep
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolCancelingUsbSSForSystemSleep);
|
|
|
|
if (This->PowerPolicyCancelUsbSSIfCapable()) {
|
|
//
|
|
// Usbss completion event will move us from this state.
|
|
//
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
//
|
|
// If usbss irp was there it has already been canceled, so march on.
|
|
//
|
|
return WdfDevStatePwrPolCancelingWakeForSystemSleep;
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolStoppingD0CancelUsbSS(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Cancel the idle notification so we can move to another state
|
|
|
|
Arguments:
|
|
This - instance of the state machine
|
|
|
|
Return Value:
|
|
WdfDevStatePwrPolStoppingD0
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingD0CancelUsbSS);
|
|
|
|
if (This->PowerPolicyCancelUsbSSIfCapable()) {
|
|
//
|
|
// Usbss completion event will move us from this state.
|
|
//
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
//
|
|
// If usbss irp was there it has already been canceled, so march on.
|
|
//
|
|
return WdfDevStatePwrPolStoppingD0;
|
|
}
|
|
|
|
BOOLEAN
|
|
FxPkgPnp::PowerPolicyCancelUsbSSIfCapable(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Cancel the idle notification irp if capable
|
|
|
|
Arguments:
|
|
none
|
|
|
|
Return Value:
|
|
TRUE if irp was canceled
|
|
FALSE if not capable of USBSS or if Irp was already completed.
|
|
|
|
--*/
|
|
{
|
|
if (m_PowerPolicyMachine.m_Owner->m_UsbIdle == NULL ||
|
|
m_PowerPolicyMachine.m_Owner->m_UsbIdle->m_EventDropped) {
|
|
return FALSE;
|
|
}
|
|
else {
|
|
PowerPolicyCancelUsbSS();
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
WDF_DEVICE_POWER_POLICY_STATE
|
|
FxPkgPnp::PowerPolTimerExpiredWakeCapableWakeInterruptArrived(
|
|
__inout FxPkgPnp* This
|
|
)
|
|
{
|
|
ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredWakeCapableWakeInterruptArrived);
|
|
|
|
if (This->PowerPolicyCancelWaitWake() == FALSE &&
|
|
This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
|
|
return WdfDevStatePwrPolTimerExpiredWakeCapableWakeSucceeded;
|
|
}
|
|
|
|
return WdfDevStatePwrPolNull;
|
|
}
|
|
|
|
|