關於基於WinCE下的聲音系統調試的一些經驗總結之驱动程式部分

 

關於基於WinCE下的聲音系統調試的一些經驗總結之驱动程式部分

分类: 工作积累-WINCE应用层 1100人阅读 评论(2) 收藏 举报
/
//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以后他的文件结构
  1. 文件夹 PATH 列表
  2. 卷序列号码为 000028F4 409E:08D7
  3. C:.
  4. │  audiosys.h
  5. │  devctxt.cpp
  6. │  devctxt.h
  7. │  hwctxt.cpp
  8. │  hwctxt.h
  9. │  i2s.cpp
  10. │  i2s.h
  11. │  input.cpp
  12. │  makefile
  13. │  midinote.cpp
  14. │  midistrm.cpp
  15. │  midistrm.h
  16. │  mixerdrv.cpp
  17. │  mixerdrv.h
  18. │  output.cpp
  19. │  sources
  20. │  strmctxt.cpp
  21. │  strmctxt.h
  22. │  wavemain.cpp
  23. │  wavemain.h
  24. │  wavepdd.h
  25. │  wfmtmidi.h
  26. │ 
  27. └─obj
  28.     └─ARMV4I
  29.         └─retail
  30.                 devctxt.obj
  31.                 hwctxt.obj
  32.                 i2s.obj
  33.                 input.obj
  34.                 midinote.obj
  35.                 midistrm.obj
  36.                 mixerdrv.obj
  37.                 output.obj
  38.                 strmctxt.obj
  39.                 wavemain.obj
  40.                 _objects.mac
很清晰的程序结构。其实很多公司的都是参照这个结构来定制自己声音部分的程式代码。而我们需要注意的这是以下几个文件:
  1. │  hwctxt.cpp
  2. │  hwctxt.h
  3. │  wavemain.cpp
  4. │  wavemain.h
这几个基本上算是做好了对声音驱动部分的所有接口。如果您要基于WinCE5.0开发一些声音控制方面的App.第一个方法您可以对注册表的一些键值进行修改。比如说触摸屏按键音,音频音量等等。另外,你也可以通过操作以上提及到的文件中的一些接口来对声音处理芯片进行控制,已实现我们所要实现的效果。这里我只分析下我说到的几个文件。其他的例如I2S之类的大家可以看一下。(I2S是一种通讯方式,数字音频传输采用这种方式来处理,WM9715就是I2S来传送系统部分的声音。)

我们先看看HWCTXT.h文件中的一些信息,直接了解他的接口部分内容。

  1. class HardwareContext
  2. {
  3. public:
  4.     static BOOL CreateHWContext(DWORD Index);
  5.     HardwareContext();
  6.     ~HardwareContext();
  7.     void Lock()   {EnterCriticalSection(&m_Lock);}
  8.     void Unlock() {LeaveCriticalSection(&m_Lock);}
  9.     DWORD GetNumInputDevices()  {return 1;}
  10.     DWORD GetNumOutputDevices() {return 1;}
  11.     DWORD GetNumMixerDevices()  {return 1;}
  12.     DeviceContext *GetInputDeviceContext(UINT DeviceId)
  13.     {
  14.         return &m_InputDeviceContext;
  15.     }
  16.     DeviceContext *GetOutputDeviceContext(UINT DeviceId)
  17.     {
  18.         return &m_OutputDeviceContext;
  19.     }
  20.     BOOL Init(DWORD Index);                                     
  21.     BOOL Deinit();
  22.     void PowerUp();
  23.     void PowerDown();
  24.     BOOL StartInputDMA();
  25.     BOOL StartOutputDMA();
  26.     void StopInputDMA();
  27.     void StopOutputDMA();
  28.     void InterruptThread();
  29.     DWORD       GetOutputGain (void);
  30.     MMRESULT    SetOutputGain (DWORD dwVolume);
  31.     DWORD       GetInputGain (void);
  32.     MMRESULT    SetInputGain (DWORD dwVolume);
  33.     BOOL        GetOutputMute (void);
  34.     MMRESULT    SetOutputMute (BOOL fMute);
  35.     BOOL        GetInputMute (void);
  36.     MMRESULT    SetInputMute (BOOL fMute);
  37. protected:
  38.     DWORD m_dwOutputGain;
  39.     DWORD m_dwInputGain;
  40.     BOOL  m_fInputMute;
  41.     BOOL  m_fOutputMute;
  42.     DWORD m_MicrophoneRouting;
  43.     DWORD m_SpeakerRouting;
  44.     DWORD m_InternalRouting;
  45.     DWORD m_MasterOutputGain;
  46.     BOOL InitInterruptThread();
  47.     BOOL InitInputDMA();
  48.     BOOL InitOutputDMA();
  49.     BOOL Codec_channel();
  50.     BOOL InitCodec();
  51.     
  52.     BOOL MapRegisters();
  53.     BOOL UnmapRegisters();
  54.     BOOL MapDMABuffers();
  55.     BOOL UnmapDMABuffers();
  56.     ULONG TransferInputBuffer(ULONG NumBuf);
  57.     ULONG TransferOutputBuffer(ULONG NumBuf);
  58.     ULONG TransferInputBuffers(DWORD dwDCSR);
  59.     ULONG TransferOutputBuffers(DWORD dwDCSR);
  60.     DWORD GetInterruptThreadPriority();
  61.     DWORD m_DriverIndex;
  62.     CRITICAL_SECTION m_Lock;
  63.     BOOL m_Initialized;
  64.     BOOL m_InPowerHandler;
  65.     DWORD m_dwSysintrOutput;
  66.     DWORD m_dwSysintrInput;
  67.     InputDeviceContext m_InputDeviceContext;
  68.     OutputDeviceContext m_OutputDeviceContext;
  69.     PBYTE       m_Input_pbDMA_PAGES[2];
  70.     PBYTE       m_Output_pbDMA_PAGES[2];
  71.     BOOL m_InputDMARunning;
  72.     BOOL m_OutputDMARunning;
  73.     ULONG m_OutBytes[2];
  74.     ULONG m_InBytes[2];
  75.     WORD  m_nOutputVolume;                  // Current HW Playback Volume 
  76.     WORD  m_nInputVolume;                   // Current HW Input (Microphone) Volume 
  77.     HANDLE m_hAudioInterrupt;               // Handle to Audio Interrupt event.
  78.     HANDLE m_hAudioInterruptThread;         // Handle to thread which waits on an audio interrupt event.
  79.     //----------------------- Platform specific members ----------------------------------
  80.     DWORD  m_OutputDMAStatus;                   // Output DMA channel's status
  81.     DWORD  m_InputDMAStatus;                    // Input DMA channel's status
  82.     BOOL AudioMute(DWORD channel, BOOL bMute);  
  83.     //------------------------------------------------------------------------------------
  84. };
  85. void CallInterruptThread(HardwareContext *pHWContext);
  86. //----------------------------------- Helper Functions and Macros ----------------------------------------
  87. //======== Record =========
  88. #define ioRecordPointerLow                      (g_pDMAregs->DIDST1)
  89. #define ioRecordPointerHigh                     (g_pDMAregs->DIDST1)
  90. #define RECORD_DMA_BUFFER_PHYS                  (g_PhysDMABufferAddr.LowPart + 2 * AUDIO_DMA_PAGE_SIZE)
  91. #define AUDIO_RESET_RECORD_POINTER()            {ioRecordPointerLow  = (RECORD_DMA_BUFFER_PHYS);    /
  92.                                                  ioRecordPointerHigh = (RECORD_DMA_BUFFER_PHYS+ AUDIO_DMA_PAGE_SIZE); }
  93. #define AUDIO_IN_CLEAR_INTERRUPTS()             (g_pDMAregs->DCON1 = g_pDMAregs->DCON1)
  94. #define AUDIO_IN_DMA_ENABLE()                   {   g_pDMAregs->DMASKTRIG1 = ENABLE_DMA_CHANNEL; /
  95.                                                     g_pDMAregs->DMASKTRIG1 &= STOP_DMA_TRANSFER; /
  96.                                                     g_pIISregs->IISFCON |= ( RECEIVE_FIFO_ACCESS_DMA  | RECEIVE_FIFO_ENABLE);   /
  97.                                                     g_pIISregs->IISCON  |= RECEIVE_DMA_REQUEST_ENABLE;   }
  98.                                                     
  99. #define AUDIO_IN_DMA_DISABLE()                  {   StopI2SClock(); /
  100.                                                     g_pIISregs->IISCON &= ~RECEIVE_DMA_REQUEST_ENABLE;  /
  101.                                                     g_pIISregs->IISFCON &= ( RECEIVE_FIFO_ACCESS_DMA  | RECEIVE_FIFO_ENABLE);   /
  102.                                                     g_pDMAregs->DMASKTRIG1 |= STOP_DMA_TRANSFER;    }
  103. #define SELECT_AUDIO_DMA_INPUT_BUFFER_A()       (g_pDMAregs->DIDST1 = (int)(g_PhysDMABufferAddr.LowPart+2*AUDIO_DMA_PAGE_SIZE) )
  104. #define SELECT_AUDIO_DMA_INPUT_BUFFER_B()       (g_pDMAregs->DIDST1 = (int)(g_PhysDMABufferAddr.LowPart+3*AUDIO_DMA_PAGE_SIZE) )
  105. //======== Playback =========
  106. #define ioPlaybackPointerLow                    (g_pDMAregs->DISRC2)
  107. #define ioPlaybackPointerHigh                   (g_pDMAregs->DISRC2)
  108. #define AUDIO_RESET_PLAYBACK_POINTER()          {ioPlaybackPointerLow  = (g_PhysDMABufferAddr.LowPart); /
  109.                                                  ioPlaybackPointerHigh = (g_PhysDMABufferAddr.LowPart + AUDIO_DMA_PAGE_SIZE); }   
  110. #define AUDIO_OUT_CLEAR_INTERRUPTS()            (g_pDMAregs->DCON2 = g_pDMAregs->DCON2)
  111. #define AUDIO_OUT_DMA_ENABLE()                  {   StartI2SClock(); /
  112.                                                     g_pDMAregs->DMASKTRIG2 |= ENABLE_DMA_CHANNEL;  }
  113.                                                     
  114. #define AUDIO_OUT_DMA_DISABLE()                 { StopI2SClock();  g_pDMAregs->DMASKTRIG2 &= ~ENABLE_DMA_CHANNEL; }
  115. #define SELECT_AUDIO_DMA_OUTPUT_BUFFER_A()      (g_pDMAregs->DISRC2 = (int)(g_PhysDMABufferAddr.LowPart) )
  116. #define SELECT_AUDIO_DMA_OUTPUT_BUFFER_B()      (g_pDMAregs->DISRC2 = (int)(g_PhysDMABufferAddr.LowPart+AUDIO_DMA_PAGE_SIZE) )
  117. //------------------------------------------ Externs ----------------------------------------------
  118. extern HardwareContext *g_pHWContext;
