📄 hwctxt.cpp
字号:
}
m_fOutputRenderMonoOnly = (dwOutputRenderMonoOnly == 1);
RegCloseKey(hDevKey);
}
return (TRUE);
}
DWORD HardwareContext::GetInterruptThreadPriority()
{
HKEY hDevKey;
DWORD dwValType;
DWORD dwValLen;
LONG regError;
DWORD dwPrio = INTERRUPT_THREAD_PRIORITY_DEFAULT; // Default priority
hDevKey = OpenDeviceKey((LPWSTR)m_DriverIndex);
if (hDevKey)
{
dwValLen = sizeof(DWORD);
regError = RegQueryValueEx(hDevKey,
TEXT("Priority256"),
NULL,
&dwValType,
(PUCHAR)&dwPrio,
&dwValLen);
if (regError != ERROR_SUCCESS)
{
DEBUGMSG(ZONE_INIT,(TEXT("WAVEDEV_GetRegKeys: INFO: Failed opening \\Drivers\\BuiltIn\\WaveDev\\Priority256\r\n")));
}
RegCloseKey(hDevKey);
}
return dwPrio;
}
BOOL HardwareContext::Deinit()
{
DEBUGMSG(ZONE_INIT, (TEXT("HardwareContext::Deinit\r\n")));
m_audioDeinit = TRUE;
StopOutputDMA();
StopInputDMA();
UnmapDMA();
//Power down Codec and shutdown the AClink/IIS
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::HandleAudioInterrupt()
{
DWORD dwDCSR;
DWORD dwDINT;
ULONG InputTransferred;
ULONG OutputTransferred;
int buffer;
dwDINT = m_pDMARegisters->dint;
if(dwDINT & DMAC_AC97AUDIORCV)
{
//
// I N P U T
//
dwDCSR = m_pDMARegisters->dcsr[m_RecordingChannel];
//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;
// Handle the interrupt
buffer = GetLastInputBuffer();
InputTransferred = TransferInputBuffer(buffer);
if( InputTransferred==0 )
{
StopInputDMA();
}
}
if(dwDINT & DMAC_AC97AUDIOXMIT)
{
//
// O U T P U T
//
dwDCSR = m_pDMARegisters->dcsr[m_PlaybackChannel];
//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;
// Handle the interrupt
buffer = GetNextOutputBuffer();
OutputTransferred = TransferOutputBuffer(buffer);
if(!m_OutputDMARunning)
{
if(OutputTransferred)
{
// More data to play. Restart DMA engine by loading the descriptor
// address reg to initialize DMA, pointing to the buffer just loaded.
m_pDMARegisters->ddg[m_PlaybackChannel].ddadr =
(buffer == 0) ? (UINT32)m_vpAudioXmitA_Physical : (UINT32)m_vpAudioXmitB_Physical;;
// Set the RUN bit and also enable STOPINTR so that we know DMA is done
// on last buffer. A zero length buffer is considered the last buffer.
m_pDMARegisters->dcsr[m_PlaybackChannel] |= DCSR_RUN | DCSR_STOPIRQEN;
m_OutputDMARunning=TRUE;
}
else
{
// No more data to play. Will stop when the previous buffer
StopOutputDMA();
}
}
}
return;
}
void HardwareContext::InterruptThread()
{
while (TRUE)
{
InterruptDone(m_SysIntrAudioDMA);
WaitForSingleObject(m_hAudioInterrupt, INFINITE);
if (TRUE == m_audioDeinit)
{
return;
}
Lock();
HandleAudioInterrupt();
Unlock();
} // while(TRUE)
}
void CallInterruptThread(HardwareContext *pHWContext)
{
DEBUGMSG(ZONE_INIT, (TEXT("CallInterruptThread")));
pHWContext->InterruptThread();
}
#if !USE_I2S_INTERFACE
BOOL HardwareContext::TestAcLink()
{
BOOL RetVal=TRUE;
int i;
unsigned short int Value;
for (i=0;i<0x80;i+=2)
{
SafeReadCodec(i, &Value, DEV_AUDIO);
RETAILMSG(1, (TEXT( "register::value %x %x" ),i,Value ));
}
return (RetVal);
}
#endif
//------------------------------------------------------------------------------------------------------------
// Function: FillDescriptors
//
// Purpose: Fill the descriptors with appropriate data
//
// Note: This code could be cleaner, but I want to be explicit on the programming of descriptors
//
//-------------------------------------------------------------------------------------------------------------
BOOL HardwareContext::FillOutputDescriptors( void )
{
union DmaCmdReg CmdBuff;
memset (&CmdBuff,0, sizeof (CmdBuff));
// set individual bit fields to for debug.
#define USE_BITFIELD
#ifdef USE_BITFIELD
// set values with bit fields
CmdBuff.DcmdReg.len = AUDIO_BUFFER_SIZE; //length of memory buffer
CmdBuff.DcmdReg.width = 0x3; // binary 11 (see quick Quick Reference sheet to DMA programming in the cotulla EAS)
CmdBuff.DcmdReg.size = 0x3; // binary 11
CmdBuff.DcmdReg.endian = 0; // little endian
CmdBuff.DcmdReg.flybyt = 0; // Flowthrough
CmdBuff.DcmdReg.flybys = 0; // Flowthrough
CmdBuff.DcmdReg.endirqen = 1; // 1 means Interrupt when decrement length = 0;
CmdBuff.DcmdReg.startirqen = 0; // 1 means Interrupt when the desc is loaded
CmdBuff.DcmdReg.flowtrg = 1; // 1 means the target is an external peripheral
CmdBuff.DcmdReg.flowsrc = 0; // 1 means the source is an external peripheral (and needs flow con
CmdBuff.DcmdReg.inctrgadd = 0; // 1 means increment the target address (since it's memory)
CmdBuff.DcmdReg.incsrcadd = 1; // 1 means increment the source address (since it's a peripheral)
#else
// set value based on masks
CmdBuff.DcmdDword = DMAC_AC97_XMITAB_CMD_MASK | AUDIO_BUFFER_SIZE;
#endif
//
// fill XmitA Descriptor
//
m_vpAudioXmitA->ddadr= (UINT32)m_vpAudioXmitB_Physical ; // address of the next (XmitB) descriptor
#if USE_I2S_INTERFACE
m_vpAudioXmitA->dtadr= DMAC_IIS_AUDIO_XMIT_FIFO; // source address of the IIS XmitA buffer
#else
m_vpAudioXmitA->dtadr= DMAC_AC97_AUDIO_XMIT_FIFO; // source address of the AC97 XmitA buffer
#endif
m_vpAudioXmitA->dsadr= (UINT32)(m_Output_pbDMA_PAGES_Physical[0]); // destination address of the XmitA buffer
m_vpAudioXmitA->dcmd = CmdBuff.DcmdDword ; // size and cmd values of the XmitA buffer
//
// fill XmitB Descriptor
//
m_vpAudioXmitB->ddadr= (UINT32)m_vpAudioXmitA_Physical; // address of the next (XmitA) descriptor
#if USE_I2S_INTERFACE
m_vpAudioXmitB->dtadr= DMAC_IIS_AUDIO_XMIT_FIFO; // source address of the IIS XmitB buffer
#else
m_vpAudioXmitB->dtadr= DMAC_AC97_AUDIO_XMIT_FIFO; // source address of the AC97 XmitB buffer
#endif
m_vpAudioXmitB->dsadr= (UINT32)(m_Output_pbDMA_PAGES_Physical[1]) ; // destination address of the XmitB buffer
m_vpAudioXmitB->dcmd = CmdBuff.DcmdDword ; // size and cmd values of the XmitB buffer
return TRUE;
}
//------------------------------------------------------------------------------------------------------------
// Function: FillDescriptors
//
// Purpose: Fill the descriptors with appropriate data
//
// Note: This code could be cleaner, but I want to be explicit on the programming of descriptors
//
//-------------------------------------------------------------------------------------------------------------
BOOL HardwareContext::FillInputDescriptors( void )
{
union DmaCmdReg CmdBuff;
memset (&CmdBuff,0, sizeof (CmdBuff));
// set individual bit fields to for debug.
#define USE_BITFIELD
#ifdef USE_BITFIELD
// set values with bit fields
CmdBuff.DcmdReg.len = AUDIO_BUFFER_SIZE; //length of the memory buffer
CmdBuff.DcmdReg.width = 0x3; // binary 11 (see quick Quick Reference sheet to DMA programming in the cotulla EAS)
CmdBuff.DcmdReg.size = 0x3; // binary 11
CmdBuff.DcmdReg.endian = 0; // little endian
CmdBuff.DcmdReg.flybyt = 0; // Flowthrough
CmdBuff.DcmdReg.flybys = 0; // Flowthrough
CmdBuff.DcmdReg.endirqen = 1; // 1 means Interrupt when decrement length = 0;
CmdBuff.DcmdReg.startirqen = 0; // 1 means Interrupt when the desc is loaded
CmdBuff.DcmdReg.flowtrg = 0; // 1 means the target is an external peripheral
CmdBuff.DcmdReg.flowsrc = 1; // 1 means the source is an external peripheral (and needs flow control)
CmdBuff.DcmdReg.inctrgadd = 1; // 1 means increment the target address (since it's memory)
CmdBuff.DcmdReg.incsrcadd = 0; // 1 means increment the source address (since it's a peripheral)
#else
// set value based on masks
CmdBuff.DcmdDword = DMAC_AC97_RCVAB_CMD_MASK | AUDIO_BUFFER_SIZE;
#endif
//
// fill RcvA Descriptor
//
m_vpAudioRcvA-> ddadr= (UINT32)m_vpAudioRcvB_Physical; // address of the next (RcvB) descriptor
m_vpAudioRcvA-> dtadr= (UINT32)(m_Input_pbDMA_PAGES_Physical[0]); // source address of the AC97 RcvA buffer
#if USE_I2S_INTERFACE
m_vpAudioRcvA-> dsadr= DMAC_IIS_AUDIO_RCV_FIFO; // destination address of the RcvA buffer
#else
m_vpAudioRcvA-> dsadr= DMAC_AC97_AUDIO_RCV_FIFO; // destination address of the RcvA buffer
#endif
m_vpAudioRcvA-> dcmd = CmdBuff.DcmdDword ; // size and cmd values of the RcvA buffer
//
// fill RcvB Descriptor
//
m_vpAudioRcvB-> ddadr= (UINT32)m_vpAudioRcvA_Physical ; // address of the next (RcvA) descriptor
m_vpAudioRcvB-> dtadr= (UINT32)(m_Input_pbDMA_PAGES_Physical[1]); // source address of the AC97 RcvB buffer
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -