mirror of
https://github.com/reactos/reactos.git
synced 2025-03-10 10:14:44 +00:00
550 lines
11 KiB
C++
550 lines
11 KiB
C++
//
|
|
// Copyright (C) Microsoft. All rights reserved.
|
|
//
|
|
#ifndef _FXPOWERIDLESTATEMACHINE_H_
|
|
#define _FXPOWERIDLESTATEMACHINE_H_
|
|
|
|
//
|
|
// This is a magical number based on inspection. If the queue overflows,
|
|
// it is OK to increase these numbers without fear of either dependencies or
|
|
// weird side affects.
|
|
//
|
|
const UCHAR FxPowerIdleEventQueueDepth = 8;
|
|
|
|
enum FxPowerIdleEvents {
|
|
// CAN BE REUSED = 0x0001,
|
|
PowerIdleEventPowerUpFailed = 0x0002,
|
|
PowerIdleEventPowerUpComplete = 0x0004,
|
|
PowerIdleEventPowerDown = 0x0008,
|
|
PowerIdleEventPowerDownFailed = 0x0010,
|
|
PowerIdleEventTimerExpired = 0x0020,
|
|
PowerIdleEventEnabled = 0x0040,
|
|
PowerIdleEventDisabled = 0x0080,
|
|
PowerIdleEventIoDecrement = 0x0100,
|
|
PowerIdleEventIoIncrement = 0x0200,
|
|
PowerIdleEventStart = 0x0400,
|
|
PowerIdleEventStop = 0x0800,
|
|
PowerIdleNull = 0x0000,
|
|
};
|
|
|
|
// begin_wpp config
|
|
// CUSTOM_TYPE(FxPowerIdleEvents, ItemEnum(FxPowerIdleEvents));
|
|
// end_wpp
|
|
|
|
enum FxPowerIdleStates {
|
|
FxIdleStopped = 1,
|
|
FxIdleStarted,
|
|
FxIdleStartedPowerUp,
|
|
FxIdleStartedPowerFailed,
|
|
FxIdleDisabled,
|
|
FxIdleCheckIoCount,
|
|
FxIdleBusy,
|
|
FxIdleDecrementIo,
|
|
FxIdleStartTimer,
|
|
FxIdleTimerRunning,
|
|
FxIdleTimingOut,
|
|
FxIdleTimedOut,
|
|
FxIdleTimedOutIoIncrement,
|
|
FxIdleTimedOutPowerDown,
|
|
FxIdleTimedOutPowerDownFailed,
|
|
FxIdleGoingToDx,
|
|
FxIdleInDx,
|
|
FxIdleInDxIoIncrement,
|
|
FxIdleInDxPowerUpFailure,
|
|
FxIdleInDxStopped,
|
|
FxIdleInDxDisabled,
|
|
FxIdleInDxEnabled,
|
|
FxIdlePowerUp,
|
|
FxIdlePowerUpComplete,
|
|
FxIdleTimedOutDisabled,
|
|
FxIdleTimedOutEnabled,
|
|
FxIdleCancelTimer,
|
|
FxIdleWaitForTimeout,
|
|
FxIdleTimerExpired,
|
|
FxIdleDisabling,
|
|
FxIdleDisablingWaitForTimeout,
|
|
FxIdleDisablingTimerExpired,
|
|
FxIdlePowerFailedWaitForTimeout,
|
|
FxIdlePowerFailed,
|
|
FxIdleMax,
|
|
};
|
|
|
|
//
|
|
// NOTE: if you change these flags (order, values, etc), you must also modify
|
|
// m_FlagsByName to match your changes.
|
|
//
|
|
enum FxPowerIdleFlags {
|
|
FxPowerIdleTimerEnabled = 0x01,
|
|
FxPowerIdleInDx = 0x02,
|
|
FxPowerIdleTimerCanceled = 0x04,
|
|
FxPowerIdleTimerStarted = 0x08,
|
|
FxPowerIdlePowerFailed = 0x10,
|
|
FxPowerIdleIsStarted = 0x20,
|
|
FxPowerIdleIoPresentSent = 0x40,
|
|
FxPowerIdleSendPnpPowerUpEvent = 0x80,
|
|
};
|
|
|
|
enum FxPowerReferenceFlags {
|
|
FxPowerReferenceDefault = 0x0,
|
|
FxPowerReferenceSendPnpPowerUpEvent = 0x1
|
|
};
|
|
|
|
typedef
|
|
FxPowerIdleStates
|
|
(*PFN_POWER_IDLE_STATE_ENTRY_FUNCTION)(
|
|
FxPowerIdleMachine*
|
|
);
|
|
|
|
struct FxPowerIdleTargetState {
|
|
FxPowerIdleEvents PowerIdleEvent;
|
|
|
|
FxPowerIdleStates PowerIdleState;
|
|
|
|
#if FX_SUPER_DBG
|
|
BOOLEAN EventDebugged;
|
|
#endif
|
|
};
|
|
|
|
struct FxIdleStateTable {
|
|
PFN_POWER_IDLE_STATE_ENTRY_FUNCTION StateFunc;
|
|
|
|
const FxPowerIdleTargetState* TargetStates;
|
|
|
|
ULONG TargetStatesCount;
|
|
};
|
|
|
|
class FxPowerIdleMachine : public FxStump {
|
|
|
|
public:
|
|
FxPowerIdleMachine(
|
|
VOID
|
|
);
|
|
|
|
~FxPowerIdleMachine(
|
|
VOID
|
|
);
|
|
|
|
_Must_inspect_result_
|
|
NTSTATUS
|
|
Init(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
EnableTimer(
|
|
VOID
|
|
);
|
|
|
|
BOOLEAN
|
|
DisableTimer(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
Start(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
Stop(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
Reset(
|
|
VOID
|
|
);
|
|
|
|
_Must_inspect_result_
|
|
NTSTATUS
|
|
IoIncrement(
|
|
VOID
|
|
);
|
|
|
|
_Must_inspect_result_
|
|
NTSTATUS
|
|
IoIncrementWithFlags(
|
|
__in FxPowerReferenceFlags Flags,
|
|
__out_opt PULONG Count = NULL
|
|
);
|
|
|
|
VOID
|
|
IoDecrement(
|
|
__in_opt PVOID Tag = NULL,
|
|
__in_opt LONG Line = 0,
|
|
__in_opt PSTR File = NULL
|
|
);
|
|
|
|
BOOLEAN
|
|
QueryReturnToIdle(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
WaitForD0(
|
|
VOID
|
|
)
|
|
{
|
|
m_D0NotificationEvent.EnterCRAndWaitAndLeave();
|
|
}
|
|
|
|
_Must_inspect_result_
|
|
NTSTATUS
|
|
PowerReference(
|
|
__in BOOLEAN WaitForD0,
|
|
__in_opt PVOID Tag = NULL,
|
|
__in_opt LONG Line = 0,
|
|
__in_opt PSTR File = NULL
|
|
)
|
|
{
|
|
return PowerReferenceWorker(WaitForD0, FxPowerReferenceDefault, Tag, Line, File);
|
|
}
|
|
|
|
_Must_inspect_result_
|
|
NTSTATUS
|
|
PowerReferenceWithFlags(
|
|
__in FxPowerReferenceFlags Flags
|
|
)
|
|
{
|
|
return PowerReferenceWorker(FALSE, // WaitForD0
|
|
Flags);
|
|
}
|
|
|
|
VOID
|
|
ProcessPowerEvent(
|
|
__in FxPowerIdleEvents Event
|
|
);
|
|
|
|
protected:
|
|
|
|
VOID
|
|
ProcessEventLocked(
|
|
__in FxPowerIdleEvents Event
|
|
);
|
|
|
|
BOOLEAN
|
|
IsTransitioning(
|
|
VOID
|
|
)
|
|
{
|
|
return m_D0NotificationEvent.ReadState() ? FALSE : TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
CancelIdleTimer(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// If we are canceling the timer, be well sure it is started
|
|
//
|
|
ASSERT(m_Flags & FxPowerIdleTimerStarted);
|
|
|
|
if (m_PowerTimeoutTimer.Stop()) {
|
|
m_Flags &= ~FxPowerIdleTimerStarted;
|
|
return TRUE;
|
|
}
|
|
else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
InD0Locked(
|
|
VOID
|
|
)
|
|
{
|
|
return m_D0NotificationEvent.ReadState() ? TRUE : FALSE;
|
|
}
|
|
|
|
VOID
|
|
SendD0Notification(
|
|
VOID
|
|
);
|
|
|
|
_Must_inspect_result_
|
|
NTSTATUS
|
|
PowerReferenceWorker(
|
|
__in BOOLEAN WaitForD0,
|
|
__in FxPowerReferenceFlags Flags,
|
|
__in_opt PVOID Tag = NULL,
|
|
__in_opt LONG Line = 0,
|
|
__in_opt PSTR File = NULL
|
|
);
|
|
|
|
static
|
|
MdDeferredRoutineType
|
|
_PowerTimeoutDpcRoutine;
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
Stopped(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
Started(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
StartedPowerUp(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
StartedPowerFailed(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
Disabled(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
CheckIoCount(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
DecrementIo(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
StartTimer(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
TimingOut(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
TimedOutIoIncrement(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
TimedOutPowerDown(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
TimedOutPowerDownFailed(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
GoingToDx(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
InDx(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
InDxIoIncrement(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
InDxPowerUpFailure(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
InDxStopped(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
InDxDisabled(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
InDxEnabled(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
PowerUp(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
PowerUpComplete(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
TimedOutDisabled(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
TimedOutEnabled(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
CancelTimer(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
TimerExpired(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
Disabling(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
DisablingTimerExpired(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
static
|
|
FxPowerIdleStates
|
|
PowerFailed(
|
|
__inout FxPowerIdleMachine* This
|
|
);
|
|
|
|
private:
|
|
VOID
|
|
CheckAssumptions(
|
|
VOID
|
|
);
|
|
|
|
public:
|
|
LARGE_INTEGER m_PowerTimeout;
|
|
|
|
protected:
|
|
//
|
|
// Lock which guards state
|
|
//
|
|
MxLock m_Lock;
|
|
|
|
//
|
|
// Number of pending requests which require being in D0
|
|
//
|
|
ULONG m_IoCount;
|
|
|
|
//
|
|
// Tracks power references and releases.
|
|
//
|
|
FxTagTracker* m_TagTracker;
|
|
|
|
//
|
|
// Timer which will be set when the I/O count goes to zero
|
|
//
|
|
MxTimer m_PowerTimeoutTimer;
|
|
|
|
//
|
|
// Event to wait on when transitioning from Dx to D0
|
|
//
|
|
FxCREvent m_D0NotificationEvent;
|
|
|
|
union {
|
|
//
|
|
// Combintaion of FxPowerIdleFlags enum values
|
|
//
|
|
UCHAR m_Flags;
|
|
|
|
//
|
|
// Not used in the code. Here so that you can easily decode m_Flags in
|
|
// the debugger without needing the enum definition.
|
|
//
|
|
struct {
|
|
UCHAR TimerEnabled : 1;
|
|
UCHAR InDx : 1;
|
|
UCHAR TimerCanceled : 1;
|
|
UCHAR TimerStarted : 1;
|
|
UCHAR TimerPowerFailed : 1;
|
|
UCHAR IsStarted : 1;
|
|
UCHAR IoPresentSent : 1;
|
|
UCHAR SendPnpPowerUpEvent : 1;
|
|
} m_FlagsByName;
|
|
};
|
|
|
|
//
|
|
// Index into m_EventHistory where to place the next value
|
|
//
|
|
UCHAR m_EventHistoryIndex;
|
|
|
|
//
|
|
// Index into m_StateHistory where to place the next value
|
|
UCHAR m_StateHistoryIndex;
|
|
|
|
//
|
|
// our current state
|
|
//
|
|
FxPowerIdleStates m_CurrentIdleState;
|
|
|
|
//
|
|
// Circular history of events fed into this state machine
|
|
//
|
|
FxPowerIdleEvents m_EventHistory[FxPowerIdleEventQueueDepth];
|
|
|
|
//
|
|
// Circular history of states the state machine was in
|
|
//
|
|
FxPowerIdleStates m_StateHistory[FxPowerIdleEventQueueDepth];
|
|
|
|
static const FxPowerIdleTargetState m_StoppedStates[];
|
|
static const FxPowerIdleTargetState m_StartedStates[];
|
|
static const FxPowerIdleTargetState m_DisabledStates[];
|
|
static const FxPowerIdleTargetState m_BusyStates[];
|
|
static const FxPowerIdleTargetState m_TimerRunningStates[];
|
|
static const FxPowerIdleTargetState m_TimedOutStates[];
|
|
static const FxPowerIdleTargetState m_InDxStates[];
|
|
static const FxPowerIdleTargetState m_WaitForTimeoutStates[];
|
|
static const FxPowerIdleTargetState m_DisablingWaitForTimeoutStates[];
|
|
static const FxPowerIdleTargetState m_PowerFailedWaitForTimeoutStates[];
|
|
|
|
static const FxIdleStateTable m_StateTable[];
|
|
|
|
//
|
|
// We use a coalescable timer for idle timeout. The tolerable delay for the
|
|
// idle timer is defined below. The value below is an arbitrary choice and
|
|
// can be changed if necessary. MSDN documentation suggests 100 ms as being
|
|
// a reasonable choice.
|
|
//
|
|
static const ULONG m_IdleTimerTolerableDelayMS = 100;
|
|
};
|
|
|
|
#endif // _FXPOWERIDLESTATEMACHINE_H_
|