📄 aaci_audio.c
字号:
//-----------------------------------------------------------------------
// VOID AACI_RegWrite32 (USHORT reg, ULONG val)
//
// Writes 32 bits to the 5530/5540 I/O port
//-----------------------------------------------------------------------
VOID AACI_RegWrite32(USHORT reg, ULONG val)
{
PULONG reg_loc;
reg_loc = (PULONG)(g_AudioRegBase + reg);
*reg_loc = val;
}
//-----------------------------------------------------------------------
// ULONG AACI_RegRead32(USHORT reg)
//
// Reads 32 bits from the 5530/5540 I/O port
//-----------------------------------------------------------------------
ULONG AACI_RegRead32(USHORT reg)
{
PULONG reg_loc;
ULONG val;
reg_loc = (PULONG)(g_AudioRegBase + reg);
val = *reg_loc;
return( val );
}
// -----------------------------------------------------------------------------
// Clear FIFO Functions
// -----------------------------------------------------------------------------
// Clear the FIFO by enabling transmit, waiting for it to empty then
// disabling transmit
static BOOL ClearTransmitFIFO()
{
DWORD dwStatus, dwCount = 0;
// Make sure FIFO is enabled
AACI_RegWrite32( AACIReg_Channel1TxControl,
AACI_RegRead32(AACIReg_Channel1TxControl) |
AACIBit_EnableFIFO );
Sleep(10);
// Wait till not busy
dwStatus = AACI_RegRead32(AACIReg_Channel1Status);
while( (dwCount < 10) && (dwStatus & AACIBit_TXFIFOBusy) )
{
// Check for any flagged interrupts (and clear them if need be)
if( (dwStatus & AACIBit_TXUnderrun) && !(dwStatus & AACIBit_TXFIFOEmpty) )
{
ERRMSG("Underrun occurred (FIFO not empty)");
AACI_RegWrite32( AACIReg_IntClear, AACIBit_TxUEC1 );
}
Sleep(50);
dwStatus = AACI_RegRead32(AACIReg_Channel1Status);
dwCount++;
}
// Disable FIFO and clear interrupts
AACI_RegWrite32( AACIReg_Channel1TxControl,
AACI_RegRead32(AACIReg_Channel1TxControl) &
~(AACIBit_EnableFIFO) );
AACI_RegWrite32( AACIReg_IntClear, AACIBit_TxUEC1 );
// Had to quit out of busy loop?
if( dwCount == 10 )
{
WRNMSG2("ClearTransmitFIFO: WARNING! count=%d, status=0x%04x",
dwCount, AACI_RegRead32(AACIReg_Channel1Status));
return FALSE;
}
return TRUE;
}
// Clear the FIFO by reading the received data
static BOOL ClearReceiveFIFO( DWORD *pdwDataRead )
{
DWORD dwData, dwCount = 0; // dwStatus, dwNewStatus;
// Make sure FIFO disabled and clear interrupts
AACI_RegWrite32( AACIReg_Channel1RxControl,
AACI_RegRead32(AACIReg_Channel1RxControl) &
~(AACIBit_EnableFIFO) );
AACI_RegWrite32( AACIReg_IntClear, AACIBit_RxTOFEC1 | AACIBit_RxOEC1 );
// Read all the data in the FIFO
// (NOTE: Do not use RX_FIFOSIZE as we may be called from the Test API in
// different modes)
while( !(AACI_RegRead32(AACIReg_Channel1Status) & AACIBit_RXFIFOEmpty) &&
dwCount < (RX_FIFOSIZE_NOTCOMPACT*2) )
{
dwData = AACI_RegRead32( AACIReg_Channel1FIFO );
dwCount++;
}
// Return bytes read if we are given something to put them in
if( pdwDataRead ) *pdwDataRead = dwCount;
// Did something go wrong? (usually means that there is incoming data
// held in slots, we can ignore this)
if( dwCount == (RX_FIFOSIZE_NOTCOMPACT*2) ||
(AACI_RegRead32(AACIReg_Channel1Status) & AACIBit_RXFIFOBusy) )
{
WRNMSG2("ClearReceiveFIFO: WARNING! read=%d, status=0x%04x", dwCount,
AACI_RegRead32(AACIReg_Channel1Status));
return FALSE;
}
return TRUE;
}
#ifdef DEBUG
//-----------------------------------------------------------------------
// Debug information
//-----------------------------------------------------------------------
#define PRINT_STEREO_VOLUME(m,v) \
PRINTMSG( ZONE_INIT, \
(TEXT("%21s = 0x%04x (Mute = %d, Left = 0x%03x, Right = 0x%03x)\n"), \
TEXT(m), v, (v & LM4549A_BIT_VOLUME_MUTE) != 0, (v >> 8) & 0x3F, \
v & 0x3F) )
#define PRINT_MONO_VOLUME(m,v) \
PRINTMSG( ZONE_INIT, \
(TEXT("%21s = 0x%04x (Mute = %d, Mono = 0x%03x)\n"), \
TEXT(m), v, (v & LM4549A_BIT_VOLUME_MUTE) != 0, v & 0x3F) )
#define PRINT_SETTING(m,s) \
PRINTMSG( ZONE_INIT, \
(TEXT("%21s = 0x%04x\n"), TEXT(m), s) )
static void DumpCurrentSettings()
{
USHORT codec_data;
codec_data = AACI_CodecRead16( LM4549A_RESET );
PRINT_SETTING( "Reset", codec_data );
codec_data = AACI_CodecRead16( LM4549A_MASTER_VOLUME );
PRINT_STEREO_VOLUME( "Master volume", codec_data );
codec_data = AACI_CodecRead16( LM4549A_LINE_LEV_OUT_VOL );
PRINT_STEREO_VOLUME( "Line Level out volume", codec_data );
codec_data = AACI_CodecRead16( LM4549A_MASTER_VOLUME_MONO );
PRINT_MONO_VOLUME( "Master Mono volume", codec_data );
codec_data = AACI_CodecRead16( LM4549A_PC_BEEP_VOLUME );
PRINTMSG( ZONE_INIT, (TEXT("%21s = 0x%04x (Mute = %d, Mono = 0x%02x)\n"),
TEXT("PC Beep volume"), codec_data,
(codec_data & LM4549A_BIT_VOLUME_MUTE) != 0, (codec_data>>1) & 0xF) );
codec_data = AACI_CodecRead16( LM4549A_PHONE_VOLUME );
PRINT_MONO_VOLUME( "Phone volume", codec_data );
codec_data = AACI_CodecRead16( LM4549A_MIC_VOLUME );
PRINTMSG( ZONE_INIT, (TEXT("%21s = 0x%04x (Mute = %d, Gain = %d, Mono = 0x%03x)\n"),
TEXT("Mic volume"), codec_data,
(codec_data & LM4549A_BIT_VOLUME_MUTE) != 0,
(codec_data & LM4549A_BIT_VOLUME_GAIN) != 0, codec_data & 0x1F) );
codec_data = AACI_CodecRead16( LM4549A_LINE_IN_VOLUME );
PRINT_STEREO_VOLUME( "Line in volume", codec_data );
codec_data = AACI_CodecRead16( LM4549A_CD_VOLUME );
PRINT_STEREO_VOLUME( "CD volume", codec_data );
codec_data = AACI_CodecRead16( LM4549A_VIDEO_VOLUME );
PRINT_STEREO_VOLUME( "Video volume", codec_data );
codec_data = AACI_CodecRead16( LM4549A_AUX_VOLUME );
PRINT_STEREO_VOLUME( "AUX volume", codec_data );
codec_data = AACI_CodecRead16( LM4549A_PCM_OUT_VOL );
PRINT_STEREO_VOLUME( "PCM out volume", codec_data );
codec_data = AACI_CodecRead16( LM4549A_RECORD_SELECT );
PRINTMSG( ZONE_INIT, (TEXT("%21s = 0x%04x (Left = 0x%02x, Right = 0x%02x)\n"),
TEXT("Record Select"), codec_data, (codec_data >> 8) & 0x7,
codec_data & 0x7) );
codec_data = AACI_CodecRead16( LM4549A_RECORD_GAIN );
PRINTMSG( ZONE_INIT, (TEXT("%21s = 0x%04x (Mute = %d, Left = 0x%02x, Right = 0x%02x)\n"),
TEXT("Record Gain"), codec_data,
(codec_data & LM4549A_BIT_VOLUME_MUTE) != 0, (codec_data >> 8) & 0xF,
codec_data & 0xF) );
codec_data = AACI_CodecRead16( LM4549A_GENERAL_PURPOSE );
PRINT_SETTING( "General Purpose", codec_data );
codec_data = AACI_CodecRead16( LM4549A_3D_CONTROL );
PRINT_SETTING( "3D Control", codec_data );
codec_data = AACI_CodecRead16( LM4549A_POWERDOWN_CTRL_STAT );
PRINT_SETTING( "Powerdown Status", codec_data );
codec_data = AACI_CodecRead16( LM4549A_EXT_AUDIO_ID );
PRINT_SETTING( "Extended Audio ID", codec_data );
codec_data = AACI_CodecRead16( LM4549A_EXT_AUDIO_CTRL_STAT );
PRINT_SETTING( "Extended Audio Status", codec_data );
codec_data = AACI_CodecRead16( LM4549A_PCM_FRONT_DAC_RATE );
PRINT_SETTING( "PCM Front DAC Rate", codec_data );
codec_data = AACI_CodecRead16( LM4549A_PCM_ADC_RATE );
PRINT_SETTING( "PCM ADC Rate", codec_data );
codec_data = AACI_CodecRead16( LM4549A_VENDOR_ID1 );
PRINT_SETTING( "Vendor ID1", codec_data );
codec_data = AACI_CodecRead16( LM4549A_VENDOR_ID2 );
PRINT_SETTING( "Vendor ID2", codec_data );
}
#endif // DEBUG
#ifdef TEST_API
// -----------------------------------------------------------------------------
// Test Functions
// -----------------------------------------------------------------------------
#define TESTWAIT_TRANSMIT 5000
#define TESTWAIT_RECEIVE 5000
#define PAUSE Sleep(100)
DWORD TestTransmit( DWORD uMsg )
{
DWORD dwTest;
DWORD dwTXCtrl, dwTXSize;
DWORD dwRet = MMSYSERR_NOERROR, dwResult;
RETAILMSG( TRUE, (TEXT("TestTransmit v0.5\n")) );
if( !g_fInUse[WAPI_OUT] )
{
RETAILMSG( TRUE, (TEXT("TestTransmit_xxx: ERROR - WaveOut channel should have been opened\n")) );
return MMSYSERR_ERROR;
}
if( g_fInUse[WAPI_IN] )
{
// We need to take over the whole AACI so we need both channels
RETAILMSG( TRUE, (TEXT("TestTransmit_xxx: ERROR - WaveIn channel in use\n")) );
return MMSYSERR_ERROR;
}
g_fTesting = TRUE;
g_fInUse[WAPI_IN] = TRUE; // Stop anyone else using the record channel
// whilst we are testing playback
g_fTestIntDisable = TRUE; // Assume we don't want interrupts to continue
// after the first one
// Reset device to get into known state
ResetDevice();
dwTXCtrl = AACIBit_Slot3DataInFIFO | AACIBit_Slot4DataInFIFO |
AACIBit_EnableFIFOMode;
// Set output rate to 8KHz
AACI_CodecWrite16( LM4549A_PCM_FRONT_DAC_RATE, 8000 );
// Disable AACI and then Transmit & Receive FIFOs
PAUSE;
AACI_RegWrite32( AACIReg_MainControl, 0 );
AACI_RegWrite32( AACIReg_Channel1TxControl, 0 );
AACI_RegWrite32( AACIReg_Channel1RxControl, 0 );
PAUSE;
// Turn on AACI without slot comms
AACI_RegWrite32( AACIReg_MainControl, AACIBit_Enable );
// Create an interrupt event
g_hTestInterrupt = CreateEvent( NULL, FALSE, FALSE, NULL );
for( dwTest = 0; dwTest < 6; dwTest++ )
{
switch( dwTest )
{
case 0:
RETAILMSG( TRUE, (TEXT("Data size 16 bits: ")) );
dwTXSize = AACIBit_DataSize16bits;
break;
case 1:
RETAILMSG( TRUE, (TEXT("Data size 12 bits: ")) );
dwTXSize = AACIBit_DataSize12bits;
break;
case 2:
RETAILMSG( TRUE, (TEXT("Data size 18 bits: ")) );
dwTXSize = AACIBit_DataSize18bits;
break;
case 3:
RETAILMSG( TRUE, (TEXT("Data size 20 bits: ")) );
dwTXSize = AACIBit_DataSize20bits;
break;
case 4:
RETAILMSG( TRUE, (TEXT("Data size 16 bits compact: ")) );
dwTXSize = AACIBit_DataSize16bits | AACIBit_EnableCompactMode;
break;
case 5:
RETAILMSG( TRUE, (TEXT("Data size 12 bits compact: ")) );
dwTXSize = AACIBit_DataSize12bits | AACIBit_EnableCompactMode;
break;
}
// Set up Transmit FIFO (Disable AACI whilst changing transmit size
// and compact mode)
AACI_RegWrite32( AACIReg_MainControl, 0 );
AACI_RegWrite32( AACIReg_Channel1TxControl, dwTXCtrl | dwTXSize );
AACI_RegWrite32( AACIReg_Channel1IntEnable, 0 );
PAUSE;
AACI_RegWrite32( AACIReg_MainControl, AACIBit_Enable );
// Clear the event of any previous interrupts
ResetEvent( g_hTestInterrupt );
switch (uMsg)
{
case TESTTX_FIFOSIZE:
dwResult = TestTransmit_FIFOSize( (dwTest < 4) );
break;
case TESTTX_COMPLETE:
dwResult = TestTransmit_Complete( (dwTest < 4) );
break;
case TESTTX_HALFEMPTY:
dwResult = TestTransmit_HalfEmpty( (dwTest < 4) );
break;
default:
RETAILMSG(TRUE, (TEXT("TestTransmit: Unsupported test %d\n"),
uMsg) );
dwResult = MMSYSERR_ERROR;
}
if( dwResult != MMSYSERR_NOERROR ) dwRet = dwResult;
// Check for error?
if( !ClearTransmitFIFO() )
{
RETAILMSG(TRUE, (TEXT("TestTransmit: WARNING - problems clearing FIFO after test\n")) );
}
}
CloseHandle( g_hTestInterrupt );
// Clean up
ResetDevice();
AACI_SetVolume(g_nVolume);
g_fInUse[WAPI_IN] = FALSE;
g_fTesting = FALSE;
return dwRet;
}
static DWORD TestTransmit_FIFOSize( BOOL fNotCompact )
{
DWORD dwCount = 0;
// Fill up FIFO!
while( !(AACI_RegRead32( AACIReg_Channel1Status ) & AACIBit_TXFIFOFull) &&
dwCount <= TX_FIFOSIZE_NOTCOMPACT )
{
// Left Channel (or both when compact enabled)
AACI_RegWrite32( AACIReg_Channel1FIFO, 0 );
dwCount++;
// Right Channel (when not compact)
if( fNotCompact )
{
AACI_RegWrite32( AACIReg_Channel1FIFO, 0 );
dwCount++;
}
}
if( ((fNotCompact && dwCount == TX_FIFOSIZE_NOTCOMPACT) ||
(!fNotCompact && dwCount == TX_FIFOSIZE_COMPACT)) &&
(AACI_RegRead32( AACIReg_Channel1Status ) & AACIBit_TXFIFOFull) )
{
RETAILMSG( TRUE, (TEXT("PASS\n")) );
return MMSYSERR_NOERROR;
}
RETAILMSG( TRUE, (TEXT("FAIL (size=%d)\n"),dwCount) );
return MMSYSERR_ERROR;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -