reactos/sdk/lib/drivers/wdf/shared/irphandlers/pnp/selfmanagediostatemachine.cpp
Victor Perevertkin 8a978a179f
[WDF] Add Windows Driver Framework files
Takern from Microsoft GitHub repo:
d9c6040fe9

Licensed under MIT
2020-11-03 00:06:26 +03:00

469 lines
11 KiB
C++

/*++
Copyright (c) Microsoft. All rights reserved.
Module Name:
SelfManagedIoStateMachine.cpp
Abstract:
This module implements the self managed io state machine start / stop logic
in the framework.
Author:
Environment:
Both kernel and user mode
Revision History:
--*/
#include "pnppriv.hpp"
extern "C" {
#if defined(EVENT_TRACING)
#include "SelfManagedIoStateMachine.tmh"
#endif
}
// * - We can get a restart from the created state if a PDO is newly enumerated
// but was disabled on a previous enumeration. Treat restart as an init
// in this case.
const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_CreatedStates[] =
{
{ SelfManagedIoEventStart, FxSelfManagedIoInit DEBUGGED_EVENT },
{ SelfManagedIoEventFlush, FxSelfManagedIoCreated DEBUGGED_EVENT },
{ SelfManagedIoEventCleanup, FxSelfManagedIoFinal DEBUGGED_EVENT },
};
const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_InitFailedStates[] =
{
{ SelfManagedIoEventSuspend, FxSelfManagedIoInitFailed DEBUGGED_EVENT },
{ SelfManagedIoEventFlush, FxSelfManagedIoFlushing DEBUGGED_EVENT },
};
const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_StartedStates[] =
{
{ SelfManagedIoEventSuspend, FxSelfManagedIoSuspending DEBUGGED_EVENT },
};
const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_StoppedStates[] =
{
{ SelfManagedIoEventStart, FxSelfManagedIoRestarting DEBUGGED_EVENT },
{ SelfManagedIoEventSuspend, FxSelfManagedIoStopped DEBUGGED_EVENT },
{ SelfManagedIoEventFlush, FxSelfManagedIoFlushing DEBUGGED_EVENT },
};
const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_FailedStates[] =
{
{ SelfManagedIoEventFlush, FxSelfManagedIoFlushing DEBUGGED_EVENT },
{ SelfManagedIoEventSuspend, FxSelfManagedIoFailed DEBUGGED_EVENT },
};
const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_FlushedStates[] =
{
{ SelfManagedIoEventStart, FxSelfManagedIoRestarting DEBUGGED_EVENT },
{ SelfManagedIoEventCleanup, FxSelfManagedIoCleanup DEBUGGED_EVENT },
{ SelfManagedIoEventFlush, FxSelfManagedIoFlushed TRAP_ON_EVENT },
};
const FxSelfManagedIoStateTable FxSelfManagedIoMachine::m_StateTable[] =
{
// FxSelfManagedIoCreated
{ NULL,
FxSelfManagedIoMachine::m_CreatedStates,
ARRAY_SIZE(FxSelfManagedIoMachine::m_CreatedStates),
},
// FxSelfManagedIoInit
{ FxSelfManagedIoMachine::Init,
NULL,
0,
},
// FxSelfManagedIoInitFailed
{ NULL,
FxSelfManagedIoMachine::m_InitFailedStates,
ARRAY_SIZE(FxSelfManagedIoMachine::m_InitFailedStates),
},
// FxSelfManagedIoStarted
{ NULL,
FxSelfManagedIoMachine::m_StartedStates,
ARRAY_SIZE(FxSelfManagedIoMachine::m_StartedStates),
},
// FxSelfManagedIoSuspending
{ FxSelfManagedIoMachine::Suspending,
NULL,
0,
},
// FxSelfManagedIoStopped
{ NULL,
FxSelfManagedIoMachine::m_StoppedStates,
ARRAY_SIZE(FxSelfManagedIoMachine::m_StoppedStates),
},
// FxSelfManagedIoRestarting
{ FxSelfManagedIoMachine::Restarting,
NULL,
0,
},
// FxSelfManagedIoFailed
{ NULL,
FxSelfManagedIoMachine::m_FailedStates,
ARRAY_SIZE(FxSelfManagedIoMachine::m_FailedStates),
},
// FxSelfManagedIoFlushing
{ FxSelfManagedIoMachine::Flushing,
NULL,
0,
},
// FxSelfManagedIoFlushed
{ NULL,
FxSelfManagedIoMachine::m_FlushedStates,
ARRAY_SIZE(FxSelfManagedIoMachine::m_FlushedStates),
},
// FxSelfManagedIoCleanup
{ FxSelfManagedIoMachine::Cleanup,
NULL,
0,
},
// FxSelfManagedIoFinal
{ NULL,
NULL,
0,
},
};
FxSelfManagedIoMachine::FxSelfManagedIoMachine(
__in FxPkgPnp* PkgPnp
)
{
m_PkgPnp = PkgPnp;
m_EventHistoryIndex = 0;
m_StateHistoryIndex = 0;
m_CurrentState = FxSelfManagedIoCreated;
RtlZeroMemory(&m_Events, sizeof(m_Events));
RtlZeroMemory(&m_States, sizeof(m_States));
//
// Make sure we can fit the state into a byte
//
ASSERT(FxSelfManagedIoMax <= 0xFF);
}
NTSTATUS
FxSelfManagedIoMachine::_CreateAndInit(
__deref_out FxSelfManagedIoMachine** SelfManagedIoMachine,
__in FxPkgPnp* PkgPnp
)
{
NTSTATUS status;
FxSelfManagedIoMachine * selfManagedIoMachine;
*SelfManagedIoMachine = NULL;
selfManagedIoMachine = new (PkgPnp->GetDriverGlobals()) FxSelfManagedIoMachine(
PkgPnp
);
if (selfManagedIoMachine == NULL) {
DoTraceLevelMessage(
PkgPnp->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
"Self managed I/O state machine allocation failed for "
"WDFDEVICE 0x%p",
PkgPnp->GetDevice()->GetHandle());
return STATUS_INSUFFICIENT_RESOURCES;
}
status = selfManagedIoMachine->m_StateMachineLock.Initialize();
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
PkgPnp->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
"Self managed I/O state machine lock initialization failed for "
"WDFDEVICE 0x%p, %!STATUS!",
PkgPnp->GetDevice()->GetHandle(),
status);
delete selfManagedIoMachine;
return status;
}
*SelfManagedIoMachine = selfManagedIoMachine;
return status;
}
VOID
FxSelfManagedIoMachine::InitializeMachine(
__in PWDF_PNPPOWER_EVENT_CALLBACKS Callbacks
)
/*++
Routine Description:
Sets all the function event callbacks.
Arguments:
Callbacks - list of callbacks to set
Return Value:
None
--*/
{
m_DeviceSelfManagedIoCleanup.m_Method = Callbacks->EvtDeviceSelfManagedIoCleanup;
m_DeviceSelfManagedIoFlush.m_Method = Callbacks->EvtDeviceSelfManagedIoFlush;
m_DeviceSelfManagedIoInit.m_Method = Callbacks->EvtDeviceSelfManagedIoInit;
m_DeviceSelfManagedIoSuspend.m_Method = Callbacks->EvtDeviceSelfManagedIoSuspend;
m_DeviceSelfManagedIoRestart.m_Method = Callbacks->EvtDeviceSelfManagedIoRestart;
}
WDFDEVICE
FxSelfManagedIoMachine::GetDeviceHandle(
VOID
)
{
return m_PkgPnp->GetDevice()->GetHandle();
}
_Must_inspect_result_
NTSTATUS
FxSelfManagedIoMachine::ProcessEvent(
__in FxSelfManagedIoEvents Event
)
/*++
Routine Description:
Processes an event and runs it through the state machine. Unlike other
state machines in the framework, this one acquires lock in the event
processing function rather then relying on the caller to do so.
Arguments:
Event - The event to feed into the state machine.
Return Value:
result of the event
--*/
{
const FxSelfManagedIoStateTable* entry;
FxSelfManagedIoStates newState;
NTSTATUS status;
m_StateMachineLock.AcquireLock(m_PkgPnp->GetDriverGlobals());
m_Events.History[m_EventHistoryIndex] = (UCHAR) Event;
m_EventHistoryIndex = (m_EventHistoryIndex + 1) %
(sizeof(m_Events.History)/sizeof(m_Events.History[0]));
entry = &m_StateTable[m_CurrentState-FxSelfManagedIoCreated];
newState = FxSelfManagedIoMax;
for (ULONG i = 0; i < entry->TargetStatesCount; i++) {
if (entry->TargetStates[i].SelfManagedIoEvent == Event) {
DO_EVENT_TRAP(&entry->TargetStates[i]);
newState = entry->TargetStates[i].SelfManagedIoState;
break;
}
}
if (newState == FxSelfManagedIoMax) {
//
// We always can handle io increment/decrement from any state, but we
// should not be dropping any other events from this state.
//
COVERAGE_TRAP();
}
status = STATUS_SUCCESS;
while (newState != FxSelfManagedIoMax) {
DoTraceLevelMessage(
m_PkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
"WDFDEVICE 0x%p !devobj 0x%p entering self managed io state "
"%!FxSelfManagedIoStates! from %!FxSelfManagedIoStates!",
m_PkgPnp->GetDevice()->GetHandle(),
m_PkgPnp->GetDevice()->GetDeviceObject(),
newState, m_CurrentState);
m_States.History[m_StateHistoryIndex] = (UCHAR) newState;
m_StateHistoryIndex = (m_StateHistoryIndex + 1) %
(sizeof(m_States.History)/sizeof(m_States.History[0]));
m_CurrentState = (BYTE) newState;
entry = &m_StateTable[m_CurrentState-FxSelfManagedIoCreated];
if (entry->StateFunc != NULL) {
newState = entry->StateFunc(this, &status);
}
else {
newState = FxSelfManagedIoMax;
}
}
m_StateMachineLock.ReleaseLock(m_PkgPnp->GetDriverGlobals());
return status;
}
FxSelfManagedIoStates
FxSelfManagedIoMachine::Init(
__in FxSelfManagedIoMachine* This,
__out PNTSTATUS Status
)
/*++
Routine Description:
Calls the event callback for initializing self managed io.
Arguments:
This - instance of the state machine
Status - result of the event callback into the driver
Return Value:
new machine state
--*/
{
*Status = This->m_DeviceSelfManagedIoInit.Invoke(This->GetDeviceHandle());
if (NT_SUCCESS(*Status)) {
return FxSelfManagedIoStarted;
}
else {
return FxSelfManagedIoInitFailed;
}
}
FxSelfManagedIoStates
FxSelfManagedIoMachine::Suspending(
__in FxSelfManagedIoMachine* This,
__out PNTSTATUS Status
)
/*++
Routine Description:
Invokes the self managed io suspend event callback. Upon failure goes to
the failed state and awaits teardown of the stack.
Arguments:
This - instance of the state machine
Status - result of the event callback into the driver
Return Value:
new machine state
--*/
{
*Status = This->m_DeviceSelfManagedIoSuspend.Invoke(This->GetDeviceHandle());
if (NT_SUCCESS(*Status)) {
return FxSelfManagedIoStopped;
}
else {
return FxSelfManagedIoFailed;
}
}
FxSelfManagedIoStates
FxSelfManagedIoMachine::Restarting(
__in FxSelfManagedIoMachine* This,
__out PNTSTATUS Status
)
/*++
Routine Description:
Invokes the self managed io event callback for restarting self managed io
from the stopped state.
Arguments:
This - instance of the state machine
Status - result of the event callback into the driver
Return Value:
new machine state
--*/
{
*Status = This->m_DeviceSelfManagedIoRestart.Invoke(This->GetDeviceHandle());
if (NT_SUCCESS(*Status)) {
return FxSelfManagedIoStarted;
}
else {
return FxSelfManagedIoFailed;
}
}
FxSelfManagedIoStates
FxSelfManagedIoMachine::Flushing(
__in FxSelfManagedIoMachine* This,
__out PNTSTATUS Status
)
/*++
Routine Description:
Calls the self managed io flush routine.
Arguments:
This - instance of the state machine
Status - result of the event callback into the driver
Return Value:
FxSelfManagedIoFlushed
--*/
{
UNREFERENCED_PARAMETER(Status);
This->m_DeviceSelfManagedIoFlush.Invoke(This->GetDeviceHandle());
return FxSelfManagedIoFlushed;
}
FxSelfManagedIoStates
FxSelfManagedIoMachine::Cleanup(
__in FxSelfManagedIoMachine* This,
__out PNTSTATUS Status
)
/*++
Routine Description:
Calls the self managed io cleanup routine.
Arguments:
This - instance of the state machine
Status - result of the event callback into the driver
Return Value:
FxSelfManagedIoFinal
--*/
{
UNREFERENCED_PARAMETER(Status);
This->m_DeviceSelfManagedIoCleanup.Invoke(This->GetDeviceHandle());
return FxSelfManagedIoFinal;
}