ReactOS 0.4.17-dev-1281-g065abb3
devsm_power.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, unconfigured device in D0, selective
5 * suspend and resume
6 * COPYRIGHT: Copyright 2026 Justin Miller <justin.miller@reactos.org>
7 */
8
9/* INCLUDES *******************************************************************/
10
11#include "usbhub3.h"
12
13/* GLOBALS ********************************************************************/
14
16
17/* PDO started, device in D0 with no configuration selected */
20
21/* PDO leaving D0, running the suspend sub machine */
23 { NULL, "SuspendingUnconfigured", 0,
25
26/* PDO in a low power state, device suspended at its port */
28 { NULL, "SuspendedUnconfigured", SM_STATE_TAKES_REQUESTS,
30
31/* Device suspended because its hub suspended */
33 { NULL, "UnconfiguredHubSuspended", 0,
35
36/* Suspend sub machine: the device suspended at its port */
39
40/* Suspended while the hub is suspended too; m_D3Cold once the port lost power */
42 { NULL, "SuspendedHubSuspended", SM_STATE_YIELDS_TO_CALLER,
44
45/* The device must be enumerated again once PnP powers it up */
47 { NULL, "AwaitingPowerUpForReset", SM_STATE_YIELDS_TO_CALLER,
49
50/* The device woke the system; waiting for PnP to power it up */
52 { NULL, "AwaitingPowerUpAfterWake", SM_STATE_YIELDS_TO_CALLER,
54
55/* The port lost power while the device was suspended */
57 { NULL, "OffAfterD3Cold", SM_STATE_YIELDS_TO_CALLER,
59
60/* FUNCTIONS ******************************************************************/
61
64{
66}
67
68/* UNCONFIGURED IN D0 *********************************************************/
69
73{
74 switch (Event)
75 {
76 case DsmEvent::ClientResetPipe:
77 case DsmEvent::ClientClearStall:
78 case DsmEvent::ClientSetInterface:
79 case DsmEvent::ClientSyncResetPipe:
81 return SmHandled();
82
83 case DsmEvent::DeviceTextQuery:
85 return SmHandled();
86
87 case DsmEvent::ClientCyclePort:
89 return SmHandled();
90
91 case DsmEvent::NoPingResponse:
92 return SmHandled();
93
94 case DsmEvent::HubSuspending:
96
97 case DsmEvent::HubGetDescriptor:
101
102 case DsmEvent::ClientUnconfigure:
105
106 case DsmEvent::ClientResetDevice:
108
109 case DsmEvent::ClientSelectConfig:
112
113 case DsmEvent::PdoPowerDown:
115
116 case DsmEvent::PortDetached:
117 return DetachUnconfigured();
118
119 case DsmEvent::LpmSettingChanged:
122
123 case DsmEvent::PdoPowerDownFinal:
124 if (DisableWhenUnused())
126
129 return SmTransition(&StoppedReady);
130
131 case DsmEvent::ClientStreams:
133
134 default:
135 return SmUnhandled();
136 }
137}
138
142{
143 switch (Event)
144 {
145 case DsmEvent::PortFault:
148
149 case DsmEvent::PortSuspendDone:
151
152 case DsmEvent::PortDetached:
153 return DetachUnconfigured();
154
155 default:
156 return SmUnhandled();
157 }
158}
159
160/* PDO stopped: the device is disabled and its port turned off */
164{
165 if (Event != DsmEvent::ControllerIoctlDone)
166 return SmUnhandled();
167
169}
170
174{
175 switch (Event)
176 {
177 case DsmEvent::PortDetached:
180
181 case DsmEvent::PortDisableDone:
182 case DsmEvent::PortFault:
184 return SmTransition(&Stopped);
185
186 default:
187 return SmUnhandled();
188 }
189}
190
193{
196}
197
201{
202 switch (Event)
203 {
204 case DsmEvent::Succeeded:
205 case DsmEvent::Failed:
207
208 case DsmEvent::HubSuspending:
211
212 case DsmEvent::PortDetached:
214 return DetachUnconfigured();
215
216 default:
217 return SmUnhandled();
218 }
219}
220
223{
225 return SmCall(&DeviceSuspended);
226}
227
231{
232 switch (Event)
233 {
234 case DsmEvent::ClientSetInterface:
235 case DsmEvent::ClientResetPipe:
236 case DsmEvent::ClientSyncResetPipe:
237 case DsmEvent::ClientUnconfigure:
238 case DsmEvent::ClientSelectConfig:
239 case DsmEvent::ClientResetDevice:
240 case DsmEvent::ClientClearStall:
242 return SmHandled();
243
244 case DsmEvent::NoPingResponse:
245 return SmHandled();
246
247 case DsmEvent::DeviceTextQuery:
249 return SmHandled();
250
251 case DsmEvent::ClientCyclePort:
253 return SmHandled();
254
255 case DsmEvent::HubGetDescriptor:
257 return SmHandled();
258
259 case DsmEvent::NeedsReenumeration:
260 return ReenumForResume(FALSE);
261
262 case DsmEvent::ResumeDone:
265
266 case DsmEvent::PdoCleanup:
269
270 case DsmEvent::PortDetached:
271 return DetachUnconfigured();
272
273 case DsmEvent::HubStopping:
276
277 case DsmEvent::ClientStreams:
279
280 case DsmEvent::HubStoppingAfterSuspend:
283
284 case DsmEvent::PortFault:
286
287 case DsmEvent::PdoPreStart:
289
290 default:
291 return SmUnhandled();
292 }
293}
294
298{
299 if (Event != DsmEvent::ControllerIoctlDone)
300 return SmUnhandled();
301
302 return ReenumForPreStart();
303}
304
308{
309 switch (Event)
310 {
311 case DsmEvent::NeedsReenumeration:
313
314 case DsmEvent::ResumedWithHub:
316
317 case DsmEvent::SuspendedAfterHubResume:
319
320 case DsmEvent::PortDetached:
321 return DetachUnconfigured();
322
323 default:
324 return SmUnhandled();
325 }
326}
327
331{
332 switch (Event)
333 {
334 case DsmEvent::PortResumeDone:
336
337 case DsmEvent::PortFault:
338 case DsmEvent::PortResumeTimeout:
339 case DsmEvent::PortNowDisabled:
340 case DsmEvent::PortNowEnabledOnReconnect:
342
343 case DsmEvent::PortDetached:
344 return DetachUnconfigured();
345
346 default:
347 return SmUnhandled();
348 }
349}
350
351/* SUSPEND SUB MACHINE ********************************************************/
352
353/* Arm the device for wake if needed, flush its IO and suspend its port */
356{
357 if (ArmForWakeWanted())
358 {
361 }
362
366}
367
371{
372 if ((Event != DsmEvent::ControllerIoctlDone) && (Event != DsmEvent::ControllerIoctlFailed))
373 return SmUnhandled();
374
377}
378
382{
383 switch (Event)
384 {
385 case DsmEvent::TransferDone:
387 break;
388
389 case DsmEvent::TransferFailed:
391 break;
392
393 default:
394 return SmUnhandled();
395 }
396
399}
400
404{
405 if (Event != DsmEvent::ControllerIoctlDone)
406 return SmUnhandled();
407
409}
410
414{
415 switch (Event)
416 {
417 case DsmEvent::PortSuspendDone:
418 return EndWith(DsmEvent::Succeeded);
419
420 case DsmEvent::HubSuspending:
422
423 case DsmEvent::PortFault:
424 return EndWith(DsmEvent::Failed);
425
426 case DsmEvent::PortDetached:
427 return EndWith(DsmEvent::PortDetached);
428
429 default:
430 return SmUnhandled();
431 }
432}
433
437{
438 switch (Event)
439 {
440 case DsmEvent::PortFault:
442 return EndWith(DsmEvent::Failed);
443
444 case DsmEvent::HubSuspending:
446
447 case DsmEvent::PortSuspendDone:
448 return EndWith(DsmEvent::Succeeded);
449
450 case DsmEvent::PortDetached:
452 return EndWith(DsmEvent::PortDetached);
453
454 default:
455 return SmUnhandled();
456 }
457}
458
459/* Arming failed: the port is still suspended but the suspend reports failure */
463{
464 switch (Event)
465 {
466 case DsmEvent::PortFault:
467 case DsmEvent::PortSuspendDone:
469 return EndWith(DsmEvent::Failed);
470
471 case DsmEvent::HubSuspending:
473
474 case DsmEvent::PortDetached:
476 return EndWith(DsmEvent::PortDetached);
477
478 default:
479 return SmUnhandled();
480 }
481}
482
486{
487 switch (Event)
488 {
489 case DsmEvent::PortSuspendDone:
490 case DsmEvent::PortFault:
491 case DsmEvent::PortDisableDone:
492 return EndWith(DsmEvent::HubSuspending);
493
494 case DsmEvent::PortDetached:
495 return EndWith(DsmEvent::PortDetached);
496
497 default:
498 return SmUnhandled();
499 }
500}
501
502/* SUSPENDED SUB MACHINE ******************************************************/
503
507{
508 switch (Event)
509 {
510 case DsmEvent::PortNowEnabledOnReconnect:
513 return SuspendedResumedByPort();
514
515 case DsmEvent::HubSuspending:
516 m_D3Cold = FALSE;
518
519 case DsmEvent::PdoPowerUp:
521
522 case DsmEvent::PortResumeDone:
524 return SuspendedResumedByPort();
525
526 case DsmEvent::PortNowDisabled:
531
532 default:
533 return SmUnhandled();
534 }
535}
536
537/* The port resumed on its own: a wake from an armed device or a stray resume */
540{
541 if (DeviceArmedForWake())
542 {
545 }
546
548}
549
553{
554 if ((Event != DsmEvent::ControllerIoctlDone) && (Event != DsmEvent::ControllerIoctlFailed))
555 return SmUnhandled();
556
558}
559
560/* Device not armed for wake goes back to suspend */
564{
565 switch (Event)
566 {
567 case DsmEvent::PortSuspendDone:
569
570 case DsmEvent::HubSuspending:
572
573 case DsmEvent::PortDetached:
574 return EndWith(DsmEvent::PortDetached);
575
576 case DsmEvent::PortFault:
577 return EndWith(DsmEvent::PortFault);
578
579 default:
580 return SmUnhandled();
581 }
582}
583
587{
588 switch (Event)
589 {
590 case DsmEvent::PortSuspendDone:
591 m_D3Cold = FALSE;
593
594 case DsmEvent::PortDetached:
596 return EndWith(DsmEvent::PortDetached);
597
598 case DsmEvent::PortFault:
600 return EndWith(DsmEvent::PortFault);
601
602 default:
603 return SmUnhandled();
604 }
605}
606
607/* PnP powers the device up: resume the port, then restart its IO */
611{
612 switch (Event)
613 {
614 case DsmEvent::PortFault:
615 case DsmEvent::PortResumeTimeout:
616 case DsmEvent::PortResumeAbortedForSuspend:
618 return EndWith(DsmEvent::PortFault);
619
620 case DsmEvent::PortResumeDone:
623
624 case DsmEvent::PortDetached:
626 return EndWith(DsmEvent::PortDetached);
627
628 case DsmEvent::PortNowDisabled:
629 case DsmEvent::PortNowEnabledOnReconnect:
631 return EndWith(DsmEvent::NeedsReenumeration);
632
633 default:
634 return SmUnhandled();
635 }
636}
637
641{
642 if ((Event != DsmEvent::ControllerIoctlDone) && (Event != DsmEvent::ControllerIoctlFailed))
643 return SmUnhandled();
644
645 if (DisarmOnResume())
646 {
650 }
651
652 return SuspendedResumeDone();
653}
654
658{
659 if ((Event != DsmEvent::TransferDone) && (Event != DsmEvent::TransferFailed))
660 return SmUnhandled();
661
662 return SuspendedResumeDone();
663}
664
665/* Resume finished; a reset on resume turns it into a re-enumeration */
668{
670 return SuspendedNeedsReset();
671
673 return EndWith(DsmEvent::NeedsReenumeration);
674
675 return EndWith(DsmEvent::ResumeDone);
676}
677
680{
683 return EndWith(DsmEvent::NeedsReenumeration);
684}
685
688{
691 return SmHandled();
692}
693
697{
698 switch (Event)
699 {
700 case DsmEvent::PdoPowerUp:
703
704 case DsmEvent::HubSuspending:
707
708 case DsmEvent::HubStopping:
710
711 default:
712 return SmUnhandled();
713 }
714}
715
719{
720 if (Event != DsmEvent::ControllerIoctlDone)
721 return SmUnhandled();
722
725}
726
730{
731 switch (Event)
732 {
733 case DsmEvent::PortDetached:
734 return EndWith(DsmEvent::PortDetached);
735
736 case DsmEvent::PortFault:
737 case DsmEvent::PortDisableDone:
738 return EndWith(DsmEvent::HubStopping);
739
740 default:
741 return SmUnhandled();
742 }
743}
744
748{
749 switch (Event)
750 {
751 case DsmEvent::NeedsReenumeration:
752 if (m_D3Cold)
754
756
757 case DsmEvent::ResumedWithHub:
758 if (m_D3Cold)
760
761 return SuspendedResumedByPort();
762
763 case DsmEvent::SuspendedAfterHubResume:
764 if (m_D3Cold)
766
769
771
772 default:
773 return SmUnhandled();
774 }
775}
776
780{
781 switch (Event)
782 {
783 case DsmEvent::PdoPowerUp:
784 return SuspendedNeedsReset();
785
786 case DsmEvent::HubSuspending:
789
790 default:
791 return SmUnhandled();
792 }
793}
794
798{
799 if (Event != DsmEvent::ControllerIoctlDone)
800 return SmUnhandled();
801
804}
805
806/* The port is turned off and the device will be reset on its next resume */
807VOID
809{
812}
813
817{
818 switch (Event)
819 {
820 case DsmEvent::PortDetached:
822 return EndWith(DsmEvent::PortDetached);
823
824 case DsmEvent::PortFault:
825 return EndWith(DsmEvent::PortFault);
826
827 case DsmEvent::PortDisableDone:
828 m_D3Cold = FALSE;
830
831 default:
832 return SmUnhandled();
833 }
834}
835
839{
840 switch (Event)
841 {
842 case DsmEvent::PdoPowerUp:
843 return EndWith(DsmEvent::NeedsReenumeration);
844
845 case DsmEvent::HubSuspending:
846 m_D3Cold = TRUE;
848
849 default:
850 return SmUnhandled();
851 }
852}
SM_RESULT RemovalDropPowerAndPark()
BOOLEAN ArmForWakeWanted()
Definition: devmisc.cpp:501
BOOLEAN m_EndpointsConfigured
Definition: devsm.h:1840
VOID AbortDeviceIo()
Definition: devhcd.cpp:901
SM_RESULT SelectConfigValidate()
SM_RESULT SuspendedPortDownForHub(_In_ DsmEvent Event)
VOID FailHubDescriptorRequest()
Definition: hubioctl.cpp:383
SM_RESULT UnconfiguredDisabledForRestart(_In_ DsmEvent Event)
BOOLEAN DisarmOnResume()
Definition: devmisc.cpp:518
static const State Requesting
Definition: devsm.h:229
SM_RESULT SuspendedPortResumed(_In_ DsmEvent Event)
static const State SuspendedUnconfigured
Definition: devsm.h:949
static const State AwaitingPort
Definition: devsm.h:222
SM_RESULT ReenumForHubResume(_In_ BOOLEAN Configured)
static const State SuspendingUnconfigured
Definition: devsm.h:948
SM_RESULT RemovalDeleteForgetAndPark()
SM_RESULT UnconfiguredDisabledForStop(_In_ DsmEvent Event)
SM_RESULT SuspendedResumedByPort()
BOOLEAN DeviceArmedForWake()
Definition: devmisc.cpp:509
SM_RESULT SuspendEndedForHub(_In_ DsmEvent Event)
static const State ResumingPort
Definition: devsm.h:236
static const State OffAfterD3Cold
Definition: devsm.h:955
SM_RESULT OnSuspendingUnconfigured(_In_ DsmEvent Event)
SM_RESULT SuspendedPurgedAfterWake(_In_ DsmEvent Event)
SM_RESULT SuspendedIoStartedOnWake(_In_ DsmEvent Event)
SM_RESULT OnSuspendedUnconfigured(_In_ DsmEvent Event)
DSM_THEN m_Resume
Definition: devsm.h:1845
SM_RESULT ReenumForResume(_In_ BOOLEAN Configured)
VOID RequestPortDisable()
Definition: hubport.cpp:638
VOID FinishWaitWake()
Definition: childpdo.cpp:4136
SM_RESULT SuspendedPurgedForReset(_In_ DsmEvent Event)
VOID MarkSystemWakeSource()
Definition: childpdo.cpp:4143
BOOLEAN ResetOnResumeFromS0()
Definition: devmisc.cpp:339
VOID CyclePortForClient()
Definition: childpdo.cpp:4070
SM_RESULT SuspendedPortOffForStop(_In_ DsmEvent Event)
VOID ClearResetAtResume()
Definition: childpdo.cpp:4109
VOID FailClientRequest()
Definition: childpdo.cpp:3558
SM_RESULT UnconfiguredSuspendedForHub(_In_ DsmEvent Event)
SM_RESULT SuspendIoAborted(_In_ DsmEvent Event)
SM_RESULT DisableForRemoval(_In_ DSM_THEN After)
VOID RequestPortSuspend()
Definition: hubport.cpp:644
SM_RESULT SuspendPortArmed(_In_ DsmEvent Event)
SM_RESULT SuspendedIoStarted(_In_ DsmEvent Event)
static const State SuspendingPort
Definition: devsm.h:235
SM_RESULT UnconfiguredByClient(_In_ DsmEvent Event)
SM_RESULT OnOffAfterD3Cold(_In_ DsmEvent Event)
VOID ArmForWake()
Definition: devreq.cpp:887
static const State SettingU2Timeout
Definition: devsm.h:841
SM_RESULT ReenumForPreStart()
VOID DisarmWake()
Definition: devreq.cpp:912
static const State StoppedReady
Definition: devsm.h:835
VOID SetNullConfiguration()
Definition: devreq.cpp:777
SM_RESULT RemovalAckAndPark()
SM_RESULT SuspendedPortOffForReset(_In_ DsmEvent Event)
SM_RESULT EndWith(_In_ DsmEvent Result)
Definition: devsm.cpp:186
SM_RESULT OnAwaitingPowerUpAfterWake(_In_ DsmEvent Event)
SM_RESULT ToAwaitingDetachOrRemove(_In_ BOOLEAN Configured)
static const State SuspendedHubSuspended
Definition: devsm.h:952
VOID RequestPortResume()
Definition: hubport.cpp:650
DSM_NEXT m_AfterPurge
Definition: devsm.h:1855
static const State DisablingDevice
Definition: devsm.h:243
SM_RESULT SuspendedNeedsReset()
SM_RESULT CallStep(_In_ DSM_THEN Then)
Definition: devsm.cpp:552
SM_RESULT SuspendStart()
VOID GetDescriptorForHub()
Definition: devreq.cpp:1108
static const State DisablingPort
Definition: devsm.h:221
SM_RESULT SuspendPortPlain(_In_ DsmEvent Event)
SM_RESULT SuspendPortArmFailed(_In_ DsmEvent Event)
VOID DereferenceDevicePower()
Definition: fanout.cpp:1044
VOID DisablePortMarkingReset()
SM_RESULT EnterHubSuspendedReleasingPower()
static const State AwaitingPowerUpForReset
Definition: devsm.h:953
SM_RESULT SuspendedResumeDone()
BOOLEAN ResetAtResumeMarked()
Definition: childpdo.cpp:4116
VOID SignalPnpWaiter()
Definition: childpdo.cpp:4023
SM_RESULT DetachUnconfigured()
SM_RESULT EnterAwaitingPowerUpAfterWake()
SM_RESULT HubDescriptorDone(_In_ DsmEvent Event)
SM_RESULT ReportMissingAndLeave()
static const State DeviceSuspended
Definition: devsm.h:951
SM_RESULT SuspendedBackDown(_In_ DsmEvent Event)
BOOLEAN m_FromConfigured
Definition: devsm.h:1850
SM_RESULT ReenumForClientUnconfigured()
SM_RESULT ForwardStreams(_In_ const State *ReturnTo)
Definition: devsm.cpp:645
SM_RESULT EnterSuspended()
VOID PurgeIoForSuspend()
Definition: devhcd.cpp:917
SM_RESULT AtPassive(_In_ DSM_THEN Then)
Definition: devsm.cpp:177
BOOLEAN DisableWhenUnused()
Definition: devmisc.cpp:331
SM_RESULT OnAwaitingPowerUpForReset(_In_ DsmEvent Event)
VOID StartDeviceIo()
Definition: devhcd.cpp:934
SM_RESULT UnconfiguredResumedWithHub(_In_ DsmEvent Event)
static const State RequestingCritical
Definition: devsm.h:230
VOID ForceResetOnNextStart()
Definition: childpdo.cpp:4090
SM_RESULT OnSuspendedHubSuspended(_In_ DsmEvent Event)
static const State AwaitingPowerUpAfterWake
Definition: devsm.h:954
SM_RESULT OnUnconfiguredOn(_In_ DsmEvent Event)
Definition: devsm_power.cpp:71
SM_RESULT SuspendIoPurged(_In_ DsmEvent Event)
SM_RESULT UnconfiguredPortOffForStop(_In_ DsmEvent Event)
static const State Stopped
Definition: devsm.h:836
SM_RESULT OnUnconfiguredHubSuspended(_In_ DsmEvent Event)
SM_RESULT OnDeviceSuspended(_In_ DsmEvent Event)
SM_RESULT EnterSuspendingUnconfigured()
BOOLEAN m_D3Cold
Definition: devsm.h:1854
SM_RESULT SuspendedDisarmed(_In_ DsmEvent Event)
VOID SignalQueryText()
Definition: childpdo.cpp:4064
SM_RESULT GoUnconfiguredOn()
Definition: devsm_power.cpp:63
SM_RESULT SuspendArmed(_In_ DsmEvent Event)
VOID MarkResetAtResume()
Definition: childpdo.cpp:4102
static const State UnconfiguredHubSuspended
Definition: devsm.h:950
static const State UnconfiguredOn
Definition: devsm.h:947
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
@ LpmSettingChanged
static const DsmEvent PowerLpmDiscards[]
Definition: devsm_power.cpp:15
_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
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFREQUEST Request
_In_ WDFDPC _In_ BOOLEAN Wait
Definition: wdfdpc.h:170