好了,到這裡大家估計已經基本上暈了,我來給大家刪除點東西。大家就能看的非常清晰

  1. class HardwareContext
  2. {
  3. public:
  4.   
  5. //通用接口部分


  6. protected:
  7.  
    //保护接口部分


  8.     //----------------------- Platform specific members ----------------------------------
  9. //成员
  10.     //------------------------------------------------------------------------------------

  11. };

  12. void CallInterruptThread(HardwareContext *pHWContext);


  13. //----------------------------------- Helper Functions and Macros ----------------------------------------

  14. //======== Record =========

  15. //------------------------------------------ Externs ----------------------------------------------
  16. extern HardwareContext *g_pHWContext;
好了。通用接口部分我们可以自由使用,接口再wavemain.cpp中都已经给我们做好了流式驱动通用的接口。大家只要简单的了解下格式就可以很容易的去使用他。

现在,我们准备自由发挥了。在自由发挥前,我们再做个热身运动,看一看wavemain.cpp.

  1. BOOL CALLBACK DllMain(HANDLE hDLL,
  2.                       DWORD dwReason,
  3.                       LPVOID lpvReserved)
  4. {
  5.     switch (dwReason) {
  6.         case DLL_PROCESS_ATTACH :
  7.             DEBUGREGISTER((HINSTANCE)hDLL);
  8.             DisableThreadLibraryCalls((HMODULE) hDLL);
  9.             break;
  10.         case DLL_PROCESS_DETACH :
  11.             break;
  12.         case DLL_THREAD_DETACH :
  13.             break;
  14.         case DLL_THREAD_ATTACH :
  15.             break;
  16.         default :
  17.             break;
  18.     }
  19.     return TRUE;
  20. }
  21. // -----------------------------------------------------------------------------
  22. //
  23. // @doc     WDEV_EXT
  24. //
  25. // @topic   WAV Device Interface | Implements the WAVEDEV.DLL device
  26. //          interface. These functions are required for the device to
  27. //          be loaded by DEVICE.EXE.
  28. //
  29. // @xref                          <nl>
  30. //          <f WAV_Init>,         <nl>
  31. //          <f WAV_Deinit>,       <nl>
  32. //          <f WAV_Open>,         <nl>
  33. //          <f WAV_Close>,        <nl>
  34. //          <f WAV_Read>,         <nl>
  35. //          <f WAV_Write>,        <nl>
  36. //          <f WAV_Seek>,         <nl>
  37. //          <f WAV_PowerUp>,      <nl>
  38. //          <f WAV_PowerDown>,    <nl>
  39. //          <f WAV_IOControl>     <nl>
  40. //
  41. // -----------------------------------------------------------------------------
  42. //
  43. // @doc     WDEV_EXT
  44. //
  45. ---------
  46. extern "C" DWORD WAV_Init(DWORD Index)
  47. {
  48.     return((DWORD)HardwareContext::CreateHWContext(Index));
  49. }

  50. extern "C" BOOL WAV_Deinit(DWORD dwData)
  51. {
  52.     return(g_pHWContext->Deinit());
  53. }

  54. extern "C" PDWORD WAV_Open( DWORD dwData,
  55.               DWORD dwAccess,
  56.               DWORD dwShareMode)
  57. {
  58.     // allocate and return handle context to efficiently verify caller trust level
  59.     return new DWORD(NULL); // assume untrusted. Can't tell for sure until WAV_IoControl
  60. }

  61. extern "C" BOOL WAV_Close(PDWORD pdwData)
  62. {
  63.     // we trust the device manager to give us a valid context to free.
  64.     delete pdwData;
  65.     return(TRUE);
  66. }

  67. extern "C" DWORD WAV_Read(DWORD dwData,
  68.                LPVOID pBuf,
  69.                DWORD Len)
  70. {
  71.     // Return length read
  72.     return(0);
  73. }

  74. extern "C" DWORD WAV_Write(DWORD dwData,
  75.                 LPCVOID pBuf,
  76.                 DWORD Len)
  77. {
  78.     // return number of bytes written (or -1 for error)
  79.     return(0);
  80. }

  81. extern "C" DWORD WAV_Seek(DWORD dwData,
  82.                long pos,
  83.                DWORD type)
  84. {
  85.     // return an error
  86.     return((DWORD)-1);
  87. }

  88. extern "C" VOID WAV_PowerUp(VOID)
  89. {
  90.     g_pHWContext->PowerUp();
  91.     return;
  92. }

  93. extern "C" VOID WAV_PowerDown(VOID)
  94. {
  95.     g_pHWContext->PowerDown();
  96.     return;
  97. }
  98. BOOL HandleWaveMessage(PMMDRV_MESSAGE_PARAMS pParams, DWORD *pdwResult)
  99. {
  100.     //  set the error code to be no error first
  101.     SetLastError(MMSYSERR_NOERROR);
  102.     UINT uMsg = pParams->uMsg;
  103.     UINT uDeviceId = pParams->uDeviceId;
  104.     DWORD dwParam1 = pParams->dwParam1;
  105.     DWORD dwParam2 = pParams->dwParam2;
  106.     DWORD dwUser   = pParams->dwUser;
  107.     StreamContext *pStreamContext = (StreamContext *)dwUser;
  108.     DWORD dwRet;
  109.     g_pHWContext->Lock();
  110.     switch (uMsg)
  111.     {
  112.         //很多个CASE,我们就省略掉了,大家自己看看找到自己要用的           
  113.         default:
  114.         dwRet  = MMSYSERR_NOTSUPPORTED;
  115.     }
  116.     g_pHWContext->Unlock();
  117.     // Pass the return code back via pBufOut
  118.     //这个地方的处理很奇妙哦。很好的方法。
  119.     if (pdwResult)
  120.     {
  121.         *pdwResult = dwRet;
  122.     }
  123.     return(TRUE);
  124. }

  125. extern "C" BOOL WAV_IOControl(PDWORD  pdwOpenData,
  126.                    DWORD  dwCode,
  127.                    PBYTE  pBufIn,
  128.                    DWORD  dwLenIn,
  129.                    PBYTE  pBufOut,
  130.                    DWORD  dwLenOut,
  131.                    PDWORD pdwActualOut)
  132. {
  133.     // check caller trust. if context hasn't been initialized, load from CeGetCallerTrust.
  134.     if (*pdwOpenData != OEM_CERTIFY_TRUST) {
  135.         if (OEM_CERTIFY_TRUST != (*pdwOpenData = CeGetCallerTrust())) {
  136.             PRINTMSG(ZONE_WARN, (TEXT("WAV_IoControl: untrusted process/r/n")));
  137.             SetLastError(ERROR_ACCESS_DENIED);
  138.             return FALSE;
  139.         }
  140.     }
  141. //以下为无敌的出错处理部分,非常指的我们学习的。
  142.     _try
  143.     {
  144.         switch (dwCode)
  145.         {
  146.         case IOCTL_MIX_MESSAGE:
  147.                         return HandleMixerMessage((PMMDRV_MESSAGE_PARAMS)pBufIn, (DWORD *)pBufOut);
  148.         case IOCTL_WAV_MESSAGE:
  149.             return HandleWaveMessage((PMMDRV_MESSAGE_PARAMS)pBufIn, (DWORD *)pBufOut);
  150.         }
  151.     }
  152.     _except (GetExceptionCode() == STATUS_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  153.     {
  154.         RETAILMSG(1, (TEXT("EXCEPTION IN WAV_IOControl!!!!/r/n")));
  155.         SetLastError(E_FAIL);
  156.     }
以上的部分就是我们做APP程序最终的接口部分了。我们会用到 WAV_IOControl作为最后的app调用的入口来对那些看的眼花缭乱的case进行调用操作。关于CASE和case所对应的函数就是针对不同的芯片处理的不同功能,针对不同的芯片有不同的处理函数实现,这个需要大家静下心来仔细阅读芯片的datasheet了。

下一篇我们就来一起看看WM9715这个传说中的芯片。很牛X的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值