hwctxt.cpp
资源名称:SMDK2440.rar [点击查看]
上传用户:qiulin1960
上传日期:2013-10-16
资源大小:2844k
文件大小:52k
源码类别:
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 SC2410 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 SC2410 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 Catfish Reference Platform:
- Hardware - Samsung SC2410 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 "I2S.h"
- #include "utldrv.h"
- #include "hwctxt.h"
- //#define DMA_FLAG 1
- //#define DEBUGMSG(a,b) RETAILMSG(0,b)
- #define DMA_CH_MIC 2
- #define DMA_CH_OUT 1
- #define DELAY_COUNT 0x100000
- #define L3M (0x04) // TOUT2 // charlie
- #define L3C (0x10) // TCLK0
- #define L3D (0x08) // TOUT3
- //----- Macro used to send commands to the audio codec chip over the SPI bus -----
- // NOTE: The command format is 16 bits: bits[15-9] = register
- // bits[8-0] = data command
- //
- // Refer to the TILV320AC reference guide for details.
- //
- //#define SEND_CODEC_COMMAND(reg, dat) { SPI_SendWord((reg | dat)); }
- int rec_mode=0;
- //-------------------------------- Global Variables --------------------------------------
- volatile IISreg *v_pIISregs = NULL; // I2S 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;
- UTL_FASTCALL g_tblFastCall; // Needed for fast driver->driver calling mechanism
- HANDLE g_hUTLObject = INVALID_HANDLE_VALUE;
- HardwareContext *g_pHWContext = NULL;
- unsigned int delay_count;
- //----------------------------------------------------------------------------------------
- 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
- };
- void dump_audio_input_sfr(void);
- // charlie
- void _WrL3Addr(unsigned char data)
- {
- int i,j;
- v_pIOPregs->rGPBDAT &= ~(L3D|L3M|L3C); //L3D=L/L3M=L(in address mode)/L3C=L
- v_pIOPregs->rGPBDAT |= L3C; //L3C=H
- for(j=0;j<10;j++); //tsu(L3) > 190ns
- //PD[8:6]=L3D:L3C:L3M
- for(i=0;i<8;i++) //LSB first
- {
- if(data&0x1) //if data's LSB is 'H'
- {
- v_pIOPregs->rGPBDAT &= ~L3C; //L3C=L
- v_pIOPregs->rGPBDAT |= L3D; //L3D=H
- for(j=0;j<10;j++); //tcy(L3) > 500ns
- v_pIOPregs->rGPBDAT |= L3C; //L3C=H
- v_pIOPregs->rGPBDAT |= L3D; //L3D=H
- for(j=0;j<10;j++); //tcy(L3) > 500ns
- }
- else //if data's LSB is 'L'
- {
- v_pIOPregs->rGPBDAT &= ~L3C; //L3C=L
- v_pIOPregs->rGPBDAT &= ~L3D; //L3D=L
- for(j=0;j<10;j++); //tcy(L3) > 500ns
- v_pIOPregs->rGPBDAT |= L3C; //L3C=H
- v_pIOPregs->rGPBDAT &= ~L3D; //L3D=L
- for(j=0;j<10;j++); //tcy(L3) > 500ns
- }
- data >>=1;
- }
- v_pIOPregs->rGPBDAT|=L3C|L3M; //L3M=H,L3C=H
- }
- void _WrL3Data(unsigned char data,int halt)
- {
- int i,j;
- if(halt)
- {
- v_pIOPregs->rGPBDAT|=L3C; //L3C=H(while tstp, L3 interface halt condition)
- for(j=0;j<10;j++); //tstp(L3) > 190ns
- }
- v_pIOPregs->rGPBDAT|=L3C|L3M; //L3M=H(in data transfer mode)
- for(j=0;j<10;j++); //tsu(L3)D > 190ns
- //PD[8:6]=L3D:L3C:L3M
- for(i=0;i<8;i++)
- {
- if(data&0x1) //if data's LSB is 'H'
- {
- v_pIOPregs->rGPBDAT &= ~L3C; //L3C=L
- v_pIOPregs->rGPBDAT |= L3D; //L3D=H
- for(j=0;j<10;j++); //tcy(L3) > 500ns
- v_pIOPregs->rGPBDAT |= (L3C|L3D); //L3C=H,L3D=H
- for(j=0;j<10;j++); //tcy(L3) > 500ns
- }
- else //if data's LSB is 'L'
- {
- v_pIOPregs->rGPBDAT &= ~L3C; //L3C=L
- v_pIOPregs->rGPBDAT &= ~L3D; //L3D=L
- for(j=0;j<10;j++); //tcy(L3) > 500ns
- v_pIOPregs->rGPBDAT |= L3C; //L3C=H
- v_pIOPregs->rGPBDAT &= ~L3D; //L3D=L
- for(j=0;j<10;j++); //tcy(L3) > 500ns
- }
- data>>=1; //for check next bit
- }
- v_pIOPregs->rGPBDAT|=L3C|L3M; //L3M=H,L3C=H
- }
- 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);
- m_Initialized=FALSE;
- }
- HardwareContext::~HardwareContext()
- {
- DeleteCriticalSection(&m_Lock);
- }
- BOOL HardwareContext::Init(DWORD Index)
- {
- if (m_Initialized)
- {
- return FALSE;
- }
- //----- 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")));
- 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")));
- goto Exit;
- }
- //----- 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")));
- goto Exit;
- }
- m_Initialized=TRUE;
- //
- // 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);
- Exit:
- return m_Initialized;
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 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()
- {
- DWORD dwBytes;
- v_pIISregs = (volatile IISreg *)VirtualAlloc(0,sizeof(IISreg),MEM_RESERVE, PAGE_NOACCESS);
- if (!v_pIISregs)
- {
- DEBUGMSG(1,(TEXT("IISreg: VirtualAlloc failed!rn")));
- return FALSE;
- }
- if (!VirtualCopy((PVOID)v_pIISregs,(PVOID)(IIS_BASE),sizeof(IISreg), PAGE_READWRITE | PAGE_NOCACHE ))
- {
- DEBUGMSG(1,(TEXT("IISreg: VirtualCopy failed!rn")));
- return FALSE;
- }
- v_pIOPregs = (volatile IOPreg *)VirtualAlloc(0,sizeof(IOPreg),MEM_RESERVE, PAGE_NOACCESS);
- if (!v_pIOPregs)
- {
- DEBUGMSG(1,(TEXT("IOPreg: VirtualAlloc failed!rn")));
- return FALSE;
- }
- if (!VirtualCopy((PVOID)v_pIOPregs,(PVOID)(IOP_BASE),sizeof(IOPreg), PAGE_READWRITE | PAGE_NOCACHE ))
- {
- DEBUGMSG(1,(TEXT("IOPreg: VirtualCopy failed!rn")));
- return FALSE;
- }
- v_pDMAregs = (volatile DMAreg *)VirtualAlloc(0,sizeof(DMAreg),MEM_RESERVE, PAGE_NOACCESS);
- if (!v_pDMAregs)
- {
- DEBUGMSG(1,(TEXT("DMAreg: VirtualAlloc failed!rn")));
- return FALSE;
- }
- if (!VirtualCopy((PVOID)v_pDMAregs,(PVOID)(DMA_BASE),sizeof(DMAreg), PAGE_READWRITE | PAGE_NOCACHE ))
- {
- DEBUGMSG(1,(TEXT("DMAreg: VirtualCopy failed!rn")));
- return FALSE;
- }
- s2440INT = (volatile INTreg *)VirtualAlloc(0,sizeof(INTreg),MEM_RESERVE, PAGE_NOACCESS);
- if (!v_pDMAregs)
- {
- DEBUGMSG(1,(TEXT("INTreg: VirtualAlloc failed!rn")));
- return FALSE;
- }
- if (!VirtualCopy((PVOID)s2440INT,(PVOID)(INT_BASE),sizeof(INTreg), PAGE_READWRITE | PAGE_NOCACHE ))
- {
- DEBUGMSG(1,(TEXT("INTreg: VirtualCopy failed!rn")));
- return FALSE;
- }
- g_pCLKPWRreg = (volatile CLKPWRreg *)VirtualAlloc(0,sizeof(CLKPWRreg),MEM_RESERVE, PAGE_NOACCESS);
- if (!g_pCLKPWRreg)
- {
- DEBUGMSG(1,(TEXT("DMAreg: VirtualAlloc failed!rn")));
- return FALSE;
- }
- if (!VirtualCopy((PVOID)g_pCLKPWRreg,(PVOID)(CLKPWR_BASE),sizeof(CLKPWRreg), PAGE_READWRITE | PAGE_NOCACHE ))
- {
- DEBUGMSG(1,(TEXT("DMAreg: VirtualCopy failed!rn")));
- return FALSE;
- }
- PowerUp();
- return TRUE;
- MAP_ERROR:
- return FALSE;
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 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();
- // v_pIISregs->rIISCON &= ~RECEIVE_DMA_REQUEST_ENABLE;
- // v_pIISregs->rIISFCON &= ~( RECEIVE_FIFO_ACCESS_DMA | RECEIVE_FIFO_ENABLE);
- // v_pDMAregs->rDMASKTRIG1 |= STOP_DMA_TRANSFER;
- // v_pDMAregs->rDMASKTRIG1 &= ~ENABLE_DMA_CHANNEL;;
- //AUDIO_OUT_DMA_DISABLE();
- v_pDMAregs->rDMASKTRIG2 |= STOP_DMA_TRANSFER;
- v_pDMAregs->rDMASKTRIG2 &= ~ENABLE_DMA_CHANNEL;
- //----- 2. Disable/clear DMA input/output interrupts -----
- //AUDIO_IN_CLEAR_INTERRUPTS();
- v_pDMAregs->rDCON1 = v_pDMAregs->rDCON1;
- //AUDIO_OUT_CLEAR_INTERRUPTS();
- v_pDMAregs->rDCON2 = v_pDMAregs->rDCON2;
- //----- 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;
- }
- BOOL HardwareContext::Codec_channel()
- {
- //****** Port B Initialize *****
- v_pIOPregs->rGPBDAT |= L3M|L3C; //start condition : L3M=H, L3C=H
- v_pIOPregs->rGPBUP |= 0x1c; //pull-up disable
- v_pIOPregs->rGPBCON = ((v_pIOPregs->rGPBCON & 0x3ffc0f) | 0x000150);
- _WrL3Addr(0x14+2); //STATUS (000101xx+10)
- if( m_InputDMARunning & m_OutputDMARunning )
- _WrL3Data(0xa3,0); //1,0,0,0,0,0,01 : OGS=0,IGS=0,ADC_NI,DAC_NI,sngl speed,AoffDon
- else if( m_InputDMARunning )
- _WrL3Data(0xa2,0); //1,0,0,0,0,0,01 : OGS=0,IGS=0,ADC_NI,DAC_NI,sngl speed,AoffDon
- else if( m_OutputDMARunning )
- _WrL3Data(0xa1,0); //1,0,0,0,0,0,01 : OGS=0,IGS=0,ADC_NI,DAC_NI,sngl speed,AoffDon
- else
- _WrL3Data(0xa0,0); //1,0,0,0,0,0,01 : OGS=0,IGS=0,ADC_NI,DAC_NI,sngl speed,AoffDon
- 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()
- {
- int i;
- // int mode =0; // play
- DEBUGMSG(1,(TEXT("+++InitCodecn")));
- //****** Port B Initialize *****
- v_pIOPregs->rGPBDAT |= L3M|L3C; //start condition : L3M=H, L3C=H
- v_pIOPregs->rGPBUP |= 0x1c; //pull-up disable
- v_pIOPregs->rGPBCON = ((v_pIOPregs->rGPBCON & 0x3ffc0f) | 0x000150);
- /****** L3 Interface ******/
- #if (AUDIO_CODEC_CLOCK == 256) // test value
- RETAILMSG(1,(TEXT("256 clockn")));
- _WrL3Addr(0x14+2); //STATUS (000101xx+10)
- _WrL3Data(0x60,0); //0,1,10,000,0 : reset,256fs,no DCfilter,iis
- _WrL3Addr(0x14+2); //STATUS (000101xx+10)
- _WrL3Data(0x20,0); //0,0,10,000,0 : no reset,256fs,no DCfilter,iis
- _WrL3Addr(0x14+2); //STATUS (000101xx+10)
- _WrL3Data(0xa1,0); //1,0,0,0,0,0,01 : OGS=0,IGS=0,ADC_NI,DAC_NI,sngl speed,AoffDon
- #else
- RETAILMSG(1,(TEXT("384 clockn")));
- _WrL3Addr(0x14+2); //STATUS (000101xx+10)
- _WrL3Data(0x50,0); //0,1,01,000,0 : reset,384fs,no DCfilter,iis
- _WrL3Addr(0x14+2); //STATUS (000101xx+10)
- _WrL3Data(0x10,0); //0,0,01,000,0 : no reset,384fs,no DCfilter,iis
- _WrL3Addr(0x14+2); //STATUS (000101xx+10)
- _WrL3Data(0xa1,0); ///1,0,0,0,0,0,01 : OGS=0,IGS=0,ADC_NI,DAC_NI,sngl speed,AoffDon
- #endif
- _WrL3Addr(0x14 + 0); //DATA0 (000101xx+00)
- _WrL3Data(0xc2,0); //11000,010 : DATA0, Extended addr(010)
- _WrL3Data(0x4d,0); //010,011,01 : DATA0, MS=9dB, Ch1=on Ch2=off,
- 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()
- {
- int tmp;
- //----- 1. Initialize the DMA channel for output mode and use the first output DMA buffer -----
- v_pDMAregs->rDISRC2 = (int)(AUDIO_DMA_BUFFER_PHYS);
- v_pDMAregs->rDISRCC2 &= ~(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->rDIDST2 = (int)IISFIF_PHYS;
- v_pDMAregs->rDIDSTC2 |= (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->rDCON2 = ( HANDSHAKE_MODE | GENERATE_INTERRUPT | I2SSDO_DMA2 | DMA_TRIGGERED_BY_HARDWARE
- | TRANSFER_HALF_WORD | (AUDIO_DMA_PAGE_SIZE / 2 ) );
- //----- 4. Reset the playback pointers -----
- //AUDIO_RESET_PLAYBACK_POINTER();
- ioPlaybackPointerLow = (AUDIO_DMA_BUFFER_PHYS);
- ioPlaybackPointerHigh = (AUDIO_DMA_BUFFER_PHYS + AUDIO_DMA_PAGE_SIZE);
- DEBUGMSG(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()
- {
- //RETAILMSG(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;
- ULONG 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;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // To correct left/right channel on ouput stream,
- // You should reset IISCON[0] bit.
- Lock();
- v_pIISregs->rIISCON &= ~IIS_INTERFACE_ENABLE;
- v_pIISregs->rIISCON |= TRANSMIT_DMA_REQUEST_ENABLE;
- v_pIISregs->rIISCON &= ~TRANSMIT_IDLE_CMD;
- v_pIISregs->rIISFCON |= ( TRANSMIT_FIFO_ACCESS_DMA | TRANSMIT_FIFO_ENABLE );
- v_pIISregs->rIISMOD |= IIS_TRANSMIT_MODE;
- v_pIISregs->rIISCON |= IIS_INTERFACE_ENABLE;
- Unlock();
- ////////////////////////////////////////////////////////////////////////////////
- //----- 5. Make sure the audio isn't muted -----
- AudioMute(DMA_CH_OUT, FALSE);
- //----- 6. Start the DMA controller -----
- //AUDIO_RESET_PLAYBACK_POINTER();
- ioPlaybackPointerLow = (AUDIO_DMA_BUFFER_PHYS);
- ioPlaybackPointerHigh = (AUDIO_DMA_BUFFER_PHYS + AUDIO_DMA_PAGE_SIZE);
- //SELECT_AUDIO_DMA_OUTPUT_BUFFER_A();
- v_pDMAregs->rDISRC2 = (int)(AUDIO_DMA_BUFFER_PHYS);
- Codec_channel(); // Turn ON output channel
- // charlie, start A buffer
- //AUDIO_OUT_DMA_ENABLE();
- v_pDMAregs->rDMASKTRIG2 &= ~STOP_DMA_TRANSFER;
- v_pDMAregs->rDMASKTRIG2 |= ENABLE_DMA_CHANNEL;
- // wait for DMA to start.
- delay_count = 0;
- while((v_pDMAregs->rDSTAT2&0xfffff)==0){
- if( delay_count++ > DELAY_COUNT ) break;
- }
- // change the buffer pointer
- //SELECT_AUDIO_DMA_OUTPUT_BUFFER_B();
- v_pDMAregs->rDISRC2 = (int)(AUDIO_DMA_BUFFER_PHYS+AUDIO_DMA_PAGE_SIZE);
- // Set DMA for B Buffer
- }
- else // We didn't transfer any data, so DMA wasn't enabled
- {
- m_OutputDMARunning=FALSE;
- }
- }
- DEBUGMSG(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()
- {
- //----- 1. If the output DMA is running, stop it -----
- if (m_OutputDMARunning)
- {
- m_OutputDMAStatus = DMA_CLEAR;
- //AUDIO_OUT_DMA_DISABLE();
- v_pDMAregs->rDMASKTRIG2 |= STOP_DMA_TRANSFER;
- v_pDMAregs->rDMASKTRIG2 &= ~ENABLE_DMA_CHANNEL;
- //AUDIO_OUT_CLEAR_INTERRUPTS();
- v_pDMAregs->rDCON2 = v_pDMAregs->rDCON2;
- v_pIISregs->rIISCON &= ~TRANSMIT_DMA_REQUEST_ENABLE;
- v_pIISregs->rIISCON |= TRANSMIT_IDLE_CMD;
- v_pIISregs->rIISFCON &= ~( TRANSMIT_FIFO_ACCESS_DMA | TRANSMIT_FIFO_ENABLE );
- v_pIISregs->rIISMOD &= ~IIS_TRANSMIT_MODE;
- AudioMute(DMA_CH_OUT, TRUE);
- }
- m_OutputDMARunning = FALSE;
- Codec_channel();
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 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 SC2410
- 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;
- DEBUGMSG(1,(TEXT("+++InitInputDMAn")));
- //============================ Configure DMA Channel 1 ===========================
- //------ On platforms with the revsion of the Samsung SC2410 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->rDISRC1 = (int)IISFIF_PHYS;
- v_pDMAregs->rDISRCC1 = (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->rDIDST1 = (int)(AUDIO_DMA_BUFFER_PHYS);
- v_pDMAregs->rDIDSTC1 &= ~(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->rDCON1 = ( HANDSHAKE_MODE | GENERATE_INTERRUPT | I2SSDI_DMA1 | DMA_TRIGGERED_BY_HARDWARE
- | TRANSFER_HALF_WORD | (AUDIO_DMA_PAGE_SIZE / 2) );
- return TRUE;
- INIT_ERROR:
- return FALSE;
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 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 SC2410
- CPU this driver was developed on. See the header
- at the top of this file for details.
- Returns: Boolean indicating success
- -------------------------------------------------------------------*/
- BOOL HardwareContext::StartInputDMA()
- {
- int tmp;
- //goto START_ERROR;
- //------ On platforms with the revsion of the Samsung SC2410 CPU with the IIS SLAVE bug fix, this -----
- // code can be used to configure DMA channel 1 for input.
- DEBUGMSG(1,(_T("StartInputDMA()++rn")));
- 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;
- }
- v_pIISregs->rIISCON |= RECEIVE_DMA_REQUEST_ENABLE;
- v_pIISregs->rIISCON &= ~RECEIVE_IDLE_CMD;
- v_pIISregs->rIISFCON |= ( RECEIVE_FIFO_ACCESS_DMA | RECEIVE_FIFO_ENABLE);
- v_pIISregs->rIISMOD |= IIS_RECEIVE_MODE;
- //----- 4. Make sure the audio isn't muted -----
- AudioMute(DMA_CH_MIC, FALSE);
- //----- 5. Start the input DMA -----
- //AUDIO_RESET_RECORD_POINTER();
- ioRecordPointerLow = (RECORD_DMA_BUFFER_PHYS);
- ioRecordPointerHigh = (RECORD_DMA_BUFFER_PHYS+ AUDIO_DMA_PAGE_SIZE);
- //SELECT_AUDIO_DMA_INPUT_BUFFER_A();
- v_pDMAregs->rDIDST1 = (int)(AUDIO_DMA_BUFFER_PHYS+2*AUDIO_DMA_PAGE_SIZE);
- Codec_channel(); // Turn On Input channel
- v_pDMAregs->rDMASKTRIG1 &= ~STOP_DMA_TRANSFER;
- v_pDMAregs->rDMASKTRIG1 |= ENABLE_DMA_CHANNEL;
- // wait for DMA to start.
- delay_count = 0;
- while((v_pDMAregs->rDSTAT2&0xfffff)==0){
- if( delay_count++ > DELAY_COUNT ) break;
- }
- // change the buffer pointer
- //SELECT_AUDIO_DMA_INPUT_BUFFER_B();
- v_pDMAregs->rDIDST1 = (int)(AUDIO_DMA_BUFFER_PHYS+3*AUDIO_DMA_PAGE_SIZE);
- }
- DEBUGMSG(1,(_T("StartInputDMA()--rn")));
- 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 SC2410
- 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 SC2410 CPU with the IIS SLAVE bug fix, this -----
- // code can be used to configure DMA channel 1 for input.
- DEBUGMSG(1,(_T("StopInputDMA()++rn")));
- //----- 1. If the output DMA is running, stop it -----
- if (m_InputDMARunning)
- {
- m_InputDMAStatus = DMA_CLEAR;
- v_pIISregs->rIISCON &= ~RECEIVE_DMA_REQUEST_ENABLE;
- v_pIISregs->rIISCON |= RECEIVE_IDLE_CMD;
- v_pIISregs->rIISFCON &= ~( RECEIVE_FIFO_ACCESS_DMA | RECEIVE_FIFO_ENABLE);
- v_pIISregs->rIISMOD &= ~IIS_RECEIVE_MODE;
- v_pDMAregs->rDMASKTRIG1 |= STOP_DMA_TRANSFER;
- v_pDMAregs->rDMASKTRIG1 &= ~ENABLE_DMA_CHANNEL;
- // AUDIO_IN_DMA_DISABLE();
- // v_pIISregs->rIISCON &= ~RECEIVE_DMA_REQUEST_ENABLE;
- // v_pIISregs->rIISFCON &= ~( RECEIVE_FIFO_ACCESS_DMA | RECEIVE_FIFO_ENABLE);
- // v_pDMAregs->rDMASKTRIG1 |= STOP_DMA_TRANSFER;
- //AUDIO_IN_CLEAR_INTERRUPTS();
- v_pDMAregs->rDCON1 = v_pDMAregs->rDCON1;
- AudioMute(DMA_CH_MIC, TRUE);
- }
- m_InputDMARunning = FALSE;
- Codec_channel();
- DEBUGMSG(1,(_T("StopInputDMA()--rn")));
- }
- 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()
- {
- // SPI_Init();
- I2S_Init();
- AudioMute((DMA_CH_OUT | DMA_CH_MIC), FALSE); // 030711
- }
- /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 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()
- {
- StopOutputDMA();
- 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);
- 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);
- DEBUGMSG(1,(TEXT("%xn"),Bits));
- 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);
- // charlie
- BytesTransferred += TransferOutputBuffer(OUT_BUFFER_B);
- break; // charlie
- // 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)
- {
- int tmp;
- 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);
- int tmp;
- 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);
- BytesTransferred += TransferInputBuffer(IN_BUFFER_B);
- break;
- // 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;
- int tmp;
- BOOL dmaInterruptSource = 0;
- // Fast way to access embedded pointers in wave headers in other processes.
- SetProcPermissions((DWORD)-1);
- while(TRUE)
- {
- WaitForSingleObject(m_hAudioInterrupt, INFINITE);
- DEBUGMSG(1,(TEXT("0x%xn"),s2440INT->rINTMSK));
- DEBUGMSG(1,(TEXT("startn")));
- dmaInterruptSource = 0;
- //----- 1. Grab the lock -----
- Lock();
- __try
- {
- DEBUGMSG(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
- if( s2440INT->rINTMSK & BIT_DMA1 ){
- dmaInterruptSource |= DMA_CH_MIC; // Input DMA is supported...
- }
- if( s2440INT->rINTMSK & BIT_DMA2 ){
- dmaInterruptSource |= DMA_CH_OUT; // Output 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
- //SELECT_AUDIO_DMA_INPUT_BUFFER_B();
- v_pDMAregs->rDIDST1 = (int)(AUDIO_DMA_BUFFER_PHYS+3*AUDIO_DMA_PAGE_SIZE);
- DEBUGMSG(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
- //SELECT_AUDIO_DMA_INPUT_BUFFER_A();
- v_pDMAregs->rDIDST1 = (int)(AUDIO_DMA_BUFFER_PHYS+2*AUDIO_DMA_PAGE_SIZE);
- DEBUGMSG(1,(TEXT("2n")));
- }
- /*
- //----- 5. Schedule the next DMA transfer -----
- //AUDIO_IN_DMA_ENABLE();
- v_pDMAregs->rDMASKTRIG1 |= ENABLE_DMA_CHANNEL;
- v_pDMAregs->rDMASKTRIG1 &= ~STOP_DMA_TRANSFER;
- v_pIISregs->rIISFCON |= ( RECEIVE_FIFO_ACCESS_DMA | RECEIVE_FIFO_ENABLE);
- v_pIISregs->rIISCON |= RECEIVE_DMA_REQUEST_ENABLE;
- */
- //----- 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)
- {
- 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->rDSTAT2&0xfffff)==0){
- if( delay_count++ > DELAY_COUNT ) break;
- }
- //SELECT_AUDIO_DMA_OUTPUT_BUFFER_B(); // charlie. B => A
- v_pDMAregs->rDISRC2 = (int)(AUDIO_DMA_BUFFER_PHYS+AUDIO_DMA_PAGE_SIZE);
- }else
- {
- 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->rDSTAT2&0xfffff)==0){
- if( delay_count++ > DELAY_COUNT ) break;
- }
- //SELECT_AUDIO_DMA_OUTPUT_BUFFER_A(); // charlie. B => A
- v_pDMAregs->rDISRC2 = (int)(AUDIO_DMA_BUFFER_PHYS);
- }
- //----- 8. Schedule the next DMA transfer -----
- //AUDIO_OUT_DMA_ENABLE();
- //v_pDMAregs->rDMASKTRIG2 &= ~STOP_DMA_TRANSFER;
- //v_pDMAregs->rDMASKTRIG2 |= ENABLE_DMA_CHANNEL;
- //----- 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;
- DEBUGMSG(1,(TEXT("Mute:%dn"),bMute));
- //
- // Turn off/on mute bit in control register B.
- //
- if( !m_InputDMARunning && !m_OutputDMARunning ) // 030711
- {
- if(bMute)
- {
- _WrL3Addr(0x14+0); //DATA0 (000101xx+00)
- _WrL3Data(0xa4,0); //mute
- }
- else
- {
- _WrL3Addr(0x14+0); //DATA0,
- _WrL3Data(0xa0,0); //no mute
- }
- }
- 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("WAVEDEV::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("WAVEDEV::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;
- 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);
- } break;
- case IOCTL_POWER_SET:
- {
- CEDEVICE_POWER_STATE NewDx;
- 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("WAVEDEV: IOCTL_POWER_SET: D%u => D%u rn"), NewDx, m_Dx));
- Unlock();
- *pdwActualOut = sizeof(CEDEVICE_POWER_STATE);
- } else {
- bRc = FALSE;
- dwErr = ERROR_INVALID_PARAMETER;
- }
- } break;
- case IOCTL_POWER_GET:
- if ( !pdwActualOut || !pBufOut || (dwLenOut < sizeof(CEDEVICE_POWER_STATE)) ) {
- bRc = FALSE;
- dwErr = ERROR_INVALID_PARAMETER;
- break;
- }
- *(PCEDEVICE_POWER_STATE)pBufOut = m_Dx;
- RETAILMSG(1, (TEXT("WAVEDEV: IOCTL_POWER_GET: D%u rn"), m_Dx));
- *pdwActualOut = sizeof(CEDEVICE_POWER_STATE);
- break;
- default:
- bRc = FALSE;
- dwErr = ERROR_INVALID_FUNCTION;
- DEBUGMSG (ZONE_FUNCTION, (TEXT(" Unsupported ioctl 0x%Xrn"), dwCode));
- break;
- }
- if ( !bRc ) {
- SetLastError(dwErr);
- }
- return(bRc);
- }