⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hwctxt.cpp

📁 wince5.0 BSP包
💻 CPP
📖 第 1 页 / 共 4 页
字号:
//
// 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.\r\n")));
		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.\r\n")));
		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.\r\n")));
		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.\r\n")));    
    
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!\r\n")));
		return(FALSE);
	}
	if (!VirtualCopy((PVOID)v_pAC97regs, (PVOID)(AC97_BASE), sizeof(AC97reg), PAGE_READWRITE | PAGE_NOCACHE))
	{
		AC97MSG(1, (TEXT("AC97reg: VirtualCopy failed!\r\n")));
		return(FALSE);
	}

	v_pIOPregs = (volatile IOPreg *)VirtualAlloc(0,sizeof(IOPreg),MEM_RESERVE, PAGE_NOACCESS);
	if (!v_pIOPregs)
	{
		AC97MSG(1,(TEXT("IOPreg: VirtualAlloc failed!\r\n")));
		return FALSE;
	}
	if (!VirtualCopy((PVOID)v_pIOPregs,(PVOID)(IOP_BASE),sizeof(IOPreg), PAGE_READWRITE | PAGE_NOCACHE ))
	{
		AC97MSG(1,(TEXT("IOPreg: VirtualCopy failed!\r\n")));
		return FALSE;
	}

	v_pDMAregs = (volatile DMAreg *)VirtualAlloc(0,sizeof(DMAreg),MEM_RESERVE, PAGE_NOACCESS);
	if (!v_pDMAregs)
	{
		AC97MSG(1,(TEXT("DMAreg: VirtualAlloc failed!\r\n")));
		return FALSE;
	}
	if (!VirtualCopy((PVOID)v_pDMAregs,(PVOID)(DMA_BASE),sizeof(DMAreg), PAGE_READWRITE | PAGE_NOCACHE ))
	{
		AC97MSG(1,(TEXT("DMAreg: VirtualCopy failed!\r\n")));
		return FALSE;
	}

	s2440INT = (volatile INTreg *)VirtualAlloc(0,sizeof(INTreg),MEM_RESERVE, PAGE_NOACCESS);
	if (!v_pDMAregs)
	{
		AC97MSG(1,(TEXT("INTreg: VirtualAlloc failed!\r\n")));
		return FALSE;
	}
	if (!VirtualCopy((PVOID)s2440INT,(PVOID)(INT_BASE),sizeof(INTreg), PAGE_READWRITE | PAGE_NOCACHE ))
	{
		AC97MSG(1,(TEXT("INTreg: VirtualCopy failed!\r\n")));
		return FALSE;
	}

	g_pCLKPWRreg = (volatile CLKPWRreg *)VirtualAlloc(0,sizeof(CLKPWRreg),MEM_RESERVE, PAGE_NOACCESS);
	if (!g_pCLKPWRreg)
	{
		AC97MSG(1,(TEXT("DMAreg: VirtualAlloc failed!\r\n")));
		return FALSE;
	}
	if (!VirtualCopy((PVOID)g_pCLKPWRreg,(PVOID)(CLKPWR_BASE),sizeof(CLKPWRreg), PAGE_READWRITE | PAGE_NOCACHE ))
	{
		AC97MSG(1,(TEXT("DMAreg: VirtualCopy failed!\r\n")));
		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!\r\n")));
		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.\r\n")));
		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 -----
	//		   

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -