📄 hwctxt.cpp
字号:
// Enable STOPINTR so that we know DMA is done on final buffer. A zero length buffer
// is considered the final buffer.
// And finally set RUN bit to start DMA.
m_pDMARegisters->dcsr[m_PlaybackChannel] |= DCSR_RUN | DCSR_STOPIRQEN;
DEBUGMSG(ZONE_ERROR, (TEXT("Started Output DMA\r\n")));
}
else
{
m_OutputDMARunning=FALSE;
DEBUGMSG(ZONE_ERROR, (TEXT("no Output started with DMA\r\n")));
}
}
}
void HardwareContext::StopOutputDMA()
{
DEBUGMSG(ZONE_VERBOSE, (TEXT("StopOutputDMA\r\n")));
if (m_OutputDMARunning)
{
//stop the dma channel and mute
StopDmac(m_PlaybackChannel);
m_OutputDMARunning=FALSE;
}
}
int HardwareContext::GetLastInputBuffer(void)
{
return ((UINT32)m_pDMARegisters->ddg[m_RecordingChannel].dtadr >= (UINT32)m_Input_pbDMA_PAGES_Physical[1]) ? 0 : 1 ;
}
void HardwareContext::StartInputDMA()
{
if (!m_InputDMARunning)
{
#if RT_ALC5621
m_RTCodec->WriteCodecRegMask(RT5621_MISC_CTRL,DISABLE_FAST_VREG,DISABLE_FAST_VREG); //disable fast vreg,it will affect quality of audio
#else
m_RTCodec->WriteCodecRegMask(RT_MISC_CTRL,DISABLE_FAST_VREG,DISABLE_FAST_VREG); //disable fast vreg,it will affect quality of audio
#endif
//set it on every buffer due to ac97 work around. (???)
SetSampleRate(SAMPLERATE, WAPI_IN);
// For now, pretend input dma is running in case we accidentally get reentered
m_InputDMARunning=TRUE;
//DMA_CH_RCV:
DEBUGMSG(ZONE_ERROR, (TEXT( "Starting DMA Recieve channel \r\n" )) );
m_pDMARegisters->ddg[m_RecordingChannel].ddadr = (UINT32)m_vpAudioRcvA_Physical;
#if USE_I2S_INTERFACE
m_pDMARegisters->drcmr[DMA_CHMAP_I2S_RCV] = DMA_MAP_VALID_MASK | m_RecordingChannel ;
m_pI2SRegs->SAICR=XLLP_SAICR_ROR;//clear receive FIFO overrun
#else
m_pDMARegisters->drcmr[DMA_CHMAP_AC97_RCV] = DMA_MAP_VALID_MASK | m_RecordingChannel ;
m_pAc97regs->PISR = 0x10; // clear Pcm Input Fifo status
m_pAc97regs->PISR = 0x8; // dedicated write to clear EOC bit
#endif
m_pDMARegisters->dcsr[m_RecordingChannel] |= DCSR_RUN; // set the RUN bit
}
}
void HardwareContext::StopInputDMA()
{
if (m_InputDMARunning)
{
m_InputDMARunning=FALSE;
StopDmac(m_RecordingChannel);
}
}
/* ;resample stereo output to mono output?
;set this if your platform has only mono speaker. if your platform supports
; both mono speaker and a stereo headset you'll have to dynamically change
; the flag in wavedev2 driver for proper output rendering (mono vs. stereo)
;MainstoneIII has both a mono speaker and a stereo headphone jack. But unfortunately
; headphone presence detection is not supported by the onboard philips codec.
; For this reason we only render mono output.
"HKLM\Drivers\BuiltIn\WaveDev\OutputRenderMonoOnly"=dword:1 <-- Reg Key
m_fOutputRenderMonoOnly <-- flag in wavedev2 driver
*/
#define WAV_OUTPUT_RENDER_MONO_ONLY TEXT("OutputRenderMonoOnly")
BOOL HardwareContext::GetRegKeys()
{
HKEY hDevKey;
hDevKey = OpenDeviceKey((LPWSTR)m_DriverIndex);
if (hDevKey)
{
DWORD dwValLen = sizeof(DWORD);
DWORD dwOutputRenderMonoOnly = 0;
LONG regError = RegQueryValueEx(hDevKey, WAV_OUTPUT_RENDER_MONO_ONLY, NULL, NULL,
(PUCHAR)&dwOutputRenderMonoOnly, &dwValLen);
if (regError != ERROR_SUCCESS)
{
DEBUGMSG(ZONE_INIT,(TEXT("WAVEDEV_GetRegKeys: INFO: Failed opening \\Drivers\\BuiltIn\\WaveDev\\OutputRenderMonoOnly\r\n")));
}
m_fOutputRenderMonoOnly = (dwOutputRenderMonoOnly == 1);
RegCloseKey(hDevKey);
}
return (TRUE);
}
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;
}
BOOL HardwareContext::InitInterruptThread()
{
DEBUGMSG(ZONE_INIT, (TEXT("+InitInterruptThread\r\n")));
m_hAudioInputInterruptThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL,
0,
(LPTHREAD_START_ROUTINE)CallInputInterruptThread,
this,
0,
NULL);
m_hAudioOutputInterruptThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL,
0,
(LPTHREAD_START_ROUTINE)CallOutputInterruptThread,
this,
0,
NULL);
if (!m_hAudioInputInterruptThread)
{
return FALSE;
}
if (!m_hAudioOutputInterruptThread)
{
return FALSE;
}
// Bump up the priority since the interrupt must be serviced immediately.
CeSetThreadPriority(m_hAudioInputInterruptThread, GetInterruptThreadPriority());
CeSetThreadPriority(m_hAudioOutputInterruptThread, GetInterruptThreadPriority());
DEBUGMSG(ZONE_INIT, (TEXT("-InitInterruptThread\r\n")));
return TRUE;
}
BOOL HardwareContext::Deinit()
{
DEBUGMSG(ZONE_INIT, (TEXT("HardwareContext::Deinit\r\n")));
m_audioDeinit = TRUE;
StopOutputDMA();
StopInputDMA();
UnmapDMA();
//Power down Codec and shutdown the AClink
PowerDown();
#if USE_I2S_INTERFACE
//De-allocate the I2S
DeInitializeI2S(m_InPowerHandler);
#else
//De-allocate the AC97
DeInitializeACLink(FALSE, DEV_AUDIO);
#endif
DeinitAudioDMA();
UnMapDeviceRegisters();
m_Initialized = FALSE;
return TRUE;
}
ULONG HardwareContext::TransferInputBuffer(ULONG NumBuf)
{
ULONG BytesTransferred;
PBYTE pBufferStart = m_Input_pbDMA_PAGES[NumBuf];
PBYTE pBufferEnd = pBufferStart + AUDIO_BUFFER_SIZE;
PBYTE pBufferLast;
DEBUGMSG(ZONE_FUNCTION, (TEXT("TransferInputBuffer %d"), NumBuf));
pBufferLast = m_InputDeviceContext.TransferBuffer(pBufferStart, pBufferEnd,NULL);
BytesTransferred = pBufferLast-pBufferStart;
return BytesTransferred;
}
ULONG HardwareContext::TransferOutputBuffer(ULONG NumBuf)
{
ULONG BytesTransferred;
PBYTE pBufferStart = m_Output_pbDMA_PAGES[NumBuf];
PBYTE pBufferEnd = pBufferStart + AUDIO_BUFFER_SIZE;
PBYTE pBufferLast;
DEBUGMSG(ZONE_FUNCTION, (TEXT("TransferOutputBuffer %d\r\n"), NumBuf));
pBufferLast = m_OutputDeviceContext.TransferBuffer(pBufferStart, pBufferEnd,NULL);
BytesTransferred = pBufferLast-pBufferStart;
// PXA27x AC'97 Controller will transmit data in multiple of 32 bytes only.
// The trailing bytes will not be transmitted.
// So we pad the buffer with zeroes to a multiple of 32 bytes.
if(int pad = (BytesTransferred % 32))
{
// number of bytes to pad
pad = 32 - pad;
StreamContext::ClearBuffer(pBufferLast, pBufferLast+pad);
BytesTransferred += pad;
}
// Set DMA transfer length based on actual data in buffer.
// Also set STOP bit if it is the last buffer (ie. zero length buffer).
if(NumBuf == 0)
{
m_vpAudioXmitA->dcmd = DMAC_AC97_XMITAB_CMD_MASK | BytesTransferred;
if(BytesTransferred)
{
m_vpAudioXmitA->ddadr &= ~DESC_ADDRESS_STOP_MASK;
}
else
{
m_vpAudioXmitA->ddadr |= DESC_ADDRESS_STOP_MASK;
}
}
else
{
m_vpAudioXmitB->dcmd = DMAC_AC97_XMITAB_CMD_MASK | BytesTransferred;
if(BytesTransferred)
{
m_vpAudioXmitB->ddadr &= ~DESC_ADDRESS_STOP_MASK;
}
else
{
m_vpAudioXmitB->ddadr |= DESC_ADDRESS_STOP_MASK;
}
}
DEBUGMSG(ZONE_VERBOSE, (TEXT("Fill buffer[%d]: 0x%x\r\n"), NumBuf, BytesTransferred));
return BytesTransferred;
}
VOID HardwareContext::GetInterruptType()
{
DWORD dwDCSR;
DWORD dwDINT;
dwDINT = m_pDMARegisters->dint;
DEBUGMSG(ZONE_VERBOSE, (TEXT( "HardwareContext::GetInterruptType: DINT=0x%x\r\n" ), dwDINT));
if(dwDINT & DMAC_AC97AUDIORCV)
{
//
// I N P U T
//
dwDCSR = m_pDMARegisters->dcsr[m_RecordingChannel];
DEBUGMSG(ZONE_VERBOSE, (TEXT( "GetInterruptType: RCV DCSR: 0x%x\r\n" ),dwDCSR));
// Provide waiting Object the current value of DCSR
// SetEventData(hInputIntEvent, dwDCSR);
//did we get an input error?
if (dwDCSR & DCSR_BUSERRINTR)
{
DEBUGMSG(ZONE_ERROR, (TEXT( "DCSR_BUSERRINTR ERROR on input\r\n" )) );
DEBUGCHK(0); // an unplanned dma interrupt occured
DumpDmacRegs();
}
//did we get an input start interrupt?
if (dwDCSR & DCSR_STARTINTR)
{
DEBUGMSG(ZONE_VERBOSE, (TEXT( "DCSR_STARTINTR on input\r\n" )) );
DEBUGCHK(0); // an unplanned dma interrupt occured
}
//did we get an input end interrupt?
if (dwDCSR & DCSR_ENDINTR) //if the input channel stopped at the end of a buffer xfer
{
DEBUGMSG(ZONE_ERROR, (TEXT( "DCSR_ENDINTR on intput\r\n" )) );
}
//did we get an input stop interrupt?
if (dwDCSR & DCSR_STOPINTR)
{
DEBUGMSG(ZONE_VERBOSE, (TEXT( "DCSR_STOPINTR on input\r\n" )) );
dwDCSR &= ~DCSR_STOPIRQEN;
DEBUGCHK(0); // an unplanned dma interrupt occured
}
// Clear the status
m_pDMARegisters->dcsr[m_RecordingChannel] = dwDCSR;
SetEvent(hInputIntEvent);
}
if(dwDINT & DMAC_AC97AUDIOXMIT)
{
//
// O U T P U T
//
dwDCSR = m_pDMARegisters->dcsr[m_PlaybackChannel];
DEBUGMSG(ZONE_VERBOSE, (TEXT( "GetInterruptType: OUT DCSR: 0x%x\r\n" ),dwDCSR));
// Provide waiting Object the current value of DCSR
// SetEventData(hOutputIntEvent, dwDCSR);
//did we get an output error?
if (dwDCSR & DCSR_BUSERRINTR)
{
DEBUGMSG(ZONE_ERROR, (TEXT( "DCSR_BUSERRINTR ERROR on output\r\n" )) );
DumpDmacRegs();
//note if we get here, we have a lot more to do than clear the interrupt.
DEBUGCHK(0); // an unplanned dma interrupt occured
}
//did we get an output start interrupt?
if (dwDCSR & DCSR_STARTINTR)
{
DEBUGMSG(ZONE_VERBOSE, (TEXT( "DCSR_STARTINTR on output\r\n" )) );
}
//did we get an output end interrupt?
if (dwDCSR & DCSR_ENDINTR) //if the out channel stopped at the end of a buffer xfer
{
DEBUGMSG(ZONE_VERBOSE, (TEXT( "DCSR_ENDINTR on output\r\n" )) );
}
//did we get an output stop interrupt?
if (dwDCSR & DCSR_STOPINTR)
{
DEBUGMSG(ZONE_VERBOSE, (TEXT( "DCSR_STOPINTR on output\r\n" )) );
dwDCSR &= ~DCSR_STOPIRQEN;
m_OutputDMARunning = FALSE;
}
// Clear the status
m_pDMARegisters->dcsr[m_PlaybackChannel] = dwDCSR;
SetEvent(hOutputIntEvent);
}
// RETAILMSG(1, (TEXT( "dwDINT=%x"),dwDINT));
return;
}
void HardwareContext::InterruptThread()
{
while (TRUE)
{
WaitForSingleObject(m_hAudioInterrupt, INFINITE);
if (TRUE == m_audioDeinit)
{
return;
}
// Grab the lock
Lock();
GetInterruptType();
Unlock();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -