📄 wmwavepdd.c
字号:
/*-----------------------------------------------------------------------------
* Copyright (c) Wolfson Microelectronics plc. All rights reserved.
*
* This software as well as any related documentation is furnished under
* license and may only be used or copied in accordance with the terms of the
* license. The information in this file is furnished for informational use
* only, is subject to change without notice, and should not be construed as
* a commitment by Wolfson Microelectronics plc. Wolfson Microelectronics plc
* assumes no responsibility or liability for any errors or inaccuracies that
* may appear in this document or any software that may be provided in
* association with this document.
*
* Except as permitted by such license, no part of this document may be
* reproduced, stored in a retrieval system, or transmitted in any form or by
* any means without the express written consent of Wolfson Microelectronics plc.
*
* $Id: WMWavepdd.c 3117 2006-04-28 13:46:49Z fb $
*
* The PDD (Platform Dependent Driver) is responsible for
* communicating with the audio circuit to start and stop playback
* and/or recording and initialize and deinitialize the circuits.
*
* Warning:
* This driver is specifically written for Wolfson Codecs. It is not a
* general CODEC device driver.
*
* --------------------------------------------------------------------------*/
/*
* Include files
*/
#include <wavemdd.h>
#if ( _WIN32_WCE >= 500 && !defined( WM_BSP_TAHITI ) )
# include <bsp_cfg.h>
#else
# include <oalintr.h>
#endif
#include "WDCL.h"
/*
* NOTE: The audio path functions that are included by WMAudioPaths.h
* and used in this file is only an example of one way of setting
* up paths through the codec. In general we have gone for the
* approach of enabling as many paths through the codec as possible
* so that there is a good chance that which ever input and output
* is used some audio will get through.
*
* It is therefore important that developers optimize this to suit
* the application. It may be that you need to make changes to these
* functions or use different functions from this file.
*
* If you have any queries, or suggestions for audio paths that
* are not covered in the Wolfson Device Control Library please feel
* free to contact the apps team (apps@wolfsonmicro.com).
*/
#if !WM_AUDIO || !WM_AUDIO_STREAM
#error Mismatch: The Wolfson library is not configured for Audio or Audio Streaming, build system is configured for Audio
#endif /* !WM_AUDIO */
#if WM_USE_DYNAMIC_DMA_CHANNEL
#error WM_USE_DYNAMIC_DMA_CHANNEL _must_ be defined as FALSE in WMPlatformConfig.h.
#endif /* WM_USE_DYNAMIC_DMA_CHANNEL */
/*
* Global definitions
*/
/* WinCE volume scheme: 16 bits of Left and 16 bits of Right (0xRRRRLLLL) */
#define RIGHT_VOLUME_MASK 0xFFFF0000
#define RIGHT_VOLUME_SHIFT 16
#define LEFT_VOLUME_MASK 0x0000FFFF
#define LEFT_VOLUME_SHIFT 0
#define RIGHT_VOL( _vol ) ((unsigned short)(((_vol) & RIGHT_VOLUME_MASK) >> RIGHT_VOLUME_SHIFT))
#define LEFT_VOL( _vol ) ((unsigned short)(((_vol) & LEFT_VOLUME_MASK) >> LEFT_VOLUME_SHIFT))
DWORD gIntrAudio = SYSINTR_AUDIO;
static WM_DEVICE_HANDLE g_hAudioDevice;
static WM_STREAM_HANDLE g_hOutputStream;
static WM_STREAM_HANDLE g_hInputStream;
static WM_CHIPTYPE s_deviceType;
/*
* Shared audio data. This data is
* shared between the device process
* and the power managment process
*/
typedef struct tagWM_SHARED_AUDIO_DATA
{
BOOL inPowerHandler;
BOOL moreData[2];
} WM_SHARED_AUDIO_DATA;
/*
* Global audio data variable for the device process.
*/
static volatile WM_SHARED_AUDIO_DATA *g_pWMAudioDeviceData = NULL;
HANDLE g_hGlobalDataDeviceMutex;
#define WM_GLOBAL_DATA_MUTEX_NAME _T("WMGlobalDataMutex")
#define WM_GLOBAL_TIME_OUT 1000 /* 1 second timeout */
/*
* When the volume is zero we mute the
* codec so that we get maximum attenuation.
* This global define allows us to check if
* we are at zero volume and should leave
* the codec outputs muted.
*/
static BOOL g_OutputMaxAtten = FALSE;
static WM_AUDIO_SIGNAL g_SignalL;
static WM_AUDIO_SIGNAL g_SignalR;
struct _global_volume
{
ULONG dwMasterVolume;
ULONG dwLineInVolume;
ULONG dwMicVolume;
BOOL fMasterMute;
BOOL fLineInMute;
BOOL fMicMute;
ULONG dwInputSelect;
} g_VolumeSettings;
static CEDEVICE_POWER_STATE g_DxState;
/*
* Work out what sort of chip it is.
*/
#define IS_WM9713_DEVICE( _device ) (WM_CHIP_WM9713 == (_device))
#ifndef ZONE_ALWAYS
# define ZONE_ALWAYS TRUE
#endif
/*
* Macros to check if the DMA is currently running
*/
#define OUTPUTDMARUNNING( _pWMAudioData ) ( TRUE == _pWMAudioData->moreData[WAPI_OUT] ) \
? TRUE : FALSE
#define INPUTDMARUNNING( _pWMAudioData ) ( TRUE == _pWMAudioData->moreData[WAPI_IN] ) \
? TRUE : FALSE
/*
* Function prototypes
*/
static MMRESULT private_PddWaveGetDeviceCaps( WAPI_INOUT apidir, void * pCaps );
static MMRESULT private_PddWaveOpen( WAPI_INOUT apidir,
LPWAVEFORMATEX lpFormat,
BOOL fQueryFormatOnly
);
static MMRESULT private_PddWaveOutStart( PWAVEHDR pwh,
volatile WM_SHARED_AUDIO_DATA *pWMAudioData
);
static MMRESULT private_PddWaveInStart( volatile WM_SHARED_AUDIO_DATA *pWMAudioData );
static void private_PddWaveOutContinue( PWAVEHDR pwh );
static void private_PddWaveInContinue( PWAVEHDR pwh );
static MMRESULT private_PddWaveOutStop( volatile WM_SHARED_AUDIO_DATA *pWMAudioData );
static MMRESULT private_PddWaveInStop( volatile WM_SHARED_AUDIO_DATA *pWMAudioData );
static void private_PddWaveFillBuffer( PWAVEHDR pwd );
static void private_PddWaveComplete( PWAVEHDR pwh, ULONG cbBytesCompleted );
static void private_PddWaveGetBuffer( PWAVEHDR pwh );
static ULONG private_PddWaveGetVolume( void );
static MMRESULT private_PddWaveSetVolume( ULONG volume );
static MMRESULT private_SetMixerValue( DWORD dwControl, DWORD dwSetting );
static MMRESULT private_GetMixerValue( DWORD dwControl, PDWORD pdwSetting );
static void private_PddPowerUp( void );
static void private_PddPowerDown( void );
static MMRESULT private_MuteAllOutputs( volatile WM_SHARED_AUDIO_DATA *pWMAudioData,
BOOL mute );
static MMRESULT private_PrepareOutputPaths( WM_STREAM_ID stream,
volatile WM_SHARED_AUDIO_DATA *pWMAudioData,
BOOL enable
);
static MMRESULT private_PrepareInputPaths( WM_STREAM_ID stream,
volatile WM_SHARED_AUDIO_DATA *pWMAudioData,
BOOL enable
);
/*-----------------------------------------------------------------------------
* Function: PDD_AudioDeinitialize
*
* This function turns off and disconnects the audio device
*
* Parameters:
* none
*
* Returns: void
*---------------------------------------------------------------------------*/
void PDD_AudioDeinitialize( void )
{
DEBUGMSG(ZONE_FUNCTION, (TEXT( "PDD_AudioDeinitialize+\r\n" )) );
if ( g_hAudioDevice )
{
/*
* Power down the device.
*/
private_PddPowerDown();
WMAudioShutdown( g_hAudioDevice );
}
DEBUGMSG(ZONE_FUNCTION, (TEXT( "PDD_AudioDeinitialize-\r\n" )) );
}
/*-----------------------------------------------------------------------------
* Function: PDD_AudioGetInterruptType
*
* This function determines the cause of the audio interrupt and returns the
* current device status.
*
* Parameters:
* none
*
* Returns: AUDIO_STATE
* An interger indicating the type of interrupt.
* AUDIO_STATE_OUT_PLAYING Sound is currently playing.
* AUDIO_STATE_OUT_UNDERFLOW Sound was playing, but not enough data
* has been supplied to continue.
* AUDIO_STATE_IN_RECORDING Sound is currently recording.
* AUDIO_STATE_IN_OVERFLOW Sound was recording, but the reserve
* buffer was not processed in time.
* AUDIO_STATE_IN_STOPPED Recording has stopped.
* AUDIO_STATE_IGNORE Ignore this interrupt.
*---------------------------------------------------------------------------*/
AUDIO_STATE PDD_AudioGetInterruptType(void)
{
AUDIO_STATE retval = AUDIO_STATE_IGNORE;
WMAUDIO_INTSTATE intState;
/*
* An audio interrupt has occured. We need to tell the MDD who owns it
* and what state that puts us in.
*
* NOTE: You can return both an input and an output state simultaneously
* by simply OR'ing the two values together (output and input are held
* in upper and lower nibbles respectively).
*/
/*
* I N P U T
*/
/*
* Call the Wolfson library to find out which interrupts occured on the input stream.
* This function will clear the interrupt, if necessary, for us as well.
*/
intState = WMAudioCheckStreamInterrupts( g_hAudioDevice, g_hInputStream );
/*
* Check for DMA bus error on input stream.
*/
if ( intState & WMAUDIO_INT_ERROR )
{
/*
* If a bus error is received this is treated as fatal as we should
* not be getting errors of this sort.
*/
DEBUGMSG( ZONE_ERROR, ( TEXT ( "DCSR_BUSERRINTR on input\r\n" ) ) );
retval |= AUDIO_STATE_IGNORE;
ASSERT(0);
}
/*
* Check for DMA end interrupt on input stream.
*/
if ( intState & WMAUDIO_INT_END )
{
/*
* Let the Wolfson library know that another DMA buffer has
* been filled.
*/
WMAudioHandleInterrupt( g_hAudioDevice, g_hInputStream );
/*
* If the driver is still expecting more data
* then signal that to the MDD that it is still recording,
* else signal that it has stopped recording.
*/
if ( INPUTDMARUNNING( g_pWMAudioDeviceData ) )
retval |= AUDIO_STATE_IN_RECORDING;
else
retval |= AUDIO_STATE_IN_STOPPED;
}
/*
* Check for DMA start interrupt on input stream.
*/
if ( intState & WMAUDIO_INT_START )
{
/*
* We do not use start interrupts for this driver so we should never
* receive a start interrupt for this stream.
*/
DEBUGMSG( ZONE_ERROR, ( TEXT ( "DCSR_STARTINTER on input\r\n" ) ) );
retval |= AUDIO_STATE_IGNORE;
ASSERT(0);
}
/*
* O U T P U T
*/
/*
* Call the Wolfson library to find out which interrupts occured on the output stream.
* This function will clear the interrupt, if necessary, for us as well.
*/
intState = WMAudioCheckStreamInterrupts( g_hAudioDevice, g_hOutputStream );
/*
* Check for DMA bus error on output stream.
*/
if ( intState & WMAUDIO_INT_ERROR )
{
/*
* If a bus error is received this is treated as fatal as we should
* not be getting errors of this sort.
*/
DEBUGMSG( ZONE_ERROR, ( TEXT ( "DCSR_BUSERRINTR on output\r\n" ) ) );
retval |= AUDIO_STATE_IGNORE;
ASSERT(0);
}
/*
* Check for DMA end interrupt on output stream.
*/
if ( intState & WMAUDIO_INT_END )
{
/*
* Let the Wolfson library know that another DMA buffer has
* been transmitted.
*/
WMAudioHandleInterrupt( g_hAudioDevice, g_hOutputStream );
/*
* If the driver is still expecting more data
* then signal that to the MDD that it is still playing,
* else signal that it has stopped playing.
*/
if ( OUTPUTDMARUNNING( g_pWMAudioDeviceData ) )
retval |= AUDIO_STATE_OUT_PLAYING;
else
retval |= AUDIO_STATE_OUT_STOPPED;
}
/*
* Check for DMA start interrupt on output stream.
*/
if ( intState & WMAUDIO_INT_START )
{
/*
* We do not use start interrupts for this driver so we should never
* receive a start interrupt for this stream.
*/
DEBUGMSG( ZONE_ERROR, ( TEXT ( "DCSR_STARTINTER on output\r\n" ) ) );
retval |= AUDIO_STATE_IGNORE;
ASSERT(0);
}
return retval;
}
/*-----------------------------------------------------------------------------
* Function: PDD_AudioInitialize
*
* This function initializes the audio device for operation
*
* Parameters:
* dwIndex Passed to the WAV_Init function. This allows the PDD layer
* to get device configuration information from the driver's
* registry entry.
*
* Returns: BOOL
* TRUE indicates success. FALSE indicates failure.
*---------------------------------------------------------------------------*/
BOOL PDD_AudioInitialize( DWORD dwIndex )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -