reactos/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/powerpolicystatemachineum.cpp

214 lines
5.1 KiB
C++
Raw Normal View History

/*++
Copyright (c) Microsoft. All rights reserved.
Module Name:
PowerPolicyStateMachineUM.cpp
Abstract:
Environment:
User mode only
Revision History:
--*/
#include "..\pnppriv.hpp"
#include "FxUsbIdleInfo.hpp"
extern "C" {
#if defined(EVENT_TRACING)
#include "PowerPolicyStateMachineUM.tmh"
#endif
}
VOID
FxPkgPnp::PowerPolicyUpdateSystemWakeSource(
__in FxIrp* Irp
)
/*++
Routine Description:
Gets source of wake if OS supports this.
Arguments:
Irp
Return Value:
None
--*/
{
PFX_DRIVER_GLOBALS pFxDriverGlobals;
UNREFERENCED_PARAMETER(Irp);
if (m_Device->IsPdo()) {
pFxDriverGlobals = GetDriverGlobals();
DoTraceLevelMessage(
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
"For PDOs, FxPkgPnp::PowerPolicyUpdateSystemWakeSource should NOT "
"be a no-op!");
FxVerifierDbgBreakPoint(pFxDriverGlobals);
}
}
BOOLEAN
FxPkgPnp::ShouldProcessPowerPolicyEventOnDifferentThread(
__in KIRQL CurrentIrql,
__in BOOLEAN CallerSpecifiedProcessingOnDifferentThread
)
/*++
Routine Description:
This function returns whether the power policy state machine should process
the current event on the same thread or on a different one.
This function has been added to work around a bug in the state machines.
The idle state machine always calls PowerPolicyProcessEvent with the idle
state machine lock held. Some events sent by the idle state machine can
cause the power policy state machine to invoke
FxPowerIdleMachine::QueryReturnToIdle().
FxPowerIdleMachine::QueryReturnToIdle() will try to acquire the idle state
machine lock, which is already being held, so it will result in a recursive
acquire of the idle state machine lock.
The above bug only affects UMDF, but not KMDF. In KMDF, the idle state
machine lock is a spinlock. When PowerPolicyProcessEvent is called, it is
called with the spinlock held and hence at dispatch level. Note that if
called at a non-passive IRQL, PowerPolicyProcessEvent will always queue a
work item to process the event at passive IRQL later. Queuing a work item
forces processing to happen on a different thread and hence we don't
attempt to recursively acquire the spinlock. On the other hand, with UMDF
we are always at passive IRQL and hence we process the event on the same
thread and run into the recursive acquire problem.
Arguments:
CurrentIrql - The current IRQL
CallerSpecifiedProcessingOnDifferentThread - Whether or not caller of
PowerPolicyProcessEvent specified that the event be processed on a
different thread.
Returns:
TRUE if the power policy state machine should process the event on a
different thread.
FALSE if the power policy state machine should process the event on the
same thread
--*/
{
//
// For UMDF, we ignore the IRQL and just do what the caller of
// PowerPolicyProcessEvent wants.
//
UNREFERENCED_PARAMETER(CurrentIrql);
return CallerSpecifiedProcessingOnDifferentThread;
}
_Must_inspect_result_
NTSTATUS
FxUsbIdleInfo::Initialize(
VOID
)
{
HRESULT hr;
NTSTATUS status;
FxDevice* device;
IWudfDeviceStack *devStack;
device = ((FxPkgPnp*)m_CallbackInfo.IdleContext)->GetDevice();
devStack = device->GetDeviceStack();
hr = devStack->InitializeUsbSS();
if (S_OK == hr) {
status = STATUS_SUCCESS;
}
else {
PUMDF_VERSION_DATA driverVersion = devStack->GetMinDriverVersion();
BOOL preserveCompat =
devStack->ShouldPreserveIrpCompletionStatusCompatibility();
status = CHostFxUtil::NtStatusFromHr(hr,
driverVersion->MajorNumber,
driverVersion->MinorNumber,
preserveCompat);
}
return status;
}
VOID
FxPkgPnp::PowerPolicySubmitUsbIdleNotification(
VOID
)
{
//
// This will be set to TRUE if USBSS completion event gets dropped.
//
m_PowerPolicyMachine.m_Owner->m_UsbIdle->m_EventDropped = FALSE;
m_Device->GetDeviceStack()->SubmitUsbIdleNotification(
&(m_PowerPolicyMachine.m_Owner->m_UsbIdle->m_CallbackInfo),
_PowerPolicyUsbSelectiveSuspendCompletionRoutine,
this);
}
VOID
FxPkgPnp::PowerPolicyCancelUsbSS(
VOID
)
{
m_Device->GetDeviceStack()->CancelUsbSS();
}
__drv_maxIRQL(PASSIVE_LEVEL)
VOID
FxUsbIdleInfo::_UsbIdleCallback(
__in PVOID Context
)
{
FxPkgPnp* pPkgPnp;
pPkgPnp = (FxPkgPnp*) Context;
DoTraceLevelMessage(
pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
"Entering USB Selective Suspend Idle callback");
pPkgPnp->PowerPolicyProcessEvent(PwrPolUsbSelectiveSuspendCallback);
}
VOID
FxPowerPolicyMachine::UsbSSCallbackProcessingComplete(
VOID
)
{
FxDevice* device = m_PkgPnp->GetDevice();
DoTraceLevelMessage(
m_PkgPnp->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
"USB Selective Suspend Idle callback processing is complete");
device->GetDeviceStack()->SignalUsbSSCallbackProcessingComplete();
}