//
//    Copyright (C) Microsoft.  All rights reserved.
//
#ifndef _FXPOWERPOLICYSTATEMACHINE_H_
#define _FXPOWERPOLICYSTATEMACHINE_H_

#include "fxpoweridlestatemachine.hpp"
#include "fxpoxinterface.hpp"

// @@SMVERIFY_SPLIT_BEGIN
//
// Treat these values as a bit field when comparing for known dropped events in
// the current state and treat them as values when they known transition events
// from state to the next.
//
enum FxPowerPolicyEvent {
    PwrPolInvalid                       = 0x00000000,
    PwrPolStart                         = 0x00000001,
    PwrPolStop                          = 0x00000002,
    PwrPolSx                            = 0x00000004,
    PwrPolS0                            = 0x00000008,
    PwrPolPowerDown                     = 0x00000010,
    PwrPolPowerUp                       = 0x00000020,
    PwrPolPowerDownIoStopped            = 0x00000040,
    PwrPolPowerUpHwStarted              = 0x00000080,
    PwrPolWakeArrived                   = 0x00000100,
    PwrPolWakeSuccess                   = 0x00000200,
    PwrPolWakeFailed                    = 0x00000400,
    PwrPolIoPresent                     = 0x00000800,
    PwrPolPowerTimeoutExpired           = 0x00001000,
    PwrPolS0IdlePolicyChanged           = 0x00002000,
    PwrPolSurpriseRemove                = 0x00004000,
    PwrPolUsbSelectiveSuspendCallback   = 0x00008000,
    PwrPolUsbSelectiveSuspendCompleted  = 0x00010000,
    PwrPolPowerDownFailed               = 0x00020000,
    PwrPolPowerUpFailed                 = 0x00040000,
    PwrPolImplicitPowerDown             = 0x00080000,
    PwrPolImplicitPowerDownFailed       = 0x00100000,
    PwrPolPowerUpNotSeen                = 0x00200000,
    PwrPolDevicePowerNotRequired        = 0x00400000,
    PwrPolDevicePowerRequired           = 0x00800000,
    PwrPolRemove                        = 0x01000000,
    PwrPolWakeInterruptFired            = 0x02000000,

    //
    // Not a real event, just a value that indicates all of the events which
    // goto the head of the queue and are always processed, even if the state is
    // locked.  This applies to the power policy owner state machine.
    //
    PwrPolPriorityEventsMask            = PwrPolPowerUp |
                                          PwrPolPowerDown |
                                          PwrPolPowerUpFailed |
                                          PwrPolPowerDownFailed |
                                          PwrPolPowerDownIoStopped |
                                          PwrPolPowerUpHwStarted |
                                          PwrPolImplicitPowerDown |
                                          PwrPolImplicitPowerDownFailed |
                                          PwrPolWakeArrived |
                                          PwrPolWakeSuccess |
                                          PwrPolWakeFailed |
                                          PwrPolPowerUpNotSeen |
                                          PwrPolUsbSelectiveSuspendCompleted |
                                          PwrPolWakeInterruptFired,

    //
    // Not a real event, just a value that indicates all of the events which
    // goto the head of the queue and are always processed, even if the state is
    // locked.  This applies to the not power policy owner state machine.
    //
    PwrPolNotOwnerPriorityEventsMask    = PwrPolPowerUp |
                                          PwrPolPowerUpFailed |
                                          PwrPolPowerDown |
                                          PwrPolPowerDownFailed,

    //
    // Not a real event, just a value that indicate all of the events which
    // should not be in the queue, if a similar event is already enqueued.
    //
    PowerPolSingularEventMask           = PwrPolS0IdlePolicyChanged |
    //
    // A device could have multiple wake interrupts that could each fire
    // this event.
    //
                                          PwrPolWakeInterruptFired,


    PwrPolNull                          = 0xFFFFFFFF,
};

