📄 aaci_audio.c
字号:
// 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)
{
RETAILMSG( DBG_AACI, (TEXT("AACI_GetVolume()\r\n")));
MISC1("AACI_GetVolume: 0x%08x", g_nVolume);
return g_nVolume;
}
FILE* fp = NULL; // for test
//---------------------------------------------------------
// VOID AACI_SetVolume(ULONG)
//
// Sets the digital volume based on the value sent by the caller
//---------------------------------------------------------
#define DEFAULT_MINI_VOLUME 4
VOID AACI_SetVolume(ULONG Vol)
{
USHORT rVol, lVol, codecVol;
UCHAR rIdx, lIdx;
g_nVolume = Vol;
RETAILMSG( 0, (TEXT("Vol (size=%d)\n"),Vol) );
// Extract top 5 MSBs from Left and Right channel volumes
rIdx = (UCHAR)((Vol & 0xF8000000) >> (32 - 5));//高5位
lIdx = (UCHAR)((Vol & 0x0000F800) >> (16 - 5));//中间五位
RETAILMSG( DBG_AACI, (TEXT("AACI_SetVolume()\r\n")));
// Convert to CODEC volume range
// NOTE: Swap L & R as output is reversed on Versatile
lVol = VolumeLUT[rIdx];//总共有32档2的5次方 --总共32档
rVol = VolumeLUT[lIdx];//总共有32档2的5次方 --总共32档
RETAILMSG( 0, (TEXT("lIdx (size=%d)\n"),lIdx) );
RETAILMSG( 0, (TEXT("rIdx (size=%d)\n"),rIdx) );
RETAILMSG( 0, (TEXT("lVol (size=%d)\n"),lVol) );
RETAILMSG( 0, (TEXT("rVol (size=%d)\n"),rVol) );
// 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 )//这个成立则对应 LOUT2/ROUT2 VOL =100000--这种情况衰减倍数太多基本就没有输出,所以可以直接关掉
codecVol = LM4549A_BIT_VOLUME_MUTE;
MISC2("AACI_SetVolume: MSFT:0x%08x, CODEC:0x%04x", Vol, codecVol);
Volume = codecVol;
//add junxz 调整到最小音量不为最大的bug
//当音量小于一定的值时就关掉功放
if(lIdx < DEFAULT_MINI_VOLUME || rIdx < DEFAULT_MINI_VOLUME)
{
AACI_CodecWrite16( 0x18, 0xe000 );
//AACI_RegWrite32( AACIReg_Slot12Tx, 0x00000 );
//AACI_RegWrite32( AACIReg_Slot12Tx, (AACI_CodecRead16(0x54)&(~0x07)) <<4);
//SET_SLOT12_FALSE;
set_pa_off();
}
else
{
if(lout&&playflags)
{
if(TRUE==leftout)
{
AACI_CodecWrite16( 0x18, 0xa000 );
}
else
{
AACI_CodecWrite16( 0x18, AACI_CodecRead16(0x18)|0x001d);
}
//AACI_RegWrite32( AACIReg_Slot12Tx, (AACI_CodecRead16(0x54)|0x07) <<4 );
//SET_SLOT12_TRUE;
set_pa_on();
}
else if(headphone&&playflags)
{
AACI_CodecWrite16( 0x18, 0x4000);
}
}
if(lout&&playflags)//如果当前是用喇叭并且当前是在播放
AACI_CodecWrite16( 0x02, Volume&0x7fff );//控制喇叭寄存器(通过0x02控制音量)
else
AACI_CodecWrite16( 0x02, Volume|0x8000 );//控制喇叭寄存器(通过0x02控制音量)
if(headphone&&playflags)//如果当前是用耳机并且当前是在播放
AACI_CodecWrite16( 0x04, Volume&0x7fff );//控制喇叭寄存器(通过0x02控制音量)
else
AACI_CodecWrite16( 0x04, Volume|0x8000 );//控制喇叭寄存器(通过0x02控制音量)
}
//---------------------------------------------------------
// VOID AACI_LeftSound(WAPI_INOUT)
//
// Sets WAPI_OUT or WAPI_IN to set left speaker on or off
//---------------------------------------------------------
void AACI_LeftSound(WAPI_INOUT apidir)
{
if((WAPI_OUT == apidir)&&(headphone!=TRUE)) // off left speaker
{
if(fp)fprintf(fp, "off left speaker\n");
leftout = FALSE;
AACI_CodecWrite16(0x02, AACI_CodecRead16(0x02)|0x001f);
RETAILMSG( 0, (TEXT("AACI_LeftSound() -> OFF AACI_CodecRead16(0x18)=0x%x\r\n"), AACI_CodecRead16(0x18)) );
}
else if((WAPI_IN == apidir)&&(headphone!=TRUE)) // on left speaker
{
if(fp)fprintf(fp, "on left speaker\n");
leftout = TRUE;
//for test
AACI_CodecWrite16(0x02, AACI_CodecRead16(0x02)&(~0x001f)); // modify by he
//AACI_CodecWrite16(0x02, Volume);
RETAILMSG( 0, (TEXT("AACI_LeftSound() -> ON AACI_CodecRead16(0x18)=0x%x\r\n"), AACI_CodecRead16(0x18)) );
}
}
// -----------------------------------------------------------------------------
//
// 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);
}
#define WM9712_WRITE 1
#define WM9712_READ 0
//-----------------------------------------------------------------------
//
// USHORT AACI_CodecRead16( USHORT codec_reg )
//
// Reads data from the CODEC
//
//-----------------------------------------------------------------------
USHORT AACI_CodecRead16( USHORT codec_reg )
{
#ifdef WAV_DEBUG
USHORT ret;
USHORT data = codec_reg;
ULONG size;
if(hd_9712 != INVALID_HANDLE_VALUE)
DeviceIoControl(hd_9712, WM9712_READ, (BYTE*)&data, sizeof(USHORT), &ret, NULL, &size, NULL);
return ret;
#else
ENTERMUTEX;
// 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")
RELEASEMUTEX;
return( (USHORT)(AACI_RegRead32( AACIReg_Slot2Rx ) >> 4) );
#endif
}
typedef struct
{
USHORT reg;
USHORT data;
} PARA, *pPARA;
//-----------------------------------------------------------------------
//
// void AACI_CodecWrite16( USHORT codec_reg, USHORT codec_data )
//
// Writes data to the CODEC
//
//-----------------------------------------------------------------------
VOID AACI_CodecWrite16( USHORT codec_reg, USHORT codec_data )
{
#ifdef WAV_DEBUG
int ret;
PARA para;
para.reg = codec_reg;
para.data = codec_data;
if(hd_9712 != INVALID_HANDLE_VALUE)
DeviceIoControl(hd_9712, WM9712_WRITE, (BYTE*)¶, sizeof(PARA), &ret, NULL, NULL, NULL);
#else
ENTERMUTEX;
CodecSend( (((ULONG)codec_reg) << 12), (((ULONG)codec_data) << 4) );
RELEASEMUTEX;
#endif
}
//-----------------------------------------------------------------------
// 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -