📄 hwctxt.cpp
字号:
{
PBYTE pVirtDMABufferAddr = NULL;
DMA_ADAPTER_OBJECT Adapter;
memset(&Adapter, 0, sizeof(DMA_ADAPTER_OBJECT));
Adapter.InterfaceType = Internal;
Adapter.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);
// Allocate a block of virtual memory (physically contiguous) for the DMA buffers.
//
pVirtDMABufferAddr = (PBYTE)HalAllocateCommonBuffer(&Adapter, (AUDIO_DMA_PAGE_SIZE * 4), &g_PhysDMABufferAddr, FALSE);
if (pVirtDMABufferAddr == NULL)
{
RETAILMSG(TRUE, (TEXT("WAVEDEV.DLL:HardwareContext::MapDMABuffers() - Failed to allocate DMA buffer.\r\n")));
return(FALSE);
}
// Setup the DMA page pointers.
// NOTE: Currently, input and output each have two DMA pages: these pages are used in a round-robin
// fashion so that the OS can read/write one buffer while the audio codec chip read/writes the other buffer.
//
m_Output_pbDMA_PAGES[0] = pVirtDMABufferAddr;
m_Output_pbDMA_PAGES[1] = pVirtDMABufferAddr + AUDIO_DMA_PAGE_SIZE;
m_Input_pbDMA_PAGES[0] = pVirtDMABufferAddr + (2 * AUDIO_DMA_PAGE_SIZE);
m_Input_pbDMA_PAGES[1] = pVirtDMABufferAddr + (3 * AUDIO_DMA_PAGE_SIZE);
return(TRUE);
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: UnmapDMABuffers()
Description: Unmaps the DMA buffers used for audio input/output
on the AC97 bus.
Returns: Boolean indicating success
-------------------------------------------------------------------*/
BOOL HardwareContext::UnmapDMABuffers()
{
if(m_Output_pbDMA_PAGES[0])
{
VirtualFree((PVOID)m_Output_pbDMA_PAGES[0], 0, MEM_RELEASE);
}
return TRUE;
}
#if (AC97_READY_CHECK_METHOD == 1) // AC97 Interrupt Thread
HANDLE AC97_InterruptEvent = NULL;
HANDLE AC97_Thread = NULL;
DWORD g_AC97SysIntr = SYSINTR_UNDEFINED;
DWORD g_AC97Irq = IRQ_WDT_AC97;
DWORD AC97InterruptThread(void);
DWORD Codec_Ready_Irq = 0;
static DWORD AC97InterruptThread(void)
{
while(1)
{
WaitForSingleObject(AC97_InterruptEvent, INFINITE);
RETAILMSG(1,(_T("AC97InterruptThread() !!\r\n")));
if ( (v_pAC97regs->AC_GLBSTAT& 0x400000))
{
Codec_Ready_Irq=1;
RETAILMSG(1,(_T("Codec Ready!\r\n")));
v_pAC97regs->AC_GLBCTRL &= ~(0x400000); // codec ready interrupt disable
}
s2443INT->INTSUBMSK &= ~(1<< IRQ_SUB_AC97);
s2443INT->INTMSK &= ~(1 << IRQ_WDT_AC97);
}
}
static void AC97_InterruptThread_Initialize(void)
{
DWORD threadID;
if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &g_AC97Irq, sizeof(UINT32), &g_AC97SysIntr, sizeof(UINT32), NULL))
{
RETAILMSG(1, (TEXT("ERROR: AC97Irq: Failed to request sysintr value for AC97 interrupt.\r\n")));
}
if (AC97_InterruptEvent == NULL)
{
AC97_InterruptEvent = CreateEvent(NULL, FALSE, FALSE,NULL);
if (NULL == AC97_InterruptEvent) {
RETAILMSG(1,(TEXT("AC97 interrupt event Error1\r\n")));
}
// initialize the card insertion interrupt event
if (!InterruptInitialize (g_AC97SysIntr, AC97_InterruptEvent, 0, 0)) {
RETAILMSG(1,(TEXT("AC97 interrupt event Error2\r\n")));
}
}
if (AC97_Thread == NULL)
{
AC97_Thread = CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)AC97InterruptThread,
0,
0,
&threadID);
if (NULL == AC97_Thread ) {
RETAILMSG(1,(TEXT("Create AC97 Interrupt Thread Fail\r\n")));
}
}
RETAILMSG(1,(TEXT("Use AC97 Int for initialization\r\n")));
}
#endif
// Kingfish2 AC97 Initialize function
BOOL HardwareContext::AC97_Init()
{
RETAILMSG(AC97_DEBUG,(_T("WAVDEV_AC97::AC97_Init()++\r\n")));
//----- 1. IMPORTANT: By default, the internal clock is disabled. To configure the controller ------
// we must first enable it.
// v_pCLKPWRreg->CLKCON |= AC97_INTERNAL_CLOCK_ENABLE; // Enable the CPU clock to the AC97 controller
//AC97_GPIO_Init();
#ifdef EVT1
// v_pIOPregs->GPECON = (v_pIOPregs->GPECON & ~(0x3ff << 10)); //GPE[4:0]=AC_SDATA_OUT AC_SDATA_IN AC_nRESET AC_BIT_CLK AC_SYNC
// v_pIOPregs->GPEUDP = (v_pIOPregs->GPEUDP & ~(0x3ff << 10)) | (0x155 << 10); //The pull up function is disabled GPE[4:0] 1 1111
// v_pIOPregs->GPEDAT = v_pIOPregs->GPEDAT & ~(0x1f << 10); //The pull up function is disabled GPE[4:0] 1 1111
v_pIOPregs->GPECON = (v_pIOPregs->GPECON & ~(0x3ff)) | 0x3ff; //GPE[4:0]=AC_SDATA_OUT AC_SDATA_IN AC_nRESET AC_BIT_CLK AC_SYNC
v_pIOPregs->GPEUDP = (v_pIOPregs->GPEUDP & ~(0x3ff)) | 0x155; //The pull up function is disabled GPE[4:0] 1 1111
v_pIOPregs->GPEDAT = v_pIOPregs->GPEDAT & ~(0x1f); //The pull up function is disabled GPE[4:0] 1 1111
#else
// v_pIOPregs->GPECON = (v_pIOPregs->GPECON & ~(0x3ff << 10)); //GPE[4:0]=AC_SDATA_OUT AC_SDATA_IN AC_nRESET AC_BIT_CLK AC_SYNC
// v_pIOPregs->GPEUDP = (v_pIOPregs->GPEUDP & ~(0x3ff << 10)) | (0x2AA << 10); //The pull up function is disabled GPE[4:0] 1 1111
// v_pIOPregs->GPEDAT = v_pIOPregs->GPEDAT & ~(0x1f << 10); //The pull up function is disabled GPE[4:0] 1 1111
v_pIOPregs->GPECON = (v_pIOPregs->GPECON & ~(0x3ff)) | 0x3ff; //GPE[4:0]=AC_SDATA_OUT AC_SDATA_IN AC_nRESET AC_BIT_CLK AC_SYNC
v_pIOPregs->GPEUDP = (v_pIOPregs->GPEUDP & ~(0x3ff)) | 0x2AA; //The pull up function is disabled GPE[4:0] 1 1111
v_pIOPregs->GPEDAT = v_pIOPregs->GPEDAT & ~(0x1f); //The pull up function is disabled GPE[4:0] 1 1111
#endif
// v_pAC97regs->AC_GLBCTRL = 0;
// Delay(10); //Sleep(5);
// Write into the AC97 Global Control Register
//Cold Reset
v_pAC97regs->AC_GLBCTRL = 0x1;
Delay(10); //Sleep(5);
v_pAC97regs->AC_GLBCTRL = 0x0;
Delay(10); //Sleep(5);
//Ajay
v_pAC97regs->AC_GLBCTRL = 0x1;
Delay(10); //Sleep(5);
v_pAC97regs->AC_GLBCTRL = 0x0;
Delay(10); //Sleep(5);
//AC-link On
v_pAC97regs->AC_GLBCTRL = (1<<2);
Delay(10); //Sleep(5);
//Transfer data enable using AC-link
v_pAC97regs->AC_GLBCTRL = v_pAC97regs->AC_GLBCTRL | (1<<3);
Delay(10); //Sleep(5);
// Enable the Codec ready Interrupt Ajay
v_pAC97regs->AC_GLBCTRL = v_pAC97regs->AC_GLBCTRL | (1<<22);
Delay(10); //Sleep(5);
// while (!(v_pAC97regs->AC_GLBSTAT& 0x400000));
RETAILMSG(AC97_DEBUG,(_T("WAVEDEV_AC97::AC97 Codec Ready!\r\n")));
v_pAC97regs->AC_GLBCTRL &= ~(0x400000); // codec ready interrupt disable
Delay(10); //Sleep(5);
#if AC97_RECORD_MICIN
v_pAC97regs->AC_GLBCTRL = (v_pAC97regs->AC_GLBCTRL & ~(0x3f<<8)) | 0x2200; // PCM_OUT=DMA,PCM_IN=OFF,MIC=DMA;
#else
v_pAC97regs->AC_GLBCTRL = (v_pAC97regs->AC_GLBCTRL & ~(0x3f<<10)) | 0x2800; // PCM_OUT=DMA,PCM_IN=DMA,MIC=OFF;
#endif
RETAILMSG(AC97_DEBUG,(_T("WAVDEV_AC97::AC97_Init()--\r\n")));
return TRUE;
}
BOOL HardwareContext::Codec_channel()
{
Lock();
// Kingfish2 AC97
if( m_InputDMARunning & m_OutputDMARunning )
{
RETAILMSG(AC97_DEBUG1,(_T("Codec_channel() - In & Out\r\n")));
WriteCodecRegister(AC97_POWER_CONTROL, AC97_PWR_D0); // ADC, DAC power up
}
else if( m_InputDMARunning )
{
RETAILMSG(AC97_DEBUG1,(_T("Codec_channel() - In\r\n")));
WriteCodecRegister(AC97_POWER_CONTROL, AC97_PWR_PR1); // DAC power down
//WriteCodecRegister(AC97_POWER_DOWN1, 0xb9cf);
//WriteCodecRegister(AC97_POWER_DOWN2, 0xbff0);
}
else if( m_OutputDMARunning )
{
RETAILMSG(AC97_DEBUG1,(_T("Codec_channel() - Out\r\n")));
WriteCodecRegister(AC97_POWER_CONTROL, AC97_PWR_PR0); // ADC power down
}
else
{
RETAILMSG(AC97_DEBUG1,(_T("Codec_channel() - none\r\n")));
WriteCodecRegister(AC97_POWER_CONTROL, AC97_PWR_PR1|AC97_PWR_PR0); // ADC/DAC power down
}
Unlock();
return(TRUE);
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: InitCodec()
Description: Initializes the audio codec chip.
Notes: The audio codec chip is intialized for output mode
but powered down. To conserve battery life, the chip
is only powered up when the user starts playing a
file.
Specifically, the powerup/powerdown logic is done
in the AudioMute() function. If either of the
audio channels are unmuted, then the chip is powered
up; otherwise the chip is powered own.
Returns: Boolean indicating success
-------------------------------------------------------------------*/
BOOL HardwareContext::InitCodec()
{
USHORT CodecRead;
ULONG CodecVendorID, CodecRevision;
RETAILMSG(AC97_DEBUG, (TEXT("+++InitCodec\r\n")));
// write the Codec software reset
// 00h
WriteCodecRegister(AC97_RESET, 0x683F);
// Enable the VRA
// 2Ah
WriteCodecRegister(AC97_EXT_AUDIO_CONTROL, AC97_ENABLE_VRA);
WriteCodecRegister(AC97_PCM_DAC_RATE, 44100); // Write default Sample rate for DAC
WriteCodecRegister(AC97_PCM_ADC_RATE, 44100); // Write default Sample rate for DAC
// get the Vendor ID and revision
// 7Ch
CodecVendorID = ULONG(ReadCodecRegister( AC97_VENDOR_ID1 )) << 16;
// 7E
CodecRead = ReadCodecRegister( AC97_VENDOR_ID2 );
CodecVendorID |= ULONG(CodecRead) & 0x0000ff00;
CodecRevision = ULONG(CodecRead) & 0x000000ff;
if ( !( CodecVendorID == AC97_VENDOR_SIGMATEL && CodecRevision == 0x66))
{
// now power down the Analog section of the AC97
// and power it back up. This forces the Sigmatel
// to calibrate it's analog levels
// 26h
WriteCodecRegister(AC97_POWER_CONTROL, AC97_PWR_ANLOFF );
Delay(10); //Sleep(5);
RETAILMSG(AC97_DEBUG,(_T("WriteCodecRegister(AC97_POWER_CONTROL, AC97_PWR_ANLOFF)\r\n")));
}
// Turn Power on for sections
// 26h
WriteCodecRegister( AC97_POWER_CONTROL, AC97_PWR_D0 );
// Write the Analog reg
// 6Eh
//WriteCodecRegister( AC97_ANALOG_SPEC, 0x0000 );
// write HP Out Value
// 04h
WriteCodecRegister( AC97_HEADPHONE_VOL, 0x0606 ); //0x0202); //0x0404 );
// Mute unusing analog source except -------------------------------
// PCBEEP_VOL - 0ah
WriteCodecRegister( AC97_PCBEEP_VOL, 0x8000 );
// PHONE_VOL - 0ch
WriteCodecRegister( AC97_PHONE_VOL, 0x8008 );
// LINEIN_VOL - 10h
WriteCodecRegister( AC97_LINEIN_VOL, 0x8808 );
// CD_VOL - 12h
WriteCodecRegister( AC97_CD_VOL, 0x8808 );
// Mic volume - 0eh
WriteCodecRegister( AC97_MIC_VOL, 0x8008 );
// write the wave out volume
// 18h
WriteCodecRegister( AC97_PCMOUT_VOL, 0x0808 ); //0x0000 ); //0x0606 );
#if AC97_RECORD_MICIN
// ADC Gain Control, 30dB
// BOOSTEN =1
// tmp = ReadCodecRegister(AC97_MIC_VOL) & ~(0x1<<6);
// WriteCodecRegister(AC97_MIC_VOL, tmp | (0x1<<6));
WriteCodecRegister( AC97_MIC_VOL, (1<<15)|(1<<6) ); // Mute & BOOTEN
//ADC Input Slot => left slot6, right slot9, MIC GAIN VAL=1
WriteCodecRegister( AC97_INTR_PAGE, 0x0 );
WriteCodecRegister( AC97_ANALOG_SPEC, 0x0024 );
//Left, Right => MIC
WriteCodecRegister( AC97_RECORD_SELECT, AC97_RECMUX_MIC );
// set up a default record gain
// 1Ch
//WriteCodecRegister( AC97_RECORD_GAIN, AC97_RECORD_GAIN_VAL );
WriteCodecRegister( AC97_RECORD_GAIN, 0x0909 );
#else
WriteCodecRegister( AC97_LINEIN_VOL, 0x8808 ); //For PCM In
//ADC Input Slot => left slot3, right slot4, MIC GAIN VAL=1
//WriteCodecRegister( AC97_INTR_PAGE, 0x0 );
//Select Slots for ADC Data on AC Link Left=3 , Right=4
//WriteCodecRegister( AC97_ANALOG_SPEC, 0x0000 ); //For PCM IN
//Left, Right => LineIn
WriteCodecRegister( AC97_RECORD_SELECT, 0x0505 );// for PCM In
// set up a default record gain
// 1Ch
WriteCodecRegister( AC97_RECORD_GAIN, 0x0909 ); //For PCM In
WriteCodecRegister( 0x5A, 0x10); // for distinguish pcm in and output
WriteCodecRegister( 0x5C, 0x20); // for distinguish pcm in and output
#endif
// Init MIC-IN configurations
// 20h
WriteCodecRegister( AC97_GENERAL_PURPOSE, 0x0000 ); //MIC1 Selected
// Now write High Pass Filter Bypass Control Register
// 78h
//WriteCodecRegister( AC97_HPF_BYPASS, AC97_HIPASS_DISABLE );
RETAILMSG(AC97_DEBUG, (TEXT("---InitCodec\r\n")));
return(TRUE);
}
MMRESULT HardwareContext::SetOutputGain (DWORD dwGain)
{
m_dwOutputGain = dwGain & 0xffff; // save off so we can return this from GetGain - but only MONO
// convert 16-bit gain to 5-bit attenuation
UCHAR ucGain;
if (m_dwOutputGain == 0) {
ucGain = 0x3F; // mute: set maximum attenuation
}
else {
ucGain = (UCHAR) ((0xffff - m_dwOutputGain) >> 11); // codec supports 64dB attenuation, we'll only use 32
}
ASSERT((ucGain & 0xC0) == 0); // bits 6,7 clear indicate DATA0 in Volume mode.
// Kingfish2. I can't find output gain of CODEC
// WriteCodecRegister( AC97_RECORD_GAIN, AC97_RECORD_GAIN_VAL );
return MMSYSERR_NOERROR;
}
MMRESULT HardwareContext::SetOutputMute (BOOL fMute)
{
Lock();
m_fOutputMute = fMute;
WriteCodecRegister(0x02, 0x8000); // OUT2 volume Muted. Kingfish2
Unlock();
return MMSYSERR_NOERROR;
}
BOOL HardwareContext::GetOutputMute (void)
{
return m_fOutputMute;
}
DWORD HardwareContext::GetOutputGain (void)
{
return m_dwOutputGain;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -