ReactOS 0.4.15-dev-8102-g108db8f
powerstatemachine.cpp
Go to the documentation of this file.
1/*++
2Copyright (c) Microsoft. All rights reserved.
3
4Module Name:
5
6 PowerStateMachine.cpp
7
8Abstract:
9
10 This module implements the Power state machine for the driver framework.
11 This code was split out from FxPkgPnp.cpp.
12
13Author:
14
15
16
17
18Environment:
19
20 Both kernel and user mode
21
22Revision History:
23
24
25
26--*/
27
28#include "pnppriv.hpp"
29
30extern "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
73{
77};
78
80{
84};
85
87{
92};
93
95{
100};
101
103{
110};
111
113{
120};
121
123{
126};
127
129{
132};
133
135{
141};
142
144{
150};
151
153{
157};
158
160{
164};
165
167{
170};
171
173{
176};
177
179{
180 // WdfDevStatePowerObjectCreated
181 { NULL,
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
198 NULL,
199 { FALSE,
200 0 },
201 },
202
203 // WdfDevStatePowerCheckDeviceTypeNP
206 NULL,
207 { FALSE,
208 0 },
209 },
210
211 // WdfDevStatePowerCheckParentState
214 NULL,
215 { FALSE,
216 0 },
217 },
218
219 // WdfDevStatePowerCheckParentStateNP
222 NULL,
223 { FALSE,
224 0 },
225 },
226
227 // WdfDevStatePowerEnablingWakeAtBus
230 NULL,
231 { FALSE,
232 0 },
233 },
234
235 // WdfDevStatePowerEnablingWakeAtBusNP
238 NULL,
239 { FALSE,
240 0 },
241 },
242
243 // WdfDevStatePowerD0
247 { TRUE,
249 PowerD0 // A non WDF power policy owner might send a D0 irp
250 // while we are in D0
251 },
252 },
253
254 // WdfDevStatePowerD0NP
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
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
277 PowerD0 // A non WDF power policy owner might send a D0 irp
278 // while we are in D0
279 },
280 },
281
282 // WdfDevStatePowerD0BusWakeOwnerNP
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
293 PowerD0 // A non WDF power policy owner might send a D0 irp
294 // while we are in D0
295 },
296 },
297
298 // WdfDevStatePowerD0ArmedForWake
302 { TRUE,
304 PowerWakeArrival | // PowerIsWakeRequestPresent() returned true in
305 // WdfDevStatePowerD0BusWakeOwner and raced with
306 // this event being processed
308 PowerD0 // A non WDF power policy owner might send a D0 irp
309 // while we are in D0
310 },
311 },
312
313 // WdfDevStatePowerD0ArmedForWakeNP
317 { TRUE,
319 PowerWakeArrival | // PowerIsWakeRequestPresent() returned true in
320 // WdfDevStatePowerD0BusWakeOwnerNP and raced with
321 // this event being processed
323 PowerD0 // A non WDF power policy owner might send a D0 irp
324 // while we are in D0
325 },
326 },
327
328 // WdfDevStatePowerD0DisarmingWakeAtBus
331 NULL,
332 { FALSE,
333 0 },
334 },
335
336 // WdfDevStatePowerD0DisarmingWakeAtBusNP
339 NULL,
340 { FALSE,
341 0 },
342 },
343
344 // WdfDevStatePowerD0Starting
347 NULL,
348 { FALSE,
349 0 },
350 },
351
352 // WdfDevStatePowerD0StartingConnectInterrupt
355 NULL,
356 { FALSE,
357 0 },
358 },
359
360 // WdfDevStatePowerD0StartingDmaEnable
363 NULL,
364 { FALSE,
365 0 },
366 },
367
368 // WdfDevStatePowerD0StartingStartSelfManagedIo
371 NULL,
372 { FALSE,
373 0 },
374 },
375
376 // WdfDevStatePowerDecideD0State
379 NULL,
380 { FALSE,
381 0 },
382 },
383
384 // WdfDevStatePowerGotoD3Stopped
387 NULL,
388 { FALSE,
389 0 },
390 },
391
392 // WdfDevStatePowerStopped
393 { NULL,
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)
403 },
404
405 // WdfDevStatePowerStartingCheckDeviceType
408 NULL,
409 { FALSE,
410 0 },
411 },
412
413 // WdfDevStatePowerStartingChild
416 NULL,
417 { TRUE,
418 0 },
419 },
420
421 // WdfDevStatePowerDxDisablingWakeAtBus
424 NULL,
425 { FALSE,
426 0 },
427 },
428
429 // WdfDevStatePowerDxDisablingWakeAtBusNP
432 NULL,
433 { FALSE,
434 0 },
435 },
436
437 // WdfDevStatePowerGotoDx
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
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
468 NULL,
469 { FALSE,
470 0 },
471 },
472
473 // WdfDevStatePowerGotoDxIoStoppedNP
476 NULL,
477 { FALSE,
478 0 },
479 },
480
481 // WdfDevStatePowerGotoDxNPFailed
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,
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
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,
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
556 NULL,
557 { FALSE,
558 0 },
559 },
560
561 // WdfDevStatePowerGotoDxArmedForWakeNP
564 NULL,
565 { FALSE,
566 0 },
567 },
568
569 // WdfDevStatePowerGotoDxIoStoppedArmedForWake
572 NULL,
573 { FALSE,
574 0 },
575 },
576
577 // WdfDevStatePowerGotoDxIoStoppedArmedForWakeNP
580 NULL,
581 { FALSE,
582 0 },
583 },
584
585 // WdfDevStatePowerDxArmedForWake
586 { NULL,
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,
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
608 NULL,
609 { FALSE,
610 0 },
611 },
612
613 // WdfDevStatePowerCheckParentStateArmedForWakeNP
616 NULL,
617 { FALSE,
618 0 },
619 },
620
621 // WdfDevStatePowerWaitForParentArmedForWake
622 { NULL,
624 NULL,
625 { FALSE,
626 0 },
627 },
628
629 // WdfDevStatePowerWaitForParentArmedForWakeNP
630 { NULL,
632 NULL,
633 { FALSE,
634 0 },
635 },
636
637 // WdfDevStatePowerStartSelfManagedIo
640 NULL,
641 { FALSE,
642 0 },
643 },
644
645 // WdfDevStatePowerStartSelfManagedIoNP
648 NULL,
649 { FALSE,
650 0 },
651 },
652
653 // WdfDevStatePowerStartSelfManagedIoFailed
656 NULL,
657 { FALSE,
658 0 },
659 },
660
661 // WdfDevStatePowerStartSelfManagedIoFailedNP
664 NULL,
665 { FALSE,
666 0 },
667 },
668
669 // WdfDevStatePowerWaitForParent
670 { NULL,
672 NULL,
673 { FALSE,
674 0 },
675 },
676
677 // WdfDevStatePowerWaitForParentNP
678 { NULL,
680 NULL,
681 { FALSE,
682 0 },
683 },
684
685 // WdfDevStatePowerWakePending
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
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
708 NULL,
709 { FALSE,
710 0 },
711 },
712
713 // WdfDevStatePowerWakingNP
716 NULL,
717 { FALSE,
718 0 },
719 },
720
721 // WdfDevStatePowerWakingConnectInterrupt
724 NULL,
725 { FALSE,
726 0 },
727 },
728
729 // WdfDevStatePowerWakingConnectInterruptNP
732 NULL,
733 { FALSE,
734 0 },
735 },
736
737 // WdfDevStatePowerWakingConnectInterruptFailed
740 NULL,
741 { FALSE,
742 0 },
743 },
744
745 // WdfDevStatePowerWakingConnectInterruptFailedNP
748 NULL,
749 { FALSE,
750 0 },
751 },
752
753 // WdfDevStatePowerWakingDmaEnable
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
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
776 NULL,
777 { FALSE,
778 0 },
779 },
780
781 // WdfDevStatePowerWakingDmaEnableFailedNP
784 NULL,
785 { FALSE,
786 0 },
787 },
788
789 // WdfDevStatePowerReportPowerUpFailedDerefParent
792 NULL,
793 { FALSE,
794 0
795 },
796 },
797
798 // WdfDevStatePowerReportPowerUpFailed
801 NULL,
802 { TRUE,
803 0
804 },
805 },
806
807 // WdfDevStatePowerPowerFailedPowerDown
810 NULL,
811 { FALSE,
812 0 },
813 },
814
815 // WdfDevStatePowerReportPowerDownFailed
818 NULL,
819 { TRUE,
820 0 },
821 },
822
823 // WdfDevStatePowerInitialConnectInterruptFailed
826 NULL,
827 { FALSE,
828 0 },
829 },
830
831 // WdfDevStatePowerInitialDmaEnableFailed
834 NULL,
835 { FALSE,
836 0 },
837 },
838
839 // WdfDevStatePowerInitialSelfManagedIoFailed
842 NULL,
843 { FALSE,
844 0 },
845 },
846
847 // WdfDevStatePowerInitialPowerUpFailedDerefParent
850 NULL,
851 { FALSE,
852 0 },
853 },
854
855 // WdfDevStatePowerInitialPowerUpFailed
858 NULL,
859 { FALSE,
860 0 },
861 },
862
863 // WdfDevStatePowerDxStoppedDisarmWake
866 NULL,
867 { FALSE,
868 0 },
869 },
870
871 // WdfDevStatePowerDxStoppedDisarmWakeNP
874 NULL,
875 { FALSE,
876 0 },
877 },
878
879 // WdfDevStatePowerGotoDxStoppedDisableInterruptNP
882 NULL,
883 { FALSE,
884 0 },
885 },
886
887 // WdfDevStatePowerGotoDxStopped
890 NULL,
891 { FALSE,
892 0 },
893 },
894
895 // WdfDevStatePowerDxStopped
896 { NULL,
899 { TRUE,
900 0 },
901 },
902
903 // WdfDevStatePowerGotoStopped
906 NULL,
907 { FALSE,
908 0 },
909 },
910
911 // WdfDevStatePowerStoppedCompleteDx
914 NULL,
915 { FALSE,
916 0 },
917 },
918
919 // WdfDevStatePowerDxStoppedDecideDxState
922 NULL,
923 { FALSE,
924 0 },
925 },
926
927 // WdfDevStatePowerDxStoppedArmForWake
930 NULL,
931 { FALSE,
932 0 },
933 },
934
935 // WdfDevStatePowerDxStoppedArmForWakeNP
938 NULL,
939 { FALSE,
940 0 },
941 },
942
943 // WdfDevStatePowerFinalPowerDownFailed
946 NULL,
947 { FALSE,
948 0 },
949 },
950
951 // WdfDevStatePowerFinal
952 { NULL,
954 NULL,
955 { FALSE,
956 0 },
957 },
958
959 // WdfDevStatePowerGotoImplicitD3DisarmWakeAtBus
962 NULL,
963 { FALSE,
964 0 },
965 },
966
967 // WdfDevStatePowerUpFailed
970 NULL,
971 { FALSE,
972 0 },
973 },
974
975 // WdfDevStatePowerUpFailedDerefParent
978 NULL,
979 { FALSE,
980 0 },
981 },
982
983 // WdfDevStatePowerGotoDxFailed
986 NULL,
987 { FALSE,
988 0 },
989 },
990
991 // WdfDevStatePowerGotoDxStoppedDisableInterrupt
994 NULL,
995 { FALSE,
996 0 },
997 },
998
999 // WdfDevStatePowerUpFailedNP
1002 NULL,
1003 { FALSE,
1004 0 },
1005 },
1006
1007 // WdfDevStatePowerUpFailedDerefParentNP
1010 NULL,
1011 { FALSE,
1012 0 },
1013 },
1014
1015 // WdfDevStatePowerNotifyingD0ExitToWakeInterrupts
1018 NULL,
1019 { FALSE,
1020 0 },
1021 },
1022
1023 // WdfDevStatePowerNotifyingD0EntryToWakeInterrupts
1026 NULL,
1027 { FALSE,
1028 0 },
1029 },
1030 // WdfDevStatePowerNotifyingD0ExitToWakeInterruptsNP
1033 NULL,
1034 { FALSE,
1035 0 },
1036 },
1037
1038 // WdfDevStatePowerNotifyingD0EntryToWakeInterrupts
1041 NULL,
1042 { FALSE,
1043 0 },
1044 },
1045
1046 // WdfDevStatePowerNull
1047 // *** no entry for this state ***
1048};
1049
1050// @@SMVERIFY_SPLIT_END
1051
1055 __inout FxPkgPnp* Pnp,
1057 )
1058{
1060
1062 if (!NT_SUCCESS(status)) {
1063 return status;
1064 }
1065
1066 return STATUS_SUCCESS;
1067}
1068
1069VOID
1071 VOID
1072 )
1073/*++
1074
1075Routine 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
1082Arguments:
1083 None
1084
1085Return Value:
1086 None
1087
1088 --*/
1089{
1090 WDFCASSERT(sizeof(FxPowerStateInfo) == sizeof(ULONG));
1091
1092 WDFCASSERT((sizeof(m_WdfPowerStates)/sizeof(m_WdfPowerStates[0]))
1093 ==
1095
1096 // we assume these are the same length when we update the history index
1098 sizeof(m_PowerMachine.m_Queue.Events[0]))
1099 ==
1101 sizeof(m_PowerMachine.m_States.History[0])));
1102}
1103
1104
1105/*++
1106
1107The locking model for the Power state machine requires that events be enqueued
1108possibly at DISPATCH_LEVEL. It also requires that the state machine be
1109runnable at PASSIVE_LEVEL. Consequently, we have two locks, one DISPATCH_LEVEL
1110lock that guards the event queue and one PASSIVE_LEVEL lock that guards the
1111state machine itself.
1112
1113The Power state machine has a few constraints that the PnP state machine
1114doesn't. Sometimes it has to call some driver functions at PASSIVE_LEVEL, but
1115with the disks turned off. This means that these functions absolutely must not
1116page fault. You might think that this means that we should call the driver at
1117DISPATCH_LEVEL, and you'd be right if your only concern were for perfectly
1118safe code. The problem with that approach, though is that it will force much
1119of the rest of the driver to DISPATCH_LEVEL, which will only push the driver
1120writer into using lots of asynchronous work items, which will complicate their
1121code and make it unsafe in a new variety of ways. So we're going to go with
1122PASSIVE_LEVEL here and setting a timeout of 20 seconds. If the driver faults,
1123the timer will fire and log the failure. This also means that the driver must
1124complete these callbacks within 20 seconds. Even beyond that, it means that
1125the work items must be queued onto a special thread, one that once the machine
1126has started to go to sleep, never handles any work items that may fault.
1127
1128Algorithm:
1129
11301) Acquire the Power queue lock.
11312) Enqueue the request. Requests are put at the end of the queue.
11323) Drop the Power queue lock.
11334) If the thread is running at PASSIVE_LEVEL, skip to step 6.
11345) Queue a work item onto the special power thread.
11356) Attempt to acquire the state machine lock, with a near-zero-length timeout.
11367) If successful, skip to step 9.
11378) Queue a work item onto the special power thread.
11389) Acquire the state machine lock.
113910) Acquire the Power queue lock.
114011) Attempt to dequeue an event.
114112) Drop the Power queue lock.
114213) If there was no event to dequeue, drop the state machine lock and exit.
114314) Execute the state handler. This may involve taking one of the other state
1144 machine queue locks, briefly, to deliver an event.
114515) Go to Step 10.
1146
1147Implementing this algorithm requires three functions.
1148
1149PowerProcessEvent -- Implements steps 1-8.
1150_PowerProcessEventInner -- Implements step 9.
1151PowerProcessEventInner -- Implements steps 10-15.
1152
1153--*/
1154
1155VOID
1158 __in BOOLEAN ProcessOnDifferentThread
1159 )
1160/*++
1161
1162Routine Description:
1163 This function implements steps 1-8 of the algorithm described above.
1164
1165Arguments:
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
1171Return Value:
1172
1173 NTSTATUS
1174
1175--*/
1176{
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 //
1193 }
1194 else {
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(),
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
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(),
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 //
1242 //
1243 // Stick it on the front of the queue, making it the next
1244 // event that will be processed.
1245 //
1247 }
1248 else {
1249 //
1250 // Stick it on the end of the queue.
1251 //
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
1271
1272 if (FxWaitLockInternal::IsLockAcquired(status)) {
1274
1275 //
1276 // We now hold the state machine lock. So call the function that
1277 // dispatches the next state.
1278 //
1280
1281 //
1282 // The pnp state machine should be the only one deleting the object
1283 //
1284 ASSERT(info.m_DeleteObject == FALSE);
1285
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 //
1306}
1307
1308VOID
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
1344VOID
1347 )
1348/*++
1349
1350Routine 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;
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()) {
1377
1378 //
1379 // The queue is empty.
1380 //
1381 m_PowerMachine.Unlock(oldIrql);
1382 return;
1383 }
1384
1386
1387 //
1388 // At this point, we need to determine whether we can process this
1389 // event.
1390 //
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 //
1417 }
1418
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) {
1447 "WDFDEVICE 0x%p !devobj 0x%p current power state "
1448 "%!WDF_DEVICE_POWER_STATE! dropping event %!FxPowerEvent!",
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
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(),
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 //
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 //
1498 break;
1499 }
1500 }
1501 else {
1502 //
1503 // Now enter the new state.
1504 //
1505 PowerEnterNewState(newState);
1506 }
1507 }
1508}
1509
1510VOID
1513 )
1514/*++
1515
1516Routine Description:
1517 This function looks up the handler for a state and
1518 then calls it.
1519
1520Arguments:
1521 Event - Current PnP event
1522
1523Return Value:
1524
1525 NTSTATUS
1526
1527--*/
1528{
1530 WDF_DEVICE_POWER_STATE currentState, newState;
1532 FxWatchdog watchdog(this);
1533
1534 currentState = m_Device->GetDevicePowerState();
1535 newState = State;
1536
1537 while (newState != WdfDevStatePowerNull) {
1540 "WDFDEVICE 0x%p !devobj 0x%p entering Power State "
1541 "%!WDF_DEVICE_POWER_STATE! from %!WDF_DEVICE_POWER_STATE!",
1544 newState, currentState);
1545
1546 if (m_PowerStateCallbacks != NULL) {
1547 //
1548 // Callback for leaving the old state
1549 //
1550 RtlZeroMemory(&data, sizeof(data));
1551
1553 data.Data.LeaveState.CurrentState = currentState;
1554 data.Data.LeaveState.NewState = newState;
1555
1556 m_PowerStateCallbacks->Invoke(currentState,
1559 &data);
1560 }
1561
1563 (USHORT) newState;
1564
1565 if (m_PowerStateCallbacks != NULL) {
1566 //
1567 // Callback for entering the new state
1568 //
1569 RtlZeroMemory(&data, sizeof(data));
1570
1572 data.Data.EnterState.CurrentState = currentState;
1573 data.Data.EnterState.NewState = newState;
1574
1575 m_PowerStateCallbacks->Invoke(newState,
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
1611 data.Data.PostProcessState.CurrentState = currentState;
1612
1613 m_PowerStateCallbacks->Invoke(currentState,
1616 &data);
1617 }
1618 }
1619}
1620
1624 )
1625/*++
1626
1627Routine 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
1631Arguments:
1632 none
1633
1634Return Value:
1635
1636 new power state
1637
1638--*/
1639{
1641 BOOLEAN parentOn;
1642
1643 status = This->PowerCheckParentOverload(&parentOn);
1644
1645 if (!NT_SUCCESS(status)) {
1647 }
1648 else if (parentOn) {
1650 }
1651 else {
1653 }
1654}
1655
1659 )
1660/*++
1661
1662Routine Description:
1663 This function implements the Check Parent (NP) state. Its only task
1664 is to dispatch to the FDO and PDO logic.
1665
1666Arguments:
1667 none
1668
1669Return Value:
1670
1671 new power state
1672
1673--*/
1674{
1676 BOOLEAN parentOn;
1677
1678 status = This->PowerCheckParentOverload(&parentOn);
1679
1680 if (!NT_SUCCESS(status)) {
1682 }
1683 else if (parentOn) {
1685 }
1686 else {
1688 }
1689}
1690
1694 )
1695/*++
1696
1697Routine Description:
1698 This function implements the Check Type state. Its only task
1699 is to dispatch to the FDO and PDO logic.
1700
1701Arguments:
1702 none
1703
1704Return Value:
1705
1706 new power state
1707
1708--*/
1709{
1710 return This->PowerCheckDeviceTypeOverload();
1711}
1712
1716 )
1717/*++
1718
1719Routine Description:
1720 This function implements the Check Type (NP) state. Its only task
1721 is to dispatch to the FDO and PDO logic.
1722
1723Arguments:
1724 none
1725
1726Return Value:
1727
1728 new power state
1729
1730--*/
1731{
1732 return This->PowerCheckDeviceTypeNPOverload();
1733}
1734
1738 )
1739/*++
1740
1741Routine Description:
1742 This function requests the driver to arm the device in a bus generic fashion.
1743
1744Arguments:
1745 The package which contains this instance of the state machine
1746
1747Return Value:
1748 new power state
1749
1750 --*/
1751{
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
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 //
1771 }
1772 else {
1773 This->PowerCompleteWakeRequestFromWithinMachine(status);
1774
1776 }
1777}
1778
1782 )
1783/*++
1784
1785Routine Description:
1786 This function requests the driver to arm the device in a bus generic fashion.
1787
1788Arguments:
1789 The package which contains this instance of the state machine
1790
1791Return Value:
1792 new power state
1793
1794 --*/
1795{
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
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 //
1816 }
1817 else {
1818 //
1819 // Complete the irp with the error that callback indicated
1820 //
1821 COVERAGE_TRAP();
1822
1823 This->PowerCompleteWakeRequestFromWithinMachine(status);
1824
1826 }
1827}
1828
1832 )
1833/*++
1834
1835Routine Description:
1836 D0 state where we cannot wake the machine
1837
1838Arguments:
1839 This - Instance of this state machine
1840
1841Return 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
1853 }
1854
1855 return WdfDevStatePowerNull;
1856}
1857
1861 )
1862/*++
1863
1864Routine Description:
1865 D0 state where we can't cause paging IO and we cannot wake the machine
1866
1867Arguments:
1868 This - Instance of this state machine
1869
1870Return 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();
1881 }
1882
1883 return WdfDevStatePowerNull;
1884}
1885
1886
1890 )
1891/*++
1892
1893Routine 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
1898Arguments:
1899 none
1900
1901Return 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
1914 }
1915 else if (This->PowerIsWakeRequestPresent()) {
1917 }
1918 else {
1919 return WdfDevStatePowerNull;
1920 }
1921}
1922
1926 )
1927/*++
1928
1929Routine 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
1934Arguments:
1935 none
1936
1937Return 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
1950 }
1951 else if (This->PowerIsWakeRequestPresent()) {
1953 }
1954 else {
1955 return WdfDevStatePowerNull;
1956 }
1957}
1958
1962 )
1963/*++
1964
1965Routine 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
1970Arguments:
1971 This - instance of the state machine
1972
1973Return 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
1985 }
1986
1987 return WdfDevStatePowerNull;
1988}
1989
1993 )
1994/*++
1995
1996Routine 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
2001Arguments:
2002 This - instance of the state machine
2003
2004Return 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
2016 }
2017
2018 return WdfDevStatePowerNull;
2019}
2020
2024 )
2025/*++
2026
2027Routine 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
2031Arguments:
2032 This - instance of the state machine
2033
2034Return 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
2054}
2055
2059 )
2060/*++
2061
2062Routine 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
2066Arguments:
2067 This - This instance of the state machine
2068
2069Return 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 //
2091}
2092
2096 )
2097/*++
2098
2099Routine 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
2103Arguments:
2104 This - This instance of the state machine
2105
2106Return 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 //
2127}
2128
2132 )
2133/*++
2134
2135Routine Description:
2136 This function calls D0Entry and the moves to the next state based on the
2137 result.
2138
2139Arguments:
2140 This - instance of the state machine
2141
2142Return Value:
2143 new power state
2144
2145--*/
2146{
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)) {
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
2170 }
2171
2173}
2174
2178 )
2179/*++
2180
2181Routine 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
2186Arguments:
2187 This - instance of the state machine
2188
2189Return Value:
2190 new state machine state
2191
2192 --*/
2193{
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 //
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
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);
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 //
2229}
2230
2234 )
2235/*++
2236
2237Routine Description:
2238 The device is movig to D0 for the first time. Enable any DMA enablers
2239 attached to the device.
2240
2241Arguments:
2242 This - instance of the state machine
2243
2244Return Value:
2245 new machine state
2246
2247 --*/
2248{
2249 if (This->PowerDmaEnableAndScan(TRUE) == FALSE) {
2251 }
2252
2254}
2255
2259 )
2260/*++
2261
2262Routine 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
2266Arguments:
2267 This - instance of the state machine
2268
2269Return 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) {
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
2298}
2299
2303 )
2304/*++
2305
2306Routine 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
2310Arguments:
2311 This - instance of the state machine
2312
2313Return 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) {
2324 }
2325 else {
2326 return WdfDevStatePowerD0;
2327 }
2328 }
2329 else {
2330 //
2331 // Non-pageable.
2332 //
2333 if (This->m_SharedPower.m_WaitWakeOwner) {
2335 }
2336 else {
2337 return WdfDevStatePowerD0NP;
2338 }
2339 }
2340}
2341
2345 )
2346/*++
2347
2348Routine Description:
2349 This function implements the D3 Stopped state.
2350
2351Arguments:
2352 none
2353
2354Return Value:
2355
2356 new power state
2357
2358--*/
2359{
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)) {
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(),
2411 );
2412
2413 if (!NT_SUCCESS(status)) {
2414 failed = TRUE;
2415
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(),
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(),
2442 if (!NT_SUCCESS(status)) {
2443 failed = TRUE;
2444
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(),
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) {
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
2475}
2476
2480 )
2481/*++
2482
2483Routine 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
2488Arguments:
2489 This - instance of the state machine
2490
2491Return Value:
2492 WdfDevStatePowerStartingChild or WdfDevStatePowerD0Starting
2493
2494 --*/
2495{
2496 if (This->m_Device->IsPdo()) {
2498 }
2499 else {
2501 }
2502}
2503
2507 )
2508/*++
2509
2510Routine Description:
2511 Get the parent into a D0 state
2512
2513Arguments:
2514 This - instance of the state machine
2515
2516Return Value:
2517 WdfDevStatePowerNull or WdfDevStatePowerD0Starting
2518
2519 --*/
2520{
2522 BOOLEAN parentOn;
2523
2524 status = This->PowerCheckParentOverload(&parentOn);
2525
2526 if (!NT_SUCCESS(status)) {
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
2535 }
2536 else if (parentOn) {
2537 //
2538 // Parent is powered on, start the power up sequence
2539 //
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
2554 )
2555/*++
2556
2557Routine Description:
2558 This function implements the Disable Wake at Bus state.
2559
2560Arguments:
2561 This - instance of the state machine
2562
2563Return 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
2577}
2578
2582 )
2583/*++
2584
2585Routine Description:
2586 This function implements the Disable Wake at Bus state.
2587
2588Arguments:
2589 This - instance of the state machine
2590
2591Return 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
2605}
2606
2610 )
2611/*++
2612
2613Routine Description:
2614 State where we go into Dx in the pageable path.
2615
2616Arguments:
2617 The instance of this state machine
2618
2619Return Value:
2620 new power state
2621
2622 --*/
2623{
2624 This->PowerGotoDx();
2625
2626 return WdfDevStatePowerNull;
2627}
2628
2632 )
2633/*++
2634
2635Routine Description:
2636 State where we go into Dx in the NP path.
2637
2638Arguments:
2639 The instance of this state machine
2640
2641Return Value:
2642 new power state
2643
2644 --*/
2645{
2646 This->PowerGotoDx();
2647
2648 return WdfDevStatePowerNull;
2649}
2650
2654 )
2655{
2656 if (This->PowerGotoDxIoStopped() == FALSE) {
2658 }
2659
2660 return WdfDevStatePowerDx;
2661}
2662
2666 )
2667{
2668 if (This->PowerGotoDxIoStoppedNP() == FALSE) {
2670 }
2671
2672 return WdfDevStatePowerDxNP;
2673}
2674
2678 )
2679/*++
2680
2681Routine Description:
2682 Going to Dx in the NP path failed. Disconnect all the interrupts.
2683
2684Arguments:
2685 This - instance of the state machine
2686
2687Return Value:
2688 WdfDevStatePowerReportPowerDownFailed
2689
2690 --*/
2691{
2692 This->DisconnectInterruptNP();
2693
2695}
2696
2697VOID
2699 VOID
2700 )
2701/*++
2702
2703Routine Description:
2704 Implements the going into Dx logic for the pageable path.
2705
2706Arguments:
2707 None
2708
2709Return Value:
2710 None
2711
2712 --*/
2713{
2716
2717 //
2718 // Tell the driver to stop its self-managed I/O
2719 //
2721
2722 if (!NT_SUCCESS(status)) {
2725 "EvtDeviceSelfManagedIoStop failed %!STATUS!", status);
2726
2728 }
2729 }
2730
2731
2732
2733
2734
2735 // Top-edge queue hold
2737
2739}
2740
2741BOOLEAN
2743 VOID
2744 )
2745/*++
2746
2747Routine Description:
2748 Implements the going into Dx logic for the pageable path.
2749
2750
2751
2752Arguments:
2753 None
2754
2755Return Value:
2756 TRUE if the power down succeeded, FALSE otherwise
2757
2758 --*/
2759{
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 //
2772
2778 break;
2779
2780 default:
2782 break;
2783 }
2784
2785 //
2786 // Can we even be a power pageable device and be in hibernation path?
2787 //
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 //
2797 }
2798
2799 if (PowerDmaPowerDown() == FALSE) {
2800 failed = TRUE;
2801 }
2802
2805 state
2806 );
2807
2808 if (!NT_SUCCESS(status)) {
2809 failed = TRUE;
2810
2813 "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p, "
2814 "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!",
2817 }
2818
2819 //
2820 // interrupt disable & disconnect
2821 //
2822
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 //
2849 notifyFlags |= NotifyResourcesArmedForWake;
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
2867
2868 if (!NT_SUCCESS(status)) {
2871 "EvtDeviceD0Exit WDFEVICE 0x%p !devobj 0x%p, new state "
2872 "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!",
2875
2876 failed = TRUE;
2877 }
2878
2879 //
2880 // If this is a child, release the power reference on the parent
2881 //
2883
2884 //
2885 // Set our state no matter if power down failed or not
2886 //
2888
2889 //
2890 // Stopping self managed io previously failed, convert that failure into
2891 // a local failure here.
2892 //
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 //
2904
2905 //
2906 // This state will record that we encountered an internal error.
2907 //
2908 return FALSE;
2909 }
2910
2912
2914
2915 return TRUE;
2916}
2917
2918BOOLEAN
2920 VOID
2921 )
2922/*++
2923
2924Routine Description:
2925 This function implements going into the Dx state in the NP path.
2926
2927Arguments:
2928 None
2929
2930Return Value:
2931 TRUE if the power down succeeded, FALSE otherwise
2932
2933 --*/
2934{
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 //
2946
2952 break;
2953
2954 default:
2956 break;
2957 }
2958
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 //
2966 }
2967
2968 if (PowerDmaPowerDown() == FALSE) {
2969 failed = TRUE;
2970 }
2971
2974 state
2975 );
2976
2977 if (!NT_SUCCESS(status)) {
2978 failed = TRUE;
2979
2982 "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p, "
2983 "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!",
2986 }
2987
2988 //
2989 // Interrupt disable (and NO disconnect)
2990 //
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
3006
3007 if (!NT_SUCCESS(status)) {
3010 "EvtDeviceD0Exit WDFDEVICE 0x%p !devobj 0x%p, new state "
3011 "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!",
3014
3015 failed = TRUE;
3016 }
3017
3018 //
3019 // If this is a child, release the power reference on the parent
3020 //
3022
3023 //
3024 // Set our state no matter if power down failed or not
3025 //
3027
3028 //
3029 // Stopping self managed io previously failed, convert that failure into
3030 // a local failure here.
3031 //
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 //
3043
3044 //
3045 // This state will record that we encountered an internal error.
3046 //
3047 return FALSE;
3048 }
3049
3051
3053
3054 return TRUE;
3055}
3056
3060 )
3061/*++
3062
3063Routine Description:
3064 This function implements the Dx state when we are armed for wake.
3065
3066Arguments:
3067 This - The instance of the state machine
3068
3069Return Value:
3070
3071 new power state
3072
3073--*/
3074{
3075 This->PowerGotoDx();
3076
3077 return WdfDevStatePowerNull;
3078}
3079
3083 )
3084/*++
3085
3086Routine Description:
3087 This function implements the Dx state when we are armed for wake in the NP
3088 path.
3089
3090Arguments:
3091 This - The instance of the state machine
3092
3093Return Value:
3094
3095 new power state
3096
3097--*/
3098{
3099 This->PowerGotoDx();
3100
3101 return WdfDevStatePowerNull;
3102}
3103
3107 )
3108{
3109 if (This->PowerGotoDxIoStopped() == FALSE) {
3111 }
3112
3114}
3115
3119 )
3120{
3121 if (This->PowerGotoDxIoStoppedNP() == FALSE) {
3123 }
3124
3126}
3127
3131 )
3132/*++
3133
3134Routine 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
3140Arguments:
3141 This - instance of the state machine
3142
3143Return Value:
3144 new state
3145
3146 --*/
3147
3148{
3150 BOOLEAN parentOn;
3151
3152 status = This->PowerCheckParentOverload(&parentOn);
3153
3154 if (!NT_SUCCESS(status)) {
3156 }
3157 else if (parentOn) {
3159 }
3160 else {
3162 }
3163}
3164
3168 )
3169/*++
3170
3171Routine Description:
3172 Same as PowerCheckParentStateArmedForWake, but we are in the NP path
3173
3174Arguments:
3175 This - instance of the state machine
3176
3177Return Value:
3178 new state
3179
3180 --*/
3181{
3183 BOOLEAN parentOn;
3184
3185 status = This->PowerCheckParentOverload(&parentOn);
3186
3187 if (!NT_SUCCESS(status)) {
3189 }
3190 else if (parentOn) {
3192 }
3193 else {
3195 }
3196}
3197
3201 )
3202/*++
3203
3204Routine 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
3209Arguments:
3210 This - The instance of the state machine
3211
3212Return 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) {
3228
3229 status = This->m_SelfManagedIoMachine->Start();
3230
3231 if (!NT_SUCCESS(status)) {
3233 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
3234 "EvtDeviceSelfManagedIoRestart failed - %!STATUS!", status);
3235
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) {
3252 }
3253 else {
3254 return WdfDevStatePowerD0;
3255 }
3256}
3257
3261 )
3262/*++
3263
3264Routine 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
3269Arguments:
3270 This - The instance of the state machine
3271
3272Return 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) {
3288
3289 status = This->m_SelfManagedIoMachine->Start();
3290
3291 if (!NT_SUCCESS(status)) {
3293 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
3294 "EvtDeviceSelfManagedIoRestart failed - %!STATUS!", status);
3295
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) {
3311 }
3312 else {
3313 return WdfDevStatePowerD0NP;
3314 }
3315}
3316
3320 )
3321/*++
3322
3323Routine 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
3327Arguments:
3328 This - instance of the state machine
3329
3330Return Value:
3331 WdfDevStatePowerWakingDmaEnableFailed
3332
3333 --*/
3334{
3335
3336
3337
3338
3339 This->m_Device->m_PkgIo->StopProcessingForPower(FxIoStopProcessingForPowerHold);
3340
3342}
3343
3347 )
3348/*++
3349
3350Routine 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
3354Arguments:
3355 This - instance of the state machine
3356
3357Return Value:
3358 WdfDevStatePowerWakingDmaEnableFailedNP
3359
3360 --*/
3361{
3362
3363
3364
3365
3366 This->m_Device->m_PkgIo->StopProcessingForPower(FxIoStopProcessingForPowerHold);
3367
3369}
3370
3371
3375 )
3376/*++
3377
3378Routine 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
3384Arguments:
3385 This - The instance of the state machine
3386
3387Return Value:
3388 return WdfDevStatePowerNull
3389
3390 --*/
3391{
3392 This->PowerCompletePendedWakeIrp();
3393 return WdfDevStatePowerNull;
3394}
3395
3399 )
3400/*++
3401
3402Routine 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
3408Arguments:
3409 This - The instance of the state machine
3410
3411Return Value:
3412 return WdfDevStatePowerNull
3413
3414 --*/
3415{
3416 This->PowerCompletePendedWakeIrp();
3417 return WdfDevStatePowerNull;
3418}
3419
3423 )
3424/*++
3425
3426Routine 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
3431Arguments:
3432 This - The instance of the state machine
3433
3434Return Value:
3435
3436 new power state
3437
3438--*/
3439{
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)) {
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
3460 }
3461
3463}
3464
3465
3469 )
3470/*++
3471
3472Routine 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
3476Arguments:
3477 This - The instance of the state machine
3478
3479Return Value:
3480
3481 new power state
3482
3483--*/
3484{
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)) {
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
3505 }
3506
3508}
3509
3513 )
3514/*++
3515
3516Routine 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
3521Arguments:
3522 This - instance of the state machine
3523
3524Return Value:
3525 new state
3526
3527 --*/
3528{
3530
3531 //
3532 // interrupt connect and enable
3533 //
3534 status = This->NotifyResourceObjectsD0(NotifyResourcesExplicitPowerup);
3535
3536 if (!NT_SUCCESS(status)) {
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)) {
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);
3553 }
3554
3556}
3557
3561 )
3562/*++
3563
3564Routine 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
3569Arguments:
3570 This - instance of the state machine
3571
3572Return Value:
3573 new state
3574
3575 --*/
3576{
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)) {
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)) {
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);
3602 }
3603
3605}
3606
3610 )
3611/*++
3612
3613Routine Description:
3614 Connecting or enabling the interrupts failed. Disable and disconnect any
3615 interrupts which have been connected and maybe enabled.
3616
3617Arguments:
3618 This - instance of the state machine
3619
3620Return Value:
3621 WdfDevStatePowerReportPowerUpFailed
3622
3623 --*/
3624{
3625 This->PowerConnectInterruptFailed();
3626
3628}
3629
3633 )
3634/*++
3635
3636Routine Description:
3637 Enabling the interrupts failed. Disable and disconnect any
3638 interrupts which have been connected and maybe enabled.
3639
3640Arguments:
3641 This - instance of the state machine
3642
3643Return 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 //
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
3663}
3664
3665BOOLEAN
3667 __in BOOLEAN ImplicitPowerUp
3668 )
3669{
3671
3672 if (PowerDmaPowerUp() == FALSE) {
3673 return FALSE;
3674 }
3675
3676 if (m_EnumInfo != NULL) {
3677 //
3678 // Scan for children
3679 //
3681
3682 ple = NULL;
3684 ((FxChildList*) ple->GetTransactionedObject())->ScanForChildren();
3685 }
3686
3688 }
3689
3690 if (ImplicitPowerUp == FALSE) {
3692 }
3693
3694 return TRUE;
3695}
3696
3700 )
3701/*++
3702
3703Routine Description:
3704 The device is returning to D0 from Dx. Power up all DMA enablers and scan
3705 for children.
3706
3707Arguments:
3708 This - instance of the state machine
3709
3710Return Value:
3711 new machine state
3712
3713 --*/
3714{
3715 if (This->PowerDmaEnableAndScan(FALSE) == FALSE) {
3717 }
3718
3719 //
3720 // Return the state that we should drop into next.
3721 //
3722 return WdfDevStatePowerNull;
3723}
3724
3728 )
3729/*++
3730
3731Routine 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
3735Arguments:
3736 This - instance of the state machine
3737
3738Return Value:
3739 new machine state
3740
3741 --*/
3742{
3743 if (This->PowerDmaEnableAndScan(FALSE) == FALSE) {
3745 }
3746
3747 //
3748 // Return the state that we should drop into next.
3749 //
3750 return WdfDevStatePowerNull;
3751}
3752
3756 )
3757/*++
3758
3759Routine Description:
3760 Powering up a DMA enabler failed. Power down all DMA enablers and progress
3761 down the failed power up path.
3762
3763Arguments:
3764 This - instance of the state machine
3765
3766Return Value:
3767 WdfDevStatePowerWakingConnectInterruptFailed
3768
3769 --*/
3770{
3772
3773 (void) This->PowerDmaPowerDown();
3774
3775 status = This->m_DeviceD0ExitPreInterruptsDisabled.Invoke(
3776 This->m_Device->GetHandle(),
3778 );
3779
3780 if (!NT_SUCCESS(status)) {
3781 //
3782 // Report the error, but continue forward
3783 //
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(),
3791 }
3792
3794}
3795
3799 )
3800/*++
3801
3802Routine 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
3806Arguments:
3807 This - instance of the state machine
3808
3809Return Value:
3810 WdfDevStatePowerWakingConnectInterruptFailedNP
3811
3812 --*/
3813{
3815
3816 COVERAGE_TRAP();
3817
3818 (void) This->PowerDmaPowerDown();
3819
3820 status = This->m_DeviceD0ExitPreInterruptsDisabled.Invoke(
3821 This->m_Device->GetHandle(),
3823 );
3824
3825 if (!NT_SUCCESS(status)) {
3826 //
3827 // Report the error, but continue forward
3828 //
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(),
3836 }
3837
3839}
3840
3844 )
3845/*++
3846
3847Routine Description:
3848 Power up failed. Release the reference on the parent that was taken at the
3849 start of power up.
3850
3851Arguments:
3852 This - instance of the state machine.
3853
3854Return 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
3865}
3866
3870 )
3871/*++
3872
3873Routine Description:
3874 Posts PowerUpFailed event to the PnP state machine and then waits for death.
3875 The pended Power IRP is also completed.
3876
3877Arguments:
3878 This - The instance of the state machine
3879
3880Return 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
3896 )
3897/*++
3898
3899Routine 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
3904Arguments:
3905 This - instance of the state machine
3906
3907Return 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
3922}
3923
3927 )
3928/*++
3929
3930Routine Description:
3931 Posts PowerDownFailed event to the PnP state machine and then waits for death.
3932 The pended Power IRP is also completed.
3933
3934Arguments:
3935 This - The instance of the state machine
3936
3937Return Value:
3938 WdfDevStatePowerNull
3939
3940 --*/
3941{
3942
3943
3944
3945
3946 This->PowerReleasePendingDeviceIrp();
3947 This->PowerSendPowerDownFailureEvent(FxPowerDownTypeExplicit);
3948
3949 return WdfDevStatePowerNull;
3950}
3951
3955 )
3956/*++
3957
3958Routine 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
3963Arguments:
3964 This - instance of the state machine
3965
3966Return Value:
3967 WdfDevStatePowerInitialPowerUpFailedDerefParent
3968
3969 --*/
3970{
3971 This->PowerConnectInterruptFailed();
3972
3974}
3975
3976
3980 )
3981/*++
3982
3983Routine 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
3987Arguments:
3988 This - instance of the state machine
3989
3990Return Value:
3991 WdfDevStatePowerInitialConnectInterruptFailed
3992
3993 --*/
3994{
3996
3997 (void) This->PowerDmaPowerDown();
3998
3999 status = This->m_DeviceD0ExitPreInterruptsDisabled.Invoke(
4000 This->m_Device->GetHandle(),
4002 );
4003
4004 if (!NT_SUCCESS(status)) {
4005 //
4006 // Report the error, but continue forward
4007 //
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(),
4015 }
4016
4018}
4019
4023 )
4024/*++
4025
4026Routine 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
4031Arguments:
4032 This - instance of the state machine
4033
4034Return Value:
4035 WdfDevStatePowerInitialDmaEnableFailed
4036
4037 --*/
4038{
4039
4040
4041
4042
4043 This->m_Device->m_PkgIo->StopProcessingForPower(FxIoStopProcessingForPowerHold);
4044
4046}
4047
4051 )
4052/*++
4053
4054Routine Description:
4055 Dereferences the parent's power ref count we took during start up
4056
4057Arguments:
4058 This - The instance of the state machine
4059
4060Return 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
4072}
4073
4077 )
4078/*++
4079
4080Routine Description:
4081 Posts PowerUpFailed event to the PnP state machine and then waits for death.
4082
4083Arguments:
4084 This - The instance of the state machine
4085
4086Return Value:
4087 WdfDevStatePowerStopped
4088
4089 --*/
4090{
4091 This->PowerSendPowerUpFailureEvent();
4092
4094}
4095
4099 )
4100/*++
4101
4102Routine Description:
4103 Disarms the device from wake because the device is being stopped/removed
4104 while in Dx.
4105
4106Arguments:
4107 This - instance of the state machine
4108
4109Return 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
4123}
4124
4128 )
4129/*++
4130
4131Routine Description:
4132 Disarms the device from wake because the device is being stopped/removed
4133 while in Dx.
4134
4135Arguments:
4136 This - instance of the state machine
4137
4138Return 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
4152}
4153
4157 )
4158/*++
4159
4160Routine 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
4164Arguments:
4165 This - instance of the state machine
4166
4167Return Value:
4168 WdfDevStatePowerGotoDxStopped
4169
4170 --*/
4171{
4172 This->NotifyResourceObjectsDx(NotifyResourcesSurpriseRemoved);
4173
4175}
4176
4180 )
4181/*++
4182
4183Routine 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
4187Arguments:
4188 This - instance of the state machine
4189
4190Return Value:
4191 WdfDevStatePowerStopped
4192
4193 --*/
4194{
4195 This->PowerSendPowerDownEvents(FxPowerDownTypeImplicit);
4196
4198}
4199
4203 )
4204/*++
4205
4206Routine 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
4211Arguments:
4212 This - instance of the state machine
4213
4214Return 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();
4227}
4228
4232 )
4233/*++
4234
4235Routine 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
4240Arguments:
4241 This - instance of the state machine
4242
4243Return 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();
4256}
4257
4261 )
4262/*++
4263
4264Routine Description:
4265 We are implicitly powering up the stack while in the Dx state. Decide
4266 which Dx "holding" state to transition to.
4267
4268Arguments:
4269 This - instance of the state machine
4270
4271Return 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();
4296 }
4297 else {
4298 return WdfDevStatePowerDx;
4299 }
4300 }
4301 else {
4302 if (This->PowerIsWakeRequestPresent()) {
4303 COVERAGE_TRAP();
4305 }
4306 else {
4307 COVERAGE_TRAP();
4308 return WdfDevStatePowerDxNP;
4309 }
4310 }
4311}
4312
4316 )
4317/*++
4318
4319Routine 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
4325Arguments:
4326 This - instance of the state machine
4327
4328Return Value:
4329 new power state
4330
4331 --*/
4332{
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();
4353 }
4354 else {
4355 COVERAGE_TRAP();
4356 This->PowerCompleteWakeRequestFromWithinMachine(status);
4357 return WdfDevStatePowerDx;
4358 }
4359}
4360
4364 )
4365/*++
4366
4367Routine 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
4373Arguments:
4374 This - instance of the state machine
4375
4376Return Value:
4377 new power state
4378
4379 --*/
4380{
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();
4401 }
4402 else {
4403 COVERAGE_TRAP();
4404 This->PowerCompleteWakeRequestFromWithinMachine(status);
4405 return WdfDevStatePowerDxNP;
4406 }
4407}
4408
4412 )
4413/*++
4414
4415Routine Description:
4416 Posts PowerDownFailed event to the PnP state machine and then waits for death.
4417
4418Arguments:
4419 This - The instance of the state machine
4420
4421Return 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
4436}
4437
4441 )
4442/*++
4443
4444Routine Description:
4445 Disconnects interrupts
4446
4447Arguments:
4448 This - The instance of the state machine
4449
4450Return 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 |
4464
4466}
4467
4471 )
4472/*++
4473
4474Routine Description:
4475 Disconnects interrupts
4476
4477Arguments:
4478 This - The instance of the state machine
4479
4480Return 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 |
4495
4497}
4498
4502 )
4503/*++
4504
4505Routine Description:
4506 Disconnects interrupts
4507
4508Arguments:
4509 This - The instance of the state machine
4510
4511Return Value:
4512 WdfDevStatePowerReportPowerDownFailed
4513
4514 --*/
4515{
4516 //
4517 // NotifyResourceObjectsDx will log any errors
4518 //
4519 (void) This->NotifyResourceObjectsDx(NotifyResourcesForceDisconnect |
4521
4523}
4524
4528 )
4529/*++
4530
4531Routine Description:
4532 Disconnects interrupts
4533
4534Arguments:
4535 This - The instance of the state machine
4536
4537Return Value:
4538 WdfDevStatePowerGotoDxStopped
4539
4540 --*/
4541{
4542 //
4543 // NotifyResourceObjectsDx will log any errors
4544 //
4545 (void) This->NotifyResourceObjectsDx(NotifyResourcesForceDisconnect |
4547
4549}
4550
4554 )
4555/*++
4556
4557Routine Description:
4558 Disconnects interrupts
4559
4560Arguments:
4561 This - The instance of the state machine
4562
4563Return 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
4575}
4576
4580 )
4581/*++
4582
4583Routine Description:
4584 Disconnects interrupts
4585
4586Arguments:
4587 This - The instance of the state machine
4588
4589Return 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
4601}
4602
4606 )
4607/*++
4608
4609Routine Description:
4610 Notifies the wake interrupt state machines that the device has entered
4611 D0
4612
4613Arguments:
4614 This - The instance of the state machine
4615
4616Return Value:
4617 WdfDevStatePowerWakingConnectInterrupt if there are no wake interrupts
4618 or WdfDevStatePowerNull otherwise
4619
4620 --*/
4621{
4622 if (This->m_WakeInterruptCount == 0) {
4624 }
4625
4626 This->SendEventToAllWakeInterrupts(WakeInterruptEventEnteringD0);
4627
4628 return WdfDevStatePowerNull;;
4629}
4630
4634 )
4635/*++
4636
4637Routine Description:
4638 Notifies the wake interrupt state machines that the device is about
4639 to exit D0
4640
4641Arguments:
4642 This - The instance of the state machine
4643
4644Return Value:
4645 WdfDevStatePowerDx if there are no wake interrupts or WdfDevStatePowerNull
4646 otherwise
4647
4648 --*/
4649{
4650 if (This->m_WakeInterruptCount == 0) {
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
4683 )
4684/*++
4685
4686Routine Description:
4687 Notifies the wake interrupt state machines that the device has entered
4688 D0
4689
4690Arguments:
4691 This - The instance of the state machine
4692
4693Return Value:
4694 WdfDevStatePowerWakingConnectInterruptNP if there are no wake interrupts
4695 or WdfDevStatePowerNull otherwise
4696
4697 --*/
4698{
4699 if (This->m_WakeInterruptCount == 0) {
4701 }
4702
4703 This->SendEventToAllWakeInterrupts(WakeInterruptEventEnteringD0);
4704
4705 return WdfDevStatePowerNull;;
4706}
4707
4711 )
4712/*++
4713
4714Routine Description:
4715 Notifies the wake interrupt state machines that the device is about
4716 to exit D0
4717
4718Arguments:
4719 This - The instance of the state machine
4720
4721Return Value:
4722 WdfDevStatePowerDxNP if there are no wake interrupts or WdfDevStatePowerNull
4723 otherwise
4724
4725 --*/
4726{
4727 if (This->m_WakeInterruptCount == 0) {
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
4757VOID
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 //
4770 "Force disconnecting interrupts on !devobj 0x%p, WDFDEVICE %p",
4772 m_Device->GetHandle());
4773
4774 //
4775 // NotifyResourceObjectsDx will log any errors
4776 //
4778}
4779
4780BOOLEAN
4783 )
4784/*++
4785
4786Routine 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
4801Arguments:
4802 WaitWakeStatus - The final status of the wait wake request
4803
4804Return Value:
4805 TRUE if there there was a request to cancel
4806
4807 --*/
4808{
4810 //
4811 // The power machine will eventually call PowerCompletePendedWakeIrp
4812 // to complete the request.
4813 //
4816 }
4817 else if (NT_SUCCESS(WaitWakeStatus)) {
4819 }
4820 else {
4822 }
4823
4824 return TRUE;
4825 }
4826 else {
4827 return FALSE;
4828 }
4829}
4830
4831VOID
4833 VOID
4834 )
4835/*++
4836
4837Routine 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
4842Arguments:
4843 None
4844
4845Return Value:
4846 None
4847
4848 --*/
4849{
4851 KIRQL irql;
4852
4854 COVERAGE_TRAP();
4855 return;
4856 }
4857
4858 //
4859 // Pop an irp off of the list
4860 //
4865
4867
4869
4871}
4872
4873VOID
4876 )
4877/*++
4878
4879Routine 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
4885Arguments:
4886 Status - Final status of the wake irp
4887
4888Return Value:
4889 None
4890
4891 --*/
4892{
4895 }
4896}
4897
4898BOOLEAN
4901 )
4902/*++
4903
4904Routine 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
4909Arguments:
4910 WaitWakeStatus - final status for the wake request
4911
4912Return Value:
4913 TRUE if there was a request and we cleared the cancel routine, FALSE
4914 otherwise
4915
4916 --*/
4917{
4918 KIRQL irql;
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 //
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 //
4935
4937 MdCancelRoutine pOldCancelRoutine;
4938 FxIrp wwIrp;
4939
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 //
4954 pParentPkg->IsPowerPolicyOwner() &&
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
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()) {
4979 "WDFDEVICE 0x%p !devobj 0x%p WW !irp 0x%p is a source "
4980 "of wake", m_Device->GetHandle(),
4983
4985 }
4986 }
4987
4988 //
4989 // Set the status for the irp when it is completed later
4990 //
4992
4993 //
4994 // Queue the irp for completion later
4995 //
4997 wwIrp.ListEntry());
4998
4999 wwIrp.SetIrp(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 }
5015
5016 return result;
5017}
5018
5019VOID
5022 )
5023{
5024 if (IsPowerPolicyOwner()) {
5026 }
5027}
5028
5029VOID
5032 )
5033/*++
5034
5035Routine Description:
5036 The device has powered down, inform the power policy state machine
5037
5038Arguments:
5039 Type - the type of power down being performed
5040
5041Return 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 //
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 //
5068 return;
5069 }
5070
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 //
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 //
5093 }
5094}
5095
5096VOID
5098 VOID
5099 )
5100/*++
5101
5102Routine Description:
5103 Sends power up events to the pnp and power policy state machines
5104
5105Arguments:
5106 None
5107
5108Return Value:
5109 None
5110
5111 --*/
5112{
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 //
5121}
5122
5123VOID
5126 )
5127/*++
5128
5129Routine Description:
5130 Sends a power down failure event to the pnp state machine marks an internal
5131 error.
5132
5133Arguments:
5134 None
5135
5136Return Value:
5137 None
5138
5139 --*/
5140{
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 //
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 //
5160 }
5161 else {
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 //
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 //
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 //
5196 }
5197 }
5198}
5199
5200VOID
5202 VOID
5203 )
5204/*++
5205
5206Routine Description:
5207 Sends a power up failure event to the pnp state machine marks an internal
5208 error.
5209
5210Arguments:
5211 None
5212
5213Return Value:
5214 None
5215
5216 --*/
5217{
5220
5222
5225 }
5226}
5227
5228VOID
5231 )
5232/*++
5233
5234Routine Description:
5235 Stores the state in the object and notifies the system of the change.
5236
5237Arguments:
5238 State - new device state
5239
5240Return Value:
5241 VOID
5242
5243 --*/
5244{
5245 POWER_STATE powerState;
5246
5247 //
5248 // Remember our previous state
5249 //
5251
5252 //
5253 // Set our new state
5254 //
5255 ASSERT(State <= 0xFF);
5257
5258 //
5259 // Notify the system of the new power state.
5260 //
5261 switch (State) {
5264 powerState.DeviceState = PowerDeviceD3;
5265 break;
5266
5267 case WdfPowerDeviceD0:
5270
5271 default:
5272 powerState.DeviceState = (DEVICE_POWER_STATE) State;
5273 break;
5274 }
5275
5279 powerState);
5280}
5281
5282VOID
5284 VOID
5285 )
5286/*++
5287
5288Routine 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
5294Arguments:
5295 This - instance of the state machine
5296
5297Return Value:
5298 None
5299
5300 --*/
5301
5302{
5304
5306
5307 if (!NT_SUCCESS(status)) {
5308 //
5309 // Report the error, but continue forward
5310 //
5313 "Interrupt(s) disconnect on WDFDEVICE %p failed, %!STATUS!",
5315 }
5316
5319
5320 if (!NT_SUCCESS(status)) {
5321 //
5322 // Report the error, but continue forward
5323 //
5326 "EvtDeviceD0Exit WDFDEVICE 0x%p !devobj 0x%p failed, %!STATUS!",
5329 }
5330
5332}
5333
5334
5335
5336
5337
5338
5339
5340
5341VOID
5344 __in MdIrp Irp
5345 )
5346/*++
5347
5348Routine 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
5353Arguments:
5354 DeviceObject - Instance of this state machine
5355 Irp - The wait wake request being canceled
5356
5357Return Value:
5358 None
5359
5360 --*/
5361{
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
5373 pThis = pDevice->GetPdoPkg();
5374
5376
5377 //
5378 // Clear out the IRQL and set our state to disarming
5379 //
5380 pThis->m_PowerMachine.m_WaitWakeLock.Acquire(&irql);
5381
5383 pThis->m_SharedPower.m_WaitWakeIrp != NULL);
5384
5386 irp.ListEntry());
5387
5388 //
5389 // Set the status for the irp when it is completed later
5390 //
5392
5394
5395 pThis->m_PowerMachine.m_WaitWakeLock.Release(irql);
5396
5398}
unsigned char BOOLEAN
Type
Definition: Type.h:7
static int state
Definition: maze.c:121
LONG NTSTATUS
Definition: precomp.h:26
WDFDEVICE __inline GetHandle(VOID)
Definition: fxdevice.hpp:237
MdDeviceObject __inline GetDeviceObject(VOID)
Definition: fxdevice.hpp:174
CfxDevice * m_ParentDevice
Definition: fxdevice.hpp:569
static FxDevice * GetFxDevice(__in MdDeviceObject DeviceObject)
Definition: fxdeviceum.cpp:60
FxPkgPnp * m_PkgPnp
Definition: fxdevice.hpp:670
__inline WDF_DEVICE_POWER_STATE GetDevicePowerState()
Definition: fxdevice.hpp:1157
FxPkgIo * m_PkgIo
Definition: fxdevice.hpp:669
__inline VOID SetDevicePowerState(__in WDF_DEVICE_POWER_STATE DeviceState)
Definition: fxdevice.hpp:1182
__inline FxPkgPdo * GetPdoPkg(VOID)
Definition: fxdevice.hpp:1254
Definition: fxirp.hpp:28
POWER_ACTION GetParameterPowerShutdownType()
Definition: fxirpum.cpp:719
MdCancelRoutine SetCancelRoutine(__in_opt MdCancelRoutine CancelRoutine)
Definition: fxirpum.cpp:124
KIRQL GetCancelIrql()
Definition: fxirpum.cpp:492
VOID SetStatus(__in NTSTATUS Status)
Definition: fxirpum.cpp:457
NTSTATUS GetStatus()
Definition: fxirpum.cpp:466
PLIST_ENTRY ListEntry()
Definition: fxirpum.cpp:535
DEVICE_POWER_STATE GetParameterPowerStateDeviceState()
Definition: fxirpum.cpp:695
static MdIrp GetIrpFromListEntry(__in PLIST_ENTRY Ple)
Definition: fxirpum.cpp:1190
MdIrp SetIrp(MdIrp irp)
Definition: fxirpkm.hpp:71
BOOLEAN IsCanceled()
Definition: fxirpum.cpp:484
__inline PFX_DRIVER_GLOBALS GetDriverGlobals(VOID)
Definition: fxobject.hpp:734
CfxDevice * m_Device
Definition: fxobject.hpp:329
_Must_inspect_result_ NTSTATUS StopProcessingForPower(__in FxIoStopProcessingForPowerAction Action)
Definition: fxpkgio.cpp:1143
static WDF_DEVICE_POWER_STATE PowerStartingChild(__inout FxPkgPnp *This)
VOID SetInternalFailure(VOID)
Definition: fxpkgpnp.cpp:4856
static WDF_DEVICE_POWER_STATE PowerReportPowerDownFailed(__inout FxPkgPnp *This)
static WDF_DEVICE_POWER_STATE PowerWakingDmaEnable(__inout FxPkgPnp *This)
BOOLEAN PowerDmaEnableAndScan(__in BOOLEAN ImplicitPowerUp)
static MdCancelRoutineType _PowerWaitWakeCancelRoutine
Definition: fxpkgpnp.hpp:2736
static WDF_DEVICE_POWER_STATE PowerD0DisarmingWakeAtBusNP(__inout FxPkgPnp *This)
static WDF_DEVICE_POWER_STATE PowerD0ArmedForWake(__inout FxPkgPnp *This)
static WDF_DEVICE_POWER_STATE PowerNotifyingD0ExitToWakeInterruptsNP(__inout FxPkgPnp *This)
static const POWER_EVENT_TARGET_STATE m_PowerD0BusWakeOwnerNPOtherStates[]
Definition: fxpkgpnp.hpp:4411
static WDF_DEVICE_POWER_STATE PowerWakePendingNP(__inout FxPkgPnp *This)
BOOLEAN PowerGotoDxIoStoppedNP(VOID)
static WDF_DEVICE_POWER_STATE PowerStartSelfManagedIoFailed(__inout FxPkgPnp *This)
VOID PowerCompleteWakeRequestFromWithinMachine(__in NTSTATUS Status)