1 /*++
2 Copyright (c) Microsoft. All rights reserved.
3
4 Module Name:
5
6 SelfManagedIoStateMachine.cpp
7
8 Abstract:
9
10 This module implements the self managed io state machine start / stop logic
11 in the framework.
12
13 Author:
14
15
16
17 Environment:
18 Both kernel and user mode
19
20 Revision History:
21
22
23
24 --*/
25
26 #include "pnppriv.hpp"
27
28 extern "C" {
29 #if defined(EVENT_TRACING)
30 #include "SelfManagedIoStateMachine.tmh"
31 #endif
32 }
33
34 // * - We can get a restart from the created state if a PDO is newly enumerated
35 // but was disabled on a previous enumeration. Treat restart as an init
36 // in this case.
37 const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_CreatedStates[] =
38 {
39 { SelfManagedIoEventStart, FxSelfManagedIoInit DEBUGGED_EVENT },
40 { SelfManagedIoEventFlush, FxSelfManagedIoCreated DEBUGGED_EVENT },
41 { SelfManagedIoEventCleanup, FxSelfManagedIoFinal DEBUGGED_EVENT },
42 };
43
44 const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_InitFailedStates[] =
45 {
46 { SelfManagedIoEventSuspend, FxSelfManagedIoInitFailed DEBUGGED_EVENT },
47 { SelfManagedIoEventFlush, FxSelfManagedIoFlushing DEBUGGED_EVENT },
48 };
49
50 const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_StartedStates[] =
51 {
52 { SelfManagedIoEventSuspend, FxSelfManagedIoSuspending DEBUGGED_EVENT },
53 };
54
55 const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_StoppedStates[] =
56 {
57 { SelfManagedIoEventStart, FxSelfManagedIoRestarting DEBUGGED_EVENT },
58 { SelfManagedIoEventSuspend, FxSelfManagedIoStopped DEBUGGED_EVENT },
59 { SelfManagedIoEventFlush, FxSelfManagedIoFlushing DEBUGGED_EVENT },
60 };
61
62 const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_FailedStates[] =
63 {
64 { SelfManagedIoEventFlush, FxSelfManagedIoFlushing DEBUGGED_EVENT },
65 { SelfManagedIoEventSuspend, FxSelfManagedIoFailed DEBUGGED_EVENT },
66 };
67
68 const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_FlushedStates[] =
69 {
70 { SelfManagedIoEventStart, FxSelfManagedIoRestarting DEBUGGED_EVENT },
71 { SelfManagedIoEventCleanup, FxSelfManagedIoCleanup DEBUGGED_EVENT },
72 { SelfManagedIoEventFlush, FxSelfManagedIoFlushed TRAP_ON_EVENT },
73 };
74
75 const FxSelfManagedIoStateTable FxSelfManagedIoMachine::m_StateTable[] =
76 {
77 // FxSelfManagedIoCreated
78 { NULL,
79 FxSelfManagedIoMachine::m_CreatedStates,
80 ARRAY_SIZE(FxSelfManagedIoMachine::m_CreatedStates),
81 },
82
83 // FxSelfManagedIoInit
84 { FxSelfManagedIoMachine::Init,
85 NULL,
86 0,
87 },
88
89 // FxSelfManagedIoInitFailed
90 { NULL,
91 FxSelfManagedIoMachine::m_InitFailedStates,
92 ARRAY_SIZE(FxSelfManagedIoMachine::m_InitFailedStates),
93 },
94
95 // FxSelfManagedIoStarted
96 { NULL,
97 FxSelfManagedIoMachine::m_StartedStates,
98 ARRAY_SIZE(FxSelfManagedIoMachine::m_StartedStates),
99 },
100
101 // FxSelfManagedIoSuspending
102 { FxSelfManagedIoMachine::Suspending,
103 NULL,
104 0,
105 },
106
107 // FxSelfManagedIoStopped
108 { NULL,
109 FxSelfManagedIoMachine::m_StoppedStates,
110 ARRAY_SIZE(FxSelfManagedIoMachine::m_StoppedStates),
111 },
112
113 // FxSelfManagedIoRestarting
114 { FxSelfManagedIoMachine::Restarting,
115 NULL,
116 0,
117 },
118
119 // FxSelfManagedIoFailed
120 { NULL,
121 FxSelfManagedIoMachine::m_FailedStates,
122 ARRAY_SIZE(FxSelfManagedIoMachine::m_FailedStates),
123 },
124
125 // FxSelfManagedIoFlushing
126 { FxSelfManagedIoMachine::Flushing,
127 NULL,
128 0,
129 },
130
131 // FxSelfManagedIoFlushed
132 { NULL,
133 FxSelfManagedIoMachine::m_FlushedStates,
134 ARRAY_SIZE(FxSelfManagedIoMachine::m_FlushedStates),
135 },
136
137 // FxSelfManagedIoCleanup
138 { FxSelfManagedIoMachine::Cleanup,
139 NULL,
140 0,
141 },
142
143 // FxSelfManagedIoFinal
144 { NULL,
145 NULL,
146 0,
147 },
148 };
149
FxSelfManagedIoMachine(__in FxPkgPnp * PkgPnp)150 FxSelfManagedIoMachine::FxSelfManagedIoMachine(
151 __in FxPkgPnp* PkgPnp
152 )
153 {
154 m_PkgPnp = PkgPnp;
155
156 m_EventHistoryIndex = 0;
157 m_StateHistoryIndex = 0;
158
159 m_CurrentState = FxSelfManagedIoCreated;
160
161 RtlZeroMemory(&m_Events, sizeof(m_Events));
162 RtlZeroMemory(&m_States, sizeof(m_States));
163
164 //
165 // Make sure we can fit the state into a byte
166 //
167 ASSERT(FxSelfManagedIoMax <= 0xFF);
168 }
169
170 NTSTATUS
_CreateAndInit(__deref_out FxSelfManagedIoMachine ** SelfManagedIoMachine,__in FxPkgPnp * PkgPnp)171 FxSelfManagedIoMachine::_CreateAndInit(
172 __deref_out FxSelfManagedIoMachine** SelfManagedIoMachine,
173 __in FxPkgPnp* PkgPnp
174 )
175 {
176 NTSTATUS status;
177 FxSelfManagedIoMachine * selfManagedIoMachine;
178
179 *SelfManagedIoMachine = NULL;
180
181 selfManagedIoMachine = new (PkgPnp->GetDriverGlobals()) FxSelfManagedIoMachine(
182 PkgPnp
183 );
184
185 if (selfManagedIoMachine == NULL) {
186 DoTraceLevelMessage(
187 PkgPnp->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
188 "Self managed I/O state machine allocation failed for "
189 "WDFDEVICE 0x%p",
190 PkgPnp->GetDevice()->GetHandle());
191
192 return STATUS_INSUFFICIENT_RESOURCES;
193 }
194
195 status = selfManagedIoMachine->m_StateMachineLock.Initialize();
196 if (!NT_SUCCESS(status)) {
197 DoTraceLevelMessage(
198 PkgPnp->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
199 "Self managed I/O state machine lock initialization failed for "
200 "WDFDEVICE 0x%p, %!STATUS!",
201 PkgPnp->GetDevice()->GetHandle(),
202 status);
203
204 delete selfManagedIoMachine;
205
206 return status;
207 }
208
209 *SelfManagedIoMachine = selfManagedIoMachine;
210
211 return status;
212 }
213
214
215 VOID
InitializeMachine(__in PWDF_PNPPOWER_EVENT_CALLBACKS Callbacks)216 FxSelfManagedIoMachine::InitializeMachine(
217 __in PWDF_PNPPOWER_EVENT_CALLBACKS Callbacks
218 )
219 /*++
220
221 Routine Description:
222 Sets all the function event callbacks.
223
224 Arguments:
225 Callbacks - list of callbacks to set
226
227 Return Value:
228 None
229
230 --*/
231 {
232 m_DeviceSelfManagedIoCleanup.m_Method = Callbacks->EvtDeviceSelfManagedIoCleanup;
233 m_DeviceSelfManagedIoFlush.m_Method = Callbacks->EvtDeviceSelfManagedIoFlush;
234 m_DeviceSelfManagedIoInit.m_Method = Callbacks->EvtDeviceSelfManagedIoInit;
235 m_DeviceSelfManagedIoSuspend.m_Method = Callbacks->EvtDeviceSelfManagedIoSuspend;
236 m_DeviceSelfManagedIoRestart.m_Method = Callbacks->EvtDeviceSelfManagedIoRestart;
237 }
238
239 WDFDEVICE
GetDeviceHandle(VOID)240 FxSelfManagedIoMachine::GetDeviceHandle(
241 VOID
242 )
243 {
244 return m_PkgPnp->GetDevice()->GetHandle();
245 }
246
247 _Must_inspect_result_
248 NTSTATUS
ProcessEvent(__in FxSelfManagedIoEvents Event)249 FxSelfManagedIoMachine::ProcessEvent(
250 __in FxSelfManagedIoEvents Event
251 )
252 /*++
253
254 Routine Description:
255 Processes an event and runs it through the state machine. Unlike other
256 state machines in the framework, this one acquires lock in the event
257 processing function rather then relying on the caller to do so.
258
259 Arguments:
260 Event - The event to feed into the state machine.
261
262 Return Value:
263 result of the event
264
265 --*/
266 {
267 const FxSelfManagedIoStateTable* entry;
268 FxSelfManagedIoStates newState;
269 NTSTATUS status;
270
271 m_StateMachineLock.AcquireLock(m_PkgPnp->GetDriverGlobals());
272
273 m_Events.History[m_EventHistoryIndex] = (UCHAR) Event;
274 m_EventHistoryIndex = (m_EventHistoryIndex + 1) %
275 (sizeof(m_Events.History)/sizeof(m_Events.History[0]));
276
277 entry = &m_StateTable[m_CurrentState-FxSelfManagedIoCreated];
278 newState = FxSelfManagedIoMax;
279
280 for (ULONG i = 0; i < entry->TargetStatesCount; i++) {
281 if (entry->TargetStates[i].SelfManagedIoEvent == Event) {
282 DO_EVENT_TRAP(&entry->TargetStates[i]);
283 newState = entry->TargetStates[i].SelfManagedIoState;
284 break;
285 }
286 }
287
288 if (newState == FxSelfManagedIoMax) {
289 //
290 // We always can handle io increment/decrement from any state, but we
291 // should not be dropping any other events from this state.
292 //
293
294 COVERAGE_TRAP();
295 }
296
297 status = STATUS_SUCCESS;
298
299 while (newState != FxSelfManagedIoMax) {
300 DoTraceLevelMessage(
301 m_PkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
302 "WDFDEVICE 0x%p !devobj 0x%p entering self managed io state "
303 "%!FxSelfManagedIoStates! from %!FxSelfManagedIoStates!",
304 m_PkgPnp->GetDevice()->GetHandle(),
305 m_PkgPnp->GetDevice()->GetDeviceObject(),
306 newState, m_CurrentState);
307
308 m_States.History[m_StateHistoryIndex] = (UCHAR) newState;
309 m_StateHistoryIndex = (m_StateHistoryIndex + 1) %
310 (sizeof(m_States.History)/sizeof(m_States.History[0]));
311
312 m_CurrentState = (BYTE) newState;
313 entry = &m_StateTable[m_CurrentState-FxSelfManagedIoCreated];
314
315 if (entry->StateFunc != NULL) {
316 newState = entry->StateFunc(this, &status);
317 }
318 else {
319 newState = FxSelfManagedIoMax;
320 }
321 }
322
323 m_StateMachineLock.ReleaseLock(m_PkgPnp->GetDriverGlobals());
324
325 return status;
326 }
327
328 FxSelfManagedIoStates
Init(__in FxSelfManagedIoMachine * This,__out PNTSTATUS Status)329 FxSelfManagedIoMachine::Init(
330 __in FxSelfManagedIoMachine* This,
331 __out PNTSTATUS Status
332 )
333 /*++
334
335 Routine Description:
336 Calls the event callback for initializing self managed io.
337
338 Arguments:
339 This - instance of the state machine
340
341 Status - result of the event callback into the driver
342
343 Return Value:
344 new machine state
345
346 --*/
347 {
348 *Status = This->m_DeviceSelfManagedIoInit.Invoke(This->GetDeviceHandle());
349
350 if (NT_SUCCESS(*Status)) {
351 return FxSelfManagedIoStarted;
352 }
353 else {
354 return FxSelfManagedIoInitFailed;
355 }
356 }
357
358 FxSelfManagedIoStates
Suspending(__in FxSelfManagedIoMachine * This,__out PNTSTATUS Status)359 FxSelfManagedIoMachine::Suspending(
360 __in FxSelfManagedIoMachine* This,
361 __out PNTSTATUS Status
362 )
363 /*++
364
365 Routine Description:
366 Invokes the self managed io suspend event callback. Upon failure goes to
367 the failed state and awaits teardown of the stack.
368
369 Arguments:
370 This - instance of the state machine
371
372 Status - result of the event callback into the driver
373
374 Return Value:
375 new machine state
376
377 --*/
378 {
379 *Status = This->m_DeviceSelfManagedIoSuspend.Invoke(This->GetDeviceHandle());
380
381 if (NT_SUCCESS(*Status)) {
382 return FxSelfManagedIoStopped;
383 }
384 else {
385 return FxSelfManagedIoFailed;
386 }
387 }
388
389 FxSelfManagedIoStates
Restarting(__in FxSelfManagedIoMachine * This,__out PNTSTATUS Status)390 FxSelfManagedIoMachine::Restarting(
391 __in FxSelfManagedIoMachine* This,
392 __out PNTSTATUS Status
393 )
394 /*++
395
396 Routine Description:
397 Invokes the self managed io event callback for restarting self managed io
398 from the stopped state.
399
400 Arguments:
401 This - instance of the state machine
402
403 Status - result of the event callback into the driver
404
405 Return Value:
406 new machine state
407
408 --*/
409 {
410 *Status = This->m_DeviceSelfManagedIoRestart.Invoke(This->GetDeviceHandle());
411
412 if (NT_SUCCESS(*Status)) {
413 return FxSelfManagedIoStarted;
414 }
415 else {
416 return FxSelfManagedIoFailed;
417 }
418 }
419
420 FxSelfManagedIoStates
Flushing(__in FxSelfManagedIoMachine * This,__out PNTSTATUS Status)421 FxSelfManagedIoMachine::Flushing(
422 __in FxSelfManagedIoMachine* This,
423 __out PNTSTATUS Status
424 )
425 /*++
426
427 Routine Description:
428 Calls the self managed io flush routine.
429
430 Arguments:
431 This - instance of the state machine
432
433 Status - result of the event callback into the driver
434
435 Return Value:
436 FxSelfManagedIoFlushed
437
438 --*/
439 {
440 UNREFERENCED_PARAMETER(Status);
441 This->m_DeviceSelfManagedIoFlush.Invoke(This->GetDeviceHandle());
442 return FxSelfManagedIoFlushed;
443 }
444
445 FxSelfManagedIoStates
Cleanup(__in FxSelfManagedIoMachine * This,__out PNTSTATUS Status)446 FxSelfManagedIoMachine::Cleanup(
447 __in FxSelfManagedIoMachine* This,
448 __out PNTSTATUS Status
449 )
450 /*++
451
452 Routine Description:
453 Calls the self managed io cleanup routine.
454
455 Arguments:
456 This - instance of the state machine
457
458 Status - result of the event callback into the driver
459
460 Return Value:
461 FxSelfManagedIoFinal
462
463 --*/
464 {
465 UNREFERENCED_PARAMETER(Status);
466
467 This->m_DeviceSelfManagedIoCleanup.Invoke(This->GetDeviceHandle());
468 return FxSelfManagedIoFinal;
469 }
470