1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FdoPower.cpp 8 9 Abstract: 10 11 This module implements the pnp/power package for the driver 12 framework. This, specifically, is the power code. 13 14 Author: 15 16 17 18 19 Environment: 20 21 Both kernel and user mode 22 23 Revision History: 24 25 26 27 28 --*/ 29 30 #include "pnppriv.hpp" 31 32 33 34 35 #if defined(EVENT_TRACING) 36 extern "C" { 37 #include "FdoPower.tmh" 38 } 39 #endif 40 41 _Must_inspect_result_ 42 NTSTATUS 43 FxPkgFdo::_PowerPassDown( 44 __inout FxPkgPnp* This, 45 __in FxIrp *Irp 46 ) 47 48 /*++ 49 50 Routine Description: 51 52 This method is invoked when a Power Irp we don't handle comes into the 53 driver. 54 55 Arguemnts: 56 57 This - the package 58 59 Irp - a pointer to the FxIrp 60 61 Returns: 62 63 NTSTATUS 64 65 --*/ 66 { 67 FxPkgFdo* pThis; 68 NTSTATUS status; 69 MdIrp pIrp; 70 71 pIrp = Irp->GetIrp(); 72 pThis = (FxPkgFdo*) This; 73 74 // 75 // FDOs don't handle this IRP, so simply pass it down. 76 // 77 Irp->StartNextPowerIrp(); 78 Irp->CopyCurrentIrpStackLocationToNext(); 79 80 status = Irp->PoCallDriver(pThis->m_Device->GetAttachedDevice()); 81 82 Mx::MxReleaseRemoveLock(pThis->m_Device->GetRemoveLock(), 83 pIrp); 84 85 return status; 86 } 87 88 _Must_inspect_result_ 89 NTSTATUS 90 FxPkgFdo::_DispatchSetPower( 91 __inout FxPkgPnp* This, 92 __in FxIrp *Irp 93 ) 94 /*++ 95 96 Routine Description: 97 98 This method is invoked when a SetPower IRP enters the driver. 99 100 Arguemnts: 101 102 Device - a pointer to the FxDevice 103 104 Irp - a pointer to the FxIrp 105 106 Returns: 107 108 NTSTATUS 109 110 --*/ 111 112 { 113 if (Irp->GetParameterPowerType() == SystemPowerState) { 114 return ((FxPkgFdo*) This)->DispatchSystemSetPower(Irp); 115 } 116 else { 117 return ((FxPkgFdo*) This)->DispatchDeviceSetPower(Irp); 118 } 119 } 120 121 _Must_inspect_result_ 122 NTSTATUS 123 FxPkgFdo::_DispatchQueryPower( 124 __inout FxPkgPnp* This, 125 __in FxIrp *Irp 126 ) 127 128 /*++ 129 130 Routine Description: 131 132 This method is invoked when a QueryPower IRP enters the driver. 133 134 Arguemnts: 135 136 This - The package 137 138 Irp - a pointer to the FxIrp 139 140 Returns: 141 142 NTSTATUS 143 144 --*/ 145 146 { 147 if (Irp->GetParameterPowerType() == SystemPowerState) { 148 return ((FxPkgFdo*) This)->DispatchSystemQueryPower(Irp); 149 } 150 else { 151 return ((FxPkgFdo*) This)->DispatchDeviceQueryPower(Irp); 152 } 153 } 154 155 _Must_inspect_result_ 156 NTSTATUS 157 FxPkgFdo::_SystemPowerS0Completion( 158 __in MdDeviceObject DeviceObject, 159 __in MdIrp OriginalIrp, 160 __in PVOID Context 161 ) 162 { 163 FxPkgPnp* pPkgPnp; 164 KIRQL irql; 165 FxIrp irp(OriginalIrp); 166 167 pPkgPnp = (FxPkgPnp*) Context; 168 169 // 170 // Ideally we would like to complete the S0 irp before we start 171 // processing the event in the state machine so that the D0 irp 172 // comes after the S0 is moving up the stack... 173 // 174 // ... BUT ... 175 // 176 // ... by allowing the S0 irp to go up the stack first, we must then 177 // handle pnp requests from the current power policy state (because 178 // the S0 irp could be the last S irp in the system and when completed, 179 // the pnp lock is released). So, we process the event first so 180 // that we can move into a state where we can handle pnp events in 181 // the power policy state machine. 182 // 183 // We mitigate the situation a little bit by forcing the processing of the 184 // event to occur on the power policy thread rather then in the current 185 // context. 186 // 187 Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql); 188 pPkgPnp->PowerPolicyProcessEvent(PwrPolS0); 189 Mx::MxLowerIrql(irql); 190 191 irp.StartNextPowerIrp(); 192 193 // 194 // Let the irp continue on its way 195 // 196 if (irp.PendingReturned()) { 197 irp.MarkIrpPending(); 198 } 199 200 Mx::MxReleaseRemoveLock((&FxDevice::_GetFxWdmExtension(DeviceObject)->IoRemoveLock), 201 OriginalIrp); 202 203 return irp.GetStatus(); 204 } 205 206 _Must_inspect_result_ 207 NTSTATUS 208 FxPkgFdo::_SystemPowerSxCompletion( 209 __in MdDeviceObject DeviceObject, 210 __in MdIrp OriginalIrp, 211 __in PVOID Context 212 ) 213 { 214 FxPkgFdo *pThis; 215 FxIrp irp(OriginalIrp); 216 217 UNREFERENCED_PARAMETER(DeviceObject); 218 219 pThis = (FxPkgFdo*) Context; 220 221 ASSERT(pThis->IsPowerPolicyOwner()); 222 ASSERT(OriginalIrp == pThis->GetPendingSystemPowerIrp()); 223 224 pThis->PowerPolicyProcessEvent(PwrPolSx); 225 226 // 227 // Power policy will complete the system irp 228 // 229 return STATUS_MORE_PROCESSING_REQUIRED; 230 } 231 232 _Must_inspect_result_ 233 NTSTATUS 234 FxPkgFdo::DispatchSystemSetPower( 235 __in FxIrp *Irp 236 ) 237 { 238 NTSTATUS status; 239 MxDeviceObject deviceObject(m_Device->GetDeviceObject()); 240 241 m_SystemPowerState = (BYTE) Irp->GetParameterPowerStateSystemState(); 242 deviceObject.SetPowerState(SystemPowerState, 243 Irp->GetParameterPowerState()); 244 245 if (IsPowerPolicyOwner()) { 246 // 247 // If we are going to S0, we just notify the power policy state machine 248 // and then let the request go (per the fast resume spec). Otherwise, 249 // send the request down and on the way up, send the Dx request. 250 // 251 if (m_SystemPowerState == PowerSystemWorking) { 252 // 253 // Post the event into the state machine when the irp is going up 254 // the stack. See the comment in _SystemPowerS0Completion for more 255 // detail as to why. 256 // 257 Irp->CopyCurrentIrpStackLocationToNext(); 258 Irp->SetCompletionRoutineEx(deviceObject.GetObject(), 259 _SystemPowerS0Completion, 260 this); 261 262 return Irp->PoCallDriver(m_Device->GetAttachedDevice()); 263 } 264 else { 265 // 266 // Stash away the irp for the power policy state machine. We will 267 // post the event to the power policy state machine when the S irp 268 // completes back to this driver. 269 // 270 SetPendingSystemPowerIrp(Irp); 271 272 Irp->CopyCurrentIrpStackLocationToNext(); 273 Irp->SetCompletionRoutineEx(deviceObject.GetObject(), 274 _SystemPowerSxCompletion, 275 this); 276 277 Irp->PoCallDriver(m_Device->GetAttachedDevice()); 278 279 status = STATUS_PENDING; 280 } 281 } 282 else { 283 // 284 // We don't do anything with S irps if we are not the power policy 285 // owner. 286 // 287 // This will release the remove lock as well. 288 // 289 status = _PowerPassDown(this, Irp); 290 } 291 292 return status; 293 } 294 295 _Must_inspect_result_ 296 NTSTATUS 297 FxPkgFdo::DispatchDeviceSetPower( 298 __in FxIrp *Irp 299 ) 300 301 { 302 NTSTATUS status; 303 304 if (IsPowerPolicyOwner()) { 305 if (m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp == FALSE && 306 m_PowerPolicyMachine.m_Owner->m_RequestedPowerDownIrp == FALSE) { 307 // 308 // A power irp arrived, but we did not request it. log and bugcheck 309 // 310 DoTraceLevelMessage( 311 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 312 "Received set device power irp 0x%p on WDFDEVICE 0x%p !devobj 0x%p, " 313 "but the irp was not requested by the device (the power policy owner)", 314 Irp->GetIrp(), m_Device->GetHandle(), 315 m_Device->GetDeviceObject()); 316 317 FxVerifierBugCheck(GetDriverGlobals(), // globals 318 WDF_POWER_MULTIPLE_PPO, // specific type 319 (ULONG_PTR)m_Device->GetDeviceObject(), //parm 2 320 (ULONG_PTR)Irp->GetIrp()); // parm 3 321 322 /* NOTREACHED */ 323 } 324 325 // 326 // We are no longer requesting a power irp because we received the one 327 // we requested. 328 // 329 if (m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp) { 330 m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp = FALSE; 331 } else { 332 m_PowerPolicyMachine.m_Owner->m_RequestedPowerDownIrp = FALSE; 333 } 334 } 335 336 // 337 // Determine if we are raising or lowering the device power state. 338 // 339 if (Irp->GetParameterPowerStateDeviceState() == PowerDeviceD0) { 340 status = RaiseDevicePower(Irp); 341 } 342 else { 343 status = LowerDevicePower(Irp); 344 } 345 346 return status; 347 } 348 349 _Must_inspect_result_ 350 NTSTATUS 351 FxPkgFdo::RaiseDevicePower( 352 __in FxIrp *Irp 353 ) 354 { 355 Irp->MarkIrpPending(); 356 Irp->CopyCurrentIrpStackLocationToNext(); 357 Irp->SetCompletionRoutineEx(m_Device->GetDeviceObject(), 358 RaiseDevicePowerCompletion, 359 this); 360 361 Irp->PoCallDriver(m_Device->GetAttachedDevice()); 362 363 return STATUS_PENDING; 364 } 365 366 _Must_inspect_result_ 367 NTSTATUS 368 FxPkgFdo::RaiseDevicePowerCompletion( 369 __in MdDeviceObject DeviceObject, 370 __in MdIrp OriginalIrp, 371 __in PVOID Context 372 ) 373 { 374 FxPkgFdo* pThis; 375 FxIrp irp(OriginalIrp); 376 377 UNREFERENCED_PARAMETER(DeviceObject); 378 379 pThis = (FxPkgFdo*) Context; 380 381 // 382 // We can safely cache away the device power irp in our fdo package 383 // storage because we know we can only get one device power irp at 384 // a time. 385 // 386 pThis->SetPendingDevicePowerIrp(&irp); 387 388 // 389 // Kick off the power state machine. 390 // 391 pThis->PowerProcessEvent(PowerD0); 392 393 return STATUS_MORE_PROCESSING_REQUIRED; 394 } 395 396 _Must_inspect_result_ 397 NTSTATUS 398 FxPkgFdo::LowerDevicePower( 399 __in FxIrp *Irp 400 ) 401 { 402 SetPendingDevicePowerIrp(Irp); 403 404 // 405 // Kick off the power state machine. 406 // 407 PowerProcessEvent(PowerDx); 408 409 return STATUS_PENDING; 410 } 411 412 _Must_inspect_result_ 413 NTSTATUS 414 FxPkgFdo::DispatchSystemQueryPower( 415 __in FxIrp *Irp 416 ) 417 { 418 if (PowerPolicyIsWakeEnabled()) { 419 NTSTATUS status; 420 421 status = PowerPolicyHandleSystemQueryPower( 422 Irp->GetParameterPowerStateSystemState() 423 ); 424 425 Irp->SetStatus(status); 426 427 if (!NT_SUCCESS(status)) { 428 return CompletePowerRequest(Irp, status); 429 } 430 } 431 432 // 433 // Passing down the irp because one of the following 434 // a) We don't care b/c we don't control the power policy 435 // b) we are not enabled for arming for wake from Sx 436 // c) we can wake from the queried S state 437 // 438 return _PowerPassDown(this, Irp); 439 } 440 441 _Must_inspect_result_ 442 NTSTATUS 443 FxPkgFdo::DispatchDeviceQueryPower( 444 __in FxIrp *Irp 445 ) 446 { 447 // 448 // Either the framework is the power policy owner and we wouldn't be sending 449 // a device query power or we are a subordinate will do what the power 450 // policy owner wants 100% of the time. 451 // 452 Irp->SetStatus(STATUS_SUCCESS); 453 454 // 455 // This will release the remove lock 456 // 457 return _PowerPassDown(this, Irp); 458 } 459 460 VOID 461 FxPkgFdo::PowerReleasePendingDeviceIrp( 462 __in BOOLEAN IrpMustBePresent 463 ) 464 { 465 MdIrp pIrp; 466 467 pIrp = ClearPendingDevicePowerIrp(); 468 469 UNREFERENCED_PARAMETER(IrpMustBePresent); 470 ASSERT(IrpMustBePresent == FALSE || pIrp != NULL); 471 472 if (pIrp != NULL) { 473 FxIrp irp(pIrp); 474 475 if (irp.GetParameterPowerStateDeviceState() == PowerDeviceD0) { 476 // 477 // We catch D0 irps on the way up, so complete it 478 // 479 CompletePowerRequest(&irp, STATUS_SUCCESS); 480 } 481 else { 482 irp.SetStatus(STATUS_SUCCESS); 483 484 // 485 // We catch Dx irps on the way down, so send it on its way 486 // 487 // This will also release the remove lock 488 // 489 (void) _PowerPassDown(this, &irp); 490 } 491 } 492 } 493 494 WDF_DEVICE_POWER_STATE 495 FxPkgFdo::PowerCheckDeviceTypeOverload( 496 VOID 497 ) 498 /*++ 499 500 Routine Description: 501 This function implements the Check Type state. This is FDO code, 502 so the answer is reductionistly simple. 503 504 Arguments: 505 none 506 507 Return Value: 508 509 new power state 510 511 --*/ 512 { 513 return WdfDevStatePowerWaking; 514 } 515 516 WDF_DEVICE_POWER_STATE 517 FxPkgFdo::PowerCheckDeviceTypeNPOverload( 518 VOID 519 ) 520 /*++ 521 522 Routine Description: 523 This function implements the Check Type state. This is FDO code, 524 so the answer is reductionistly simple. 525 526 Arguments: 527 none 528 529 Return Value: 530 531 new power state 532 533 --*/ 534 { 535 return WdfDevStatePowerWakingNP; 536 } 537 538 _Must_inspect_result_ 539 NTSTATUS 540 FxPkgFdo::PowerCheckParentOverload( 541 __out BOOLEAN* ParentOn 542 ) 543 /*++ 544 545 Routine Description: 546 This function implements the CheckParent state. Its 547 job is to determine which state we should go to next based on whether 548 the parent is in D0. But since this is the FDO code, we can't know 549 that. So just assume that the PDO will guarantee it. 550 551 Arguments: 552 none 553 554 Return Value: 555 556 new power state 557 558 --*/ 559 { 560 ASSERT(!"This state shouldn't be reachable for an FDO."); 561 *ParentOn = TRUE; 562 return STATUS_SUCCESS; 563 } 564 565 VOID 566 FxPkgFdo::PowerParentPowerDereference( 567 VOID 568 ) 569 /*++ 570 571 Routine Description: 572 This virtual function is a nop for an FDO. PDOs implement this function 573 574 Arguments: 575 None 576 577 Return Value: 578 None 579 580 --*/ 581 { 582 DO_NOTHING(); 583 } 584