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

📄 hwctxt.cpp

📁 SBC2410 WinCE 5.0 BSP.绝大多数驱动已经调通。
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//
// 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 ******
				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.

-*/

#include "wavemain.h"
#include <s2410.h>
#include "dma.h"
#include "I2S.h"
#include "tlv320ac.h"
#include "utldrv.h"
#include "hwctxt.h"
#include <p2.h>

#define DMA_FLAG 1
#define DMA_CH_MIC 2
#define DMA_CH_OUT 1

#define L3M (0x04)	// TOUT2
#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		*g_pIISregs		= NULL;		// I2S control registers
volatile IOPreg		*g_pIOPregs		= NULL;		// GPIO registers (needed to enable I2S and SPI)
volatile SSPreg		*g_pSPIregs     = NULL;		// SPI control registers

volatile DMAreg		*g_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 	*s2410INT 		= NULL;
				
UTL_FASTCALL    g_tblFastCall;							// Needed for fast driver->driver calling mechanism
HANDLE          g_hUTLObject		= INVALID_HANDLE_VALUE;

HardwareContext *g_pHWContext		= NULL;
//----------------------------------------------------------------------------------------

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
}; 
// charlie
void _WrL3Addr(unsigned char data)
{	
    int i,j;

    g_pIOPregs->rGPBDAT &= ~(L3D|L3M|L3C);		//L3D=L/L3M=L(in address mode)/L3C=L
    g_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'
	{
	    g_pIOPregs->rGPBDAT &= ~L3C;	            //L3C=L
	    g_pIOPregs->rGPBDAT |= L3D;	            //L3D=H		    
	    for(j=0;j<10;j++);	                    //tcy(L3) > 500ns
	    g_pIOPregs->rGPBDAT |= L3C;	            //L3C=H
	    g_pIOPregs->rGPBDAT |= L3D;	            //L3D=H
	    for(j=0;j<10;j++);	                    //tcy(L3) > 500ns
	}
	else		                                //if data's LSB is 'L'
	{
	    g_pIOPregs->rGPBDAT &= ~L3C;	            //L3C=L
	    g_pIOPregs->rGPBDAT &= ~L3D;	            //L3D=L
	    for(j=0;j<10;j++);	                    //tcy(L3) > 500ns
	    g_pIOPregs->rGPBDAT |= L3C;	            //L3C=H
	    g_pIOPregs->rGPBDAT &= ~L3D;	            //L3D=L
	    for(j=0;j<10;j++);	                    //tcy(L3) > 500ns
	}
	data >>=1;
    }
    g_pIOPregs->rGPBDAT|=L3C|L3M;	            //L3M=H,L3C=H
}


void _WrL3Data(unsigned char data,int halt)
{
    int i,j;

    if(halt)
    {
        g_pIOPregs->rGPBDAT|=L3C;	            //L3C=H(while tstp, L3 interface halt condition)
        for(j=0;j<10;j++);                       //tstp(L3) > 190ns
    }

    g_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'
        {
	    g_pIOPregs->rGPBDAT &= ~L3C;	            //L3C=L
            g_pIOPregs->rGPBDAT |= L3D;	        //L3D=H
            for(j=0;j<10;j++);	                //tcy(L3) > 500ns
            g_pIOPregs->rGPBDAT |= (L3C|L3D);    //L3C=H,L3D=H
            for(j=0;j<10;j++);	                //tcy(L3) > 500ns
        }
        else		//if data's LSB is 'L'
        {
	    g_pIOPregs->rGPBDAT &= ~L3C;	            //L3C=L
	    g_pIOPregs->rGPBDAT &= ~L3D;	            //L3D=L
            for(j=0;j<10;j++);	                //tcy(L3) > 500ns
            g_pIOPregs->rGPBDAT |= L3C;	        //L3C=H
	    g_pIOPregs->rGPBDAT &= ~L3D;	            //L3D=L
            for(j=0;j<10;j++);	                //tcy(L3) > 500ns
        }
        data>>=1;	//for check next bit
    }
    
    g_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.\r\n")));
        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")));
        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.\r\n")));
        goto Exit;
    }
    m_Initialized=TRUE;

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()
{

	// IIS registers.
	//
    g_pIISregs = (volatile IISreg *)VirtualAlloc(0, sizeof(IISreg), MEM_RESERVE, PAGE_NOACCESS);
	if (!g_pIISregs)
	{
		DEBUGMSG(1, (TEXT("IISreg: VirtualAlloc failed!\r\n")));
		return(FALSE);
	}
	if (!VirtualCopy((PVOID)g_pIISregs, (PVOID)(IIS_BASE), sizeof(IISreg), PAGE_READWRITE | PAGE_NOCACHE))
	{
		DEBUGMSG(1, (TEXT("IISreg: VirtualCopy failed!\r\n")));
		return(FALSE);
	}

	// SPI registers.
	//
    g_pSPIregs = (volatile SSPreg *)VirtualAlloc(0, sizeof(SSPreg), MEM_RESERVE, PAGE_NOACCESS);
	if (!g_pSPIregs)
	{
		DEBUGMSG(1, (TEXT("SPIreg: VirtualAlloc failed!\r\n")));
		return(FALSE);
	}
	if (!VirtualCopy((PVOID)g_pSPIregs, (PVOID)(SSP_BASE), sizeof(SSPreg), PAGE_READWRITE | PAGE_NOCACHE))
	{
		DEBUGMSG(1, (TEXT("SPIreg: VirtualCopy failed!\r\n")));
		return(FALSE);
	}

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

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

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

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

	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;

⌨️ 快捷键说明

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