//
// Bit packed ULONG.
//
union FxPwrPolStateInfo {
    struct {
        //
        // Indicates whether the state is open to all events
        //
        ULONG QueueOpen : 1;

        //
        // Bit of events we know we can drop in this state
        //
        ULONG KnownDroppedEvents : 31;
    } Bits;

    struct {
        //
        // Maps to the same bit location as QueueOpen.  Since we start
        // KnownDroppedEvents at the next bit, start our bits by at the next
        // bit as well.
        //
        ULONG Reserved : 1;

        //
        // These are defined so that we can easily tell in the debugger what
        // each set bit in KnownDroppedEvents maps to in the FxPowerPolicyEvent
        // enum
        //
        ULONG PwrPolStartKnown : 1;
        ULONG PwrPolStopKnown : 1;
        ULONG PwrPolSxKnown : 1;
        ULONG PwrPolS0Known : 1;
        ULONG PwrPolPowerDownKnown : 1;
        ULONG PwrPolPowerUpKnown : 1;
        ULONG PwrPolPowerDownIoStoppedKnown : 1;
        ULONG PwrPolPowerUpHwStartedKnown : 1;
        ULONG PwrPolWakeArrivedKnown : 1;
        ULONG PwrPolWakeSuccessKnown : 1;
        ULONG PwrPolWakeFailedKnown : 1;
        ULONG PwrPolIoPresentKnown : 1;
        ULONG PwrPolPowerTimeoutExpiredKnown : 1;
        ULONG PwrPolS0IdlePolicyChangedKnown : 1;
        ULONG PwrPolSurpriseRemoveKnown : 1;
        ULONG PwrPolUsbSelectiveSuspendCallbackKnown : 1;
        ULONG PwrPolUsbSelectiveSuspendCompletedKnown : 1;
        ULONG PwrPolPowerDownFailedKnown : 1;
        ULONG PwrPolPowerUpFailedKnown : 1;
    } BitsByName;
};

struct POWER_POLICY_EVENT_TARGET_STATE {
    FxPowerPolicyEvent PowerPolicyEvent;

    WDF_DEVICE_POWER_POLICY_STATE TargetState;

    EVENT_TRAP_FIELD
};

typedef const POWER_POLICY_EVENT_TARGET_STATE* CPPOWER_POLICY_EVENT_TARGET_STATE;

typedef
WDF_DEVICE_POWER_POLICY_STATE
(*PFN_POWER_POLICY_STATE_ENTRY_FUNCTION)(
    FxPkgPnp* This
    );

typedef struct POWER_POLICY_STATE_TABLE {
    //
    // Framework internal function to handle the transition into this state
    //
    PFN_POWER_POLICY_STATE_ENTRY_FUNCTION StateFunc;

    //
    // First state transition out of this state
    //
    POWER_POLICY_EVENT_TARGET_STATE FirstTargetState;

    //
    // Other state transitions out of this state if FirstTargetState is not
    // matched.  This is an array where we expect the final element to be
    // { PwrPolNull, WdfDevStatePwrPolNull }
    //
    CPPOWER_POLICY_EVENT_TARGET_STATE OtherTargetStates;

    //
    // Whether we allow transitions out of this state that are not D state
    // related events, ie if this is a green dot state, TRUE, if this is a red
    // dot state, FALSE.  D state events (PwrPolPowerUp, PwrPolPowerDown)
    // are never affected by the queue state and are always processed.
    //
    FxPwrPolStateInfo StateInfo;

} *PPOWER_POLICY_STATE_TABLE;

typedef const POWER_POLICY_STATE_TABLE* CPPOWER_POLICY_STATE_TABLE;

typedef
WDF_DEVICE_POWER_POLICY_STATE
(*PFN_NOT_POWER_POLICY_OWNER_STATE_ENTRY_FUNCTION)(
    FxPkgPnp* This
    );

