📄 aaci_audio.c
字号:
//yz_change for DMA
//(*pfnFillFIFO)(pwh);
//Disable Tx Interrupt
AACI_RegWrite32( AACIReg_Channel1IntEnable,
AACI_RegRead32( AACIReg_Channel1IntEnable ) &
~(AACIBit_TxCIE | AACIBit_TxIE | AACIBit_TxUIE) );
// Clear any transmit underruns now we have filled the FIFO
if( AACI_RegRead32( AACIReg_Channel1Status ) & AACIBit_TXUnderrun )
{
TESTMSG("AACI_WaveContinue: Transmit Underrun - too slow!");
AACI_RegWrite32( AACIReg_IntClear, AACIBit_TxUEC1 );
}
}
else // (apidir == WAPI_IN)
{
TESTMSG("AACI_WaveContinue: WAPI_IN");
(*pfnGetFIFO)(pwh);
// Clear any receive overruns now we have emptied the FIFO
if( AACI_RegRead32( AACIReg_Channel1Status ) & AACIBit_RXOverrun )
{
TESTMSG("AACI_WaveContinue: Receive Overrun - too slow!");
AACI_RegWrite32( AACIReg_IntClear, AACIBit_RxOEC1 );
}
}
}
#endif
}
//-------------------------------------------------------
// VOID AACI_WaveEndOfData(WAPI_INOUT apidir)
//
// Signals we have no more data to play
// (only called for WAPI_OUT).
//-------------------------------------------------------
VOID AACI_WaveEndOfData(WAPI_INOUT apidir)
{
#if 0
FUNC_WPDD("+AACI_WaveEndOfData");
RETAILMSG( yz_debug, (TEXT("AACI_WaveEndOfData()\r\n")));
if( apidir == WAPI_OUT )
{
g_fTxEndOfData = TRUE;
// Once we get this, we won't be given any more data to play
gv_fMoreData[WAPI_OUT] = FALSE;
// Cause one final interrupt to make the driver return a STOPPED status
DmaCmd = DMA_CMD_STOP;
SetEvent( hAudioInterrupt );
}
FUNC_WPDD("-AACI_WaveEndOfData");
#endif
}
//-------------------------------------------------------
// VOID AACI_WaveStop(WAPI_INOUT apidir)
//
// Stops the wave stream.
//-------------------------------------------------------
VOID AACI_WaveStop(WAPI_INOUT apidir)
{
//FILE *f_in;
FUNC_WPDD("+AACI_WaveStop");
//RETAILMSG(yz_debug, (TEXT("AACI_WaveStop()\r\n")));
// No more data to play
gv_fMoreData[apidir] = FALSE;
if( g_dwRunMode[apidir] != RUNMODE_STOPPED )
{
g_dwRunMode[apidir] = RUNMODE_STOPPED;
if( apidir == WAPI_OUT )
{
OnPlayStop();
//yz_change for DMA
/*
// Disable the AACI Transmit interrupts
AACI_RegWrite32( AACIReg_Channel1IntEnable,
AACI_RegRead32( AACIReg_Channel1IntEnable ) &
~(AACIBit_TxCIE | AACIBit_TxIE | AACIBit_TxUIE) );
*/
/*
//yz_add for test
f_in = fopen("\\windows\\hello_world.wav", "rb");
if(f_in == NULL)
RETAILMSG(1, (TEXT("PDD_DMAThread() - file open FAILED!\r\n")));
if((fread(total_buf, sizeof( char ), 200000, f_in)) != 200000)
RETAILMSG(1, (TEXT("PDD_DMAThread() - file read Error! %d\r\n")));
MMC_StartDMA(2, 0x10004090, total_buf, 200000);
fclose(f_in);
RETAILMSG(1, (TEXT("AACI_WaveStop(): File read done!\r\n")));
*/
if( !ClearTransmitFIFO() )
{
ERRMSG("AACI_WaveStop: Failed to clear Transmit FIFO");
}
RETAILMSG( 1 , (TEXT("aaci : stop\r\n")));
}
else // (apidir == WAPI_IN)
{
BOOL fCleared;
// Disable the AACI Receive interrupts
AACI_RegWrite32( AACIReg_Channel1IntEnable,
AACI_RegRead32( AACIReg_Channel1IntEnable ) &
~(AACIBit_RxIE | AACIBit_RxOIE |
AACIBit_RxTIE | AACIBit_RxTOIE) );
// Clear the receive FIFO
fCleared = ClearReceiveFIFO(NULL);
if( !fCleared )
{
ERRMSG("AACI_WaveStop: Failed to clear Receive FIFO");
}
OnRecordStop();
}
}
FUNC_WPDD("-AACI_WaveStop");
}
// -----------------------------------------------------------------------------
// VOID AACI_Standby (WAPI_INOUT apidir)
//
// Called between playing sounds to save power
// -----------------------------------------------------------------------------
VOID AACI_Standby(WAPI_INOUT apidir)
{
FUNC_WPDD("+AACI_Standby");
// Make sure we have stopped
AACI_WaveStop(apidir);
if( (g_dwRunMode[WAPI_OUT] == RUNMODE_STOPPED) &&
(g_dwRunMode[WAPI_IN] == RUNMODE_STOPPED) )
{
// Power down device
PowerDown();
}
RETAILMSG( 1 , (TEXT("aaci : standby\r\n")));
FUNC_WPDD("-AACI_Standby");
}
//---------------------------------------------------------
// VOID AACI_Deinitialize(VOID)
//
// This routine is called when the driver
// is being unloaded. Free up memory, etc.
//---------------------------------------------------------
VOID AACI_Deinitialize(VOID)
{
FUNC_WPDD("+AACI_Deinitialize");
if( g_AudioRegBase )
{
// Disable AACI functionality
AACI_RegWrite32( AACIReg_MainControl, 0 );
// Unmap hardware register space
MmUnmapIoSpace( g_AudioRegBase, AACI_HWREGS_SIZE );
}
OnDeinit();
FUNC_WPDD("-AACI_Deinitialize");
}
//---------------------------------------------------------
// ULONG AACI_GetVolume(VOID)
//
// Returns the digital volume to the caller
//---------------------------------------------------------
ULONG AACI_GetVolume(VOID)
{
MISC1("AACI_GetVolume: 0x%08x", g_nVolume);
return g_nVolume;
}
//---------------------------------------------------------
// VOID AACI_SetVolume(ULONG)
//
// Sets the digital volume based on the value sent by the caller
//---------------------------------------------------------
VOID AACI_SetVolume(ULONG Vol)
{
USHORT rVol, lVol, codecVol;
UCHAR rIdx, lIdx;
g_nVolume = Vol;
// Extract top 5 MSBs from Left and Right channel volumes
rIdx = (UCHAR)((Vol & 0xF8000000) >> (32 - 5));
lIdx = (UCHAR)((Vol & 0x0000F800) >> (16 - 5));
// Convert to CODEC volume range
// NOTE: Swap L & R as output is reversed on Versatile
lVol = VolumeLUT[rIdx];
rVol = VolumeLUT[lIdx];
// Create CODEC data packet
codecVol = (rVol) | (lVol << 8);
// Check for mute volume setting on both channels, and convert to
// complete mute
if ( codecVol == LM4549A_MUTEVOL_RL )
codecVol = LM4549A_BIT_VOLUME_MUTE;
MISC2("AACI_SetVolume: MSFT:0x%08x, CODEC:0x%04x", Vol, codecVol);
AACI_CodecWrite16( LM4549A_MASTER_VOLUME, codecVol );
}
// -----------------------------------------------------------------------------
//
// AUDIO_STATE AACI_GetInterruptType(VOID)
//
// Called by the driver's ISR.
// Returns the state of the stream being Played/Recorded.
// -----------------------------------------------------------------------------
AUDIO_STATE AACI_GetInterruptType(VOID)
{
AUDIO_STATE asResult = AUDIO_STATE_IGNORE;
ULONG ulStatus;
#ifdef TEST_API
if( !g_fTesting )
{
#endif
ulStatus = AACI_RegRead32( AACIReg_Channel1IntStatus );
// check WAPI_IN first
if( g_dwRunMode[WAPI_IN] == RUNMODE_RUNNING )
{
if( gv_fMoreData[WAPI_IN] )
{
if( ulStatus & AACIBit_RxIE )
{
asResult |= AUDIO_STATE_IN_RECORDING;
}
else if( AACI_RegRead32( AACIReg_Channel1Status ) &
AACIBit_RXFIFOHalfFull )
{
// No obvious interrupt, but channel status shows half
// full, so report recording
asResult |= AUDIO_STATE_IN_RECORDING;
WRNMSG1("AACI_GetInterruptType: Receive status halffull but no interrupt!");
}
}
else
{
// Signal end of recording
asResult |= AUDIO_STATE_IN_STOPPED;
g_dwRunMode[WAPI_IN] = RUNMODE_STOPPING;
#ifdef AACI_STATS
MISC1( "AACI_GetInterruptType: Stopping receive - no more data (read %d bytes)",
g_dwBytesRecorded[WAPI_IN] );
#endif
}
}
else
{
if( ulStatus & (AACIBit_RxIE | AACIBit_RxOIE |
AACIBit_RxTIE | AACIBit_RxTOIE) )
{
// Getting receive interrupts when not running - disable them
VERBOSEMSG("AACI_GetInterruptType: Disabling Receive interrupts as not running");
AACI_RegWrite32( AACIReg_Channel1IntEnable,
AACI_RegRead32( AACIReg_Channel1IntEnable ) &
~(AACIBit_RxIE | AACIBit_RxOIE |
AACIBit_RxTIE | AACIBit_RxTOIE) );
}
}
// check WAPI_OUT
if( g_dwRunMode[WAPI_OUT] == RUNMODE_RUNNING )
{
//RETAILMSG( 1 , (TEXT("aaci : query interrupt \r\n")));
//if( DmaCmd == DMA_CMD_START )
asResult |= AUDIO_STATE_OUT_PLAYING;
}
else
{
if( ulStatus & (AACIBit_TxCIE | AACIBit_TxIE | AACIBit_TxUIE) )
{
// Getting transmit interrupts when not running - disable them
VERBOSEMSG("AACI_GetInterruptType: Disabling Transmit interrupts as not running");
AACI_RegWrite32( AACIReg_Channel1IntEnable,
AACI_RegRead32( AACIReg_Channel1IntEnable ) &
~(AACIBit_TxCIE | AACIBit_TxIE | AACIBit_TxUIE) );
}
}
#ifdef TEST_API
}
else
{
// Just TESTING... Save the interrupt status for the tests
g_dwTestIntStatus = AACI_RegRead32( AACIReg_Channel1IntStatus );
TESTMSG2("AACI_GetInterruptType: ints=0x%08x, status=0x%04x",
g_dwTestIntStatus, AACI_RegRead32(AACIReg_Channel1Status));
// Disable any other interrupts (clears the interrupt status)
if( g_fTestIntDisable ) AACI_RegWrite32( AACIReg_Channel1IntEnable, 0 );
// Wake up any tests waiting for an interrupt
SetEvent( g_hTestInterrupt );
}
#endif
return asResult;
}
// -----------------------------------------------------------------------------
// FIFO operations
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Hardware (CODEC and AACI) operations
// -----------------------------------------------------------------------------
// Internal function to send raw data to the codec
static VOID CodecSend( ULONG raw_codec_reg, ULONG raw_codec_data )
{
// First check that the AACISLxTX registers are empty
TESTWAIT(!( AACI_RegRead32(AACIReg_SlotFlag) &
(AACIBit_Slot1TXEmpty | AACIBit_Slot2TXEmpty)),
"Slot1TXEmpty | Slot2TXEmpty")
AACI_RegWrite32( AACIReg_Slot2Tx, raw_codec_data );
AACI_RegWrite32( AACIReg_Slot1Tx, raw_codec_reg );
// Pause so that slots can be transmitted
Sleep(1);
// Wait till slots 1&2 transmit complete
TESTWAIT(AACI_RegRead32(AACIReg_SlotFlag) &
(AACIBit_Slot1TXBusy | AACIBit_Slot2TXBusy),
"Slot1TXBusy | Slot2TXBusy")
// Pause here for the operation to complete on the CODEC, i.e. wait for
// data to be returned or CODEC registers to be updated depending on
// read or write
Sleep(1);
}
//-----------------------------------------------------------------------
//
// USHORT AACI_CodecRead16( USHORT codec_reg )
//
// Reads data from the CODEC
//
//-----------------------------------------------------------------------
USHORT AACI_CodecRead16( USHORT codec_reg )
{
// Tell the codec we are trying to read a register
CodecSend( (((ULONG)codec_reg) << 12) | AACIBit_Slot1Tx_Read, (ULONG)0 );
// Check if LM4549 has returned requested value
TESTWAIT(!( AACI_RegRead32( AACIReg_SlotFlag ) & AACIBit_Slot2RXValid ),
"Slot2RXValid")
return( (USHORT)(AACI_RegRead32( AACIReg_Slot2Rx ) >> 4) );
}
//-----------------------------------------------------------------------
//
// void AACI_CodecWrite16( USHORT codec_reg, USHORT codec_data )
//
// Writes data to the CODEC
//
//-----------------------------------------------------------------------
VOID AACI_CodecWrite16( USHORT codec_reg, USHORT codec_data )
{
CodecSend( (((ULONG)codec_reg) << 12), (((ULONG)codec_data) << 4) );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -