ReactOS 0.4.17-dev-1281-g065abb3
devsm_remove.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, detach and removal
5 * COPYRIGHT: Copyright 2026 Justin Miller <justin.miller@reactos.org>
6 */
7
8/* INCLUDES *******************************************************************/
9
10#include "usbhub3.h"
11
12/* GLOBALS ********************************************************************/
13
15{
18};
19
20/* Reported missing to PnP and waiting for the PDO removal; the configured flavor disables its endpoints first */
24
26 { NULL, "DetachedReportedConfigured", SM_STATE_TAKES_REQUESTS,
28
29/* PnP saw the device missing; the child is off the hub's list */
31 { NULL, "DetachedMissing", SM_STATE_TAKES_REQUESTS,
33
34/* Device disabled in the controller, waiting for PnP to remove the PDO */
36 { NULL, "AwaitingRemove", SM_STATE_TAKES_REQUESTS,
38
39/* Port cycled after a failure, device still in the controller; waiting for detach or remove */
41 { NULL, "AwaitingDetachOrRemove", SM_STATE_TAKES_REQUESTS,
43
44/* Device disabled in the controller and the port is off */
46 { NULL, "ParkedPortOff", SM_STATE_TAKES_REQUESTS,
48
50 { NULL, "ParkedPortOn", SM_STATE_TAKES_REQUESTS,
52
53/* PDO removed and the device deleted, waiting for the detach */
55 { NULL, "RemovedPortOff", SM_STATE_TAKES_REQUESTS,
57
59 { NULL, "RemovedPortOn", SM_STATE_TAKES_REQUESTS,
61
62/* Sub machine: the device is detached or about to be, answer events without touching it */
64 { NULL, "DetachedEvents", SM_STATE_YIELDS_TO_CALLER,
66
67/* Sub machine: the device is gone from the controller, its port still on */
70
71/* FUNCTIONS ******************************************************************/
72
75{
76 return SmCall(&PortOffEvents);
77}
78
81{
82 return SmCall(&PortOnEvents);
83}
84
87{
88 return SmCall(&DetachedEvents);
89}
90
91/* DETACHED WITH A PDO ********************************************************/
92
93/* Device left without its configuration programmed in the controller */
96{
99}
100
101/* Device left with its configuration programmed in the controller */
104{
107}
108
111{
117 return SmCall(&DetachedEvents);
118}
119
122{
127 return SmCall(&DetachedEvents);
128}
129
133{
134 switch (Event)
135 {
136 case DsmEvent::PdoReportedMissing:
138
139 case DsmEvent::PdoCleanup:
140 ForgetChild();
143
144 case DsmEvent::PdoPowerDownFinal:
146
147 case DsmEvent::HubStoppingAfterSuspend:
149
150 case DsmEvent::HubStopping:
152
153 default:
154 return SmUnhandled();
155 }
156}
157
160{
162 ForgetChild();
164 return SmCall(&DetachedEvents);
165}
166
170{
171 switch (Event)
172 {
173 case DsmEvent::HubStopping:
174 case DsmEvent::HubStoppingAfterSuspend:
176
177 case DsmEvent::PdoCleanup:
179
180 case DsmEvent::PdoPowerDownFinal:
182
183 default:
184 return SmUnhandled();
185 }
186}
187
188/* Disable the endpoints if they are programmed, then the device, then run After */
191 _In_ DSM_THEN After)
192{
193 m_AfterDisable = After;
196
198}
199
203{
204 if (Event != DsmEvent::ControllerIoctlDone)
205 return SmUnhandled();
206
208}
209
213{
214 if (Event != DsmEvent::ControllerIoctlDone)
215 return SmUnhandled();
216
217 return (this->*m_AfterDisable)();
218}
219
222{
226}
227
228/* Free everything the controller holds for the device and wait to be deleted */
231{
237}
238
241{
243 return RemovalLeaveHub();
244}
245
248{
253}
254
257{
259 return RemovalHubStopped();
260}
261
264{
266 return RemovalHubStopped();
267}
268
271{
275}
276
277/*
278 * PDO still to be removed. m_Unregistered and m_ChildForgotten say
279 * how much of leaving the hub is already done.
280 */
284{
285 switch (Event)
286 {
287 case DsmEvent::PdoReportedMissing:
289 return SmUnhandled();
290
291 ForgetChild();
294 if (!m_Unregistered)
295 {
299 }
300
302
303 case DsmEvent::PdoCleanup:
304 if (!m_ChildForgotten)
305 {
306 ForgetChild();
308 }
309
310 if (!m_Unregistered)
311 {
314 }
315
317
318 default:
319 return SmUnhandled();
320 }
321}
322
323/* Report the device missing from a state where the port is off */
326{
336}
337
338/* PORT CYCLED, DEVICE STILL PROGRAMMED ***************************************/
339
343{
344 switch (Event)
345 {
346 case DsmEvent::PdoCleanup:
348
349 case DsmEvent::PortDetached:
352
353 return DetachUnconfigured();
354
355 case DsmEvent::HubStopping:
357
358 case DsmEvent::PdoPowerDownFinal:
361
362 case DsmEvent::HubStoppingAfterSuspend:
364
365 default:
366 return SmUnhandled();
367 }
368}
369
372{
374 return DetachConfigured();
375}
376
379{
381}
382
383/* Free the controller's copy of the device, forget the child, tell PnP; port stays off */
386{
390 ForgetChild();
393}
394
397{
401}
402
405{
409}
410
411/* PARKED AND REMOVED *********************************************************/
412
416{
417 switch (Event)
418 {
419 case DsmEvent::PortDetached:
421
422 case DsmEvent::PdoCleanup:
424
425 case DsmEvent::PortResumeDone:
426 case DsmEvent::PortNowEnabledOnReconnect:
427 if (!m_PortMayResume)
428 return SmUnhandled();
429
430 return SmTransition(&ParkedPortOn);
431
432 default:
433 return SmUnhandled();
434 }
435}
436
440{
441 switch (Event)
442 {
443 case DsmEvent::PortOffForHubSuspend:
446
447 case DsmEvent::PdoCleanup:
449
450 case DsmEvent::PortDetached:
452
453 default:
454 return SmUnhandled();
455 }
456}
457
460{
464 ForgetChild();
467}
468
472{
473 switch (Event)
474 {
475 case DsmEvent::PortDetached:
476 return EndAfterDetach();
477
478 case DsmEvent::PortNowEnabledOnReconnect:
479 case DsmEvent::PortResumeDone:
481
482 default:
483 return SmUnhandled();
484 }
485}
486
490{
491 switch (Event)
492 {
493 case DsmEvent::PortOffForHubSuspend:
495
496 case DsmEvent::PortDetached:
497 return EndAfterDetach();
498
499 default:
500 return SmUnhandled();
501 }
502}
503
504/* PDO cleanup while the port is being disabled */
508{
509 switch (Event)
510 {
511 case DsmEvent::PortDetached:
514
515 case DsmEvent::PortDisableDone:
516 case DsmEvent::PortFault:
519
520 default:
521 return SmUnhandled();
522 }
523}
524
528{
529 if (Event != DsmEvent::ControllerIoctlDone)
530 return SmUnhandled();
531
533}
534
537{
541 ForgetChild();
543 return (this->*m_AfterDelete)();
544}
545
548{
550}
551
552/* SUB MACHINES ***************************************************************/
553
557{
558 switch (Event)
559 {
560 case DsmEvent::ClientCyclePort:
561 case DsmEvent::NoPingResponse:
562 case DsmEvent::PortNowSuspended:
563 case DsmEvent::PortNowEnabled:
564 case DsmEvent::PortResetTimeout:
565 case DsmEvent::LpmSettingChanged:
566 case DsmEvent::PortFault:
567 case DsmEvent::PortNowDisabled:
568 return SmHandled();
569
570 case DsmEvent::ClientSelectConfig:
571 case DsmEvent::ClientResetDevice:
572 case DsmEvent::ClientClearStall:
573 case DsmEvent::ClientSyncResetPipe:
574 case DsmEvent::ClientResetPipe:
575 case DsmEvent::ClientSetInterface:
576 case DsmEvent::ClientUnconfigure:
578 return SmHandled();
579
580 case DsmEvent::HubGetDescriptor:
582 return SmHandled();
583
584 case DsmEvent::PdoPreStart:
585 AckPreStart();
586 return SmHandled();
587
588 case DsmEvent::HubResumed:
589 case DsmEvent::HubResumedWithReset:
590 case DsmEvent::HubStarted:
591 case DsmEvent::HubResumedInS0:
594
595 case DsmEvent::PdoPowerDown:
596 case DsmEvent::PdoInstallMsOsExt:
597 case DsmEvent::PdoPowerUp:
600
601 case DsmEvent::HubSuspending:
604
605 case DsmEvent::ClientStreams:
607
608 default:
609 return SmUnhandled();
610 }
611}
612
616{
617 switch (Event)
618 {
619 case DsmEvent::PortNowDisabled:
620 case DsmEvent::PortNowEnabled:
621 case DsmEvent::PortResetTimeout:
622 case DsmEvent::LpmSettingChanged:
623 case DsmEvent::ClientCyclePort:
624 case DsmEvent::PortDisableDone:
625 case DsmEvent::PortFault:
626 case DsmEvent::NoPingResponse:
627 case DsmEvent::PortSuspendDone:
628 case DsmEvent::PortResetAbortedForSuspend:
629 case DsmEvent::PortNowEnabledOnReconnect:
630 case DsmEvent::PortNowSuspended:
631 case DsmEvent::PortResumeDone:
632 return SmHandled();
633
634 case DsmEvent::ClientUnconfigure:
635 case DsmEvent::ClientSyncResetPipe:
636 case DsmEvent::ClientSetInterface:
637 case DsmEvent::ClientResetDevice:
638 case DsmEvent::ClientResetPipe:
639 case DsmEvent::ClientClearStall:
640 case DsmEvent::ClientSelectConfig:
642 return SmHandled();
643
644 case DsmEvent::HubGetDescriptor:
646 return SmHandled();
647
648 case DsmEvent::PdoPreStart:
649 AckPreStart();
650 return SmHandled();
651
652 case DsmEvent::HubResumed:
653 case DsmEvent::HubStarted:
654 case DsmEvent::HubResumedWithReset:
655 case DsmEvent::HubResumedInS0:
657 return SmTransition(&PortOnEvents);
658
659 case DsmEvent::HubStoppingAfterSuspend:
661 return SmTransition(&PortOnEvents);
662
663 case DsmEvent::PdoPowerDownFinal:
664 case DsmEvent::PdoPowerUp:
665 case DsmEvent::PdoInstallMsOsExt:
666 case DsmEvent::PdoPowerDown:
668 return SmTransition(&PortOnEvents);
669
670 case DsmEvent::HubSuspending:
672
673 case DsmEvent::ClientStreams:
675
676 case DsmEvent::HubStopping:
678 return SmTransition(&PortOnEvents);
679
680 default:
681 return SmUnhandled();
682 }
683}
684
688{
689 switch (Event)
690 {
691 case DsmEvent::PortDetached:
692 return EndWith(DsmEvent::PortDetached);
693
694 case DsmEvent::PortFault:
695 case DsmEvent::PortDisableDone:
697 return EndWith(DsmEvent::PortOffForHubSuspend);
698
699 default:
700 return SmUnhandled();
701 }
702}
SM_RESULT RemovalDropPowerAndPark()
static const State AwaitingRemove
Definition: devsm.h:751
BOOLEAN m_EndpointsConfigured
Definition: devsm.h:1840
BOOLEAN m_ChildForgotten
Definition: devsm.h:1841
SM_RESULT RemovalLeaveHub()
VOID DeleteDefaultEndpoint()
Definition: devhcd.cpp:558
VOID FailHubDescriptorRequest()
Definition: hubioctl.cpp:383
SM_RESULT RemovalDeleteAndFinish()
static const State RemovedPortOn
Definition: devsm.h:756
VOID ConfirmStopWhileSuspended()
Definition: fanout.cpp:1050
SM_RESULT RemovalAckHubStop()
static const State RemovedPortOff
Definition: devsm.h:755
SM_RESULT OnAwaitingRemove(_In_ DsmEvent Event)
SM_RESULT RemovalDeleteForgetAndPark()
SM_RESULT OnRemovedPortOff(_In_ DsmEvent Event)
DSM_THEN m_AfterDisable
Definition: devsm.h:1844
SM_RESULT OnParkedPortOff(_In_ DsmEvent Event)
SM_RESULT EndAfterDetach()
Definition: devsm_enum.cpp:120
static const State DisablingEndpoints
Definition: devsm.h:239
static const State PortOffEvents
Definition: devsm.h:699
VOID AckPreStart()
Definition: childpdo.cpp:4051
VOID DeleteDeviceInController()
Definition: devhcd.cpp:568
VOID MarkDisconnected()
Definition: devmisc.cpp:474
VOID FailClientRequest()
Definition: childpdo.cpp:3558
SM_RESULT RemovalPowerDownDone()
static const State ParkedPortOff
Definition: devsm.h:753
SM_RESULT RemovalDeleteForget()
SM_RESULT DisableForRemoval(_In_ DSM_THEN After)
SM_RESULT EnterDetachedMissing()
VOID DereferencePort()
Definition: hubchild.cpp:325
SM_RESULT RemovalAckAndPark()
VOID ReportDeviceMissing()
Definition: childpdo.cpp:3932
VOID NotifyDisconnected()
Definition: childpdo.cpp:3952
SM_RESULT EndWith(_In_ DsmEvent Result)
Definition: devsm.cpp:186
static const State DetachedReported
Definition: devsm.h:748
SM_RESULT OnPortOnEvents(_In_ DsmEvent Event)
static const State DisablingDevice
Definition: devsm.h:243
SM_RESULT EnterWithPortOff()
SM_RESULT RemovalDropPowerForHubStop()
SM_RESULT RemovalHubStopped()
static const State AwaitingDetachOrRemove
Definition: devsm.h:752
SM_RESULT RemovalEndpointsDisabled(_In_ DsmEvent Event)
SM_RESULT RemovalDeviceDisabled(_In_ DsmEvent Event)
static const State PortOnEvents
Definition: devsm.h:758
VOID ReferenceDevicePower()
Definition: fanout.cpp:1038
SM_RESULT OnAwaitingDetachOrRemove(_In_ DsmEvent Event)
static const State DisablingPort
Definition: devsm.h:221
VOID DereferenceDevicePower()
Definition: fanout.cpp:1044
SM_RESULT EnterDetachedReported()
SM_RESULT CleanupDeleteAll()
DSM_THEN m_AfterDelete
Definition: devsm.h:1835
VOID ForgetChild()
Definition: devmisc.cpp:467
static const State ParkedPortOn
Definition: devsm.h:754
SM_RESULT EnterDetachedReportedConfigured()
SM_RESULT OnDetachedReported(_In_ DsmEvent Event)
static const State DetachedMissing
Definition: devsm.h:750
VOID SignalPnpWaiter()
Definition: childpdo.cpp:4023
SM_RESULT CleanupPortDisabled(_In_ DsmEvent Event)
SM_RESULT DetachUnconfigured()
static const State DetachedReportedConfigured
Definition: devsm.h:749
VOID NotifyPortDetached()
Definition: hubport.cpp:632
SM_RESULT ReportMissingAndLeave()
SM_RESULT OnRemovedPortOn(_In_ DsmEvent Event)
SM_RESULT ForwardStreams(_In_ const State *ReturnTo)
Definition: devsm.cpp:645
SM_RESULT CleanupDeviceDisabled(_In_ DsmEvent Event)
SM_RESULT PortOnOffForHubSuspend(_In_ DsmEvent Event)
static const State DetachedEvents
Definition: devsm.h:757
BOOLEAN m_PortMayResume
Definition: devsm.h:1843
SM_RESULT RemovalNotifyThenReport()
VOID UnregisterFromHub()
Definition: fanout.cpp:1032
BOOLEAN m_Unregistered
Definition: devsm.h:1842
SM_RESULT RemovalDeleteForgetPortOn()
SM_RESULT CleanupDone()
SM_RESULT AtPassive(_In_ DSM_THEN Then)
Definition: devsm.cpp:177
SM_RESULT DetachConfigured()
SM_RESULT OnParkedPortOn(_In_ DsmEvent Event)
VOID SignalPnpPowerFailure()
Definition: childpdo.cpp:4031
VOID DeleteConfigEndpoints()
Definition: devhcd.cpp:1283
SM_RESULT EnterWithPortOn()
SM_RESULT OnDetachedEvents(_In_ DsmEvent Event)
SM_RESULT OnDetachedMissing(_In_ DsmEvent Event)
SM_RESULT EnterDetachedEvents()
VOID DiscardHubEvents()
Definition: devsm_enum.cpp:131
SM_RESULT RemovalDeleteAfterLeaving()
static const State AwaitingDelete
Definition: devsm.h:328
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
@ PortResetAbortedForSuspend
@ PortDisableDone
@ PortSuspendDone
static const DsmEvent DetachedEventDiscards[]
_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
#define SM_STATE_NEEDS_PASSIVE
Definition: smengine.h:40
One state. Handler gets every event the state sees.
Definition: smengine.h:93
_In_ WDFDPC _In_ BOOLEAN Wait
Definition: wdfdpc.h:170