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

📄 ac97codec.cpp

📁 EP931X系列的WinCE声卡驱动源代码
💻 CPP
字号:
//**********************************************************************
//                                                                      
// Filename: ac97audio.cpp 
//                                                                      
// Description: interface for the AC97 codec.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Use of this source code is subject to the terms of the Cirrus 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.
//
// Copyright(c) Cirrus Logic Corporation 2002, All Rights Reserved                       
//                                                                      
//**********************************************************************
#include "wavecommon.h"
#include "ac97regs.h"
#include <hwdefs.h>


//
// Set the codec read timeout to 1ms
//
#define TIMEOUT_AC97_READ           1000
#define TIMEOUT_AC97_RESET          20000



//****************************************************************************
// AC97Codec::AC97Codec
//****************************************************************************
// 
// 
//
AC97Codec::AC97Codec(void)
{
}

//****************************************************************************
// AC97Codec::~AC97Codec
//****************************************************************************
// 
// 
//
AC97Codec::~AC97Codec(void)
{
}

//****************************************************************************
// AC97Codec::Initialize
//****************************************************************************
// 
// 
//
MMRESULT AC97Codec::Initialize(void )
{
    ULONG   ulRawIntStatus, ulSR;
    BOOL    b;
    LARGE_INTEGER liStart, liCurrent;

    //
    // Write the following registers.
    //
    HalWriteCommonReg
    (
        CSC_DEVCFG, 
        DEVCFG_I2SONSSP | DEVCFG_I2SONAC97 | DEVCFG_A1ONG | DEVCFG_A2ONG,
        0 
    );

    
    //
    // Initialize the AC97 controller to use channel 1.
    //
    m_puAC97Ch = AC97I_CH1_BASE;
           
    //
    // Enable the AC97 controller internal loopback.  Override codec ready.
    //
    *AC97I_GCR = GCR_AC97IFE;

    //
    // Set the TIMEDRESET bit.  Will cause a > 1uSec reset of the ac-link.
    // This bit is self resetting.
    //
    *AC97I_RESET = RESET_TIMEDRESET;
    Sleep(1);    

    //
    // Wait for the codec ready signal from the AC97 codec.
    //
    b = QueryPerformanceCounter(&liStart);
    ASSERT(b);
    for(;;)
    {
        b = QueryPerformanceCounter(&liCurrent);

        //
        // Check to see if the codec is ready.
        //
        ulRawIntStatus = *AC97I_RGIS;
        if(ulRawIntStatus & GCR_OCODECREADY)
            break;

        //
        // See if we hit the timeout.
        //
        if(liStart.QuadPart + TIMEOUT_AC97_RESET <liCurrent.QuadPart)
        {
            ERRMSG((L"AAC: Codec interface Failed to Reset \r\n"));
            return MMSYSERR_NOTENABLED;
        }
    }

    //
    // Set up the rx and tx channels
    //
    m_puAC97Ch[AC97I_RXCR>>2] = (m_ulRXCR = RXCR_CM | RXCR_RSIZE_16 | RXCR_SLOT3 | RXCR_SLOT4) | RXCR_REN;
    m_puAC97Ch[AC97I_TXCR>>2] = (m_ulTXCR = TXCR_CM | TXCR_RSIZE_16 | TXCR_SLOT3 | TXCR_SLOT4) | TXCR_TEN;    
    

    
    //
    // Wait until Rx fifo is no longer empty, which means that
    // the codec is pumping ADC data across the AC-link.
    //
    b = QueryPerformanceCounter(&liStart);
    ASSERT(b);
    for(;;)
    {
        Sleep(2);

        b = QueryPerformanceCounter(&liCurrent);

        // 
        // Check to see if there is any data in the receive fifo.
        //
        ulSR = m_puAC97Ch[AC97I_SR>>2];
        if(!(ulSR & SR_RXFE))
            break;

        if(liStart.QuadPart + TIMEOUT_AC97_RESET <liCurrent.QuadPart)
        {
            ERRMSG((L"AC97: Receive Interface Failed to Initialize.\r\n"));
            return MMSYSERR_NOTENABLED;
        }
    }

    //
    // Disable rx and txchannel
    //
    m_puAC97Ch[AC97I_RXCR>>2] = m_ulRXCR;
    m_puAC97Ch[AC97I_TXCR>>2] = m_ulTXCR;

    PokeAC97(AC97_MASTER_VOLUME, 0x0);
    PokeAC97(AC97_PCMOUT_VOLUME, 0x0);

    //
    // Set up the codec so that variable sample rates are enabled.
    //
    PokeAC97(AC97_EXT_AUDIO_POWER, EXT_AUDIO_POWER_VRA);

    // PokeAC97(AC97_RECORD_SELECT, RECORD_SELECT_LINEIN);
    // PokeAC97(AC97_RECORD_GAIN, 0x0);
    
    //SetPlaybackSampleRate(44100,0);
    //SetRecordSampleRate(44100,0);
    //CaptureNPlay();

    return MMSYSERR_NOERROR;
}

