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

📄 aaci_audio.c

📁 ARM9基于WINDOWSCE的BSP源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
// Release Status:OS005-SW-70002-r0p0-00REL0
// $Copyright: 
// ----------------------------------------------------------------
// This confidential and proprietary software may be used only as
// authorised by a licensing agreement from ARM Limited
//   (C) COPYRIGHT 2004 ARM Limited
//       ALL RIGHTS RESERVED
// The entire notice above must be reproduced on all authorised
// copies and copies may only be made to the extent permitted
// by a licensing agreement from ARM Limited.
// ----------------------------------------------------------------
// File:     aaci_audio.c,v
// Revision: 1.2
// ----------------------------------------------------------------
// $

//--------------------------------------------------------------------------------
//
//                    PL041 AACI & LM4549A - Audio functions
//
//     This is a group of hardware specific functions that define a general
//  interface to be portable to other Operating systems and to run on the
//  National Semiconductor LM4549A CODEC and ARM PL041 AACI.
//
//     These functions include interfaces to an AC'97 Codec, Hardware
//  Initialization and currently run on the Intergrator/CP platforms.
//
//     This driver is set-up to use the dedicated AACI h/w registers to send 
//  and receive configuration data on slots 1 & 2, of the CODEC frame, to and 
//  from the LM4549A CODEC.
//  The AACI FIFOs are only used for sending and receiving wave channel data 
//  on slots 3 & 4, of the CODEC frame, left and right channels respectively.
//  Please read the ARM PrimeCell AACI (PL041) Technical Reference Manual for 
//  more information.
//--------------------------------------------------------------------------------

#include <windows.h>
#include <pkfuncs.h>
#include <ceddk.h>
#include <types.h>
#include <waveddsi.h>
#include <wavedbg.h>
#include <oalfuncs.h>

#include "wavmsg.h"
#include "pdd_audio.h"
#include <dma.h>
#include "oalintr.h"
#include "wavemdd.h"

int OnInit();
int OnDeinit();
int OnPlayOpen();
int OnPlayStart();
int OnPlayStop();
int OnPlayClose();

int OnRecordOpen();
int OnRecordStart();
int OnRecordStop();
int OnRecordClose();

//---------------------------
// AACI Control
//---------------------------
VOID AACI_RegWrite32(USHORT reg, ULONG val);
ULONG AACI_RegRead32(USHORT reg);

//---------------------------
// CODEC Control
//---------------------------
VOID AACI_CodecWrite16( USHORT codec_reg, USHORT codec_data );
USHORT AACI_CodecRead16( USHORT codec_reg );

//---------------------------
// FIFO operations
//---------------------------
VOID FillFIFO_M8(PWAVEHDR pwh){};
VOID FillFIFO_M16(PWAVEHDR pwh){};
VOID FillFIFO_S8(PWAVEHDR pwh){};
VOID FillFIFO_S16(PWAVEHDR pwh){};
VOID GetFIFO_M8(PWAVEHDR pwh){};
VOID GetFIFO_M16(PWAVEHDR pwh){};
VOID GetFIFO_S8(PWAVEHDR pwh){};
VOID GetFIFO_S16(PWAVEHDR pwh){};

// Internal functions
static void DumpCurrentSettings();
static VOID CodecSend( ULONG raw_codec_reg, ULONG raw_codec_data );
static BOOL ResetDevice();
static void PowerUp();
static void PowerDown();
static BOOL ClearTransmitFIFO();
static BOOL ClearReceiveFIFO(DWORD *);

#ifdef TEST_API
// Internal test functions
static DWORD TestTransmit_FIFOSize(BOOL);
static DWORD TestTransmit_Complete(BOOL);
static DWORD TestTransmit_HalfEmpty(BOOL);
static DWORD TestReceive_Overrun(BOOL);
static DWORD TestReceive_HalfFull(BOOL);
static DWORD TestReceive_Runaway(BOOL);
#endif

// Keep this uncommented to enable transmit compact mode (recommended)
//#define TX_COMPACT_MODE
// Keep this uncommented to enable receive compact mode (recommended)
//#define RX_COMPACT_MODE

// Test and wait for flags to clear
#define _TWMAX 10
#define TESTWAIT(test,dbgmsg)                       \
    {                                               \
        int _testwait = 0;                          \
        while( (test) && _testwait < _TWMAX )       \
        {                                           \
            Sleep(1);                               \
            _testwait++;                            \
        }                                           \
        if( _testwait == _TWMAX )                   \
            ERRMSG1("AACI: Failed to wait for %s", TEXT(dbgmsg) ); \
    }
        
// FIFO Sizes for testing and use in filling/clearing the FIFOs
#define TX_FIFOSIZE_NOTCOMPACT 512
#define TX_FIFOSIZE_COMPACT    (TX_FIFOSIZE_NOTCOMPACT/2)
#define RX_FIFOSIZE_NOTCOMPACT 512
#define RX_FIFOSIZE_COMPACT    (RX_FIFOSIZE_NOTCOMPACT/2)

#ifdef TX_COMPACT_MODE
#define TX_FIFOSIZE     TX_FIFOSIZE_COMPACT
#else
#define TX_FIFOSIZE     TX_FIFOSIZE_NOTCOMPACT
#endif
#ifdef RX_COMPACT_MODE
#define RX_FIFOSIZE     RX_FIFOSIZE_COMPACT
#else
#define RX_FIFOSIZE     RX_FIFOSIZE_NOTCOMPACT
#endif

//--------------------------------------------------------------------------------
// Variables - local and globally global
//--------------------------------------------------------------------------------

// The event handler (from MDD layer)
extern HANDLE hAudioInterrupt;

#ifdef DEBUG
// To get access to the debug zones (from MDD layer)
extern DBGPARAM dpCurSettings;
#endif

// System Interrupt - used by MDD layer
ULONG gIntrAudio;

static BOOL g_fPowerOn;             // Current Power setting
static ULONG g_nVolume;             // Current master volume setting (MSFT format)
static UCHAR *g_AudioRegBase = NULL;// Pointer to memory mapped AACI regs.

#ifdef TEST_API
// When we are performing tests
static BOOL g_fTesting = FALSE;     // Specifies whether testing or not
static BOOL g_fTestIntDisable;      // AACI Interrupts disabled on AACI interrupt?
static HANDLE g_hTestInterrupt;     // Test interrupt event - set on AACI interrupt
static DWORD g_dwTestIntStatus;     // AACI status flags on interrupt
#endif

// The following arrays contains 2 entries, One for input, one for output
static BOOL g_fInUse[2];            // Channel in use?
static DWORD g_dwRunMode[2];        // Channel receiving/transmitting data?
static BOOL g_fTxEndOfData;         // Channel transmit end of data?
static PWAVEFORMATEX g_pwfx[2];     // Current channel format

#define RUNMODE_STOPPED  0
#define RUNMODE_STOPPING 1
#define RUNMODE_RUNNING  2

// This variable may be accessed by different processes (i.e. via interrupts) 
// and is likely to change in a time critical fashion. Optimization may cause 
// errors if not declared volatile.
static volatile BOOL gv_fMoreData[2];   // Any more data to transmit/receive?

// Current shortcuts to FIFO fill/get functions - dependent on wave format
static VOID (*pfnFillFIFO)(PWAVEHDR);
static VOID (*pfnGetFIFO)(PWAVEHDR);

// Volume control translation array - from MSFT format to CODEC format
const USHORT VolumeLUT[] = {
    0x20, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
    0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
    0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
    0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };

// Keep a record of all the bytes played and recorded in a 
//  wavestart-wavestop session
#ifdef AACI_STATS
static DWORD g_dwBytesRecorded[2];
#endif

