1 /*++
2 Copyright (c) Microsoft. All rights reserved.
3 
4 Module Name:
5 
6     PowerStateMachine.cpp
7 
8 Abstract:
9 
10     This module implements the Power state machine for the driver framework.
11     This code was split out from FxPkgPnp.cpp.
12 
13 Author:
14 
15 
16 
17 
18 Environment:
19 
20     Both kernel and user mode
21 
22 Revision History:
23 
24 
25 
26 --*/
27 
28 #include "pnppriv.hpp"
29 
30 extern "C" {
31 #if defined(EVENT_TRACING)
32 #include "PowerStateMachine.tmh"
33 #endif
34 }
35 
36 #if FX_STATE_MACHINE_VERIFY
37     #define VALIDATE_POWER_STATE(_CurrentState, _NewState)                        \
38         ValidatePowerStateEntryFunctionReturnValue((_CurrentState), (_NewState))
39 #else
40     #define VALIDATE_POWER_STATE(_CurrentState, _NewState)   (0)
41 #endif  //FX_STATE_MACHINE_VERIFY
42 
43 
44 // @@SMVERIFY_SPLIT_BEGIN
45 
46 //
47 // The Power State Machine
48 //
49 // This state machine responds to power IRPs that relate
50 // to devices.  It is a subordinate, responding either to IRPs
51 // that are sent by other drivers, or by IRPs that are
52 // sent by the Power Policy State Machine.
53 //
54 // It responds to:
55 //
56 // IRP_MN_SET_POWER -- device power IRPs only
57 // IRP_MN_WAIT_WAKE
58 // IRP_MN_WAIT_WAKE Complete
59 // PowerImplicitD0
60 // PowerImplicitD3
61 // ParentMovesToD0
62 // PowerPolicyStop
63 // PowerMarkPageable
64 // PowerMarkNonpageable
65 //
66 
67 
68 
69 
70 
71 
72 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerD0OtherStates[] =
73 {
74     { PowerImplicitD3,              WdfDevStatePowerGotoD3Stopped DEBUGGED_EVENT },
75     { PowerMarkNonpageable,         WdfDevStatePowerDecideD0State DEBUGGED_EVENT },
76     { PowerEventMaximum,            WdfDevStatePowerNull },
77 };
78 
79 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerD0NPOtherStates[] =
80 {
81     { PowerImplicitD3,              WdfDevStatePowerGotoD3Stopped DEBUGGED_EVENT },
82     { PowerMarkPageable,            WdfDevStatePowerDecideD0State DEBUGGED_EVENT },
83     { PowerEventMaximum,            WdfDevStatePowerNull },
84 };
85 
86 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerD0BusWakeOwnerOtherStates[] =
87 {
88     { PowerWakeArrival,             WdfDevStatePowerEnablingWakeAtBus DEBUGGED_EVENT },
89     { PowerImplicitD3,              WdfDevStatePowerGotoD3Stopped DEBUGGED_EVENT },
90     { PowerMarkNonpageable,         WdfDevStatePowerDecideD0State DEBUGGED_EVENT },
91     { PowerEventMaximum,            WdfDevStatePowerNull },
92 };
93 
94 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerD0BusWakeOwnerNPOtherStates[] =
95 {
96     { PowerWakeArrival,             WdfDevStatePowerEnablingWakeAtBusNP DEBUGGED_EVENT },
97     { PowerImplicitD3,              WdfDevStatePowerGotoD3Stopped DEBUGGED_EVENT },
98     { PowerMarkPageable,            WdfDevStatePowerD0BusWakeOwner DEBUGGED_EVENT },
99     { PowerEventMaximum,            WdfDevStatePowerNull },
100 };
101 
102 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerD0ArmedForWakeOtherStates[] =
103 {
104     { PowerWakeSucceeded,           WdfDevStatePowerD0DisarmingWakeAtBus DEBUGGED_EVENT },
105     { PowerWakeFailed,              WdfDevStatePowerD0DisarmingWakeAtBus DEBUGGED_EVENT },
106     { PowerWakeCanceled,            WdfDevStatePowerD0DisarmingWakeAtBus DEBUGGED_EVENT },
107     { PowerMarkNonpageable,         WdfDevStatePowerD0ArmedForWakeNP TRAP_ON_EVENT },
108     { PowerImplicitD3,              WdfDevStatePowerGotoImplicitD3DisarmWakeAtBus DEBUGGED_EVENT },
109     { PowerEventMaximum,            WdfDevStatePowerNull },
110 };
111 
112 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerD0ArmedForWakeNPOtherStates[] =
113 {
114     { PowerWakeSucceeded,           WdfDevStatePowerD0DisarmingWakeAtBusNP DEBUGGED_EVENT },
115     { PowerWakeFailed,              WdfDevStatePowerD0DisarmingWakeAtBusNP TRAP_ON_EVENT },
116     { PowerWakeCanceled,            WdfDevStatePowerD0DisarmingWakeAtBusNP DEBUGGED_EVENT },
117     { PowerMarkPageable,            WdfDevStatePowerD0ArmedForWake TRAP_ON_EVENT },
118     { PowerImplicitD3,              WdfDevStatePowerGotoImplicitD3DisarmWakeAtBus TRAP_ON_EVENT },
119     { PowerEventMaximum,            WdfDevStatePowerNull },
120 };
121 
122 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerDNotZeroOtherStates[] =
123 {
124     { PowerImplicitD3,              WdfDevStatePowerGotoDxStoppedDisableInterrupt DEBUGGED_EVENT },
125     { PowerEventMaximum,            WdfDevStatePowerNull },
126 };
127 
128 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerDNotZeroNPOtherStates[] =
129 {
130     { PowerImplicitD3, WdfDevStatePowerGotoDxStoppedDisableInterruptNP DEBUGGED_EVENT },
131     { PowerEventMaximum, WdfDevStatePowerNull },
132 };
133 
134 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_DxArmedForWakeOtherStates[] =
135 {
136     { PowerWakeSucceeded,           WdfDevStatePowerWakePending DEBUGGED_EVENT },
137     { PowerWakeCanceled,            WdfDevStatePowerWakePending DEBUGGED_EVENT },
138     { PowerWakeFailed,              WdfDevStatePowerWakePending DEBUGGED_EVENT },
139     { PowerImplicitD3,              WdfDevStatePowerDxStoppedDisarmWake TRAP_ON_EVENT },
140     { PowerEventMaximum,            WdfDevStatePowerNull },
141 };
142 
143 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_DxArmedForWakeNPOtherStates[] =
144 {
145     { PowerWakeSucceeded,           WdfDevStatePowerWakePendingNP DEBUGGED_EVENT },
146     { PowerWakeFailed,              WdfDevStatePowerWakePendingNP DEBUGGED_EVENT },
147     { PowerWakeCanceled,            WdfDevStatePowerWakePendingNP DEBUGGED_EVENT },
148     { PowerImplicitD3,              WdfDevStatePowerDxStoppedDisarmWakeNP TRAP_ON_EVENT },
149     { PowerEventMaximum,            WdfDevStatePowerNull },
150 };
151 
152 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_WakePendingOtherStates[] =
153 {
154     { PowerImplicitD0,              WdfDevStatePowerCheckParentStateArmedForWake TRAP_ON_EVENT },
155     { PowerImplicitD3,              WdfDevStatePowerDxStoppedDisarmWake DEBUGGED_EVENT },
156     { PowerEventMaximum,            WdfDevStatePowerNull },
157 };
158 
159 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_WakePendingNPOtherStates[] =
160 {
161     { PowerImplicitD0,              WdfDevStatePowerCheckParentStateArmedForWakeNP TRAP_ON_EVENT },
162     { PowerImplicitD3,              WdfDevStatePowerDxStoppedDisarmWakeNP DEBUGGED_EVENT },
163     { PowerEventMaximum,            WdfDevStatePowerNull },
164 };
165 
166 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerStoppedOtherStates[] =
167 {
168     { PowerDx,                      WdfDevStatePowerStoppedCompleteDx DEBUGGED_EVENT },
169     { PowerEventMaximum,            WdfDevStatePowerNull },
170 };
171 
172 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerDxStoppedOtherStates[] =
173 {
174     { PowerD0,                      WdfDevStatePowerGotoStopped DEBUGGED_EVENT },
175     { PowerEventMaximum,            WdfDevStatePowerNull },
176 };
177 
178 const POWER_STATE_TABLE FxPkgPnp::m_WdfPowerStates[] =
179 {
180     // WdfDevStatePowerObjectCreated
181     {   NULL,
182         { PowerImplicitD0, WdfDevStatePowerStartingCheckDeviceType DEBUGGED_EVENT },
183         NULL,
184         { TRUE,
185           PowerMarkPageable | // parent sends usage notifications before the PDO is
186           PowerMarkNonpageable | // started
187           PowerParentToD0 | // parent powered up upon enumeration of child
188           PowerDx | // If we are on top of a power policy owner who sends a Dx
189                     // during start (or after AddDevice, etc)
190           PowerD0   // If we are on top of a power policy owner who sends a D0
191                     // to the stack in start device, we can get this event early
192         },
193     },
194 
195     // WdfDevStatePowerCheckDeviceType
196     {   FxPkgPnp::PowerCheckDeviceType,
197         { PowerEventMaximum, WdfDevStatePowerNull },
198         NULL,
199         { FALSE,
200           0 },
201     },
202 
203     // WdfDevStatePowerCheckDeviceTypeNP
204     {   FxPkgPnp::PowerCheckDeviceTypeNP,
205         { PowerEventMaximum, WdfDevStatePowerNull },
206         NULL,
207         { FALSE,
208           0 },
209     },
210 
211     // WdfDevStatePowerCheckParentState
212     {   FxPkgPnp::PowerCheckParentState,
213         { PowerEventMaximum, WdfDevStatePowerNull },
214         NULL,
215         { FALSE,
216           0 },
217     },
218 
219     // WdfDevStatePowerCheckParentStateNP
220     {   FxPkgPnp::PowerCheckParentStateNP,
221         { PowerEventMaximum, WdfDevStatePowerNull },
222         NULL,
223         { FALSE,
224           0 },
225     },
226 
227     // WdfDevStatePowerEnablingWakeAtBus
228     {   FxPkgPnp::PowerEnablingWakeAtBus,
229         { PowerEventMaximum, WdfDevStatePowerNull },
230         NULL,
231         { FALSE,
232           0 },
233     },
234 
235     // WdfDevStatePowerEnablingWakeAtBusNP
236     {   FxPkgPnp::PowerEnablingWakeAtBusNP,
237         { PowerEventMaximum, WdfDevStatePowerNull },
238         NULL,
239         { FALSE,
240           0 },
241     },
242 
243     // WdfDevStatePowerD0
244     {   FxPkgPnp::PowerDZero,
245         { PowerDx, WdfDevStatePowerGotoDx DEBUGGED_EVENT },
246         FxPkgPnp::m_PowerD0OtherStates,
247         { TRUE,
248           PowerImplicitD3 |
249           PowerD0               // A non WDF power policy owner might send a D0 irp
250                                 // while we are in D0
251         },
252     },
253 
254     // WdfDevStatePowerD0NP
255     {   FxPkgPnp::PowerD0NP,
256         { PowerDx, WdfDevStatePowerGotoDxNP DEBUGGED_EVENT },
257         FxPkgPnp::m_PowerD0NPOtherStates,
258         { TRUE,
259           PowerD0               // A non WDF power policy owner might send a D0 irp
260                                 // while we are in D0
261         },
262     },
263 
264     // WdfDevStatePowerD0BusWakeOwner
265     {   FxPkgPnp::PowerD0BusWakeOwner,
266         { PowerDx, WdfDevStatePowerGotoDx DEBUGGED_EVENT },
267         FxPkgPnp::m_PowerD0BusWakeOwnerOtherStates,
268         { TRUE,
269           PowerWakeSucceeded |  // During surprise remove, the pnp state machine
270                                 // could complete the ww request and result in
271                                 // this event before the pwr pol machine is stopped
272           PowerWakeCanceled |   // while powering up, the wait wake owner canceled
273                                 // the ww irp
274           PowerWakeFailed   |   // while powering up, the wait wake owner failed
275                                 // the ww irp
276           PowerParentToD0 |
277           PowerD0               // A non WDF power policy owner might send a D0 irp
278                                 // while we are in D0
279         },
280     },
281 
282     // WdfDevStatePowerD0BusWakeOwnerNP
283     {   FxPkgPnp::PowerD0BusWakeOwnerNP,
284         { PowerDx, WdfDevStatePowerGotoDxNP DEBUGGED_EVENT },
285         FxPkgPnp::m_PowerD0BusWakeOwnerNPOtherStates,
286         { TRUE,
287           PowerWakeSucceeded |  // During surprise remove, the pnp state machine
288                                 // could complete the ww request and result in
289                                 // this event before the pwr pol machine is stopped
290           PowerWakeCanceled |   // while powering up, the wait wake owner canceled
291                                 // the ww irp
292           PowerParentToD0 |
293           PowerD0               // A non WDF power policy owner might send a D0 irp
294                                 // while we are in D0
295         },
296     },
297 
298     // WdfDevStatePowerD0ArmedForWake
299     {   FxPkgPnp::PowerD0ArmedForWake,
300         { PowerDx, WdfDevStatePowerGotoDxArmedForWake DEBUGGED_EVENT },
301         FxPkgPnp::m_PowerD0ArmedForWakeOtherStates,
302         { TRUE,
303           PowerParentToD0 |
304           PowerWakeArrival  |   // PowerIsWakeRequestPresent() returned true in
305                                 // WdfDevStatePowerD0BusWakeOwner and raced with
306                                 // this event being processed
307           PowerWakeCanceled |
308           PowerD0               // A non WDF power policy owner might send a D0 irp
309                                 // while we are in D0
310         },
311     },
312 
313     // WdfDevStatePowerD0ArmedForWakeNP
314     {   FxPkgPnp::PowerD0ArmedForWakeNP,
315         { PowerDx, WdfDevStatePowerGotoDxArmedForWakeNP DEBUGGED_EVENT },
316         FxPkgPnp::m_PowerD0ArmedForWakeNPOtherStates,
317         { TRUE,
318           PowerParentToD0 |
319           PowerWakeArrival  |   // PowerIsWakeRequestPresent() returned true in
320                                 // WdfDevStatePowerD0BusWakeOwnerNP and raced with
321                                 // this event being processed
322           PowerWakeCanceled |
323           PowerD0               // A non WDF power policy owner might send a D0 irp
324                                 // while we are in D0
325         },
326     },
327 
328     // WdfDevStatePowerD0DisarmingWakeAtBus
329     {   FxPkgPnp::PowerD0DisarmingWakeAtBus,
330         { PowerEventMaximum, WdfDevStatePowerNull },
331         NULL,
332         { FALSE,
333           0 },
334     },
335 
336     // WdfDevStatePowerD0DisarmingWakeAtBusNP
337     {   FxPkgPnp::PowerD0DisarmingWakeAtBusNP,
338         { PowerEventMaximum, WdfDevStatePowerNull },
339         NULL,
340         { FALSE,
341           0 },
342     },
343 
344     // WdfDevStatePowerD0Starting
345     {   FxPkgPnp::PowerD0Starting,
346         { PowerEventMaximum, WdfDevStatePowerNull },
347         NULL,
348         { FALSE,
349           0 },
350     },
351 
352     // WdfDevStatePowerD0StartingConnectInterrupt
353     {   FxPkgPnp::PowerD0StartingConnectInterrupt,
354         { PowerEventMaximum, WdfDevStatePowerNull },
355         NULL,
356         { FALSE,
357           0 },
358     },
359 
360     // WdfDevStatePowerD0StartingDmaEnable
361     {   FxPkgPnp::PowerD0StartingDmaEnable,
362         { PowerEventMaximum, WdfDevStatePowerNull },
363         NULL,
364         { FALSE,
365           0 },
366     },
367 
368     // WdfDevStatePowerD0StartingStartSelfManagedIo
369     {   FxPkgPnp::PowerD0StartingStartSelfManagedIo,
370         { PowerEventMaximum, WdfDevStatePowerNull },
371         NULL,
372         { FALSE,
373           0 },
374     },
375 
376     // WdfDevStatePowerDecideD0State
377     {   FxPkgPnp::PowerDecideD0State,
378         { PowerEventMaximum, WdfDevStatePowerNull },
379         NULL,
380         { FALSE,
381           0 },
382     },
383 
384     // WdfDevStatePowerGotoD3Stopped
385     {   FxPkgPnp::PowerGotoD3Stopped,
386         { PowerEventMaximum, WdfDevStatePowerNull },
387         NULL,
388         { FALSE,
389           0 },
390     },
391 
392     // WdfDevStatePowerStopped
393     {   NULL,
394         { PowerImplicitD0, WdfDevStatePowerStartingCheckDeviceType DEBUGGED_EVENT },
395         FxPkgPnp::m_PowerStoppedOtherStates,
396         { TRUE,
397           PowerD0 |             // as a filter above the PPO and the PPO powers on the stack
398                                 // before seeing a surprise remove or remove irp
399           PowerWakeFailed |     // power policy owner canceled the wake request while
400                                 // we were transitioning to stop (or after the
401                                 // transition succeeded)
402           PowerParentToD0 },
403     },
404 
405     // WdfDevStatePowerStartingCheckDeviceType
406     {   FxPkgPnp::PowerStartingCheckDeviceType,
407         { PowerEventMaximum, WdfDevStatePowerNull },
408         NULL,
409         { FALSE,
410           0 },
411     },
412 
413     // WdfDevStatePowerStartingChild
414     {   FxPkgPnp::PowerStartingChild,
415         { PowerParentToD0, WdfDevStatePowerD0Starting DEBUGGED_EVENT },
416         NULL,
417         { TRUE,
418           0 },
419     },
420 
421     // WdfDevStatePowerDxDisablingWakeAtBus
422     {   FxPkgPnp::PowerDxDisablingWakeAtBus,
423         { PowerEventMaximum, WdfDevStatePowerNull },
424         NULL,
425         { FALSE,
426           0 },
427     },
428 
429     // WdfDevStatePowerDxDisablingWakeAtBusNP
430     {   FxPkgPnp::PowerDxDisablingWakeAtBusNP,
431         { PowerEventMaximum, WdfDevStatePowerNull },
432         NULL,
433         { FALSE,
434           0 },
435     },
436 
437     // WdfDevStatePowerGotoDx
438     {   FxPkgPnp::PowerGotoDNotZero,
439         { PowerCompleteDx, WdfDevStatePowerNotifyingD0ExitToWakeInterrupts DEBUGGED_EVENT },
440         NULL,
441         { FALSE,
442           PowerWakeArrival |    // on a PDO which is the PPO, it will send a wake
443                                 // request in this state.
444 
445 
446           PowerParentToD0       // Parent is powering up while this device is powering
447                                 // down
448         },
449     },
450 
451     // WdfDevStatePowerGotoDxNP
452     {   FxPkgPnp::PowerGotoDNotZeroNP,
453         { PowerCompleteDx, WdfDevStatePowerNotifyingD0ExitToWakeInterruptsNP DEBUGGED_EVENT },
454         NULL,
455         { FALSE,
456           PowerWakeArrival |    // on a PDO which is the PPO, it will send a wake
457                                 // request in this state.
458 
459 
460           PowerParentToD0       // Parent is powering up while this device is powering
461                                 // down
462         },
463     },
464 
465     // WdfDevStatePowerGotoDxIoStopped
466     {   FxPkgPnp::PowerGotoDNotZeroIoStopped,
467         { PowerEventMaximum, WdfDevStatePowerNull },
468         NULL,
469         { FALSE,
470           0 },
471     },
472 
473     // WdfDevStatePowerGotoDxIoStoppedNP
474     {   FxPkgPnp::PowerGotoDNotZeroIoStoppedNP,
475         { PowerEventMaximum, WdfDevStatePowerNull },
476         NULL,
477         { FALSE,
478           0 },
479     },
480 
481     // WdfDevStatePowerGotoDxNPFailed
482     {   FxPkgPnp::PowerGotoDxNPFailed,
483         { PowerEventMaximum, WdfDevStatePowerNull },
484         NULL,
485         { FALSE,
486           0 },
487     },
488 
489     // NOTE:  can't use PowerDx as a func name since it's an enum value
490     // WdfDevStatePowerDx
491     {   NULL,
492         { PowerD0, WdfDevStatePowerCheckDeviceType DEBUGGED_EVENT },
493         FxPkgPnp::m_PowerDNotZeroOtherStates,
494         { TRUE,
495           PowerWakeArrival |    // on a PDO which is the PPO, it will send a wake
496                                 // request in this state.
497 
498 
499 
500           PowerWakeCanceled |   // on a PDO which is the PPO, it will cancel the
501                                 // the wake request in this state.  Since we didn't
502                                 // handle PowerWakeArrival in WdfDevStatePowerGotoDx
503                                 // for this scenario, we must also handle the canel
504                                 // here.  Even if we handle wake arrived in that
505                                 // state, the PPO (non KMDF) could send a wake
506                                 // request while in Dx and then cancel it in Dx,
507                                 // so we must still ignore this event here.
508 
509           PowerWakeSucceeded |  // on a PDO which is the PPO, a completion of the
510                                 // wait wake can arrive in this state.  This event
511                                 // can be ignored and the pending wait wake will
512                                 // be completed.
513 
514           PowerImplicitD3 |
515           PowerParentToD0 |     // parent went to D0 first while the PDO was still
516                                 // in Dx
517 
518           PowerDx               // power policy sent a Dx to Dx transition
519         },
520     },
521 
522     // WdfDevStatePowerDxNP
523     {   NULL,
524         { PowerD0, WdfDevStatePowerCheckDeviceTypeNP DEBUGGED_EVENT },
525         FxPkgPnp::m_PowerDNotZeroNPOtherStates,
526         { TRUE,
527           PowerWakeArrival |    // on a PDO which is the PPO, it will send a wake
528                                 // request in this state.
529 
530 
531 
532           PowerWakeCanceled |   // on a PDO which is the PPO, it will cancel the
533                                 // the wake request in this state.  Since we didn't
534                                 // handle PowerWakeArrival in WdfDevStatePowerGotoDx
535                                 // for this scenario, we must also handle the canel
536                                 // here.  Even if we handle wake arrived in that
537                                 // state, the PPO (non KMDF) could send a wake
538                                 // request while in Dx and then cancel it in Dx,
539                                 // so we must still ignore this event here.
540 
541           PowerWakeSucceeded |  // on a PDO which is the PPO, a completion of the
542                                 // wait wake can arrive in this state.  This event
543                                 // can be ignored and the pending wait wake will
544                                 // be completed.
545 
546           PowerParentToD0 |     // parent went to D0 first while the PDO was still
547                                 // in Dx
548 
549           PowerDx               // power policy sent a Dx to Dx transition
550         },
551     },
552 
553     // WdfDevStatePowerGotoDxArmedForWake
554     {   FxPkgPnp::PowerGotoDxArmedForWake,
555         { PowerCompleteDx, WdfDevStatePowerGotoDxIoStoppedArmedForWake DEBUGGED_EVENT },
556         NULL,
557         { FALSE,
558           0 },
559     },
560 
561     // WdfDevStatePowerGotoDxArmedForWakeNP
562     {   FxPkgPnp::PowerGotoDxArmedForWakeNP,
563         { PowerCompleteDx, WdfDevStatePowerGotoDxIoStoppedArmedForWakeNP DEBUGGED_EVENT },
564         NULL,
565         { FALSE,
566           0 },
567     },
568 
569     // WdfDevStatePowerGotoDxIoStoppedArmedForWake
570     {   FxPkgPnp::PowerGotoDxIoStoppedArmedForWake,
571         { PowerEventMaximum, WdfDevStatePowerNull },
572         NULL,
573         { FALSE,
574           0 },
575     },
576 
577     // WdfDevStatePowerGotoDxIoStoppedArmedForWakeNP
578     {   FxPkgPnp::PowerGotoDxIoStoppedArmedForWakeNP,
579         { PowerEventMaximum, WdfDevStatePowerNull },
580         NULL,
581         { FALSE,
582           0 },
583     },
584 
585     // WdfDevStatePowerDxArmedForWake
586     {   NULL,
587         { PowerD0, WdfDevStatePowerCheckParentStateArmedForWake DEBUGGED_EVENT },
588         FxPkgPnp::m_DxArmedForWakeOtherStates,
589         { TRUE,
590           PowerParentToD0      // can occur on a PDO when a Dx transition completes
591                                // on the parent and it wakes up before the child
592         },
593     },
594 
595     // WdfDevStatePowerDxArmedForWakeNP
596     {   NULL,
597         { PowerD0, WdfDevStatePowerCheckParentStateArmedForWakeNP DEBUGGED_EVENT },
598         FxPkgPnp::m_DxArmedForWakeNPOtherStates,
599         { TRUE,
600           PowerParentToD0      // can occur on a PDO when a Dx transition completes
601                                // on the parent and it wakes up before the child
602         },
603     },
604 
605     // WdfDevStatePowerCheckParentStateArmedForWake
606     {   FxPkgPnp::PowerCheckParentStateArmedForWake,
607         { PowerEventMaximum, WdfDevStatePowerNull },
608         NULL,
609         { FALSE,
610           0 },
611     },
612 
613     // WdfDevStatePowerCheckParentStateArmedForWakeNP
614     {   FxPkgPnp::PowerCheckParentStateArmedForWakeNP,
615         { PowerEventMaximum, WdfDevStatePowerNull },
616         NULL,
617         { FALSE,
618           0 },
619     },
620 
621     // WdfDevStatePowerWaitForParentArmedForWake
622     {   NULL,
623         { PowerParentToD0, WdfDevStatePowerDxDisablingWakeAtBus DEBUGGED_EVENT },
624         NULL,
625         { FALSE,
626           0 },
627     },
628 
629     // WdfDevStatePowerWaitForParentArmedForWakeNP
630     {   NULL,
631         { PowerParentToD0, WdfDevStatePowerDxDisablingWakeAtBusNP DEBUGGED_EVENT },
632         NULL,
633         { FALSE,
634           0 },
635     },
636 
637     // WdfDevStatePowerStartSelfManagedIo
638     {   FxPkgPnp::PowerStartSelfManagedIo,
639         { PowerEventMaximum, WdfDevStatePowerNull },
640         NULL,
641         { FALSE,
642           0 },
643     },
644 
645     // WdfDevStatePowerStartSelfManagedIoNP
646     {   FxPkgPnp::PowerStartSelfManagedIoNP,
647         { PowerEventMaximum, WdfDevStatePowerNull },
648         NULL,
649         { FALSE,
650           0 },
651     },
652 
653     // WdfDevStatePowerStartSelfManagedIoFailed
654     {   FxPkgPnp::PowerStartSelfManagedIoFailed,
655         { PowerEventMaximum, WdfDevStatePowerNull },
656         NULL,
657         { FALSE,
658           0 },
659     },
660 
661     // WdfDevStatePowerStartSelfManagedIoFailedNP
662     {   FxPkgPnp::PowerStartSelfManagedIoFailedNP,
663         { PowerEventMaximum, WdfDevStatePowerNull },
664         NULL,
665         { FALSE,
666           0 },
667     },
668 
669     // WdfDevStatePowerWaitForParent
670     {   NULL,
671         { PowerParentToD0, WdfDevStatePowerWaking DEBUGGED_EVENT },
672         NULL,
673         { FALSE,
674           0 },
675     },
676 
677     // WdfDevStatePowerWaitForParentNP
678     {   NULL,
679         { PowerParentToD0, WdfDevStatePowerWakingNP DEBUGGED_EVENT },
680         NULL,
681         { FALSE,
682           0 },
683     },
684 
685     // WdfDevStatePowerWakePending
686     {   FxPkgPnp::PowerWakePending,
687         { PowerD0, WdfDevStatePowerCheckParentStateArmedForWake DEBUGGED_EVENT },
688         FxPkgPnp::m_WakePendingOtherStates,
689         { TRUE,
690           PowerParentToD0 // parent moved to D0 while the child was moving to
691                           // D0 from Dx armed for wake
692         },
693     },
694 
695     // WdfDevStatePowerWakePendingNP
696     {   FxPkgPnp::PowerWakePendingNP,
697         { PowerD0, WdfDevStatePowerCheckParentStateArmedForWakeNP DEBUGGED_EVENT },
698         FxPkgPnp::m_WakePendingNPOtherStates,
699         { TRUE,
700           PowerParentToD0 // parent moved to D0 while the child was moving to
701                           // D0 from Dx armed for wake
702         },
703     },
704 
705     // WdfDevStatePowerWaking
706     {   FxPkgPnp::PowerWaking,
707         { PowerEventMaximum, WdfDevStatePowerNull },
708         NULL,
709         { FALSE,
710           0 },
711     },
712 
713     // WdfDevStatePowerWakingNP
714     {   FxPkgPnp::PowerWakingNP,
715         { PowerEventMaximum, WdfDevStatePowerNull },
716         NULL,
717         { FALSE,
718           0 },
719     },
720 
721     // WdfDevStatePowerWakingConnectInterrupt
722     {   FxPkgPnp::PowerWakingConnectInterrupt,
723         { PowerEventMaximum, WdfDevStatePowerNull },
724         NULL,
725         { FALSE,
726           0 },
727     },
728 
729     // WdfDevStatePowerWakingConnectInterruptNP
730     {   FxPkgPnp::PowerWakingConnectInterruptNP,
731         { PowerEventMaximum, WdfDevStatePowerNull },
732         NULL,
733         { FALSE,
734           0 },
735     },
736 
737     // WdfDevStatePowerWakingConnectInterruptFailed
738     {   FxPkgPnp::PowerWakingConnectInterruptFailed,
739         { PowerEventMaximum, WdfDevStatePowerNull },
740         NULL,
741         { FALSE,
742           0 },
743     },
744 
745     // WdfDevStatePowerWakingConnectInterruptFailedNP
746     {   FxPkgPnp::PowerWakingConnectInterruptFailedNP,
747         { PowerEventMaximum, WdfDevStatePowerNull },
748         NULL,
749         { FALSE,
750           0 },
751     },
752 
753     // WdfDevStatePowerWakingDmaEnable
754     {   FxPkgPnp::PowerWakingDmaEnable,
755         { PowerCompleteD0, WdfDevStatePowerStartSelfManagedIo DEBUGGED_EVENT },
756         NULL,
757         { FALSE,
758           PowerParentToD0 // parent moved to D0 while the child was moving to
759                           // D0 from Dx armed for wake
760         },
761     },
762 
763     // WdfDevStatePowerWakingDmaEnableNP
764     {   FxPkgPnp::PowerWakingDmaEnableNP,
765         { PowerCompleteD0, WdfDevStatePowerStartSelfManagedIoNP DEBUGGED_EVENT },
766         NULL,
767         { FALSE,
768           PowerParentToD0 // parent moved to D0 while the child was moving to
769                           // D0 from Dx armed for wake
770         },
771     },
772 
773     // WdfDevStatePowerWakingDmaEnableFailed
774     {   FxPkgPnp::PowerWakingDmaEnableFailed,
775         { PowerEventMaximum, WdfDevStatePowerNull },
776         NULL,
777         { FALSE,
778           0 },
779     },
780 
781     // WdfDevStatePowerWakingDmaEnableFailedNP
782     {   FxPkgPnp::PowerWakingDmaEnableFailedNP,
783         { PowerEventMaximum, WdfDevStatePowerNull },
784         NULL,
785         { FALSE,
786           0 },
787     },
788 
789     // WdfDevStatePowerReportPowerUpFailedDerefParent
790     {   FxPkgPnp::PowerReportPowerUpFailedDerefParent,
791         { PowerEventMaximum, WdfDevStatePowerNull },
792         NULL,
793         { FALSE,
794           0
795         },
796     },
797 
798     // WdfDevStatePowerReportPowerUpFailed
799     {   FxPkgPnp::PowerReportPowerUpFailed,
800         { PowerImplicitD3, WdfDevStatePowerPowerFailedPowerDown DEBUGGED_EVENT },
801         NULL,
802         { TRUE,
803           0
804         },
805     },
806 
807     // WdfDevStatePowerPowerFailedPowerDown
808     {   FxPkgPnp::PowerPowerFailedPowerDown,
809         { PowerEventMaximum, WdfDevStatePowerNull },
810         NULL,
811         { FALSE,
812           0 },
813     },
814 
815     // WdfDevStatePowerReportPowerDownFailed
816     {   FxPkgPnp::PowerReportPowerDownFailed,
817         { PowerImplicitD3, WdfDevStatePowerPowerFailedPowerDown DEBUGGED_EVENT },
818         NULL,
819         { TRUE,
820           0 },
821     },
822 
823     // WdfDevStatePowerInitialConnectInterruptFailed
824     {   FxPkgPnp::PowerInitialConnectInterruptFailed,
825         { PowerEventMaximum, WdfDevStatePowerNull },
826         NULL,
827         { FALSE,
828           0 },
829     },
830 
831     // WdfDevStatePowerInitialDmaEnableFailed
832     {   FxPkgPnp::PowerInitialDmaEnableFailed,
833         { PowerEventMaximum, WdfDevStatePowerNull },
834         NULL,
835         { FALSE,
836           0 },
837     },
838 
839     // WdfDevStatePowerInitialSelfManagedIoFailed
840     {   FxPkgPnp::PowerInitialSelfManagedIoFailed,
841         { PowerEventMaximum, WdfDevStatePowerNull },
842         NULL,
843         { FALSE,
844           0 },
845     },
846 
847     // WdfDevStatePowerInitialPowerUpFailedDerefParent
848     {   FxPkgPnp::PowerInitialPowerUpFailedDerefParent,
849         { PowerEventMaximum, WdfDevStatePowerNull },
850         NULL,
851         { FALSE,
852           0 },
853     },
854 
855     // WdfDevStatePowerInitialPowerUpFailed
856     {   FxPkgPnp::PowerInitialPowerUpFailed,
857         { PowerEventMaximum, WdfDevStatePowerNull },
858         NULL,
859         { FALSE,
860           0 },
861     },
862 
863     // WdfDevStatePowerDxStoppedDisarmWake
864     {   FxPkgPnp::PowerDxStoppedDisarmWake,
865         { PowerEventMaximum, WdfDevStatePowerNull },
866         NULL,
867         { FALSE,
868           0 },
869     },
870 
871     // WdfDevStatePowerDxStoppedDisarmWakeNP
872     {   FxPkgPnp::PowerDxStoppedDisarmWakeNP,
873         { PowerEventMaximum, WdfDevStatePowerNull },
874         NULL,
875         { FALSE,
876           0 },
877     },
878 
879     // WdfDevStatePowerGotoDxStoppedDisableInterruptNP
880     {   FxPkgPnp::PowerGotoDxStoppedDisableInterruptNP,
881         { PowerEventMaximum, WdfDevStatePowerNull },
882         NULL,
883         { FALSE,
884           0 },
885     },
886 
887     // WdfDevStatePowerGotoDxStopped
888     {   FxPkgPnp::PowerGotoDxStopped,
889         { PowerEventMaximum, WdfDevStatePowerNull },
890         NULL,
891         { FALSE,
892           0 },
893     },
894 
895     // WdfDevStatePowerDxStopped
896     {   NULL,
897         { PowerImplicitD0, WdfDevStatePowerDxStoppedDecideDxState TRAP_ON_EVENT },
898         FxPkgPnp::m_PowerDxStoppedOtherStates,
899         { TRUE,
900           0 },
901     },
902 
903     // WdfDevStatePowerGotoStopped
904     {   FxPkgPnp::PowerGotoStopped,
905         { PowerEventMaximum, WdfDevStatePowerNull },
906         NULL,
907         { FALSE,
908           0 },
909     },
910 
911     // WdfDevStatePowerStoppedCompleteDx
912     {   FxPkgPnp::PowerStoppedCompleteDx,
913         { PowerEventMaximum, WdfDevStatePowerNull },
914         NULL,
915         { FALSE,
916           0 },
917     },
918 
919     // WdfDevStatePowerDxStoppedDecideDxState
920     {   FxPkgPnp::PowerDxStoppedDecideDxState,
921         { PowerEventMaximum, WdfDevStatePowerNull },
922         NULL,
923         { FALSE,
924           0 },
925     },
926 
927     // WdfDevStatePowerDxStoppedArmForWake
928     {   FxPkgPnp::PowerDxStoppedArmForWake,
929         { PowerEventMaximum, WdfDevStatePowerNull },
930         NULL,
931         { FALSE,
932           0 },
933     },
934 
935     // WdfDevStatePowerDxStoppedArmForWakeNP
936     {   FxPkgPnp::PowerDxStoppedArmForWakeNP,
937         { PowerEventMaximum, WdfDevStatePowerNull },
938         NULL,
939         { FALSE,
940           0 },
941     },
942 
943     // WdfDevStatePowerFinalPowerDownFailed
944     {   FxPkgPnp::PowerFinalPowerDownFailed,
945         { PowerEventMaximum, WdfDevStatePowerNull },
946         NULL,
947         { FALSE,
948           0 },
949     },
950 
951     // WdfDevStatePowerFinal
952     {   NULL,
953         { PowerEventMaximum, WdfDevStatePowerNull },
954         NULL,
955         { FALSE,
956           0 },
957     },
958 
959     // WdfDevStatePowerGotoImplicitD3DisarmWakeAtBus
960     {   FxPkgPnp::PowerGotoImplicitD3DisarmWakeAtBus,
961         { PowerEventMaximum, WdfDevStatePowerNull DEBUGGED_EVENT },
962         NULL,
963         { FALSE,
964             0 },
965     },
966 
967     // WdfDevStatePowerUpFailed
968     {   FxPkgPnp::PowerUpFailed,
969         { PowerEventMaximum, WdfDevStatePowerNull },
970         NULL,
971         { FALSE,
972           0 },
973     },
974 
975     // WdfDevStatePowerUpFailedDerefParent
976     {   FxPkgPnp::PowerUpFailedDerefParent,
977         { PowerEventMaximum, WdfDevStatePowerNull },
978         NULL,
979         { FALSE,
980           0 },
981     },
982 
983     // WdfDevStatePowerGotoDxFailed
984     {   FxPkgPnp::PowerGotoDxFailed,
985         { PowerEventMaximum, WdfDevStatePowerNull },
986         NULL,
987         { FALSE,
988           0 },
989     },
990 
991     // WdfDevStatePowerGotoDxStoppedDisableInterrupt
992     {   FxPkgPnp::PowerGotoDxStoppedDisableInterrupt,
993         { PowerEventMaximum, WdfDevStatePowerNull },
994         NULL,
995         { FALSE,
996           0 },
997     },
998 
999     // WdfDevStatePowerUpFailedNP
1000     {   FxPkgPnp::PowerUpFailedNP,
1001         { PowerEventMaximum, WdfDevStatePowerNull },
1002         NULL,
1003         { FALSE,
1004           0 },
1005     },
1006 
1007     // WdfDevStatePowerUpFailedDerefParentNP
1008     {   FxPkgPnp::PowerUpFailedDerefParentNP,
1009         { PowerEventMaximum, WdfDevStatePowerNull },
1010         NULL,
1011         { FALSE,
1012           0 },
1013     },
1014 
1015     // WdfDevStatePowerNotifyingD0ExitToWakeInterrupts
1016     {   FxPkgPnp::PowerNotifyingD0ExitToWakeInterrupts,
1017         { PowerWakeInterruptCompleteTransition, WdfDevStatePowerGotoDxIoStopped DEBUGGED_EVENT },
1018         NULL,
1019         { FALSE,
1020           0 },
1021     },
1022 
1023     // WdfDevStatePowerNotifyingD0EntryToWakeInterrupts
1024     {   FxPkgPnp::PowerNotifyingD0EntryToWakeInterrupts,
1025         { PowerWakeInterruptCompleteTransition, WdfDevStatePowerWakingConnectInterrupt DEBUGGED_EVENT },
1026         NULL,
1027         { FALSE,
1028           0 },
1029     },
1030     // WdfDevStatePowerNotifyingD0ExitToWakeInterruptsNP
1031     {   FxPkgPnp::PowerNotifyingD0ExitToWakeInterruptsNP,
1032         { PowerWakeInterruptCompleteTransition, WdfDevStatePowerGotoDxIoStoppedNP TRAP_ON_EVENT },
1033         NULL,
1034         { FALSE,
1035           0 },
1036     },
1037 
1038     // WdfDevStatePowerNotifyingD0EntryToWakeInterrupts
1039     {   FxPkgPnp::PowerNotifyingD0EntryToWakeInterruptsNP,
1040         { PowerWakeInterruptCompleteTransition, WdfDevStatePowerWakingConnectInterruptNP TRAP_ON_EVENT },
1041         NULL,
1042         { FALSE,
1043           0 },
1044     },
1045 
1046     // WdfDevStatePowerNull
1047     // *** no entry for this state ***
1048 };
1049 
1050 // @@SMVERIFY_SPLIT_END
1051 
1052 _Must_inspect_result_
1053 NTSTATUS
Init(__inout FxPkgPnp * Pnp,__in PFN_PNP_EVENT_WORKER WorkerRoutine)1054 FxPowerMachine::Init(
1055     __inout FxPkgPnp* Pnp,
1056     __in PFN_PNP_EVENT_WORKER WorkerRoutine
1057     )
1058 {
1059     NTSTATUS status;
1060 
1061     status = FxThreadedEventQueue::Init(Pnp, WorkerRoutine);
1062     if (!NT_SUCCESS(status)) {
1063         return status;
1064     }
1065 
1066     return STATUS_SUCCESS;
1067 }
1068 
1069 VOID
PowerCheckAssumptions(VOID)1070 FxPkgPnp::PowerCheckAssumptions(
1071     VOID
1072     )
1073 /*++
1074 
1075 Routine Description:
1076     This routine is never actually called by running code, it just has
1077     WDFCASSERTs who upon failure, would not allow this file to be compiled.
1078 
1079     DO NOT REMOVE THIS FUNCTION just because it is not called by any running
1080     code.
1081 
1082 Arguments:
1083     None
1084 
1085 Return Value:
1086     None
1087 
1088   --*/
1089 {
1090     WDFCASSERT(sizeof(FxPowerStateInfo) == sizeof(ULONG));
1091 
1092     WDFCASSERT((sizeof(m_WdfPowerStates)/sizeof(m_WdfPowerStates[0]))
1093                ==
1094                (WdfDevStatePowerNull - WdfDevStatePowerObjectCreated));
1095 
1096     // we assume these are the same length when we update the history index
1097     WDFCASSERT((sizeof(m_PowerMachine.m_Queue.Events)/
1098                 sizeof(m_PowerMachine.m_Queue.Events[0]))
1099                ==
1100                (sizeof(m_PowerMachine.m_States.History)/
1101                 sizeof(m_PowerMachine.m_States.History[0])));
1102 }
1103 
1104 
1105 /*++
1106 
1107 The locking model for the Power state machine requires that events be enqueued
1108 possibly at DISPATCH_LEVEL.  It also requires that the state machine be
1109 runnable at PASSIVE_LEVEL.  Consequently, we have two locks, one DISPATCH_LEVEL
1110 lock that guards the event queue and one PASSIVE_LEVEL lock that guards the
1111 state machine itself.
1112 
1113 The Power state machine has a few constraints that the PnP state machine
1114 doesn't.  Sometimes it has to call some driver functions at PASSIVE_LEVEL, but
1115 with the disks turned off.  This means that these functions absolutely must not
1116 page fault.  You might think that this means that we should call the driver at
1117 DISPATCH_LEVEL, and you'd be right if your only concern were for perfectly
1118 safe code.  The problem with that approach, though is that it will force much
1119 of the rest of the driver to DISPATCH_LEVEL, which will only push the driver
1120 writer into using lots of asynchronous work items, which will complicate their
1121 code and make it unsafe in a new variety of ways.  So we're going to go with
1122 PASSIVE_LEVEL here and setting a timeout of 20 seconds.  If the driver faults,
1123 the timer will fire and log the failure.  This also means that the driver must
1124 complete these callbacks within 20 seconds.  Even beyond that, it means that
1125 the work items must be queued onto a special thread, one that once the machine
1126 has started to go to sleep, never handles any work items that may fault.
1127 
1128 Algorithm:
1129 
1130 1)  Acquire the Power queue lock.
1131 2)  Enqueue the request.  Requests are put at the end of the queue.
1132 3)  Drop the Power queue lock.
1133 4)  If the thread is running at PASSIVE_LEVEL, skip to step 6.
1134 5)  Queue a work item onto the special power thread.
1135 6)  Attempt to acquire the state machine lock, with a near-zero-length timeout.
1136 7)  If successful, skip to step 9.
1137 8)  Queue a work item onto the special power thread.
1138 9)  Acquire the state machine lock.
1139 10) Acquire the Power queue lock.
1140 11) Attempt to dequeue an event.
1141 12) Drop the Power queue lock.
1142 13) If there was no event to dequeue, drop the state machine lock and exit.
1143 14) Execute the state handler.  This may involve taking one of the other state
1144     machine queue locks, briefly, to deliver an event.
1145 15) Go to Step 10.
1146 
1147 Implementing this algorithm requires three functions.
1148 
1149 PowerProcessEvent         -- Implements steps 1-8.
1150 _PowerProcessEventInner   -- Implements step 9.
1151 PowerProcessEventInner    -- Implements steps 10-15.
1152 
1153 --*/
1154 
1155 VOID
PowerProcessEvent(__in FxPowerEvent Event,__in BOOLEAN ProcessOnDifferentThread)1156 FxPkgPnp::PowerProcessEvent(
1157     __in FxPowerEvent Event,
1158     __in BOOLEAN ProcessOnDifferentThread
1159     )
1160 /*++
1161 
1162 Routine Description:
1163     This function implements steps 1-8 of the algorithm described above.
1164 
1165 Arguments:
1166     Event - Current Power event
1167 
1168     ProcessOnDifferentThread - Process the event on a different thread
1169         regardless of IRQL. By default this is FALSE as per the declaration.
1170 
1171 Return Value:
1172 
1173     NTSTATUS
1174 
1175 --*/
1176 {
1177     NTSTATUS status;
1178     KIRQL irql;
1179 
1180     //
1181     // Take the lock, raising to DISPATCH_LEVEL.
1182     //
1183     m_PowerMachine.Lock(&irql);
1184 
1185     //
1186     // If the input Event is any of the events described by PowerSingularEventMask,
1187     // then check whether it is already queued up. If so, then dont enqueue this
1188     // Event.
1189     //
1190     if (Event & PowerSingularEventMask) {
1191         if ((m_PowerMachine.m_SingularEventsPresent & Event) == 0x00) {
1192             m_PowerMachine.m_SingularEventsPresent |= Event;
1193         }
1194         else {
1195             DoTraceLevelMessage(
1196                 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
1197                 "WDFDEVICE 0x%p !devobj 0x%p current pwr pol state "
1198                 "%!WDF_DEVICE_POWER_STATE! dropping event %!FxPowerEvent! because "
1199                 "the Event is already enqueued.", m_Device->GetHandle(),
1200                 m_Device->GetDeviceObject(),
1201                 m_Device->GetDevicePowerState(),
1202                 Event);
1203 
1204             m_PowerMachine.Unlock(irql);
1205             return;
1206         }
1207     }
1208 
1209     if (m_PowerMachine.IsFull()) {
1210         //
1211         // The queue is full.  Bail.
1212         //
1213         m_PowerMachine.Unlock(irql);
1214 
1215         ASSERT(!"The Power queue is full.  This shouldn't be able to happen.");
1216         return;
1217     }
1218 
1219     if (m_PowerMachine.IsClosedLocked()) {
1220         DoTraceLevelMessage(
1221             GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
1222             "WDFDEVICE 0x%p !devobj 0x%p current pwr pol state "
1223             "%!WDF_DEVICE_POWER_STATE! dropping event %!FxPowerEvent! because "
1224             "of a closed queue", m_Device->GetHandle(),
1225             m_Device->GetDeviceObject(),
1226             m_Device->GetDevicePowerState(),
1227             Event);
1228 
1229         //
1230         // The queue is closed.  Bail
1231         //
1232         m_PowerMachine.Unlock(irql);
1233 
1234         return;
1235     }
1236 
1237     //
1238     // Enqueue the event.  Whether the event goes on the front
1239     // or the end of the queue depends on which event it is.
1240     //
1241     if (Event & PowerPriorityEventsMask) {
1242         //
1243         // Stick it on the front of the queue, making it the next
1244         // event that will be processed.
1245         //
1246         m_PowerMachine.m_Queue.Events[m_PowerMachine.InsertAtHead()] = (USHORT) Event;
1247     }
1248     else {
1249         //
1250         // Stick it on the end of the queue.
1251         //
1252         m_PowerMachine.m_Queue.Events[m_PowerMachine.InsertAtTail()] = (USHORT) Event;
1253     }
1254 
1255     //
1256     // Drop the lock.
1257     //
1258     m_PowerMachine.Unlock(irql);
1259 
1260     //
1261     // Now, if we are running at PASSIVE_LEVEL, attempt to run the state
1262     // machine on this thread.  If we can't do that, then queue a work item.
1263     //
1264 
1265     if (irql == PASSIVE_LEVEL &&
1266         FALSE == ProcessOnDifferentThread) {
1267         LONGLONG timeout = 0;
1268 
1269         status = m_PowerMachine.m_StateMachineLock.AcquireLock(
1270             GetDriverGlobals(), &timeout);
1271 
1272         if (FxWaitLockInternal::IsLockAcquired(status)) {
1273             FxPostProcessInfo info;
1274 
1275             //
1276             // We now hold the state machine lock.  So call the function that
1277             // dispatches the next state.
1278             //
1279             PowerProcessEventInner(&info);
1280 
1281             //
1282             // The pnp state machine should be the only one deleting the object
1283             //
1284             ASSERT(info.m_DeleteObject == FALSE);
1285 
1286             m_PowerMachine.m_StateMachineLock.ReleaseLock(GetDriverGlobals());
1287 
1288             info.Evaluate(this);
1289 
1290             return;
1291         }
1292     }
1293 
1294     //
1295     // The tag added above will be released when the work item runs
1296     //
1297 
1298     // For one reason or another, we couldn't run the state machine on this
1299     // thread.  So queue a work item to do it.  If m_PnPWorkItemEnqueuing
1300     // is non-zero, that means that the work item is already being enqueued
1301     // on another thread.  This is significant, since it means that we can't do
1302     // anything with the work item on this thread, but it's okay, since the
1303     // work item will pick up our work and do it.
1304     //
1305     m_PowerMachine.QueueToThread();
1306 }
1307 
1308 VOID
_PowerProcessEventInner(__in FxPkgPnp * This,__in FxPostProcessInfo * Info,__in PVOID WorkerContext)1309 FxPkgPnp::_PowerProcessEventInner(
1310     __in FxPkgPnp* This,
1311     __in FxPostProcessInfo* Info,
1312     __in PVOID WorkerContext
1313     )
1314 {
1315 
1316     UNREFERENCED_PARAMETER(WorkerContext);
1317 
1318     //
1319     // Take the state machine lock.
1320     //
1321     This->m_PowerMachine.m_StateMachineLock.AcquireLock(
1322         This->GetDriverGlobals()
1323         );
1324 
1325     //
1326     // Call the function that will actually run the state machine.
1327     //
1328     This->PowerProcessEventInner(Info);
1329 
1330     //
1331     // We are being called from the work item and m_WorkItemRunning is > 0, so
1332     // we cannot be deleted yet.
1333     //
1334     ASSERT(Info->SomethingToDo() == FALSE);
1335 
1336     //
1337     // Now release the lock
1338     //
1339     This->m_PowerMachine.m_StateMachineLock.ReleaseLock(
1340         This->GetDriverGlobals()
1341         );
1342 }
1343 
1344 VOID
PowerProcessEventInner(__inout FxPostProcessInfo * Info)1345 FxPkgPnp::PowerProcessEventInner(
1346     __inout FxPostProcessInfo* Info
1347     )
1348 /*++
1349 
1350 Routine Description:
1351     This routine runs the state machine.  It implements steps 10-15 of the
1352     algorithm described above.
1353 
1354 --*/
1355 {
1356     WDF_DEVICE_POWER_STATE currentPowerState, newState;
1357     CPPOWER_STATE_TABLE entry;
1358     FxPowerEvent event;
1359     KIRQL       oldIrql;
1360 
1361     //
1362     // Process as many events as we can.
1363     //
1364     for (;;) {
1365 
1366         newState = WdfDevStatePowerNull;
1367         currentPowerState = m_Device->GetDevicePowerState();
1368         entry = GetPowerTableEntry(currentPowerState);
1369 
1370         //
1371         // Get an event from the queue.
1372         //
1373         m_PowerMachine.Lock(&oldIrql);
1374 
1375         if (m_PowerMachine.IsEmpty()) {
1376             m_PowerMachine.GetFinishedState(Info);
1377 
1378             //
1379             // The queue is empty.
1380             //
1381             m_PowerMachine.Unlock(oldIrql);
1382             return;
1383         }
1384 
1385         event = (FxPowerEvent) m_PowerMachine.m_Queue.Events[m_PowerMachine.GetHead()];
1386 
1387         //
1388         // At this point, we need to determine whether we can process this
1389         // event.
1390         //
1391         if (event & PowerPriorityEventsMask) {
1392             //
1393             // These are always possible to handle.
1394             //
1395             DO_NOTHING();
1396         }
1397         else {
1398             //
1399             // Check to see if this state can handle new events.
1400             //
1401             if (entry->StateInfo.Bits.QueueOpen == FALSE) {
1402                 //
1403                 // This state can't handle new events.
1404                 //
1405                 m_PowerMachine.Unlock(oldIrql);
1406                 return;
1407             }
1408         }
1409 
1410         //
1411         // If the event obtained from the queue was a singular event, then
1412         // clear the flag to allow other similar events to be put into this
1413         // queue for processing.
1414         //
1415         if (m_PowerMachine.m_SingularEventsPresent & event) {
1416            m_PowerMachine.m_SingularEventsPresent &= ~event;
1417         }
1418 
1419         m_PowerMachine.IncrementHead();
1420         m_PowerMachine.Unlock(oldIrql);
1421 
1422         //
1423         // Find the entry in the power state table that corresponds to this event
1424         //
1425         if (entry->FirstTargetState.PowerEvent == event) {
1426             newState = entry->FirstTargetState.TargetState;
1427 
1428             DO_EVENT_TRAP(&entry->FirstTargetState);
1429         }
1430         else if (entry->OtherTargetStates != NULL) {
1431             ULONG i = 0;
1432 
1433             for (i = 0;
1434                  entry->OtherTargetStates[i].PowerEvent != PowerEventMaximum;
1435                  i++) {
1436                 if (entry->OtherTargetStates[i].PowerEvent == event) {
1437                     newState = entry->OtherTargetStates[i].TargetState;
1438                     DO_EVENT_TRAP(&entry->OtherTargetStates[i]);
1439                     break;
1440                 }
1441             }
1442         }
1443 
1444         if (newState == WdfDevStatePowerNull) {
1445             DoTraceLevelMessage(
1446                 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
1447                 "WDFDEVICE 0x%p !devobj 0x%p current power state "
1448                 "%!WDF_DEVICE_POWER_STATE! dropping event %!FxPowerEvent!",
1449                 m_Device->GetHandle(),
1450                 m_Device->GetDeviceObject(),
1451                 m_Device->GetDevicePowerState(), event);
1452 
1453             //
1454             // This state doesn't respond to the Event.  Potentially throw
1455             // the event away.
1456             //
1457             if ((entry->StateInfo.Bits.KnownDroppedEvents & event) == 0) {
1458                 COVERAGE_TRAP();
1459 
1460                 DoTraceLevelMessage(
1461                     GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP,
1462                     "WDFDEVICE %p !devobj 0x%p current state "
1463                     "%!WDF_DEVICE_POWER_STATE! event %!FxPowerEvent! is not a "
1464                     "known dropped event, known dropped events are "
1465                     "%!FxPowerEvent!", m_Device->GetHandle(),
1466                     m_Device->GetDeviceObject(),
1467                     m_Device->GetDevicePowerState(),
1468                     event, entry->StateInfo.Bits.KnownDroppedEvents);
1469 
1470 
1471             }
1472 
1473             switch (event) {
1474             case PowerWakeSucceeded:
1475             case PowerWakeFailed:
1476             case PowerWakeCanceled:
1477                 //
1478                 // There are states where we don't care if the wake completed.
1479                 // Since the completion/cancellation of the wake request posts
1480                 // an event which it assumes will complete the request, we must
1481                 // catch these events here and complete the request.
1482                 //
1483                 PowerCompletePendedWakeIrp();
1484                 break;
1485 
1486             case PowerD0:
1487             case PowerDx:
1488                 //
1489                 // There are some (non WDF) power policy owner implementations
1490                 // which send Dx to Dx or D0 to D0 transitions to the stack.
1491                 //
1492                 // We don't explicitly handle them in the state machine.
1493                 //
1494                 // Instead, we complete the pended irp if are about to drop it
1495                 // on the floor.
1496                 //
1497                 PowerReleasePendingDeviceIrp();
1498                 break;
1499             }
1500         }
1501         else {
1502             //
1503             // Now enter the new state.
1504             //
1505             PowerEnterNewState(newState);
1506         }
1507     }
1508 }
1509 
1510 VOID
PowerEnterNewState(__in WDF_DEVICE_POWER_STATE State)1511 FxPkgPnp::PowerEnterNewState(
1512     __in WDF_DEVICE_POWER_STATE State
1513     )
1514 /*++
1515 
1516 Routine Description:
1517     This function looks up the handler for a state and
1518     then calls it.
1519 
1520 Arguments:
1521     Event - Current PnP event
1522 
1523 Return Value:
1524 
1525     NTSTATUS
1526 
1527 --*/
1528 {
1529     CPPOWER_STATE_TABLE    entry;
1530     WDF_DEVICE_POWER_STATE currentState, newState;
1531     WDF_DEVICE_POWER_NOTIFICATION_DATA data;
1532     FxWatchdog watchdog(this);
1533 
1534     currentState = m_Device->GetDevicePowerState();
1535     newState = State;
1536 
1537     while (newState != WdfDevStatePowerNull) {
1538         DoTraceLevelMessage(
1539             GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNPPOWERSTATES,
1540             "WDFDEVICE 0x%p !devobj 0x%p entering Power State "
1541             "%!WDF_DEVICE_POWER_STATE! from %!WDF_DEVICE_POWER_STATE!",
1542             m_Device->GetHandle(),
1543             m_Device->GetDeviceObject(),
1544             newState, currentState);
1545 
1546         if (m_PowerStateCallbacks != NULL) {
1547             //
1548             // Callback for leaving the old state
1549             //
1550             RtlZeroMemory(&data, sizeof(data));
1551 
1552             data.Type = StateNotificationLeaveState;
1553             data.Data.LeaveState.CurrentState = currentState;
1554             data.Data.LeaveState.NewState = newState;
1555 
1556             m_PowerStateCallbacks->Invoke(currentState,
1557                                           StateNotificationLeaveState,
1558                                           m_Device->GetHandle(),
1559                                           &data);
1560         }
1561 
1562         m_PowerMachine.m_States.History[m_PowerMachine.IncrementHistoryIndex()] =
1563             (USHORT) newState;
1564 
1565         if (m_PowerStateCallbacks != NULL) {
1566             //
1567             // Callback for entering the new state
1568             //
1569             RtlZeroMemory(&data, sizeof(data));
1570 
1571             data.Type = StateNotificationEnterState;
1572             data.Data.EnterState.CurrentState = currentState;
1573             data.Data.EnterState.NewState = newState;
1574 
1575             m_PowerStateCallbacks->Invoke(newState,
1576                                           StateNotificationEnterState,
1577                                           m_Device->GetHandle(),
1578                                           &data);
1579         }
1580 
1581         m_Device->SetDevicePowerState(newState);
1582         currentState = newState;
1583 
1584         entry = GetPowerTableEntry(currentState);
1585 
1586         //
1587         // And call the state handler, if there is one.
1588         //
1589         if (entry->StateFunc != NULL) {
1590             watchdog.StartTimer(currentState);
1591             newState = entry->StateFunc(this);
1592             watchdog.CancelTimer(currentState);
1593 
1594             //
1595             // Validate the return value if FX_STATE_MACHINE_VERIFY is enabled
1596             //
1597             VALIDATE_POWER_STATE(currentState, newState);
1598 
1599         }
1600         else {
1601             newState = WdfDevStatePowerNull;
1602         }
1603 
1604         if (m_PowerStateCallbacks != NULL) {
1605             //
1606             // Callback for post processing the new state
1607             //
1608             RtlZeroMemory(&data, sizeof(data));
1609 
1610             data.Type = StateNotificationPostProcessState;
1611             data.Data.PostProcessState.CurrentState = currentState;
1612 
1613             m_PowerStateCallbacks->Invoke(currentState,
1614                                           StateNotificationPostProcessState,
1615                                           m_Device->GetHandle(),
1616                                           &data);
1617         }
1618     }
1619 }
1620 
1621 WDF_DEVICE_POWER_STATE
PowerCheckParentState(__inout FxPkgPnp * This)1622 FxPkgPnp::PowerCheckParentState(
1623     __inout FxPkgPnp*   This
1624     )
1625 /*++
1626 
1627 Routine Description:
1628     This function implements the Check Parent state.  Its only task
1629     is to dispatch to the FDO and PDO logic and handle error.
1630 
1631 Arguments:
1632     none
1633 
1634 Return Value:
1635 
1636     new power state
1637 
1638 --*/
1639 {
1640     NTSTATUS status;
1641     BOOLEAN parentOn;
1642 
1643     status = This->PowerCheckParentOverload(&parentOn);
1644 
1645     if (!NT_SUCCESS(status)) {
1646         return WdfDevStatePowerUpFailed;
1647     }
1648     else if (parentOn) {
1649         return WdfDevStatePowerWaking;
1650     }
1651     else {
1652         return WdfDevStatePowerWaitForParent;
1653     }
1654 }
1655 
1656 WDF_DEVICE_POWER_STATE
PowerCheckParentStateNP(__inout FxPkgPnp * This)1657 FxPkgPnp::PowerCheckParentStateNP(
1658     __inout FxPkgPnp*   This
1659     )
1660 /*++
1661 
1662 Routine Description:
1663     This function implements the Check Parent (NP) state.  Its only task
1664     is to dispatch to the FDO and PDO logic.
1665 
1666 Arguments:
1667     none
1668 
1669 Return Value:
1670 
1671     new power state
1672 
1673 --*/
1674 {
1675     NTSTATUS status;
1676     BOOLEAN parentOn;
1677 
1678     status = This->PowerCheckParentOverload(&parentOn);
1679 
1680     if (!NT_SUCCESS(status)) {
1681         return WdfDevStatePowerUpFailedNP;
1682     }
1683     else if (parentOn) {
1684         return WdfDevStatePowerWakingNP;
1685     }
1686     else {
1687         return WdfDevStatePowerWaitForParentNP;
1688     }
1689 }
1690 
1691 WDF_DEVICE_POWER_STATE
PowerCheckDeviceType(__inout FxPkgPnp * This)1692 FxPkgPnp::PowerCheckDeviceType(
1693     __inout FxPkgPnp*   This
1694     )
1695 /*++
1696 
1697 Routine Description:
1698     This function implements the Check Type state.  Its only task
1699     is to dispatch to the FDO and PDO logic.
1700 
1701 Arguments:
1702     none
1703 
1704 Return Value:
1705 
1706     new power state
1707 
1708 --*/
1709 {
1710     return This->PowerCheckDeviceTypeOverload();
1711 }
1712 
1713 WDF_DEVICE_POWER_STATE
PowerCheckDeviceTypeNP(__inout FxPkgPnp * This)1714 FxPkgPnp::PowerCheckDeviceTypeNP(
1715     __inout FxPkgPnp*   This
1716     )
1717 /*++
1718 
1719 Routine Description:
1720     This function implements the Check Type (NP) state.  Its only task
1721     is to dispatch to the FDO and PDO logic.
1722 
1723 Arguments:
1724     none
1725 
1726 Return Value:
1727 
1728     new power state
1729 
1730 --*/
1731 {
1732     return This->PowerCheckDeviceTypeNPOverload();
1733 }
1734 
1735 WDF_DEVICE_POWER_STATE
PowerEnablingWakeAtBus(__inout FxPkgPnp * This)1736 FxPkgPnp::PowerEnablingWakeAtBus(
1737     __inout FxPkgPnp*   This
1738     )
1739 /*++
1740 
1741 Routine Description:
1742     This function requests the driver to arm the device in a bus generic fashion.
1743 
1744 Arguments:
1745     The package which contains this instance of the state machine
1746 
1747 Return Value:
1748     new power state
1749 
1750   --*/
1751 {
1752     NTSTATUS status;
1753 
1754     //
1755     // We should only get into this state when this devobj is not a PDO and a
1756     // power policy owner.
1757     //
1758     ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE);
1759 
1760     status = This->PowerEnableWakeAtBusOverload();
1761 
1762     ASSERT(status != STATUS_CANCELLED);
1763 
1764     if (NT_SUCCESS(status)) {
1765         //
1766         // No matter of the irp status (canceled, pending, completed), we always
1767         // transition to the D0ArmedForWake state because that is where we
1768         // we handle the change in the irp's status.
1769         //
1770         return WdfDevStatePowerD0ArmedForWake;
1771     }
1772     else {
1773         This->PowerCompleteWakeRequestFromWithinMachine(status);
1774 
1775         return WdfDevStatePowerD0BusWakeOwner;
1776     }
1777 }
1778 
1779 WDF_DEVICE_POWER_STATE
PowerEnablingWakeAtBusNP(__inout FxPkgPnp * This)1780 FxPkgPnp::PowerEnablingWakeAtBusNP(
1781     __inout FxPkgPnp*   This
1782     )
1783 /*++
1784 
1785 Routine Description:
1786     This function requests the driver to arm the device in a bus generic fashion.
1787 
1788 Arguments:
1789     The package which contains this instance of the state machine
1790 
1791 Return Value:
1792     new power state
1793 
1794   --*/
1795 {
1796     NTSTATUS status;
1797 
1798     //
1799     // We should only get into this state when this devobj is not a PDO and a
1800     // power policy owner.
1801     //
1802     ASSERT((This->m_Device->IsPdo() &&
1803         This->IsPowerPolicyOwner()) == FALSE);
1804 
1805     status = This->PowerEnableWakeAtBusOverload();
1806 
1807     ASSERT(status != STATUS_CANCELLED);
1808 
1809     if (NT_SUCCESS(status)) {
1810         //
1811         // No matter of the irp status (canceled, pending, completed), we always
1812         // transition to the D0ArmedForWake state because that is where we
1813         // we handle the change in the irp's status.
1814         //
1815         return WdfDevStatePowerD0ArmedForWakeNP;
1816     }
1817     else {
1818         //
1819         // Complete the irp with the error that callback indicated
1820         //
1821         COVERAGE_TRAP();
1822 
1823         This->PowerCompleteWakeRequestFromWithinMachine(status);
1824 
1825         return WdfDevStatePowerD0BusWakeOwnerNP;
1826     }
1827 }
1828 
1829 WDF_DEVICE_POWER_STATE
PowerDZero(__inout FxPkgPnp * This)1830 FxPkgPnp::PowerDZero(
1831     __inout FxPkgPnp*   This
1832     )
1833 /*++
1834 
1835 Routine Description:
1836     D0 state where we cannot wake the machine
1837 
1838 Arguments:
1839     This - Instance of this state machine
1840 
1841 Return Value:
1842     new power state machine state
1843 
1844   --*/
1845 {
1846     if ((This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) == 0) {
1847         //
1848         // We are non pageable, go to that state now
1849         //
1850         COVERAGE_TRAP();
1851 
1852         return WdfDevStatePowerDecideD0State;
1853     }
1854 
1855     return WdfDevStatePowerNull;
1856 }
1857 
1858 WDF_DEVICE_POWER_STATE
PowerD0NP(__inout FxPkgPnp * This)1859 FxPkgPnp::PowerD0NP(
1860     __inout FxPkgPnp*   This
1861     )
1862 /*++
1863 
1864 Routine Description:
1865     D0 state where we can't cause paging IO and we cannot wake the machine
1866 
1867 Arguments:
1868     This - Instance of this state machine
1869 
1870 Return Value:
1871     new power state machine state
1872 
1873   --*/
1874 {
1875     if (This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) {
1876         //
1877         // We are pageable, go to that state now
1878         //
1879         COVERAGE_TRAP();
1880         return WdfDevStatePowerDecideD0State;
1881     }
1882 
1883     return WdfDevStatePowerNull;
1884 }
1885 
1886 
1887 WDF_DEVICE_POWER_STATE
PowerD0BusWakeOwner(__inout FxPkgPnp * This)1888 FxPkgPnp::PowerD0BusWakeOwner(
1889     __inout FxPkgPnp*   This
1890     )
1891 /*++
1892 
1893 Routine Description:
1894     This function implements the D0 state.  It's job is to figure out whether
1895     we need to swtich to the D0NP state, and to wait around for an event
1896     of some kind or another.
1897 
1898 Arguments:
1899     none
1900 
1901 Return Value:
1902 
1903     new power state
1904 
1905 --*/
1906 {
1907     if ((This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) == 0) {
1908         //
1909         // We are non pageable, go to that state now
1910         //
1911         COVERAGE_TRAP();
1912 
1913         return WdfDevStatePowerDecideD0State;
1914     }
1915     else if (This->PowerIsWakeRequestPresent()) {
1916         return WdfDevStatePowerEnablingWakeAtBus;
1917     }
1918     else {
1919         return WdfDevStatePowerNull;
1920     }
1921 }
1922 
1923 WDF_DEVICE_POWER_STATE
PowerD0BusWakeOwnerNP(__inout FxPkgPnp * This)1924 FxPkgPnp::PowerD0BusWakeOwnerNP(
1925     __inout FxPkgPnp*   This
1926     )
1927 /*++
1928 
1929 Routine Description:
1930     This function implements the D0NP state.  It's job is to figure out whether
1931     we need to swtich to the D0 state, and to wait around for an event
1932     of some kind or another.
1933 
1934 Arguments:
1935     none
1936 
1937 Return Value:
1938 
1939     new power state
1940 
1941 --*/
1942 {
1943     if (This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) {
1944         //
1945         // Pageable.
1946         //
1947         COVERAGE_TRAP();
1948 
1949         return WdfDevStatePowerDecideD0State;
1950     }
1951     else if (This->PowerIsWakeRequestPresent()) {
1952         return WdfDevStatePowerEnablingWakeAtBusNP;
1953     }
1954     else {
1955         return WdfDevStatePowerNull;
1956     }
1957 }
1958 
1959 WDF_DEVICE_POWER_STATE
PowerD0ArmedForWake(__inout FxPkgPnp * This)1960 FxPkgPnp::PowerD0ArmedForWake(
1961     __inout FxPkgPnp*   This
1962     )
1963 /*++
1964 
1965 Routine Description:
1966     Device is in D0 and armed for wake.  Complete any pended D0 irp if the power
1967     policy owner make a D0 to D0 transition.  Transition the NP version of
1968     this state if we are no longer pageable.
1969 
1970 Arguments:
1971     This - instance of the state machine
1972 
1973 Return Value:
1974     new state machine state
1975 
1976   --*/
1977 {
1978     if ((This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) == 0) {
1979         //
1980         // We are non pageable, go to that state now
1981         //
1982         COVERAGE_TRAP();
1983 
1984         return WdfDevStatePowerDecideD0State;
1985     }
1986 
1987     return WdfDevStatePowerNull;
1988 }
1989 
1990 WDF_DEVICE_POWER_STATE
PowerD0ArmedForWakeNP(__inout FxPkgPnp * This)1991 FxPkgPnp::PowerD0ArmedForWakeNP(
1992     __inout FxPkgPnp*   This
1993     )
1994 /*++
1995 
1996 Routine Description:
1997     Device is in D0 and armed for wake.  Complete any pended D0 irp if the power
1998     policy owner make a D0 to D0 transition.  Transition the pageable version of
1999     this state if we are no longer NP.
2000 
2001 Arguments:
2002     This - instance of the state machine
2003 
2004 Return Value:
2005     new state machine state
2006 
2007   --*/
2008 {
2009     if (This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) {
2010         //
2011         // We are pageable, go to that state now
2012         //
2013         COVERAGE_TRAP();
2014 
2015         return WdfDevStatePowerDecideD0State;
2016     }
2017 
2018     return WdfDevStatePowerNull;
2019 }
2020 
2021 WDF_DEVICE_POWER_STATE
PowerGotoImplicitD3DisarmWakeAtBus(__inout FxPkgPnp * This)2022 FxPkgPnp::PowerGotoImplicitD3DisarmWakeAtBus(
2023     __inout FxPkgPnp*   This
2024     )
2025 /*++
2026 
2027 Routine Description:
2028     Disarms the bus after we have armed it.  The device is going to implicit D3
2029     and it has not yet been powered down.
2030 
2031 Arguments:
2032     This - instance of the state machine
2033 
2034 Return Value:
2035     new state machine state
2036 
2037   --*/
2038 {
2039     //
2040     // We should only get into this state when this devobj is a PDO and not a
2041     // power policy owner.
2042     //
2043     ASSERT((This->m_Device->IsPdo() &&
2044         This->IsPowerPolicyOwner()) == FALSE);
2045 
2046     //
2047     // Disarm
2048     // No need to complete the pended ww irp. State machine will complete it
2049     // in PnpFailed handler, or upper driver will cancel it.
2050     //
2051     This->PowerDisableWakeAtBusOverload();
2052 
2053     return WdfDevStatePowerGotoD3Stopped;
2054 }
2055 
2056 WDF_DEVICE_POWER_STATE
PowerD0DisarmingWakeAtBus(__inout FxPkgPnp * This)2057 FxPkgPnp::PowerD0DisarmingWakeAtBus(
2058     __inout FxPkgPnp*   This
2059     )
2060 /*++
2061 
2062 Routine Description:
2063     Disarms the bus after we have armed it.  The device is still in D0 so it has
2064     not yet powered down.
2065 
2066 Arguments:
2067     This - This instance of the state machine
2068 
2069 Return Value:
2070     None.
2071 
2072   --*/
2073 {
2074     //
2075     // We should only get into this state when this devobj is not a PDO and a
2076     // power policy owner.
2077     //
2078     ASSERT((This->m_Device->IsPdo() &&
2079         This->IsPowerPolicyOwner()) == FALSE);
2080 
2081     //
2082     // Disarm
2083     //
2084     This->PowerDisableWakeAtBusOverload();
2085     This->PowerCompletePendedWakeIrp();
2086 
2087     //
2088     // Go back to normal unarmed D0 with bus wake ownership
2089     //
2090     return WdfDevStatePowerD0BusWakeOwner;
2091 }
2092 
2093 WDF_DEVICE_POWER_STATE
PowerD0DisarmingWakeAtBusNP(__inout FxPkgPnp * This)2094 FxPkgPnp::PowerD0DisarmingWakeAtBusNP(
2095     __inout FxPkgPnp*   This
2096     )
2097 /*++
2098 
2099 Routine Description:
2100     Disarms the bus after we have armed it.  The device is still in D0 so it has
2101     not yet powered down.
2102 
2103 Arguments:
2104     This - This instance of the state machine
2105 
2106 Return Value:
2107     None.
2108 
2109   --*/
2110 {
2111     //
2112     // We should only get into this state when this devobj is not a PDO and a
2113     // power policy owner.
2114     //
2115     ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE);
2116 
2117     //
2118     // Disarm
2119     //
2120     This->PowerDisableWakeAtBusOverload();
2121     This->PowerCompletePendedWakeIrp();
2122 
2123     //
2124     // Go back to normal unarmed D0 with bus wake ownership
2125     //
2126     return WdfDevStatePowerD0BusWakeOwnerNP;
2127 }
2128 
2129 WDF_DEVICE_POWER_STATE
PowerD0Starting(__inout FxPkgPnp * This)2130 FxPkgPnp::PowerD0Starting(
2131     __inout FxPkgPnp*   This
2132     )
2133 /*++
2134 
2135 Routine Description:
2136     This function calls D0Entry and the moves to the next state based on the
2137     result.
2138 
2139 Arguments:
2140     This - instance of the state machine
2141 
2142 Return Value:
2143     new power state
2144 
2145 --*/
2146 {
2147     NTSTATUS    status;
2148 
2149     //
2150     // Call the driver to tell it to put the hardware into the working
2151     // state.
2152     //
2153     // m_DevicePowerState is the "old" state because we update it after the
2154     // D0Entry callback.
2155     //
2156     status = This->m_DeviceD0Entry.Invoke(
2157         This->m_Device->GetHandle(),
2158         (WDF_POWER_DEVICE_STATE) This->m_DevicePowerState);
2159 
2160     if (!NT_SUCCESS(status)) {
2161         DoTraceLevelMessage(
2162             This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2163             "EvtDeviceD0Entry WDFDEVICE 0x%p !devobj 0x%p,  old state "
2164             "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!",
2165             This->m_Device->GetHandle(),
2166             This->m_Device->GetDeviceObject(),
2167             This->m_DevicePowerState, status);
2168 
2169         return WdfDevStatePowerInitialPowerUpFailedDerefParent;
2170     }
2171 
2172     return WdfDevStatePowerD0StartingConnectInterrupt;
2173 }
2174 
2175 WDF_DEVICE_POWER_STATE
PowerD0StartingConnectInterrupt(__inout FxPkgPnp * This)2176 FxPkgPnp::PowerD0StartingConnectInterrupt(
2177     __inout FxPkgPnp*   This
2178     )
2179 /*++
2180 
2181 Routine Description:
2182     Continues bringing the device into D0 from the D3 final state.  This routine
2183     connects and enables the interrupts.  If successful it will open up the power
2184     managed i/o queues.
2185 
2186 Arguments:
2187     This - instance of the state machine
2188 
2189 Return Value:
2190     new state machine state
2191 
2192   --*/
2193 {
2194     NTSTATUS status;
2195 
2196     //
2197     // Connect the interrupt and enable it
2198     //
2199     status = This->NotifyResourceObjectsD0(NotifyResourcesNoFlags);
2200     if (!NT_SUCCESS(status)) {
2201         //
2202         // NotifyResourceObjectsD0 has already logged the error, no need to
2203         // repeat any error messsages here
2204         //
2205         return WdfDevStatePowerInitialConnectInterruptFailed;
2206     }
2207 
2208     status = This->m_DeviceD0EntryPostInterruptsEnabled.Invoke(
2209         This->m_Device->GetHandle(),
2210         (WDF_POWER_DEVICE_STATE) This->m_DevicePowerState);
2211 
2212     if (!NT_SUCCESS(status)) {
2213 
2214         DoTraceLevelMessage(
2215             This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2216             "EvtDeviceD0EntryPostInterruptsEnabed WDFDEVICE 0x%p !devobj 0x%p, "
2217             "old state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!",
2218             This->m_Device->GetHandle(),
2219             This->m_Device->GetDeviceObject(),
2220             This->m_DevicePowerState, status);
2221         return WdfDevStatePowerInitialConnectInterruptFailed;
2222     }
2223 
2224     //
2225     // Last, figure out which state to drop into.  This is the juncture
2226     // where we figure out if we're doing power in a pageable fashion.
2227     //
2228     return WdfDevStatePowerD0StartingDmaEnable;
2229 }
2230 
2231 WDF_DEVICE_POWER_STATE
PowerD0StartingDmaEnable(__inout FxPkgPnp * This)2232 FxPkgPnp::PowerD0StartingDmaEnable(
2233     __inout FxPkgPnp*   This
2234     )
2235 /*++
2236 
2237 Routine Description:
2238     The device is movig to D0 for the first time.  Enable any DMA enablers
2239     attached to the device.
2240 
2241 Arguments:
2242     This - instance of the state machine
2243 
2244 Return Value:
2245     new machine state
2246 
2247   --*/
2248 {
2249     if (This->PowerDmaEnableAndScan(TRUE) == FALSE) {
2250         return WdfDevStatePowerInitialDmaEnableFailed;
2251     }
2252 
2253     return WdfDevStatePowerD0StartingStartSelfManagedIo;
2254 }
2255 
2256 WDF_DEVICE_POWER_STATE
PowerD0StartingStartSelfManagedIo(__inout FxPkgPnp * This)2257 FxPkgPnp::PowerD0StartingStartSelfManagedIo(
2258     __inout FxPkgPnp*   This
2259     )
2260 /*++
2261 
2262 Routine Description:
2263     The device is entering D0 from the final Dx state (either start or restart
2264     perhaps).  Send a start event to self managed io and then release
2265 
2266 Arguments:
2267     This - instance of the state machine
2268 
2269 Return Value:
2270     new state machine state
2271 
2272   --*/
2273 {
2274 
2275 
2276 
2277 
2278     This->m_Device->m_PkgIo->ResumeProcessingForPower();
2279 
2280     if (This->m_SelfManagedIoMachine != NULL) {
2281         NTSTATUS status;
2282 
2283         status = This->m_SelfManagedIoMachine->Start();
2284 
2285         if (!NT_SUCCESS(status)) {
2286             // return WdfDevStatePowerInitialSelfManagedIoFailed; __REACTOS__ : allow to fail
2287         }
2288     }
2289 
2290     This->PowerSetDevicePowerState(WdfPowerDeviceD0);
2291 
2292     //
2293     // Send the PowerUp event to both the PnP and the Power Policy state machines.
2294     //
2295     This->PowerSendPowerUpEvents();
2296 
2297     return WdfDevStatePowerDecideD0State;
2298 }
2299 
2300 WDF_DEVICE_POWER_STATE
PowerDecideD0State(__inout FxPkgPnp * This)2301 FxPkgPnp::PowerDecideD0State(
2302     __inout FxPkgPnp*   This
2303     )
2304 /*++
2305 
2306 Routine Description:
2307     Decide which D0 state we should transition to given the wait wake ownership
2308     of this device and if DO_POWER_PAGABLE is set or not.
2309 
2310 Arguments:
2311     This - instance of the state machine
2312 
2313 Return Value:
2314     new power state
2315 
2316   --*/
2317 {
2318     if (This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) {
2319         //
2320         // Pageable.
2321         //
2322         if (This->m_SharedPower.m_WaitWakeOwner) {
2323             return WdfDevStatePowerD0BusWakeOwner;
2324         }
2325         else {
2326             return WdfDevStatePowerD0;
2327         }
2328     }
2329     else {
2330         //
2331         // Non-pageable.
2332         //
2333         if (This->m_SharedPower.m_WaitWakeOwner) {
2334             return WdfDevStatePowerD0BusWakeOwnerNP;
2335         }
2336         else {
2337             return WdfDevStatePowerD0NP;
2338         }
2339     }
2340 }
2341 
2342 WDF_DEVICE_POWER_STATE
PowerGotoD3Stopped(__inout FxPkgPnp * This)2343 FxPkgPnp::PowerGotoD3Stopped(
2344     __inout FxPkgPnp*   This
2345     )
2346 /*++
2347 
2348 Routine Description:
2349     This function implements the D3 Stopped state.
2350 
2351 Arguments:
2352     none
2353 
2354 Return Value:
2355 
2356     new power state
2357 
2358 --*/
2359 {
2360     NTSTATUS status;
2361     BOOLEAN failed;
2362 
2363     failed = FALSE;
2364 
2365     //
2366     // We *must* call suspend here even though the pnp state machine called self
2367     // managed io stop.  Consider the following:
2368     // 1 this device is a filter
2369     // 2 the power policy owner has idle enabled and the device stack is
2370     //   currently idled out (in Dx)
2371     // 3 the query remove comes, this driver processes it and succeeds
2372     //   self managed io stop
2373     // 4 before the PwrPolStop event is processed in this driver, the pwr policy
2374     //   owner moves the stack into D0.
2375     // 5 now this driver processed the PwrPolStop and moves into this state.  We
2376     //   now need to make sure self managed i/o is in the stopped state before
2377     //   doing anything else.
2378     //
2379 
2380     //
2381     // The self managed io state machine can handle a suspend event when it is
2382     // already in the stopped state.
2383     //
2384     // Tell the driver to stop its self-managed I/O.
2385     //
2386     if (This->m_SelfManagedIoMachine != NULL) {
2387         status = This->m_SelfManagedIoMachine->Suspend();
2388 
2389         if (!NT_SUCCESS(status)) {
2390             DoTraceLevelMessage(
2391                 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2392                 "EvtDeviceSelfManagedIoStop failed %!STATUS!", status);
2393             failed = TRUE;
2394         }
2395     }
2396 
2397 
2398 
2399 
2400 
2401     // Top-edge queue hold.
2402     This->m_Device->m_PkgIo->StopProcessingForPower(FxIoStopProcessingForPowerHold);
2403 
2404     if (This->PowerDmaPowerDown() == FALSE) {
2405         failed = TRUE;
2406     }
2407 
2408     status = This->m_DeviceD0ExitPreInterruptsDisabled.Invoke(
2409         This->m_Device->GetHandle(),
2410         WdfPowerDeviceD3Final
2411         );
2412 
2413     if (!NT_SUCCESS(status)) {
2414         failed = TRUE;
2415 
2416         DoTraceLevelMessage(
2417             This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2418             "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p, "
2419             "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!",
2420             This->m_Device->GetHandle(),
2421             This->m_Device->GetDeviceObject(),
2422             WdfPowerDeviceD3Final, status);
2423     }
2424 
2425     //
2426     // Disconnect the interrupt.
2427     //
2428     status = This->NotifyResourceObjectsDx(NotifyResourcesForceDisconnect);
2429     if (!NT_SUCCESS(status)) {
2430         //
2431         // NotifyResourceObjectsDx already traced the error
2432         //
2433         failed = TRUE;
2434     }
2435 
2436     //
2437     // Call the driver to tell it to put the hardware into a sleeping
2438     // state.
2439     //
2440     status = This->m_DeviceD0Exit.Invoke(This->m_Device->GetHandle(),
2441                                          WdfPowerDeviceD3Final);
2442     if (!NT_SUCCESS(status)) {
2443         failed = TRUE;
2444 
2445         DoTraceLevelMessage(
2446             This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2447             "EvtDeviceD0Exit WDFDEVICE 0x%p !devobj 0x%p, new state "
2448             "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!",
2449             This->m_Device->GetHandle(),
2450             This->m_Device->GetDeviceObject(),
2451             WdfPowerDeviceD3Final, status);
2452     }
2453 
2454     This->PowerSetDevicePowerState(WdfPowerDeviceD3Final);
2455 
2456     //
2457     // If this is a child, release the power reference on the parent
2458     //
2459     This->PowerParentPowerDereference();
2460 
2461     if (failed) {
2462         return WdfDevStatePowerFinalPowerDownFailed;
2463     }
2464 
2465     This->PowerSendPowerDownEvents(FxPowerDownTypeImplicit);
2466 
2467     //
2468     // If we are not the PPO for the stack we could receive a power irp
2469     // during the middle of an implicit power down so we cannot assume
2470     // that there will be no pended power irp during an implicit power down.
2471     //
2472     ASSERT(This->IsPowerPolicyOwner() ? This->m_PendingDevicePowerIrp == NULL  : TRUE);
2473 
2474     return WdfDevStatePowerStopped;
2475 }
2476 
2477 WDF_DEVICE_POWER_STATE
PowerStartingCheckDeviceType(__inout FxPkgPnp * This)2478 FxPkgPnp::PowerStartingCheckDeviceType(
2479     __inout FxPkgPnp*   This
2480     )
2481 /*++
2482 
2483 Routine Description:
2484     The device is implicitly powering up from the created or stopped state.
2485     Determine if this is a PDO or not to determine if we must bring the parent
2486     back into D0.
2487 
2488 Arguments:
2489     This - instance of the state machine
2490 
2491 Return Value:
2492     WdfDevStatePowerStartingChild or WdfDevStatePowerD0Starting
2493 
2494   --*/
2495 {
2496     if (This->m_Device->IsPdo()) {
2497         return WdfDevStatePowerStartingChild;
2498     }
2499     else {
2500         return WdfDevStatePowerD0Starting;
2501     }
2502 }
2503 
2504 WDF_DEVICE_POWER_STATE
PowerStartingChild(__inout FxPkgPnp * This)2505 FxPkgPnp::PowerStartingChild(
2506     __inout FxPkgPnp*   This
2507     )
2508 /*++
2509 
2510 Routine Description:
2511     Get the parent into a D0 state
2512 
2513 Arguments:
2514     This - instance of the state machine
2515 
2516 Return Value:
2517     WdfDevStatePowerNull or WdfDevStatePowerD0Starting
2518 
2519   --*/
2520 {
2521     NTSTATUS status;
2522     BOOLEAN parentOn;
2523 
2524     status = This->PowerCheckParentOverload(&parentOn);
2525 
2526     if (!NT_SUCCESS(status)) {
2527         DoTraceLevelMessage(
2528             This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2529             "PowerReference on parent WDFDEVICE %p for child WDFDEVICE %p "
2530             "failed, %!STATUS!", This->m_Device->m_ParentDevice->m_Device->GetHandle(),
2531                 This->m_Device->GetHandle(),
2532             status);
2533 
2534         return WdfDevStatePowerInitialPowerUpFailed;
2535     }
2536     else if (parentOn) {
2537         //
2538         // Parent is powered on, start the power up sequence
2539         //
2540         return WdfDevStatePowerD0Starting;
2541     }
2542     else {
2543         //
2544         // The call to PowerReference will bring the parent into D0 and
2545         // move us out of this state after we return.
2546         //
2547         return WdfDevStatePowerNull;
2548     }
2549 }
2550 
2551 WDF_DEVICE_POWER_STATE
PowerDxDisablingWakeAtBus(__inout FxPkgPnp * This)2552 FxPkgPnp::PowerDxDisablingWakeAtBus(
2553     __inout FxPkgPnp*   This
2554     )
2555 /*++
2556 
2557 Routine Description:
2558     This function implements the Disable Wake at Bus state.
2559 
2560 Arguments:
2561     This - instance of the state machine
2562 
2563 Return Value:
2564     WdfDevStatePowerWaking
2565 
2566 --*/
2567 {
2568     //
2569     // We should only get into this state when this devobj is not a PDO and a
2570     // power policy owner.
2571     //
2572     ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE);
2573 
2574     This->PowerDisableWakeAtBusOverload();
2575 
2576     return WdfDevStatePowerWaking;
2577 }
2578 
2579 WDF_DEVICE_POWER_STATE
PowerDxDisablingWakeAtBusNP(__inout FxPkgPnp * This)2580 FxPkgPnp::PowerDxDisablingWakeAtBusNP(
2581     __inout FxPkgPnp*   This
2582     )
2583 /*++
2584 
2585 Routine Description:
2586     This function implements the Disable Wake at Bus state.
2587 
2588 Arguments:
2589     This - instance of the state machine
2590 
2591 Return Value:
2592     WdfDevStatePowerWakingNP
2593 
2594 --*/
2595 {
2596     //
2597     // We should only get into this state when this devobj is not a PDO and a
2598     // power policy owner.
2599     //
2600     ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE);
2601 
2602     This->PowerDisableWakeAtBusOverload();
2603 
2604     return WdfDevStatePowerWakingNP;
2605 }
2606 
2607 WDF_DEVICE_POWER_STATE
PowerGotoDNotZero(__inout FxPkgPnp * This)2608 FxPkgPnp::PowerGotoDNotZero(
2609     __inout FxPkgPnp*   This
2610     )
2611 /*++
2612 
2613 Routine Description:
2614     State where we go into Dx in the pageable path.
2615 
2616 Arguments:
2617     The instance of this state machine
2618 
2619 Return Value:
2620     new power state
2621 
2622   --*/
2623 {
2624     This->PowerGotoDx();
2625 
2626     return WdfDevStatePowerNull;
2627 }
2628 
2629 WDF_DEVICE_POWER_STATE
PowerGotoDNotZeroNP(__inout FxPkgPnp * This)2630 FxPkgPnp::PowerGotoDNotZeroNP(
2631     __inout FxPkgPnp*   This
2632     )
2633 /*++
2634 
2635 Routine Description:
2636     State where we go into Dx in the NP path.
2637 
2638 Arguments:
2639     The instance of this state machine
2640 
2641 Return Value:
2642     new power state
2643 
2644   --*/
2645 {
2646     This->PowerGotoDx();
2647 
2648     return WdfDevStatePowerNull;
2649 }
2650 
2651 WDF_DEVICE_POWER_STATE
PowerGotoDNotZeroIoStopped(__inout FxPkgPnp * This)2652 FxPkgPnp::PowerGotoDNotZeroIoStopped(
2653     __inout FxPkgPnp*   This
2654     )
2655 {
2656     if (This->PowerGotoDxIoStopped() == FALSE) {
2657         return WdfDevStatePowerGotoDxFailed;
2658     }
2659 
2660     return WdfDevStatePowerDx;
2661 }
2662 
2663 WDF_DEVICE_POWER_STATE
PowerGotoDNotZeroIoStoppedNP(__inout FxPkgPnp * This)2664 FxPkgPnp::PowerGotoDNotZeroIoStoppedNP(
2665     __inout FxPkgPnp*   This
2666     )
2667 {
2668     if (This->PowerGotoDxIoStoppedNP() == FALSE) {
2669         return WdfDevStatePowerGotoDxNPFailed;
2670     }
2671 
2672     return WdfDevStatePowerDxNP;
2673 }
2674 
2675 WDF_DEVICE_POWER_STATE
PowerGotoDxNPFailed(__inout FxPkgPnp * This)2676 FxPkgPnp::PowerGotoDxNPFailed(
2677     __inout FxPkgPnp*   This
2678     )
2679 /*++
2680 
2681 Routine Description:
2682     Going to Dx in the NP path failed.  Disconnect all the interrupts.
2683 
2684 Arguments:
2685     This - instance of the state machine
2686 
2687 Return Value:
2688     WdfDevStatePowerReportPowerDownFailed
2689 
2690   --*/
2691 {
2692     This->DisconnectInterruptNP();
2693 
2694     return WdfDevStatePowerReportPowerDownFailed;
2695 }
2696 
2697 VOID
PowerGotoDx(VOID)2698 FxPkgPnp::PowerGotoDx(
2699     VOID
2700     )
2701 /*++
2702 
2703 Routine Description:
2704     Implements the going into Dx logic for the pageable path.
2705 
2706 Arguments:
2707     None
2708 
2709 Return Value:
2710     None
2711 
2712   --*/
2713 {
2714     if (m_SelfManagedIoMachine != NULL) {
2715         NTSTATUS    status;
2716 
2717         //
2718         // Tell the driver to stop its self-managed I/O
2719         //
2720         status = m_SelfManagedIoMachine->Suspend();
2721 
2722         if (!NT_SUCCESS(status)) {
2723             DoTraceLevelMessage(
2724                 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2725                 "EvtDeviceSelfManagedIoStop failed %!STATUS!", status);
2726 
2727             m_PowerMachine.m_IoCallbackFailure = TRUE;
2728         }
2729     }
2730 
2731 
2732 
2733 
2734 
2735     // Top-edge queue hold
2736     m_Device->m_PkgIo->StopProcessingForPower(FxIoStopProcessingForPowerHold);
2737 
2738     PowerPolicyProcessEvent(PwrPolPowerDownIoStopped);
2739 }
2740 
2741 BOOLEAN
PowerGotoDxIoStopped(VOID)2742 FxPkgPnp::PowerGotoDxIoStopped(
2743     VOID
2744     )
2745 /*++
2746 
2747 Routine Description:
2748     Implements the going into Dx logic for the pageable path.
2749 
2750 
2751 
2752 Arguments:
2753     None
2754 
2755 Return Value:
2756     TRUE if the power down succeeded, FALSE otherwise
2757 
2758   --*/
2759 {
2760     WDF_POWER_DEVICE_STATE state;
2761     NTSTATUS    status;
2762     BOOLEAN     failed;
2763     FxIrp   irp;
2764     ULONG   notifyFlags;
2765 
2766     failed = FALSE;
2767 
2768     //
2769     // First determine the state that will be indicated to the driver
2770     //
2771     irp.SetIrp(m_PendingDevicePowerIrp);
2772 
2773     switch (irp.GetParameterPowerShutdownType()) {
2774     case PowerActionShutdown:
2775     case PowerActionShutdownReset:
2776     case PowerActionShutdownOff:
2777         state = WdfPowerDeviceD3Final;
2778         break;
2779 
2780     default:
2781         state = (WDF_POWER_DEVICE_STATE) irp.GetParameterPowerStateDeviceState();
2782         break;
2783     }
2784 
2785     //
2786     // Can we even be a power pageable device and be in hibernation path?
2787     //
2788     if (m_SystemPowerState == PowerSystemHibernate &&
2789         GetUsageCount(WdfSpecialFileHibernation) != 0) {
2790         COVERAGE_TRAP();
2791 
2792         //
2793         // This device is in the hibernation path and the target system state is
2794         // S4.  Tell the driver that it should do special handling.
2795         //
2796         state = WdfPowerDevicePrepareForHibernation;
2797     }
2798 
2799     if (PowerDmaPowerDown() == FALSE) {
2800         failed = TRUE;
2801     }
2802 
2803     status = m_DeviceD0ExitPreInterruptsDisabled.Invoke(
2804         m_Device->GetHandle(),
2805         state
2806         );
2807 
2808     if (!NT_SUCCESS(status)) {
2809         failed = TRUE;
2810 
2811         DoTraceLevelMessage(
2812             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2813             "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p, "
2814             "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!",
2815             m_Device->GetHandle(),
2816             m_Device->GetDeviceObject(), state, status);
2817     }
2818 
2819     //
2820     // interrupt disable & disconnect
2821     //
2822 
2823     notifyFlags = NotifyResourcesExplicitPowerDown;
2824 
2825     //
2826     // In general, m_WaitWakeIrp is accessed through guarded InterlockedExchange
2827     // operations. However, following is a special case where we just want to know
2828     // the current value. It is possible that the value of m_WaitWakeIrp can
2829     // change right after we query it. Users of NotifyResourcesArmedForWake will
2830     // need to be aware of this fact.
2831     //
2832     // Note that relying on m_WaitWakeIrp to decide whether to disconnect the wake
2833     // interrupts or not is unreliable and may result in a race condition between
2834     // the device powering down and a wake interrupt firing:
2835     //
2836     // Thread A: Device is powering down and is going to disconnect wake interrupts
2837     //           unless m_WaitWakeIrp is not NULL.
2838     // Thread B: Wake interrupt fires (holding the OS interrupt lock) which results
2839     //           in completing the IRP_MN_WAIT_WAKE and setting m_WaitWakeIrp to NULL.
2840     //           Thread then blocks waiting for the device to power up.
2841     // Thread A: m_WaitWakeIrp is NULL so we disconnect the wake interrupt, but are
2842     //           blocked waiting to acquire the lock held by the ISR. The deadlock
2843     //           results in bugcheck 0x9F since the Dx IRP is being blocked.
2844     //
2845     // The m_WakeInterruptsKeepConnected flag is set when we request a IRP_MN_WAIT_WAKE
2846     // in the device powering down path, and is cleared below once it is used.
2847     //
2848     if (m_SharedPower.m_WaitWakeIrp != NULL || m_WakeInterruptsKeepConnected == TRUE) {
2849         notifyFlags |= NotifyResourcesArmedForWake;
2850         m_WakeInterruptsKeepConnected = FALSE;
2851     }
2852 
2853     status = NotifyResourceObjectsDx(notifyFlags);
2854     if (!NT_SUCCESS(status)) {
2855         //
2856         // NotifyResourceObjectsDx already traced the error
2857         //
2858         failed = TRUE;
2859     }
2860 
2861     //
2862     // Call the driver to tell it to put the hardware into a sleeping
2863     // state.
2864     //
2865 
2866     status = m_DeviceD0Exit.Invoke(m_Device->GetHandle(), state);
2867 
2868     if (!NT_SUCCESS(status)) {
2869         DoTraceLevelMessage(
2870             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2871             "EvtDeviceD0Exit WDFEVICE 0x%p !devobj 0x%p, new state "
2872             "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!",
2873             m_Device->GetHandle(),
2874             m_Device->GetDeviceObject(), state, status);
2875 
2876         failed = TRUE;
2877     }
2878 
2879     //
2880     // If this is a child, release the power reference on the parent
2881     //
2882     PowerParentPowerDereference();
2883 
2884     //
2885     // Set our state no matter if power down failed or not
2886     //
2887     PowerSetDevicePowerState(state);
2888 
2889     //
2890     // Stopping self managed io previously failed, convert that failure into
2891     // a local failure here.
2892     //
2893     if (m_PowerMachine.m_IoCallbackFailure) {
2894         m_PowerMachine.m_IoCallbackFailure = FALSE;
2895         failed = TRUE;
2896     }
2897 
2898     if (failed) {
2899         //
2900         // Power policy will use this property when it is processing the
2901         // completion of the Dx irp.
2902         //
2903         m_PowerMachine.m_PowerDownFailure = TRUE;
2904 
2905         //
2906         // This state will record that we encountered an internal error.
2907         //
2908         return FALSE;
2909     }
2910 
2911     PowerSendPowerDownEvents(FxPowerDownTypeExplicit);
2912 
2913     PowerReleasePendingDeviceIrp();
2914 
2915     return TRUE;
2916 }
2917 
2918 BOOLEAN
PowerGotoDxIoStoppedNP(VOID)2919 FxPkgPnp::PowerGotoDxIoStoppedNP(
2920     VOID
2921     )
2922 /*++
2923 
2924 Routine Description:
2925     This function implements going into the Dx state in the NP path.
2926 
2927 Arguments:
2928     None
2929 
2930 Return Value:
2931     TRUE if the power down succeeded, FALSE otherwise
2932 
2933   --*/
2934 {
2935     WDF_POWER_DEVICE_STATE state;
2936     NTSTATUS    status;
2937     BOOLEAN     failed;
2938     FxIrp   irp;
2939 
2940     failed = FALSE;
2941 
2942     //
2943     // First determine the state that will be indicated to the driver
2944     //
2945     irp.SetIrp(m_PendingDevicePowerIrp);
2946 
2947     switch (irp.GetParameterPowerShutdownType()) {
2948     case PowerActionShutdown:
2949     case PowerActionShutdownReset:
2950     case PowerActionShutdownOff:
2951         state = WdfPowerDeviceD3Final;
2952         break;
2953 
2954     default:
2955         state = (WDF_POWER_DEVICE_STATE) irp.GetParameterPowerStateDeviceState();
2956         break;
2957     }
2958 
2959     if (m_SystemPowerState == PowerSystemHibernate &&
2960         GetUsageCount(WdfSpecialFileHibernation) != 0) {
2961         //
2962         // This device is in the hibernation path and the target system state is
2963         // S4.  Tell the driver that it should do special handling.
2964         //
2965         state = WdfPowerDevicePrepareForHibernation;
2966     }
2967 
2968     if (PowerDmaPowerDown()  == FALSE) {
2969         failed = TRUE;
2970     }
2971 
2972     status = m_DeviceD0ExitPreInterruptsDisabled.Invoke(
2973         m_Device->GetHandle(),
2974         state
2975         );
2976 
2977     if (!NT_SUCCESS(status)) {
2978         failed = TRUE;
2979 
2980         DoTraceLevelMessage(
2981             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2982             "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p, "
2983             "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!",
2984             m_Device->GetHandle(),
2985             m_Device->GetDeviceObject(), state, status);
2986     }
2987 
2988     //
2989     // Interrupt disable (and NO disconnect)
2990     //
2991     status = NotifyResourceObjectsDx(NotifyResourcesNP);
2992 
2993     if (!NT_SUCCESS(status)) {
2994         //
2995         // NotifyResourceObjectsDx already traced the error
2996         //
2997         failed = TRUE;
2998     }
2999 
3000     //
3001     // Call the driver to tell it to put the hardware into a sleeping
3002     // state.
3003     //
3004 
3005     status = m_DeviceD0Exit.Invoke(m_Device->GetHandle(), state);
3006 
3007     if (!NT_SUCCESS(status)) {
3008         DoTraceLevelMessage(
3009             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
3010             "EvtDeviceD0Exit WDFDEVICE 0x%p !devobj 0x%p, new state "
3011             "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!",
3012             m_Device->GetHandle(),
3013             m_Device->GetDeviceObject(), state, status);
3014 
3015         failed = TRUE;
3016     }
3017 
3018     //
3019     // If this is a child, release the power reference on the parent
3020     //
3021     PowerParentPowerDereference();
3022 
3023     //
3024     // Set our state no matter if power down failed or not
3025     //
3026     PowerSetDevicePowerState(state);
3027 
3028     //
3029     // Stopping self managed io previously failed, convert that failure into
3030     // a local failure here.
3031     //
3032     if (m_PowerMachine.m_IoCallbackFailure) {
3033         m_PowerMachine.m_IoCallbackFailure = FALSE;
3034         failed = TRUE;
3035     }
3036 
3037     if (failed) {
3038         //
3039         // Power policy will use this property when it is processing the
3040         // completion of the Dx irp.
3041         //
3042         m_PowerMachine.m_PowerDownFailure = TRUE;
3043 
3044         //
3045         // This state will record that we encountered an internal error.
3046         //
3047         return FALSE;
3048     }
3049 
3050     PowerSendPowerDownEvents(FxPowerDownTypeExplicit);
3051 
3052     PowerReleasePendingDeviceIrp();
3053 
3054     return TRUE;
3055 }
3056 
3057 WDF_DEVICE_POWER_STATE
PowerGotoDxArmedForWake(__inout FxPkgPnp * This)3058 FxPkgPnp::PowerGotoDxArmedForWake(
3059     __inout FxPkgPnp*   This
3060     )
3061 /*++
3062 
3063 Routine Description:
3064     This function implements the Dx state when we are armed for wake.
3065 
3066 Arguments:
3067     This - The instance of the state machine
3068 
3069 Return Value:
3070 
3071     new power state
3072 
3073 --*/
3074 {
3075     This->PowerGotoDx();
3076 
3077     return WdfDevStatePowerNull;
3078 }
3079 
3080 WDF_DEVICE_POWER_STATE
PowerGotoDxArmedForWakeNP(__inout FxPkgPnp * This)3081 FxPkgPnp::PowerGotoDxArmedForWakeNP(
3082     __inout FxPkgPnp*   This
3083     )
3084 /*++
3085 
3086 Routine Description:
3087     This function implements the Dx state when we are armed for wake in the NP
3088     path.
3089 
3090 Arguments:
3091     This - The instance of the state machine
3092 
3093 Return Value:
3094 
3095     new power state
3096 
3097 --*/
3098 {
3099     This->PowerGotoDx();
3100 
3101     return WdfDevStatePowerNull;
3102 }
3103 
3104 WDF_DEVICE_POWER_STATE
PowerGotoDxIoStoppedArmedForWake(__inout FxPkgPnp * This)3105 FxPkgPnp::PowerGotoDxIoStoppedArmedForWake(
3106     __inout FxPkgPnp*   This
3107     )
3108 {
3109     if (This->PowerGotoDxIoStopped() == FALSE) {
3110         return WdfDevStatePowerGotoDxFailed;
3111     }
3112 
3113     return WdfDevStatePowerDxArmedForWake;
3114 }
3115 
3116 WDF_DEVICE_POWER_STATE
PowerGotoDxIoStoppedArmedForWakeNP(__inout FxPkgPnp * This)3117 FxPkgPnp::PowerGotoDxIoStoppedArmedForWakeNP(
3118     __inout FxPkgPnp*   This
3119     )
3120 {
3121     if (This->PowerGotoDxIoStoppedNP() == FALSE) {
3122         return WdfDevStatePowerGotoDxNPFailed;
3123     }
3124 
3125     return WdfDevStatePowerDxArmedForWakeNP;
3126 }
3127 
3128 WDF_DEVICE_POWER_STATE
PowerCheckParentStateArmedForWake(__inout FxPkgPnp * This)3129 FxPkgPnp::PowerCheckParentStateArmedForWake(
3130     __inout FxPkgPnp*   This
3131     )
3132 /*++
3133 
3134 Routine Description:
3135     The PDO was armed for wake in Dx and needs to be disarmed at the bus level.
3136     The child can only be disarmed while the parent is in D0, so check the state
3137     of the parent.  If in D0, move directly to the disarm state, otherwise move
3138     into a wait state and disarm once the parent is in D0.
3139 
3140 Arguments:
3141     This - instance of the state machine
3142 
3143 Return Value:
3144     new state
3145 
3146   --*/
3147 
3148 {
3149     NTSTATUS status;
3150     BOOLEAN parentOn;
3151 
3152     status = This->PowerCheckParentOverload(&parentOn);
3153 
3154     if (!NT_SUCCESS(status)) {
3155         return WdfDevStatePowerUpFailed;
3156     }
3157     else if (parentOn) {
3158         return WdfDevStatePowerDxDisablingWakeAtBus;
3159     }
3160     else {
3161         return WdfDevStatePowerWaitForParentArmedForWake;
3162     }
3163 }
3164 
3165 WDF_DEVICE_POWER_STATE
PowerCheckParentStateArmedForWakeNP(__inout FxPkgPnp * This)3166 FxPkgPnp::PowerCheckParentStateArmedForWakeNP(
3167     __inout FxPkgPnp*   This
3168     )
3169 /*++
3170 
3171 Routine Description:
3172     Same as PowerCheckParentStateArmedForWake, but we are in the NP path
3173 
3174 Arguments:
3175     This - instance of the state machine
3176 
3177 Return Value:
3178     new state
3179 
3180   --*/
3181 {
3182     NTSTATUS status;
3183     BOOLEAN parentOn;
3184 
3185     status = This->PowerCheckParentOverload(&parentOn);
3186 
3187     if (!NT_SUCCESS(status)) {
3188         return WdfDevStatePowerUpFailedNP;
3189     }
3190     else if (parentOn) {
3191         return WdfDevStatePowerDxDisablingWakeAtBusNP;
3192     }
3193     else {
3194         return WdfDevStatePowerWaitForParentArmedForWakeNP;
3195     }
3196 }
3197 
3198 WDF_DEVICE_POWER_STATE
PowerStartSelfManagedIo(__inout FxPkgPnp * This)3199 FxPkgPnp::PowerStartSelfManagedIo(
3200     __inout FxPkgPnp*   This
3201     )
3202 /*++
3203 
3204 Routine Description:
3205     This function implements the Start Self-Managed I/O state.  It tells the
3206     driver that it can resume operations that were not interlocked with
3207     the PnP and Power state machines.
3208 
3209 Arguments:
3210     This - The instance of the state machine
3211 
3212 Return Value:
3213 
3214     new power state
3215 
3216 --*/
3217 {
3218 
3219 
3220 
3221 
3222 
3223     // Top-edge queue release
3224     This->m_Device->m_PkgIo->ResumeProcessingForPower();
3225 
3226     if (This->m_SelfManagedIoMachine != NULL) {
3227         NTSTATUS    status;
3228 
3229         status = This->m_SelfManagedIoMachine->Start();
3230 
3231         if (!NT_SUCCESS(status)) {
3232             DoTraceLevelMessage(
3233                 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
3234                 "EvtDeviceSelfManagedIoRestart failed - %!STATUS!", status);
3235 
3236             return WdfDevStatePowerStartSelfManagedIoFailed;
3237         }
3238     }
3239 
3240     This->PowerSetDevicePowerState(WdfPowerDeviceD0);
3241 
3242     //
3243     // Send the PowerUp event to both the PnP and the Power Policy state
3244     // machines.
3245     //
3246     This->PowerSendPowerUpEvents();
3247 
3248     This->PowerReleasePendingDeviceIrp();
3249 
3250     if (This->m_SharedPower.m_WaitWakeOwner) {
3251         return WdfDevStatePowerD0BusWakeOwner;
3252     }
3253     else {
3254         return WdfDevStatePowerD0;
3255     }
3256 }
3257 
3258 WDF_DEVICE_POWER_STATE
PowerStartSelfManagedIoNP(__inout FxPkgPnp * This)3259 FxPkgPnp::PowerStartSelfManagedIoNP(
3260     __inout FxPkgPnp*   This
3261     )
3262 /*++
3263 
3264 Routine Description:
3265     This function implements the Start Self-Managed I/O state.  It tells the
3266     driver that it can resume operations that were not interlocked with
3267     the PnP and Power state machines.
3268 
3269 Arguments:
3270     This - The instance of the state machine
3271 
3272 Return Value:
3273 
3274     new power state
3275 
3276 --*/
3277 {
3278 
3279 
3280 
3281 
3282 
3283     // Top-edge queue release
3284     This->m_Device->m_PkgIo->ResumeProcessingForPower();
3285 
3286     if (This->m_SelfManagedIoMachine != NULL) {
3287         NTSTATUS    status;
3288 
3289         status = This->m_SelfManagedIoMachine->Start();
3290 
3291         if (!NT_SUCCESS(status)) {
3292             DoTraceLevelMessage(
3293                 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
3294                 "EvtDeviceSelfManagedIoRestart failed - %!STATUS!", status);
3295 
3296             return WdfDevStatePowerStartSelfManagedIoFailedNP;
3297         }
3298     }
3299 
3300     This->PowerSetDevicePowerState(WdfPowerDeviceD0);
3301 
3302     //
3303     // Send the PowerUp event to both the PnP and the Power Policy state machines.
3304     //
3305     This->PowerSendPowerUpEvents();
3306 
3307     This->PowerReleasePendingDeviceIrp();
3308 
3309     if (This->m_SharedPower.m_WaitWakeOwner) {
3310         return WdfDevStatePowerD0BusWakeOwnerNP;
3311     }
3312     else {
3313         return WdfDevStatePowerD0NP;
3314     }
3315 }
3316 
3317 WDF_DEVICE_POWER_STATE
PowerStartSelfManagedIoFailed(__inout FxPkgPnp * This)3318 FxPkgPnp::PowerStartSelfManagedIoFailed(
3319     __inout FxPkgPnp*   This
3320     )
3321 /*++
3322 
3323 Routine Description:
3324     Starting self managed io back up from an explicit Dx to D0 transition failed.
3325     Hold the power managed queues and proceed down the power up failure path.
3326 
3327 Arguments:
3328     This - instance of the state machine
3329 
3330 Return Value:
3331     WdfDevStatePowerWakingDmaEnableFailed
3332 
3333   --*/
3334 {
3335 
3336 
3337 
3338 
3339     This->m_Device->m_PkgIo->StopProcessingForPower(FxIoStopProcessingForPowerHold);
3340 
3341     return WdfDevStatePowerWakingDmaEnableFailed;
3342 }
3343 
3344 WDF_DEVICE_POWER_STATE
PowerStartSelfManagedIoFailedNP(__inout FxPkgPnp * This)3345 FxPkgPnp::PowerStartSelfManagedIoFailedNP(
3346     __inout FxPkgPnp*   This
3347     )
3348 /*++
3349 
3350 Routine Description:
3351     Starting self managed io back up from an explicit Dx to D0 transition failed.
3352     Hold the power managed queues and proceed down the power up failure path.
3353 
3354 Arguments:
3355     This - instance of the state machine
3356 
3357 Return Value:
3358     WdfDevStatePowerWakingDmaEnableFailedNP
3359 
3360   --*/
3361 {
3362 
3363 
3364 
3365 
3366     This->m_Device->m_PkgIo->StopProcessingForPower(FxIoStopProcessingForPowerHold);
3367 
3368     return WdfDevStatePowerWakingDmaEnableFailedNP;
3369 }
3370 
3371 
3372 WDF_DEVICE_POWER_STATE
PowerWakePending(__inout FxPkgPnp * This)3373 FxPkgPnp::PowerWakePending(
3374     __inout FxPkgPnp*   This
3375     )
3376 /*++
3377 
3378 Routine Description:
3379     State that indicates a successful wake from Dx.  Primarily exists so that
3380     the driver writer can register to know about the entrance into this state.
3381     It also completes the pended wait wake request (which posts the appopriate
3382     events to the power policy state machine if it's listening).
3383 
3384 Arguments:
3385     This - The instance of the state machine
3386 
3387 Return Value:
3388     return WdfDevStatePowerNull
3389 
3390   --*/
3391 {
3392     This->PowerCompletePendedWakeIrp();
3393     return WdfDevStatePowerNull;
3394 }
3395 
3396 WDF_DEVICE_POWER_STATE
PowerWakePendingNP(__inout FxPkgPnp * This)3397 FxPkgPnp::PowerWakePendingNP(
3398     __inout FxPkgPnp*   This
3399     )
3400 /*++
3401 
3402 Routine Description:
3403     State that indicates a successful wake from Dx.  Primarily exists so that
3404     the driver writer can register to know about the entrance into this state.
3405     It also completes the pended wait wake request (which posts the appopriate
3406     events to the power policy state machine if it's listening).
3407 
3408 Arguments:
3409     This - The instance of the state machine
3410 
3411 Return Value:
3412     return WdfDevStatePowerNull
3413 
3414   --*/
3415 {
3416     This->PowerCompletePendedWakeIrp();
3417     return WdfDevStatePowerNull;
3418 }
3419 
3420 WDF_DEVICE_POWER_STATE
PowerWaking(__inout FxPkgPnp * This)3421 FxPkgPnp::PowerWaking(
3422     __inout FxPkgPnp*   This
3423     )
3424 /*++
3425 
3426 Routine Description:
3427     This function implements the Waking state.  Its job is to call into the
3428     driver to tell it to restore its hardware, and then to connect interrupts
3429     and release the queues.
3430 
3431 Arguments:
3432     This - The instance of the state machine
3433 
3434 Return Value:
3435 
3436     new power state
3437 
3438 --*/
3439 {
3440     NTSTATUS status;
3441 
3442     //
3443     // m_DevicePowerState is the "old" state because we update it after the
3444     // D0Entry callback in SelfManagedIo or PowerPolicyStopped
3445     //
3446     status = This->m_DeviceD0Entry.Invoke(
3447         This->m_Device->GetHandle(),
3448         (WDF_POWER_DEVICE_STATE) This->m_DevicePowerState);
3449 
3450     if (!NT_SUCCESS(status)) {
3451         DoTraceLevelMessage(
3452             This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
3453             "EvtDeviceD0Entry WDFDEVICE 0x%p !devobj 0x%p, old state "
3454             "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!",
3455             This->m_Device->GetHandle(),
3456             This->m_Device->GetDeviceObject(),
3457             This->m_DevicePowerState, status);
3458 
3459         return WdfDevStatePowerUpFailedDerefParent;
3460     }
3461 
3462     return WdfDevStatePowerNotifyingD0EntryToWakeInterrupts;
3463 }
3464 
3465 
3466 WDF_DEVICE_POWER_STATE
PowerWakingNP(__inout FxPkgPnp * This)3467 FxPkgPnp::PowerWakingNP(
3468     __inout FxPkgPnp*   This
3469     )
3470 /*++
3471 
3472 Routine Description:
3473     This function implements the WakingNP state.  Its job is to call into the
3474     driver to tell it to restore its hardware and release the queues.
3475 
3476 Arguments:
3477     This - The instance of the state machine
3478 
3479 Return Value:
3480 
3481     new power state
3482 
3483 --*/
3484 {
3485     NTSTATUS status;
3486 
3487     //
3488     // m_DevicePowerState is the "old" state because we update it after the
3489     // D0Entry callback in SelfManagedIoNP or PowerPolicyStopped
3490     //
3491     status = This->m_DeviceD0Entry.Invoke(
3492         This->m_Device->GetHandle(),
3493         (WDF_POWER_DEVICE_STATE) This->m_DevicePowerState);
3494 
3495     if (!NT_SUCCESS(status)) {
3496         DoTraceLevelMessage(
3497             This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
3498             "EvtDeviceD0Entry WDFDEVICE 0x%p !devobj 0x%p, old state "
3499             "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!",
3500             This->m_Device->GetHandle(),
3501             This->m_Device->GetDeviceObject(),
3502             This->m_DevicePowerState, status);
3503 
3504         return WdfDevStatePowerUpFailedDerefParentNP;
3505     }
3506 
3507     return WdfDevStatePowerNotifyingD0EntryToWakeInterruptsNP;
3508 }
3509 
3510 WDF_DEVICE_POWER_STATE
PowerWakingConnectInterrupt(__inout FxPkgPnp * This)3511 FxPkgPnp::PowerWakingConnectInterrupt(
3512     __inout FxPkgPnp*   This
3513     )
3514 /*++
3515 
3516 Routine Description:
3517     The device is returning to D0 in the power pageable path.  Connect and
3518     enable the interrupts.  If that succeeds, scan for children and then
3519     open the power managed I/O queues.
3520 
3521 Arguments:
3522     This - instance of the state machine
3523 
3524 Return Value:
3525     new state
3526 
3527   --*/
3528 {
3529     NTSTATUS status;
3530 
3531     //
3532     // interrupt connect and enable
3533     //
3534     status = This->NotifyResourceObjectsD0(NotifyResourcesExplicitPowerup);
3535 
3536     if (!NT_SUCCESS(status)) {
3537         return WdfDevStatePowerWakingConnectInterruptFailed;
3538     }
3539 
3540     status = This->m_DeviceD0EntryPostInterruptsEnabled.Invoke(
3541         This->m_Device->GetHandle(),
3542         (WDF_POWER_DEVICE_STATE) This->m_DevicePowerState);
3543 
3544     if (!NT_SUCCESS(status)) {
3545         DoTraceLevelMessage(
3546             This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
3547             "EvtDeviceD0EntryPostInterruptsEnabed WDFDEVICE 0x%p !devobj 0x%p, "
3548             "old state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!",
3549             This->m_Device->GetHandle(),
3550             This->m_Device->GetDeviceObject(),
3551             This->m_DevicePowerState, status);
3552         return WdfDevStatePowerWakingConnectInterruptFailed;
3553     }
3554 
3555     return WdfDevStatePowerWakingDmaEnable;
3556 }
3557 
3558 WDF_DEVICE_POWER_STATE
PowerWakingConnectInterruptNP(__inout FxPkgPnp * This)3559 FxPkgPnp::PowerWakingConnectInterruptNP(
3560     __inout FxPkgPnp*   This
3561     )
3562 /*++
3563 
3564 Routine Description:
3565     The device is returning to D0 in the power pageable path.
3566     Enable the interrupts.  If that succeeds, scan for children and then
3567     open the power managed I/O queues.
3568 
3569 Arguments:
3570     This - instance of the state machine
3571 
3572 Return Value:
3573     new state
3574 
3575   --*/
3576 {
3577     NTSTATUS status;
3578 
3579     //
3580     // interrupt enable (already connected b/c they were never disconnected
3581     // during the Dx transition).
3582     //
3583     status = This->NotifyResourceObjectsD0(NotifyResourcesNP);
3584 
3585     if (!NT_SUCCESS(status)) {
3586         return WdfDevStatePowerWakingConnectInterruptFailedNP;
3587     }
3588 
3589     status = This->m_DeviceD0EntryPostInterruptsEnabled.Invoke(
3590         This->m_Device->GetHandle(),
3591         (WDF_POWER_DEVICE_STATE) This->m_DevicePowerState);
3592 
3593     if (!NT_SUCCESS(status)) {
3594         DoTraceLevelMessage(
3595             This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
3596             "EvtDeviceD0EntryPostInterruptsEnabed WDFDEVICE 0x%p !devobj 0x%p, "
3597             "old state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!",
3598             This->m_Device->GetHandle(),
3599             This->m_Device->GetDeviceObject(),
3600             This->m_DevicePowerState, status);
3601         return WdfDevStatePowerWakingConnectInterruptFailedNP;
3602     }
3603 
3604     return WdfDevStatePowerWakingDmaEnableNP;
3605 }
3606 
3607 WDF_DEVICE_POWER_STATE
PowerWakingConnectInterruptFailed(__inout FxPkgPnp * This)3608 FxPkgPnp::PowerWakingConnectInterruptFailed(
3609     __inout FxPkgPnp*   This
3610     )
3611 /*++
3612 
3613 Routine Description:
3614     Connecting or enabling the interrupts failed.  Disable and disconnect any
3615     interrupts which have been connected and maybe enabled.
3616 
3617 Arguments:
3618     This - instance of the state machine
3619 
3620 Return Value:
3621     WdfDevStatePowerReportPowerUpFailed
3622 
3623   --*/
3624 {
3625     This->PowerConnectInterruptFailed();
3626 
3627     return WdfDevStatePowerReportPowerUpFailedDerefParent;
3628 }
3629 
3630 WDF_DEVICE_POWER_STATE
PowerWakingConnectInterruptFailedNP(__inout FxPkgPnp * This)3631 FxPkgPnp::PowerWakingConnectInterruptFailedNP(
3632     __inout FxPkgPnp*   This
3633     )
3634 /*++
3635 
3636 Routine Description:
3637     Enabling the interrupts failed.  Disable and disconnect any
3638     interrupts which have been connected and maybe enabled.
3639 
3640 Arguments:
3641     This - instance of the state machine
3642 
3643 Return Value:
3644     WdfDevStatePowerReportPowerUpFailed
3645 
3646   --*/
3647 {
3648     //
3649     // PowerConnectInterruptFailed will call IoDisconnectInterrupt.  Since we
3650     // are in the NP path, this may cause a deadlock between this thread and
3651     // paging I/O.  Log something to the IFR so that if the watchdog timer kicks
3652     // in, at least we have context as to why we died.
3653     //
3654     DoTraceLevelMessage(
3655         This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
3656         "Force disconnecting interupts on !devobj %p, WDFDEVICE %p",
3657         This->m_Device->GetDeviceObject(),
3658         This->m_Device->GetHandle());
3659 
3660     This->PowerConnectInterruptFailed();
3661 
3662     return WdfDevStatePowerReportPowerUpFailedDerefParent;
3663 }
3664 
3665 BOOLEAN
PowerDmaEnableAndScan(__in BOOLEAN ImplicitPowerUp)3666 FxPkgPnp::PowerDmaEnableAndScan(
3667     __in BOOLEAN ImplicitPowerUp
3668     )
3669 {
3670     FxTransactionedEntry* ple;
3671 
3672     if (PowerDmaPowerUp() == FALSE) {
3673         return FALSE;
3674     }
3675 
3676     if (m_EnumInfo != NULL) {
3677         //
3678         // Scan for children
3679         //
3680         m_EnumInfo->m_ChildListList.LockForEnum(GetDriverGlobals());
3681 
3682         ple = NULL;
3683         while ((ple = m_EnumInfo->m_ChildListList.GetNextEntry(ple)) != NULL) {
3684             ((FxChildList*) ple->GetTransactionedObject())->ScanForChildren();
3685         }
3686 
3687         m_EnumInfo->m_ChildListList.UnlockFromEnum(GetDriverGlobals());
3688     }
3689 
3690     if (ImplicitPowerUp == FALSE) {
3691         PowerPolicyProcessEvent(PwrPolPowerUpHwStarted);
3692     }
3693 
3694     return TRUE;
3695 }
3696 
3697 WDF_DEVICE_POWER_STATE
PowerWakingDmaEnable(__inout FxPkgPnp * This)3698 FxPkgPnp::PowerWakingDmaEnable(
3699     __inout FxPkgPnp*   This
3700     )
3701 /*++
3702 
3703 Routine Description:
3704     The device is returning to D0 from Dx.  Power up all DMA enablers and scan
3705     for children.
3706 
3707 Arguments:
3708     This - instance of the state machine
3709 
3710 Return Value:
3711     new machine state
3712 
3713   --*/
3714 {
3715     if (This->PowerDmaEnableAndScan(FALSE) == FALSE) {
3716         return WdfDevStatePowerWakingDmaEnableFailed;
3717     }
3718 
3719     //
3720     // Return the state that we should drop into next.
3721     //
3722     return WdfDevStatePowerNull;
3723 }
3724 
3725 WDF_DEVICE_POWER_STATE
PowerWakingDmaEnableNP(__inout FxPkgPnp * This)3726 FxPkgPnp::PowerWakingDmaEnableNP(
3727     __inout FxPkgPnp*   This
3728     )
3729 /*++
3730 
3731 Routine Description:
3732     The device is returning to D0 from Dx in the NP path.  Power up all DMA
3733     enablers and scan for children.
3734 
3735 Arguments:
3736     This - instance of the state machine
3737 
3738 Return Value:
3739     new machine state
3740 
3741   --*/
3742 {
3743     if (This->PowerDmaEnableAndScan(FALSE) == FALSE) {
3744         return WdfDevStatePowerWakingDmaEnableFailedNP;
3745     }
3746 
3747     //
3748     // Return the state that we should drop into next.
3749     //
3750     return WdfDevStatePowerNull;
3751 }
3752 
3753 WDF_DEVICE_POWER_STATE
PowerWakingDmaEnableFailed(__inout FxPkgPnp * This)3754 FxPkgPnp::PowerWakingDmaEnableFailed(
3755     __inout FxPkgPnp*   This
3756     )
3757 /*++
3758 
3759 Routine Description:
3760     Powering up a DMA enabler failed.  Power down all DMA enablers and progress
3761     down the failed power up path.
3762 
3763 Arguments:
3764     This - instance of the state machine
3765 
3766 Return Value:
3767     WdfDevStatePowerWakingConnectInterruptFailed
3768 
3769   --*/
3770 {
3771     NTSTATUS status;
3772 
3773     (void) This->PowerDmaPowerDown();
3774 
3775     status = This->m_DeviceD0ExitPreInterruptsDisabled.Invoke(
3776         This->m_Device->GetHandle(),
3777         WdfPowerDeviceD3Final
3778         );
3779 
3780     if (!NT_SUCCESS(status)) {
3781         //
3782         // Report the error, but continue forward
3783         //
3784         DoTraceLevelMessage(
3785             This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
3786             "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p "
3787             "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!",
3788             This->m_Device->GetHandle(),
3789             This->m_Device->GetDeviceObject(),
3790             WdfPowerDeviceD3Final, status);
3791     }
3792 
3793     return WdfDevStatePowerWakingConnectInterruptFailed;
3794 }
3795 
3796 WDF_DEVICE_POWER_STATE
PowerWakingDmaEnableFailedNP(__inout FxPkgPnp * This)3797 FxPkgPnp::PowerWakingDmaEnableFailedNP(
3798     __inout FxPkgPnp*   This
3799     )
3800 /*++
3801 
3802 Routine Description:
3803     Powering up a DMA enabler failed in the NP path.  Power down all DMA
3804     enablers and progress down the failed power up path.
3805 
3806 Arguments:
3807     This - instance of the state machine
3808 
3809 Return Value:
3810     WdfDevStatePowerWakingConnectInterruptFailedNP
3811 
3812   --*/
3813 {
3814     NTSTATUS status;
3815 
3816     COVERAGE_TRAP();
3817 
3818     (void) This->PowerDmaPowerDown();
3819 
3820     status = This->m_DeviceD0ExitPreInterruptsDisabled.Invoke(
3821         This->m_Device->GetHandle(),
3822         WdfPowerDeviceD3Final
3823         );
3824 
3825     if (!NT_SUCCESS(status)) {
3826         //
3827         // Report the error, but continue forward
3828         //
3829         DoTraceLevelMessage(
3830             This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
3831             "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p "
3832             "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!",
3833             This->m_Device->GetHandle(),
3834             This->m_Device->GetDeviceObject(),
3835             WdfPowerDeviceD3Final, status);
3836     }
3837 
3838     return WdfDevStatePowerWakingConnectInterruptFailedNP;
3839 }
3840 
3841 WDF_DEVICE_POWER_STATE
PowerReportPowerUpFailedDerefParent(__inout FxPkgPnp * This)3842 FxPkgPnp::PowerReportPowerUpFailedDerefParent(
3843     __inout FxPkgPnp*   This
3844     )
3845 /*++
3846 
3847 Routine Description:
3848     Power up failed.  Release the reference on the parent that was taken at the
3849     start of power up.
3850 
3851 Arguments:
3852     This - instance of the state machine.
3853 
3854 Return Value:
3855     WdfDevStatePowerInitialPowerUpFailed
3856 
3857   --*/
3858 {
3859     //
3860     // If this is a child, release the power reference on the parent
3861     //
3862     This->PowerParentPowerDereference();
3863 
3864     return WdfDevStatePowerReportPowerUpFailed;
3865 }
3866 
3867 WDF_DEVICE_POWER_STATE
PowerReportPowerUpFailed(__inout FxPkgPnp * This)3868 FxPkgPnp::PowerReportPowerUpFailed(
3869     __inout FxPkgPnp*   This
3870     )
3871 /*++
3872 
3873 Routine Description:
3874     Posts PowerUpFailed event to the PnP state machine and then waits for death.
3875     The pended Power IRP is also completed.
3876 
3877 Arguments:
3878     This - The instance of the state machine
3879 
3880 Return Value:
3881     new power state
3882 
3883   --*/
3884 {
3885     This->m_SystemPowerAction = PowerActionNone;
3886 
3887     This->PowerReleasePendingDeviceIrp();
3888     This->PowerSendPowerUpFailureEvent();
3889 
3890     return WdfDevStatePowerNull;
3891 }
3892 
3893 WDF_DEVICE_POWER_STATE
PowerPowerFailedPowerDown(__inout FxPkgPnp * This)3894 FxPkgPnp::PowerPowerFailedPowerDown(
3895     __inout FxPkgPnp*   This
3896     )
3897 /*++
3898 
3899 Routine Description:
3900     We failed to power up/down properly and now the power policy state machine wants
3901     to power down the device.  Since power policy and pnp rely on power posting
3902     power down events to make forward progress, we must do that here
3903 
3904 Arguments:
3905     This - instance of the state machine
3906 
3907 Return Value:
3908     WdfDevStatePowerStopped
3909 
3910   --*/
3911 {
3912     //
3913     // Even though we failed power up and never really powered down, record our
3914     // state as powered down, so that if we are restarted (can easily happen for
3915     // a PDO), we have the correct previous state.
3916     //
3917     This->PowerSetDevicePowerState(WdfPowerDeviceD3Final);
3918 
3919     This->PowerSendPowerDownEvents(FxPowerDownTypeImplicit);
3920 
3921     return WdfDevStatePowerStopped;
3922 }
3923 
3924 WDF_DEVICE_POWER_STATE
PowerReportPowerDownFailed(__inout FxPkgPnp * This)3925 FxPkgPnp::PowerReportPowerDownFailed(
3926     __inout FxPkgPnp*   This
3927     )
3928 /*++
3929 
3930 Routine Description:
3931     Posts PowerDownFailed event to the PnP state machine and then waits for death.
3932     The pended Power IRP is also completed.
3933 
3934 Arguments:
3935     This - The instance of the state machine
3936 
3937 Return Value:
3938     WdfDevStatePowerNull
3939 
3940   --*/
3941 {
3942 
3943 
3944 
3945 
3946     This->PowerReleasePendingDeviceIrp();
3947     This->PowerSendPowerDownFailureEvent(FxPowerDownTypeExplicit);
3948 
3949     return WdfDevStatePowerNull;
3950 }
3951 
3952 WDF_DEVICE_POWER_STATE
PowerInitialConnectInterruptFailed(__inout FxPkgPnp * This)3953 FxPkgPnp::PowerInitialConnectInterruptFailed(
3954     __inout FxPkgPnp*   This
3955     )
3956 /*++
3957 
3958 Routine Description:
3959     When bringing the device out of the D3 final state, connecting or enabling
3960     the interrupts failed.  Disconnect and disable any interrupts which are
3961     connected and possibly  enabled.
3962 
3963 Arguments:
3964     This - instance of the state machine
3965 
3966 Return Value:
3967     WdfDevStatePowerInitialPowerUpFailedDerefParent
3968 
3969   --*/
3970 {
3971     This->PowerConnectInterruptFailed();
3972 
3973     return WdfDevStatePowerInitialPowerUpFailedDerefParent;
3974 }
3975 
3976 
3977 WDF_DEVICE_POWER_STATE
PowerInitialDmaEnableFailed(__inout FxPkgPnp * This)3978 FxPkgPnp::PowerInitialDmaEnableFailed(
3979     __inout FxPkgPnp*   This
3980     )
3981 /*++
3982 
3983 Routine Description:
3984     Initial power up of the device failed while enabling DMA.  Disable any
3985     started DMA enablers and proceed down the initial power up failure path.
3986 
3987 Arguments:
3988     This - instance of the state machine
3989 
3990 Return Value:
3991     WdfDevStatePowerInitialConnectInterruptFailed
3992 
3993   --*/
3994 {
3995     NTSTATUS status;
3996 
3997     (void) This->PowerDmaPowerDown();
3998 
3999     status = This->m_DeviceD0ExitPreInterruptsDisabled.Invoke(
4000         This->m_Device->GetHandle(),
4001         WdfPowerDeviceD3Final
4002         );
4003 
4004     if (!NT_SUCCESS(status)) {
4005         //
4006         // Report the error, but continue forward
4007         //
4008         DoTraceLevelMessage(
4009             This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
4010             "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p "
4011             "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!",
4012             This->m_Device->GetHandle(),
4013             This->m_Device->GetDeviceObject(),
4014             WdfPowerDeviceD3Final, status);
4015     }
4016 
4017     return WdfDevStatePowerInitialConnectInterruptFailed;
4018 }
4019 
4020 WDF_DEVICE_POWER_STATE
PowerInitialSelfManagedIoFailed(__inout FxPkgPnp * This)4021 FxPkgPnp::PowerInitialSelfManagedIoFailed(
4022     __inout FxPkgPnp*   This
4023     )
4024 /*++
4025 
4026 Routine Description:
4027     The self managed io start failed when bringing the device out of Dx with an
4028     implicit D0 transition.  Hold the power queues that were previous open can
4029     continue to cleanup
4030 
4031 Arguments:
4032     This - instance of the state machine
4033 
4034 Return Value:
4035     WdfDevStatePowerInitialDmaEnableFailed
4036 
4037   --*/
4038 {
4039 
4040 
4041 
4042 
4043     This->m_Device->m_PkgIo->StopProcessingForPower(FxIoStopProcessingForPowerHold);
4044 
4045     return WdfDevStatePowerInitialDmaEnableFailed;
4046 }
4047 
4048 WDF_DEVICE_POWER_STATE
PowerInitialPowerUpFailedDerefParent(__inout FxPkgPnp * This)4049 FxPkgPnp::PowerInitialPowerUpFailedDerefParent(
4050     __inout FxPkgPnp*   This
4051     )
4052 /*++
4053 
4054 Routine Description:
4055     Dereferences the parent's power ref count we took during start up
4056 
4057 Arguments:
4058     This - The instance of the state machine
4059 
4060 Return Value:
4061     WdfDevStatePowerInitialPowerUpFailed
4062 
4063   --*/
4064 {
4065 
4066     //
4067     // If this is a child, release the power reference on the parent
4068     //
4069     This->PowerParentPowerDereference();
4070 
4071     return WdfDevStatePowerInitialPowerUpFailed;
4072 }
4073 
4074 WDF_DEVICE_POWER_STATE
PowerInitialPowerUpFailed(__inout FxPkgPnp * This)4075 FxPkgPnp::PowerInitialPowerUpFailed(
4076     __inout FxPkgPnp*   This
4077     )
4078 /*++
4079 
4080 Routine Description:
4081     Posts PowerUpFailed event to the PnP state machine and then waits for death.
4082 
4083 Arguments:
4084     This - The instance of the state machine
4085 
4086 Return Value:
4087     WdfDevStatePowerStopped
4088 
4089   --*/
4090 {
4091     This->PowerSendPowerUpFailureEvent();
4092 
4093     return WdfDevStatePowerStopped;
4094 }
4095 
4096 WDF_DEVICE_POWER_STATE
PowerDxStoppedDisarmWake(__inout FxPkgPnp * This)4097 FxPkgPnp::PowerDxStoppedDisarmWake(
4098     __inout FxPkgPnp*   This
4099     )
4100 /*++
4101 
4102 Routine Description:
4103     Disarms the device from wake because the device is being stopped/removed
4104     while in Dx.
4105 
4106 Arguments:
4107     This - instance of the state machine
4108 
4109 Return Value:
4110     WdfDevStatePowerDxStopped
4111 
4112   --*/
4113 {
4114     //
4115     // We should only get into this state when this devobj is not a PDO and a
4116     // power policy owner.
4117     //
4118     ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE);
4119 
4120     This->PowerDisableWakeAtBusOverload();
4121 
4122     return WdfDevStatePowerGotoDxStoppedDisableInterrupt;
4123 }
4124 
4125 WDF_DEVICE_POWER_STATE
PowerDxStoppedDisarmWakeNP(__inout FxPkgPnp * This)4126 FxPkgPnp::PowerDxStoppedDisarmWakeNP(
4127     __inout FxPkgPnp*   This
4128     )
4129 /*++
4130 
4131 Routine Description:
4132     Disarms the device from wake because the device is being stopped/removed
4133     while in Dx.
4134 
4135 Arguments:
4136     This - instance of the state machine
4137 
4138 Return Value:
4139     WdfDevStatePowerGotoDxStoppedDisableInterruptNP
4140 
4141   --*/
4142 {
4143     //
4144     // We should only get into this state when this devobj is not a PDO and a
4145     // power policy owner.
4146     //
4147     ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE);
4148 
4149     This->PowerDisableWakeAtBusOverload();
4150 
4151     return WdfDevStatePowerGotoDxStoppedDisableInterruptNP;
4152 }
4153 
4154 WDF_DEVICE_POWER_STATE
PowerGotoDxStoppedDisableInterruptNP(__inout FxPkgPnp * This)4155 FxPkgPnp::PowerGotoDxStoppedDisableInterruptNP(
4156     __inout FxPkgPnp*   This
4157     )
4158 /*++
4159 
4160 Routine Description:
4161     Device is in Dx and was implicitly powered down. Disable the interrupt since
4162     the interrupt was not disconnected in the NP power down path.
4163 
4164 Arguments:
4165     This - instance of the state machine
4166 
4167 Return Value:
4168     WdfDevStatePowerGotoDxStopped
4169 
4170   --*/
4171 {
4172     This->NotifyResourceObjectsDx(NotifyResourcesSurpriseRemoved);
4173 
4174     return WdfDevStatePowerGotoDxStopped;
4175 }
4176 
4177 WDF_DEVICE_POWER_STATE
PowerGotoDxStopped(__inout FxPkgPnp * This)4178 FxPkgPnp::PowerGotoDxStopped(
4179     __inout FxPkgPnp*   This
4180     )
4181 /*++
4182 
4183 Routine Description:
4184     Device is in Dx and being removed/stopped.  Inform the other state machines
4185     that the device is powered down so that they may continue.
4186 
4187 Arguments:
4188     This - instance of the state machine
4189 
4190 Return Value:
4191     WdfDevStatePowerStopped
4192 
4193   --*/
4194 {
4195     This->PowerSendPowerDownEvents(FxPowerDownTypeImplicit);
4196 
4197     return WdfDevStatePowerStopped;
4198 }
4199 
4200 WDF_DEVICE_POWER_STATE
PowerGotoStopped(__inout FxPkgPnp * This)4201 FxPkgPnp::PowerGotoStopped(
4202     __inout FxPkgPnp*   This
4203     )
4204 /*++
4205 
4206 Routine Description:
4207     We are in the Dx state and the power policy owner sent an explicit D0 irp
4208     to the stack.  Transition to the stopped state which will transition to the
4209     D0 state when receiving an implicit D0.
4210 
4211 Arguments:
4212     This - instance of the state machine
4213 
4214 Return Value:
4215     WdfDevStatePowerStopped
4216 
4217   --*/
4218 {
4219     //
4220     // We should only get into this state when this devobj is not the power
4221     // policy owner.
4222     //
4223     ASSERT(This->IsPowerPolicyOwner() == FALSE);
4224 
4225     This->PowerReleasePendingDeviceIrp();
4226     return WdfDevStatePowerStopped;
4227 }
4228 
4229 WDF_DEVICE_POWER_STATE
PowerStoppedCompleteDx(__inout FxPkgPnp * This)4230 FxPkgPnp::PowerStoppedCompleteDx(
4231     __inout FxPkgPnp*   This
4232     )
4233 /*++
4234 
4235 Routine Description:
4236     We were in the Stopped state and the power policy owner sent an explicit
4237     Dx request to the stack.  We will move to the DxStopped state where we will
4238     transition to a Dx state when an implicit D0 is received.
4239 
4240 Arguments:
4241     This - instance of the state machine
4242 
4243 Return Value:
4244     WdfDevStatePowerDxStopped
4245 
4246   --*/
4247 {
4248     //
4249     // We should only get into this state when this devobj is not the power
4250     // policy owner.
4251     //
4252     ASSERT(This->IsPowerPolicyOwner() == FALSE);
4253 
4254     This->PowerReleasePendingDeviceIrp();
4255     return WdfDevStatePowerDxStopped;
4256 }
4257 
4258 WDF_DEVICE_POWER_STATE
PowerDxStoppedDecideDxState(__inout FxPkgPnp * This)4259 FxPkgPnp::PowerDxStoppedDecideDxState(
4260     __inout FxPkgPnp*   This
4261     )
4262 /*++
4263 
4264 Routine Description:
4265     We are implicitly powering up the stack while in the Dx state.  Decide
4266     which Dx "holding" state to transition to.
4267 
4268 Arguments:
4269     This - instance of the state machine
4270 
4271 Return Value:
4272     new power state
4273 
4274   --*/
4275 {
4276     //
4277     // We should only get into this state when this devobj is not the power
4278     // policy owner.
4279     //
4280     ASSERT(This->IsPowerPolicyOwner() == FALSE);
4281 
4282     //
4283     // Move power policy back into a working state
4284     //
4285     // While it seems odd to send a power up in a Dx state, the power up is
4286     // really an indication to the power policy state machine that the implicit
4287     // D0 has been successfully processed, basically, it is a status event more
4288     // then an indication of true power state.
4289     //
4290     This->PowerSendPowerUpEvents();
4291 
4292     if (This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) {
4293         if (This->PowerIsWakeRequestPresent()) {
4294             COVERAGE_TRAP();
4295             return WdfDevStatePowerDxStoppedArmForWake;
4296         }
4297         else {
4298             return WdfDevStatePowerDx;
4299         }
4300     }
4301     else {
4302         if (This->PowerIsWakeRequestPresent()) {
4303             COVERAGE_TRAP();
4304             return WdfDevStatePowerDxStoppedArmForWakeNP;
4305         }
4306         else {
4307             COVERAGE_TRAP();
4308             return WdfDevStatePowerDxNP;
4309         }
4310     }
4311 }
4312 
4313 WDF_DEVICE_POWER_STATE
PowerDxStoppedArmForWake(__inout FxPkgPnp * This)4314 FxPkgPnp::PowerDxStoppedArmForWake(
4315     __inout FxPkgPnp*   This
4316     )
4317 /*++
4318 
4319 Routine Description:
4320     We are implicitly powering the stack back up while the device is in Dx
4321     and there is a wait wake request presnt on this device.  Enable wake at
4322     the bus level and then move to the appropriate state based on the enabling
4323     status.
4324 
4325 Arguments:
4326     This - instance of the state machine
4327 
4328 Return Value:
4329     new power state
4330 
4331   --*/
4332 {
4333     NTSTATUS status;
4334 
4335     COVERAGE_TRAP();
4336 
4337     //
4338     // We should only get into this state when this devobj is not a PDO and a
4339     // power policy owner.
4340     //
4341     ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE);
4342 
4343     status = This->PowerEnableWakeAtBusOverload();
4344 
4345     if (NT_SUCCESS(status)) {
4346         //
4347         // No matter of the irp status (canceled, pending, completed), we always
4348         // transition to the D0ArmedForWake state because that is where we
4349         // we handle the change in the irp's status.
4350         //
4351         COVERAGE_TRAP();
4352         return WdfDevStatePowerDxArmedForWake;
4353     }
4354     else {
4355         COVERAGE_TRAP();
4356         This->PowerCompleteWakeRequestFromWithinMachine(status);
4357         return WdfDevStatePowerDx;
4358     }
4359 }
4360 
4361 WDF_DEVICE_POWER_STATE
PowerDxStoppedArmForWakeNP(__inout FxPkgPnp * This)4362 FxPkgPnp::PowerDxStoppedArmForWakeNP(
4363     __inout FxPkgPnp*   This
4364     )
4365 /*++
4366 
4367 Routine Description:
4368     We are implicitly powering the stack back up while the device is in Dx
4369     and there is a wait wake request presnt on this device.  Enable wake at
4370     the bus level and then move to the appropriate state based on the enabling
4371     status.
4372 
4373 Arguments:
4374     This - instance of the state machine
4375 
4376 Return Value:
4377     new power state
4378 
4379   --*/
4380 {
4381     NTSTATUS status;
4382 
4383     COVERAGE_TRAP();
4384 
4385     //
4386     // We should only get into this state when this devobj is not a PDO and a
4387     // power policy owner.
4388     //
4389     ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE);
4390 
4391     status = This->PowerEnableWakeAtBusOverload();
4392 
4393     if (NT_SUCCESS(status)) {
4394         //
4395         // No matter of the irp status (canceled, pending, completed), we always
4396         // transition to the D0ArmedForWake state because that is where we
4397         // we handle the change in the irp's status.
4398         //
4399         COVERAGE_TRAP();
4400         return WdfDevStatePowerDxArmedForWakeNP;
4401     }
4402     else {
4403         COVERAGE_TRAP();
4404         This->PowerCompleteWakeRequestFromWithinMachine(status);
4405         return WdfDevStatePowerDxNP;
4406     }
4407 }
4408 
4409 WDF_DEVICE_POWER_STATE
PowerFinalPowerDownFailed(__inout FxPkgPnp * This)4410 FxPkgPnp::PowerFinalPowerDownFailed(
4411     __inout FxPkgPnp*   This
4412     )
4413 /*++
4414 
4415 Routine Description:
4416     Posts PowerDownFailed event to the PnP state machine and then waits for death.
4417 
4418 Arguments:
4419     This - The instance of the state machine
4420 
4421 Return Value:
4422     WdfDevStatePowerStopped
4423 
4424   --*/
4425 {
4426     This->PowerSendPowerDownFailureEvent(FxPowerDownTypeImplicit);
4427 
4428     //
4429     // If we are not the PPO for the stack we could receive a power irp
4430     // during the middle of an implicit power down so we cannot assume
4431     // that there will be no pended power irp during an implicit power down.
4432     //
4433     ASSERT(This->IsPowerPolicyOwner() ? This->m_PendingDevicePowerIrp == NULL  : TRUE);
4434 
4435     return WdfDevStatePowerStopped;
4436 }
4437 
4438 WDF_DEVICE_POWER_STATE
PowerUpFailedDerefParent(__inout FxPkgPnp * This)4439 FxPkgPnp::PowerUpFailedDerefParent(
4440     __inout FxPkgPnp*   This
4441     )
4442 /*++
4443 
4444 Routine Description:
4445     Disconnects interrupts
4446 
4447 Arguments:
4448     This - The instance of the state machine
4449 
4450 Return Value:
4451     WdfDevStatePowerReportPowerUpFailed
4452 
4453   --*/
4454 {
4455     //
4456     // Notify the interrupt state machines that the power up failed
4457     //
4458     This->SendEventToAllWakeInterrupts(WakeInterruptEventD0EntryFailed);
4459     //
4460     // NotifyResourceObjectsDx will log any errors
4461     //
4462     (void) This->NotifyResourceObjectsDx(NotifyResourcesForceDisconnect |
4463                                      NotifyResourcesDisconnectInactive);
4464 
4465     return WdfDevStatePowerReportPowerUpFailedDerefParent;
4466 }
4467 
4468 WDF_DEVICE_POWER_STATE
PowerUpFailed(__inout FxPkgPnp * This)4469 FxPkgPnp::PowerUpFailed(
4470     __inout FxPkgPnp*   This
4471     )
4472 /*++
4473 
4474 Routine Description:
4475     Disconnects interrupts
4476 
4477 Arguments:
4478     This - The instance of the state machine
4479 
4480 Return Value:
4481     WdfDevStatePowerReportPowerUpFailed
4482 
4483   --*/
4484 {
4485     COVERAGE_TRAP();
4486     //
4487     // Notify the interrupt state machines that the power up failed
4488     //
4489     This->SendEventToAllWakeInterrupts(WakeInterruptEventD0EntryFailed);
4490     //
4491     // NotifyResourceObjectsDx will log any errors
4492     //
4493     (void) This->NotifyResourceObjectsDx(NotifyResourcesForceDisconnect |
4494                                      NotifyResourcesDisconnectInactive);
4495 
4496     return WdfDevStatePowerReportPowerUpFailed;
4497 }
4498 
4499 WDF_DEVICE_POWER_STATE
PowerGotoDxFailed(__inout FxPkgPnp * This)4500 FxPkgPnp::PowerGotoDxFailed(
4501     __inout FxPkgPnp*   This
4502     )
4503 /*++
4504 
4505 Routine Description:
4506     Disconnects interrupts
4507 
4508 Arguments:
4509     This - The instance of the state machine
4510 
4511 Return Value:
4512     WdfDevStatePowerReportPowerDownFailed
4513 
4514   --*/
4515 {
4516     //
4517     // NotifyResourceObjectsDx will log any errors
4518     //
4519     (void) This->NotifyResourceObjectsDx(NotifyResourcesForceDisconnect |
4520                                      NotifyResourcesDisconnectInactive);
4521 
4522     return WdfDevStatePowerReportPowerDownFailed;
4523 }
4524 
4525 WDF_DEVICE_POWER_STATE
PowerGotoDxStoppedDisableInterrupt(__inout FxPkgPnp * This)4526 FxPkgPnp::PowerGotoDxStoppedDisableInterrupt(
4527     __inout FxPkgPnp*   This
4528     )
4529 /*++
4530 
4531 Routine Description:
4532     Disconnects interrupts
4533 
4534 Arguments:
4535     This - The instance of the state machine
4536 
4537 Return Value:
4538     WdfDevStatePowerGotoDxStopped
4539 
4540   --*/
4541 {
4542     //
4543     // NotifyResourceObjectsDx will log any errors
4544     //
4545     (void) This->NotifyResourceObjectsDx(NotifyResourcesForceDisconnect |
4546                                      NotifyResourcesDisconnectInactive);
4547 
4548     return WdfDevStatePowerGotoDxStopped;
4549 }
4550 
4551 WDF_DEVICE_POWER_STATE
PowerUpFailedDerefParentNP(__inout FxPkgPnp * This)4552 FxPkgPnp::PowerUpFailedDerefParentNP(
4553     __inout FxPkgPnp*   This
4554     )
4555 /*++
4556 
4557 Routine Description:
4558     Disconnects interrupts
4559 
4560 Arguments:
4561     This - The instance of the state machine
4562 
4563 Return Value:
4564     WdfDevStatePowerReportPowerUpFailed
4565 
4566   --*/
4567 {
4568     //
4569     // Notify the interrupt state machines that the power up failed
4570     //
4571     This->SendEventToAllWakeInterrupts(WakeInterruptEventD0EntryFailed);
4572     This->DisconnectInterruptNP();
4573 
4574     return WdfDevStatePowerReportPowerUpFailedDerefParent;
4575 }
4576 
4577 WDF_DEVICE_POWER_STATE
PowerUpFailedNP(__inout FxPkgPnp * This)4578 FxPkgPnp::PowerUpFailedNP(
4579     __inout FxPkgPnp*   This
4580     )
4581 /*++
4582 
4583 Routine Description:
4584     Disconnects interrupts
4585 
4586 Arguments:
4587     This - The instance of the state machine
4588 
4589 Return Value:
4590     WdfDevStatePowerReportPowerUpFailed
4591 
4592   --*/
4593 {
4594     //
4595     // Notify the interrupt state machines that the power up failed
4596     //
4597     This->SendEventToAllWakeInterrupts(WakeInterruptEventD0EntryFailed);
4598     This->DisconnectInterruptNP();
4599 
4600     return WdfDevStatePowerReportPowerUpFailed;
4601 }
4602 
4603 WDF_DEVICE_POWER_STATE
PowerNotifyingD0EntryToWakeInterrupts(__inout FxPkgPnp * This)4604 FxPkgPnp::PowerNotifyingD0EntryToWakeInterrupts(
4605     __inout FxPkgPnp*   This
4606     )
4607 /*++
4608 
4609 Routine Description:
4610     Notifies the wake interrupt state machines that the device has entered
4611     D0
4612 
4613 Arguments:
4614     This - The instance of the state machine
4615 
4616 Return Value:
4617     WdfDevStatePowerWakingConnectInterrupt if there are no wake interrupts
4618     or WdfDevStatePowerNull otherwise
4619 
4620   --*/
4621 {
4622     if (This->m_WakeInterruptCount == 0) {
4623         return WdfDevStatePowerWakingConnectInterrupt;
4624     }
4625 
4626     This->SendEventToAllWakeInterrupts(WakeInterruptEventEnteringD0);
4627 
4628     return WdfDevStatePowerNull;;
4629 }
4630 
4631 WDF_DEVICE_POWER_STATE
PowerNotifyingD0ExitToWakeInterrupts(__inout FxPkgPnp * This)4632 FxPkgPnp::PowerNotifyingD0ExitToWakeInterrupts(
4633     __inout FxPkgPnp*   This
4634     )
4635 /*++
4636 
4637 Routine Description:
4638     Notifies the wake interrupt state machines that the device is about
4639     to exit D0
4640 
4641 Arguments:
4642     This - The instance of the state machine
4643 
4644 Return Value:
4645     WdfDevStatePowerDx if there are no wake interrupts or WdfDevStatePowerNull
4646     otherwise
4647 
4648   --*/
4649 {
4650     if (This->m_WakeInterruptCount == 0) {
4651         return WdfDevStatePowerGotoDxIoStopped;
4652     }
4653 
4654     //
4655     // Indiciate to the wake interrupt state machine that the device is
4656     // leaving D0 and also whether the device is armed for wake. The wake
4657     // interrupt machine treats these differently as described below.
4658     //
4659     if (This->m_WakeInterruptsKeepConnected == TRUE ||
4660         This->m_SharedPower.m_WaitWakeIrp != NULL) {
4661         This->SendEventToAllWakeInterrupts(WakeInterruptEventLeavingD0);
4662     }
4663     else {
4664         //
4665         // When a wake interrupt is not armed for wake it will be disconnected
4666         // by the power state machine once the wake interrupt state machine
4667         // acknowledges the transition. If the interrupt fires between
4668         // the time this event is posted and it is disconnected, it needs to be
4669         // delivered to the driver or a deadlock could occur between PO state machine
4670         // trying to disconnect the interrupt and the wake interrupt machine
4671         // holding on to the ISR waiting for the device to return to D0 before
4672         // delivering the interrupt.
4673         //
4674         This->SendEventToAllWakeInterrupts(WakeInterruptEventLeavingD0NotArmedForWake);
4675     }
4676 
4677     return WdfDevStatePowerNull;;
4678 }
4679 
4680 WDF_DEVICE_POWER_STATE
PowerNotifyingD0EntryToWakeInterruptsNP(__inout FxPkgPnp * This)4681 FxPkgPnp::PowerNotifyingD0EntryToWakeInterruptsNP(
4682     __inout FxPkgPnp*   This
4683     )
4684 /*++
4685 
4686 Routine Description:
4687     Notifies the wake interrupt state machines that the device has entered
4688     D0
4689 
4690 Arguments:
4691     This - The instance of the state machine
4692 
4693 Return Value:
4694     WdfDevStatePowerWakingConnectInterruptNP if there are no wake interrupts
4695     or WdfDevStatePowerNull otherwise
4696 
4697   --*/
4698 {
4699     if (This->m_WakeInterruptCount == 0) {
4700         return WdfDevStatePowerWakingConnectInterruptNP;
4701     }
4702 
4703     This->SendEventToAllWakeInterrupts(WakeInterruptEventEnteringD0);
4704 
4705     return WdfDevStatePowerNull;;
4706 }
4707 
4708 WDF_DEVICE_POWER_STATE
PowerNotifyingD0ExitToWakeInterruptsNP(__inout FxPkgPnp * This)4709 FxPkgPnp::PowerNotifyingD0ExitToWakeInterruptsNP(
4710     __inout FxPkgPnp*   This
4711     )
4712 /*++
4713 
4714 Routine Description:
4715     Notifies the wake interrupt state machines that the device is about
4716     to exit D0
4717 
4718 Arguments:
4719     This - The instance of the state machine
4720 
4721 Return Value:
4722     WdfDevStatePowerDxNP if there are no wake interrupts or WdfDevStatePowerNull
4723     otherwise
4724 
4725   --*/
4726 {
4727     if (This->m_WakeInterruptCount == 0) {
4728         return WdfDevStatePowerGotoDxIoStoppedNP;
4729     }
4730 
4731     //
4732     // Indiciate to the wake interrupt state machine that the device is
4733     // leaving D0 and also whether the device is armed for wake. The wake
4734     // interrupt machine treats these differently as described below
4735     //
4736     if (This->m_WakeInterruptsKeepConnected == TRUE ||
4737         This->m_SharedPower.m_WaitWakeIrp != NULL) {
4738         This->SendEventToAllWakeInterrupts(WakeInterruptEventLeavingD0);
4739     }
4740     else {
4741         //
4742         // When a wake interrupt is not armed for wake it will be disconnected by
4743         // the power state machine once the wake interrupt state machine
4744         // acknowledges the transition. If the interrupt fires between
4745         // the time this event is posted and it is disconnected, it needs to be
4746         // delivered to the driver or a deadlock could occur between PO state machine
4747         // trying to disconnect the interrupt and the wake interrupt machine holding on
4748         // to the ISR waiting for the device to return to D0 before delivering the
4749         // interrupt.
4750         //
4751         This->SendEventToAllWakeInterrupts(WakeInterruptEventLeavingD0NotArmedForWake);
4752     }
4753 
4754     return WdfDevStatePowerNull;;
4755 }
4756 
4757 VOID
DisconnectInterruptNP(VOID)4758 FxPkgPnp::DisconnectInterruptNP(
4759     VOID
4760     )
4761 {
4762     //
4763     // NotifyResourceObjectsDx will call IoDisconnectInterrupt.  Since we
4764     // are in the NP path, this may cause a deadlock between this thread and
4765     // paging I/O.  Log something to the IFR so that if the watchdog timer kicks
4766     // in, at least we have context as to why we died.
4767     //
4768     DoTraceLevelMessage(
4769         GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
4770         "Force disconnecting interrupts on !devobj 0x%p, WDFDEVICE %p",
4771         m_Device->GetDeviceObject(),
4772         m_Device->GetHandle());
4773 
4774     //
4775     // NotifyResourceObjectsDx will log any errors
4776     //
4777     (void) NotifyResourceObjectsDx(NotifyResourcesForceDisconnect);
4778 }
4779 
4780 BOOLEAN
PowerIndicateWaitWakeStatus(__in NTSTATUS WaitWakeStatus)4781 FxPkgPnp::PowerIndicateWaitWakeStatus(
4782     __in NTSTATUS WaitWakeStatus
4783     )
4784 /*++
4785 
4786 Routine Description:
4787     If there is a pended wait wake request, this routine will remove the cancel
4788     routine and post the appropriate event to the power state machine.  The
4789     consumer of this event will do the actual completion of the wait wake
4790     request.
4791 
4792     The difference between this routine and
4793     PowerCompleteWakeRequestFromWithinMachine is that
4794     PowerCompleteWakeRequestFromWithinMachine is a private API to the state
4795     machine and will attempt to complete the request immediately instead of
4796     deferring the completion through the posting of a power state machine event.
4797 
4798     PowerCompletePendedWakeIrp is used within the state machine to complete the
4799     IRP deferred by this routine.
4800 
4801 Arguments:
4802     WaitWakeStatus - The final status of the wait wake request
4803 
4804 Return Value:
4805     TRUE if there there was a request to cancel
4806 
4807   --*/
4808 {
4809     if (PowerMakeWakeRequestNonCancelable(WaitWakeStatus)) {
4810         //
4811         // The power machine will eventually call PowerCompletePendedWakeIrp
4812         // to complete the request.
4813         //
4814         if (WaitWakeStatus == STATUS_CANCELLED) {
4815             PowerProcessEvent(PowerWakeCanceled);
4816         }
4817         else if (NT_SUCCESS(WaitWakeStatus)) {
4818             PowerProcessEvent(PowerWakeSucceeded);
4819         }
4820         else {
4821             PowerProcessEvent(PowerWakeFailed);
4822         }
4823 
4824         return TRUE;
4825     }
4826     else {
4827         return FALSE;
4828     }
4829 }
4830 
4831 VOID
PowerCompletePendedWakeIrp(VOID)4832 FxPkgPnp::PowerCompletePendedWakeIrp(
4833     VOID
4834     )
4835 /*++
4836 
4837 Routine Description:
4838     Completes the wait wake request that was pended by the power state machine.
4839     It is valid if there is no request to complete (the only time there will be
4840     a request to complete is when this power state machine is the wait wake owner
4841 
4842 Arguments:
4843     None
4844 
4845 Return Value:
4846     None
4847 
4848   --*/
4849 {
4850     PLIST_ENTRY ple;
4851     KIRQL irql;
4852 
4853     if (m_SharedPower.m_WaitWakeOwner == FALSE) {
4854         COVERAGE_TRAP();
4855         return;
4856     }
4857 
4858     //
4859     // Pop an irp off of the list
4860     //
4861     m_PowerMachine.m_WaitWakeLock.Acquire(&irql);
4862     ASSERT(IsListEmpty(&m_PowerMachine.m_WaitWakeIrpToBeProcessedList) == FALSE);
4863     ple = RemoveHeadList(&m_PowerMachine.m_WaitWakeIrpToBeProcessedList);
4864     m_PowerMachine.m_WaitWakeLock.Release(irql);
4865 
4866     InitializeListHead(ple);
4867 
4868     FxIrp irp(FxIrp::GetIrpFromListEntry(ple));
4869 
4870     CompletePowerRequest(&irp, irp.GetStatus());
4871 }
4872 
4873 VOID
PowerCompleteWakeRequestFromWithinMachine(__in NTSTATUS WaitWakeStatus)4874 FxPkgPnp::PowerCompleteWakeRequestFromWithinMachine(
4875     __in NTSTATUS WaitWakeStatus
4876     )
4877 /*++
4878 
4879 Routine Description:
4880     Completes a wait wake from within the power state machine.  Contrary to
4881     PowerIndicateWaitWakeStatus which posts an event to the state machine to
4882     process the irp's status change, this routine attempts to complete the
4883     irp immediately.
4884 
4885 Arguments:
4886     Status - Final status of the wake irp
4887 
4888 Return Value:
4889     None
4890 
4891   --*/
4892 {
4893     if (PowerMakeWakeRequestNonCancelable(WaitWakeStatus)) {
4894         PowerCompletePendedWakeIrp();
4895     }
4896 }
4897 
4898 BOOLEAN
PowerMakeWakeRequestNonCancelable(__in NTSTATUS WaitWakeStatus)4899 FxPkgPnp::PowerMakeWakeRequestNonCancelable(
4900     __in NTSTATUS WaitWakeStatus
4901     )
4902 /*++
4903 
4904 Routine Description:
4905     Attempts to clear the cancel routine from the pended wake request.  If
4906     successful, it will put the wake request on a pending wake list to be
4907     completed later by PowerCompletePendedWakeIrp .
4908 
4909 Arguments:
4910     WaitWakeStatus - final status for the wake request
4911 
4912 Return Value:
4913     TRUE if there was a request and we cleared the cancel routine, FALSE
4914     otherwise
4915 
4916   --*/
4917 {
4918     KIRQL irql;
4919     BOOLEAN result;
4920 
4921     //
4922     // Currently we assume that if we are the bus wait wake owner and that only
4923     // PDOs can be bus wake owners, so we must have a parent device.
4924     //
4925     ASSERT(m_SharedPower.m_WaitWakeOwner &&
4926         (m_Device->m_ParentDevice != NULL));
4927 
4928     result = FALSE;
4929 
4930     //
4931     // Attempt to retrieve the wait wake irp.  We can safely dereference the
4932     // PIRP in while holding the lock as long as it is not NULL.
4933     //
4934     m_PowerMachine.m_WaitWakeLock.Acquire(&irql);
4935 
4936     if (m_SharedPower.m_WaitWakeIrp != NULL) {
4937         MdCancelRoutine pOldCancelRoutine;
4938         FxIrp wwIrp;
4939 
4940         wwIrp.SetIrp(m_SharedPower.m_WaitWakeIrp);
4941 
4942         pOldCancelRoutine = wwIrp.SetCancelRoutine(NULL);
4943 
4944         if (pOldCancelRoutine != NULL) {
4945             FxPkgPnp* pParentPkg;
4946 
4947             pParentPkg = m_Device->m_ParentDevice->m_PkgPnp;
4948 
4949             //
4950             // Propagate the successful wake status from the parent to this
4951             // child's WW IRP if the parent is the PPO for its stack.
4952             //
4953             if (NT_SUCCESS(WaitWakeStatus) &&
4954                 pParentPkg->IsPowerPolicyOwner() &&
4955                 pParentPkg->m_PowerPolicyMachine.m_Owner->m_SystemWakeSource) {
4956                 //
4957                 // The only way that m_SystemWakeSource can be TRUE is if
4958                 // FxLibraryGlobals.PoGetSystemWake != NULL and if it is not
4959                 // NULL, then FxLibraryGlobals.PoSetSystemWake cannot be NULL
4960                 // either.
4961 
4962 
4963 
4964 
4965 
4966                 FxPkgPnp::_PowerSetSystemWakeSource(&wwIrp);
4967 
4968                 //
4969                 // If this PDO is the PPO for its stack, then we must mark this
4970                 // device as the system wake source if we have any
4971                 // enumerated PDOs off of this PDO so that we can propagate the
4972                 // system wake source attribute to our children stacks.
4973                 // (For a FDO which is the PPO, we do this in the WW completion
4974                 // routine.)
4975                 //
4976                 if (IsPowerPolicyOwner()) {
4977                     DoTraceLevelMessage(
4978                         GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
4979                         "WDFDEVICE 0x%p !devobj 0x%p WW !irp 0x%p is a source "
4980                         "of wake", m_Device->GetHandle(),
4981                         m_Device->GetDeviceObject(),
4982                         m_SharedPower.m_WaitWakeIrp);
4983 
4984                     m_PowerPolicyMachine.m_Owner->m_SystemWakeSource = TRUE;
4985                 }
4986             }
4987 
4988             //
4989             // Set the status for the irp when it is completed later
4990             //
4991             wwIrp.SetStatus(WaitWakeStatus);
4992 
4993             //
4994             // Queue the irp for completion later
4995             //
4996             InsertTailList(&m_PowerMachine.m_WaitWakeIrpToBeProcessedList,
4997                            wwIrp.ListEntry());
4998 
4999             wwIrp.SetIrp(NULL);
5000             m_SharedPower.m_WaitWakeIrp = NULL;
5001             result = TRUE;
5002         }
5003         else {
5004             //
5005             // The irp is being canceled as we run here.  As soon as the spin
5006             // lock is dropped, the cancel routine will run (or continue if it
5007             // is blocked on this lock).  Do nothing here and let the cancel
5008             // routine run its course.
5009             //
5010             ASSERT(wwIrp.IsCanceled());
5011             DO_NOTHING();
5012         }
5013     }
5014     m_PowerMachine.m_WaitWakeLock.Release(irql);
5015 
5016     return result;
5017 }
5018 
5019 VOID
PowerSendIdlePowerEvent(__in FxPowerIdleEvents Event)5020 FxPkgPnp::PowerSendIdlePowerEvent(
5021     __in FxPowerIdleEvents Event
5022     )
5023 {
5024     if (IsPowerPolicyOwner()) {
5025         m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.ProcessPowerEvent(Event);
5026     }
5027 }
5028 
5029 VOID
PowerSendPowerDownEvents(__in FxPowerDownType Type)5030 FxPkgPnp::PowerSendPowerDownEvents(
5031     __in FxPowerDownType Type
5032     )
5033 /*++
5034 
5035 Routine Description:
5036     The device has powered down, inform the power policy state machine
5037 
5038 Arguments:
5039     Type - the type of power down being performed
5040 
5041 Return Value:
5042     None
5043 
5044   --*/
5045 {
5046     //
5047     // If this is an implicit power type, there is completion routine on the
5048     // power irp and we must send these events in the power state machine
5049     // regardless if we are the PPO or not.
5050     //
5051     if (Type == FxPowerDownTypeImplicit) {
5052         PowerSendIdlePowerEvent(PowerIdleEventPowerDown);
5053 
5054         //
5055         // If we are the power policy owner, there is no need to distinguish
5056         // between an implicit power down or an explicit power down since the
5057         // PPO controls all power irps in the stack and a power policy stop
5058         // (e.g. an implicit power down) will not be racing with a real power
5059         // irp.
5060         //
5061         // The non PPO state machine needs to distinguish between the 2 types
5062         // of power downs because both of them may occur simultaneously and we
5063         // don't want to interpret the power down event for the real Dx irp with
5064         // the power down event for the (final) implicit power down.
5065         //
5066         PowerPolicyProcessEvent(IsPowerPolicyOwner() ? PwrPolPowerDown
5067                                                      : PwrPolImplicitPowerDown);
5068         return;
5069     }
5070 
5071     ASSERT(Type == FxPowerDownTypeExplicit);
5072 
5073     //
5074     // If we are the PPO, then we will send PwrPolPowerDown in the completion
5075     // routine passed to PoRequestPowerIrp.  If we are not the PPO, we must send
5076     // the event now because we have no such completion routine.
5077     //
5078     if (IsPowerPolicyOwner()) {
5079         //
5080         // Transition the idle state machine to off immediately.
5081         //
5082         m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.ProcessPowerEvent(
5083             PowerIdleEventPowerDown
5084             );
5085     }
5086     else {
5087         //
5088         // If we are not the PPO, there is no idle state machine to send an
5089         // event to and there is no Po request completion routine to send this
5090         // event, so we send it now.
5091         //
5092         PowerPolicyProcessEvent(PwrPolPowerDown);
5093     }
5094 }
5095 
5096 VOID
PowerSendPowerUpEvents(VOID)5097 FxPkgPnp::PowerSendPowerUpEvents(
5098     VOID
5099     )
5100 /*++
5101 
5102 Routine Description:
5103     Sends power up events to the pnp and power policy state machines
5104 
5105 Arguments:
5106     None
5107 
5108 Return Value:
5109     None
5110 
5111   --*/
5112 {
5113     PowerSendIdlePowerEvent(PowerIdleEventPowerUpComplete);
5114 
5115     //
5116     // This must be called *before* PowerPostParentToD0ToChildren so that we
5117     // clear the child power up guard variable in the power policy state machine
5118     // and then post an event which will unblock the child.
5119     //
5120     PowerPolicyProcessEvent(PwrPolPowerUp);
5121 }
5122 
5123 VOID
PowerSendPowerDownFailureEvent(__in FxPowerDownType Type)5124 FxPkgPnp::PowerSendPowerDownFailureEvent(
5125     __in FxPowerDownType Type
5126     )
5127 /*++
5128 
5129 Routine Description:
5130     Sends a power down failure event to the pnp state machine marks an internal
5131     error.
5132 
5133 Arguments:
5134     None
5135 
5136 Return Value:
5137     None
5138 
5139   --*/
5140 {
5141     SetInternalFailure();
5142 
5143     if (IsPowerPolicyOwner()) {
5144         //
5145         // If we are the PPO and this is an explicit power operation, then we
5146         // will send PwrPolPowerDownFailed in the completion routine passed to
5147         // PoRequestPowerIrp.   Otherwise, if this is an implicit power operation
5148         // that failed, we need to send the event now because there is no
5149         // Po completion routine to send the event later.
5150         //
5151         if (Type == FxPowerDownTypeImplicit) {
5152             //
5153             // Since there is no power irp to complete, we must send the event
5154             // now.
5155             //
5156             // We only send PwrPolImplicitPowerDownFailed if we are not the
5157             // PPO, so we can't share code with the !PPO path.
5158             //
5159             PowerPolicyProcessEvent(PwrPolPowerDownFailed);
5160         }
5161         else {
5162             ASSERT(Type == FxPowerDownTypeExplicit);
5163 
5164             //
5165             // Process the state change immediately in the idle state machine.
5166             // We should do this only on an explicit power down since the PPO
5167             // will have disabled the idle state machine before attempting an
5168             // implicit power down.
5169             //
5170             m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.ProcessPowerEvent(
5171                 PowerIdleEventPowerDownFailed
5172                 );
5173         }
5174     }
5175     else {
5176         //
5177         // We are not the PPO, so we must send the event now because we have no
5178         // such completion routine.  Decide which event to send to the
5179         // !PPO state machine.
5180         //
5181         PowerPolicyProcessEvent(
5182             Type == FxPowerDownTypeImplicit ? PwrPolImplicitPowerDownFailed
5183                                             : PwrPolPowerDownFailed
5184             );
5185 
5186         //
5187         // Send the pnp event last becuase if we are in the middle of a Dx
5188         // transition during S0, there is no S irp to guard a pnp state change
5189         // from occurring immediately after sending this event.  If we sent it
5190         // before sending the power policy message, power policy might not
5191         // transition to the failed state by the time pnp does creating a
5192         // mismatch.
5193         //
5194         if (FALSE == m_ReleaseHardwareAfterDescendantsOnFailure) {
5195             PnpProcessEvent(PnpEventPowerDownFailed);
5196         }
5197     }
5198 }
5199 
5200 VOID
PowerSendPowerUpFailureEvent(VOID)5201 FxPkgPnp::PowerSendPowerUpFailureEvent(
5202     VOID
5203     )
5204 /*++
5205 
5206 Routine Description:
5207     Sends a power up failure event to the pnp state machine marks an internal
5208     error.
5209 
5210 Arguments:
5211     None
5212 
5213 Return Value:
5214     None
5215 
5216   --*/
5217 {
5218     SetInternalFailure();
5219     PowerSendIdlePowerEvent(PowerIdleEventPowerUpFailed);
5220 
5221     PowerPolicyProcessEvent(PwrPolPowerUpFailed);
5222 
5223     if (FALSE == m_ReleaseHardwareAfterDescendantsOnFailure) {
5224         PnpProcessEvent(PnpEventPowerUpFailed);
5225     }
5226 }
5227 
5228 VOID
PowerSetDevicePowerState(__in WDF_POWER_DEVICE_STATE State)5229 FxPkgPnp::PowerSetDevicePowerState(
5230     __in WDF_POWER_DEVICE_STATE State
5231     )
5232 /*++
5233 
5234 Routine Description:
5235     Stores the state in the object and notifies the system of the change.
5236 
5237 Arguments:
5238     State - new device state
5239 
5240 Return Value:
5241     VOID
5242 
5243   --*/
5244 {
5245     POWER_STATE powerState;
5246 
5247     //
5248     // Remember our previous state
5249     //
5250     m_DevicePowerStateOld = m_DevicePowerState;
5251 
5252     //
5253     // Set our new state
5254     //
5255     ASSERT(State <= 0xFF);
5256     m_DevicePowerState = (BYTE) State;
5257 
5258     //
5259     // Notify the system of the new power state.
5260     //
5261     switch (State) {
5262     case WdfPowerDeviceD3Final:
5263     case WdfPowerDevicePrepareForHibernation:
5264         powerState.DeviceState = PowerDeviceD3;
5265         break;
5266 
5267     case WdfPowerDeviceD0:
5268          m_SystemPowerAction = PowerActionNone;
5269          __fallthrough;
5270 
5271     default:
5272         powerState.DeviceState = (DEVICE_POWER_STATE) State;
5273         break;
5274     }
5275 
5276     MxDeviceObject deviceObject(m_Device->GetDeviceObject());
5277     deviceObject.SetPowerState(
5278                     DevicePowerState,
5279                     powerState);
5280 }
5281 
5282 VOID
PowerConnectInterruptFailed(VOID)5283 FxPkgPnp::PowerConnectInterruptFailed(
5284     VOID
5285     )
5286 /*++
5287 
5288 Routine Description:
5289     Worker routine for all the paths where we are trying to bring the device into
5290     D0 and failed while trying to connect or enable an interrupt.  This routine
5291     disables and disconnects all interrupts, calls D0Exit, and sets the device
5292     state.
5293 
5294 Arguments:
5295     This - instance of the state machine
5296 
5297 Return Value:
5298     None
5299 
5300   --*/
5301 
5302 {
5303     NTSTATUS status;
5304 
5305     status = NotifyResourceObjectsDx(NotifyResourcesForceDisconnect);
5306 
5307     if (!NT_SUCCESS(status)) {
5308         //
5309         // Report the error, but continue forward
5310         //
5311         DoTraceLevelMessage(
5312             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
5313             "Interrupt(s) disconnect on WDFDEVICE %p failed, %!STATUS!",
5314             m_Device->GetHandle(), status);
5315     }
5316 
5317     status = m_DeviceD0Exit.Invoke(m_Device->GetHandle(),
5318         WdfPowerDeviceD3Final);
5319 
5320     if (!NT_SUCCESS(status)) {
5321         //
5322         // Report the error, but continue forward
5323         //
5324         DoTraceLevelMessage(
5325             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
5326             "EvtDeviceD0Exit WDFDEVICE 0x%p !devobj 0x%p failed, %!STATUS!",
5327             m_Device->GetHandle(),
5328             m_Device->GetDeviceObject(), status);
5329     }
5330 
5331     PowerSetDevicePowerState(WdfPowerDeviceD3Final);
5332 }
5333 
5334 
5335 
5336 
5337 
5338 
5339 
5340 
5341 VOID
_PowerWaitWakeCancelRoutine(__in MdDeviceObject DeviceObject,__in MdIrp Irp)5342 FxPkgPnp::_PowerWaitWakeCancelRoutine(
5343     __in MdDeviceObject DeviceObject,
5344     __in MdIrp Irp
5345     )
5346 /*++
5347 
5348 Routine Description:
5349     Cancel routine for the pended wait wake irp.  This will post an event to
5350     the power state machine to process the cancellation under the machine's
5351     lock and complete the irp later.
5352 
5353 Arguments:
5354     DeviceObject - Instance of this state machine
5355     Irp - The wait wake request being canceled
5356 
5357 Return Value:
5358     None
5359 
5360   --*/
5361 {
5362     CfxDevice* pDevice;
5363     FxPkgPdo* pThis;
5364     FxIrp irp(Irp);
5365     KIRQL irql;
5366 
5367     //
5368     // Release the IO cancel spinlock because we use our own
5369     //
5370     Mx::ReleaseCancelSpinLock(irp.GetCancelIrql());
5371 
5372     pDevice = FxDevice::GetFxDevice(DeviceObject);
5373     pThis = pDevice->GetPdoPkg();
5374 
5375     ASSERT(pThis->m_SharedPower.m_WaitWakeOwner);
5376 
5377     //
5378     // Clear out the IRQL and set our state to disarming
5379     //
5380     pThis->m_PowerMachine.m_WaitWakeLock.Acquire(&irql);
5381 
5382     ASSERT(pThis->m_SharedPower.m_WaitWakeIrp == Irp &&
5383               pThis->m_SharedPower.m_WaitWakeIrp != NULL);
5384 
5385     InsertTailList(&pThis->m_PowerMachine.m_WaitWakeIrpToBeProcessedList,
5386                    irp.ListEntry());
5387 
5388     //
5389     // Set the status for the irp when it is completed later
5390     //
5391     irp.SetStatus(STATUS_CANCELLED);
5392 
5393     pThis->m_SharedPower.m_WaitWakeIrp = NULL;
5394 
5395     pThis->m_PowerMachine.m_WaitWakeLock.Release(irql);
5396 
5397     pThis->PowerProcessEvent(PowerWakeCanceled);
5398 }
5399