📄 ac97.c
字号:
/*++
Copyright (c) 2000-2005 BSQUARE Corporation. All rights reserved.
Module Name:
ac97.c
Module Description:
This module contains the platform independent code
of AC97 register accesses
Author:
GJS Nov 2000
Revision History:
Jun Li, July, 2001
Modified to seperate the AC97 code and the platform dependent code
--*/
#include <windows.h>
#include "ac97.h"
//#undef DEBUGMSG
//#define DEBUGMSG(cond, msg) NKDbgPrintfW##msg
//Global Volume levels
ULONG glVolume = 0;
ULONG grVolume = 0;
BOOL
AC97ResetRegisters(
IN PSC_AC97 *pAC97
)
{
BOOL Status = FALSE;
DEBUGMSG(1, (TEXT("+AC97ResetRegisters\r\n")));
//
// Any write to the Reset register will reset
//
Status = AC97WriteReg(pAC97,
AC97_RESET,
0xffff);
DEBUGMSG(1, (TEXT("-AC97ResetRegisters\r\n")));
return Status;
}
//
// Returns Volume regardless of Mute state
//
BOOL
AC97GetMasterVolume(
IN PSC_AC97 *pAC97,
OUT ULONG *LVol,
OUT ULONG *RVol
)
{
BOOL Status;
ULONG Data;
DEBUGMSG(1, (TEXT("+AC97GetMasterVolume\r\n")));
Status = AC97ReadReg(pAC97,
AC97_MASTER_VOLUME,
&Data);
DEBUGMSG(1, (TEXT("AC97GetMasterVolume Data %x \r\n\r\n"),Data));
DEBUGMSG(1, (TEXT("AC97GetMasterVolume Status %x \r\n\r\n"),Status));
if (Status) {
*LVol = (Data & VOLUME_LEFT_MASK) >> VOLUME_LEFT_SHIFT;
*RVol = (Data & VOLUME_RIGHT_MASK) >> VOLUME_RIGHT_SHIFT;
}
return Status;
}
//
// Set master volume - will overwrite MUTE
//
BOOL
AC97SetMasterVolume(
IN PSC_AC97 *pAC97,
IN ULONG LVol,
IN ULONG RVol
)
{
BOOL Status;
ULONG Data;
Data = ((LVol << VOLUME_LEFT_SHIFT) & VOLUME_LEFT_MASK) |
((RVol << VOLUME_RIGHT_SHIFT) & VOLUME_RIGHT_MASK);
// pb1x00 boards use LINE_OUT on the codec
// db1x00 boards use HP_OUT, so we set both here
Status = AC97WriteReg(pAC97,
AC97_MASTER_VOLUME,
Data);
Status = AC97WriteReg(pAC97,
AC97_ALT_LINE_LEVEL_OUT_VOLUME,
Data);
return Status;
}
//
// Returns Volume regardless of Mute state
//
BOOL
AC97GetPCMOutVolume(
IN PSC_AC97 *pAC97,
OUT ULONG *LVol,
OUT ULONG *RVol
)
{
BOOL Status;
ULONG Data;
DEBUGMSG(1, (TEXT("+AC97GetPCMOutVolume\r\n")));
Status = AC97ReadReg(pAC97,
AC97_PCM_OUT_VOLUME,
&Data);
if (Status) {
*LVol = (Data & VOLUME_LEFT_MASK) >> VOLUME_LEFT_SHIFT;
*RVol = (Data & VOLUME_RIGHT_MASK) >> VOLUME_RIGHT_SHIFT;
}
return Status;
}
//
// Set master volume - will overwrite MUTE
//
BOOL
AC97SetPCMOutVolume(
IN PSC_AC97 *pAC97,
IN ULONG LVol,
IN ULONG RVol
)
{
BOOL Status;
ULONG Data;
Data = ((LVol << VOLUME_LEFT_SHIFT) & VOLUME_LEFT_MASK) |
((RVol << VOLUME_RIGHT_SHIFT) & VOLUME_RIGHT_MASK);
Status = AC97WriteReg(pAC97,
AC97_PCM_OUT_VOLUME,
Data);
return Status;
}
/*
This CODEC has a master volume and PCM volume
The Master has a range from -46.5db to 0db in 1.5db steps
00000 == 0db gain
The PCM has a range of:
+12db == 00000
-34.5db == 11111
again, in 1.5db steps.
Hence, the entire volume range is +12db to -81db
The range of volumes is 16-bits per channel
Hence if 0xffff == 12db and 0x0000 == -81db
The are 62 possible volume settings (64 is close enough)
However, it is best to keep the input stage (in this case PCM) at the lowest reasonable
value to prevent distortion, namely clipping.
*/
BOOLEAN
CodecSetVolume(
IN PSC_AC97 *pAC97,
IN ULONG Volume
)
{
ULONG lVolume;
ULONG rVolume;
BOOLEAN test;
ULONG VolLevel;
DEBUGMSG(1, (TEXT("+CodecSetVolume\r\n")));
VolLevel = (UCHAR) Volume & 0xff; // Get the Actual Level
glVolume = Volume & 0xffff;
grVolume = (Volume >> 16) & 0xffff;
// Now scale the volume to 00 - 0x3f
// shift right by 10 bits
lVolume = 0x3f - (glVolume >> 10);
rVolume = 0x3f - (grVolume >> 10);
DEBUGMSG(1,(TEXT("lVolume: %X rVolume: %X\r\n"),lVolume, rVolume));
test = AC97SetMasterVolume( pAC97, lVolume, rVolume);
return test;
}
ULONG
CodecGetVolume(
IN PSC_AC97 *pAC97
)
{
ULONG lVolume;
ULONG rVolume;
IN ULONG Volume;
DEBUGMSG(1, (TEXT("CodecGetVolume\r\n")));
//
// Use the globals to prevent rounding errosa instead of the line below
//
//AC97GetMasterVolume( CodecDevice, &lVolume, &rVolume);
lVolume = glVolume;
rVolume = grVolume;
Volume = lVolume | (rVolume << 16);
DEBUGMSG(1, (TEXT("CodecGetVolume Volume %x\r\n"),Volume));
return Volume;
}
BOOL
CodecSetMasterMute(
IN PSC_AC97 *pAC97
)
{
AC97WriteReg(pAC97,
AC97_ALT_LINE_LEVEL_OUT_VOLUME,
VOLUME_MUTE);
return AC97WriteReg(pAC97,
AC97_MASTER_VOLUME,
VOLUME_MUTE);
}
BOOL
CodecClrMasterMute(
IN PSC_AC97 *pAC97
)
{
ULONG lVolume;
ULONG rVolume;
// Return to previous setting
lVolume = 0x1f - (glVolume >> 11);
rVolume = 0x1f - (grVolume >> 11);
return AC97SetMasterVolume(pAC97,
lVolume,
rVolume);
}
BOOL
CodecSetSampleRate(
IN PSC_AC97 *pAC97,
IN ULONG Hertz
)
{
BOOL Status = FALSE;
if (Hertz < 8000 || Hertz > 48000) {
DEBUGMSG(1,(L"CODEC: Rate not supported\r\n"));
goto ErrorReturn;
}
Status = AC97WriteReg(pAC97,
AC97_EXTENDED_AUDIO_STATUS_CONTROL,
1);
if (Status) {
Status = AC97WriteReg(pAC97,
AC97_PCM_FRONT_DAC_RATE,
Hertz);
}
ErrorReturn:
return Status;
}
BOOL
CodecSetADCSampleRate(
IN PSC_AC97 *pAC97,
IN ULONG Hertz
)
{
BOOL Status = FALSE;
if (Hertz < 8000 || Hertz > 48000) {
DEBUGMSG(1,(L"CODEC: Rate not supported\r\n"));
goto ErrorReturn;
}
Status = AC97WriteReg(pAC97,
AC97_EXTENDED_AUDIO_STATUS_CONTROL,
1);
if (Status) {
Status = AC97WriteReg(pAC97,
AC97_PCM_ADC_RATE,
Hertz);
}
ErrorReturn:
return Status;
}
BOOL
CodecPowerDown(
IN PSC_AC97 *pAC97
)
{
BOOL Status = FALSE;
ULONG Value = 0;
//
// The Codec must be powered down with sequential writes
// to the Powerdown Ctrl/Stat Register.
// Power down ADC.
Value = PR0;
Status = AC97WriteReg(pAC97,
AC97_POWER_CONTROL,
Value);
if (!Status)
goto ErrorReturn;
// Power down DAC.
Value |= PR1;
Status = AC97WriteReg(pAC97,
AC97_POWER_CONTROL,
Value);
if (!Status)
goto ErrorReturn;
// Power down analog mixer (VREF on).
Value |= PR2;
Status = AC97WriteReg(pAC97,
AC97_POWER_CONTROL,
Value);
if (!Status)
goto ErrorReturn;
// Power down digital clk.
Value |= PR5;
Status = AC97WriteReg(pAC97,
AC97_POWER_CONTROL,
Value);
if (!Status)
goto ErrorReturn;
// Power down headphone amp.
Value |= PR6;
Status = AC97WriteReg(pAC97,
AC97_POWER_CONTROL,
Value);
if (!Status)
goto ErrorReturn;
// Finally power down AC-Link to stop the bit clk.
Value |= PR4;
Status = AC97WriteReg(pAC97,
AC97_POWER_CONTROL,
Value);
ErrorReturn:
return Status;
}
BOOL
CodecPowerUp(
IN PSC_AC97 *pAC97
)
{
BOOL Status = FALSE;
ULONG Value;
INT Timeout = 1000;
//
// Reading the Codec Ready bit of the Controller
// status register does not work, try reading
// a Codec register until the Codec is ready.
//
while (!Status)
{
Status = AC97ReadReg(pAC97,
AC97_POWER_CONTROL,
&Value);
Timeout--;
}
if (!Timeout)
goto ErrorReturn;
// Currently turned off components.
Value = PR6 | PR5 | PR2 | PR1 | PR0;
// Power up headphone amp.
Value &= ~PR6;
Status = AC97WriteReg(pAC97,
AC97_POWER_CONTROL,
Value);
if (!Status)
goto ErrorReturn;
// Power up digital clk.
Value &= ~PR5;
Status = AC97WriteReg(pAC97,
AC97_POWER_CONTROL,
Value);
if (!Status)
goto ErrorReturn;
// Power up analog mixer (VREF on).
Value &= ~PR2;
Status = AC97WriteReg(pAC97,
AC97_POWER_CONTROL,
Value);
if (!Status)
goto ErrorReturn;
// Power up DAC.
Value &= ~PR1;
Status = AC97WriteReg(pAC97,
AC97_POWER_CONTROL,
Value);
if (!Status)
goto ErrorReturn;
// Power up ADC.
Value &= ~PR0;
Status = AC97WriteReg(pAC97,
AC97_POWER_CONTROL,
Value);
ErrorReturn:
return Status;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -