mirror of
https://github.com/reactos/reactos.git
synced 2025-03-10 10:14:44 +00:00
469 lines
11 KiB
C++
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;
|
|
}
|