📄 ac97.cpp
字号:
/*++
Copyright (c) 2004 Sten
Contact information:
mail: stenri@mail.ru
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Module Name:
ac97.cpp
Abstract: AC'97 code functions
Revision History:
Sten 01/01/2004
Initial release. Started expiriments on using AC'97.. Wow!!
--*/
extern "C" {
#pragma warning ( push, 3 )
#include <ntddk.h>
#pragma warning ( pop )
}
#pragma warning ( disable: 4514 ) // unreferenced inline function has been removed
#pragma warning ( disable: 4127 ) // conditional expression is constant
#include <windef.h>
#include <ntverp.h>
#include "softice.h"
#include "defs.h"
#include "pci.h"
#include "ac97.h"
#include "keyboard.h"
#include "mp3.h"
static USHORT NAMBAR = 0; // BAR for mixer
static USHORT NABMBAR = 0; // BAR for bus master regs
static UCHAR INTLINE = 0; // interrupt line for the device
static ULONG INTVECTOR = 0; // AC97 Interrupt vector
static PVOID OldHandler = 0; // Old AC97 IRQ handler
static ULONG *BDL_BUFFER = 0; // pointer to the Buffer Descriptor List
UCHAR *WAV_BUFFER1 = 0; // pointer to the first wav buffer
UCHAR *WAV_BUFFER2 = 0; // pointer to the second wav buffer
ULONG AC97_PCI_ADDRESS = 0; // AC97 PCI address
///////////////////////////////////////////////////////////////////////////////////
//
// AC97 IRQ Handler
//
///////////////////////////////////////////////////////////////////////////////////
static __declspec(naked) VOID ac97_IRQHandler( VOID )
{
__asm
{
pushad
push fs
push ds
push es
mov eax, 00000030h
mov fs,ax
mov eax, 23h
mov ds,ax
mov es,ax
mov ebp,esp
sub esp,32
}
USHORT dwStsReg;
USHORT dwPOSRReg;
__asm
{
mov dx, ds:[NABMBAR]
add dx, GLOB_STS_REG ; set pointer to Global Status reg
in ax, dx
mov dwStsReg, ax
mov dx, ds:[NABMBAR]
add dx, PO_SR_REG ; set pointer to PCM Out Cntl reg
in ax, dx
mov dwPOSRReg, ax
}
if (*si_IceIsActive)
{
DbgPrint("AC97 Handler: %04X %04X\n", dwStsReg,dwPOSRReg);
}
//_Out:
__asm
{
movzx eax, INTLINE ; send End Of Interrupt signal
call si_SendSpecificEOI
mov esp,ebp
pop es
pop ds
pop fs
popad
//iretd
jmp cs:[OldHandler]
}
}
///////////////////////////////////////////////////////////////////////////////////
//
// Initialize AC97
//
///////////////////////////////////////////////////////////////////////////////////
BOOL ac97_Init( VOID )
{
// Detect/reset AC97
if ((AC97_PCI_ADDRESS = pciFindDevice(MAKELONG(INTEL_VID, ICH5_DID))) == 0)
if ((AC97_PCI_ADDRESS = pciFindDevice(MAKELONG(INTEL_VID, ICH4_DID))) == 0)
if ((AC97_PCI_ADDRESS = pciFindDevice(MAKELONG(INTEL_VID, ICH3_DID))) == 0)
if ((AC97_PCI_ADDRESS = pciFindDevice(MAKELONG(INTEL_VID, ICH2_DID))) == 0)
if ((AC97_PCI_ADDRESS = pciFindDevice(MAKELONG(INTEL_VID, ICH0_DID))) == 0)
if ((AC97_PCI_ADDRESS = pciFindDevice(MAKELONG(INTEL_VID, ICH_DID))) == 0)
{
DbgPrint("Warning: AC97 not found.\n");
return FALSE;
}
__asm
{
; get ICH base address regs for mixer and bus master
mov eax, AC97_PCI_ADDRESS
mov al, NAMBAR_REG
call pciRegRead16 ; read PCI registers 10-11
and dx, IO_ADDR_MASK ; mask off BIT0
mov ds:[NAMBAR], dx ; save audio mixer base addy
mov al, NABMBAR_REG
call pciRegRead16
and dx, IO_ADDR_MASK
mov ds:[NABMBAR], dx ; save bus master base addy
mov al, INTLINE_REG
call pciRegRead8
mov ds:[INTLINE], dl ; save int line register
movzx eax, dl
call si_IRQ2INT
mov ds:[INTVECTOR], eax
mov al, PCI_CMD_REG
call pciRegRead16 ; read PCI command register
or dl, IO_ENA+BM_ENA ; enable IO and bus master
call pciRegWrite16
}
DbgPrint("AC97 INT LINE: %d\n", INTLINE);
DbgPrint("AC97 VECTOR: %08x\n", INTVECTOR);
/**/
KIRQL Irql;
KAFFINITY Affinity;
ULONG MappedVector = HalGetInterruptVector(PCIBus,
0,
INTLINE,
INTLINE,
&Irql,
&Affinity);
INTVECTOR = MappedVector & 0x000000FF; // low Mapped vector 8 bits seems
// to be real system-vector
DbgPrint("AC97 MAPPED VECTOR: %08x\n", MappedVector);
DbgPrint("AC97 MAPPED VECTOR Affinity: %08x\n", Affinity);
DbgPrint("AC97 MAPPED VECTOR Irql: %08x\n", Irql);
/**/
if (!INTVECTOR)
{
DbgPrint("Error: unable to map AC97 IRQ to system vector.\n");
return FALSE;
}
//-----------------------------------------------------------------------
// Install my own AC97 IRQ handler
//-----------------------------------------------------------------------
OldHandler = SetInterruptHandler(INTVECTOR, ac97_IRQHandler, 0x8e);
DbgPrint("Old AC97 IRQ Handler: %08X\n", OldHandler);
// Allocate buffer for the BDL
// It's bad style to use MmAllocateContiguousMemory to alloc memory
// for DMA operations but.. :)
PHYSICAL_ADDRESS HighestAcceptable;
HighestAcceptable.QuadPart = 0xFFFFFFFF;
BDL_BUFFER = (ULONG *)MmAllocateContiguousMemory(256, HighestAcceptable);
WAV_BUFFER1 = (UCHAR *)MmAllocateContiguousMemory(WAV_BUFFER_SIZE, HighestAcceptable);
WAV_BUFFER2 = (UCHAR *)MmAllocateContiguousMemory(WAV_BUFFER_SIZE, HighestAcceptable);
if ((!BDL_BUFFER) || (!WAV_BUFFER1) || (!WAV_BUFFER2))
{
DbgPrint("Error: unable to allocate enough contiguous physical memory.\n");
return FALSE;
}
// fill our buffers with zeroes
memset(WAV_BUFFER1, 0, WAV_BUFFER_SIZE);
memset(WAV_BUFFER2, 0, WAV_BUFFER_SIZE);
return TRUE;
}
VOID ac97_PrepareToPlay( VOID )
{
// initialize AC97 DMA controller
ac97_ResetDMA();
ac97_CreateBDL();
ac97_SetBDLAddress();
ac97_SetLastValidIndex(31);
__asm
{
movzx eax, INTLINE
call si_EnableIRQ
}
}
///////////////////////////////////////////////////////////////////////////////////
//
// Free allocated memory
//
///////////////////////////////////////////////////////////////////////////////////
VOID ac97_Done( VOID )
{
if (BDL_BUFFER) MmFreeContiguousMemory(BDL_BUFFER);
if (WAV_BUFFER1) MmFreeContiguousMemory(WAV_BUFFER1);
if (WAV_BUFFER2) MmFreeContiguousMemory(WAV_BUFFER2);
AC97_PCI_ADDRESS = 0;
BDL_BUFFER = 0;
WAV_BUFFER1 = 0;
WAV_BUFFER2 = 0;
// Uninstall AC97 IRQ handler
if (OldHandler)
{
SetInterruptHandler(INTVECTOR,OldHandler, 0x8e);
OldHandler = 0;
}
}
///////////////////////////////////////////////////////////////////////////////////
//
// Set PCM Front DAC Rate
//
///////////////////////////////////////////////////////////////////////////////////
VOID ac97_SetPcmFrontDacRate( USHORT dwRate )
{
__asm
{
push eax
push edx
mov ax, dwRate
mov dx, ds:[NAMBAR] ; get mixer base address
add dx, CODEC_PCM_FRONT_DACRATE_REG
out dx, ax ; out sample rate
mov eax, 4
call si_DelayMilliSec ; delays cuz codecs are slow
pop edx
pop eax
}
}
///////////////////////////////////////////////////////////////////////////////////
//
// Set PCM Surround DAC Rate
//
///////////////////////////////////////////////////////////////////////////////////
VOID ac97_SetPcmSurroundDacRate( USHORT dwRate )
{
__asm
{
push eax
push edx
mov ax, dwRate
mov dx, ds:[NAMBAR] ; get mixer base address
add dx, CODEC_PCM_SURND_DACRATE_REG
out dx, ax ; out sample rate
mov eax, 4
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -