2020-09-24 20:51:15 +00:00
|
|
|
/*++
|
|
|
|
|
|
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
|
|
|
|
Module Name:
|
|
|
|
|
|
|
|
FxInterrupt.hpp
|
|
|
|
|
|
|
|
Abstract:
|
|
|
|
|
|
|
|
This module implements a frameworks managed interrupt object
|
|
|
|
|
|
|
|
Author:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Environment:
|
|
|
|
|
|
|
|
Both kernel and user mode
|
|
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
|
|
|
#ifndef _FXINTERRUPT_H_
|
|
|
|
#define _FXINTERRUPT_H_
|
|
|
|
|
2020-10-16 03:30:51 +00:00
|
|
|
#include "fxwakeinterruptstatemachine.hpp"
|
2020-09-24 20:51:15 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// We need two parameters for KeSynchronizeExecution when enabling
|
|
|
|
// and disabling interrupts, so we use this structure on the stack since its
|
|
|
|
// a synchronous call.
|
|
|
|
//
|
|
|
|
struct FxInterruptEnableParameters {
|
|
|
|
FxInterrupt* Interrupt;
|
|
|
|
NTSTATUS ReturnVal;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef FxInterruptEnableParameters FxInterruptDisableParameters;
|
|
|
|
|
|
|
|
|
|
|
|
class FxInterrupt : public FxNonPagedObject {
|
|
|
|
|
|
|
|
friend FxPkgPnp;
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
//
|
|
|
|
// User supplied configuration
|
|
|
|
//
|
|
|
|
WDF_TRI_STATE m_ShareVector;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Kernel Interupt object
|
|
|
|
//
|
|
|
|
struct _KINTERRUPT* m_Interrupt;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Kernel spinlock for Interrupt
|
|
|
|
//
|
|
|
|
MdLock* m_SpinLock;
|
|
|
|
|
|
|
|
KIRQL m_OldIrql;
|
|
|
|
volatile KIRQL m_SynchronizeIrql;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Built in SpinLock/PassiveLock
|
|
|
|
//
|
|
|
|
MxLock m_BuiltInSpinLock;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Passive-level interrupt handling.
|
|
|
|
//
|
|
|
|
FxWaitLock* m_WaitLock;
|
|
|
|
|
|
|
|
//
|
|
|
|
// DpcForIsr and WorkItemForIsr support. Note that a DPC is still
|
|
|
|
// needed even if the driver opts to use WorkItemForIsr when
|
|
|
|
// driver handles interrupts at DIRQL.
|
|
|
|
//
|
|
|
|
#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE))
|
|
|
|
KDPC m_Dpc;
|
|
|
|
#endif
|
|
|
|
FxSystemWorkItem* m_SystemWorkItem;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Automatic serialization: this is the callback lock for the object the DPC or
|
|
|
|
// work-item will synchronize with.
|
|
|
|
//
|
|
|
|
FxCallbackLock* m_CallbackLock;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Set to TRUE when WDF is responsible for disposing the wait-lock.
|
|
|
|
//
|
|
|
|
BOOLEAN m_DisposeWaitLock;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Value provided by driver. When TRUE we use IoReportActive/Inactive to
|
|
|
|
// do soft connect/disconnect on explicit power transitions.
|
|
|
|
//
|
|
|
|
BOOLEAN m_UseSoftDisconnect;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Set to TRUE for passive-level interrupt handling.
|
|
|
|
//
|
|
|
|
BOOLEAN m_PassiveHandling;
|
|
|
|
|
|
|
|
// set to TRUE once the interrupt has been added to the pnp package's
|
|
|
|
// interrupt list
|
|
|
|
BOOLEAN m_AddedToList;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Indicates whether the driver has forced a disconnect. If so, then
|
|
|
|
// we should stop automatically managing the connected state.
|
|
|
|
//
|
|
|
|
BOOLEAN m_Connected;
|
|
|
|
BOOLEAN m_ForceDisconnected;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Indicates whether the m_EvtInterruptPostEnable succeeded or not.
|
|
|
|
//
|
|
|
|
BOOLEAN m_Enabled;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Save floating point when the ISR runs
|
|
|
|
//
|
|
|
|
BOOLEAN m_FloatingSave;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Set to TRUE if interrupt is created in the prepare hardware callback.
|
|
|
|
//
|
|
|
|
BOOLEAN m_CreatedInPrepareHardware;
|
|
|
|
|
|
|
|
//
|
|
|
|
// State machine to manage a wake capable interrupt
|
|
|
|
//
|
|
|
|
FxWakeInterruptMachine* m_WakeInterruptMachine;
|
|
|
|
|
|
|
|
|
|
|
|
#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE))
|
|
|
|
//
|
|
|
|
// Set to true on successful connect or when driver reports active.
|
|
|
|
// (this field is mainly for aid in debugging)
|
|
|
|
//
|
|
|
|
BOOLEAN m_Active;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
|
|
// Interrupt policy
|
|
|
|
//
|
|
|
|
BOOLEAN m_SetPolicy;
|
|
|
|
WDF_INTERRUPT_POLICY m_Policy;
|
|
|
|
WDF_INTERRUPT_PRIORITY m_Priority;
|
|
|
|
GROUP_AFFINITY m_Processors;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Callbacks
|
|
|
|
//
|
|
|
|
PFN_WDF_INTERRUPT_ENABLE m_EvtInterruptEnable;
|
|
|
|
PFN_WDF_INTERRUPT_DISABLE m_EvtInterruptDisable;
|
|
|
|
|
|
|
|
PFN_WDF_INTERRUPT_ISR m_EvtInterruptIsr;
|
|
|
|
PFN_WDF_INTERRUPT_DPC m_EvtInterruptDpc;
|
|
|
|
PFN_WDF_INTERRUPT_WORKITEM m_EvtInterruptWorkItem;
|
|
|
|
|
|
|
|
#if ((FX_CORE_MODE)==(FX_CORE_USER_MODE))
|
|
|
|
//
|
|
|
|
// Rd interrupt object
|
|
|
|
//
|
|
|
|
RD_INTERRUPT_CONTEXT m_RdInterruptContext;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Each interrupt object has this structure which comprises an event and a
|
|
|
|
// wait structure. The wait struture is associted with interrupt's callback
|
|
|
|
// and the event, and is queued to threadpool. The callback is invoked when
|
|
|
|
// the event is set.
|
|
|
|
//
|
|
|
|
FxInterruptWaitblock* m_InterruptWaitblock;
|
|
|
|
|
|
|
|
//
|
|
|
|
// True if the interrupt callback can queue another interrupt wait.
|
|
|
|
// Set to true when interrupt is connected and false when interrupts
|
|
|
|
// callbacks and waits are flushed.
|
|
|
|
//
|
|
|
|
BOOLEAN m_CanQueue;
|
|
|
|
|
|
|
|
//
|
|
|
|
// UMDF's handling of interrupt is split in two parts:
|
|
|
|
// 1. framwork code- runs at passive always and therefore uses mode-agnostic
|
|
|
|
// code meant for passive-level handling, tracked through m_PassiveLevel
|
|
|
|
// field of interrupt object.
|
|
|
|
// 2. redirector code- does passive handling of all of level-triggered
|
|
|
|
// interrupt and DIRQL handing of all others (edge and msi). Driver
|
|
|
|
// doesn't have any choice in that. The PassiveHandling field in the
|
|
|
|
// interrupt config is always set for passive for UMDF (through UMDF's
|
|
|
|
// init function).
|
|
|
|
//
|
|
|
|
// This field stores the type of handling done by redirector as opposed to
|
|
|
|
// m_PassiveHandling which stores user's choice.
|
|
|
|
//
|
|
|
|
BOOLEAN m_PassiveHandlingByRedirector;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
|
|
// PnP data about the interrupt.
|
|
|
|
//
|
|
|
|
WDF_INTERRUPT_INFO m_InterruptInfo;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Weak ref to the translated resource interrupt descriptor.
|
|
|
|
// It is valid from prepare hardware callback to release hardware callback.
|
|
|
|
//
|
|
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR m_CmTranslatedResource;
|
|
|
|
|
|
|
|
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
|
|
|
|
//
|
|
|
|
// Callback used to set m_Disconnecting, synchronized to running ISRs.
|
|
|
|
// Only runs if m_IsEdgeTriggeredNonMsiInterrupt is TRUE.
|
|
|
|
//
|
|
|
|
static
|
|
|
|
MdInterruptSynchronizeRoutineType _InterruptMarkDisconnecting;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Backup KINTERRUPT pointer, captured from the KMDF ISR thunk. We need it
|
|
|
|
// because valid interrupts may arrive before IoConnectInterruptEx sets
|
|
|
|
// FxInterrupt.m_Interrupt. Non-NULL only if m_IsEdgeTriggeredNonMsiInterrupt is TRUE.
|
|
|
|
//
|
|
|
|
struct _KINTERRUPT* m_InterruptCaptured;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
|
|
// Used to mark the interrupt disconnect window, and to discard interrupts
|
|
|
|
// that arrive within this window. Only set if m_IsEdgeTriggeredNonMsiInterrupt is TRUE.
|
|
|
|
//
|
|
|
|
BOOLEAN m_Disconnecting;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Set if this is an Edge-Triggered non-MSI interrupt. These interrupts are
|
|
|
|
// stateful and it is important not to drop any around the connection window.
|
|
|
|
//
|
|
|
|
BOOLEAN m_IsEdgeTriggeredNonMsiInterrupt;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
LIST_ENTRY m_PnpList;
|
|
|
|
|
|
|
|
public:
|
|
|
|
FxInterrupt(
|
|
|
|
__in PFX_DRIVER_GLOBALS FxDriverGlobals
|
|
|
|
);
|
|
|
|
|
|
|
|
virtual
|
|
|
|
~FxInterrupt(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
static
|
|
|
|
NTSTATUS
|
|
|
|
_CreateAndInit(
|
|
|
|
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
|
|
|
__in CfxDevice * Device,
|
|
|
|
__in_opt FxObject * Parent,
|
|
|
|
__in PWDF_OBJECT_ATTRIBUTES Attributes,
|
|
|
|
__in PWDF_INTERRUPT_CONFIG Configuration,
|
|
|
|
__out FxInterrupt ** Interrupt
|
|
|
|
);
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
2020-10-16 03:30:51 +00:00
|
|
|
CreateWakeInterruptMachine(
|
2020-09-24 20:51:15 +00:00
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
Initialize(
|
|
|
|
__in CfxDevice* Device,
|
|
|
|
__in FxObject* Parent,
|
|
|
|
__in PWDF_INTERRUPT_CONFIG Configuration
|
|
|
|
);
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
InitializeWorker(
|
|
|
|
__in FxObject* Parent,
|
|
|
|
__in PWDF_INTERRUPT_CONFIG Configuration
|
|
|
|
);
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
InitializeInternal(
|
|
|
|
__in FxObject* Parent,
|
|
|
|
__in PWDF_INTERRUPT_CONFIG Configuration
|
|
|
|
);
|
|
|
|
|
|
|
|
virtual
|
|
|
|
BOOLEAN
|
|
|
|
Dispose(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
virtual
|
|
|
|
VOID
|
|
|
|
DeleteObject(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
OnPostReleaseHardware(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
DpcHandler(
|
|
|
|
__in_opt PVOID SystemArgument1,
|
|
|
|
__in_opt PVOID SystemArgument2
|
|
|
|
);
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
QueueDpcForIsr(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
Synchronize(
|
|
|
|
__in PFN_WDF_INTERRUPT_SYNCHRONIZE Callback,
|
|
|
|
__in WDFCONTEXT Context
|
|
|
|
);
|
|
|
|
|
|
|
|
struct _KINTERRUPT*
|
|
|
|
GetInterruptPtr(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
__inline
|
|
|
|
BOOLEAN
|
|
|
|
IsWakeCapable(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return ((m_WakeInterruptMachine != NULL) ? TRUE:FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
SetActiveForWake(
|
|
|
|
__in BOOLEAN ActiveForWake
|
|
|
|
)
|
|
|
|
{
|
|
|
|
m_WakeInterruptMachine->m_ActiveForWake = ActiveForWake;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
IsActiveForWake(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if ((m_WakeInterruptMachine != NULL) &&
|
|
|
|
(m_WakeInterruptMachine->m_ActiveForWake)) {
|
|
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
ProcessWakeInterruptEvent(
|
|
|
|
__in FxWakeInterruptEvents Event
|
|
|
|
)
|
|
|
|
{
|
|
|
|
m_WakeInterruptMachine->ProcessEvent(Event);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE))
|
|
|
|
|
|
|
|
VOID
|
|
|
|
ReportActive(
|
|
|
|
_In_ BOOLEAN Internal = FALSE
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
ReportInactive(
|
|
|
|
_In_ BOOLEAN Internal = FALSE
|
|
|
|
);
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
IsSoftDisconnectCapable(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (m_UseSoftDisconnect &&
|
|
|
|
FxLibraryGlobals.IoReportInterruptInactive != NULL &&
|
|
|
|
m_Interrupt != NULL &&
|
|
|
|
m_Connected) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif ((FX_CORE_MODE)==(FX_CORE_USER_MODE))
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
IsSoftDisconnectCapable(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// Not implemented for UMDF
|
|
|
|
//
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
ReportActive(
|
|
|
|
_In_ BOOLEAN Internal = FALSE
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UNREFERENCED_PARAMETER(Internal);
|
|
|
|
//
|
|
|
|
// Not implemented for UMDF
|
|
|
|
//
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
ReportInactive(
|
|
|
|
_In_ BOOLEAN Internal = FALSE
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UNREFERENCED_PARAMETER(Internal);
|
|
|
|
//
|
|
|
|
// Not implemented for UMDF
|
|
|
|
//
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
VOID
|
|
|
|
WorkItemHandler(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
QueueWorkItemForIsr(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
__inline
|
|
|
|
BOOLEAN
|
|
|
|
IsPassiveHandling(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return m_PassiveHandling;
|
|
|
|
}
|
|
|
|
|
|
|
|
__inline
|
|
|
|
BOOLEAN
|
|
|
|
IsPassiveConnect(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// UMDF's handling of interrupt is split in two parts:
|
|
|
|
// 1. framework code that runs at passive always in host process and
|
|
|
|
// therefore uses mode-agnostic code meant for passive-level handling,
|
|
|
|
// tracked through m_PassiveHandling member.
|
|
|
|
// field of interrupt object.
|
|
|
|
// 2. redirector code that does passive handling of all of level-triggered
|
|
|
|
// interrupt and DIRQL handing of all others (edge and msi). Driver
|
|
|
|
// doesn't have any choice in that. The m_PassiveHandling field in the
|
|
|
|
// interrupt config is always set for passive for UMDF (through UMDF's
|
|
|
|
// init function). m_PasiveHandlingByRedirector member is present to
|
|
|
|
// this part of code.
|
|
|
|
// In summary, m_PassiveHandling and m_PasiveHandlingByRedirector
|
|
|
|
// effectively maintain how the interrupt is connected (passive or DIRQL),
|
|
|
|
// for KMDF and UMDF respectively. This routine tells how the
|
|
|
|
// interrupt is connnected by looking at these members.
|
|
|
|
//
|
|
|
|
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
|
|
|
|
return IsPassiveHandling();
|
|
|
|
#else
|
|
|
|
return m_PassiveHandlingByRedirector;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
__inline
|
|
|
|
BOOLEAN
|
|
|
|
IsAutomaticSerialization(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return m_CallbackLock != NULL ? TRUE : FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
AcquireLock(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
TryToAcquireLock(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
ReleaseLock(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
CfxDevice*
|
|
|
|
GetDevice(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return m_Device;
|
|
|
|
}
|
|
|
|
|
|
|
|
PWDF_INTERRUPT_INFO
|
|
|
|
GetInfo(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
WDFINTERRUPT
|
|
|
|
GetHandle(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return (WDFINTERRUPT) GetObjectHandle();
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
IsSharedSpinLock(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return m_SpinLock != &m_BuiltInSpinLock.Get() ? TRUE : FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
IsSyncIrqlSet(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return m_SynchronizeIrql != PASSIVE_LEVEL ? TRUE : FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
KIRQL
|
|
|
|
GetSyncIrql(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return m_SynchronizeIrql;
|
|
|
|
}
|
|
|
|
|
|
|
|
KIRQL
|
|
|
|
GetResourceIrql(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return m_InterruptInfo.Irql;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
SharesLock(
|
|
|
|
FxInterrupt* Interrupt
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return m_SpinLock == Interrupt->m_SpinLock ? TRUE : FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
VOID
|
|
|
|
Reset(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
ResetInternal(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
SetSyncIrql(
|
|
|
|
KIRQL SyncIrql
|
|
|
|
)
|
|
|
|
{
|
|
|
|
m_SynchronizeIrql = SyncIrql;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Called from workitem to perform final flushing of any
|
|
|
|
// outstanding DPC's and dereferencing of objects.
|
|
|
|
//
|
|
|
|
VOID
|
|
|
|
FlushAndRundown(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
FlushAndRundownInternal(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
static
|
|
|
|
MdInterruptServiceRoutineType _InterruptThunk;
|
|
|
|
|
|
|
|
static
|
|
|
|
EVT_SYSTEMWORKITEM _InterruptWorkItemCallback;
|
|
|
|
|
|
|
|
static
|
|
|
|
MdInterruptSynchronizeRoutineType _InterruptSynchronizeThunk;
|
|
|
|
|
|
|
|
#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE))
|
|
|
|
|
|
|
|
static
|
|
|
|
MdDeferredRoutineType _InterruptDpcThunk;
|
|
|
|
|
|
|
|
#elif ((FX_CORE_MODE)==(FX_CORE_USER_MODE))
|
|
|
|
|
|
|
|
static
|
|
|
|
MX_WORKITEM_ROUTINE _InterruptWorkItemThunk;
|
|
|
|
|
|
|
|
VOID
|
|
|
|
ThreadpoolWaitCallback(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
QueueSingleWaitOnInterruptEvent(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
StartThreadpoolWaitQueue(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
StopAndFlushThreadpoolWaitQueue(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
|
|
// Helper functions to enable an interrupt.
|
|
|
|
// Sequence:
|
|
|
|
// (1) InterruptEnable
|
|
|
|
// (2) _InterruptEnableThunk
|
|
|
|
// (3) InterruptEnableInvokeCallback
|
|
|
|
//
|
|
|
|
NTSTATUS
|
|
|
|
InterruptEnable(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
static
|
|
|
|
MdInterruptSynchronizeRoutineType _InterruptEnableThunk;
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
InterruptEnableInvokeCallback(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Helper functions to disable an interrupt.
|
|
|
|
// Sequence:
|
|
|
|
// (1) InterruptDisable
|
|
|
|
// (2) _InterruptDisableThunk
|
|
|
|
// (3) InterruptDisableInvokeCallback
|
|
|
|
//
|
|
|
|
NTSTATUS
|
|
|
|
InterruptDisable(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
static
|
|
|
|
MdInterruptSynchronizeRoutineType _InterruptDisableThunk;
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
InterruptDisableInvokeCallback(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
public:
|
|
|
|
static
|
|
|
|
BOOLEAN
|
|
|
|
_IsMessageInterrupt(
|
|
|
|
__in USHORT ResourceFlags
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (ResourceFlags & CM_RESOURCE_INTERRUPT_MESSAGE) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
BOOLEAN
|
|
|
|
_IsWakeHintedInterrupt(
|
|
|
|
__in USHORT ResourceFlags
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (ResourceFlags & CM_RESOURCE_INTERRUPT_WAKE_HINT) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
Connect(
|
|
|
|
__in ULONG NotifyFlags
|
|
|
|
);
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
ConnectInternal(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
Disconnect(
|
|
|
|
__in ULONG NotifyFlags
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
DisconnectInternal(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
ForceDisconnect(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
ForceReconnect(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
FilterResourceRequirements(
|
|
|
|
__inout PIO_RESOURCE_DESCRIPTOR IoResourceDescriptor
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
AssignResources(
|
|
|
|
__in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescRaw,
|
|
|
|
__in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescTrans
|
|
|
|
);
|
|
|
|
|
|
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR
|
|
|
|
GetResources(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
// Weak ref to the translated resource interrupt descriptor.
|
|
|
|
// It is valid from prepare hardware callback to release hardware callback.
|
|
|
|
return m_CmTranslatedResource;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
AssignResourcesInternal(
|
|
|
|
__in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescRaw,
|
|
|
|
__in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescTrans,
|
|
|
|
__in PWDF_INTERRUPT_INFO InterruptConfig
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
RevokeResources(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
RevokeResourcesInternal(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
SetPolicy(
|
|
|
|
__in WDF_INTERRUPT_POLICY Policy,
|
|
|
|
__in WDF_INTERRUPT_PRIORITY Priority,
|
|
|
|
__in PGROUP_AFFINITY TargetProcessorSet
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
SetPolicyInternal(
|
|
|
|
__in WDF_INTERRUPT_POLICY Policy,
|
|
|
|
__in WDF_INTERRUPT_PRIORITY Priority,
|
|
|
|
__in PGROUP_AFFINITY TargetProcessorSet
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
FlushQueuedDpcs(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
FlushQueuedWorkitem(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
InvokeWakeInterruptEvtIsr(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
WakeInterruptIsr(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
IsLevelTriggered(
|
|
|
|
__in ULONG Flags
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return ((Flags & CM_RESOURCE_INTERRUPT_LEVEL_LATCHED_BITS)
|
|
|
|
== CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE);
|
|
|
|
}
|
|
|
|
|
|
|
|
__inline
|
|
|
|
BOOLEAN
|
|
|
|
QueueDeferredRoutineForIsr(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// Queue DPC for KMDF and workitem for UMDF. Note that driver can either
|
|
|
|
// specify EvtInterruptDpc or EvtInterruptWorkItem, and therefore it can
|
|
|
|
// either call WdfInterruptQueueDpcForisr or WdfInterruptQueueWorkitemForIsr.
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
|
|
|
|
return QueueDpcForIsr();
|
|
|
|
#else
|
|
|
|
return QueueWorkItemForIsr();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
_SynchronizeExecution(
|
|
|
|
__in MdInterrupt Interrupt,
|
|
|
|
__in MdInterruptSynchronizeRoutine SynchronizeRoutine,
|
|
|
|
__in PVOID SynchronizeContext
|
|
|
|
);
|
|
|
|
|
|
|
|
#endif // _FXINTERRUPT_H_
|