📄 hwctxt.cpp
字号:
DEBUGMSG(ZONE_FUNCTION,(TEXT("+++StartOutputDMA\n")));
if (!m_OutputDMARunning)
{
//----- 1. Initialize our buffer counters -----
m_OutputDMARunning=TRUE;
m_OutputDMABuffer = OUT_BUFFER_A;
m_OutBytes[OUT_BUFFER_A]=m_OutBytes[OUT_BUFFER_B]=0;
//----- 2. Prime both output buffer with as much sound data as possible -----
ULONG OutputTransferred = TransferOutputBuffer(OUT_BUFFER_A);
OutputTransferred += TransferOutputBuffer(OUT_BUFFER_B);
//----- 3. If we did transfer any data to the DMA buffers, go ahead and enable DMA -----
if (OutputTransferred)
{
//----- 4. Configure the DMA channel for playback -----
if (!InitOutputDMA())
{
DEBUGMSG(ZONE_ERROR, (TEXT("HardwareContext::StartOutputDMA() - Unable to initialize output DMA channel!\r\n")));
goto Exit;
}
////////////////////////////////////////////////////////////////////////////////
// To correct left/right channel on ouput stream,
// You should reset IISCON[0] bit.
// Disable interface. This reset forces L/R bit to be reset
g_pIISregs->IISCON &= ~IIS_INTERFACE_ENABLE;
g_pIISregs->IISCON |= TRANSMIT_DMA_REQUEST_ENABLE;
g_pIISregs->IISCON &= ~TRANSMIT_IDLE_CMD;
g_pIISregs->IISFCON |= ( TRANSMIT_FIFO_ACCESS_DMA | TRANSMIT_FIFO_ENABLE );
g_pIISregs->IISMOD |= IIS_TRANSMIT_MODE;
//----- 5. Make sure the audio isn't muted -----
AudioMute(DMA_CH_OUT, FALSE);
//----- 6. Start the DMA controller -----
// Set DMA to start on buffer A
g_pDMAregs->DISRC2 = (g_PhysDMABufferAddr.LowPart);
Codec_channel(); // Turn ON output channel
// Start the DMA!
g_pDMAregs->DMASKTRIG2 &= ~STOP_DMA_TRANSFER;
g_pDMAregs->DMASKTRIG2 |= ENABLE_DMA_CHANNEL;
// wait for DMA to start so we can set the start address of buffer B.
while ((g_pDMAregs->DSTAT2&0xfffff)==0);
// Wait for some data to appear in the IIS transmit FIFO
while ( !(g_pIISregs->IISCON & TRANSMIT_FIFO_READY) ) ;
// Now reenable the IIS interface
g_pIISregs->IISCON |= IIS_INTERFACE_ENABLE;
// change the buffer pointer so the DMA autoswitches to buffer B once it's finished with A
g_pDMAregs->DISRC2 = (g_PhysDMABufferAddr.LowPart + AUDIO_DMA_PAGE_SIZE);
}
else // We didn't transfer any data, so DMA wasn't enabled
{
m_OutputDMARunning=FALSE;
}
}
DEBUGMSG(ZONE_FUNCTION,(TEXT("---StartOutputDMA\n")));
bRet = TRUE;
Exit:
return bRet;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: StopOutputDMA()
Description: Stops any DMA activity on the output channel.
Returns: Boolean indicating success
-------------------------------------------------------------------*/
void HardwareContext::StopOutputDMA()
{
//----- 1. If the output DMA is running, stop it -----
if (m_OutputDMARunning)
{
// Disable DMA
g_pDMAregs->DMASKTRIG2 |= STOP_DMA_TRANSFER;
g_pDMAregs->DMASKTRIG2 &= ~ENABLE_DMA_CHANNEL;
// Clear output interrupt
g_pDMAregs->DCON2 = g_pDMAregs->DCON2;
g_pIISregs->IISCON &= ~TRANSMIT_DMA_REQUEST_ENABLE;
g_pIISregs->IISCON |= TRANSMIT_IDLE_CMD;
g_pIISregs->IISFCON &= ~( TRANSMIT_FIFO_ACCESS_DMA | TRANSMIT_FIFO_ENABLE );
g_pIISregs->IISMOD &= ~IIS_TRANSMIT_MODE;
AudioMute(DMA_CH_OUT, TRUE);
m_OutputDMARunning = FALSE;
Codec_channel();
}
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: InitInputDMA()
Description: Initializes the DMA channel for input.
Notes: ***** NOT IMPLEMENTED *****
The following routine is not implemented due to a
hardware bug in the revision of the Samsung SC2410
CPU this driver was developed on. See the header
at the top of this file for details.
Returns: Boolean indicating success
-------------------------------------------------------------------*/
BOOL HardwareContext::InitInputDMA()
{
DEBUGMSG(ZONE_FUNCTION,(TEXT("+++InitInputDMA\n")));
if (!g_PhysDMABufferAddr.LowPart)
{
DEBUGMSG(TRUE, (TEXT("ERROR:HardwareContext::InitInputDMA: Invalid DMA buffer physical address.\r\n")));
return(FALSE);
}
//============================ Configure DMA Channel 1 ===========================
//------ On platforms with the revsion of the Samsung SC2410 CPU with the IIS SLAVE bug fix, this -----
// code can be used to configure DMA channel 1 for input.
//----- 1. Initialize the DMA channel for input mode and use the first input DMA buffer -----
g_pDMAregs->DISRC1 = (int)(S3C2410X_BASE_REG_PA_IISBUS+0x10);
g_pDMAregs->DISRCC1 = (SOURCE_PERIPHERAL_BUS | FIXED_SOURCE_ADDRESS); // Source is periperal bus, fixed addr
//----- 2. Initialize the DMA channel to receive data over the I2S bus -----
g_pDMAregs->DIDSTC1 &= ~(DESTINATION_PERIPHERAL_BUS | FIXED_DESTINATION_ADDRESS); // Destination is system bus, increment addr
//----- 3. Configure the DMA channel's transfer characteristics: handshake, sync PCLK, interrupt, -----
// single tx, single service, I2SSDI, I2S request, no auto-reload, half-word, tx count
g_pDMAregs->DCON1 = ( HANDSHAKE_MODE | GENERATE_INTERRUPT | I2SSDI_DMA1 | DMA_TRIGGERED_BY_HARDWARE
| TRANSFER_HALF_WORD | (AUDIO_DMA_PAGE_SIZE / 2)
);
return(TRUE);
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: StartInputDMA()
Description: Starts inputting the recorded sound data from the
audio codec chip via DMA.
Notes: ***** NOT IMPLEMENTED *****
The following routine is not implemented due to a
hardware bug in the revision of the Samsung SC2410
CPU this driver was developed on. See the header
at the top of this file for details.
Returns: Boolean indicating success
-------------------------------------------------------------------*/
BOOL HardwareContext::StartInputDMA()
{
BOOL bRet=FALSE;
//------ On platforms with the revsion of the Samsung SC2410 CPU with the IIS SLAVE bug fix, this -----
// code can be used to configure DMA channel 1 for input.
DEBUGMSG(ZONE_FUNCTION,(TEXT("+++StartInputDMA\n")));
if (!m_InputDMARunning)
{
//----- 1. Initialize our buffer counters -----
m_InputDMARunning=TRUE;
Codec_channel(); // Turn On Input channel
//----- 2. Prime the output buffer with sound data -----
m_InputDMABuffer = IN_BUFFER_A;
//----- 3. Configure the DMA channel for record -----
if (!InitInputDMA())
{
DEBUGMSG(ZONE_ERROR, (TEXT("HardwareContext::StartInputDMA() - Unable to initialize input DMA channel!\r\n")));
goto Exit;
}
g_pIISregs->IISCON |= RECEIVE_DMA_REQUEST_ENABLE;
g_pIISregs->IISCON &= ~RECEIVE_IDLE_CMD;
g_pIISregs->IISFCON |= ( RECEIVE_FIFO_ACCESS_DMA | RECEIVE_FIFO_ENABLE);
g_pIISregs->IISMOD |= IIS_RECEIVE_MODE;
//----- 4. Make sure the audio isn't muted -----
AudioMute(DMA_CH_MIC, FALSE);
//----- 5. Start the input DMA -----
g_pDMAregs->DIDST1 = g_PhysDMABufferAddr.LowPart + (2 * AUDIO_DMA_PAGE_SIZE);
Codec_channel(); // Turn On Input channel
g_pDMAregs->DMASKTRIG1 = ENABLE_DMA_CHANNEL;
// wait for DMA to start.
while ((g_pDMAregs->DSTAT1&0xfffff)==0);
// change the buffer pointer
g_pDMAregs->DIDST1 = g_PhysDMABufferAddr.LowPart + (3 * AUDIO_DMA_PAGE_SIZE);
}
DEBUGMSG(ZONE_FUNCTION,(TEXT("---StartInputDMA\n")));
bRet=TRUE;
Exit:
return bRet;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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 SC2410
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 SC2410 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)
{
g_pIISregs->IISCON &= ~RECEIVE_DMA_REQUEST_ENABLE;
g_pIISregs->IISCON |= RECEIVE_IDLE_CMD;
g_pIISregs->IISFCON &= ~( RECEIVE_FIFO_ACCESS_DMA | RECEIVE_FIFO_ENABLE);
g_pIISregs->IISMOD &= ~IIS_RECEIVE_MODE;
// Disable DMA
g_pDMAregs->DMASKTRIG1 |= STOP_DMA_TRANSFER;
g_pDMAregs->DMASKTRIG1 &= ~ENABLE_DMA_CHANNEL;
// Clear input interrupt
g_pDMAregs->DCON1 = g_pDMAregs->DCON1;
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;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: InitInterruptThread()
Description: Initializes the IST for handling DMA interrupts.
Returns: Boolean indicating success
-------------------------------------------------------------------*/
BOOL HardwareContext::InitInterruptThread()
{
m_hAudioInterrupt = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!m_hAudioInterrupt)
{
ERRMSG("Unable to create interrupt event");
return(FALSE);
}
if (! InterruptInitialize(m_dwSysintrOutput, m_hAudioInterrupt, NULL, 0))
{
ERRMSG("Unable to initialize output interrupt");
return FALSE;
}
if (! InterruptInitialize(m_dwSysintrInput, m_hAudioInterrupt, NULL, 0))
{
ERRMSG("Unable to initialize input interrupt");
return FALSE;
}
m_hAudioInterruptThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL,
0,
(LPTHREAD_START_ROUTINE)CallInterruptThread,
this,
0,
NULL);
if (!m_hAudioInterruptThread)
{
ERRMSG("Unable to create interrupt thread");
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.
Returns: Boolean indicating success
-------------------------------------------------------------------*/
void HardwareContext::PowerUp()
{
// Init SPI interface;
I2S_Init();
// Init codec registers
InitCodec();
// Reload current gain settings
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -