ReactOS 0.4.17-dev-1281-g065abb3
devsm_report.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: Device state machine, reporting the device to PnP and the
5 * device that failed enumeration
6 * COPYRIGHT: Copyright 2026 Justin Miller <justin.miller@reactos.org>
7 */
8
9/* INCLUDES *******************************************************************/
10
11#include "usbhub3.h"
12
13/* GLOBALS ********************************************************************/
14
17
18static const DsmEvent PortOffDiscards[] =
19{
22};
23
24/* Adds the device to the hub's child list and creates its PDO */
26 { NULL, "ReportingToPnp", SM_STATE_TAKES_REQUESTS,
28
29/* Creates a PDO for a device that failed enumeration so PnP shows it as failed */
31 { NULL, "ReportingUnknown", SM_STATE_TAKES_REQUESTS,
33
34/* The failed device's PDO exists; m_FailedPoweredUp once PnP powered it up */
36 { NULL, "FailedDevice", SM_STATE_TAKES_REQUESTS,
38
39/* The failed device detached, waiting for PnP to clean up its PDO */
41 { NULL, "FailedDeviceGone", SM_STATE_TAKES_REQUESTS,
43
44/* Sub machine of FailedDevice: keeps hub and PnP events balanced */
46 { NULL, "FailedDeviceEvents", SM_STATE_YIELDS_TO_CALLER,
48
50 { NULL, "FailedHubSuspended", SM_STATE_YIELDS_TO_CALLER,
52
53/* Sub machine for a device whose port is off: answers everything without touching the device */
55 { NULL, "PortOffEvents", SM_STATE_YIELDS_TO_CALLER,
57
58/* FUNCTIONS ******************************************************************/
59
60/* REPORTING TO PNP ***********************************************************/
61
64{
67}
68
72{
73 switch (Event)
74 {
75 case DsmEvent::Succeeded:
77
78 case DsmEvent::PortDetached:
80
81 default:
82 return SmUnhandled();
83 }
84}
85
88{
89 switch (AddChildToHub())
90 {
91 case DsmAddChildDone:
92 return ReportCreatePdo();
93
96
97 default:
100
102 return ReportCreatePdo();
103 }
104}
105
108{
109 if (CreatePdo())
110 return EndWith(DsmEvent::Succeeded);
111
112 AskPortCycle();
113 ForgetChild();
115}
116
117/* Another device with the same serial number is still in the list */
121{
122 BOOLEAN stopped;
123
124 switch (Event)
125 {
126 case DsmEvent::HubStopping:
127 case DsmEvent::HubSuspending:
128 stopped = StopTimer();
129 AskPortCycle();
130 if (stopped)
132
134
135 case DsmEvent::TimerFired:
137
138 case DsmEvent::PortDetached:
139 if (StopTimer())
140 return EndWith(DsmEvent::PortDetached);
141
143
144 default:
145 return SmUnhandled();
146 }
147}
148
152{
153 switch (Event)
154 {
155 case DsmEvent::PortDetached:
157
158 case DsmEvent::TimerFired:
160
161 default:
162 return SmUnhandled();
163 }
164}
165
169{
170 if (Event != DsmEvent::PortDetached)
171 return SmUnhandled();
172
173 return EndWith(DsmEvent::PortDetached);
174}
175
176/* FAILED DEVICE **************************************************************/
177
180{
182}
183
186{
188 {
190 return EndWith(DsmEvent::Succeeded);
191 }
192
193 AskPortCycle();
195}
196
200{
201 switch (Event)
202 {
203 case DsmEvent::Succeeded:
205 return SmTransition(&FailedDevice);
206
207 case DsmEvent::PortDetached:
208 return EndAfterDetach();
209
210 default:
211 return SmUnhandled();
212 }
213}
214
217{
218 return SmCall(&FailedDeviceEvents);
219}
220
224{
225 switch (Event)
226 {
227 case DsmEvent::PdoCleanup:
230
231 case DsmEvent::PdoPowerUp:
233 AskPortCycle();
234
237 return SmTransition(&FailedDevice);
238
239 case DsmEvent::PortDetached:
241
242 case DsmEvent::PortNowEnabledOnReconnect:
244
245 default:
246 return SmUnhandled();
247 }
248}
249
250/* A failed device came back on reconnect; keep its port off */
254{
255 switch (Event)
256 {
257 case DsmEvent::PortDisableDone:
258 case DsmEvent::PortFault:
259 return SmTransition(&FailedDevice);
260
261 case DsmEvent::PortDetached:
263 return SmUnhandled();
264
266
267 default:
268 return SmUnhandled();
269 }
270}
271
274{
277 return SmCall(&PortOffEvents);
278}
279
283{
284 if (Event != DsmEvent::PdoCleanup)
285 return SmUnhandled();
286
288 return LeaveHub();
289}
290
291/* Unregister from the hub and wait to be deleted */
294{
299}
300
304{
305 switch (Event)
306 {
307 case DsmEvent::PdoPreStart:
308 AckPreStart();
309 return SmHandled();
310
311 case DsmEvent::HubGetDescriptor:
313 return SmHandled();
314
315 case DsmEvent::PortNowEnabled:
316 case DsmEvent::PortNowDisabled:
317 case DsmEvent::PortNowSuspended:
318 return SmHandled();
319
320 case DsmEvent::PdoPowerDownFinal:
321 case DsmEvent::PdoInstallMsOsExt:
322 case DsmEvent::PdoPowerDown:
325
326 case DsmEvent::HubResumedInS0:
327 case DsmEvent::HubStarted:
330
331 case DsmEvent::HubSuspending:
333
334 case DsmEvent::HubStoppingAfterSuspend:
337
338 case DsmEvent::HubStopping:
341
342 default:
343 return SmUnhandled();
344 }
345}
346
350{
351 switch (Event)
352 {
353 case DsmEvent::PortDetached:
355 return EndWith(DsmEvent::PortDetached);
356
357 case DsmEvent::PortDisableDone:
358 case DsmEvent::PortFault:
360
361 default:
362 return SmUnhandled();
363 }
364}
365
368{
370 return SmCall(&HubSuspended);
371}
372
376{
377 switch (Event)
378 {
379 case DsmEvent::HubStoppedHoldingReference:
382
383 case DsmEvent::NeedsReenumeration:
384 case DsmEvent::SuspendedAfterHubResume:
385 case DsmEvent::ResumedWithHub:
387
388 case DsmEvent::PortDetached:
389 return EndWith(DsmEvent::PortDetached);
390
391 case DsmEvent::HubStoppingAfterSuspend:
394
395 default:
396 return SmUnhandled();
397 }
398}
399
400/* PORT OFF EVENTS ************************************************************/
401
405{
406 switch (Event)
407 {
408 case DsmEvent::ClientCyclePort:
409 case DsmEvent::PortDisableDone:
410 case DsmEvent::PortResetTimeout:
411 case DsmEvent::PortResetAbortedForSuspend:
412 case DsmEvent::PortNowEnabled:
413 case DsmEvent::PortSuspendDone:
414 case DsmEvent::LpmSettingChanged:
415 case DsmEvent::PortFault:
416 case DsmEvent::PortNowSuspended:
417 return SmHandled();
418
419 case DsmEvent::ClientResetPipe:
420 case DsmEvent::ClientSetInterface:
421 case DsmEvent::ClientSyncResetPipe:
422 case DsmEvent::ClientResetDevice:
423 case DsmEvent::ClientSelectConfig:
424 case DsmEvent::ClientClearStall:
425 case DsmEvent::ClientUnconfigure:
427 return SmHandled();
428
429 case DsmEvent::HubGetDescriptor:
431 return SmHandled();
432
433 case DsmEvent::PdoPreStart:
434 AckPreStart();
435 return SmHandled();
436
437 case DsmEvent::HubResumed:
438 case DsmEvent::HubStarted:
439 case DsmEvent::HubResumedWithReset:
440 case DsmEvent::HubResumedInS0:
443
444 case DsmEvent::PdoPowerDownFinal:
445 case DsmEvent::PdoPowerUp:
446 case DsmEvent::PdoInstallMsOsExt:
447 case DsmEvent::PdoPowerDown:
450
451 case DsmEvent::HubStopping:
452 case DsmEvent::HubSuspending:
455
456 case DsmEvent::HubStoppingAfterSuspend:
459
460 case DsmEvent::ClientStreams:
462
463 default:
464 return SmUnhandled();
465 }
466}
unsigned char BOOLEAN
Definition: actypes.h:127
SM_RESULT OnReportingUnknown(_In_ DsmEvent Event)
VOID FailHubDescriptorRequest()
Definition: hubioctl.cpp:383
SM_RESULT OnFailedDevice(_In_ DsmEvent Event)
static const State StoppedAddressed
Definition: devsm.h:834
BOOLEAN CreatePlaceholderPdo()
Definition: childpdo.cpp:3913
SM_RESULT OnFailedDeviceEvents(_In_ DsmEvent Event)
static const State RemovedPortOn
Definition: devsm.h:756
VOID ConfirmStopWhileSuspended()
Definition: fanout.cpp:1050
static const State AwaitingPort
Definition: devsm.h:222
SM_RESULT OnFailedDeviceGone(_In_ DsmEvent Event)
SM_RESULT EndDetachedOnTimer(_In_ DsmEvent Event)
Definition: devsm.cpp:485
BOOLEAN CreatePdo()
Definition: childpdo.cpp:3893
static const State ReportingUnknown
Definition: devsm.h:694
static const State FailedDevice
Definition: devsm.h:695
SM_RESULT EndAfterDetach()
Definition: devsm_enum.cpp:120
static const State PortOffEvents
Definition: devsm.h:699
VOID AckPreStart()
Definition: childpdo.cpp:4051
VOID FailClientRequest()
Definition: childpdo.cpp:3558
BOOLEAN StopTimer()
Definition: hubchild.cpp:295
SM_RESULT EnterReportingUnknown()
SM_RESULT EnterReportingToPnp()
SM_RESULT LeaveHub()
SM_RESULT OnReportingToPnp(_In_ DsmEvent Event)
static const State TimerAfterDetach
Definition: devsm.h:242
static const State FailedDeviceEvents
Definition: devsm.h:697
SM_RESULT EndOnDetach(_In_ DsmEvent Event)
SM_RESULT DisableAndDelete(_In_ DSM_THEN After)
Definition: devsm.cpp:315
DSM_ADD_CHILD AddChildToHub()
Definition: devmisc.cpp:419
SM_RESULT OnFailedHubSuspended(_In_ DsmEvent Event)
VOID DereferencePort()
Definition: hubchild.cpp:325
VOID AskPortCycle()
Definition: hubport.cpp:656
VOID ReportDeviceMissing()
Definition: childpdo.cpp:3932
SM_RESULT EndWith(_In_ DsmEvent Result)
Definition: devsm.cpp:186
SM_RESULT FailedPortOffForHub(_In_ DsmEvent Event)
SM_RESULT ReportDuplicateWaitEnded(_In_ DsmEvent Event)
SM_RESULT CallAtPassive(_In_ DSM_THEN Then)
Definition: devsm.cpp:513
static const State IgnoringHub
Definition: devsm.h:237
SM_RESULT EnterFailedDeviceGone()
SM_RESULT ReportCycledWithTimer(_In_ DsmEvent Event)
VOID ReferenceDevicePower()
Definition: fanout.cpp:1038
BOOLEAN m_FailedPoweredUp
Definition: devsm.h:1839
static const State DisablingPort
Definition: devsm.h:221
VOID DereferenceDevicePower()
Definition: fanout.cpp:1044
VOID ForgetChild()
Definition: devmisc.cpp:467
SM_RESULT FailedPortDisabledAgain(_In_ DsmEvent Event)
static const State ReportingToPnp
Definition: devsm.h:693
VOID DropSerialNumber()
Definition: hubid.cpp:1198
SM_RESULT ReportUnknownPdo()
VOID SignalPnpWaiter()
Definition: childpdo.cpp:4023
VOID NotifyPortDetached()
Definition: hubport.cpp:632
BOOLEAN DuplicateRetriesUsedUp()
Definition: devmisc.cpp:98
SM_RESULT ReportAddChild()
static const State HubSuspended
Definition: devsm.h:422
SM_RESULT ForwardStreams(_In_ const State *ReturnTo)
Definition: devsm.cpp:645
VOID UnregisterFromHub()
Definition: fanout.cpp:1032
SM_RESULT EnterFailedDevice()
static const State FailedDeviceGone
Definition: devsm.h:696
SM_RESULT AtPassive(_In_ DSM_THEN Then)
Definition: devsm.cpp:177
SM_RESULT Delay(_In_ DSM_DELAY Kind, _In_ DSM_NEXT Next)
Definition: devsm.cpp:291
VOID SignalPnpPowerFailure()
Definition: childpdo.cpp:4031
SM_RESULT ReportCreatePdo()
SM_RESULT OnPortOffEvents(_In_ DsmEvent Event)
VOID DiscardHubEvents()
Definition: devsm_enum.cpp:131
VOID ReportEnumFailure()
Definition: childpdo.cpp:3922
SM_RESULT EnterFailedHubSuspended()
static const State FailedHubSuspended
Definition: devsm.h:698
static const State AwaitingDelete
Definition: devsm.h:328
VOID StartDuplicateRetries()
Definition: devmisc.cpp:92
static SM_RESULT SmTransition(_In_ const State *Target)
Definition: smengine.h:194
static SM_RESULT SmCall(_In_ const State *Start)
Definition: smengine.h:209
static SM_RESULT SmUnhandled()
Definition: smengine.h:188
DsmEvent
Definition: devsm.h:15
@ NoPingResponse
@ LpmSettingChanged
@ PortNowDisabled
@ PdoReportedMissing
@ DsmDelayDuplicate
Definition: devsm.h:129
@ DsmAddChildDone
Definition: devsm.h:116
@ DsmAddChildDuplicate
Definition: devsm.h:117
static const DsmEvent ReportLpmDiscards[]
static const DsmEvent MissingDiscards[]
static const DsmEvent PortOffDiscards[]
_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
#define _In_
Definition: no_sal2.h:158
#define SM_STATE_TAKES_REQUESTS
Definition: smengine.h:39
#define SM_STATE_YIELDS_TO_CALLER
Definition: smengine.h:42
One state. Handler gets every event the state sees.
Definition: smengine.h:93
_In_ WDFDPC _In_ BOOLEAN Wait
Definition: wdfdpc.h:170