📄 hwctxt.cpp
字号:
hardware bug in the revision of the Samsung SC2440
CPU this driver was developed on. See the header
at the top of this file for details.
Returns: Boolean indicating success
-------------------------------------------------------------------*/
BOOL HardwareContext::StartInputDMA()
{
//------ On platforms with the revsion of the Samsung SC2440 CPU with the IIS SLAVE bug fix, this -----
// code can be used to configure DMA channel 1 for input.
AC97MSG(1,(TEXT("+++StartInputDMA\n")));
if(!m_InputDMARunning)
{
//----- 1. Initialize our buffer counters -----
m_InputDMARunning=TRUE;
Codec_channel(); // Turn On Input channel
m_InBytes[IN_BUFFER_A]=m_InBytes[IN_BUFFER_B]=0;
//----- 2. Prime the output buffer with sound data -----
m_InputDMAStatus = (DMA_DONEA | DMA_DONEB) & ~DMA_BIU;
//----- 3. Configure the DMA channel for record -----
if(!InitInputDMA())
{
DEBUGMSG(ZONE_ERROR, (TEXT("HardwareContext::StartInputDMA() - Unable to initialize input DMA channel!\r\n")));
goto START_ERROR;
}
#if DMA_FLAG
v_pAC97regs->rAC_GLBCTRL = (v_pAC97regs->rAC_GLBCTRL & ~(0x3<<8)) | (0x2<<8); // 0x2 = DMA
#else
v_pAC97regs->rAC_GLBCTRL = (v_pAC97regs->rAC_GLBCTRL & ~(0x3<<8)) | (0x1<<8); // 0x1 = PIO
#endif
//----- 4. Make sure the audio isn't muted -----
AudioMute(DMA_CH_MIC, FALSE);
//----- 5. Start the input DMA -----
AUDIO_RESET_RECORD_POINTER();
SELECT_AUDIO_DMA_INPUT_BUFFER_A();
Codec_channel(); // Turn On Input channel
v_pDMAregs->rDMASKTRIG2 = ENABLE_DMA_CHANNEL;
#if DMA_FLAG
// wait for DMA to start.
delay_count = 0;
while((v_pDMAregs->rDSTAT2&0xfffff)==0){
RETAILMSG(1,(_T("2")));
#if WAIT_DMA_END
Sleep(1);
#else
if( delay_count++ > DELAY_COUNT ) break;
#endif
}
// change the buffer pointer
SELECT_AUDIO_DMA_INPUT_BUFFER_B();
#endif
}
AC97MSG(1,(TEXT("---StartInputDMA\n")));
return TRUE;
START_ERROR:
return FALSE;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: StopInputDMA()
Description: Stops any DMA activity on the input channel.
Notes: ***** NOT IMPLEMENTED *****
The following routine is not implemented due to a
hardware bug in the revision of the Samsung SC2440
CPU this driver was developed on. See the header
at the top of this file for details.
Returns: Boolean indicating success
-------------------------------------------------------------------*/
void HardwareContext::StopInputDMA()
{
//------ On platforms with the revsion of the Samsung SC2440 CPU with the IIS SLAVE bug fix, this -----
// code can be used to configure DMA channel 1 for input.
//----- 1. If the output DMA is running, stop it -----
if (m_InputDMARunning)
{
AUDIO_IN_DMA_DISABLE(); // jylee
AUDIO_IN_CLEAR_INTERRUPTS();
m_InputDMAStatus = DMA_CLEAR;
v_pAC97regs->rAC_GLBCTRL = (v_pAC97regs->rAC_GLBCTRL & ~(0x3<<8)) | (0x0<<8); // 0x0 = OFF
AudioMute(DMA_CH_MIC, TRUE);
}
m_InputDMARunning = FALSE;
Codec_channel();
}
DWORD HardwareContext::GetInterruptThreadPriority()
{
HKEY hDevKey;
DWORD dwValType;
DWORD dwValLen;
DWORD dwPrio = 249; // Default priority
hDevKey = OpenDeviceKey((LPWSTR)m_DriverIndex);
if (hDevKey)
{
dwValLen = sizeof(DWORD);
RegQueryValueEx(
hDevKey,
TEXT("Priority256"),
NULL,
&dwValType,
(PUCHAR)&dwPrio,
&dwValLen);
RegCloseKey(hDevKey);
}
return dwPrio;
}
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// SetForceSpeaker is called from the device context to update the state of the
// m_bForceSpeaker variable.
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
DWORD HardwareContext::ForceSpeaker( BOOL bForceSpeaker )
{
// If m_NumForcedSpeaker is non-zero, audio should be routed to an
// external speaker (if hw permits).
if (bForceSpeaker)
{
m_NumForcedSpeaker++;
if (m_NumForcedSpeaker==1)
{
RecalcSpeakerEnable();
}
}
else
{
m_NumForcedSpeaker--;
if (m_NumForcedSpeaker==0)
{
RecalcSpeakerEnable();
}
}
return MMSYSERR_NOERROR;
}
// Control the hardware speaker enable
void HardwareContext::SetSpeakerEnable(BOOL bEnable)
{
// Code to turn speaker on/off here
return;
}
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// RecalcSpeakerEnable decides whether to enable the speaker or not.
// For now, it only looks at the m_bForceSpeaker variable, but it could
// also look at whether the headset is plugged in
// and/or whether we're in a voice call. Some mechanism would
// need to be implemented to inform the wave driver of changes in the state of
// these variables however.
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
void HardwareContext::RecalcSpeakerEnable()
{
SetSpeakerEnable(m_NumForcedSpeaker);
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: InitInterruptThread()
Description: Initializes the IST for handling DMA interrupts.
Returns: Boolean indicating success
-------------------------------------------------------------------*/
BOOL HardwareContext::InitInterruptThread()
{
BOOL bSuccess;
m_hAudioInterrupt = CreateEvent( NULL, FALSE, FALSE, NULL);
if (!m_hAudioInterrupt)
{
return FALSE;
}
bSuccess = InterruptInitialize(m_IntrAudio, m_hAudioInterrupt, NULL, 0);
m_hAudioInterruptThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL,
0,
(LPTHREAD_START_ROUTINE)CallInterruptThread,
this,
0,
NULL);
if (!m_hAudioInterruptThread)
{
return FALSE;
}
// Bump up the priority since the interrupt must be serviced immediately.
CeSetThreadPriority(m_hAudioInterruptThread, GetInterruptThreadPriority());
return TRUE;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: PowerUp()
Description: Powers up the audio codec chip.
Notes: Currently, this function is unimplemented because
the audio codec chip is ONLY powered up when the
user wishes to play or record. The AudioMute() function
handles the powerup sequence.
Returns: Boolean indicating success
-------------------------------------------------------------------*/
void HardwareContext::PowerUp()
{
RETAILMSG(1,(_T("AC97:PowerUP()\r\n")));
AC97_Init();
//AC97_GPIO_Init();
InitCodec();
//AudioMute(DMA_CH_OUT, FALSE); // 030711
// setup DMA output
//InitOutputDMA();
//AudioMute((DMA_CH_OUT | DMA_CH_MIC), FALSE);
AudioMute(DMA_CH_OUT, FALSE);
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: PowerDown()
Description: Powers down the audio codec chip.
Notes: Even if the input/output channels are muted, this
function powers down the audio codec chip in order
to conserve battery power.
Returns: Boolean indicating success
-------------------------------------------------------------------*/
void HardwareContext::PowerDown()
{
RETAILMSG(1,(_T("AC97:PowerDown()\r\n")));
//StopOutputDMA();
m_OutputDMAStatus = DMA_CLEAR;
AUDIO_OUT_DMA_DISABLE();
AUDIO_OUT_CLEAR_INTERRUPTS();
v_pAC97regs->rAC_GLBCTRL = (v_pAC97regs->rAC_GLBCTRL & ~(0x3<<12)) | (0x0<<12); // 0x0 = OFF
//AudioMute(DMA_CH_OUT, TRUE);
m_OutputDMARunning = FALSE;
m_InputDMARunning = FALSE;
AudioMute((DMA_CH_OUT | DMA_CH_MIC), TRUE);
}
//############################################ Helper Functions #############################################
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: TransferOutputBuffer()
Description: Retrieves the next "mixed" audio buffer of data to
DMA into the output channel.
Returns: Number of bytes needing to be transferred.
-------------------------------------------------------------------*/
ULONG HardwareContext::TransferOutputBuffer(ULONG NumBuf)
{
ULONG BytesTransferred = 0;
PBYTE pBufferStart = m_Output_pbDMA_PAGES[NumBuf];
PBYTE pBufferEnd = pBufferStart + AUDIO_DMA_PAGE_SIZE;
PBYTE pBufferLast;
__try
{
pBufferLast = m_OutputDeviceContext.TransferBuffer(pBufferStart, pBufferEnd,NULL);
BytesTransferred = m_OutBytes[NumBuf] = pBufferLast-pBufferStart;
// Enable if you need to clear the rest of the DMA buffer
StreamContext::ClearBuffer(pBufferLast,pBufferEnd);
//memset(pBufferStart, 0, AUDIO_DMA_PAGE_SIZE);
if(NumBuf == OUT_BUFFER_A) // Output Buffer A
{
m_OutputDMAStatus &= ~DMA_DONEA;
m_OutputDMAStatus |= DMA_STRTA;
}
else // Output Buffer B
{
m_OutputDMAStatus &= ~DMA_DONEB;
m_OutputDMAStatus |= DMA_STRTB;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
DEBUGMSG(ZONE_ERROR, (TEXT("WAVDEV2.DLL:TransferOutputBuffer() - EXCEPTION: %d"), GetExceptionCode()));
}
return BytesTransferred;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: TransferOutputBuffers()
Description: Determines which output buffer (A or B) needs to
be filled with sound data. The correct buffer is
then populated with data and ready to DMA to the
output channel.
Returns: Boolean indicating success
-------------------------------------------------------------------*/
ULONG HardwareContext::TransferOutputBuffers(DWORD dwDCSR)
{
ULONG BytesTransferred = 0;
ULONG BytesTotal;
DWORD Bits = dwDCSR & (DMA_DONEA|DMA_DONEB|DMA_BIU);
switch (Bits)
{
case 0:
case DMA_BIU:
// No done bits set- must not be my interrupt
return 0;
case DMA_DONEA|DMA_DONEB|DMA_BIU:
// Load B, then A
BytesTransferred = TransferOutputBuffer(OUT_BUFFER_B);
// fall through
case DMA_DONEA: // This should never happen!
case DMA_DONEA|DMA_BIU:
BytesTransferred += TransferOutputBuffer(OUT_BUFFER_A); // charlie, A => B
break;
case DMA_DONEA|DMA_DONEB:
// Load A, then B
BytesTransferred = TransferOutputBuffer(OUT_BUFFER_A);
#if DMA_FLAG
// charlie
BytesTransferred += TransferOutputBuffer(OUT_BUFFER_B);
break; // charlie
#endif
// fall through
case DMA_DONEB|DMA_BIU: // This should never happen!
case DMA_DONEB:
// Load B
BytesTransferred += TransferOutputBuffer(OUT_BUFFER_B); // charlie, B => A
break;
}
// If it was our interrupt, but we weren't able to transfer any bytes
// (e.g. no full buffers ready to be emptied)
// and all the output DMA buffers are now empty, then stop the output DMA
BytesTotal = m_OutBytes[OUT_BUFFER_A]+m_OutBytes[OUT_BUFFER_B];
if (BytesTotal==0)
{
StopOutputDMA();
}
return BytesTransferred;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: TransferInputBuffer()
Description: Retrieves the chunk of recorded sound data and inputs
it into an audio buffer for potential "mixing".
Returns: Number of bytes needing to be transferred.
-------------------------------------------------------------------*/
ULONG HardwareContext::TransferInputBuffer(ULONG NumBuf)
{
ULONG BytesTransferred = 0;
PBYTE pBufferStart = m_Input_pbDMA_PAGES[NumBuf];
PBYTE pBufferEnd = pBufferStart + AUDIO_DMA_PAGE_SIZE;
PBYTE pBufferLast;
__try
{
pBufferLast = m_InputDeviceContext.TransferBuffer(pBufferStart, pBufferEnd,NULL);
BytesTransferred = m_InBytes[NumBuf] = pBufferLast-pBufferStart;
if(NumBuf == IN_BUFFER_A) // Input Buffer A
{
m_InputDMAStatus &= ~DMA_DONEA;
m_InputDMAStatus |= DMA_STRTA;
}
else // Input Buffer B
{
m_InputDMAStatus &= ~DMA_DONEB;
m_InputDMAStatus |= DMA_STRTB;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
DEBUGMSG(ZONE_ERROR, (TEXT("WAVDEV2.DLL:TransferInputBuffer() - EXCEPTION: %d"), GetExceptionCode()));
}
return BytesTransferred;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: TransferInputBuffers()
Description: Determines which input buffer (A or B) needs to
be filled with recorded sound data. The correct
buffer is then populated with recorded sound data
from the input channel.
Returns: Boolean indicating success
-------------------------------------------------------------------*/
ULONG HardwareContext::TransferInputBuffers(DWORD dwDCSR)
{
ULONG BytesTransferred=0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -