📄 ac97codec.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
// EULA.RTF on your install media.
//
// Copyright(c) Cirrus Logic Corporation 2005, 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;
//
// Enable the interrupt incase we are using PIO instead of DMA.
//
m_puAC97Ch[AC97I_IE>>2] = m_ulIE = 0;
//
// 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);
PokeAC97(AC97_HEADPHONE_VOLUME,0x0);
//
// Set up the codec so that variable sample rates are enabled.
//
PokeAC97(AC97_EXT_AUDIO_POWER, 0xF);
// PokeAC97(AC97_EXT_AUDIO_POWER, EXT_AUDIO_POWER_VRA);
//PokeAC97(AC97_RECORD_SELECT, AC97_RECMUX_LINE);
PokeAC97(AC97_RECORD_SELECT, 0x0); //microphone
PokeAC97(AC97_MISC_CRYSTAL_CONTROL,0x10);
// PokeAC97(AC97_MIC_VOLUME, 0x8);
// PokeAC97(AC97_LINEIN_VOLUME, 0x0808 );
PokeAC97(AC97_RECORD_GAIN_MIC,0x0 );
PokeAC97(AC97_RECORD_GAIN, 0x0);
//PokeAC97(AC97_CD_VOLUME , 0x0 );
// PokeAC97(AC97_VIDEO_VOLUME , 0x0 );
// PokeAC97(AC97_AUX_VOLUME , 0x0 );
// PokeAC97(AC97_PCMOUT_VOLUME, 0x0808 );
// PokeAC97(AC97_PHONE_VOLUME, 0x0008);
// PokeAC97(AC97_MASTER_VOLUME,0x0);
//PokeAC97(AC97_GENERAL_PURPOSE,0x100); //select mic2
//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 - ( ( 0x1F * ( ulRightVolume)) / 0xFFFF );
ulLeft = 0x1F - ( ( 0x1F * ( ulLeftVolume)) / 0xFFFF );
//
// Writ to the AC97 codec register.
//
m_VolumeSettings.dwMasterVolume= ulRightVolume<<16 | ulLeftVolume;
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)
{
//
// For PIO mode an interrupt is generated continously if the
// Transmit Interrupt is enabled, but transmit is disabled.
//
// Enabled Transmit then enable the interrupt.
//
m_puAC97Ch[AC97I_TXCR>>2] = m_ulTXCR | TXCR_TEN;
m_puAC97Ch[AC97I_IE>>2] = m_ulIE |= IE_TIE;
return MMSYSERR_NOERROR;
}
//****************************************************************************
// AC97Codec::StopPlayback
//****************************************************************************
//
//
//
MMRESULT AC97Codec::StopPlayback(ULONG ulChannel)
{
//
// For PIO mode an interrupt is generated continously if the
// Transmit Interrupt is enabled, but transmit is disabled.
//
// Disable the Transmit Interrupt then disable transmit.
//
DWORD dwAC97Status;
while(1)
{
dwAC97Status=m_puAC97Ch[AC97I_SR >>2];
if( dwAC97Status & ( ( 0x1<<6) | (0x1<<1) ) )
break;
//RETAILMSG(1,(L"97data\r\n") );
}
m_puAC97Ch[AC97I_IE>>2] = m_ulIE &= ~IE_TIE;
m_puAC97Ch[AC97I_TXCR>>2] = m_ulTXCR ;
return MMSYSERR_NOERROR;
}
//****************************************************************************
// AC97Codec::StartRecord
//****************************************************************************
//
//
//
MMRESULT AC97Codec::StartRecord(ULONG ulChannel)
{
//
// For PIO mode an interrupt is generated continously if the
// Receive Interrupt is enabled, but receive is disabled.
//
// Enabled Receive then enable the Receive Interrupt.
//
m_puAC97Ch[AC97I_RXCR>>2] = m_ulRXCR | RXCR_REN;
m_puAC97Ch[AC97I_IE>>2] = m_ulIE |= IE_RIE;
return MMSYSERR_NOERROR;
}
//****************************************************************************
// AC97Codec::StopRecord
//****************************************************************************
//
//
//
MMRESULT AC97Codec::StopRecord(ULONG ulChannel)
{
//
// For PIO mode an interrupt is generated continously if the
// Recieve Interrupt is enabled, but Receive is disabled.
//
// Disable the Recieve Interrupt then disable Recieve.
//
m_puAC97Ch[AC97I_IE>>2] = m_ulIE &= ~IE_RIE;
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)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -