hwctxt.cpp

来自「S3C24A0的完整BSP包,对开发此芯片的开发者很有用.」· C++ 代码 · 共 1,380 行 · 第 1/3 页

CPP
1,380
字号
//
// 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 SC24A0 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 <s3c24A0.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 DBG_AUDIO 0


#define L3M (1<<17)	// GPIO17
#define L3C (1<<16)	// GPIO16
#define L3D (1<<15)	// GPIO15

//----- 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 S3C24A0_IISBUS_REG 	*g_pIISregs		= NULL;		// I2S control registers
volatile S3C24A0_IOPORT_REG 	*g_pIOPregs		= NULL;		// GPIO registers (needed to enable I2S and SPI)
volatile S3C24A0_SPI_REG		*g_pSPIregs     = NULL;		// SPI control registers

volatile S3C24A0_DMA_REG 		*g_pDMA0regs	= NULL;		// DMA0 registers audio in (needed for I/O on I2S bus)
volatile S3C24A0_DMA_REG 		*g_pDMA2regs	= NULL;		// DMA1 registers audio out (needed for I/O on I2S bus)
volatile S3C24A0_CLKPWR_REG 	*g_pCLKPWRreg	= NULL;		// Clock power registers (needed to enable I2S and SPI clocks)
volatile S3C24A0_INTR_REG 	*s24A0INT 		= 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->GPDAT &= ~(L3D|L3M|L3C);		//L3D=L/L3M=L(in address mode)/L3C=L
    g_pIOPregs->GPDAT |= 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->GPDAT &= ~L3C;	            //L3C=L
	    g_pIOPregs->GPDAT |= L3D;	            //L3D=H		    
	    for(j=0;j<10;j++);	                    //tcy(L3) > 500ns
	    g_pIOPregs->GPDAT |= L3C;	            //L3C=H
	    g_pIOPregs->GPDAT |= L3D;	            //L3D=H
	    for(j=0;j<10;j++);	                    //tcy(L3) > 500ns
	}
	else		                                //if data's LSB is 'L'
	{
	    g_pIOPregs->GPDAT &= ~L3C;	            //L3C=L
	    g_pIOPregs->GPDAT &= ~L3D;	            //L3D=L
	    for(j=0;j<10;j++);	                    //tcy(L3) > 500ns
	    g_pIOPregs->GPDAT |= L3C;	            //L3C=H
	    g_pIOPregs->GPDAT &= ~L3D;	            //L3D=L
	    for(j=0;j<10;j++);	                    //tcy(L3) > 500ns
	}
	data >>=1;
    }
    g_pIOPregs->GPDAT|=L3C|L3M;	            //L3M=H,L3C=H
}


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

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

    g_pIOPregs->GPDAT|=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->GPDAT &= ~L3C;	            //L3C=L
            g_pIOPregs->GPDAT |= L3D;	        //L3D=H
            for(j=0;j<10;j++);	                //tcy(L3) > 500ns
            g_pIOPregs->GPDAT |= (L3C|L3D);    //L3C=H,L3D=H
            for(j=0;j<10;j++);	                //tcy(L3) > 500ns
        }
        else		//if data's LSB is 'L'
        {
	    g_pIOPregs->GPDAT &= ~L3C;	            //L3C=L
	    g_pIOPregs->GPDAT &= ~L3D;	            //L3D=L
            for(j=0;j<10;j++);	                //tcy(L3) > 500ns
            g_pIOPregs->GPDAT |= L3C;	        //L3C=H
	    g_pIOPregs->GPDAT &= ~L3D;	            //L3D=L
            for(j=0;j<10;j++);	                //tcy(L3) > 500ns
        }
        data>>=1;	//for check next bit
    }
    
    g_pIOPregs->GPDAT|=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)
{
    UINT32 Irq;
	
    if (m_Initialized)
    {
        return(FALSE);
    }
    m_IntrAudio = SYSINTR_NOP;
	
    Irq = IRQ_AUDIO;
    if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &Irq, sizeof(UINT32), &m_IntrAudio, sizeof(UINT32), NULL))
    {
        RETAILMSG(1, (TEXT("ERROR: Failed to request the audio sysintr.\r\n")));
        m_IntrAudio = SYSINTR_UNDEFINED;
        return(FALSE);
    }

	RETAILMSG(1, (TEXT("AUDIO sysintr is %d\r\n"),m_IntrAudio));
	
	//----- 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())
	{
		RETAILMSG(DBG_AUDIO, (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())
    {
		RETAILMSG(DBG_AUDIO, (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())
    {
		RETAILMSG(DBG_AUDIO, (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 S3C24A0_IISBUS_REG*)VirtualAlloc(0, sizeof(S3C24A0_IISBUS_REG), MEM_RESERVE, PAGE_NOACCESS);
	if (!g_pIISregs)
	{
		RETAILMSG(1, (TEXT("S3C24A0_IISBUS_REG: VirtualAlloc failed!\r\n")));
		return(FALSE);
	}
	if (!VirtualCopy((PVOID)g_pIISregs, (PVOID)(S3C24A0_BASE_REG_PA_IISBUS>>8), sizeof(S3C24A0_IISBUS_REG), PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL))
	{
		RETAILMSG(1, (TEXT("S3C24A0_IISBUS_REG: VirtualCopy failed!\r\n")));
		return(FALSE);
	}
	// SPI registers.
	//
    g_pSPIregs = (volatile S3C24A0_SPI_REG*)VirtualAlloc(0, sizeof(S3C24A0_SPI_REG), MEM_RESERVE, PAGE_NOACCESS);
	if (!g_pSPIregs)
	{
		DEBUGMSG(1, (TEXT("SPIreg: VirtualAlloc failed!\r\n")));
		return(FALSE);
	}
	if (!VirtualCopy((PVOID)g_pSPIregs, (PVOID)(S3C24A0_BASE_REG_PA_SPI0>>8), sizeof(S3C24A0_SPI_REG), PAGE_READWRITE | PAGE_NOCACHE  | PAGE_PHYSICAL))
	{
		DEBUGMSG(1, (TEXT("S3C24A0_SPI_REG: VirtualCopy failed!\r\n")));
		return(FALSE);
	}

	g_pIOPregs = (volatile S3C24A0_IOPORT_REG*)VirtualAlloc(0, sizeof(S3C24A0_IOPORT_REG), MEM_RESERVE, PAGE_NOACCESS);
	if (!g_pIOPregs)
	{
		RETAILMSG(1, (TEXT("S3C24A0_IOPORT_REG: VirtualAlloc failed!\r\n")));
		return(FALSE);
	}
	if (!VirtualCopy((PVOID)g_pIOPregs, (PVOID)(S3C24A0_BASE_REG_PA_IOPORT>>8), sizeof(S3C24A0_IOPORT_REG), PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL))
	{
		RETAILMSG(1, (TEXT("S3C24A0_IOPORT_REG: VirtualCopy failed!\r\n")));
		return(FALSE);
	}

	g_pDMA0regs = (volatile S3C24A0_DMA_REG*)VirtualAlloc(0, sizeof(S3C24A0_DMA_REG), MEM_RESERVE, PAGE_NOACCESS);
	if (!g_pDMA0regs)
	{
		RETAILMSG(1, (TEXT("S3C24A0_DMA_REG0: VirtualAlloc failed!\r\n")));
		return(FALSE);
	}
	if (!VirtualCopy((PVOID)g_pDMA0regs, (PVOID)(S3C24A0_BASE_REG_PA_DMA0>>8), sizeof(S3C24A0_DMA_REG), PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL))
	{
		RETAILMSG(1, (TEXT("S3C24A0_DMA_REG0: VirtualCopy failed!\r\n")));
		return(FALSE);
	}

	g_pDMA2regs = (volatile S3C24A0_DMA_REG *)VirtualAlloc(0, sizeof(S3C24A0_DMA_REG), MEM_RESERVE, PAGE_NOACCESS);
	if (!g_pDMA2regs)
	{
		RETAILMSG(1, (TEXT("S3C24A0_DMA_REG1: VirtualAlloc failed!\r\n")));
		return(FALSE);
	}
	if (!VirtualCopy((PVOID)g_pDMA2regs, (PVOID)(S3C24A0_BASE_REG_PA_DMA2>>8), sizeof(S3C24A0_DMA_REG), PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL))
	{
		RETAILMSG(1, (TEXT("S3C24A0_DMA_REG1: VirtualCopy failed!\r\n")));
		return(FALSE);
	}

	s24A0INT = (volatile S3C24A0_INTR_REG*)VirtualAlloc(0, sizeof(S3C24A0_INTR_REG), MEM_RESERVE, PAGE_NOACCESS);
	if (!s24A0INT)
	{
		RETAILMSG(1, (TEXT("S3C24A0_INTR_REG: VirtualAlloc failed!\r\n")));
		return(FALSE);
	}
	if (!VirtualCopy((PVOID)s24A0INT, (PVOID)(S3C24A0_BASE_REG_PA_INTR>>8), sizeof(S3C24A0_INTR_REG), PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL))
	{
		RETAILMSG(1, (TEXT("S3C24A0_INTR_REG: VirtualCopy failed!\r\n")));
		return(FALSE);
	}

	g_pCLKPWRreg = (volatile S3C24A0_CLKPWR_REG *)VirtualAlloc(0, sizeof(S3C24A0_CLKPWR_REG), MEM_RESERVE, PAGE_NOACCESS);
	if (!g_pCLKPWRreg)
	{
		RETAILMSG(1, (TEXT("S3C24A0_CLKPWR_REG: VirtualAlloc failed!\r\n")));
		return(FALSE);
	}
	if (!VirtualCopy((PVOID)g_pCLKPWRreg, (PVOID)(S3C24A0_BASE_REG_PA_CLOCK_POWER>>8), sizeof(S3C24A0_CLKPWR_REG), PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL))
	{
		RETAILMSG(1, (TEXT("S3C24A0_CLKPWR_REG: 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)))
	{
		RETAILMSG(DBG_AUDIO, (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)(IMAGE_AUDIO_DMA_BUFFER_PHYS>>8), (AUDIO_DMA_PAGE_SIZE * 4), PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL))
	{
		RETAILMSG(DBG_AUDIO, (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;

⌨️ 快捷键说明

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