hwctxt.cpp
上传用户:qiulin1960
上传日期:2013-10-16
资源大小:2844k
文件大小:52k
源码类别:

Windows CE

开发平台:

Windows_Unix

  1. //
  2. // Copyright (c) Microsoft Corporation.  All rights reserved.
  3. //
  4. //
  5. // Use of this source code is subject to the terms of the Microsoft end-user
  6. // license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
  7. // If you did not accept the terms of the EULA, you are not authorized to use
  8. // this source code. For a copy of the EULA, please see the LICENSE.RTF on your
  9. // install media.
  10. //
  11. /*++
  12. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  13. ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  14. THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  15. PARTICULAR PURPOSE.
  16.    
  17. Module Name: HWCTXT.CPP
  18. Abstract: Platform dependent code for the mixing audio driver.
  19. Notes: The following file contains all the hardware specific code
  20. for the mixing audio driver.  This code's primary responsibilities
  21. are:
  22. * Initialize audio hardware (including codec chip)
  23. * Schedule DMA operations (move data from/to buffers)
  24. * Handle audio interrupts
  25. All other tasks (mixing, volume control, etc.) are handled by the "upper"
  26. layers of this driver.
  27. ****** IMPORTANT ******
  28. Presently, audio input (i.e. RECORD functionality) IS NOT implemented.  On 
  29. this platform, in order to record the TLV320AIC codec chip needs to be 
  30. configured as MASTER and the CPU's I2S controller configured as SLAVE.  
  31. Unfortunately, a hardware bug in the current Samsung CPU samples prevents 
  32. SLAVE mode from working properly.  As a result, only audio playback is 
  33. supported by configuring the CPU I2S controller as MASTER and the audio
  34. codec chip as SLAVE.  
  35. The final revision of the Samsung SC2410 CPU is expected to fix this 
  36. hardware bug.  Once this issue is resolved, the CPU's I2S controller 
  37. (look at I2S.CPP) should be configured in SLAVE mode and the audio codec 
  38. chip (see InitCodec() below) should be configured as MASTER.  With these
  39. changes, the following routines need to be implemented:
  40. InitInputDMA() - initialize the input DMA channel
  41. StartInputDMA() - starts DMA operations on the input DMA channel
  42. StopInputDMA() - stops any current DMA operations on the input DMA channel
  43. For the SC2410 CPU, DMA channel 2 can be used for both input and output.  In this,
  44. configuration, however, only one type operation (input or output) can execute.  In 
  45. order to implement simultaneous playback and recording, two things must be done:
  46.  
  47. 1) Input DMA should be moved to DMA Channel 1; Output DMA still uses DMA Channel 2.
  48. 2) Step #3 in InterruptThread() needs to be implemented so that the DMA interrupt
  49.    source (input DMA or output DMA?) can be determined.  The interrupt source needs
  50.    to be determined so that the appropriate buffers can be copied (Steps #4,#5...etc.).
  51. Lastly, the m_OutputDMAStatus and m_InputDMAStatus variables shouldn't need to be modified.  
  52. The logic surrounding these drivers is simply used to determine which buffer (A or B) needs
  53. processing.
  54. Environment: PocketPC Catfish Reference Platform:
  55. Hardware - Samsung SC2410 CPU
  56.    TI TLV320AIC audio codec chip where: 
  57. 1) SPI bus is used for control 
  58. 2) I2S bus is used for data (CPU is master
  59.    and codec chip is slave)
  60. Software - Windows CE 3.0 and later.    
  61. -*/
  62. #include "wavemain.h"
  63. #include <p2.h>
  64. #include "s2440.h"
  65. #include "dma.h"
  66. #include "I2S.h"
  67. #include "utldrv.h"
  68. #include "hwctxt.h"
  69. //#define DMA_FLAG 1
  70. //#define DEBUGMSG(a,b) RETAILMSG(0,b)
  71. #define DMA_CH_MIC 2
  72. #define DMA_CH_OUT 1
  73. #define DELAY_COUNT 0x100000
  74. #define L3M (0x04) // TOUT2 // charlie
  75. #define L3C (0x10) // TCLK0
  76. #define L3D (0x08) // TOUT3
  77. //----- Macro used to send commands to the audio codec chip over the SPI bus -----
  78. // NOTE: The command format is 16 bits: bits[15-9] = register
  79. // bits[8-0] = data command
  80. //
  81. // Refer to the TILV320AC reference guide for details.
  82. //
  83. //#define SEND_CODEC_COMMAND(reg, dat) { SPI_SendWord((reg | dat));  }
  84. int rec_mode=0;
  85. //-------------------------------- Global Variables --------------------------------------
  86. volatile IISreg *v_pIISregs = NULL; // I2S control registers
  87. volatile IOPreg *v_pIOPregs = NULL; // GPIO registers (needed to enable I2S and SPI)
  88. volatile DMAreg *v_pDMAregs = NULL; // DMA registers (needed for I/O on I2S bus)
  89. volatile CLKPWRreg *g_pCLKPWRreg = NULL; // Clock power registers (needed to enable I2S and SPI clocks)
  90. volatile INTreg  *s2440INT  = NULL;
  91. UTL_FASTCALL    g_tblFastCall; // Needed for fast driver->driver calling mechanism
  92. HANDLE          g_hUTLObject = INVALID_HANDLE_VALUE;
  93. HardwareContext *g_pHWContext = NULL;
  94. unsigned int delay_count;
  95. //----------------------------------------------------------------------------------------
  96. DBGPARAM dpCurSettings = {
  97.     TEXT("CONSOLE"), {
  98.         TEXT("0"),TEXT("1"),TEXT("2"),TEXT("3"),
  99.         TEXT("4"),TEXT("5"),TEXT("6"),TEXT("7"),
  100.         TEXT("8"),TEXT("9"),TEXT("10"),TEXT("11"),
  101.         TEXT("12"),TEXT("Function"),TEXT("Init"),TEXT("Error")},
  102.     0x8000  // Errors only, by default
  103. }; 
  104. void dump_audio_input_sfr(void);
  105. // charlie
  106. void _WrL3Addr(unsigned char data)
  107. {
  108.     int i,j;
  109.     v_pIOPregs->rGPBDAT &= ~(L3D|L3M|L3C); //L3D=L/L3M=L(in address mode)/L3C=L
  110.     v_pIOPregs->rGPBDAT |= L3C;                 //L3C=H
  111.     for(j=0;j<10;j++);                     //tsu(L3) > 190ns
  112.     
  113.     //PD[8:6]=L3D:L3C:L3M
  114.     for(i=0;i<8;i++)                         //LSB first
  115.     {
  116. if(data&0x1)                             //if data's LSB is 'H'
  117. {
  118.     v_pIOPregs->rGPBDAT &= ~L3C;             //L3C=L
  119.     v_pIOPregs->rGPBDAT |= L3D;             //L3D=H     
  120.     for(j=0;j<10;j++);                     //tcy(L3) > 500ns
  121.     v_pIOPregs->rGPBDAT |= L3C;             //L3C=H
  122.     v_pIOPregs->rGPBDAT |= L3D;             //L3D=H
  123.     for(j=0;j<10;j++);                     //tcy(L3) > 500ns
  124. }
  125. else                                 //if data's LSB is 'L'
  126. {
  127.     v_pIOPregs->rGPBDAT &= ~L3C;             //L3C=L
  128.     v_pIOPregs->rGPBDAT &= ~L3D;             //L3D=L
  129.     for(j=0;j<10;j++);                     //tcy(L3) > 500ns
  130.     v_pIOPregs->rGPBDAT |= L3C;             //L3C=H
  131.     v_pIOPregs->rGPBDAT &= ~L3D;             //L3D=L
  132.     for(j=0;j<10;j++);                     //tcy(L3) > 500ns
  133. }
  134. data >>=1;
  135.     }
  136.     v_pIOPregs->rGPBDAT|=L3C|L3M;             //L3M=H,L3C=H
  137. }
  138. void _WrL3Data(unsigned char data,int halt)
  139. {
  140.     int i,j;
  141.     if(halt)
  142.     {
  143.         v_pIOPregs->rGPBDAT|=L3C;             //L3C=H(while tstp, L3 interface halt condition)
  144.         for(j=0;j<10;j++);                       //tstp(L3) > 190ns
  145.     }
  146.     v_pIOPregs->rGPBDAT|=L3C|L3M;             //L3M=H(in data transfer mode)
  147.     for(j=0;j<10;j++);                         //tsu(L3)D > 190ns
  148.     //PD[8:6]=L3D:L3C:L3M
  149.     for(i=0;i<8;i++)
  150.     {
  151.         if(data&0x1)                         //if data's LSB is 'H'
  152.         {
  153.     v_pIOPregs->rGPBDAT &= ~L3C;             //L3C=L
  154.             v_pIOPregs->rGPBDAT |= L3D;         //L3D=H
  155.             for(j=0;j<10;j++);                 //tcy(L3) > 500ns
  156.             v_pIOPregs->rGPBDAT |= (L3C|L3D);    //L3C=H,L3D=H
  157.             for(j=0;j<10;j++);                 //tcy(L3) > 500ns
  158.         }
  159.         else //if data's LSB is 'L'
  160.         {
  161.     v_pIOPregs->rGPBDAT &= ~L3C;             //L3C=L
  162.     v_pIOPregs->rGPBDAT &= ~L3D;             //L3D=L
  163.             for(j=0;j<10;j++);                 //tcy(L3) > 500ns
  164.             v_pIOPregs->rGPBDAT |= L3C;         //L3C=H
  165.     v_pIOPregs->rGPBDAT &= ~L3D;             //L3D=L
  166.             for(j=0;j<10;j++);                 //tcy(L3) > 500ns
  167.         }
  168.         data>>=1; //for check next bit
  169.     }
  170.     
  171.     v_pIOPregs->rGPBDAT|=L3C|L3M;             //L3M=H,L3C=H
  172. }
  173. BOOL HardwareContext::CreateHWContext(DWORD Index)
  174. {
  175.     if (g_pHWContext)
  176.     {
  177.         return TRUE;
  178.     }
  179.     g_pHWContext = new HardwareContext;
  180.     if (!g_pHWContext)
  181.     {
  182.         return FALSE;
  183.     }
  184.     return g_pHWContext->Init(Index);
  185. }
  186. HardwareContext::HardwareContext()
  187. : m_InputDeviceContext(), m_OutputDeviceContext()
  188. {
  189.     InitializeCriticalSection(&m_Lock);
  190.     m_Initialized=FALSE;
  191. }
  192. HardwareContext::~HardwareContext()
  193. {
  194.     DeleteCriticalSection(&m_Lock);
  195. }
  196. BOOL HardwareContext::Init(DWORD Index)
  197. {
  198.     if (m_Initialized)
  199.     {
  200.         return FALSE;
  201.     }
  202. //----- 1. Initialize the state/status variables -----
  203.     m_DriverIndex = Index;
  204.     m_IntrAudio         = SYSINTR_AUDIO;
  205.     m_InPowerHandler    = FALSE;
  206.     m_InputDMARunning   = FALSE;
  207.     m_OutputDMARunning  = FALSE;
  208. m_InputDMAStatus = DMA_CLEAR;
  209. m_OutputDMAStatus = DMA_CLEAR;
  210.     //----- 2. Map the necessary descriptory channel and control registers into the driver's virtual address space -----
  211. if(!MapRegisters())
  212. {
  213. DEBUGMSG(ZONE_ERROR, (TEXT("WAVEDEV.DLL:HardwareContext::Init() - Failed to map config registers.rn")));
  214.         goto Exit;
  215. }
  216.     //----- 3. Map the DMA buffers into driver's virtual address space -----
  217.     if(!MapDMABuffers())
  218.     {
  219. DEBUGMSG(ZONE_ERROR, (TEXT("WAVEDEV.DLL:HardwareContext::Init() - Failed to map DMA buffers.rn")));
  220.         goto Exit;
  221.     }
  222.     //----- 4. Configure the Codec -----
  223.     InitCodec();
  224.     
  225. //----- 5. Initialize the interrupt thread -----
  226.     if (!InitInterruptThread())
  227.     {
  228. DEBUGMSG(ZONE_ERROR, (TEXT("WAVEDEV.DLL:HardwareContext::Init() - Failed to initialize interrupt thread.rn")));
  229.         goto Exit;
  230.     }
  231.     m_Initialized=TRUE;
  232.     //
  233.     // Power Manager expects us to init in D0.
  234.     // We are normally in D4 unless we are opened for play.
  235.     // Inform the PM.
  236.     //
  237.     m_Dx = D0;
  238.     DevicePowerNotify(_T("WAV1:"),(_CEDEVICE_POWER_STATE)D4, POWER_NAME);
  239.     
  240. Exit:
  241.     return m_Initialized;
  242. }
  243. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  244. Function: MapRegisters()
  245. Description: Maps the config registers used by both the SPI and
  246. I2S controllers.
  247. Notes: The SPI and I2S controllers both use the GPIO config
  248. registers, so these MUST be initialized FIRST.
  249. Returns: Boolean indicating success
  250. -------------------------------------------------------------------*/
  251. BOOL HardwareContext::MapRegisters()
  252. {
  253.     DWORD dwBytes;
  254.     
  255.     v_pIISregs = (volatile IISreg *)VirtualAlloc(0,sizeof(IISreg),MEM_RESERVE, PAGE_NOACCESS);
  256. if (!v_pIISregs)
  257. {
  258. DEBUGMSG(1,(TEXT("IISreg: VirtualAlloc failed!rn")));
  259. return FALSE;
  260. }
  261. if (!VirtualCopy((PVOID)v_pIISregs,(PVOID)(IIS_BASE),sizeof(IISreg), PAGE_READWRITE | PAGE_NOCACHE ))
  262. {
  263. DEBUGMSG(1,(TEXT("IISreg: VirtualCopy failed!rn")));
  264. return FALSE;
  265. }
  266. v_pIOPregs = (volatile IOPreg *)VirtualAlloc(0,sizeof(IOPreg),MEM_RESERVE, PAGE_NOACCESS);
  267. if (!v_pIOPregs)
  268. {
  269. DEBUGMSG(1,(TEXT("IOPreg: VirtualAlloc failed!rn")));
  270. return FALSE;
  271. }
  272. if (!VirtualCopy((PVOID)v_pIOPregs,(PVOID)(IOP_BASE),sizeof(IOPreg), PAGE_READWRITE | PAGE_NOCACHE ))
  273. {
  274. DEBUGMSG(1,(TEXT("IOPreg: VirtualCopy failed!rn")));
  275. return FALSE;
  276. }
  277. v_pDMAregs = (volatile DMAreg *)VirtualAlloc(0,sizeof(DMAreg),MEM_RESERVE, PAGE_NOACCESS);
  278. if (!v_pDMAregs)
  279. {
  280. DEBUGMSG(1,(TEXT("DMAreg: VirtualAlloc failed!rn")));
  281. return FALSE;
  282. }
  283. if (!VirtualCopy((PVOID)v_pDMAregs,(PVOID)(DMA_BASE),sizeof(DMAreg), PAGE_READWRITE | PAGE_NOCACHE ))
  284. {
  285. DEBUGMSG(1,(TEXT("DMAreg: VirtualCopy failed!rn")));
  286. return FALSE;
  287. }
  288. s2440INT = (volatile INTreg *)VirtualAlloc(0,sizeof(INTreg),MEM_RESERVE, PAGE_NOACCESS);
  289. if (!v_pDMAregs)
  290. {
  291. DEBUGMSG(1,(TEXT("INTreg: VirtualAlloc failed!rn")));
  292. return FALSE;
  293. }
  294. if (!VirtualCopy((PVOID)s2440INT,(PVOID)(INT_BASE),sizeof(INTreg), PAGE_READWRITE | PAGE_NOCACHE ))
  295. {
  296. DEBUGMSG(1,(TEXT("INTreg: VirtualCopy failed!rn")));
  297. return FALSE;
  298. }
  299. g_pCLKPWRreg = (volatile CLKPWRreg *)VirtualAlloc(0,sizeof(CLKPWRreg),MEM_RESERVE, PAGE_NOACCESS);
  300. if (!g_pCLKPWRreg)
  301. {
  302. DEBUGMSG(1,(TEXT("DMAreg: VirtualAlloc failed!rn")));
  303. return FALSE;
  304. }
  305. if (!VirtualCopy((PVOID)g_pCLKPWRreg,(PVOID)(CLKPWR_BASE),sizeof(CLKPWRreg), PAGE_READWRITE | PAGE_NOCACHE ))
  306. {
  307. DEBUGMSG(1,(TEXT("DMAreg: VirtualCopy failed!rn")));
  308. return FALSE;
  309. }
  310.    
  311.     PowerUp();
  312. return TRUE;
  313. MAP_ERROR:
  314. return FALSE;
  315. }
  316. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  317. Function: Deinit()
  318. Description: Deinitializest the hardware: disables DMA channel(s), 
  319. clears any pending interrupts, powers down the audio
  320. codec chip, etc.
  321. Returns: Boolean indicating success
  322. -------------------------------------------------------------------*/
  323. BOOL HardwareContext::Deinit()
  324. {
  325. //----- 1. Disable the input/output channels -----
  326. // AUDIO_IN_DMA_DISABLE();
  327. // v_pIISregs->rIISCON &= ~RECEIVE_DMA_REQUEST_ENABLE;
  328. // v_pIISregs->rIISFCON &= ~( RECEIVE_FIFO_ACCESS_DMA  | RECEIVE_FIFO_ENABLE);
  329. // v_pDMAregs->rDMASKTRIG1 |= STOP_DMA_TRANSFER;
  330. // v_pDMAregs->rDMASKTRIG1 &= ~ENABLE_DMA_CHANNEL;;
  331. //AUDIO_OUT_DMA_DISABLE();
  332. v_pDMAregs->rDMASKTRIG2 |= STOP_DMA_TRANSFER;
  333. v_pDMAregs->rDMASKTRIG2 &= ~ENABLE_DMA_CHANNEL;
  334. //----- 2. Disable/clear DMA input/output interrupts -----
  335. //AUDIO_IN_CLEAR_INTERRUPTS();
  336. v_pDMAregs->rDCON1 = v_pDMAregs->rDCON1;
  337. //AUDIO_OUT_CLEAR_INTERRUPTS();
  338. v_pDMAregs->rDCON2 = v_pDMAregs->rDCON2;
  339. //----- 3. Turn the audio hardware off -----
  340.     AudioMute(DMA_CH_OUT | DMA_CH_MIC, TRUE);
  341.     //----- 4. Unmap the control registers and DMA buffers -----
  342.     UnmapRegisters();
  343. UnmapDMABuffers();
  344.     return TRUE;
  345. }
  346. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  347. Function: UnmapRegisters()
  348. Description: Unmaps the config registers used by both the SPI and
  349. I2S controllers.
  350. Notes: The SPI and I2S controllers both use the GPIO config
  351. registers, so these MUST be deinitialized LAST.
  352. Returns: Boolean indicating success
  353. -------------------------------------------------------------------*/
  354. BOOL HardwareContext::UnmapRegisters()
  355. {
  356. //----- 1. Free the fast driver-->driver calling mechanism object -----
  357. if(g_hUTLObject) 
  358. {
  359.         CloseHandle(g_hUTLObject);
  360. }
  361. return TRUE;
  362. }
  363. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  364. Function: MapDMABuffers()
  365. Description: Maps the DMA buffers used for audio input/output
  366. on the I2S bus.
  367. Returns: Boolean indicating success
  368. -------------------------------------------------------------------*/
  369. BOOL HardwareContext::MapDMABuffers()
  370. {
  371.     BOOL bSuccess=FALSE;
  372. PBYTE pTemp;
  373.     //----- 1. Allocate a block of virtual memory big enough to hold the DMA buffers -----
  374.     if(!(pTemp = (PBYTE)VirtualAlloc(0, AUDIO_DMA_PAGE_SIZE * 4, MEM_RESERVE, PAGE_NOACCESS)))
  375. {
  376. DEBUGMSG(ZONE_ERROR, (TEXT("WAVEDEV.DLL:HardwareContext::MapDMABuffers() - Unable to allocate memory for DMA buffers!rn")));
  377. goto MAP_ERROR;
  378. }
  379.     //----- 2. Map the physical DMA buffer to the virtual address we just allocated -----
  380. if(!VirtualCopy((LPVOID)pTemp, (LPVOID)AUDIO_DMA_BUFFER_BASE, (AUDIO_DMA_PAGE_SIZE * 4), 
  381. PAGE_READWRITE | PAGE_NOCACHE))
  382. {
  383. DEBUGMSG(ZONE_ERROR, (TEXT("WAVEDEV.DLL:HardwareContext::MapDMABuffers() - VirtualCopy() failed when binding DMA buffers.rn")));
  384. goto MAP_ERROR;
  385.     }
  386. //----- 3. Setup the DMA page pointers -----
  387. //    NOTE: Currently, input and output each have two DMA pages; these pages are used in a round-robin
  388. //  fashion so that the OS can read/write one buffer while the audio codec chip read/writes the
  389. //  other buffer.
  390.     m_Output_pbDMA_PAGES[0] = pTemp;
  391.     m_Output_pbDMA_PAGES[1] = pTemp + AUDIO_DMA_PAGE_SIZE;
  392.     m_Input_pbDMA_PAGES[0]  = pTemp + 2*AUDIO_DMA_PAGE_SIZE;
  393.     m_Input_pbDMA_PAGES[1]  = pTemp + 3*AUDIO_DMA_PAGE_SIZE;
  394.     return TRUE;
  395. MAP_ERROR:
  396. if(pTemp)
  397. VirtualFree(pTemp, 0, MEM_RELEASE);
  398. return FALSE;
  399. }
  400. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  401. Function: UnmapDMABuffers()
  402. Description: Unmaps the DMA buffers used for audio input/output
  403. on the I2S bus.
  404. Returns: Boolean indicating success
  405. -------------------------------------------------------------------*/
  406. BOOL HardwareContext::UnmapDMABuffers()
  407. {
  408. if(m_Output_pbDMA_PAGES[0])
  409. {
  410. VirtualFree((PVOID)m_Output_pbDMA_PAGES[0], 0, MEM_RELEASE);
  411. }
  412. return TRUE;
  413. }
  414. BOOL HardwareContext::Codec_channel()
  415. {
  416.     //****** Port B Initialize *****
  417.     v_pIOPregs->rGPBDAT |= L3M|L3C; //start condition : L3M=H, L3C=H
  418.     v_pIOPregs->rGPBUP  |= 0x1c; //pull-up disable
  419.     v_pIOPregs->rGPBCON = ((v_pIOPregs->rGPBCON & 0x3ffc0f) | 0x000150);
  420. _WrL3Addr(0x14+2); //STATUS (000101xx+10)    
  421. if( m_InputDMARunning & m_OutputDMARunning )
  422.     _WrL3Data(0xa3,0); //1,0,0,0,0,0,01 : OGS=0,IGS=0,ADC_NI,DAC_NI,sngl speed,AoffDon
  423. else if( m_InputDMARunning )
  424. _WrL3Data(0xa2,0); //1,0,0,0,0,0,01 : OGS=0,IGS=0,ADC_NI,DAC_NI,sngl speed,AoffDon
  425. else if( m_OutputDMARunning )
  426. _WrL3Data(0xa1,0); //1,0,0,0,0,0,01 : OGS=0,IGS=0,ADC_NI,DAC_NI,sngl speed,AoffDon
  427. else
  428.      _WrL3Data(0xa0,0); //1,0,0,0,0,0,01 : OGS=0,IGS=0,ADC_NI,DAC_NI,sngl speed,AoffDon
  429.     return TRUE;
  430. }
  431. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  432. Function: InitCodec()
  433. Description: Initializes the audio codec chip.
  434. Notes: The audio codec chip is intialized for output mode
  435. but powered down.  To conserve battery life, the chip
  436. is only powered up when the user starts playing a 
  437. file.
  438. Specifically, the powerup/powerdown logic is done 
  439. in the AudioMute() function.  If either of the 
  440. audio channels are unmuted, then the chip is powered
  441. up; otherwise the chip is powered own.
  442. Returns: Boolean indicating success
  443. -------------------------------------------------------------------*/
  444. BOOL HardwareContext::InitCodec()
  445. {
  446. int i;
  447. // int mode =0; // play
  448. DEBUGMSG(1,(TEXT("+++InitCodecn")));
  449.     //****** Port B Initialize *****
  450.     v_pIOPregs->rGPBDAT |= L3M|L3C; //start condition : L3M=H, L3C=H
  451.     v_pIOPregs->rGPBUP  |= 0x1c; //pull-up disable
  452.     v_pIOPregs->rGPBCON = ((v_pIOPregs->rGPBCON & 0x3ffc0f) | 0x000150);
  453.     /****** L3 Interface ******/
  454. #if (AUDIO_CODEC_CLOCK == 256) // test value
  455. RETAILMSG(1,(TEXT("256 clockn")));
  456.     _WrL3Addr(0x14+2); //STATUS (000101xx+10)
  457.     _WrL3Data(0x60,0); //0,1,10,000,0 : reset,256fs,no DCfilter,iis
  458.     _WrL3Addr(0x14+2); //STATUS (000101xx+10)
  459.     _WrL3Data(0x20,0); //0,0,10,000,0 : no reset,256fs,no DCfilter,iis
  460.     
  461.     _WrL3Addr(0x14+2); //STATUS (000101xx+10)
  462.     _WrL3Data(0xa1,0); //1,0,0,0,0,0,01 : OGS=0,IGS=0,ADC_NI,DAC_NI,sngl speed,AoffDon
  463. #else
  464. RETAILMSG(1,(TEXT("384 clockn")));
  465.     _WrL3Addr(0x14+2); //STATUS (000101xx+10)
  466.     _WrL3Data(0x50,0); //0,1,01,000,0 : reset,384fs,no DCfilter,iis
  467.     _WrL3Addr(0x14+2); //STATUS (000101xx+10)
  468.     _WrL3Data(0x10,0); //0,0,01,000,0 : no reset,384fs,no DCfilter,iis
  469.     
  470.     _WrL3Addr(0x14+2); //STATUS (000101xx+10)
  471.     _WrL3Data(0xa1,0); ///1,0,0,0,0,0,01 : OGS=0,IGS=0,ADC_NI,DAC_NI,sngl speed,AoffDon
  472. #endif
  473. _WrL3Addr(0x14 + 0);     //DATA0 (000101xx+00)
  474. _WrL3Data(0xc2,0);       //11000,010  : DATA0, Extended addr(010) 
  475. _WrL3Data(0x4d,0);       //010,011,01 : DATA0, MS=9dB, Ch1=on Ch2=off, 
  476. return TRUE;
  477. }
  478. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  479. Function: InitOutputDMA()
  480. Description: Initializes the DMA channel for output.
  481. Notes: DMA Channel 2 is used for transmitting output sound
  482. data from system memory to the I2S controller.
  483. Returns: Boolean indicating success
  484. -------------------------------------------------------------------*/
  485. BOOL HardwareContext::InitOutputDMA()
  486. {
  487. int tmp;
  488. //----- 1. Initialize the DMA channel for output mode and use the first output DMA buffer -----
  489.     v_pDMAregs->rDISRC2 = (int)(AUDIO_DMA_BUFFER_PHYS); 
  490.     v_pDMAregs->rDISRCC2 &= ~(SOURCE_PERIPHERAL_BUS | FIXED_SOURCE_ADDRESS); // Source is system bus, increment addr
  491.     //----- 2. Initialize the DMA channel to send data over the I2S bus -----
  492.     v_pDMAregs->rDIDST2 = (int)IISFIF_PHYS; 
  493.     v_pDMAregs->rDIDSTC2 |= (DESTINATION_PERIPHERAL_BUS | FIXED_DESTINATION_ADDRESS); // Dest is  periperal bus, fixed addr
  494. //----- 3. Configure the DMA channel's transfer characteristics: handshake, sync PCLK, interrupt, -----
  495. //    single tx, single service, I2SSDO, I2S request, no auto-reload, half-word, tx count
  496. v_pDMAregs->rDCON2 = (  HANDSHAKE_MODE | GENERATE_INTERRUPT | I2SSDO_DMA2 | DMA_TRIGGERED_BY_HARDWARE 
  497.    | TRANSFER_HALF_WORD | (AUDIO_DMA_PAGE_SIZE / 2 ) );
  498. //----- 4. Reset the playback pointers -----
  499. //AUDIO_RESET_PLAYBACK_POINTER();
  500. ioPlaybackPointerLow  = (AUDIO_DMA_BUFFER_PHYS);
  501. ioPlaybackPointerHigh = (AUDIO_DMA_BUFFER_PHYS + AUDIO_DMA_PAGE_SIZE);
  502. DEBUGMSG(1,(TEXT("---InitOutputDMAn")));
  503. return TRUE;
  504. }
  505. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  506. Function: StartOutputDMA()
  507. Description: Starts outputting the sound data to the audio codec
  508. chip via DMA.
  509. Notes: Currently, both playback and record share the same
  510. DMA channel.  Consequently, we can only start this
  511. operation if the input channel isn't using DMA.
  512. Returns: Boolean indicating success
  513. -------------------------------------------------------------------*/
  514. BOOL HardwareContext::StartOutputDMA()
  515. {
  516. //RETAILMSG(1,(TEXT("+++StartOutputDMAn")));
  517. if(!m_OutputDMARunning && (m_Dx == D0) )
  518. // if(!m_OutputDMARunning)
  519.     {
  520.         //----- 1. Initialize our buffer counters -----
  521.         m_OutputDMARunning=TRUE;
  522.         m_OutBytes[OUT_BUFFER_A]=m_OutBytes[OUT_BUFFER_B]=0;
  523.         //----- 2. Prime the output buffer with sound data -----
  524. m_OutputDMAStatus = (DMA_DONEA | DMA_DONEB) & ~DMA_BIU;
  525. ULONG OutputTransferred = TransferOutputBuffers(m_OutputDMAStatus);
  526.         
  527. //----- 3. If we did transfer any data to the DMA buffers, go ahead and enable DMA -----
  528. if(OutputTransferred)
  529.         {
  530. //----- 4. Configure the DMA channel for playback -----
  531. if(!InitOutputDMA())
  532. {
  533. DEBUGMSG(ZONE_ERROR, (TEXT("HardwareContext::StartOutputDMA() - Unable to initialize output DMA channel!rn")));
  534. goto START_ERROR;
  535. }
  536. ////////////////////////////////////////////////////////////////////////////////
  537. // To correct left/right channel on ouput stream,
  538. // You should reset IISCON[0] bit.
  539. Lock();
  540. v_pIISregs->rIISCON  &= ~IIS_INTERFACE_ENABLE;
  541. v_pIISregs->rIISCON  |= TRANSMIT_DMA_REQUEST_ENABLE;
  542. v_pIISregs->rIISCON  &= ~TRANSMIT_IDLE_CMD;
  543. v_pIISregs->rIISFCON |= ( TRANSMIT_FIFO_ACCESS_DMA | TRANSMIT_FIFO_ENABLE );
  544. v_pIISregs->rIISMOD  |= IIS_TRANSMIT_MODE;
  545. v_pIISregs->rIISCON  |= IIS_INTERFACE_ENABLE;
  546. Unlock();
  547. ////////////////////////////////////////////////////////////////////////////////
  548. //----- 5. Make sure the audio isn't muted -----
  549. AudioMute(DMA_CH_OUT, FALSE);
  550. //----- 6. Start the DMA controller -----
  551. //AUDIO_RESET_PLAYBACK_POINTER();
  552. ioPlaybackPointerLow  = (AUDIO_DMA_BUFFER_PHYS);
  553. ioPlaybackPointerHigh = (AUDIO_DMA_BUFFER_PHYS + AUDIO_DMA_PAGE_SIZE);
  554. //SELECT_AUDIO_DMA_OUTPUT_BUFFER_A();
  555. v_pDMAregs->rDISRC2 = (int)(AUDIO_DMA_BUFFER_PHYS);
  556. Codec_channel(); // Turn ON output channel
  557. // charlie, start A buffer
  558. //AUDIO_OUT_DMA_ENABLE();
  559. v_pDMAregs->rDMASKTRIG2 &= ~STOP_DMA_TRANSFER;
  560. v_pDMAregs->rDMASKTRIG2 |= ENABLE_DMA_CHANNEL;
  561.         // wait for DMA to start.
  562.         delay_count = 0;
  563.         while((v_pDMAregs->rDSTAT2&0xfffff)==0){
  564.          if( delay_count++ > DELAY_COUNT ) break;
  565.         }        
  566.         // change the buffer pointer
  567.         //SELECT_AUDIO_DMA_OUTPUT_BUFFER_B();
  568.         v_pDMAregs->rDISRC2 = (int)(AUDIO_DMA_BUFFER_PHYS+AUDIO_DMA_PAGE_SIZE);
  569.         // Set DMA for B Buffer
  570.         }
  571.         else    // We didn't transfer any data, so DMA wasn't enabled
  572.         {
  573.             m_OutputDMARunning=FALSE;
  574.         }
  575.     }
  576.     
  577.     DEBUGMSG(1,(TEXT("---StartOutputDMAn")));
  578. return TRUE;
  579. START_ERROR:
  580. return FALSE;
  581. }
  582. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  583. Function: StopOutputDMA()
  584. Description: Stops any DMA activity on the output channel.
  585. Returns: Boolean indicating success
  586. -------------------------------------------------------------------*/
  587. void HardwareContext::StopOutputDMA()
  588. {
  589. //----- 1. If the output DMA is running, stop it -----
  590.     if (m_OutputDMARunning)
  591. {
  592. m_OutputDMAStatus = DMA_CLEAR;
  593. //AUDIO_OUT_DMA_DISABLE();
  594. v_pDMAregs->rDMASKTRIG2 |= STOP_DMA_TRANSFER;
  595. v_pDMAregs->rDMASKTRIG2 &= ~ENABLE_DMA_CHANNEL;
  596. //AUDIO_OUT_CLEAR_INTERRUPTS();
  597. v_pDMAregs->rDCON2 = v_pDMAregs->rDCON2;
  598. v_pIISregs->rIISCON &= ~TRANSMIT_DMA_REQUEST_ENABLE;
  599. v_pIISregs->rIISCON |= TRANSMIT_IDLE_CMD;
  600. v_pIISregs->rIISFCON &= ~(  TRANSMIT_FIFO_ACCESS_DMA | TRANSMIT_FIFO_ENABLE  );
  601. v_pIISregs->rIISMOD  &= ~IIS_TRANSMIT_MODE;
  602. AudioMute(DMA_CH_OUT, TRUE);
  603.     }
  604. m_OutputDMARunning = FALSE;
  605. Codec_channel();
  606. }
  607. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  608. Function: InitInputDMA()
  609. Description: Initializes the DMA channel for input.
  610. Notes: ***** NOT IMPLEMENTED *****
  611. The following routine is not implemented due to a
  612. hardware bug in the revision of the Samsung SC2410
  613. CPU this driver was developed on.  See the header
  614. at the top of this file for details.
  615. Returns: Boolean indicating success
  616. -------------------------------------------------------------------*/
  617. BOOL HardwareContext::InitInputDMA()
  618. {
  619. //goto INIT_ERROR;
  620. DEBUGMSG(1,(TEXT("+++InitInputDMAn")));
  621. //============================ Configure DMA Channel 1 ===========================
  622. //------ On platforms with the revsion of the Samsung SC2410 CPU with the IIS SLAVE bug fix, this -----
  623. //  code can be used to configure DMA channel 1 for input.
  624. //----- 1. Initialize the DMA channel for input mode and use the first input DMA buffer -----
  625. v_pDMAregs->rDISRC1 = (int)IISFIF_PHYS;
  626. v_pDMAregs->rDISRCC1 = (SOURCE_PERIPHERAL_BUS | FIXED_SOURCE_ADDRESS); // Source is periperal bus, fixed addr
  627.     
  628.     //----- 2. Initialize the DMA channel to receive data over the I2S bus -----
  629.     v_pDMAregs->rDIDST1 = (int)(AUDIO_DMA_BUFFER_PHYS); 
  630.     v_pDMAregs->rDIDSTC1 &= ~(DESTINATION_PERIPHERAL_BUS | FIXED_DESTINATION_ADDRESS); // Destination is system bus, increment addr
  631. //----- 3. Configure the DMA channel's transfer characteristics: handshake, sync PCLK, interrupt, -----
  632. //    single tx, single service, I2SSDI, I2S request, no auto-reload, half-word, tx count
  633. v_pDMAregs->rDCON1 = (  HANDSHAKE_MODE | GENERATE_INTERRUPT | I2SSDI_DMA1 | DMA_TRIGGERED_BY_HARDWARE 
  634.    | TRANSFER_HALF_WORD | (AUDIO_DMA_PAGE_SIZE / 2) );    
  635. return TRUE;
  636. INIT_ERROR:
  637. return FALSE;
  638. }
  639. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  640. Function: StartInputDMA()
  641. Description: Starts inputting the recorded sound data from the 
  642. audio codec chip via DMA.
  643. Notes: ***** NOT IMPLEMENTED *****
  644. The following routine is not implemented due to a
  645. hardware bug in the revision of the Samsung SC2410
  646. CPU this driver was developed on.  See the header
  647. at the top of this file for details.
  648. Returns: Boolean indicating success
  649. -------------------------------------------------------------------*/
  650. BOOL HardwareContext::StartInputDMA()
  651. {
  652. int tmp;
  653. //goto START_ERROR;
  654. //------ On platforms with the revsion of the Samsung SC2410 CPU with the IIS SLAVE bug fix, this -----
  655. //  code can be used to configure DMA channel 1 for input.
  656. DEBUGMSG(1,(_T("StartInputDMA()++rn")));
  657. if(!m_InputDMARunning)
  658.     {
  659.         //----- 1. Initialize our buffer counters -----
  660.         m_InputDMARunning=TRUE;
  661. Codec_channel();        // Turn On Input channel
  662.         m_InBytes[IN_BUFFER_A]=m_InBytes[IN_BUFFER_B]=0;
  663.         //----- 2. Prime the output buffer with sound data -----
  664. m_InputDMAStatus = (DMA_DONEA | DMA_DONEB) & ~DMA_BIU;
  665. //----- 3. Configure the DMA channel for record -----
  666. if(!InitInputDMA())
  667. {
  668. DEBUGMSG(ZONE_ERROR, (TEXT("HardwareContext::StartInputDMA() - Unable to initialize input DMA channel!rn")));
  669. goto START_ERROR;
  670. }
  671. v_pIISregs->rIISCON  |= RECEIVE_DMA_REQUEST_ENABLE;  
  672. v_pIISregs->rIISCON  &= ~RECEIVE_IDLE_CMD;
  673. v_pIISregs->rIISFCON |= ( RECEIVE_FIFO_ACCESS_DMA  | RECEIVE_FIFO_ENABLE);
  674. v_pIISregs->rIISMOD  |= IIS_RECEIVE_MODE;
  675. //----- 4. Make sure the audio isn't muted -----
  676. AudioMute(DMA_CH_MIC, FALSE);
  677. //----- 5. Start the input DMA -----
  678. //AUDIO_RESET_RECORD_POINTER();
  679. ioRecordPointerLow  = (RECORD_DMA_BUFFER_PHYS);
  680. ioRecordPointerHigh = (RECORD_DMA_BUFFER_PHYS+ AUDIO_DMA_PAGE_SIZE);
  681. //SELECT_AUDIO_DMA_INPUT_BUFFER_A();
  682. v_pDMAregs->rDIDST1 = (int)(AUDIO_DMA_BUFFER_PHYS+2*AUDIO_DMA_PAGE_SIZE);
  683. Codec_channel();        // Turn On Input channel
  684. v_pDMAregs->rDMASKTRIG1 &= ~STOP_DMA_TRANSFER;
  685. v_pDMAregs->rDMASKTRIG1 |= ENABLE_DMA_CHANNEL;
  686.         // wait for DMA to start.
  687.         delay_count = 0;
  688.         while((v_pDMAregs->rDSTAT2&0xfffff)==0){
  689.          if( delay_count++ > DELAY_COUNT ) break;
  690.         } 
  691.         // change the buffer pointer
  692.         //SELECT_AUDIO_DMA_INPUT_BUFFER_B();
  693.         v_pDMAregs->rDIDST1 = (int)(AUDIO_DMA_BUFFER_PHYS+3*AUDIO_DMA_PAGE_SIZE);
  694. }
  695. DEBUGMSG(1,(_T("StartInputDMA()--rn")));
  696. return TRUE;
  697. START_ERROR:
  698. return FALSE;
  699. }
  700. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  701. Function: StopInputDMA()
  702. Description: Stops any DMA activity on the input channel.
  703. Notes: ***** NOT IMPLEMENTED *****
  704. The following routine is not implemented due to a
  705. hardware bug in the revision of the Samsung SC2410
  706. CPU this driver was developed on.  See the header
  707. at the top of this file for details.
  708. Returns: Boolean indicating success
  709. -------------------------------------------------------------------*/
  710. void HardwareContext::StopInputDMA()
  711. {
  712. //------ On platforms with the revsion of the Samsung SC2410 CPU with the IIS SLAVE bug fix, this -----
  713. //  code can be used to configure DMA channel 1 for input.
  714. DEBUGMSG(1,(_T("StopInputDMA()++rn")));
  715. //----- 1. If the output DMA is running, stop it -----
  716.     if (m_InputDMARunning)
  717. {
  718. m_InputDMAStatus = DMA_CLEAR;
  719. v_pIISregs->rIISCON &= ~RECEIVE_DMA_REQUEST_ENABLE;
  720. v_pIISregs->rIISCON |= RECEIVE_IDLE_CMD;
  721. v_pIISregs->rIISFCON &= ~( RECEIVE_FIFO_ACCESS_DMA  | RECEIVE_FIFO_ENABLE);
  722. v_pIISregs->rIISMOD  &= ~IIS_RECEIVE_MODE;
  723. v_pDMAregs->rDMASKTRIG1 |= STOP_DMA_TRANSFER;
  724. v_pDMAregs->rDMASKTRIG1 &= ~ENABLE_DMA_CHANNEL;
  725. // AUDIO_IN_DMA_DISABLE();
  726. // v_pIISregs->rIISCON &= ~RECEIVE_DMA_REQUEST_ENABLE;
  727. // v_pIISregs->rIISFCON &= ~( RECEIVE_FIFO_ACCESS_DMA  | RECEIVE_FIFO_ENABLE);
  728. // v_pDMAregs->rDMASKTRIG1 |= STOP_DMA_TRANSFER;
  729. //AUDIO_IN_CLEAR_INTERRUPTS();
  730. v_pDMAregs->rDCON1 = v_pDMAregs->rDCON1;
  731. AudioMute(DMA_CH_MIC, TRUE);
  732.     }
  733. m_InputDMARunning = FALSE;
  734. Codec_channel();
  735. DEBUGMSG(1,(_T("StopInputDMA()--rn")));
  736. }
  737. DWORD HardwareContext::GetInterruptThreadPriority()
  738. {
  739.     HKEY hDevKey;
  740.     DWORD dwValType;
  741.     DWORD dwValLen;
  742.     DWORD dwPrio = 249; // Default priority
  743.     hDevKey = OpenDeviceKey((LPWSTR)m_DriverIndex);
  744.     if (hDevKey)
  745.     {
  746.         dwValLen = sizeof(DWORD);
  747.         RegQueryValueEx(
  748.             hDevKey,
  749.             TEXT("Priority256"),
  750.             NULL,
  751.             &dwValType,
  752.             (PUCHAR)&dwPrio,
  753.             &dwValLen);
  754.         RegCloseKey(hDevKey);
  755.     }
  756.     return dwPrio;
  757. }
  758. /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
  759. // SetForceSpeaker is called from the device context to update the state of the
  760. // m_bForceSpeaker variable.
  761. /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
  762. DWORD HardwareContext::ForceSpeaker( BOOL bForceSpeaker )
  763. {
  764.     // If m_NumForcedSpeaker is non-zero, audio should be routed to an
  765.     // external speaker (if hw permits).
  766.     if (bForceSpeaker)
  767.     {
  768.         m_NumForcedSpeaker++;
  769.         if (m_NumForcedSpeaker==1)
  770.         {
  771.             RecalcSpeakerEnable();
  772.         }
  773.     }
  774.     else
  775.     {
  776.         m_NumForcedSpeaker--;
  777.         if (m_NumForcedSpeaker==0)
  778.         {
  779.             RecalcSpeakerEnable();
  780.         }
  781.     }
  782.     return MMSYSERR_NOERROR;
  783. }
  784. // Control the hardware speaker enable
  785. void HardwareContext::SetSpeakerEnable(BOOL bEnable)
  786. {
  787.     // Code to turn speaker on/off here
  788.     return;
  789. }
  790. /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
  791. // RecalcSpeakerEnable decides whether to enable the speaker or not.
  792. // For now, it only looks at the m_bForceSpeaker variable, but it could
  793. // also look at whether the headset is plugged in
  794. // and/or whether we're in a voice call. Some mechanism would
  795. // need to be implemented to inform the wave driver of changes in the state of
  796. // these variables however.
  797. /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
  798. void HardwareContext::RecalcSpeakerEnable()
  799. {
  800.     SetSpeakerEnable(m_NumForcedSpeaker);
  801. }
  802. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  803. Function: InitInterruptThread()
  804. Description: Initializes the IST for handling DMA interrupts.
  805. Returns: Boolean indicating success
  806. -------------------------------------------------------------------*/
  807. BOOL HardwareContext::InitInterruptThread()
  808. {
  809.     BOOL bSuccess;
  810.     
  811.     m_hAudioInterrupt = CreateEvent( NULL, FALSE, FALSE, NULL);
  812.     if (!m_hAudioInterrupt)
  813.     {
  814.         return FALSE;
  815.     }
  816.     bSuccess = InterruptInitialize(m_IntrAudio, m_hAudioInterrupt, NULL, 0);
  817.     m_hAudioInterruptThread  = CreateThread((LPSECURITY_ATTRIBUTES)NULL,
  818.                                             0,
  819.                                             (LPTHREAD_START_ROUTINE)CallInterruptThread,
  820.                                             this,
  821.                                             0,
  822.                                             NULL);
  823.     if (!m_hAudioInterruptThread)
  824.     {
  825.         return FALSE;
  826.     }
  827.     // Bump up the priority since the interrupt must be serviced immediately.
  828. CeSetThreadPriority(m_hAudioInterruptThread, GetInterruptThreadPriority());
  829.     return TRUE;
  830. }
  831. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  832. Function: PowerUp()
  833. Description: Powers up the audio codec chip.
  834. Notes: Currently, this function is unimplemented because
  835. the audio codec chip is ONLY powered up when the 
  836. user wishes to play or record.  The AudioMute() function
  837. handles the powerup sequence.
  838. Returns: Boolean indicating success
  839. -------------------------------------------------------------------*/
  840. void HardwareContext::PowerUp()
  841. {
  842. //    SPI_Init();
  843.     I2S_Init();
  844.     AudioMute((DMA_CH_OUT | DMA_CH_MIC), FALSE); // 030711
  845. }
  846. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  847. Function: PowerDown()
  848. Description: Powers down the audio codec chip.
  849. Notes: Even if the input/output channels are muted, this
  850. function powers down the audio codec chip in order
  851. to conserve battery power.
  852. Returns: Boolean indicating success
  853. -------------------------------------------------------------------*/
  854. void HardwareContext::PowerDown()
  855. {
  856.     StopOutputDMA();
  857. AudioMute((DMA_CH_OUT | DMA_CH_MIC), TRUE);
  858. }
  859. //############################################ Helper Functions #############################################
  860. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  861. Function: TransferOutputBuffer()
  862. Description: Retrieves the next "mixed" audio buffer of data to
  863. DMA into the output channel.
  864. Returns: Number of bytes needing to be transferred.
  865. -------------------------------------------------------------------*/
  866. ULONG HardwareContext::TransferOutputBuffer(ULONG NumBuf)
  867. {
  868.     ULONG BytesTransferred = 0;
  869.     PBYTE pBufferStart = m_Output_pbDMA_PAGES[NumBuf];
  870.     PBYTE pBufferEnd = pBufferStart + AUDIO_DMA_PAGE_SIZE;
  871.     PBYTE pBufferLast;
  872. __try
  873. {
  874. pBufferLast = m_OutputDeviceContext.TransferBuffer(pBufferStart, pBufferEnd,NULL);
  875. BytesTransferred = m_OutBytes[NumBuf] = pBufferLast-pBufferStart;
  876. // Enable if you need to clear the rest of the DMA buffer
  877. StreamContext::ClearBuffer(pBufferLast,pBufferEnd);
  878. if(NumBuf == OUT_BUFFER_A) // Output Buffer A
  879. {
  880. m_OutputDMAStatus &= ~DMA_DONEA;
  881. m_OutputDMAStatus |= DMA_STRTA;
  882. }
  883. else // Output Buffer B
  884. {
  885. m_OutputDMAStatus &= ~DMA_DONEB;
  886. m_OutputDMAStatus |= DMA_STRTB;
  887. }
  888. }
  889. __except(EXCEPTION_EXECUTE_HANDLER) 
  890. {
  891. DEBUGMSG(ZONE_ERROR, (TEXT("WAVDEV2.DLL:TransferOutputBuffer() - EXCEPTION: %d"), GetExceptionCode()));
  892. }
  893.     return BytesTransferred;
  894. }
  895. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  896. Function: TransferOutputBuffers()
  897. Description: Determines which output buffer (A or B) needs to 
  898. be filled with sound data.  The correct buffer is
  899. then populated with data and ready to DMA to the 
  900. output channel.
  901. Returns: Boolean indicating success
  902. -------------------------------------------------------------------*/
  903. ULONG HardwareContext::TransferOutputBuffers(DWORD dwDCSR)
  904. {
  905.     ULONG BytesTransferred = 0;
  906.     ULONG BytesTotal;
  907.     DWORD Bits = dwDCSR & (DMA_DONEA|DMA_DONEB|DMA_BIU);
  908. DEBUGMSG(1,(TEXT("%xn"),Bits));
  909. switch (Bits)
  910.     {
  911.     case 0:
  912.     case DMA_BIU:
  913.         // No done bits set- must not be my interrupt
  914.         return 0;
  915.     case DMA_DONEA|DMA_DONEB|DMA_BIU:
  916.         // Load B, then A
  917.         BytesTransferred = TransferOutputBuffer(OUT_BUFFER_B);
  918.         // fall through
  919.     case DMA_DONEA: // This should never happen!
  920.     case DMA_DONEA|DMA_BIU:
  921. BytesTransferred += TransferOutputBuffer(OUT_BUFFER_A); // charlie, A => B
  922.         break;
  923.     case DMA_DONEA|DMA_DONEB:
  924.         // Load A, then B
  925.         BytesTransferred = TransferOutputBuffer(OUT_BUFFER_A);
  926.         // charlie
  927.         BytesTransferred += TransferOutputBuffer(OUT_BUFFER_B);
  928.         break; // charlie
  929.         // fall through
  930.     case DMA_DONEB|DMA_BIU: // This should never happen!
  931.     case DMA_DONEB:
  932.         // Load B
  933.         BytesTransferred += TransferOutputBuffer(OUT_BUFFER_B); // charlie, B => A
  934.         break;
  935.     }
  936.     // If it was our interrupt, but we weren't able to transfer any bytes
  937.     // (e.g. no full buffers ready to be emptied)
  938.     // and all the output DMA buffers are now empty, then stop the output DMA
  939.     BytesTotal = m_OutBytes[OUT_BUFFER_A]+m_OutBytes[OUT_BUFFER_B];
  940. if (BytesTotal==0)
  941.     {
  942. StopOutputDMA();
  943.     }
  944.     return BytesTransferred;
  945. }
  946. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  947. Function: TransferInputBuffer()
  948. Description: Retrieves the chunk of recorded sound data and inputs
  949. it into an audio buffer for potential "mixing".
  950. Returns: Number of bytes needing to be transferred.
  951. -------------------------------------------------------------------*/
  952. ULONG HardwareContext::TransferInputBuffer(ULONG NumBuf)
  953. {
  954. int tmp;
  955.     ULONG BytesTransferred = 0;
  956.     PBYTE pBufferStart = m_Input_pbDMA_PAGES[NumBuf];
  957.     PBYTE pBufferEnd = pBufferStart + AUDIO_DMA_PAGE_SIZE;
  958.     PBYTE pBufferLast;
  959. __try
  960. {
  961. pBufferLast = m_InputDeviceContext.TransferBuffer(pBufferStart, pBufferEnd,NULL);
  962. BytesTransferred = m_InBytes[NumBuf] = pBufferLast-pBufferStart;
  963. if(NumBuf == IN_BUFFER_A) // Input Buffer A
  964. {
  965. m_InputDMAStatus &= ~DMA_DONEA;
  966. m_InputDMAStatus |= DMA_STRTA;
  967. }
  968. else // Input Buffer B
  969. {
  970. m_InputDMAStatus &= ~DMA_DONEB;
  971. m_InputDMAStatus |= DMA_STRTB;
  972. }
  973. }
  974. __except(EXCEPTION_EXECUTE_HANDLER) 
  975. {
  976. DEBUGMSG(ZONE_ERROR, (TEXT("WAVDEV2.DLL:TransferInputBuffer() - EXCEPTION: %d"), GetExceptionCode()));
  977. }
  978.     return BytesTransferred;
  979. }
  980. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  981. Function: TransferInputBuffers()
  982. Description: Determines which input buffer (A or B) needs to 
  983. be filled with recorded sound data.  The correct 
  984. buffer is then populated with recorded sound data
  985. from the input channel.
  986. Returns: Boolean indicating success
  987. -------------------------------------------------------------------*/
  988. ULONG HardwareContext::TransferInputBuffers(DWORD dwDCSR)
  989. {
  990.     ULONG BytesTransferred=0;
  991.     DWORD Bits = dwDCSR & (DMA_DONEA|DMA_DONEB|DMA_BIU);
  992.     int tmp;
  993.     switch (Bits)
  994.     {
  995.     case 0:
  996.     case DMA_BIU:
  997.         // No done bits set- must not be my interrupt
  998.         return 0;
  999.     case DMA_DONEA|DMA_DONEB|DMA_BIU:
  1000.         // Load B, then A
  1001.         BytesTransferred = TransferInputBuffer(IN_BUFFER_B);
  1002.         // fall through
  1003.     case DMA_DONEA: // This should never happen!
  1004.     case DMA_DONEA|DMA_BIU:
  1005.         // Load A
  1006.         BytesTransferred += TransferInputBuffer(IN_BUFFER_A);
  1007.         break;
  1008.     case DMA_DONEA|DMA_DONEB:
  1009.         // Load A, then B
  1010.         BytesTransferred = TransferInputBuffer(IN_BUFFER_A);
  1011. BytesTransferred += TransferInputBuffer(IN_BUFFER_B);
  1012. break;
  1013.         // fall through
  1014.     case DMA_DONEB|DMA_BIU: // This should never happen!
  1015.     case DMA_DONEB:
  1016.         // Load B
  1017.         BytesTransferred += TransferInputBuffer(IN_BUFFER_B);
  1018.         break;
  1019.     }
  1020.     // If it was our interrupt, but we weren't able to transfer any bytes
  1021.     // (e.g. no empty buffers ready to be filled)
  1022.     // Then stop the input DMA
  1023.     if (BytesTransferred==0)
  1024.     {
  1025.         StopInputDMA();
  1026.     }
  1027.     return BytesTransferred;
  1028. }
  1029. void HardwareContext::InterruptThread()
  1030. {
  1031.     ULONG InputTransferred, OutputTransferred;
  1032. int tmp;
  1033. BOOL dmaInterruptSource = 0;
  1034.     // Fast way to access embedded pointers in wave headers in other processes.
  1035. SetProcPermissions((DWORD)-1);
  1036.     while(TRUE)
  1037.     {
  1038. WaitForSingleObject(m_hAudioInterrupt, INFINITE);
  1039. DEBUGMSG(1,(TEXT("0x%xn"),s2440INT->rINTMSK));
  1040. DEBUGMSG(1,(TEXT("startn")));
  1041. dmaInterruptSource = 0;
  1042. //----- 1. Grab the lock -----
  1043. Lock();
  1044. __try
  1045. {
  1046. DEBUGMSG(1,(TEXT("tryn")));
  1047. //----- 3. Determine the interrupt source (input DMA operation or output DMA operation?) -----
  1048. //----- NOTE: Often, platforms use two separate DMA channels for input/output operations but
  1049. // have the OAL return SYSINTR_AUDIO as the interrupt source.  If this is the case,
  1050. // then the interrupt source (input or output DMA channel) must be determined in
  1051. // this step.
  1052. // charlie, determine the interrupt source
  1053. if( s2440INT->rINTMSK & BIT_DMA1 ){
  1054. dmaInterruptSource |= DMA_CH_MIC; // Input DMA is supported...
  1055. }
  1056. if( s2440INT->rINTMSK & BIT_DMA2 ){
  1057. dmaInterruptSource |= DMA_CH_OUT; // Output DMA is supported...
  1058. }
  1059. // For determine the interrupt source
  1060. //----- 2. Acknowledge the DMA interrupt -----
  1061. InterruptDone(m_IntrAudio);
  1062. if ( m_Dx != D0 ) continue;
  1063. //----- 4. Handle any interrupts on the input source -----
  1064. //    NOTE: The InterruptDone() call below automatically clears the interrupt.
  1065. // if((m_InputDMARunning) && (dmaInterruptSource == DMA_CH_MIC))
  1066. if((dmaInterruptSource == DMA_CH_MIC))
  1067. {
  1068. //----- Determine which buffer just completed the DMA transfer -----
  1069. if(m_InputDMAStatus & DMA_BIU)
  1070. {
  1071. m_InputDMAStatus &= ~DMA_STRTB; // Buffer B just completed...
  1072. m_InputDMAStatus |= DMA_DONEB;
  1073. m_InputDMAStatus &= ~DMA_BIU; // Buffer A is in use
  1074. //SELECT_AUDIO_DMA_INPUT_BUFFER_B();
  1075. v_pDMAregs->rDIDST1 = (int)(AUDIO_DMA_BUFFER_PHYS+3*AUDIO_DMA_PAGE_SIZE);
  1076. DEBUGMSG(1,(TEXT("1n")));
  1077. }else
  1078. {
  1079. m_InputDMAStatus &= ~DMA_STRTA; // Buffer A just completed...
  1080. m_InputDMAStatus |= DMA_DONEA;
  1081. m_InputDMAStatus |= DMA_BIU; // Buffer B is in use
  1082. //SELECT_AUDIO_DMA_INPUT_BUFFER_A();
  1083. v_pDMAregs->rDIDST1 = (int)(AUDIO_DMA_BUFFER_PHYS+2*AUDIO_DMA_PAGE_SIZE);
  1084. DEBUGMSG(1,(TEXT("2n")));
  1085. }
  1086. /*
  1087. //----- 5. Schedule the next DMA transfer -----
  1088. //AUDIO_IN_DMA_ENABLE();
  1089. v_pDMAregs->rDMASKTRIG1 |= ENABLE_DMA_CHANNEL; 
  1090. v_pDMAregs->rDMASKTRIG1 &= ~STOP_DMA_TRANSFER; 
  1091. v_pIISregs->rIISFCON |= ( RECEIVE_FIFO_ACCESS_DMA  | RECEIVE_FIFO_ENABLE);
  1092. v_pIISregs->rIISCON  |= RECEIVE_DMA_REQUEST_ENABLE;
  1093. */
  1094. //----- 6. Retrieve the next chunk of recorded data from the non-playing buffer -----
  1095. InputTransferred = TransferInputBuffers(m_InputDMAStatus);
  1096. }
  1097. //----- 7. Handle any interrupts on the output source -----
  1098. //    NOTE: The InterruptDone() call below automatically clears the interrupt.
  1099. // if((m_OutputDMARunning) && (dmaInterruptSource == DMA_CH_OUT))
  1100. // if((dmaInterruptSource == DMA_CH_OUT))
  1101. else
  1102. {
  1103. //----- Determine which buffer just completed the DMA transfer -----
  1104. if(m_OutputDMAStatus & DMA_BIU)
  1105. {
  1106. m_OutputDMAStatus &= ~DMA_STRTB; // Buffer A just completed...
  1107. m_OutputDMAStatus |= DMA_DONEB;
  1108. m_OutputDMAStatus &= ~DMA_BIU; // Buffer B is in use
  1109. delay_count = 0;
  1110.     while((v_pDMAregs->rDSTAT2&0xfffff)==0){
  1111.          if( delay_count++ > DELAY_COUNT ) break;
  1112.          } 
  1113. //SELECT_AUDIO_DMA_OUTPUT_BUFFER_B(); // charlie. B => A
  1114. v_pDMAregs->rDISRC2 = (int)(AUDIO_DMA_BUFFER_PHYS+AUDIO_DMA_PAGE_SIZE);
  1115. }else
  1116. {
  1117. m_OutputDMAStatus &= ~DMA_STRTA; // Buffer B just completed...
  1118. m_OutputDMAStatus |= DMA_DONEA;
  1119. m_OutputDMAStatus |= DMA_BIU; // Buffer A is in use
  1120. delay_count = 0;
  1121. while((v_pDMAregs->rDSTAT2&0xfffff)==0){
  1122.          if( delay_count++ > DELAY_COUNT ) break;
  1123.          } 
  1124. //SELECT_AUDIO_DMA_OUTPUT_BUFFER_A(); // charlie. B => A
  1125. v_pDMAregs->rDISRC2 = (int)(AUDIO_DMA_BUFFER_PHYS);
  1126. }
  1127. //----- 8. Schedule the next DMA transfer -----
  1128. //AUDIO_OUT_DMA_ENABLE();
  1129. //v_pDMAregs->rDMASKTRIG2 &= ~STOP_DMA_TRANSFER;
  1130. //v_pDMAregs->rDMASKTRIG2 |= ENABLE_DMA_CHANNEL;
  1131. //----- 9. Fill the non-playing buffer with the next chunk of audio data to play -----
  1132. OutputTransferred = TransferOutputBuffers(m_OutputDMAStatus);
  1133. }
  1134. }
  1135. __except(EXCEPTION_EXECUTE_HANDLER) 
  1136. {
  1137. DEBUGMSG(ZONE_ERROR, (TEXT("WAVDEV2.DLL:InterruptThread() - EXCEPTION: %d"), GetExceptionCode()));
  1138. }
  1139. //----- 10. Give up the lock ----- 
  1140. Unlock();
  1141. }  
  1142. }
  1143. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1144. Function: AudioMute()
  1145. Description: Mutes/unmutes the specified audio channel.
  1146. Notes: If both audio channels are MUTED, then the chip 
  1147. is powered down to conserve battery life.  
  1148. Alternatively, if either audio channel is unMUTED, 
  1149. the chip is powered up.
  1150. Returns: Boolean indicating success
  1151. -------------------------------------------------------------------*/
  1152. BOOL HardwareContext::AudioMute(DWORD channel, BOOL bMute)
  1153. {
  1154. static DWORD dwActiveChannel = 0;
  1155. DEBUGMSG(1,(TEXT("Mute:%dn"),bMute));
  1156. // 
  1157. // Turn off/on mute bit in control register B.
  1158. // 
  1159. if( !m_InputDMARunning && !m_OutputDMARunning ) // 030711
  1160. {
  1161. if(bMute)
  1162. {
  1163. _WrL3Addr(0x14+0); //DATA0 (000101xx+00)
  1164. _WrL3Data(0xa4,0); //mute
  1165. }
  1166. else
  1167. {
  1168. _WrL3Addr(0x14+0); //DATA0, 
  1169. _WrL3Data(0xa0,0); //no mute
  1170. }
  1171. }
  1172. return TRUE;
  1173. }
  1174. void CallInterruptThread(HardwareContext *pHWContext)
  1175. {
  1176.     pHWContext->InterruptThread();
  1177. }
  1178. DWORD 
  1179. HardwareContext::Open(
  1180.     void
  1181.     )
  1182. {
  1183.     DWORD mmErr = MMSYSERR_NOERROR;
  1184.     
  1185.     // Don't allow play when not on, if there is a power constraint upon us.
  1186.     if ( D0 != m_Dx )
  1187.     {
  1188.         // Tell the Power Manager we need to power up.
  1189.         // If there is a power constraint then fail.
  1190.         DWORD dwErr = DevicePowerNotify(_T("WAV1:"), D0, POWER_NAME);
  1191.         if ( ERROR_SUCCESS !=  dwErr ) {
  1192.             RETAILMSG(1, (TEXT("WAVEDEV::Open:DevicePowerNotify ERROR: %urn"), dwErr ));
  1193.             mmErr = MMSYSERR_ERROR;
  1194.         }
  1195.     }
  1196.     
  1197.     return mmErr;
  1198. }
  1199. DWORD 
  1200. HardwareContext::Close(
  1201.     void
  1202.     )
  1203. {
  1204.     DWORD mmErr = MMSYSERR_NOERROR;
  1205.     DWORD dwErr;
  1206.     
  1207.     // we are done so inform Power Manager to power us down, 030711
  1208. //    dwErr = DevicePowerNotify(_T("WAV1:"), (_CEDEVICE_POWER_STATE)D4, POWER_NAME);
  1209.     if ( ERROR_SUCCESS !=  dwErr ) {
  1210.         RETAILMSG(1, (TEXT("WAVEDEV::Close:DevicePowerNofify ERROR: %urn"), dwErr ));
  1211. mmErr = MMSYSERR_ERROR;
  1212.     }
  1213.     
  1214.     return mmErr;
  1215. }
  1216. BOOL 
  1217. HardwareContext::IOControl( 
  1218.     DWORD  dwOpenData,
  1219.     DWORD  dwCode,
  1220.     PBYTE  pBufIn,
  1221.     DWORD  dwLenIn,
  1222.     PBYTE  pBufOut,
  1223.     DWORD  dwLenOut,
  1224.     PDWORD pdwActualOut)
  1225. {
  1226.     DWORD dwErr = ERROR_SUCCESS;    
  1227.     BOOL  bRc = TRUE;
  1228.     UNREFERENCED_PARAMETER(dwOpenData);
  1229.     
  1230.     switch (dwCode) {
  1231.         //
  1232.         // Power Management
  1233.         //
  1234.         case IOCTL_POWER_CAPABILITIES: 
  1235.         {
  1236.             PPOWER_CAPABILITIES ppc;
  1237.             
  1238.             if ( !pdwActualOut || !pBufOut || (dwLenOut < sizeof(POWER_CAPABILITIES)) ) {
  1239.                 bRc = FALSE;
  1240.                 dwErr = ERROR_INVALID_PARAMETER;
  1241.                 break;
  1242.             }
  1243.             
  1244.             ppc = (PPOWER_CAPABILITIES)pBufOut;
  1245.             
  1246.             memset(ppc, 0, sizeof(POWER_CAPABILITIES));
  1247.             // support D0, D4
  1248.             ppc->DeviceDx = 0x11;
  1249.             // no wake
  1250.             // no inrush
  1251.             // Report our nominal power consumption in uAmps rather than mWatts.
  1252.             ppc->Flags = POWER_CAP_PREFIX_MICRO | POWER_CAP_UNIT_AMPS;
  1253.             // REVIEW: Do we enable all these for normal playback?
  1254.             // D0: SPI + I2S + CODEC (Playback) + Headphone= 
  1255.             //     0.5 mA + 0.5 mA + (23 mW, into BUGBUG ohms ) + (30 mW, into 32 ohms)
  1256.             //     500 uA + 500 uA + 23000 uA + 32000 uA
  1257.             ppc->Power[D0] = 56000;
  1258.             
  1259.             *pdwActualOut = sizeof(POWER_CAPABILITIES);
  1260.         } break;
  1261.         case IOCTL_POWER_SET: 
  1262.         {
  1263.             CEDEVICE_POWER_STATE NewDx;
  1264.             
  1265.             if ( !pdwActualOut || !pBufOut || (dwLenOut < sizeof(CEDEVICE_POWER_STATE)) ) {
  1266.                 bRc = FALSE;
  1267.                 dwErr = ERROR_INVALID_PARAMETER;
  1268.                 break;
  1269.             }
  1270.             
  1271.             NewDx = *(PCEDEVICE_POWER_STATE)pBufOut;
  1272.             if ( VALID_DX(NewDx) ) {
  1273.                 // grab the CS since the normal Xxx_PowerXxx can not.
  1274.                 Lock();
  1275.                 switch ( NewDx ) {
  1276.                     case D0:
  1277.                         if (m_Dx != D0) {
  1278.                             PowerUp();
  1279.                             m_Dx = D0;
  1280.                         }
  1281.                         break;
  1282.                     default:
  1283.                         if (m_Dx != (_CEDEVICE_POWER_STATE)D4) {
  1284.                             PowerDown();
  1285.                             m_Dx = (_CEDEVICE_POWER_STATE)D4;
  1286.                         }
  1287.                         break;
  1288.                 }
  1289.                 
  1290.                 // return our state
  1291.                 *(PCEDEVICE_POWER_STATE)pBufOut = m_Dx;
  1292. //RETAILMSG(1, (TEXT("WAVEDEV: IOCTL_POWER_SET: D%u => D%u rn"), NewDx, m_Dx));
  1293.                 Unlock();
  1294.                 
  1295.                 *pdwActualOut = sizeof(CEDEVICE_POWER_STATE);
  1296.             } else {
  1297.                 bRc = FALSE;
  1298.                 dwErr = ERROR_INVALID_PARAMETER;
  1299.             }
  1300.             
  1301.         } break;
  1302.         case IOCTL_POWER_GET: 
  1303.             if ( !pdwActualOut || !pBufOut || (dwLenOut < sizeof(CEDEVICE_POWER_STATE)) ) {
  1304.                 bRc = FALSE;
  1305.                 dwErr = ERROR_INVALID_PARAMETER;
  1306.                 break;
  1307.             }
  1308.             *(PCEDEVICE_POWER_STATE)pBufOut = m_Dx;
  1309.             RETAILMSG(1, (TEXT("WAVEDEV: IOCTL_POWER_GET: D%u rn"), m_Dx));
  1310.             *pdwActualOut = sizeof(CEDEVICE_POWER_STATE);
  1311.             break;
  1312.             
  1313.         default:
  1314.             bRc = FALSE;
  1315.             dwErr = ERROR_INVALID_FUNCTION;
  1316.             DEBUGMSG (ZONE_FUNCTION, (TEXT(" Unsupported ioctl 0x%Xrn"), dwCode));
  1317.             break;            
  1318.     }
  1319.     
  1320.     if ( !bRc ) {
  1321.         SetLastError(dwErr);
  1322.     }
  1323.     
  1324.     return(bRc);
  1325. }