關於基於WinCE下的聲音系統調試的一些經驗總結之驱动程式部分
/
//Author:Mercury Xu
//Date:2008-12-05
//Descrption:聲音作為WinCE系統中一個比較基礎的配置大家已經都不會陌生。
// 本文主要是總結下作者在調試WM9715聲卡驅動芯片
// 過程中遇到的一些問題
//OS:WinCE5.0
/
正文:
最近一直在調試關於WM9715的東東,整體調試下來感覺9715的確是個很好很強大的芯片。下面我們按照我的開發思路來整理下關於9715開發的一些心得體會。
首先我們來看下WinCE的聲音處理部分的一些基礎知識。如果您對這一部分已經爛熟於心了,請跳到下一個segment。如果您對WM971X系列爛熟於心了。。I'm sorry。看我的文实在是浪费您的时间了。
另外。大家可以参考下《Windows CE实用开发技术》之 8.10 驱动程序实例分析,這裡張老師已經將驅動的結構講的非常清晰了。大家可以參考下。張老師的書中所提及的是ES1371,我以下的文章針對芯片為WM9715.關於9715的datasheet,大家可以參考wolfson的官方站上的datasheet。
Segment I: WinCE的声音驱动部分
WinCE的声音驱动其实很清晰的给了我们大家。以samsung24X0系来说。你会在X:/WINCE500/PUBLIC/COMMON/OAK/CSP/ARM/SAMSUNG/S3C2410X/WAVEDEV类似的目录下找到他们。以下为我Tree以后他的文件结构
很清晰的程序结构。其实很多公司的都是参照这个结构来定制自己声音部分的程式代码。而我们需要注意的这是以下几个文件:
我们先看看HWCTXT.h文件中的一些信息,直接了解他的接口部分内容。
好了,到這裡大家估計已經基本上暈了,我來給大家刪除點東西。大家就能看的非常清晰
好了。通用接口部分我们可以自由使用,接口再wavemain.cpp中都已经给我们做好了流式驱动通用的接口。大家只要简单的了解下格式就可以很容易的去使用他。
现在,我们准备自由发挥了。在自由发挥前,我们再做个热身运动,看一看wavemain.cpp.
以上的部分就是我们做APP程序最终的接口部分了。我们会用到
WAV_IOControl作为最后的app调用的入口来对那些看的眼花缭乱的case进行调用操作。关于CASE和case所对应的函数就是针对不同的芯片处理的不同功能,针对不同的芯片有不同的处理函数实现,这个需要大家静下心来仔细阅读芯片的datasheet了。
下一篇我们就来一起看看WM9715这个传说中的芯片。很牛X的。
//Author:Mercury Xu
//Date:2008-12-05
//Descrption:聲音作為WinCE系統中一個比較基礎的配置大家已經都不會陌生。
// 本文主要是總結下作者在調試WM9715聲卡驅動芯片
// 過程中遇到的一些問題
//OS:WinCE5.0
/
正文:
最近一直在調試關於WM9715的東東,整體調試下來感覺9715的確是個很好很強大的芯片。下面我們按照我的開發思路來整理下關於9715開發的一些心得體會。
首先我們來看下WinCE的聲音處理部分的一些基礎知識。如果您對這一部分已經爛熟於心了,請跳到下一個segment。如果您對WM971X系列爛熟於心了。。I'm sorry。看我的文实在是浪费您的时间了。
另外。大家可以参考下《Windows CE实用开发技术》之 8.10 驱动程序实例分析,這裡張老師已經將驅動的結構講的非常清晰了。大家可以參考下。張老師的書中所提及的是ES1371,我以下的文章針對芯片為WM9715.關於9715的datasheet,大家可以參考wolfson的官方站上的datasheet。
Segment I: WinCE的声音驱动部分
WinCE的声音驱动其实很清晰的给了我们大家。以samsung24X0系来说。你会在X:/WINCE500/PUBLIC/COMMON/OAK/CSP/ARM/SAMSUNG/S3C2410X/WAVEDEV类似的目录下找到他们。以下为我Tree以后他的文件结构
- 文件夹 PATH 列表
- 卷序列号码为 000028F4 409E:08D7
- C:.
- │ audiosys.h
- │ devctxt.cpp
- │ devctxt.h
- │ hwctxt.cpp
- │ hwctxt.h
- │ i2s.cpp
- │ i2s.h
- │ input.cpp
- │ makefile
- │ midinote.cpp
- │ midistrm.cpp
- │ midistrm.h
- │ mixerdrv.cpp
- │ mixerdrv.h
- │ output.cpp
- │ sources
- │ strmctxt.cpp
- │ strmctxt.h
- │ wavemain.cpp
- │ wavemain.h
- │ wavepdd.h
- │ wfmtmidi.h
- │
- └─obj
- └─ARMV4I
- └─retail
- devctxt.obj
- hwctxt.obj
- i2s.obj
- input.obj
- midinote.obj
- midistrm.obj
- mixerdrv.obj
- output.obj
- strmctxt.obj
- wavemain.obj
- _objects.mac
- │ hwctxt.cpp
- │ hwctxt.h
- │ wavemain.cpp
- │ wavemain.h
我们先看看HWCTXT.h文件中的一些信息,直接了解他的接口部分内容。
- class HardwareContext
- {
- public:
- static BOOL CreateHWContext(DWORD Index);
- HardwareContext();
- ~HardwareContext();
- void Lock() {EnterCriticalSection(&m_Lock);}
- void Unlock() {LeaveCriticalSection(&m_Lock);}
- DWORD GetNumInputDevices() {return 1;}
- DWORD GetNumOutputDevices() {return 1;}
- DWORD GetNumMixerDevices() {return 1;}
- DeviceContext *GetInputDeviceContext(UINT DeviceId)
- {
- return &m_InputDeviceContext;
- }
- DeviceContext *GetOutputDeviceContext(UINT DeviceId)
- {
- return &m_OutputDeviceContext;
- }
- BOOL Init(DWORD Index);
- BOOL Deinit();
- void PowerUp();
- void PowerDown();
- BOOL StartInputDMA();
- BOOL StartOutputDMA();
- void StopInputDMA();
- void StopOutputDMA();
- void InterruptThread();
- DWORD GetOutputGain (void);
- MMRESULT SetOutputGain (DWORD dwVolume);
- DWORD GetInputGain (void);
- MMRESULT SetInputGain (DWORD dwVolume);
- BOOL GetOutputMute (void);
- MMRESULT SetOutputMute (BOOL fMute);
- BOOL GetInputMute (void);
- MMRESULT SetInputMute (BOOL fMute);
- protected:
- DWORD m_dwOutputGain;
- DWORD m_dwInputGain;
- BOOL m_fInputMute;
- BOOL m_fOutputMute;
- DWORD m_MicrophoneRouting;
- DWORD m_SpeakerRouting;
- DWORD m_InternalRouting;
- DWORD m_MasterOutputGain;
- BOOL InitInterruptThread();
- BOOL InitInputDMA();
- BOOL InitOutputDMA();
- BOOL Codec_channel();
- BOOL InitCodec();
- BOOL MapRegisters();
- BOOL UnmapRegisters();
- BOOL MapDMABuffers();
- BOOL UnmapDMABuffers();
- ULONG TransferInputBuffer(ULONG NumBuf);
- ULONG TransferOutputBuffer(ULONG NumBuf);
- ULONG TransferInputBuffers(DWORD dwDCSR);
- ULONG TransferOutputBuffers(DWORD dwDCSR);
- DWORD GetInterruptThreadPriority();
- DWORD m_DriverIndex;
- CRITICAL_SECTION m_Lock;
- BOOL m_Initialized;
- BOOL m_InPowerHandler;
- DWORD m_dwSysintrOutput;
- DWORD m_dwSysintrInput;
- InputDeviceContext m_InputDeviceContext;
- OutputDeviceContext m_OutputDeviceContext;
- PBYTE m_Input_pbDMA_PAGES[2];
- PBYTE m_Output_pbDMA_PAGES[2];
- BOOL m_InputDMARunning;
- BOOL m_OutputDMARunning;
- ULONG m_OutBytes[2];
- ULONG m_InBytes[2];
- WORD m_nOutputVolume; // Current HW Playback Volume
- WORD m_nInputVolume; // Current HW Input (Microphone) Volume
- HANDLE m_hAudioInterrupt; // Handle to Audio Interrupt event.
- HANDLE m_hAudioInterruptThread; // Handle to thread which waits on an audio interrupt event.
- //----------------------- Platform specific members ----------------------------------
- DWORD m_OutputDMAStatus; // Output DMA channel's status
- DWORD m_InputDMAStatus; // Input DMA channel's status
- BOOL AudioMute(DWORD channel, BOOL bMute);
- //------------------------------------------------------------------------------------
- };
- void CallInterruptThread(HardwareContext *pHWContext);
- //----------------------------------- Helper Functions and Macros ----------------------------------------
- //======== Record =========
- #define ioRecordPointerLow (g_pDMAregs->DIDST1)
- #define ioRecordPointerHigh (g_pDMAregs->DIDST1)
- #define RECORD_DMA_BUFFER_PHYS (g_PhysDMABufferAddr.LowPart + 2 * AUDIO_DMA_PAGE_SIZE)
- #define AUDIO_RESET_RECORD_POINTER() {ioRecordPointerLow = (RECORD_DMA_BUFFER_PHYS); /
- ioRecordPointerHigh = (RECORD_DMA_BUFFER_PHYS+ AUDIO_DMA_PAGE_SIZE); }
- #define AUDIO_IN_CLEAR_INTERRUPTS() (g_pDMAregs->DCON1 = g_pDMAregs->DCON1)
- #define AUDIO_IN_DMA_ENABLE() { g_pDMAregs->DMASKTRIG1 = ENABLE_DMA_CHANNEL; /
- g_pDMAregs->DMASKTRIG1 &= STOP_DMA_TRANSFER; /
- g_pIISregs->IISFCON |= ( RECEIVE_FIFO_ACCESS_DMA | RECEIVE_FIFO_ENABLE); /
- g_pIISregs->IISCON |= RECEIVE_DMA_REQUEST_ENABLE; }
- #define AUDIO_IN_DMA_DISABLE() { StopI2SClock(); /
- g_pIISregs->IISCON &= ~RECEIVE_DMA_REQUEST_ENABLE; /
- g_pIISregs->IISFCON &= ( RECEIVE_FIFO_ACCESS_DMA | RECEIVE_FIFO_ENABLE); /
- g_pDMAregs->DMASKTRIG1 |= STOP_DMA_TRANSFER; }
- #define SELECT_AUDIO_DMA_INPUT_BUFFER_A() (g_pDMAregs->DIDST1 = (int)(g_PhysDMABufferAddr.LowPart+2*AUDIO_DMA_PAGE_SIZE) )
- #define SELECT_AUDIO_DMA_INPUT_BUFFER_B() (g_pDMAregs->DIDST1 = (int)(g_PhysDMABufferAddr.LowPart+3*AUDIO_DMA_PAGE_SIZE) )
- //======== Playback =========
- #define ioPlaybackPointerLow (g_pDMAregs->DISRC2)
- #define ioPlaybackPointerHigh (g_pDMAregs->DISRC2)
- #define AUDIO_RESET_PLAYBACK_POINTER() {ioPlaybackPointerLow = (g_PhysDMABufferAddr.LowPart); /
- ioPlaybackPointerHigh = (g_PhysDMABufferAddr.LowPart + AUDIO_DMA_PAGE_SIZE); }
- #define AUDIO_OUT_CLEAR_INTERRUPTS() (g_pDMAregs->DCON2 = g_pDMAregs->DCON2)
- #define AUDIO_OUT_DMA_ENABLE() { StartI2SClock(); /
- g_pDMAregs->DMASKTRIG2 |= ENABLE_DMA_CHANNEL; }
- #define AUDIO_OUT_DMA_DISABLE() { StopI2SClock(); g_pDMAregs->DMASKTRIG2 &= ~ENABLE_DMA_CHANNEL; }
- #define SELECT_AUDIO_DMA_OUTPUT_BUFFER_A() (g_pDMAregs->DISRC2 = (int)(g_PhysDMABufferAddr.LowPart) )
- #define SELECT_AUDIO_DMA_OUTPUT_BUFFER_B() (g_pDMAregs->DISRC2 = (int)(g_PhysDMABufferAddr.LowPart+AUDIO_DMA_PAGE_SIZE) )
- //------------------------------------------ Externs ----------------------------------------------
- extern HardwareContext *g_pHWContext;
- class HardwareContext
- {
- public:
-
- //通用接口部分
- protected:
-
//保护接口部分
- //----------------------- Platform specific members ----------------------------------
- //成员
- //------------------------------------------------------------------------------------
- };
- void CallInterruptThread(HardwareContext *pHWContext);
- //----------------------------------- Helper Functions and Macros ----------------------------------------
- //======== Record =========
- //------------------------------------------ Externs ----------------------------------------------
- extern HardwareContext *g_pHWContext;
现在,我们准备自由发挥了。在自由发挥前,我们再做个热身运动,看一看wavemain.cpp.
- BOOL CALLBACK DllMain(HANDLE hDLL,
- DWORD dwReason,
- LPVOID lpvReserved)
- {
- switch (dwReason) {
- case DLL_PROCESS_ATTACH :
- DEBUGREGISTER((HINSTANCE)hDLL);
- DisableThreadLibraryCalls((HMODULE) hDLL);
- break;
- case DLL_PROCESS_DETACH :
- break;
- case DLL_THREAD_DETACH :
- break;
- case DLL_THREAD_ATTACH :
- break;
- default :
- break;
- }
- return TRUE;
- }
- // -----------------------------------------------------------------------------
- //
- // @doc WDEV_EXT
- //
- // @topic WAV Device Interface | Implements the WAVEDEV.DLL device
- // interface. These functions are required for the device to
- // be loaded by DEVICE.EXE.
- //
- // @xref <nl>
- // <f WAV_Init>, <nl>
- // <f WAV_Deinit>, <nl>
- // <f WAV_Open>, <nl>
- // <f WAV_Close>, <nl>
- // <f WAV_Read>, <nl>
- // <f WAV_Write>, <nl>
- // <f WAV_Seek>, <nl>
- // <f WAV_PowerUp>, <nl>
- // <f WAV_PowerDown>, <nl>
- // <f WAV_IOControl> <nl>
- //
- // -----------------------------------------------------------------------------
- //
- // @doc WDEV_EXT
- //
- ---------
- extern "C" DWORD WAV_Init(DWORD Index)
- {
- return((DWORD)HardwareContext::CreateHWContext(Index));
- }
- extern "C" BOOL WAV_Deinit(DWORD dwData)
- {
- return(g_pHWContext->Deinit());
- }
- extern "C" PDWORD WAV_Open( DWORD dwData,
- DWORD dwAccess,
- DWORD dwShareMode)
- {
- // allocate and return handle context to efficiently verify caller trust level
- return new DWORD(NULL); // assume untrusted. Can't tell for sure until WAV_IoControl
- }
- extern "C" BOOL WAV_Close(PDWORD pdwData)
- {
- // we trust the device manager to give us a valid context to free.
- delete pdwData;
- return(TRUE);
- }
- extern "C" DWORD WAV_Read(DWORD dwData,
- LPVOID pBuf,
- DWORD Len)
- {
- // Return length read
- return(0);
- }
- extern "C" DWORD WAV_Write(DWORD dwData,
- LPCVOID pBuf,
- DWORD Len)
- {
- // return number of bytes written (or -1 for error)
- return(0);
- }
- extern "C" DWORD WAV_Seek(DWORD dwData,
- long pos,
- DWORD type)
- {
- // return an error
- return((DWORD)-1);
- }
- extern "C" VOID WAV_PowerUp(VOID)
- {
- g_pHWContext->PowerUp();
- return;
- }
- extern "C" VOID WAV_PowerDown(VOID)
- {
- g_pHWContext->PowerDown();
- return;
- }
- BOOL HandleWaveMessage(PMMDRV_MESSAGE_PARAMS pParams, DWORD *pdwResult)
- {
- // set the error code to be no error first
- SetLastError(MMSYSERR_NOERROR);
- UINT uMsg = pParams->uMsg;
- UINT uDeviceId = pParams->uDeviceId;
- DWORD dwParam1 = pParams->dwParam1;
- DWORD dwParam2 = pParams->dwParam2;
- DWORD dwUser = pParams->dwUser;
- StreamContext *pStreamContext = (StreamContext *)dwUser;
- DWORD dwRet;
- g_pHWContext->Lock();
- switch (uMsg)
- {
- //很多个CASE,我们就省略掉了,大家自己看看找到自己要用的
- default:
- dwRet = MMSYSERR_NOTSUPPORTED;
- }
- g_pHWContext->Unlock();
- // Pass the return code back via pBufOut
- //这个地方的处理很奇妙哦。很好的方法。
- if (pdwResult)
- {
- *pdwResult = dwRet;
- }
- return(TRUE);
- }
- extern "C" BOOL WAV_IOControl(PDWORD pdwOpenData,
- DWORD dwCode,
- PBYTE pBufIn,
- DWORD dwLenIn,
- PBYTE pBufOut,
- DWORD dwLenOut,
- PDWORD pdwActualOut)
- {
- // check caller trust. if context hasn't been initialized, load from CeGetCallerTrust.
- if (*pdwOpenData != OEM_CERTIFY_TRUST) {
- if (OEM_CERTIFY_TRUST != (*pdwOpenData = CeGetCallerTrust())) {
- PRINTMSG(ZONE_WARN, (TEXT("WAV_IoControl: untrusted process/r/n")));
- SetLastError(ERROR_ACCESS_DENIED);
- return FALSE;
- }
- }
- //以下为无敌的出错处理部分,非常指的我们学习的。
- _try
- {
- switch (dwCode)
- {
- case IOCTL_MIX_MESSAGE:
- return HandleMixerMessage((PMMDRV_MESSAGE_PARAMS)pBufIn, (DWORD *)pBufOut);
- case IOCTL_WAV_MESSAGE:
- return HandleWaveMessage((PMMDRV_MESSAGE_PARAMS)pBufIn, (DWORD *)pBufOut);
- }
- }
- _except (GetExceptionCode() == STATUS_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
- {
- RETAILMSG(1, (TEXT("EXCEPTION IN WAV_IOControl!!!!/r/n")));
- SetLastError(E_FAIL);
- }
下一篇我们就来一起看看WM9715这个传说中的芯片。很牛X的。