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

📄 wmcontrollink.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: WMControlLink.c 2656 2006-01-27 08:03:53Z fb $
 *
 * This file encapsulates the control operations required by drivers for Wolfson 
 * chips.
 *
 * Warning:
 *  This driver is specifically written for Wolfson Codecs. It is not a 
 *  general CODEC device driver.
 *
 * -----------------------------------------------------------------------------*/
 
/*
 * Include files
 */
#include "WMCommon.h"
#include "WMDevice.h"
#include "WMGlobals.h"
#include "WMControlLink.h"

#if WM_TESTING
#   include "Test/WMTestCommon.h"
#   include "Test/WMLinkTests.h"
#   include "Test/WMGPIOTests.h"
#endif

/*
 * Global definitions
 */

/*
 * Convert between registers and array indices.
 */
#define REG_TO_INDEX( _reg )        ( (_reg) >> 1 )
#define INDEX_TO_REG( _index )      ( (_index) << 1 )

/*
 * Shorthand for whether to do register operation tracing.
 */
#if WM_DEBUG_TRACE_REGISTERS
#   define WM_REG_TRACE             WM_TRACE
#else
#   define WM_REG_TRACE( _hDevice, _args )      (0)
#endif /* WM_DEBUG_TRACE_REGISTERS */

/*
 * There are two sets of code for handling volume registers with BOTH bits
 * (which update both registers with a single write).
 * 
 *  - Generic code which checks through all signals on the device to find
 *    other signals which match, and updates those.
 *  - Quick and dirty code which hard-codes for the WM8731 family, but
 *    has a simple switch statement.
 * 
 * If WM_BOTH_QUICK_AND_DIRTY is set to TRUE (the default), the quicker but
 * WM8731-family-specific code is built.  If set to FALSE, the generic code
 * is built.
 */
#define WM_BOTH_QUICK_AND_DIRTY     TRUE

/*
 * Private data
 */


/*
 * Function prototypes
 */
WMSTATUS WMPlatformLinkInit( WM_DEVICE_HANDLE hDevice, 
                                       WM_DRIVER_ID driverId 
                                     );
void WMPlatformLinkShutdown( WM_DEVICE_HANDLE hDevice,
                                       WM_DRIVER_ID driverId
                                     );
WMSTATUS WMPlatformRead( WM_DEVICE_HANDLE hDevice,
                                   WM_REGTYPE reg, 
                                   WM_REGVAL *pValue
                                 );
WMSTATUS WMPlatformWrite( WM_DEVICE_HANDLE hDevice,
                                    WM_REGTYPE reg,
                                    WM_REGVAL value
                                  );
WMSTATUS WMPlatformInitDeviceId( WM_DEVICE_HANDLE hDevice );
WMSTATUS WMPlatformReset( WM_DEVICE_HANDLE hDevice );
WMSTATUS WMPlatformWake( WM_DEVICE_HANDLE hDevice );

static WM_BOOL private_IsValidRegister( WM_DEVICE_HANDLE hDevice,
                                        WM_REGTYPE       reg
                                      );
static void private_ResetState( WM_DEVICE_HANDLE hDevice );

#if WM_USE_SHADOW_REGISTERS
static WMSTATUS private_InitShadowRegisters( WM_DEVICE_HANDLE hDevice );

static WMSTATUS private_WriteShadowRegister( WM_DEVICE_HANDLE   hDevice,
                                             WM_REGTYPE         reg,
                                             WM_REGVAL          value
                                           );

static WMSTATUS private_ReadShadowRegister( WM_DEVICE_HANDLE    hDevice,
                                            WM_REGTYPE          reg,
                                            WM_REGVAL           *pValue
                                          );
static WMSTATUS private_ReadDefaultShadowRegister( WM_DEVICE_HANDLE    hDevice,
                                                   WM_REGTYPE          reg,
                                                   WM_REGVAL           *pValue
                                                 );
#endif /* WM_USE_SHADOW_REGISTERS */
/*-----------------------------------------------------------------------------
 * Function:    WMLinkInit
 *
 * Initialises the use of the control link by a given driver.
 *
 * Parameters:
 *      hDevice             handle to the device (from WMOpenDevice)
 *      driverId            The driver ID (e.g. WM_DRIVER_AUDIO)
 *
 * Returns:     WMSTATUS
 *      See WMStatus.h.
 *---------------------------------------------------------------------------*/