//-----------------------------------------------------------------------------
//
//  UCHAR AACI_Initialize (UINT Irq, UINT SysIntr, UINT IoBase)
//
//  Initializes the AACI and LM4549 hardware.
//  It has to be called with the resources that were assigned by the OS
//
//  This function:
//
//  - Maps the Irq to a system interrupt number
//  - Maps in the AACI hardware register addresses
//  - Reset and initialize the CODEC
//
//  Resources assigned by the system:
//
//  unsigned int    Irq,
//  unsigned int    SysIntr,
//  unsigned int    IoBase
//
//--------------------------------------------------------------------------------
BOOL AACI_Initialize (UINT Irq, UINT SysIntr, UINT IoBase)
{
    BOOL bRet = FALSE;
    PHYSICAL_ADDRESS PhysicalAddress;

    // Turn on various DEBUG messages - (see public\common\oak\inc\wavedbg.h)
#ifdef DEBUG
    // All INIT messages
    dpCurSettings.ulZoneMask |= (1<<10);
    // PDD Function debug 
    //dpCurSettings.ulZoneMask |= (1<<6) | (1<<13);
    // All debug messages (even MDD layer)
    //dpCurSettings.ulZoneMask = 0xFFFF;
#endif

	FUNC_WPDD("+AACI_Initialize");

	RETAILMSG(1,(TEXT("AACI PDD 1.1\r\n")));

    PRINTMSG(ZONE_INIT, (TEXT("AACI Initialising - version %d.%d"),
            WAVEDEV_VERSION_MAJOR,WAVEDEV_VERSION_MINOR) );
    
    // Set up system interrupt for MDD layer
    gIntrAudio = SysIntr;

    // Setup global variables for input and output buffers
    gv_fMoreData[WAPI_OUT]  = FALSE;
    gv_fMoreData[WAPI_IN]   = FALSE;
    g_fInUse[WAPI_OUT]      = FALSE;
    g_fInUse[WAPI_IN]       = FALSE;
    g_dwRunMode[WAPI_OUT]   = RUNMODE_STOPPED;
    g_dwRunMode[WAPI_IN]    = RUNMODE_STOPPED;
    g_fTxEndOfData          = FALSE;
    g_pwfx[WAPI_OUT]        = NULL;
    g_pwfx[WAPI_IN]         = NULL;

    // NOTE: g_nVolume should get properly set on boot up by a WPDM_SETVOLOUME
    //  message (from the WAVAPI.DLL). We set it here to 0 to reflect the 
    //  default CODEC setting (mute)
    g_nVolume = 0;

    // Map in address space for AACI hardware registers
    PhysicalAddress.HighPart = 0;
    PhysicalAddress.LowPart = IoBase;
    g_AudioRegBase = (UCHAR *)MmMapIoSpace (PhysicalAddress, AACI_HWREGS_SIZE,
                                            FALSE);
    if( !g_AudioRegBase )
    {
        ERRMSG("PDD_AudioInitialize: Map audio registers failed");
    }
    else
    {
        // Set up the device
        if( ResetDevice() )
        {
            g_fPowerOn = TRUE;

#ifdef DEBUG
            // Show what the initialised settings are
            DumpCurrentSettings();
#endif
            // All is well, AACI is up and working
            bRet = TRUE;
        }
    }


	OnInit();
	
	AACI_RegWrite32( AACIReg_Channel1TxControl, 
		AACI_RegRead32(AACIReg_Channel1TxControl) & 
		(~AACIBit_EnableFIFO) );
	
	//Disable Tx Interrupt	
	AACI_RegWrite32( AACIReg_Channel1IntEnable, 
		AACI_RegRead32( AACIReg_Channel1IntEnable ) & 
		~(AACIBit_TxCIE | AACIBit_TxIE /*| AACIBit_TxUIE*/) );
	
	// Enable Transmit
	AACI_RegWrite32( AACIReg_Channel1TxControl, 
		AACI_RegRead32(AACIReg_Channel1TxControl) | 
		AACIBit_EnableFIFO );
/*
	//yz_add for DMA !!
    if(!(g_DMAEvent= CreateEvent( NULL, FALSE, FALSE,NULL))) {
        RETAILMSG(1, (TEXT("CreateEvent(g_DMAEvent) FAILED\r\n")));
        bRet = FALSE;
    }	

    hDMAThread  = CreateThread((LPSECURITY_ATTRIBUTES)NULL,
                                          0,
                                          (LPTHREAD_START_ROUTINE)PDD_DMAThread,
                                          NULL,
                                          0,
                                          NULL);
	DmaCmd = DMA_CMD_STOP;
    if (!hDMAThread) {    	
        RETAILMSG(1, (TEXT("hDMAThread Create FAILED\r\n")));
        bRet = FALSE;
    }	

	SetThreadPriority( hDMAThread , THREAD_PRIORITY_ABOVE_NORMAL );
*/
    FUNC_WPDD("-AACI_Initialize");

    return bRet;
}

static BOOL ResetDevice()
{
    int loop = 0;
    
    // Start by disabling the AACI
    AACI_RegWrite32( AACIReg_MainControl, 0 );

    INITMSG("AACI: Disabling Interrupts");
    AACI_RegWrite32( AACIReg_SlotIntEnable, 0 );
    AACI_RegWrite32( AACIReg_Channel1IntEnable, 0 );

    INITMSG("AACI: Clearing Interrupts");
    AACI_RegWrite32( AACIReg_IntClear, AACIBit_ClearAllInts );

    INITMSG("AACI: Cold reset");
    AACI_RegWrite32( AACIReg_Reset, 0x0 );
    Sleep(200);     // Wait while device resets
    AACI_RegWrite32( AACIReg_Reset, 0x1 );

#ifdef TX_COMPACT_MODE
    INITMSG("AACI: Setup Transmit FIFO1 (Compact mode)");
#else
    INITMSG("AACI: Setup Transmit FIFO1 (Non-compact mode)");
#endif
    if( AACI_RegRead32(AACIReg_Channel1Status) & (AACIBit_TXFIFOBusy) )
    {
        ERRMSG("AACI ERROR: Transmit FIFO1 busy!");
    }
    // Set up Transmit FIFO
    AACI_RegWrite32( AACIReg_Channel1TxControl,
        AACIBit_Slot3DataInFIFO |
        AACIBit_Slot4DataInFIFO |
#ifdef TX_COMPACT_MODE
        AACIBit_EnableCompactMode |
#endif
        AACIBit_DataSize16bits |
        AACIBit_EnableFIFOMode );

#ifdef RX_COMPACT_MODE
    INITMSG("AACI: Setup Receive FIFO1 (Compact mode)");
#else
    INITMSG("AACI: Setup Receive FIFO1 (Non-compact mode)");
#endif
    if( AACI_RegRead32(AACIReg_Channel1Status) & (AACIBit_RXFIFOBusy) )
    {
        ERRMSG("AACI ERROR: Receive FIFO1 busy!");
    }
    // Set up Receive FIFO
    AACI_RegWrite32( AACIReg_Channel1RxControl,
        AACIBit_Slot3DataInFIFO |
        AACIBit_Slot4DataInFIFO |
#ifdef RX_COMPACT_MODE
        AACIBit_EnableCompactMode |

⌨️ 快捷键说明

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