⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hwctxt.cpp

📁 freescale i.mx31 BSP CE5.0全部源码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
        else
        {
            m_InputDMAStatus &= ~DMA_DONEB;
        }
    }
    __except(EXCEPTION_EXECUTE_HANDLER) 
    {
        DEBUGMSG(ZONE_ERROR, (TEXT("WAVDEV2.DLL:TransferInputBuffer() - ")
                              TEXT("EXCEPTION: %d"), GetExceptionCode()));
    }

    return BytesTransferred;
}


//-----------------------------------------------------------------------------
//
//  Function:  TransferInputBuffers
//
//  This function determines which DMA input buffer (A and/or B) needs to be
//  transferred to the audio application-supplied data buffers.  The DMA input
//  buffer can be reused once the data has been copied out.
//
//  If there is insufficient space in the application-supplied data buffers to
//  transfer out all of the data that is currently in the DMA input buffers,
//  then all excess data is simply discarded.
//
//  Parameters:
//      dwDCSR
//          [in] Current status of the input DMA.
//      checkFirst
//          [in] Identifies which of the two available DMA input buffers
//               should be transferred first in order to maintain the
//               correct sequencing of the input audio stream.
//
//  Returns:
//      Returns number of bytes placed into the input buffers.
//
//-----------------------------------------------------------------------------
ULONG HardwareContext::TransferInputBuffers(DWORD dwDCSR, DWORD checkFirst)
{
    ULONG BytesTransferred=0;

    if (checkFirst == IN_BUFFER_A)
    {
        if (dwDCSR & DMA_DONEA)
        {
            BytesTransferred = TransferInputBuffer(IN_BUFFER_A);
        }

        if (dwDCSR & DMA_DONEB)
        {
            BytesTransferred += TransferInputBuffer(IN_BUFFER_B);
        }
    }
    else    // (checkFirst == IN_BUFFER_B)
    {
        if (dwDCSR & DMA_DONEB)
        {
            BytesTransferred = TransferInputBuffer(IN_BUFFER_B);
        }

        if (dwDCSR & DMA_DONEA)
        {
            BytesTransferred += TransferInputBuffer(IN_BUFFER_A);
        }
    }

    return BytesTransferred;
}

#endif // #ifdef AUDIO_RECORDING_ENABLED


