1 //
2 //    Copyright (C) Microsoft.  All rights reserved.
3 //
4 #ifndef _FXPOWERPOLICYSTATEMACHINE_H_
5 #define _FXPOWERPOLICYSTATEMACHINE_H_
6 
7 #include "fxpoweridlestatemachine.hpp"
8 #include "fxpoxinterface.hpp"
9 
10 // @@SMVERIFY_SPLIT_BEGIN
11 //
12 // Treat these values as a bit field when comparing for known dropped events in
13 // the current state and treat them as values when they known transition events
14 // from state to the next.
15 //
16 enum FxPowerPolicyEvent {
17     PwrPolInvalid                       = 0x00000000,
18     PwrPolStart                         = 0x00000001,
19     PwrPolStop                          = 0x00000002,
20     PwrPolSx                            = 0x00000004,
21     PwrPolS0                            = 0x00000008,
22     PwrPolPowerDown                     = 0x00000010,
23     PwrPolPowerUp                       = 0x00000020,
24     PwrPolPowerDownIoStopped            = 0x00000040,
25     PwrPolPowerUpHwStarted              = 0x00000080,
26     PwrPolWakeArrived                   = 0x00000100,
27     PwrPolWakeSuccess                   = 0x00000200,
28     PwrPolWakeFailed                    = 0x00000400,
29     PwrPolIoPresent                     = 0x00000800,
30     PwrPolPowerTimeoutExpired           = 0x00001000,
31     PwrPolS0IdlePolicyChanged           = 0x00002000,
32     PwrPolSurpriseRemove                = 0x00004000,
33     PwrPolUsbSelectiveSuspendCallback   = 0x00008000,
34     PwrPolUsbSelectiveSuspendCompleted  = 0x00010000,
35     PwrPolPowerDownFailed               = 0x00020000,
36     PwrPolPowerUpFailed                 = 0x00040000,
37     PwrPolImplicitPowerDown             = 0x00080000,
38     PwrPolImplicitPowerDownFailed       = 0x00100000,
39     PwrPolPowerUpNotSeen                = 0x00200000,
40     PwrPolDevicePowerNotRequired        = 0x00400000,
41     PwrPolDevicePowerRequired           = 0x00800000,
42     PwrPolRemove                        = 0x01000000,
43     PwrPolWakeInterruptFired            = 0x02000000,
44 
45     //
46     // Not a real event, just a value that indicates all of the events which
47     // goto the head of the queue and are always processed, even if the state is
48     // locked.  This applies to the power policy owner state machine.
49     //
50     PwrPolPriorityEventsMask            = PwrPolPowerUp |
51                                           PwrPolPowerDown |
52                                           PwrPolPowerUpFailed |
53                                           PwrPolPowerDownFailed |
54                                           PwrPolPowerDownIoStopped |
55                                           PwrPolPowerUpHwStarted |
56                                           PwrPolImplicitPowerDown |
57                                           PwrPolImplicitPowerDownFailed |
58                                           PwrPolWakeArrived |
59                                           PwrPolWakeSuccess |
60                                           PwrPolWakeFailed |
61                                           PwrPolPowerUpNotSeen |
62                                           PwrPolUsbSelectiveSuspendCompleted |
63                                           PwrPolWakeInterruptFired,
64 
65     //
66     // Not a real event, just a value that indicates all of the events which
67     // goto the head of the queue and are always processed, even if the state is
68     // locked.  This applies to the not power policy owner state machine.
69     //
70     PwrPolNotOwnerPriorityEventsMask    = PwrPolPowerUp |
71                                           PwrPolPowerUpFailed |
72                                           PwrPolPowerDown |
73                                           PwrPolPowerDownFailed,
74 
75     //
76     // Not a real event, just a value that indicate all of the events which
77     // should not be in the queue, if a similar event is already enqueued.
78     //
79     PowerPolSingularEventMask           = PwrPolS0IdlePolicyChanged |
80     //
81     // A device could have multiple wake interrupts that could each fire
82     // this event.
83     //
84                                           PwrPolWakeInterruptFired,
85 
86 
87     PwrPolNull                          = 0xFFFFFFFF,
88 };
89 
90 //
91 // Bit packed ULONG.
92 //
93 union FxPwrPolStateInfo {
94     struct {
95         //
96         // Indicates whether the state is open to all events
97         //
98         ULONG QueueOpen : 1;
99 
100         //
101         // Bit of events we know we can drop in this state
102         //
103         ULONG KnownDroppedEvents : 31;
104     } Bits;
105 
106     struct {
107         //
108         // Maps to the same bit location as QueueOpen.  Since we start
109         // KnownDroppedEvents at the next bit, start our bits by at the next
110         // bit as well.
111         //
112         ULONG Reserved : 1;
113 
114         //
115         // These are defined so that we can easily tell in the debugger what
116         // each set bit in KnownDroppedEvents maps to in the FxPowerPolicyEvent
117         // enum
118         //
119         ULONG PwrPolStartKnown : 1;
120         ULONG PwrPolStopKnown : 1;
121         ULONG PwrPolSxKnown : 1;
122         ULONG PwrPolS0Known : 1;
123         ULONG PwrPolPowerDownKnown : 1;
124         ULONG PwrPolPowerUpKnown : 1;
125         ULONG PwrPolPowerDownIoStoppedKnown : 1;
126         ULONG PwrPolPowerUpHwStartedKnown : 1;
127         ULONG PwrPolWakeArrivedKnown : 1;
128         ULONG PwrPolWakeSuccessKnown : 1;
129         ULONG PwrPolWakeFailedKnown : 1;
130         ULONG PwrPolIoPresentKnown : 1;
131         ULONG PwrPolPowerTimeoutExpiredKnown : 1;
132         ULONG PwrPolS0IdlePolicyChangedKnown : 1;
133         ULONG PwrPolSurpriseRemoveKnown : 1;
134         ULONG PwrPolUsbSelectiveSuspendCallbackKnown : 1;
135         ULONG PwrPolUsbSelectiveSuspendCompletedKnown : 1;
136         ULONG PwrPolPowerDownFailedKnown : 1;
137         ULONG PwrPolPowerUpFailedKnown : 1;
138     } BitsByName;
139 };
140 
141 struct POWER_POLICY_EVENT_TARGET_STATE {
142     FxPowerPolicyEvent PowerPolicyEvent;
143 
144     WDF_DEVICE_POWER_POLICY_STATE TargetState;
145 
146     EVENT_TRAP_FIELD
147 };
148 
149 typedef const POWER_POLICY_EVENT_TARGET_STATE* CPPOWER_POLICY_EVENT_TARGET_STATE;
150 
151 typedef
152 WDF_DEVICE_POWER_POLICY_STATE
153 (*PFN_POWER_POLICY_STATE_ENTRY_FUNCTION)(
154     FxPkgPnp* This
155     );
156 
157 typedef struct POWER_POLICY_STATE_TABLE {
158     //
159     // Framework internal function to handle the transition into this state
160     //
161     PFN_POWER_POLICY_STATE_ENTRY_FUNCTION StateFunc;
162 
163     //
164     // First state transition out of this state
165     //
166     POWER_POLICY_EVENT_TARGET_STATE FirstTargetState;
167 
168     //
169     // Other state transitions out of this state if FirstTargetState is not
170     // matched.  This is an array where we expect the final element to be
171     // { PwrPolNull, WdfDevStatePwrPolNull }
172     //
173     CPPOWER_POLICY_EVENT_TARGET_STATE OtherTargetStates;
174 
175     //
176     // Whether we allow transitions out of this state that are not D state
177     // related events, ie if this is a green dot state, TRUE, if this is a red
178     // dot state, FALSE.  D state events (PwrPolPowerUp, PwrPolPowerDown)
179     // are never affected by the queue state and are always processed.
180     //
181     FxPwrPolStateInfo StateInfo;
182 
183 } *PPOWER_POLICY_STATE_TABLE;
184 
185 typedef const POWER_POLICY_STATE_TABLE* CPPOWER_POLICY_STATE_TABLE;
186 
187 typedef
188 WDF_DEVICE_POWER_POLICY_STATE
189 (*PFN_NOT_POWER_POLICY_OWNER_STATE_ENTRY_FUNCTION)(
190     FxPkgPnp* This
191     );
192 
193 typedef struct NOT_POWER_POLICY_OWNER_STATE_TABLE {
194     //
195     // The current power policy state that this entry applies to
196     //
197     WDF_DEVICE_POWER_POLICY_STATE CurrentTargetState;
198 
199     //
200     // Framework internal function to handle the transition into this state
201     //
202     PFN_NOT_POWER_POLICY_OWNER_STATE_ENTRY_FUNCTION StateFunc;
203 
204     //
205     // Only state transition out of this state
206     //
207     CPPOWER_POLICY_EVENT_TARGET_STATE TargetStates;
208 
209     UCHAR TargetStatesCount;
210 
211     BOOLEAN QueueOpen;
212 
213 } *PNOT_POWER_POLICY_OWNER_STATE_TABLE;
214 
215 typedef const NOT_POWER_POLICY_OWNER_STATE_TABLE* CPNOT_POWER_POLICY_OWNER_STATE_TABLE;
216 
217 #if FX_STATE_MACHINE_VERIFY
218 #define MAX_PWR_POL_STATE_ENTRY_FN_RETURN_STATES    (5)
219 
220 struct PWR_POL_STATE_ENTRY_FUNCTION_TARGET_STATE {
221     //
222     // Return value from state entry function
223     //
224     WDF_DEVICE_POWER_POLICY_STATE State;
225 
226     //
227     // type of device the returning state applies to
228     //
229     FxStateMachineDeviceType  DeviceType;
230 
231     //
232     // Info about the state transition
233     //
234     PSTR Comment;
235 };
236 
237 struct PWR_POL_STATE_ENTRY_FN_RETURN_STATE_TABLE {
238     //
239     // array of state transitions caused by state entry function
240     //
241     PWR_POL_STATE_ENTRY_FUNCTION_TARGET_STATE TargetStates[MAX_PWR_POL_STATE_ENTRY_FN_RETURN_STATES];
242 };
243 
244 typedef const PWR_POL_STATE_ENTRY_FN_RETURN_STATE_TABLE*  CPPWR_POL_STATE_ENTRY_FN_RETURN_STATE_TABLE;
245 #endif  // FX_STATE_MACHINE_VERIFY
246 
247 
248 // @@SMVERIFY_SPLIT_END
249 
250 enum FxPowerPolicyConstants {
251     FxPowerPolicyNoTimeout = 0,
252 
253     FxPowerPolicyDefaultTimeout = 5000,             // Timeout in milliseconds
254 };
255 
256 enum CancelIrpCompletionOwnership {
257     CancelOwnershipUnclaimed = 0,
258     CancelOwnershipClaimed = 1,
259 };
260 
261 enum FxPowerPolicySxWakeSettingsFlags {
262     FxPowerPolicySxWakeDeviceEnabledFlag = 0x1,
263     FxPowerPolicySxWakeChildrenArmedFlag = 0x2,
264 };
265 
266 struct PolicySettings {
PolicySettingsPolicySettings267     PolicySettings()
268     {
269         WmiInstance = NULL;
270         DxState = PowerDeviceD3;
271 
272         Enabled = Overridable = Set = Dirty = FALSE;
273     }
274 
275     ~PolicySettings();
276 
277     //
278     // Dx state to put the device in when the policy is applied
279     //
280     DEVICE_POWER_STATE DxState;
281 
282     FxWmiInstanceInternal* WmiInstance;
283 
284     BOOLEAN Enabled;
285 
286     BOOLEAN Overridable;
287 
288     BOOLEAN Set;
289 
290     BOOLEAN Dirty;
291 };
292 
293 typedef struct _POX_SETTINGS {
294     PFN_WDFDEVICE_WDM_POST_PO_FX_REGISTER_DEVICE
295                             EvtDeviceWdmPostPoFxRegisterDevice;
296     PFN_WDFDEVICE_WDM_PRE_PO_FX_UNREGISTER_DEVICE
297                             EvtDeviceWdmPrePoFxUnregisterDevice;
298     PPO_FX_COMPONENT Component;
299     PPO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK ComponentActiveConditionCallback;
300     PPO_FX_COMPONENT_IDLE_CONDITION_CALLBACK ComponentIdleConditionCallback;
301     PPO_FX_COMPONENT_IDLE_STATE_CALLBACK ComponentIdleStateCallback;
302     PPO_FX_POWER_CONTROL_CALLBACK PowerControlCallback;
303     PVOID PoFxDeviceContext;
304 } POX_SETTINGS, *PPOX_SETTINGS;
305 
306 class IdleTimeoutManagement {
307 
308 private:
309     //
310     // This member is used to control whether or not the idle timeout is
311     // determined by the power manager when running on Windows 8 and above.
312     // The value of this member is some combination of the flags defined below.
313     //
314     LONG volatile m_IdleTimeoutStatus;
315 
316     //
317     // Flags for the m_IdleTimeoutStatus member
318     //
319     //    IdleTimeoutStatusFrozen - This flag implies that the decision on
320     //        whether the power manager determines the idle timeout is "frozen"
321     //        and can no longer be changed. The decision is frozen during start
322     //        IRP completion processing, just before WDF registers with the
323     //        power manager.
324     //
325     //    IdleTimeoutSystemManaged - This flag implies that the power manager
326     //        determines the idle timeout on Windows 8 and above. If this flag
327     //        is not set, the idle timeout specified by the client driver is
328     //        used.
329     //
330     //    IdleTimeoutPoxSettingsSpecified - This flag implies that the client
331     //        driver has already specified the settings that need to be used
332     //        when registering with the power framework. This flag is used to
333     //        track that the settings are not specified more than once.
334     //
335     enum IdleTimeoutStatusFlag {
336         IdleTimeoutStatusFrozen         = 0x00000001,
337         IdleTimeoutSystemManaged        = 0x00000002,
338         IdleTimeoutPoxSettingsSpecified = 0x00000004,
339     };
340 
341     //
342     // Result returned by the UpdateIdleTimeoutStatus() method
343     //
344     enum IdleTimeoutStatusUpdateResult {
345         //
346         // Flags were sucessfully updated
347         //
348         IdleTimeoutStatusFlagsUpdated,
349 
350         //
351         // The flag we were trying to set was already set
352         //
353         IdleTimeoutStatusFlagAlreadySet,
354 
355         //
356         // It is too late to set the flag. The flags have already been frozen.
357         // Flags are frozen the first time a device is started.
358         //
359         IdleTimeoutStatusFlagsAlreadyFrozen,
360 
361         //
362         // Flags are being set by multiple threads in parallel. This is not
363         // supported.
364         //
365         IdleTimeoutStatusFlagsUnexpected
366     };
367 
368     //
369     // This member contains the client driver's settings that will be used when
370     // we register with the power manager on Windows 8 and above.
371     //
372     PPOX_SETTINGS m_PoxSettings;
373 
374 private:
375     IdleTimeoutStatusUpdateResult
376     UpdateIdleTimeoutStatus(
377         __in IdleTimeoutStatusFlag Flag
378         );
379 
380     CfxDevice *
381     GetDevice(
382         VOID
383         );
384 
385 public:
IdleTimeoutManagement(VOID)386     IdleTimeoutManagement(
387         VOID
388         ) : m_IdleTimeoutStatus(0),
389             m_PoxSettings(NULL)
390     {
391     }
392 
~IdleTimeoutManagement(VOID)393     ~IdleTimeoutManagement(
394         VOID
395         )
396     {
397         BYTE * buffer = NULL;
398         ULONG poxSettingsOffset;
399 
400         if (NULL != m_PoxSettings) {
401 
402             buffer = (BYTE*) m_PoxSettings;
403 
404             //
405             // In the function FxPkgPnp::AssignPowerFrameworkSettings, we had
406             // allocated a buffer which we need to free now. Note that
407             // m_PoxSettings does not necessarily point to the beginning of the
408             // buffer. It points to the POX_SETTINGS structure in the buffer,
409             // which may or may not be in the beginning. If it is not in the
410             // beginning, figure out where the beginning of the buffer is.
411             //
412             if (m_PoxSettings->Component != NULL) {
413                 //
414                 // The computation below won't overflow because we already
415                 // performed this computation successfully using safeint
416                 // functions in FxPkgPnp::AssignPowerFrameworkSettings.
417                 //
418                 poxSettingsOffset =
419                         (sizeof(*(m_PoxSettings->Component->IdleStates)) *
420                                 (m_PoxSettings->Component->IdleStateCount)) +
421                         (sizeof(*(m_PoxSettings->Component)));
422             }
423             else {
424                 poxSettingsOffset = 0;
425             }
426 
427             //
428             // Move to the beginning of the buffer
429             //
430             buffer = buffer - poxSettingsOffset;
431 
432             //
433             // Free the buffer
434             //
435             MxMemory::MxFreePool(buffer);
436         }
437     }
438 
439     static
440     BOOLEAN
441     _SystemManagedIdleTimeoutAvailable(
442         VOID
443         );
444 
445     NTSTATUS
446     UseSystemManagedIdleTimeout(
447         __in PFX_DRIVER_GLOBALS DriverGlobals
448         );
449 
450     VOID
451     FreezeIdleTimeoutManagementStatus(
452         __in PFX_DRIVER_GLOBALS DriverGlobals
453         );
454 
455     BOOLEAN
456     UsingSystemManagedIdleTimeout(
457         VOID
458         );
459 
460     NTSTATUS
461     CommitPowerFrameworkSettings(
462         __in PFX_DRIVER_GLOBALS DriverGlobals,
463         __in PPOX_SETTINGS PoxSettings
464         );
465 
466     BOOLEAN
467     DriverSpecifiedPowerFrameworkSettings(
468         VOID
469         );
470 
471     PPOX_SETTINGS
GetPowerFrameworkSettings(VOID)472     GetPowerFrameworkSettings(
473         VOID
474         )
475     {
476         return m_PoxSettings;
477     }
478 };
479 
480 struct IdlePolicySettings : PolicySettings {
IdlePolicySettingsIdlePolicySettings481     IdlePolicySettings(
482         VOID
483         ) : PolicySettings()
484     {
485         WakeFromS0Capable = FALSE;
486         UsbSSCapable = FALSE;
487         PowerUpIdleDeviceOnSystemWake = FALSE;
488         UsbSSCapabilityKnown = FALSE;
489     }
490 
491     //
492     // TRUE if the device capable of waking from S0
493     //
494     BOOLEAN WakeFromS0Capable;
495 
496     //
497     // This member is meaningful only if the WakeFromS0Capable member (above) is
498     // TRUE. The WakeFromS0Capable member indicates whether or not wake-from-S0
499     // is currently enabled. If wake-from-S0 is currently enabled, the
500     // UsbSSCapable member indicates whether the wake-from-S0 support is generic
501     // or USB SS specific. If wake-from-S0 is not enabled, the UsbSSCapable
502     // member is ignored.
503     //
504     BOOLEAN UsbSSCapable;
505 
506     //
507     // TRUE if we know whether the device supports generic wake or USB SS wake.
508     // This value is initialized to FALSE and remains FALSE until the first time
509     // that the driver specifies S0-idle settings with an idle capability value
510     // of IdleCanWakeFromS0 or IdleUsbSelectiveSuspend. When the driver
511     // specifies one of these idle capabilities, this value is set to TRUE and
512     // remains TRUE for the lifetime of the device.
513     //
514     BOOLEAN UsbSSCapabilityKnown;
515 
516     //
517     // TRUE if idle enabled device should be powered up even when idle,
518     // when resuming from Sx
519     //
520     BOOLEAN PowerUpIdleDeviceOnSystemWake;
521 
522     //
523     // Member to manage interactions with the power manager for S0-idle support
524     // on Win8 and above
525     //
526     IdleTimeoutManagement m_TimeoutMgmt;
527 };
528 
529 struct WakePolicySettings : PolicySettings {
WakePolicySettingsWakePolicySettings530     WakePolicySettings(
531         VOID
532         ) : PolicySettings()
533     {
534         ArmForWakeIfChildrenAreArmedForWake = FALSE;
535         IndicateChildWakeOnParentWake = FALSE;
536     }
537 
538     //
539     // TRUE if the device should arm for wake when one or more children are
540     // armed for wake.
541     //
542     BOOLEAN ArmForWakeIfChildrenAreArmedForWake;
543 
544     //
545     // TRUE if the device should propagate the wake status to its children.
546     //
547     BOOLEAN IndicateChildWakeOnParentWake;
548 };
549 
550 struct FxPowerPolicyOwnerSettings : public FxStump {
551 
552 friend FxPowerPolicyMachine;
553 
554 public:
555     FxPowerPolicyOwnerSettings(
556         __in FxPkgPnp* PkgPnp
557         );
558 
559     ~FxPowerPolicyOwnerSettings(
560         VOID
561         );
562 
563     _Must_inspect_result_
564     NTSTATUS
565     Init(
566         VOID
567         );
568 
569     VOID
570     CleanupPowerCallback(
571         VOID
572         );
573 
574     VOID
IncrementChildrenArmedForWakeCountFxPowerPolicyOwnerSettings575     IncrementChildrenArmedForWakeCount(
576         VOID
577         )
578     {
579         InterlockedIncrement(&m_ChildrenArmedCount);
580     }
581 
582     VOID
DecrementChildrenArmedForWakeCountFxPowerPolicyOwnerSettings583     DecrementChildrenArmedForWakeCount(
584         VOID
585         )
586     {
587         InterlockedDecrement(&m_ChildrenArmedCount);
588     }
589 
590 protected:
591     static
592     MdCallbackFunctionType
593     _PowerStateCallback;
594 
595 public:
596     FxPowerIdleMachine m_PowerIdleMachine;
597     FxPoxInterface m_PoxInterface;
598 
599 
600 
601 
602 
603 
604     FxPowerDeviceArmWakeFromS0          m_DeviceArmWakeFromS0;
605     FxPowerDeviceArmWakeFromSx          m_DeviceArmWakeFromSx;
606 
607     FxPowerDeviceDisarmWakeFromS0       m_DeviceDisarmWakeFromS0;
608     FxPowerDeviceDisarmWakeFromSx       m_DeviceDisarmWakeFromSx;
609 
610     FxPowerDeviceWakeFromS0Triggered    m_DeviceWakeFromS0Triggered;
611     FxPowerDeviceWakeFromSxTriggered    m_DeviceWakeFromSxTriggered;
612 
613     FxUsbIdleInfo* m_UsbIdle;
614 
615     FxPkgPnp* m_PkgPnp;
616 
617     WakePolicySettings m_WakeSettings;
618 
619     IdlePolicySettings m_IdleSettings;
620 
621     //
622     // Nibble packed structure.  Each D state is encoded 4 bits.  The S state is
623     // used as the "index" within the ULONG.  PowerSystemUnspecified is the
624     // first 4 bits of the first byte, etc. etc. ...
625     //
626     ULONG m_SystemToDeviceStateMap;
627 
628     //
629     // The number of children who are in the D0 state.  If this count is > 0,
630     // then this parent cannot idle out while in S0.  Note that each child also
631     // has an explicit call to PowerReference against this device which is used
632     // to control the idle timer for this device.
633     //
634     ULONG m_ChildrenPoweredOnCount;
635 
636     //
637     // The number of children who are currently armed for wake.  This count
638     // can be used by the the wake owner to determine whether wake should be
639     // enabled or not for a parent stack if arming for wake depends on
640     // children being armed for wake.
641     //
642     LONG m_ChildrenArmedCount;
643 
644     //
645     // The status of the last wait wake IRP to complete in the stack
646     //
647     NTSTATUS m_WaitWakeStatus;
648 
649     //
650     // Dx state to put the device into when an Sx irp arrives and the device is
651     // not armed for wake from Sx. DEVICE_POWER_STATE values are used.
652     //
653     BYTE m_IdealDxStateForSx;
654 
655     //
656     // Track power requests to assert if someone other than this driver sent it
657     // and to determine if this driver has received the requested irp (to catch
658     // someone above completing irp w/o sending to this driver)
659     //
660     BOOLEAN m_RequestedPowerUpIrp;
661     BOOLEAN m_RequestedPowerDownIrp;
662     BOOLEAN m_RequestedWaitWakeIrp;
663 
664     //
665     // Tracks wake event being dropped
666     //
667     BOOLEAN m_WakeCompletionEventDropped;
668 
669     BOOLEAN m_PowerFailed;
670 
671     //
672     // Indicates whether we can cause paging I/O by writing to the registry
673     //
674     BOOLEAN m_CanSaveState;
675 
676     //
677     // Guard to stop children from powering up while the parent is in Dx or
678     // about to transition into Dx.
679     //
680     BOOLEAN m_ChildrenCanPowerUp;
681 
682     //
683     // TRUE if our device caused the machine to wake up.  Access to this value
684     // is not synchronized between the parent and PDO.  The parent sets it to
685     // TRUE upon successful completion of the WW irp and cleared after
686     // EvtDeviceDisarmWakeFromSx.  If a PDO's WW IRP is completed within this
687     // window, the PDO's WW IRP will have PoSetSystemWake called on it.  It is
688     // acceptable if the PDO's WW IRP completion races with the clearing of the
689     // value and is not set as a source of wake.
690     //
691     BOOLEAN m_SystemWakeSource;
692 
693 protected:
694     PCALLBACK_OBJECT m_PowerCallbackObject;
695 
696     PVOID m_PowerCallbackRegistration;
697 
698     LONG m_WaitWakeCancelCompletionOwnership;
699 
700 };
701 
702 //
703 // This type of union is done so that we can
704 // 1) shrink the array element to the smallest size possible
705 // 2) keep types within the structure so we can dump it in the debugger
706 //
707 union FxPowerPolicyMachineStateHistory {
708     struct {
709         WDF_DEVICE_POWER_POLICY_STATE State1 : 16;
710         WDF_DEVICE_POWER_POLICY_STATE State2 : 16;
711         WDF_DEVICE_POWER_POLICY_STATE State3 : 16;
712         WDF_DEVICE_POWER_POLICY_STATE State4 : 16;
713         WDF_DEVICE_POWER_POLICY_STATE State5 : 16;
714         WDF_DEVICE_POWER_POLICY_STATE State6 : 16;
715         WDF_DEVICE_POWER_POLICY_STATE State7 : 16;
716         WDF_DEVICE_POWER_POLICY_STATE State8 : 16;
717     } S;
718 
719     USHORT History[FxPowerPolicyEventQueueDepth];
720 };
721 
722 struct FxPowerPolicyMachine : public FxThreadedEventQueue {
723     FxPowerPolicyMachine(
724         VOID
725         );
726 
727     ~FxPowerPolicyMachine(
728         VOID
729         );
730 
731     VOID
732     UsbSSCallbackProcessingComplete(
733         VOID
734         );
735 
736     _Must_inspect_result_
737     NTSTATUS
738     InitUsbSS(
739         VOID
740         );
741 
742     VOID
SetWaitWakeUnclaimedFxPowerPolicyMachine743     SetWaitWakeUnclaimed(
744         VOID
745         )
746     {
747         m_Owner->m_WaitWakeCancelCompletionOwnership = CancelOwnershipUnclaimed;
748     }
749 
750     BOOLEAN
CanCompleteWaitWakeIrpFxPowerPolicyMachine751     CanCompleteWaitWakeIrp(
752         VOID
753         )
754     {
755         //
756         // We have 2 potential call sites racing on trying to complete the wait
757         // wake irp.  The first is the cancelling call site.  The other is the
758         // irp's completion routine.  What we want is for the *2nd* (and last)
759         // call site to actually complete the irp.  This is why we check to see
760         // if the result of the exchange is that the ownership is already claimed
761         // (and not unclaimed as one might first be led to think).
762         //
763         if (InterlockedExchange(&m_Owner->m_WaitWakeCancelCompletionOwnership,
764                                 CancelOwnershipClaimed) == CancelOwnershipClaimed) {
765             return TRUE;
766         }
767         else {
768             return FALSE;
769         }
770     }
771 
772 public:
773     FxPowerPolicyEvent m_Queue[FxPowerPolicyEventQueueDepth];
774 
775     FxPowerPolicyMachineStateHistory m_States;
776 
777     FxPowerPolicyOwnerSettings* m_Owner;
778 
779     union {
780         ULONG m_SingularEventsPresent;
781 
782         union {
783             //
784             // These are defined so that we can easily tell in the debugger what
785             // each set bit in m_SingularEventsPresent maps to in the
786             // FxPowerPolicyEvent enum.
787             //
788             ULONG PwrPolStartKnown : 1;
789             ULONG PwrPolStopKnown : 1;
790             ULONG PwrPolSxKnown : 1;
791             ULONG PwrPolS0Known : 1;
792             ULONG PwrPolPowerDownKnown : 1;
793             ULONG PwrPolPowerUpKnown : 1;
794             ULONG PwrPolPowerDownIoStoppedKnown : 1;
795             ULONG PwrPolPowerUpHwStartedKnown : 1;
796             ULONG PwrPolWakeArrivedKnown : 1;
797             ULONG PwrPolWakeSuccessKnown : 1;
798             ULONG PwrPolWakeFailedKnown : 1;
799             ULONG PwrPolIoPresentKnown : 1;
800             ULONG PwrPolPowerTimeoutExpiredKnown : 1;
801             ULONG PwrPolS0IdlePolicyChangedKnown : 1;
802             ULONG PwrPolSurpriseRemoveKnown : 1;
803             ULONG PwrPolUsbSelectiveSuspendCallbackKnown : 1;
804             ULONG PwrPolUsbSelectiveSuspendCompletedKnown : 1;
805             ULONG PwrPolPowerDownFailedKnown : 1;
806             ULONG PwrPolPowerUpFailedKnown : 1;
807         } m_SingularEventsPresentByName;
808     };
809 };
810 
811 #endif // _FXPOWERPOLICYSTATEMACHINE_H_
812