//****************************************************************************
// AC97Codec::SetVolume
//****************************************************************************
// 
// 
//
MMRESULT AC97Codec::SetVolume
(
    ULONG ulRightVolume, 
    ULONG ulLeftVolume, 
    ULONG ulChannel
)
{
    ULONG   ulRight, ulLeft;
    //
    // Convert the volume to AC97 volume values.
    //
    // Input     Codec Value      db Value
    // 0xFFFF       0             12.5db 
    // 0            0x1F          -34.5db
    // 1.5 db steps
    //
    ulRight = 0x1F - (ulRightVolume>>27);
    ulLeft  = 0x1F - (ulLeftVolume>>27);

    //
    // Writ to the AC97 codec register.
    //        
    PokeAC97(AC97_PCMOUT_VOLUME, (ulRight << 8) | ulLeft);

    return MMSYSERR_NOERROR;
}

//****************************************************************************
// AC97Codec::SetRecordSampleRate
//****************************************************************************
// 
// 
//
MMRESULT AC97Codec::SetRecordSampleRate(ULONG ulFrequency, ULONG ulChannel)
{
    return PokeAC97(AC97_PCM_LR_ADC_RATE, ulFrequency);
}

//****************************************************************************
// AC97Codec::SetPlaybackSampleRate
//****************************************************************************
// 
// 
//
MMRESULT AC97Codec::SetPlaybackSampleRate(ULONG ulFrequency, ULONG ulChannel)
{
    return PokeAC97(AC97_PCM_FRONT_DAC_RATE, ulFrequency);
}


//****************************************************************************
// AC97Codec::StartPlayback
//****************************************************************************
// 
// 
//
MMRESULT AC97Codec::StartPlayback(ULONG ulChannel)
{
    m_puAC97Ch[AC97I_TXCR>>2] = m_ulTXCR | TXCR_TEN;
    return MMSYSERR_NOERROR;
}

//****************************************************************************
// AC97Codec::StopPlayback
//****************************************************************************
// 
// 
//
MMRESULT AC97Codec::StopPlayback(ULONG ulChannel)
{
    m_puAC97Ch[AC97I_TXCR>>2] = m_ulTXCR ;
    return MMSYSERR_NOERROR;
}

//****************************************************************************
// AC97Codec::StartRecord
//****************************************************************************
// 
// 
//
MMRESULT AC97Codec::StartRecord(ULONG ulChannel)
{
    m_puAC97Ch[AC97I_RXCR>>2] = m_ulRXCR  | RXCR_REN;
    return MMSYSERR_NOERROR;
}

//****************************************************************************
// AC97Codec::StopRecord
//****************************************************************************
// 
// 
//
MMRESULT AC97Codec::StopRecord(ULONG ulChannel)
{
    m_puAC97Ch[AC97I_RXCR>>2] = m_ulRXCR;
    return MMSYSERR_NOERROR;
}


//****************************************************************************
// AC97Codec::GetDmaPort
//****************************************************************************
// 
// 
//
ULONG  AC97Codec::GetDmaPort(void)
{
    return PRALLOC_AAC1;
}


//****************************************************************************
// PeekAC97
//****************************************************************************
// Read an AC97 codec Register.  
//
// ulCodecReg - AC97 Codec Register
// pulValue   - Codec Register value.
//
// Return MMSYSERROR_NOERROR
//        MMSYSERROR_ERROR
//
MMRESULT AC97Codec::PeekAC97(UINT ulCodecReg, PULONG pulValue)
{
    ULONG ulRGIS;
    LARGE_INTEGER liStart, liCurrent;
    BOOL    b;

    //
    // How it is supposed to work is:
    //  - The ac97 controller sends out a read addr in slot 1.
    //  - In the next frame, the codec will echo that address back in slot 1
    //    and send the data in slot 2.  SLOT2RXVALID will be set to 1.
    //
    // Read until SLOT2RXVALID goes to 1.  Reading the data in AACS2DATA
    // clears SLOT2RXVALID.
    //
    b = QueryPerformanceCounter(&liStart);
    for(;;)
    {
        //
        // Sleep for a little bit.
        //
        //Sleep(1);

        b = QueryPerformanceCounter(&liCurrent);

        // 
        // Check to see if there is any data in the receive fifo.
        //
        ulRGIS = *AC97I_RGIS;
        if(ulRGIS & GIS_SLOT1TXCOMPLETE)
            break;

        if((liStart.QuadPart + TIMEOUT_AC97_READ) <liCurrent.QuadPart)
        {
            ERRMSG((L"PeekAC97 SLOT2TXVALID timed out. reg = 0x%02x.\r\n", ulCodecReg));
            return MMSYSERR_ERROR;
        }
    }


    //if( !(ulRGIS & GIS_SLOT2RXVALID) )
    //{
    //    ERRMSG((L"PeekAC97: SLOT2RXVALID timed out, reg = 0x%02x..\n", ulCodecReg)); 
    //    return MMSYSERR_ERROR;
    //}

    //
    // Write the address to AACS1DATA.
    //
    *AC97I_S1DATA = ulCodecReg;

    b = QueryPerformanceCounter(&liStart);
    for(;;)
    {
        //
        // Sleep for a little bit.
        //
        // Sleep(1);
        b = QueryPerformanceCounter(&liCurrent);

        // 
        // Check to see if there is any data in the receive fifo.
        //
        ulRGIS = *AC97I_RGIS;
        if((ulRGIS & (GIS_SLOT1TXCOMPLETE | GIS_SLOT2RXVALID)) ==
           (GIS_SLOT1TXCOMPLETE | GIS_SLOT2RXVALID))
            break;

        if((liStart.QuadPart + TIMEOUT_AC97_READ) <liCurrent.QuadPart)
        {
            ERRMSG((L"PeekAC97 timed out reading reg = 0x%04x.\r\n", ulCodecReg));
            return MMSYSERR_ERROR;
        }
    }

    //
    // Read in the value from S2Data
    //
    *pulValue = *AC97I_S2DATA;
    AC97_MSG((L"PeekAC97: Reg = 0x%02x, Value = 0x%04x\r\n",ulCodecReg, *pulValue));
    
    return MMSYSERR_NOERROR;
}


