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