//-----------------------------------------------------------------------------
//
//  Function:  InterruptThread
//
//  This function is the IST for handling audio input and output DMA interrupts.
//
//  Parameters:
//      None.
//
//  Returns:
//      None.
//
//-----------------------------------------------------------------------------
void HardwareContext::InterruptThread()
{
#ifdef AUDIO_RECORDING_ENABLED
    DWORD recCheckFirst = IN_BUFFER_A;
#endif
    DWORD dwRet = 0;
    UINT32 bufDescStatus[NUM_DMA_BUFFERS];

    DEBUGMSG(ZONE_FUNCTION,(_T("+HardwareContext::InterruptThread\n")));

    // Fast way to access embedded pointers in wave headers in other processes.
    SetProcPermissions((DWORD)-1);

    while (TRUE)
    {
        // Wait for the IST to be signaled by the OAL interrupt handler.
        WaitForSingleObject(m_hAudioInterrupt, INFINITE);

        // Grab the lock.
        Lock();

        __try
        {
            // Handle DMA output (i.e., audio playback) if it is active.
            if (m_OutputDMARunning)
            {
                PCSP_SSI_REG pStDACSSI = BSPAudioGetStDACSSI();
                DWORD ssi_sisr = INREG32(&pStDACSSI->SISR);
                if (ssi_sisr & CSP_BITFMASK(SSI_SISR_ROE0))
                {
                    // Don't expect to see this ever if the SSI is used only
                    // for audio playback to the PMIC Stereo DAC.
                    ERRORMSG(ZONE_ERROR, (_T("ERROR: SSI%d RX overrun ")
                                          _T("error\n"),
                                          (pStDACSSI == m_pSSI1 ? 1 : 2)));
                }

                // Get the transfer status of the DMA output buffers.
                if (!DDKSdmaGetChainStatus(m_OutputDMAChan, bufDescStatus))
                {
                    ERRORMSG(ZONE_ERROR,(_T("Could not retrieve output buffer ")
                                         _T("status\r\n")));
                }

                if (bufDescStatus[OUT_BUFFER_A] & DDK_DMA_FLAGS_ERROR)
                {
                    ERRORMSG(ZONE_ERROR,(_T("ERROR:  Error flag set in ")
                                         _T("OUT_BUFFER_A descriptor\r\n")));
                }

                if (bufDescStatus[OUT_BUFFER_B] & DDK_DMA_FLAGS_ERROR)
                {
                    ERRORMSG(ZONE_ERROR,(_T("ERROR:  Error flag set in ")
                                         _T("OUT_BUFFER_B descriptor\r\n")));
                }                        
                
                // Set DMA status bits according to retrieved transfer status.
                if (!(bufDescStatus[OUT_BUFFER_A] & DDK_DMA_FLAGS_BUSY))
                {
                    // The data in DMA buffer A has been transmitted and the
                    // buffer may now be reused.
                    m_OutputDMAStatus |= DMA_DONEA;
                    DDKSdmaClearBufDescStatus(m_OutputDMAChan, OUT_BUFFER_A);
                }

                if (!(bufDescStatus[OUT_BUFFER_B] & DDK_DMA_FLAGS_BUSY))
                {
                    // The data in DMA buffer B has been transmitted and the
                    // buffer may now be reused.
                    m_OutputDMAStatus |= DMA_DONEB;
                    DDKSdmaClearBufDescStatus(m_OutputDMAChan, OUT_BUFFER_B);
                }

                // Try to refill any empty output DMA buffers with new data
                // and then start another DMA output operation only if at
                // least one empty buffer was refilled.
                if (TransferOutputBuffers(m_OutputDMAStatus))
                {
                    // Check for SSI transmitter underrun errors. These are
                    // bad and can result in unpredictable swapping of the 
                    // left/right audio channels.
                    if (ssi_sisr & CSP_BITFMASK(SSI_SISR_TUE0))
                    {
                        ERRORMSG(ZONE_ERROR, (_T("ERROR: SSI%d TX underrun ")
                                              _T("error\n"),
                                             (pStDACSSI == m_pSSI1 ? 1 : 2)));
                    }

                    // SDMA will disable itself on buffer underrun.  
                    // Force channel to be enabled since we should now 
                    // have a buffer ready
                    DDKSdmaStartChan(m_OutputDMAChan);
                }
                else if ((m_OutputDMAStatus & DMA_DONEA) &&
                         (m_OutputDMAStatus & DMA_DONEB))
                {
                    // The upper audio driver layer has no more data, so we can
                    // terminate the current DMA operation because all DMA
                    // buffers are empty.
                    //
                    // Otherwise, wait until the currently still in-progress
                    // DMA operation has been completed (and we get another DMA
                    // event interrupt) before stopping the DMA.
                    //
                    StopOutputDMA();
                }
            }

#ifdef AUDIO_RECORDING_ENABLED
            // Handle DMA input (i.e., audio recording) if it is active.
            if (m_InputDMARunning)
            {
                PCSP_SSI_REG pVCodecSSI = BSPAudioGetVCodecSSI();
                DWORD ssi_sisr = INREG32(&pVCodecSSI->SISR);
                if (ssi_sisr & CSP_BITFMASK(SSI_SISR_TUE0))
                {
                    // Don't expect to see this ever if the SSI is used only
                    // for audio recording using the PMIC Voice CODEC.
                    ERRORMSG(ZONE_ERROR, (_T("ERROR: SSI%d TX underrun ")
                                          _T("error\n"),
                                          (pVCodecSSI == m_pSSI1 ? 1 : 2)));
                }

                // Get the transfer status of the DMA input buffers.
                if (!DDKSdmaGetChainStatus(m_InputDMAChan, bufDescStatus))
                {
                    ERRORMSG(ZONE_ERROR,(_T("Could not retrieve input buffer ")
                                         _T("status\r\n")));
                }

                if (bufDescStatus[IN_BUFFER_A] & DDK_DMA_FLAGS_ERROR)
                {
                    ERRORMSG(ZONE_ERROR,(_T("ERROR:  Error flag set in ")
                                         _T("IN_BUFFER_A\r\n")));
                }

                if (bufDescStatus[IN_BUFFER_B] & DDK_DMA_FLAGS_ERROR)
                {
                    ERRORMSG(ZONE_ERROR,(_T("ERROR:  Error flag set in ")
                                         _T("IN_BUFFER_B\r\n")));
                }                        
                
                // Set DMA status bits according to retrieved transfer status.
                if (!(bufDescStatus[IN_BUFFER_A] & DDK_DMA_FLAGS_BUSY))
                {
                    // Mark input buffer A as having new audio data.
                    m_InputDMAStatus |= DMA_DONEA;
                    DDKSdmaClearBufDescStatus(m_InputDMAChan, IN_BUFFER_A);
                }

                if (!(bufDescStatus[IN_BUFFER_B] & DDK_DMA_FLAGS_BUSY))
                {
                    // Mark input buffer B as having new audio data.
                    m_InputDMAStatus |= DMA_DONEB;
                    DDKSdmaClearBufDescStatus(m_InputDMAChan, IN_BUFFER_B);
                }

                // Try to empty out the input DMA buffers by copying the data
                // up to the application-supplied data buffers.
                //
                // Note that we require the higher-level audio application
                // to provide enough data buffers to transfer all of the new
                // data from the input DMA buffers. Otherwise, we will be
                // forced to discard the data and just continue recording.
                TransferInputBuffers(m_InputDMAStatus, recCheckFirst);

                // Update the recCheckFirst flag to mark the first input DMA
                // buffer that should be transferred in order to maintain the
                // correct ABABABAB... input DMA buffer sequencing.
                //
                // Note that except for the 2 cases that we check for below, we
                // do not need to change the current value of the recCheckFirst
                // flag. Here are some pseudocode blocks to explain why:
                //
                //     if ((recCheckFirst == IN_BUFFER_A) &&
                //         (m_InputDMAStatus & DMA_DONEA) &&
                //         (m_InputDMAStatus & DMA_DONEB))
                //     {
                //         // This means that both input DMA buffers A and
                //         // B were full and that the data was copied out
                //         // during the handling of this interrupt. So we
                //         // can just continue the input DMA operation in
                //         // the same state.
                //     }
                //     if ((recCheckFirst == IN_BUFFER_A)  &&
                //         !(m_InputDMAStatus & DMA_DONEA) &&
                //         !(m_InputDMAStatus & DMA_DONEB))
                //     {
                //         // This is an invalid or error condition that
                //         // should never happen because it indicates that
                //         // we got an input DMA interrupt but neither
                //         // input buffer was full.
                //     }
                //     if ((recCheckFirst == IN_BUFFER_A)  &&
                //         !(m_InputDMAStatus & DMA_DONEA) &&
                //         (m_InputDMAStatus & DMA_DONEB))
                //     {
                //         // This is an invalid or error condition that
                //         // should never happen because it indicates that
                //         // we've lost our expected ABABABAB... buffer
                //         // sequencing.
                //     }
                //     if ((recCheckFirst == IN_BUFFER_A) &&
                //         (m_InputDMAStatus & DMA_DONEA) &&
                //         !(m_InputDMAStatus & DMA_DONEB))
                //     {
                //         // This is the only scenario that we need to
                //         // check for (see the code below).
                //     }
                //
                // The same logic can be applied for the cases where the
                // recCheckFirst flag is equal to IN_BUFFER_B.
                if ((recCheckFirst == IN_BUFFER_A) &&
                    (m_InputDMAStatus & DMA_DONEA) &&
                    !(m_InputDMAStatus & DMA_DONEB))
                {
                    // Input DMA buffer A was full and just transferred but
                    // input DMA buffer B was not yet full so we must check
                    // it first when handling the next input DMA interrupt.
                    recCheckFirst = IN_BUFFER_B;
                }
                else if ((recCheckFirst == IN_BUFFER_B) &&
                         (m_InputDMAStatus & DMA_DONEB) &&
                         !(m_InputDMAStatus & DMA_DONEA))
                {
                    // Input DMA buffer B was full and just transferred but
                    // input DMA buffer A was not yet full so we must check
                    // it first when handling the next input DMA interrupt.
                    recCheckFirst = IN_BUFFER_A;
                }

                // Check for SSI receiver overrun errors. These are
                // bad and can result in unpredictable swapping of the 
                // left/right audio channels.
                if (ssi_sisr & CSP_BITFMASK(SSI_SISR_ROE0))
                {
                    ERRORMSG(ZONE_ERROR, (_T("ERROR: SSI%d RX overrun ")
                                          _T("error\n"),
                                          (pVCodecSSI == m_pSSI1 ? 1 : 2)));
                }

                // Force the input DMA channel to be enabled again since we
                // now have at least one input DMA buffer that's ready to be
                // used.
                DDKSdmaStartChan(m_InputDMAChan);
            }
#endif // #ifdef AUDIO_RECORDING_ENABLED
        }
        __except(EXCEPTION_EXECUTE_HANDLER) 
        {
            DEBUGMSG(ZONE_ERROR, (TEXT("WAVDEV2.DLL:InterruptThread() - ")
                                  TEXT("EXCEPTION: %d"),
                 GetExceptionCode()));
        }

        // No need to call InterruptDone since we are using SDMA interrupts
        Unlock();
    }  

    CloseHandle(m_hAudioInterrupt);
    m_hAudioInterrupt = NULL;

    DEBUGMSG(ZONE_FUNCTION,(_T("-HardwareContext::InterruptThread\n")));
}


//-----------------------------------------------------------------------------
//
//  Function:  CallInterruptThread
//
//  This function serves as a wrapper for the IST called within the hardware
//  context.
//
//  Parameters:
//      None.
//
//  Returns:
//      None.
//
//-----------------------------------------------------------------------------
void CallInterruptThread(HardwareContext *pHWContext)
{
    if (pHWContext != NULL)
    {
        pHWContext->InterruptThread();
    }
    else
    {
        DEBUGMSG(ZONE_ERROR, (TEXT("CallInterruptThread() called with ")
                              TEXT("pHWContext == NULL\n")));
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -