ReactOS 0.4.16-dev-329-g9223134
powerpolicystatemachine.cpp
Go to the documentation of this file.
1/*++
2
3Copyright (c) Microsoft. All rights reserved.
4
5Module Name:
6
7 PowerPolicyStateMachine.cpp
8
9Abstract:
10
11 This module implements the Power Policy state machine for the driver
12 framework. This code was split out from FxPkgPnp.cpp.
13
14Author:
15
16
17
18
19Environment:
20
21 Both kernel and user mode
22
23Revision History:
24
25
26
27--*/
28
29#include "pnppriv.hpp"
30
31#if FX_IS_KERNEL_MODE
32#include <usbdrivr.h>
33#endif
34
35#include "fxusbidleinfo.hpp"
36
37extern "C" {
38#if defined(EVENT_TRACING)
39#include "PowerPolicyStateMachine.tmh"
40#endif
41}
42
43//
44// The Power Policy State Machine
45//
46// This state machine responds to the following events:
47//
48// PowerUp
49// PowerDown
50// PowerPolicyStart
51// PowerPolicyStop
52// IRP_MN_SET_POWER -- System State S0
53// IRP_MN_SET_POWER -- System State Sx
54// PowerTimeoutExpired
55// IoPresent
56// IRP_MN_WAIT_WAKE Complete
57// IRP_MN_WAIT_WAKE Failed
58//
59
60#if FX_SUPER_DBG
61 #define ASSERT_PWR_POL_STATE(_This, _State) \
62 ASSERT((_This)->m_Device->GetDevicePowerPolicyState() == (_State))
63#else
64 #define ASSERT_PWR_POL_STATE(_This, _State) (0)
65#endif
66
67#if FX_STATE_MACHINE_VERIFY
68 #define VALIDATE_PWR_POL_STATE(_CurrentState, _NewState) \
69 ValidatePwrPolStateEntryFunctionReturnValue((_CurrentState), (_NewState))
70#else
71 #define VALIDATE_PWR_POL_STATE(_CurrentState, _NewState) (0)
72#endif //FX_STATE_MACHINE_VERIFY
73
74// @@SMVERIFY_SPLIT_BEGIN
75
77{
80};
81
83{
86};
87
89{
95};
96
98{
105};
106
108{
111};
112
114{
117};
118
120{
127};
128
130{
134};
135
137{
140};
141
143{
147};
148
150{
153};
154
156{
160};
161
163{
167};
168
170{
174};
175
177{
180};
181
183{
189};
190
192{
199};
200
202{
205};
206
208{
211};
212
214{
218};
219
221{
230};
231
233{
244};
245
247{
250};
251
253{
257};
258
260{
264};
265
267{
271};
272
274{
277};
278
280{
284};
285
287{
290};
291
293{
296};
297
299{
304};
305
307{
311};
312
314{
317};
318
320{
324};
325
327{
330};
331
333{
336};
337
339{
342};
343
345{
348};
349
351{
354};
355
357{
363};
364
366{
369};
370
372{
375};
376
378{
382};
383
385{
388};
389
391{
395};
396
398{
402};
403
405{
408};
409
411{
414};
415
417{
420};
421
423{
427};
428
430{
433};
434
436{
439};
440
442{
445};
446
448{
452};
453
455{
458};
459
461{
465};
466
468{
471};
472
474{
477};
478
480{
483};
484
486{
489};
490
492{
495};
496
498{
502};
503
505{
508};
509
511{
514};
515
517{
520};
521
523{
526};
527
529{
532};
533
535{
538};
539
541{
546};
547
549{
552};
553
555{
558};
559
561{
562 // transition function,
563 // { first target state },
564 // other target states
565 // queue open,
566
567 // WdfDevStatePwrPolObjectCreated
568 { NULL,
571 { TRUE,
572 PwrPolS0 | // Sx -> S0 transition on a PDO which was enumerated and
573 // in the disabled state
574
575 PwrPolSx | // Sx transition right after enumeration
577 },
578
579 // WdfDevStatePwrPolStarting
583 { FALSE,
584 PwrPolPowerUpFailed // If the power state machine fails D0 entry upon
585 // initial start, we will get this event here. The
586 // pnp s.m. will not rely on the pwr pol s.m. to
587 // power down the stack in this case.
588 },
589 },
590
591 // WdfDevStatePwrPolStartingSucceeded
594 NULL,
595 { FALSE,
596 0 },
597 },
598
599 // WdfDevStatePwrPolStartingFailed
602 NULL,
603 { TRUE,
604 0 },
605 },
606
607 // WdfDevStatePwrPolStartingDecideS0Wake
609 { PwrPolNull, WdfDevStatePwrPolNull }, // transition out based on wake from S0 enabled
610 NULL,
611 { FALSE,
612 0 },
613 },
614
615 // WdfDevStatePwrPolStartedIdleCapable
619 { TRUE,
620 PwrPolS0 | // If the machine send a query Sx and it fails, it will send
621 // an S0 while in the running state (w/out ever sending a true set Sx irp)
622 PwrPolWakeArrived | // If the wake request is failed by the bus in between WakeArrived
623 // being posted in TimerExpiredWakeCapapble and being
624 // processed, this event will show up in this state if the idle
625 // setting changed at this exact moment as well
626 PwrPolPowerUp | // posted by power when we are powering up the first time
627 PwrPolIoPresent | // posted by the idle state machine. If we return
628 // to idle this can happen
629 PwrPolDevicePowerNotRequired | // The device-power-not-required event arrived just after an
630 // I/O request or or an S0-idle policy change caused us to
631 // become active again. The event is ignored in this case.
632 PwrPolDevicePowerRequired // The device-power-required event arrived, but we had already
633 // powered-up the device proactively because we detected that
634 // power was needed. The event is ignored in this case.
635 },
636 },
637
638 // WdfDevStatePwrPolTimerExpiredNoWake
642 { FALSE,
643 0 },
644 },
645
646 // WdfDevStatePwrPolTimerExpiredNoWakeCompletePowerDown
648 // NOTE: see the comments PowerPolWaitingArmedUsbSS() about why we query the
649 // idle state instead of going directly to WdfDevStatePwrPolWaitingUnarmed
652 { FALSE,
653 0 },
654 },
655
656 // WdfDevStatePwrPolWaitingUnarmed
657 { NULL,
660 { TRUE,
661 PwrPolS0 | // If the machine send a query Sx and it fails, it will send
662 // an S0 while in the running state (w/out ever sending a true set Sx irp)
663 PwrPolDevicePowerNotRequired // When moving from Sx -> S0, we do not power up the
664 // device if:
665 // (UsingSystemManagedIdleTimeout == TRUE) and
666 // (IdleEnabled == TRUE) and
667 // (WakeFromS0Capable == FALSE) and
668 // (PowerUpIdleDeviceOnSystemWake == FALSE).
669 // In this situation, we declare to the active/idle
670 // state machine that we are idle, but ignore the
671 // device-power-not-required event, because we are
672 // already in Dx.
673 },
674 },
675
676 // WdfDevStatePwrPolWaitingUnarmedQueryIdle
679 NULL,
680 { FALSE,
681 0 },
682 },
683
684 // WdfDevStatePwrPolS0NoWakePowerUp
688 { FALSE,
689 0 },
690 },
691
692 // WdfDevStatePwrPolS0NoWakeCompletePowerUp
696 { FALSE,
697 0 },
698 },
699
700 // WdfDevStatePwrPolSystemSleepFromDeviceWaitingUnarmed
702 { PwrPolNull, WdfDevStatePwrPolNull }, // transition out based on wake from Sx enabled
703 NULL,
704 { FALSE,
705 0 },
706 },
707
708 // WdfDevStatePwrPolSystemSleepNeedWake
712 { FALSE,
713 0 },
714 },
715
716 // WdfDevStatePwrPolSystemSleepNeedWakeCompletePowerUp
720 { FALSE,
721 0 },
722 },
723
724 // WdfDevStatePwrPolSystemSleepPowerRequestFailed
727 NULL,
728 { FALSE,
729 0, },
730 },
731
732 // WdfDevStatePwrPolCheckPowerPageable
734 { PwrPolNull, WdfDevStatePwrPolNull }, // transition out based on which DO_POWER_Xxx flags set on DO
735 NULL,
736 { FALSE,
737 0 },
738 },
739
740 // WdfDevStatePwrPolSleepingWakeWakeArrived
744 { FALSE,
745 PwrPolWakeFailed | // wake completed before we could cancel
746 // the request, so the event may end up here
747 PwrPolWakeSuccess| // -do-
748 PwrPolWakeInterruptFired // Wake interrupt fired when during power
749 // down as part of system sleep transition
750
751 },
752 },
753
754 // WdfDevStatePwrPolSleepingWakeRevertArmWake
758 { FALSE,
759 0 },
760 },
761
762 // WdfDevStatePwrPolSystemAsleepWakeArmed
766 { TRUE,
767 PwrPolWakeFailed | // Wake failed while in Sx
768 PwrPolIoPresent | // IO arrived when the machine was going to Sx
769 PwrPolPowerTimeoutExpired | // we don't cancel the power timer when we goto
770 // sleep from an idleable state
771 PwrPolDevicePowerNotRequired // Upon receiving Sx, we simulated a device-power-
772 // not-required, so the device-power-requirement
773 // state machine sent us this event in response.
774 // We can drop it because we already powered down.
775 },
776 },
777
778 // WdfDevStatePwrPolSystemWakeDeviceWakeEnabled
782 { FALSE,
783 PwrPolWakeInterruptFired // wake interrupt fired as we were waking the
784 // device on receiving S0 due to other reasons.
785 // This event can fire until the wake interrupt
786 // machine is notified of the power up.
787 },
788 },
789
790 // WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceled
794 { FALSE,
795 PwrPolWakeInterruptFired // wake interrupt fired as we were waking the
796 // device on receiving S0 due to other reasons.
797 // This event can fire until the wake interrupt
798 // machine is notified of the power up.
799 },
800 },
801
802 // WdfDevStatePwrPolSystemWakeDeviceWakeDisarm
804 { PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func
805 NULL,
806 { FALSE,
807 0 },
808 },
809
810 // WdfDevStatePwrPolSystemWakeDeviceWakeTriggered
811 { NULL,
813 NULL,
814 { TRUE,
815 0 },
816 },
817
818 // WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredS0
822 { FALSE,
823 0 },
824 },
825
826 // WdfDevStatePwrPolSystemWakeDeviceWokeDisarm
828 { PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func
829 NULL,
830 { FALSE,
831 0 },
832 },
833
834 // WdfDevStatePwrPolSleepingWakeWakeArrivedNP,
838 { FALSE,
839 PwrPolWakeFailed | // wake completed before we could cancel
840 // the request, so the event may end up here
841 PwrPolWakeSuccess| // -do-
842 PwrPolWakeInterruptFired // Wake interrupt fired when during power
843 // down as part of system sleep transition
844
845 },
846 },
847
848 // WdfDevStatePwrPolSleepingWakeRevertArmWakeNP,
852 { FALSE,
853 0 },
854 },
855
856 // WdfDevStatePwrPolSleepingWakePowerDownFailed
860 { FALSE,
861 0 },
862 },
863
864 // WdfDevStatePwrPolSleepingWakePowerDownFailedWakeCanceled
867 NULL,
868 { FALSE,
869 0 },
870 },
871
872 // WdfDevStatePwrPolSystemAsleepWakeArmedNP
876 { TRUE,
877 PwrPolWakeFailed | // Wake failed while in Sx
878 PwrPolIoPresent | // IO arrived when the machine was going to Sx
879 PwrPolPowerTimeoutExpired // we don't cancel the power timer when we goto
880 // sleep from an idleable state
881 },
882 },
883
884 // WdfDevStatePwrPolSystemWakeDeviceWakeEnabledNP
888 { FALSE,
889 PwrPolWakeInterruptFired // wake interrupt fired as we were waking the
890 // device on receiving S0 due to other reasons.
891 // This event can fire until the wake interrupt
892 // machine is notified of the power up.
893 },
894 },
895
896 // WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceledNP
900 { FALSE,
901 PwrPolWakeSuccess | // wake succeeded and completed before we could cancel
902 // the request, so the event ends up here
903
904 PwrPolWakeInterruptFired // wake interrupt fired as we were waking the
905 // device on receiving S0 due to other reasons.
906 // This event can fire until the wake interrupt
907 // machine is notified of the power up.
908 },
909 },
910
911 // WdfDevStatePwrPolSystemWakeDeviceWakeDisarmNP
913 { PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func
914 NULL,
915 { FALSE,
916 0 },
917 },
918
919 // WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredNP
920 { NULL,
922 NULL,
923 { TRUE,
924 PwrPolIoPresent // I/O arrived before S0 arrival
925 },
926 },
927
928 // WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredS0NP
932 { FALSE,
933 0 },
934 },
935
936 // WdfDevStatePwrPolSystemWakeDeviceWokeDisarmNP
938 { PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func
939 NULL,
940 { FALSE,
941 0 },
942 },
943
944 // WdfDevStatePwrPolSystemWakeDeviceWakeCompletePowerUp
948 { FALSE,
949 0 },
950 },
951
952 // WdfDevStatePwrPolSleeping
955 NULL,
956 { FALSE,
957 0 },
958 },
959
960 // WdfDevStatePwrPolSleepingNoWakePowerDown
964 { FALSE,
965 0 },
966 },
967
968 // WdfDevStatePwrPolSleepingNoWakeCompletePowerDown
972 { FALSE,
973 PwrPolWakeArrived // wake arrived event posted after the ww irp
974 // completed from SleepingSendWake state. Ignore this
975 // event since wake is already trigged.
976 },
977 },
978
979 // WdfDevStatePwrPolSleepingNoWakeDxRequestFailed
981 { PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func
982 NULL,
983 { FALSE,
984 0 },
985 },
986
987 // WdfDevStatePwrPolSleepingWakePowerDown
991 { FALSE,
992 0 },
993 },
994
995 // WdfDevStatePwrPolSleepingSendWake
999 { FALSE,
1000 0 },
1001 },
1002
1003 // WdfDevStatePwrPolSystemAsleepNoWake
1006 NULL,
1007 { TRUE,
1008 PwrPolS0IdlePolicyChanged | // Policy changed while the device is in Dx
1009 // because of Sx, we will reevaluate the idle
1010 // settings when we return to S0 anyways
1011 PwrPolWakeArrived | // If arming for wake from sx failed, the WakeArrived
1012 // event that was a part of that arming is dequeued here
1013 PwrPolIoPresent | // I/O showed up when going into Sx
1015 PwrPolDevicePowerNotRequired // Upon receiving Sx, we simulated a device-power-
1016 // not-required, so the device-power-requirement
1017 // state machine sent us this event in response.
1018 // We can drop it because we already powered down.
1019 },
1020 },
1021
1022 // WdfDevStatePwrPolSystemWakeDeviceWakeDisabled
1024 { PwrPolNull, WdfDevStatePwrPolNull }, // transition out based on wake from S0 enabled
1025 NULL,
1026 { FALSE,
1027 0 },
1028 },
1029
1030 // WdfDevStatePwrPolSystemWakeDeviceToD0
1034 { FALSE,
1035 0 },
1036 },
1037
1038 // WdfDevStatePwrPolSystemWakeDeviceToD0CompletePowerUp
1042 { FALSE,
1043 0 },
1044 },
1045
1046 // WdfDevStatePwrPolSystemWakeQueryIdle
1048 { PwrPolNull, WdfDevStatePwrPolNull}, // transition out based on timer expiration state
1049 NULL,
1050 { FALSE,
1051 0 },
1052 },
1053
1054 // WdfDevStatePwrPolStartedWakeCapable
1058 { TRUE,
1059 PwrPolS0 | // If the machine send a query Sx and it fails, it will send
1060 // an S0 while in the running state (w/out ever sending a true set Sx irp)
1062 PwrPolWakeArrived | // If the wake request is failed by the bus in between WakeArrived
1063 // being posted in TimerExpiredWakeCapapble and being
1064 // processed, this event will show up in this state
1065
1066 PwrPolWakeSuccess | // wake succeeded while we were trying to cancel it
1067 // while coming out of WaitingArmed b/c of io present
1068
1069 PwrPolWakeFailed | // wake request failed while we were trying to cancel it
1070 // while coming out of WaitingArmed b/c of io present
1071
1073 PwrPolUsbSelectiveSuspendCompleted | // When returning from a success resume
1074 // from USB SS, the completion of the irp will
1075 // occur in the started state
1076
1077 PwrPolIoPresent | // posted by the idle state machine. If we return
1078 // to idle this can happen
1079 PwrPolDevicePowerNotRequired | // The device-power-not-required event arrived just after an
1080 // I/O request or or an S0-idle policy change caused us to
1081 // become active again. The event is ignored in this case.
1082 PwrPolDevicePowerRequired // The device-power-required event arrived, but we had already
1083 // powered-up the device proactively because we detected that
1084 // power was needed. The event is ignored in this case.
1085 },
1086 },
1087
1088 // WdfDevStatePwrPolTimerExpiredDecideUsbSS
1091 NULL,
1092 { FALSE,
1093 0 },
1094 },
1095
1096 // WdfDevStatePwrPolTimerExpiredWakeCapablePowerDown
1100 { FALSE,
1101 0 },
1102 },
1103
1104 // WdfDevStatePwrPolTimerExpiredWakeCapableSendWake
1108 { FALSE,
1109 0 },
1110 },
1111
1112 // WdfDevStatePwrPolTimerExpiredWakeCapableUsbSS
1116 { TRUE,
1117 0 },
1118 },
1119
1120 // WdfDevStatePwrPolTimerExpiredWakeCapableWakeArrived
1124 { FALSE,
1125 0 },
1126 },
1127
1128 // WdfDevStatePwrPolTimerExpiredWakeCapableCancelWake
1132 { FALSE,
1133 0 },
1134 },
1135
1136 // WdfDevStatePwrPolTimerExpiredWakeCapableWakeCanceled
1139 NULL,
1140 { FALSE,
1141 0 },
1142 },
1143
1144 // WdfDevStatePwrPolTimerExpiredWakeCapableCleanup
1147 NULL,
1148 { FALSE,
1149 0 },
1150 },
1151
1152 // WdfDevStatePwrPolTimerExpiredWakeCapableDxAllocFailed
1155 NULL,
1156 { FALSE,
1157 0 },
1158 },
1159
1160 // WdfDevStatePwrPolTimerExpiredWakeCompletedPowerDown
1164 { FALSE,
1165 PwrPolWakeSuccess | // arming callback failed while going into Dx armed for wake from S0
1166 // but bus completed wake request with success
1167
1168 PwrPolWakeArrived // if the wake request completes before PwrPolWakeArrived
1169 // can be processed in the PwrPolTimerExpiredWakeCapableSendWake
1170 // state, it will show up here
1171 },
1172 },
1173
1174 // WdfDevStatePwrPolTimerExpiredWakeCompletedPowerUp
1178 { FALSE,
1179 PwrPolWakeSuccess | // arming callback failed while going into Dx armed for wake from S0
1180 // but bus completed wake request with success
1181
1182 PwrPolWakeArrived // if the wake request completes before PwrPolWakeArrived
1183 // can be processed in the WdfDevStatePwrPolTimerExpiredWakeCapableSendWake
1184 // state, it will show up here
1185 },
1186 },
1187
1188 // WdfDevStatePwrPolWaitingArmedUsbSS
1191 NULL,
1192 { FALSE,
1193 0 },
1194 },
1195
1196 // WdfDevStatePwrPolWaitingArmed
1197 { NULL,
1200 { TRUE,
1201 PwrPolS0 // If the machine send a query Sx and it fails, it will send
1202 // an S0 while in the running state (w/out ever sending a true set Sx irp)
1203 },
1204 },
1205
1206 // WdfDevStatePwrPolWaitingArmedQueryIdle
1209 NULL,
1210 { FALSE,
1211 0 },
1212 },
1213
1214 // WdfDevStatePwrPolIoPresentArmed
1218 { FALSE,
1219 PwrPolWakeInterruptFired // wake interrupt fired as we were waking the
1220 // device on receiving IO.This event can fire
1221 // until the wake interrupt machine is notified
1222 // of the power up.
1223 },
1224 },
1225
1226 // WdfDevStatePwrPolIoPresentArmedWakeCanceled
1230 { FALSE,
1231 PwrPolWakeSuccess | // The wake status was already processed before entering
1232 // this state - indicates that the client driver is
1233 // probably propagating a duplicate wake status using
1234 // the WdfDeviceIndicateWakeStatus ddi.
1235
1236 PwrPolWakeFailed | // The wake status was already processed before entering
1237 // this state - indicates that the client driver is
1238 // probably propagating a duplicate wake status using
1239 // the WdfDeviceIndicateWakeStatus ddi.
1240
1241 PwrPolWakeInterruptFired // wake interrupt fired as we were waking the
1242 // device on receiving IO.This event can fire
1243 // until the wake interrupt machine is notified
1244 // of the power up.
1245
1246 },
1247 },
1248
1249 // WdfDevStatePwrPolS0WakeDisarm,
1251 { PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func
1252 NULL,
1253 { FALSE,
1254 0 },
1255 },
1256
1257 // WdfDevStatePwrPolS0WakeCompletePowerUp
1261 { FALSE,
1262 0 },
1263 },
1264
1265 // WdfDevStatePwrPolTimerExpiredWakeSucceeded
1267 { PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func
1268 NULL,
1269 { FALSE,
1270 0 },
1271 },
1272
1273 // WdfDevStatePwrPolTimerExpiredWakeCompletedDisarm
1276 NULL,
1277 { FALSE,
1278 0 },
1279 },
1280
1281 // WdfDevStatePwrPolTimerExpiredWakeCapableWakeSucceeded
1282 { NULL,
1285 { FALSE,
1286 0 },
1287 },
1288
1289 // WdfDevStatePwrPolTimerExpiredWakeCapableWakeFailed
1290 { NULL,
1293 { FALSE,
1294 0 },
1295 },
1296
1297 // WdfDevStatePwrPolWakeFailedUsbSS
1300 NULL,
1301 { FALSE,
1302 0 },
1303 },
1304
1305 // WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedCancelWake
1309 { FALSE,
1310 0 },
1311 },
1312
1313 // WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled
1316 NULL,
1317 { FALSE,
1318 0 },
1319 },
1320
1321 // WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedUsbSS
1324 NULL,
1325 { FALSE,
1326 0 },
1327 },
1328
1329 // WdfDevStatePwrPolCancelingWakeForSystemSleep
1333 { FALSE,
1334 0 },
1335 },
1336
1337 // WdfDevStatePwrPolCancelingWakeForSystemSleepWakeCanceled
1341 { FALSE,
1342 PwrPolWakeSuccess // Wake completed successfully right as the transition
1343 // from WaitingArmed to goto Sx occurred
1344 },
1345 },
1346
1347 // WdfDevStatePwrPolDisarmingWakeForSystemSleepCompletePowerUp
1351 { FALSE,
1352 0, },
1353 },
1354
1355 // WdfDevStatePwrPolPowerUpForSystemSleepFailed
1358 NULL,
1359 { FALSE,
1360 0 },
1361 },
1362
1363 // WdfDevStatePwrPolWokeFromS0UsbSS
1366 NULL,
1367 { FALSE,
1368 0 },
1369 },
1370
1371 // WdfDevStatePwrPolWokeFromS0
1375 { FALSE,
1376 0 },
1377 },
1378
1379 // WdfDevStatePwrPolWokeFromS0NotifyDriver
1382 NULL,
1383 { FALSE,
1384 0 },
1385 },
1386
1387 // WdfDevStatePwrPolStoppingResetDevice
1391 { FALSE,
1392 0 },
1393 },
1394
1395 // WdfDevStatePwrPolStoppingResetDeviceCompletePowerUp
1399 { FALSE,
1400 0 },
1401 },
1402
1403 // WdfDevStatePwrPolStoppingResetDeviceFailed
1406 NULL,
1407 { FALSE,
1408 0 },
1409 },
1410
1411 // WdfDevStatePwrPolStoppingD0
1415 { FALSE,
1416 PwrPolWakeSuccess | // In the waiting armed state, the wake completed
1417 // right after PwrPolStop arrived
1418 PwrPolWakeFailed // wake completed before we could cancel
1419 // the request, so the event may end up here
1420 },
1421 },
1422
1423 // WdfDevStatePwrPolStoppingD0Failed
1426 NULL,
1427 { FALSE,
1428 0 },
1429 },
1430
1431 // WdfDevStatePwrPolStoppingDisarmWake
1435 { FALSE,
1436 PwrPolWakeFailed | // wake completed before we could cancel
1437 // the request, so the event may end up here
1438 PwrPolWakeSuccess // -do-
1439 },
1440 },
1441
1442 // WdfDevStatePwrPolStoppingDisarmWakeCancelWake
1446 { FALSE,
1447 PwrPolUsbSelectiveSuspendCompleted // pwr pol stopped from a usb SS device
1448 // in Dx and the irp completed when the D0
1449 // irp was sent
1450 },
1451 },
1452
1453 // WdfDevStatePwrPolStoppingDisarmWakeWakeCanceled
1455 { PwrPolNull, WdfDevStatePwrPolNull}, // transition to Stopping occurs in function
1456 NULL,
1457 { FALSE,
1458 PwrPolUsbSelectiveSuspendCompleted // pwr pol stopped from a usb SS device
1459 // in Dx and the irp completed when the D0
1460 // irp was sent
1461 },
1462 },
1463
1464 // WdfDevStatePwrPolStopping
1468 { FALSE,
1469 PwrPolUsbSelectiveSuspendCompleted // pwr pol stopped from a usb SS device
1470 // in Dx and the irp completed when the D0
1471 // irp was sent
1472 },
1473 },
1474
1475 // WdfDevStatePwrPolStoppingFailed
1478 NULL,
1479 { FALSE,
1480 0 },
1481 },
1482
1483 // WdfDevStatePwrPolStoppingSendStatus
1486 NULL,
1487 { FALSE,
1488 0 },
1489 },
1490
1491 // WdfDevStatePwrPolStoppingCancelTimer
1494 NULL,
1495 { FALSE,
1496 0 },
1497 },
1498
1499 // WdfDevStatePwrPolStoppingWaitForIdleTimeout
1500 { NULL,
1502 NULL,
1503 { TRUE,
1504 0 },
1505 },
1506
1507 // WdfDevStatePwrPolStoppingCancelUsbSS
1510 NULL,
1511 { FALSE,
1512 0 },
1513 },
1514
1515 // WdfDevStatePwrPolStoppingWaitForUsbSSCompletion
1516 { NULL,
1518 NULL,
1519 { TRUE,
1520 0 },
1521 },
1522
1523 // WdfDevStatePwrPolStoppingCancelWake
1527 { TRUE,
1528 0 },
1529 },
1530
1531 // WdfDevStatePwrPolStopped
1532 { NULL,
1535 { TRUE,
1536 PwrPolPowerTimeoutExpired | // idle timer fired right before stopping
1537 // pwr policy and before pwr pol could process
1538 // the timeout
1539 PwrPolIoPresent | // I/O arrived while transitioning to the
1540 // stopped state
1541 PwrPolDevicePowerRequired // Due to a power-related failure, we declared our device state
1542 // as failed and stopped the power policy state machine. But
1543 // before stopping the power policy machine, we would have
1544 // declared ourselves as powered-on (maybe fake) in order to
1545 // move the power framework to a consistent state. Since we've
1546 // already declared ourselves as powered-on, we can drop this.
1547 },
1548 },
1549
1550 // WdfDevStatePwrPolCancelUsbSS
1554 { TRUE,
1555 PwrPolIoPresent // I/O arrived while we were waiting for the USB idle notification IOCTL
1556 // to be completed after we had canceled it. It is okay to drop this
1557 // event because we are already in the process to returning to the powered-
1558 // up state.
1559 },
1560 },
1561
1562 // WdfDevStatePwrPolStarted
1566 { TRUE,
1567 PwrPolS0 | // If the machine send a query Sx and it fails, it will send
1568 // an S0 while in the running state (w/out ever sending a true set Sx irp)
1569 PwrPolWakeArrived | // If the wake request is failed by the bus in between WakeArrived
1570 // being posted in TimerExpiredWakeCapapble and being
1571 // processed, this event will show up in this state if the idle
1572 // setting changed at this exact moment as well
1573 PwrPolWakeSuccess | // returning from Dx armed for wake from Sx, wake
1574 // is completed w/success after S0 irp arrives
1576 PwrPolUsbSelectiveSuspendCompleted | // sent when we move out of the armed
1577 // & idle enabled state into the
1578 // idle disabled state
1579 PwrPolIoPresent |// This just indicates that I/O arrived, which is fine here
1580 PwrPolPowerTimeoutExpired | // this can happen when idle timer is disabled
1581 // due to policy change while powering up.
1582 PwrPolDevicePowerRequired // idle policy changed when device was powered down
1583 // due to S0-idle. The policy change caused us to power
1584 // up. As part of powering up, the device-power-required
1585 // event arrived. Can drop because we already powered-up.
1586 },
1587 },
1588
1589 // WdfDevStatePwrPolStartedCancelTimer
1592 NULL,
1593 { FALSE,
1594 0 },
1595 },
1596
1597 // WdfDevStatePwrPolStartedWaitForIdleTimeout
1598 { NULL,
1601 { TRUE,
1602 0 },
1603 },
1604
1605 // WdfDevStatePwrPolStartedWakeCapableCancelTimerForSleep
1608 NULL,
1609 { FALSE,
1610 0 },
1611 },
1612
1613 // WdfDevStatePwrPolStartedWakeCapableWaitForIdleTimeout
1614 { NULL,
1616 NULL,
1617 { TRUE,
1618 0 },
1619 },
1620
1621 // WdfDevStatePwrPolStartedWakeCapableSleepingUsbSS
1624 NULL,
1625 { TRUE,
1626 0 },
1627 },
1628
1629 // WdfDevStatePwrPolStartedIdleCapableCancelTimerForSleep
1632 NULL,
1633 { FALSE,
1634 0 },
1635 },
1636
1637 // WdfDevStatePwrPolStartedIdleCapableWaitForIdleTimeout
1638 { NULL,
1640 NULL,
1641 { TRUE,
1642 0 },
1643 },
1644
1645 // WdfDevStatePwrPolDeviceD0PowerRequestFailed
1648 NULL,
1649 { FALSE,
1650 0 },
1651 },
1652
1653 // WdfDevStatePwrPolDevicePowerRequestFailed
1657 { TRUE,
1658 PwrPolUsbSelectiveSuspendCompleted | // Device was suspened and surprise
1659 // removed while in Dx
1660 PwrPolS0 | // If the device failed D0Exit while the machine was going into
1661 // Sx, then we will get this event when the machine comes back up
1662
1663 PwrPolWakeArrived | // wake was completed before PwrPolWakeArrived was
1664 // sent. On immediate power down or up, the power
1665 // operation failed
1666
1667 PwrPolWakeFailed | // If the device failed exit d0 after being armed, the
1668 // this event will be processed in the failed state
1669 PwrPolDevicePowerRequired | // We can drop because we already declared ourselves
1670 // as being powered on (fake power-on in order to
1671 // move the power framework to consistent state).
1672 PwrPolIoPresent // We're being notified that we need to be powered-on because
1673 // there is I/O to process, but the device is already in failed
1674 // state and is about to be removed.
1675 },
1676 },
1677
1678 // State exists only for the non power policy owner state machine
1679 // WdfDevStatePwrPolGotoDx
1680 { NULL,
1682 NULL,
1683 { TRUE,
1684 0 },
1685 },
1686
1687 // WdfDevStatePwrPolGotoDxInDx
1688 { NULL,
1690 NULL,
1691 { TRUE,
1692 0 },
1693 },
1694
1695 // State exists only for the non power policy owner state machine
1696 // WdfDevStatePwrPolDx
1697 { NULL,
1699 NULL,
1700 { TRUE,
1701 0 },
1702 },
1703
1704 // State exists only for the non power policy owner state machine
1705 // WdfDevStatePwrPolGotoD0
1706 { NULL,
1708 NULL,
1709 { TRUE,
1710 0 },
1711 },
1712
1713 // WdfDevStatePwrPolGotoD0InD0
1714 { NULL,
1716 NULL,
1717 { TRUE,
1718 0 },
1719 },
1720
1721 // WdfDevStatePwrPolFinal
1722 { NULL,
1724 NULL,
1725 { TRUE,
1726 0 },
1727 },
1728
1729 // WdfDevStatePwrPolSleepingPowerDownNotProcessed
1732 NULL,
1733 { FALSE,
1734 0 },
1735 },
1736
1737 // WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownNotProcessed
1740 NULL,
1741 { FALSE,
1742 0 },
1743 },
1744
1745 // WdfDevStatePwrPolTimerExpiredNoWakePowerDownNotProcessed
1748 NULL,
1749 { FALSE,
1750 0 },
1751 },
1752
1753 // WdfDevStatePwrPolTimerExpiredNoWakePoweredDownDisableIdleTimer
1756 NULL,
1757 { FALSE,
1758 0 },
1759 },
1760
1761 // WdfDevStatePwrPolStoppingWaitingForImplicitPowerDown
1762 { NULL,
1764 NULL,
1765 { FALSE,
1766 0 },
1767 },
1768
1769 // WdfDevStatePwrPolStoppingPoweringUp
1770 { NULL,
1772 NULL,
1773 { FALSE,
1774 0 },
1775 },
1776
1777 // WdfDevStatePwrPolStoppingPoweringDown
1778 { NULL,
1780 NULL,
1781 { FALSE,
1782 0 },
1783 },
1784
1785 // WdfDevStatePwrPolPowerUpForSystemSleepNotSeen
1788 NULL,
1789 { FALSE,
1790 0 },
1791 },
1792
1793 // WdfDevStatePwrPolWaitingArmedStoppingCancelUsbSS
1796 NULL,
1797 { FALSE,
1798 PwrPolWakeFailed | // wake completed before we could cancel
1799 // the request, so the event may end up here
1800 PwrPolWakeSuccess // -do-
1801 },
1802 },
1803
1804 // WdfDevStatePwrPolWaitingArmedWakeFailedCancelUsbSS
1807 NULL,
1808 { FALSE,
1809 0 },
1810 },
1811
1812 // WdfDevStatePwrPolWaitingArmedIoPresentCancelUsbSS
1815 NULL,
1816 { FALSE,
1817 PwrPolWakeFailed | // wake completed before we could cancel
1818 // the request, so the event may end up here
1819 PwrPolWakeSuccess | // -do-
1820 PwrPolWakeInterruptFired // wake interrupt fired as we were waking the
1821 // device on receiving IO.This event can fire
1822 // until the wake interrupt machine is notified
1823 // of the power up.
1824 },
1825 },
1826
1827 // WdfDevStatePwrPolWaitingArmedWakeSucceededCancelUsbSS
1830 NULL,
1831 { FALSE,
1832 0 },
1833 },
1834
1835 // WdfDevStatePwrPolCancelingUsbSSForSystemSleep
1838 NULL,
1839 { FALSE,
1840 PwrPolWakeFailed | // wake completed before we could cancel
1841 // the request, so the event may end up here
1842 PwrPolWakeSuccess // -do-
1843 },
1844 },
1845
1846 // WdfDevStatePwrPolStoppingD0CancelUsbSS
1849 NULL,
1850 { FALSE,
1851 PwrPolWakeFailed | // wake completed before we could cancel
1852 // the request, so the event may end up here
1853 PwrPolWakeSuccess // -do-
1854 },
1855 },
1856
1857 // WdfDevStatePwrPolStartingPoweredUp
1860 NULL,
1861 { FALSE,
1862 0 },
1863 },
1864
1865 // WdfDevStatePwrPolIdleCapableDeviceIdle
1869 { TRUE,
1870 0 },
1871 },
1872
1873 // WdfDevStatePwrPolDeviceIdleReturnToActive
1876 NULL,
1877 { FALSE,
1878 0 },
1879 },
1880
1881 // WdfDevStatePwrPolDeviceIdleSleeping
1884 NULL,
1885 { FALSE,
1886 0 },
1887 },
1888
1889 // WdfDevStatePwrPolDeviceIdleStopping
1892 NULL,
1893 { FALSE,
1894 0 },
1895 },
1896
1897 // WdfDevStatePwrPolTimerExpiredNoWakeUndoPowerDown
1900 NULL,
1901 { FALSE,
1902 0 },
1903 },
1904
1905 // WdfDevStatePwrPolWakeCapableDeviceIdle
1909 { TRUE,
1910 PwrPolDevicePowerRequired // The device-power-required event arrived, but we had already
1911 // powered-up the device proactively because we detected that
1912 // power was needed. And after we powered up, we become idle
1913 // again and arrived in our current state before the device-
1914 // power-required event was received. The event is ignored in
1915 // this case.
1916 },
1917 },
1918
1919 // WdfDevStatePwrPolWakeCapableUsbSSCompleted
1922 NULL,
1923 { FALSE,
1924 0 },
1925 },
1926
1927 // WdfDevStatePwrPolTimerExpiredWakeCapableUndoPowerDown
1930 NULL,
1931 { FALSE,
1932 0 },
1933 },
1934
1935 // WdfDevStatePwrPolTimerExpiredWakeCompletedHardwareStarted
1938 NULL,
1939 { FALSE,
1940 0 },
1941 },
1942
1943 // WdfDevStatePwrPolStoppedRemoving
1946 NULL,
1947 { FALSE,
1948 0 },
1949 },
1950
1951 // WdfDevStatePwrPolRemoved
1955 { TRUE,
1956 PwrPolSx | // device is disabled (must be a PDO) and then the machine
1957 // moves into an Sx state
1958 PwrPolS0 | // driver failed power up when moving out of S0 Dx idle
1959 // state and system resumed after failure
1960 PwrPolS0IdlePolicyChanged // driver changes S0 idle settings while being
1961 // removed
1962 },
1963 },
1964
1965 // WdfDevStatePwrPolRestarting
1969 { FALSE,
1970 0 },
1971 },
1972
1973 // WdfDevStatePwrPolRestartingFailed
1976 NULL,
1977 { FALSE,
1978 0 },
1979 },
1980
1981 // WdfDevStatePwrPolStartingPoweredUpFailed
1984 NULL,
1985 { FALSE,
1986 0 },
1987 },
1988
1989 // WdfDevStatePwrPolTimerExpiredNoWakeReturnToActive
1992 NULL,
1993 { FALSE,
1994 0 },
1995 },
1996
1997 // WdfDevStatePwrPolWaitingArmedWakeInterruptFired
2001 { FALSE,
2002 0 },
2003 },
2004
2005 // WdfDevStatePwrPolSystemWakeDeviceWakeInterruptFired
2009 { FALSE,
2010 0 },
2011 },
2012
2013 // WdfDevStatePwrPolSystemWakeDeviceWakeInterruptFiredNP
2017 { FALSE,
2018 0 },
2019 },
2020
2021 // WdfDevStatePwrPolTimerExpiredWakeCapableWakeInterruptArrived
2025 { FALSE,
2026 0 },
2027 },
2028
2029 // WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeInterruptArrived
2030 { NULL,
2033 { FALSE,
2034 0 },
2035 },
2036
2037 // WdfDevStatePwrPolWaitingArmedWakeInterruptFiredDuringPowerDown
2038 { NULL,
2041 { FALSE,
2042 0 },
2043 },
2044
2045 // WdfDevStatePwrPolNull
2046 // *** no entry for this state ***
2047};
2048
2049// @@SMVERIFY_SPLIT_END
2050
2051VOID
2053 VOID
2054 )
2055/*++
2056
2057Routine Description:
2058 This routine is never actually called by running code, it just has
2059 WDFCASSERTs who upon failure, would not allow this file to be compiled.
2060
2061 DO NOT REMOVE THIS FUNCTION just because it is not callec by any running
2062 code.
2063
2064Arguments:
2065 None
2066
2067Return Value:
2068 None
2069
2070 --*/
2071{
2072 WDFCASSERT(sizeof(FxPwrPolStateInfo) == sizeof(ULONG));
2073
2075 ==
2077
2078 // we assume these are the same length when we update the history index
2080 sizeof(m_PowerPolicyMachine.m_Queue[0]))
2081 ==
2084}
2085
2086CfxDevice *
2088 VOID
2089 )
2090{
2091 IdlePolicySettings * idlePolicySettings = NULL;
2092 FxPowerPolicyOwnerSettings * ppoSettings = NULL;
2093 FxPkgPnp * pPkgPnp = NULL;
2094
2095 idlePolicySettings = (IdlePolicySettings *) CONTAINING_RECORD(
2096 this,
2098 m_TimeoutMgmt
2099 );
2101 idlePolicySettings,
2103 m_IdleSettings
2104 );
2105 pPkgPnp = ppoSettings->m_PkgPnp;
2106
2107 return pPkgPnp->GetDevice();
2108}
2109
2113 )
2114{
2115 LONG idleTimeoutStatusSnapshot;
2116 LONG updatedIdleTimeoutStatus;
2117 LONG preInterlockedIdleTimeoutStatus;
2118
2119 //
2120 // Take a snapshot of the idle timeout management status
2121 //
2122 idleTimeoutStatusSnapshot = m_IdleTimeoutStatus;
2123
2124 //
2125 // Verify that the flag we're trying to set is not already set
2126 //
2127 if (0 != (idleTimeoutStatusSnapshot & Flag)) {
2129 }
2130
2131 //
2132 // Verify that the idle timeout management status is not already
2133 // "frozen"
2134 //
2135 if (0 != (idleTimeoutStatusSnapshot & IdleTimeoutStatusFrozen)) {
2136 //
2137 // It was too late to set the flag. The flag value was already
2138 // "frozen".
2139 //
2141 }
2142
2143 //
2144 // Try to set the flag
2145 //
2146 updatedIdleTimeoutStatus = idleTimeoutStatusSnapshot | Flag;
2147
2148 preInterlockedIdleTimeoutStatus = InterlockedCompareExchange(
2150 updatedIdleTimeoutStatus,
2151 idleTimeoutStatusSnapshot
2152 );
2153 if (preInterlockedIdleTimeoutStatus != idleTimeoutStatusSnapshot) {
2154
2155 if (0 != (preInterlockedIdleTimeoutStatus &
2157 //
2158 // It was too late to set the flag. The flag value was already
2159 // "frozen".
2160 //
2162 }
2163 else {
2164 //
2165 // Idle timeout management status is being changed by multiple
2166 // threads in parallel. This is not supported.
2167 //
2169 }
2170 }
2171
2172 //
2173 // We have successfully set the flag
2174 //
2176}
2177
2181 )
2182{
2184 IdleTimeoutStatusUpdateResult statusUpdateResult;
2185 CfxDevice * device;
2186
2187 //
2188 // First check if we are running on Windows 8 or above
2189 //
2191
2192 //
2193 // Get the device object so we can use it for logging
2194 //
2195 device = GetDevice();
2196
2197 //
2198 // Try to update the flag that specifies that the power framework should
2199 // determine the idle timeout.
2200 //
2202
2203 switch (statusUpdateResult) {
2205 {
2206 //
2207 // Status is already frozen. Too late to update it.
2208 //
2212 "WDFDEVICE %p !devobj %p If the power framework is made "
2213 "responsible for determining the idle timeout, then the "
2214 "first call to assign S0-idle policy must occur before the "
2215 "first start IRP is completed. However, in this case, it "
2216 "occurred after the first start IRP was completed. "
2217 "%!STATUS!.",
2218 device->GetHandle(),
2219 device->GetDeviceObject(),
2220 status
2221 );
2223 }
2224 break;
2225
2227 {
2228 //
2229 // Status being updated from multiple threads in parallel. Not
2230 // supported.
2231 //
2235 "WDFDEVICE %p !devobj %p Calls to assign S0-idle settings "
2236 "and to specify power framework settings are happening in "
2237 "parallel. The driver needs to serialize these calls with "
2238 "respect to each other. %!STATUS!.",
2239 device->GetHandle(),
2240 device->GetDeviceObject(),
2241 status
2242 );
2244 }
2245 break;
2246
2248 {
2249 //
2250 // Status flag was already set. This should never happen for the
2251 // IdleTimeoutSystemManaged flag. The caller ensures this.
2252 //
2253 ASSERTMSG(
2254 "IdleTimeoutManagement::UseSystemManagedIdleTimeout was "
2255 "called more than once\n", FALSE);
2256 }
2257
2258 //
2259 // Fall through
2260 //
2261 // || || ||
2262 // \/ \/ \/
2263 //
2265 {
2267 }
2268 break;
2269
2270 default:
2271 {
2272 ASSERTMSG("Unexpected IdleTimeoutStatusUpdateResult value\n",
2273 FALSE);
2275 }
2276 }
2277
2278 } else {
2279 //
2280 // If we're not running on Windows 8 or above, then there is nothing to
2281 // do.
2282 //
2284 }
2285
2286 return status;
2287}
2288
2289VOID
2292 )
2293{
2294 LONG idleTimeoutSnapshot;
2295 LONG idleTimeoutStatus;
2296 LONG idleTimeoutPreviousStatus;
2297 CfxDevice * device;
2298
2299 //
2300 // Get the device object so we can use it for logging
2301 //
2302 device = GetDevice();
2303
2304 //
2305 // Take a snapshot of the idle timeout management status
2306 //
2307 idleTimeoutSnapshot = m_IdleTimeoutStatus;
2308
2309 //
2310 // Set the bit that freezes the status
2311 //
2312 idleTimeoutStatus = idleTimeoutSnapshot | IdleTimeoutStatusFrozen;
2313
2314 //
2315 // Update the status
2316 //
2317 idleTimeoutPreviousStatus = InterlockedExchange(&m_IdleTimeoutStatus,
2318 idleTimeoutStatus);
2319
2320 if (idleTimeoutPreviousStatus != idleTimeoutSnapshot) {
2321 //
2322 // An update of idle timeout status is racing with the freezing of idle
2323 // timeout status
2324 //
2327 "WDFDEVICE %p !devobj %p The driver's S0-idle settings and/or power"
2328 " framework settings did not take effect because they were supplied"
2329 " too late. The driver must ensure that the settings are provided "
2330 "before the first start IRP is completed.",
2331 device->GetHandle(),
2332 device->GetDeviceObject()
2333 );
2335 }
2336
2337 //
2338 // If the driver has specified power framework settings and system managed
2339 // idle timeout is available on this OS, then the driver must have opted for
2340 // system managed idle timeout.
2341 //
2342 if ((0 != (idleTimeoutStatus & IdleTimeoutPoxSettingsSpecified)) &&
2344 (0 == (idleTimeoutStatus & IdleTimeoutSystemManaged))) {
2347 "WDFDEVICE %p !devobj %p The driver specified power framework "
2348 "settings, but did not opt for system-managed idle timeout.",
2349 device->GetHandle(),
2350 device->GetDeviceObject()
2351 );
2353 }
2354}
2355
2356BOOLEAN
2358 VOID
2359 )
2360{
2361 //
2362 // If the value of this constant is changed, the debugger extension needs
2363 // to be fixed as well.
2364 //
2366
2368}
2369
2370BOOLEAN
2372 VOID
2373 )
2374{
2376}
2377
2381 __in PPOX_SETTINGS PoxSettings
2382 )
2383{
2385 IdleTimeoutStatusUpdateResult statusUpdateResult;
2386 PVOID oldPoxSettings = NULL;
2387 BOOLEAN settingsSuccessfullySaved = FALSE;
2388 CfxDevice * device;
2389
2390 //
2391 // We should never get here if system-managed idle timeout is not available
2392 //
2394
2395 //
2396 // Get the device object so we can use it for logging
2397 //
2398 device = GetDevice();
2399
2400 //
2401 // Try to save the driver's power framework settings
2402 //
2404 PoxSettings,
2405 NULL // Comparand
2406 );
2407 if (NULL != oldPoxSettings) {
2408 //
2409 // The driver's power framework settings have already been specified
2410 // earlier. The driver should not be attempting to specify them more
2411 // than once.
2412 //
2416 "WDFDEVICE %p !devobj %p The driver attempted to specify power "
2417 "framework settings more than once. %!STATUS!.",
2418 device->GetHandle(),
2419 device->GetDeviceObject(),
2420 status
2421 );
2423 goto exit;
2424 }
2425 settingsSuccessfullySaved = TRUE;
2426
2427 //
2428 // Try to update the flag that indicates that the client driver has
2429 // specified settings that are to be used when we register with the power
2430 // framework.
2431 //
2432 statusUpdateResult = UpdateIdleTimeoutStatus(
2434 );
2435 switch (statusUpdateResult) {
2437 {
2438 //
2439 // Status is already frozen. Too late to update it.
2440 //
2444 "WDFDEVICE %p !devobj %p Power framework settings must be "
2445 "specified before the first start IRP is completed. %!STATUS!.",
2446 device->GetHandle(),
2447 device->GetDeviceObject(),
2448 status
2449 );
2451 goto exit;
2452 }
2453 break;
2454
2456 {
2457 //
2458 // Status being updated from multiple threads in parallel. Not
2459 // supported.
2460 //
2464 "WDFDEVICE %p !devobj %p Calls to assign S0-idle settings and "
2465 "to specify power framework settings are happening in parallel."
2466 " The driver needs to serialize these calls with respect to "
2467 "each other. %!STATUS!.",
2468 device->GetHandle(),
2469 device->GetDeviceObject(),
2470 status
2471 );
2473 goto exit;
2474 }
2475 break;
2476
2478 {
2479 //
2480 // Status flag was already set. This should never happen for the
2481 // IdleTimeoutPoxSettingsSpecified flag because we have logic in the
2482 // beginning of this function to ensure that only the first caller
2483 // attempts to set this flag.
2484 //
2485 ASSERTMSG(
2486 "Attempt to set the IdleTimeoutPoxSettingsSpecified flag more "
2487 "than once\n", FALSE);
2489 goto exit;
2490 }
2491
2493 {
2495 }
2496 break;
2497
2498 default:
2499 {
2500 ASSERTMSG("Unexpected IdleTimeoutStatusUpdateResult value\n",
2501 FALSE);
2503 goto exit;
2504 }
2505 }
2506
2507 //
2508 // If we get here, we must have a successful status
2509 //
2511
2512exit:
2513 if (FALSE == NT_SUCCESS(status)) {
2514 if (settingsSuccessfullySaved) {
2515 //
2516 // Since a failure has occurred, we must reset the pointer to the
2517 // power framework settings.
2518 //
2520 }
2521 }
2522 return status;
2523}
2524
2526{
2527
2528
2529
2530
2531
2532
2533
2534}
2535
2537 VOID
2539{
2540 m_Owner = NULL;
2541
2542 RtlZeroMemory(&m_Queue[0], sizeof(m_Queue));
2543 RtlZeroMemory(&m_States, sizeof(m_States));
2544
2546
2548}
2549
2551 VOID
2552 )
2553{
2554 if (m_Owner != NULL) {
2555 delete m_Owner;
2556 m_Owner = NULL;
2557 }
2558}
2559
2563 VOID
2564 )
2565{
2566 FxUsbIdleInfo* pInfo;
2568
2569 //
2570 // The field is already set, we are good to go
2571 //
2572 if (m_Owner->m_UsbIdle != NULL) {
2573 return STATUS_SUCCESS;
2574 }
2575
2577
2578 if (pInfo == NULL) {
2580 }
2581
2582 status = pInfo->Initialize();
2583 if (!NT_SUCCESS(status)) {
2584 delete pInfo;
2585 return status;
2586 }
2587
2589 pInfo,
2590 NULL) == NULL) {
2591 //
2592 // This thread was the one that set the field value.
2593 //
2594 DO_NOTHING();
2595 }
2596 else {
2597 //
2598 // Another thread raced in and beat this thread in setting the field,
2599 // just delete our allocation and use the other allocated FxUsbIdleInfo.
2600 //
2601 delete pInfo;
2602 }
2603
2604 return STATUS_SUCCESS;
2605}
2606
2608 __in FxPkgPnp* PkgPnp
2609 ) : m_PoxInterface(PkgPnp)
2610{
2611 ULONG i;
2612
2613 m_UsbIdle = NULL;
2614
2615 m_PkgPnp = PkgPnp;
2616
2617 //
2618 // Default every state to D3 except for system working which is D0 by
2619 // default.
2620 //
2622
2623 for (i = 0; i < PowerSystemMaximum; i++) {
2626 : PowerDeviceD3,
2628 }
2629
2631
2638
2642
2646
2649}
2650
2652 VOID
2653 )
2654{
2655 //
2656 // There are paths which cleanup this object which do not go through the
2657 // pnp state machine, so make sure the power object callback fields are
2658 // freed. In these paths, we are guaranteed PASSIVE_LEVEL b/c there will
2659 // be no dangling references which can cause deletion at a greater IRQL.
2660 //
2662
2663 if (m_UsbIdle != NULL) {
2664 delete m_UsbIdle;
2665 m_UsbIdle = NULL;
2666 }
2667}
2668
2669VOID
2671 VOID
2672 )
2673/*++
2674
2675Routine Description:
2676 Cleans up the power state callback registration for this object.
2677
2678Arguments:
2679 None
2680
2681Return Value:
2682 None
2683
2684 --*/
2685{
2689
2690 }
2691
2692 if (m_PowerCallbackObject != NULL) {
2695 }
2696}
2697
2701 VOID
2702 )
2703/*++
2704
2705Routine Description:
2706 Initialize the object. We will try to register a power state callback so
2707 that we can be informed of when the machine is changing S states. We are
2708 interested in system state changes because we need to know when NOT to write
2709 to the registry (to save wake settings) so that we don't cause a deadlock
2710 in a non power pageable device while moving into Sx.
2711
2712Arguments:
2713 None
2714
2715Return Value:
2716 NTSTATUS
2717
2718 --*/
2719{
2723
2724 RtlInitUnicodeString(&string, L"\\Callback\\PowerState");
2726 &oa,
2727 &string,
2729 NULL,
2730 NULL
2731 );
2732
2733 //
2734 // Create a callback object, but we do not want to be the first ones
2735 // to create it (it should be created way before we load in NTOS
2736 // anyways)
2737 //
2739
2740 if (NT_SUCCESS(status)) {
2744 this
2745 );
2746
2748 //
2749 // Non-critical failure, so we'll free the callback object and keep
2750 // going
2751 //
2754 }
2755 }
2756
2757 //
2758 // Initialize FxPowerIdleMachine
2759 //
2761 if (!NT_SUCCESS(status)) {
2762 return status;
2763 }
2764
2765 return status;
2766}
2767
2768VOID
2773 )
2774/*++
2775
2776Routine Description:
2777 Callback invoked by the power subsystem when the system is changing S states
2778
2779Arguments:
2780 Context - FxPowerPolicyOwnerSettings pointer (the "this" pointer)
2781
2782 Argument1 - Reason why the callback was invoked, we only care about
2783 PO_CB_SYSTEM_STATE_LOCK
2784
2785 Argument2 - State transition that is occurring
2786
2787Return Value:
2788 None
2789
2790 --*/
2791{
2793
2795
2797 return;
2798 }
2799
2801 pThis->m_PkgPnp->GetDriverGlobals(),
2802 NULL
2803 );
2804
2805 if (Argument2 == (PVOID) 0) {
2806 //
2807 // Write out the state if necessary before we turn off the paging path.
2808 //
2809 pThis->m_PkgPnp->SaveState(TRUE);
2810
2811 //
2812 // Exiting S0
2813 //
2814 pThis->m_CanSaveState = FALSE;
2815 }
2816 else if (Argument2 == (PVOID) 1) {
2817 //
2818 // We have reentered S0
2819 //
2820 pThis->m_CanSaveState = TRUE;
2821
2822 //
2823 // Write out the state if necessary now that the paging path is back
2824 //
2825 pThis->m_PkgPnp->SaveState(TRUE);
2826 }
2827
2829 pThis->m_PkgPnp->GetDriverGlobals()
2830 );
2831}
2832
2833/*++
2834
2835The locking model for the Power policy state machine requires that events be enqueued
2836possibly at DISPATCH_LEVEL. It also requires that the state machine be
2837runnable at PASSIVE_LEVEL. Consequently, we have two locks, one DISPATCH_LEVEL
2838lock that guards the event queue and one PASSIVE_LEVEL lock that guards the
2839state machine itself.
2840
2841The Power policy state machine has a few constraints that the PnP state machine
2842doesn't. Sometimes it has to call some driver functions at PASSIVE_LEVEL, but
2843with the disks turned off. This means that these functions absolutely must not
2844page fault. You might think that this means that we should call the driver at
2845DISPATCH_LEVEL, and you'd be right if your only concern were for perfectly
2846safe code. The problem with that approach, though is that it will force much
2847of the rest of the driver to DISPATCH_LEVEL, which will only push the driver
2848writer into using lots of asynchronous work items, which will complicate their
2849code and make it unsafe in a new variety of ways. So we're going to go with
2850PASSIVE_LEVEL here and setting a timeout of 20 seconds. If the driver faults,
2851the timer will fire and log the failure. This also means that the driver must
2852complete these callbacks within 20 seconds. Even beyond that, it means that
2853the work items must be queued onto a special thread, one that once the machine
2854has started to go to sleep, never handles any work items that may fault.
2855
2856Algorithm:
2857
28581) Acquire the Power policy queue lock.
28592) Enqueue the event. events are put at the end of the queue.
28603) Drop the Power policy queue lock.
28614) If the thread is running at PASSIVE_LEVEL, skip to step 6.
28625) Queue a work item onto the special power thread.
28636) Attempt to acquire the state machine lock, with a zero-length timeout (*).
28647) If successful, skip to step 9.
28658) Queue a work item onto the special power thread.
28669) Acquire the state machine lock.
286710) Acquire the Power policy queue lock.
286811) Attempt to dequeue an event.
286912) Drop the Power policyqueue lock.
287013) If there was no event to dequeue, drop the state machine lock and exit.
287114) Execute the state handler. This may involve taking one of the other state
2872 machine queue locks, briefly, to deliver an event.
287315) Go to Step 10.
2874
2875(*) zero length is different then NULL (infinite) being passed for the timeout
2876
2877Implementing this algorithm requires three functions.
2878
2879PowerPolicyProcessEvent -- Implements steps 1-8.
2880_PowerPolicyProcessEventInner -- Implements step 9.
2881PowerPolicyProcessEventInner -- Implements steps 10-15.
2882
2883--*/
2884
2885VOID
2888 __in BOOLEAN ProcessOnDifferentThread
2889 )
2890/*++
2891
2892Routine Description:
2893 This function implements steps 1-8 of the algorithm described above.
2894
2895Arguments:
2896 Event - Current Power event
2897
2898Return Value:
2899
2900 NTSTATUS
2901
2902--*/
2903{
2905 ULONG mask;
2906 KIRQL irql;
2907
2908 //
2909 // Take the lock, raising to DISPATCH_LEVEL.
2910 //
2912
2913 //
2914 // If the input Event is any of the events described by PowerSingularEventMask,
2915 // then check whether it is already queued up. If so, then dont enqueue this
2916 // Event.
2917 //
2921 }
2922 else {
2925 "WDFDEVICE 0x%p !devobj 0x%p current pwr pol state "
2926 "%!WDF_DEVICE_POWER_POLICY_STATE! dropping event "
2927 "%!FxPowerPolicyEvent! because the Event is already enqueued.",
2931
2932 m_PowerPolicyMachine.Unlock(irql);
2933 return;
2934 }
2935 }
2936
2938 //
2939 // The queue is full. Bail.
2940 //
2941 m_PowerPolicyMachine.Unlock(irql);
2942
2943 ASSERT(!"The Power queue is full. This shouldn't be able to happen.");
2944 return;
2945 }
2946
2950 "WDFDEVICE 0x%p !devobj 0x%p current pwr pol state "
2951 "%!WDF_DEVICE_POWER_POLICY_STATE! dropping event "
2952 "%!FxPowerPolicyEvent! because of a closed queue",
2956
2957 //
2958 // The queue is closed. Bail
2959 //
2960 m_PowerPolicyMachine.Unlock(irql);
2961
2962 return;
2963 }
2964
2965 //
2966 // Enqueue the event. Whether the event goes on the front
2967 // or the end of the queue depends on which event it is and if we are the
2968 // PPO or not.
2969 //
2970 // Yes, mask could be a member variable of m_PowerPolicyMachine, but why
2971 // waste 4 bytes when it is very easy to figure out?
2972 //
2975
2976 if (Event & mask) {
2977 //
2978 // Stick it on the front of the queue, making it the next event that
2979 // will be processed if, otherwise let these events go by.
2980 //
2982 }
2983 else {
2984 //
2985 // Stick it on the end of the queue.
2986 //
2988 }
2989
2990 //
2991 // Drop the lock.
2992 //
2993 m_PowerPolicyMachine.Unlock(irql);
2994
2995 //
2996 // Now, if we are running at PASSIVE_LEVEL, attempt to run the state
2997 // machine on this thread. If we can't do that, then queue a work item.
2998 //
3000 irql,
3001 ProcessOnDifferentThread
3002 )) {
3003
3004 LONGLONG timeout = 0;
3005
3008
3009 if (FxWaitLockInternal::IsLockAcquired(status)) {
3011
3012 //
3013 // We now hold the state machine lock. So call the function that
3014 // dispatches the next state.
3015 //
3017
3018 //
3019 // The pnp state machine should be the only one deleting the object
3020 //
3021 ASSERT(info.m_DeleteObject == FALSE);
3022
3025
3026 info.Evaluate(this);
3027
3028 return;
3029 }
3030 }
3031
3032 //
3033 // The tag added above will be released when the work item runs
3034 //
3035
3036 //
3037 // For one reason or another, we couldn't run the state machine on this
3038 // thread. So queue a work item to do it. If m_PnPWorkItemEnqueuing
3039 // is non-zero, that means that the work item is already being enqueued
3040 // on another thread. This is significant, since it means that we can't do
3041 // anything with the work item on this thread, but it's okay, since the
3042 // work item will pick up our work and do it.
3043 //
3045}
3046
3047VOID
3052 )
3053{
3054
3056
3057 //
3058 // Take the state machine lock.
3059 //
3060 This->m_PowerPolicyMachine.m_StateMachineLock.AcquireLock(
3061 This->GetDriverGlobals()
3062 );
3063
3064 //
3065 // Call the function that will actually run the state machine.
3066 //
3067 This->PowerPolicyProcessEventInner(Info);
3068
3069 //
3070 // We are being called from the work item and m_WorkItemRunning is > 0, so
3071 // we cannot be deleted yet.
3072 //
3073 ASSERT(Info->SomethingToDo() == FALSE);
3074
3075 //
3076 // Now release the lock
3077 //
3078 This->m_PowerPolicyMachine.m_StateMachineLock.ReleaseLock(
3079 This->GetDriverGlobals()
3080 );
3081}
3082
3083VOID
3086 )
3087{
3090 ULONG i;
3091 KIRQL irql;
3092
3093 if (IsPowerPolicyOwner()) {
3095
3096 //
3097 // Process as many events as we can.
3098 //
3099 for ( ; ; ) {
3101
3102 //
3103 // Get an event from the queue.
3104 //
3106
3109
3110 //
3111 // The queue is empty.
3112 //
3113 m_PowerPolicyMachine.Unlock(irql);
3114 return;
3115 }
3116
3118
3119 //
3120 // At this point, we need to determine whether we can process this
3121 // event.
3122 //
3124 //
3125 // These are always possible to handle.
3126 //
3127 DO_NOTHING();
3128 }
3129 else {
3130 //
3131 // Check to see if this state can handle new events, ie if this
3132 // is a green dot (queue open) or red dot (queue *not* open) state.
3133 //
3134 if (entry->StateInfo.Bits.QueueOpen == FALSE) {
3135 //
3136 // This state can't handle new events.
3137 //
3138 m_PowerPolicyMachine.Unlock(irql);
3139 return;
3140 }
3141 }
3142
3143 //
3144 // If the event obtained from the queue was a singular event, then
3145 // clear the flag to allow other similar events to be put into this
3146 // queue for processing.
3147 //
3150 }
3151
3153 m_PowerPolicyMachine.Unlock(irql);
3154
3155 //
3156 // Find the entry in the power policy state table that corresponds
3157 // to this event.
3158 //
3159 newState = WdfDevStatePwrPolNull;
3160
3161 if (entry->FirstTargetState.PowerPolicyEvent == event) {
3162 newState = entry->FirstTargetState.TargetState;
3163
3164 DO_EVENT_TRAP(&entry->FirstTargetState);
3165 }
3166 else if (entry->OtherTargetStates != NULL) {
3167 for (i = 0;
3168 entry->OtherTargetStates[i].PowerPolicyEvent != PwrPolNull;
3169 i++) {
3170 if (entry->OtherTargetStates[i].PowerPolicyEvent == event) {
3171 newState = entry->OtherTargetStates[i].TargetState;
3172 DO_EVENT_TRAP(&entry->OtherTargetStates[i]);
3173 break;
3174 }
3175 }
3176 }
3177
3178 if (newState == WdfDevStatePwrPolNull) {
3179 //
3180 // This state doesn't respond to the event. Just throw the event
3181 // away.
3182 //
3185 "WDFDEVICE 0x%p !devobj 0x%p current pwr pol state "
3186 "%!WDF_DEVICE_POWER_POLICY_STATE! dropping event "
3187 "%!FxPowerPolicyEvent!", m_Device->GetHandle(),
3190
3191 if ((entry->StateInfo.Bits.KnownDroppedEvents & event) == 0) {
3192 COVERAGE_TRAP();
3193
3196 "WDFDEVICE 0x%p !devobj 0x%p current state "
3197 "%!WDF_DEVICE_POWER_POLICY_STATE!, policy event "
3198 "%!FxPowerPolicyEvent! is not a known dropped "
3199 "event, known dropped events are %!FxPowerPolicyEvent!",
3202 event, entry->StateInfo.Bits.KnownDroppedEvents);
3203
3204
3205 }
3206
3207 //
3208 // Failsafes for events which have required processing in them.
3209 //
3210 switch (event) {
3211 case PwrPolSx:
3212 //
3213 // The Sx handling code expects that the state machine
3214 // complete the Sx irp. (S0 irps are never pended). Since
3215 // we don't have a state to transition to that will complete
3216 // the request, do so now.
3217 //
3218 // (This can legitimately happen if a PDO is disabled and
3219 // the machines moves into an Sx state.)
3220 //
3222 break;
3223
3225 //
3226 // This state did not handle the event and event got
3227 // dropped. However some state is definitely going to wait
3228 // for this event. That's why we need m_EventDropped flag.
3229 // If we didn't have this flag there will be no way to know
3230 // if the event got dropped and some state will end up
3231 // waiting for it indefinitely.
3232 //
3234 break;
3235
3238 break;
3239
3240 case PwrPolWakeSuccess:
3241 case PwrPolWakeFailed:
3242 //
3243 // This state did not handle the event and event got
3244 // dropped. However some state is definitely going to wait
3245 // for this event. That's why we need
3246 // m_WakeCompletionEventDropped flag. If we didn't have this
3247 // flag there will be no way to know if the event got
3248 // dropped and some state will end up waiting for it
3249 // indefinitely.
3250 //
3252 break;
3253
3254 default:
3255 DO_NOTHING();
3256 break;
3257 }
3258 }
3259 else {
3260 //
3261 // Now enter the new state.
3262 //
3263 PowerPolicyEnterNewState(newState);
3264 }
3265 }
3266 }
3267 else {
3268 //
3269 // Process as many events as we can.
3270 //
3271 for ( ; ; ) {
3273
3274#pragma prefast(suppress:__WARNING_DEREF_NULL_PTR, "The current power policy state will always be in the table so entry will never be NULL")
3277 );
3278
3279 //
3280 // Get an event from the queue.
3281 //
3283
3285 //
3286 // The queue is empty.
3287 //
3288 m_PowerPolicyMachine.Unlock(irql);
3289 return;
3290 }
3291
3293
3294 //
3295 // At this point, we need to determine whether we can process this
3296 // event.
3297 //
3299 //
3300 // These are always possible to handle.
3301 //
3302 DO_NOTHING();
3303 }
3304 else {
3305 //
3306 // Check to see if this state can handle new events, ie if this
3307 // is a green dot (queue open) or red dot (queue *not* open) state.
3308 //
3309 if (entry->QueueOpen == FALSE) {
3310 //
3311 // This state can't handle new events.
3312 //
3313 m_PowerPolicyMachine.Unlock(irql);
3314 return;
3315 }
3316 }
3317
3318 //
3319 // If the event obtained from the queue was a singular event, then
3320 // clear the flag to allow other similar events to be put into this
3321 // queue for processing.
3322 //
3325 }
3326
3328 m_PowerPolicyMachine.Unlock(irql);
3329
3330 if (entry != NULL && entry->TargetStatesCount > 0) {
3331 for (i = 0; i < entry->TargetStatesCount; i++) {
3332 if (event == entry->TargetStates[i].PowerPolicyEvent) {
3333 DO_EVENT_TRAP(&entry->TargetStates[i]);
3334
3335 //
3336 // Now enter the new state.
3337 //
3339 entry->TargetStates[i].TargetState);
3340 break;
3341 }
3342 }
3343 }
3344 }
3345 }
3346}
3347
3348VOID
3351 )
3352/*++
3353
3354Routine Description:
3355 This function looks up the handler for a state and then calls it.
3356
3357Arguments:
3358 Event - Current power plicy event
3359
3360Return Value:
3361
3362 NTSTATUS
3363
3364--*/
3365{
3367 WDF_DEVICE_POWER_POLICY_STATE currentState, newState;
3369 FxWatchdog watchdog(this);
3370
3371 currentState = m_Device->GetDevicePowerPolicyState();
3372 newState = NewState;
3373
3374 while (newState != WdfDevStatePwrPolNull) {
3377 "WDFDEVICE 0x%p !devobj 0x%p entering power policy state "
3378 "%!WDF_DEVICE_POWER_POLICY_STATE! from "
3379 "%!WDF_DEVICE_POWER_POLICY_STATE!", m_Device->GetHandle(),
3380 m_Device->GetDeviceObject(), newState, currentState);
3381
3383 //
3384 // Callback for leaving the old state
3385 //
3386 RtlZeroMemory(&data, sizeof(data));
3387
3389 data.Data.LeaveState.CurrentState = currentState;
3390 data.Data.LeaveState.NewState = newState;
3391
3392 m_PowerPolicyStateCallbacks->Invoke(currentState,
3395 &data);
3396 }
3397
3400
3402 //
3403 // Callback for entering the new state
3404 //
3405 RtlZeroMemory(&data, sizeof(data));
3406
3408 data.Data.EnterState.CurrentState = currentState;
3409 data.Data.EnterState.NewState = newState;
3410
3414 &data);
3415 }
3416
3418 currentState = newState;
3419
3420 entry = GetPowerPolicyTableEntry(currentState);
3421
3422 //
3423 // And call the state handler, if there is one.
3424 //
3425 if (entry->StateFunc != NULL) {
3426 watchdog.StartTimer(currentState);
3427 newState = entry->StateFunc(this);
3428 watchdog.CancelTimer(currentState);
3429
3430 //
3431 // Validate the return value if FX_STATE_MACHINE_VERIFY is enabled
3432 //
3433 VALIDATE_PWR_POL_STATE(currentState, newState);
3434
3435 }
3436 else {
3437 newState = WdfDevStatePwrPolNull;
3438 }
3439
3441 //
3442 // Callback for post processing the new state
3443 //
3444 RtlZeroMemory(&data, sizeof(data));
3445
3447 data.Data.PostProcessState.CurrentState = currentState;
3448
3449 m_PowerPolicyStateCallbacks->Invoke(currentState,
3452 &data);
3453 }
3454 }
3455}
3456
3457
3458/*++
3459
3460One of the goals of the Driver Framework is to make it really easy to write
3461a driver for a device which keeps the device in the lowest useful power state
3462at all times. This could (and often does) mean that the device remains in the
3463D0 state whenever the machine is running. Or it could mean that the device is
3464only in D0 when there are outstanding IRPs in its queues. Or it could mean
3465that the device is in D0 whenever the driver explicitly says that it has to be.
3466
3467Consequently, the Power Policy state machine has a bunch of states that relate
3468only to managing the state of the device while the system is running, possibly
3469allowing the device to "idle-out" to low power states while it isn't being
3470heavily used. Once that idle-out process has begun, there needs to be some
3471way for the Framework I/O Package and the driver itself to tell the Power Policy
3472engine that the device must, for some time at least, be in the D0 (high-power,
3473working) state. The problem is made much harder by the fact that the driver
3474(or the Framework itself) probably has to stall some operation while the device
3475is brought back into the D0 state.
3476
3477So we've created two operations, PowerReference and PowerDereference, which
3478tell the Power Policy state machine when a device needs to be in the D0 state.
3479The I/O Package uses these internally, and the driver may as well. We want
3480these operations to be as light-weight as possible, so that a driver never
3481experiences meaningful degradation in performance simply because it chose to
3482be a good electricity consumer and enabled idle-time power management.
3483Fortunately, the Framework I/O package can significantly reduce the number of
3484times that it needs to call these functions by only calling them when the
3485queue state transitions from empty to non-empty or back again. A caller within
3486the driver itself will need to be aware that their usage can be somewhat
3487expensive.
3488
3489Furthermore, these functions need to be callable at both PASSIVE_LEVEL and
3490DISPATCH_LEVEL. This really necessitates two versions, as a PASSIVE_LEVEL
3491user within the driver probably would like us to block while the device is
3492moved into D0, while a DISPATCH_LEVEL user (or the Framework I/O package) would
3493prefer a much more asynchronous mode of use.
3494
3495Dealing with these multiple modes involves a fairly complex locking scheme. Here
3496is a statement of algorithm.
3497
3498Locks:
3499
3500A) Idle Transition Spinlock - DISPATCH_LEVEL
3501B) Device in D0 Notification Event - PASSIVE_LEVEL
3502
3503Device-wide variables:
3504
3505 I) Power Reference Count - number of outstanding reasons to be in D0.
3506 II) Idle Timout -- value set by the driver which governs the idle timer
3507III) Transitioning -- boolean indicating whether we're in the process of
3508 moving the device from Dx to D0.
3509
3510PowerDecrement:
3511
35121) Take Idle Transition lock.
35133) Decrement of the device-wide power reference count.
35143) If that's not zero, drop the lock and exit.
35154) Set the driver's Idle Timer.
35165) Drop the Idle Transition lock.
3517
3518PowerIncrement:
3519
3520 1) Take Idle Transition lock.
3521 2) Increment of the device-wide power reference count.
3522 3) If that's 1, then we're transitioning out of idle. Goto Step 6.
3523 4) If Transitioning == TRUE, we need to wait, Goto Step 13.
3524 5) Drop the Idle Transition lock. Exit.
3525 6) Cancel the Idle Timer. If that was unsuccessful, then the timer was not
3526 set, which means that the device has either moved out of D0 or it is moving
3527 out of D0. Goto Step 8.
3528 7) Drop the Idle Transition lock. Exit.
3529 8) The timer was not succefully cancelled. This means that we have timed out
3530 in the past and we need to put the device back in D0.
3531 Set Transitioning = TRUE.
3532 9) Drop Idle Transition lock.
353310) Reset the D0 Notification Event.
353411) Send IoPresent event to the Power Policy state machine.
353512) If IRQL == DISPATCH_LEVEL goto Step 15.
353613) Wait for the D0 Notification Event.
353714) Exit.
353815) Note that I/O needs to be restarted later.
353916) Exit STATUS_PENDING.
3540
3541--*/
3545 )
3546{
3548
3549 This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.Start();
3550
3551 This->PowerProcessEvent(PowerImplicitD0);
3552
3553 //
3554 // Wait for the successful power up before starting any idle timers. If
3555 // the power up fails, we will not send a power policy stop from the pnp
3556 // engine.
3557 //
3558 return WdfDevStatePwrPolNull;
3559}
3560
3564 )
3565/*++
3566
3567Routine Description:
3568 The power state policy state machine has powered up. Tell the active/idle
3569 state machine to initialize.
3570
3571 The device needs to be in D0 before the active/idle state machine registers
3572 with the power framework. Therefore, we wait until the power state machine
3573 has brought the device into D0 before we tell the active/idle state machine
3574 to start. Moving the device into D0 allows us to touch hardware if needed
3575 (for example, to determine the number of components in the device) before
3576 registering with the power framework.
3577
3578Arguments:
3579 This - instance of the state machine
3580
3581Return Value:
3582 WdfDevStatePwrPolNull
3583
3584--*/
3585{
3588
3589 //
3590 // The decision regarding whether or not the power framework determines the
3591 // idle timeout is now "frozen" and cannot be changed unless the device is
3592 // stopped and restarted.
3593 //
3594 This->m_PowerPolicyMachine.m_Owner->
3595 m_IdleSettings.m_TimeoutMgmt.FreezeIdleTimeoutManagementStatus(
3596 This->GetDriverGlobals()
3597 );
3598
3599 status = This->m_PowerPolicyMachine.m_Owner->
3600 m_PoxInterface.InitializeComponents();
3601 if (FALSE == NT_SUCCESS(status)) {
3603 }
3604
3606}
3607
3611 )
3612/*++
3613
3614Routine Description:
3615 We failed to initialize the device's components. We have already started the
3616 power state machine, so ask it to run down before we tell the PNP state
3617 machine to fail device start.
3618
3619Arguments:
3620 This - instance of the state machine
3621
3622Return Value:
3623 WdfDevStatePwrPolNull
3624
3625--*/
3626{
3628
3629 This->PowerProcessEvent(PowerImplicitD3);
3630
3631 return WdfDevStatePwrPolNull;
3632}
3633
3637 )
3638/*++
3639
3640Routine Description:
3641 The power policy state machine has successfully started. Notify the pnp
3642 state machine that this has occurred and then tell the active/idle state
3643 machine to move to an active state.
3644
3645Arguments:
3646 This - instance of the state machine
3647
3648Return Value:
3649 WdfDevStatePwrPolStartingDecideS0Wake
3650
3651 --*/
3652{
3654
3655 This->PnpProcessEvent(PnpEventPwrPolStarted);
3656
3658}
3659
3663 )
3664/*++
3665
3666Routine Description:
3667 Attempting to bring the device into the D0 state failed. Report the status
3668 to pnp.
3669
3670Arguments:
3671 This - instance of the state machine
3672
3673Return Value
3674 WdfDevStatePwrPolNull
3675
3676 --*/
3677{
3678 KIRQL irql;
3679
3681
3682 This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.Stop();
3683
3684 //
3685 // We raise IRQL to dispatch level so that pnp is forced onto its own thread
3686 // to process the PwrPolStartFailed event. If pnp is on the power thread when
3687 // it processes the event and it tries to delete the dedicated thread, it
3688 // will deadlock waiting for the thread its on to exit.
3689 //
3690 Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql);
3691 This->PnpProcessEvent(PnpEventPwrPolStartFailed);
3692 Mx::MxLowerIrql(irql);
3693
3694 return WdfDevStatePwrPolNull;
3695}
3696
3700 )
3701{
3703
3704 This->PowerPolicyChildrenCanPowerUp();
3705
3706 //
3707 // Save idle state if it is dirty. We check when deciding the S0 state
3708 // because any change in the S0 idle settings will go through this state.
3709 //
3710 This->SaveState(TRUE);
3711
3712 //
3713 // If necessary update the idle timeout hint to the power framework
3714 //
3715 This->m_PowerPolicyMachine.m_Owner->m_PoxInterface.UpdateIdleTimeoutHint();
3716
3717 if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.Enabled) {
3718 if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.WakeFromS0Capable) {
3719 //
3720 // We can idle out and wake from S0
3721 //
3723 }
3724 else {
3725 //
3726 // We can idle out, but not wake from the idle state
3727 //
3729 }
3730 }
3731
3733}
3734
3738 )
3739{
3741
3742 //
3743 // Enable the idle state machine. This will release any threads who are
3744 // waiting for the device to return to D0.
3745 //
3746 This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.EnableTimer();
3747
3748 return WdfDevStatePwrPolNull;
3749}
3750
3754 )
3755/*++
3756
3757Routine Description:
3758 We are now idle. Tell the active/idle state machine to move us to an idle
3759 state.
3760
3761Arguments:
3762 This - instance of the state machine
3763
3764Return Value:
3765 WdfDevStatePwrPolNull
3766
3767 --*/
3768{
3769 BOOLEAN canPowerDown;
3771
3772 canPowerDown = This->m_PowerPolicyMachine.m_Owner->
3773 m_PoxInterface.DeclareComponentIdle();
3774
3775 //
3776 // If we are using driver-managed idle timeout we can power down immediately
3777 // and so we jump to the next state (that initiates power down) immediately.
3778 // If we are using system-managed idle timeout, we wait in the current state
3779 // for device-power-not-required notification.
3780 //
3781 return (canPowerDown ?
3784}
3785
3789 )
3790/*++
3791
3792Routine Description:
3793 We are idle, but still in D0. We need to return to an active state.
3794
3795Arguments:
3796 This - instance of the state machine
3797
3798Return Value:
3799 WdfDevStatePwrPolNull
3800
3801 --*/
3802{
3804
3805 This->m_PowerPolicyMachine.m_Owner->
3806 m_PoxInterface.RequestComponentActive();
3807
3809}
3810
3814 )
3815/*++
3816
3817Routine Description:
3818 We are idle, but still in D0. System is going to a low power state.
3819
3820Arguments:
3821 This - instance of the state machine
3822
3823Return Value:
3824 WdfDevStatePwrPolNull
3825
3826 --*/
3827{
3829
3830 //
3831 // Normally we'd make the component active when we get the device-power-
3832 // required notification. But we've not yet processed the device-power-not-
3833 // required notification, so we will not be processing the device-power-
3834 // required notification either. So let's activate the component before we
3835 // process the Sx IRP.
3836 //
3837 This->m_PowerPolicyMachine.m_Owner->
3838 m_PoxInterface.RequestComponentActive();
3839
3841}
3842
3846 )
3847/*++
3848
3849Routine Description:
3850 We are idle, but still in D0. Power policy state machine is being stopped.
3851
3852Arguments:
3853 This - instance of the state machine
3854
3855Return Value:
3856 WdfDevStatePwrPolNull
3857
3858 --*/
3859{
3861
3862 //
3863 // Normally we'd make the component active when we get the device-power-
3864 // required notification. But we've not yet processed the device-power-not-
3865 // required notification, so we will not be processing the device-power-
3866 // required notification either. So let's activate the component before we
3867 // process the stop/remove request.
3868 //
3869 This->m_PowerPolicyMachine.m_Owner->
3870 m_PoxInterface.RequestComponentActive();
3871
3873}
3874
3878 )
3879{
3880 BOOLEAN poweredDown;
3881 NTSTATUS notifyPowerDownStatus;
3882
3884
3885 //
3886 // Notify the device power requirement state machine that we are about to
3887 // power down.
3888 //
3889 notifyPowerDownStatus = This->m_PowerPolicyMachine.m_Owner->
3890 m_PoxInterface.NotifyDevicePowerDown();
3891 if (FALSE == NT_SUCCESS(notifyPowerDownStatus)) {
3892 //
3893 // We couldn't notify the device power requirement state machine that
3894 // we are about to power down, because the "device-power-required"
3895 // notification has already arrived. So we should not power down at this
3896 // time. Revert back to the started state.
3897 //
3899 }
3900
3901 poweredDown = This->PowerPolicyCanIdlePowerDown(
3902 This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.DxState
3903 );
3904
3905 if (poweredDown == FALSE) {
3906 //
3907 // Upon failure, revert back to the started state.
3908 //
3910 }
3911
3912 return WdfDevStatePwrPolNull;
3913}
3914
3918 )
3919/*++
3920
3921Routine Description:
3922 The device idled out and we sent the Dx request. The power state machine has
3923 gone as far as stopping I/O is waiting to be notified to complete the Dx
3924 process. Send the PowerCompleteDx event to move the device fully into Dx.
3925
3926Arguments:
3927 This - instance of the state machine
3928
3929Return Value:
3930 WdfDevStatePwrPolNull
3931
3932 --*/
3933{
3936
3937 This->PowerProcessEvent(PowerCompleteDx);
3938
3939 return WdfDevStatePwrPolNull;
3940}
3941
3945 )
3946/*++
3947
3948Routine Description:
3949 The device was in the WaitingUnarmed state and received a PwrPolIoPresent
3950 event. Before committing the device to move back to D0, check to see if
3951 the device has returned to an idle state. This can easily happen if the
3952 driver causes a power reference in D0Exit accidentally and the power
3953 reference is removed before exiting the function.
3954
3955Arguments:
3956 This - instance of the state machine
3957
3958Return Value:
3959 new state
3960
3961 --*/
3962{
3964
3965 //
3966 // If QueryReturnToIdle returns TRUE, return to the waiting state
3967 //
3968 if (This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.QueryReturnToIdle()) {
3970 }
3971 else {
3973 }
3974}
3975
3979 )
3980{
3982
3984
3985 //
3986 // Attempt to get back to the D0 state
3987 //
3988 This->m_PowerPolicyMachine.m_Owner->
3989 m_PoxInterface.RequestComponentActive();
3990 status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry);
3991
3992 if (!NT_SUCCESS(status)) {
3993 COVERAGE_TRAP();
3995 }
3996
3997 return WdfDevStatePwrPolNull;
3998}
3999
4003 )
4004/*++
4005
4006Routine Description:
4007 The device was in a Dx unarmed for wake while in S0 and is now being brought
4008 into the D0 state. The device is currently in a partial D0 state (HW
4009 started), move it into the full D0 state by sending PowerCompleteD0 to the
4010 power state machine.
4011
4012Arguments:
4013 This - instance of the state machine
4014
4015Return Value:
4016 WdfDevStatePwrPolNull
4017
4018 --*/
4019{
4021
4022 This->m_PowerPolicyMachine.m_Owner->
4023 m_PoxInterface.DeviceIsPoweredOn();
4024
4025 This->PowerProcessEvent(PowerCompleteD0);
4026
4027 return WdfDevStatePwrPolNull;
4028}
4029
4033 )
4034{
4035 SYSTEM_POWER_STATE systemState;
4036
4039
4040 systemState = This->PowerPolicyGetPendingSystemState();
4041
4042 if (This->PowerPolicyIsWakeEnabled() &&
4043 This->PowerPolicyCanWakeFromSystemState(systemState)) {
4045 }
4046 else {
4048 }
4049}
4050
4054 )
4055{
4058
4060
4061 result = This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer();
4062 ASSERT(result);
4064
4065 status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry);
4066
4067 //
4068 // We are currently in Dx and not armed for wake. While the current Dx
4069 // state may not be the same Dx state we would be for Sx, we can't get to
4070 // D0 to arm ourselves for Sx wake so just leave ourselves as is.
4071 //
4072 if (!NT_SUCCESS(status)) {
4074 This->GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP,
4075 "Failed to allocate D0 request to disarm from wake from S0 to allow "
4076 "arm for wake from Sx, %!STATUS!", status);
4077
4078 COVERAGE_TRAP();
4079
4080 //
4081 // If D0 IRP allocation fails, we don't treat that as an error. Instead,
4082 // we just let the device remain in Dx without arming it for
4083 // wake-from-Sx, even though the driver had enabled wake-from-Sx.
4084 //
4086 }
4087
4088 return WdfDevStatePwrPolNull;
4089}
4090
4094 )
4095/*++
4096
4097Routine Description:
4098 The machine is going into Sx while the device was in Dx. We have started
4099 the D0 process. The power state machine has moved the device into the HW
4100 working state and is waiting to be notified to complete the D0 process.
4101 Send the PowerCompleteD0 event to complete it.
4102
4103Arguments:
4104 This - instance of the state machine
4105
4106Return Value:
4107 WdfDevStatePwrPolNull
4108
4109 --*/
4110{
4113
4114 This->PowerProcessEvent(PowerCompleteD0);
4115
4116 return WdfDevStatePwrPolNull;
4117}
4118
4122 )
4123/*++
4124
4125Routine Description:
4126 Power up failed in the power state machine. Complete the pending system
4127 power irp with success (system ignores the results) even if the Dx irp
4128 failed.
4129
4130Arguments:
4131 This - instance of the state machine
4132
4133Return Value:
4134 new state WdfDevStatePwrPolDevicePowerRequestFailed
4135
4136 --*/
4137{
4139
4140 This->PowerPolicyCompleteSystemPowerIrp();
4141
4143}
4144
4148 )
4149/*++
4150
4151Routine Description:
4152 Checks to see if the device should move down the power pagable wake path
4153 or the NP path.
4154
4155Arguments:
4156 This - instance of the state machine
4157
4158Return Value:
4159 new state
4160
4161 --*/
4162{
4163 ULONG flags;
4165
4167
4168 deviceObject.SetObject(This->m_Device->GetDeviceObject());
4170
4171 if (flags & DO_POWER_PAGABLE) {
4172 ASSERT((flags & DO_POWER_INRUSH) == 0);
4173
4175 }
4176 else {
4177 //
4178 // DO_POWER_INRUSH also gets us to this state, but since it is mutually
4179 // exclusive with DO_POWER_PAGABLE, we don't need to check for it
4180 //
4182 }
4183}
4184
4188 )
4189/*++
4190
4191Routine Description:
4192 The device is in partial Dx (I/O has stopped) and will now be armed for wake.
4193 Complete the going Dx transition by sending a PowerCompleteDx irp to the
4194
4195Arguments:
4196 This - instance of the state machine
4197
4198Return Value:
4199 new state
4200
4201 --*/
4202{
4204 ULONG wakeReason;
4205
4208
4209 ASSERT(This->PowerPolicyCanWakeFromSystemState(
4210 This->PowerPolicyGetPendingSystemState()
4211 ));
4212
4213 wakeReason = This->PowerPolicyGetCurrentWakeReason();
4214
4215 status = This->m_PowerPolicyMachine.m_Owner->m_DeviceArmWakeFromSx.Invoke(
4216 This->m_Device->GetHandle(),
4219 );
4220
4221 if (!NT_SUCCESS(status)) {
4223 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
4224 "WDFDEVICE %p Failed to arm for wake from Sx, %!STATUS!",
4225 This->m_Device->GetHandle(), status);
4226
4228 }
4229
4230 //
4231 // If the PDO is the Power Policy owner, then enable wake at bus, otherwise
4232 // the power state machine will enable wake at bus.
4233 //
4234 if (This->m_Device->IsPdo()) {
4235 status = This->PowerEnableWakeAtBusOverload();
4236 if (!NT_SUCCESS(status)) {
4238 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
4239 "WDFDEVICE %p Failed to Enable Wake at Bus, %!STATUS!",
4240 This->m_Device->GetHandle(), status);
4242 }
4243 }
4244
4245 This->PowerProcessEvent(PowerCompleteDx);
4246
4247 return WdfDevStatePwrPolNull;
4248}
4249
4253 )
4254{
4257
4259 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
4260 "reverting arm for wake from Sx due to failure to allocate wait wake "
4261 "request or wait wake request completed immeidately. Device will *NOT* "
4262 "be armed for wake from Sx");
4263
4264 //
4265 // Enable calls should be matched with Disable calls even in the failure
4266 // cases. However, for the Enable wake at bus failure, we do not call the
4267 // disable wake at bus method as we try to keep the failure behavior
4268 // consistent with the Power State machine. Only the Device Disarm wake
4269 // callback will be invoked here.
4270 //
4271 This->PowerPolicyDisarmWakeFromSx();
4272
4273 //
4274 // attempt to cancel ww
4275 //
4276 if (This->PowerPolicyCancelWaitWake() == FALSE &&
4277 This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
4279 }
4280
4281 return WdfDevStatePwrPolNull;
4282}
4283
4287 )
4288{
4290 This->PowerPolicyCompleteSystemPowerIrp();
4291
4292 return WdfDevStatePwrPolNull;
4293}
4294
4298 )
4299{
4302
4303 if (This->PowerPolicyCancelWaitWake() == FALSE &&
4304 This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
4306 }
4307
4308 return WdfDevStatePwrPolNull;
4309}
4310
4314 )
4315{
4318
4319 //
4320 // Make a note of the fact that system was woken by
4321 // a wake interrupt of this device
4322 //
4323 This->m_SystemWokenByWakeInterrupt = TRUE;
4324
4325 if (This->PowerPolicyCancelWaitWake() == FALSE &&
4326 This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
4327
4329 }
4330
4331 return WdfDevStatePwrPolNull;
4332}
4333
4337 )
4338{
4340
4343
4344 status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry);
4345
4346 if (!NT_SUCCESS(status)) {
4347 COVERAGE_TRAP();
4349 }
4350
4351 return WdfDevStatePwrPolNull;
4352}
4353
4357 )
4358{
4361
4362 //
4363 // If the PDO is the Power Policy owner, then disable wake at bus, otherwise
4364 // the power state machine will disable wake at bus.
4365 //
4366 if (This->m_Device->IsPdo()) {
4367 This->PowerDisableWakeAtBusOverload();
4368 }
4369
4370 This->PowerPolicyDisarmWakeFromSx();
4371
4373}
4374
4378 )
4379{
4381
4384
4385 status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry);
4386
4387 if (!NT_SUCCESS(status)) {
4388 COVERAGE_TRAP();
4390 }
4391
4392 return WdfDevStatePwrPolNull;
4393}
4394
4398 )
4399{
4402
4403 //
4404 // If the PDO is the Power Policy owner, then disable wake at bus, otherwise
4405 // the power state machine will enable wake at bus.
4406 //
4407 if (This->m_Device->IsPdo()) {
4408 This->PowerDisableWakeAtBusOverload();
4409 }
4410
4411 This->m_PowerPolicyMachine.m_Owner->m_DeviceWakeFromSxTriggered.Invoke(
4412 This->m_Device->GetHandle()
4413 );
4414
4415 This->PowerPolicyDisarmWakeFromSx();
4416
4418}
4419
4423 )
4424/*++
4425
4426Routine Description:
4427 The device is in partial Dx (I/O has stopped) and will now be armed for wake.
4428 Complete the going Dx transition by sending a PowerCompleteDx irp to the
4429 power state machine.
4430
4431Arguments:
4432 This - instance of the state machine
4433
4434Return Value:
4435 new state
4436
4437 --*/
4438{
4440 ULONG wakeReason;
4441
4444
4445 ASSERT(This->PowerPolicyCanWakeFromSystemState(
4446 This->PowerPolicyGetPendingSystemState()
4447 ));
4448
4449 wakeReason = This->PowerPolicyGetCurrentWakeReason();
4450
4451 status = This->m_PowerPolicyMachine.m_Owner->m_DeviceArmWakeFromSx.Invoke(
4452 This->m_Device->GetHandle(),
4455 );
4456
4457 if (!NT_SUCCESS(status)) {
4459 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
4460 "WDFDEVICE %p Failed to arm for wake from Sx, %!STATUS!",
4461 This->m_Device->GetHandle(), status);
4462
4464 }
4465
4466 //
4467 // If the PDO is the Power Policy owner, then enable wake at bus, otherwise
4468 // the power state machine will enable wake at bus.
4469 //
4470 if (This->m_Device->IsPdo()) {
4471 status = This->PowerEnableWakeAtBusOverload();
4472 if (!NT_SUCCESS(status)) {
4474 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
4475 "WDFDEVICE %p Failed to Enable Wake at Bus, %!STATUS!",
4476 This->m_Device->GetHandle(), status);
4478 }
4479 }
4480
4481 This->PowerProcessEvent(PowerCompleteDx);
4482
4483 return WdfDevStatePwrPolNull;
4484}
4485
4489 )
4490{
4493
4495 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
4496 "reverting arm for wake from Sx due to failure to allocate wait wake "
4497 "request or wait wake request completed immeidately. Device will *NOT* "
4498 "be armed for wake from Sx");
4499
4500 //
4501 // Enable calls should be matched with Disable calls even in the failure
4502 // cases. However, for the Enable wake at bus failure, we do not call the
4503 // disable wake at bus method as we try to keep the failure behavior
4504 // consistent with the Power State machine. Only the Device Disarm wake
4505 // callback will be invoked here.
4506 //
4507 This->PowerPolicyDisarmWakeFromSx();
4508
4509 //
4510 // attempt to cancel ww
4511 //
4512 if (This->PowerPolicyCancelWaitWake() == FALSE &&
4513 This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
4515 }
4516
4517 return WdfDevStatePwrPolNull;
4518}
4519
4523 )
4524/*++
4525
4526Routine Description:
4527 Power down failed in the power state machine. Cancel the wait wake irp
4528 that was just sent down and revert the arming before moving to the failed
4529 state.
4530
4531Arguments:
4532 This - instance of the state machine.
4533
4534Return Value:
4535 new state
4536
4537 --*/
4538{
4541
4542 if (This->PowerPolicyCancelWaitWake() == FALSE &&
4543 This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
4545 }
4546
4547 return WdfDevStatePwrPolNull;
4548}
4549
4553 )
4554/*++
4555
4556Routine Description:
4557 Wait wake irp has been cancelled. Complete the Sx irp and goto the failed
4558 state.
4559
4560Arguments:
4561 This - instance of the state machine
4562
4563Return Value:
4564 new state
4565
4566 --*/
4567{
4570
4571 This->PowerPolicyCompleteSystemPowerIrp();
4572
4574}
4575
4579 )
4580{
4582
4583 This->PowerPolicyCompleteSystemPowerIrp();
4584
4585 return WdfDevStatePwrPolNull;
4586}
4587
4591 )
4592{
4594
4595 if (This->PowerPolicyCancelWaitWake() == FALSE &&
4596 This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
4598 }
4599
4600 return WdfDevStatePwrPolNull;
4601}
4602
4606 )
4607{
4610
4611 //
4612 // Make a notee of the fact that system was woken by
4613 // a wake interrupt of this device
4614 //
4615 This->m_SystemWokenByWakeInterrupt = TRUE;
4616
4617 if (This->PowerPolicyCancelWaitWake() == FALSE &&
4618 This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) {
4620 }
4621
4622 return WdfDevStatePwrPolNull;
4623}
4624
4628 )
4629{
4631
4634
4635 status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry);
4636
4637 if (!NT_SUCCESS(status)) {
4638 COVERAGE_TRAP();
4640 }
4641
4642 return WdfDevStatePwrPolNull;
4643}
4644
4648 )
4649{
4651
4652 //
4653 // If the PDO is the Power Policy owner, then disable wake at bus, otherwise
4654 // the power state machine will disable wake at bus.
4655 //
4656 if (This->m_Device->IsPdo()) {
4657 This->PowerDisableWakeAtBusOverload();
4658 }
4659
4660 This->PowerPolicyDisarmWakeFromSx();
4661
4663}
4664
4668 )
4669{
4671
4673
4674 status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry);
4675
4676 if (!NT_SUCCESS(status)) {
4677 COVERAGE_TRAP();
4679 }
4680
4681 return WdfDevStatePwrPolNull;
4682}
4683
4687 )
4688{
4690
4691 //
4692 // If the PDO is the Power Policy owner, then disable wake at bus, otherwise
4693 // the power state machine will disable wake at bus.
4694 //
4695 if (This->m_Device->IsPdo()) {
4696 This->PowerDisableWakeAtBusOverload();
4697 }
4698
4699 This->m_PowerPolicyMachine.m_Owner->m_DeviceWakeFromSxTriggered.Invoke(
4700 This->m_Device->GetHandle()
4701 );
4702
4703 This->PowerPolicyDisarmWakeFromSx();
4704
4706}
4707
4711 )
4712/*++
4713
4714Routine Description:
4715 The system went into Sx and the device was armed for wake. The system has
4716 now returned to S0, the device has started the D0 transition, and the device
4717 has been disarmed for wake. We must now complete the D0 transition by sending
4718 PowerCompleteD0 to the power state machine.
4719
4720Arguments:
4721 This - instance of the state machine
4722
4723Return Value:
4724 WdfDevStatePwrPolNull
4725
4726 --*/
4727{
4730
4731 //
4732 // Simulate a device-power-required notification from the power framework.
4733 // An S0-IRP is essentially equivalent to a device-power-required
4734 // notification.
4735 //
4736 This->m_PowerPolicyMachine.m_Owner->
4737 m_PoxInterface.SimulateDevicePowerRequired();
4738
4739 //
4740 // Notify the device-power-requirement state machine that we are powered on
4741 //
4742 This->m_PowerPolicyMachine.m_Owner->
4743 m_PoxInterface.DeviceIsPoweredOn();
4744
4745 This->PowerProcessEvent(PowerCompleteD0);
4746
4747 return WdfDevStatePwrPolNull;
4748}
4749
4753 )
4754/*++
4755
4756Routine Description:
4757 The machine is going into Sx. Send a Dx irp to the stack. The "x" depends
4758 on if the target system state is one which we can wake the system and
4759 the device is enabled to wake from Sx.
4760
4761Arguments:
4762 This - instance of the state machine
4763
4764Return Value:
4765 new state
4766
4767 --*/
4768{
4769 NTSTATUS notifyPowerDownStatus;
4770 SYSTEM_POWER_STATE systemState;
4771
4773
4774 //
4775 // If the bus/PDO is not in the hibernate path, then verify that all the
4776 // children have powered down by now.
4777 //
4778 if (This->GetUsageCount(WdfSpecialFileHibernation) == 0 &&
4779 This->m_PowerPolicyMachine.m_Owner->m_ChildrenPoweredOnCount > 0) {
4781 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
4782 "WDFDEVICE %p powering down before child devices have powered down. "
4783 "This usually indicates a faulty child device that completed the Sx "
4784 "irp before sending the Dx irp",
4785 This->m_Device->GetHandle());
4786
4788 This->m_Device->GetDriverGlobals());
4789 }
4790
4791 //
4792 // Simulate a device-power-not-required notification from the power
4793 // framework. An Sx-IRP is essentially equivalent to a device-power-not-
4794 // required notification.
4795 //
4796 This->m_PowerPolicyMachine.m_Owner->
4797 m_PoxInterface.SimulateDevicePowerNotRequired();
4798
4799 //
4800 // Notify the device-power-requirement state machine that we are about to
4801 // power down
4802 //
4803 notifyPowerDownStatus = This->m_PowerPolicyMachine.m_Owner->
4804 m_PoxInterface.NotifyDevicePowerDown();
4805
4806 //
4807 // We simulated a device-power-not-required notification before we notified
4808 // the device-power-requirement state machine that we are powering down.
4809 // Therefore, our notification should have succeeded.
4810 //
4811 ASSERT(NT_SUCCESS(notifyPowerDownStatus));
4812 UNREFERENCED_PARAMETER(notifyPowerDownStatus);
4813
4814 systemState = This->PowerPolicyGetPendingSystemState();
4815
4816 if (This->PowerPolicyIsWakeEnabled() &&
4817 This->PowerPolicyCanWakeFromSystemState(systemState)) {
4819 }
4820 else {
4822 }
4823}
4824
4828 )
4829/*++
4830
4831Routine Description:
4832 Machine is going into Sx and the device is not enabled to wake from Sx.
4833 Request a D3 irp to put the device into a low power state.
4834
4835Arguments:
4836 This - instance of the state machine
4837
4838Return Value:
4839 new state
4840
4841 --*/
4842{
4844 DEVICE_POWER_STATE dxState;
4845
4847
4848 dxState = (DEVICE_POWER_STATE)
4849 This->m_PowerPolicyMachine.m_Owner->m_IdealDxStateForSx;
4850
4851 if (dxState != PowerDeviceD3) {
4852 DEVICE_POWER_STATE dxMappedState;
4853
4854 //
4855 // Get the lightest Dx state for this Sx state as reported by the
4856 // device capabilities of the stack.
4857 //
4858 dxMappedState = _GetPowerCapState(
4859 This->PowerPolicyGetPendingSystemState(),
4860 This->m_PowerPolicyMachine.m_Owner->m_SystemToDeviceStateMap
4861 );
4862
4863 //
4864 // If the ideal desired state is lighter than what the S->D mapping says
4865 // is the lightest supported D state, use the mapping value instead.
4866 //
4867 if (dxState < dxMappedState) {
4868 dxState = dxMappedState;
4869 }
4870 }
4871
4872 ASSERT(dxState >= PowerDeviceD1 && dxState <= PowerDeviceD3);
4873
4874 status = This->PowerPolicyPowerDownForSx(dxState, Retry);
4875
4876 if (!NT_SUCCESS(status)) {
4877 COVERAGE_TRAP();
4879 }
4880
4881 return WdfDevStatePwrPolNull;
4882}
4883
4887 )
4888