📄 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.
//
//-----------------------------------------------------------------------------
//
// Copyright (C) 2005, 2006, Freescale Semiconductor, Inc. All Rights Reserved.
// THIS SOURCE CODE IS CONFIDENTIAL AND PROPRIETARY AND MAY NOT
// BE USED OR DISTRIBUTED WITHOUT THE WRITTEN PERMISSION OF
// FREESCALE SEMICONDUCTOR, INC.
//
//-----------------------------------------------------------------------------
//
// File: hwctxt.cpp
//
// Platform dependent code for the WinCE WAV audio driver. This code's primary
// responsibilities are:
//
// 1. Initialize the platform's audio hardware (e.g., audio CODEC,
// amplifiers, etc.).
// 2. Initialize and configure all associated hardware components (e.g.,
// DMA controllers, Synchronous Serial Interfaces (SSIs), audio MUXes,
// interrupt controllers, etc.).
// 3. Configure DMA operations to move audio data between the memory buffers
// and the SSIs.
// 4. Handle audio hardware-related interrupt events.
// 5. Configure the audio hardware to perform audio playback and recording
// functions.
// 6. Provide smart power management to minimize power consumption (e.g.,
// powering up components only as required and powering them down when
// they are no longer needed). Note, however, that we don't do any
// power management for components that are not directly audio-related.
// For example, we will disable the clock signal for the SSIs when
// we stop playing audio but we won't powerdown the clock/reset module
// since that may still be needed by other parts of the system.
//
// All other tasks (e.g., audio stream mixing, resampling etc.) are currently
// handled by the "upper" layers of the WinCE audio driver.
//
// This device driver implementation is based upon the audio features and
// components provided by the Freescale Power Management ICs (PMICs) in
// conjunction with either an i.MX or MXC-based platform.
//
// More specifically, the following key platform-dependent hardware components
// are used to provide the audio playback and recording functions:
//
// PMIC Components:
//
// * Stereo DAC for playback along with associated mixers, output
// amplifiers, and audio output jacks.
// * Voice CODEC for recording along with associated mixers, input
// amplifiers, and audio microphone input jacks.
//
// i.MX or MXC Components:
//
// * SSI1 for Voice CODEC I/O
// * SSI2 for Stereo DAC I/O
// * SDMA to handle audio I/O between memory and SSI1/SSI2.
// * Audio MUX to route the audio stream between the SSI and the
// PMIC Voice CODEC or Stereo DAC.
// * Clock and Reset Module to generate the required clock signals for
// SSI1/SSI2 (and the PMIC clock input in the case of the MC13783 PMIC).
//
// See also the corresponding PMIC-specific source files for complete details
// about the implementation of the BSP interface for audio. For example, in
// the case of the MX31 platform, the rest of the audio driver code can be
// found in the following files:
//
// WINCE500\PLATFORM\MX31\SRC\DRIVERS\WAVEDEV\ATLAS\HWCTXT.CPP
// WINCE500\PUBLIC\COMMON\OAK\CSP\ARM\FREESCALE\PMIC\ATLAS\...
// ...\SDK\PMIC_AUDIO.CPP
//
//-----------------------------------------------------------------------------
#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include <Mmsystem.h> // For timer driver interface.
#include "wavemain.h"
// Define the size (in data words) of the SSI TX FIFO. This is normally 8.
#define SSI_TX_FIFO_DEPTH 8 // Default 8
//-----------------------------------------------------------------------------
// External Variables
#ifdef DEBUG
extern DBGPARAM dpCurSettings;
#endif // #ifdef DEBUG
//-----------------------------------------------------------------------------
// Defines
const unsigned short HardwareContext::INTR_PRIORITY_REGKEY[12] =
TEXT("IntPriority");
//-----------------------------------------------------------------------------
// Exported Global Variables
HardwareContext *g_pHWContext = NULL;
//-----------------------------------------------------------------------------
// Local Global Variables
static PHYSICAL_ADDRESS g_PhysDMABufferAddr;
static BOOL g_saveOutputDMARunning = FALSE;
#ifdef AUDIO_RECORDING_ENABLED
static BOOL g_saveInputDMARunning = FALSE;
#endif
//-----------------------------------------------------------------------------
//
// Function: CreateHWContext
//
// This function is invoked by the WAV_Init to create a device instance
// that will be passed to the WAV_Open and WAV_DeInit functions. If
// multiple devices are supported, a unique device instance should be
// returned for each device.
//
// Parameters:
// Index
// [in] Context parameter passed to the WAV_Init function
//
// Returns:
// Returns TRUE if successful, otherwise returns FALSE.
//
//-----------------------------------------------------------------------------
BOOL HardwareContext::CreateHWContext(DWORD Index)
{
DEBUGMSG(ZONE_FUNCTION,(_T("+HardwareContext::CreateHWContext\n")));
if (g_pHWContext)
{
return(TRUE);
}
g_pHWContext = new HardwareContext;
if (!g_pHWContext)
{
return(FALSE);
}
DEBUGMSG(ZONE_FUNCTION,(_T("-HardwareContext::CreateHWContext\n")));
return(g_pHWContext->Init(Index));
}
//-----------------------------------------------------------------------------
//
// Function: HardwareContext
//
// This function is the constructor for the hardware context class.
//
// Parameters:
// None.
//
// Returns:
// None.
//
//-----------------------------------------------------------------------------
HardwareContext::HardwareContext()
#ifdef AUDIO_RECORDING_ENABLED
: m_InputDeviceContext(), m_OutputDeviceContext()
#else
: m_OutputDeviceContext()
#endif
{
DEBUGMSG(ZONE_FUNCTION,(_T("+HardwareContext::HardwareContext\n")));
InitializeCriticalSection(&m_Lock);
m_Initialized = FALSE;
// This flag is only set to TRUE when PowerDown() is called.
m_audioPowerdown = FALSE;
// The actual interrupt handler thread will be created later by calling
// CreateThread() in InitInterruptThread().
m_hAudioInterruptThread = NULL;
// Initialize the timer ID and timeout event for both playback and
// recording operations.
//
// We must create the events before we create the event handling thread
// because the event handling thread will immediately begin to run once
// it has been created.
m_AudioDelayDisableTimerID[0] = NULL;
m_hAudioDelayDisableEvent[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
#ifdef AUDIO_RECORDING_ENABLED
m_AudioDelayDisableTimerID[1] = NULL;
m_hAudioDelayDisableEvent[1] = CreateEvent(NULL, FALSE, FALSE, NULL);
#endif
// Also initialize the delayed disable timer event handling thread.
// The actual thread will be created later by calling CreateThread()
// in Init().
m_hAudioDelayedDisableThread = NULL;
DEBUGMSG(ZONE_FUNCTION,(_T("-HardwareContext::HardwareContext\n")));
}
//-----------------------------------------------------------------------------
//
// Function: ~HardwareContext
//
// This function is the destructor for the hardware context class.
//
// Parameters:
// None.
//
// Returns:
// None.
//
//-----------------------------------------------------------------------------
HardwareContext::~HardwareContext()
{
DEBUGMSG(ZONE_FUNCTION,(_T("+HardwareContext::~HardwareContext\n")));
Lock();
if (m_AudioDelayDisableTimerID[0] != NULL)
{
timeKillEvent(m_AudioDelayDisableTimerID[0]);
m_AudioDelayDisableTimerID[0] = NULL;
}
#ifdef AUDIO_RECORDING_ENABLED
if (m_AudioDelayDisableTimerID[1] != NULL)
{
timeKillEvent(m_AudioDelayDisableTimerID[1]);
m_AudioDelayDisableTimerID[1] = NULL;
}
#endif
Unlock();
DeleteCriticalSection(&m_Lock);
if (m_hAudioDelayDisableEvent[0] != NULL)
{
CloseHandle(m_hAudioDelayDisableEvent[0]);
m_hAudioDelayDisableEvent[0] = NULL;
}
#ifdef AUDIO_RECORDING_ENABLED
if (m_hAudioDelayDisableEvent[1] != NULL)
{
CloseHandle(m_hAudioDelayDisableEvent[1]);
m_hAudioDelayDisableEvent[1] = NULL;
}
#endif
DEBUGMSG(ZONE_FUNCTION,(_T("-HardwareContext::~HardwareContext\n")));
}
//-----------------------------------------------------------------------------
//
// Function: Init
//
// This function initializes the hardware context for the audio device.
//
// Parameters:
// Index
// [in] Context parameter passed to the WAV_Init function
//
// Returns:
// Returns TRUE if successful, otherwise returns FALSE.
//
//-----------------------------------------------------------------------------
BOOL HardwareContext::Init(DWORD Index)
{
DEBUGMSG(ZONE_FUNCTION,(_T("+HardwareContext::Init\n")));
// If we have already initialized this device, return error
if (m_Initialized)
{
return(FALSE);
}
// Initialize hardware context to be muted and zero gain since hardware
// should currently be in a powered down state. The audio hardware will
// be automatically powered up when audio playback/recording is actually
// initiated.
m_dwOutputGain = 0;
m_fOutputMute = TRUE;
#ifdef AUDIO_RECORDING_ENABLED
m_dwInputGain = 0x0000;
m_fInputMute = TRUE;
#endif
m_CodecPwrState = AUDIO_PWR_STATE_OFF;
// Initialize the driver state/status variables
m_DriverIndex = Index;
m_OutputDMARunning = FALSE;
m_OutputDMAStatus = DMA_CLEAR;
#ifdef AUDIO_RECORDING_ENABLED
m_InputDMARunning = FALSE;
m_InputDMAStatus = DMA_CLEAR;
#endif
// Initialize BSP-specific configuration.
if (!BSPAudioInit())
{
DEBUGMSG(ZONE_ERROR, (TEXT("WAVEDEV.DLL:HardwareContext::Init() - ")
TEXT("BSPInit failed\r\n")));
goto cleanUp;
}
// Map the DMA buffers.
if (!MapDMABuffers())
{
DEBUGMSG(ZONE_ERROR, (TEXT("WAVEDEV.DLL:HardwareContext::Init() - ")
TEXT("MapDMABuffers failed\r\n")));
goto cleanUp;
}
// Initialize the output DMA.
if (!InitOutputDMA())
{
DEBUGMSG(ZONE_ERROR, (TEXT("WAVEDEV.DLL:HardwareContext::Init() - ")
TEXT("Failed to initialize output DMA.\r\n")));
goto cleanUp;
}
#ifdef AUDIO_RECORDING_ENABLED
// Initialize the input DMA.
if (!InitInputDMA())
{
DEBUGMSG(ZONE_ERROR, (TEXT("WAVEDEV.DLL:HardwareContext::Init() - ")
TEXT("Failed to initialize input DMA.\r\n")));
goto cleanUp;
}
#endif
// Initialize and create audio processing IST.
if ((m_hAudioInterruptThread == NULL) && (!InitInterruptThread()))
{
DEBUGMSG(ZONE_ERROR, (TEXT("WAVEDEV.DLL:HardwareContext::Init() - ")
TEXT("Failed to initialize interrupt thread.\r\n")));
goto cleanUp;
}
// Initialize and create delayed disable timer event handling thread.
if ((m_hAudioDelayedDisableThread == NULL) &&
((PLAYBACK_DISABLE_DELAY_MSEC > 0) || (RECORD_DISABLE_DELAY_MSEC > 0)))
{
// Create a thread to handle the CODEC disable delay timer events.
m_hAudioDelayedDisableThread =
CreateThread((LPSECURITY_ATTRIBUTES)NULL,
0,
(LPTHREAD_START_ROUTINE)BSPAudioDisableDelayHandler,
this,
0,
NULL);
if (!m_hAudioDelayedDisableThread)
{
ERRMSG("Unable to create audio CODEC delayed disable timer event "
"handling thread");
goto cleanUp;
}
}
m_Initialized = TRUE;
cleanUp:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -