reactos/sdk/lib/drivers/wdf/shared/inc/private/common/fxpoweridlestatemachine.hpp
Victor Perevertkin 8a978a179f
[WDF] Add Windows Driver Framework files
Takern from Microsoft GitHub repo:
d9c6040fe9

Licensed under MIT
2020-11-03 00:06:26 +03:00

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_