ReactOS 0.4.17-dev-1281-g065abb3
epsm.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS USB Controller Extension
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: Endpoint state machine
5 * COPYRIGHT: Copyright 2026 Justin Miller <justin.miller@reactos.org>
6 */
7
8/* INCLUDES *******************************************************************/
9
10#include "ucx01000.h"
11
12/* GLOBALS ********************************************************************/
13
15{
16 { "HubStartRequest", SmEventRequest, FALSE },
17 { "HubPurge", SmEventRequest, FALSE },
18 { "HubTreePurge", SmEventRequest, FALSE },
19 { "HubAbort", SmEventRequest, FALSE },
20 { "HubDisconnect", SmEventRequest, FALSE },
21 { "HubDisable", SmEventRequest, FALSE },
22 { "HubDeviceReset", SmEventRequest, FALSE },
23 { "DeviceResetDone", SmEventRequest, FALSE },
24 { "ConfigureDone", SmEventRequest, FALSE },
25 { "HubEndpointReset", SmEventRequest, FALSE },
26 { "Delete", SmEventRequest, FALSE },
27 { "ClientAbortUrb", SmEventRequest, FALSE },
28 { "ClientStreamsEnable", SmEventRequest, FALSE },
29 { "ClientStreamsDisable", SmEventRequest, FALSE },
30 { "AbortUrbParked", SmEventCompletion, FALSE },
31 { "AbortDone", SmEventCompletion, FALSE },
32 { "PurgeDone", SmEventCompletion, FALSE },
33 { "EndpointResetDone", SmEventCompletion, FALSE },
34 { "StreamsOpened", SmEventCompletion, FALSE },
35 { "StreamsClosed", SmEventCompletion, FALSE },
36 { "ControllerResetStarting", SmEventCompletion, FALSE },
37 { "StaleReplaced", SmEventCompletion, FALSE },
38 { "ControllerResetDone", SmEventResume, FALSE },
39};
40
41static_assert(RTL_NUMBER_OF(EndpointMachine::EventInfo) == static_cast<ULONG>(EpEvent::Count),
42 "EventInfo must have one entry per EpEvent");
43
44/* Endpoint is not running on the controller, hub requests are acked as is */
47
49 { &Inactive, "Created", 0, &EndpointMachine::OnCreated, NULL };
50
52 { &Inactive, "Disabled", 0, &EndpointMachine::OnDisabled, NULL };
53
54/* Off the controller's endpoint list, so a controller reset never resumes it */
56 { &Inactive, "Retired", 0, &EndpointMachine::OnRetired, NULL };
57
59 { &Retired, "Stale", 0, &EndpointMachine::OnStale, NULL };
60
62 { &Retired, "AwaitingDestroy", 0, NULL, NULL };
63
66
67/* Waiting on a completion, a controller reset pauses the machine in place */
69 { NULL, "Busy", 0, &EndpointMachine::OnBusy, NULL };
70
73
74/* One request handed to the client driver, returns to m_ReturnTo when done */
76 { &Busy, "Operation", 0, &EndpointMachine::OnOperation, NULL };
77
79 { &Operation, "AwaitingAbortUrb", 0, &EndpointMachine::OnAwaitingAbortUrb, NULL };
80
83
85 { &Operation, "EnablingStreams", 0,
87
89 { &Operation, "DisablingStreams", 0,
91
93 { &Operation, "ResettingPipe", 0,
95
96/* Controller reset hit an operation started from Enabled */
98 { NULL, "OperationHeld", 0,
100
102 { NULL, "OperationUnwinding", 0, &EndpointMachine::OnOperationUnwinding, NULL };
103
104/* FUNCTIONS ******************************************************************/
105
106VOID
109{
117
119}
120
128{
129 if (Event == EpEvent::ClientAbortUrb)
130 return SmCurrent() == &Enabled;
131
132 return TRUE;
133}
134
135VOID
137{
139}
140
141VOID
143{
145}
146
150{
151 switch (Event)
152 {
153 case EpEvent::HubStartRequest:
154 case EpEvent::HubPurge:
155 case EpEvent::HubAbort:
156 case EpEvent::HubDeviceReset:
158 return SmHandled();
159
160 case EpEvent::HubTreePurge:
162 return SmHandled();
163
164 case EpEvent::HubDisconnect:
165 return SmHandled();
166
167 case EpEvent::ControllerResetStarting:
169
170 case EpEvent::ControllerResetDone:
171 return SmHandled();
172
173 default:
174 return SmUnhandled();
175 }
176}
177
181{
182 switch (Event)
183 {
184 case EpEvent::Delete:
185 return Retire();
186
187 case EpEvent::ConfigureDone:
188 m_Enabled = TRUE;
189 if (!CanStart())
191
193 return SmTransition(&Enabled);
194
195 case EpEvent::DeviceResetDone:
197 return SmHandled();
198
199 default:
200 return SmUnhandled();
201 }
202}
203
207{
208 switch (Event)
209 {
210 case EpEvent::Delete:
211 return Retire();
212
213 case EpEvent::HubDisable:
214 case EpEvent::HubDeviceReset:
217 return SmHandled();
218
219 case EpEvent::ConfigureDone:
220 case EpEvent::DeviceResetDone:
221 m_Enabled = TRUE;
222 return TryStart();
223
224 case EpEvent::HubStartRequest:
225 return TryStart();
226
227 case EpEvent::ClientStreamsEnable:
229
230 case EpEvent::ClientStreamsDisable:
232
233 case EpEvent::HubEndpointReset:
235
236 default:
237 return SmUnhandled();
238 }
239}
240
244{
245 if (Event == EpEvent::ControllerResetStarting)
246 {
248 return SmHandled();
249 }
250
251 return SmUnhandled();
252}
253
257{
258 if (Event == EpEvent::StaleReplaced)
259 {
262 }
263
264 return SmUnhandled();
265}
266
270{
271 switch (Event)
272 {
273 case EpEvent::ClientStreamsEnable:
275
276 case EpEvent::ClientStreamsDisable:
278
279 case EpEvent::HubEndpointReset:
281
282 case EpEvent::ClientAbortUrb:
285
286 case EpEvent::HubAbort:
289
290 case EpEvent::HubDisable:
291 case EpEvent::HubDeviceReset:
294
295 case EpEvent::HubPurge:
297
298 case EpEvent::HubTreePurge:
300
301 case EpEvent::HubDisconnect:
303
304 case EpEvent::ControllerResetStarting:
307
308 default:
309 return SmUnhandled();
310 }
311}
312
316{
317 switch (Event)
318 {
319 case EpEvent::ControllerResetStarting:
321
322 case EpEvent::ControllerResetDone:
323 return SmHandled();
324
325 default:
326 return SmUnhandled();
327 }
328}
329
332{
334
336 {
339 }
340
341 return SmHandled();
342}
343
347{
348 if (Event != EpEvent::PurgeDone)
349 return SmUnhandled();
350
355
356 return SmTransition(&Disabled);
357}
358
362{
363 if (Event != EpEvent::ControllerResetStarting)
364 return SmUnhandled();
365
366 /* Endpoint is already purged, Busy pauses in place */
367 if (m_ReturnTo == &Disabled)
368 return SmUnhandled();
369
372}
373
377{
378 if (Event == EpEvent::AbortUrbParked)
379 return SmTransition(&Aborting);
380
381 return SmUnhandled();
382}
383
386{
388 return SmHandled();
389}
390
394{
395 if (Event != EpEvent::AbortDone)
396 return SmUnhandled();
397
398 if (m_AbortForHub)
399 {
402 }
403 else
404 {
407 }
408
409 return SmTransition(&Enabled);
410}
411
414{
415 if (m_ReturnTo == &Enabled)
417 else
419
420 return SmHandled();
421}
422
426{
427 if (Event != EpEvent::StreamsOpened)
428 return SmUnhandled();
429
431 return SmTransition(m_ReturnTo);
432}
433
436{
437 /* A deprogrammed device has no streams on the controller to tear down */
440 else
442
443 return SmHandled();
444}
445
449{
450 if (Event != EpEvent::StreamsClosed)
451 return SmUnhandled();
452
454 return SmTransition(m_ReturnTo);
455}
456
459{
462 else
464
465 return SmHandled();
466}
467
471{
472 if (Event != EpEvent::EndpointResetDone)
473 return SmUnhandled();
474
476 return SmTransition(m_ReturnTo);
477}
478
481{
483}
484
488{
489 if (Event == EpEvent::ControllerResetDone)
491
492 return SmUnhandled();
493}
494
502{
503 if (Event == EpEvent::ControllerResetStarting)
505
506 /* A hub abort only ever has the abort itself outstanding */
508 {
509 if (Event != EpEvent::AbortDone)
510 return SmUnhandled();
511
514 }
515
516 switch (Event)
517 {
518 case EpEvent::AbortUrbParked:
519 case EpEvent::AbortDone:
521 break;
522
523 case EpEvent::StreamsOpened:
525 break;
526
527 case EpEvent::StreamsClosed:
529 break;
530
531 case EpEvent::EndpointResetDone:
533 break;
534
535 default:
536 return SmUnhandled();
537 }
538
540}
541
548{
549 SmBeginPause();
551 return SmPaused();
552}
553
556 _In_ PURGE_FOLLOW_UP FollowUp)
557{
558 m_AfterPurge = FollowUp;
559 return SmTransition(&Purging);
560}
561
564 _In_ const State* Target,
565 _In_ const State* ReturnTo)
566{
567 m_ReturnTo = ReturnTo;
568 return SmTransition(Target);
569}
570
573{
574 if (!CanStart())
575 {
577 return SmHandled();
578 }
579
582 return SmTransition(&Enabled);
583}
584
591{
592 if (!ClientHoldsHandle())
593 {
596 }
597
598 if (ParkAsStale())
599 return SmTransition(&Stale);
600
603}
604
607{
608 return m_Enabled && DeviceAllowsStart();
609}
#define RTL_NUMBER_OF(x)
Definition: RtlRegistry.c:12
unsigned char BOOLEAN
Definition: actypes.h:127
static const State Inactive
Definition: epsm.h:74
VOID CompleteAbortUrb()
Definition: pipe.cpp:783
static const State ResettingPipe
Definition: epsm.h:88
VOID FailResetRequest()
Definition: pipe.cpp:691
VOID AckControllerReset()
Definition: pipe.cpp:816
VOID FinishStreamsOpenRequest(_In_ BOOLEAN ForceFailure)
Definition: pipe.cpp:720
SM_RESULT OnOperation(_In_ EpEvent Event)
Definition: epsm.cpp:360
static const State AwaitingDestroy
Definition: epsm.h:79
SM_RESULT OnBusy(_In_ EpEvent Event)
Definition: epsm.cpp:314
static const State Purging
Definition: epsm.h:82
VOID FinishStreamsCloseRequest()
Definition: pipe.cpp:762
BOOLEAN DeviceAllowsStart()
Definition: pipe.cpp:925
SM_RESULT OnAborting(_In_ EpEvent Event)
Definition: epsm.cpp:392
static const State Busy
Definition: epsm.h:81
SM_RESULT EnterDisablingStreams()
Definition: epsm.cpp:435
SM_RESULT OnAwaitingAbortUrb(_In_ EpEvent Event)
Definition: epsm.cpp:375
static const State Stale
Definition: epsm.h:78
SM_RESULT EnterAborting()
Definition: epsm.cpp:385
VOID ForwardResetRequest()
Definition: pipe.cpp:682
VOID StartEndpoint()
Definition: pipe.cpp:663
SM_RESULT StartPurge(_In_ PURGE_FOLLOW_UP FollowUp)
Definition: epsm.cpp:555
static const State EnablingStreams
Definition: epsm.h:86
SM_RESULT BeginOperation(_In_ const State *Target, _In_ const State *ReturnTo)
Definition: epsm.cpp:563
VOID SmDereference()
Definition: epsm.cpp:142
SM_RESULT EnterPurging()
Definition: epsm.cpp:331
VOID ParkStreamsDisableRequest()
Definition: pipe.cpp:750
BOOLEAN CanStart()
Definition: epsm.cpp:606
BOOLEAN m_PauseAfterPurge
Definition: epsm.h:218
BOOLEAN DeviceDisconnected()
Definition: pipe.cpp:937
SM_RESULT OnEnabled(_In_ EpEvent Event)
Definition: epsm.cpp:268
const State * m_HeldOperation
Definition: epsm.h:214
SM_RESULT OnOperationUnwinding(_In_ EpEvent Event)
Reset under an outstanding operation: finish it, then purge.
Definition: epsm.cpp:500
SM_RESULT OnResettingPipe(_In_ EpEvent Event)
Definition: epsm.cpp:469
VOID AbortEndpoint()
Definition: pipe.cpp:676
SM_RESULT OnEnablingStreams(_In_ EpEvent Event)
Definition: epsm.cpp:424
VOID ReferenceEndpoint()
Definition: pipe.cpp:651
VOID ForwardStreamsDisableRequest()
Definition: pipe.cpp:741
VOID FinishEndpointResetRequest()
Definition: pipe.cpp:698
VOID RejectStreamsEnableRequest()
Definition: pipe.cpp:713
static const State Enabled
Definition: epsm.h:80
@ PurgeFollowUpTreePurge
Definition: epsm.h:70
@ PurgeFollowUpHubOperation
Definition: epsm.h:69
@ PurgeFollowUpNone
Definition: epsm.h:68
SM_RESULT Retire()
An endpoint the client still has a handle to stays around as stale.
Definition: epsm.cpp:590
static const State OperationUnwinding
Definition: epsm.h:90
BOOLEAN m_AbortForHub
Definition: epsm.h:217
BOOLEAN DeviceDeprogrammed()
Definition: pipe.cpp:931
UcxEndpoint * Endpoint() const
Definition: epsm.h:58
PURGE_FOLLOW_UP m_AfterPurge
Definition: epsm.h:215
SM_RESULT EnterOperationHeld()
Definition: epsm.cpp:480
static const State Retired
Definition: epsm.h:77
VOID DereferenceEndpoint()
Definition: pipe.cpp:657
VOID ForwardStreamsEnableRequest()
Definition: pipe.cpp:704
VOID DeleteEndpoint()
Definition: pipe.cpp:844
UcxEndpoint * m_Endpoint
Definition: epsm.h:212
SM_RESULT OnCreated(_In_ EpEvent Event)
Definition: epsm.cpp:179
VOID DeleteStaleEndpoint()
Definition: pipe.cpp:914
static const State AwaitingAbortUrb
Definition: epsm.h:84
SM_RESULT OnOperationHeld(_In_ EpEvent Event)
Definition: epsm.cpp:486
BOOLEAN ClientHoldsHandle()
Definition: pipe.cpp:943
VOID CompleteHubOperation()
Definition: pipe.cpp:796
static const State Aborting
Definition: epsm.h:85
VOID PurgeEndpoint()
Definition: pipe.cpp:670
SM_RESULT OnPurging(_In_ EpEvent Event)
Definition: epsm.cpp:345
SM_RESULT OnDisabled(_In_ EpEvent Event)
Definition: epsm.cpp:205
BOOLEAN ParkAsStale()
Definition: pipe.cpp:867
VOID CompleteTreePurge()
Definition: pipe.cpp:803
SM_RESULT TryStart()
Definition: epsm.cpp:572
SM_RESULT OnDisablingStreams(_In_ EpEvent Event)
Definition: epsm.cpp:447
static const State DisablingStreams
Definition: epsm.h:87
SM_RESULT OnInactive(_In_ EpEvent Event)
Definition: epsm.cpp:148
static const State OperationHeld
Definition: epsm.h:89
static const State Created
Definition: epsm.h:75
SM_RESULT EnterEnablingStreams()
Definition: epsm.cpp:413
SM_RESULT PauseForControllerReset()
Pause before the ack; nothing may touch the machine after it.
Definition: epsm.cpp:547
SM_RESULT OnRetired(_In_ EpEvent Event)
Definition: epsm.cpp:242
SM_RESULT OnStale(_In_ EpEvent Event)
Definition: epsm.cpp:255
VOID Initialize(_In_ UcxEndpoint *Endpoint)
Definition: epsm.cpp:107
const State * m_ReturnTo
Definition: epsm.h:213
static const State Operation
Definition: epsm.h:83
SM_RESULT EnterResettingPipe()
Definition: epsm.cpp:458
static const State Disabled
Definition: epsm.h:76
static const SM_EVENT_INFO EventInfo[]
Definition: epsm.h:63
BOOLEAN SmAccepts(_In_ EpEvent Event)
Abort URB is only taken while running; the caller fails the URB on FALSE.
Definition: epsm.cpp:126
VOID SmReference()
Definition: epsm.cpp:136
BOOLEAN m_Enabled
Definition: epsm.h:216
const State * SmCurrent() const
Definition: smengine.h:130
VOID SmInitialize(_In_ const State *Initial)
Definition: smengine.h:349
static SM_RESULT SmTransition(_In_ const State *Target)
Definition: smengine.h:194
_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
EpEvent
Definition: epsm.h:15
FP_OP Operation
Definition: fpcontrol.c:150
_In_ UCXHUB_DEVICE_CONTEXT _In_ UCXENDPOINT Endpoint
Definition: hubucx.h:238
#define _In_
Definition: no_sal2.h:158
@ Inactive
Definition: sacdrv.h:287
#define SM_STATE_TAKES_REQUESTS
Definition: smengine.h:39
@ SmEventRequest
Definition: smengine.h:25
@ SmEventResume
Definition: smengine.h:26
@ SmEventCompletion
Definition: smengine.h:24
One state. Handler gets every event the state sees.
Definition: smengine.h:93
uint32_t ULONG
Definition: typedefs.h:59
_In_ WDFIOTARGET Target
Definition: wdfrequest.h:306