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