📄 hwctxt.cpp
字号:
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();
DeInitAC97(FALSE);
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;
// 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);
}
return;
}
void HardwareContext::InterruptThread()
{
while (TRUE)
{
WaitForSingleObject(m_hAudioInterrupt, INFINITE);
if (TRUE == m_audioDeinit)
{
return;
}
// Grab the lock
Lock();
GetInterruptType();
Unlock();
InterruptDone(m_SysIntrAudioDMA);
} // while(TRUE)
}
void CallInterruptThread(HardwareContext *pHWContext)
{
DEBUGMSG(ZONE_INIT, (TEXT("CallInterruptThread")));
pHWContext->InterruptThread();
}
void CallInputInterruptThread(HardwareContext *pHWContext)
{
DEBUGMSG(ZONE_INIT, (TEXT("CallInputInterruptThread")));
pHWContext->InputInterruptThread();
}
void CallOutputInterruptThread(HardwareContext *pHWContext)
{
DEBUGMSG(ZONE_INIT, (TEXT("CallOutputInterruptThread")));
pHWContext->OutputInterruptThread();
}
void HardwareContext::InputInterruptThread( )
{
ULONG InputTransferred;
DEBUGMSG(ZONE_INIT, (TEXT("InputInterruptThread")));
while (TRUE)
{
WaitForSingleObject(hInputIntEvent, INFINITE);
if (TRUE == m_audioDeinit)
{
return;
}
DEBUGMSG(ZONE_VERBOSE, (TEXT( "DCSR_ENDINTR on intput\r\n" )) );
Lock();
int buffer = GetLastInputBuffer();
InputTransferred = TransferInputBuffer(buffer);
if( InputTransferred==0 )
{
StopInputDMA();
}
Unlock();
}
}
void HardwareContext::OutputInterruptThread( )
{
DEBUGMSG(ZONE_INIT, (TEXT("OutputInterruptThread")));
while (TRUE)
{
WaitForSingleObject(hOutputIntEvent, INFINITE);
if (TRUE == m_audioDeinit)
{
return;
}
DEBUGMSG(ZONE_VERBOSE, (TEXT( "DCSR_ENDINTER on output\r\n" )) );
Lock();
int buffer = GetNextOutputBuffer();
ULONG Bytes = TransferOutputBuffer(buffer);
if(!m_OutputDMARunning)
{
if(Bytes)
{
// 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();
}
}
Unlock();
}
}
BOOL HardwareContext::TestAcLink()
{
BOOL RetVal=TRUE;
int i;
unsigned short int Value;
for (i=0;i<0x80;i+=2)
{
SafeReadAC97(i, &Value);
RETAILMSG(1, (TEXT( "register::value %x %x" ),i,Value ));
}
return (RetVal);
}
//------------------------------------------------------------------------------------------------------------
// 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
m_vpAudioXmitA->DTADR= DMAC_AC97_AUDIO_XMIT_FIFO; // source address of the AC97 XmitA buffer
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -