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

📄 hwctxt.cpp

📁 基于WINCE 的音频驱动源码
💻 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 ******
				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.

-*/

#include "wavemain.h"
#include <s3c2440a.h>
#include "s3c2440a_dmatransfer.h"
#include "I2S.h"
#include "hwctxt.h"
#include <ceddk.h>

#define DMA_CH_MIC 2
#define DMA_CH_OUT 1

#define L3M (0x04)	// TOUT2
#define L3C (0x10)	// TCLK0
#define L3D (0x08)	// TOUT3

// UDA1341 Register definitions
// The codec has three "addressing modes", which could also be thought of as registers
#define UDA1341_ADDR_DATA0  0x14    // 00010100 | 00  (ID | data0)
#define UDA1341_ADDR_DATA1  0x15    // 00010100 | 01  (ID | data1)
#define UDA1341_ADDR_STATUS	0x16    // 00010100 | 10  (ID | status)

// Status register bits
// Think of the status register as two separate 7-bit register (StatusA and StatusB)
// with bit 7 selecting between the two.

#define UDA1341_STATUS_A            0x00
#define UDA1341_STATUS_B            0x80
#define UDA1341_STATUS_DCFILTER     0x01 // bit 0: DC Filter on
#define UDA1341_STATUS_FMTIIS       0x00 // bit 1-3: format status
#define UDA1341_STATUS_FMT_LSB16    0x02
#define UDA1341_STATUS_FMT_LSB18    0x04
#define UDA1341_STATUS_FMT_LSB20    0x06
#define UDA1341_STATUS_FMT_MSB      0x08
#define UDA1341_STATUS_FMT_MSB16    0x0A
#define UDA1341_STATUS_FMT_MSB18    0x0C
#define UDA1341_STATUS_FMT_MSB20    0x0E
#define UDA1341_STATUS_CLK512       0x00 // bits 4,5: system clock
#define UDA1341_STATUS_CLK384       0x10 // 
#define UDA1341_STATUS_CLK256       0x20 // 
#define UDA1341_STATUS_RESET        0x40 // bit 6: reset

#define UDA1341_STATUS_PWR_DAC      0x01 // bit 0: DAC power on
#define UDA1341_STATUS_PWR_ADC      0x02 // bit 1: ADC power on
#define UDA1341_STATUS_IGS          0x20 // bit 5: IGS - ADC 6dB Boost
#define UDA1341_STATUS_OGS          0x40 // bit 6: OGS - DAC 6dB Boost


int rec_mode=0;
//-------------------------------- Global Variables --------------------------------------
volatile S3C2440A_IISBUS_REG *g_pIISregs		= NULL;		// I2S control registers
volatile S3C2440A_IOPORT_REG *g_pIOPregs		= NULL;		// GPIO registers (needed to enable I2S and SPI)
volatile S3C2440A_SPI_REG    *g_pSPIregs        = NULL;		// SPI control registers

volatile S3C2440A_DMA_REG    *g_pDMAregs		= NULL;		// DMA registers (needed for I/O on I2S bus)
volatile S3C2440A_CLKPWR_REG *g_pCLKPWRreg	= NULL;		// Clock power registers (needed to enable I2S and SPI clocks)
volatile S3C2440A_INTR_REG *s2440INT 		= NULL;
				
HardwareContext *g_pHWContext		= NULL;

PHYSICAL_ADDRESS g_PhysDMABufferAddr;

//----------------------------------------------------------------------------------------

#ifdef DEBUG
DBGPARAM dpCurSettings = {
    TEXT("WaveDriver"), {
		 TEXT("Test")           //  0   ZONE_TEST
		,TEXT("Params")         //  1   ZONE_PARAMS     
		,TEXT("Verbose")        //  2   ZONE_VERBOSE    
		,TEXT("Interrupt")      //  3   ZONE_INTERRUPT  
		,TEXT("WODM")           //  4   ZONE_WODM       
		,TEXT("WIDM")           //  5   ZONE_WIDM       
		,TEXT("PDD")            //  6   ZONE_PDD        
		,TEXT("MDD")            //  7   ZONE_MDD        
		,TEXT("Regs")           //  8   ZONE_REGS       
		,TEXT("Misc")           //  9   ZONE_MISC       
		,TEXT("Init")           // 10   ZONE_INIT       
		,TEXT("IOcontrol")      // 11   ZONE_IOCTL      
		,TEXT("Alloc")          // 12   ZONE_ALLOC      
		,TEXT("Function")       // 13   ZONE_FUNCTION   
		,TEXT("Warning")        // 14   ZONE_WARN       
		,TEXT("Error")          // 15   ZONE_ERROR      
	},
        (1 << 15)   // Errors
    |   (1 << 14)   // Warnings
}; 
#endif

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

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


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

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

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

	m_dwInputGain = 0xFFFF;
	m_dwOutputGain = 0xFFFF;
    m_fInputMute = FALSE;
    m_fOutputMute = FALSE;


    if (m_Initialized)
    {
        return(FALSE);
    }

    // Call the OAL to translate the audio IRQ into a SYSINTR value.
    //
    Irq = IRQ_DMA2;  // audio output DMA interrupt.
    if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &Irq, sizeof(UINT32), &m_dwSysintrOutput, sizeof(UINT32), NULL))
    {
        RETAILMSG(TRUE, (TEXT("ERROR: HardwareContext::Init: Failed to obtain sysintr value for output interrupt.\r\n")));
        return FALSE;
    }

    Irq = IRQ_DMA1;  // audio input DMA interrupt.
    if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &Irq, sizeof(UINT32), &m_dwSysintrInput, sizeof(UINT32), NULL))
    {
        RETAILMSG(TRUE, (TEXT("ERROR: HardwareContext::Init: Failed to obtain sysintr value for input interrupt.\r\n")));
        return FALSE;
    }

	//----- 1. Initialize the state/status variables -----
    m_DriverIndex		= Index;
    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 S3C2440A_IISBUS_REG*)VirtualAlloc(0, sizeof(S3C2440A_IISBUS_REG), MEM_RESERVE, PAGE_NOACCESS);
	if (!g_pIISregs)
	{
		DEBUGMSG(1, (TEXT("IISreg: VirtualAlloc failed!\r\n")));
		return(FALSE);
	}
	if (!VirtualCopy((PVOID)g_pIISregs, (PVOID)(S3C2440A_BASE_REG_PA_IISBUS >> 8), sizeof(S3C2440A_IISBUS_REG), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE))
	{
		DEBUGMSG(1, (TEXT("IISreg: VirtualCopy failed!\r\n")));
		return(FALSE);
	}

	// SPI registers.
	//
    g_pSPIregs = (volatile S3C2440A_SPI_REG*)VirtualAlloc(0, sizeof(S3C2440A_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)(S3C2440A_BASE_REG_PA_SPI >> 8), sizeof(S3C2440A_SPI_REG), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE))
	{
		DEBUGMSG(1, (TEXT("SPIreg: VirtualCopy failed!\r\n")));
		return(FALSE);
	}

⌨️ 快捷键说明

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