//****************************************************************************
// PokeAC97
//****************************************************************************
// Writes an AC97 codec Register.  
//
// ulCodecReg - AC97 Codec Register
// ulValue    - New Codec Register valuie.
//
// Return MMSYSERROR_NOERROR
//        MMSYSERROR_ERROR
//
MMRESULT AC97Codec::PokeAC97(ULONG ulCodecReg, ULONG ulValue)
{
    BOOL    b;
    ULONG   ulRGIS;
    LARGE_INTEGER   liStart, liCurrent;

    AC97_MSG((L"PokeAC97: Reg = 0x%02x, Value = 0x%04x\r\n",ulCodecReg, ulValue));
    
    //
    // Read AACS2DATA to be sure and clear the SLOT2RXVALID bit.  
    // May not be necessary, not sure.
    //
//    uiTemp = Ac97Global->AACS2DATA.Value;
    
    //
    // Write the data to AACS2DATA, then the address to AACS1DATA.
    //
    *AC97I_S2DATA = ulValue;
    *AC97I_S1DATA = ulCodecReg;

    b = QueryPerformanceCounter(&liStart);
    for(;;)
    {
        //
        // Sleep for a little bit.
        //
        // Sleep(1);
        b = QueryPerformanceCounter(&liCurrent);

        // 
        // Check to see if there is any data in the receive fifo.
        //
        ulRGIS = *AC97I_RGIS;
        if(ulRGIS & GIS_SLOT2TXCOMPLETE)
            break;

        if((liStart.QuadPart + TIMEOUT_AC97_READ) <liCurrent.QuadPart)
        {
            ERRMSG((L"PokeAC97: SLOT2TXVALID timed out reg = 0x%02x.\r\n", ulCodecReg));
            return MMSYSERR_ERROR;
        }
    }

    return MMSYSERR_NOERROR;
}

static volatile ULONG ulJunk;
//****************************************************************************
// I2SCodec::ProducePIOTone
//****************************************************************************
// For Debug only.
//
// Uses I2S to produce a PIO tone. 
// 
//
void AC97Codec::ProducePIOTone(void)
{
    ULONG ulCount;
    volatile ULONG ulTemp;
    volatile ULONG ulSR;
    ULONG ulMax= 0x80008000, ulMin=0x7FFF7FFF;

    //
    // Enable the AC97 transmit channel 0.
    //
    m_puAC97Ch[AC97I_TXCR>>2] = m_ulTXCR | TXCR_TEN;

    ulTemp = ulMax;
    for(ulCount = 0; ;ulCount ++)
    {
        if(ulCount& 0x40)
        {
            ulTemp = ulMax;
        }
        else
        {
            ulTemp = ulMin;
        }

        do
        {
            ulSR = m_puAC97Ch[AC97I_SR >>2];
        } while( ulSR & SR_TXFF);
        m_puAC97Ch[AC97I_DR >>2] = ulTemp;
    }
}


//****************************************************************************
// I2SCodec::CapturePIO
//****************************************************************************
// For Debug only.
//
// Uses I2S to produce a PIO tone. 
// 
//
void AC97Codec::CapturePIO(void)
{
    ULONG ulCount;
    volatile ULONG ulTemp[100];
    volatile ULONG ulSR;

    //
    // Enable the AC97 capture channel 0.
    //
    m_puAC97Ch[AC97I_RXCR>>2] = m_ulRXCR | RXCR_REN;

    for(;;)
    {
        for(ulCount = 0; ulCount <100;ulCount ++)
        {
            do
            {
                ulSR = m_puAC97Ch[AC97I_SR >>2];
            } while( ulSR & SR_RXFE);
            ulTemp[ulCount] = m_puAC97Ch[AC97I_DR >>2] ;
        }
    }
}

//****************************************************************************
// I2SCodec::CaptureNPlay
//****************************************************************************
// Play and capture to test the AC97 codec interface.
// 
//
void AC97Codec::CaptureNPlay(void)
{
    volatile ULONG ulTemp;
    volatile ULONG ulSR;


    //
    // Enable the AC97 transmitt channel 0.
    //
    m_puAC97Ch[AC97I_RXCR>>2] = m_ulRXCR | RXCR_REN;
    m_puAC97Ch[AC97I_TXCR>>2] = m_ulTXCR | TXCR_TEN;

    for(;;)
    {
        do
        {
            ulSR = m_puAC97Ch[AC97I_SR >>2];
        } while( ulSR & SR_RXFE);
        ulTemp = m_puAC97Ch[AC97I_DR >>2] ;
        ulSR = m_puAC97Ch[AC97I_SR >>2];

        if(!( ulSR & SR_TXFF))
        {
            m_puAC97Ch[AC97I_DR >>2] = ulTemp;
        }
    }
}


⌨️ 快捷键说明

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