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

📄 wmxscaledma.c

📁 WM9713 audio codec driver for WinCE 5.0
💻 C
📖 第 1 页 / 共 4 页
字号:
 /*-----------------------------------------------------------------------------
 * Copyright (c) Wolfson Microelectronics plc.  All rights reserved.
 *
 * This software as well as any related documentation is furnished under 
 * license and may only be used or copied in accordance with the terms of the 
 * license. The information in this file is furnished for informational use 
 * only, is subject to change without notice, and should not be construed as 
 * a commitment by Wolfson Microelectronics plc. Wolfson Microelectronics plc
 * assumes no responsibility or liability for any errors or inaccuracies that
 * may appear in this document or any software that may be provided in
 * association with this document. 
 *
 * Except as permitted by such license, no part of this document may be 
 * reproduced, stored in a retrieval system, or transmitted in any form or by 
 * any means without the express written consent of Wolfson Microelectronics plc. 
 *
 * $Id: WMXScaleDMA.c 2924 2006-04-12 12:50:25Z fb $
 *
 * This file contains XScale specific DMA functionality for the drivers for
 * the Wolfson chips.
 *
 * Warning:
 *  This driver is specifically written for Wolfson Codecs. It is not a 
 *  general CODEC device driver.
 *
 * -----------------------------------------------------------------------------*/

/*
 * IMPORTANT
 *
 * The functions in this file must obey two rules:
 *
 * 1. They do not use any memory other than stack space and parameters passed in.
 * 2. They do not make system calls, unless WMSystemCallsAllowed returns TRUE.
 *
 * All functions take a context parameter, which passes in pointers to the virtual
 * addresses of memory-mapped registers, and stores what type of device is being
 * accessed.
 * 
 * Some client functions provide shared memory via the v_pWMData member of the
 * context structure.  This cannot be relied on.
 */
 
/*
 * Include files
 */ 
#include "WMCommon.h"
#include "WMDevice.h"
#include "WMGlobals.h"
#include "WMAudio.h"
#include "WMAudioInternal.h"
#include "WMPlatformDeviceContext.h"
#include "WMDMAContext.h"
#include "WMVoice.h"
#include "WMDMA.h"
#include "Test/WMTestCommon.h"
#include "WMPlatformInternalTests.h"
#include "WMPlatform_OS.h"

/*
 * Only build this if we're doing Audio Streaming support.
 */
#if WM_AUDIO_STREAM

/*
 * Private data
 */

/*
 * Structure holding the DMA channel corresponding to an API channel.
 */
typedef struct tagAPIToDMAChannelMapping
{
	const WMAUDIO_CHANNEL		APIChannel;
    const XLLP_DMAC_CHANNEL_T   DMAChannel;
} APIToDMAChannelMapping;

/*
 * And the initial values in the table.  Note that the channel numbers will
 * be overwritten if we are using dynamic channel allocation.
 */
APIToDMAChannelMapping s_DMAChannelsAvailable [] =
{
    { WMAUDIO_AC97_STEREO_OUT, WMDMA_STEREO_OUT },
    { WMAUDIO_AC97_STEREO_IN,  WMDMA_STEREO_IN }
#if WM_MONODAC
    ,
    { WMAUDIO_AC97_MONO_OUT,   WMDMA_MONO_OUT }
#endif
#if WM_I2S
     ,
    { WMAUDIO_I2S_STEREO_OUT,  WMDMA_STEREO_OUT },
    { WMAUDIO_I2S_STEREO_IN,   WMDMA_STEREO_IN }
#endif /* WM_I2S */
#if WM_VOICE
    ,
    { WMAUDIO_VOICE_OUT,       WMDMA_VOICE_OUT },
    { WMAUDIO_VOICE_IN,        WMDMA_VOICE_IN }
#endif /* WM_VOICE */
};

#ifdef DEBUG
#   ifndef WMDMA_DMA_STORE_DEBUG
#       define WMDMA_DMA_STORE_DEBUG FALSE
#   endif

#   if WMDMA_DMA_STORE_DEBUG
/*
 * For debugging DMA it can take too long to write out the DMA registers -
 * by the time you've written them out, another interrupt has come along and
 * you've missed your chance.  We solve this by capturing an array of the last
 * few sets of registers, and then you can display these periodically, or just
 * inspect the values in a debugger.
 * 
 * Note: if you enable this option it can take up a _lot_ of memory.
 */

