📄 hwctxt.cpp
字号:
//
// 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.
-2005.11.12 - DonGo.
-*/
#include "wavemain.h"
#include <s3c2443.h>
#include "I2S.h"
#include "hwctxt.h"
#include <p2.h>
#include <bsp.h>
#include <S3C2443REF_GPIO.h>
#define DMA_FLAG 1
#define DMA_CH_MIC 1
#define DMA_CH_OUT 2
#define DBG_WAV 0
#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)
#define L3C (1<<2) // GPG2 = L3CLOCK
#define L3D (1<<1) // GPG1 = L3DATA
#define L3M (1<<0) // GPG0 = L3MODE
// debug message
#define DBG_ON 0 // Debug message on/off
#define DBG_AUDIO 0
unsigned int delay_count;
#define DELAY_COUNT (100000)
//----- 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 S3C2443_IISBUS_REG *g_pIISregs = NULL; // I2S control registers
volatile S3C2443_IOPORT_REG *g_pIOPregs = NULL; // GPIO registers (needed to enable I2S and SPI)
volatile S3C2443_DMA_REG *g_pDMAregs = NULL; // DMA1 registers audio in (needed for I/O on I2S bus)
volatile S3C2443_CLKPWR_REG *g_pCLKPWRreg = NULL; // Clock power registers (needed to enable I2S and SPI clocks)
volatile S3C2443_INTR_REG *s2443INT = NULL;
//UTL_FASTCALL g_tblFastCall; // Needed for fast driver->driver calling mechanism
HANDLE g_hUTLObject = INVALID_HANDLE_VALUE;
HardwareContext *g_pHWContext = NULL;
PHYSICAL_ADDRESS g_PhysDMABufferAddr;
UINT32 g_ForCount=1;
int TransferCount;
extern int g_NeedtoSleep;
//----------------------------------------------------------------------------------------
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 _WrL3Addr(unsigned char data)
{
volatile int i,j;
g_pIOPregs->GPGDAT = g_pIOPregs->GPGDAT & ~(L3D | L3M | L3C) | L3C; //L3D=L, L3M=L(in address mode), L3C=H
for(j=0;j<4;j++); //tsu(L3) > 190ns
//GPG[2:0]=L3C:L3D:L3M
for(i=0;i<8;i++) //LSB first
{
if(data & 0x1) //If data's LSB is 'H'
{
g_pIOPregs->GPGDAT &= ~L3C; //L3C=L
g_pIOPregs->GPGDAT |= L3D; //L3D=H
for(j=0;j<4;j++); //tcy(L3) > 500ns
g_pIOPregs->GPGDAT |= L3C; //L3C=H
g_pIOPregs->GPGDAT |= L3D; //L3D=H
for(j=0;j<4;j++); //tcy(L3) > 500ns
}
else //If data's LSB is 'L'
{
g_pIOPregs->GPGDAT &= ~L3C; //L3C=L
g_pIOPregs->GPGDAT &= ~L3D; //L3D=L
for(j=0;j<4;j++); //tcy(L3) > 500ns
g_pIOPregs->GPGDAT |= L3C; //L3C=H
g_pIOPregs->GPGDAT &= ~L3D; //L3D=L
for(j=0;j<4;j++); //tcy(L3) > 500ns
}
data >>= 1;
}
g_pIOPregs->GPGDAT = g_pIOPregs->GPGDAT & ~(L3D | L3M | L3C) | (L3C | L3M); //L3M=H,L3C=H
}
void _WrL3Data(unsigned char data,int halt)
{
volatile int i,j;
if(halt)
{
g_pIOPregs->GPGDAT = g_pIOPregs->GPGDAT & ~(L3D | L3M | L3C) | L3C; //L3C=H(while tstp, L3 interface halt condition)
for(j=0;j<4;j++); //tstp(L3) > 190ns
}
g_pIOPregs->GPGDAT = g_pIOPregs->GPGDAT & ~(L3D | L3M | L3C) | (L3C | L3M); //L3M=H(in data transfer mode)
for(j=0;j<4;j++); //tsu(L3)D > 190ns
//GPG[2:0]=L3C:L3D:L3M
for(i=0;i<8;i++)
{
if(data & 0x1) //if data's LSB is 'H'
{
g_pIOPregs->GPGDAT &= ~L3C; //L3C=L
g_pIOPregs->GPGDAT |= L3D; //L3D=H
for(j=0;j<4;j++); //tcy(L3) > 500ns
g_pIOPregs->GPGDAT |= (L3C | L3D); //L3C=H,L3D=H
for(j=0;j<4;j++); //tcy(L3) > 500ns
}
else //If data's LSB is 'L'
{
g_pIOPregs->GPGDAT &= ~L3C; //L3C=L
g_pIOPregs->GPGDAT &= ~L3D; //L3D=L
for(j=0;j<4;j++); //tcy(L3) > 500ns
g_pIOPregs->GPGDAT |= L3C; //L3C=H
g_pIOPregs->GPGDAT &= ~L3D; //L3D=L
for(j=0;j<4;j++); //tcy(L3) > 500ns
}
data >>= 1; //For check next bit
}
g_pIOPregs->GPGDAT = g_pIOPregs->GPGDAT & ~(L3D | L3M | L3C) | (L3C | L3M); //L3M=H,L3C=H
}
BOOL Codec_channel111()
{
//RETAILMSG(DBG_ON, (TEXT("+Codec_channel\r\n")));
//****** L3 I/F (GPIO) Initialize *****
//----------------------------------------------------------
//PORT G GROUP
//Ports : GPG0 GPG1 GPG2
//Signal : L3MODE L3DATA L3CLK
//Setting: OUTPUT OUTPUT OUTPUT
// [1:0] [3:2] [5:4]
//Binary : 01 01 01
//----------------------------------------------------------
g_pIOPregs->GPGDAT = g_pIOPregs->GPGDAT & ~(L3M|L3C|L3D) |(L3M|L3C); //Start condition : L3M=H, L3C=H
g_pIOPregs->GPGDAT = g_pIOPregs->GPGDAT & ~(0x3f);
g_pIOPregs->GPGDAT |= ((0x1<<4) |(0x1<<2) |(0x1<<0));
#ifdef EVT1
g_pIOPregs->EXTINT1 = READEXTINT1(g_pIOPregs->EXTINT1) | (1<<11)|(1<<7)|(1<<3);
#else
g_pIOPregs->GPGUDP = g_pIOPregs->GPGUDP & ~(0x3f<<0) | (2<<4)|(2<<2)|(2<<0); // 1:Pull-Down disable
#endif
g_pIOPregs->GPGDAT = g_pIOPregs->GPGDAT & ~(L3M|L3C|L3D) |(L3M|L3C); //Start condition : L3M=H, L3C=H
#if 0
_WrL3Addr(0x14+2); //STATUS (000101xx+10)
if( m_InputDMARunning & m_OutputDMARunning )
_WrL3Data(0xa3,0); // 1010 0011 : OGS=0,IGS=6db,ADC_NI,DAC_NI,sngl speed,AonDon
else if( m_InputDMARunning )
_WrL3Data(0xa2,0); // 1010 0010 : OGS=0,IGS=6db,ADC_NI,DAC_NI,sngl speed,AonDoff
else if( m_OutputDMARunning )
_WrL3Data(0xa1,0); // 1010 0001 : OGS=0,IGS=6db,ADC_NI,DAC_NI,sngl speed,AoffDon
else
_WrL3Data(0xa0,0); // 1010 0000 : OGS=0,IGS=6db,ADC_NI,DAC_NI,sngl speed,AoffDoff
#else
_WrL3Addr(0x14+2); //STATUS (000101xx+10)
_WrL3Data(0xa1,0); // 1010 0011 : OGS=0,IGS=6db,ADC_NI,DAC_NI,sngl speed,AonDon
#endif
//RETAILMSG(DBG_ON, (TEXT("-Codec_channel\r\n")));
return(TRUE);
}
//Sub-Routines
//Setting Port related to IIS
void IIS_Port_Init(void)
{
//----------------------------------------------------------
//PORT G GROUP
//Ports : GPG0 GPG1 GPG2
//Signal : L3MODE L3DATA L3CLK
//Setting: OUTPUT OUTPUT OUTPUT
// [1:0] [3:2] [5:4]
//Binary : 01 01 01
//----------------------------------------------------------
g_pIOPregs->GPGCON = g_pIOPregs->GPGCON & ~((0x3<<4)|(0x3<<2)|(0x3));
g_pIOPregs->GPGCON |= ((0x1<<4)|(0x1<<2)|(0x1)); // output setting
#ifdef EVT1
g_pIOPregs->EXTINT1 = READEXTINT1(g_pIOPregs->EXTINT1) | (1<<11)|(1<<7)|(1<<3);
#else
g_pIOPregs->GPGUDP = g_pIOPregs->GPGUDP & ~(0x3f<<0) | (2<<4)|(2<<2)|(2<<0); // 1:Pull-Down disable
#endif
//-------------------------------------------------------------------------------
//PORT E GROUP
//Ports : GPE4 GPE3 GPE2 GPE1 GPE0
//Signal : I2S DO I2S DI CDCLK I2S CLK I2S LRCLK
//Binary : 10, 10, 10, 10, 10
//-------------------------------------------------------------------------------
g_pIOPregs->GPECON = g_pIOPregs->GPECON & ~(0x3ff) | 0x2aa;
#ifdef EVT1
g_pIOPregs->GPEUDP = g_pIOPregs->GPEUDP & ~(0x3ff) | 0x155;
#else
g_pIOPregs->GPEUDP = g_pIOPregs->GPEUDP & ~(0x3ff) | 0x2AA;
#endif
}
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;
//RETAILMSG(1, (TEXT("AUDIO sysintr is %d\r\n"), m_IntrAudio));
//----- 1. Initialize the state/status variables -----
m_DriverIndex = Index;
m_IntrAudio = IRQ_AUDIO; // Just init data...
m_InPowerHandler = FALSE;
m_InputDMARunning = FALSE;
m_OutputDMARunning = FALSE;
m_InputDMAStatus = DMA_CLEAR;
m_OutputDMAStatus = DMA_CLEAR;
bIdlePwrDown = TRUE; // TRUE = Codec Power Turned off
//----- 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.5 Init the GPIO ports
IIS_Port_Init();
//----- 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;
}
// Call the OAL to translate the audio IRQ into a SYSINTR value.
//
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;
}
RETAILMSG(1, (TEXT("Audio Input IRQ(DMA1) mapping: [IRQ:%d->sysIRQ:%d].\r\n"), Irq, m_dwSysintrInput));
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;
}
RETAILMSG(1, (TEXT("Audio Output IRQ(DMA2) mapping: [IRQ:%d->sysIRQ:%d].\r\n"), Irq, m_dwSysintrOutput));
//Initialize the IIS registers
I2S_Init();
//----- 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;
}
// Codec_channel111();
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 S3C2443_IISBUS_REG*)VirtualAlloc(0, sizeof(S3C2443_IISBUS_REG), MEM_RESERVE, PAGE_NOACCESS);
if (!g_pIISregs)
{
RETAILMSG(1, (TEXT("S3C2443_IISBUS_REG: VirtualAlloc failed!\r\n")));
return(FALSE);
}
if (!VirtualCopy((PVOID)g_pIISregs, (PVOID)(S3C2443_BASE_REG_PA_IISBUS>>8), sizeof(S3C2443_IISBUS_REG), PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL))
{
RETAILMSG(1, (TEXT("S3C2443_IISBUS_REG: VirtualCopy failed!\r\n")));
return(FALSE);
}
g_pIOPregs = (volatile S3C2443_IOPORT_REG*)VirtualAlloc(0, sizeof(S3C2443_IOPORT_REG), MEM_RESERVE, PAGE_NOACCESS);
if (!g_pIOPregs)
{
RETAILMSG(1, (TEXT("S3C2443_IOPORT_REG: VirtualAlloc failed!\r\n")));
return(FALSE);
}
if (!VirtualCopy((PVOID)g_pIOPregs, (PVOID)(S3C2443_BASE_REG_PA_IOPORT>>8), sizeof(S3C2443_IOPORT_REG), PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL))
{
RETAILMSG(1, (TEXT("S3C2443_IOPORT_REG: VirtualCopy failed!\r\n")));
return(FALSE);
}
g_pDMAregs = (volatile S3C2443_DMA_REG*)VirtualAlloc(0, sizeof(S3C2443_DMA_REG), MEM_RESERVE, PAGE_NOACCESS);
if (!g_pDMAregs)
{
RETAILMSG(1, (TEXT("S3C2443_DMA_REG1: VirtualAlloc failed!\r\n")));
return(FALSE);
}
if (!VirtualCopy((PVOID)g_pDMAregs, (PVOID)(S3C2443_BASE_REG_PA_DMA>>8), sizeof(S3C2443_DMA_REG), PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL))
{
RETAILMSG(1, (TEXT("S3C2443_DMA_REG1: VirtualCopy failed!\r\n")));
return(FALSE);
}
s2443INT = (volatile S3C2443_INTR_REG*)VirtualAlloc(0, sizeof(S3C2443_INTR_REG), MEM_RESERVE, PAGE_NOACCESS);
if (!s2443INT)
{
RETAILMSG(1, (TEXT("S3C2443_INTR_REG: VirtualAlloc failed!\r\n")));
return(FALSE);
}
if (!VirtualCopy((PVOID)s2443INT, (PVOID)(S3C2443_BASE_REG_PA_INTR>>8), sizeof(S3C2443_INTR_REG), PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL))
{
RETAILMSG(1, (TEXT("S3C2443_INTR_REG: VirtualCopy failed!\r\n")));
return(FALSE);
}
g_pCLKPWRreg = (volatile S3C2443_CLKPWR_REG *)VirtualAlloc(0, sizeof(S3C2443_CLKPWR_REG), MEM_RESERVE, PAGE_NOACCESS);
if (!g_pCLKPWRreg)
{
RETAILMSG(1, (TEXT("S3C2443_CLKPWR_REG: VirtualAlloc failed!\r\n")));
return(FALSE);
}
if (!VirtualCopy((PVOID)g_pCLKPWRreg, (PVOID)(S3C2443_BASE_REG_PA_CLOCK_POWER>>8), sizeof(S3C2443_CLKPWR_REG), PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL))
{
RETAILMSG(1, (TEXT("S3C2443_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;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -