ReactOS 0.4.17-dev-1281-g065abb3
idlesm.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS USB Hub Driver
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: Idle notification state machine of a hub child device
5 * COPYRIGHT: Copyright 2026 Justin Miller <justin.miller@reactos.org>
6 */
7
8/* INCLUDES *******************************************************************/
9
10#include "usbhub3.h"
11
12/* GLOBALS ********************************************************************/
13
14/* Posts are serialized by m_PostLock, so nothing is ever left queued */
16{
17 { "Start", SmEventCompletion, FALSE },
18 { "RequestSubmitted", SmEventCompletion, FALSE },
19 { "RequestCanceled", SmEventCompletion, FALSE },
20 { "WorkItemRan", SmEventCompletion, FALSE },
21 { "ClientCallbackFinished", SmEventCompletion, FALSE },
22 { "PoweredUp", SmEventCompletion, FALSE },
23 { "PoweringDown", SmEventCompletion, FALSE },
24 { "Cleanup", SmEventCompletion, FALSE },
25};
26
27static_assert(RTL_NUMBER_OF(IdleMachine::EventInfo) == static_cast<ULONG>(IdleEvent::Count),
28 "EventInfo must have one entry per IdleEvent");
29
31 { NULL, "Starting", 0, &IdleMachine::OnStarting, NULL };
32
33/* Child device exists, power changes that need no work are dropped */
35 { NULL, "Present", 0, &IdleMachine::OnPresent, NULL };
36
38 { &Present, "NoRequest", 0, &IdleMachine::OnNoRequest, NULL };
39
41 { &NoRequest, "Ready", 0, &IdleMachine::OnReady, NULL };
42
44 { &NoRequest, "SuspendUnsupported", 0, &IdleMachine::OnSuspendUnsupported, NULL };
45
46/* Request held without a callback, selective suspend is unsupported */
48 { &Present, "Parked", 0, &IdleMachine::OnParked, NULL };
49
50/* Request held on the selective suspend path */
52 { &Present, "Holding", 0, &IdleMachine::OnHolding, NULL };
53
54/* Held request is cancelable and no callback is running */
56 { &Holding, "Pending", 0, &IdleMachine::OnPending, NULL };
57
59 { &Pending, "AwaitingWorkItem", 0, &IdleMachine::OnAwaitingWorkItem, NULL };
60
62 { &Pending, "CallbackDone", 0, NULL, NULL };
63
65 { &Holding, "CallbackRunning", 0, &IdleMachine::OnCallbackRunning, NULL };
66
67/* Cancel routine owns the request, wait for it */
69 { &Holding, "AwaitingCancel", 0, &IdleMachine::OnAwaitingCancel, NULL };
70
71/* Child device cleaned up, new requests fail */
73 { NULL, "Removed", 0, &IdleMachine::OnRemoved, NULL };
74
76 { &Removed, "Gone", 0, NULL, NULL };
77
79 { &Removed, "CallbackRemoved", 0, &IdleMachine::OnCallbackRemoved, NULL };
80
82 { &Removed, "AwaitingCancelRemoved", 0, &IdleMachine::OnAwaitingCancelRemoved, NULL };
83
84/* FUNCTIONS ******************************************************************/
85
86VOID
89{
91 m_Pdo = Pdo;
93 m_NewIrp = NULL;
100
102}
103
115{
116 IDLE_FOLLOW_UP followUp;
117 PIRP finished = NULL;
118 PIRP callbackIrp = NULL;
120 BOOLEAN MustPend;
121 KIRQL irql;
122
124
125 m_NewIrp = Irp;
129
130 SmPost(Event);
131
132 followUp = m_FollowUp;
134 MustPend = m_ReturnPending;
135
136 if (followUp == FollowUpCompleteHeld)
137 {
138 finished = m_HeldIrp;
139 m_HeldIrp = NULL;
140 }
141 else if (followUp == FollowUpRejectNew)
142 {
143 finished = Irp;
144 }
145 else if (followUp == FollowUpCallback)
146 {
147 callbackIrp = m_HeldIrp;
148 }
149
150 m_NewIrp = NULL;
152
153 if (followUp == FollowUpCallback)
154 {
155 InvokeIdleCallback(callbackIrp);
156 Post(IdleEvent::ClientCallbackFinished, NULL);
157 }
158 else if (followUp == FollowUpWorkItem)
159 {
161 }
162
163 if (finished != NULL)
164 CompleteIdleRequest(finished, status);
165
166 return MustPend ? STATUS_PENDING : status;
167}
168
169/* Complete the held request once the lock is dropped */
170VOID
173{
176}
177
178/* Complete the request of this post once the lock is dropped */
179VOID
182{
185}
186
187VOID
189{
191
194}
195
196/* Take the cancel routine back and complete, or wait for the cancel */
200{
203
205 return SmTransition(&Ready);
206}
207
210{
213
215 return SmTransition(&Gone);
216}
217
218/* The first power change or cancel seen during the callback picks the outcome */
221{
223
224 if (m_PowerChange == PowerUp)
226 else if (m_PowerChange == PowerDown)
228 else
230
231 if (m_CancelSeen)
232 {
234 return SmTransition(&Ready);
235 }
236
238 return SmTransition(&CallbackDone);
239
240 return Release(status);
241}
242
246{
247 if (Event != IdleEvent::Start)
248 return SmUnhandled();
249
252}
253
257{
258 if (Event == IdleEvent::PoweredUp || Event == IdleEvent::PoweringDown)
259 return SmHandled();
260
261 return SmUnhandled();
262}
263
267{
268 if (Event == IdleEvent::Cleanup)
269 return SmTransition(&Gone);
270
271 return SmUnhandled();
272}
273
277{
278 switch (Event)
279 {
280 case IdleEvent::RequestSubmitted:
281 HoldNew();
282 if (ArmCancel(m_HeldIrp))
283 {
286 }
287
288 /* Already canceled; the IRP was marked pending, so return pending */
291 return SmHandled();
292
293 case IdleEvent::RequestCanceled:
294 case IdleEvent::WorkItemRan:
295 return SmHandled();
296
297 default:
298 return SmUnhandled();
299 }
300}
301
305{
306 if (Event != IdleEvent::RequestSubmitted)
307 return SmUnhandled();
308
309 HoldNew();
310 if (ArmCancel(m_HeldIrp))
311 return SmTransition(&Parked);
312
314 return SmHandled();
315}
316
320{
321 switch (Event)
322 {
323 case IdleEvent::RequestSubmitted:
325 return SmHandled();
326
327 case IdleEvent::RequestCanceled:
330
331 case IdleEvent::Cleanup:
332 return ReleaseForRemoval();
333
334 default:
335 return SmUnhandled();
336 }
337}
338
342{
343 switch (Event)
344 {
345 case IdleEvent::RequestSubmitted:
347 return SmHandled();
348
349 case IdleEvent::WorkItemRan:
350 return SmHandled();
351
352 default:
353 return SmUnhandled();
354 }
355}
356
360{
361 switch (Event)
362 {
363 case IdleEvent::RequestCanceled:
365 return SmTransition(&Ready);
366
367 case IdleEvent::PoweredUp:
368 return Release(STATUS_SUCCESS);
369
370 case IdleEvent::PoweringDown:
372
373 case IdleEvent::Cleanup:
374 return ReleaseForRemoval();
375
376 default:
377 return SmUnhandled();
378 }
379}
380
384{
385 if (Event != IdleEvent::WorkItemRan)
386 return SmUnhandled();
387
392}
393
397{
398 switch (Event)
399 {
400 case IdleEvent::ClientCallbackFinished:
401 return EndCallback();
402
403 case IdleEvent::PoweredUp:
404 case IdleEvent::PoweringDown:
406 m_PowerChange = (Event == IdleEvent::PoweredUp) ? PowerUp : PowerDown;
407 return SmHandled();
408
409 case IdleEvent::RequestCanceled:
410 /* A second cancel is not expected */
411 if (m_CancelSeen)
412 return SmUnhandled();
413
415 return SmHandled();
416
417 case IdleEvent::Cleanup:
419
420 default:
421 return SmUnhandled();
422 }
423}
424
428{
429 switch (Event)
430 {
431 case IdleEvent::RequestCanceled:
433 return SmTransition(&Ready);
434
435 case IdleEvent::Cleanup:
437
438 default:
439 return SmUnhandled();
440 }
441}
442
446{
447 switch (Event)
448 {
449 case IdleEvent::RequestSubmitted:
451 return SmHandled();
452
453 case IdleEvent::RequestCanceled:
454 case IdleEvent::WorkItemRan:
455 return SmHandled();
456
457 default:
458 return SmUnhandled();
459 }
460}
461
462/* The held request is left as is, the same as the previous machine */
466{
467 if (Event == IdleEvent::ClientCallbackFinished)
468 return SmTransition(&Gone);
469
470 return SmUnhandled();
471}
472
476{
477 if (Event != IdleEvent::RequestCanceled)
478 return SmUnhandled();
479
481 return SmTransition(&Gone);
482}
#define RTL_NUMBER_OF(x)
Definition: RtlRegistry.c:12
unsigned char BOOLEAN
Definition: actypes.h:127
LONG NTSTATUS
Definition: precomp.h:26
_In_ BOOLEAN Release
Definition: cdrom.h:920
static const State AwaitingCancelRemoved
Definition: idlesm.h:105
static const SM_EVENT_INFO EventInfo[]
Definition: idlesm.h:70
SM_RESULT EndCallback()
Definition: idlesm.cpp:220
NTSTATUS m_FollowUpStatus
Definition: idlesm.h:197
SM_RESULT OnCallbackRunning(_In_ IdleEvent Event)
Definition: idlesm.cpp:395
VOID HoldNew()
Definition: idlesm.cpp:188
BOOLEAN m_CancelSeen
Definition: idlesm.h:202
PIRP m_HeldIrp
Definition: idlesm.h:195
BOOLEAN m_SuspendSupported
Definition: idlesm.h:201
IDLE_POWER_CHANGE m_PowerChange
Definition: idlesm.h:199
static const State CallbackRemoved
Definition: idlesm.h:104
BOOLEAN DisarmCancel(_In_ PIRP Irp)
Definition: suspend.cpp:126
SM_RESULT OnSuspendUnsupported(_In_ IdleEvent Event)
Definition: idlesm.cpp:303
static const State AwaitingCancel
Definition: idlesm.h:101
static const State Holding
Definition: idlesm.h:96
SM_RESULT Release(_In_ NTSTATUS Status)
Definition: idlesm.cpp:198
SM_RESULT OnAwaitingCancelRemoved(_In_ IdleEvent Event)
Definition: idlesm.cpp:474
VOID Initialize(_In_ HubPdo *Pdo)
Definition: idlesm.cpp:87
NTSTATUS Post(_In_ IdleEvent Event, _In_opt_ PIRP Irp)
Irp is the new idle IRP for RequestSubmitted, else NULL.
Definition: idlesm.cpp:112
static const State Pending
Definition: idlesm.h:97
static const State Gone
Definition: idlesm.h:103
BOOLEAN m_ReturnPending
Definition: idlesm.h:200
SM_RESULT OnAwaitingWorkItem(_In_ IdleEvent Event)
Definition: idlesm.cpp:382
SM_RESULT OnStarting(_In_ IdleEvent Event)
Definition: idlesm.cpp:244
SM_RESULT OnRemoved(_In_ IdleEvent Event)
Definition: idlesm.cpp:444
HubPdo * Pdo() const
Definition: idlesm.h:58
VOID QueueIdleWorkItem()
Definition: suspend.cpp:134
SM_RESULT OnCallbackRemoved(_In_ IdleEvent Event)
Definition: idlesm.cpp:464
IDLE_FOLLOW_UP
Definition: idlesm.h:74
@ FollowUpCompleteHeld
Definition: idlesm.h:76
@ FollowUpNone
Definition: idlesm.h:75
@ FollowUpCallback
Definition: idlesm.h:78
@ FollowUpRejectNew
Definition: idlesm.h:77
@ FollowUpWorkItem
Definition: idlesm.h:79
BOOLEAN SelectiveSuspendSupported()
Definition: suspend.cpp:88
static const State Parked
Definition: idlesm.h:95
static const State CallbackDone
Definition: idlesm.h:99
SM_RESULT OnPresent(_In_ IdleEvent Event)
Definition: idlesm.cpp:255
SM_RESULT ReleaseForRemoval()
Definition: idlesm.cpp:209
PIRP m_NewIrp
Definition: idlesm.h:196
VOID FinishHeld(_In_ NTSTATUS Status)
Definition: idlesm.cpp:171
IDLE_FOLLOW_UP m_FollowUp
Definition: idlesm.h:198
SM_RESULT OnPending(_In_ IdleEvent Event)
Definition: idlesm.cpp:358
VOID CompleteIdleRequest(_In_ PIRP Irp, _In_ NTSTATUS Status)
Definition: suspend.cpp:152
static const State CallbackRunning
Definition: idlesm.h:100
VOID MarkRequestPending(_In_ PIRP Irp)
Definition: suspend.cpp:100
VOID RejectNew(_In_ NTSTATUS Status)
Definition: idlesm.cpp:180
BOOLEAN ArmCancel(_In_ PIRP Irp)
Definition: suspend.cpp:108
SM_RESULT OnParked(_In_ IdleEvent Event)
Definition: idlesm.cpp:318
SM_RESULT OnAwaitingCancel(_In_ IdleEvent Event)
Definition: idlesm.cpp:426
SM_RESULT OnReady(_In_ IdleEvent Event)
Definition: idlesm.cpp:275
static const State Present
Definition: idlesm.h:91
static const State SuspendUnsupported
Definition: idlesm.h:94
static const State Removed
Definition: idlesm.h:102
@ PowerUp
Definition: idlesm.h:85
@ PowerUnchanged
Definition: idlesm.h:84
@ PowerDown
Definition: idlesm.h:86
SM_RESULT OnNoRequest(_In_ IdleEvent Event)
Definition: idlesm.cpp:265
static const State Ready
Definition: idlesm.h:93
VOID InvokeIdleCallback(_In_ PIRP Irp)
Definition: suspend.cpp:140
HubPdo * m_Pdo
Definition: idlesm.h:194
KSPIN_LOCK m_PostLock
Definition: idlesm.h:193
static const State Starting
Definition: idlesm.h:90
SM_RESULT OnHolding(_In_ IdleEvent Event)
Definition: idlesm.cpp:340
static const State NoRequest
Definition: idlesm.h:92
static const State AwaitingWorkItem
Definition: idlesm.h:98
VOID SmInitialize(_In_ const State *Initial)
Definition: smengine.h:349
static SM_RESULT SmTransition(_In_ const State *Target)
Definition: smengine.h:194
static SM_RESULT SmHandled()
Definition: smengine.h:182
static SM_RESULT SmUnhandled()
Definition: smengine.h:188
BOOLEAN SmPost(_In_ IdleEvent Ev)
Definition: smengine.h:370
_Check_return_ _In_ DXGK_EVENT_TYPE _In_ ULONG Event
Definition: dispmprt.h:1287
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
KIRQL irql
Definition: wave.h:1
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
#define KeInitializeSpinLock(sl)
Definition: env_spec_w32.h:604
@ Removed
Definition: fbtusb.h:86
@ Pending
Definition: fs_rec.h:186
Status
Definition: gdiplustypes.h:24
_In_ PCWSTR _Out_ PULONG _Out_ PBOOLEAN Present
_In_ UCXUSBDEVICE _In_ PDEVICE_OBJECT Pdo
Definition: hubucx.h:280
IdleEvent
Definition: idlesm.h:15
_In_ PIRP Irp
Definition: kse.h:79
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
#define STATUS_POWER_STATE_INVALID
Definition: ntstatus.h:957
#define STATUS_SUCCESS
Definition: shellext.h:65
@ SmEventCompletion
Definition: smengine.h:24
One state. Handler gets every event the state sees.
Definition: smengine.h:93
Definition: ps.c:97
#define STATUS_PENDING
Definition: telnetd.h:14
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_NO_SUCH_DEVICE
Definition: udferr_usr.h:136
#define STATUS_DEVICE_BUSY
Definition: udferr_usr.h:129
#define STATUS_CANCELLED
Definition: udferr_usr.h:170
#define NT_ASSERT
Definition: rtlfuncs.h:3334