WMSTATUS WMLinkInit( WM_DEVICE_HANDLE hDevice, WM_DRIVER_ID driverId )
{
    WM_DEVICE_CONTEXT   *pDeviceContext = WMHANDLE_TO_DEVICE( hDevice );
    WMSTATUS            status;
    WM_CHIPTYPE         chipType;
    WM_CHIPREV          chipRev;

    unsigned int driver = DRIVER_TO_INDEX( driverId );
    WM_ASSERT( hDevice, driver < WM_MAX_DRIVERS );

    /*
     * Check to make sure this is a valid driverId
     */
    if ( driver > WM_MAX_DRIVERS )
    {
        status = WMS_INVALID_PARAMETER;
        goto error0;
    }

    /*
     * Lock our global data.
     */
    if ( !WMLockGlobalData( hDevice ) )
    {
        status = WMS_LOCK_TIMED_OUT;
        goto error0;
    }
    
    /*
     * Let the platform layer do its stuff.
     */
    if ( !(pDeviceContext->flags & DEVICE_INITIALISED ) )
    {
#if WM_CACHE_POWER_STATE
        /*
         * If it's I2S we've automatically got a link, and we need it
         * for our initialisation.
         */
        if ( pDeviceContext->v_pWMData &&
             WM_IS_I2S_DEVICE_ID( pDeviceContext->deviceID )
           )
        {
            pDeviceContext->v_pWMData->WmPower |= WM_POWER_LINK;
        }
#endif

        WM_TRACE( hDevice, ( "=======================================================" ) );
        WM_TRACE( hDevice,
                  ( "===  Wolfson Device Control Library version %s  ===",
                    WM_VERSION_STRING
                  )
                );
        WM_TRACE( hDevice, ( "=======================================================" ) );
        
#if WM_USE_SHADOW_REGISTERS
        /* 
         * Note: Read-Only devices have to initialise the shadow registers
         *       _before_ initialising the link.
         */
        if ( pDeviceContext->v_pWMData &&
             !WM_DEVICE_HAS_READBACK( pDeviceContext->deviceID )
           )
        {
            /*
             * If this is the first driver to be then we need to
             * initialise our shadow registers.  Assume it's at its default
             * values, and hope no-one else is writing to it
             * directly before we get a chance.
             */
            if ( 0 == pDeviceContext->v_pWMData->activeDrivers )
            {
                /*
                 * Set our shadow registers to their default values.
                 */
                status = private_InitShadowRegisters( hDevice );
                if ( WM_ERROR( status ) )
                {
                    goto error0;
                }
            }
        }
#endif

        status = WMPlatformLinkInit( hDevice, driverId );
        if ( WM_ERROR( status ) && 
             ! ( WM_IS_GENERIC_FAMILY( hDevice ) && WMS_UNSUPPORTED == status ) )
        {
            goto error1;
        }
    }
    
    /*
     * The link should now be running.
     */
#if WM_CACHE_POWER_STATE
    if ( pDeviceContext->v_pWMData )
    {
        pDeviceContext->v_pWMData->WmPower |= WM_POWER_LINK;
    }
#endif

    /*
     * Check what we are.
     */
    status = WMGetDeviceType( hDevice, &chipType, &chipRev );
    if ( WM_ERROR( status ) )
    {
        goto error2;
    }

    /*
     * And tell the user.
     */
    WM_TRACE( hDevice, ( "Using Wolfson device %s rev %c",
              WM_CHIP_STRING( chipType ),
              ( WM_REV_UNKNOWN == chipRev ) ? '?' : chipRev
            ));
    
    /*
     * Now do initialisation which relies on the shared memory area.
     */
    if ( pDeviceContext->v_pWMData )
    {
#if WM_USE_SHADOW_REGISTERS
        /* 
         * Note: Read-Write devices have to initialise the shadow registers 
         *       _after_ initialising the link and getting the Device Type.
         */
        if ( WM_DEVICE_HAS_READBACK( pDeviceContext->deviceID ) )
        {
            /*
             * If this is the first driver to be then we need to
             * initialise our shadow registers.  Assume it's at its default
             * values, and hope no-one else is writing to it
             * directly before we get a chance.
             */
            if ( 0 == pDeviceContext->v_pWMData->activeDrivers )
            {
                /*
                 * Set our shadow registers to their default values.
                 */
                status = private_InitShadowRegisters( hDevice );
                if ( WM_ERROR( status ) )
                {
                    goto error0;
                }
            }
        }
#endif
        /*
         * If this is the first driver to be then we need to
         * initialise our state.  Assume it's at its default
         * values, and hope no-one else is writing to it
         * directly before we get a chance.
         */
        if ( 0 == pDeviceContext->v_pWMData->activeDrivers )
        {
            private_ResetState( hDevice );
            
#if WM_CACHE_POWER_STATE
            /* Note: the link should be running now. */
            pDeviceContext->v_pWMData->WmPower |= WM_POWER_LINK;
#endif /* WM_CACHE_POWER_STATE */
        }

        /*
         * We've got another driver.
         */
        if ( !(pDeviceContext->v_pWMData->activeDrivers & WM_DRIVER_MASK( driver ) ) )
        {
            pDeviceContext->v_pWMData->activeDrivers |= WM_DRIVER_MASK( driver );

#if WM_CACHE_POWER_STATE
            pDeviceContext->v_pWMData->powerRequirements[driver] = 0;
#endif
        }
    }
    
    /*
     * We've got another driver.
     */
    pDeviceContext->activeDrivers |= WM_DRIVER_MASK( driver );

    /* Let other threads in again */
    WMUnlockGlobalData( hDevice );

    /*
     * Do some sanity tests if we've been asked to.
     */
#if WM_TESTING
#   if WM_AUTOTEST_BASIC
    WMTEST_RUN( WMTestLink( hDevice ) );
#   endif
#   if WM_GPIO_CONTROL
#       if WM_AUTOTEST_GPIO_CONTROL_BASIC
            WMTEST_RUN( WMTestGPIOBasic( hDevice ) );
#       endif
#       if WM_AUTOTEST_GPIO_CONTROL_ADVANCED
            WMTEST_RUN( WMTestGPIOAdvanced( hDevice ) );
#       endif
#   endif /* WM_GPIO_CONTROL */
#endif  /* WM_TESTING */

    /*
     * We're done.
     */
    return status;

    /*
     * Error cleanup.
     */
error2:
    WMLinkShutdown( hDevice, driverId );

error1:
    WMUnlockGlobalData( hDevice );
    
error0:
    return status;
}

