ReactOS  0.4.15-dev-3187-ge372f2b
wakeinterruptstatemachine.cpp
Go to the documentation of this file.
1 /*++
2 Copyright (c) Microsoft. All rights reserved.
3 
4 Module Name:
5 
6  WakeInterrupt.cpp
7 
8 Abstract:
9 
10  This module implements the wake interrupt logic in the framework.
11 
12 --*/
13 
14 #include "pnppriv.hpp"
15 
16 extern "C" {
17 #if defined(EVENT_TRACING)
18 #include "WakeInterruptStateMachine.tmh"
19 #endif
20 }
21 
24 {
26 };
27 
30 {
34 };
35 
38 {
42 };
43 
46 {
50 };
51 
54 {
57 };
58 
59 
62 {
63  // WakeInterruptFailed
67  },
68 
69  // WakeInterruptD0
70  { NULL,
73  },
74 
75  // WakeInterruptDx
79  },
80 
81  // WakeInterruptWaking
85  },
86 
87  // WakeInterruptInvokingEvtIsrPostWakeStates
89  NULL,
90  0,
91  },
92 
93  // WakeInterruptCompletingD0States
95  NULL,
96  0,
97  },
98 
99  // WakeInterruptInvokingEvtIsrInD0
101  NULL,
102  0,
103  },
104 
105  // WakeInterruptDxNotArmedForWake
109  },
110 
111  // WakeInterruptInvokingEvtIsrInDxNotArmedForWake
113  NULL,
114  0,
115  },
116 };
117 
121 {
122  //
123  // Make sure we can fit the state into a byte
124  //
125  C_ASSERT(WakeInterruptMax <= 0xFF);
126 
128 
129  RtlZeroMemory(&m_Queue, sizeof(m_Queue));
130  RtlZeroMemory(&m_States, sizeof(m_States));
131 
132  //
133  // Store the initial state in the state history array
134  //
137 }
138 
139 VOID
142  )
143 {
145  KIRQL irql;
146  LONGLONG timeout = 0;
147 
148  //
149  // Acquire state machine *queue* lock, raising to DISPATCH_LEVEL
150  //
151  Lock(&irql);
152 
153  if (IsFull()) {
154  //
155  // The queue is full. This should never happen.
156  //
157  Unlock(irql);
158 
159  ASSERTMSG("The wake interrupt state machine queue is full\n",
160  FALSE);
161  return;
162  }
163 
164  if (IsClosedLocked()) {
165  //
166  // The queue is closed. This should never happen.
167  //
170  "WDFDEVICE 0x%p !devobj 0x%p current wake interrupt state"
171  " %!FxWakeInterruptStates! dropping event "
172  "%!FxWakeInterruptEvents! because of a closed queue",
176  Event);
177 
178  Unlock(irql);
179 
180  ASSERTMSG(
181  "The wake interrupt state machine queue is closed\n",
182  FALSE
183  );
184  return;
185  }
186 
187  //
188  // Enqueue the event
189  //
191 
192  //
193  // Drop the state machine *queue* lock
194  //
195  Unlock(irql);
196 
197  //
198  // Now, if we are running at PASSIVE_LEVEL, attempt to run the state machine
199  // on this thread. If we can't do that, then queue a work item.
200  //
201  if (irql == PASSIVE_LEVEL) {
202  //
203  // Try to acquire the state machine lock
204  //
205  status = m_StateMachineLock.AcquireLock(
207  &timeout
208  );
209  if (FxWaitLockInternal::IsLockAcquired(status)) {
211 
212  //
213  // We now hold the state machine lock. So call the function that
214  // dispatches the next state.
215  //
217 
218  //
219  // The pnp state machine should be the only one deleting the object
220  //
221  ASSERT(info.m_DeleteObject == FALSE);
222 
223  //
224  // Release the state machine lock
225  //
226  m_StateMachineLock.ReleaseLock(
228  );
229 
230  info.Evaluate(m_PkgPnp);
231 
232  return;
233  }
234  }
235 
236  //
237  // For one reason or another, we couldn't run the state machine on this
238  // thread. So queue a work item to do it.
239  //
240  QueueToThread();
241  return;
242 }
243 
244 VOID
246  __inout FxPkgPnp* PkgPnp,
248  __in PVOID WorkerContext
249  )
250 {
251 
252  UNREFERENCED_PARAMETER(PkgPnp);
253 
254  FxWakeInterruptMachine * pThis = (FxWakeInterruptMachine *) WorkerContext;
255 
256  //
257  // Take the state machine lock.
258  //
259  pThis->m_StateMachineLock.AcquireLock(
260  pThis->m_PkgPnp->GetDriverGlobals()
261  );
262 
263  //
264  // Call the function that will actually run the state machine.
265  //
266  pThis->ProcessEventInner(Info);
267 
268  //
269  // We are being called from the work item and m_WorkItemRunning is > 0, so
270  // we cannot be deleted yet.
271  //
272  ASSERT(Info->SomethingToDo() == FALSE);
273 
274  //
275  // Now release the state machine lock
276  //
277  pThis->m_StateMachineLock.ReleaseLock(
278  pThis->m_PkgPnp->GetDriverGlobals()
279  );
280 
281  return;
282 }
283 
284 VOID
287  )
288 {
289  KIRQL irql;
292  FxWakeInterruptStates newState;
293 
294  //
295  // Process as many events as we can
296  //
297  for ( ; ; ) {
298  //
299  // Acquire state machine *queue* lock
300  //
301  Lock(&irql);
302 
303  if (IsEmpty()) {
304  //
305  // The queue is empty.
306  //
308  Unlock(irql);
309  return;
310  }
311 
312  //
313  // Get the event from the queue
314  //
315  event = m_Queue[GetHead()];
316  IncrementHead();
317 
318  //
319  // Drop the state machine *queue* lock
320  //
321  Unlock(irql);
322 
323  //
324  // Get the state table entry for the current state
325  //
326  // NOTE: Prefast complains about buffer overflow if (m_CurrentState ==
327  // WakeInterruptMax), but that should never happen because WakeInterruptMax is not a real
328  // state. We just use it to represent the maximum value in the enum that
329  // defines the states.
330  //
333 
334  //
335  // Based on the event received, figure out the next state
336  //
337  newState = WakeInterruptMax;
338  for (ULONG i = 0; i < entry->TargetStatesCount; i++) {
339  if (entry->TargetStates[i].WakeInterruptEvent == event) {
340  DO_EVENT_TRAP(&entry->TargetStates[i]);
341  newState = entry->TargetStates[i].WakeInterruptState;
342  break;
343  }
344  }
345 
346  if (newState == WakeInterruptMax) {
347  //
348  // Unexpected event for this state
349  //
353  TRACINGPNP,
354  "WDFDEVICE 0x%p !devobj 0x%p wake interrupt state "
355  "%!FxWakeInterruptStates! dropping event "
356  "%!FxWakeInterruptEvents!",
360  event
361  );
362 
363  COVERAGE_TRAP();
364  }
365 
366  while (newState != WakeInterruptMax) {
371  "WDFDEVICE 0x%p !devobj 0x%p entering wake interrupt "
372  "state %!FxWakeInterruptStates! from "
373  "%!FxWakeInterruptStates!",
376  newState,
378  );
379 
380  //
381  // Update the state history array
382  //
384 
385  //
386  // Move to the new state
387  //
388  m_CurrentState = (BYTE) newState;
390 
391  //
392  // Invoke the state entry function (if present) for the new state
393  //
394  if (entry->StateFunc != NULL) {
395  newState = entry->StateFunc(this);
396  }
397  else {
398  newState = WakeInterruptMax;
399  }
400  }
401  }
402 
403  return;
404 }
405 
406 
410  )
411 {
412  This->m_PkgPnp->PowerPolicyProcessEvent(PwrPolWakeInterruptFired);
413 
414  return WakeInterruptMax;
415 }
416 
420  )
421 {
422  //
423  // Flush queued callbacks so that we know that nobody is still trying to
424  // synchronize against this interrupt. For KMDF this will flush DPCs and
425  // for UMDF this will send a message to reflector to flush queued DPCs.
426  //
427  This->m_Interrupt->FlushQueuedDpcs();
428 
429 #if FX_IS_KERNEL_MODE
430  //
431  // Rundown the workitem if present (passive-level interrupt support or KMDF).
432  // Not needed for UMDF since reflector doesn't use workitem for isr.
433  //
434  This->m_Interrupt->FlushQueuedWorkitem();
435 
436 #endif
437 
438  This->m_PkgPnp->AckPendingWakeInterruptOperation(FALSE);
439 
440  return WakeInterruptMax;
441 }
442 
446  )
447 {
448  //
449  // Ask power state machine to process the acknowledgement event
450  // on a different thread as we could be running the state machine's
451  // engine in the context of a wake ISR, and the power
452  // state machine will attempt to disconnect this interrupt when
453  // it processes the acknowledgement event.
454  //
455  This->m_PkgPnp->AckPendingWakeInterruptOperation(TRUE);
456 
457  return WakeInterruptMax;
458 }
459 
460 
464  )
465 {
466  This->m_Interrupt->InvokeWakeInterruptEvtIsr();
467 
468  This->m_IsrEvent.Set();
469 
471 }
472 
476  )
477 {
478  This->m_Interrupt->InvokeWakeInterruptEvtIsr();
479 
480  This->m_IsrEvent.Set();
481 
483 }
484 
488  )
489 {
490  This->m_PkgPnp->AckPendingWakeInterruptOperation(FALSE);
491 
492  return WakeInterruptD0;
493 }
494 
498  )
499 {
500  This->m_Interrupt->InvokeWakeInterruptEvtIsr();
501 
502  This->m_IsrEvent.Set();
503 
504  return WakeInterruptD0;
505 }
506 
510  )
511 {
512  //
513  // Device failed to power up and we are not invoking the
514  // client driver's callback. So we cannot claim the
515  // interrupt
516  //
517  This->m_Claimed = FALSE;
518 
519  This->m_IsrEvent.Set();
520 
521  return WakeInterruptMax;
522 }
523 
524 
UCHAR GetHead(VOID)
__inline CfxDevice * GetDevice(VOID)
Definition: fxpackage.hpp:46
MdDeviceObject __inline GetDeviceObject(VOID)
Definition: fxdevice.hpp:174
const UCHAR FxWakeInterruptEventQueueDepth
#define TRUE
Definition: types.h:120
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
WDFDEVICE __inline GetHandle(VOID)
Definition: fxdevice.hpp:237
static FxWakeInterruptStates CompletingD0(__in FxWakeInterruptMachine *This)
static const FxWakeInterruptTargetState m_FailedStates[]
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_INTERRUPT_CONFIG _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFINTERRUPT * Interrupt
Definition: wdfinterrupt.h:372
#define __analysis_assume(expr)
Definition: ms_sal.h:2893
LONG NTSTATUS
Definition: precomp.h:26
static FxWakeInterruptStates Waking(__in FxWakeInterruptMachine *This)
FxWakeInterruptEvents m_Queue[FxWakeInterruptEventQueueDepth]
KIRQL irql
Definition: wave.h:1
Definition: dhcpd.h:245
static const FxWakeInterruptTargetState m_D0States[]
UCHAR IncrementHistoryIndex(VOID)
#define TRACE_LEVEL_INFORMATION
Definition: storswtr.h:29
static FxWakeInterruptStates Dx(__in FxWakeInterruptMachine *This)
#define TRACINGPNPPOWERSTATES
Definition: dbgtrace.h:69
GLbitfield GLuint64 timeout
Definition: glext.h:7164
_Must_inspect_result_ _In_ WDFCHILDLIST _In_ PWDF_CHILD_LIST_ITERATOR _Out_ WDFDEVICE _Inout_opt_ PWDF_CHILD_RETRIEVE_INFO Info
Definition: wdfchildlist.h:683
UCHAR KIRQL
Definition: env_spec_w32.h:591
BOOLEAN IsFull(VOID)
VOID IncrementHead(VOID)
#define FALSE
Definition: types.h:117
#define ASSERTMSG(msg, exp)
Definition: nt_native.h:431
_In_ PVOID _In_ ULONG Event
Definition: iotypes.h:467
#define DO_EVENT_TRAP(x)
Definition: fxpkgpnp.hpp:61
static const FxWakeInterruptTargetState m_DxStates[]
#define COVERAGE_TRAP()
Definition: fxmacros.hpp:246
#define C_ASSERT(e)
Definition: intsafe.h:73
FxPkgPnp * m_PkgPnp
VOID ProcessEvent(__in FxWakeInterruptEvents Event)
UCHAR History[FxWakeInterruptEventQueueDepth]
int64_t LONGLONG
Definition: typedefs.h:68
UCHAR InsertAtTail(VOID)
#define ASSERT(a)
Definition: mode.c:44
static const FxWakeInterruptTargetState m_DxNotArmedForWakeStates[]
struct _test_info info[]
Definition: SetCursorPos.c:19
unsigned char UCHAR
Definition: xmlstorage.h:181
uint32_t entry
Definition: isohybrid.c:63
static FxWakeInterruptStates InvokingEvtIsrInD0(__in FxWakeInterruptMachine *This)
#define DEBUGGED_EVENT
Definition: fxpkgpnp.hpp:59
static FxWakeInterruptStates Failed(__in FxWakeInterruptMachine *This)
#define __inout
Definition: dbghelp.h:50
struct _cl_event * event
Definition: glext.h:7739
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
BOOLEAN IsClosedLocked(VOID)
unsigned char BYTE
Definition: xxhash.c:193
FxWakeInterruptMachine(__in FxInterrupt *Interrupt)
VOID GetFinishedState(__inout FxPostProcessInfo *Info)
#define TRACINGPNP
Definition: dbgtrace.h:67
static FxWakeInterruptStates InvokingEvtIsrPostWake(__in FxWakeInterruptMachine *This)
__inline PFX_DRIVER_GLOBALS GetDriverGlobals(VOID)
Definition: fxobject.hpp:734
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
BOOLEAN IsEmpty(VOID)
#define ARRAY_SIZE(a)
Definition: main.h:24
static VOID _ProcessEventInner(__inout FxPkgPnp *PkgPnp, __inout FxPostProcessInfo *Info, __in PVOID WorkerContext)
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, "Enter, WDFDEVICE %p", Device)
#define NULL
Definition: types.h:112
static const FxWakeInterruptStateTable m_StateTable[]
FxWakeInterruptMachineStateHistory m_States
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWAITLOCK * Lock
Definition: wdfsync.h:124
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
VOID ProcessEventInner(__inout FxPostProcessInfo *Info)
#define __in
Definition: dbghelp.h:35
static SERVICE_STATUS status
Definition: service.c:31
static FxWakeInterruptStates InvokingEvtIsrInDxNotArmedForWake(__in FxWakeInterruptMachine *This)
static FxWakeInterruptStates DxNotArmedForWake(__in FxWakeInterruptMachine *This)
FxWaitLockInternal m_StateMachineLock
Definition: ps.c:97
static const FxWakeInterruptTargetState m_WakingStates[]