typedef struct NOT_POWER_POLICY_OWNER_STATE_TABLE {
    //
    // The current power policy state that this entry applies to
    //
    WDF_DEVICE_POWER_POLICY_STATE CurrentTargetState;

    //
    // Framework internal function to handle the transition into this state
    //
    PFN_NOT_POWER_POLICY_OWNER_STATE_ENTRY_FUNCTION StateFunc;

    //
    // Only state transition out of this state
    //
    CPPOWER_POLICY_EVENT_TARGET_STATE TargetStates;

    UCHAR TargetStatesCount;

    BOOLEAN QueueOpen;

} *PNOT_POWER_POLICY_OWNER_STATE_TABLE;

typedef const NOT_POWER_POLICY_OWNER_STATE_TABLE* CPNOT_POWER_POLICY_OWNER_STATE_TABLE;

#if FX_STATE_MACHINE_VERIFY
#define MAX_PWR_POL_STATE_ENTRY_FN_RETURN_STATES    (5)

struct PWR_POL_STATE_ENTRY_FUNCTION_TARGET_STATE {
    //
    // Return value from state entry function
    //
    WDF_DEVICE_POWER_POLICY_STATE State;

    //
    // type of device the returning state applies to
    //
    FxStateMachineDeviceType  DeviceType;

    //
    // Info about the state transition
    //
    PSTR Comment;
};

struct PWR_POL_STATE_ENTRY_FN_RETURN_STATE_TABLE {
    //
    // array of state transitions caused by state entry function
    //
    PWR_POL_STATE_ENTRY_FUNCTION_TARGET_STATE TargetStates[MAX_PWR_POL_STATE_ENTRY_FN_RETURN_STATES];
};

typedef const PWR_POL_STATE_ENTRY_FN_RETURN_STATE_TABLE*  CPPWR_POL_STATE_ENTRY_FN_RETURN_STATE_TABLE;
#endif  // FX_STATE_MACHINE_VERIFY


// @@SMVERIFY_SPLIT_END

enum FxPowerPolicyConstants {
    FxPowerPolicyNoTimeout = 0,

    FxPowerPolicyDefaultTimeout = 5000,             // Timeout in milliseconds
};

enum CancelIrpCompletionOwnership {
    CancelOwnershipUnclaimed = 0,
    CancelOwnershipClaimed = 1,
};

enum FxPowerPolicySxWakeSettingsFlags {
    FxPowerPolicySxWakeDeviceEnabledFlag = 0x1,
    FxPowerPolicySxWakeChildrenArmedFlag = 0x2,
};

struct PolicySettings {
    PolicySettings()
    {
        WmiInstance = NULL;
        DxState = PowerDeviceD3;

        Enabled = Overridable = Set = Dirty = FALSE;
    }

    ~PolicySettings();

    //
    // Dx state to put the device in when the policy is applied
    //
    DEVICE_POWER_STATE DxState;

    FxWmiInstanceInternal* WmiInstance;

    BOOLEAN Enabled;

    BOOLEAN Overridable;

    BOOLEAN Set;

    BOOLEAN Dirty;
};

typedef struct _POX_SETTINGS {
    PFN_WDFDEVICE_WDM_POST_PO_FX_REGISTER_DEVICE
                            EvtDeviceWdmPostPoFxRegisterDevice;
    PFN_WDFDEVICE_WDM_PRE_PO_FX_UNREGISTER_DEVICE
                            EvtDeviceWdmPrePoFxUnregisterDevice;
    PPO_FX_COMPONENT Component;
    PPO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK ComponentActiveConditionCallback;
    PPO_FX_COMPONENT_IDLE_CONDITION_CALLBACK ComponentIdleConditionCallback;
    PPO_FX_COMPONENT_IDLE_STATE_CALLBACK ComponentIdleStateCallback;
    PPO_FX_POWER_CONTROL_CALLBACK PowerControlCallback;
    PVOID PoFxDeviceContext;
} POX_SETTINGS, *PPOX_SETTINGS;

