hwctxt.cpp
资源名称:SMDK2440.rar [点击查看]
上传用户:qiulin1960
上传日期:2013-10-16
资源大小:2844k
文件大小:54k
源码类别:
Windows CE
开发平台:
Windows_Unix
- //
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //
- //
- // Use of this source code is subject to the terms of the Microsoft 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.
- //
- /*++
- 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.
- Module Name: HWCTXT.CPP
- Abstract: Platform dependent code for the mixing audio driver.
- Notes: The following file contains all the hardware specific code
- for the mixing audio driver. This code's primary responsibilities
- are:
- * Initialize audio hardware (including codec chip)
- * Schedule DMA operations (move data from/to buffers)
- * Handle audio interrupts
- All other tasks (mixing, volume control, etc.) are handled by the "upper"
- layers of this driver.
- ****** IMPORTANT ******
- Presently, audio input (i.e. RECORD functionality) IS NOT implemented. On
- this platform, in order to record the TLV320AIC codec chip needs to be
- configured as MASTER and the CPU's I2S controller configured as SLAVE.
- Unfortunately, a hardware bug in the current Samsung CPU samples prevents
- SLAVE mode from working properly. As a result, only audio playback is
- supported by configuring the CPU I2S controller as MASTER and the audio
- codec chip as SLAVE.
- The final revision of the Samsung SC2440 CPU is expected to fix this
- hardware bug. Once this issue is resolved, the CPU's I2S controller
- (look at I2S.CPP) should be configured in SLAVE mode and the audio codec
- chip (see InitCodec() below) should be configured as MASTER. With these
- changes, the following routines need to be implemented:
- InitInputDMA() - initialize the input DMA channel
- StartInputDMA() - starts DMA operations on the input DMA channel
- StopInputDMA() - stops any current DMA operations on the input DMA channel
- For the SC2440 CPU, DMA channel 2 can be used for both input and output. In this,
- configuration, however, only one type operation (input or output) can execute. In
- order to implement simultaneous playback and recording, two things must be done:
- 1) Input DMA should be moved to DMA Channel 1; Output DMA still uses DMA Channel 2.
- 2) Step #3 in InterruptThread() needs to be implemented so that the DMA interrupt
- source (input DMA or output DMA?) can be determined. The interrupt source needs
- to be determined so that the appropriate buffers can be copied (Steps #4,#5...etc.).
- Lastly, the m_OutputDMAStatus and m_InputDMAStatus variables shouldn't need to be modified.
- The logic surrounding these drivers is simply used to determine which buffer (A or B) needs
- processing.
- Environment: PocketPC SMDK2440 Reference Platform:
- Hardware - Samsung SC2440 CPU
- TI TLV320AIC audio codec chip where:
- 1) SPI bus is used for control
- 2) I2S bus is used for data (CPU is master
- and codec chip is slave)
- Software - Windows CE 3.0 and later.
- -*/
- #include "wavemain.h"
- #include <p2.h>
- #include "s2440.h"
- #include "dma.h"
- #include "hwctxt.h"
- #define DMA_FLAG 1
- #define AC97_DEBUG 0
- #define AC97MSG(a,b) RETAILMSG(AC97_DEBUG,b)
- #define DMA_CH_MIC 2
- #define DMA_CH_OUT 1
- #define WAIT_DMA_END 0
- #define DELAY_COUNT 0x1000
- int rec_mode=0;
- //-------------------------------- Global Variables --------------------------------------
- volatile AC97reg *v_pAC97regs = NULL; // AC97 control registers
- volatile IOPreg *v_pIOPregs = NULL; // GPIO registers (needed to enable I2S and SPI)
- volatile DMAreg *v_pDMAregs = NULL; // DMA registers (needed for I/O on I2S bus)
- volatile CLKPWRreg *g_pCLKPWRreg = NULL; // Clock power registers (needed to enable I2S and SPI clocks)
- volatile INTreg *s2440INT = NULL;
- HANDLE g_hUTLObject = INVALID_HANDLE_VALUE;
- HardwareContext *g_pHWContext = NULL;
- void AC97_GPIO_Init();
- unsigned int delay_count;
- //----------------------------------------------------------------------------------------
- /*#ifdef DEBUG
- DBGPARAM dpCurSettings = {
- TEXT("CONSOLE"), {
- TEXT("0"),TEXT("1"),TEXT("2"),TEXT("3"),
- TEXT("4"),TEXT("5"),TEXT("6"),TEXT("7"),
- TEXT("8"),TEXT("9"),TEXT("10"),TEXT("11"),
- TEXT("12"),TEXT("Function"),TEXT("Init"),TEXT("Error")},
- 0x8000 // Errors only, by default
- };
- #endif
- */
- // Static Functions
- volatile static int loop = S2440FCLK/100000;
- static void Delay(USHORT count)
- {
- volatile int i, j;
- for(;count > 0;count--)
- for(i=0;i < loop; i++) { j++; }
- }
- static void WriteCodecRegister(UCHAR Reg, USHORT Val)
- {
- v_pAC97regs->rAC_CODEC_CMD = (Reg << AC97_CMD_ADDR_SHIFT) | (Val << AC97_CMD_DATA_SHIFT);
- Delay(100);
- //Sleep(5);
- v_pAC97regs->rAC_CODEC_CMD |= (AC97_READ_COMMAND); //To receive SLOTREQ bits when VRA is '1'.
- }
- static USHORT ReadCodecRegister(UCHAR Reg)
- {
- USHORT retval;
- v_pAC97regs->rAC_CODEC_CMD = AC97_READ_COMMAND | (Reg << AC97_CMD_ADDR_SHIFT);
- Delay(100);
- //Sleep(5);
- retval = v_pAC97regs->rAC_CODEC_STAT & AC97_STAT_DATA_READ_MASK;
- return retval;
- }
- BOOL HardwareContext::CreateHWContext(DWORD Index)
- {
- if (g_pHWContext)
- {
- return TRUE;
- }
- g_pHWContext = new HardwareContext;
- if (!g_pHWContext)
- {
- return FALSE;
- }
- return g_pHWContext->Init(Index);
- }
- HardwareContext::HardwareContext()
- : m_InputDeviceContext(), m_OutputDeviceContext()
- {
- InitializeCriticalSection(&m_Lock);
- }
- HardwareContext::~HardwareContext()
- {
- DeleteCriticalSection(&m_Lock);
- }
- BOOL HardwareContext::Init(DWORD Index)
- {
- BOOL bRet = TRUE;
- //----- 1. Initialize the state/status variables -----
- m_DriverIndex = Index;
- m_IntrAudio = SYSINTR_AUDIO;
- m_InPowerHandler = FALSE;
- m_InputDMARunning = FALSE;
- m_OutputDMARunning = FALSE;
- m_InputDMAStatus = DMA_CLEAR;
- m_OutputDMAStatus = DMA_CLEAR;
- //----- 2. Map the necessary descriptory channel and control registers into the driver's virtual address space -----
- if(!MapRegisters())
- {
- DEBUGMSG(ZONE_ERROR, (TEXT("WAVEDEV.DLL:HardwareContext::Init() - Failed to map config registers.rn")));
- bRet = FALSE;
- goto Exit;
- }
- //----- 3. Map the DMA buffers into driver's virtual address space -----
- if(!MapDMABuffers())
- {
- DEBUGMSG(ZONE_ERROR, (TEXT("WAVEDEV.DLL:HardwareContext::Init() - Failed to map DMA buffers.rn")));
- bRet = FALSE;
- goto Exit;
- }
- //---- Configure the AC97 Controller
- AC97_Init();
- //----- 4. Configure the Codec -----
- InitCodec();
- //----- 5. Initialize the interrupt thread -----
- if (!InitInterruptThread())
- {
- DEBUGMSG(ZONE_ERROR, (TEXT("WAVEDEV.DLL:HardwareContext::Init() - Failed to initialize interrupt thread.rn")));
- bRet = FALSE;
- goto Exit;
- }
- //
- // Power Manager expects us to init in D0.
- // We are normally in D4 unless we are opened for play.
- // Inform the PM.
- //
- m_Dx = D0;
- //DevicePowerNotify(_T("WAV1:"),(_CEDEVICE_POWER_STATE)D4, POWER_NAME);
- RETAILMSG(1,(_T("AC97AUDIO::Init.rn")));
- Exit:
- return bRet;
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Function: MapRegisters()
- Description: Maps the config registers used by both the SPI and
- I2S controllers.
- Notes: The SPI and I2S controllers both use the GPIO config
- registers, so these MUST be initialized FIRST.
- Returns: Boolean indicating success
- -------------------------------------------------------------------*/
- BOOL HardwareContext::MapRegisters()
- {
- v_pAC97regs = (volatile AC97reg *)VirtualAlloc(0, sizeof(AC97reg), MEM_RESERVE, PAGE_NOACCESS);
- if (!v_pAC97regs)
- {
- AC97MSG(1, (TEXT("AC97reg: VirtualAlloc failed!rn")));
- return(FALSE);
- }
- if (!VirtualCopy((PVOID)v_pAC97regs, (PVOID)(AC97_BASE), sizeof(AC97reg), PAGE_READWRITE | PAGE_NOCACHE))
- {
- AC97MSG(1, (TEXT("AC97reg: VirtualCopy failed!rn")));
- return(FALSE);
- }
- v_pIOPregs = (volatile IOPreg *)VirtualAlloc(0,sizeof(IOPreg),MEM_RESERVE, PAGE_NOACCESS);
- if (!v_pIOPregs)
- {
- AC97MSG(1,(TEXT("IOPreg: VirtualAlloc failed!rn")));
- return FALSE;
- }
- if (!VirtualCopy((PVOID)v_pIOPregs,(PVOID)(IOP_BASE),sizeof(IOPreg), PAGE_READWRITE | PAGE_NOCACHE ))
- {
- AC97MSG(1,(TEXT("IOPreg: VirtualCopy failed!rn")));
- return FALSE;
- }
- v_pDMAregs = (volatile DMAreg *)VirtualAlloc(0,sizeof(DMAreg),MEM_RESERVE, PAGE_NOACCESS);
- if (!v_pDMAregs)
- {
- AC97MSG(1,(TEXT("DMAreg: VirtualAlloc failed!rn")));
- return FALSE;
- }
- if (!VirtualCopy((PVOID)v_pDMAregs,(PVOID)(DMA_BASE),sizeof(DMAreg), PAGE_READWRITE | PAGE_NOCACHE ))
- {
- AC97MSG(1,(TEXT("DMAreg: VirtualCopy failed!rn")));
- return FALSE;
- }
- s2440INT = (volatile INTreg *)VirtualAlloc(0,sizeof(INTreg),MEM_RESERVE, PAGE_NOACCESS);
- if (!v_pDMAregs)
- {
- AC97MSG(1,(TEXT("INTreg: VirtualAlloc failed!rn")));
- return FALSE;
- }
- if (!VirtualCopy((PVOID)s2440INT,(PVOID)(INT_BASE),sizeof(INTreg), PAGE_READWRITE | PAGE_NOCACHE ))
- {
- AC97MSG(1,(TEXT("INTreg: VirtualCopy failed!rn")));
- return FALSE;
- }
- g_pCLKPWRreg = (volatile CLKPWRreg *)VirtualAlloc(0,sizeof(CLKPWRreg),MEM_RESERVE, PAGE_NOACCESS);
- if (!g_pCLKPWRreg)
- {
- AC97MSG(1,(TEXT("DMAreg: VirtualAlloc failed!rn")));
- return FALSE;
- }
- if (!VirtualCopy((PVOID)g_pCLKPWRreg,(PVOID)(CLKPWR_BASE),sizeof(CLKPWRreg), PAGE_READWRITE | PAGE_NOCACHE ))
- {
- AC97MSG(1,(TEXT("DMAreg: VirtualCopy failed!rn")));
- return FALSE;
- }
- return TRUE;
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Function: Deinit()
- Description: Deinitializest the hardware: disables DMA channel(s),
- clears any pending interrupts, powers down the audio
- codec chip, etc.
- Returns: Boolean indicating success
- -------------------------------------------------------------------*/
- BOOL HardwareContext::Deinit()
- {
- //----- 1. Disable the input/output channels -----
- // AUDIO_IN_DMA_DISABLE();
- AUDIO_OUT_DMA_DISABLE();
- //----- 2. Disable/clear DMA input/output interrupts -----
- AUDIO_IN_CLEAR_INTERRUPTS();
- AUDIO_OUT_CLEAR_INTERRUPTS();
- //----- 3. Turn the audio hardware off -----
- AudioMute(DMA_CH_OUT | DMA_CH_MIC, TRUE);
- //----- 4. Unmap the control registers and DMA buffers -----
- UnmapRegisters();
- UnmapDMABuffers();
- return TRUE;
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Function: UnmapRegisters()
- Description: Unmaps the config registers used by both the SPI and
- I2S controllers.
- Notes: The SPI and I2S controllers both use the GPIO config
- registers, so these MUST be deinitialized LAST.
- Returns: Boolean indicating success
- -------------------------------------------------------------------*/
- BOOL HardwareContext::UnmapRegisters()
- {
- //----- 1. Free the fast driver-->driver calling mechanism object -----
- if(g_hUTLObject)
- {
- CloseHandle(g_hUTLObject);
- }
- return TRUE;
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Function: MapDMABuffers()
- Description: Maps the DMA buffers used for audio input/output
- on the I2S bus.
- Returns: Boolean indicating success
- -------------------------------------------------------------------*/
- BOOL HardwareContext::MapDMABuffers()
- {
- BOOL bSuccess=FALSE;
- PBYTE pTemp;
- //----- 1. Allocate a block of virtual memory big enough to hold the DMA buffers -----
- if(!(pTemp = (PBYTE)VirtualAlloc(0, AUDIO_DMA_PAGE_SIZE * 4, MEM_RESERVE, PAGE_NOACCESS)))
- {
- DEBUGMSG(ZONE_ERROR, (TEXT("WAVEDEV.DLL:HardwareContext::MapDMABuffers() - Unable to allocate memory for DMA buffers!rn")));
- goto MAP_ERROR;
- }
- //----- 2. Map the physical DMA buffer to the virtual address we just allocated -----
- if(!VirtualCopy((LPVOID)pTemp, (LPVOID)AUDIO_DMA_BUFFER_BASE, (AUDIO_DMA_PAGE_SIZE * 4),
- PAGE_READWRITE | PAGE_NOCACHE))
- {
- DEBUGMSG(ZONE_ERROR, (TEXT("WAVEDEV.DLL:HardwareContext::MapDMABuffers() - VirtualCopy() failed when binding DMA buffers.rn")));
- goto MAP_ERROR;
- }
- //----- 3. 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] = pTemp;
- m_Output_pbDMA_PAGES[1] = pTemp + AUDIO_DMA_PAGE_SIZE;
- m_Input_pbDMA_PAGES[0] = pTemp + 2*AUDIO_DMA_PAGE_SIZE;
- m_Input_pbDMA_PAGES[1] = pTemp + 3*AUDIO_DMA_PAGE_SIZE;
- return TRUE;
- MAP_ERROR:
- if(pTemp)
- VirtualFree(pTemp, 0, MEM_RELEASE);
- return FALSE;
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Function: UnmapDMABuffers()
- Description: Unmaps the DMA buffers used for audio input/output
- on the I2S 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;
- }
- void AC97_GPIO_Init()
- {
- //----- 2. Configure the GPIO pins for AC97 mode -----
- //
- // AC_SDATA_OUT - GPE4
- // AC_SDATA_IN - GPE3
- // AC_nRESET - GPE2
- // AC_BIT_CLK - GPE1
- // AC_SYNC - GPE0
- //
- // Port Init for AC97
- //PG[4:0]=AC_SDATA_OUT:AC_SDATA_IN:AC_nRESET:AC_BIT_CLK:AC_SYNC
- v_pIOPregs->rGPECON = ((v_pIOPregs->rGPECON & 0xfffffc00) | 0x3ff);
- v_pIOPregs->rGPEUP = (v_pIOPregs->rGPEUP & ~(0x1f)) | 0x1f;
- //Delay(10);
- //Sleep(5);
- }
- BOOL HardwareContext::AC97_Init()
- {
- RETAILMSG(AC97_DEBUG,(_T("WAVDEV_AC97::AC97_Init()++rn")));
- //----- 1. IMPORTANT: By default, the internal clock is disabled. To configure the controller ------
- // we must first enable it.
- g_pCLKPWRreg->rCLKCON |= AC97_INTERNAL_CLOCK_ENABLE; // Enable the CPU clock to the AC97 controller
- AC97_GPIO_Init();
- v_pAC97regs->rAC_GLBCTRL = 0;
- Delay(10); //Sleep(5);
- // Write into the AC97 Global Control Register
- //Cold Reset
- v_pAC97regs->rAC_GLBCTRL = 0x1;
- Delay(10); //Sleep(5);
- v_pAC97regs->rAC_GLBCTRL = 0x0;
- Delay(10); //Sleep(5);
- //AC-link On
- v_pAC97regs->rAC_GLBCTRL = (1<<2);
- Delay(10); //Sleep(5);
- //Transfer data enable using AC-link
- v_pAC97regs->rAC_GLBCTRL = v_pAC97regs->rAC_GLBCTRL | (1<<3);
- Delay(10); //Sleep(5);
- // Disable the Codec ready Interrupt
- v_pAC97regs->rAC_GLBCTRL = v_pAC97regs->rAC_GLBCTRL | (1<<22);
- Delay(10); //Sleep(5);
- //while (!(v_pAC97regs->rAC_GLBSTAT& 0x400000));
- RETAILMSG(AC97_DEBUG,(_T("WAVEDEV_AC97::AC97 Codec Ready!rn")));
- v_pAC97regs->rAC_GLBCTRL &= ~(0x400000); // codec ready interrupt disable
- Delay(10); //Sleep(5);
- v_pAC97regs->rAC_GLBCTRL = (v_pAC97regs->rAC_GLBCTRL & ~(0x3f<<8)) | 0x0000; // PCM_OUT=OFF,PCM_IN=OFF,MIC=OFF;
- //v_pAC97regs->rAC_GLBCTRL = (v_pAC97regs->rAC_GLBCTRL & ~(0x3f<<8)) | 0x2200; // PCM_OUT=DMA,PCM_IN=OFF,MIC=DMA;
- RETAILMSG(AC97_DEBUG,(_T("WAVDEV_AC97::AC97_Init()--rn")));
- return TRUE;
- }
- BOOL HardwareContext::Codec_channel()
- {
- if( m_InputDMARunning & m_OutputDMARunning )
- {
- RETAILMSG(AC97_DEBUG,(_T("Codec_channel() - In & Outrn")));
- WriteCodecRegister(AC97_POWER_CONTROL, AC97_PWR_D0); // ADC, DAC power up
- }
- else if( m_InputDMARunning )
- {
- RETAILMSG(AC97_DEBUG,(_T("Codec_channel() - Inrn")));
- WriteCodecRegister(AC97_POWER_CONTROL, AC97_PWR_PR1); // DAC power down
- }
- else if( m_OutputDMARunning )
- {
- RETAILMSG(AC97_DEBUG,(_T("Codec_channel() - Outrn")));
- WriteCodecRegister(AC97_POWER_CONTROL, AC97_PWR_PR0); // ADC power down
- }
- else
- {
- RETAILMSG(AC97_DEBUG,(_T("Codec_channel() - nonern")));
- WriteCodecRegister(AC97_POWER_CONTROL, AC97_PWR_PR1|AC97_PWR_PR0); // ADC/DAC power down
- }
- 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 power_up/down 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;
- AC97MSG(1, (TEXT("+++InitCodecrn")));
- // 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;
- /*
- RETAILMSG(AC97_DEBUG, (TEXT("STAC9766 Codec Vendor ID: %08x rn"), CodecVendorID));
- RETAILMSG(AC97_DEBUG, (TEXT("STAC9766 Codec Revision: %02xrn"), CodecRevision));
- 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)rn")));
- }
- */
- // 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, 0x0404 ); //0x0202); //0x0404 );
- // Mute unusing analog source except -------------------------------
- // PCBEEP_VOL - 0ah
- WriteCodecRegister( AC97_PCBEEP_VOL, 0x8000 );
- // PHONE_VOL - 0ch
- WriteCodecRegister( AC97_PHONE_VOL, 0x8000 );
- // LINEIN_VOL - 10h
- WriteCodecRegister( AC97_LINEIN_VOL, 0x8000 );
- // CD_VOL - 12h
- WriteCodecRegister( AC97_CD_VOL, 0x8000 );
- // VIDEO_VOL - 14h
- WriteCodecRegister( AC97_VIDEO_VOL, 0x8000 );
- // AUX_VOL - 16h
- WriteCodecRegister( AC97_AUX_VOL, 0x8000 );
- // write the wave out volume
- // 18h
- WriteCodecRegister( AC97_PCMOUT_VOL, 0x0505 ); //0x0000 ); //0x0606 );
- // Init MIC-IN configurations
- // 20h
- WriteCodecRegister( AC97_GENERAL_PURPOSE, 0x0000 ); //MIC1 Selected
- // 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 );
- // Now write High Pass Filter Bypass Control Register
- // 78h
- WriteCodecRegister( AC97_HPF_BYPASS, AC97_HIPASS_DISABLE );
- AC97MSG(1, (TEXT("---InitCodecrn")));
- return(TRUE);
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Function: InitOutputDMA()
- Description: Initializes the DMA channel for output.
- Notes: DMA Channel 2 is used for transmitting output sound
- data from system memory to the I2S controller.
- Returns: Boolean indicating success
- -------------------------------------------------------------------*/
- BOOL HardwareContext::InitOutputDMA()
- {
- //----- 1. Initialize the DMA channel for output mode and use the first output DMA buffer -----
- v_pDMAregs->rDISRC1 = (int)(PLAY_DMA_BUFFER_PHYS);
- v_pDMAregs->rDISRCC1 &= ~(SOURCE_PERIPHERAL_BUS | FIXED_SOURCE_ADDRESS); // Source is system bus, increment addr
- //----- 2. Initialize the DMA channel to send data over the I2S bus -----
- v_pDMAregs->rDIDST1 = (int)AC_PCMDATA_PHYS;
- //v_pDMAregs->rDIDSTC1 |= (DESTINATION_PERIPHERAL_BUS | FIXED_DESTINATION_ADDRESS); // Dest is periperal bus, fixed addr
- v_pDMAregs->rDIDSTC1 = (DESTINATION_PERIPHERAL_BUS | FIXED_DESTINATION_ADDRESS); // Dest is periperal bus, fixed addr
- //----- 3. Configure the DMA channel's transfer characteristics: handshake, sync PCLK, interrupt, -----
- // single tx, single service, I2SSDO, I2S request, no auto-reload, half-word, tx count
- v_pDMAregs->rDCON1 = ( HANDSHAKE_MODE | GENERATE_INTERRUPT | AC97PCMOUT_DMA1 | DMA_TRIGGERED_BY_HARDWARE
- #if DMA_FLAG
- // | TRANSFER_HALF_WORD | (AUDIO_DMA_PAGE_SIZE / 2 ) );
- | TRANSFER_WORD | (AUDIO_DMA_PAGE_SIZE / 4 ) );
- #else
- // | NO_DMA_AUTO_RELOAD | TRANSFER_HALF_WORD | (AUDIO_DMA_PAGE_SIZE / 2) );
- | NO_DMA_AUTO_RELOAD | TRANSFER_WORD | (AUDIO_DMA_PAGE_SIZE / 4 ) );
- #endif
- //----- 4. Reset the playback pointers -----
- AUDIO_RESET_PLAYBACK_POINTER();
- AC97MSG(1,(TEXT("---InitOutputDMAn")));
- return TRUE;
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Function: StartOutputDMA()
- Description: Starts outputting the sound data to the audio codec
- chip via DMA.
- Notes: Currently, both playback and record share the same
- DMA channel. Consequently, we can only start this
- operation if the input channel isn't using DMA.
- Returns: Boolean indicating success
- -------------------------------------------------------------------*/
- BOOL HardwareContext::StartOutputDMA()
- {
- ULONG OutputTransferred;
- AC97MSG(1,(TEXT("+++StartOutputDMAn")));
- if(!m_OutputDMARunning && (m_Dx == D0) )
- // if(!m_OutputDMARunning)
- {
- //----- 1. Initialize our buffer counters -----
- m_OutputDMARunning=TRUE;
- m_OutBytes[OUT_BUFFER_A]=m_OutBytes[OUT_BUFFER_B]=0;
- //----- 2. Prime the output buffer with sound data -----
- //m_OutputDMAStatus = (DMA_DONEA | DMA_DONEB) & ~DMA_BIU;
- //RETAILMSG(1,(_T("dmastat = %xrn"), m_OutputDMAStatus));
- m_OutputDMAStatus = (DMA_DONEA | DMA_DONEB) & ~DMA_BIU;
- OutputTransferred = TransferOutputBuffers(m_OutputDMAStatus);
- //----- 3. If we did transfer any data to the DMA buffers, go ahead and enable DMA -----
- if(OutputTransferred)
- {
- //----- 4. Configure the DMA channel for playback -----
- if(!InitOutputDMA())
- {
- DEBUGMSG(ZONE_ERROR, (TEXT("HardwareContext::StartOutputDMA() - Unable to initialize output DMA channel!rn")));
- goto START_ERROR;
- }
- #if DMA_FLAG
- v_pAC97regs->rAC_GLBCTRL = (v_pAC97regs->rAC_GLBCTRL & ~(0x3<<12)) | (0x2<<12); // 0x2 = DMA
- #else
- v_pAC97regs->rAC_GLBCTRL = (v_pAC97regs->rAC_GLBCTRL & ~(0x3<<12)) | (0x1<<12); // 0x1 = PIO
- #endif
- //----- 5. Make sure the audio isn't muted -----
- AudioMute(DMA_CH_OUT, FALSE);
- //----- 6. Start the DMA controller -----
- AUDIO_RESET_PLAYBACK_POINTER();
- SELECT_AUDIO_DMA_OUTPUT_BUFFER_A();
- Codec_channel(); // Turn ON output channel
- // charlie, start A buffer
- AUDIO_OUT_DMA_ENABLE();
- #if DMA_FLAG
- // wait for DMA to start.
- delay_count = 0;
- while((v_pDMAregs->rDSTAT1&0xfffff)==0){
- RETAILMSG(1,(_T("1")));
- #if WAIT_DMA_END
- Sleep(1);
- #else
- if( delay_count++ > DELAY_COUNT ) break;
- #endif
- }
- // change the buffer pointer
- SELECT_AUDIO_DMA_OUTPUT_BUFFER_B();
- // Set DMA for B Buffer
- #endif
- }
- else // We didn't transfer any data, so DMA wasn't enabled
- {
- m_OutputDMARunning=FALSE;
- }
- }
- AC97MSG(1,(TEXT("---StartOutputDMAn")));
- return TRUE;
- START_ERROR:
- return FALSE;
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Function: StopOutputDMA()
- Description: Stops any DMA activity on the output channel.
- Returns: Boolean indicating success
- -------------------------------------------------------------------*/
- void HardwareContext::StopOutputDMA()
- {
- AC97MSG(1,(_T("StopOutputDMA()++rn")));
- // jylee,040220
- // you should do this sleep operation for AC-Link operation.
- Sleep(1);
- //----- 1. If the output DMA is running, stop it -----
- if (m_OutputDMARunning)
- {
- m_OutputDMAStatus = DMA_CLEAR;
- AUDIO_OUT_DMA_DISABLE();
- AUDIO_OUT_CLEAR_INTERRUPTS();
- v_pAC97regs->rAC_GLBCTRL = (v_pAC97regs->rAC_GLBCTRL & ~(0x3<<12)) | (0x0<<12); // 0x0 = OFF
- AudioMute(DMA_CH_OUT, TRUE);
- }
- m_OutputDMARunning = FALSE;
- Codec_channel();
- /*
- // jylee, 040220
- // Clear AC97 PCMDATA FIFO.
- for (int i=0; i<AC97_PCMDATA_FIFO_LENGTH;i++)
- {
- v_pAC97regs->rAC_PCMDATA = 0x00000000;
- }
- */
- AC97MSG(1,(_T("StopOutputDMA()--rn")));
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Function: InitInputDMA()
- Description: Initializes the DMA channel for input.
- Notes: ***** NOT IMPLEMENTED *****
- The following routine is not implemented due to a
- hardware bug in the revision of the Samsung SC2440
- CPU this driver was developed on. See the header
- at the top of this file for details.
- Returns: Boolean indicating success
- -------------------------------------------------------------------*/
- BOOL HardwareContext::InitInputDMA()
- {
- //goto INIT_ERROR;
- AC97MSG(1,(TEXT("+++InitInputDMAn")));
- //============================ Configure DMA Channel 1 ===========================
- //------ On platforms with the revsion of the Samsung SC2440 CPU with the IIS SLAVE bug fix, this -----
- // code can be used to configure DMA channel 1 for input.
- //----- 1. Initialize the DMA channel for input mode and use the first input DMA buffer -----
- v_pDMAregs->rDISRC2 = (int)AC_MICDATA_PHYS;
- v_pDMAregs->rDISRCC2 = (SOURCE_PERIPHERAL_BUS | FIXED_SOURCE_ADDRESS); // Source is periperal bus, fixed addr
- //----- 2. Initialize the DMA channel to receive data over the I2S bus -----
- v_pDMAregs->rDIDST2 = (int)(RECORD_DMA_BUFFER_PHYS); //(AUDIO_DMA_BUFFER_PHYS);
- v_pDMAregs->rDIDSTC2 &= ~(DESTINATION_PERIPHERAL_BUS | FIXED_DESTINATION_ADDRESS); // Destination is system bus, increment addr
- //----- 3. Configure the DMA channel's transfer characteristics: handshake, sync PCLK, interrupt, -----
- // single tx, single service, I2SSDI, I2S request, no auto-reload, half-word, tx count
- v_pDMAregs->rDCON2 = ( HANDSHAKE_MODE | GENERATE_INTERRUPT | AC97MICIN_DMA2 | DMA_TRIGGERED_BY_HARDWARE
- #if DMA_FLAG
- #if (INCHANNELS==2)
- | TRANSFER_WORD | (AUDIO_DMA_PAGE_SIZE / 4) );
- #else
- | TRANSFER_HALF_WORD | (AUDIO_DMA_PAGE_SIZE / 2) );
- #endif
- #else /* DMA_FLAG */
- | NO_DMA_AUTO_RELOAD | TRANSFER_WORD | (AUDIO_DMA_PAGE_SIZE / 4) );
- //| NO_DMA_AUTO_RELOAD | TRANSFER_HALF_WORD | (AUDIO_DMA_PAGE_SIZE / 2) );
- #endif /* DMA_FLAG */
- return TRUE;
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Function: StartInputDMA()
- Description: Starts inputting the recorded sound data from the
- audio codec chip via DMA.
- Notes: ***** NOT IMPLEMENTED *****
- The following routine is not implemented due to a
- hardware bug in the revision of the Samsung SC2440
- CPU this driver was developed on. See the header
- at the top of this file for details.
- Returns: Boolean indicating success
- -------------------------------------------------------------------*/
- BOOL HardwareContext::StartInputDMA()
- {
- //------ On platforms with the revsion of the Samsung SC2440 CPU with the IIS SLAVE bug fix, this -----
- // code can be used to configure DMA channel 1 for input.
- AC97MSG(1,(TEXT("+++StartInputDMAn")));
- if(!m_InputDMARunning)
- {
- //----- 1. Initialize our buffer counters -----
- m_InputDMARunning=TRUE;
- Codec_channel(); // Turn On Input channel
- m_InBytes[IN_BUFFER_A]=m_InBytes[IN_BUFFER_B]=0;
- //----- 2. Prime the output buffer with sound data -----
- m_InputDMAStatus = (DMA_DONEA | DMA_DONEB) & ~DMA_BIU;
- //----- 3. Configure the DMA channel for record -----
- if(!InitInputDMA())
- {
- DEBUGMSG(ZONE_ERROR, (TEXT("HardwareContext::StartInputDMA() - Unable to initialize input DMA channel!rn")));
- goto START_ERROR;
- }
- #if DMA_FLAG
- v_pAC97regs->rAC_GLBCTRL = (v_pAC97regs->rAC_GLBCTRL & ~(0x3<<8)) | (0x2<<8); // 0x2 = DMA
- #else
- v_pAC97regs->rAC_GLBCTRL = (v_pAC97regs->rAC_GLBCTRL & ~(0x3<<8)) | (0x1<<8); // 0x1 = PIO
- #endif
- //----- 4. Make sure the audio isn't muted -----
- AudioMute(DMA_CH_MIC, FALSE);
- //----- 5. Start the input DMA -----
- AUDIO_RESET_RECORD_POINTER();
- SELECT_AUDIO_DMA_INPUT_BUFFER_A();
- Codec_channel(); // Turn On Input channel
- v_pDMAregs->rDMASKTRIG2 = ENABLE_DMA_CHANNEL;
- #if DMA_FLAG
- // wait for DMA to start.
- delay_count = 0;
- while((v_pDMAregs->rDSTAT2&0xfffff)==0){
- RETAILMSG(1,(_T("2")));
- #if WAIT_DMA_END
- Sleep(1);
- #else
- if( delay_count++ > DELAY_COUNT ) break;
- #endif
- }
- // change the buffer pointer
- SELECT_AUDIO_DMA_INPUT_BUFFER_B();
- #endif
- }
- AC97MSG(1,(TEXT("---StartInputDMAn")));
- return TRUE;
- START_ERROR:
- return FALSE;
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Function: StopInputDMA()
- Description: Stops any DMA activity on the input channel.
- Notes: ***** NOT IMPLEMENTED *****
- The following routine is not implemented due to a
- hardware bug in the revision of the Samsung SC2440
- CPU this driver was developed on. See the header
- at the top of this file for details.
- Returns: Boolean indicating success
- -------------------------------------------------------------------*/
- void HardwareContext::StopInputDMA()
- {
- //------ On platforms with the revsion of the Samsung SC2440 CPU with the IIS SLAVE bug fix, this -----
- // code can be used to configure DMA channel 1 for input.
- //----- 1. If the output DMA is running, stop it -----
- if (m_InputDMARunning)
- {
- AUDIO_IN_DMA_DISABLE(); // jylee
- AUDIO_IN_CLEAR_INTERRUPTS();
- m_InputDMAStatus = DMA_CLEAR;
- v_pAC97regs->rAC_GLBCTRL = (v_pAC97regs->rAC_GLBCTRL & ~(0x3<<8)) | (0x0<<8); // 0x0 = OFF
- AudioMute(DMA_CH_MIC, TRUE);
- }
- m_InputDMARunning = FALSE;
- Codec_channel();
- }
- DWORD HardwareContext::GetInterruptThreadPriority()
- {
- HKEY hDevKey;
- DWORD dwValType;
- DWORD dwValLen;
- DWORD dwPrio = 249; // Default priority
- hDevKey = OpenDeviceKey((LPWSTR)m_DriverIndex);
- if (hDevKey)
- {
- dwValLen = sizeof(DWORD);
- RegQueryValueEx(
- hDevKey,
- TEXT("Priority256"),
- NULL,
- &dwValType,
- (PUCHAR)&dwPrio,
- &dwValLen);
- RegCloseKey(hDevKey);
- }
- return dwPrio;
- }
- /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
- // SetForceSpeaker is called from the device context to update the state of the
- // m_bForceSpeaker variable.
- /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
- DWORD HardwareContext::ForceSpeaker( BOOL bForceSpeaker )
- {
- // If m_NumForcedSpeaker is non-zero, audio should be routed to an
- // external speaker (if hw permits).
- if (bForceSpeaker)
- {
- m_NumForcedSpeaker++;
- if (m_NumForcedSpeaker==1)
- {
- RecalcSpeakerEnable();
- }
- }
- else
- {
- m_NumForcedSpeaker--;
- if (m_NumForcedSpeaker==0)
- {
- RecalcSpeakerEnable();
- }
- }
- return MMSYSERR_NOERROR;
- }
- // Control the hardware speaker enable
- void HardwareContext::SetSpeakerEnable(BOOL bEnable)
- {
- // Code to turn speaker on/off here
- return;
- }
- /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
- // RecalcSpeakerEnable decides whether to enable the speaker or not.
- // For now, it only looks at the m_bForceSpeaker variable, but it could
- // also look at whether the headset is plugged in
- // and/or whether we're in a voice call. Some mechanism would
- // need to be implemented to inform the wave driver of changes in the state of
- // these variables however.
- /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
- void HardwareContext::RecalcSpeakerEnable()
- {
- SetSpeakerEnable(m_NumForcedSpeaker);
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Function: InitInterruptThread()
- Description: Initializes the IST for handling DMA interrupts.
- Returns: Boolean indicating success
- -------------------------------------------------------------------*/
- BOOL HardwareContext::InitInterruptThread()
- {
- BOOL bSuccess;
- m_hAudioInterrupt = CreateEvent( NULL, FALSE, FALSE, NULL);
- if (!m_hAudioInterrupt)
- {
- return FALSE;
- }
- bSuccess = InterruptInitialize(m_IntrAudio, m_hAudioInterrupt, NULL, 0);
- m_hAudioInterruptThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL,
- 0,
- (LPTHREAD_START_ROUTINE)CallInterruptThread,
- this,
- 0,
- NULL);
- if (!m_hAudioInterruptThread)
- {
- return FALSE;
- }
- // Bump up the priority since the interrupt must be serviced immediately.
- CeSetThreadPriority(m_hAudioInterruptThread, GetInterruptThreadPriority());
- return TRUE;
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Function: PowerUp()
- Description: Powers up the audio codec chip.
- Notes: Currently, this function is unimplemented because
- the audio codec chip is ONLY powered up when the
- user wishes to play or record. The AudioMute() function
- handles the powerup sequence.
- Returns: Boolean indicating success
- -------------------------------------------------------------------*/
- void HardwareContext::PowerUp()
- {
- RETAILMSG(1,(_T("AC97:PowerUP()rn")));
- AC97_Init();
- //AC97_GPIO_Init();
- InitCodec();
- //AudioMute(DMA_CH_OUT, FALSE); // 030711
- // setup DMA output
- //InitOutputDMA();
- //AudioMute((DMA_CH_OUT | DMA_CH_MIC), FALSE);
- AudioMute(DMA_CH_OUT, FALSE);
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Function: PowerDown()
- Description: Powers down the audio codec chip.
- Notes: Even if the input/output channels are muted, this
- function powers down the audio codec chip in order
- to conserve battery power.
- Returns: Boolean indicating success
- -------------------------------------------------------------------*/
- void HardwareContext::PowerDown()
- {
- RETAILMSG(1,(_T("AC97:PowerDown()rn")));
- //StopOutputDMA();
- m_OutputDMAStatus = DMA_CLEAR;
- AUDIO_OUT_DMA_DISABLE();
- AUDIO_OUT_CLEAR_INTERRUPTS();
- v_pAC97regs->rAC_GLBCTRL = (v_pAC97regs->rAC_GLBCTRL & ~(0x3<<12)) | (0x0<<12); // 0x0 = OFF
- //AudioMute(DMA_CH_OUT, TRUE);
- m_OutputDMARunning = FALSE;
- m_InputDMARunning = FALSE;
- AudioMute((DMA_CH_OUT | DMA_CH_MIC), TRUE);
- }
- //############################################ Helper Functions #############################################
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Function: TransferOutputBuffer()
- Description: Retrieves the next "mixed" audio buffer of data to
- DMA into the output channel.
- Returns: Number of bytes needing to be transferred.
- -------------------------------------------------------------------*/
- ULONG HardwareContext::TransferOutputBuffer(ULONG NumBuf)
- {
- ULONG BytesTransferred = 0;
- PBYTE pBufferStart = m_Output_pbDMA_PAGES[NumBuf];
- PBYTE pBufferEnd = pBufferStart + AUDIO_DMA_PAGE_SIZE;
- PBYTE pBufferLast;
- __try
- {
- pBufferLast = m_OutputDeviceContext.TransferBuffer(pBufferStart, pBufferEnd,NULL);
- BytesTransferred = m_OutBytes[NumBuf] = pBufferLast-pBufferStart;
- // Enable if you need to clear the rest of the DMA buffer
- StreamContext::ClearBuffer(pBufferLast,pBufferEnd);
- //memset(pBufferStart, 0, AUDIO_DMA_PAGE_SIZE);
- if(NumBuf == OUT_BUFFER_A) // Output Buffer A
- {
- m_OutputDMAStatus &= ~DMA_DONEA;
- m_OutputDMAStatus |= DMA_STRTA;
- }
- else // Output Buffer B
- {
- m_OutputDMAStatus &= ~DMA_DONEB;
- m_OutputDMAStatus |= DMA_STRTB;
- }
- }
- __except(EXCEPTION_EXECUTE_HANDLER)
- {
- DEBUGMSG(ZONE_ERROR, (TEXT("WAVDEV2.DLL:TransferOutputBuffer() - EXCEPTION: %d"), GetExceptionCode()));
- }
- return BytesTransferred;
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Function: TransferOutputBuffers()
- Description: Determines which output buffer (A or B) needs to
- be filled with sound data. The correct buffer is
- then populated with data and ready to DMA to the
- output channel.
- Returns: Boolean indicating success
- -------------------------------------------------------------------*/
- ULONG HardwareContext::TransferOutputBuffers(DWORD dwDCSR)
- {
- ULONG BytesTransferred = 0;
- ULONG BytesTotal;
- DWORD Bits = dwDCSR & (DMA_DONEA|DMA_DONEB|DMA_BIU);
- switch (Bits)
- {
- case 0:
- case DMA_BIU:
- // No done bits set- must not be my interrupt
- return 0;
- case DMA_DONEA|DMA_DONEB|DMA_BIU:
- // Load B, then A
- BytesTransferred = TransferOutputBuffer(OUT_BUFFER_B);
- // fall through
- case DMA_DONEA: // This should never happen!
- case DMA_DONEA|DMA_BIU:
- BytesTransferred += TransferOutputBuffer(OUT_BUFFER_A); // charlie, A => B
- break;
- case DMA_DONEA|DMA_DONEB:
- // Load A, then B
- BytesTransferred = TransferOutputBuffer(OUT_BUFFER_A);
- #if DMA_FLAG
- // charlie
- BytesTransferred += TransferOutputBuffer(OUT_BUFFER_B);
- break; // charlie
- #endif
- // fall through
- case DMA_DONEB|DMA_BIU: // This should never happen!
- case DMA_DONEB:
- // Load B
- BytesTransferred += TransferOutputBuffer(OUT_BUFFER_B); // charlie, B => A
- break;
- }
- // If it was our interrupt, but we weren't able to transfer any bytes
- // (e.g. no full buffers ready to be emptied)
- // and all the output DMA buffers are now empty, then stop the output DMA
- BytesTotal = m_OutBytes[OUT_BUFFER_A]+m_OutBytes[OUT_BUFFER_B];
- if (BytesTotal==0)
- {
- StopOutputDMA();
- }
- return BytesTransferred;
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Function: TransferInputBuffer()
- Description: Retrieves the chunk of recorded sound data and inputs
- it into an audio buffer for potential "mixing".
- Returns: Number of bytes needing to be transferred.
- -------------------------------------------------------------------*/
- ULONG HardwareContext::TransferInputBuffer(ULONG NumBuf)
- {
- ULONG BytesTransferred = 0;
- PBYTE pBufferStart = m_Input_pbDMA_PAGES[NumBuf];
- PBYTE pBufferEnd = pBufferStart + AUDIO_DMA_PAGE_SIZE;
- PBYTE pBufferLast;
- __try
- {
- pBufferLast = m_InputDeviceContext.TransferBuffer(pBufferStart, pBufferEnd,NULL);
- BytesTransferred = m_InBytes[NumBuf] = pBufferLast-pBufferStart;
- if(NumBuf == IN_BUFFER_A) // Input Buffer A
- {
- m_InputDMAStatus &= ~DMA_DONEA;
- m_InputDMAStatus |= DMA_STRTA;
- }
- else // Input Buffer B
- {
- m_InputDMAStatus &= ~DMA_DONEB;
- m_InputDMAStatus |= DMA_STRTB;
- }
- }
- __except(EXCEPTION_EXECUTE_HANDLER)
- {
- DEBUGMSG(ZONE_ERROR, (TEXT("WAVDEV2.DLL:TransferInputBuffer() - EXCEPTION: %d"), GetExceptionCode()));
- }
- return BytesTransferred;
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Function: TransferInputBuffers()
- Description: Determines which input buffer (A or B) needs to
- be filled with recorded sound data. The correct
- buffer is then populated with recorded sound data
- from the input channel.
- Returns: Boolean indicating success
- -------------------------------------------------------------------*/
- ULONG HardwareContext::TransferInputBuffers(DWORD dwDCSR)
- {
- ULONG BytesTransferred=0;
- DWORD Bits = dwDCSR & (DMA_DONEA|DMA_DONEB|DMA_BIU);
- switch (Bits)
- {
- case 0:
- case DMA_BIU:
- // No done bits set- must not be my interrupt
- return 0;
- case DMA_DONEA|DMA_DONEB|DMA_BIU:
- // Load B, then A
- BytesTransferred = TransferInputBuffer(IN_BUFFER_B);
- // fall through
- case DMA_DONEA: // This should never happen!
- case DMA_DONEA|DMA_BIU:
- // Load A
- BytesTransferred += TransferInputBuffer(IN_BUFFER_A);
- break;
- case DMA_DONEA|DMA_DONEB:
- // Load A, then B
- BytesTransferred = TransferInputBuffer(IN_BUFFER_A);
- #if 0 //DMA_FLAG
- BytesTransferred += TransferInputBuffer(IN_BUFFER_B);
- break;
- #endif
- // fall through
- case DMA_DONEB|DMA_BIU: // This should never happen!
- case DMA_DONEB:
- // Load B
- BytesTransferred += TransferInputBuffer(IN_BUFFER_B);
- break;
- }
- // If it was our interrupt, but we weren't able to transfer any bytes
- // (e.g. no empty buffers ready to be filled)
- // Then stop the input DMA
- if (BytesTransferred==0)
- {
- StopInputDMA();
- }
- return BytesTransferred;
- }
- void HardwareContext::InterruptThread()
- {
- ULONG InputTransferred, OutputTransferred;
- BOOL dmaInterruptSource = 0;
- // Fast way to access embedded pointers in wave headers in other processes.
- SetProcPermissions((DWORD)-1);
- while(TRUE)
- {
- WaitForSingleObject(m_hAudioInterrupt, INFINITE);
- AC97MSG(1,(TEXT("0x%xn"),s2440INT->rINTMSK));
- AC97MSG(1,(TEXT("startn")));
- dmaInterruptSource = 0;
- //----- 1. Grab the lock -----
- Lock();
- __try
- {
- AC97MSG(1,(TEXT("tryn")));
- //----- 3. Determine the interrupt source (input DMA operation or output DMA operation?) -----
- //----- NOTE: Often, platforms use two separate DMA channels for input/output operations but
- // have the OAL return SYSINTR_AUDIO as the interrupt source. If this is the case,
- // then the interrupt source (input or output DMA channel) must be determined in
- // this step.
- // charlie, determine the interrupt source
- // s2440INT->rSRCPND
- if( s2440INT->rINTMSK & BIT_DMA1 ){
- dmaInterruptSource |= DMA_CH_OUT; // Output DMA is supported...
- }
- if( s2440INT->rINTMSK & BIT_DMA2 ){
- dmaInterruptSource |= DMA_CH_MIC; // Input DMA is supported...
- }
- // For determine the interrupt source
- //----- 2. Acknowledge the DMA interrupt -----
- InterruptDone(m_IntrAudio);
- if ( m_Dx != D0 ) continue;
- //----- 4. Handle any interrupts on the input source -----
- // NOTE: The InterruptDone() call below automatically clears the interrupt.
- // if((m_InputDMARunning) && (dmaInterruptSource == DMA_CH_MIC))
- if((dmaInterruptSource == DMA_CH_MIC))
- {
- //----- Determine which buffer just completed the DMA transfer -----
- if(m_InputDMAStatus & DMA_BIU)
- {
- m_InputDMAStatus &= ~DMA_STRTB; // Buffer B just completed...
- m_InputDMAStatus |= DMA_DONEB;
- m_InputDMAStatus &= ~DMA_BIU; // Buffer A is in use
- #if DMA_FLAG
- SELECT_AUDIO_DMA_INPUT_BUFFER_B();
- #else
- SELECT_AUDIO_DMA_INPUT_BUFFER_A();
- #endif
- AC97MSG(1,(TEXT("1n")));
- }else
- {
- m_InputDMAStatus &= ~DMA_STRTA; // Buffer A just completed...
- m_InputDMAStatus |= DMA_DONEA;
- m_InputDMAStatus |= DMA_BIU; // Buffer B is in use
- #if DMA_FLAG
- SELECT_AUDIO_DMA_INPUT_BUFFER_A();
- #else
- SELECT_AUDIO_DMA_INPUT_BUFFER_B();
- #endif
- AC97MSG(1,(TEXT("2n")));
- }
- #if !DMA_FLAG
- //----- 5. Schedule the next DMA transfer -----
- AUDIO_IN_DMA_ENABLE();
- #endif
- //----- 6. Retrieve the next chunk of recorded data from the non-playing buffer -----
- InputTransferred = TransferInputBuffers(m_InputDMAStatus);
- }
- //----- 7. Handle any interrupts on the output source -----
- // NOTE: The InterruptDone() call below automatically clears the interrupt.
- // if((m_OutputDMARunning) && (dmaInterruptSource == DMA_CH_OUT))
- // if((dmaInterruptSource == DMA_CH_OUT))
- else
- {
- //----- Determine which buffer just completed the DMA transfer -----
- if(m_OutputDMAStatus & DMA_BIU)
- {
- //RETAILMSG(DMA_CHK,(_T("BBrn")));
- m_OutputDMAStatus &= ~DMA_STRTB; // Buffer A just completed...
- m_OutputDMAStatus |= DMA_DONEB;
- m_OutputDMAStatus &= ~DMA_BIU; // Buffer B is in use
- delay_count = 0;
- while((v_pDMAregs->rDSTAT1&0xfffff)==0){
- RETAILMSG(1,(_T("3")));
- #if WAIT_DMA_END
- Sleep(1);
- #else
- if( delay_count++ > DELAY_COUNT ) break;
- #endif
- }
- #if DMA_FLAG
- SELECT_AUDIO_DMA_OUTPUT_BUFFER_B(); // charlie. B => A
- #else
- SELECT_AUDIO_DMA_OUTPUT_BUFFER_A(); // charlie. B => A
- #endif
- }else
- {
- //RETAILMSG(DMA_CHK,(_T("AArn")));
- m_OutputDMAStatus &= ~DMA_STRTA; // Buffer B just completed...
- m_OutputDMAStatus |= DMA_DONEA;
- m_OutputDMAStatus |= DMA_BIU; // Buffer A is in use
- delay_count = 0;
- while((v_pDMAregs->rDSTAT1&0xfffff)==0)
- {
- RETAILMSG(1,(_T("4")));
- #if WAIT_DMA_END
- Sleep(1);
- #else
- if( delay_count++ > DELAY_COUNT ) break;
- #endif
- }
- #if DMA_FLAG
- SELECT_AUDIO_DMA_OUTPUT_BUFFER_A(); // charlie. B => A
- #else
- SELECT_AUDIO_DMA_OUTPUT_BUFFER_B(); // charlie. B => A
- #endif
- }
- #if !DMA_FLAG
- //----- 8. Schedule the next DMA transfer -----
- AUDIO_OUT_DMA_ENABLE();
- #endif
- //----- 9. Fill the non-playing buffer with the next chunk of audio data to play -----
- OutputTransferred = TransferOutputBuffers(m_OutputDMAStatus);
- }
- }
- __except(EXCEPTION_EXECUTE_HANDLER)
- {
- DEBUGMSG(ZONE_ERROR, (TEXT("WAVDEV2.DLL:InterruptThread() - EXCEPTION: %d"), GetExceptionCode()));
- }
- //----- 10. Give up the lock -----
- Unlock();
- }
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Function: AudioMute()
- Description: Mutes/unmutes the specified audio channel.
- Notes: If both audio channels are MUTED, then the chip
- is powered down to conserve battery life.
- Alternatively, if either audio channel is unMUTED,
- the chip is powered up.
- Returns: Boolean indicating success
- -------------------------------------------------------------------*/
- BOOL HardwareContext::AudioMute(DWORD channel, BOOL bMute)
- {
- static DWORD dwActiveChannel = 0;
- USHORT volume;
- //
- // Turn off/on mute bit in volume control register.
- //
- if( (channel & DMA_CH_OUT ) && !m_OutputDMARunning ) // 030711
- {
- if(bMute)
- {
- volume = ReadCodecRegister(AC97_HEADPHONE_VOL);
- WriteCodecRegister(AC97_HEADPHONE_VOL, volume | 0x8000);
- }
- else
- {
- volume = ReadCodecRegister(AC97_HEADPHONE_VOL);
- WriteCodecRegister(AC97_HEADPHONE_VOL, volume & ~0x8000);
- }
- }
- if( (channel & DMA_CH_MIC ) && !m_InputDMARunning )
- {
- if(bMute)
- {
- volume = ReadCodecRegister(AC97_MIC_VOL);
- WriteCodecRegister(AC97_MIC_VOL, volume | 0x8000);
- }
- else
- {
- volume = ReadCodecRegister(AC97_MIC_VOL);
- WriteCodecRegister(AC97_MIC_VOL, volume & ~0x8000);
- }
- }
- return TRUE;
- }
- void CallInterruptThread(HardwareContext *pHWContext)
- {
- pHWContext->InterruptThread();
- }
- DWORD
- HardwareContext::Open(
- void
- )
- {
- DWORD mmErr = MMSYSERR_NOERROR;
- // Don't allow play when not on, if there is a power constraint upon us.
- if ( D0 != m_Dx )
- {
- // Tell the Power Manager we need to power up.
- // If there is a power constraint then fail.
- DWORD dwErr = DevicePowerNotify(_T("WAV1:"), D0, POWER_NAME);
- if ( ERROR_SUCCESS != dwErr ) {
- RETAILMSG(1, (TEXT("AC97::Open:DevicePowerNotify ERROR: %urn"), dwErr ));
- mmErr = MMSYSERR_ERROR;
- }
- }
- return mmErr;
- }
- DWORD
- HardwareContext::Close(
- void
- )
- {
- DWORD mmErr = MMSYSERR_NOERROR;
- /*
- DWORD dwErr;
- // we are done so inform Power Manager to power us down, 030711
- // dwErr = DevicePowerNotify(_T("WAV1:"), (_CEDEVICE_POWER_STATE)D4, POWER_NAME);
- if ( ERROR_SUCCESS != dwErr ) {
- RETAILMSG(1, (TEXT("AC97::Close:DevicePowerNofify ERROR: %urn"), dwErr ));
- mmErr = MMSYSERR_ERROR;
- }
- */
- return mmErr;
- }
- BOOL
- HardwareContext::IOControl(
- DWORD dwOpenData,
- DWORD dwCode,
- PBYTE pBufIn,
- DWORD dwLenIn,
- PBYTE pBufOut,
- DWORD dwLenOut,
- PDWORD pdwActualOut)
- {
- DWORD dwErr = ERROR_SUCCESS;
- BOOL bRc = TRUE;
- UNREFERENCED_PARAMETER(dwOpenData);
- switch (dwCode) {
- //
- // Power Management
- //
- case IOCTL_POWER_CAPABILITIES:
- {
- PPOWER_CAPABILITIES ppc;
- RETAILMSG(1,(_T("IOCTL_POWER_CAPABILITIES++rn")));
- if ( !pdwActualOut || !pBufOut || (dwLenOut < sizeof(POWER_CAPABILITIES)) ) {
- bRc = FALSE;
- dwErr = ERROR_INVALID_PARAMETER;
- break;
- }
- ppc = (PPOWER_CAPABILITIES)pBufOut;
- memset(ppc, 0, sizeof(POWER_CAPABILITIES));
- // support D0, D4
- ppc->DeviceDx = 0x11;
- // no wake
- // no inrush
- // Report our nominal power consumption in uAmps rather than mWatts.
- ppc->Flags = POWER_CAP_PREFIX_MICRO | POWER_CAP_UNIT_AMPS;
- // REVIEW: Do we enable all these for normal playback?
- // D0: SPI + I2S + CODEC (Playback) + Headphone=
- // 0.5 mA + 0.5 mA + (23 mW, into BUGBUG ohms ) + (30 mW, into 32 ohms)
- // 500 uA + 500 uA + 23000 uA + 32000 uA
- ppc->Power[D0] = 56000;
- *pdwActualOut = sizeof(POWER_CAPABILITIES);
- RETAILMSG(1,(_T("IOCTL_POWER_CAPABILITIES--rn")));
- } break;
- case IOCTL_POWER_SET:
- bRc = TRUE;
- break;
- /*
- {
- CEDEVICE_POWER_STATE NewDx;
- RETAILMSG(1,(_T("IOCTL_POWER_SET++rn")));
- if ( !pdwActualOut || !pBufOut || (dwLenOut < sizeof(CEDEVICE_POWER_STATE)) ) {
- bRc = FALSE;
- dwErr = ERROR_INVALID_PARAMETER;
- break;
- }
- NewDx = *(PCEDEVICE_POWER_STATE)pBufOut;
- if ( VALID_DX(NewDx) ) {
- // grab the CS since the normal Xxx_PowerXxx can not.
- Lock();
- switch ( NewDx ) {
- case D0:
- if (m_Dx != D0) {
- PowerUp();
- m_Dx = D0;
- }
- break;
- default:
- if (m_Dx != (_CEDEVICE_POWER_STATE)D4) {
- PowerDown();
- m_Dx = (_CEDEVICE_POWER_STATE)D4;
- }
- break;
- }
- // return our state
- *(PCEDEVICE_POWER_STATE)pBufOut = m_Dx;
- RETAILMSG(1, (TEXT("AC97AUDIO: IOCTL_POWER_SET: D%u => D%u rn"), NewDx, m_Dx));
- Unlock();
- *pdwActualOut = sizeof(CEDEVICE_POWER_STATE);
- } else {
- bRc = FALSE;
- dwErr = ERROR_INVALID_PARAMETER;
- }
- RETAILMSG(1,(_T("IOCTL_POWER_SET--rn")));
- } break;
- */
- case IOCTL_POWER_GET:
- RETAILMSG(1,(_T("IOCTL_POWER_GET++rn")));
- if ( !pdwActualOut || !pBufOut || (dwLenOut < sizeof(CEDEVICE_POWER_STATE)) ) {
- bRc = FALSE;
- dwErr = ERROR_INVALID_PARAMETER;
- break;
- }
- *(PCEDEVICE_POWER_STATE)pBufOut = m_Dx;
- RETAILMSG(1, (TEXT("AC97AUDIO: IOCTL_POWER_GET: D%u rn"), m_Dx));
- *pdwActualOut = sizeof(CEDEVICE_POWER_STATE);
- RETAILMSG(1,(_T("IOCTL_POWER_GET++rn")));
- break;
- default:
- bRc = FALSE;
- dwErr = ERROR_INVALID_FUNCTION;
- DEBUGMSG (ZONE_FUNCTION, (TEXT(" Unsupported ioctl 0x%Xrn"), dwCode));
- break;
- }
- if ( !bRc ) {
- SetLastError(dwErr);
- }
- return(bRc);
- }