1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 PdoPower.cpp 8 9 Abstract: 10 11 This module implements the Pnp package for Pdo devices. 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 // Tracing support 31 #if defined(EVENT_TRACING) 32 extern "C" { 33 #include "PdoPower.tmh" 34 } 35 #endif 36 37 _Must_inspect_result_ 38 NTSTATUS 39 FxPkgPdo::_DispatchPowerSequence( 40 __inout FxPkgPnp* This, 41 __in FxIrp *Irp 42 ) 43 /*++ 44 45 Routine Description: 46 report the power sequence for the child 47 48 Arguments: 49 This - the package 50 51 Irp - the request 52 53 Return Value: 54 STATUS_NOT_SUPPORTED 55 56 --*/ 57 { 58 return ((FxPkgPdo*) This)->CompletePowerRequest(Irp, STATUS_NOT_SUPPORTED); 59 } 60 61 _Must_inspect_result_ 62 NTSTATUS 63 FxPkgPdo::_DispatchSetPower( 64 __inout FxPkgPnp* This, 65 __in FxIrp *Irp 66 ) 67 /*++ 68 69 Routine Description: 70 71 This method is invoked when a SetPower IRP enters the driver. 72 73 Arguemnts: 74 75 Device - a pointer to the FxDevice 76 77 Irp - a pointer to the FxIrp 78 79 Returns: 80 81 NTSTATUS 82 83 --*/ 84 { 85 if (Irp->GetParameterPowerType() == SystemPowerState) { 86 return ((FxPkgPdo*) This)->DispatchSystemSetPower(Irp); 87 } 88 else { 89 return ((FxPkgPdo*) This)->DispatchDeviceSetPower(Irp); 90 } 91 } 92 93 _Must_inspect_result_ 94 NTSTATUS 95 FxPkgPdo::DispatchSystemSetPower( 96 __in FxIrp *Irp 97 ) 98 { 99 KIRQL irql; 100 MxDeviceObject deviceObject(m_Device->GetDeviceObject()); 101 102 m_SystemPowerState = (BYTE) Irp->GetParameterPowerStateSystemState(); 103 deviceObject.SetPowerState(SystemPowerState, 104 Irp->GetParameterPowerState()); 105 106 if (IsPowerPolicyOwner()) { 107 if (m_SystemPowerState == PowerSystemWorking) { 108 // 109 // Ideally we would like to complete the S0 irp before we start 110 // processing the event in the state machine so that the D0 irp 111 // comes after the S0 is moving up the stack... 112 // 113 // ... BUT ... 114 // 115 // ... by allowing the S0 irp to go up the stack first, we must then 116 // handle pnp requests from the current power policy state (because 117 // the S0 irp could be the last S irp in the system and when completed, 118 // the pnp lock is released). So, we process the event first so 119 // that we can move into a state where we can handle pnp events in 120 // the power policy state machine. 121 // 122 // We mitigate the situation a little bit by forcing the processing of the 123 // event to occur on the power policy thread rather then in the current 124 // context. 125 // 126 Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql); 127 PowerPolicyProcessEvent(PwrPolS0); 128 Mx::MxLowerIrql(irql); 129 130 return CompletePowerRequest(Irp, STATUS_SUCCESS); 131 } 132 else { 133 // 134 // Power policy state machine will complete the request later 135 // 136 SetPendingSystemPowerIrp(Irp); 137 PowerPolicyProcessEvent(PwrPolSx); 138 return STATUS_PENDING; 139 } 140 } 141 else { 142 // 143 // Since we are not the power policy owner, we just complete all S irps 144 // 145 return CompletePowerRequest(Irp, STATUS_SUCCESS); 146 } 147 } 148 149 _Must_inspect_result_ 150 NTSTATUS 151 FxPkgPdo::DispatchDeviceSetPower( 152 __in FxIrp *Irp 153 ) 154 { 155 if (IsPowerPolicyOwner()) { 156 if (m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp == FALSE && 157 m_PowerPolicyMachine.m_Owner->m_RequestedPowerDownIrp == FALSE) { 158 // 159 // A power irp arrived, but we did not request it. ASSERT and log 160 // an error. 161 // 162 DoTraceLevelMessage( 163 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 164 "Received set device power irp 0x%p on WDFDEVICE 0x%p !devobj 0x%p, " 165 "but the irp was not requested by the device (the power policy owner)", 166 Irp->GetIrp(), 167 m_Device->GetHandle(), 168 m_Device->GetDeviceObject()); 169 170 ASSERTMSG("Received set device power irp but the irp was not " 171 "requested by the device (the power policy owner)\n", 172 FALSE); 173 } 174 175 // 176 // We are no longer requesting a power irp because we received the one 177 // we requested. 178 // 179 if (m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp) { 180 m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp = FALSE; 181 } 182 else { 183 m_PowerPolicyMachine.m_Owner->m_RequestedPowerDownIrp = FALSE; 184 } 185 } 186 187 SetPendingDevicePowerIrp(Irp); 188 189 if (Irp->GetParameterPowerStateDeviceState() == PowerDeviceD0) { 190 PowerProcessEvent(PowerD0); 191 } 192 else { 193 PowerProcessEvent(PowerDx); 194 } 195 196 return STATUS_PENDING; 197 } 198 199 _Must_inspect_result_ 200 NTSTATUS 201 FxPkgPdo::_DispatchQueryPower( 202 __inout FxPkgPnp* This, 203 __in FxIrp *Irp 204 ) 205 /*++ 206 207 Routine Description: 208 Dispatches query power for system and device requests 209 210 Arguments: 211 This - the package 212 213 Irp - the query power request 214 215 Return Value: 216 NTSTATUS 217 218 --*/ 219 { 220 FxPkgPdo* pThis; 221 NTSTATUS status; 222 223 pThis = ((FxPkgPdo*) This); 224 225 if (Irp->GetParameterPowerType() == SystemPowerState 226 && 227 This->PowerPolicyIsWakeEnabled()) { 228 229 status = pThis->PowerPolicyHandleSystemQueryPower( 230 Irp->GetParameterPowerStateSystemState() 231 ); 232 } 233 else { 234 status = STATUS_SUCCESS; 235 } 236 237 return pThis->CompletePowerRequest(Irp, status); 238 } 239 240 VOID 241 FxPkgPdo::PowerReleasePendingDeviceIrp( 242 __in BOOLEAN IrpMustBePresent 243 ) 244 { 245 MdIrp pIrp; 246 247 pIrp = ClearPendingDevicePowerIrp(); 248 249 UNREFERENCED_PARAMETER(IrpMustBePresent); 250 ASSERT(IrpMustBePresent == FALSE || pIrp != NULL); 251 252 if (pIrp != NULL) { 253 FxIrp irp(pIrp); 254 255 CompletePowerRequest(&irp, STATUS_SUCCESS); 256 } 257 } 258 259 _Must_inspect_result_ 260 NTSTATUS 261 FxPkgPdo::PowerCheckParentOverload( 262 __in BOOLEAN* ParentOn 263 ) 264 /*++ 265 266 Routine Description: 267 This function implements the CheckParent state. Its 268 job is to determine which state we should go to next based on whether 269 the parent is in D0. 270 271 Arguments: 272 none 273 274 Return Value: 275 276 VOID 277 278 --*/ 279 { 280 281 282 283 284 return (m_Device->m_ParentDevice->m_PkgPnp)-> 285 PowerPolicyCanChildPowerUp(ParentOn); 286 } 287 288 WDF_DEVICE_POWER_STATE 289 FxPkgPdo::PowerCheckDeviceTypeOverload( 290 VOID 291 ) 292 /*++ 293 294 Routine Description: 295 This function implements the Check Type state. This is a PDO. 296 297 Arguments: 298 none 299 300 Return Value: 301 302 new power state 303 304 --*/ 305 { 306 return WdfDevStatePowerCheckParentState; 307 } 308 309 WDF_DEVICE_POWER_STATE 310 FxPkgPdo::PowerCheckDeviceTypeNPOverload( 311 VOID 312 ) 313 /*++ 314 315 Routine Description: 316 This function implements the Check Type state. This is a PDO. 317 318 Arguments: 319 none 320 321 Return Value: 322 323 new power state 324 325 --*/ 326 { 327 return WdfDevStatePowerCheckParentStateNP; 328 } 329 330 _Must_inspect_result_ 331 NTSTATUS 332 FxPkgPdo::PowerEnableWakeAtBusOverload( 333 VOID 334 ) 335 /*++ 336 337 Routine Description: 338 Arms the device at the bus level for wake. This arming is generic since 339 the bus driver can only configure the device generically. The power policy 340 owner has already armed the device for wake in a device specific fashion 341 when it processed the wake irp (EvtDeviceArmDeviceForWakeFromS0/x if the ppo 342 is a WDF driver). 343 344 Arguments: 345 None 346 347 Return Value: 348 NTSTATUS, !NT_SUCCESS if the arm failed 349 350 --*/ 351 { 352 NTSTATUS status; 353 354 // 355 // The EnableWakeAtBus callback should not be called twice in a row without 356 // an intermediate call to the DisableWakeAtBus callback. 357 // 358 ASSERT(m_EnableWakeAtBusInvoked == FALSE); 359 360 status = m_DeviceEnableWakeAtBus.Invoke( 361 m_Device->GetHandle(), 362 (SYSTEM_POWER_STATE) m_SystemPowerState 363 ); 364 365 if (NT_SUCCESS(status)) { 366 m_EnableWakeAtBusInvoked = TRUE; 367 PowerNotifyParentChildWakeArmed(); 368 } 369 370 return status; 371 } 372 373 VOID 374 FxPkgPdo::PowerDisableWakeAtBusOverload( 375 VOID 376 ) 377 /*++ 378 379 Routine Description: 380 Disarms the device at the bus level for wake. This disarming is generic 381 since the bus driver can only configure the device generically. The power 382 policy owner may have already disarmed the device for wake in a device 383 specific fashion. For a WDF ppo EvtDeviceDisarmDeviceForWakeFromS0/x is 384 called after the bus has disarmed. 385 386 Arguments: 387 None 388 389 Return Value: 390 None 391 392 --*/ 393 { 394 if (m_EnableWakeAtBusInvoked) { 395 m_EnableWakeAtBusInvoked = FALSE; 396 PowerNotifyParentChildWakeDisarmed(); 397 398 m_DeviceDisableWakeAtBus.Invoke(m_Device->GetHandle()); 399 } 400 } 401 402 VOID 403 FxPkgPdo::PowerParentPowerDereference( 404 VOID 405 ) 406 /*++ 407 408 Routine Description: 409 Releases the child power reference on the parent device. This allows the 410 parent to enter into an idle capable state. This power reference does not 411 prevent the parent from moving into Dx when the system power state changes. 412 413 Arguments: 414 None 415 416 Return Value: 417 None 418 419 --*/ 420 { 421 422 m_Device->m_ParentDevice->m_PkgPnp->PowerPolicyChildPoweredDown(); 423 } 424 425 VOID 426 FxPkgPdo::PowerNotifyParentChildWakeArmed( 427 VOID 428 ) 429 /*++ 430 431 Routine Description: 432 Notifies the parent device that the child is armed for wake. This will 433 cause the parent to increment its count of children armed for wake. 434 435 Arguments: 436 None 437 438 Return Value: 439 None 440 441 --*/ 442 { 443 FxPowerPolicyOwnerSettings* settings; 444 445 ASSERT(m_Device->m_ParentDevice != NULL); 446 447 448 449 450 451 settings = m_Device->m_ParentDevice->m_PkgPnp-> 452 m_PowerPolicyMachine.m_Owner; 453 if (settings != NULL) { 454 settings->IncrementChildrenArmedForWakeCount(); 455 } 456 } 457 458 VOID 459 FxPkgPdo::PowerNotifyParentChildWakeDisarmed( 460 VOID 461 ) 462 /*++ 463 464 Routine Description: 465 Notifies the parent device that the child is not armed for wake. This will 466 cause the parent to decrement its count of children armed for wake. 467 468 Arguments: 469 None 470 471 Return Value: 472 None 473 474 --*/ 475 { 476 FxPowerPolicyOwnerSettings* settings; 477 478 ASSERT(m_Device->m_ParentDevice != NULL); 479 480 481 482 483 484 settings = m_Device->m_ParentDevice->m_PkgPnp-> 485 m_PowerPolicyMachine.m_Owner; 486 if (settings != NULL) { 487 settings->DecrementChildrenArmedForWakeCount(); 488 } 489 } 490