windows-nt/Source/XPSP1/NT/drivers/ddk/wdmaudio/sb16/common.cpp
2020-09-26 16:20:57 +08:00

947 lines
30 KiB
C++

/*****************************************************************************
* common.cpp - Common code used by all the sb16 miniports.
*****************************************************************************
* Copyright (c) 1997-2000 Microsoft Corporation. All rights reserved.
*
* Implmentation of the common code object. This class deals with interrupts
* for the device, and is a collection of common code used by all the
* miniports.
*/
#include "common.h"
#define STR_MODULENAME "sb16Adapter: "
/*****************************************************************************
* CAdapterCommon
*****************************************************************************
* Adapter common object.
*/
class CAdapterCommon
: public IAdapterCommon,
public IAdapterPowerManagement,
public CUnknown
{
private:
PINTERRUPTSYNC m_pInterruptSync;
PUCHAR m_pWaveBase;
PWAVEMINIPORTSB16 m_WaveMiniportSB16;
#ifdef EVENT_SUPPORT
PTOPOMINIPORTSB16 m_TopoMiniportSB16; // Topology miniport of SB16.
#endif
PDEVICE_OBJECT m_pDeviceObject;
DEVICE_POWER_STATE m_PowerState;
BYTE MixerSettings[DSP_MIX_MAXREGS];
void AcknowledgeIRQ
( void
);
public:
DECLARE_STD_UNKNOWN();
DEFINE_STD_CONSTRUCTOR(CAdapterCommon);
~CAdapterCommon();
/*****************************************************************************
* IAdapterCommon methods
*/
STDMETHODIMP_(NTSTATUS) Init
(
IN PRESOURCELIST ResourceList,
IN PDEVICE_OBJECT DeviceObject
);
STDMETHODIMP_(PINTERRUPTSYNC) GetInterruptSync
( void
);
STDMETHODIMP_(void) SetWaveMiniport (IN PWAVEMINIPORTSB16 Miniport)
{
m_WaveMiniportSB16 = Miniport;
}
STDMETHODIMP_(BYTE) ReadController
( void
);
STDMETHODIMP_(BOOLEAN) WriteController
(
IN BYTE Value
);
STDMETHODIMP_(NTSTATUS) ResetController
( void
);
STDMETHODIMP_(void) MixerRegWrite
(
IN BYTE Index,
IN BYTE Value
);
STDMETHODIMP_(BYTE) MixerRegRead
(
IN BYTE Index
);
STDMETHODIMP_(void) MixerReset
( void
);
STDMETHODIMP RestoreMixerSettingsFromRegistry
( void
);
STDMETHODIMP SaveMixerSettingsToRegistry
( void
);
#ifdef EVENT_SUPPORT
//
// The topology miniport needs to tell us the pointer to the Event-interface.
//
STDMETHODIMP_(void) SetTopologyMiniport (IN PTOPOMINIPORTSB16 Miniport)
{
m_TopoMiniportSB16 = Miniport;
};
#endif
/*************************************************************************
* IAdapterPowerManagement implementation
*
* This macro is from PORTCLS.H. It lists all the interface's functions.
*/
IMP_IAdapterPowerManagement;
friend
NTSTATUS
InterruptServiceRoutine
(
IN PINTERRUPTSYNC InterruptSync,
IN PVOID DynamicContext
);
};
static
MIXERSETTING DefaultMixerSettings[] =
{
{ L"LeftMasterVol", DSP_MIX_MASTERVOLIDX_L, 0xD8 },
{ L"RightMasterVol", DSP_MIX_MASTERVOLIDX_R, 0xD8 },
{ L"LeftWaveVol", DSP_MIX_VOICEVOLIDX_L, 0xD8 },
{ L"RightWaveVol", DSP_MIX_VOICEVOLIDX_R, 0xD8 },
{ L"LeftMidiVol", DSP_MIX_FMVOLIDX_L, 0xD8 },
{ L"RightMidiVol", DSP_MIX_FMVOLIDX_R, 0xD8 },
{ L"LeftCDVol", DSP_MIX_CDVOLIDX_L, 0xD8 },
{ L"RightCDVol", DSP_MIX_CDVOLIDX_R, 0xD8 },
{ L"LeftLineInVol", DSP_MIX_LINEVOLIDX_L, 0xD8 },
{ L"RightLineInVol", DSP_MIX_LINEVOLIDX_R, 0xD8 },
{ L"MicVol", DSP_MIX_MICVOLIDX, 0xD8 },
{ L"PcSpkrVol", DSP_MIX_SPKRVOLIDX, 0x00 },
{ L"OutputMixer", DSP_MIX_OUTMIXIDX, 0x1E },
{ L"LeftInputMixer", DSP_MIX_ADCMIXIDX_L, 0x55 },
{ L"RightInputMixer", DSP_MIX_ADCMIXIDX_R, 0x2B },
{ L"LeftInputGain", DSP_MIX_INGAINIDX_L, 0x00 },
{ L"RightInputGain", DSP_MIX_INGAINIDX_R, 0x00 },
{ L"LeftOutputGain", DSP_MIX_OUTGAINIDX_L, 0x80 },
{ L"RightOutputGain", DSP_MIX_OUTGAINIDX_R, 0x80 },
{ L"MicAGC", DSP_MIX_AGCIDX, 0x01 },
{ L"LeftTreble", DSP_MIX_TREBLEIDX_L, 0x80 },
{ L"RightTreble", DSP_MIX_TREBLEIDX_R, 0x80 },
{ L"LeftBass", DSP_MIX_BASSIDX_L, 0x80 },
{ L"RightBass", DSP_MIX_BASSIDX_R, 0x80 },
};
#pragma code_seg("PAGE")
/*****************************************************************************
* NewAdapterCommon()
*****************************************************************************
* Create a new adapter common object.
*/
NTSTATUS
NewAdapterCommon
(
OUT PUNKNOWN * Unknown,
IN REFCLSID,
IN PUNKNOWN UnknownOuter OPTIONAL,
IN POOL_TYPE PoolType
)
{
PAGED_CODE();
ASSERT(Unknown);
STD_CREATE_BODY_
(
CAdapterCommon,
Unknown,
UnknownOuter,
PoolType,
PADAPTERCOMMON
);
}
/*****************************************************************************
* CAdapterCommon::Init()
*****************************************************************************
* Initialize an adapter common object.
*/
NTSTATUS
CAdapterCommon::
Init
(
IN PRESOURCELIST ResourceList,
IN PDEVICE_OBJECT DeviceObject
)
{
PAGED_CODE();
ASSERT(ResourceList);
ASSERT(DeviceObject);
//
// Make sure we have the resources we expect
//
if ((ResourceList->NumberOfPorts() < 1) ||
(ResourceList->NumberOfInterrupts() != 1))
{
_DbgPrintF (DEBUGLVL_TERSE, ("unknown configuration; check your code!"));
// Bail out.
return STATUS_INSUFFICIENT_RESOURCES;
}
m_pDeviceObject = DeviceObject;
m_WaveMiniportSB16 = NULL;
#ifdef EVENT_SUPPORT
m_TopoMiniportSB16 = NULL;
#endif
//
// Get the base address for the wave device.
//
ASSERT(ResourceList->FindTranslatedPort(0));
m_pWaveBase = (PUCHAR)(ResourceList->FindTranslatedPort(0)->u.Port.Start.QuadPart);
//
// Set initial device power state
//
m_PowerState = PowerDeviceD0;
//
// Reset the hardware.
//
NTSTATUS ntStatus = ResetController();
if(NT_SUCCESS(ntStatus))
{
_DbgPrintF(DEBUGLVL_VERBOSE,("ResetController Succeeded"));
AcknowledgeIRQ();
//
// Hook up the interrupt.
//
ntStatus = PcNewInterruptSync( // See portcls.h
&m_pInterruptSync, // Save object ptr
NULL, // OuterUnknown(optional).
ResourceList, // He gets IRQ from ResourceList.
0, // Resource Index
InterruptSyncModeNormal // Run ISRs once until we get SUCCESS
);
if (NT_SUCCESS(ntStatus) && m_pInterruptSync)
{ // run this ISR first
ntStatus = m_pInterruptSync->RegisterServiceRoutine(InterruptServiceRoutine,PVOID(this),FALSE);
if (NT_SUCCESS(ntStatus))
{
ntStatus = m_pInterruptSync->Connect();
}
// if we could not connect or register the ISR, release the object.
if (!NT_SUCCESS (ntStatus))
{
m_pInterruptSync->Release();
m_pInterruptSync = NULL;
}
}
} else
{
_DbgPrintF(DEBUGLVL_TERSE,("ResetController Failure"));
}
return ntStatus;
}
/*****************************************************************************
* CAdapterCommon::~CAdapterCommon()
*****************************************************************************
* Destructor.
*/
CAdapterCommon::
~CAdapterCommon
( void
)
{
PAGED_CODE();
_DbgPrintF(DEBUGLVL_VERBOSE,("[CAdapterCommon::~CAdapterCommon]"));
if (m_pInterruptSync)
{
m_pInterruptSync->Disconnect();
m_pInterruptSync->Release();
m_pInterruptSync = NULL;
}
}
/*****************************************************************************
* CAdapterCommon::NonDelegatingQueryInterface()
*****************************************************************************
* Obtains an interface.
*/
STDMETHODIMP
CAdapterCommon::
NonDelegatingQueryInterface
(
REFIID Interface,
PVOID * Object
)
{
PAGED_CODE();
ASSERT(Object);
if (IsEqualGUIDAligned(Interface,IID_IUnknown))
{
*Object = PVOID(PUNKNOWN(PADAPTERCOMMON(this)));
}
else
if (IsEqualGUIDAligned(Interface,IID_IAdapterCommon))
{
*Object = PVOID(PADAPTERCOMMON(this));
}
else
if (IsEqualGUIDAligned(Interface,IID_IAdapterPowerManagement))
{
*Object = PVOID(PADAPTERPOWERMANAGEMENT(this));
}
else
{
*Object = NULL;
}
if (*Object)
{
PUNKNOWN(*Object)->AddRef();
return STATUS_SUCCESS;
}
return STATUS_INVALID_PARAMETER;
}
/*****************************************************************************
* CAdapterCommon::GetInterruptSync()
*****************************************************************************
* Get a pointer to the interrupt synchronization object.
*/
STDMETHODIMP_(PINTERRUPTSYNC)
CAdapterCommon::
GetInterruptSync
( void
)
{
PAGED_CODE();
return m_pInterruptSync;
}
#pragma code_seg()
/*****************************************************************************
* CAdapterCommon::ReadController()
*****************************************************************************
* Read a byte from the controller.
*/
STDMETHODIMP_(BYTE)
CAdapterCommon::
ReadController
( void
)
{
BYTE returnValue = BYTE(-1);
ASSERT(m_pWaveBase);
ULONGLONG startTime = PcGetTimeInterval(0);
do {
if (READ_PORT_UCHAR (m_pWaveBase + DSP_REG_DATAAVAIL) & 0x80)
{
returnValue = READ_PORT_UCHAR (m_pWaveBase + DSP_REG_READ);
}
} while ((PcGetTimeInterval(startTime) < GTI_MILLISECONDS(100)) &&
(BYTE(-1) == returnValue));
ASSERT((BYTE(-1) != returnValue) || !"ReadController timeout!");
return returnValue;
}
/*****************************************************************************
* CAdapterCommon::WriteController()
*****************************************************************************
* Write a byte to the controller.
*/
STDMETHODIMP_(BOOLEAN)
CAdapterCommon::
WriteController
(
IN BYTE Value
)
{
ASSERT(m_pWaveBase);
BOOLEAN returnValue = FALSE;
ULONGLONG startTime = PcGetTimeInterval(0);
do
{
BYTE status = READ_PORT_UCHAR (m_pWaveBase + DSP_REG_WRITE);
if ((status & 0x80) == 0)
{
WRITE_PORT_UCHAR (m_pWaveBase + DSP_REG_WRITE, Value);
returnValue = TRUE;
}
} while ((PcGetTimeInterval(startTime) < GTI_MILLISECONDS(100)) &&
! returnValue);
ASSERT(returnValue || !"WriteController timeout");
return returnValue;
}
/*****************************************************************************
* CAdapterCommon::MixerRegWrite()
*****************************************************************************
* Writes a mixer register.
*/
STDMETHODIMP_(void)
CAdapterCommon::
MixerRegWrite
(
IN BYTE Index,
IN BYTE Value
)
{
ASSERT( m_pWaveBase );
BYTE actualIndex;
// only hit the hardware if we're in an acceptable power state
if( m_PowerState <= PowerDeviceD1 )
{
actualIndex = (BYTE) ((Index < 0x80) ? (Index + DSP_MIX_BASEIDX) : Index);
WRITE_PORT_UCHAR (m_pWaveBase + DSP_REG_MIXREG, actualIndex);
WRITE_PORT_UCHAR (m_pWaveBase + DSP_REG_MIXDATA, Value);
}
if(Index < DSP_MIX_MAXREGS)
{
MixerSettings[Index] = Value;
}
}
/*****************************************************************************
* CAdapterCommon::MixerRegRead()
*****************************************************************************
* Reads a mixer register.
*/
STDMETHODIMP_(BYTE)
CAdapterCommon::
MixerRegRead
(
IN BYTE Index
)
{
if(Index < DSP_MIX_MAXREGS)
{
return MixerSettings[Index];
}
//
// Not in the cache? Read from HW directly.
//
// We need to make sure that we can access the HW directly for
// the volumes that can change externally.
// This is done here with passing an index outside of the cache.
// Since the an index=0 is actually DSP_MIX_BASEIDX which is less
// than the cache size (DSP_MIX_MAXREGS), you can access any volume
// directly with passing DSP_MIX_BASEIDX + index.
// You could also pass a flag - but we want to keep the changes
// minimal - or create a new function like MixerRegReadDirect().
//
WRITE_PORT_UCHAR (m_pWaveBase + DSP_REG_MIXREG, Index);
return READ_PORT_UCHAR (m_pWaveBase + DSP_REG_MIXDATA);
}
/*****************************************************************************
* CAdapterCommon::MixerReset()
*****************************************************************************
* Resets the mixer
*/
STDMETHODIMP_(void)
CAdapterCommon::
MixerReset
( void
)
{
ASSERT(m_pWaveBase);
WRITE_PORT_UCHAR (m_pWaveBase + DSP_REG_MIXREG, DSP_MIX_DATARESETIDX);
WRITE_PORT_UCHAR (m_pWaveBase + DSP_REG_MIXDATA, 0);
RestoreMixerSettingsFromRegistry();
}
/*****************************************************************************
* CAdapterCommon::AcknowledgeIRQ()
*****************************************************************************
* Acknowledge interrupt request.
*/
void
CAdapterCommon::
AcknowledgeIRQ
( void
)
{
ASSERT(m_pWaveBase);
READ_PORT_UCHAR (m_pWaveBase + DSP_REG_ACK16BIT);
READ_PORT_UCHAR (m_pWaveBase + DSP_REG_ACK8BIT);
}
/*****************************************************************************
* CAdapterCommon::ResetController()
*****************************************************************************
* Resets the controller.
*/
STDMETHODIMP_(NTSTATUS)
CAdapterCommon::
ResetController(void)
{
NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
// write a 1 to the reset bit
WRITE_PORT_UCHAR (m_pWaveBase + DSP_REG_RESET,1);
// wait for at least 3 microseconds
KeStallExecutionProcessor (5L); // okay, 5us
// write a 0 to the reset bit
WRITE_PORT_UCHAR (m_pWaveBase + DSP_REG_RESET,0);
// hang out for 100us
KeStallExecutionProcessor (100L);
// read the controller
BYTE ReadVal = ReadController ();
// check return value
if( ReadVal == BYTE(0xAA) )
{
ntStatus = STATUS_SUCCESS;
}
return ntStatus;
}
/*****************************************************************************
* CAdapterCommon::RestoreMixerSettingsFromRegistry()
*****************************************************************************
* Restores the mixer settings based on settings stored in the registry.
*/
STDMETHODIMP
CAdapterCommon::
RestoreMixerSettingsFromRegistry
( void
)
{
PREGISTRYKEY DriverKey;
PREGISTRYKEY SettingsKey;
_DbgPrintF(DEBUGLVL_VERBOSE,("[RestoreMixerSettingsFromRegistry]"));
// open the driver registry key
NTSTATUS ntStatus = PcNewRegistryKey( &DriverKey, // IRegistryKey
NULL, // OuterUnknown
DriverRegistryKey, // Registry key type
KEY_ALL_ACCESS, // Access flags
m_pDeviceObject, // Device object
NULL, // Subdevice
NULL, // ObjectAttributes
0, // Create options
NULL ); // Disposition
if(NT_SUCCESS(ntStatus))
{
UNICODE_STRING KeyName;
ULONG Disposition;
// make a unicode strong for the subkey name
RtlInitUnicodeString( &KeyName, L"Settings" );
// open the settings subkey
ntStatus = DriverKey->NewSubKey( &SettingsKey, // Subkey
NULL, // OuterUnknown
KEY_ALL_ACCESS, // Access flags
&KeyName, // Subkey name
REG_OPTION_NON_VOLATILE, // Create options
&Disposition );
if(NT_SUCCESS(ntStatus))
{
ULONG ResultLength;
if(Disposition == REG_CREATED_NEW_KEY)
{
// copy default settings
for(ULONG i = 0; i < SIZEOF_ARRAY(DefaultMixerSettings); i++)
{
MixerRegWrite( DefaultMixerSettings[i].RegisterIndex,
DefaultMixerSettings[i].RegisterSetting );
}
} else
{
// allocate data to hold key info
PVOID KeyInfo = ExAllocatePool(PagedPool, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD));
if(NULL != KeyInfo)
{
// loop through all mixer settings
for(UINT i = 0; i < SIZEOF_ARRAY(DefaultMixerSettings); i++)
{
// init key name
RtlInitUnicodeString( &KeyName, DefaultMixerSettings[i].KeyName );
// query the value key
ntStatus = SettingsKey->QueryValueKey( &KeyName,
KeyValuePartialInformation,
KeyInfo,
sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD),
&ResultLength );
if(NT_SUCCESS(ntStatus))
{
PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = PKEY_VALUE_PARTIAL_INFORMATION(KeyInfo);
if(PartialInfo->DataLength == sizeof(DWORD))
{
// set mixer register to registry value
MixerRegWrite( DefaultMixerSettings[i].RegisterIndex,
BYTE(*(PDWORD(PartialInfo->Data))) );
}
} else
{
// if key access failed, set to default
MixerRegWrite( DefaultMixerSettings[i].RegisterIndex,
DefaultMixerSettings[i].RegisterSetting );
}
}
// free the key info
ExFreePool(KeyInfo);
} else
{
// copy default settings
for(ULONG i = 0; i < SIZEOF_ARRAY(DefaultMixerSettings); i++)
{
MixerRegWrite( DefaultMixerSettings[i].RegisterIndex,
DefaultMixerSettings[i].RegisterSetting );
}
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
// release the settings key
SettingsKey->Release();
}
// release the driver key
DriverKey->Release();
}
return ntStatus;
}
/*****************************************************************************
* CAdapterCommon::SaveMixerSettingsToRegistry()
*****************************************************************************
* Saves the mixer settings to the registry.
*/
STDMETHODIMP
CAdapterCommon::
SaveMixerSettingsToRegistry
( void
)
{
PREGISTRYKEY DriverKey;
PREGISTRYKEY SettingsKey;
_DbgPrintF(DEBUGLVL_VERBOSE,("[SaveMixerSettingsToRegistry]"));
// open the driver registry key
NTSTATUS ntStatus = PcNewRegistryKey( &DriverKey, // IRegistryKey
NULL, // OuterUnknown
DriverRegistryKey, // Registry key type
KEY_ALL_ACCESS, // Access flags
m_pDeviceObject, // Device object
NULL, // Subdevice
NULL, // ObjectAttributes
0, // Create options
NULL ); // Disposition
if(NT_SUCCESS(ntStatus))
{
UNICODE_STRING KeyName;
// make a unicode strong for the subkey name
RtlInitUnicodeString( &KeyName, L"Settings" );
// open the settings subkey
ntStatus = DriverKey->NewSubKey( &SettingsKey, // Subkey
NULL, // OuterUnknown
KEY_ALL_ACCESS, // Access flags
&KeyName, // Subkey name
REG_OPTION_NON_VOLATILE, // Create options
NULL );
if(NT_SUCCESS(ntStatus))
{
// loop through all mixer settings
for(UINT i = 0; i < SIZEOF_ARRAY(MixerSettings); i++)
{
// init key name
RtlInitUnicodeString( &KeyName, DefaultMixerSettings[i].KeyName );
// set the key
DWORD KeyValue = DWORD(MixerSettings[DefaultMixerSettings[i].RegisterIndex]);
ntStatus = SettingsKey->SetValueKey( &KeyName, // Key name
REG_DWORD, // Key type
PVOID(&KeyValue),
sizeof(DWORD) );
if(!NT_SUCCESS(ntStatus))
{
break;
}
}
// release the settings key
SettingsKey->Release();
}
// release the driver key
DriverKey->Release();
}
return ntStatus;
}
/*****************************************************************************
* CAdapterCommon::PowerChangeState()
*****************************************************************************
* Change power state for the device.
*/
STDMETHODIMP_(void)
CAdapterCommon::
PowerChangeState
(
IN POWER_STATE NewState
)
{
UINT i;
_DbgPrintF( DEBUGLVL_VERBOSE, ("[CAdapterCommon::PowerChangeState]"));
// Is this actually a state change?
if( NewState.DeviceState != m_PowerState )
{
// switch on new state
switch( NewState.DeviceState )
{
case PowerDeviceD0:
// Insert your code here for entering the full power state (D0).
// This code may be a function of the current power state. Note that
// property accesses such as volume and mute changes may occur when
// the device is in a sleep state (D1-D3) and should be cached in the
// driver to be restored upon entering D0. However, it should also be
// noted that new miniport and new streams will only be attempted at
// D0 -- PortCls will place the device in D0 prior to the NewStream call.
// Save the new state. This local value is used to determine when to cache
// property accesses and when to permit the driver from accessing the hardware.
m_PowerState = NewState.DeviceState;
// restore mixer settings
for(i = 0; i < DSP_MIX_MAXREGS - 1; i++)
{
if( i != DSP_MIX_MICVOLIDX )
{
MixerRegWrite( BYTE(i), MixerSettings[i] );
}
}
if (m_WaveMiniportSB16)
{
m_WaveMiniportSB16->RestoreSampleRate();
}
break;
case PowerDeviceD1:
// This sleep state is the lowest latency sleep state with respect to the
// latency time required to return to D0. The driver can still access
// the hardware in this state if desired. If the driver is not being used
// an inactivity timer in PortCls will place the driver in this state after
// a timeout period controllable via the registry.
case PowerDeviceD2:
// This is a medium latency sleep state. In this state the device driver
// cannot assume that it can touch the hardware so any accesses need to be
// cached and the hardware restored upon entering D0 (or D1 conceivably).
case PowerDeviceD3:
// This is a full hibernation state and is the longest latency sleep state.
// The driver cannot access the hardware in this state and must cache any
// hardware accesses and restore the hardware upon returning to D0 (or D1).
// Save the new state.
m_PowerState = NewState.DeviceState;
_DbgPrintF(DEBUGLVL_VERBOSE,(" Entering D%d",ULONG(m_PowerState)-ULONG(PowerDeviceD0)));
break;
default:
_DbgPrintF(DEBUGLVL_VERBOSE,(" Unknown Device Power State"));
break;
}
}
}
/*****************************************************************************
* CAdapterCommon::QueryPowerChangeState()
*****************************************************************************
* Query to see if the device can
* change to this power state
*/
STDMETHODIMP_(NTSTATUS)
CAdapterCommon::
QueryPowerChangeState
(
IN POWER_STATE NewStateQuery
)
{
_DbgPrintF( DEBUGLVL_TERSE, ("[CAdapterCommon::QueryPowerChangeState]"));
// Check here to see of a legitimate state is being requested
// based on the device state and fail the call if the device/driver
// cannot support the change requested. Otherwise, return STATUS_SUCCESS.
// Note: A QueryPowerChangeState() call is not guaranteed to always preceed
// a PowerChangeState() call.
return STATUS_SUCCESS;
}
/*****************************************************************************
* CAdapterCommon::QueryDeviceCapabilities()
*****************************************************************************
* Called at startup to get the caps for the device. This structure provides
* the system with the mappings between system power state and device power
* state. This typically will not need modification by the driver.
*
*/
STDMETHODIMP_(NTSTATUS)
CAdapterCommon::
QueryDeviceCapabilities
(
IN PDEVICE_CAPABILITIES PowerDeviceCaps
)
{
_DbgPrintF( DEBUGLVL_TERSE, ("[CAdapterCommon::QueryDeviceCapabilities]"));
return STATUS_SUCCESS;
}
/*****************************************************************************
* InterruptServiceRoutine()
*****************************************************************************
* ISR.
*/
NTSTATUS
InterruptServiceRoutine
(
IN PINTERRUPTSYNC InterruptSync,
IN PVOID DynamicContext
)
{
ASSERT(InterruptSync);
ASSERT(DynamicContext);
CAdapterCommon *that = (CAdapterCommon *) DynamicContext;
//
// We are here because the MPU tried and failed, so
// must be a wave interrupt.
//
ASSERT(that->m_pWaveBase);
//
// Read the Interrupt status register.
//
BYTE IntrStatus = that->MixerRegRead (0x82);
//
// In case we really read the interrupt status register, we should
// also USE it and make sure that we really have a wave interrupt
// and not something else!
//
if (IntrStatus & 0x03) // Voice8 or Voice16 Interrupt
{
//
// Make sure there is a wave miniport.
//
if (that->m_WaveMiniportSB16)
{
//
// Tell it it needs to do some work.
//
that->m_WaveMiniportSB16->ServiceWaveISR ();
}
//
// ACK the ISR.
//
that->AcknowledgeIRQ();
}
#ifdef EVENT_SUPPORT
//
// This code will fire a volume event in case the HW volume has changed.
//
else if (IntrStatus & 0x10) // Volume interrupt on C16X-mixers
{
//
// Ack vol interrupt
//
IntrStatus &= ~0x10;
that->MixerRegWrite (0x82, IntrStatus);
//
// Generate an event for the master volume (as an example)
//
if (that->m_TopoMiniportSB16)
{
that->m_TopoMiniportSB16->ServiceEvent ();
}
}
#endif
return STATUS_SUCCESS;
}