1 //
2 //    Copyright (C) Microsoft.  All rights reserved.
3 //
4 #ifndef _FXPOWERSTATEMACHINE_H_
5 #define _FXPOWERSTATEMACHINE_H_
6 
7 // @@SMVERIFY_SPLIT_BEGIN
8 //
9 // Treat these values as a bit field when comparing for known dropped events in
10 // the current state and treat them as values when they known transition events
11 // from state to the next.
12 //
13 enum FxPowerEvent {
14     PowerEventInvalid               = 0x0000,
15     PowerD0                         = 0x0001,
16     PowerDx                         = 0x0002,
17     PowerWakeArrival                = 0x0004,
18     PowerWakeSucceeded              = 0x0008,
19     PowerWakeFailed                 = 0x0010,
20     PowerWakeCanceled               = 0x0020,
21     PowerImplicitD0                 = 0x0040,
22     PowerImplicitD3                 = 0x0080,
23     PowerParentToD0                 = 0x0100,
24     PowerMarkPageable               = 0x0200,
25     PowerMarkNonpageable            = 0x0400,
26     PowerCompleteD0                 = 0x0800,
27     PowerCompleteDx                 = 0x1000,
28     PowerWakeInterruptCompleteTransition
29                                     = 0x2000,
30 
31     //
32     // Not a real event, just a value that indicates all of the events which
33     // goto the head of the queue and are always processed, even if the state is
34     // locked.
35     //
36     PowerPriorityEventsMask         = PowerParentToD0 |
37                                       PowerCompleteD0 |
38                                       PowerCompleteDx |
39                                       PowerWakeInterruptCompleteTransition,
40 
41     //
42     // Not a real event, just a value that indicate all of the events which
43     // should not be in the queue, if a similar event is already enqueued.
44     //
45     PowerSingularEventMask          = PowerParentToD0,
46 
47     PowerEventMaximum               = 0xFFFF,
48 };
49 
50 union FxPowerStateInfo {
51     struct {
52         //
53         // Is this a state where we rest and wait for events to bring us out
54         // of that state.
55         //
56         // NOTE:  this value is purely notational, we don't use it anywhere in
57         //        the state machine.  If need be, reuse this slot for something
58         //        else without worry.
59         //
60         ULONG QueueOpen : 1;
61 
62         //
63         // Bit of events we know we can drop in this state
64         //
65         ULONG KnownDroppedEvents : 31;
66     } Bits;
67 
68     struct {
69         //
70         // Maps to the same bit location as QueueOpen.  Since we start
71         // KnownDroppedEvents at the next bit, start our bits by at the next
72         // bit as well.
73         //
74         ULONG Reserved : 1;
75 
76         //
77         // These are defined so that we can easily tell in the debugger what
78         // each set bit in KnownDroppedEvents maps to in the FxPowerEvent enum
79         //
80         ULONG PowerD0Known : 1;
81         ULONG PowerDxKnown : 1;
82         ULONG PowerWakeArrivalKnown : 1;
83         ULONG PowerWakeSucceededKnown : 1;
84         ULONG PowerWakeFailedKnown : 1;
85         ULONG PowerWakeCanceledKnown : 1;
86         ULONG PowerImplicitD0Known : 1;
87         ULONG PowerImplicitD3Known : 1;
88         ULONG PowerParentToD0Known : 1;
89         ULONG PowerMarkPageableKnown : 1;
90         ULONG PowerMarkNonpageableKnown : 1;
91         ULONG PowerCompleteD0Known : 1;
92         ULONG PowerCompleteDxKnown : 1;
93     } BitsByName;
94 };
95 
96 
97 struct POWER_EVENT_TARGET_STATE {
98     FxPowerEvent            PowerEvent;
99 
100     WDF_DEVICE_POWER_STATE  TargetState;
101 
102     EVENT_TRAP_FIELD
103 };
104 
105 typedef const POWER_EVENT_TARGET_STATE* CPPPOWER_EVENT_TARGET_STATE;
106 
107 typedef
108 WDF_DEVICE_POWER_STATE
109 (*PFN_POWER_STATE_ENTRY_FUNCTION)(
110     FxPkgPnp*
111     );
112 
113 typedef struct POWER_STATE_TABLE {
114     //
115     // Function called when the state is entered
116     //
117     PFN_POWER_STATE_ENTRY_FUNCTION  StateFunc;
118 
119     //
120     // First state transition out of this state
121     //
122     POWER_EVENT_TARGET_STATE FirstTargetState;
123 
124     //
125     // Other state transitions out of this state if FirstTargetState is not
126     // matched.  This is an array where we expect the final element to be
127     // { PowerEventMaximum, WdfDevStatePowerNull }
128     //
129     CPPPOWER_EVENT_TARGET_STATE OtherTargetStates;
130 
131     FxPowerStateInfo StateInfo;
132 
133 } *PPOWER_STATE_TABLE;
134 
135 typedef const POWER_STATE_TABLE* CPPOWER_STATE_TABLE;
136 
137 #if FX_STATE_MACHINE_VERIFY
138 #define MAX_POWER_STATE_ENTRY_FN_RETURN_STATES    (5)
139 
140 struct POWER_STATE_ENTRY_FUNCTION_TARGET_STATE {
141     //
142     // Return value from state entry function
143     //
144     WDF_DEVICE_POWER_STATE State;
145 
146     //
147     // type of device the returning state applies to
148     //
149     FxStateMachineDeviceType  DeviceType;
150 
151     //
152     // Info about the state transition
153     //
154     PSTR Comment;
155 };
156 
157 struct POWER_STATE_ENTRY_FN_RETURN_STATE_TABLE {
158     //
159     // array of state transitions caused by state entry function
160     //
161     POWER_STATE_ENTRY_FUNCTION_TARGET_STATE TargetStates[MAX_POWER_STATE_ENTRY_FN_RETURN_STATES];
162 };
163 
164 typedef const POWER_STATE_ENTRY_FN_RETURN_STATE_TABLE*  CPPOWER_STATE_ENTRY_FN_RETURN_STATE_TABLE;
165 #endif  // FX_STATE_MACHINE_VERIFY
166 
167 // @@SMVERIFY_SPLIT_END
168 
169 //
170 // This type of union is done so that we can
171 // 1) shrink the array element to the smallest size possible
172 // 2) keep types within the structure so we can dump it in the debugger
173 //
174 union FxPowerMachineEventQueue {
175     struct {
176         FxPowerEvent Event1 : 16;
177         FxPowerEvent Event2 : 16;
178         FxPowerEvent Event3 : 16;
179         FxPowerEvent Event4 : 16;
180         FxPowerEvent Event5 : 16;
181         FxPowerEvent Event6 : 16;
182         FxPowerEvent Event7 : 16;
183         FxPowerEvent Event8 : 16;
184     } E;
185 
186     USHORT Events[PowerEventQueueDepth];
187 };
188 
189 //
190 // Same as FxPowerMachineEventQueue
191 //
192 union FxPowerMachineStateHistory {
193     struct {
194         WDF_DEVICE_POWER_STATE State1 : 16;
195         WDF_DEVICE_POWER_STATE State2 : 16;
196         WDF_DEVICE_POWER_STATE State3 : 16;
197         WDF_DEVICE_POWER_STATE State4 : 16;
198         WDF_DEVICE_POWER_STATE State5 : 16;
199         WDF_DEVICE_POWER_STATE State6 : 16;
200         WDF_DEVICE_POWER_STATE State7 : 16;
201         WDF_DEVICE_POWER_STATE State8 : 16;
202     } S;
203 
204     USHORT History[PowerEventQueueDepth];
205 };
206 
207 struct FxPowerMachine : public FxThreadedEventQueue {
208     FxPowerMachine(
209         VOID
210         ) : FxThreadedEventQueue(PowerEventQueueDepth)
211     {
212         //
213         // m_WaitWakeLock can not be initialized here since Initiliaze can
214         // return failure for UM. It's now being initialized in Init() function.
215         //
216 
217         InitializeListHead(&m_WaitWakeIrpToBeProcessedList);
218 
219         RtlZeroMemory(&m_Queue, sizeof(m_Queue));
220         RtlZeroMemory(&m_States, sizeof(m_States));
221 
222         m_States.History[IncrementHistoryIndex()] = WdfDevStatePowerObjectCreated;
223         m_IoCallbackFailure = FALSE;
224         m_PowerDownFailure = FALSE;
225         m_SingularEventsPresent = 0x0;
226     }
227 
228     _Must_inspect_result_
229     NTSTATUS
230     Init(
231         __inout FxPkgPnp* Pnp,
232         __in PFN_PNP_EVENT_WORKER WorkerRoutine
233         );
234 
235     FxPowerMachineEventQueue m_Queue;
236 
237     FxPowerMachineStateHistory m_States;
238 
239     //
240     // Lock to guard wait wake irp
241     //
242     MxLock m_WaitWakeLock;
243 
244     //
245     // List of wait wake requests which have either been completed or cancelled
246     // and we are waiting for the state machine to process and complete the irp.
247     //
248     // We require a list of irps (instead of just storage for one irp) because
249     // the power policy owner might be misbehaving and sending wake requests
250     // successively down the stack and we want the state machine to be able
251     // to keep track of all the requests.
252     //
253     LIST_ENTRY m_WaitWakeIrpToBeProcessedList;
254 
255     union {
256         USHORT m_SingularEventsPresent;
257 
258         union {
259             //
260             // These are defined so that we can easily tell in the debugger what
261             // each set bit in m_SingularEventsPresent maps to in the
262             // FxPowerEvent enum.
263             //
264             USHORT PowerD0Known : 1;
265             USHORT PowerDxKnown : 1;
266             USHORT PowerWakeArrivalKnown : 1;
267             USHORT PowerWakeSucceededKnown : 1;
268             USHORT PowerWakeFailedKnown : 1;
269             USHORT PowerWakeCanceledKnown : 1;
270             USHORT PowerImplicitD0Known : 1;
271             USHORT PowerImplicitD3Known : 1;
272             USHORT PowerParentToD0Known : 1;
273             USHORT PowerMarkPageableKnown : 1;
274             USHORT PowerMarkNonpageableKnown : 1;
275             USHORT PowerCompleteD0Known : 1;
276             USHORT PowerCompleteDxKnown : 1;
277         } m_SingularEventsPresentByName;
278     };
279 
280     BOOLEAN m_IoCallbackFailure;
281 
282     BOOLEAN m_PowerDownFailure;
283 };
284 
285 #endif // _FXPOWERSTATEMACHINE_H_
286