1 /*++ 2 Copyright (c) Microsoft. All rights reserved. 3 4 Module Name: 5 6 PowerStateMachine.cpp 7 8 Abstract: 9 10 This module implements the Power state machine for the driver framework. 11 This code was split out from FxPkgPnp.cpp. 12 13 Author: 14 15 16 17 18 Environment: 19 20 Both kernel and user mode 21 22 Revision History: 23 24 25 26 --*/ 27 28 #include "pnppriv.hpp" 29 30 extern "C" { 31 #if defined(EVENT_TRACING) 32 #include "PowerStateMachine.tmh" 33 #endif 34 } 35 36 #if FX_STATE_MACHINE_VERIFY 37 #define VALIDATE_POWER_STATE(_CurrentState, _NewState) \ 38 ValidatePowerStateEntryFunctionReturnValue((_CurrentState), (_NewState)) 39 #else 40 #define VALIDATE_POWER_STATE(_CurrentState, _NewState) (0) 41 #endif //FX_STATE_MACHINE_VERIFY 42 43 44 // @@SMVERIFY_SPLIT_BEGIN 45 46 // 47 // The Power State Machine 48 // 49 // This state machine responds to power IRPs that relate 50 // to devices. It is a subordinate, responding either to IRPs 51 // that are sent by other drivers, or by IRPs that are 52 // sent by the Power Policy State Machine. 53 // 54 // It responds to: 55 // 56 // IRP_MN_SET_POWER -- device power IRPs only 57 // IRP_MN_WAIT_WAKE 58 // IRP_MN_WAIT_WAKE Complete 59 // PowerImplicitD0 60 // PowerImplicitD3 61 // ParentMovesToD0 62 // PowerPolicyStop 63 // PowerMarkPageable 64 // PowerMarkNonpageable 65 // 66 67 68 69 70 71 72 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerD0OtherStates[] = 73 { 74 { PowerImplicitD3, WdfDevStatePowerGotoD3Stopped DEBUGGED_EVENT }, 75 { PowerMarkNonpageable, WdfDevStatePowerDecideD0State DEBUGGED_EVENT }, 76 { PowerEventMaximum, WdfDevStatePowerNull }, 77 }; 78 79 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerD0NPOtherStates[] = 80 { 81 { PowerImplicitD3, WdfDevStatePowerGotoD3Stopped DEBUGGED_EVENT }, 82 { PowerMarkPageable, WdfDevStatePowerDecideD0State DEBUGGED_EVENT }, 83 { PowerEventMaximum, WdfDevStatePowerNull }, 84 }; 85 86 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerD0BusWakeOwnerOtherStates[] = 87 { 88 { PowerWakeArrival, WdfDevStatePowerEnablingWakeAtBus DEBUGGED_EVENT }, 89 { PowerImplicitD3, WdfDevStatePowerGotoD3Stopped DEBUGGED_EVENT }, 90 { PowerMarkNonpageable, WdfDevStatePowerDecideD0State DEBUGGED_EVENT }, 91 { PowerEventMaximum, WdfDevStatePowerNull }, 92 }; 93 94 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerD0BusWakeOwnerNPOtherStates[] = 95 { 96 { PowerWakeArrival, WdfDevStatePowerEnablingWakeAtBusNP DEBUGGED_EVENT }, 97 { PowerImplicitD3, WdfDevStatePowerGotoD3Stopped DEBUGGED_EVENT }, 98 { PowerMarkPageable, WdfDevStatePowerD0BusWakeOwner DEBUGGED_EVENT }, 99 { PowerEventMaximum, WdfDevStatePowerNull }, 100 }; 101 102 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerD0ArmedForWakeOtherStates[] = 103 { 104 { PowerWakeSucceeded, WdfDevStatePowerD0DisarmingWakeAtBus DEBUGGED_EVENT }, 105 { PowerWakeFailed, WdfDevStatePowerD0DisarmingWakeAtBus DEBUGGED_EVENT }, 106 { PowerWakeCanceled, WdfDevStatePowerD0DisarmingWakeAtBus DEBUGGED_EVENT }, 107 { PowerMarkNonpageable, WdfDevStatePowerD0ArmedForWakeNP TRAP_ON_EVENT }, 108 { PowerImplicitD3, WdfDevStatePowerGotoImplicitD3DisarmWakeAtBus DEBUGGED_EVENT }, 109 { PowerEventMaximum, WdfDevStatePowerNull }, 110 }; 111 112 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerD0ArmedForWakeNPOtherStates[] = 113 { 114 { PowerWakeSucceeded, WdfDevStatePowerD0DisarmingWakeAtBusNP DEBUGGED_EVENT }, 115 { PowerWakeFailed, WdfDevStatePowerD0DisarmingWakeAtBusNP TRAP_ON_EVENT }, 116 { PowerWakeCanceled, WdfDevStatePowerD0DisarmingWakeAtBusNP DEBUGGED_EVENT }, 117 { PowerMarkPageable, WdfDevStatePowerD0ArmedForWake TRAP_ON_EVENT }, 118 { PowerImplicitD3, WdfDevStatePowerGotoImplicitD3DisarmWakeAtBus TRAP_ON_EVENT }, 119 { PowerEventMaximum, WdfDevStatePowerNull }, 120 }; 121 122 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerDNotZeroOtherStates[] = 123 { 124 { PowerImplicitD3, WdfDevStatePowerGotoDxStoppedDisableInterrupt DEBUGGED_EVENT }, 125 { PowerEventMaximum, WdfDevStatePowerNull }, 126 }; 127 128 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerDNotZeroNPOtherStates[] = 129 { 130 { PowerImplicitD3, WdfDevStatePowerGotoDxStoppedDisableInterruptNP DEBUGGED_EVENT }, 131 { PowerEventMaximum, WdfDevStatePowerNull }, 132 }; 133 134 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_DxArmedForWakeOtherStates[] = 135 { 136 { PowerWakeSucceeded, WdfDevStatePowerWakePending DEBUGGED_EVENT }, 137 { PowerWakeCanceled, WdfDevStatePowerWakePending DEBUGGED_EVENT }, 138 { PowerWakeFailed, WdfDevStatePowerWakePending DEBUGGED_EVENT }, 139 { PowerImplicitD3, WdfDevStatePowerDxStoppedDisarmWake TRAP_ON_EVENT }, 140 { PowerEventMaximum, WdfDevStatePowerNull }, 141 }; 142 143 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_DxArmedForWakeNPOtherStates[] = 144 { 145 { PowerWakeSucceeded, WdfDevStatePowerWakePendingNP DEBUGGED_EVENT }, 146 { PowerWakeFailed, WdfDevStatePowerWakePendingNP DEBUGGED_EVENT }, 147 { PowerWakeCanceled, WdfDevStatePowerWakePendingNP DEBUGGED_EVENT }, 148 { PowerImplicitD3, WdfDevStatePowerDxStoppedDisarmWakeNP TRAP_ON_EVENT }, 149 { PowerEventMaximum, WdfDevStatePowerNull }, 150 }; 151 152 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_WakePendingOtherStates[] = 153 { 154 { PowerImplicitD0, WdfDevStatePowerCheckParentStateArmedForWake TRAP_ON_EVENT }, 155 { PowerImplicitD3, WdfDevStatePowerDxStoppedDisarmWake DEBUGGED_EVENT }, 156 { PowerEventMaximum, WdfDevStatePowerNull }, 157 }; 158 159 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_WakePendingNPOtherStates[] = 160 { 161 { PowerImplicitD0, WdfDevStatePowerCheckParentStateArmedForWakeNP TRAP_ON_EVENT }, 162 { PowerImplicitD3, WdfDevStatePowerDxStoppedDisarmWakeNP DEBUGGED_EVENT }, 163 { PowerEventMaximum, WdfDevStatePowerNull }, 164 }; 165 166 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerStoppedOtherStates[] = 167 { 168 { PowerDx, WdfDevStatePowerStoppedCompleteDx DEBUGGED_EVENT }, 169 { PowerEventMaximum, WdfDevStatePowerNull }, 170 }; 171 172 const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerDxStoppedOtherStates[] = 173 { 174 { PowerD0, WdfDevStatePowerGotoStopped DEBUGGED_EVENT }, 175 { PowerEventMaximum, WdfDevStatePowerNull }, 176 }; 177 178 const POWER_STATE_TABLE FxPkgPnp::m_WdfPowerStates[] = 179 { 180 // WdfDevStatePowerObjectCreated 181 { NULL, 182 { PowerImplicitD0, WdfDevStatePowerStartingCheckDeviceType DEBUGGED_EVENT }, 183 NULL, 184 { TRUE, 185 PowerMarkPageable | // parent sends usage notifications before the PDO is 186 PowerMarkNonpageable | // started 187 PowerParentToD0 | // parent powered up upon enumeration of child 188 PowerDx | // If we are on top of a power policy owner who sends a Dx 189 // during start (or after AddDevice, etc) 190 PowerD0 // If we are on top of a power policy owner who sends a D0 191 // to the stack in start device, we can get this event early 192 }, 193 }, 194 195 // WdfDevStatePowerCheckDeviceType 196 { FxPkgPnp::PowerCheckDeviceType, 197 { PowerEventMaximum, WdfDevStatePowerNull }, 198 NULL, 199 { FALSE, 200 0 }, 201 }, 202 203 // WdfDevStatePowerCheckDeviceTypeNP 204 { FxPkgPnp::PowerCheckDeviceTypeNP, 205 { PowerEventMaximum, WdfDevStatePowerNull }, 206 NULL, 207 { FALSE, 208 0 }, 209 }, 210 211 // WdfDevStatePowerCheckParentState 212 { FxPkgPnp::PowerCheckParentState, 213 { PowerEventMaximum, WdfDevStatePowerNull }, 214 NULL, 215 { FALSE, 216 0 }, 217 }, 218 219 // WdfDevStatePowerCheckParentStateNP 220 { FxPkgPnp::PowerCheckParentStateNP, 221 { PowerEventMaximum, WdfDevStatePowerNull }, 222 NULL, 223 { FALSE, 224 0 }, 225 }, 226 227 // WdfDevStatePowerEnablingWakeAtBus 228 { FxPkgPnp::PowerEnablingWakeAtBus, 229 { PowerEventMaximum, WdfDevStatePowerNull }, 230 NULL, 231 { FALSE, 232 0 }, 233 }, 234 235 // WdfDevStatePowerEnablingWakeAtBusNP 236 { FxPkgPnp::PowerEnablingWakeAtBusNP, 237 { PowerEventMaximum, WdfDevStatePowerNull }, 238 NULL, 239 { FALSE, 240 0 }, 241 }, 242 243 // WdfDevStatePowerD0 244 { FxPkgPnp::PowerDZero, 245 { PowerDx, WdfDevStatePowerGotoDx DEBUGGED_EVENT }, 246 FxPkgPnp::m_PowerD0OtherStates, 247 { TRUE, 248 PowerImplicitD3 | 249 PowerD0 // A non WDF power policy owner might send a D0 irp 250 // while we are in D0 251 }, 252 }, 253 254 // WdfDevStatePowerD0NP 255 { FxPkgPnp::PowerD0NP, 256 { PowerDx, WdfDevStatePowerGotoDxNP DEBUGGED_EVENT }, 257 FxPkgPnp::m_PowerD0NPOtherStates, 258 { TRUE, 259 PowerD0 // A non WDF power policy owner might send a D0 irp 260 // while we are in D0 261 }, 262 }, 263 264 // WdfDevStatePowerD0BusWakeOwner 265 { FxPkgPnp::PowerD0BusWakeOwner, 266 { PowerDx, WdfDevStatePowerGotoDx DEBUGGED_EVENT }, 267 FxPkgPnp::m_PowerD0BusWakeOwnerOtherStates, 268 { TRUE, 269 PowerWakeSucceeded | // During surprise remove, the pnp state machine 270 // could complete the ww request and result in 271 // this event before the pwr pol machine is stopped 272 PowerWakeCanceled | // while powering up, the wait wake owner canceled 273 // the ww irp 274 PowerWakeFailed | // while powering up, the wait wake owner failed 275 // the ww irp 276 PowerParentToD0 | 277 PowerD0 // A non WDF power policy owner might send a D0 irp 278 // while we are in D0 279 }, 280 }, 281 282 // WdfDevStatePowerD0BusWakeOwnerNP 283 { FxPkgPnp::PowerD0BusWakeOwnerNP, 284 { PowerDx, WdfDevStatePowerGotoDxNP DEBUGGED_EVENT }, 285 FxPkgPnp::m_PowerD0BusWakeOwnerNPOtherStates, 286 { TRUE, 287 PowerWakeSucceeded | // During surprise remove, the pnp state machine 288 // could complete the ww request and result in 289 // this event before the pwr pol machine is stopped 290 PowerWakeCanceled | // while powering up, the wait wake owner canceled 291 // the ww irp 292 PowerParentToD0 | 293 PowerD0 // A non WDF power policy owner might send a D0 irp 294 // while we are in D0 295 }, 296 }, 297 298 // WdfDevStatePowerD0ArmedForWake 299 { FxPkgPnp::PowerD0ArmedForWake, 300 { PowerDx, WdfDevStatePowerGotoDxArmedForWake DEBUGGED_EVENT }, 301 FxPkgPnp::m_PowerD0ArmedForWakeOtherStates, 302 { TRUE, 303 PowerParentToD0 | 304 PowerWakeArrival | // PowerIsWakeRequestPresent() returned true in 305 // WdfDevStatePowerD0BusWakeOwner and raced with 306 // this event being processed 307 PowerWakeCanceled | 308 PowerD0 // A non WDF power policy owner might send a D0 irp 309 // while we are in D0 310 }, 311 }, 312 313 // WdfDevStatePowerD0ArmedForWakeNP 314 { FxPkgPnp::PowerD0ArmedForWakeNP, 315 { PowerDx, WdfDevStatePowerGotoDxArmedForWakeNP DEBUGGED_EVENT }, 316 FxPkgPnp::m_PowerD0ArmedForWakeNPOtherStates, 317 { TRUE, 318 PowerParentToD0 | 319 PowerWakeArrival | // PowerIsWakeRequestPresent() returned true in 320 // WdfDevStatePowerD0BusWakeOwnerNP and raced with 321 // this event being processed 322 PowerWakeCanceled | 323 PowerD0 // A non WDF power policy owner might send a D0 irp 324 // while we are in D0 325 }, 326 }, 327 328 // WdfDevStatePowerD0DisarmingWakeAtBus 329 { FxPkgPnp::PowerD0DisarmingWakeAtBus, 330 { PowerEventMaximum, WdfDevStatePowerNull }, 331 NULL, 332 { FALSE, 333 0 }, 334 }, 335 336 // WdfDevStatePowerD0DisarmingWakeAtBusNP 337 { FxPkgPnp::PowerD0DisarmingWakeAtBusNP, 338 { PowerEventMaximum, WdfDevStatePowerNull }, 339 NULL, 340 { FALSE, 341 0 }, 342 }, 343 344 // WdfDevStatePowerD0Starting 345 { FxPkgPnp::PowerD0Starting, 346 { PowerEventMaximum, WdfDevStatePowerNull }, 347 NULL, 348 { FALSE, 349 0 }, 350 }, 351 352 // WdfDevStatePowerD0StartingConnectInterrupt 353 { FxPkgPnp::PowerD0StartingConnectInterrupt, 354 { PowerEventMaximum, WdfDevStatePowerNull }, 355 NULL, 356 { FALSE, 357 0 }, 358 }, 359 360 // WdfDevStatePowerD0StartingDmaEnable 361 { FxPkgPnp::PowerD0StartingDmaEnable, 362 { PowerEventMaximum, WdfDevStatePowerNull }, 363 NULL, 364 { FALSE, 365 0 }, 366 }, 367 368 // WdfDevStatePowerD0StartingStartSelfManagedIo 369 { FxPkgPnp::PowerD0StartingStartSelfManagedIo, 370 { PowerEventMaximum, WdfDevStatePowerNull }, 371 NULL, 372 { FALSE, 373 0 }, 374 }, 375 376 // WdfDevStatePowerDecideD0State 377 { FxPkgPnp::PowerDecideD0State, 378 { PowerEventMaximum, WdfDevStatePowerNull }, 379 NULL, 380 { FALSE, 381 0 }, 382 }, 383 384 // WdfDevStatePowerGotoD3Stopped 385 { FxPkgPnp::PowerGotoD3Stopped, 386 { PowerEventMaximum, WdfDevStatePowerNull }, 387 NULL, 388 { FALSE, 389 0 }, 390 }, 391 392 // WdfDevStatePowerStopped 393 { NULL, 394 { PowerImplicitD0, WdfDevStatePowerStartingCheckDeviceType DEBUGGED_EVENT }, 395 FxPkgPnp::m_PowerStoppedOtherStates, 396 { TRUE, 397 PowerD0 | // as a filter above the PPO and the PPO powers on the stack 398 // before seeing a surprise remove or remove irp 399 PowerWakeFailed | // power policy owner canceled the wake request while 400 // we were transitioning to stop (or after the 401 // transition succeeded) 402 PowerParentToD0 }, 403 }, 404 405 // WdfDevStatePowerStartingCheckDeviceType 406 { FxPkgPnp::PowerStartingCheckDeviceType, 407 { PowerEventMaximum, WdfDevStatePowerNull }, 408 NULL, 409 { FALSE, 410 0 }, 411 }, 412 413 // WdfDevStatePowerStartingChild 414 { FxPkgPnp::PowerStartingChild, 415 { PowerParentToD0, WdfDevStatePowerD0Starting DEBUGGED_EVENT }, 416 NULL, 417 { TRUE, 418 0 }, 419 }, 420 421 // WdfDevStatePowerDxDisablingWakeAtBus 422 { FxPkgPnp::PowerDxDisablingWakeAtBus, 423 { PowerEventMaximum, WdfDevStatePowerNull }, 424 NULL, 425 { FALSE, 426 0 }, 427 }, 428 429 // WdfDevStatePowerDxDisablingWakeAtBusNP 430 { FxPkgPnp::PowerDxDisablingWakeAtBusNP, 431 { PowerEventMaximum, WdfDevStatePowerNull }, 432 NULL, 433 { FALSE, 434 0 }, 435 }, 436 437 // WdfDevStatePowerGotoDx 438 { FxPkgPnp::PowerGotoDNotZero, 439 { PowerCompleteDx, WdfDevStatePowerNotifyingD0ExitToWakeInterrupts DEBUGGED_EVENT }, 440 NULL, 441 { FALSE, 442 PowerWakeArrival | // on a PDO which is the PPO, it will send a wake 443 // request in this state. 444 445 446 PowerParentToD0 // Parent is powering up while this device is powering 447 // down 448 }, 449 }, 450 451 // WdfDevStatePowerGotoDxNP 452 { FxPkgPnp::PowerGotoDNotZeroNP, 453 { PowerCompleteDx, WdfDevStatePowerNotifyingD0ExitToWakeInterruptsNP DEBUGGED_EVENT }, 454 NULL, 455 { FALSE, 456 PowerWakeArrival | // on a PDO which is the PPO, it will send a wake 457 // request in this state. 458 459 460 PowerParentToD0 // Parent is powering up while this device is powering 461 // down 462 }, 463 }, 464 465 // WdfDevStatePowerGotoDxIoStopped 466 { FxPkgPnp::PowerGotoDNotZeroIoStopped, 467 { PowerEventMaximum, WdfDevStatePowerNull }, 468 NULL, 469 { FALSE, 470 0 }, 471 }, 472 473 // WdfDevStatePowerGotoDxIoStoppedNP 474 { FxPkgPnp::PowerGotoDNotZeroIoStoppedNP, 475 { PowerEventMaximum, WdfDevStatePowerNull }, 476 NULL, 477 { FALSE, 478 0 }, 479 }, 480 481 // WdfDevStatePowerGotoDxNPFailed 482 { FxPkgPnp::PowerGotoDxNPFailed, 483 { PowerEventMaximum, WdfDevStatePowerNull }, 484 NULL, 485 { FALSE, 486 0 }, 487 }, 488 489 // NOTE: can't use PowerDx as a func name since it's an enum value 490 // WdfDevStatePowerDx 491 { NULL, 492 { PowerD0, WdfDevStatePowerCheckDeviceType DEBUGGED_EVENT }, 493 FxPkgPnp::m_PowerDNotZeroOtherStates, 494 { TRUE, 495 PowerWakeArrival | // on a PDO which is the PPO, it will send a wake 496 // request in this state. 497 498 499 500 PowerWakeCanceled | // on a PDO which is the PPO, it will cancel the 501 // the wake request in this state. Since we didn't 502 // handle PowerWakeArrival in WdfDevStatePowerGotoDx 503 // for this scenario, we must also handle the canel 504 // here. Even if we handle wake arrived in that 505 // state, the PPO (non KMDF) could send a wake 506 // request while in Dx and then cancel it in Dx, 507 // so we must still ignore this event here. 508 509 PowerWakeSucceeded | // on a PDO which is the PPO, a completion of the 510 // wait wake can arrive in this state. This event 511 // can be ignored and the pending wait wake will 512 // be completed. 513 514 PowerImplicitD3 | 515 PowerParentToD0 | // parent went to D0 first while the PDO was still 516 // in Dx 517 518 PowerDx // power policy sent a Dx to Dx transition 519 }, 520 }, 521 522 // WdfDevStatePowerDxNP 523 { NULL, 524 { PowerD0, WdfDevStatePowerCheckDeviceTypeNP DEBUGGED_EVENT }, 525 FxPkgPnp::m_PowerDNotZeroNPOtherStates, 526 { TRUE, 527 PowerWakeArrival | // on a PDO which is the PPO, it will send a wake 528 // request in this state. 529 530 531 532 PowerWakeCanceled | // on a PDO which is the PPO, it will cancel the 533 // the wake request in this state. Since we didn't 534 // handle PowerWakeArrival in WdfDevStatePowerGotoDx 535 // for this scenario, we must also handle the canel 536 // here. Even if we handle wake arrived in that 537 // state, the PPO (non KMDF) could send a wake 538 // request while in Dx and then cancel it in Dx, 539 // so we must still ignore this event here. 540 541 PowerWakeSucceeded | // on a PDO which is the PPO, a completion of the 542 // wait wake can arrive in this state. This event 543 // can be ignored and the pending wait wake will 544 // be completed. 545 546 PowerParentToD0 | // parent went to D0 first while the PDO was still 547 // in Dx 548 549 PowerDx // power policy sent a Dx to Dx transition 550 }, 551 }, 552 553 // WdfDevStatePowerGotoDxArmedForWake 554 { FxPkgPnp::PowerGotoDxArmedForWake, 555 { PowerCompleteDx, WdfDevStatePowerGotoDxIoStoppedArmedForWake DEBUGGED_EVENT }, 556 NULL, 557 { FALSE, 558 0 }, 559 }, 560 561 // WdfDevStatePowerGotoDxArmedForWakeNP 562 { FxPkgPnp::PowerGotoDxArmedForWakeNP, 563 { PowerCompleteDx, WdfDevStatePowerGotoDxIoStoppedArmedForWakeNP DEBUGGED_EVENT }, 564 NULL, 565 { FALSE, 566 0 }, 567 }, 568 569 // WdfDevStatePowerGotoDxIoStoppedArmedForWake 570 { FxPkgPnp::PowerGotoDxIoStoppedArmedForWake, 571 { PowerEventMaximum, WdfDevStatePowerNull }, 572 NULL, 573 { FALSE, 574 0 }, 575 }, 576 577 // WdfDevStatePowerGotoDxIoStoppedArmedForWakeNP 578 { FxPkgPnp::PowerGotoDxIoStoppedArmedForWakeNP, 579 { PowerEventMaximum, WdfDevStatePowerNull }, 580 NULL, 581 { FALSE, 582 0 }, 583 }, 584 585 // WdfDevStatePowerDxArmedForWake 586 { NULL, 587 { PowerD0, WdfDevStatePowerCheckParentStateArmedForWake DEBUGGED_EVENT }, 588 FxPkgPnp::m_DxArmedForWakeOtherStates, 589 { TRUE, 590 PowerParentToD0 // can occur on a PDO when a Dx transition completes 591 // on the parent and it wakes up before the child 592 }, 593 }, 594 595 // WdfDevStatePowerDxArmedForWakeNP 596 { NULL, 597 { PowerD0, WdfDevStatePowerCheckParentStateArmedForWakeNP DEBUGGED_EVENT }, 598 FxPkgPnp::m_DxArmedForWakeNPOtherStates, 599 { TRUE, 600 PowerParentToD0 // can occur on a PDO when a Dx transition completes 601 // on the parent and it wakes up before the child 602 }, 603 }, 604 605 // WdfDevStatePowerCheckParentStateArmedForWake 606 { FxPkgPnp::PowerCheckParentStateArmedForWake, 607 { PowerEventMaximum, WdfDevStatePowerNull }, 608 NULL, 609 { FALSE, 610 0 }, 611 }, 612 613 // WdfDevStatePowerCheckParentStateArmedForWakeNP 614 { FxPkgPnp::PowerCheckParentStateArmedForWakeNP, 615 { PowerEventMaximum, WdfDevStatePowerNull }, 616 NULL, 617 { FALSE, 618 0 }, 619 }, 620 621 // WdfDevStatePowerWaitForParentArmedForWake 622 { NULL, 623 { PowerParentToD0, WdfDevStatePowerDxDisablingWakeAtBus DEBUGGED_EVENT }, 624 NULL, 625 { FALSE, 626 0 }, 627 }, 628 629 // WdfDevStatePowerWaitForParentArmedForWakeNP 630 { NULL, 631 { PowerParentToD0, WdfDevStatePowerDxDisablingWakeAtBusNP DEBUGGED_EVENT }, 632 NULL, 633 { FALSE, 634 0 }, 635 }, 636 637 // WdfDevStatePowerStartSelfManagedIo 638 { FxPkgPnp::PowerStartSelfManagedIo, 639 { PowerEventMaximum, WdfDevStatePowerNull }, 640 NULL, 641 { FALSE, 642 0 }, 643 }, 644 645 // WdfDevStatePowerStartSelfManagedIoNP 646 { FxPkgPnp::PowerStartSelfManagedIoNP, 647 { PowerEventMaximum, WdfDevStatePowerNull }, 648 NULL, 649 { FALSE, 650 0 }, 651 }, 652 653 // WdfDevStatePowerStartSelfManagedIoFailed 654 { FxPkgPnp::PowerStartSelfManagedIoFailed, 655 { PowerEventMaximum, WdfDevStatePowerNull }, 656 NULL, 657 { FALSE, 658 0 }, 659 }, 660 661 // WdfDevStatePowerStartSelfManagedIoFailedNP 662 { FxPkgPnp::PowerStartSelfManagedIoFailedNP, 663 { PowerEventMaximum, WdfDevStatePowerNull }, 664 NULL, 665 { FALSE, 666 0 }, 667 }, 668 669 // WdfDevStatePowerWaitForParent 670 { NULL, 671 { PowerParentToD0, WdfDevStatePowerWaking DEBUGGED_EVENT }, 672 NULL, 673 { FALSE, 674 0 }, 675 }, 676 677 // WdfDevStatePowerWaitForParentNP 678 { NULL, 679 { PowerParentToD0, WdfDevStatePowerWakingNP DEBUGGED_EVENT }, 680 NULL, 681 { FALSE, 682 0 }, 683 }, 684 685 // WdfDevStatePowerWakePending 686 { FxPkgPnp::PowerWakePending, 687 { PowerD0, WdfDevStatePowerCheckParentStateArmedForWake DEBUGGED_EVENT }, 688 FxPkgPnp::m_WakePendingOtherStates, 689 { TRUE, 690 PowerParentToD0 // parent moved to D0 while the child was moving to 691 // D0 from Dx armed for wake 692 }, 693 }, 694 695 // WdfDevStatePowerWakePendingNP 696 { FxPkgPnp::PowerWakePendingNP, 697 { PowerD0, WdfDevStatePowerCheckParentStateArmedForWakeNP DEBUGGED_EVENT }, 698 FxPkgPnp::m_WakePendingNPOtherStates, 699 { TRUE, 700 PowerParentToD0 // parent moved to D0 while the child was moving to 701 // D0 from Dx armed for wake 702 }, 703 }, 704 705 // WdfDevStatePowerWaking 706 { FxPkgPnp::PowerWaking, 707 { PowerEventMaximum, WdfDevStatePowerNull }, 708 NULL, 709 { FALSE, 710 0 }, 711 }, 712 713 // WdfDevStatePowerWakingNP 714 { FxPkgPnp::PowerWakingNP, 715 { PowerEventMaximum, WdfDevStatePowerNull }, 716 NULL, 717 { FALSE, 718 0 }, 719 }, 720 721 // WdfDevStatePowerWakingConnectInterrupt 722 { FxPkgPnp::PowerWakingConnectInterrupt, 723 { PowerEventMaximum, WdfDevStatePowerNull }, 724 NULL, 725 { FALSE, 726 0 }, 727 }, 728 729 // WdfDevStatePowerWakingConnectInterruptNP 730 { FxPkgPnp::PowerWakingConnectInterruptNP, 731 { PowerEventMaximum, WdfDevStatePowerNull }, 732 NULL, 733 { FALSE, 734 0 }, 735 }, 736 737 // WdfDevStatePowerWakingConnectInterruptFailed 738 { FxPkgPnp::PowerWakingConnectInterruptFailed, 739 { PowerEventMaximum, WdfDevStatePowerNull }, 740 NULL, 741 { FALSE, 742 0 }, 743 }, 744 745 // WdfDevStatePowerWakingConnectInterruptFailedNP 746 { FxPkgPnp::PowerWakingConnectInterruptFailedNP, 747 { PowerEventMaximum, WdfDevStatePowerNull }, 748 NULL, 749 { FALSE, 750 0 }, 751 }, 752 753 // WdfDevStatePowerWakingDmaEnable 754 { FxPkgPnp::PowerWakingDmaEnable, 755 { PowerCompleteD0, WdfDevStatePowerStartSelfManagedIo DEBUGGED_EVENT }, 756 NULL, 757 { FALSE, 758 PowerParentToD0 // parent moved to D0 while the child was moving to 759 // D0 from Dx armed for wake 760 }, 761 }, 762 763 // WdfDevStatePowerWakingDmaEnableNP 764 { FxPkgPnp::PowerWakingDmaEnableNP, 765 { PowerCompleteD0, WdfDevStatePowerStartSelfManagedIoNP DEBUGGED_EVENT }, 766 NULL, 767 { FALSE, 768 PowerParentToD0 // parent moved to D0 while the child was moving to 769 // D0 from Dx armed for wake 770 }, 771 }, 772 773 // WdfDevStatePowerWakingDmaEnableFailed 774 { FxPkgPnp::PowerWakingDmaEnableFailed, 775 { PowerEventMaximum, WdfDevStatePowerNull }, 776 NULL, 777 { FALSE, 778 0 }, 779 }, 780 781 // WdfDevStatePowerWakingDmaEnableFailedNP 782 { FxPkgPnp::PowerWakingDmaEnableFailedNP, 783 { PowerEventMaximum, WdfDevStatePowerNull }, 784 NULL, 785 { FALSE, 786 0 }, 787 }, 788 789 // WdfDevStatePowerReportPowerUpFailedDerefParent 790 { FxPkgPnp::PowerReportPowerUpFailedDerefParent, 791 { PowerEventMaximum, WdfDevStatePowerNull }, 792 NULL, 793 { FALSE, 794 0 795 }, 796 }, 797 798 // WdfDevStatePowerReportPowerUpFailed 799 { FxPkgPnp::PowerReportPowerUpFailed, 800 { PowerImplicitD3, WdfDevStatePowerPowerFailedPowerDown DEBUGGED_EVENT }, 801 NULL, 802 { TRUE, 803 0 804 }, 805 }, 806 807 // WdfDevStatePowerPowerFailedPowerDown 808 { FxPkgPnp::PowerPowerFailedPowerDown, 809 { PowerEventMaximum, WdfDevStatePowerNull }, 810 NULL, 811 { FALSE, 812 0 }, 813 }, 814 815 // WdfDevStatePowerReportPowerDownFailed 816 { FxPkgPnp::PowerReportPowerDownFailed, 817 { PowerImplicitD3, WdfDevStatePowerPowerFailedPowerDown DEBUGGED_EVENT }, 818 NULL, 819 { TRUE, 820 0 }, 821 }, 822 823 // WdfDevStatePowerInitialConnectInterruptFailed 824 { FxPkgPnp::PowerInitialConnectInterruptFailed, 825 { PowerEventMaximum, WdfDevStatePowerNull }, 826 NULL, 827 { FALSE, 828 0 }, 829 }, 830 831 // WdfDevStatePowerInitialDmaEnableFailed 832 { FxPkgPnp::PowerInitialDmaEnableFailed, 833 { PowerEventMaximum, WdfDevStatePowerNull }, 834 NULL, 835 { FALSE, 836 0 }, 837 }, 838 839 // WdfDevStatePowerInitialSelfManagedIoFailed 840 { FxPkgPnp::PowerInitialSelfManagedIoFailed, 841 { PowerEventMaximum, WdfDevStatePowerNull }, 842 NULL, 843 { FALSE, 844 0 }, 845 }, 846 847 // WdfDevStatePowerInitialPowerUpFailedDerefParent 848 { FxPkgPnp::PowerInitialPowerUpFailedDerefParent, 849 { PowerEventMaximum, WdfDevStatePowerNull }, 850 NULL, 851 { FALSE, 852 0 }, 853 }, 854 855 // WdfDevStatePowerInitialPowerUpFailed 856 { FxPkgPnp::PowerInitialPowerUpFailed, 857 { PowerEventMaximum, WdfDevStatePowerNull }, 858 NULL, 859 { FALSE, 860 0 }, 861 }, 862 863 // WdfDevStatePowerDxStoppedDisarmWake 864 { FxPkgPnp::PowerDxStoppedDisarmWake, 865 { PowerEventMaximum, WdfDevStatePowerNull }, 866 NULL, 867 { FALSE, 868 0 }, 869 }, 870 871 // WdfDevStatePowerDxStoppedDisarmWakeNP 872 { FxPkgPnp::PowerDxStoppedDisarmWakeNP, 873 { PowerEventMaximum, WdfDevStatePowerNull }, 874 NULL, 875 { FALSE, 876 0 }, 877 }, 878 879 // WdfDevStatePowerGotoDxStoppedDisableInterruptNP 880 { FxPkgPnp::PowerGotoDxStoppedDisableInterruptNP, 881 { PowerEventMaximum, WdfDevStatePowerNull }, 882 NULL, 883 { FALSE, 884 0 }, 885 }, 886 887 // WdfDevStatePowerGotoDxStopped 888 { FxPkgPnp::PowerGotoDxStopped, 889 { PowerEventMaximum, WdfDevStatePowerNull }, 890 NULL, 891 { FALSE, 892 0 }, 893 }, 894 895 // WdfDevStatePowerDxStopped 896 { NULL, 897 { PowerImplicitD0, WdfDevStatePowerDxStoppedDecideDxState TRAP_ON_EVENT }, 898 FxPkgPnp::m_PowerDxStoppedOtherStates, 899 { TRUE, 900 0 }, 901 }, 902 903 // WdfDevStatePowerGotoStopped 904 { FxPkgPnp::PowerGotoStopped, 905 { PowerEventMaximum, WdfDevStatePowerNull }, 906 NULL, 907 { FALSE, 908 0 }, 909 }, 910 911 // WdfDevStatePowerStoppedCompleteDx 912 { FxPkgPnp::PowerStoppedCompleteDx, 913 { PowerEventMaximum, WdfDevStatePowerNull }, 914 NULL, 915 { FALSE, 916 0 }, 917 }, 918 919 // WdfDevStatePowerDxStoppedDecideDxState 920 { FxPkgPnp::PowerDxStoppedDecideDxState, 921 { PowerEventMaximum, WdfDevStatePowerNull }, 922 NULL, 923 { FALSE, 924 0 }, 925 }, 926 927 // WdfDevStatePowerDxStoppedArmForWake 928 { FxPkgPnp::PowerDxStoppedArmForWake, 929 { PowerEventMaximum, WdfDevStatePowerNull }, 930 NULL, 931 { FALSE, 932 0 }, 933 }, 934 935 // WdfDevStatePowerDxStoppedArmForWakeNP 936 { FxPkgPnp::PowerDxStoppedArmForWakeNP, 937 { PowerEventMaximum, WdfDevStatePowerNull }, 938 NULL, 939 { FALSE, 940 0 }, 941 }, 942 943 // WdfDevStatePowerFinalPowerDownFailed 944 { FxPkgPnp::PowerFinalPowerDownFailed, 945 { PowerEventMaximum, WdfDevStatePowerNull }, 946 NULL, 947 { FALSE, 948 0 }, 949 }, 950 951 // WdfDevStatePowerFinal 952 { NULL, 953 { PowerEventMaximum, WdfDevStatePowerNull }, 954 NULL, 955 { FALSE, 956 0 }, 957 }, 958 959 // WdfDevStatePowerGotoImplicitD3DisarmWakeAtBus 960 { FxPkgPnp::PowerGotoImplicitD3DisarmWakeAtBus, 961 { PowerEventMaximum, WdfDevStatePowerNull DEBUGGED_EVENT }, 962 NULL, 963 { FALSE, 964 0 }, 965 }, 966 967 // WdfDevStatePowerUpFailed 968 { FxPkgPnp::PowerUpFailed, 969 { PowerEventMaximum, WdfDevStatePowerNull }, 970 NULL, 971 { FALSE, 972 0 }, 973 }, 974 975 // WdfDevStatePowerUpFailedDerefParent 976 { FxPkgPnp::PowerUpFailedDerefParent, 977 { PowerEventMaximum, WdfDevStatePowerNull }, 978 NULL, 979 { FALSE, 980 0 }, 981 }, 982 983 // WdfDevStatePowerGotoDxFailed 984 { FxPkgPnp::PowerGotoDxFailed, 985 { PowerEventMaximum, WdfDevStatePowerNull }, 986 NULL, 987 { FALSE, 988 0 }, 989 }, 990 991 // WdfDevStatePowerGotoDxStoppedDisableInterrupt 992 { FxPkgPnp::PowerGotoDxStoppedDisableInterrupt, 993 { PowerEventMaximum, WdfDevStatePowerNull }, 994 NULL, 995 { FALSE, 996 0 }, 997 }, 998 999 // WdfDevStatePowerUpFailedNP 1000 { FxPkgPnp::PowerUpFailedNP, 1001 { PowerEventMaximum, WdfDevStatePowerNull }, 1002 NULL, 1003 { FALSE, 1004 0 }, 1005 }, 1006 1007 // WdfDevStatePowerUpFailedDerefParentNP 1008 { FxPkgPnp::PowerUpFailedDerefParentNP, 1009 { PowerEventMaximum, WdfDevStatePowerNull }, 1010 NULL, 1011 { FALSE, 1012 0 }, 1013 }, 1014 1015 // WdfDevStatePowerNotifyingD0ExitToWakeInterrupts 1016 { FxPkgPnp::PowerNotifyingD0ExitToWakeInterrupts, 1017 { PowerWakeInterruptCompleteTransition, WdfDevStatePowerGotoDxIoStopped DEBUGGED_EVENT }, 1018 NULL, 1019 { FALSE, 1020 0 }, 1021 }, 1022 1023 // WdfDevStatePowerNotifyingD0EntryToWakeInterrupts 1024 { FxPkgPnp::PowerNotifyingD0EntryToWakeInterrupts, 1025 { PowerWakeInterruptCompleteTransition, WdfDevStatePowerWakingConnectInterrupt DEBUGGED_EVENT }, 1026 NULL, 1027 { FALSE, 1028 0 }, 1029 }, 1030 // WdfDevStatePowerNotifyingD0ExitToWakeInterruptsNP 1031 { FxPkgPnp::PowerNotifyingD0ExitToWakeInterruptsNP, 1032 { PowerWakeInterruptCompleteTransition, WdfDevStatePowerGotoDxIoStoppedNP TRAP_ON_EVENT }, 1033 NULL, 1034 { FALSE, 1035 0 }, 1036 }, 1037 1038 // WdfDevStatePowerNotifyingD0EntryToWakeInterrupts 1039 { FxPkgPnp::PowerNotifyingD0EntryToWakeInterruptsNP, 1040 { PowerWakeInterruptCompleteTransition, WdfDevStatePowerWakingConnectInterruptNP TRAP_ON_EVENT }, 1041 NULL, 1042 { FALSE, 1043 0 }, 1044 }, 1045 1046 // WdfDevStatePowerNull 1047 // *** no entry for this state *** 1048 }; 1049 1050 // @@SMVERIFY_SPLIT_END 1051 1052 _Must_inspect_result_ 1053 NTSTATUS 1054 FxPowerMachine::Init( 1055 __inout FxPkgPnp* Pnp, 1056 __in PFN_PNP_EVENT_WORKER WorkerRoutine 1057 ) 1058 { 1059 NTSTATUS status; 1060 1061 status = FxThreadedEventQueue::Init(Pnp, WorkerRoutine); 1062 if (!NT_SUCCESS(status)) { 1063 return status; 1064 } 1065 1066 return STATUS_SUCCESS; 1067 } 1068 1069 VOID 1070 FxPkgPnp::PowerCheckAssumptions( 1071 VOID 1072 ) 1073 /*++ 1074 1075 Routine Description: 1076 This routine is never actually called by running code, it just has 1077 WDFCASSERTs who upon failure, would not allow this file to be compiled. 1078 1079 DO NOT REMOVE THIS FUNCTION just because it is not called by any running 1080 code. 1081 1082 Arguments: 1083 None 1084 1085 Return Value: 1086 None 1087 1088 --*/ 1089 { 1090 WDFCASSERT(sizeof(FxPowerStateInfo) == sizeof(ULONG)); 1091 1092 WDFCASSERT((sizeof(m_WdfPowerStates)/sizeof(m_WdfPowerStates[0])) 1093 == 1094 (WdfDevStatePowerNull - WdfDevStatePowerObjectCreated)); 1095 1096 // we assume these are the same length when we update the history index 1097 WDFCASSERT((sizeof(m_PowerMachine.m_Queue.Events)/ 1098 sizeof(m_PowerMachine.m_Queue.Events[0])) 1099 == 1100 (sizeof(m_PowerMachine.m_States.History)/ 1101 sizeof(m_PowerMachine.m_States.History[0]))); 1102 } 1103 1104 1105 /*++ 1106 1107 The locking model for the Power state machine requires that events be enqueued 1108 possibly at DISPATCH_LEVEL. It also requires that the state machine be 1109 runnable at PASSIVE_LEVEL. Consequently, we have two locks, one DISPATCH_LEVEL 1110 lock that guards the event queue and one PASSIVE_LEVEL lock that guards the 1111 state machine itself. 1112 1113 The Power state machine has a few constraints that the PnP state machine 1114 doesn't. Sometimes it has to call some driver functions at PASSIVE_LEVEL, but 1115 with the disks turned off. This means that these functions absolutely must not 1116 page fault. You might think that this means that we should call the driver at 1117 DISPATCH_LEVEL, and you'd be right if your only concern were for perfectly 1118 safe code. The problem with that approach, though is that it will force much 1119 of the rest of the driver to DISPATCH_LEVEL, which will only push the driver 1120 writer into using lots of asynchronous work items, which will complicate their 1121 code and make it unsafe in a new variety of ways. So we're going to go with 1122 PASSIVE_LEVEL here and setting a timeout of 20 seconds. If the driver faults, 1123 the timer will fire and log the failure. This also means that the driver must 1124 complete these callbacks within 20 seconds. Even beyond that, it means that 1125 the work items must be queued onto a special thread, one that once the machine 1126 has started to go to sleep, never handles any work items that may fault. 1127 1128 Algorithm: 1129 1130 1) Acquire the Power queue lock. 1131 2) Enqueue the request. Requests are put at the end of the queue. 1132 3) Drop the Power queue lock. 1133 4) If the thread is running at PASSIVE_LEVEL, skip to step 6. 1134 5) Queue a work item onto the special power thread. 1135 6) Attempt to acquire the state machine lock, with a near-zero-length timeout. 1136 7) If successful, skip to step 9. 1137 8) Queue a work item onto the special power thread. 1138 9) Acquire the state machine lock. 1139 10) Acquire the Power queue lock. 1140 11) Attempt to dequeue an event. 1141 12) Drop the Power queue lock. 1142 13) If there was no event to dequeue, drop the state machine lock and exit. 1143 14) Execute the state handler. This may involve taking one of the other state 1144 machine queue locks, briefly, to deliver an event. 1145 15) Go to Step 10. 1146 1147 Implementing this algorithm requires three functions. 1148 1149 PowerProcessEvent -- Implements steps 1-8. 1150 _PowerProcessEventInner -- Implements step 9. 1151 PowerProcessEventInner -- Implements steps 10-15. 1152 1153 --*/ 1154 1155 VOID 1156 FxPkgPnp::PowerProcessEvent( 1157 __in FxPowerEvent Event, 1158 __in BOOLEAN ProcessOnDifferentThread 1159 ) 1160 /*++ 1161 1162 Routine Description: 1163 This function implements steps 1-8 of the algorithm described above. 1164 1165 Arguments: 1166 Event - Current Power event 1167 1168 ProcessOnDifferentThread - Process the event on a different thread 1169 regardless of IRQL. By default this is FALSE as per the declaration. 1170 1171 Return Value: 1172 1173 NTSTATUS 1174 1175 --*/ 1176 { 1177 NTSTATUS status; 1178 KIRQL irql; 1179 1180 // 1181 // Take the lock, raising to DISPATCH_LEVEL. 1182 // 1183 m_PowerMachine.Lock(&irql); 1184 1185 // 1186 // If the input Event is any of the events described by PowerSingularEventMask, 1187 // then check whether it is already queued up. If so, then dont enqueue this 1188 // Event. 1189 // 1190 if (Event & PowerSingularEventMask) { 1191 if ((m_PowerMachine.m_SingularEventsPresent & Event) == 0x00) { 1192 m_PowerMachine.m_SingularEventsPresent |= Event; 1193 } 1194 else { 1195 DoTraceLevelMessage( 1196 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 1197 "WDFDEVICE 0x%p !devobj 0x%p current pwr pol state " 1198 "%!WDF_DEVICE_POWER_STATE! dropping event %!FxPowerEvent! because " 1199 "the Event is already enqueued.", m_Device->GetHandle(), 1200 m_Device->GetDeviceObject(), 1201 m_Device->GetDevicePowerState(), 1202 Event); 1203 1204 m_PowerMachine.Unlock(irql); 1205 return; 1206 } 1207 } 1208 1209 if (m_PowerMachine.IsFull()) { 1210 // 1211 // The queue is full. Bail. 1212 // 1213 m_PowerMachine.Unlock(irql); 1214 1215 ASSERT(!"The Power queue is full. This shouldn't be able to happen."); 1216 return; 1217 } 1218 1219 if (m_PowerMachine.IsClosedLocked()) { 1220 DoTraceLevelMessage( 1221 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 1222 "WDFDEVICE 0x%p !devobj 0x%p current pwr pol state " 1223 "%!WDF_DEVICE_POWER_STATE! dropping event %!FxPowerEvent! because " 1224 "of a closed queue", m_Device->GetHandle(), 1225 m_Device->GetDeviceObject(), 1226 m_Device->GetDevicePowerState(), 1227 Event); 1228 1229 // 1230 // The queue is closed. Bail 1231 // 1232 m_PowerMachine.Unlock(irql); 1233 1234 return; 1235 } 1236 1237 // 1238 // Enqueue the event. Whether the event goes on the front 1239 // or the end of the queue depends on which event it is. 1240 // 1241 if (Event & PowerPriorityEventsMask) { 1242 // 1243 // Stick it on the front of the queue, making it the next 1244 // event that will be processed. 1245 // 1246 m_PowerMachine.m_Queue.Events[m_PowerMachine.InsertAtHead()] = (USHORT) Event; 1247 } 1248 else { 1249 // 1250 // Stick it on the end of the queue. 1251 // 1252 m_PowerMachine.m_Queue.Events[m_PowerMachine.InsertAtTail()] = (USHORT) Event; 1253 } 1254 1255 // 1256 // Drop the lock. 1257 // 1258 m_PowerMachine.Unlock(irql); 1259 1260 // 1261 // Now, if we are running at PASSIVE_LEVEL, attempt to run the state 1262 // machine on this thread. If we can't do that, then queue a work item. 1263 // 1264 1265 if (irql == PASSIVE_LEVEL && 1266 FALSE == ProcessOnDifferentThread) { 1267 LONGLONG timeout = 0; 1268 1269 status = m_PowerMachine.m_StateMachineLock.AcquireLock( 1270 GetDriverGlobals(), &timeout); 1271 1272 if (FxWaitLockInternal::IsLockAcquired(status)) { 1273 FxPostProcessInfo info; 1274 1275 // 1276 // We now hold the state machine lock. So call the function that 1277 // dispatches the next state. 1278 // 1279 PowerProcessEventInner(&info); 1280 1281 // 1282 // The pnp state machine should be the only one deleting the object 1283 // 1284 ASSERT(info.m_DeleteObject == FALSE); 1285 1286 m_PowerMachine.m_StateMachineLock.ReleaseLock(GetDriverGlobals()); 1287 1288 info.Evaluate(this); 1289 1290 return; 1291 } 1292 } 1293 1294 // 1295 // The tag added above will be released when the work item runs 1296 // 1297 1298 // For one reason or another, we couldn't run the state machine on this 1299 // thread. So queue a work item to do it. If m_PnPWorkItemEnqueuing 1300 // is non-zero, that means that the work item is already being enqueued 1301 // on another thread. This is significant, since it means that we can't do 1302 // anything with the work item on this thread, but it's okay, since the 1303 // work item will pick up our work and do it. 1304 // 1305 m_PowerMachine.QueueToThread(); 1306 } 1307 1308 VOID 1309 FxPkgPnp::_PowerProcessEventInner( 1310 __in FxPkgPnp* This, 1311 __in FxPostProcessInfo* Info, 1312 __in PVOID WorkerContext 1313 ) 1314 { 1315 1316 UNREFERENCED_PARAMETER(WorkerContext); 1317 1318 // 1319 // Take the state machine lock. 1320 // 1321 This->m_PowerMachine.m_StateMachineLock.AcquireLock( 1322 This->GetDriverGlobals() 1323 ); 1324 1325 // 1326 // Call the function that will actually run the state machine. 1327 // 1328 This->PowerProcessEventInner(Info); 1329 1330 // 1331 // We are being called from the work item and m_WorkItemRunning is > 0, so 1332 // we cannot be deleted yet. 1333 // 1334 ASSERT(Info->SomethingToDo() == FALSE); 1335 1336 // 1337 // Now release the lock 1338 // 1339 This->m_PowerMachine.m_StateMachineLock.ReleaseLock( 1340 This->GetDriverGlobals() 1341 ); 1342 } 1343 1344 VOID 1345 FxPkgPnp::PowerProcessEventInner( 1346 __inout FxPostProcessInfo* Info 1347 ) 1348 /*++ 1349 1350 Routine Description: 1351 This routine runs the state machine. It implements steps 10-15 of the 1352 algorithm described above. 1353 1354 --*/ 1355 { 1356 WDF_DEVICE_POWER_STATE currentPowerState, newState; 1357 CPPOWER_STATE_TABLE entry; 1358 FxPowerEvent event; 1359 KIRQL oldIrql; 1360 1361 // 1362 // Process as many events as we can. 1363 // 1364 for (;;) { 1365 1366 newState = WdfDevStatePowerNull; 1367 currentPowerState = m_Device->GetDevicePowerState(); 1368 entry = GetPowerTableEntry(currentPowerState); 1369 1370 // 1371 // Get an event from the queue. 1372 // 1373 m_PowerMachine.Lock(&oldIrql); 1374 1375 if (m_PowerMachine.IsEmpty()) { 1376 m_PowerMachine.GetFinishedState(Info); 1377 1378 // 1379 // The queue is empty. 1380 // 1381 m_PowerMachine.Unlock(oldIrql); 1382 return; 1383 } 1384 1385 event = (FxPowerEvent) m_PowerMachine.m_Queue.Events[m_PowerMachine.GetHead()]; 1386 1387 // 1388 // At this point, we need to determine whether we can process this 1389 // event. 1390 // 1391 if (event & PowerPriorityEventsMask) { 1392 // 1393 // These are always possible to handle. 1394 // 1395 DO_NOTHING(); 1396 } 1397 else { 1398 // 1399 // Check to see if this state can handle new events. 1400 // 1401 if (entry->StateInfo.Bits.QueueOpen == FALSE) { 1402 // 1403 // This state can't handle new events. 1404 // 1405 m_PowerMachine.Unlock(oldIrql); 1406 return; 1407 } 1408 } 1409 1410 // 1411 // If the event obtained from the queue was a singular event, then 1412 // clear the flag to allow other similar events to be put into this 1413 // queue for processing. 1414 // 1415 if (m_PowerMachine.m_SingularEventsPresent & event) { 1416 m_PowerMachine.m_SingularEventsPresent &= ~event; 1417 } 1418 1419 m_PowerMachine.IncrementHead(); 1420 m_PowerMachine.Unlock(oldIrql); 1421 1422 // 1423 // Find the entry in the power state table that corresponds to this event 1424 // 1425 if (entry->FirstTargetState.PowerEvent == event) { 1426 newState = entry->FirstTargetState.TargetState; 1427 1428 DO_EVENT_TRAP(&entry->FirstTargetState); 1429 } 1430 else if (entry->OtherTargetStates != NULL) { 1431 ULONG i = 0; 1432 1433 for (i = 0; 1434 entry->OtherTargetStates[i].PowerEvent != PowerEventMaximum; 1435 i++) { 1436 if (entry->OtherTargetStates[i].PowerEvent == event) { 1437 newState = entry->OtherTargetStates[i].TargetState; 1438 DO_EVENT_TRAP(&entry->OtherTargetStates[i]); 1439 break; 1440 } 1441 } 1442 } 1443 1444 if (newState == WdfDevStatePowerNull) { 1445 DoTraceLevelMessage( 1446 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 1447 "WDFDEVICE 0x%p !devobj 0x%p current power state " 1448 "%!WDF_DEVICE_POWER_STATE! dropping event %!FxPowerEvent!", 1449 m_Device->GetHandle(), 1450 m_Device->GetDeviceObject(), 1451 m_Device->GetDevicePowerState(), event); 1452 1453 // 1454 // This state doesn't respond to the Event. Potentially throw 1455 // the event away. 1456 // 1457 if ((entry->StateInfo.Bits.KnownDroppedEvents & event) == 0) { 1458 COVERAGE_TRAP(); 1459 1460 DoTraceLevelMessage( 1461 GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP, 1462 "WDFDEVICE %p !devobj 0x%p current state " 1463 "%!WDF_DEVICE_POWER_STATE! event %!FxPowerEvent! is not a " 1464 "known dropped event, known dropped events are " 1465 "%!FxPowerEvent!", m_Device->GetHandle(), 1466 m_Device->GetDeviceObject(), 1467 m_Device->GetDevicePowerState(), 1468 event, entry->StateInfo.Bits.KnownDroppedEvents); 1469 1470 1471 } 1472 1473 switch (event) { 1474 case PowerWakeSucceeded: 1475 case PowerWakeFailed: 1476 case PowerWakeCanceled: 1477 // 1478 // There are states where we don't care if the wake completed. 1479 // Since the completion/cancellation of the wake request posts 1480 // an event which it assumes will complete the request, we must 1481 // catch these events here and complete the request. 1482 // 1483 PowerCompletePendedWakeIrp(); 1484 break; 1485 1486 case PowerD0: 1487 case PowerDx: 1488 // 1489 // There are some (non WDF) power policy owner implementations 1490 // which send Dx to Dx or D0 to D0 transitions to the stack. 1491 // 1492 // We don't explicitly handle them in the state machine. 1493 // 1494 // Instead, we complete the pended irp if are about to drop it 1495 // on the floor. 1496 // 1497 PowerReleasePendingDeviceIrp(); 1498 break; 1499 } 1500 } 1501 else { 1502 // 1503 // Now enter the new state. 1504 // 1505 PowerEnterNewState(newState); 1506 } 1507 } 1508 } 1509 1510 VOID 1511 FxPkgPnp::PowerEnterNewState( 1512 __in WDF_DEVICE_POWER_STATE State 1513 ) 1514 /*++ 1515 1516 Routine Description: 1517 This function looks up the handler for a state and 1518 then calls it. 1519 1520 Arguments: 1521 Event - Current PnP event 1522 1523 Return Value: 1524 1525 NTSTATUS 1526 1527 --*/ 1528 { 1529 CPPOWER_STATE_TABLE entry; 1530 WDF_DEVICE_POWER_STATE currentState, newState; 1531 WDF_DEVICE_POWER_NOTIFICATION_DATA data; 1532 FxWatchdog watchdog(this); 1533 1534 currentState = m_Device->GetDevicePowerState(); 1535 newState = State; 1536 1537 while (newState != WdfDevStatePowerNull) { 1538 DoTraceLevelMessage( 1539 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNPPOWERSTATES, 1540 "WDFDEVICE 0x%p !devobj 0x%p entering Power State " 1541 "%!WDF_DEVICE_POWER_STATE! from %!WDF_DEVICE_POWER_STATE!", 1542 m_Device->GetHandle(), 1543 m_Device->GetDeviceObject(), 1544 newState, currentState); 1545 1546 if (m_PowerStateCallbacks != NULL) { 1547 // 1548 // Callback for leaving the old state 1549 // 1550 RtlZeroMemory(&data, sizeof(data)); 1551 1552 data.Type = StateNotificationLeaveState; 1553 data.Data.LeaveState.CurrentState = currentState; 1554 data.Data.LeaveState.NewState = newState; 1555 1556 m_PowerStateCallbacks->Invoke(currentState, 1557 StateNotificationLeaveState, 1558 m_Device->GetHandle(), 1559 &data); 1560 } 1561 1562 m_PowerMachine.m_States.History[m_PowerMachine.IncrementHistoryIndex()] = 1563 (USHORT) newState; 1564 1565 if (m_PowerStateCallbacks != NULL) { 1566 // 1567 // Callback for entering the new state 1568 // 1569 RtlZeroMemory(&data, sizeof(data)); 1570 1571 data.Type = StateNotificationEnterState; 1572 data.Data.EnterState.CurrentState = currentState; 1573 data.Data.EnterState.NewState = newState; 1574 1575 m_PowerStateCallbacks->Invoke(newState, 1576 StateNotificationEnterState, 1577 m_Device->GetHandle(), 1578 &data); 1579 } 1580 1581 m_Device->SetDevicePowerState(newState); 1582 currentState = newState; 1583 1584 entry = GetPowerTableEntry(currentState); 1585 1586 // 1587 // And call the state handler, if there is one. 1588 // 1589 if (entry->StateFunc != NULL) { 1590 watchdog.StartTimer(currentState); 1591 newState = entry->StateFunc(this); 1592 watchdog.CancelTimer(currentState); 1593 1594 // 1595 // Validate the return value if FX_STATE_MACHINE_VERIFY is enabled 1596 // 1597 VALIDATE_POWER_STATE(currentState, newState); 1598 1599 } 1600 else { 1601 newState = WdfDevStatePowerNull; 1602 } 1603 1604 if (m_PowerStateCallbacks != NULL) { 1605 // 1606 // Callback for post processing the new state 1607 // 1608 RtlZeroMemory(&data, sizeof(data)); 1609 1610 data.Type = StateNotificationPostProcessState; 1611 data.Data.PostProcessState.CurrentState = currentState; 1612 1613 m_PowerStateCallbacks->Invoke(currentState, 1614 StateNotificationPostProcessState, 1615 m_Device->GetHandle(), 1616 &data); 1617 } 1618 } 1619 } 1620 1621 WDF_DEVICE_POWER_STATE 1622 FxPkgPnp::PowerCheckParentState( 1623 __inout FxPkgPnp* This 1624 ) 1625 /*++ 1626 1627 Routine Description: 1628 This function implements the Check Parent state. Its only task 1629 is to dispatch to the FDO and PDO logic and handle error. 1630 1631 Arguments: 1632 none 1633 1634 Return Value: 1635 1636 new power state 1637 1638 --*/ 1639 { 1640 NTSTATUS status; 1641 BOOLEAN parentOn; 1642 1643 status = This->PowerCheckParentOverload(&parentOn); 1644 1645 if (!NT_SUCCESS(status)) { 1646 return WdfDevStatePowerUpFailed; 1647 } 1648 else if (parentOn) { 1649 return WdfDevStatePowerWaking; 1650 } 1651 else { 1652 return WdfDevStatePowerWaitForParent; 1653 } 1654 } 1655 1656 WDF_DEVICE_POWER_STATE 1657 FxPkgPnp::PowerCheckParentStateNP( 1658 __inout FxPkgPnp* This 1659 ) 1660 /*++ 1661 1662 Routine Description: 1663 This function implements the Check Parent (NP) state. Its only task 1664 is to dispatch to the FDO and PDO logic. 1665 1666 Arguments: 1667 none 1668 1669 Return Value: 1670 1671 new power state 1672 1673 --*/ 1674 { 1675 NTSTATUS status; 1676 BOOLEAN parentOn; 1677 1678 status = This->PowerCheckParentOverload(&parentOn); 1679 1680 if (!NT_SUCCESS(status)) { 1681 return WdfDevStatePowerUpFailedNP; 1682 } 1683 else if (parentOn) { 1684 return WdfDevStatePowerWakingNP; 1685 } 1686 else { 1687 return WdfDevStatePowerWaitForParentNP; 1688 } 1689 } 1690 1691 WDF_DEVICE_POWER_STATE 1692 FxPkgPnp::PowerCheckDeviceType( 1693 __inout FxPkgPnp* This 1694 ) 1695 /*++ 1696 1697 Routine Description: 1698 This function implements the Check Type state. Its only task 1699 is to dispatch to the FDO and PDO logic. 1700 1701 Arguments: 1702 none 1703 1704 Return Value: 1705 1706 new power state 1707 1708 --*/ 1709 { 1710 return This->PowerCheckDeviceTypeOverload(); 1711 } 1712 1713 WDF_DEVICE_POWER_STATE 1714 FxPkgPnp::PowerCheckDeviceTypeNP( 1715 __inout FxPkgPnp* This 1716 ) 1717 /*++ 1718 1719 Routine Description: 1720 This function implements the Check Type (NP) state. Its only task 1721 is to dispatch to the FDO and PDO logic. 1722 1723 Arguments: 1724 none 1725 1726 Return Value: 1727 1728 new power state 1729 1730 --*/ 1731 { 1732 return This->PowerCheckDeviceTypeNPOverload(); 1733 } 1734 1735 WDF_DEVICE_POWER_STATE 1736 FxPkgPnp::PowerEnablingWakeAtBus( 1737 __inout FxPkgPnp* This 1738 ) 1739 /*++ 1740 1741 Routine Description: 1742 This function requests the driver to arm the device in a bus generic fashion. 1743 1744 Arguments: 1745 The package which contains this instance of the state machine 1746 1747 Return Value: 1748 new power state 1749 1750 --*/ 1751 { 1752 NTSTATUS status; 1753 1754 // 1755 // We should only get into this state when this devobj is not a PDO and a 1756 // power policy owner. 1757 // 1758 ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE); 1759 1760 status = This->PowerEnableWakeAtBusOverload(); 1761 1762 ASSERT(status != STATUS_CANCELLED); 1763 1764 if (NT_SUCCESS(status)) { 1765 // 1766 // No matter of the irp status (canceled, pending, completed), we always 1767 // transition to the D0ArmedForWake state because that is where we 1768 // we handle the change in the irp's status. 1769 // 1770 return WdfDevStatePowerD0ArmedForWake; 1771 } 1772 else { 1773 This->PowerCompleteWakeRequestFromWithinMachine(status); 1774 1775 return WdfDevStatePowerD0BusWakeOwner; 1776 } 1777 } 1778 1779 WDF_DEVICE_POWER_STATE 1780 FxPkgPnp::PowerEnablingWakeAtBusNP( 1781 __inout FxPkgPnp* This 1782 ) 1783 /*++ 1784 1785 Routine Description: 1786 This function requests the driver to arm the device in a bus generic fashion. 1787 1788 Arguments: 1789 The package which contains this instance of the state machine 1790 1791 Return Value: 1792 new power state 1793 1794 --*/ 1795 { 1796 NTSTATUS status; 1797 1798 // 1799 // We should only get into this state when this devobj is not a PDO and a 1800 // power policy owner. 1801 // 1802 ASSERT((This->m_Device->IsPdo() && 1803 This->IsPowerPolicyOwner()) == FALSE); 1804 1805 status = This->PowerEnableWakeAtBusOverload(); 1806 1807 ASSERT(status != STATUS_CANCELLED); 1808 1809 if (NT_SUCCESS(status)) { 1810 // 1811 // No matter of the irp status (canceled, pending, completed), we always 1812 // transition to the D0ArmedForWake state because that is where we 1813 // we handle the change in the irp's status. 1814 // 1815 return WdfDevStatePowerD0ArmedForWakeNP; 1816 } 1817 else { 1818 // 1819 // Complete the irp with the error that callback indicated 1820 // 1821 COVERAGE_TRAP(); 1822 1823 This->PowerCompleteWakeRequestFromWithinMachine(status); 1824 1825 return WdfDevStatePowerD0BusWakeOwnerNP; 1826 } 1827 } 1828 1829 WDF_DEVICE_POWER_STATE 1830 FxPkgPnp::PowerDZero( 1831 __inout FxPkgPnp* This 1832 ) 1833 /*++ 1834 1835 Routine Description: 1836 D0 state where we cannot wake the machine 1837 1838 Arguments: 1839 This - Instance of this state machine 1840 1841 Return Value: 1842 new power state machine state 1843 1844 --*/ 1845 { 1846 if ((This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) == 0) { 1847 // 1848 // We are non pageable, go to that state now 1849 // 1850 COVERAGE_TRAP(); 1851 1852 return WdfDevStatePowerDecideD0State; 1853 } 1854 1855 return WdfDevStatePowerNull; 1856 } 1857 1858 WDF_DEVICE_POWER_STATE 1859 FxPkgPnp::PowerD0NP( 1860 __inout FxPkgPnp* This 1861 ) 1862 /*++ 1863 1864 Routine Description: 1865 D0 state where we can't cause paging IO and we cannot wake the machine 1866 1867 Arguments: 1868 This - Instance of this state machine 1869 1870 Return Value: 1871 new power state machine state 1872 1873 --*/ 1874 { 1875 if (This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) { 1876 // 1877 // We are pageable, go to that state now 1878 // 1879 COVERAGE_TRAP(); 1880 return WdfDevStatePowerDecideD0State; 1881 } 1882 1883 return WdfDevStatePowerNull; 1884 } 1885 1886 1887 WDF_DEVICE_POWER_STATE 1888 FxPkgPnp::PowerD0BusWakeOwner( 1889 __inout FxPkgPnp* This 1890 ) 1891 /*++ 1892 1893 Routine Description: 1894 This function implements the D0 state. It's job is to figure out whether 1895 we need to swtich to the D0NP state, and to wait around for an event 1896 of some kind or another. 1897 1898 Arguments: 1899 none 1900 1901 Return Value: 1902 1903 new power state 1904 1905 --*/ 1906 { 1907 if ((This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) == 0) { 1908 // 1909 // We are non pageable, go to that state now 1910 // 1911 COVERAGE_TRAP(); 1912 1913 return WdfDevStatePowerDecideD0State; 1914 } 1915 else if (This->PowerIsWakeRequestPresent()) { 1916 return WdfDevStatePowerEnablingWakeAtBus; 1917 } 1918 else { 1919 return WdfDevStatePowerNull; 1920 } 1921 } 1922 1923 WDF_DEVICE_POWER_STATE 1924 FxPkgPnp::PowerD0BusWakeOwnerNP( 1925 __inout FxPkgPnp* This 1926 ) 1927 /*++ 1928 1929 Routine Description: 1930 This function implements the D0NP state. It's job is to figure out whether 1931 we need to swtich to the D0 state, and to wait around for an event 1932 of some kind or another. 1933 1934 Arguments: 1935 none 1936 1937 Return Value: 1938 1939 new power state 1940 1941 --*/ 1942 { 1943 if (This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) { 1944 // 1945 // Pageable. 1946 // 1947 COVERAGE_TRAP(); 1948 1949 return WdfDevStatePowerDecideD0State; 1950 } 1951 else if (This->PowerIsWakeRequestPresent()) { 1952 return WdfDevStatePowerEnablingWakeAtBusNP; 1953 } 1954 else { 1955 return WdfDevStatePowerNull; 1956 } 1957 } 1958 1959 WDF_DEVICE_POWER_STATE 1960 FxPkgPnp::PowerD0ArmedForWake( 1961 __inout FxPkgPnp* This 1962 ) 1963 /*++ 1964 1965 Routine Description: 1966 Device is in D0 and armed for wake. Complete any pended D0 irp if the power 1967 policy owner make a D0 to D0 transition. Transition the NP version of 1968 this state if we are no longer pageable. 1969 1970 Arguments: 1971 This - instance of the state machine 1972 1973 Return Value: 1974 new state machine state 1975 1976 --*/ 1977 { 1978 if ((This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) == 0) { 1979 // 1980 // We are non pageable, go to that state now 1981 // 1982 COVERAGE_TRAP(); 1983 1984 return WdfDevStatePowerDecideD0State; 1985 } 1986 1987 return WdfDevStatePowerNull; 1988 } 1989 1990 WDF_DEVICE_POWER_STATE 1991 FxPkgPnp::PowerD0ArmedForWakeNP( 1992 __inout FxPkgPnp* This 1993 ) 1994 /*++ 1995 1996 Routine Description: 1997 Device is in D0 and armed for wake. Complete any pended D0 irp if the power 1998 policy owner make a D0 to D0 transition. Transition the pageable version of 1999 this state if we are no longer NP. 2000 2001 Arguments: 2002 This - instance of the state machine 2003 2004 Return Value: 2005 new state machine state 2006 2007 --*/ 2008 { 2009 if (This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) { 2010 // 2011 // We are pageable, go to that state now 2012 // 2013 COVERAGE_TRAP(); 2014 2015 return WdfDevStatePowerDecideD0State; 2016 } 2017 2018 return WdfDevStatePowerNull; 2019 } 2020 2021 WDF_DEVICE_POWER_STATE 2022 FxPkgPnp::PowerGotoImplicitD3DisarmWakeAtBus( 2023 __inout FxPkgPnp* This 2024 ) 2025 /*++ 2026 2027 Routine Description: 2028 Disarms the bus after we have armed it. The device is going to implicit D3 2029 and it has not yet been powered down. 2030 2031 Arguments: 2032 This - instance of the state machine 2033 2034 Return Value: 2035 new state machine state 2036 2037 --*/ 2038 { 2039 // 2040 // We should only get into this state when this devobj is a PDO and not a 2041 // power policy owner. 2042 // 2043 ASSERT((This->m_Device->IsPdo() && 2044 This->IsPowerPolicyOwner()) == FALSE); 2045 2046 // 2047 // Disarm 2048 // No need to complete the pended ww irp. State machine will complete it 2049 // in PnpFailed handler, or upper driver will cancel it. 2050 // 2051 This->PowerDisableWakeAtBusOverload(); 2052 2053 return WdfDevStatePowerGotoD3Stopped; 2054 } 2055 2056 WDF_DEVICE_POWER_STATE 2057 FxPkgPnp::PowerD0DisarmingWakeAtBus( 2058 __inout FxPkgPnp* This 2059 ) 2060 /*++ 2061 2062 Routine Description: 2063 Disarms the bus after we have armed it. The device is still in D0 so it has 2064 not yet powered down. 2065 2066 Arguments: 2067 This - This instance of the state machine 2068 2069 Return Value: 2070 None. 2071 2072 --*/ 2073 { 2074 // 2075 // We should only get into this state when this devobj is not a PDO and a 2076 // power policy owner. 2077 // 2078 ASSERT((This->m_Device->IsPdo() && 2079 This->IsPowerPolicyOwner()) == FALSE); 2080 2081 // 2082 // Disarm 2083 // 2084 This->PowerDisableWakeAtBusOverload(); 2085 This->PowerCompletePendedWakeIrp(); 2086 2087 // 2088 // Go back to normal unarmed D0 with bus wake ownership 2089 // 2090 return WdfDevStatePowerD0BusWakeOwner; 2091 } 2092 2093 WDF_DEVICE_POWER_STATE 2094 FxPkgPnp::PowerD0DisarmingWakeAtBusNP( 2095 __inout FxPkgPnp* This 2096 ) 2097 /*++ 2098 2099 Routine Description: 2100 Disarms the bus after we have armed it. The device is still in D0 so it has 2101 not yet powered down. 2102 2103 Arguments: 2104 This - This instance of the state machine 2105 2106 Return Value: 2107 None. 2108 2109 --*/ 2110 { 2111 // 2112 // We should only get into this state when this devobj is not a PDO and a 2113 // power policy owner. 2114 // 2115 ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE); 2116 2117 // 2118 // Disarm 2119 // 2120 This->PowerDisableWakeAtBusOverload(); 2121 This->PowerCompletePendedWakeIrp(); 2122 2123 // 2124 // Go back to normal unarmed D0 with bus wake ownership 2125 // 2126 return WdfDevStatePowerD0BusWakeOwnerNP; 2127 } 2128 2129 WDF_DEVICE_POWER_STATE 2130 FxPkgPnp::PowerD0Starting( 2131 __inout FxPkgPnp* This 2132 ) 2133 /*++ 2134 2135 Routine Description: 2136 This function calls D0Entry and the moves to the next state based on the 2137 result. 2138 2139 Arguments: 2140 This - instance of the state machine 2141 2142 Return Value: 2143 new power state 2144 2145 --*/ 2146 { 2147 NTSTATUS status; 2148 2149 // 2150 // Call the driver to tell it to put the hardware into the working 2151 // state. 2152 // 2153 // m_DevicePowerState is the "old" state because we update it after the 2154 // D0Entry callback. 2155 // 2156 status = This->m_DeviceD0Entry.Invoke( 2157 This->m_Device->GetHandle(), 2158 (WDF_POWER_DEVICE_STATE) This->m_DevicePowerState); 2159 2160 if (!NT_SUCCESS(status)) { 2161 DoTraceLevelMessage( 2162 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 2163 "EvtDeviceD0Entry WDFDEVICE 0x%p !devobj 0x%p, old state " 2164 "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", 2165 This->m_Device->GetHandle(), 2166 This->m_Device->GetDeviceObject(), 2167 This->m_DevicePowerState, status); 2168 2169 return WdfDevStatePowerInitialPowerUpFailedDerefParent; 2170 } 2171 2172 return WdfDevStatePowerD0StartingConnectInterrupt; 2173 } 2174 2175 WDF_DEVICE_POWER_STATE 2176 FxPkgPnp::PowerD0StartingConnectInterrupt( 2177 __inout FxPkgPnp* This 2178 ) 2179 /*++ 2180 2181 Routine Description: 2182 Continues bringing the device into D0 from the D3 final state. This routine 2183 connects and enables the interrupts. If successful it will open up the power 2184 managed i/o queues. 2185 2186 Arguments: 2187 This - instance of the state machine 2188 2189 Return Value: 2190 new state machine state 2191 2192 --*/ 2193 { 2194 NTSTATUS status; 2195 2196 // 2197 // Connect the interrupt and enable it 2198 // 2199 status = This->NotifyResourceObjectsD0(NotifyResourcesNoFlags); 2200 if (!NT_SUCCESS(status)) { 2201 // 2202 // NotifyResourceObjectsD0 has already logged the error, no need to 2203 // repeat any error messsages here 2204 // 2205 return WdfDevStatePowerInitialConnectInterruptFailed; 2206 } 2207 2208 status = This->m_DeviceD0EntryPostInterruptsEnabled.Invoke( 2209 This->m_Device->GetHandle(), 2210 (WDF_POWER_DEVICE_STATE) This->m_DevicePowerState); 2211 2212 if (!NT_SUCCESS(status)) { 2213 2214 DoTraceLevelMessage( 2215 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 2216 "EvtDeviceD0EntryPostInterruptsEnabed WDFDEVICE 0x%p !devobj 0x%p, " 2217 "old state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", 2218 This->m_Device->GetHandle(), 2219 This->m_Device->GetDeviceObject(), 2220 This->m_DevicePowerState, status); 2221 return WdfDevStatePowerInitialConnectInterruptFailed; 2222 } 2223 2224 // 2225 // Last, figure out which state to drop into. This is the juncture 2226 // where we figure out if we're doing power in a pageable fashion. 2227 // 2228 return WdfDevStatePowerD0StartingDmaEnable; 2229 } 2230 2231 WDF_DEVICE_POWER_STATE 2232 FxPkgPnp::PowerD0StartingDmaEnable( 2233 __inout FxPkgPnp* This 2234 ) 2235 /*++ 2236 2237 Routine Description: 2238 The device is movig to D0 for the first time. Enable any DMA enablers 2239 attached to the device. 2240 2241 Arguments: 2242 This - instance of the state machine 2243 2244 Return Value: 2245 new machine state 2246 2247 --*/ 2248 { 2249 if (This->PowerDmaEnableAndScan(TRUE) == FALSE) { 2250 return WdfDevStatePowerInitialDmaEnableFailed; 2251 } 2252 2253 return WdfDevStatePowerD0StartingStartSelfManagedIo; 2254 } 2255 2256 WDF_DEVICE_POWER_STATE 2257 FxPkgPnp::PowerD0StartingStartSelfManagedIo( 2258 __inout FxPkgPnp* This 2259 ) 2260 /*++ 2261 2262 Routine Description: 2263 The device is entering D0 from the final Dx state (either start or restart 2264 perhaps). Send a start event to self managed io and then release 2265 2266 Arguments: 2267 This - instance of the state machine 2268 2269 Return Value: 2270 new state machine state 2271 2272 --*/ 2273 { 2274 2275 2276 2277 2278 This->m_Device->m_PkgIo->ResumeProcessingForPower(); 2279 2280 if (This->m_SelfManagedIoMachine != NULL) { 2281 NTSTATUS status; 2282 2283 status = This->m_SelfManagedIoMachine->Start(); 2284 2285 if (!NT_SUCCESS(status)) { 2286 // return WdfDevStatePowerInitialSelfManagedIoFailed; __REACTOS__ : allow to fail 2287 } 2288 } 2289 2290 This->PowerSetDevicePowerState(WdfPowerDeviceD0); 2291 2292 // 2293 // Send the PowerUp event to both the PnP and the Power Policy state machines. 2294 // 2295 This->PowerSendPowerUpEvents(); 2296 2297 return WdfDevStatePowerDecideD0State; 2298 } 2299 2300 WDF_DEVICE_POWER_STATE 2301 FxPkgPnp::PowerDecideD0State( 2302 __inout FxPkgPnp* This 2303 ) 2304 /*++ 2305 2306 Routine Description: 2307 Decide which D0 state we should transition to given the wait wake ownership 2308 of this device and if DO_POWER_PAGABLE is set or not. 2309 2310 Arguments: 2311 This - instance of the state machine 2312 2313 Return Value: 2314 new power state 2315 2316 --*/ 2317 { 2318 if (This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) { 2319 // 2320 // Pageable. 2321 // 2322 if (This->m_SharedPower.m_WaitWakeOwner) { 2323 return WdfDevStatePowerD0BusWakeOwner; 2324 } 2325 else { 2326 return WdfDevStatePowerD0; 2327 } 2328 } 2329 else { 2330 // 2331 // Non-pageable. 2332 // 2333 if (This->m_SharedPower.m_WaitWakeOwner) { 2334 return WdfDevStatePowerD0BusWakeOwnerNP; 2335 } 2336 else { 2337 return WdfDevStatePowerD0NP; 2338 } 2339 } 2340 } 2341 2342 WDF_DEVICE_POWER_STATE 2343 FxPkgPnp::PowerGotoD3Stopped( 2344 __inout FxPkgPnp* This 2345 ) 2346 /*++ 2347 2348 Routine Description: 2349 This function implements the D3 Stopped state. 2350 2351 Arguments: 2352 none 2353 2354 Return Value: 2355 2356 new power state 2357 2358 --*/ 2359 { 2360 NTSTATUS status; 2361 BOOLEAN failed; 2362 2363 failed = FALSE; 2364 2365 // 2366 // We *must* call suspend here even though the pnp state machine called self 2367 // managed io stop. Consider the following: 2368 // 1 this device is a filter 2369 // 2 the power policy owner has idle enabled and the device stack is 2370 // currently idled out (in Dx) 2371 // 3 the query remove comes, this driver processes it and succeeds 2372 // self managed io stop 2373 // 4 before the PwrPolStop event is processed in this driver, the pwr policy 2374 // owner moves the stack into D0. 2375 // 5 now this driver processed the PwrPolStop and moves into this state. We 2376 // now need to make sure self managed i/o is in the stopped state before 2377 // doing anything else. 2378 // 2379 2380 // 2381 // The self managed io state machine can handle a suspend event when it is 2382 // already in the stopped state. 2383 // 2384 // Tell the driver to stop its self-managed I/O. 2385 // 2386 if (This->m_SelfManagedIoMachine != NULL) { 2387 status = This->m_SelfManagedIoMachine->Suspend(); 2388 2389 if (!NT_SUCCESS(status)) { 2390 DoTraceLevelMessage( 2391 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 2392 "EvtDeviceSelfManagedIoStop failed %!STATUS!", status); 2393 failed = TRUE; 2394 } 2395 } 2396 2397 2398 2399 2400 2401 // Top-edge queue hold. 2402 This->m_Device->m_PkgIo->StopProcessingForPower(FxIoStopProcessingForPowerHold); 2403 2404 if (This->PowerDmaPowerDown() == FALSE) { 2405 failed = TRUE; 2406 } 2407 2408 status = This->m_DeviceD0ExitPreInterruptsDisabled.Invoke( 2409 This->m_Device->GetHandle(), 2410 WdfPowerDeviceD3Final 2411 ); 2412 2413 if (!NT_SUCCESS(status)) { 2414 failed = TRUE; 2415 2416 DoTraceLevelMessage( 2417 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 2418 "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p, " 2419 "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", 2420 This->m_Device->GetHandle(), 2421 This->m_Device->GetDeviceObject(), 2422 WdfPowerDeviceD3Final, status); 2423 } 2424 2425 // 2426 // Disconnect the interrupt. 2427 // 2428 status = This->NotifyResourceObjectsDx(NotifyResourcesForceDisconnect); 2429 if (!NT_SUCCESS(status)) { 2430 // 2431 // NotifyResourceObjectsDx already traced the error 2432 // 2433 failed = TRUE; 2434 } 2435 2436 // 2437 // Call the driver to tell it to put the hardware into a sleeping 2438 // state. 2439 // 2440 status = This->m_DeviceD0Exit.Invoke(This->m_Device->GetHandle(), 2441 WdfPowerDeviceD3Final); 2442 if (!NT_SUCCESS(status)) { 2443 failed = TRUE; 2444 2445 DoTraceLevelMessage( 2446 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 2447 "EvtDeviceD0Exit WDFDEVICE 0x%p !devobj 0x%p, new state " 2448 "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", 2449 This->m_Device->GetHandle(), 2450 This->m_Device->GetDeviceObject(), 2451 WdfPowerDeviceD3Final, status); 2452 } 2453 2454 This->PowerSetDevicePowerState(WdfPowerDeviceD3Final); 2455 2456 // 2457 // If this is a child, release the power reference on the parent 2458 // 2459 This->PowerParentPowerDereference(); 2460 2461 if (failed) { 2462 return WdfDevStatePowerFinalPowerDownFailed; 2463 } 2464 2465 This->PowerSendPowerDownEvents(FxPowerDownTypeImplicit); 2466 2467 // 2468 // If we are not the PPO for the stack we could receive a power irp 2469 // during the middle of an implicit power down so we cannot assume 2470 // that there will be no pended power irp during an implicit power down. 2471 // 2472 ASSERT(This->IsPowerPolicyOwner() ? This->m_PendingDevicePowerIrp == NULL : TRUE); 2473 2474 return WdfDevStatePowerStopped; 2475 } 2476 2477 WDF_DEVICE_POWER_STATE 2478 FxPkgPnp::PowerStartingCheckDeviceType( 2479 __inout FxPkgPnp* This 2480 ) 2481 /*++ 2482 2483 Routine Description: 2484 The device is implicitly powering up from the created or stopped state. 2485 Determine if this is a PDO or not to determine if we must bring the parent 2486 back into D0. 2487 2488 Arguments: 2489 This - instance of the state machine 2490 2491 Return Value: 2492 WdfDevStatePowerStartingChild or WdfDevStatePowerD0Starting 2493 2494 --*/ 2495 { 2496 if (This->m_Device->IsPdo()) { 2497 return WdfDevStatePowerStartingChild; 2498 } 2499 else { 2500 return WdfDevStatePowerD0Starting; 2501 } 2502 } 2503 2504 WDF_DEVICE_POWER_STATE 2505 FxPkgPnp::PowerStartingChild( 2506 __inout FxPkgPnp* This 2507 ) 2508 /*++ 2509 2510 Routine Description: 2511 Get the parent into a D0 state 2512 2513 Arguments: 2514 This - instance of the state machine 2515 2516 Return Value: 2517 WdfDevStatePowerNull or WdfDevStatePowerD0Starting 2518 2519 --*/ 2520 { 2521 NTSTATUS status; 2522 BOOLEAN parentOn; 2523 2524 status = This->PowerCheckParentOverload(&parentOn); 2525 2526 if (!NT_SUCCESS(status)) { 2527 DoTraceLevelMessage( 2528 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 2529 "PowerReference on parent WDFDEVICE %p for child WDFDEVICE %p " 2530 "failed, %!STATUS!", This->m_Device->m_ParentDevice->m_Device->GetHandle(), 2531 This->m_Device->GetHandle(), 2532 status); 2533 2534 return WdfDevStatePowerInitialPowerUpFailed; 2535 } 2536 else if (parentOn) { 2537 // 2538 // Parent is powered on, start the power up sequence 2539 // 2540 return WdfDevStatePowerD0Starting; 2541 } 2542 else { 2543 // 2544 // The call to PowerReference will bring the parent into D0 and 2545 // move us out of this state after we return. 2546 // 2547 return WdfDevStatePowerNull; 2548 } 2549 } 2550 2551 WDF_DEVICE_POWER_STATE 2552 FxPkgPnp::PowerDxDisablingWakeAtBus( 2553 __inout FxPkgPnp* This 2554 ) 2555 /*++ 2556 2557 Routine Description: 2558 This function implements the Disable Wake at Bus state. 2559 2560 Arguments: 2561 This - instance of the state machine 2562 2563 Return Value: 2564 WdfDevStatePowerWaking 2565 2566 --*/ 2567 { 2568 // 2569 // We should only get into this state when this devobj is not a PDO and a 2570 // power policy owner. 2571 // 2572 ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE); 2573 2574 This->PowerDisableWakeAtBusOverload(); 2575 2576 return WdfDevStatePowerWaking; 2577 } 2578 2579 WDF_DEVICE_POWER_STATE 2580 FxPkgPnp::PowerDxDisablingWakeAtBusNP( 2581 __inout FxPkgPnp* This 2582 ) 2583 /*++ 2584 2585 Routine Description: 2586 This function implements the Disable Wake at Bus state. 2587 2588 Arguments: 2589 This - instance of the state machine 2590 2591 Return Value: 2592 WdfDevStatePowerWakingNP 2593 2594 --*/ 2595 { 2596 // 2597 // We should only get into this state when this devobj is not a PDO and a 2598 // power policy owner. 2599 // 2600 ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE); 2601 2602 This->PowerDisableWakeAtBusOverload(); 2603 2604 return WdfDevStatePowerWakingNP; 2605 } 2606 2607 WDF_DEVICE_POWER_STATE 2608 FxPkgPnp::PowerGotoDNotZero( 2609 __inout FxPkgPnp* This 2610 ) 2611 /*++ 2612 2613 Routine Description: 2614 State where we go into Dx in the pageable path. 2615 2616 Arguments: 2617 The instance of this state machine 2618 2619 Return Value: 2620 new power state 2621 2622 --*/ 2623 { 2624 This->PowerGotoDx(); 2625 2626 return WdfDevStatePowerNull; 2627 } 2628 2629 WDF_DEVICE_POWER_STATE 2630 FxPkgPnp::PowerGotoDNotZeroNP( 2631 __inout FxPkgPnp* This 2632 ) 2633 /*++ 2634 2635 Routine Description: 2636 State where we go into Dx in the NP path. 2637 2638 Arguments: 2639 The instance of this state machine 2640 2641 Return Value: 2642 new power state 2643 2644 --*/ 2645 { 2646 This->PowerGotoDx(); 2647 2648 return WdfDevStatePowerNull; 2649 } 2650 2651 WDF_DEVICE_POWER_STATE 2652 FxPkgPnp::PowerGotoDNotZeroIoStopped( 2653 __inout FxPkgPnp* This 2654 ) 2655 { 2656 if (This->PowerGotoDxIoStopped() == FALSE) { 2657 return WdfDevStatePowerGotoDxFailed; 2658 } 2659 2660 return WdfDevStatePowerDx; 2661 } 2662 2663 WDF_DEVICE_POWER_STATE 2664 FxPkgPnp::PowerGotoDNotZeroIoStoppedNP( 2665 __inout FxPkgPnp* This 2666 ) 2667 { 2668 if (This->PowerGotoDxIoStoppedNP() == FALSE) { 2669 return WdfDevStatePowerGotoDxNPFailed; 2670 } 2671 2672 return WdfDevStatePowerDxNP; 2673 } 2674 2675 WDF_DEVICE_POWER_STATE 2676 FxPkgPnp::PowerGotoDxNPFailed( 2677 __inout FxPkgPnp* This 2678 ) 2679 /*++ 2680 2681 Routine Description: 2682 Going to Dx in the NP path failed. Disconnect all the interrupts. 2683 2684 Arguments: 2685 This - instance of the state machine 2686 2687 Return Value: 2688 WdfDevStatePowerReportPowerDownFailed 2689 2690 --*/ 2691 { 2692 This->DisconnectInterruptNP(); 2693 2694 return WdfDevStatePowerReportPowerDownFailed; 2695 } 2696 2697 VOID 2698 FxPkgPnp::PowerGotoDx( 2699 VOID 2700 ) 2701 /*++ 2702 2703 Routine Description: 2704 Implements the going into Dx logic for the pageable path. 2705 2706 Arguments: 2707 None 2708 2709 Return Value: 2710 None 2711 2712 --*/ 2713 { 2714 if (m_SelfManagedIoMachine != NULL) { 2715 NTSTATUS status; 2716 2717 // 2718 // Tell the driver to stop its self-managed I/O 2719 // 2720 status = m_SelfManagedIoMachine->Suspend(); 2721 2722 if (!NT_SUCCESS(status)) { 2723 DoTraceLevelMessage( 2724 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 2725 "EvtDeviceSelfManagedIoStop failed %!STATUS!", status); 2726 2727 m_PowerMachine.m_IoCallbackFailure = TRUE; 2728 } 2729 } 2730 2731 2732 2733 2734 2735 // Top-edge queue hold 2736 m_Device->m_PkgIo->StopProcessingForPower(FxIoStopProcessingForPowerHold); 2737 2738 PowerPolicyProcessEvent(PwrPolPowerDownIoStopped); 2739 } 2740 2741 BOOLEAN 2742 FxPkgPnp::PowerGotoDxIoStopped( 2743 VOID 2744 ) 2745 /*++ 2746 2747 Routine Description: 2748 Implements the going into Dx logic for the pageable path. 2749 2750 2751 2752 Arguments: 2753 None 2754 2755 Return Value: 2756 TRUE if the power down succeeded, FALSE otherwise 2757 2758 --*/ 2759 { 2760 WDF_POWER_DEVICE_STATE state; 2761 NTSTATUS status; 2762 BOOLEAN failed; 2763 FxIrp irp; 2764 ULONG notifyFlags; 2765 2766 failed = FALSE; 2767 2768 // 2769 // First determine the state that will be indicated to the driver 2770 // 2771 irp.SetIrp(m_PendingDevicePowerIrp); 2772 2773 switch (irp.GetParameterPowerShutdownType()) { 2774 case PowerActionShutdown: 2775 case PowerActionShutdownReset: 2776 case PowerActionShutdownOff: 2777 state = WdfPowerDeviceD3Final; 2778 break; 2779 2780 default: 2781 state = (WDF_POWER_DEVICE_STATE) irp.GetParameterPowerStateDeviceState(); 2782 break; 2783 } 2784 2785 // 2786 // Can we even be a power pageable device and be in hibernation path? 2787 // 2788 if (m_SystemPowerState == PowerSystemHibernate && 2789 GetUsageCount(WdfSpecialFileHibernation) != 0) { 2790 COVERAGE_TRAP(); 2791 2792 // 2793 // This device is in the hibernation path and the target system state is 2794 // S4. Tell the driver that it should do special handling. 2795 // 2796 state = WdfPowerDevicePrepareForHibernation; 2797 } 2798 2799 if (PowerDmaPowerDown() == FALSE) { 2800 failed = TRUE; 2801 } 2802 2803 status = m_DeviceD0ExitPreInterruptsDisabled.Invoke( 2804 m_Device->GetHandle(), 2805 state 2806 ); 2807 2808 if (!NT_SUCCESS(status)) { 2809 failed = TRUE; 2810 2811 DoTraceLevelMessage( 2812 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 2813 "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p, " 2814 "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", 2815 m_Device->GetHandle(), 2816 m_Device->GetDeviceObject(), state, status); 2817 } 2818 2819 // 2820 // interrupt disable & disconnect 2821 // 2822 2823 notifyFlags = NotifyResourcesExplicitPowerDown; 2824 2825 // 2826 // In general, m_WaitWakeIrp is accessed through guarded InterlockedExchange 2827 // operations. However, following is a special case where we just want to know 2828 // the current value. It is possible that the value of m_WaitWakeIrp can 2829 // change right after we query it. Users of NotifyResourcesArmedForWake will 2830 // need to be aware of this fact. 2831 // 2832 // Note that relying on m_WaitWakeIrp to decide whether to disconnect the wake 2833 // interrupts or not is unreliable and may result in a race condition between 2834 // the device powering down and a wake interrupt firing: 2835 // 2836 // Thread A: Device is powering down and is going to disconnect wake interrupts 2837 // unless m_WaitWakeIrp is not NULL. 2838 // Thread B: Wake interrupt fires (holding the OS interrupt lock) which results 2839 // in completing the IRP_MN_WAIT_WAKE and setting m_WaitWakeIrp to NULL. 2840 // Thread then blocks waiting for the device to power up. 2841 // Thread A: m_WaitWakeIrp is NULL so we disconnect the wake interrupt, but are 2842 // blocked waiting to acquire the lock held by the ISR. The deadlock 2843 // results in bugcheck 0x9F since the Dx IRP is being blocked. 2844 // 2845 // The m_WakeInterruptsKeepConnected flag is set when we request a IRP_MN_WAIT_WAKE 2846 // in the device powering down path, and is cleared below once it is used. 2847 // 2848 if (m_SharedPower.m_WaitWakeIrp != NULL || m_WakeInterruptsKeepConnected == TRUE) { 2849 notifyFlags |= NotifyResourcesArmedForWake; 2850 m_WakeInterruptsKeepConnected = FALSE; 2851 } 2852 2853 status = NotifyResourceObjectsDx(notifyFlags); 2854 if (!NT_SUCCESS(status)) { 2855 // 2856 // NotifyResourceObjectsDx already traced the error 2857 // 2858 failed = TRUE; 2859 } 2860 2861 // 2862 // Call the driver to tell it to put the hardware into a sleeping 2863 // state. 2864 // 2865 2866 status = m_DeviceD0Exit.Invoke(m_Device->GetHandle(), state); 2867 2868 if (!NT_SUCCESS(status)) { 2869 DoTraceLevelMessage( 2870 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 2871 "EvtDeviceD0Exit WDFEVICE 0x%p !devobj 0x%p, new state " 2872 "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", 2873 m_Device->GetHandle(), 2874 m_Device->GetDeviceObject(), state, status); 2875 2876 failed = TRUE; 2877 } 2878 2879 // 2880 // If this is a child, release the power reference on the parent 2881 // 2882 PowerParentPowerDereference(); 2883 2884 // 2885 // Set our state no matter if power down failed or not 2886 // 2887 PowerSetDevicePowerState(state); 2888 2889 // 2890 // Stopping self managed io previously failed, convert that failure into 2891 // a local failure here. 2892 // 2893 if (m_PowerMachine.m_IoCallbackFailure) { 2894 m_PowerMachine.m_IoCallbackFailure = FALSE; 2895 failed = TRUE; 2896 } 2897 2898 if (failed) { 2899 // 2900 // Power policy will use this property when it is processing the 2901 // completion of the Dx irp. 2902 // 2903 m_PowerMachine.m_PowerDownFailure = TRUE; 2904 2905 // 2906 // This state will record that we encountered an internal error. 2907 // 2908 return FALSE; 2909 } 2910 2911 PowerSendPowerDownEvents(FxPowerDownTypeExplicit); 2912 2913 PowerReleasePendingDeviceIrp(); 2914 2915 return TRUE; 2916 } 2917 2918 BOOLEAN 2919 FxPkgPnp::PowerGotoDxIoStoppedNP( 2920 VOID 2921 ) 2922 /*++ 2923 2924 Routine Description: 2925 This function implements going into the Dx state in the NP path. 2926 2927 Arguments: 2928 None 2929 2930 Return Value: 2931 TRUE if the power down succeeded, FALSE otherwise 2932 2933 --*/ 2934 { 2935 WDF_POWER_DEVICE_STATE state; 2936 NTSTATUS status; 2937 BOOLEAN failed; 2938 FxIrp irp; 2939 2940 failed = FALSE; 2941 2942 // 2943 // First determine the state that will be indicated to the driver 2944 // 2945 irp.SetIrp(m_PendingDevicePowerIrp); 2946 2947 switch (irp.GetParameterPowerShutdownType()) { 2948 case PowerActionShutdown: 2949 case PowerActionShutdownReset: 2950 case PowerActionShutdownOff: 2951 state = WdfPowerDeviceD3Final; 2952 break; 2953 2954 default: 2955 state = (WDF_POWER_DEVICE_STATE) irp.GetParameterPowerStateDeviceState(); 2956 break; 2957 } 2958 2959 if (m_SystemPowerState == PowerSystemHibernate && 2960 GetUsageCount(WdfSpecialFileHibernation) != 0) { 2961 // 2962 // This device is in the hibernation path and the target system state is 2963 // S4. Tell the driver that it should do special handling. 2964 // 2965 state = WdfPowerDevicePrepareForHibernation; 2966 } 2967 2968 if (PowerDmaPowerDown() == FALSE) { 2969 failed = TRUE; 2970 } 2971 2972 status = m_DeviceD0ExitPreInterruptsDisabled.Invoke( 2973 m_Device->GetHandle(), 2974 state 2975 ); 2976 2977 if (!NT_SUCCESS(status)) { 2978 failed = TRUE; 2979 2980 DoTraceLevelMessage( 2981 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 2982 "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p, " 2983 "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", 2984 m_Device->GetHandle(), 2985 m_Device->GetDeviceObject(), state, status); 2986 } 2987 2988 // 2989 // Interrupt disable (and NO disconnect) 2990 // 2991 status = NotifyResourceObjectsDx(NotifyResourcesNP); 2992 2993 if (!NT_SUCCESS(status)) { 2994 // 2995 // NotifyResourceObjectsDx already traced the error 2996 // 2997 failed = TRUE; 2998 } 2999 3000 // 3001 // Call the driver to tell it to put the hardware into a sleeping 3002 // state. 3003 // 3004 3005 status = m_DeviceD0Exit.Invoke(m_Device->GetHandle(), state); 3006 3007 if (!NT_SUCCESS(status)) { 3008 DoTraceLevelMessage( 3009 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3010 "EvtDeviceD0Exit WDFDEVICE 0x%p !devobj 0x%p, new state " 3011 "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", 3012 m_Device->GetHandle(), 3013 m_Device->GetDeviceObject(), state, status); 3014 3015 failed = TRUE; 3016 } 3017 3018 // 3019 // If this is a child, release the power reference on the parent 3020 // 3021 PowerParentPowerDereference(); 3022 3023 // 3024 // Set our state no matter if power down failed or not 3025 // 3026 PowerSetDevicePowerState(state); 3027 3028 // 3029 // Stopping self managed io previously failed, convert that failure into 3030 // a local failure here. 3031 // 3032 if (m_PowerMachine.m_IoCallbackFailure) { 3033 m_PowerMachine.m_IoCallbackFailure = FALSE; 3034 failed = TRUE; 3035 } 3036 3037 if (failed) { 3038 // 3039 // Power policy will use this property when it is processing the 3040 // completion of the Dx irp. 3041 // 3042 m_PowerMachine.m_PowerDownFailure = TRUE; 3043 3044 // 3045 // This state will record that we encountered an internal error. 3046 // 3047 return FALSE; 3048 } 3049 3050 PowerSendPowerDownEvents(FxPowerDownTypeExplicit); 3051 3052 PowerReleasePendingDeviceIrp(); 3053 3054 return TRUE; 3055 } 3056 3057 WDF_DEVICE_POWER_STATE 3058 FxPkgPnp::PowerGotoDxArmedForWake( 3059 __inout FxPkgPnp* This 3060 ) 3061 /*++ 3062 3063 Routine Description: 3064 This function implements the Dx state when we are armed for wake. 3065 3066 Arguments: 3067 This - The instance of the state machine 3068 3069 Return Value: 3070 3071 new power state 3072 3073 --*/ 3074 { 3075 This->PowerGotoDx(); 3076 3077 return WdfDevStatePowerNull; 3078 } 3079 3080 WDF_DEVICE_POWER_STATE 3081 FxPkgPnp::PowerGotoDxArmedForWakeNP( 3082 __inout FxPkgPnp* This 3083 ) 3084 /*++ 3085 3086 Routine Description: 3087 This function implements the Dx state when we are armed for wake in the NP 3088 path. 3089 3090 Arguments: 3091 This - The instance of the state machine 3092 3093 Return Value: 3094 3095 new power state 3096 3097 --*/ 3098 { 3099 This->PowerGotoDx(); 3100 3101 return WdfDevStatePowerNull; 3102 } 3103 3104 WDF_DEVICE_POWER_STATE 3105 FxPkgPnp::PowerGotoDxIoStoppedArmedForWake( 3106 __inout FxPkgPnp* This 3107 ) 3108 { 3109 if (This->PowerGotoDxIoStopped() == FALSE) { 3110 return WdfDevStatePowerGotoDxFailed; 3111 } 3112 3113 return WdfDevStatePowerDxArmedForWake; 3114 } 3115 3116 WDF_DEVICE_POWER_STATE 3117 FxPkgPnp::PowerGotoDxIoStoppedArmedForWakeNP( 3118 __inout FxPkgPnp* This 3119 ) 3120 { 3121 if (This->PowerGotoDxIoStoppedNP() == FALSE) { 3122 return WdfDevStatePowerGotoDxNPFailed; 3123 } 3124 3125 return WdfDevStatePowerDxArmedForWakeNP; 3126 } 3127 3128 WDF_DEVICE_POWER_STATE 3129 FxPkgPnp::PowerCheckParentStateArmedForWake( 3130 __inout FxPkgPnp* This 3131 ) 3132 /*++ 3133 3134 Routine Description: 3135 The PDO was armed for wake in Dx and needs to be disarmed at the bus level. 3136 The child can only be disarmed while the parent is in D0, so check the state 3137 of the parent. If in D0, move directly to the disarm state, otherwise move 3138 into a wait state and disarm once the parent is in D0. 3139 3140 Arguments: 3141 This - instance of the state machine 3142 3143 Return Value: 3144 new state 3145 3146 --*/ 3147 3148 { 3149 NTSTATUS status; 3150 BOOLEAN parentOn; 3151 3152 status = This->PowerCheckParentOverload(&parentOn); 3153 3154 if (!NT_SUCCESS(status)) { 3155 return WdfDevStatePowerUpFailed; 3156 } 3157 else if (parentOn) { 3158 return WdfDevStatePowerDxDisablingWakeAtBus; 3159 } 3160 else { 3161 return WdfDevStatePowerWaitForParentArmedForWake; 3162 } 3163 } 3164 3165 WDF_DEVICE_POWER_STATE 3166 FxPkgPnp::PowerCheckParentStateArmedForWakeNP( 3167 __inout FxPkgPnp* This 3168 ) 3169 /*++ 3170 3171 Routine Description: 3172 Same as PowerCheckParentStateArmedForWake, but we are in the NP path 3173 3174 Arguments: 3175 This - instance of the state machine 3176 3177 Return Value: 3178 new state 3179 3180 --*/ 3181 { 3182 NTSTATUS status; 3183 BOOLEAN parentOn; 3184 3185 status = This->PowerCheckParentOverload(&parentOn); 3186 3187 if (!NT_SUCCESS(status)) { 3188 return WdfDevStatePowerUpFailedNP; 3189 } 3190 else if (parentOn) { 3191 return WdfDevStatePowerDxDisablingWakeAtBusNP; 3192 } 3193 else { 3194 return WdfDevStatePowerWaitForParentArmedForWakeNP; 3195 } 3196 } 3197 3198 WDF_DEVICE_POWER_STATE 3199 FxPkgPnp::PowerStartSelfManagedIo( 3200 __inout FxPkgPnp* This 3201 ) 3202 /*++ 3203 3204 Routine Description: 3205 This function implements the Start Self-Managed I/O state. It tells the 3206 driver that it can resume operations that were not interlocked with 3207 the PnP and Power state machines. 3208 3209 Arguments: 3210 This - The instance of the state machine 3211 3212 Return Value: 3213 3214 new power state 3215 3216 --*/ 3217 { 3218 3219 3220 3221 3222 3223 // Top-edge queue release 3224 This->m_Device->m_PkgIo->ResumeProcessingForPower(); 3225 3226 if (This->m_SelfManagedIoMachine != NULL) { 3227 NTSTATUS status; 3228 3229 status = This->m_SelfManagedIoMachine->Start(); 3230 3231 if (!NT_SUCCESS(status)) { 3232 DoTraceLevelMessage( 3233 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3234 "EvtDeviceSelfManagedIoRestart failed - %!STATUS!", status); 3235 3236 return WdfDevStatePowerStartSelfManagedIoFailed; 3237 } 3238 } 3239 3240 This->PowerSetDevicePowerState(WdfPowerDeviceD0); 3241 3242 // 3243 // Send the PowerUp event to both the PnP and the Power Policy state 3244 // machines. 3245 // 3246 This->PowerSendPowerUpEvents(); 3247 3248 This->PowerReleasePendingDeviceIrp(); 3249 3250 if (This->m_SharedPower.m_WaitWakeOwner) { 3251 return WdfDevStatePowerD0BusWakeOwner; 3252 } 3253 else { 3254 return WdfDevStatePowerD0; 3255 } 3256 } 3257 3258 WDF_DEVICE_POWER_STATE 3259 FxPkgPnp::PowerStartSelfManagedIoNP( 3260 __inout FxPkgPnp* This 3261 ) 3262 /*++ 3263 3264 Routine Description: 3265 This function implements the Start Self-Managed I/O state. It tells the 3266 driver that it can resume operations that were not interlocked with 3267 the PnP and Power state machines. 3268 3269 Arguments: 3270 This - The instance of the state machine 3271 3272 Return Value: 3273 3274 new power state 3275 3276 --*/ 3277 { 3278 3279 3280 3281 3282 3283 // Top-edge queue release 3284 This->m_Device->m_PkgIo->ResumeProcessingForPower(); 3285 3286 if (This->m_SelfManagedIoMachine != NULL) { 3287 NTSTATUS status; 3288 3289 status = This->m_SelfManagedIoMachine->Start(); 3290 3291 if (!NT_SUCCESS(status)) { 3292 DoTraceLevelMessage( 3293 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3294 "EvtDeviceSelfManagedIoRestart failed - %!STATUS!", status); 3295 3296 return WdfDevStatePowerStartSelfManagedIoFailedNP; 3297 } 3298 } 3299 3300 This->PowerSetDevicePowerState(WdfPowerDeviceD0); 3301 3302 // 3303 // Send the PowerUp event to both the PnP and the Power Policy state machines. 3304 // 3305 This->PowerSendPowerUpEvents(); 3306 3307 This->PowerReleasePendingDeviceIrp(); 3308 3309 if (This->m_SharedPower.m_WaitWakeOwner) { 3310 return WdfDevStatePowerD0BusWakeOwnerNP; 3311 } 3312 else { 3313 return WdfDevStatePowerD0NP; 3314 } 3315 } 3316 3317 WDF_DEVICE_POWER_STATE 3318 FxPkgPnp::PowerStartSelfManagedIoFailed( 3319 __inout FxPkgPnp* This 3320 ) 3321 /*++ 3322 3323 Routine Description: 3324 Starting self managed io back up from an explicit Dx to D0 transition failed. 3325 Hold the power managed queues and proceed down the power up failure path. 3326 3327 Arguments: 3328 This - instance of the state machine 3329 3330 Return Value: 3331 WdfDevStatePowerWakingDmaEnableFailed 3332 3333 --*/ 3334 { 3335 3336 3337 3338 3339 This->m_Device->m_PkgIo->StopProcessingForPower(FxIoStopProcessingForPowerHold); 3340 3341 return WdfDevStatePowerWakingDmaEnableFailed; 3342 } 3343 3344 WDF_DEVICE_POWER_STATE 3345 FxPkgPnp::PowerStartSelfManagedIoFailedNP( 3346 __inout FxPkgPnp* This 3347 ) 3348 /*++ 3349 3350 Routine Description: 3351 Starting self managed io back up from an explicit Dx to D0 transition failed. 3352 Hold the power managed queues and proceed down the power up failure path. 3353 3354 Arguments: 3355 This - instance of the state machine 3356 3357 Return Value: 3358 WdfDevStatePowerWakingDmaEnableFailedNP 3359 3360 --*/ 3361 { 3362 3363 3364 3365 3366 This->m_Device->m_PkgIo->StopProcessingForPower(FxIoStopProcessingForPowerHold); 3367 3368 return WdfDevStatePowerWakingDmaEnableFailedNP; 3369 } 3370 3371 3372 WDF_DEVICE_POWER_STATE 3373 FxPkgPnp::PowerWakePending( 3374 __inout FxPkgPnp* This 3375 ) 3376 /*++ 3377 3378 Routine Description: 3379 State that indicates a successful wake from Dx. Primarily exists so that 3380 the driver writer can register to know about the entrance into this state. 3381 It also completes the pended wait wake request (which posts the appopriate 3382 events to the power policy state machine if it's listening). 3383 3384 Arguments: 3385 This - The instance of the state machine 3386 3387 Return Value: 3388 return WdfDevStatePowerNull 3389 3390 --*/ 3391 { 3392 This->PowerCompletePendedWakeIrp(); 3393 return WdfDevStatePowerNull; 3394 } 3395 3396 WDF_DEVICE_POWER_STATE 3397 FxPkgPnp::PowerWakePendingNP( 3398 __inout FxPkgPnp* This 3399 ) 3400 /*++ 3401 3402 Routine Description: 3403 State that indicates a successful wake from Dx. Primarily exists so that 3404 the driver writer can register to know about the entrance into this state. 3405 It also completes the pended wait wake request (which posts the appopriate 3406 events to the power policy state machine if it's listening). 3407 3408 Arguments: 3409 This - The instance of the state machine 3410 3411 Return Value: 3412 return WdfDevStatePowerNull 3413 3414 --*/ 3415 { 3416 This->PowerCompletePendedWakeIrp(); 3417 return WdfDevStatePowerNull; 3418 } 3419 3420 WDF_DEVICE_POWER_STATE 3421 FxPkgPnp::PowerWaking( 3422 __inout FxPkgPnp* This 3423 ) 3424 /*++ 3425 3426 Routine Description: 3427 This function implements the Waking state. Its job is to call into the 3428 driver to tell it to restore its hardware, and then to connect interrupts 3429 and release the queues. 3430 3431 Arguments: 3432 This - The instance of the state machine 3433 3434 Return Value: 3435 3436 new power state 3437 3438 --*/ 3439 { 3440 NTSTATUS status; 3441 3442 // 3443 // m_DevicePowerState is the "old" state because we update it after the 3444 // D0Entry callback in SelfManagedIo or PowerPolicyStopped 3445 // 3446 status = This->m_DeviceD0Entry.Invoke( 3447 This->m_Device->GetHandle(), 3448 (WDF_POWER_DEVICE_STATE) This->m_DevicePowerState); 3449 3450 if (!NT_SUCCESS(status)) { 3451 DoTraceLevelMessage( 3452 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3453 "EvtDeviceD0Entry WDFDEVICE 0x%p !devobj 0x%p, old state " 3454 "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", 3455 This->m_Device->GetHandle(), 3456 This->m_Device->GetDeviceObject(), 3457 This->m_DevicePowerState, status); 3458 3459 return WdfDevStatePowerUpFailedDerefParent; 3460 } 3461 3462 return WdfDevStatePowerNotifyingD0EntryToWakeInterrupts; 3463 } 3464 3465 3466 WDF_DEVICE_POWER_STATE 3467 FxPkgPnp::PowerWakingNP( 3468 __inout FxPkgPnp* This 3469 ) 3470 /*++ 3471 3472 Routine Description: 3473 This function implements the WakingNP state. Its job is to call into the 3474 driver to tell it to restore its hardware and release the queues. 3475 3476 Arguments: 3477 This - The instance of the state machine 3478 3479 Return Value: 3480 3481 new power state 3482 3483 --*/ 3484 { 3485 NTSTATUS status; 3486 3487 // 3488 // m_DevicePowerState is the "old" state because we update it after the 3489 // D0Entry callback in SelfManagedIoNP or PowerPolicyStopped 3490 // 3491 status = This->m_DeviceD0Entry.Invoke( 3492 This->m_Device->GetHandle(), 3493 (WDF_POWER_DEVICE_STATE) This->m_DevicePowerState); 3494 3495 if (!NT_SUCCESS(status)) { 3496 DoTraceLevelMessage( 3497 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3498 "EvtDeviceD0Entry WDFDEVICE 0x%p !devobj 0x%p, old state " 3499 "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", 3500 This->m_Device->GetHandle(), 3501 This->m_Device->GetDeviceObject(), 3502 This->m_DevicePowerState, status); 3503 3504 return WdfDevStatePowerUpFailedDerefParentNP; 3505 } 3506 3507 return WdfDevStatePowerNotifyingD0EntryToWakeInterruptsNP; 3508 } 3509 3510 WDF_DEVICE_POWER_STATE 3511 FxPkgPnp::PowerWakingConnectInterrupt( 3512 __inout FxPkgPnp* This 3513 ) 3514 /*++ 3515 3516 Routine Description: 3517 The device is returning to D0 in the power pageable path. Connect and 3518 enable the interrupts. If that succeeds, scan for children and then 3519 open the power managed I/O queues. 3520 3521 Arguments: 3522 This - instance of the state machine 3523 3524 Return Value: 3525 new state 3526 3527 --*/ 3528 { 3529 NTSTATUS status; 3530 3531 // 3532 // interrupt connect and enable 3533 // 3534 status = This->NotifyResourceObjectsD0(NotifyResourcesExplicitPowerup); 3535 3536 if (!NT_SUCCESS(status)) { 3537 return WdfDevStatePowerWakingConnectInterruptFailed; 3538 } 3539 3540 status = This->m_DeviceD0EntryPostInterruptsEnabled.Invoke( 3541 This->m_Device->GetHandle(), 3542 (WDF_POWER_DEVICE_STATE) This->m_DevicePowerState); 3543 3544 if (!NT_SUCCESS(status)) { 3545 DoTraceLevelMessage( 3546 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3547 "EvtDeviceD0EntryPostInterruptsEnabed WDFDEVICE 0x%p !devobj 0x%p, " 3548 "old state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", 3549 This->m_Device->GetHandle(), 3550 This->m_Device->GetDeviceObject(), 3551 This->m_DevicePowerState, status); 3552 return WdfDevStatePowerWakingConnectInterruptFailed; 3553 } 3554 3555 return WdfDevStatePowerWakingDmaEnable; 3556 } 3557 3558 WDF_DEVICE_POWER_STATE 3559 FxPkgPnp::PowerWakingConnectInterruptNP( 3560 __inout FxPkgPnp* This 3561 ) 3562 /*++ 3563 3564 Routine Description: 3565 The device is returning to D0 in the power pageable path. 3566 Enable the interrupts. If that succeeds, scan for children and then 3567 open the power managed I/O queues. 3568 3569 Arguments: 3570 This - instance of the state machine 3571 3572 Return Value: 3573 new state 3574 3575 --*/ 3576 { 3577 NTSTATUS status; 3578 3579 // 3580 // interrupt enable (already connected b/c they were never disconnected 3581 // during the Dx transition). 3582 // 3583 status = This->NotifyResourceObjectsD0(NotifyResourcesNP); 3584 3585 if (!NT_SUCCESS(status)) { 3586 return WdfDevStatePowerWakingConnectInterruptFailedNP; 3587 } 3588 3589 status = This->m_DeviceD0EntryPostInterruptsEnabled.Invoke( 3590 This->m_Device->GetHandle(), 3591 (WDF_POWER_DEVICE_STATE) This->m_DevicePowerState); 3592 3593 if (!NT_SUCCESS(status)) { 3594 DoTraceLevelMessage( 3595 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3596 "EvtDeviceD0EntryPostInterruptsEnabed WDFDEVICE 0x%p !devobj 0x%p, " 3597 "old state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", 3598 This->m_Device->GetHandle(), 3599 This->m_Device->GetDeviceObject(), 3600 This->m_DevicePowerState, status); 3601 return WdfDevStatePowerWakingConnectInterruptFailedNP; 3602 } 3603 3604 return WdfDevStatePowerWakingDmaEnableNP; 3605 } 3606 3607 WDF_DEVICE_POWER_STATE 3608 FxPkgPnp::PowerWakingConnectInterruptFailed( 3609 __inout FxPkgPnp* This 3610 ) 3611 /*++ 3612 3613 Routine Description: 3614 Connecting or enabling the interrupts failed. Disable and disconnect any 3615 interrupts which have been connected and maybe enabled. 3616 3617 Arguments: 3618 This - instance of the state machine 3619 3620 Return Value: 3621 WdfDevStatePowerReportPowerUpFailed 3622 3623 --*/ 3624 { 3625 This->PowerConnectInterruptFailed(); 3626 3627 return WdfDevStatePowerReportPowerUpFailedDerefParent; 3628 } 3629 3630 WDF_DEVICE_POWER_STATE 3631 FxPkgPnp::PowerWakingConnectInterruptFailedNP( 3632 __inout FxPkgPnp* This 3633 ) 3634 /*++ 3635 3636 Routine Description: 3637 Enabling the interrupts failed. Disable and disconnect any 3638 interrupts which have been connected and maybe enabled. 3639 3640 Arguments: 3641 This - instance of the state machine 3642 3643 Return Value: 3644 WdfDevStatePowerReportPowerUpFailed 3645 3646 --*/ 3647 { 3648 // 3649 // PowerConnectInterruptFailed will call IoDisconnectInterrupt. Since we 3650 // are in the NP path, this may cause a deadlock between this thread and 3651 // paging I/O. Log something to the IFR so that if the watchdog timer kicks 3652 // in, at least we have context as to why we died. 3653 // 3654 DoTraceLevelMessage( 3655 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3656 "Force disconnecting interupts on !devobj %p, WDFDEVICE %p", 3657 This->m_Device->GetDeviceObject(), 3658 This->m_Device->GetHandle()); 3659 3660 This->PowerConnectInterruptFailed(); 3661 3662 return WdfDevStatePowerReportPowerUpFailedDerefParent; 3663 } 3664 3665 BOOLEAN 3666 FxPkgPnp::PowerDmaEnableAndScan( 3667 __in BOOLEAN ImplicitPowerUp 3668 ) 3669 { 3670 FxTransactionedEntry* ple; 3671 3672 if (PowerDmaPowerUp() == FALSE) { 3673 return FALSE; 3674 } 3675 3676 if (m_EnumInfo != NULL) { 3677 // 3678 // Scan for children 3679 // 3680 m_EnumInfo->m_ChildListList.LockForEnum(GetDriverGlobals()); 3681 3682 ple = NULL; 3683 while ((ple = m_EnumInfo->m_ChildListList.GetNextEntry(ple)) != NULL) { 3684 ((FxChildList*) ple->GetTransactionedObject())->ScanForChildren(); 3685 } 3686 3687 m_EnumInfo->m_ChildListList.UnlockFromEnum(GetDriverGlobals()); 3688 } 3689 3690 if (ImplicitPowerUp == FALSE) { 3691 PowerPolicyProcessEvent(PwrPolPowerUpHwStarted); 3692 } 3693 3694 return TRUE; 3695 } 3696 3697 WDF_DEVICE_POWER_STATE 3698 FxPkgPnp::PowerWakingDmaEnable( 3699 __inout FxPkgPnp* This 3700 ) 3701 /*++ 3702 3703 Routine Description: 3704 The device is returning to D0 from Dx. Power up all DMA enablers and scan 3705 for children. 3706 3707 Arguments: 3708 This - instance of the state machine 3709 3710 Return Value: 3711 new machine state 3712 3713 --*/ 3714 { 3715 if (This->PowerDmaEnableAndScan(FALSE) == FALSE) { 3716 return WdfDevStatePowerWakingDmaEnableFailed; 3717 } 3718 3719 // 3720 // Return the state that we should drop into next. 3721 // 3722 return WdfDevStatePowerNull; 3723 } 3724 3725 WDF_DEVICE_POWER_STATE 3726 FxPkgPnp::PowerWakingDmaEnableNP( 3727 __inout FxPkgPnp* This 3728 ) 3729 /*++ 3730 3731 Routine Description: 3732 The device is returning to D0 from Dx in the NP path. Power up all DMA 3733 enablers and scan for children. 3734 3735 Arguments: 3736 This - instance of the state machine 3737 3738 Return Value: 3739 new machine state 3740 3741 --*/ 3742 { 3743 if (This->PowerDmaEnableAndScan(FALSE) == FALSE) { 3744 return WdfDevStatePowerWakingDmaEnableFailedNP; 3745 } 3746 3747 // 3748 // Return the state that we should drop into next. 3749 // 3750 return WdfDevStatePowerNull; 3751 } 3752 3753 WDF_DEVICE_POWER_STATE 3754 FxPkgPnp::PowerWakingDmaEnableFailed( 3755 __inout FxPkgPnp* This 3756 ) 3757 /*++ 3758 3759 Routine Description: 3760 Powering up a DMA enabler failed. Power down all DMA enablers and progress 3761 down the failed power up path. 3762 3763 Arguments: 3764 This - instance of the state machine 3765 3766 Return Value: 3767 WdfDevStatePowerWakingConnectInterruptFailed 3768 3769 --*/ 3770 { 3771 NTSTATUS status; 3772 3773 (void) This->PowerDmaPowerDown(); 3774 3775 status = This->m_DeviceD0ExitPreInterruptsDisabled.Invoke( 3776 This->m_Device->GetHandle(), 3777 WdfPowerDeviceD3Final 3778 ); 3779 3780 if (!NT_SUCCESS(status)) { 3781 // 3782 // Report the error, but continue forward 3783 // 3784 DoTraceLevelMessage( 3785 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3786 "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p " 3787 "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", 3788 This->m_Device->GetHandle(), 3789 This->m_Device->GetDeviceObject(), 3790 WdfPowerDeviceD3Final, status); 3791 } 3792 3793 return WdfDevStatePowerWakingConnectInterruptFailed; 3794 } 3795 3796 WDF_DEVICE_POWER_STATE 3797 FxPkgPnp::PowerWakingDmaEnableFailedNP( 3798 __inout FxPkgPnp* This 3799 ) 3800 /*++ 3801 3802 Routine Description: 3803 Powering up a DMA enabler failed in the NP path. Power down all DMA 3804 enablers and progress down the failed power up path. 3805 3806 Arguments: 3807 This - instance of the state machine 3808 3809 Return Value: 3810 WdfDevStatePowerWakingConnectInterruptFailedNP 3811 3812 --*/ 3813 { 3814 NTSTATUS status; 3815 3816 COVERAGE_TRAP(); 3817 3818 (void) This->PowerDmaPowerDown(); 3819 3820 status = This->m_DeviceD0ExitPreInterruptsDisabled.Invoke( 3821 This->m_Device->GetHandle(), 3822 WdfPowerDeviceD3Final 3823 ); 3824 3825 if (!NT_SUCCESS(status)) { 3826 // 3827 // Report the error, but continue forward 3828 // 3829 DoTraceLevelMessage( 3830 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3831 "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p " 3832 "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", 3833 This->m_Device->GetHandle(), 3834 This->m_Device->GetDeviceObject(), 3835 WdfPowerDeviceD3Final, status); 3836 } 3837 3838 return WdfDevStatePowerWakingConnectInterruptFailedNP; 3839 } 3840 3841 WDF_DEVICE_POWER_STATE 3842 FxPkgPnp::PowerReportPowerUpFailedDerefParent( 3843 __inout FxPkgPnp* This 3844 ) 3845 /*++ 3846 3847 Routine Description: 3848 Power up failed. Release the reference on the parent that was taken at the 3849 start of power up. 3850 3851 Arguments: 3852 This - instance of the state machine. 3853 3854 Return Value: 3855 WdfDevStatePowerInitialPowerUpFailed 3856 3857 --*/ 3858 { 3859 // 3860 // If this is a child, release the power reference on the parent 3861 // 3862 This->PowerParentPowerDereference(); 3863 3864 return WdfDevStatePowerReportPowerUpFailed; 3865 } 3866 3867 WDF_DEVICE_POWER_STATE 3868 FxPkgPnp::PowerReportPowerUpFailed( 3869 __inout FxPkgPnp* This 3870 ) 3871 /*++ 3872 3873 Routine Description: 3874 Posts PowerUpFailed event to the PnP state machine and then waits for death. 3875 The pended Power IRP is also completed. 3876 3877 Arguments: 3878 This - The instance of the state machine 3879 3880 Return Value: 3881 new power state 3882 3883 --*/ 3884 { 3885 This->m_SystemPowerAction = PowerActionNone; 3886 3887 This->PowerReleasePendingDeviceIrp(); 3888 This->PowerSendPowerUpFailureEvent(); 3889 3890 return WdfDevStatePowerNull; 3891 } 3892 3893 WDF_DEVICE_POWER_STATE 3894 FxPkgPnp::PowerPowerFailedPowerDown( 3895 __inout FxPkgPnp* This 3896 ) 3897 /*++ 3898 3899 Routine Description: 3900 We failed to power up/down properly and now the power policy state machine wants 3901 to power down the device. Since power policy and pnp rely on power posting 3902 power down events to make forward progress, we must do that here 3903 3904 Arguments: 3905 This - instance of the state machine 3906 3907 Return Value: 3908 WdfDevStatePowerStopped 3909 3910 --*/ 3911 { 3912 // 3913 // Even though we failed power up and never really powered down, record our 3914 // state as powered down, so that if we are restarted (can easily happen for 3915 // a PDO), we have the correct previous state. 3916 // 3917 This->PowerSetDevicePowerState(WdfPowerDeviceD3Final); 3918 3919 This->PowerSendPowerDownEvents(FxPowerDownTypeImplicit); 3920 3921 return WdfDevStatePowerStopped; 3922 } 3923 3924 WDF_DEVICE_POWER_STATE 3925 FxPkgPnp::PowerReportPowerDownFailed( 3926 __inout FxPkgPnp* This 3927 ) 3928 /*++ 3929 3930 Routine Description: 3931 Posts PowerDownFailed event to the PnP state machine and then waits for death. 3932 The pended Power IRP is also completed. 3933 3934 Arguments: 3935 This - The instance of the state machine 3936 3937 Return Value: 3938 WdfDevStatePowerNull 3939 3940 --*/ 3941 { 3942 3943 3944 3945 3946 This->PowerReleasePendingDeviceIrp(); 3947 This->PowerSendPowerDownFailureEvent(FxPowerDownTypeExplicit); 3948 3949 return WdfDevStatePowerNull; 3950 } 3951 3952 WDF_DEVICE_POWER_STATE 3953 FxPkgPnp::PowerInitialConnectInterruptFailed( 3954 __inout FxPkgPnp* This 3955 ) 3956 /*++ 3957 3958 Routine Description: 3959 When bringing the device out of the D3 final state, connecting or enabling 3960 the interrupts failed. Disconnect and disable any interrupts which are 3961 connected and possibly enabled. 3962 3963 Arguments: 3964 This - instance of the state machine 3965 3966 Return Value: 3967 WdfDevStatePowerInitialPowerUpFailedDerefParent 3968 3969 --*/ 3970 { 3971 This->PowerConnectInterruptFailed(); 3972 3973 return WdfDevStatePowerInitialPowerUpFailedDerefParent; 3974 } 3975 3976 3977 WDF_DEVICE_POWER_STATE 3978 FxPkgPnp::PowerInitialDmaEnableFailed( 3979 __inout FxPkgPnp* This 3980 ) 3981 /*++ 3982 3983 Routine Description: 3984 Initial power up of the device failed while enabling DMA. Disable any 3985 started DMA enablers and proceed down the initial power up failure path. 3986 3987 Arguments: 3988 This - instance of the state machine 3989 3990 Return Value: 3991 WdfDevStatePowerInitialConnectInterruptFailed 3992 3993 --*/ 3994 { 3995 NTSTATUS status; 3996 3997 (void) This->PowerDmaPowerDown(); 3998 3999 status = This->m_DeviceD0ExitPreInterruptsDisabled.Invoke( 4000 This->m_Device->GetHandle(), 4001 WdfPowerDeviceD3Final 4002 ); 4003 4004 if (!NT_SUCCESS(status)) { 4005 // 4006 // Report the error, but continue forward 4007 // 4008 DoTraceLevelMessage( 4009 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 4010 "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p " 4011 "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", 4012 This->m_Device->GetHandle(), 4013 This->m_Device->GetDeviceObject(), 4014 WdfPowerDeviceD3Final, status); 4015 } 4016 4017 return WdfDevStatePowerInitialConnectInterruptFailed; 4018 } 4019 4020 WDF_DEVICE_POWER_STATE 4021 FxPkgPnp::PowerInitialSelfManagedIoFailed( 4022 __inout FxPkgPnp* This 4023 ) 4024 /*++ 4025 4026 Routine Description: 4027 The self managed io start failed when bringing the device out of Dx with an 4028 implicit D0 transition. Hold the power queues that were previous open can 4029 continue to cleanup 4030 4031 Arguments: 4032 This - instance of the state machine 4033 4034 Return Value: 4035 WdfDevStatePowerInitialDmaEnableFailed 4036 4037 --*/ 4038 { 4039 4040 4041 4042 4043 This->m_Device->m_PkgIo->StopProcessingForPower(FxIoStopProcessingForPowerHold); 4044 4045 return WdfDevStatePowerInitialDmaEnableFailed; 4046 } 4047 4048 WDF_DEVICE_POWER_STATE 4049 FxPkgPnp::PowerInitialPowerUpFailedDerefParent( 4050 __inout FxPkgPnp* This 4051 ) 4052 /*++ 4053 4054 Routine Description: 4055 Dereferences the parent's power ref count we took during start up 4056 4057 Arguments: 4058 This - The instance of the state machine 4059 4060 Return Value: 4061 WdfDevStatePowerInitialPowerUpFailed 4062 4063 --*/ 4064 { 4065 4066 // 4067 // If this is a child, release the power reference on the parent 4068 // 4069 This->PowerParentPowerDereference(); 4070 4071 return WdfDevStatePowerInitialPowerUpFailed; 4072 } 4073 4074 WDF_DEVICE_POWER_STATE 4075 FxPkgPnp::PowerInitialPowerUpFailed( 4076 __inout FxPkgPnp* This 4077 ) 4078 /*++ 4079 4080 Routine Description: 4081 Posts PowerUpFailed event to the PnP state machine and then waits for death. 4082 4083 Arguments: 4084 This - The instance of the state machine 4085 4086 Return Value: 4087 WdfDevStatePowerStopped 4088 4089 --*/ 4090 { 4091 This->PowerSendPowerUpFailureEvent(); 4092 4093 return WdfDevStatePowerStopped; 4094 } 4095 4096 WDF_DEVICE_POWER_STATE 4097 FxPkgPnp::PowerDxStoppedDisarmWake( 4098 __inout FxPkgPnp* This 4099 ) 4100 /*++ 4101 4102 Routine Description: 4103 Disarms the device from wake because the device is being stopped/removed 4104 while in Dx. 4105 4106 Arguments: 4107 This - instance of the state machine 4108 4109 Return Value: 4110 WdfDevStatePowerDxStopped 4111 4112 --*/ 4113 { 4114 // 4115 // We should only get into this state when this devobj is not a PDO and a 4116 // power policy owner. 4117 // 4118 ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE); 4119 4120 This->PowerDisableWakeAtBusOverload(); 4121 4122 return WdfDevStatePowerGotoDxStoppedDisableInterrupt; 4123 } 4124 4125 WDF_DEVICE_POWER_STATE 4126 FxPkgPnp::PowerDxStoppedDisarmWakeNP( 4127 __inout FxPkgPnp* This 4128 ) 4129 /*++ 4130 4131 Routine Description: 4132 Disarms the device from wake because the device is being stopped/removed 4133 while in Dx. 4134 4135 Arguments: 4136 This - instance of the state machine 4137 4138 Return Value: 4139 WdfDevStatePowerGotoDxStoppedDisableInterruptNP 4140 4141 --*/ 4142 { 4143 // 4144 // We should only get into this state when this devobj is not a PDO and a 4145 // power policy owner. 4146 // 4147 ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE); 4148 4149 This->PowerDisableWakeAtBusOverload(); 4150 4151 return WdfDevStatePowerGotoDxStoppedDisableInterruptNP; 4152 } 4153 4154 WDF_DEVICE_POWER_STATE 4155 FxPkgPnp::PowerGotoDxStoppedDisableInterruptNP( 4156 __inout FxPkgPnp* This 4157 ) 4158 /*++ 4159 4160 Routine Description: 4161 Device is in Dx and was implicitly powered down. Disable the interrupt since 4162 the interrupt was not disconnected in the NP power down path. 4163 4164 Arguments: 4165 This - instance of the state machine 4166 4167 Return Value: 4168 WdfDevStatePowerGotoDxStopped 4169 4170 --*/ 4171 { 4172 This->NotifyResourceObjectsDx(NotifyResourcesSurpriseRemoved); 4173 4174 return WdfDevStatePowerGotoDxStopped; 4175 } 4176 4177 WDF_DEVICE_POWER_STATE 4178 FxPkgPnp::PowerGotoDxStopped( 4179 __inout FxPkgPnp* This 4180 ) 4181 /*++ 4182 4183 Routine Description: 4184 Device is in Dx and being removed/stopped. Inform the other state machines 4185 that the device is powered down so that they may continue. 4186 4187 Arguments: 4188 This - instance of the state machine 4189 4190 Return Value: 4191 WdfDevStatePowerStopped 4192 4193 --*/ 4194 { 4195 This->PowerSendPowerDownEvents(FxPowerDownTypeImplicit); 4196 4197 return WdfDevStatePowerStopped; 4198 } 4199 4200 WDF_DEVICE_POWER_STATE 4201 FxPkgPnp::PowerGotoStopped( 4202 __inout FxPkgPnp* This 4203 ) 4204 /*++ 4205 4206 Routine Description: 4207 We are in the Dx state and the power policy owner sent an explicit D0 irp 4208 to the stack. Transition to the stopped state which will transition to the 4209 D0 state when receiving an implicit D0. 4210 4211 Arguments: 4212 This - instance of the state machine 4213 4214 Return Value: 4215 WdfDevStatePowerStopped 4216 4217 --*/ 4218 { 4219 // 4220 // We should only get into this state when this devobj is not the power 4221 // policy owner. 4222 // 4223 ASSERT(This->IsPowerPolicyOwner() == FALSE); 4224 4225 This->PowerReleasePendingDeviceIrp(); 4226 return WdfDevStatePowerStopped; 4227 } 4228 4229 WDF_DEVICE_POWER_STATE 4230 FxPkgPnp::PowerStoppedCompleteDx( 4231 __inout FxPkgPnp* This 4232 ) 4233 /*++ 4234 4235 Routine Description: 4236 We were in the Stopped state and the power policy owner sent an explicit 4237 Dx request to the stack. We will move to the DxStopped state where we will 4238 transition to a Dx state when an implicit D0 is received. 4239 4240 Arguments: 4241 This - instance of the state machine 4242 4243 Return Value: 4244 WdfDevStatePowerDxStopped 4245 4246 --*/ 4247 { 4248 // 4249 // We should only get into this state when this devobj is not the power 4250 // policy owner. 4251 // 4252 ASSERT(This->IsPowerPolicyOwner() == FALSE); 4253 4254 This->PowerReleasePendingDeviceIrp(); 4255 return WdfDevStatePowerDxStopped; 4256 } 4257 4258 WDF_DEVICE_POWER_STATE 4259 FxPkgPnp::PowerDxStoppedDecideDxState( 4260 __inout FxPkgPnp* This 4261 ) 4262 /*++ 4263 4264 Routine Description: 4265 We are implicitly powering up the stack while in the Dx state. Decide 4266 which Dx "holding" state to transition to. 4267 4268 Arguments: 4269 This - instance of the state machine 4270 4271 Return Value: 4272 new power state 4273 4274 --*/ 4275 { 4276 // 4277 // We should only get into this state when this devobj is not the power 4278 // policy owner. 4279 // 4280 ASSERT(This->IsPowerPolicyOwner() == FALSE); 4281 4282 // 4283 // Move power policy back into a working state 4284 // 4285 // While it seems odd to send a power up in a Dx state, the power up is 4286 // really an indication to the power policy state machine that the implicit 4287 // D0 has been successfully processed, basically, it is a status event more 4288 // then an indication of true power state. 4289 // 4290 This->PowerSendPowerUpEvents(); 4291 4292 if (This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) { 4293 if (This->PowerIsWakeRequestPresent()) { 4294 COVERAGE_TRAP(); 4295 return WdfDevStatePowerDxStoppedArmForWake; 4296 } 4297 else { 4298 return WdfDevStatePowerDx; 4299 } 4300 } 4301 else { 4302 if (This->PowerIsWakeRequestPresent()) { 4303 COVERAGE_TRAP(); 4304 return WdfDevStatePowerDxStoppedArmForWakeNP; 4305 } 4306 else { 4307 COVERAGE_TRAP(); 4308 return WdfDevStatePowerDxNP; 4309 } 4310 } 4311 } 4312 4313 WDF_DEVICE_POWER_STATE 4314 FxPkgPnp::PowerDxStoppedArmForWake( 4315 __inout FxPkgPnp* This 4316 ) 4317 /*++ 4318 4319 Routine Description: 4320 We are implicitly powering the stack back up while the device is in Dx 4321 and there is a wait wake request presnt on this device. Enable wake at 4322 the bus level and then move to the appropriate state based on the enabling 4323 status. 4324 4325 Arguments: 4326 This - instance of the state machine 4327 4328 Return Value: 4329 new power state 4330 4331 --*/ 4332 { 4333 NTSTATUS status; 4334 4335 COVERAGE_TRAP(); 4336 4337 // 4338 // We should only get into this state when this devobj is not a PDO and a 4339 // power policy owner. 4340 // 4341 ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE); 4342 4343 status = This->PowerEnableWakeAtBusOverload(); 4344 4345 if (NT_SUCCESS(status)) { 4346 // 4347 // No matter of the irp status (canceled, pending, completed), we always 4348 // transition to the D0ArmedForWake state because that is where we 4349 // we handle the change in the irp's status. 4350 // 4351 COVERAGE_TRAP(); 4352 return WdfDevStatePowerDxArmedForWake; 4353 } 4354 else { 4355 COVERAGE_TRAP(); 4356 This->PowerCompleteWakeRequestFromWithinMachine(status); 4357 return WdfDevStatePowerDx; 4358 } 4359 } 4360 4361 WDF_DEVICE_POWER_STATE 4362 FxPkgPnp::PowerDxStoppedArmForWakeNP( 4363 __inout FxPkgPnp* This 4364 ) 4365 /*++ 4366 4367 Routine Description: 4368 We are implicitly powering the stack back up while the device is in Dx 4369 and there is a wait wake request presnt on this device. Enable wake at 4370 the bus level and then move to the appropriate state based on the enabling 4371 status. 4372 4373 Arguments: 4374 This - instance of the state machine 4375 4376 Return Value: 4377 new power state 4378 4379 --*/ 4380 { 4381 NTSTATUS status; 4382 4383 COVERAGE_TRAP(); 4384 4385 // 4386 // We should only get into this state when this devobj is not a PDO and a 4387 // power policy owner. 4388 // 4389 ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE); 4390 4391 status = This->PowerEnableWakeAtBusOverload(); 4392 4393 if (NT_SUCCESS(status)) { 4394 // 4395 // No matter of the irp status (canceled, pending, completed), we always 4396 // transition to the D0ArmedForWake state because that is where we 4397 // we handle the change in the irp's status. 4398 // 4399 COVERAGE_TRAP(); 4400 return WdfDevStatePowerDxArmedForWakeNP; 4401 } 4402 else { 4403 COVERAGE_TRAP(); 4404 This->PowerCompleteWakeRequestFromWithinMachine(status); 4405 return WdfDevStatePowerDxNP; 4406 } 4407 } 4408 4409 WDF_DEVICE_POWER_STATE 4410 FxPkgPnp::PowerFinalPowerDownFailed( 4411 __inout FxPkgPnp* This 4412 ) 4413 /*++ 4414 4415 Routine Description: 4416 Posts PowerDownFailed event to the PnP state machine and then waits for death. 4417 4418 Arguments: 4419 This - The instance of the state machine 4420 4421 Return Value: 4422 WdfDevStatePowerStopped 4423 4424 --*/ 4425 { 4426 This->PowerSendPowerDownFailureEvent(FxPowerDownTypeImplicit); 4427 4428 // 4429 // If we are not the PPO for the stack we could receive a power irp 4430 // during the middle of an implicit power down so we cannot assume 4431 // that there will be no pended power irp during an implicit power down. 4432 // 4433 ASSERT(This->IsPowerPolicyOwner() ? This->m_PendingDevicePowerIrp == NULL : TRUE); 4434 4435 return WdfDevStatePowerStopped; 4436 } 4437 4438 WDF_DEVICE_POWER_STATE 4439 FxPkgPnp::PowerUpFailedDerefParent( 4440 __inout FxPkgPnp* This 4441 ) 4442 /*++ 4443 4444 Routine Description: 4445 Disconnects interrupts 4446 4447 Arguments: 4448 This - The instance of the state machine 4449 4450 Return Value: 4451 WdfDevStatePowerReportPowerUpFailed 4452 4453 --*/ 4454 { 4455 // 4456 // Notify the interrupt state machines that the power up failed 4457 // 4458 This->SendEventToAllWakeInterrupts(WakeInterruptEventD0EntryFailed); 4459 // 4460 // NotifyResourceObjectsDx will log any errors 4461 // 4462 (void) This->NotifyResourceObjectsDx(NotifyResourcesForceDisconnect | 4463 NotifyResourcesDisconnectInactive); 4464 4465 return WdfDevStatePowerReportPowerUpFailedDerefParent; 4466 } 4467 4468 WDF_DEVICE_POWER_STATE 4469 FxPkgPnp::PowerUpFailed( 4470 __inout FxPkgPnp* This 4471 ) 4472 /*++ 4473 4474 Routine Description: 4475 Disconnects interrupts 4476 4477 Arguments: 4478 This - The instance of the state machine 4479 4480 Return Value: 4481 WdfDevStatePowerReportPowerUpFailed 4482 4483 --*/ 4484 { 4485 COVERAGE_TRAP(); 4486 // 4487 // Notify the interrupt state machines that the power up failed 4488 // 4489 This->SendEventToAllWakeInterrupts(WakeInterruptEventD0EntryFailed); 4490 // 4491 // NotifyResourceObjectsDx will log any errors 4492 // 4493 (void) This->NotifyResourceObjectsDx(NotifyResourcesForceDisconnect | 4494 NotifyResourcesDisconnectInactive); 4495 4496 return WdfDevStatePowerReportPowerUpFailed; 4497 } 4498 4499 WDF_DEVICE_POWER_STATE 4500 FxPkgPnp::PowerGotoDxFailed( 4501 __inout FxPkgPnp* This 4502 ) 4503 /*++ 4504 4505 Routine Description: 4506 Disconnects interrupts 4507 4508 Arguments: 4509 This - The instance of the state machine 4510 4511 Return Value: 4512 WdfDevStatePowerReportPowerDownFailed 4513 4514 --*/ 4515 { 4516 // 4517 // NotifyResourceObjectsDx will log any errors 4518 // 4519 (void) This->NotifyResourceObjectsDx(NotifyResourcesForceDisconnect | 4520 NotifyResourcesDisconnectInactive); 4521 4522 return WdfDevStatePowerReportPowerDownFailed; 4523 } 4524 4525 WDF_DEVICE_POWER_STATE 4526 FxPkgPnp::PowerGotoDxStoppedDisableInterrupt( 4527 __inout FxPkgPnp* This 4528 ) 4529 /*++ 4530 4531 Routine Description: 4532 Disconnects interrupts 4533 4534 Arguments: 4535 This - The instance of the state machine 4536 4537 Return Value: 4538 WdfDevStatePowerGotoDxStopped 4539 4540 --*/ 4541 { 4542 // 4543 // NotifyResourceObjectsDx will log any errors 4544 // 4545 (void) This->NotifyResourceObjectsDx(NotifyResourcesForceDisconnect | 4546 NotifyResourcesDisconnectInactive); 4547 4548 return WdfDevStatePowerGotoDxStopped; 4549 } 4550 4551 WDF_DEVICE_POWER_STATE 4552 FxPkgPnp::PowerUpFailedDerefParentNP( 4553 __inout FxPkgPnp* This 4554 ) 4555 /*++ 4556 4557 Routine Description: 4558 Disconnects interrupts 4559 4560 Arguments: 4561 This - The instance of the state machine 4562 4563 Return Value: 4564 WdfDevStatePowerReportPowerUpFailed 4565 4566 --*/ 4567 { 4568 // 4569 // Notify the interrupt state machines that the power up failed 4570 // 4571 This->SendEventToAllWakeInterrupts(WakeInterruptEventD0EntryFailed); 4572 This->DisconnectInterruptNP(); 4573 4574 return WdfDevStatePowerReportPowerUpFailedDerefParent; 4575 } 4576 4577 WDF_DEVICE_POWER_STATE 4578 FxPkgPnp::PowerUpFailedNP( 4579 __inout FxPkgPnp* This 4580 ) 4581 /*++ 4582 4583 Routine Description: 4584 Disconnects interrupts 4585 4586 Arguments: 4587 This - The instance of the state machine 4588 4589 Return Value: 4590 WdfDevStatePowerReportPowerUpFailed 4591 4592 --*/ 4593 { 4594 // 4595 // Notify the interrupt state machines that the power up failed 4596 // 4597 This->SendEventToAllWakeInterrupts(WakeInterruptEventD0EntryFailed); 4598 This->DisconnectInterruptNP(); 4599 4600 return WdfDevStatePowerReportPowerUpFailed; 4601 } 4602 4603 WDF_DEVICE_POWER_STATE 4604 FxPkgPnp::PowerNotifyingD0EntryToWakeInterrupts( 4605 __inout FxPkgPnp* This 4606 ) 4607 /*++ 4608 4609 Routine Description: 4610 Notifies the wake interrupt state machines that the device has entered 4611 D0 4612 4613 Arguments: 4614 This - The instance of the state machine 4615 4616 Return Value: 4617 WdfDevStatePowerWakingConnectInterrupt if there are no wake interrupts 4618 or WdfDevStatePowerNull otherwise 4619 4620 --*/ 4621 { 4622 if (This->m_WakeInterruptCount == 0) { 4623 return WdfDevStatePowerWakingConnectInterrupt; 4624 } 4625 4626 This->SendEventToAllWakeInterrupts(WakeInterruptEventEnteringD0); 4627 4628 return WdfDevStatePowerNull;; 4629 } 4630 4631 WDF_DEVICE_POWER_STATE 4632 FxPkgPnp::PowerNotifyingD0ExitToWakeInterrupts( 4633 __inout FxPkgPnp* This 4634 ) 4635 /*++ 4636 4637 Routine Description: 4638 Notifies the wake interrupt state machines that the device is about 4639 to exit D0 4640 4641 Arguments: 4642 This - The instance of the state machine 4643 4644 Return Value: 4645 WdfDevStatePowerDx if there are no wake interrupts or WdfDevStatePowerNull 4646 otherwise 4647 4648 --*/ 4649 { 4650 if (This->m_WakeInterruptCount == 0) { 4651 return WdfDevStatePowerGotoDxIoStopped; 4652 } 4653 4654 // 4655 // Indiciate to the wake interrupt state machine that the device is 4656 // leaving D0 and also whether the device is armed for wake. The wake 4657 // interrupt machine treats these differently as described below. 4658 // 4659 if (This->m_WakeInterruptsKeepConnected == TRUE || 4660 This->m_SharedPower.m_WaitWakeIrp != NULL) { 4661 This->SendEventToAllWakeInterrupts(WakeInterruptEventLeavingD0); 4662 } 4663 else { 4664 // 4665 // When a wake interrupt is not armed for wake it will be disconnected 4666 // by the power state machine once the wake interrupt state machine 4667 // acknowledges the transition. If the interrupt fires between 4668 // the time this event is posted and it is disconnected, it needs to be 4669 // delivered to the driver or a deadlock could occur between PO state machine 4670 // trying to disconnect the interrupt and the wake interrupt machine 4671 // holding on to the ISR waiting for the device to return to D0 before 4672 // delivering the interrupt. 4673 // 4674 This->SendEventToAllWakeInterrupts(WakeInterruptEventLeavingD0NotArmedForWake); 4675 } 4676 4677 return WdfDevStatePowerNull;; 4678 } 4679 4680 WDF_DEVICE_POWER_STATE 4681 FxPkgPnp::PowerNotifyingD0EntryToWakeInterruptsNP( 4682 __inout FxPkgPnp* This 4683 ) 4684 /*++ 4685 4686 Routine Description: 4687 Notifies the wake interrupt state machines that the device has entered 4688 D0 4689 4690 Arguments: 4691 This - The instance of the state machine 4692 4693 Return Value: 4694 WdfDevStatePowerWakingConnectInterruptNP if there are no wake interrupts 4695 or WdfDevStatePowerNull otherwise 4696 4697 --*/ 4698 { 4699 if (This->m_WakeInterruptCount == 0) { 4700 return WdfDevStatePowerWakingConnectInterruptNP; 4701 } 4702 4703 This->SendEventToAllWakeInterrupts(WakeInterruptEventEnteringD0); 4704 4705 return WdfDevStatePowerNull;; 4706 } 4707 4708 WDF_DEVICE_POWER_STATE 4709 FxPkgPnp::PowerNotifyingD0ExitToWakeInterruptsNP( 4710 __inout FxPkgPnp* This 4711 ) 4712 /*++ 4713 4714 Routine Description: 4715 Notifies the wake interrupt state machines that the device is about 4716 to exit D0 4717 4718 Arguments: 4719 This - The instance of the state machine 4720 4721 Return Value: 4722 WdfDevStatePowerDxNP if there are no wake interrupts or WdfDevStatePowerNull 4723 otherwise 4724 4725 --*/ 4726 { 4727 if (This->m_WakeInterruptCount == 0) { 4728 return WdfDevStatePowerGotoDxIoStoppedNP; 4729 } 4730 4731 // 4732 // Indiciate to the wake interrupt state machine that the device is 4733 // leaving D0 and also whether the device is armed for wake. The wake 4734 // interrupt machine treats these differently as described below 4735 // 4736 if (This->m_WakeInterruptsKeepConnected == TRUE || 4737 This->m_SharedPower.m_WaitWakeIrp != NULL) { 4738 This->SendEventToAllWakeInterrupts(WakeInterruptEventLeavingD0); 4739 } 4740 else { 4741 // 4742 // When a wake interrupt is not armed for wake it will be disconnected by 4743 // the power state machine once the wake interrupt state machine 4744 // acknowledges the transition. If the interrupt fires between 4745 // the time this event is posted and it is disconnected, it needs to be 4746 // delivered to the driver or a deadlock could occur between PO state machine 4747 // trying to disconnect the interrupt and the wake interrupt machine holding on 4748 // to the ISR waiting for the device to return to D0 before delivering the 4749 // interrupt. 4750 // 4751 This->SendEventToAllWakeInterrupts(WakeInterruptEventLeavingD0NotArmedForWake); 4752 } 4753 4754 return WdfDevStatePowerNull;; 4755 } 4756 4757 VOID 4758 FxPkgPnp::DisconnectInterruptNP( 4759 VOID 4760 ) 4761 { 4762 // 4763 // NotifyResourceObjectsDx will call IoDisconnectInterrupt. Since we 4764 // are in the NP path, this may cause a deadlock between this thread and 4765 // paging I/O. Log something to the IFR so that if the watchdog timer kicks 4766 // in, at least we have context as to why we died. 4767 // 4768 DoTraceLevelMessage( 4769 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 4770 "Force disconnecting interrupts on !devobj 0x%p, WDFDEVICE %p", 4771 m_Device->GetDeviceObject(), 4772 m_Device->GetHandle()); 4773 4774 // 4775 // NotifyResourceObjectsDx will log any errors 4776 // 4777 (void) NotifyResourceObjectsDx(NotifyResourcesForceDisconnect); 4778 } 4779 4780 BOOLEAN 4781 FxPkgPnp::PowerIndicateWaitWakeStatus( 4782 __in NTSTATUS WaitWakeStatus 4783 ) 4784 /*++ 4785 4786 Routine Description: 4787 If there is a pended wait wake request, this routine will remove the cancel 4788 routine and post the appropriate event to the power state machine. The 4789 consumer of this event will do the actual completion of the wait wake 4790 request. 4791 4792 The difference between this routine and 4793 PowerCompleteWakeRequestFromWithinMachine is that 4794 PowerCompleteWakeRequestFromWithinMachine is a private API to the state 4795 machine and will attempt to complete the request immediately instead of 4796 deferring the completion through the posting of a power state machine event. 4797 4798 PowerCompletePendedWakeIrp is used within the state machine to complete the 4799 IRP deferred by this routine. 4800 4801 Arguments: 4802 WaitWakeStatus - The final status of the wait wake request 4803 4804 Return Value: 4805 TRUE if there there was a request to cancel 4806 4807 --*/ 4808 { 4809 if (PowerMakeWakeRequestNonCancelable(WaitWakeStatus)) { 4810 // 4811 // The power machine will eventually call PowerCompletePendedWakeIrp 4812 // to complete the request. 4813 // 4814 if (WaitWakeStatus == STATUS_CANCELLED) { 4815 PowerProcessEvent(PowerWakeCanceled); 4816 } 4817 else if (NT_SUCCESS(WaitWakeStatus)) { 4818 PowerProcessEvent(PowerWakeSucceeded); 4819 } 4820 else { 4821 PowerProcessEvent(PowerWakeFailed); 4822 } 4823 4824 return TRUE; 4825 } 4826 else { 4827 return FALSE; 4828 } 4829 } 4830 4831 VOID 4832 FxPkgPnp::PowerCompletePendedWakeIrp( 4833 VOID 4834 ) 4835 /*++ 4836 4837 Routine Description: 4838 Completes the wait wake request that was pended by the power state machine. 4839 It is valid if there is no request to complete (the only time there will be 4840 a request to complete is when this power state machine is the wait wake owner 4841 4842 Arguments: 4843 None 4844 4845 Return Value: 4846 None 4847 4848 --*/ 4849 { 4850 PLIST_ENTRY ple; 4851 KIRQL irql; 4852 4853 if (m_SharedPower.m_WaitWakeOwner == FALSE) { 4854 COVERAGE_TRAP(); 4855 return; 4856 } 4857 4858 // 4859 // Pop an irp off of the list 4860 // 4861 m_PowerMachine.m_WaitWakeLock.Acquire(&irql); 4862 ASSERT(IsListEmpty(&m_PowerMachine.m_WaitWakeIrpToBeProcessedList) == FALSE); 4863 ple = RemoveHeadList(&m_PowerMachine.m_WaitWakeIrpToBeProcessedList); 4864 m_PowerMachine.m_WaitWakeLock.Release(irql); 4865 4866 InitializeListHead(ple); 4867 4868 FxIrp irp(FxIrp::GetIrpFromListEntry(ple)); 4869 4870 CompletePowerRequest(&irp, irp.GetStatus()); 4871 } 4872 4873 VOID 4874 FxPkgPnp::PowerCompleteWakeRequestFromWithinMachine( 4875 __in NTSTATUS WaitWakeStatus 4876 ) 4877 /*++ 4878 4879 Routine Description: 4880 Completes a wait wake from within the power state machine. Contrary to 4881 PowerIndicateWaitWakeStatus which posts an event to the state machine to 4882 process the irp's status change, this routine attempts to complete the 4883 irp immediately. 4884 4885 Arguments: 4886 Status - Final status of the wake irp 4887 4888 Return Value: 4889 None 4890 4891 --*/ 4892 { 4893 if (PowerMakeWakeRequestNonCancelable(WaitWakeStatus)) { 4894 PowerCompletePendedWakeIrp(); 4895 } 4896 } 4897 4898 BOOLEAN 4899 FxPkgPnp::PowerMakeWakeRequestNonCancelable( 4900 __in NTSTATUS WaitWakeStatus 4901 ) 4902 /*++ 4903 4904 Routine Description: 4905 Attempts to clear the cancel routine from the pended wake request. If 4906 successful, it will put the wake request on a pending wake list to be 4907 completed later by PowerCompletePendedWakeIrp . 4908 4909 Arguments: 4910 WaitWakeStatus - final status for the wake request 4911 4912 Return Value: 4913 TRUE if there was a request and we cleared the cancel routine, FALSE 4914 otherwise 4915 4916 --*/ 4917 { 4918 KIRQL irql; 4919 BOOLEAN result; 4920 4921 // 4922 // Currently we assume that if we are the bus wait wake owner and that only 4923 // PDOs can be bus wake owners, so we must have a parent device. 4924 // 4925 ASSERT(m_SharedPower.m_WaitWakeOwner && 4926 (m_Device->m_ParentDevice != NULL)); 4927 4928 result = FALSE; 4929 4930 // 4931 // Attempt to retrieve the wait wake irp. We can safely dereference the 4932 // PIRP in while holding the lock as long as it is not NULL. 4933 // 4934 m_PowerMachine.m_WaitWakeLock.Acquire(&irql); 4935 4936 if (m_SharedPower.m_WaitWakeIrp != NULL) { 4937 MdCancelRoutine pOldCancelRoutine; 4938 FxIrp wwIrp; 4939 4940 wwIrp.SetIrp(m_SharedPower.m_WaitWakeIrp); 4941 4942 pOldCancelRoutine = wwIrp.SetCancelRoutine(NULL); 4943 4944 if (pOldCancelRoutine != NULL) { 4945 FxPkgPnp* pParentPkg; 4946 4947 pParentPkg = m_Device->m_ParentDevice->m_PkgPnp; 4948 4949 // 4950 // Propagate the successful wake status from the parent to this 4951 // child's WW IRP if the parent is the PPO for its stack. 4952 // 4953 if (NT_SUCCESS(WaitWakeStatus) && 4954 pParentPkg->IsPowerPolicyOwner() && 4955 pParentPkg->m_PowerPolicyMachine.m_Owner->m_SystemWakeSource) { 4956 // 4957 // The only way that m_SystemWakeSource can be TRUE is if 4958 // FxLibraryGlobals.PoGetSystemWake != NULL and if it is not 4959 // NULL, then FxLibraryGlobals.PoSetSystemWake cannot be NULL 4960 // either. 4961 4962 4963 4964 4965 4966 FxPkgPnp::_PowerSetSystemWakeSource(&wwIrp); 4967 4968 // 4969 // If this PDO is the PPO for its stack, then we must mark this 4970 // device as the system wake source if we have any 4971 // enumerated PDOs off of this PDO so that we can propagate the 4972 // system wake source attribute to our children stacks. 4973 // (For a FDO which is the PPO, we do this in the WW completion 4974 // routine.) 4975 // 4976 if (IsPowerPolicyOwner()) { 4977 DoTraceLevelMessage( 4978 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 4979 "WDFDEVICE 0x%p !devobj 0x%p WW !irp 0x%p is a source " 4980 "of wake", m_Device->GetHandle(), 4981 m_Device->GetDeviceObject(), 4982 m_SharedPower.m_WaitWakeIrp); 4983 4984 m_PowerPolicyMachine.m_Owner->m_SystemWakeSource = TRUE; 4985 } 4986 } 4987 4988 // 4989 // Set the status for the irp when it is completed later 4990 // 4991 wwIrp.SetStatus(WaitWakeStatus); 4992 4993 // 4994 // Queue the irp for completion later 4995 // 4996 InsertTailList(&m_PowerMachine.m_WaitWakeIrpToBeProcessedList, 4997 wwIrp.ListEntry()); 4998 4999 wwIrp.SetIrp(NULL); 5000 m_SharedPower.m_WaitWakeIrp = NULL; 5001 result = TRUE; 5002 } 5003 else { 5004 // 5005 // The irp is being canceled as we run here. As soon as the spin 5006 // lock is dropped, the cancel routine will run (or continue if it 5007 // is blocked on this lock). Do nothing here and let the cancel 5008 // routine run its course. 5009 // 5010 ASSERT(wwIrp.IsCanceled()); 5011 DO_NOTHING(); 5012 } 5013 } 5014 m_PowerMachine.m_WaitWakeLock.Release(irql); 5015 5016 return result; 5017 } 5018 5019 VOID 5020 FxPkgPnp::PowerSendIdlePowerEvent( 5021 __in FxPowerIdleEvents Event 5022 ) 5023 { 5024 if (IsPowerPolicyOwner()) { 5025 m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.ProcessPowerEvent(Event); 5026 } 5027 } 5028 5029 VOID 5030 FxPkgPnp::PowerSendPowerDownEvents( 5031 __in FxPowerDownType Type 5032 ) 5033 /*++ 5034 5035 Routine Description: 5036 The device has powered down, inform the power policy state machine 5037 5038 Arguments: 5039 Type - the type of power down being performed 5040 5041 Return Value: 5042 None 5043 5044 --*/ 5045 { 5046 // 5047 // If this is an implicit power type, there is completion routine on the 5048 // power irp and we must send these events in the power state machine 5049 // regardless if we are the PPO or not. 5050 // 5051 if (Type == FxPowerDownTypeImplicit) { 5052 PowerSendIdlePowerEvent(PowerIdleEventPowerDown); 5053 5054 // 5055 // If we are the power policy owner, there is no need to distinguish 5056 // between an implicit power down or an explicit power down since the 5057 // PPO controls all power irps in the stack and a power policy stop 5058 // (e.g. an implicit power down) will not be racing with a real power 5059 // irp. 5060 // 5061 // The non PPO state machine needs to distinguish between the 2 types 5062 // of power downs because both of them may occur simultaneously and we 5063 // don't want to interpret the power down event for the real Dx irp with 5064 // the power down event for the (final) implicit power down. 5065 // 5066 PowerPolicyProcessEvent(IsPowerPolicyOwner() ? PwrPolPowerDown 5067 : PwrPolImplicitPowerDown); 5068 return; 5069 } 5070 5071 ASSERT(Type == FxPowerDownTypeExplicit); 5072 5073 // 5074 // If we are the PPO, then we will send PwrPolPowerDown in the completion 5075 // routine passed to PoRequestPowerIrp. If we are not the PPO, we must send 5076 // the event now because we have no such completion routine. 5077 // 5078 if (IsPowerPolicyOwner()) { 5079 // 5080 // Transition the idle state machine to off immediately. 5081 // 5082 m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.ProcessPowerEvent( 5083 PowerIdleEventPowerDown 5084 ); 5085 } 5086 else { 5087 // 5088 // If we are not the PPO, there is no idle state machine to send an 5089 // event to and there is no Po request completion routine to send this 5090 // event, so we send it now. 5091 // 5092 PowerPolicyProcessEvent(PwrPolPowerDown); 5093 } 5094 } 5095 5096 VOID 5097 FxPkgPnp::PowerSendPowerUpEvents( 5098 VOID 5099 ) 5100 /*++ 5101 5102 Routine Description: 5103 Sends power up events to the pnp and power policy state machines 5104 5105 Arguments: 5106 None 5107 5108 Return Value: 5109 None 5110 5111 --*/ 5112 { 5113 PowerSendIdlePowerEvent(PowerIdleEventPowerUpComplete); 5114 5115 // 5116 // This must be called *before* PowerPostParentToD0ToChildren so that we 5117 // clear the child power up guard variable in the power policy state machine 5118 // and then post an event which will unblock the child. 5119 // 5120 PowerPolicyProcessEvent(PwrPolPowerUp); 5121 } 5122 5123 VOID 5124 FxPkgPnp::PowerSendPowerDownFailureEvent( 5125 __in FxPowerDownType Type 5126 ) 5127 /*++ 5128 5129 Routine Description: 5130 Sends a power down failure event to the pnp state machine marks an internal 5131 error. 5132 5133 Arguments: 5134 None 5135 5136 Return Value: 5137 None 5138 5139 --*/ 5140 { 5141 SetInternalFailure(); 5142 5143 if (IsPowerPolicyOwner()) { 5144 // 5145 // If we are the PPO and this is an explicit power operation, then we 5146 // will send PwrPolPowerDownFailed in the completion routine passed to 5147 // PoRequestPowerIrp. Otherwise, if this is an implicit power operation 5148 // that failed, we need to send the event now because there is no 5149 // Po completion routine to send the event later. 5150 // 5151 if (Type == FxPowerDownTypeImplicit) { 5152 // 5153 // Since there is no power irp to complete, we must send the event 5154 // now. 5155 // 5156 // We only send PwrPolImplicitPowerDownFailed if we are not the 5157 // PPO, so we can't share code with the !PPO path. 5158 // 5159 PowerPolicyProcessEvent(PwrPolPowerDownFailed); 5160 } 5161 else { 5162 ASSERT(Type == FxPowerDownTypeExplicit); 5163 5164 // 5165 // Process the state change immediately in the idle state machine. 5166 // We should do this only on an explicit power down since the PPO 5167 // will have disabled the idle state machine before attempting an 5168 // implicit power down. 5169 // 5170 m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.ProcessPowerEvent( 5171 PowerIdleEventPowerDownFailed 5172 ); 5173 } 5174 } 5175 else { 5176 // 5177 // We are not the PPO, so we must send the event now because we have no 5178 // such completion routine. Decide which event to send to the 5179 // !PPO state machine. 5180 // 5181 PowerPolicyProcessEvent( 5182 Type == FxPowerDownTypeImplicit ? PwrPolImplicitPowerDownFailed 5183 : PwrPolPowerDownFailed 5184 ); 5185 5186 // 5187 // Send the pnp event last becuase if we are in the middle of a Dx 5188 // transition during S0, there is no S irp to guard a pnp state change 5189 // from occurring immediately after sending this event. If we sent it 5190 // before sending the power policy message, power policy might not 5191 // transition to the failed state by the time pnp does creating a 5192 // mismatch. 5193 // 5194 if (FALSE == m_ReleaseHardwareAfterDescendantsOnFailure) { 5195 PnpProcessEvent(PnpEventPowerDownFailed); 5196 } 5197 } 5198 } 5199 5200 VOID 5201 FxPkgPnp::PowerSendPowerUpFailureEvent( 5202 VOID 5203 ) 5204 /*++ 5205 5206 Routine Description: 5207 Sends a power up failure event to the pnp state machine marks an internal 5208 error. 5209 5210 Arguments: 5211 None 5212 5213 Return Value: 5214 None 5215 5216 --*/ 5217 { 5218 SetInternalFailure(); 5219 PowerSendIdlePowerEvent(PowerIdleEventPowerUpFailed); 5220 5221 PowerPolicyProcessEvent(PwrPolPowerUpFailed); 5222 5223 if (FALSE == m_ReleaseHardwareAfterDescendantsOnFailure) { 5224 PnpProcessEvent(PnpEventPowerUpFailed); 5225 } 5226 } 5227 5228 VOID 5229 FxPkgPnp::PowerSetDevicePowerState( 5230 __in WDF_POWER_DEVICE_STATE State 5231 ) 5232 /*++ 5233 5234 Routine Description: 5235 Stores the state in the object and notifies the system of the change. 5236 5237 Arguments: 5238 State - new device state 5239 5240 Return Value: 5241 VOID 5242 5243 --*/ 5244 { 5245 POWER_STATE powerState; 5246 5247 // 5248 // Remember our previous state 5249 // 5250 m_DevicePowerStateOld = m_DevicePowerState; 5251 5252 // 5253 // Set our new state 5254 // 5255 ASSERT(State <= 0xFF); 5256 m_DevicePowerState = (BYTE) State; 5257 5258 // 5259 // Notify the system of the new power state. 5260 // 5261 switch (State) { 5262 case WdfPowerDeviceD3Final: 5263 case WdfPowerDevicePrepareForHibernation: 5264 powerState.DeviceState = PowerDeviceD3; 5265 break; 5266 5267 case WdfPowerDeviceD0: 5268 m_SystemPowerAction = PowerActionNone; 5269 __fallthrough; 5270 5271 default: 5272 powerState.DeviceState = (DEVICE_POWER_STATE) State; 5273 break; 5274 } 5275 5276 MxDeviceObject deviceObject(m_Device->GetDeviceObject()); 5277 deviceObject.SetPowerState( 5278 DevicePowerState, 5279 powerState); 5280 } 5281 5282 VOID 5283 FxPkgPnp::PowerConnectInterruptFailed( 5284 VOID 5285 ) 5286 /*++ 5287 5288 Routine Description: 5289 Worker routine for all the paths where we are trying to bring the device into 5290 D0 and failed while trying to connect or enable an interrupt. This routine 5291 disables and disconnects all interrupts, calls D0Exit, and sets the device 5292 state. 5293 5294 Arguments: 5295 This - instance of the state machine 5296 5297 Return Value: 5298 None 5299 5300 --*/ 5301 5302 { 5303 NTSTATUS status; 5304 5305 status = NotifyResourceObjectsDx(NotifyResourcesForceDisconnect); 5306 5307 if (!NT_SUCCESS(status)) { 5308 // 5309 // Report the error, but continue forward 5310 // 5311 DoTraceLevelMessage( 5312 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 5313 "Interrupt(s) disconnect on WDFDEVICE %p failed, %!STATUS!", 5314 m_Device->GetHandle(), status); 5315 } 5316 5317 status = m_DeviceD0Exit.Invoke(m_Device->GetHandle(), 5318 WdfPowerDeviceD3Final); 5319 5320 if (!NT_SUCCESS(status)) { 5321 // 5322 // Report the error, but continue forward 5323 // 5324 DoTraceLevelMessage( 5325 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 5326 "EvtDeviceD0Exit WDFDEVICE 0x%p !devobj 0x%p failed, %!STATUS!", 5327 m_Device->GetHandle(), 5328 m_Device->GetDeviceObject(), status); 5329 } 5330 5331 PowerSetDevicePowerState(WdfPowerDeviceD3Final); 5332 } 5333 5334 5335 5336 5337 5338 5339 5340 5341 VOID 5342 FxPkgPnp::_PowerWaitWakeCancelRoutine( 5343 __in MdDeviceObject DeviceObject, 5344 __in MdIrp Irp 5345 ) 5346 /*++ 5347 5348 Routine Description: 5349 Cancel routine for the pended wait wake irp. This will post an event to 5350 the power state machine to process the cancellation under the machine's 5351 lock and complete the irp later. 5352 5353 Arguments: 5354 DeviceObject - Instance of this state machine 5355 Irp - The wait wake request being canceled 5356 5357 Return Value: 5358 None 5359 5360 --*/ 5361 { 5362 CfxDevice* pDevice; 5363 FxPkgPdo* pThis; 5364 FxIrp irp(Irp); 5365 KIRQL irql; 5366 5367 // 5368 // Release the IO cancel spinlock because we use our own 5369 // 5370 Mx::ReleaseCancelSpinLock(irp.GetCancelIrql()); 5371 5372 pDevice = FxDevice::GetFxDevice(DeviceObject); 5373 pThis = pDevice->GetPdoPkg(); 5374 5375 ASSERT(pThis->m_SharedPower.m_WaitWakeOwner); 5376 5377 // 5378 // Clear out the IRQL and set our state to disarming 5379 // 5380 pThis->m_PowerMachine.m_WaitWakeLock.Acquire(&irql); 5381 5382 ASSERT(pThis->m_SharedPower.m_WaitWakeIrp == Irp && 5383 pThis->m_SharedPower.m_WaitWakeIrp != NULL); 5384 5385 InsertTailList(&pThis->m_PowerMachine.m_WaitWakeIrpToBeProcessedList, 5386 irp.ListEntry()); 5387 5388 // 5389 // Set the status for the irp when it is completed later 5390 // 5391 irp.SetStatus(STATUS_CANCELLED); 5392 5393 pThis->m_SharedPower.m_WaitWakeIrp = NULL; 5394 5395 pThis->m_PowerMachine.m_WaitWakeLock.Release(irql); 5396 5397 pThis->PowerProcessEvent(PowerWakeCanceled); 5398 } 5399