/*-----------------------------------------------------------------------------
 * Function:    WMLinkShutdown
 *
 * Marks the end of use of the control link by this driver.
 *
 * Parameters:
 *      hDevice             handle to the device (from WMOpenDevice)
 *      driverId            The driver ID (e.g. WM_DRIVER_AUDIO)
 *
 * Returns:     void
 *---------------------------------------------------------------------------*/
void WMLinkShutdown( WM_DEVICE_HANDLE hDevice, WM_DRIVER_ID driverId )
{
    WM_DEVICE_CONTEXT   *pDeviceContext = WMHANDLE_TO_DEVICE( hDevice );
    unsigned int        driver = DRIVER_TO_INDEX( driverId );
    
    WM_ASSERT( hDevice, driver < WM_MAX_DRIVERS );
    
    /*
     * Lock our global data.
     */
    if ( !WMLockGlobalData( hDevice ) )
    {
        goto done;
    }
    
    /*
     * There's one fewer driver.
     */
    if ( pDeviceContext->v_pWMData )
    {
        if ( pDeviceContext->v_pWMData->activeDrivers & WM_DRIVER_MASK( driver ) )
        {
            pDeviceContext->v_pWMData->activeDrivers &= ~WM_DRIVER_MASK( driver );

            /*
             * Global cleanup if this is the last driver to leave.
             */
            if ( 0 == pDeviceContext->v_pWMData->activeDrivers )
            {
               WMPlatformLinkShutdown( hDevice, driverId );
            }
        }
    }
    pDeviceContext->activeDrivers &= ~WM_DRIVER_MASK( driver );

    /* Let other threads in again */
    WMUnlockGlobalData( hDevice );

done:
    return;
}

/*-----------------------------------------------------------------------------
 * Function:    WMRead
 *
 * Reads the value from the given register.
 *
 * Parameters:
 *      hDevice             handle to the device (from WMOpenDevice)
 *      reg                 register to read from
 *      pValue              variable to receive value
 *
 * Returns:     WMSTATUS
 *      See WMStatus.h.
 *---------------------------------------------------------------------------*/
WMSTATUS WMRead( WM_DEVICE_HANDLE hDevice,
                 WM_REGTYPE reg, 
                 WM_REGVAL *pValue
               )
{
    WMSTATUS            status = WMS_SUCCESS;
    WMSTATUS            platformStatus;
    WM_REGVAL           value = 0;

⌨️ 快捷键说明

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