hwctxt.cpp
来自「i.mx27 soc for wince 6.0」· C++ 代码 · 共 1,746 行 · 第 1/4 页
CPP
1,746 行
// None.
//
// Returns:
// None
//
//-----------------------------------------------------------------------------
void HardwareContext::PowerUp()
{
BSPAudioPowerUp(TRUE);
// Restart the audio I/O operations that were suspended when PowerDown()
// was called.
if (g_saveOutputDMARunning)
{
StartOutputDMA();
}
#ifdef AUDIO_RECORDING_ENABLED
if (g_saveInputDMARunning)
{
StartInputDMA();
}
#endif
BSPAudioPowerUp(FALSE);
m_audioPowerdown = FALSE;
}
//-----------------------------------------------------------------------------
//
// Function: PowerDown
//
// This function powers down the audio codec chip. If the input/output
// channels are muted, then this function powers down the appropriate
// components of the audio codec chip in order to conserve battery power.
//
// The PowerDown() method will power down the entire audio chip while the
// PowerDown(const DWORD channel) allows for the independent powerdown of
// the input and/or output components to allow a finer degree of control.
//
// Parameters:
// None.
//
// Returns:
// None.
//
//-----------------------------------------------------------------------------
void HardwareContext::PowerDown()
{
// Note that for this special case, we do not need to grab the critical
// section via Lock() and Unlock() before calling StopOutputDMA() and
// StopInputDMA(). The powerdown thread runs at a high enough priority
// that all other threads will be blocked while it runs. Having the
// Lock() and Unlock() calls here may actually cause potential race
// condition problems during the shutdown process.
//
// Furthermore, we will not resume operation until the hardware is powered
// up again. At that point the hardware and audio driver state will be
// reinitialized again. So at this point, we can just go ahead and shut
// everything down.
// Manually set the timed delay disable events. This will explicitly
// trigger any in-progress delays to immediately terminate.
if (m_hAudioDelayDisableEvent[0] != NULL)
{
PulseEvent(m_hAudioDelayDisableEvent[0]);
}
#ifdef AUDIO_RECORDING_ENABLED
if (m_hAudioDelayDisableEvent[1] != NULL)
{
PulseEvent(m_hAudioDelayDisableEvent[1]);
}
#endif
// This tells the low-level PMIC driver to immediately terminate any
// pending timer delays.
BSPAudioPowerDown(FALSE);
// Set this flag to allow special handling for the powerdown procedure.
// The most important thing we want to avoid when powering down is using
// any sort of timer or other type of delay mechanism. We need to bypass
// anything like that and simply shutdown the hardware components when
// performing a powerdown operation.
m_audioPowerdown = TRUE;
// Save state for correct powerup handling.
g_saveOutputDMARunning = m_OutputDMARunning;
#ifdef AUDIO_RECORDING_ENABLED
g_saveInputDMARunning = m_InputDMARunning;
#endif
// Request all active audio-related DMA channels to stop.
StopOutputDMA();
#ifdef AUDIO_RECORDING_ENABLED
StopInputDMA();
#endif
// Request audio devices to power down.
BSPAudioPowerDown(TRUE);
}
//-----------------------------------------------------------------------------
//----------------------------- Helper Functions ------------------------------
//-----------------------------------------------------------------------------
//############################################ Helper Functions #############################################
//------------------------------------------------------------------------------
//
// FUNCTION: TransferOutputBuffer
//
// DESCRIPTION: Actual function to transfer playback data from
// the indicated buffer to DMA.
// Called by TransferOutputBuffers
//
// PARAMETERS:
// bufIndex - index of playback buffer to empty
//
// RETURNS:
// Number of bytes transferred from buffer
//
//------------------------------------------------------------------------------
UINT32 HardwareContext::TransferOutputBuffer(UINT8 bufIndex)
{
ULONG BytesTransferred = 0;
UINT8 *pBufferStart = (UINT8 *)m_Output_pbDMA_PAGES[bufIndex];
UINT8 *pBufferEnd = pBufferStart + AUDIO_DMA_PAGE_SIZE;
UINT8 *pBufferLast;
__try
{
pBufferLast = m_OutputDeviceContext.TransferBuffer(pBufferStart, pBufferEnd, NULL);
BytesTransferred = m_OutBytes[bufIndex] = pBufferLast-pBufferStart;
// Enable if you need to clear the rest of the DMA buffer
StreamContext::ClearBuffer(pBufferLast,pBufferEnd);
//if(BytesTransferred == 0)
// DmacSetRepeatType(m_DmaTxChannel, DMAC_REPEAT_DISABLED);
//else
if (BytesTransferred > 0)
DDKDmacSetSrcAddress(m_OutputDMAChan, m_DmaTxBuffer[bufIndex]);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
DEBUGMSG(ZONE_ERROR, (TEXT("WAVDEV2.DLL:TransferOutputBuffer() - EXCEPTION: %d"), GetExceptionCode()));
}
return BytesTransferred;
}
//------------------------------------------------------------------------------
//
// FUNCTION: TransferOutputBuffers
//
// DESCRIPTION: Calls TransferOutputBuffer to transfer data from
// playback buffer to DMA. Also toggles the current
// buffer index to acheive double buffering. Stops
// output dma if nothing is transferred for 2
// buffers consecutively.
//
// PARAMETERS:
// None
//
// RETURNS:
// Number of bytes transferred from buffer
//
//------------------------------------------------------------------------------
UINT32 HardwareContext::TransferOutputBuffers(void)
{
UINT32 BytesTransferred = 0;
// UINT32 DmaTransferred = 0;
DEBUGMSG(ZONE_FUNCTION, (TEXT("+TransferOutputBuffers\r\n")));
//DmaTransferred = DmacGetTransSize(m_DmaRxChannel);
//RETAILMSG(1, (TEXT("DmaTransferred(%d).\r\n"), DmaTransferred));
BytesTransferred += TransferOutputBuffer(m_TxBufIndex);
m_TxBufIndex = (m_TxBufIndex == 0)? 1 : 0;
//for( DmaTransferred = 0; DmaTransferred < 1000000000; DmaTransferred++ );
//RETAILMSG(1, (TEXT("HardwareContext::TransferOutputBuffers(%d).\r\n"), BytesTransferred));
// 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
if((m_OutBytes[0] + m_OutBytes[1] == 0) && (BytesTransferred == 0x00))
{
UINT32 status = DDKDmacGetTransStatus(m_OutputDMAChan);
if ((status == DMAC_TRANSFER_STATUS_COMPLETE) || (status == DMAC_TRANSFER_STATUS_NONE))
//if (status == DMAC_TRANSFER_STATUS_COMPLETE)
{
if(m_OutputDMARunning)
{
BSPAudioStopOutput(AUDIO_BUS_STEREO_OUT, AUDIO_PATH_HEADSET);
DDKDmacStopChan(m_OutputDMAChan);
m_OutputDMARunning = FALSE;
}
}
}
DEBUGMSG(ZONE_FUNCTION, (TEXT("-TransferOutputBuffers: BytesTransferred=%d\r\n"), BytesTransferred));
return BytesTransferred;
}
#ifdef AUDIO_RECORDING_ENABLED
//------------------------------------------------------------------------------
//
// FUNCTION: TransferInputBuffer
//
// DESCRIPTION: Actual function to transfer received data from
// DMA to the indicated receive buffer.
// Called by TransferInputBuffers
//
// PARAMETERS:
// bufIndex - index of receive buffer to fill
//
// RETURNS:
// Number of bytes transferred to buffer
//
//------------------------------------------------------------------------------
UINT32 HardwareContext::TransferInputBuffer(UINT8 bufIndex)
{
ULONG BytesTransferred = 0;
UINT8 *pBufferStart = (UINT8 *)m_Input_pbDMA_PAGES[bufIndex];
UINT8 *pBufferEnd = pBufferStart + AUDIO_DMA_PAGE_SIZE;
UINT8 *pBufferLast;
__try
{
pBufferLast = m_InputDeviceContext.TransferBuffer(pBufferStart, pBufferEnd, NULL);
BytesTransferred = m_InBytes[bufIndex] = pBufferLast-pBufferStart;
//DmacSetRepeatType(m_DmaRxChannel, DMAC_REPEAT_ONCE);
DDKDmacSetDestAddress(m_InputDMAChan, m_DmaRxBuffer[bufIndex]);
//DmacStartChan(m_DmaRxChannel);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
DEBUGMSG(ZONE_ERROR, (TEXT("WAVDEV2.DLL:TransferInputBuffer() - EXCEPTION: %d"), GetExceptionCode()));
}
return BytesTransferred;
}
//------------------------------------------------------------------------------
//
// FUNCTION: TransferInputBuffers
//
// DESCRIPTION: Calls TransferInputBuffer to transfer data from
// DMA to receive buffer. Also toggles the current
// buffer index to acheive double buffering. Stops
// input dma if nothing is transferred.
//
// PARAMETERS:
// None
//
// RETURNS:
// Number of bytes transferred to buffer
//
//------------------------------------------------------------------------------
UINT32 HardwareContext::TransferInputBuffers(void)
{
UINT32 BytesTransferred = 0;
// UINT32 DmaTransferred = 0;
DEBUGMSG(ZONE_FUNCTION, (TEXT("+TransferInputBuffers\r\n")));
// DmaTransferred = DmacGetTransSize(m_DmaRxChannel);
// RETAILMSG(1, (TEXT("DmaTransferred(%d).\r\n"), DmaTransferred));
BytesTransferred = TransferInputBuffer(m_RxBufIndex);
m_RxBufIndex = (m_RxBufIndex == 0)? 1 : 0;
// RETAILMSG(1, (TEXT("HardwareContext::TransferInputBuffers(%d).\r\n"), BytesTransferred));
// If it was our interrupt, but we weren't able to transfer any bytes
// (e.g. no empty buffers ready to be filled)
// Then stop the input DMA
if(BytesTransferred == 0)
{
if (DDKDmacGetTransStatus(m_OutputDMAChan) & DMAC_TRANSFER_STATUS_COMPLETE)
if(m_InputDMARunning)
{
BSPAudioStopInput(AUDIO_BUS_VOICE_IN, AUDIO_PATH_MIC);
DDKDmacStopChan(m_InputDMAChan);
m_InputDMARunning = FALSE;
}
}
DEBUGMSG(ZONE_FUNCTION, (TEXT("-TransferInputBuffers: BytesTransferred=%d\r\n"), BytesTransferred));
return BytesTransferred;
}
#endif
//------------------------------------------------------------------------------
//
// FUNCTION: InterruptThread
//
// DESCRIPTION: Interrupt service routine for playback and recording
// DMA interrupts
//
// PARAMETERS:
// None
//
// RETURNS:
// None
//
//------------------------------------------------------------------------------
void HardwareContext::InterruptThread()
{
#ifdef AUDIO_RECORDING_ENABLED
UINT32 InputTransferred;
#endif
UINT32 OutputTransferred;
UINT32 intrMask;
DEBUGMSG(ZONE_FUNCTION, (TEXT("+InterruptThread\r\n")));
// Fast way to access embedded pointers in wave headers in other processes.
SetProcPermissions((ULONG)-1);
while(m_Initialized)
{
DEBUGMSG(ZONE_INTERRUPT, (TEXT("+WaitForSingleObject\r\n")));
WaitForSingleObject(m_hAudioInterrupt, INFINITE);
DEBUGMSG(ZONE_INTERRUPT, (TEXT("-WaitForSingleObject\r\n")));
//----- 1. Grab the lock -----
Lock();
__try
{
//----- 2. Determine the interrupt source (input DMA operation or output DMA operation?) -----
//----- NOTE: Often, platforms use two separate DMA channels for input/output operations but
// have the OAL return SYSINTR_AUDIO as the interrupt source. If this is the case,
// then the interrupt source (input or output DMA channel) must be determined in
// this step.
intrMask = DDKDmacGetTransStatus(m_OutputDMAChan);
if(intrMask != DMAC_TRANSFER_STATUS_NONE)
{
//----- 3. Acknowledge the DMA interrupt -----
DDKDmacClearChannelIntr(m_OutputDMAChan);
InterruptDone(m_dwSysintrOutput);
if ( (intrMask == DMAC_TRANSFER_STATUS_COMPLETE) &&
(m_OutputDMARunning == TRUE) )
{
OutputTransferred = TransferOutputBuffers();
}
}
#ifdef AUDIO_RECORDING_ENABLED
intrMask = DDKDmacGetTransStatus(m_InputDMAChan);
if(intrMask != DMAC_TRANSFER_STATUS_NONE)
{
//----- 3. Acknowledge the DMA interrupt -----
DDKDmacClearChannelIntr(m_InputDMAChan);
InterruptDone(m_dwSysintrInput);
if((intrMask == DMAC_TRANSFER_STATUS_COMPLETE) && (m_InputDMARunning == TRUE))
{
InputTransferred = TransferInputBuffers();
}
}
#endif
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
DEBUGMSG(ZONE_ERROR, (TEXT("WAVDEV2.DLL:InterruptThread() - EXCEPTION: %d"), GetExceptionCode()));
}
//----- 10. Give up the lock -----
Unlock();
} // while(TRUE)
DEBUGMSG(ZONE_FUNCTION, (TEXT("-InterruptThread\r\n")));
}
//-----------------------------------------------------------------------------
//
// Function: CallInterruptThread
//
// This function serves as a wrapper for the IST called within the hardware
// context.
//
// Parameters:
// None.
//
// Returns:
// None.
//
//-----------------------------------------------------------------------------
DWORD CALLBACK CallInterruptThread(HardwareContext *pHWContext)
{
if (pHWContext != NULL)
{
pHWContext->InterruptThread();
}
else
{
DEBUGMSG(ZONE_ERROR, (TEXT("CallInterruptThread() called with ")
TEXT("pHWContext == NULL\n")));
}
return 1;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?