📄 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.
****** 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 + -