1*8a978a17SVictor Perevertkin /*++
2*8a978a17SVictor Perevertkin 
3*8a978a17SVictor Perevertkin Copyright (c) Microsoft. All rights reserved.
4*8a978a17SVictor Perevertkin 
5*8a978a17SVictor Perevertkin Module Name:
6*8a978a17SVictor Perevertkin 
7*8a978a17SVictor Perevertkin     PowerIdleStateMachine.cpp
8*8a978a17SVictor Perevertkin 
9*8a978a17SVictor Perevertkin Abstract:
10*8a978a17SVictor Perevertkin 
11*8a978a17SVictor Perevertkin     This module implements the Power Policy idle state machine for the driver
12*8a978a17SVictor Perevertkin     framework.
13*8a978a17SVictor Perevertkin 
14*8a978a17SVictor Perevertkin Author:
15*8a978a17SVictor Perevertkin 
16*8a978a17SVictor Perevertkin 
17*8a978a17SVictor Perevertkin 
18*8a978a17SVictor Perevertkin Environment:
19*8a978a17SVictor Perevertkin 
20*8a978a17SVictor Perevertkin     Both kernel and user mode
21*8a978a17SVictor Perevertkin 
22*8a978a17SVictor Perevertkin Revision History:
23*8a978a17SVictor Perevertkin 
24*8a978a17SVictor Perevertkin 
25*8a978a17SVictor Perevertkin 
26*8a978a17SVictor Perevertkin --*/
27*8a978a17SVictor Perevertkin 
28*8a978a17SVictor Perevertkin #include "pnppriv.hpp"
29*8a978a17SVictor Perevertkin 
30*8a978a17SVictor Perevertkin extern "C" {
31*8a978a17SVictor Perevertkin #if defined(EVENT_TRACING)
32*8a978a17SVictor Perevertkin #include "PowerIdleStateMachine.tmh"
33*8a978a17SVictor Perevertkin #endif
34*8a978a17SVictor Perevertkin }
35*8a978a17SVictor Perevertkin 
36*8a978a17SVictor Perevertkin const FxPowerIdleTargetState FxPowerIdleMachine::m_StoppedStates[] =
37*8a978a17SVictor Perevertkin {
38*8a978a17SVictor Perevertkin     { PowerIdleEventStart, FxIdleStarted DEBUGGED_EVENT },
39*8a978a17SVictor Perevertkin };
40*8a978a17SVictor Perevertkin 
41*8a978a17SVictor Perevertkin const FxPowerIdleTargetState FxPowerIdleMachine::m_StartedStates[] =
42*8a978a17SVictor Perevertkin {
43*8a978a17SVictor Perevertkin     { PowerIdleEventPowerUpComplete, FxIdleStartedPowerUp DEBUGGED_EVENT },
44*8a978a17SVictor Perevertkin     { PowerIdleEventPowerUpFailed, FxIdleStartedPowerFailed DEBUGGED_EVENT },
45*8a978a17SVictor Perevertkin     { PowerIdleEventStop, FxIdleStopped DEBUGGED_EVENT },
46*8a978a17SVictor Perevertkin };
47*8a978a17SVictor Perevertkin 
48*8a978a17SVictor Perevertkin const FxPowerIdleTargetState FxPowerIdleMachine::m_DisabledStates[] =
49*8a978a17SVictor Perevertkin {
50*8a978a17SVictor Perevertkin     { PowerIdleEventEnabled, FxIdleCheckIoCount DEBUGGED_EVENT },
51*8a978a17SVictor Perevertkin     { PowerIdleEventDisabled, FxIdleDisabled DEBUGGED_EVENT },
52*8a978a17SVictor Perevertkin     { PowerIdleEventPowerDown, FxIdleGoingToDx DEBUGGED_EVENT },
53*8a978a17SVictor Perevertkin     { PowerIdleEventPowerDownFailed, FxIdlePowerFailed DEBUGGED_EVENT },
54*8a978a17SVictor Perevertkin     { PowerIdleEventPowerUpFailed, FxIdlePowerFailed DEBUGGED_EVENT },
55*8a978a17SVictor Perevertkin     { PowerIdleEventStop, FxIdleStopped DEBUGGED_EVENT },
56*8a978a17SVictor Perevertkin };
57*8a978a17SVictor Perevertkin 
58*8a978a17SVictor Perevertkin const FxPowerIdleTargetState FxPowerIdleMachine::m_BusyStates[] =
59*8a978a17SVictor Perevertkin {
60*8a978a17SVictor Perevertkin     { PowerIdleEventIoDecrement, FxIdleDecrementIo DEBUGGED_EVENT },
61*8a978a17SVictor Perevertkin     { PowerIdleEventDisabled, FxIdleDisabled DEBUGGED_EVENT },
62*8a978a17SVictor Perevertkin     { PowerIdleEventPowerDown, FxIdleGoingToDx TRAP_ON_EVENT },
63*8a978a17SVictor Perevertkin     { PowerIdleEventPowerDownFailed, FxIdlePowerFailed TRAP_ON_EVENT },
64*8a978a17SVictor Perevertkin };
65*8a978a17SVictor Perevertkin 
66*8a978a17SVictor Perevertkin const FxPowerIdleTargetState FxPowerIdleMachine::m_TimerRunningStates[] =
67*8a978a17SVictor Perevertkin {
68*8a978a17SVictor Perevertkin     { PowerIdleEventDisabled, FxIdleDisabling DEBUGGED_EVENT },
69*8a978a17SVictor Perevertkin     { PowerIdleEventIoIncrement, FxIdleCancelTimer DEBUGGED_EVENT },
70*8a978a17SVictor Perevertkin     { PowerIdleEventEnabled, FxIdleCancelTimer DEBUGGED_EVENT },
71*8a978a17SVictor Perevertkin     { PowerIdleEventTimerExpired, FxIdleTimingOut DEBUGGED_EVENT },
72*8a978a17SVictor Perevertkin };
73*8a978a17SVictor Perevertkin 
74*8a978a17SVictor Perevertkin const FxPowerIdleTargetState FxPowerIdleMachine::m_TimedOutStates[] =
75*8a978a17SVictor Perevertkin {
76*8a978a17SVictor Perevertkin     { PowerIdleEventPowerDown, FxIdleTimedOutPowerDown DEBUGGED_EVENT },
77*8a978a17SVictor Perevertkin     { PowerIdleEventPowerDownFailed, FxIdleTimedOutPowerDownFailed DEBUGGED_EVENT },
78*8a978a17SVictor Perevertkin     { PowerIdleEventDisabled, FxIdleTimedOutDisabled DEBUGGED_EVENT },
79*8a978a17SVictor Perevertkin     { PowerIdleEventEnabled, FxIdleTimedOutEnabled DEBUGGED_EVENT },
80*8a978a17SVictor Perevertkin     { PowerIdleEventIoIncrement, FxIdleTimedOutIoIncrement DEBUGGED_EVENT },
81*8a978a17SVictor Perevertkin };
82*8a978a17SVictor Perevertkin 
83*8a978a17SVictor Perevertkin const FxPowerIdleTargetState FxPowerIdleMachine::m_InDxStates[] =
84*8a978a17SVictor Perevertkin {
85*8a978a17SVictor Perevertkin     { PowerIdleEventPowerUpComplete, FxIdlePowerUp DEBUGGED_EVENT },
86*8a978a17SVictor Perevertkin     { PowerIdleEventPowerUpFailed, FxIdleInDxPowerUpFailure DEBUGGED_EVENT },
87*8a978a17SVictor Perevertkin     { PowerIdleEventPowerDownFailed, FxIdleInDxPowerUpFailure TRAP_ON_EVENT },
88*8a978a17SVictor Perevertkin     { PowerIdleEventStop, FxIdleInDxStopped DEBUGGED_EVENT },
89*8a978a17SVictor Perevertkin     { PowerIdleEventDisabled, FxIdleInDxDisabled DEBUGGED_EVENT },
90*8a978a17SVictor Perevertkin     { PowerIdleEventIoIncrement, FxIdleInDxIoIncrement DEBUGGED_EVENT },
91*8a978a17SVictor Perevertkin     { PowerIdleEventIoDecrement, FxIdleInDx DEBUGGED_EVENT },
92*8a978a17SVictor Perevertkin     { PowerIdleEventPowerDown, FxIdleInDx DEBUGGED_EVENT },
93*8a978a17SVictor Perevertkin     { PowerIdleEventEnabled, FxIdleInDxEnabled DEBUGGED_EVENT },
94*8a978a17SVictor Perevertkin };
95*8a978a17SVictor Perevertkin 
96*8a978a17SVictor Perevertkin const FxPowerIdleTargetState FxPowerIdleMachine::m_WaitForTimeoutStates[] =
97*8a978a17SVictor Perevertkin {
98*8a978a17SVictor Perevertkin     { PowerIdleEventTimerExpired, FxIdleTimerExpired DEBUGGED_EVENT },
99*8a978a17SVictor Perevertkin     { PowerIdleEventPowerDownFailed, FxIdlePowerFailedWaitForTimeout TRAP_ON_EVENT },
100*8a978a17SVictor Perevertkin     { PowerIdleEventDisabled, FxIdleDisablingWaitForTimeout DEBUGGED_EVENT },
101*8a978a17SVictor Perevertkin };
102*8a978a17SVictor Perevertkin 
103*8a978a17SVictor Perevertkin const FxPowerIdleTargetState FxPowerIdleMachine::m_DisablingWaitForTimeoutStates[] =
104*8a978a17SVictor Perevertkin {
105*8a978a17SVictor Perevertkin     { PowerIdleEventTimerExpired, FxIdleDisablingTimerExpired DEBUGGED_EVENT },
106*8a978a17SVictor Perevertkin };
107*8a978a17SVictor Perevertkin 
108*8a978a17SVictor Perevertkin const FxPowerIdleTargetState FxPowerIdleMachine::m_PowerFailedWaitForTimeoutStates[] =
109*8a978a17SVictor Perevertkin {
110*8a978a17SVictor Perevertkin     { PowerIdleEventTimerExpired, FxIdlePowerFailed TRAP_ON_EVENT },
111*8a978a17SVictor Perevertkin };
112*8a978a17SVictor Perevertkin 
113*8a978a17SVictor Perevertkin const FxIdleStateTable FxPowerIdleMachine::m_StateTable[] =
114*8a978a17SVictor Perevertkin {
115*8a978a17SVictor Perevertkin     // FxIdleStopped
116*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::Stopped,
117*8a978a17SVictor Perevertkin         FxPowerIdleMachine::m_StoppedStates,
118*8a978a17SVictor Perevertkin         ARRAY_SIZE(FxPowerIdleMachine::m_StoppedStates),
119*8a978a17SVictor Perevertkin     },
120*8a978a17SVictor Perevertkin 
121*8a978a17SVictor Perevertkin     // FxIdleStarted
122*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::Started,
123*8a978a17SVictor Perevertkin         FxPowerIdleMachine::m_StartedStates,
124*8a978a17SVictor Perevertkin         ARRAY_SIZE(FxPowerIdleMachine::m_StartedStates),
125*8a978a17SVictor Perevertkin     },
126*8a978a17SVictor Perevertkin 
127*8a978a17SVictor Perevertkin     // FxIdleStartedPowerUp
128*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::StartedPowerUp,
129*8a978a17SVictor Perevertkin         NULL,
130*8a978a17SVictor Perevertkin         0,
131*8a978a17SVictor Perevertkin     },
132*8a978a17SVictor Perevertkin 
133*8a978a17SVictor Perevertkin     // FxIdleStartedPowerFailed
134*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::StartedPowerFailed,
135*8a978a17SVictor Perevertkin         NULL,
136*8a978a17SVictor Perevertkin         0,
137*8a978a17SVictor Perevertkin     },
138*8a978a17SVictor Perevertkin 
139*8a978a17SVictor Perevertkin     // FxIdleDisabled
140*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::Disabled,
141*8a978a17SVictor Perevertkin         FxPowerIdleMachine::m_DisabledStates,
142*8a978a17SVictor Perevertkin         ARRAY_SIZE(FxPowerIdleMachine::m_DisabledStates),
143*8a978a17SVictor Perevertkin     },
144*8a978a17SVictor Perevertkin 
145*8a978a17SVictor Perevertkin     // FxIdleCheckIoCount
146*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::CheckIoCount,
147*8a978a17SVictor Perevertkin         NULL,
148*8a978a17SVictor Perevertkin         0,
149*8a978a17SVictor Perevertkin     },
150*8a978a17SVictor Perevertkin 
151*8a978a17SVictor Perevertkin     // FxIdleBusy
152*8a978a17SVictor Perevertkin     {   NULL,
153*8a978a17SVictor Perevertkin         FxPowerIdleMachine::m_BusyStates,
154*8a978a17SVictor Perevertkin         ARRAY_SIZE(FxPowerIdleMachine::m_BusyStates),
155*8a978a17SVictor Perevertkin     },
156*8a978a17SVictor Perevertkin 
157*8a978a17SVictor Perevertkin     // FxIdleDecrementIo
158*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::DecrementIo,
159*8a978a17SVictor Perevertkin         NULL,
160*8a978a17SVictor Perevertkin         0,
161*8a978a17SVictor Perevertkin     },
162*8a978a17SVictor Perevertkin 
163*8a978a17SVictor Perevertkin     // FxIdleStartTimer
164*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::StartTimer,
165*8a978a17SVictor Perevertkin         NULL,
166*8a978a17SVictor Perevertkin         0,
167*8a978a17SVictor Perevertkin     },
168*8a978a17SVictor Perevertkin 
169*8a978a17SVictor Perevertkin     // FxIdleTimerRunning
170*8a978a17SVictor Perevertkin     {   NULL,
171*8a978a17SVictor Perevertkin         FxPowerIdleMachine::m_TimerRunningStates,
172*8a978a17SVictor Perevertkin         ARRAY_SIZE(FxPowerIdleMachine::m_TimerRunningStates)
173*8a978a17SVictor Perevertkin     },
174*8a978a17SVictor Perevertkin 
175*8a978a17SVictor Perevertkin     // FxIdleTimingOut
176*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::TimingOut,
177*8a978a17SVictor Perevertkin         NULL,
178*8a978a17SVictor Perevertkin         0,
179*8a978a17SVictor Perevertkin     },
180*8a978a17SVictor Perevertkin 
181*8a978a17SVictor Perevertkin     // FxIdleTimedOut
182*8a978a17SVictor Perevertkin     {   NULL,
183*8a978a17SVictor Perevertkin         FxPowerIdleMachine::m_TimedOutStates,
184*8a978a17SVictor Perevertkin         ARRAY_SIZE(FxPowerIdleMachine::m_TimedOutStates),
185*8a978a17SVictor Perevertkin     },
186*8a978a17SVictor Perevertkin 
187*8a978a17SVictor Perevertkin     // FxIdleTimedOutIoIncrement
188*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::TimedOutIoIncrement,
189*8a978a17SVictor Perevertkin         NULL,
190*8a978a17SVictor Perevertkin         0,
191*8a978a17SVictor Perevertkin     },
192*8a978a17SVictor Perevertkin 
193*8a978a17SVictor Perevertkin     // FxIdleTimedOutPowerDown
194*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::TimedOutPowerDown,
195*8a978a17SVictor Perevertkin         NULL,
196*8a978a17SVictor Perevertkin         0,
197*8a978a17SVictor Perevertkin     },
198*8a978a17SVictor Perevertkin 
199*8a978a17SVictor Perevertkin     // FxIdleTimedOutPowerDownFailed
200*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::TimedOutPowerDownFailed,
201*8a978a17SVictor Perevertkin         NULL,
202*8a978a17SVictor Perevertkin         0,
203*8a978a17SVictor Perevertkin     },
204*8a978a17SVictor Perevertkin 
205*8a978a17SVictor Perevertkin     // FxIdleGoingToDx,
206*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::GoingToDx,
207*8a978a17SVictor Perevertkin         NULL,
208*8a978a17SVictor Perevertkin         0,
209*8a978a17SVictor Perevertkin     },
210*8a978a17SVictor Perevertkin 
211*8a978a17SVictor Perevertkin     // FxIdleInDx,
212*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::InDx,
213*8a978a17SVictor Perevertkin         FxPowerIdleMachine::m_InDxStates,
214*8a978a17SVictor Perevertkin         ARRAY_SIZE(FxPowerIdleMachine::m_InDxStates),
215*8a978a17SVictor Perevertkin     },
216*8a978a17SVictor Perevertkin 
217*8a978a17SVictor Perevertkin     // FxIdleInDxIoIncrement
218*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::InDxIoIncrement,
219*8a978a17SVictor Perevertkin         NULL,
220*8a978a17SVictor Perevertkin         0,
221*8a978a17SVictor Perevertkin     },
222*8a978a17SVictor Perevertkin 
223*8a978a17SVictor Perevertkin     // FxIdleInDxPowerUpFailure
224*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::InDxPowerUpFailure,
225*8a978a17SVictor Perevertkin         NULL,
226*8a978a17SVictor Perevertkin         0,
227*8a978a17SVictor Perevertkin     },
228*8a978a17SVictor Perevertkin 
229*8a978a17SVictor Perevertkin     // FxIdleInDxStopped
230*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::InDxStopped,
231*8a978a17SVictor Perevertkin         NULL,
232*8a978a17SVictor Perevertkin         0,
233*8a978a17SVictor Perevertkin     },
234*8a978a17SVictor Perevertkin 
235*8a978a17SVictor Perevertkin     // FxIdleInDxDisabled
236*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::InDxDisabled,
237*8a978a17SVictor Perevertkin         NULL,
238*8a978a17SVictor Perevertkin         0,
239*8a978a17SVictor Perevertkin     },
240*8a978a17SVictor Perevertkin 
241*8a978a17SVictor Perevertkin     // FxIdleInDxEnabled
242*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::InDxEnabled,
243*8a978a17SVictor Perevertkin         NULL,
244*8a978a17SVictor Perevertkin         0,
245*8a978a17SVictor Perevertkin     },
246*8a978a17SVictor Perevertkin 
247*8a978a17SVictor Perevertkin     // FxIdlePowerUp
248*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::PowerUp,
249*8a978a17SVictor Perevertkin         NULL,
250*8a978a17SVictor Perevertkin         0,
251*8a978a17SVictor Perevertkin     },
252*8a978a17SVictor Perevertkin 
253*8a978a17SVictor Perevertkin     // FxIdlePowerUpComplete
254*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::PowerUpComplete,
255*8a978a17SVictor Perevertkin         NULL,
256*8a978a17SVictor Perevertkin         0,
257*8a978a17SVictor Perevertkin     },
258*8a978a17SVictor Perevertkin 
259*8a978a17SVictor Perevertkin     // FxIdleTimedOutDisabled
260*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::TimedOutDisabled,
261*8a978a17SVictor Perevertkin         NULL,
262*8a978a17SVictor Perevertkin         0,
263*8a978a17SVictor Perevertkin     },
264*8a978a17SVictor Perevertkin 
265*8a978a17SVictor Perevertkin     // FxIdleTimedOutEnabled
266*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::TimedOutEnabled,
267*8a978a17SVictor Perevertkin         NULL,
268*8a978a17SVictor Perevertkin         0,
269*8a978a17SVictor Perevertkin     },
270*8a978a17SVictor Perevertkin 
271*8a978a17SVictor Perevertkin     // FxIdleCancelTimer
272*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::CancelTimer,
273*8a978a17SVictor Perevertkin         NULL,
274*8a978a17SVictor Perevertkin         0,
275*8a978a17SVictor Perevertkin     },
276*8a978a17SVictor Perevertkin 
277*8a978a17SVictor Perevertkin     // FxIdleWaitForTimeout
278*8a978a17SVictor Perevertkin     {   NULL,
279*8a978a17SVictor Perevertkin         FxPowerIdleMachine::m_WaitForTimeoutStates,
280*8a978a17SVictor Perevertkin         ARRAY_SIZE(FxPowerIdleMachine::m_WaitForTimeoutStates),
281*8a978a17SVictor Perevertkin     },
282*8a978a17SVictor Perevertkin 
283*8a978a17SVictor Perevertkin     // FxIdleTimerExpired
284*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::TimerExpired,
285*8a978a17SVictor Perevertkin         NULL,
286*8a978a17SVictor Perevertkin         0,
287*8a978a17SVictor Perevertkin     },
288*8a978a17SVictor Perevertkin 
289*8a978a17SVictor Perevertkin     // FxIdleDisabling
290*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::Disabling,
291*8a978a17SVictor Perevertkin         NULL,
292*8a978a17SVictor Perevertkin         0,
293*8a978a17SVictor Perevertkin     },
294*8a978a17SVictor Perevertkin 
295*8a978a17SVictor Perevertkin     // FxIdleDisablingWaitForTimeout
296*8a978a17SVictor Perevertkin     {   NULL,
297*8a978a17SVictor Perevertkin         FxPowerIdleMachine::m_DisablingWaitForTimeoutStates,
298*8a978a17SVictor Perevertkin         ARRAY_SIZE(FxPowerIdleMachine::m_DisablingWaitForTimeoutStates),
299*8a978a17SVictor Perevertkin     },
300*8a978a17SVictor Perevertkin 
301*8a978a17SVictor Perevertkin     // FxIdleDisablingTimerExpired
302*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::DisablingTimerExpired,
303*8a978a17SVictor Perevertkin         NULL,
304*8a978a17SVictor Perevertkin         0,
305*8a978a17SVictor Perevertkin     },
306*8a978a17SVictor Perevertkin 
307*8a978a17SVictor Perevertkin     // FxIdlePowerFailedWaitForTimeout
308*8a978a17SVictor Perevertkin     {   NULL,
309*8a978a17SVictor Perevertkin         FxPowerIdleMachine::m_PowerFailedWaitForTimeoutStates,
310*8a978a17SVictor Perevertkin         ARRAY_SIZE(FxPowerIdleMachine::m_PowerFailedWaitForTimeoutStates),
311*8a978a17SVictor Perevertkin     },
312*8a978a17SVictor Perevertkin 
313*8a978a17SVictor Perevertkin     // FxIdlePowerFailed
314*8a978a17SVictor Perevertkin     {   FxPowerIdleMachine::PowerFailed,
315*8a978a17SVictor Perevertkin         NULL,
316*8a978a17SVictor Perevertkin         0,
317*8a978a17SVictor Perevertkin     },
318*8a978a17SVictor Perevertkin };
319*8a978a17SVictor Perevertkin 
320*8a978a17SVictor Perevertkin __inline
321*8a978a17SVictor Perevertkin FxPkgPnp*
GetPnpPkg(__inout FxPowerIdleMachine * This)322*8a978a17SVictor Perevertkin GetPnpPkg(
323*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
324*8a978a17SVictor Perevertkin     )
325*8a978a17SVictor Perevertkin {
326*8a978a17SVictor Perevertkin     return CONTAINING_RECORD(This,
327*8a978a17SVictor Perevertkin                              FxPowerPolicyOwnerSettings,
328*8a978a17SVictor Perevertkin                              m_PowerIdleMachine)->m_PkgPnp;
329*8a978a17SVictor Perevertkin }
330*8a978a17SVictor Perevertkin 
331*8a978a17SVictor Perevertkin 
FxPowerIdleMachine(VOID)332*8a978a17SVictor Perevertkin FxPowerIdleMachine::FxPowerIdleMachine(
333*8a978a17SVictor Perevertkin     VOID
334*8a978a17SVictor Perevertkin     )
335*8a978a17SVictor Perevertkin /*++
336*8a978a17SVictor Perevertkin 
337*8a978a17SVictor Perevertkin Routine Description:
338*8a978a17SVictor Perevertkin     Constructs the power idle state machine
339*8a978a17SVictor Perevertkin 
340*8a978a17SVictor Perevertkin Arguments:
341*8a978a17SVictor Perevertkin     None
342*8a978a17SVictor Perevertkin 
343*8a978a17SVictor Perevertkin Return Value:
344*8a978a17SVictor Perevertkin     None
345*8a978a17SVictor Perevertkin 
346*8a978a17SVictor Perevertkin   --*/
347*8a978a17SVictor Perevertkin {
348*8a978a17SVictor Perevertkin     //
349*8a978a17SVictor Perevertkin     // m_Lock and m_PowerTimeoutTimer are now being initialized in Init method
350*8a978a17SVictor Perevertkin     // since they may fail for UM.
351*8a978a17SVictor Perevertkin     //
352*8a978a17SVictor Perevertkin 
353*8a978a17SVictor Perevertkin     m_PowerTimeout.QuadPart = 0;
354*8a978a17SVictor Perevertkin     m_CurrentIdleState = FxIdleStopped;
355*8a978a17SVictor Perevertkin 
356*8a978a17SVictor Perevertkin     m_EventHistoryIndex = 0;
357*8a978a17SVictor Perevertkin     m_StateHistoryIndex = 0;
358*8a978a17SVictor Perevertkin 
359*8a978a17SVictor Perevertkin     RtlZeroMemory(&m_EventHistory[0], sizeof(m_EventHistory));
360*8a978a17SVictor Perevertkin     RtlZeroMemory(&m_StateHistory[0], sizeof(m_StateHistory));
361*8a978a17SVictor Perevertkin 
362*8a978a17SVictor Perevertkin     m_TagTracker = NULL;
363*8a978a17SVictor Perevertkin }
364*8a978a17SVictor Perevertkin 
~FxPowerIdleMachine(VOID)365*8a978a17SVictor Perevertkin FxPowerIdleMachine::~FxPowerIdleMachine(
366*8a978a17SVictor Perevertkin     VOID
367*8a978a17SVictor Perevertkin     )
368*8a978a17SVictor Perevertkin {
369*8a978a17SVictor Perevertkin     if (m_TagTracker != NULL) {
370*8a978a17SVictor Perevertkin         delete m_TagTracker;
371*8a978a17SVictor Perevertkin         m_TagTracker = NULL;
372*8a978a17SVictor Perevertkin     }
373*8a978a17SVictor Perevertkin }
374*8a978a17SVictor Perevertkin 
375*8a978a17SVictor Perevertkin _Must_inspect_result_
376*8a978a17SVictor Perevertkin NTSTATUS
Init(VOID)377*8a978a17SVictor Perevertkin FxPowerIdleMachine::Init(
378*8a978a17SVictor Perevertkin     VOID
379*8a978a17SVictor Perevertkin     )
380*8a978a17SVictor Perevertkin {
381*8a978a17SVictor Perevertkin     NTSTATUS status;
382*8a978a17SVictor Perevertkin 
383*8a978a17SVictor Perevertkin     //
384*8a978a17SVictor Perevertkin     // For KM, event initialize always succeeds. For UM, it might fail.
385*8a978a17SVictor Perevertkin     //
386*8a978a17SVictor Perevertkin     status = m_D0NotificationEvent.Initialize(NotificationEvent, TRUE);
387*8a978a17SVictor Perevertkin     if (!NT_SUCCESS(status)) {
388*8a978a17SVictor Perevertkin         return status;
389*8a978a17SVictor Perevertkin     }
390*8a978a17SVictor Perevertkin 
391*8a978a17SVictor Perevertkin     //
392*8a978a17SVictor Perevertkin     // For KM, timer initialize always succeeds. For UM, it might fail.
393*8a978a17SVictor Perevertkin     //
394*8a978a17SVictor Perevertkin     status = m_PowerTimeoutTimer.Initialize(this, _PowerTimeoutDpcRoutine, 0);
395*8a978a17SVictor Perevertkin     if (!NT_SUCCESS(status)) {
396*8a978a17SVictor Perevertkin         return status;
397*8a978a17SVictor Perevertkin     }
398*8a978a17SVictor Perevertkin 
399*8a978a17SVictor Perevertkin     Reset();
400*8a978a17SVictor Perevertkin 
401*8a978a17SVictor Perevertkin     return STATUS_SUCCESS;
402*8a978a17SVictor Perevertkin }
403*8a978a17SVictor Perevertkin 
404*8a978a17SVictor Perevertkin VOID
CheckAssumptions(VOID)405*8a978a17SVictor Perevertkin FxPowerIdleMachine::CheckAssumptions(
406*8a978a17SVictor Perevertkin     VOID
407*8a978a17SVictor Perevertkin     )
408*8a978a17SVictor Perevertkin /*++
409*8a978a17SVictor Perevertkin 
410*8a978a17SVictor Perevertkin Routine Description:
411*8a978a17SVictor Perevertkin     This routine is never actually called by running code, it just has
412*8a978a17SVictor Perevertkin     WDFCASSERTs who upon failure, would not allow this file to be compiled.
413*8a978a17SVictor Perevertkin 
414*8a978a17SVictor Perevertkin     DO NOT REMOVE THIS FUNCTION just because it is not called by any running
415*8a978a17SVictor Perevertkin     code.
416*8a978a17SVictor Perevertkin 
417*8a978a17SVictor Perevertkin Arguments:
418*8a978a17SVictor Perevertkin     None
419*8a978a17SVictor Perevertkin 
420*8a978a17SVictor Perevertkin Return Value:
421*8a978a17SVictor Perevertkin     None
422*8a978a17SVictor Perevertkin 
423*8a978a17SVictor Perevertkin   --*/
424*8a978a17SVictor Perevertkin {
425*8a978a17SVictor Perevertkin     WDFCASSERT((sizeof(m_StateTable)/sizeof(m_StateTable[0]))
426*8a978a17SVictor Perevertkin                ==
427*8a978a17SVictor Perevertkin                (FxIdleMax - FxIdleStopped));
428*8a978a17SVictor Perevertkin }
429*8a978a17SVictor Perevertkin 
430*8a978a17SVictor Perevertkin FxPowerIdleStates
Stopped(__inout FxPowerIdleMachine * This)431*8a978a17SVictor Perevertkin FxPowerIdleMachine::Stopped(
432*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
433*8a978a17SVictor Perevertkin     )
434*8a978a17SVictor Perevertkin /*++
435*8a978a17SVictor Perevertkin 
436*8a978a17SVictor Perevertkin Routine Description:
437*8a978a17SVictor Perevertkin     State machine has entered the stopped state, clear the started flag
438*8a978a17SVictor Perevertkin 
439*8a978a17SVictor Perevertkin Arguments:
440*8a978a17SVictor Perevertkin     This - instance of the state machine
441*8a978a17SVictor Perevertkin 
442*8a978a17SVictor Perevertkin Return Value:
443*8a978a17SVictor Perevertkin     FxIdleMax
444*8a978a17SVictor Perevertkin 
445*8a978a17SVictor Perevertkin   --*/
446*8a978a17SVictor Perevertkin {
447*8a978a17SVictor Perevertkin     This->m_Flags &= ~FxPowerIdleIsStarted;
448*8a978a17SVictor Perevertkin 
449*8a978a17SVictor Perevertkin     return FxIdleMax;
450*8a978a17SVictor Perevertkin }
451*8a978a17SVictor Perevertkin 
452*8a978a17SVictor Perevertkin FxPowerIdleStates
Started(__inout FxPowerIdleMachine * This)453*8a978a17SVictor Perevertkin FxPowerIdleMachine::Started(
454*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
455*8a978a17SVictor Perevertkin     )
456*8a978a17SVictor Perevertkin /*++
457*8a978a17SVictor Perevertkin 
458*8a978a17SVictor Perevertkin Routine Description:
459*8a978a17SVictor Perevertkin     State machine has entered the started state, set the started flag
460*8a978a17SVictor Perevertkin 
461*8a978a17SVictor Perevertkin Arguments:
462*8a978a17SVictor Perevertkin     This - instance of the state machine
463*8a978a17SVictor Perevertkin 
464*8a978a17SVictor Perevertkin Return Value:
465*8a978a17SVictor Perevertkin     FxIdleMax
466*8a978a17SVictor Perevertkin 
467*8a978a17SVictor Perevertkin   --*/
468*8a978a17SVictor Perevertkin {
469*8a978a17SVictor Perevertkin     This->m_Flags |= FxPowerIdleIsStarted;
470*8a978a17SVictor Perevertkin 
471*8a978a17SVictor Perevertkin     //
472*8a978a17SVictor Perevertkin     // We are in the started state, but we are not powered up.
473*8a978a17SVictor Perevertkin     //
474*8a978a17SVictor Perevertkin     This->m_D0NotificationEvent.Clear();
475*8a978a17SVictor Perevertkin 
476*8a978a17SVictor Perevertkin     return FxIdleMax;
477*8a978a17SVictor Perevertkin }
478*8a978a17SVictor Perevertkin 
479*8a978a17SVictor Perevertkin FxPowerIdleStates
StartedPowerUp(__inout FxPowerIdleMachine * This)480*8a978a17SVictor Perevertkin FxPowerIdleMachine::StartedPowerUp(
481*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
482*8a978a17SVictor Perevertkin     )
483*8a978a17SVictor Perevertkin /*++
484*8a978a17SVictor Perevertkin 
485*8a978a17SVictor Perevertkin Routine Description:
486*8a978a17SVictor Perevertkin     We were in the started and powered off state.  We are powered up,
487*8a978a17SVictor Perevertkin     so set the event now so that we can wake up any waiters.
488*8a978a17SVictor Perevertkin 
489*8a978a17SVictor Perevertkin Arguments:
490*8a978a17SVictor Perevertkin     This - instance of the state machine
491*8a978a17SVictor Perevertkin 
492*8a978a17SVictor Perevertkin Return Value:
493*8a978a17SVictor Perevertkin     FxIdleDisabled
494*8a978a17SVictor Perevertkin 
495*8a978a17SVictor Perevertkin   --*/
496*8a978a17SVictor Perevertkin {
497*8a978a17SVictor Perevertkin     //
498*8a978a17SVictor Perevertkin     // Moving from the started state to the powered on state
499*8a978a17SVictor Perevertkin     //
500*8a978a17SVictor Perevertkin     This->SendD0Notification();
501*8a978a17SVictor Perevertkin 
502*8a978a17SVictor Perevertkin     return FxIdleDisabled;
503*8a978a17SVictor Perevertkin }
504*8a978a17SVictor Perevertkin 
505*8a978a17SVictor Perevertkin FxPowerIdleStates
StartedPowerFailed(__inout FxPowerIdleMachine * This)506*8a978a17SVictor Perevertkin FxPowerIdleMachine::StartedPowerFailed(
507*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
508*8a978a17SVictor Perevertkin     )
509*8a978a17SVictor Perevertkin /*++
510*8a978a17SVictor Perevertkin 
511*8a978a17SVictor Perevertkin Routine Description:
512*8a978a17SVictor Perevertkin     The state machine was started, but the initial power up failed.  Mark the
513*8a978a17SVictor Perevertkin     failure.
514*8a978a17SVictor Perevertkin 
515*8a978a17SVictor Perevertkin Arguments:
516*8a978a17SVictor Perevertkin     This - instance of the state machine
517*8a978a17SVictor Perevertkin 
518*8a978a17SVictor Perevertkin Return Value:
519*8a978a17SVictor Perevertkin     FxIdleStarted
520*8a978a17SVictor Perevertkin 
521*8a978a17SVictor Perevertkin   --*/
522*8a978a17SVictor Perevertkin {
523*8a978a17SVictor Perevertkin     //
524*8a978a17SVictor Perevertkin     // Failed to initially power up
525*8a978a17SVictor Perevertkin     //
526*8a978a17SVictor Perevertkin     This->m_Flags |= FxPowerIdlePowerFailed;
527*8a978a17SVictor Perevertkin 
528*8a978a17SVictor Perevertkin     //
529*8a978a17SVictor Perevertkin     // We assume in the started state that the event is set
530*8a978a17SVictor Perevertkin     //
531*8a978a17SVictor Perevertkin     ASSERT(This->m_D0NotificationEvent.ReadState() == 0);
532*8a978a17SVictor Perevertkin 
533*8a978a17SVictor Perevertkin     return FxIdleStarted;
534*8a978a17SVictor Perevertkin }
535*8a978a17SVictor Perevertkin 
536*8a978a17SVictor Perevertkin FxPowerIdleStates
Disabled(__inout FxPowerIdleMachine * This)537*8a978a17SVictor Perevertkin FxPowerIdleMachine::Disabled(
538*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
539*8a978a17SVictor Perevertkin     )
540*8a978a17SVictor Perevertkin /*++
541*8a978a17SVictor Perevertkin 
542*8a978a17SVictor Perevertkin Routine Description:
543*8a978a17SVictor Perevertkin     State machine has entered the disabled state, unblock all waiters
544*8a978a17SVictor Perevertkin 
545*8a978a17SVictor Perevertkin Arguments:
546*8a978a17SVictor Perevertkin     This - instance of the state machine
547*8a978a17SVictor Perevertkin 
548*8a978a17SVictor Perevertkin Return Value:
549*8a978a17SVictor Perevertkin     FxIdleMax
550*8a978a17SVictor Perevertkin 
551*8a978a17SVictor Perevertkin   --*/
552*8a978a17SVictor Perevertkin 
553*8a978a17SVictor Perevertkin {
554*8a978a17SVictor Perevertkin     This->m_Flags &= ~FxPowerIdleTimerEnabled;
555*8a978a17SVictor Perevertkin 
556*8a978a17SVictor Perevertkin     return FxIdleMax;
557*8a978a17SVictor Perevertkin }
558*8a978a17SVictor Perevertkin 
559*8a978a17SVictor Perevertkin FxPowerIdleStates
CheckIoCount(__inout FxPowerIdleMachine * This)560*8a978a17SVictor Perevertkin FxPowerIdleMachine::CheckIoCount(
561*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
562*8a978a17SVictor Perevertkin     )
563*8a978a17SVictor Perevertkin /*++
564*8a978a17SVictor Perevertkin 
565*8a978a17SVictor Perevertkin Routine Description:
566*8a978a17SVictor Perevertkin     Checks the IO count and transitions the appropriate state.   This is the
567*8a978a17SVictor Perevertkin     first state we are in after being disabled or after transitioning from Dx to
568*8a978a17SVictor Perevertkin     D0.
569*8a978a17SVictor Perevertkin 
570*8a978a17SVictor Perevertkin Arguments:
571*8a978a17SVictor Perevertkin     This - instance of the state machine
572*8a978a17SVictor Perevertkin 
573*8a978a17SVictor Perevertkin Return Value:
574*8a978a17SVictor Perevertkin     new state machine state
575*8a978a17SVictor Perevertkin 
576*8a978a17SVictor Perevertkin   --*/
577*8a978a17SVictor Perevertkin {
578*8a978a17SVictor Perevertkin     This->m_Flags |= FxPowerIdleTimerEnabled;
579*8a978a17SVictor Perevertkin 
580*8a978a17SVictor Perevertkin     if (This->m_IoCount == 0) {
581*8a978a17SVictor Perevertkin         return FxIdleStartTimer;
582*8a978a17SVictor Perevertkin     }
583*8a978a17SVictor Perevertkin     else {
584*8a978a17SVictor Perevertkin         return FxIdleBusy;
585*8a978a17SVictor Perevertkin     }
586*8a978a17SVictor Perevertkin }
587*8a978a17SVictor Perevertkin 
588*8a978a17SVictor Perevertkin FxPowerIdleStates
DecrementIo(__inout FxPowerIdleMachine * This)589*8a978a17SVictor Perevertkin FxPowerIdleMachine::DecrementIo(
590*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
591*8a978a17SVictor Perevertkin     )
592*8a978a17SVictor Perevertkin /*++
593*8a978a17SVictor Perevertkin 
594*8a978a17SVictor Perevertkin Routine Description:
595*8a978a17SVictor Perevertkin     Checks the IO count and returns a new state
596*8a978a17SVictor Perevertkin 
597*8a978a17SVictor Perevertkin Arguments:
598*8a978a17SVictor Perevertkin     This - instance of the state machine
599*8a978a17SVictor Perevertkin 
600*8a978a17SVictor Perevertkin Return Value:
601*8a978a17SVictor Perevertkin     new state machine state
602*8a978a17SVictor Perevertkin 
603*8a978a17SVictor Perevertkin   --*/
604*8a978a17SVictor Perevertkin {
605*8a978a17SVictor Perevertkin     if (This->m_IoCount == 0) {
606*8a978a17SVictor Perevertkin         return FxIdleStartTimer;
607*8a978a17SVictor Perevertkin     }
608*8a978a17SVictor Perevertkin     else {
609*8a978a17SVictor Perevertkin         return FxIdleBusy;
610*8a978a17SVictor Perevertkin     }
611*8a978a17SVictor Perevertkin }
612*8a978a17SVictor Perevertkin 
613*8a978a17SVictor Perevertkin FxPowerIdleStates
StartTimer(__inout FxPowerIdleMachine * This)614*8a978a17SVictor Perevertkin FxPowerIdleMachine::StartTimer(
615*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
616*8a978a17SVictor Perevertkin     )
617*8a978a17SVictor Perevertkin /*++
618*8a978a17SVictor Perevertkin 
619*8a978a17SVictor Perevertkin Routine Description:
620*8a978a17SVictor Perevertkin     The io count is now at zero.  Start the idle timer so that when it expires,
621*8a978a17SVictor Perevertkin     the device will move into Dx.
622*8a978a17SVictor Perevertkin 
623*8a978a17SVictor Perevertkin Arguments:
624*8a978a17SVictor Perevertkin     This - instance of the state machine
625*8a978a17SVictor Perevertkin 
626*8a978a17SVictor Perevertkin Return Value:
627*8a978a17SVictor Perevertkin     FxIdleMax
628*8a978a17SVictor Perevertkin 
629*8a978a17SVictor Perevertkin   --*/
630*8a978a17SVictor Perevertkin {
631*8a978a17SVictor Perevertkin     ASSERT((This->m_Flags & FxPowerIdleTimerEnabled) && This->m_IoCount == 0);
632*8a978a17SVictor Perevertkin 
633*8a978a17SVictor Perevertkin     This->m_Flags |= FxPowerIdleTimerStarted;
634*8a978a17SVictor Perevertkin     This->m_PowerTimeoutTimer.Start(This->m_PowerTimeout,
635*8a978a17SVictor Perevertkin                                     m_IdleTimerTolerableDelayMS);
636*8a978a17SVictor Perevertkin 
637*8a978a17SVictor Perevertkin     return FxIdleTimerRunning;
638*8a978a17SVictor Perevertkin }
639*8a978a17SVictor Perevertkin 
640*8a978a17SVictor Perevertkin 
641*8a978a17SVictor Perevertkin FxPowerIdleStates
TimingOut(__inout FxPowerIdleMachine * This)642*8a978a17SVictor Perevertkin FxPowerIdleMachine::TimingOut(
643*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
644*8a978a17SVictor Perevertkin     )
645*8a978a17SVictor Perevertkin /*++
646*8a978a17SVictor Perevertkin 
647*8a978a17SVictor Perevertkin Routine Description:
648*8a978a17SVictor Perevertkin     The idle timer has expired. Indicate to the power policy state machine
649*8a978a17SVictor Perevertkin     that it should power down.
650*8a978a17SVictor Perevertkin 
651*8a978a17SVictor Perevertkin Arguments:
652*8a978a17SVictor Perevertkin     This - instance of the state machine
653*8a978a17SVictor Perevertkin 
654*8a978a17SVictor Perevertkin Return Value:
655*8a978a17SVictor Perevertkin     FxIdleTimedOut
656*8a978a17SVictor Perevertkin 
657*8a978a17SVictor Perevertkin   --*/
658*8a978a17SVictor Perevertkin {
659*8a978a17SVictor Perevertkin #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
660*8a978a17SVictor Perevertkin     GetPnpPkg(This)->PowerPolicyProcessEvent(PwrPolPowerTimeoutExpired);
661*8a978a17SVictor Perevertkin #else
662*8a978a17SVictor Perevertkin     GetPnpPkg(This)->PowerPolicyProcessEvent(
663*8a978a17SVictor Perevertkin         PwrPolPowerTimeoutExpired,
664*8a978a17SVictor Perevertkin         TRUE // ProcessEventOnDifferentThread
665*8a978a17SVictor Perevertkin         );
666*8a978a17SVictor Perevertkin #endif
667*8a978a17SVictor Perevertkin 
668*8a978a17SVictor Perevertkin     //
669*8a978a17SVictor Perevertkin     // Timer is no longer running.  Used when we disable the state machine and
670*8a978a17SVictor Perevertkin     // need to know the timer's running state.
671*8a978a17SVictor Perevertkin     //
672*8a978a17SVictor Perevertkin     //
673*8a978a17SVictor Perevertkin     This->m_Flags &= ~FxPowerIdleTimerStarted;
674*8a978a17SVictor Perevertkin 
675*8a978a17SVictor Perevertkin     //
676*8a978a17SVictor Perevertkin     // While the device is still powered up, we are no longer in D0 in terms of
677*8a978a17SVictor Perevertkin     // PowerReference returning immmediately if TRUE is specified to that call.
678*8a978a17SVictor Perevertkin     //
679*8a978a17SVictor Perevertkin     This->m_D0NotificationEvent.Clear();
680*8a978a17SVictor Perevertkin 
681*8a978a17SVictor Perevertkin     return FxIdleTimedOut;
682*8a978a17SVictor Perevertkin }
683*8a978a17SVictor Perevertkin 
684*8a978a17SVictor Perevertkin FxPowerIdleStates
TimedOutIoIncrement(__inout FxPowerIdleMachine * This)685*8a978a17SVictor Perevertkin FxPowerIdleMachine::TimedOutIoIncrement(
686*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
687*8a978a17SVictor Perevertkin     )
688*8a978a17SVictor Perevertkin /*++
689*8a978a17SVictor Perevertkin 
690*8a978a17SVictor Perevertkin Routine Description:
691*8a978a17SVictor Perevertkin     A power reference occurred after we notified the power policy machine of
692*8a978a17SVictor Perevertkin     a power timeout, but before we timed out. Send an io present event to the
693*8a978a17SVictor Perevertkin     power policy machine so that it can move into the D0 state/not timed out
694*8a978a17SVictor Perevertkin     state again.
695*8a978a17SVictor Perevertkin 
696*8a978a17SVictor Perevertkin Arguments:
697*8a978a17SVictor Perevertkin     This - instance of the state machine
698*8a978a17SVictor Perevertkin 
699*8a978a17SVictor Perevertkin Return Value:
700*8a978a17SVictor Perevertkin     FxIdleTimedOut
701*8a978a17SVictor Perevertkin 
702*8a978a17SVictor Perevertkin   --*/
703*8a978a17SVictor Perevertkin {
704*8a978a17SVictor Perevertkin     FxPkgPnp* pPkgPnp;
705*8a978a17SVictor Perevertkin 
706*8a978a17SVictor Perevertkin     pPkgPnp = GetPnpPkg(This);
707*8a978a17SVictor Perevertkin 
708*8a978a17SVictor Perevertkin     if (This->m_Flags & FxPowerIdleIoPresentSent) {
709*8a978a17SVictor Perevertkin         DoTraceLevelMessage(
710*8a978a17SVictor Perevertkin             pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
711*8a978a17SVictor Perevertkin             "WDFDEVICE %p idle (in D0) not sending io present event (already sent)",
712*8a978a17SVictor Perevertkin             pPkgPnp->GetDevice()->GetHandle());
713*8a978a17SVictor Perevertkin     }
714*8a978a17SVictor Perevertkin     else {
715*8a978a17SVictor Perevertkin #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
716*8a978a17SVictor Perevertkin         pPkgPnp->PowerPolicyProcessEvent(PwrPolIoPresent);
717*8a978a17SVictor Perevertkin #else
718*8a978a17SVictor Perevertkin         pPkgPnp->PowerPolicyProcessEvent(
719*8a978a17SVictor Perevertkin             PwrPolIoPresent,
720*8a978a17SVictor Perevertkin             TRUE // ProcessEventOnDifferentThread
721*8a978a17SVictor Perevertkin             );
722*8a978a17SVictor Perevertkin #endif
723*8a978a17SVictor Perevertkin 
724*8a978a17SVictor Perevertkin         This->m_Flags |= FxPowerIdleIoPresentSent;
725*8a978a17SVictor Perevertkin     }
726*8a978a17SVictor Perevertkin 
727*8a978a17SVictor Perevertkin     return FxIdleTimedOut;
728*8a978a17SVictor Perevertkin }
729*8a978a17SVictor Perevertkin 
730*8a978a17SVictor Perevertkin FxPowerIdleStates
TimedOutPowerDown(__inout FxPowerIdleMachine * This)731*8a978a17SVictor Perevertkin FxPowerIdleMachine::TimedOutPowerDown(
732*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
733*8a978a17SVictor Perevertkin     )
734*8a978a17SVictor Perevertkin /*++
735*8a978a17SVictor Perevertkin 
736*8a978a17SVictor Perevertkin Routine Description:
737*8a978a17SVictor Perevertkin     The idle timer fired and we are now powering down.  Clear the flag that
738*8a978a17SVictor Perevertkin     limits our sending of the io present event to one time while in the timed
739*8a978a17SVictor Perevertkin     out state.
740*8a978a17SVictor Perevertkin 
741*8a978a17SVictor Perevertkin Arguments:
742*8a978a17SVictor Perevertkin     This - instance of the state machine
743*8a978a17SVictor Perevertkin 
744*8a978a17SVictor Perevertkin Return Value:
745*8a978a17SVictor Perevertkin     FxIdleGoingToDx
746*8a978a17SVictor Perevertkin 
747*8a978a17SVictor Perevertkin   --*/
748*8a978a17SVictor Perevertkin {
749*8a978a17SVictor Perevertkin     //
750*8a978a17SVictor Perevertkin     // We can send the io present event again
751*8a978a17SVictor Perevertkin     //
752*8a978a17SVictor Perevertkin     This->m_Flags &= ~FxPowerIdleIoPresentSent;
753*8a978a17SVictor Perevertkin 
754*8a978a17SVictor Perevertkin     return FxIdleGoingToDx;
755*8a978a17SVictor Perevertkin }
756*8a978a17SVictor Perevertkin 
757*8a978a17SVictor Perevertkin FxPowerIdleStates
TimedOutPowerDownFailed(__inout FxPowerIdleMachine * This)758*8a978a17SVictor Perevertkin FxPowerIdleMachine::TimedOutPowerDownFailed(
759*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
760*8a978a17SVictor Perevertkin     )
761*8a978a17SVictor Perevertkin /*++
762*8a978a17SVictor Perevertkin 
763*8a978a17SVictor Perevertkin Routine Description:
764*8a978a17SVictor Perevertkin     The idle timer fired and we could no power down.  Clear the flag that
765*8a978a17SVictor Perevertkin     limits our sending of the io present event to one time while in the timed
766*8a978a17SVictor Perevertkin     out state.
767*8a978a17SVictor Perevertkin 
768*8a978a17SVictor Perevertkin Arguments:
769*8a978a17SVictor Perevertkin     This - instance of the state machine
770*8a978a17SVictor Perevertkin 
771*8a978a17SVictor Perevertkin Return Value:
772*8a978a17SVictor Perevertkin     FxIdlePowerFailed
773*8a978a17SVictor Perevertkin 
774*8a978a17SVictor Perevertkin   --*/
775*8a978a17SVictor Perevertkin {
776*8a978a17SVictor Perevertkin     //
777*8a978a17SVictor Perevertkin     // We can send the io present event again
778*8a978a17SVictor Perevertkin     //
779*8a978a17SVictor Perevertkin     This->m_Flags &= ~FxPowerIdleIoPresentSent;
780*8a978a17SVictor Perevertkin 
781*8a978a17SVictor Perevertkin     return FxIdlePowerFailed;
782*8a978a17SVictor Perevertkin }
783*8a978a17SVictor Perevertkin 
784*8a978a17SVictor Perevertkin FxPowerIdleStates
GoingToDx(__inout FxPowerIdleMachine * This)785*8a978a17SVictor Perevertkin FxPowerIdleMachine::GoingToDx(
786*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
787*8a978a17SVictor Perevertkin     )
788*8a978a17SVictor Perevertkin /*++
789*8a978a17SVictor Perevertkin 
790*8a978a17SVictor Perevertkin Routine Description:
791*8a978a17SVictor Perevertkin     The device is going into Dx.  It could be going into Dx because the idle
792*8a978a17SVictor Perevertkin     timer expired or because the machine is moving into Sx, the reason doesn't
793*8a978a17SVictor Perevertkin     matter though.  Clear the in D0 event.
794*8a978a17SVictor Perevertkin 
795*8a978a17SVictor Perevertkin Arguments:
796*8a978a17SVictor Perevertkin     This - instance of the state machine
797*8a978a17SVictor Perevertkin 
798*8a978a17SVictor Perevertkin Return Value:
799*8a978a17SVictor Perevertkin     FxIdleInDx
800*8a978a17SVictor Perevertkin 
801*8a978a17SVictor Perevertkin   --*/
802*8a978a17SVictor Perevertkin {
803*8a978a17SVictor Perevertkin     This->m_D0NotificationEvent.Clear();
804*8a978a17SVictor Perevertkin     return FxIdleInDx;
805*8a978a17SVictor Perevertkin }
806*8a978a17SVictor Perevertkin 
807*8a978a17SVictor Perevertkin FxPowerIdleStates
InDx(__inout FxPowerIdleMachine * This)808*8a978a17SVictor Perevertkin FxPowerIdleMachine::InDx(
809*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
810*8a978a17SVictor Perevertkin     )
811*8a978a17SVictor Perevertkin /*++
812*8a978a17SVictor Perevertkin 
813*8a978a17SVictor Perevertkin Routine Description:
814*8a978a17SVictor Perevertkin     The device has moved into Dx.   If there is no pending io, mark the device
815*8a978a17SVictor Perevertkin     as idle.  We can be in Dx with pending io if IoIncrement was called after
816*8a978a17SVictor Perevertkin     the device moved into Dx.
817*8a978a17SVictor Perevertkin 
818*8a978a17SVictor Perevertkin Arguments:
819*8a978a17SVictor Perevertkin     This - instance of the state machine
820*8a978a17SVictor Perevertkin 
821*8a978a17SVictor Perevertkin Return Value:
822*8a978a17SVictor Perevertkin     FxIdleMax
823*8a978a17SVictor Perevertkin 
824*8a978a17SVictor Perevertkin   --*/
825*8a978a17SVictor Perevertkin {
826*8a978a17SVictor Perevertkin     This->m_Flags |= FxPowerIdleInDx;
827*8a978a17SVictor Perevertkin 
828*8a978a17SVictor Perevertkin     return FxIdleMax;
829*8a978a17SVictor Perevertkin }
830*8a978a17SVictor Perevertkin 
831*8a978a17SVictor Perevertkin FxPowerIdleStates
InDxIoIncrement(__inout FxPowerIdleMachine * This)832*8a978a17SVictor Perevertkin FxPowerIdleMachine::InDxIoIncrement(
833*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
834*8a978a17SVictor Perevertkin     )
835*8a978a17SVictor Perevertkin /*++
836*8a978a17SVictor Perevertkin 
837*8a978a17SVictor Perevertkin Routine Description:
838*8a978a17SVictor Perevertkin     In Dx and the io count went up.  Send the event to the power policy state
839*8a978a17SVictor Perevertkin     machine indicating new io is present.
840*8a978a17SVictor Perevertkin 
841*8a978a17SVictor Perevertkin Arguments:
842*8a978a17SVictor Perevertkin     This - instance of the state machine
843*8a978a17SVictor Perevertkin 
844*8a978a17SVictor Perevertkin Return Value:
845*8a978a17SVictor Perevertkin     FxIdleInDx
846*8a978a17SVictor Perevertkin 
847*8a978a17SVictor Perevertkin   --*/
848*8a978a17SVictor Perevertkin {
849*8a978a17SVictor Perevertkin     FxPkgPnp* pPkgPnp;
850*8a978a17SVictor Perevertkin 
851*8a978a17SVictor Perevertkin     pPkgPnp = GetPnpPkg(This);
852*8a978a17SVictor Perevertkin 
853*8a978a17SVictor Perevertkin     if (This->m_Flags & FxPowerIdleIoPresentSent) {
854*8a978a17SVictor Perevertkin         DoTraceLevelMessage(
855*8a978a17SVictor Perevertkin             pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
856*8a978a17SVictor Perevertkin             "WDFDEVICE %p idle (in Dx) not sending io present event (already sent)",
857*8a978a17SVictor Perevertkin             pPkgPnp->GetDevice()->GetHandle());
858*8a978a17SVictor Perevertkin     }
859*8a978a17SVictor Perevertkin     else {
860*8a978a17SVictor Perevertkin #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
861*8a978a17SVictor Perevertkin         pPkgPnp->PowerPolicyProcessEvent(PwrPolIoPresent);
862*8a978a17SVictor Perevertkin #else
863*8a978a17SVictor Perevertkin         pPkgPnp->PowerPolicyProcessEvent(
864*8a978a17SVictor Perevertkin             PwrPolIoPresent,
865*8a978a17SVictor Perevertkin             TRUE // ProcessEventOnDifferentThread
866*8a978a17SVictor Perevertkin             );
867*8a978a17SVictor Perevertkin #endif
868*8a978a17SVictor Perevertkin         This->m_Flags |= FxPowerIdleIoPresentSent;
869*8a978a17SVictor Perevertkin     }
870*8a978a17SVictor Perevertkin 
871*8a978a17SVictor Perevertkin     return FxIdleInDx;
872*8a978a17SVictor Perevertkin }
873*8a978a17SVictor Perevertkin 
874*8a978a17SVictor Perevertkin FxPowerIdleStates
InDxPowerUpFailure(__inout FxPowerIdleMachine * This)875*8a978a17SVictor Perevertkin FxPowerIdleMachine::InDxPowerUpFailure(
876*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
877*8a978a17SVictor Perevertkin     )
878*8a978a17SVictor Perevertkin /*++
879*8a978a17SVictor Perevertkin 
880*8a978a17SVictor Perevertkin Routine Description:
881*8a978a17SVictor Perevertkin     Device is in Dx and there was a failure in the power up path.  The device
882*8a978a17SVictor Perevertkin     is no longer idle, even though it is stil in Dx.
883*8a978a17SVictor Perevertkin 
884*8a978a17SVictor Perevertkin Arguments:
885*8a978a17SVictor Perevertkin     This - instance of the state machine
886*8a978a17SVictor Perevertkin 
887*8a978a17SVictor Perevertkin Return Value:
888*8a978a17SVictor Perevertkin     FxIdlePowerFailed
889*8a978a17SVictor Perevertkin 
890*8a978a17SVictor Perevertkin   --*/
891*8a978a17SVictor Perevertkin {
892*8a978a17SVictor Perevertkin     //
893*8a978a17SVictor Perevertkin     // FxPowerIdleInDx - We are no longer in Dx
894*8a978a17SVictor Perevertkin     // FxPowerIdleIoPresentSent = We can send the io present event again
895*8a978a17SVictor Perevertkin     //
896*8a978a17SVictor Perevertkin     This->m_Flags &= ~(FxPowerIdleInDx | FxPowerIdleIoPresentSent);
897*8a978a17SVictor Perevertkin 
898*8a978a17SVictor Perevertkin     return FxIdlePowerFailed;
899*8a978a17SVictor Perevertkin }
900*8a978a17SVictor Perevertkin 
901*8a978a17SVictor Perevertkin FxPowerIdleStates
InDxStopped(__inout FxPowerIdleMachine * This)902*8a978a17SVictor Perevertkin FxPowerIdleMachine::InDxStopped(
903*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
904*8a978a17SVictor Perevertkin     )
905*8a978a17SVictor Perevertkin /*++
906*8a978a17SVictor Perevertkin 
907*8a978a17SVictor Perevertkin Routine Description:
908*8a978a17SVictor Perevertkin     The state machine was stopped while in the Dx state.  When the machine is in
909*8a978a17SVictor Perevertkin     the stopped state, the notification event is in the signaled state.
910*8a978a17SVictor Perevertkin 
911*8a978a17SVictor Perevertkin Arguments:
912*8a978a17SVictor Perevertkin     This - instance of the state machine
913*8a978a17SVictor Perevertkin 
914*8a978a17SVictor Perevertkin Return Value:
915*8a978a17SVictor Perevertkin     FxIdleStopped
916*8a978a17SVictor Perevertkin 
917*8a978a17SVictor Perevertkin   --*/
918*8a978a17SVictor Perevertkin {
919*8a978a17SVictor Perevertkin     //
920*8a978a17SVictor Perevertkin     // When the machine is in the stopped state, the notification event is in
921*8a978a17SVictor Perevertkin     // the signaled state.
922*8a978a17SVictor Perevertkin     //
923*8a978a17SVictor Perevertkin     This->SendD0Notification();
924*8a978a17SVictor Perevertkin 
925*8a978a17SVictor Perevertkin     //
926*8a978a17SVictor Perevertkin     // We are not longer idle since we are not in the Dx state anymore
927*8a978a17SVictor Perevertkin     //
928*8a978a17SVictor Perevertkin     This->m_Flags &= ~FxPowerIdleInDx;
929*8a978a17SVictor Perevertkin 
930*8a978a17SVictor Perevertkin     //
931*8a978a17SVictor Perevertkin     // We are no longer enabled since we are stopped from the Dx state
932*8a978a17SVictor Perevertkin     //
933*8a978a17SVictor Perevertkin     This->m_Flags &= ~FxPowerIdleTimerEnabled;
934*8a978a17SVictor Perevertkin 
935*8a978a17SVictor Perevertkin     //
936*8a978a17SVictor Perevertkin     // We can send the io present event again
937*8a978a17SVictor Perevertkin     //
938*8a978a17SVictor Perevertkin     This->m_Flags &= ~FxPowerIdleIoPresentSent;
939*8a978a17SVictor Perevertkin 
940*8a978a17SVictor Perevertkin     return FxIdleStopped;
941*8a978a17SVictor Perevertkin }
942*8a978a17SVictor Perevertkin 
943*8a978a17SVictor Perevertkin FxPowerIdleStates
InDxDisabled(__inout FxPowerIdleMachine * This)944*8a978a17SVictor Perevertkin FxPowerIdleMachine::InDxDisabled(
945*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
946*8a978a17SVictor Perevertkin     )
947*8a978a17SVictor Perevertkin /*++
948*8a978a17SVictor Perevertkin 
949*8a978a17SVictor Perevertkin Routine Description:
950*8a978a17SVictor Perevertkin     The device is in Dx and the state machine is being disabled (most likely due
951*8a978a17SVictor Perevertkin     to a surprise remove).
952*8a978a17SVictor Perevertkin 
953*8a978a17SVictor Perevertkin Arguments:
954*8a978a17SVictor Perevertkin     This - instance of the state machine
955*8a978a17SVictor Perevertkin 
956*8a978a17SVictor Perevertkin Return Value:
957*8a978a17SVictor Perevertkin     FxIdleDisabled
958*8a978a17SVictor Perevertkin 
959*8a978a17SVictor Perevertkin   --*/
960*8a978a17SVictor Perevertkin {
961*8a978a17SVictor Perevertkin     //
962*8a978a17SVictor Perevertkin     // Idle timer is being disabled while in Dx.  Remain in Dx.
963*8a978a17SVictor Perevertkin     //
964*8a978a17SVictor Perevertkin     This->m_Flags &= ~FxPowerIdleTimerEnabled;
965*8a978a17SVictor Perevertkin 
966*8a978a17SVictor Perevertkin     return FxIdleInDx;
967*8a978a17SVictor Perevertkin }
968*8a978a17SVictor Perevertkin 
969*8a978a17SVictor Perevertkin FxPowerIdleStates
InDxEnabled(__inout FxPowerIdleMachine * This)970*8a978a17SVictor Perevertkin FxPowerIdleMachine::InDxEnabled(
971*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
972*8a978a17SVictor Perevertkin     )
973*8a978a17SVictor Perevertkin /*++
974*8a978a17SVictor Perevertkin 
975*8a978a17SVictor Perevertkin Routine Description:
976*8a978a17SVictor Perevertkin     The device is in Dx and the state machine is being enabled (most like due
977*8a978a17SVictor Perevertkin     to trying to remain in Dx after Sx->S0.
978*8a978a17SVictor Perevertkin 
979*8a978a17SVictor Perevertkin Arguments:
980*8a978a17SVictor Perevertkin     This - instance of the state machine
981*8a978a17SVictor Perevertkin 
982*8a978a17SVictor Perevertkin Return Value:
983*8a978a17SVictor Perevertkin     FxIdleInDx
984*8a978a17SVictor Perevertkin 
985*8a978a17SVictor Perevertkin   --*/
986*8a978a17SVictor Perevertkin {
987*8a978a17SVictor Perevertkin     //
988*8a978a17SVictor Perevertkin     // Idle timer is being enabled while in Dx.  Remain in Dx.
989*8a978a17SVictor Perevertkin     //
990*8a978a17SVictor Perevertkin     This->m_Flags |= FxPowerIdleTimerEnabled;
991*8a978a17SVictor Perevertkin 
992*8a978a17SVictor Perevertkin     return FxIdleInDx;
993*8a978a17SVictor Perevertkin }
994*8a978a17SVictor Perevertkin 
995*8a978a17SVictor Perevertkin FxPowerIdleStates
PowerUp(__inout FxPowerIdleMachine * This)996*8a978a17SVictor Perevertkin FxPowerIdleMachine::PowerUp(
997*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
998*8a978a17SVictor Perevertkin     )
999*8a978a17SVictor Perevertkin /*++
1000*8a978a17SVictor Perevertkin 
1001*8a978a17SVictor Perevertkin Routine Description:
1002*8a978a17SVictor Perevertkin     The device powered up enough to where we can let waiters go and start pounding
1003*8a978a17SVictor Perevertkin     on their hardware.
1004*8a978a17SVictor Perevertkin 
1005*8a978a17SVictor Perevertkin Arguments:
1006*8a978a17SVictor Perevertkin     This - instance of the state machine
1007*8a978a17SVictor Perevertkin 
1008*8a978a17SVictor Perevertkin Return Value:
1009*8a978a17SVictor Perevertkin     FxIdlePowerUpComplete
1010*8a978a17SVictor Perevertkin 
1011*8a978a17SVictor Perevertkin   --*/
1012*8a978a17SVictor Perevertkin {
1013*8a978a17SVictor Perevertkin     //
1014*8a978a17SVictor Perevertkin     // FxPowerIdleInDx - we are not longer idle since we are not in the Dx state
1015*8a978a17SVictor Perevertkin     //                   anymore
1016*8a978a17SVictor Perevertkin     // FxPowerIdleIoPresentSent - We can send the io present event again
1017*8a978a17SVictor Perevertkin     //
1018*8a978a17SVictor Perevertkin     This->m_Flags &= ~(FxPowerIdleInDx | FxPowerIdleIoPresentSent);
1019*8a978a17SVictor Perevertkin 
1020*8a978a17SVictor Perevertkin     This->SendD0Notification();
1021*8a978a17SVictor Perevertkin 
1022*8a978a17SVictor Perevertkin     return FxIdlePowerUpComplete;
1023*8a978a17SVictor Perevertkin }
1024*8a978a17SVictor Perevertkin 
1025*8a978a17SVictor Perevertkin FxPowerIdleStates
PowerUpComplete(__inout FxPowerIdleMachine * This)1026*8a978a17SVictor Perevertkin FxPowerIdleMachine::PowerUpComplete(
1027*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
1028*8a978a17SVictor Perevertkin     )
1029*8a978a17SVictor Perevertkin /*++
1030*8a978a17SVictor Perevertkin 
1031*8a978a17SVictor Perevertkin Routine Description:
1032*8a978a17SVictor Perevertkin     The device is moving into D0, determine which D0 state to move into
1033*8a978a17SVictor Perevertkin     based on the enabled state and io count.
1034*8a978a17SVictor Perevertkin 
1035*8a978a17SVictor Perevertkin Arguments:
1036*8a978a17SVictor Perevertkin     This - instance of the state machine
1037*8a978a17SVictor Perevertkin 
1038*8a978a17SVictor Perevertkin Return Value:
1039*8a978a17SVictor Perevertkin     new state
1040*8a978a17SVictor Perevertkin 
1041*8a978a17SVictor Perevertkin   --*/
1042*8a978a17SVictor Perevertkin {
1043*8a978a17SVictor Perevertkin     if (This->m_Flags & FxPowerIdleTimerEnabled) {
1044*8a978a17SVictor Perevertkin         if (This->m_Flags & FxPowerIdleTimerStarted) {
1045*8a978a17SVictor Perevertkin             COVERAGE_TRAP();
1046*8a978a17SVictor Perevertkin             return FxIdleTimerRunning;
1047*8a978a17SVictor Perevertkin         }
1048*8a978a17SVictor Perevertkin         else {
1049*8a978a17SVictor Perevertkin             return FxIdleCheckIoCount;
1050*8a978a17SVictor Perevertkin         }
1051*8a978a17SVictor Perevertkin     }
1052*8a978a17SVictor Perevertkin     else {
1053*8a978a17SVictor Perevertkin         //
1054*8a978a17SVictor Perevertkin         // Not enabled, better not have a timer running
1055*8a978a17SVictor Perevertkin         //
1056*8a978a17SVictor Perevertkin         ASSERT((This->m_Flags & FxPowerIdleTimerStarted) == 0);
1057*8a978a17SVictor Perevertkin 
1058*8a978a17SVictor Perevertkin         return FxIdleDisabled;
1059*8a978a17SVictor Perevertkin     }
1060*8a978a17SVictor Perevertkin }
1061*8a978a17SVictor Perevertkin 
1062*8a978a17SVictor Perevertkin FxPowerIdleStates
TimedOutDisabled(__inout FxPowerIdleMachine * This)1063*8a978a17SVictor Perevertkin FxPowerIdleMachine::TimedOutDisabled(
1064*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
1065*8a978a17SVictor Perevertkin     )
1066*8a978a17SVictor Perevertkin /*++
1067*8a978a17SVictor Perevertkin 
1068*8a978a17SVictor Perevertkin Routine Description:
1069*8a978a17SVictor Perevertkin     The power idle state machine is moving into the disabled state.  Set the
1070*8a978a17SVictor Perevertkin     D0 event.
1071*8a978a17SVictor Perevertkin 
1072*8a978a17SVictor Perevertkin Arguments:
1073*8a978a17SVictor Perevertkin     This - instance of the state machine
1074*8a978a17SVictor Perevertkin 
1075*8a978a17SVictor Perevertkin Return Value:
1076*8a978a17SVictor Perevertkin     FxIdleDisabled
1077*8a978a17SVictor Perevertkin 
1078*8a978a17SVictor Perevertkin   --*/
1079*8a978a17SVictor Perevertkin {
1080*8a978a17SVictor Perevertkin     //
1081*8a978a17SVictor Perevertkin     // Notify any waiters that we are now in D0
1082*8a978a17SVictor Perevertkin     //
1083*8a978a17SVictor Perevertkin     This->SendD0Notification();
1084*8a978a17SVictor Perevertkin 
1085*8a978a17SVictor Perevertkin     //
1086*8a978a17SVictor Perevertkin     // We can send the io present event again
1087*8a978a17SVictor Perevertkin     //
1088*8a978a17SVictor Perevertkin     This->m_Flags &= ~FxPowerIdleIoPresentSent;
1089*8a978a17SVictor Perevertkin 
1090*8a978a17SVictor Perevertkin     return FxIdleDisabled;
1091*8a978a17SVictor Perevertkin }
1092*8a978a17SVictor Perevertkin 
1093*8a978a17SVictor Perevertkin FxPowerIdleStates
TimedOutEnabled(__inout FxPowerIdleMachine * This)1094*8a978a17SVictor Perevertkin FxPowerIdleMachine::TimedOutEnabled(
1095*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
1096*8a978a17SVictor Perevertkin     )
1097*8a978a17SVictor Perevertkin {
1098*8a978a17SVictor Perevertkin     //
1099*8a978a17SVictor Perevertkin     // Notify any waiters that we are now in D0
1100*8a978a17SVictor Perevertkin     //
1101*8a978a17SVictor Perevertkin     This->SendD0Notification();
1102*8a978a17SVictor Perevertkin 
1103*8a978a17SVictor Perevertkin     //
1104*8a978a17SVictor Perevertkin     // We can send the io present event again
1105*8a978a17SVictor Perevertkin     //
1106*8a978a17SVictor Perevertkin     This->m_Flags &= ~FxPowerIdleIoPresentSent;
1107*8a978a17SVictor Perevertkin 
1108*8a978a17SVictor Perevertkin     return FxIdleCheckIoCount;
1109*8a978a17SVictor Perevertkin }
1110*8a978a17SVictor Perevertkin 
1111*8a978a17SVictor Perevertkin FxPowerIdleStates
CancelTimer(__inout FxPowerIdleMachine * This)1112*8a978a17SVictor Perevertkin FxPowerIdleMachine::CancelTimer(
1113*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
1114*8a978a17SVictor Perevertkin     )
1115*8a978a17SVictor Perevertkin /*++
1116*8a978a17SVictor Perevertkin 
1117*8a978a17SVictor Perevertkin Routine Description:
1118*8a978a17SVictor Perevertkin     The timer is running and we need to cancel it because of an io increment or
1119*8a978a17SVictor Perevertkin     the state machine being disabled.
1120*8a978a17SVictor Perevertkin 
1121*8a978a17SVictor Perevertkin Arguments:
1122*8a978a17SVictor Perevertkin     This - instance of the state machine
1123*8a978a17SVictor Perevertkin 
1124*8a978a17SVictor Perevertkin Return Value:
1125*8a978a17SVictor Perevertkin     new state
1126*8a978a17SVictor Perevertkin 
1127*8a978a17SVictor Perevertkin   --*/
1128*8a978a17SVictor Perevertkin {
1129*8a978a17SVictor Perevertkin     if (This->CancelIdleTimer()) {
1130*8a978a17SVictor Perevertkin         return FxIdleCheckIoCount;
1131*8a978a17SVictor Perevertkin     }
1132*8a978a17SVictor Perevertkin     else {
1133*8a978a17SVictor Perevertkin         return FxIdleWaitForTimeout;
1134*8a978a17SVictor Perevertkin     }
1135*8a978a17SVictor Perevertkin }
1136*8a978a17SVictor Perevertkin 
1137*8a978a17SVictor Perevertkin FxPowerIdleStates
TimerExpired(__inout FxPowerIdleMachine * This)1138*8a978a17SVictor Perevertkin FxPowerIdleMachine::TimerExpired(
1139*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
1140*8a978a17SVictor Perevertkin     )
1141*8a978a17SVictor Perevertkin /*++
1142*8a978a17SVictor Perevertkin 
1143*8a978a17SVictor Perevertkin Routine Description:
1144*8a978a17SVictor Perevertkin     The timer was not canceled because it was running.  The timer has now
1145*8a978a17SVictor Perevertkin     fired, so we can move forward.
1146*8a978a17SVictor Perevertkin 
1147*8a978a17SVictor Perevertkin Arguments:
1148*8a978a17SVictor Perevertkin     This - instance of the state machine
1149*8a978a17SVictor Perevertkin 
1150*8a978a17SVictor Perevertkin Return Value:
1151*8a978a17SVictor Perevertkin     FxIdleCheckIoCount
1152*8a978a17SVictor Perevertkin 
1153*8a978a17SVictor Perevertkin   --*/
1154*8a978a17SVictor Perevertkin {
1155*8a978a17SVictor Perevertkin     This->m_Flags &= ~FxPowerIdleTimerStarted;
1156*8a978a17SVictor Perevertkin 
1157*8a978a17SVictor Perevertkin     return FxIdleCheckIoCount;
1158*8a978a17SVictor Perevertkin }
1159*8a978a17SVictor Perevertkin 
1160*8a978a17SVictor Perevertkin FxPowerIdleStates
Disabling(__inout FxPowerIdleMachine * This)1161*8a978a17SVictor Perevertkin FxPowerIdleMachine::Disabling(
1162*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
1163*8a978a17SVictor Perevertkin     )
1164*8a978a17SVictor Perevertkin /*++
1165*8a978a17SVictor Perevertkin 
1166*8a978a17SVictor Perevertkin Routine Description:
1167*8a978a17SVictor Perevertkin     Timer is running and the state machine is being disabled.  Cancel the idle
1168*8a978a17SVictor Perevertkin     timer.
1169*8a978a17SVictor Perevertkin 
1170*8a978a17SVictor Perevertkin Arguments:
1171*8a978a17SVictor Perevertkin     This - instance of the state machine
1172*8a978a17SVictor Perevertkin 
1173*8a978a17SVictor Perevertkin Return Value:
1174*8a978a17SVictor Perevertkin     new state
1175*8a978a17SVictor Perevertkin 
1176*8a978a17SVictor Perevertkin   --*/
1177*8a978a17SVictor Perevertkin {
1178*8a978a17SVictor Perevertkin     if (This->CancelIdleTimer()) {
1179*8a978a17SVictor Perevertkin         return FxIdleDisabled;
1180*8a978a17SVictor Perevertkin     }
1181*8a978a17SVictor Perevertkin     else {
1182*8a978a17SVictor Perevertkin         return FxIdleDisablingWaitForTimeout;
1183*8a978a17SVictor Perevertkin     }
1184*8a978a17SVictor Perevertkin }
1185*8a978a17SVictor Perevertkin 
1186*8a978a17SVictor Perevertkin FxPowerIdleStates
DisablingTimerExpired(__inout FxPowerIdleMachine * This)1187*8a978a17SVictor Perevertkin FxPowerIdleMachine::DisablingTimerExpired(
1188*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
1189*8a978a17SVictor Perevertkin     )
1190*8a978a17SVictor Perevertkin /*++
1191*8a978a17SVictor Perevertkin 
1192*8a978a17SVictor Perevertkin Routine Description:
1193*8a978a17SVictor Perevertkin     When disabling the state machine, the timer could not be canceled.  The
1194*8a978a17SVictor Perevertkin     timer has now expired and the state machine can move forward.
1195*8a978a17SVictor Perevertkin 
1196*8a978a17SVictor Perevertkin Arguments:
1197*8a978a17SVictor Perevertkin     This - instance of the state machine
1198*8a978a17SVictor Perevertkin 
1199*8a978a17SVictor Perevertkin Return Value:
1200*8a978a17SVictor Perevertkin     FxIdleDisabled
1201*8a978a17SVictor Perevertkin 
1202*8a978a17SVictor Perevertkin   --*/
1203*8a978a17SVictor Perevertkin {
1204*8a978a17SVictor Perevertkin     This->m_Flags &= ~FxPowerIdleTimerStarted;
1205*8a978a17SVictor Perevertkin 
1206*8a978a17SVictor Perevertkin #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
1207*8a978a17SVictor Perevertkin     GetPnpPkg(This)->PowerPolicyProcessEvent(PwrPolPowerTimeoutExpired);
1208*8a978a17SVictor Perevertkin #else
1209*8a978a17SVictor Perevertkin     GetPnpPkg(This)->PowerPolicyProcessEvent(
1210*8a978a17SVictor Perevertkin         PwrPolPowerTimeoutExpired,
1211*8a978a17SVictor Perevertkin         TRUE // ProcessEventOnDifferentThread
1212*8a978a17SVictor Perevertkin         );
1213*8a978a17SVictor Perevertkin #endif
1214*8a978a17SVictor Perevertkin 
1215*8a978a17SVictor Perevertkin     return FxIdleDisabled;
1216*8a978a17SVictor Perevertkin }
1217*8a978a17SVictor Perevertkin 
1218*8a978a17SVictor Perevertkin FxPowerIdleStates
PowerFailed(__inout FxPowerIdleMachine * This)1219*8a978a17SVictor Perevertkin FxPowerIdleMachine::PowerFailed(
1220*8a978a17SVictor Perevertkin     __inout FxPowerIdleMachine* This
1221*8a978a17SVictor Perevertkin     )
1222*8a978a17SVictor Perevertkin /*++
1223*8a978a17SVictor Perevertkin 
1224*8a978a17SVictor Perevertkin Routine Description:
1225*8a978a17SVictor Perevertkin     A power operation (up or down) failed.  Mark the machine as failed so that
1226*8a978a17SVictor Perevertkin     PowerReference will fail properly.
1227*8a978a17SVictor Perevertkin 
1228*8a978a17SVictor Perevertkin Arguments:
1229*8a978a17SVictor Perevertkin     This - instance of the state machine
1230*8a978a17SVictor Perevertkin 
1231*8a978a17SVictor Perevertkin Return Value:
1232*8a978a17SVictor Perevertkin     FxIdleDisabled
1233*8a978a17SVictor Perevertkin 
1234*8a978a17SVictor Perevertkin   --*/
1235*8a978a17SVictor Perevertkin {
1236*8a978a17SVictor Perevertkin     //
1237*8a978a17SVictor Perevertkin     // By this time, the timer should be stopped
1238*8a978a17SVictor Perevertkin     //
1239*8a978a17SVictor Perevertkin     ASSERT((This->m_Flags & FxPowerIdleTimerStarted) == 0);
1240*8a978a17SVictor Perevertkin 
1241*8a978a17SVictor Perevertkin     This->m_Flags |= FxPowerIdlePowerFailed;
1242*8a978a17SVictor Perevertkin 
1243*8a978a17SVictor Perevertkin     //
1244*8a978a17SVictor Perevertkin     // We are no longer enabled to time out since we are in a failed state
1245*8a978a17SVictor Perevertkin     //
1246*8a978a17SVictor Perevertkin     This->m_Flags &= ~FxPowerIdleTimerEnabled;
1247*8a978a17SVictor Perevertkin 
1248*8a978a17SVictor Perevertkin     //
1249*8a978a17SVictor Perevertkin     // Wake up any waiters and indicate failure to them.
1250*8a978a17SVictor Perevertkin     //
1251*8a978a17SVictor Perevertkin     This->SendD0Notification();
1252*8a978a17SVictor Perevertkin 
1253*8a978a17SVictor Perevertkin     return FxIdleDisabled;
1254*8a978a17SVictor Perevertkin }
1255*8a978a17SVictor Perevertkin 
1256*8a978a17SVictor Perevertkin __drv_maxIRQL(DISPATCH_LEVEL)
__drv_minIRQL(DISPATCH_LEVEL)1257*8a978a17SVictor Perevertkin __drv_minIRQL(DISPATCH_LEVEL)
1258*8a978a17SVictor Perevertkin __drv_requiresIRQL(DISPATCH_LEVEL)
1259*8a978a17SVictor Perevertkin __drv_sameIRQL
1260*8a978a17SVictor Perevertkin VOID
1261*8a978a17SVictor Perevertkin FxPowerIdleMachine::_PowerTimeoutDpcRoutine(
1262*8a978a17SVictor Perevertkin     __in     PKDPC Dpc,
1263*8a978a17SVictor Perevertkin     __in_opt PVOID Context,
1264*8a978a17SVictor Perevertkin     __in_opt PVOID SystemArgument1,
1265*8a978a17SVictor Perevertkin     __in_opt PVOID SystemArgument2
1266*8a978a17SVictor Perevertkin     )
1267*8a978a17SVictor Perevertkin /*++
1268*8a978a17SVictor Perevertkin 
1269*8a978a17SVictor Perevertkin Routine Description:
1270*8a978a17SVictor Perevertkin     Timer DPC which posts the timeout expired event to the power policy state
1271*8a978a17SVictor Perevertkin     machine
1272*8a978a17SVictor Perevertkin 
1273*8a978a17SVictor Perevertkin Arguments:
1274*8a978a17SVictor Perevertkin     Dpc - DPC
1275*8a978a17SVictor Perevertkin     Context, SysArg1, SysArg2 - Unused
1276*8a978a17SVictor Perevertkin 
1277*8a978a17SVictor Perevertkin Return Value:
1278*8a978a17SVictor Perevertkin     None
1279*8a978a17SVictor Perevertkin 
1280*8a978a17SVictor Perevertkin   --*/
1281*8a978a17SVictor Perevertkin {
1282*8a978a17SVictor Perevertkin     FxPowerIdleMachine* pThis;
1283*8a978a17SVictor Perevertkin 
1284*8a978a17SVictor Perevertkin     UNREFERENCED_PARAMETER(Dpc);
1285*8a978a17SVictor Perevertkin     UNREFERENCED_PARAMETER(SystemArgument1);
1286*8a978a17SVictor Perevertkin     UNREFERENCED_PARAMETER(SystemArgument2);
1287*8a978a17SVictor Perevertkin 
1288*8a978a17SVictor Perevertkin     pThis = (FxPowerIdleMachine*) Context;
1289*8a978a17SVictor Perevertkin 
1290*8a978a17SVictor Perevertkin     pThis->m_Lock.AcquireAtDpcLevel();
1291*8a978a17SVictor Perevertkin     pThis->ProcessEventLocked(PowerIdleEventTimerExpired);
1292*8a978a17SVictor Perevertkin 
1293*8a978a17SVictor Perevertkin #if FX_IS_KERNEL_MODE
1294*8a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1295*8a978a17SVictor Perevertkin     PFN_WDF_DRIVER_DEVICE_ADD pDriverDeviceAdd;
1296*8a978a17SVictor Perevertkin 
1297*8a978a17SVictor Perevertkin     pFxDriverGlobals = GetPnpPkg(pThis)->GetDriverGlobals();
1298*8a978a17SVictor Perevertkin 
1299*8a978a17SVictor Perevertkin     //
1300*8a978a17SVictor Perevertkin     // We need to provide XPerf with a symbol of the client to figure out
1301*8a978a17SVictor Perevertkin     // which component this idle timer is for. Since AddDevice is always there
1302*8a978a17SVictor Perevertkin     // we use that to pass the symbol along.
1303*8a978a17SVictor Perevertkin     //
1304*8a978a17SVictor Perevertkin     pDriverDeviceAdd = pFxDriverGlobals->Driver->GetDriverDeviceAddMethod();
1305*8a978a17SVictor Perevertkin 
1306*8a978a17SVictor Perevertkin     FxPerfTraceDpc(&pDriverDeviceAdd);
1307*8a978a17SVictor Perevertkin #endif
1308*8a978a17SVictor Perevertkin 
1309*8a978a17SVictor Perevertkin     pThis->m_Lock.ReleaseFromDpcLevel();
1310*8a978a17SVictor Perevertkin }
1311*8a978a17SVictor Perevertkin 
1312*8a978a17SVictor Perevertkin VOID
Reset(VOID)1313*8a978a17SVictor Perevertkin FxPowerIdleMachine::Reset(
1314*8a978a17SVictor Perevertkin     VOID
1315*8a978a17SVictor Perevertkin     )
1316*8a978a17SVictor Perevertkin /*++
1317*8a978a17SVictor Perevertkin 
1318*8a978a17SVictor Perevertkin Routine Description:
1319*8a978a17SVictor Perevertkin     Reset the state machine to a known state on a PDO restart.
1320*8a978a17SVictor Perevertkin 
1321*8a978a17SVictor Perevertkin Arguments:
1322*8a978a17SVictor Perevertkin     None
1323*8a978a17SVictor Perevertkin 
1324*8a978a17SVictor Perevertkin Return Value:
1325*8a978a17SVictor Perevertkin     None
1326*8a978a17SVictor Perevertkin 
1327*8a978a17SVictor Perevertkin   --*/
1328*8a978a17SVictor Perevertkin {
1329*8a978a17SVictor Perevertkin     FxPkgPnp* pPkgPnp;
1330*8a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1331*8a978a17SVictor Perevertkin 
1332*8a978a17SVictor Perevertkin     ASSERT(m_CurrentIdleState == FxIdleStopped);
1333*8a978a17SVictor Perevertkin 
1334*8a978a17SVictor Perevertkin     m_IoCount = 0;
1335*8a978a17SVictor Perevertkin     m_Flags = 0x0;
1336*8a978a17SVictor Perevertkin 
1337*8a978a17SVictor Perevertkin     pPkgPnp = GetPnpPkg(this);
1338*8a978a17SVictor Perevertkin     pFxDriverGlobals = pPkgPnp->GetDriverGlobals();
1339*8a978a17SVictor Perevertkin 
1340*8a978a17SVictor Perevertkin     if (pFxDriverGlobals->DebugExtension != NULL &&
1341*8a978a17SVictor Perevertkin         pFxDriverGlobals->DebugExtension->TrackPower != FxTrackPowerNone) {
1342*8a978a17SVictor Perevertkin         //
1343*8a978a17SVictor Perevertkin         // Ignore potential failure, power ref tracking is not an essential feature.
1344*8a978a17SVictor Perevertkin         //
1345*8a978a17SVictor Perevertkin         (void)FxTagTracker::CreateAndInitialize(&m_TagTracker,
1346*8a978a17SVictor Perevertkin                                                 pFxDriverGlobals,
1347*8a978a17SVictor Perevertkin                                                 FxTagTrackerTypePower,
1348*8a978a17SVictor Perevertkin                                                 pFxDriverGlobals->DebugExtension->TrackPower == FxTrackPowerRefsAndStack,
1349*8a978a17SVictor Perevertkin                                                 pPkgPnp->GetDevice());
1350*8a978a17SVictor Perevertkin     }
1351*8a978a17SVictor Perevertkin 
1352*8a978a17SVictor Perevertkin     SendD0Notification();
1353*8a978a17SVictor Perevertkin }
1354*8a978a17SVictor Perevertkin 
1355*8a978a17SVictor Perevertkin VOID
EnableTimer(VOID)1356*8a978a17SVictor Perevertkin FxPowerIdleMachine::EnableTimer(
1357*8a978a17SVictor Perevertkin     VOID
1358*8a978a17SVictor Perevertkin     )
1359*8a978a17SVictor Perevertkin /*++
1360*8a978a17SVictor Perevertkin 
1361*8a978a17SVictor Perevertkin Routine Description:
1362*8a978a17SVictor Perevertkin     Public function that the power policy state machine uses to put this state
1363*8a978a17SVictor Perevertkin     machine in to an enabled state and potentially start the idle timer.
1364*8a978a17SVictor Perevertkin 
1365*8a978a17SVictor Perevertkin Arguments:
1366*8a978a17SVictor Perevertkin     None
1367*8a978a17SVictor Perevertkin 
1368*8a978a17SVictor Perevertkin Return Value:
1369*8a978a17SVictor Perevertkin     None
1370*8a978a17SVictor Perevertkin 
1371*8a978a17SVictor Perevertkin   --*/
1372*8a978a17SVictor Perevertkin {
1373*8a978a17SVictor Perevertkin     KIRQL irql;
1374*8a978a17SVictor Perevertkin 
1375*8a978a17SVictor Perevertkin     m_Lock.Acquire(&irql);
1376*8a978a17SVictor Perevertkin     ProcessEventLocked(PowerIdleEventEnabled);
1377*8a978a17SVictor Perevertkin     m_Lock.Release(irql);
1378*8a978a17SVictor Perevertkin }
1379*8a978a17SVictor Perevertkin 
1380*8a978a17SVictor Perevertkin BOOLEAN
DisableTimer(VOID)1381*8a978a17SVictor Perevertkin FxPowerIdleMachine::DisableTimer(
1382*8a978a17SVictor Perevertkin     VOID
1383*8a978a17SVictor Perevertkin     )
1384*8a978a17SVictor Perevertkin /*++
1385*8a978a17SVictor Perevertkin 
1386*8a978a17SVictor Perevertkin Routine Description:
1387*8a978a17SVictor Perevertkin     Public function which the power policy state machine uses to put this state
1388*8a978a17SVictor Perevertkin     machine into a disabled state.  If necessary, the state machine will attempt
1389*8a978a17SVictor Perevertkin     to cancel the idle timer.
1390*8a978a17SVictor Perevertkin 
1391*8a978a17SVictor Perevertkin Arguments:
1392*8a978a17SVictor Perevertkin     None
1393*8a978a17SVictor Perevertkin 
1394*8a978a17SVictor Perevertkin Return Value:
1395*8a978a17SVictor Perevertkin     TRUE if the idle timer was cancelled and the caller may proceed directly to
1396*8a978a17SVictor Perevertkin     its new state
1397*8a978a17SVictor Perevertkin 
1398*8a978a17SVictor Perevertkin     FALSE if the idle timer was not cancelled and the caller must wait for the
1399*8a978a17SVictor Perevertkin     io timeout event to be posted before proceeding.
1400*8a978a17SVictor Perevertkin 
1401*8a978a17SVictor Perevertkin   --*/
1402*8a978a17SVictor Perevertkin {
1403*8a978a17SVictor Perevertkin     KIRQL irql;
1404*8a978a17SVictor Perevertkin     BOOLEAN disabledImmediately;
1405*8a978a17SVictor Perevertkin 
1406*8a978a17SVictor Perevertkin     m_Lock.Acquire(&irql);
1407*8a978a17SVictor Perevertkin 
1408*8a978a17SVictor Perevertkin     ProcessEventLocked(PowerIdleEventDisabled);
1409*8a978a17SVictor Perevertkin 
1410*8a978a17SVictor Perevertkin     //
1411*8a978a17SVictor Perevertkin     // If FxPowerIdleTimerStarted is still set after disabling the state machine,
1412*8a978a17SVictor Perevertkin     // then we could not cancel the timer and we must wait for the timer expired
1413*8a978a17SVictor Perevertkin     // event to be posted to this state machine.  This state machine will then
1414*8a978a17SVictor Perevertkin     // post a PwrPolIoPresent event to power policy.
1415*8a978a17SVictor Perevertkin     //
1416*8a978a17SVictor Perevertkin     if (m_Flags & FxPowerIdleTimerStarted) {
1417*8a978a17SVictor Perevertkin         disabledImmediately = FALSE;
1418*8a978a17SVictor Perevertkin     }
1419*8a978a17SVictor Perevertkin     else {
1420*8a978a17SVictor Perevertkin         disabledImmediately = TRUE;
1421*8a978a17SVictor Perevertkin     }
1422*8a978a17SVictor Perevertkin 
1423*8a978a17SVictor Perevertkin     m_Lock.Release(irql);
1424*8a978a17SVictor Perevertkin 
1425*8a978a17SVictor Perevertkin     return disabledImmediately;
1426*8a978a17SVictor Perevertkin }
1427*8a978a17SVictor Perevertkin 
1428*8a978a17SVictor Perevertkin VOID
Start(VOID)1429*8a978a17SVictor Perevertkin FxPowerIdleMachine::Start(
1430*8a978a17SVictor Perevertkin     VOID
1431*8a978a17SVictor Perevertkin     )
1432*8a978a17SVictor Perevertkin /*++
1433*8a978a17SVictor Perevertkin 
1434*8a978a17SVictor Perevertkin Routine Description:
1435*8a978a17SVictor Perevertkin     Public function that the power policy state machine uses to put this state
1436*8a978a17SVictor Perevertkin     machine into a started state so that the caller can call PowerReference
1437*8a978a17SVictor Perevertkin     successfully.
1438*8a978a17SVictor Perevertkin 
1439*8a978a17SVictor Perevertkin Arguments:
1440*8a978a17SVictor Perevertkin     None
1441*8a978a17SVictor Perevertkin 
1442*8a978a17SVictor Perevertkin Return Value:
1443*8a978a17SVictor Perevertkin     None
1444*8a978a17SVictor Perevertkin 
1445*8a978a17SVictor Perevertkin   --*/
1446*8a978a17SVictor Perevertkin {
1447*8a978a17SVictor Perevertkin     KIRQL irql;
1448*8a978a17SVictor Perevertkin     m_Lock.Acquire(&irql);
1449*8a978a17SVictor Perevertkin     ProcessEventLocked(PowerIdleEventStart);
1450*8a978a17SVictor Perevertkin     m_Lock.Release(irql);
1451*8a978a17SVictor Perevertkin }
1452*8a978a17SVictor Perevertkin 
1453*8a978a17SVictor Perevertkin VOID
Stop(VOID)1454*8a978a17SVictor Perevertkin FxPowerIdleMachine::Stop(
1455*8a978a17SVictor Perevertkin     VOID
1456*8a978a17SVictor Perevertkin     )
1457*8a978a17SVictor Perevertkin /*++
1458*8a978a17SVictor Perevertkin 
1459*8a978a17SVictor Perevertkin Routine Description:
1460*8a978a17SVictor Perevertkin     Public function which the power policy state machine uses to put this state
1461*8a978a17SVictor Perevertkin     machine into a state where PowerReference will no longer work.
1462*8a978a17SVictor Perevertkin 
1463*8a978a17SVictor Perevertkin Arguments:
1464*8a978a17SVictor Perevertkin     None
1465*8a978a17SVictor Perevertkin 
1466*8a978a17SVictor Perevertkin Return Value:
1467*8a978a17SVictor Perevertkin     None
1468*8a978a17SVictor Perevertkin 
1469*8a978a17SVictor Perevertkin   --*/
1470*8a978a17SVictor Perevertkin {
1471*8a978a17SVictor Perevertkin     KIRQL irql;
1472*8a978a17SVictor Perevertkin 
1473*8a978a17SVictor Perevertkin     m_Lock.Acquire(&irql);
1474*8a978a17SVictor Perevertkin     ProcessEventLocked(PowerIdleEventStop);
1475*8a978a17SVictor Perevertkin     m_Lock.Release(irql);
1476*8a978a17SVictor Perevertkin }
1477*8a978a17SVictor Perevertkin 
1478*8a978a17SVictor Perevertkin _Must_inspect_result_
1479*8a978a17SVictor Perevertkin NTSTATUS
PowerReferenceWorker(__in BOOLEAN WaitForD0,__in FxPowerReferenceFlags Flags,__in_opt PVOID Tag,__in_opt LONG Line,__in_opt PSTR File)1480*8a978a17SVictor Perevertkin FxPowerIdleMachine::PowerReferenceWorker(
1481*8a978a17SVictor Perevertkin     __in BOOLEAN WaitForD0,
1482*8a978a17SVictor Perevertkin     __in FxPowerReferenceFlags Flags,
1483*8a978a17SVictor Perevertkin     __in_opt PVOID Tag,
1484*8a978a17SVictor Perevertkin     __in_opt LONG Line,
1485*8a978a17SVictor Perevertkin     __in_opt PSTR File
1486*8a978a17SVictor Perevertkin     )
1487*8a978a17SVictor Perevertkin /*++
1488*8a978a17SVictor Perevertkin 
1489*8a978a17SVictor Perevertkin Routine Description:
1490*8a978a17SVictor Perevertkin     Caller wants to move the device into D0 manually.  The caller may optionally
1491*8a978a17SVictor Perevertkin     wait synchronously for the transition to occur if the device is currently in
1492*8a978a17SVictor Perevertkin     Dx.
1493*8a978a17SVictor Perevertkin 
1494*8a978a17SVictor Perevertkin Arguments:
1495*8a978a17SVictor Perevertkin     WaitForD0 - TRUE if the caller wants to synchronously wait for the Dx to D0
1496*8a978a17SVictor Perevertkin                 transition
1497*8a978a17SVictor Perevertkin 
1498*8a978a17SVictor Perevertkin     QueryPnpPending - TRUE if we are being called to bring the device back to
1499*8a978a17SVictor Perevertkin                 working state when a QueryRemove or a QueryStop
1500*8a978a17SVictor Perevertkin 
1501*8a978a17SVictor Perevertkin Return Value:
1502*8a978a17SVictor Perevertkin     NTSTATUS
1503*8a978a17SVictor Perevertkin 
1504*8a978a17SVictor Perevertkin     STATUS_SUCCESS - success
1505*8a978a17SVictor Perevertkin     STATUS_PENDING - transition is occurring
1506*8a978a17SVictor Perevertkin     STATUS_POWER_STATE_INVALID - ower transition has failed
1507*8a978a17SVictor Perevertkin 
1508*8a978a17SVictor Perevertkin   --*/
1509*8a978a17SVictor Perevertkin {
1510*8a978a17SVictor Perevertkin     NTSTATUS status;
1511*8a978a17SVictor Perevertkin     KIRQL irql;
1512*8a978a17SVictor Perevertkin     ULONG count = 0;
1513*8a978a17SVictor Perevertkin 
1514*8a978a17SVictor Perevertkin 
1515*8a978a17SVictor Perevertkin 
1516*8a978a17SVictor Perevertkin 
1517*8a978a17SVictor Perevertkin 
1518*8a978a17SVictor Perevertkin 
1519*8a978a17SVictor Perevertkin 
1520*8a978a17SVictor Perevertkin 
1521*8a978a17SVictor Perevertkin 
1522*8a978a17SVictor Perevertkin 
1523*8a978a17SVictor Perevertkin 
1524*8a978a17SVictor Perevertkin 
1525*8a978a17SVictor Perevertkin 
1526*8a978a17SVictor Perevertkin 
1527*8a978a17SVictor Perevertkin 
1528*8a978a17SVictor Perevertkin 
1529*8a978a17SVictor Perevertkin 
1530*8a978a17SVictor Perevertkin 
1531*8a978a17SVictor Perevertkin 
1532*8a978a17SVictor Perevertkin     //
1533*8a978a17SVictor Perevertkin     // Poke the state machine
1534*8a978a17SVictor Perevertkin     //
1535*8a978a17SVictor Perevertkin     status = IoIncrementWithFlags(Flags, &count);
1536*8a978a17SVictor Perevertkin 
1537*8a978a17SVictor Perevertkin     //
1538*8a978a17SVictor Perevertkin     // STATUS_PENDING indicates a Dx to D0 transition is occurring right now
1539*8a978a17SVictor Perevertkin     //
1540*8a978a17SVictor Perevertkin     if (status == STATUS_PENDING) {
1541*8a978a17SVictor Perevertkin         if (WaitForD0) {
1542*8a978a17SVictor Perevertkin             FxPkgPnp* pPkgPnp;
1543*8a978a17SVictor Perevertkin 
1544*8a978a17SVictor Perevertkin             ASSERT(Mx::MxGetCurrentIrql() <= APC_LEVEL);
1545*8a978a17SVictor Perevertkin 
1546*8a978a17SVictor Perevertkin             //
1547*8a978a17SVictor Perevertkin             // With the current usage, if WaitForD0 is TRUE, then the only
1548*8a978a17SVictor Perevertkin             // acceptable flag is FxPowerReferenceDefault.
1549*8a978a17SVictor Perevertkin             //
1550*8a978a17SVictor Perevertkin             // If the usage changes in the future such that it is acceptable to
1551*8a978a17SVictor Perevertkin             // have WaitForD0 set to TRUE and some flag(s) set, then the ASSERT
1552*8a978a17SVictor Perevertkin             // below should be updated accordingly (or removed altogether).
1553*8a978a17SVictor Perevertkin             //
1554*8a978a17SVictor Perevertkin             ASSERT(FxPowerReferenceDefault == Flags);
1555*8a978a17SVictor Perevertkin 
1556*8a978a17SVictor Perevertkin             pPkgPnp = GetPnpPkg(this);
1557*8a978a17SVictor Perevertkin 
1558*8a978a17SVictor Perevertkin             DoTraceLevelMessage(
1559*8a978a17SVictor Perevertkin                 pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
1560*8a978a17SVictor Perevertkin                 "WDFDEVICE %p in thread %p waiting synchronously for Dx to D0 "
1561*8a978a17SVictor Perevertkin                 "transition",
1562*8a978a17SVictor Perevertkin                 pPkgPnp->GetDevice()->GetHandle(),
1563*8a978a17SVictor Perevertkin                 Mx::MxGetCurrentThread());
1564*8a978a17SVictor Perevertkin 
1565*8a978a17SVictor Perevertkin             //
1566*8a978a17SVictor Perevertkin             // Returns success always
1567*8a978a17SVictor Perevertkin             //
1568*8a978a17SVictor Perevertkin             (void) FxPowerIdleMachine::WaitForD0();
1569*8a978a17SVictor Perevertkin 
1570*8a978a17SVictor Perevertkin             m_Lock.Acquire(&irql);
1571*8a978a17SVictor Perevertkin 
1572*8a978a17SVictor Perevertkin             //
1573*8a978a17SVictor Perevertkin             // If WaitForD0 is TRUE, then the FxPowerIdleSendPnpPowerUpEvent
1574*8a978a17SVictor Perevertkin             // flag can't be set. That flag is only used when the PnP state
1575*8a978a17SVictor Perevertkin             // machine waits asynchronously for the device to power up during
1576*8a978a17SVictor Perevertkin             // query-remove.
1577*8a978a17SVictor Perevertkin             //
1578*8a978a17SVictor Perevertkin             ASSERT(0 == (m_Flags & FxPowerIdleSendPnpPowerUpEvent));
1579*8a978a17SVictor Perevertkin 
1580*8a978a17SVictor Perevertkin             if ((m_Flags & FxPowerIdlePowerFailed) != 0x0 ||
1581*8a978a17SVictor Perevertkin                 (m_Flags & FxPowerIdleIsStarted) == 0x0) {
1582*8a978a17SVictor Perevertkin 
1583*8a978a17SVictor Perevertkin                 //
1584*8a978a17SVictor Perevertkin                 // Event was set because a power up or down failure occurred
1585*8a978a17SVictor Perevertkin                 //
1586*8a978a17SVictor Perevertkin                 status = STATUS_POWER_STATE_INVALID;
1587*8a978a17SVictor Perevertkin 
1588*8a978a17SVictor Perevertkin                 if (m_Flags & FxPowerIdlePowerFailed) {
1589*8a978a17SVictor Perevertkin                     DoTraceLevelMessage(
1590*8a978a17SVictor Perevertkin                         pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
1591*8a978a17SVictor Perevertkin                         "WDFDEVICE %p waiting for D0 in thread %p failed because of "
1592*8a978a17SVictor Perevertkin                         "power failure, %!STATUS!",
1593*8a978a17SVictor Perevertkin                         pPkgPnp->GetDevice()->GetHandle(),
1594*8a978a17SVictor Perevertkin                         Mx::MxGetCurrentThread(),
1595*8a978a17SVictor Perevertkin                         status);
1596*8a978a17SVictor Perevertkin                 }
1597*8a978a17SVictor Perevertkin                 else {
1598*8a978a17SVictor Perevertkin                     COVERAGE_TRAP();
1599*8a978a17SVictor Perevertkin                     DoTraceLevelMessage(
1600*8a978a17SVictor Perevertkin                         pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
1601*8a978a17SVictor Perevertkin                         "WDFDEVICE %p waiting for D0 in thread %p failed because of "
1602*8a978a17SVictor Perevertkin                         "invalid state , %!STATUS!",
1603*8a978a17SVictor Perevertkin                         pPkgPnp->GetDevice()->GetHandle(),
1604*8a978a17SVictor Perevertkin                         Mx::MxGetCurrentThread(), status);
1605*8a978a17SVictor Perevertkin                 }
1606*8a978a17SVictor Perevertkin 
1607*8a978a17SVictor Perevertkin                 //
1608*8a978a17SVictor Perevertkin                 // Decrement the io count that was taken above
1609*8a978a17SVictor Perevertkin                 //
1610*8a978a17SVictor Perevertkin                 ASSERT(m_IoCount > 0);
1611*8a978a17SVictor Perevertkin                 m_IoCount--;
1612*8a978a17SVictor Perevertkin                 ProcessEventLocked(PowerIdleEventIoDecrement);
1613*8a978a17SVictor Perevertkin             }
1614*8a978a17SVictor Perevertkin             else {
1615*8a978a17SVictor Perevertkin                 //
1616*8a978a17SVictor Perevertkin                 // Successfully returned to D0
1617*8a978a17SVictor Perevertkin                 //
1618*8a978a17SVictor Perevertkin                 status = STATUS_SUCCESS;
1619*8a978a17SVictor Perevertkin             }
1620*8a978a17SVictor Perevertkin             m_Lock.Release(irql);
1621*8a978a17SVictor Perevertkin         }
1622*8a978a17SVictor Perevertkin     }
1623*8a978a17SVictor Perevertkin 
1624*8a978a17SVictor Perevertkin     if (m_TagTracker != NULL) {
1625*8a978a17SVictor Perevertkin         //
1626*8a978a17SVictor Perevertkin         // Only track the reference if the call was successful
1627*8a978a17SVictor Perevertkin         // and the counter was actually incremented.
1628*8a978a17SVictor Perevertkin         //
1629*8a978a17SVictor Perevertkin         if (status == STATUS_SUCCESS || status == STATUS_PENDING) {
1630*8a978a17SVictor Perevertkin             m_TagTracker->UpdateTagHistory(Tag, Line, File, TagAddRef, count);
1631*8a978a17SVictor Perevertkin         }
1632*8a978a17SVictor Perevertkin     }
1633*8a978a17SVictor Perevertkin 
1634*8a978a17SVictor Perevertkin     return status;
1635*8a978a17SVictor Perevertkin }
1636*8a978a17SVictor Perevertkin 
1637*8a978a17SVictor Perevertkin _Must_inspect_result_
1638*8a978a17SVictor Perevertkin NTSTATUS
IoIncrement(VOID)1639*8a978a17SVictor Perevertkin FxPowerIdleMachine::IoIncrement(
1640*8a978a17SVictor Perevertkin     VOID
1641*8a978a17SVictor Perevertkin     )
1642*8a978a17SVictor Perevertkin /*++
1643*8a978a17SVictor Perevertkin 
1644*8a978a17SVictor Perevertkin Routine Description:
1645*8a978a17SVictor Perevertkin     Public function for any component to increment the io count.  The increment
1646*8a978a17SVictor Perevertkin     may cause the state machine to move out of the enabled state depending on
1647*8a978a17SVictor Perevertkin     the current state.
1648*8a978a17SVictor Perevertkin 
1649*8a978a17SVictor Perevertkin Arguments:
1650*8a978a17SVictor Perevertkin     None
1651*8a978a17SVictor Perevertkin 
1652*8a978a17SVictor Perevertkin Return Value:
1653*8a978a17SVictor Perevertkin     STATUS_PENDING if the state machine is transition from idle to non idle
1654*8a978a17SVictor Perevertkin 
1655*8a978a17SVictor Perevertkin     STATUS_SUCCESS otherwise
1656*8a978a17SVictor Perevertkin 
1657*8a978a17SVictor Perevertkin   --*/
1658*8a978a17SVictor Perevertkin {
1659*8a978a17SVictor Perevertkin     return IoIncrementWithFlags(FxPowerReferenceDefault);
1660*8a978a17SVictor Perevertkin }
1661*8a978a17SVictor Perevertkin 
1662*8a978a17SVictor Perevertkin _Must_inspect_result_
1663*8a978a17SVictor Perevertkin NTSTATUS
IoIncrementWithFlags(__in FxPowerReferenceFlags Flags,__out_opt PULONG Count)1664*8a978a17SVictor Perevertkin FxPowerIdleMachine::IoIncrementWithFlags(
1665*8a978a17SVictor Perevertkin     __in FxPowerReferenceFlags Flags,
1666*8a978a17SVictor Perevertkin     __out_opt PULONG Count
1667*8a978a17SVictor Perevertkin     )
1668*8a978a17SVictor Perevertkin /*++
1669*8a978a17SVictor Perevertkin 
1670*8a978a17SVictor Perevertkin Routine Description:
1671*8a978a17SVictor Perevertkin     An enchanced version of FxPowerIdleMachine::IoIncrement that has special
1672*8a978a17SVictor Perevertkin     behavior based on flags passed in by the caller. Please read the routine
1673*8a978a17SVictor Perevertkin     description of FxPowerIdleMachine::IoIncrement as well.
1674*8a978a17SVictor Perevertkin 
1675*8a978a17SVictor Perevertkin Arguments:
1676*8a978a17SVictor Perevertkin     Flags - The following flags are defined -
1677*8a978a17SVictor Perevertkin          FxPowerReferenceDefault - No special behavior
1678*8a978a17SVictor Perevertkin          FxPowerReferenceSendPnpPowerUpEvent - Set the
1679*8a978a17SVictor Perevertkin            FxPowerIdleSendPnpPowerUpEvent flag in the idle state machine flags.
1680*8a978a17SVictor Perevertkin            This will indicate to the idle state machine that when the device
1681*8a978a17SVictor Perevertkin            powers up, it needs to send the PnpEventDeviceInD0 event to the PnP
1682*8a978a17SVictor Perevertkin            state machine.
1683*8a978a17SVictor Perevertkin 
1684*8a978a17SVictor Perevertkin Return Value:
1685*8a978a17SVictor Perevertkin     STATUS_PENDING if the state machine is transition from idle to non idle
1686*8a978a17SVictor Perevertkin 
1687*8a978a17SVictor Perevertkin     STATUS_SUCCESS otherwise
1688*8a978a17SVictor Perevertkin 
1689*8a978a17SVictor Perevertkin   --*/
1690*8a978a17SVictor Perevertkin {
1691*8a978a17SVictor Perevertkin     NTSTATUS status;
1692*8a978a17SVictor Perevertkin     KIRQL irql;
1693*8a978a17SVictor Perevertkin 
1694*8a978a17SVictor Perevertkin     m_Lock.Acquire(&irql);
1695*8a978a17SVictor Perevertkin 
1696*8a978a17SVictor Perevertkin     if (m_Flags & FxPowerIdlePowerFailed) {
1697*8a978a17SVictor Perevertkin         //
1698*8a978a17SVictor Perevertkin         // fail without incrementing the count because we are in an
1699*8a978a17SVictor Perevertkin         // invalid power state
1700*8a978a17SVictor Perevertkin         //
1701*8a978a17SVictor Perevertkin         status = STATUS_POWER_STATE_INVALID;
1702*8a978a17SVictor Perevertkin         COVERAGE_TRAP();
1703*8a978a17SVictor Perevertkin     }
1704*8a978a17SVictor Perevertkin     else if ((m_Flags & FxPowerIdleIsStarted) == 0x0) {
1705*8a978a17SVictor Perevertkin         //
1706*8a978a17SVictor Perevertkin         // The state machine is not yet in a started state
1707*8a978a17SVictor Perevertkin         //
1708*8a978a17SVictor Perevertkin         status = STATUS_POWER_STATE_INVALID;
1709*8a978a17SVictor Perevertkin     }
1710*8a978a17SVictor Perevertkin     else {
1711*8a978a17SVictor Perevertkin         m_IoCount++;
1712*8a978a17SVictor Perevertkin         if (Count != NULL) {
1713*8a978a17SVictor Perevertkin             *Count = m_IoCount;
1714*8a978a17SVictor Perevertkin         }
1715*8a978a17SVictor Perevertkin 
1716*8a978a17SVictor Perevertkin         ProcessEventLocked(PowerIdleEventIoIncrement);
1717*8a978a17SVictor Perevertkin 
1718*8a978a17SVictor Perevertkin         if (InD0Locked()) {
1719*8a978a17SVictor Perevertkin             status = STATUS_SUCCESS;
1720*8a978a17SVictor Perevertkin         }
1721*8a978a17SVictor Perevertkin         else {
1722*8a978a17SVictor Perevertkin             status = STATUS_PENDING;
1723*8a978a17SVictor Perevertkin             if (Flags & FxPowerReferenceSendPnpPowerUpEvent) {
1724*8a978a17SVictor Perevertkin                 m_Flags |= FxPowerIdleSendPnpPowerUpEvent;
1725*8a978a17SVictor Perevertkin             }
1726*8a978a17SVictor Perevertkin         }
1727*8a978a17SVictor Perevertkin     }
1728*8a978a17SVictor Perevertkin     m_Lock.Release(irql);
1729*8a978a17SVictor Perevertkin 
1730*8a978a17SVictor Perevertkin     return status;
1731*8a978a17SVictor Perevertkin }
1732*8a978a17SVictor Perevertkin 
1733*8a978a17SVictor Perevertkin 
1734*8a978a17SVictor Perevertkin VOID
IoDecrement(__in_opt PVOID Tag,__in_opt LONG Line,__in_opt PSTR File)1735*8a978a17SVictor Perevertkin FxPowerIdleMachine::IoDecrement(
1736*8a978a17SVictor Perevertkin     __in_opt PVOID Tag,
1737*8a978a17SVictor Perevertkin     __in_opt LONG Line,
1738*8a978a17SVictor Perevertkin     __in_opt PSTR File
1739*8a978a17SVictor Perevertkin     )
1740*8a978a17SVictor Perevertkin /*++
1741*8a978a17SVictor Perevertkin 
1742*8a978a17SVictor Perevertkin Routine Description:
1743*8a978a17SVictor Perevertkin     Public function which allows the caller decrement the pending io count on
1744*8a978a17SVictor Perevertkin     this state machine.  If the count goes to zero and idle is enabled, then
1745*8a978a17SVictor Perevertkin     the timer is started.
1746*8a978a17SVictor Perevertkin 
1747*8a978a17SVictor Perevertkin Arguments:
1748*8a978a17SVictor Perevertkin     None
1749*8a978a17SVictor Perevertkin 
1750*8a978a17SVictor Perevertkin Return Value:
1751*8a978a17SVictor Perevertkin     None
1752*8a978a17SVictor Perevertkin 
1753*8a978a17SVictor Perevertkin   --*/
1754*8a978a17SVictor Perevertkin {
1755*8a978a17SVictor Perevertkin     KIRQL irql;
1756*8a978a17SVictor Perevertkin     FxPkgPnp* pPkgPnp;
1757*8a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1758*8a978a17SVictor Perevertkin     ULONG count;
1759*8a978a17SVictor Perevertkin 
1760*8a978a17SVictor Perevertkin     pPkgPnp = GetPnpPkg(this);
1761*8a978a17SVictor Perevertkin     pFxDriverGlobals = pPkgPnp->GetDriverGlobals();
1762*8a978a17SVictor Perevertkin 
1763*8a978a17SVictor Perevertkin     m_Lock.Acquire(&irql);
1764*8a978a17SVictor Perevertkin 
1765*8a978a17SVictor Perevertkin     if (m_IoCount == 0) {
1766*8a978a17SVictor Perevertkin         //
1767*8a978a17SVictor Perevertkin         // We can get here for the following reasons:
1768*8a978a17SVictor Perevertkin         // 1. Driver called WdfDevicveStopIdle/WdfDeviceResumeIdle in a mismatched
1769*8a978a17SVictor Perevertkin         //    manner. This is a driver bug.
1770*8a978a17SVictor Perevertkin         // 2. Framework did power deref without a corresponding power ref.
1771*8a978a17SVictor Perevertkin         //    This would be a framework bug.
1772*8a978a17SVictor Perevertkin         //
1773*8a978a17SVictor Perevertkin         // We will break into debugger if verifier is turned on. This will allow
1774*8a978a17SVictor Perevertkin         // developers to catch this problem during develeopment.
1775*8a978a17SVictor Perevertkin         // We limit this break to version 1.11+ because otherwise older drivers
1776*8a978a17SVictor Perevertkin         // may hit this, and if they cannot be fixed for some reason, then
1777*8a978a17SVictor Perevertkin         // verifier would need to be turned off to avoid the break which is not
1778*8a978a17SVictor Perevertkin         // desirable.
1779*8a978a17SVictor Perevertkin         //
1780*8a978a17SVictor Perevertkin         DoTraceLevelMessage(
1781*8a978a17SVictor Perevertkin             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
1782*8a978a17SVictor Perevertkin             "WDFDEVICE 0x%p !devobj 0x%p The device is being power-dereferenced"
1783*8a978a17SVictor Perevertkin             " without a matching power-reference. This could occur if driver"
1784*8a978a17SVictor Perevertkin             " incorrectly calls WdfDeviceResumeIdle without a matching call to"
1785*8a978a17SVictor Perevertkin             " WdfDeviceStopIdle.",
1786*8a978a17SVictor Perevertkin             pPkgPnp->GetDevice()->GetHandle(),
1787*8a978a17SVictor Perevertkin             pPkgPnp->GetDevice()->GetDeviceObject());
1788*8a978a17SVictor Perevertkin 
1789*8a978a17SVictor Perevertkin         if (pFxDriverGlobals->IsVerificationEnabled(1, 11, OkForDownLevel)) {
1790*8a978a17SVictor Perevertkin            FxVerifierDbgBreakPoint(pFxDriverGlobals);
1791*8a978a17SVictor Perevertkin         }
1792*8a978a17SVictor Perevertkin     }
1793*8a978a17SVictor Perevertkin 
1794*8a978a17SVictor Perevertkin     ASSERT(m_IoCount > 0);
1795*8a978a17SVictor Perevertkin     count = --m_IoCount;
1796*8a978a17SVictor Perevertkin     ProcessEventLocked(PowerIdleEventIoDecrement);
1797*8a978a17SVictor Perevertkin     m_Lock.Release(irql);
1798*8a978a17SVictor Perevertkin 
1799*8a978a17SVictor Perevertkin     if (m_TagTracker != NULL) {
1800*8a978a17SVictor Perevertkin         m_TagTracker->UpdateTagHistory(Tag, Line, File, TagRelease, count);
1801*8a978a17SVictor Perevertkin     }
1802*8a978a17SVictor Perevertkin }
1803*8a978a17SVictor Perevertkin 
1804*8a978a17SVictor Perevertkin BOOLEAN
QueryReturnToIdle(VOID)1805*8a978a17SVictor Perevertkin FxPowerIdleMachine::QueryReturnToIdle(
1806*8a978a17SVictor Perevertkin     VOID
1807*8a978a17SVictor Perevertkin     )
1808*8a978a17SVictor Perevertkin /*++
1809*8a978a17SVictor Perevertkin 
1810*8a978a17SVictor Perevertkin Routine Description:
1811*8a978a17SVictor Perevertkin     Public function which allows the caller to query the current io count on
1812*8a978a17SVictor Perevertkin     this state machine.  If the count non zero, the device will be brought back
1813*8a978a17SVictor Perevertkin     to D0.  If zero, the device will remain in Dx.
1814*8a978a17SVictor Perevertkin 
1815*8a978a17SVictor Perevertkin Arguments:
1816*8a978a17SVictor Perevertkin     None
1817*8a978a17SVictor Perevertkin 
1818*8a978a17SVictor Perevertkin Return Value:
1819*8a978a17SVictor Perevertkin     if TRUE is returned, there is an outstanding IO.
1820*8a978a17SVictor Perevertkin     if FALSE is returned, the device is idle.
1821*8a978a17SVictor Perevertkin 
1822*8a978a17SVictor Perevertkin   --*/
1823*8a978a17SVictor Perevertkin {
1824*8a978a17SVictor Perevertkin     KIRQL irql;
1825*8a978a17SVictor Perevertkin     BOOLEAN result;
1826*8a978a17SVictor Perevertkin 
1827*8a978a17SVictor Perevertkin     //
1828*8a978a17SVictor Perevertkin     // To return to idle, the following must be true
1829*8a978a17SVictor Perevertkin     // 1)  the device must be in Dx (FxPowerIdleInDx)
1830*8a978a17SVictor Perevertkin     // 2)  the timer must *NOT*  be running
1831*8a978a17SVictor Perevertkin     // 3)  an IO count of zero
1832*8a978a17SVictor Perevertkin     //
1833*8a978a17SVictor Perevertkin     m_Lock.Acquire(&irql);
1834*8a978a17SVictor Perevertkin 
1835*8a978a17SVictor Perevertkin     //     1
1836*8a978a17SVictor Perevertkin     if ((m_Flags & FxPowerIdleInDx) == FxPowerIdleInDx &&
1837*8a978a17SVictor Perevertkin         // 2                                        3
1838*8a978a17SVictor Perevertkin         (m_Flags & FxPowerIdleTimerStarted) == 0 && m_IoCount == 0x0) {
1839*8a978a17SVictor Perevertkin         result = TRUE;
1840*8a978a17SVictor Perevertkin     }
1841*8a978a17SVictor Perevertkin     else {
1842*8a978a17SVictor Perevertkin         result = FALSE;
1843*8a978a17SVictor Perevertkin     }
1844*8a978a17SVictor Perevertkin 
1845*8a978a17SVictor Perevertkin     //
1846*8a978a17SVictor Perevertkin     // If the caller is querying about returning to idle, then they have
1847*8a978a17SVictor Perevertkin     // processed the io present event that we previously sent.  We must clear
1848*8a978a17SVictor Perevertkin     // the flag, otherwise the following can occur
1849*8a978a17SVictor Perevertkin     // 1)  new io arrives, send the io present message
1850*8a978a17SVictor Perevertkin     // 2)  return to idle (io count goes to zero)
1851*8a978a17SVictor Perevertkin     // 3)  get queried to return to idle, return TRUE
1852*8a978a17SVictor Perevertkin     // 4)  new io arrives, we do not send the new io present message because the
1853*8a978a17SVictor Perevertkin     //     FxPowerIdleIoPresentSent flag is set.
1854*8a978a17SVictor Perevertkin     //
1855*8a978a17SVictor Perevertkin     m_Flags &= ~FxPowerIdleIoPresentSent;
1856*8a978a17SVictor Perevertkin 
1857*8a978a17SVictor Perevertkin     m_Lock.Release(irql);
1858*8a978a17SVictor Perevertkin 
1859*8a978a17SVictor Perevertkin     return result;
1860*8a978a17SVictor Perevertkin }
1861*8a978a17SVictor Perevertkin 
1862*8a978a17SVictor Perevertkin VOID
SendD0Notification(VOID)1863*8a978a17SVictor Perevertkin FxPowerIdleMachine::SendD0Notification(
1864*8a978a17SVictor Perevertkin     VOID
1865*8a978a17SVictor Perevertkin     )
1866*8a978a17SVictor Perevertkin {
1867*8a978a17SVictor Perevertkin     m_D0NotificationEvent.Set();
1868*8a978a17SVictor Perevertkin 
1869*8a978a17SVictor Perevertkin     if (m_Flags & FxPowerIdleSendPnpPowerUpEvent) {
1870*8a978a17SVictor Perevertkin 
1871*8a978a17SVictor Perevertkin         m_Flags &= ~FxPowerIdleSendPnpPowerUpEvent;
1872*8a978a17SVictor Perevertkin 
1873*8a978a17SVictor Perevertkin         //
1874*8a978a17SVictor Perevertkin         // Send an event to the Pnp state machine indicating that the device is
1875*8a978a17SVictor Perevertkin         // now in D0.
1876*8a978a17SVictor Perevertkin         //
1877*8a978a17SVictor Perevertkin #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
1878*8a978a17SVictor Perevertkin         GetPnpPkg(this)->PnpProcessEvent(PnpEventDeviceInD0);
1879*8a978a17SVictor Perevertkin #else
1880*8a978a17SVictor Perevertkin         GetPnpPkg(this)->PnpProcessEvent(
1881*8a978a17SVictor Perevertkin             PnpEventDeviceInD0,
1882*8a978a17SVictor Perevertkin             TRUE // ProcessEventOnDifferentThread
1883*8a978a17SVictor Perevertkin             );
1884*8a978a17SVictor Perevertkin #endif
1885*8a978a17SVictor Perevertkin 
1886*8a978a17SVictor Perevertkin     }
1887*8a978a17SVictor Perevertkin     return;
1888*8a978a17SVictor Perevertkin }
1889*8a978a17SVictor Perevertkin 
1890*8a978a17SVictor Perevertkin VOID
ProcessPowerEvent(__in FxPowerIdleEvents Event)1891*8a978a17SVictor Perevertkin FxPowerIdleMachine::ProcessPowerEvent(
1892*8a978a17SVictor Perevertkin     __in FxPowerIdleEvents Event
1893*8a978a17SVictor Perevertkin     )
1894*8a978a17SVictor Perevertkin /*++
1895*8a978a17SVictor Perevertkin 
1896*8a978a17SVictor Perevertkin Routine Description:
1897*8a978a17SVictor Perevertkin     Post a power related event to the state machine.
1898*8a978a17SVictor Perevertkin 
1899*8a978a17SVictor Perevertkin Arguments:
1900*8a978a17SVictor Perevertkin     Event - the event to post
1901*8a978a17SVictor Perevertkin 
1902*8a978a17SVictor Perevertkin Return Value:
1903*8a978a17SVictor Perevertkin     None
1904*8a978a17SVictor Perevertkin 
1905*8a978a17SVictor Perevertkin   --*/
1906*8a978a17SVictor Perevertkin {
1907*8a978a17SVictor Perevertkin     KIRQL irql;
1908*8a978a17SVictor Perevertkin 
1909*8a978a17SVictor Perevertkin     //
1910*8a978a17SVictor Perevertkin     // All other event types have specialized public functions
1911*8a978a17SVictor Perevertkin     //
1912*8a978a17SVictor Perevertkin     ASSERT(Event == PowerIdleEventPowerUpComplete ||
1913*8a978a17SVictor Perevertkin            Event == PowerIdleEventPowerUpFailed ||
1914*8a978a17SVictor Perevertkin            Event == PowerIdleEventPowerDown ||
1915*8a978a17SVictor Perevertkin            Event == PowerIdleEventPowerDownFailed);
1916*8a978a17SVictor Perevertkin 
1917*8a978a17SVictor Perevertkin     m_Lock.Acquire(&irql);
1918*8a978a17SVictor Perevertkin     ProcessEventLocked(Event);
1919*8a978a17SVictor Perevertkin     m_Lock.Release(irql);
1920*8a978a17SVictor Perevertkin }
1921*8a978a17SVictor Perevertkin 
1922*8a978a17SVictor Perevertkin VOID
ProcessEventLocked(__in FxPowerIdleEvents Event)1923*8a978a17SVictor Perevertkin FxPowerIdleMachine::ProcessEventLocked(
1924*8a978a17SVictor Perevertkin     __in FxPowerIdleEvents Event
1925*8a978a17SVictor Perevertkin     )
1926*8a978a17SVictor Perevertkin /*++
1927*8a978a17SVictor Perevertkin 
1928*8a978a17SVictor Perevertkin Routine Description:
1929*8a978a17SVictor Perevertkin     Processes an event and runs it through the state machine
1930*8a978a17SVictor Perevertkin 
1931*8a978a17SVictor Perevertkin Arguments:
1932*8a978a17SVictor Perevertkin 
1933*8a978a17SVictor Perevertkin 
1934*8a978a17SVictor Perevertkin Return Value:
1935*8a978a17SVictor Perevertkin 
1936*8a978a17SVictor Perevertkin 
1937*8a978a17SVictor Perevertkin   --*/
1938*8a978a17SVictor Perevertkin 
1939*8a978a17SVictor Perevertkin {
1940*8a978a17SVictor Perevertkin     const FxIdleStateTable* entry;
1941*8a978a17SVictor Perevertkin     FxPowerIdleStates newState;
1942*8a978a17SVictor Perevertkin     FxPkgPnp* pPkgPnp;
1943*8a978a17SVictor Perevertkin 
1944*8a978a17SVictor Perevertkin     pPkgPnp = GetPnpPkg(this);
1945*8a978a17SVictor Perevertkin 
1946*8a978a17SVictor Perevertkin     m_EventHistory[m_EventHistoryIndex] = Event;
1947*8a978a17SVictor Perevertkin     m_EventHistoryIndex = (m_EventHistoryIndex + 1) %
1948*8a978a17SVictor Perevertkin                           (sizeof(m_EventHistory)/sizeof(m_EventHistory[0]));
1949*8a978a17SVictor Perevertkin 
1950*8a978a17SVictor Perevertkin     entry = &m_StateTable[m_CurrentIdleState-FxIdleStopped];
1951*8a978a17SVictor Perevertkin     newState = FxIdleMax;
1952*8a978a17SVictor Perevertkin 
1953*8a978a17SVictor Perevertkin     for (ULONG i = 0; i < entry->TargetStatesCount; i++) {
1954*8a978a17SVictor Perevertkin         if (entry->TargetStates[i].PowerIdleEvent == Event) {
1955*8a978a17SVictor Perevertkin             DO_EVENT_TRAP(&entry->TargetStates[i]);
1956*8a978a17SVictor Perevertkin             newState = entry->TargetStates[i].PowerIdleState;
1957*8a978a17SVictor Perevertkin             break;
1958*8a978a17SVictor Perevertkin         }
1959*8a978a17SVictor Perevertkin     }
1960*8a978a17SVictor Perevertkin 
1961*8a978a17SVictor Perevertkin     if (newState == FxIdleMax) {
1962*8a978a17SVictor Perevertkin         switch (Event) {
1963*8a978a17SVictor Perevertkin         case PowerIdleEventIoIncrement:
1964*8a978a17SVictor Perevertkin         case PowerIdleEventIoDecrement:
1965*8a978a17SVictor Perevertkin             //
1966*8a978a17SVictor Perevertkin             // We always can handle io increment, io decrement, and query return
1967*8a978a17SVictor Perevertkin             // to idle from any state...
1968*8a978a17SVictor Perevertkin             //
1969*8a978a17SVictor Perevertkin             break;
1970*8a978a17SVictor Perevertkin 
1971*8a978a17SVictor Perevertkin         case PowerIdleEventEnabled:
1972*8a978a17SVictor Perevertkin             if (m_Flags & FxPowerIdleTimerEnabled) {
1973*8a978a17SVictor Perevertkin                 //
1974*8a978a17SVictor Perevertkin                 // Getting an enable event while enabled is OK
1975*8a978a17SVictor Perevertkin                 //
1976*8a978a17SVictor Perevertkin                 break;
1977*8a978a17SVictor Perevertkin             }
1978*8a978a17SVictor Perevertkin             //  ||   ||  Fall    ||  ||
1979*8a978a17SVictor Perevertkin             //  \/   \/  through \/  \/
1980*8a978a17SVictor Perevertkin 
1981*8a978a17SVictor Perevertkin         default:
1982*8a978a17SVictor Perevertkin             //
1983*8a978a17SVictor Perevertkin             // ...but we should not be dropping any other events from this state.
1984*8a978a17SVictor Perevertkin             //
1985*8a978a17SVictor Perevertkin 
1986*8a978a17SVictor Perevertkin             //
1987*8a978a17SVictor Perevertkin             DoTraceLevelMessage(
1988*8a978a17SVictor Perevertkin                 pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
1989*8a978a17SVictor Perevertkin                 "WDFDEVICE 0x%p !devobj 0x%p power idle state %!FxPowerIdleStates!"
1990*8a978a17SVictor Perevertkin                 " dropping event %!FxPowerIdleEvents!",
1991*8a978a17SVictor Perevertkin                 pPkgPnp->GetDevice()->GetHandle(),
1992*8a978a17SVictor Perevertkin                 pPkgPnp->GetDevice()->GetDeviceObject(),
1993*8a978a17SVictor Perevertkin                 m_CurrentIdleState, Event);
1994*8a978a17SVictor Perevertkin 
1995*8a978a17SVictor Perevertkin             COVERAGE_TRAP();
1996*8a978a17SVictor Perevertkin         }
1997*8a978a17SVictor Perevertkin     }
1998*8a978a17SVictor Perevertkin 
1999*8a978a17SVictor Perevertkin     while (newState != FxIdleMax) {
2000*8a978a17SVictor Perevertkin 
2001*8a978a17SVictor Perevertkin         DoTraceLevelMessage(
2002*8a978a17SVictor Perevertkin             pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNPPOWERSTATES,
2003*8a978a17SVictor Perevertkin             "WDFDEVICE 0x%p !devobj 0x%p entering power idle state "
2004*8a978a17SVictor Perevertkin             "%!FxPowerIdleStates! from %!FxPowerIdleStates!",
2005*8a978a17SVictor Perevertkin             pPkgPnp->GetDevice()->GetHandle(),
2006*8a978a17SVictor Perevertkin             pPkgPnp->GetDevice()->GetDeviceObject(),
2007*8a978a17SVictor Perevertkin             newState, m_CurrentIdleState);
2008*8a978a17SVictor Perevertkin 
2009*8a978a17SVictor Perevertkin         m_StateHistory[m_StateHistoryIndex] = newState;
2010*8a978a17SVictor Perevertkin         m_StateHistoryIndex = (m_StateHistoryIndex + 1) %
2011*8a978a17SVictor Perevertkin                               (sizeof(m_StateHistory)/sizeof(m_StateHistory[0]));
2012*8a978a17SVictor Perevertkin 
2013*8a978a17SVictor Perevertkin         m_CurrentIdleState = newState;
2014*8a978a17SVictor Perevertkin         entry = &m_StateTable[m_CurrentIdleState-FxIdleStopped];
2015*8a978a17SVictor Perevertkin 
2016*8a978a17SVictor Perevertkin         if (entry->StateFunc != NULL) {
2017*8a978a17SVictor Perevertkin             newState = entry->StateFunc(this);
2018*8a978a17SVictor Perevertkin         }
2019*8a978a17SVictor Perevertkin         else {
2020*8a978a17SVictor Perevertkin             newState = FxIdleMax;
2021*8a978a17SVictor Perevertkin         }
2022*8a978a17SVictor Perevertkin     }
2023*8a978a17SVictor Perevertkin }
2024