1 /*++ 2 Copyright (c) Microsoft. All rights reserved. 3 4 Module Name: 5 6 DevicePwrReq.cpp 7 8 Abstract: 9 10 This module implements the device power requirement logic in the framework. 11 12 --*/ 13 14 #include "pnppriv.hpp" 15 16 extern "C" { 17 #if defined(EVENT_TRACING) 18 #include "DevicePwrReqStateMachine.tmh" 19 #endif 20 } 21 22 const FxDevicePwrRequirementTargetState 23 FxDevicePwrRequirementMachine::m_UnregisteredStates[] = 24 { 25 {DprEventRegisteredWithPox, DprDevicePowerRequiredD0 DEBUGGED_EVENT} 26 }; 27 28 const FxDevicePwrRequirementTargetState 29 FxDevicePwrRequirementMachine::m_DevicePowerRequiredD0States[] = 30 { 31 {DprEventPoxDoesNotRequirePower, DprDevicePowerNotRequiredD0 DEBUGGED_EVENT}, 32 {DprEventUnregisteredWithPox, DprUnregistered DEBUGGED_EVENT}, 33 {DprEventDeviceReturnedToD0, DprDevicePowerRequiredD0 DEBUGGED_EVENT} 34 }; 35 36 const FxDevicePwrRequirementTargetState 37 FxDevicePwrRequirementMachine::m_DevicePowerNotRequiredD0States[] = 38 { 39 {DprEventDeviceGoingToDx, DprDevicePowerNotRequiredDx DEBUGGED_EVENT}, 40 {DprEventPoxRequiresPower, DprReportingDevicePowerAvailable DEBUGGED_EVENT}, 41 {DprEventUnregisteredWithPox, DprUnregistered TRAP_ON_EVENT} 42 }; 43 44 const FxDevicePwrRequirementTargetState 45 FxDevicePwrRequirementMachine::m_DevicePowerNotRequiredDxStates[] = 46 { 47 {DprEventDeviceReturnedToD0, DprWaitingForDevicePowerRequiredD0 DEBUGGED_EVENT}, 48 {DprEventPoxRequiresPower, DprDevicePowerRequiredDx DEBUGGED_EVENT} 49 }; 50 51 const FxDevicePwrRequirementTargetState 52 FxDevicePwrRequirementMachine::m_DevicePowerRequiredDxStates[] = 53 { 54 {DprEventDeviceReturnedToD0, DprReportingDevicePowerAvailable DEBUGGED_EVENT} 55 }; 56 57 const FxDevicePwrRequirementTargetState 58 FxDevicePwrRequirementMachine::m_WaitingForDevicePowerRequiredD0States[] = 59 { 60 {DprEventPoxRequiresPower, DprReportingDevicePowerAvailable DEBUGGED_EVENT}, 61 {DprEventDeviceReturnedToD0, DprWaitingForDevicePowerRequiredD0 TRAP_ON_EVENT}, 62 {DprEventUnregisteredWithPox, DprUnregistered DEBUGGED_EVENT}, 63 }; 64 65 const FxDevicePwrRequirementStateTable 66 FxDevicePwrRequirementMachine::m_StateTable[] = 67 { 68 // DprUnregistered 69 { NULL, 70 FxDevicePwrRequirementMachine::m_UnregisteredStates, 71 ARRAY_SIZE(FxDevicePwrRequirementMachine::m_UnregisteredStates), 72 }, 73 74 // DprDevicePowerRequiredD0 75 { NULL, 76 FxDevicePwrRequirementMachine::m_DevicePowerRequiredD0States, 77 ARRAY_SIZE(FxDevicePwrRequirementMachine::m_DevicePowerRequiredD0States), 78 }, 79 80 // DprDevicePowerNotRequiredD0 81 { FxDevicePwrRequirementMachine::PowerNotRequiredD0, 82 FxDevicePwrRequirementMachine::m_DevicePowerNotRequiredD0States, 83 ARRAY_SIZE(FxDevicePwrRequirementMachine::m_DevicePowerNotRequiredD0States), 84 }, 85 86 // DprDevicePowerNotRequiredDx 87 { NULL, 88 FxDevicePwrRequirementMachine::m_DevicePowerNotRequiredDxStates, 89 ARRAY_SIZE(FxDevicePwrRequirementMachine::m_DevicePowerNotRequiredDxStates), 90 }, 91 92 // DprDevicePowerRequiredDx 93 { FxDevicePwrRequirementMachine::PowerRequiredDx, 94 FxDevicePwrRequirementMachine::m_DevicePowerRequiredDxStates, 95 ARRAY_SIZE(FxDevicePwrRequirementMachine::m_DevicePowerRequiredDxStates), 96 }, 97 98 // DprReportingDevicePowerAvailable 99 { FxDevicePwrRequirementMachine::ReportingDevicePowerAvailable, 100 NULL, 101 0, 102 }, 103 104 // DprWaitingForDevicePowerRequiredD0 105 { NULL, 106 FxDevicePwrRequirementMachine::m_WaitingForDevicePowerRequiredD0States, 107 ARRAY_SIZE(FxDevicePwrRequirementMachine::m_WaitingForDevicePowerRequiredD0States), 108 }, 109 }; 110 111 FxDevicePwrRequirementMachine::FxDevicePwrRequirementMachine( 112 __in FxPoxInterface * PoxInterface 113 ) : FxThreadedEventQueue(FxDevicePwrRequirementEventQueueDepth) 114 { 115 // 116 // Make sure we can fit the state into a byte 117 // 118 C_ASSERT(DprMax <= 0xFF); 119 120 m_CurrentState = DprUnregistered; 121 122 RtlZeroMemory(&m_Queue, sizeof(m_Queue)); 123 RtlZeroMemory(&m_States, sizeof(m_States)); 124 125 // 126 // Store the initial state in the state history array 127 // 128 m_States.History[IncrementHistoryIndex()] = m_CurrentState; 129 m_PoxInterface = PoxInterface; 130 } 131 132 VOID 133 FxDevicePwrRequirementMachine::ProcessEvent( 134 __in FxDevicePwrRequirementEvents Event 135 ) 136 { 137 NTSTATUS status; 138 KIRQL irql; 139 LONGLONG timeout = 0; 140 141 // 142 // Acquire state machine *queue* lock, raising to DISPATCH_LEVEL 143 // 144 Lock(&irql); 145 146 if (IsFull()) { 147 // 148 // The queue is full. This should never happen. 149 // 150 Unlock(irql); 151 152 ASSERTMSG("The device power requirement state machine queue is full\n", 153 FALSE); 154 return; 155 } 156 157 if (IsClosedLocked()) { 158 // 159 // The queue is closed. This should never happen. 160 // 161 DoTraceLevelMessage( 162 m_PkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 163 "WDFDEVICE 0x%p !devobj 0x%p current device power requirement state" 164 " %!FxDevicePwrRequirementStates! dropping event " 165 "%!FxDevicePwrRequirementEvents! because of a closed queue", 166 m_PoxInterface->m_PkgPnp->GetDevice()->GetHandle(), 167 m_PoxInterface->m_PkgPnp->GetDevice()->GetDeviceObject(), 168 m_CurrentState, 169 Event); 170 171 Unlock(irql); 172 173 ASSERTMSG( 174 "The device power requirement state machine queue is closed\n", 175 FALSE 176 ); 177 return; 178 } 179 180 // 181 // Enqueue the event 182 // 183 m_Queue[InsertAtTail()] = Event; 184 185 // 186 // Drop the state machine *queue* lock 187 // 188 Unlock(irql); 189 190 // 191 // Now, if we are running at PASSIVE_LEVEL, attempt to run the state machine 192 // on this thread. If we can't do that, then queue a work item. 193 // 194 if (irql == PASSIVE_LEVEL) { 195 // 196 // Try to acquire the state machine lock 197 // 198 status = m_StateMachineLock.AcquireLock( 199 m_PoxInterface->m_PkgPnp->GetDriverGlobals(), 200 &timeout 201 ); 202 if (FxWaitLockInternal::IsLockAcquired(status)) { 203 FxPostProcessInfo info; 204 205 // 206 // We now hold the state machine lock. So call the function that 207 // dispatches the next state. 208 // 209 ProcessEventInner(&info); 210 211 // 212 // The pnp state machine should be the only one deleting the object 213 // 214 ASSERT(info.m_DeleteObject == FALSE); 215 216 // 217 // Release the state machine lock 218 // 219 m_StateMachineLock.ReleaseLock( 220 m_PoxInterface->m_PkgPnp->GetDriverGlobals() 221 ); 222 223 info.Evaluate(m_PkgPnp); 224 225 return; 226 } 227 } 228 229 // 230 // For one reason or another, we couldn't run the state machine on this 231 // thread. So queue a work item to do it. 232 // 233 QueueToThread(); 234 return; 235 } 236 237 VOID 238 FxDevicePwrRequirementMachine::_ProcessEventInner( 239 __inout FxPkgPnp* PkgPnp, 240 __inout FxPostProcessInfo* Info, 241 __in PVOID WorkerContext 242 ) 243 { 244 FxDevicePwrRequirementMachine * pThis = NULL; 245 246 UNREFERENCED_PARAMETER(WorkerContext); 247 248 pThis = PkgPnp->m_PowerPolicyMachine.m_Owner-> 249 m_PoxInterface.m_DevicePowerRequirementMachine; 250 251 // 252 // Take the state machine lock. 253 // 254 pThis->m_StateMachineLock.AcquireLock( 255 pThis->m_PoxInterface->m_PkgPnp->GetDriverGlobals() 256 ); 257 258 // 259 // Call the function that will actually run the state machine. 260 // 261 pThis->ProcessEventInner(Info); 262 263 // 264 // We are being called from the work item and m_WorkItemRunning is > 0, so 265 // we cannot be deleted yet. 266 // 267 ASSERT(Info->SomethingToDo() == FALSE); 268 269 // 270 // Now release the state machine lock 271 // 272 pThis->m_StateMachineLock.ReleaseLock( 273 pThis->m_PoxInterface->m_PkgPnp->GetDriverGlobals() 274 ); 275 276 return; 277 } 278 279 VOID 280 FxDevicePwrRequirementMachine::ProcessEventInner( 281 __inout FxPostProcessInfo* Info 282 ) 283 { 284 KIRQL irql; 285 FxDevicePwrRequirementEvents event; 286 const FxDevicePwrRequirementStateTable* entry; 287 FxDevicePwrRequirementStates newState; 288 289 // 290 // Process as many events as we can 291 // 292 for ( ; ; ) { 293 // 294 // Acquire state machine *queue* lock 295 // 296 Lock(&irql); 297 298 if (IsEmpty()) { 299 // 300 // The queue is empty. 301 // 302 GetFinishedState(Info); 303 Unlock(irql); 304 return; 305 } 306 307 // 308 // Get the event from the queue 309 // 310 event = m_Queue[GetHead()]; 311 IncrementHead(); 312 313 // 314 // Drop the state machine *queue* lock 315 // 316 Unlock(irql); 317 318 // 319 // Get the state table entry for the current state 320 // 321 // NOTE: Prefast complains about buffer overflow if (m_CurrentState == 322 // DprMax), but that should never happen because DprMax is not a real 323 // state. We just use it to represent the maximum value in the enum that 324 // defines the states. 325 // 326 __analysis_assume(m_CurrentState < DprMax); 327 entry = &m_StateTable[m_CurrentState - DprUnregistered]; 328 329 // 330 // Based on the event received, figure out the next state 331 // 332 newState = DprMax; 333 for (ULONG i = 0; i < entry->TargetStatesCount; i++) { 334 if (entry->TargetStates[i].DprEvent == event) { 335 DO_EVENT_TRAP(&entry->TargetStates[i]); 336 newState = entry->TargetStates[i].DprState; 337 break; 338 } 339 } 340 341 if (newState == DprMax) { 342 // 343 // Unexpected event for this state 344 // 345 DoTraceLevelMessage( 346 m_PoxInterface->PkgPnp()->GetDriverGlobals(), 347 TRACE_LEVEL_INFORMATION, 348 TRACINGPNP, 349 "WDFDEVICE 0x%p !devobj 0x%p device power requirement state " 350 "%!FxDevicePwrRequirementStates! dropping event " 351 "%!FxDevicePwrRequirementEvents!", 352 m_PoxInterface->PkgPnp()->GetDevice()->GetHandle(), 353 m_PoxInterface->PkgPnp()->GetDevice()->GetDeviceObject(), 354 m_CurrentState, 355 event 356 ); 357 358 COVERAGE_TRAP(); 359 } 360 361 while (newState != DprMax) { 362 DoTraceLevelMessage( 363 m_PoxInterface->PkgPnp()->GetDriverGlobals(), 364 TRACE_LEVEL_INFORMATION, 365 TRACINGPNPPOWERSTATES, 366 "WDFDEVICE 0x%p !devobj 0x%p entering device power requirement " 367 "state %!FxDevicePwrRequirementStates! from " 368 "%!FxDevicePwrRequirementStates!", 369 m_PoxInterface->PkgPnp()->GetDevice()->GetHandle(), 370 m_PoxInterface->PkgPnp()->GetDevice()->GetDeviceObject(), 371 newState, 372 m_CurrentState 373 ); 374 375 // 376 // Update the state history array 377 // 378 m_States.History[IncrementHistoryIndex()] = (UCHAR) newState; 379 380 // 381 // Move to the new state 382 // 383 m_CurrentState = (BYTE) newState; 384 entry = &m_StateTable[m_CurrentState-DprUnregistered]; 385 386 // 387 // Invoke the state entry function (if present) for the new state 388 // 389 if (entry->StateFunc != NULL) { 390 newState = entry->StateFunc(this); 391 } 392 else { 393 newState = DprMax; 394 } 395 } 396 } 397 398 return; 399 } 400 401 FxDevicePwrRequirementStates 402 FxDevicePwrRequirementMachine::PowerNotRequiredD0( 403 __in FxDevicePwrRequirementMachine* This 404 ) 405 { 406 This->m_PoxInterface->PkgPnp()->PowerPolicyProcessEvent( 407 PwrPolDevicePowerNotRequired 408 ); 409 return DprMax; 410 } 411 412 FxDevicePwrRequirementStates 413 FxDevicePwrRequirementMachine::PowerRequiredDx( 414 __in FxDevicePwrRequirementMachine* This 415 ) 416 { 417 This->m_PoxInterface->PkgPnp()->PowerPolicyProcessEvent( 418 PwrPolDevicePowerRequired 419 ); 420 return DprMax; 421 } 422 423 FxDevicePwrRequirementStates 424 FxDevicePwrRequirementMachine::ReportingDevicePowerAvailable( 425 __in FxDevicePwrRequirementMachine* This 426 ) 427 { 428 This->m_PoxInterface->PoxReportDevicePoweredOn(); 429 return DprDevicePowerRequiredD0; 430 } 431