class IdleTimeoutManagement {

private:
    //
    // This member is used to control whether or not the idle timeout is
    // determined by the power manager when running on Windows 8 and above.
    // The value of this member is some combination of the flags defined below.
    //
    LONG volatile m_IdleTimeoutStatus;

    //
    // Flags for the m_IdleTimeoutStatus member
    //
    //    IdleTimeoutStatusFrozen - This flag implies that the decision on
    //        whether the power manager determines the idle timeout is "frozen"
    //        and can no longer be changed. The decision is frozen during start
    //        IRP completion processing, just before WDF registers with the
    //        power manager.
    //
    //    IdleTimeoutSystemManaged - This flag implies that the power manager
    //        determines the idle timeout on Windows 8 and above. If this flag
    //        is not set, the idle timeout specified by the client driver is
    //        used.
    //
    //    IdleTimeoutPoxSettingsSpecified - This flag implies that the client
    //        driver has already specified the settings that need to be used
    //        when registering with the power framework. This flag is used to
    //        track that the settings are not specified more than once.
    //
    enum IdleTimeoutStatusFlag {
        IdleTimeoutStatusFrozen         = 0x00000001,
        IdleTimeoutSystemManaged        = 0x00000002,
        IdleTimeoutPoxSettingsSpecified = 0x00000004,
    };

    //
    // Result returned by the UpdateIdleTimeoutStatus() method
    //
    enum IdleTimeoutStatusUpdateResult {
        //
        // Flags were sucessfully updated
        //
        IdleTimeoutStatusFlagsUpdated,

        //
        // The flag we were trying to set was already set
        //
        IdleTimeoutStatusFlagAlreadySet,

        //
        // It is too late to set the flag. The flags have already been frozen.
        // Flags are frozen the first time a device is started.
        //
        IdleTimeoutStatusFlagsAlreadyFrozen,

        //
        // Flags are being set by multiple threads in parallel. This is not
        // supported.
        //
        IdleTimeoutStatusFlagsUnexpected
    };

    //
    // This member contains the client driver's settings that will be used when
    // we register with the power manager on Windows 8 and above.
    //
    PPOX_SETTINGS m_PoxSettings;

private:
    IdleTimeoutStatusUpdateResult
    UpdateIdleTimeoutStatus(
        __in IdleTimeoutStatusFlag Flag
        );

    CfxDevice *
    GetDevice(
        VOID
        );

public:
    IdleTimeoutManagement(
        VOID
        ) : m_IdleTimeoutStatus(0),
            m_PoxSettings(NULL)
    {
    }

    ~IdleTimeoutManagement(
        VOID
        )
    {
        BYTE * buffer = NULL;
        ULONG poxSettingsOffset;

        if (NULL != m_PoxSettings) {

            buffer = (BYTE*) m_PoxSettings;

            //
            // In the function FxPkgPnp::AssignPowerFrameworkSettings, we had
            // allocated a buffer which we need to free now. Note that
            // m_PoxSettings does not necessarily point to the beginning of the
            // buffer. It points to the POX_SETTINGS structure in the buffer,
            // which may or may not be in the beginning. If it is not in the
            // beginning, figure out where the beginning of the buffer is.
            //
            if (m_PoxSettings->Component != NULL) {
                //
                // The computation below won't overflow because we already
                // performed this computation successfully using safeint
                // functions in FxPkgPnp::AssignPowerFrameworkSettings.
                //
                poxSettingsOffset =
                        (sizeof(*(m_PoxSettings->Component->IdleStates)) *
                                (m_PoxSettings->Component->IdleStateCount)) +
                        (sizeof(*(m_PoxSettings->Component)));
            }
            else {
                poxSettingsOffset = 0;
            }

            //
            // Move to the beginning of the buffer
            //
            buffer = buffer - poxSettingsOffset;

            //
            // Free the buffer
            //
            MxMemory::MxFreePool(buffer);
        }
    }

    static
    BOOLEAN
    _SystemManagedIdleTimeoutAvailable(
        VOID
        );

    NTSTATUS
    UseSystemManagedIdleTimeout(
        __in PFX_DRIVER_GLOBALS DriverGlobals
        );

    VOID
    FreezeIdleTimeoutManagementStatus(
        __in PFX_DRIVER_GLOBALS DriverGlobals
        );

    BOOLEAN
    UsingSystemManagedIdleTimeout(
        VOID
        );

    NTSTATUS
    CommitPowerFrameworkSettings(
        __in PFX_DRIVER_GLOBALS DriverGlobals,
        __in PPOX_SETTINGS PoxSettings
        );

    BOOLEAN
    DriverSpecifiedPowerFrameworkSettings(
        VOID
        );

    PPOX_SETTINGS
    GetPowerFrameworkSettings(
        VOID
        )
    {
        return m_PoxSettings;
    }
};

struct IdlePolicySettings : PolicySettings {
    IdlePolicySettings(
        VOID
        ) : PolicySettings()
    {
        WakeFromS0Capable = FALSE;
        UsbSSCapable = FALSE;
        PowerUpIdleDeviceOnSystemWake = FALSE;
        UsbSSCapabilityKnown = FALSE;
    }

    //
    // TRUE if the device capable of waking from S0
    //
    BOOLEAN WakeFromS0Capable;

    //
    // This member is meaningful only if the WakeFromS0Capable member (above) is
    // TRUE. The WakeFromS0Capable member indicates whether or not wake-from-S0
    // is currently enabled. If wake-from-S0 is currently enabled, the
    // UsbSSCapable member indicates whether the wake-from-S0 support is generic
    // or USB SS specific. If wake-from-S0 is not enabled, the UsbSSCapable
    // member is ignored.
    //
    BOOLEAN UsbSSCapable;

    //
    // TRUE if we know whether the device supports generic wake or USB SS wake.
    // This value is initialized to FALSE and remains FALSE until the first time
    // that the driver specifies S0-idle settings with an idle capability value
    // of IdleCanWakeFromS0 or IdleUsbSelectiveSuspend. When the driver
    // specifies one of these idle capabilities, this value is set to TRUE and
    // remains TRUE for the lifetime of the device.
    //
    BOOLEAN UsbSSCapabilityKnown;

    //
    // TRUE if idle enabled device should be powered up even when idle,
    // when resuming from Sx
    //
    BOOLEAN PowerUpIdleDeviceOnSystemWake;

    //
    // Member to manage interactions with the power manager for S0-idle support
    // on Win8 and above
    //
    IdleTimeoutManagement m_TimeoutMgmt;
};

struct WakePolicySettings : PolicySettings {
    WakePolicySettings(
        VOID
        ) : PolicySettings()
    {
        ArmForWakeIfChildrenAreArmedForWake = FALSE;
        IndicateChildWakeOnParentWake = FALSE;
    }

    //
    // TRUE if the device should arm for wake when one or more children are
    // armed for wake.
    //
    BOOLEAN ArmForWakeIfChildrenAreArmedForWake;

    //
    // TRUE if the device should propagate the wake status to its children.
    //
    BOOLEAN IndicateChildWakeOnParentWake;
};

struct FxPowerPolicyOwnerSettings : public FxStump {

friend FxPowerPolicyMachine;

public:
    FxPowerPolicyOwnerSettings(
        __in FxPkgPnp* PkgPnp
        );

    ~FxPowerPolicyOwnerSettings(
        VOID
        );

    _Must_inspect_result_
    NTSTATUS
    Init(
        VOID
        );

    VOID
    CleanupPowerCallback(
        VOID
        );

    VOID
    IncrementChildrenArmedForWakeCount(
        VOID
        )
    {
        InterlockedIncrement(&m_ChildrenArmedCount);
    }

