📄 miniport.cpp
字号:
// ==============================================================================
//
// miniport.cpp - miniport driver implementation for FM synth.
// Copyright (c) 1996-2000 Microsoft Corporation. All rights reserved.
//
// ==============================================================================
#include "private.h" // contains class definitions.
#define STR_MODULENAME "FMSynth: "
#pragma code_seg("PAGE")
// ==============================================================================
// CreateMiniportMidiFM()
// Creates a MIDI FM miniport driver. This uses a
// macro from STDUNK.H to do all the work.
// ==============================================================================
NTSTATUS CreateMiniportMidiFM
(
OUT PUNKNOWN * Unknown,
IN REFCLSID ClassID,
IN PUNKNOWN UnknownOuter OPTIONAL,
IN POOL_TYPE PoolType
)
{
PAGED_CODE();
ASSERT(Unknown);
_DbgPrintF(DEBUGLVL_VERBOSE, ("CreateMiniportMidiFM"));
// expand STD_CREATE_BODY_ to take constructor(boolean) for whether to include volume
NTSTATUS ntStatus;
CMiniportMidiFM *p =
new(PoolType,'MFcP') CMiniportMidiFM(
UnknownOuter,
(IsEqualGUIDAligned(ClassID,CLSID_MiniportDriverFmSynthWithVol))
);
#ifdef DEBUG
if (IsEqualGUIDAligned(ClassID,CLSID_MiniportDriverFmSynthWithVol))
{
_DbgPrintF(DEBUGLVL_VERBOSE, ("Creating new FM miniport with volume node"));
}
#endif
if (p)
{
*Unknown = PUNKNOWN((PMINIPORTMIDI)(p));
(*Unknown)->AddRef();
ntStatus = STATUS_SUCCESS;
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
return ntStatus;
}
#pragma code_seg("PAGE")
// ==============================================================================
// CMiniportMidiFM::ProcessResources()
// Processes the resource list.
// ==============================================================================
NTSTATUS
CMiniportMidiFM::
ProcessResources
(
IN PRESOURCELIST ResourceList
)
{
PAGED_CODE();
ASSERT(ResourceList);
if (!ResourceList)
{
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
_DbgPrintF(DEBUGLVL_VERBOSE,("CMiniportMidiFM::ProcessResources"));
//
// Get counts for the types of resources.
//
ULONG countIO = ResourceList->NumberOfPorts();
ULONG countIRQ = ResourceList->NumberOfInterrupts();
ULONG countDMA = ResourceList->NumberOfDmas();
NTSTATUS ntStatus = STATUS_SUCCESS;
//
// Make sure we have the expected number of resources.
//
if ( (countIO != 1)
|| (countIRQ != 0)
|| (countDMA != 0)
)
{
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
}
if (NT_SUCCESS(ntStatus))
{
//
// Get the port address.
//
m_PortBase = PUCHAR(ResourceList->FindTranslatedPort(0)->u.Port.Start.QuadPart);
_DbgPrintF(DEBUGLVL_VERBOSE, ("Port Address = 0x%X", m_PortBase));
}
return ntStatus;
}
#pragma code_seg("PAGE")
// ==============================================================================
// CMiniportMidiFM::NonDelegatingQueryInterface()
// Obtains an interface. This function works just like a COM QueryInterface
// call and is used if the object is not being aggregated.
// ==============================================================================
STDMETHODIMP_(NTSTATUS) CMiniportMidiFM::NonDelegatingQueryInterface
(
REFIID Interface,
PVOID * Object
)
{
PAGED_CODE();
ASSERT(Object);
_DbgPrintF(DEBUGLVL_VERBOSE,("CMiniportMidiFM::NonDelegatingQueryInterface"));
if (IsEqualGUIDAligned(Interface,IID_IUnknown))
{
*Object = PVOID(PUNKNOWN(PMINIPORT(this)));
}
else if (IsEqualGUIDAligned(Interface,IID_IMiniport))
{
*Object = PVOID(PMINIPORT(this));
}
else if (IsEqualGUIDAligned(Interface,IID_IMiniportMidi))
{
*Object = PVOID(PMINIPORTMIDI(this));
}
else if (IsEqualGUIDAligned(Interface, IID_IPowerNotify))
{
*Object = PVOID(PPOWERNOTIFY(this));
}
else
{
*Object = NULL;
}
if (*Object)
{
//
// We reference the interface for the caller.
//
PUNKNOWN((PMINIPORT)*Object)->AddRef();
return STATUS_SUCCESS;
}
return STATUS_INVALID_PARAMETER;
}
#pragma code_seg()
// ==============================================================================
// CMiniportMidiFM::~CMiniportMidiFM()
// Destructor.
// ==============================================================================
CMiniportMidiFM::~CMiniportMidiFM
(
void
)
{
KIRQL oldIrql;
_DbgPrintF(DEBUGLVL_VERBOSE,("CMiniportMidiFM::~CMiniportMidiFM"));
KeAcquireSpinLock(&m_SpinLock,&oldIrql);
// Set silence on the device
Opl3_BoardReset();
KeReleaseSpinLock(&m_SpinLock,oldIrql);
if (m_Port)
{
m_Port->Release();
}
}
#pragma code_seg()
// ==============================================================================
// CMiniportMidiFM::Init()
// Initializes a the miniport.
// ==============================================================================
STDMETHODIMP_(NTSTATUS)
CMiniportMidiFM::
Init
(
IN PUNKNOWN UnknownAdapter OPTIONAL,
IN PRESOURCELIST ResourceList,
IN PPORTMIDI Port_,
OUT PSERVICEGROUP * ServiceGroup
)
{
PAGED_CODE();
ASSERT(ResourceList);
if (!ResourceList)
{
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
ASSERT(Port_);
ASSERT(ServiceGroup);
int i;
_DbgPrintF(DEBUGLVL_VERBOSE,("CMiniportMidiFM::init"));
//
// AddRef() is required because we are keeping this pointer.
//
m_Port = Port_;
m_Port->AddRef();
//
// m_fStreamExists is not explicitly set to FALSE because C++ zeros
// them out on a 'new'
//
KeInitializeSpinLock(&m_SpinLock);
//
// We want the IAdapterCommon interface on the adapter common object,
// which is given to us as a IUnknown. The QueryInterface call gives us
// an AddRefed pointer to the interface we want.
//
NTSTATUS ntStatus = ProcessResources(ResourceList);
if (NT_SUCCESS(ntStatus))
{
KIRQL oldIrql;
KeAcquireSpinLock(&m_SpinLock,&oldIrql);
for (i = 0; i < 0x200; i++) // initialize the shadow registers, used
m_SavedRegValues[i] = 0x00; // in case of power-down during playback
// Initialize the hardware.
// 1. First check to see if an opl device is present.
// 2. Then determine if it is an opl2 or opl3. Bail if opl2.
// 3. Call Opl3_BoardReset to silence and reset the device.
if (SoundSynthPresent(m_PortBase, m_PortBase))
{
// Now check if the device is an opl2 or opl3 type.
// The patches are already declared for opl3. So Init() is not defined.
// For opl2 we have to go through an init and load the patches structure.
if (SoundMidiIsOpl3())
{
_DbgPrintF(DEBUGLVL_VERBOSE, ("CMiniportMidiFM::Init Type = OPL3"));
// now silence the device and reset the board.
Opl3_BoardReset();
*ServiceGroup = NULL;
}
else
{
_DbgPrintF(DEBUGLVL_TERSE, ("CMiniportMidiFM::Init Type = OPL2"));
ntStatus = STATUS_NOT_IMPLEMENTED;
}
}
else
{
_DbgPrintF(DEBUGLVL_TERSE, ("CMiniportMidiFM::Init SoundSynthPresent failed"));
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
}
KeReleaseSpinLock(&m_SpinLock,oldIrql);
}
else
{
_DbgPrintF(DEBUGLVL_TERSE, ("CMiniportMidiFM::Init ProcessResources failed"));
}
_DbgPrintF(DEBUGLVL_VERBOSE, ("CMiniportMidiFM::Init returning 0x%X", ntStatus));
if (!NT_SUCCESS(ntStatus))
{
//
// clean up our mess
//
// release the port
m_Port->Release();
m_Port = NULL;
}
return ntStatus;
}
#pragma code_seg("PAGE")
// ==============================================================================
// NewStream()
// Creates a new stream.
// ==============================================================================
STDMETHODIMP_(NTSTATUS)
CMiniportMidiFM::
NewStream
(
OUT PMINIPORTMIDISTREAM * Stream,
IN PUNKNOWN OuterUnknown OPTIONAL,
IN POOL_TYPE PoolType,
IN ULONG Pin,
IN BOOLEAN Capture,
IN PKSDATAFORMAT DataFormat,
OUT PSERVICEGROUP * ServiceGroup
)
{
PAGED_CODE();
NTSTATUS ntStatus = STATUS_SUCCESS;
if (m_fStreamExists)
{
_DbgPrintF(DEBUGLVL_TERSE,("CMiniportMidiFM::NewStream stream already exists"));
ntStatus = STATUS_INVALID_DEVICE_REQUEST;
}
else
{
_DbgPrintF(DEBUGLVL_VERBOSE,("CMiniportMidiFM::NewStream"));
CMiniportMidiStreamFM *pStream =
new(PoolType) CMiniportMidiStreamFM(OuterUnknown);
if (pStream)
{
pStream->AddRef();
ntStatus = pStream->Init(this,m_PortBase);
if (NT_SUCCESS(ntStatus))
{
*Stream = PMINIPORTMIDISTREAM(pStream);
(*Stream)->AddRef();
*ServiceGroup = NULL;
m_fStreamExists = TRUE;
}
pStream->Release();
}
else
{
_DbgPrintF(DEBUGLVL_TERSE,("CMiniportMidiFM::NewStream failed, no memory"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
return ntStatus;
}
#pragma code_seg("PAGE")
/*----------------------------------------------------------------------------
FUNCTION NAME- CMiniportMidiFM::PowerChangeNotify()
ENTRY --- IN POWER_STATE NewState
power management status
RETURN --- void
*------------------------------------------------------------------------- */
STDMETHODIMP_(void) CMiniportMidiFM::PowerChangeNotify(
IN POWER_STATE PowerState
)
{
PAGED_CODE();
_DbgPrintF(DEBUGLVL_VERBOSE,("CMiniportMidiFM::PowerChangeNotify(%d)",PowerState));
switch (PowerState.DeviceState)
{
case PowerDeviceD0:
if (m_PowerState.DeviceState != PowerDeviceD0) // check for power state delta
{
MiniportMidiFMResume();
}
break;
case PowerDeviceD1:
case PowerDeviceD2:
case PowerDeviceD3:
default:
// Don't need to do anything special, we always remember where we are.
break;
}
m_PowerState.DeviceState = PowerState.DeviceState;
}
#pragma code_seg()
// ==========================================================================
// ==========================================================================
void
CMiniportMidiFM::
MiniportMidiFMResume()
{
KIRQL oldIrql;
BYTE i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -