📄 aaci_audio.c
字号:
//
// 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 + -