    VOID
    DecrementChildrenArmedForWakeCount(
        VOID
        )
    {
        InterlockedDecrement(&m_ChildrenArmedCount);
    }

protected:
    static
    MdCallbackFunctionType
    _PowerStateCallback;

public:
    FxPowerIdleMachine m_PowerIdleMachine;
    FxPoxInterface m_PoxInterface;






    FxPowerDeviceArmWakeFromS0          m_DeviceArmWakeFromS0;
    FxPowerDeviceArmWakeFromSx          m_DeviceArmWakeFromSx;

    FxPowerDeviceDisarmWakeFromS0       m_DeviceDisarmWakeFromS0;
    FxPowerDeviceDisarmWakeFromSx       m_DeviceDisarmWakeFromSx;

    FxPowerDeviceWakeFromS0Triggered    m_DeviceWakeFromS0Triggered;
    FxPowerDeviceWakeFromSxTriggered    m_DeviceWakeFromSxTriggered;

    FxUsbIdleInfo* m_UsbIdle;

    FxPkgPnp* m_PkgPnp;

    WakePolicySettings m_WakeSettings;

    IdlePolicySettings m_IdleSettings;

    //
    // Nibble packed structure.  Each D state is encoded 4 bits.  The S state is
    // used as the "index" within the ULONG.  PowerSystemUnspecified is the
    // first 4 bits of the first byte, etc. etc. ...
    //
    ULONG m_SystemToDeviceStateMap;

    //
    // The number of children who are in the D0 state.  If this count is > 0,
    // then this parent cannot idle out while in S0.  Note that each child also
    // has an explicit call to PowerReference against this device which is used
    // to control the idle timer for this device.
    //
    ULONG m_ChildrenPoweredOnCount;

    //
    // The number of children who are currently armed for wake.  This count
    // can be used by the the wake owner to determine whether wake should be
    // enabled or not for a parent stack if arming for wake depends on
    // children being armed for wake.
    //
    LONG m_ChildrenArmedCount;

    //
    // The status of the last wait wake IRP to complete in the stack
    //
    NTSTATUS m_WaitWakeStatus;

    //
    // Dx state to put the device into when an Sx irp arrives and the device is
    // not armed for wake from Sx. DEVICE_POWER_STATE values are used.
    //
    BYTE m_IdealDxStateForSx;

    //
    // Track power requests to assert if someone other than this driver sent it
    // and to determine if this driver has received the requested irp (to catch
    // someone above completing irp w/o sending to this driver)
    //
    BOOLEAN m_RequestedPowerUpIrp;
    BOOLEAN m_RequestedPowerDownIrp;
    BOOLEAN m_RequestedWaitWakeIrp;

    //
    // Tracks wake event being dropped
    //
    BOOLEAN m_WakeCompletionEventDropped;

    BOOLEAN m_PowerFailed;

    //
    // Indicates whether we can cause paging I/O by writing to the registry
    //
    BOOLEAN m_CanSaveState;

    //
    // Guard to stop children from powering up while the parent is in Dx or
    // about to transition into Dx.
    //
    BOOLEAN m_ChildrenCanPowerUp;

    //
    // TRUE if our device caused the machine to wake up.  Access to this value
    // is not synchronized between the parent and PDO.  The parent sets it to
    // TRUE upon successful completion of the WW irp and cleared after
    // EvtDeviceDisarmWakeFromSx.  If a PDO's WW IRP is completed within this
    // window, the PDO's WW IRP will have PoSetSystemWake called on it.  It is
    // acceptable if the PDO's WW IRP completion races with the clearing of the
    // value and is not set as a source of wake.
    //
    BOOLEAN m_SystemWakeSource;

protected:
    PCALLBACK_OBJECT m_PowerCallbackObject;

    PVOID m_PowerCallbackRegistration;

    LONG m_WaitWakeCancelCompletionOwnership;

};

//
// This type of union is done so that we can
// 1) shrink the array element to the smallest size possible
// 2) keep types within the structure so we can dump it in the debugger
//
union FxPowerPolicyMachineStateHistory {
    struct {
        WDF_DEVICE_POWER_POLICY_STATE State1 : 16;
        WDF_DEVICE_POWER_POLICY_STATE State2 : 16;
        WDF_DEVICE_POWER_POLICY_STATE State3 : 16;
        WDF_DEVICE_POWER_POLICY_STATE State4 : 16;
        WDF_DEVICE_POWER_POLICY_STATE State5 : 16;
        WDF_DEVICE_POWER_POLICY_STATE State6 : 16;
        WDF_DEVICE_POWER_POLICY_STATE State7 : 16;
        WDF_DEVICE_POWER_POLICY_STATE State8 : 16;
    } S;

    USHORT History[FxPowerPolicyEventQueueDepth];
};

struct FxPowerPolicyMachine : public FxThreadedEventQueue {
    FxPowerPolicyMachine(
        VOID
        );

    ~FxPowerPolicyMachine(
        VOID
        );

    VOID
    UsbSSCallbackProcessingComplete(
        VOID
        );

    _Must_inspect_result_
    NTSTATUS
    InitUsbSS(
        VOID
        );

    VOID
    SetWaitWakeUnclaimed(
        VOID
        )
    {
        m_Owner->m_WaitWakeCancelCompletionOwnership = CancelOwnershipUnclaimed;
    }

    BOOLEAN
    CanCompleteWaitWakeIrp(
        VOID
        )
    {
        //
        // We have 2 potential call sites racing on trying to complete the wait
        // wake irp.  The first is the cancelling call site.  The other is the
        // irp's completion routine.  What we want is for the *2nd* (and last)
        // call site to actually complete the irp.  This is why we check to see
        // if the result of the exchange is that the ownership is already claimed
        // (and not unclaimed as one might first be led to think).
        //
        if (InterlockedExchange(&m_Owner->m_WaitWakeCancelCompletionOwnership,
                                CancelOwnershipClaimed) == CancelOwnershipClaimed) {
            return TRUE;
        }
        else {
            return FALSE;
        }
    }

public:
    FxPowerPolicyEvent m_Queue[FxPowerPolicyEventQueueDepth];

    FxPowerPolicyMachineStateHistory m_States;

    FxPowerPolicyOwnerSettings* m_Owner;

    union {
        ULONG m_SingularEventsPresent;

        union {
            //
            // These are defined so that we can easily tell in the debugger what
            // each set bit in m_SingularEventsPresent maps to in the
            // FxPowerPolicyEvent enum.
            //
            ULONG PwrPolStartKnown : 1;
            ULONG PwrPolStopKnown : 1;
            ULONG PwrPolSxKnown : 1;
            ULONG PwrPolS0Known : 1;
            ULONG PwrPolPowerDownKnown : 1;
            ULONG PwrPolPowerUpKnown : 1;
            ULONG PwrPolPowerDownIoStoppedKnown : 1;
            ULONG PwrPolPowerUpHwStartedKnown : 1;
            ULONG PwrPolWakeArrivedKnown : 1;
            ULONG PwrPolWakeSuccessKnown : 1;
            ULONG PwrPolWakeFailedKnown : 1;
            ULONG PwrPolIoPresentKnown : 1;
            ULONG PwrPolPowerTimeoutExpiredKnown : 1;
            ULONG PwrPolS0IdlePolicyChangedKnown : 1;
            ULONG PwrPolSurpriseRemoveKnown : 1;
            ULONG PwrPolUsbSelectiveSuspendCallbackKnown : 1;
            ULONG PwrPolUsbSelectiveSuspendCompletedKnown : 1;
            ULONG PwrPolPowerDownFailedKnown : 1;
            ULONG PwrPolPowerUpFailedKnown : 1;
        } m_SingularEventsPresentByName;
    };
};

#endif // _FXPOWERPOLICYSTATEMACHINE_H_