#    define MAX_DMA_DEBUG 10

XLLP_DMAC_T DmacRegsStore[MAX_DMA_DEBUG] = {0};

static int               DmaDebugRun = 0;
#    endif /* WMDMA_DMA_STORE_DEBUG */
#endif /* DEBUG */

/*
 * Global definitions
 */

/*
 * Channel flags.
 */
#define WMCHAN_ACTIVE           0x00000001
#define WMCHAN_BUF1_FULL        0x00000010
#define WMCHAN_BUF2_FULL        0x00000020

/*
 * A macro to determine whether a DMA buffer is available.
 */
#define IS_BUFFER_AVAILABLE( _pChannelDef, _buf )                               \
    ( ((_pChannelDef)->pDetails->flags & WM_INPUT) ?                           \
      ((_pChannelDef)->flags & WMCHAN_ ## _buf ## _FULL ) :                     \
      !((_pChannelDef)->flags & WMCHAN_ ## _buf ## _FULL ) )

/*
 * Function prototypes
 */
static WMSTATUS private_PrepareDescriptors( WM_DEVICE_HANDLE hDevice,
                                            ChannelDef       *pChannelDef
                                          );
static WMSTATUS private_AllocateChannel( WM_DEVICE_HANDLE  hDevice,
										 ChannelDef        *pChannelDef,
										 WMAUDIO_CHANNEL   APIChannel
									   );
static void private_SetDMABufferLength( WM_DEVICE_HANDLE hDevice,
                                        ChannelDef       *pChannelDef,
                                        unsigned int     bufsize
                                      );
void private_CleanChannelBuffers( WM_DEVICE_HANDLE hDevice,
                                  ChannelDef *pChannelDef
                                );
void *private_GetNextBuffer( WM_DEVICE_HANDLE hDevice,
                             WMDMA_CHAN_HANDLE channel
                           );
void private_Flush_InputFIFO( WM_DEVICE_HANDLE hDevice, 
							  XLLP_VUINT32_T *pFIFO, 
							  unsigned int depth
							);

#ifdef DEBUG
static void private_OutputGivenDmacRegs( WM_DEVICE_HANDLE     hDevice, 
										 volatile XLLP_DMAC_T *pDmacRegs
									   );

static void private_DumpDmacRegs( WM_DEVICE_HANDLE    hDevice );
static void private_DumpDmacChannel( WM_DEVICE_HANDLE hDevice,
                                     ChannelDef       *pChannelDef
                                   );
static void private_CaptureDmacRegs( WM_DEVICE_HANDLE hDevice );
static void private_DumpCapturedDmacRegs( WM_DEVICE_HANDLE hDevice, int run );
static void private_DumpAllCapturedDmacRegs( WM_DEVICE_HANDLE hDevice );

#else /* DEBUG */
#define private_OutputGivenDmacRegs( _hDevice,_pDmacRegs) (0)
#define private_DumpDmacRegs( _hDevice ) (0)
#define private_DumpDmacChannel( _hDevice, _pChannelDef ) (0)

#define private_CaptureDmacRegs( _hDevice ) (0)
#define private_DumpCapturedDmacRegs( _hDevice, _run ) (0)
#define private_DumpAllCapturedDmacRegs( _hDevice ) (0)
#endif /* DEBUG */

#if WM_TESTING
static WM_BOOL private_TestIsBufferAvailable( WM_DEVICE_HANDLE hDevice );
#endif /* WM_TESTING */

#if WM_USE_DYNAMIC_DMA_CHANNEL
/*
 * XllpDmacInit is not exported by any of the xllp header files.
 */
extern XLLP_STATUS_T XllpDmacInit(void);
#endif /* WM_USE_DYNAMIC_DMA_CHANNEL */

/*-----------------------------------------------------------------------------
 * Function:    WMDMAInit
 *
 * Prepares the DMA subsystem for use.
 *
 * Parameters:
 *      hDevice     handle to the device (from WMOpenDevice)
 *
 * Returns:     WMSTATUS
 *      See WMStatus.h
 *---------------------------------------------------------------------------*/
WMSTATUS WMDMAInit( WM_DEVICE_HANDLE hDevice )
{
    WMSTATUS					status			= WMS_SUCCESS;
    WM_XSCALE_DEVICE_CONTEXT	*pDeviceContext = 
								(WM_XSCALE_DEVICE_CONTEXT*) hDevice;
    DMAContext					*pDMAContext	= pDeviceContext->pDMAContext;

    /*
     * Check to make sure that the DMA context is initialised.
     */
    WM_ASSERT( hDevice, pDMAContext->initialised );

#if WM_USE_DYNAMIC_DMA_CHANNEL
    {
        XLLP_STATUS_T xllpStatus;
        /* 
         * If we are using xllp to control the DMA,
         * call xllpDmacInit to initialise it.
         */
        xllpStatus = XllpDmacInit();
        status = XllpStatusToWMStatus( xllpStatus );
    }
#endif /* WM_USE_DYNAMIC_DMA_CHANNEL */
    return status;
}

/*-----------------------------------------------------------------------------
 * Function:    WMDMAShutdown
 *
 * Cleans up the DMA subsystem.
 *
 * Parameters:
 *      hDevice     handle to the device (from WMOpenDevice)
 *      channel     the channel to clean up.
 *
 * Returns:     void
 *---------------------------------------------------------------------------*/
void WMDMAShutdown( WM_DEVICE_HANDLE hDevice )
{
    WM_XSCALE_DEVICE_CONTEXT	*pDeviceContext =
									(WM_XSCALE_DEVICE_CONTEXT*) hDevice;
    DMAContext					*pDMAContext	= pDeviceContext->pDMAContext;

    if ( pDMAContext->initialised )
    {
        pDMAContext->initialised = FALSE;
    }
}

/*-----------------------------------------------------------------------------
 * Function:    WMDMAInitChannel
 *
 * Prepares the DMA channel for transferring data.
 *
 * Parameters:
 *      hDevice     handle to the device (from WMOpenDevice)
 *      APIchannel  the channel to prepare.
 *      bufsize     the size of the DMA buffer(s).
 *
 * Returns:     WMDMA_CHAN_HANDLE
 *      A channel handle to pass in to other functions.
 *---------------------------------------------------------------------------*/
WMDMA_CHAN_HANDLE WMDMAInitChannel( WM_DEVICE_HANDLE hDevice, 
                                    WMAUDIO_CHANNEL APIChannel,
                                    unsigned int bufsize
                                  )
{
	WMSTATUS					result;
    ChannelDef					*pChannelDef;
    WM_XSCALE_DEVICE_CONTEXT	*pDeviceContext	= 
									(WM_XSCALE_DEVICE_CONTEXT*) hDevice;
    DMAContext					*pDMAContext	= pDeviceContext->pDMAContext;

    WM_ASSERT( hDevice, pDMAContext->initialised );

    /*
     * Get the appropriate channel structure.
     */
	pChannelDef = WMDMAGetChannelDef( hDevice, APIChannel );
	if ( NULL == pChannelDef )
	{
		WM_ASSERT( hDevice, (NULL != pChannelDef) );
		goto error;
	}

    /* 
     * Look up the channel details.
     */
    pChannelDef->pDetails = WMDMAGetChannelDetails( hDevice, APIChannel );
	if ( NULL == pChannelDef->pDetails )
	{
		WM_ASSERT( hDevice, (NULL != pChannelDef->pDetails) );
		goto error;
	}

    /*
     * Prepare the DMA descriptors.
     */
    result = private_PrepareDescriptors( hDevice, pChannelDef );
	if ( WM_ERROR( result ) )
	{
		goto error;
	}
    
    /*
     * Clean out our buffers.
     */
    private_CleanChannelBuffers( hDevice, pChannelDef );
    
    /*
     * Set the DMA buffer length.
     */
    private_SetDMABufferLength( hDevice, pChannelDef, bufsize );

    /*
     * And return.
     */
    return pChannelDef;

error:
	return ( NULL );
}

/*-----------------------------------------------------------------------------
 * Function:    WMDMAShutdownChannel
 *
 * Cleans up the given DMA channel.
 *
 * Parameters:
 *      hDevice     handle to the device (from WMOpenDevice)
 *      channel     the channel to clean up.
 *
 * Returns:     void
 *---------------------------------------------------------------------------*/
void WMDMAShutdownChannel( WM_DEVICE_HANDLE hDevice,
                           WMDMA_CHAN_HANDLE channel
                         )
{
    WMDMAStopChannel( hDevice, channel );

#if WM_USE_DYNAMIC_DMA_CHANNEL
    {
        ChannelDef                  *pChannelDef = (ChannelDef *)channel;
        XLLP_DMAC_DRCMR_T           device;

        device = pChannelDef->pDetails->DMADevice;

        XllpDmacFreeChannel( pChannelDef->DMAChannel, device );
    }
#endif
}

/*-----------------------------------------------------------------------------
 * Function:    WMDMAGetChannelBuffer
 *
 * Returns a pointer to the current DMA buffer for the channel.
 *
 * Parameters:
 *      hDevice     handle to the device (from WMOpenDevice)
 *      channel     the channel to return the buffer for.
 *
 * Returns:     void *
 *      A pointer to the DMA buffer (of size as configured in WMDMAInit).
 *---------------------------------------------------------------------------*/
void *WMDMAGetChannelBuffer( WM_DEVICE_HANDLE hDevice,
                             WMDMA_CHAN_HANDLE channel
                           )
{
    ChannelDef					*pChannelDef	= (ChannelDef *)channel;
    void						*pBuffer		= NULL;
    WM_XSCALE_DEVICE_CONTEXT	*pDeviceContext = 
									(WM_XSCALE_DEVICE_CONTEXT*) hDevice;

    /*
     * If neither buffer is available, we can't give them a buffer.
     */
    if ( !IS_BUFFER_AVAILABLE( pChannelDef, BUF1 ) &&
         !IS_BUFFER_AVAILABLE( pChannelDef, BUF2 )
       )
    {
        pBuffer = NULL;
        goto end;
    }
    
    /*
     * Default to the next DMA buffer.
     */
    pBuffer = private_GetNextBuffer( hDevice, channel );

    /*
     * If not available, try the other one.  That should be available
     * because we checked above that at least one was available.
     */
    if ( pChannelDef->buffer1 == pBuffer &&
         !IS_BUFFER_AVAILABLE( pChannelDef, BUF1 )
       )
    {
        pBuffer = pChannelDef->buffer2;
    }
    else if ( pChannelDef->buffer2 == pBuffer &&
              !IS_BUFFER_AVAILABLE( pChannelDef, BUF2 )
            )
    {
        pBuffer = pChannelDef->buffer1;
    }
    
end:
    return pBuffer;
}

/*-----------------------------------------------------------------------------
 * Function:    WMDMAMarkBufferFull
 *
 * Marks the given DMA buffer as full and awaiting transfer.
 *
 * Parameters:
 *      hDevice     handle to the device (from WMOpenDevice)
 *      channel     the channel ID.
 *      pBuffer     the buffer to mark as full (from WMDMAGetChannelBuffer).
 *
 * Returns:     void 
 *---------------------------------------------------------------------------*/
void WMDMAMarkBufferFull( WM_DEVICE_HANDLE hDevice,
                          WMDMA_CHAN_HANDLE channel,
                          void *pBuffer
                        )
{
    ChannelDef					*pChannelDef	= (ChannelDef *)channel;
    WM_XSCALE_DEVICE_CONTEXT	*pDeviceContext = 
									(WM_XSCALE_DEVICE_CONTEXT*) hDevice;
    
    if ( pChannelDef->buffer1 == pBuffer )
    {
        pChannelDef->flags |= WMCHAN_BUF1_FULL;
    }
    else if ( pChannelDef->buffer2 == pBuffer )
    {
        pChannelDef->flags |= WMCHAN_BUF2_FULL;
    }
    else
    {
        WM_ASSERT( hDevice,
            pChannelDef->buffer1 == pBuffer || pChannelDef->buffer2 == pBuffer
            );
    }

    /*
     * If the channel is not active then start it.
     * The buffer must be full because this function has been called.
     */
    if( !( pChannelDef->flags & WMCHAN_ACTIVE ) )
    {
        WMDMAStartChannel( hDevice, channel );
	}
}

⌨️ 快捷键说明

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