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 STDCALL 158 FxPkgFdo::_SystemPowerS0Completion( 159 __in MdDeviceObject DeviceObject, 160 __in MdIrp OriginalIrp, 161 __in PVOID Context 162 ) 163 { 164 FxPkgPnp* pPkgPnp; 165 KIRQL irql; 166 FxIrp irp(OriginalIrp); 167 168 pPkgPnp = (FxPkgPnp*) Context; 169 170 // 171 // Ideally we would like to complete the S0 irp before we start 172 // processing the event in the state machine so that the D0 irp 173 // comes after the S0 is moving up the stack... 174 // 175 // ... BUT ... 176 // 177 // ... by allowing the S0 irp to go up the stack first, we must then 178 // handle pnp requests from the current power policy state (because 179 // the S0 irp could be the last S irp in the system and when completed, 180 // the pnp lock is released). So, we process the event first so 181 // that we can move into a state where we can handle pnp events in 182 // the power policy state machine. 183 // 184 // We mitigate the situation a little bit by forcing the processing of the 185 // event to occur on the power policy thread rather then in the current 186 // context. 187 // 188 Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql); 189 pPkgPnp->PowerPolicyProcessEvent(PwrPolS0); 190 Mx::MxLowerIrql(irql); 191 192 irp.StartNextPowerIrp(); 193 194 // 195 // Let the irp continue on its way 196 // 197 if (irp.PendingReturned()) { 198 irp.MarkIrpPending(); 199 } 200 201 Mx::MxReleaseRemoveLock((&FxDevice::_GetFxWdmExtension(DeviceObject)->IoRemoveLock), 202 OriginalIrp); 203 204 return irp.GetStatus(); 205 } 206 207 _Must_inspect_result_ 208 NTSTATUS 209 STDCALL 210 FxPkgFdo::_SystemPowerSxCompletion( 211 __in MdDeviceObject DeviceObject, 212 __in MdIrp OriginalIrp, 213 __in PVOID Context 214 ) 215 { 216 FxPkgFdo *pThis; 217 FxIrp irp(OriginalIrp); 218 219 UNREFERENCED_PARAMETER(DeviceObject); 220 221 pThis = (FxPkgFdo*) Context; 222 223 ASSERT(pThis->IsPowerPolicyOwner()); 224 ASSERT(OriginalIrp == pThis->GetPendingSystemPowerIrp()); 225 226 pThis->PowerPolicyProcessEvent(PwrPolSx); 227 228 // 229 // Power policy will complete the system irp 230 // 231 return STATUS_MORE_PROCESSING_REQUIRED; 232 } 233 234 _Must_inspect_result_ 235 NTSTATUS 236 FxPkgFdo::DispatchSystemSetPower( 237 __in FxIrp *Irp 238 ) 239 { 240 NTSTATUS status; 241 MxDeviceObject deviceObject(m_Device->GetDeviceObject()); 242 243 m_SystemPowerState = (BYTE) Irp->GetParameterPowerStateSystemState(); 244 deviceObject.SetPowerState(SystemPowerState, 245 Irp->GetParameterPowerState()); 246 247 if (IsPowerPolicyOwner()) { 248 // 249 // If we are going to S0, we just notify the power policy state machine 250 // and then let the request go (per the fast resume spec). Otherwise, 251 // send the request down and on the way up, send the Dx request. 252 // 253 if (m_SystemPowerState == PowerSystemWorking) { 254 // 255 // Post the event into the state machine when the irp is going up 256 // the stack. See the comment in _SystemPowerS0Completion for more 257 // detail as to why. 258 // 259 Irp->CopyCurrentIrpStackLocationToNext(); 260 Irp->SetCompletionRoutineEx(deviceObject.GetObject(), 261 _SystemPowerS0Completion, 262 this); 263 264 return Irp->PoCallDriver(m_Device->GetAttachedDevice()); 265 } 266 else { 267 // 268 // Stash away the irp for the power policy state machine. We will 269 // post the event to the power policy state machine when the S irp 270 // completes back to this driver. 271 // 272 SetPendingSystemPowerIrp(Irp); 273 274 Irp->CopyCurrentIrpStackLocationToNext(); 275 Irp->SetCompletionRoutineEx(deviceObject.GetObject(), 276 _SystemPowerSxCompletion, 277 this); 278 279 Irp->PoCallDriver(m_Device->GetAttachedDevice()); 280 281 status = STATUS_PENDING; 282 } 283 } 284 else { 285 // 286 // We don't do anything with S irps if we are not the power policy 287 // owner. 288 // 289 // This will release the remove lock as well. 290 // 291 status = _PowerPassDown(this, Irp); 292 } 293 294 return status; 295 } 296 297 _Must_inspect_result_ 298 NTSTATUS 299 FxPkgFdo::DispatchDeviceSetPower( 300 __in FxIrp *Irp 301 ) 302 303 { 304 NTSTATUS status; 305 306 if (IsPowerPolicyOwner()) { 307 if (m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp == FALSE && 308 m_PowerPolicyMachine.m_Owner->m_RequestedPowerDownIrp == FALSE) { 309 // 310 // A power irp arrived, but we did not request it. log and bugcheck 311 // 312 DoTraceLevelMessage( 313 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 314 "Received set device power irp 0x%p on WDFDEVICE 0x%p !devobj 0x%p, " 315 "but the irp was not requested by the device (the power policy owner)", 316 Irp->GetIrp(), m_Device->GetHandle(), 317 m_Device->GetDeviceObject()); 318 319 FxVerifierBugCheck(GetDriverGlobals(), // globals 320 WDF_POWER_MULTIPLE_PPO, // specific type 321 (ULONG_PTR)m_Device->GetDeviceObject(), //parm 2 322 (ULONG_PTR)Irp->GetIrp()); // parm 3 323 324 /* NOTREACHED */ 325 } 326 327 // 328 // We are no longer requesting a power irp because we received the one 329 // we requested. 330 // 331 if (m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp) { 332 m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp = FALSE; 333 } else { 334 m_PowerPolicyMachine.m_Owner->m_RequestedPowerDownIrp = FALSE; 335 } 336 } 337 338 // 339 // Determine if we are raising or lowering the device power state. 340 // 341 if (Irp->GetParameterPowerStateDeviceState() == PowerDeviceD0) { 342 status = RaiseDevicePower(Irp); 343 } 344 else { 345 status = LowerDevicePower(Irp); 346 } 347 348 return status; 349 } 350 351 _Must_inspect_result_ 352 NTSTATUS 353 FxPkgFdo::RaiseDevicePower( 354 __in FxIrp *Irp 355 ) 356 { 357 Irp->MarkIrpPending(); 358 Irp->CopyCurrentIrpStackLocationToNext(); 359 Irp->SetCompletionRoutineEx(m_Device->GetDeviceObject(), 360 RaiseDevicePowerCompletion, 361 this); 362 363 Irp->PoCallDriver(m_Device->GetAttachedDevice()); 364 365 return STATUS_PENDING; 366 } 367 368 _Must_inspect_result_ 369 NTSTATUS 370 STDCALL 371 FxPkgFdo::RaiseDevicePowerCompletion( 372 __in MdDeviceObject DeviceObject, 373 __in MdIrp OriginalIrp, 374 __in PVOID Context 375 ) 376 { 377 FxPkgFdo* pThis; 378 FxIrp irp(OriginalIrp); 379 380 UNREFERENCED_PARAMETER(DeviceObject); 381 382 pThis = (FxPkgFdo*) Context; 383 384 // 385 // We can safely cache away the device power irp in our fdo package 386 // storage because we know we can only get one device power irp at 387 // a time. 388 // 389 pThis->SetPendingDevicePowerIrp(&irp); 390 391 // 392 // Kick off the power state machine. 393 // 394 pThis->PowerProcessEvent(PowerD0); 395 396 return STATUS_MORE_PROCESSING_REQUIRED; 397 } 398 399 _Must_inspect_result_ 400 NTSTATUS 401 FxPkgFdo::LowerDevicePower( 402 __in FxIrp *Irp 403 ) 404 { 405 SetPendingDevicePowerIrp(Irp); 406 407 // 408 // Kick off the power state machine. 409 // 410 PowerProcessEvent(PowerDx); 411 412 return STATUS_PENDING; 413 } 414 415 _Must_inspect_result_ 416 NTSTATUS 417 FxPkgFdo::DispatchSystemQueryPower( 418 __in FxIrp *Irp 419 ) 420 { 421 if (PowerPolicyIsWakeEnabled()) { 422 NTSTATUS status; 423 424 status = PowerPolicyHandleSystemQueryPower( 425 Irp->GetParameterPowerStateSystemState() 426 ); 427 428 Irp->SetStatus(status); 429 430 if (!NT_SUCCESS(status)) { 431 return CompletePowerRequest(Irp, status); 432 } 433 } 434 435 // 436 // Passing down the irp because one of the following 437 // a) We don't care b/c we don't control the power policy 438 // b) we are not enabled for arming for wake from Sx 439 // c) we can wake from the queried S state 440 // 441 return _PowerPassDown(this, Irp); 442 } 443 444 _Must_inspect_result_ 445 NTSTATUS 446 FxPkgFdo::DispatchDeviceQueryPower( 447 __in FxIrp *Irp 448 ) 449 { 450 // 451 // Either the framework is the power policy owner and we wouldn't be sending 452 // a device query power or we are a subordinate will do what the power 453 // policy owner wants 100% of the time. 454 // 455 Irp->SetStatus(STATUS_SUCCESS); 456 457 // 458 // This will release the remove lock 459 // 460 return _PowerPassDown(this, Irp); 461 } 462 463 VOID 464 FxPkgFdo::PowerReleasePendingDeviceIrp( 465 __in BOOLEAN IrpMustBePresent 466 ) 467 { 468 MdIrp pIrp; 469 470 pIrp = ClearPendingDevicePowerIrp(); 471 472 UNREFERENCED_PARAMETER(IrpMustBePresent); 473 ASSERT(IrpMustBePresent == FALSE || pIrp != NULL); 474 475 if (pIrp != NULL) { 476 FxIrp irp(pIrp); 477 478 if (irp.GetParameterPowerStateDeviceState() == PowerDeviceD0) { 479 // 480 // We catch D0 irps on the way up, so complete it 481 // 482 CompletePowerRequest(&irp, STATUS_SUCCESS); 483 } 484 else { 485 irp.SetStatus(STATUS_SUCCESS); 486 487 // 488 // We catch Dx irps on the way down, so send it on its way 489 // 490 // This will also release the remove lock 491 // 492 (void) _PowerPassDown(this, &irp); 493 } 494 } 495 } 496 497 WDF_DEVICE_POWER_STATE 498 FxPkgFdo::PowerCheckDeviceTypeOverload( 499 VOID 500 ) 501 /*++ 502 503 Routine Description: 504 This function implements the Check Type state. This is FDO code, 505 so the answer is reductionistly simple. 506 507 Arguments: 508 none 509 510 Return Value: 511 512 new power state 513 514 --*/ 515 { 516 return WdfDevStatePowerWaking; 517 } 518 519 WDF_DEVICE_POWER_STATE 520 FxPkgFdo::PowerCheckDeviceTypeNPOverload( 521 VOID 522 ) 523 /*++ 524 525 Routine Description: 526 This function implements the Check Type state. This is FDO code, 527 so the answer is reductionistly simple. 528 529 Arguments: 530 none 531 532 Return Value: 533 534 new power state 535 536 --*/ 537 { 538 return WdfDevStatePowerWakingNP; 539 } 540 541 _Must_inspect_result_ 542 NTSTATUS 543 FxPkgFdo::PowerCheckParentOverload( 544 __out BOOLEAN* ParentOn 545 ) 546 /*++ 547 548 Routine Description: 549 This function implements the CheckParent state. Its 550 job is to determine which state we should go to next based on whether 551 the parent is in D0. But since this is the FDO code, we can't know 552 that. So just assume that the PDO will guarantee it. 553 554 Arguments: 555 none 556 557 Return Value: 558 559 new power state 560 561 --*/ 562 { 563 ASSERT(!"This state shouldn't be reachable for an FDO."); 564 *ParentOn = TRUE; 565 return STATUS_SUCCESS; 566 } 567 568 VOID 569 FxPkgFdo::PowerParentPowerDereference( 570 VOID 571 ) 572 /*++ 573 574 Routine Description: 575 This virtual function is a nop for an FDO. PDOs implement this function 576 577 Arguments: 578 None 579 580 Return Value: 581 None 582 583 --*/ 584 { 585 DO_NOTHING(); 586 } 587