dossb.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:12k
源码类别:

Windows CE

开发平台:

C/C++

  1. /* MikMod sound library
  2. (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
  3. complete list.
  4. This library is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Library General Public License as
  6. published by the Free Software Foundation; either version 2 of
  7. the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. GNU Library General Public License for more details.
  13.  
  14. You should have received a copy of the GNU Library General Public
  15. License along with this library; if not, write to the Free Software
  16. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  17. 02111-1307, USA.
  18. */
  19. /*==============================================================================
  20.   $Id: dossb.c,v 1.1 2004/02/01 02:01:17 raph Exp $
  21.   Sound Blaster I/O routines, common for SB8, SBPro and SB16
  22. ==============================================================================*/
  23. /*
  24. Written by Andrew Zabolotny <bit@eltech.ru>
  25. */
  26. #include <stdlib.h>
  27. #include <dpmi.h>
  28. #include <go32.h>
  29. #include <dos.h>
  30. #include <sys/nearptr.h>
  31. #include <sys/farptr.h>
  32. #include <string.h>
  33. #include "dossb.h"
  34. /********************************************* Private variables/routines *****/
  35. __sb_state sb;
  36. /* Wait for SoundBlaster for some time */
  37. volatile void __sb_wait()
  38. {
  39. inportb(SB_DSP_RESET);
  40. inportb(SB_DSP_RESET);
  41. inportb(SB_DSP_RESET);
  42. inportb(SB_DSP_RESET);
  43. inportb(SB_DSP_RESET);
  44. inportb(SB_DSP_RESET);
  45. }
  46. static void sb_irq()
  47. {
  48. /* Make sure its not a spurious IRQ */
  49. if (!irq_check(sb.irq_handle))
  50. return;
  51. sb.irqcount++;
  52. /* Acknowledge DMA transfer is complete */
  53. if (sb.mode & SBMODE_16BITS)
  54. __sb_dsp_ack_dma16();
  55. else
  56. __sb_dsp_ack_dma8();
  57. /* SoundBlaster 1.x cannot do autoinit ... */
  58. if (sb.dspver < SBVER_20)
  59. __sb_dspreg_outwlh(SBDSP_DMA_PCM8, (sb.dma_buff->size >> 1) - 1);
  60. /* Send EOI */
  61. irq_ack(sb.irq_handle);
  62. enable();
  63. if (sb.timer_callback)
  64. sb.timer_callback();
  65. }
  66. static void sb_irq_end()
  67. {
  68. }
  69. static boolean __sb_reset()
  70. {
  71. /* Disable the output */
  72. sb_output(FALSE);
  73. /* Clear pending ints if any */
  74. __sb_dsp_ack_dma8();
  75. __sb_dsp_ack_dma16();
  76. /* Reset the DSP */
  77. outportb(SB_DSP_RESET, SBM_DSP_RESET);
  78. __sb_wait();
  79. __sb_wait();
  80. outportb(SB_DSP_RESET, 0);
  81. /* Now wait for AA coming from datain port */
  82. if (__sb_dsp_in() != 0xaa)
  83. return FALSE;
  84. /* Finally, get the DSP version */
  85. if ((sb.dspver = __sb_dsp_version()) == 0xffff)
  86. return FALSE;
  87. /* Check again */
  88. if (sb.dspver != __sb_dsp_version())
  89. return FALSE;
  90. return TRUE;
  91. }
  92. /***************************************************** SB detection stuff *****/
  93. static int __sb_irq_irqdetect(int irqno)
  94. {
  95. __sb_dsp_ack_dma8();
  96. return 1;
  97. }
  98. static void __sb_irq_dmadetect()
  99. {
  100. /* Make sure its not a spurious IRQ */
  101. if (!irq_check(sb.irq_handle))
  102. return;
  103. sb.irqcount++;
  104. /* Acknowledge DMA transfer is complete */
  105. if (sb.mode & SBMODE_16BITS)
  106. __sb_dsp_ack_dma16();
  107. else
  108. __sb_dsp_ack_dma8();
  109. /* Send EOI */
  110. irq_ack(sb.irq_handle);
  111. }
  112. static boolean __sb_detect()
  113. {
  114. /* First find the port number */
  115. if (!sb.port) {
  116. int i;
  117. for (i = 5; i >= 0; i--) {
  118. sb.port = 0x210 + i * 0x10;
  119. if (__sb_reset())
  120. break;
  121. }
  122. if (i < 0) {
  123. sb.port = 0;
  124. return FALSE;
  125. }
  126. }
  127. /* Now detect the IRQ and DMA numbers */
  128. if (!sb.irq) {
  129. unsigned int irqmask, sbirqmask, sbirqcount;
  130. unsigned long timer;
  131. /* IRQ can be one of 2,3,5,7,10 */
  132. irq_detect_start(0x04ac, __sb_irq_irqdetect);
  133. /* Prepare timeout counter */
  134. _farsetsel(_dos_ds);
  135. timer = _farnspeekl(0x46c);
  136. sbirqmask = 0;
  137. sbirqcount = 10; /* Emit 10 SB irqs */
  138. /* Tell SoundBlaster to emit IRQ for 8-bit transfers */
  139. __sb_dsp_out(SBDSP_GEN_IRQ8);
  140. __sb_wait();
  141. for (;;) {
  142. irq_detect_get(0, &irqmask);
  143. if (irqmask) {
  144. sbirqmask |= irqmask;
  145. if (!--sbirqcount)
  146. break;
  147. __sb_dsp_out(SBDSP_GEN_IRQ8);
  148. }
  149. if (_farnspeekl(0x46c) - timer >= 9) /* Wait ~1/2 secs */
  150. break;
  151. }
  152. if (sbirqmask)
  153. for (sb.irq = 15; sb.irq > 0; sb.irq--)
  154. if (irq_detect_get(sb.irq, &irqmask) == 10)
  155. break;
  156. irq_detect_end();
  157. if (!sb.irq)
  158. return FALSE;
  159. }
  160. /* Detect the 8-bit and 16-bit DMAs */
  161. if (!sb.dma8 || ((sb.dspver >= SBVER_16) && !sb.dma16)) {
  162. static int __dma8[] = { 0, 1, 3 };
  163. static int __dma16[] = { 5, 6, 7 };
  164. int *dma;
  165. sb_output(FALSE);
  166. /* Temporary hook SB IRQ */
  167. sb.irq_handle = irq_hook(sb.irq, __sb_irq_dmadetect, 200);
  168. irq_enable(sb.irq_handle);
  169. if (sb.irq > 7)
  170. _irq_enable(2);
  171. /* Start a short DMA transfer and check if IRQ happened */
  172. for (;;) {
  173. int i;
  174. unsigned int timer, oldcount;
  175. if (!sb.dma8)
  176. dma = &sb.dma8;
  177. else if ((sb.dspver >= SBVER_16) && !sb.dma16)
  178. dma = &sb.dma16;
  179. else
  180. break;
  181. for (i = 0; i < 3; i++) {
  182. boolean success = 1;
  183. *dma = (dma == &sb.dma8) ? __dma8[i] : __dma16[i];
  184. oldcount = sb.irqcount;
  185. dma_disable(*dma);
  186. dma_set_mode(*dma, DMA_MODE_WRITE);
  187. dma_clear_ff(*dma);
  188. dma_set_count(*dma, 2);
  189. dma_enable(*dma);
  190. __sb_dspreg_out(SBDSP_SET_TIMING, 206); /* 20KHz */
  191. if (dma == &sb.dma8) {
  192. sb.mode = 0;
  193. __sb_dspreg_outwlh(SBDSP_DMA_PCM8, 1);
  194. } else {
  195. sb.mode = SBMODE_16BITS;
  196. __sb_dspreg_out(SBDSP_DMA_GENERIC16, 0);
  197. __sb_dsp_out(0);
  198. __sb_dsp_out(1);
  199. }
  200. _farsetsel(_dos_ds);
  201. timer = _farnspeekl(0x46c);
  202. while (oldcount == sb.irqcount)
  203. if (_farnspeekl(0x46c) - timer >= 2) {
  204. success = 0;
  205. break;
  206. }
  207. dma_disable(*dma);
  208. if (success)
  209. break;
  210. *dma = 0;
  211. }
  212. if (!*dma)
  213. break;
  214. }
  215. irq_unhook(sb.irq_handle);
  216. if (!sb.dma8 || ((sb.dspver >= SBVER_16) && !sb.dma16))
  217. return FALSE;
  218. }
  219. return TRUE;
  220. }
  221. /*************************************************** High-level interface *****/
  222. /* Detect whenever SoundBlaster is present and fill "sb" structure */
  223. boolean sb_detect()
  224. {
  225. char *env;
  226. /* Try to find the port and DMA from environment */
  227. env = getenv("BLASTER");
  228. while (env && *env) {
  229. /* Skip whitespace */
  230. while ((*env == ' ') || (*env == 't'))
  231. env++;
  232. if (!*env)
  233. break;
  234. switch (*env++) {
  235.   case 'A':
  236.   case 'a':
  237. if (!sb.port)
  238. sb.port = strtol(env, &env, 16);
  239. break;
  240.   case 'E':
  241.   case 'e':
  242. if (!sb.aweport)
  243. sb.aweport = strtol(env, &env, 16);
  244. break;
  245.   case 'I':
  246.   case 'i':
  247. if (!sb.irq)
  248. sb.irq = strtol(env, &env, 10);
  249. break;
  250.   case 'D':
  251.   case 'd':
  252. if (!sb.dma8)
  253. sb.dma8 = strtol(env, &env, 10);
  254. break;
  255.   case 'H':
  256.   case 'h':
  257. if (!sb.dma16)
  258. sb.dma16 = strtol(env, &env, 10);
  259. break;
  260.   default:
  261. /* Skip other values (H == MIDI, T == model, any other?) */
  262. while (*env && (*env != ' ') && (*env != 't'))
  263. env++;
  264. break;
  265. }
  266. }
  267. /* Try to detect missing sound card parameters */
  268. __sb_detect();
  269. if (!sb.port || !sb.irq || !sb.dma8)
  270. return FALSE;
  271. if (!__sb_reset())
  272. return FALSE;
  273. if ((sb.dspver >= SBVER_16) && !sb.dma16)
  274. return FALSE;
  275. if (sb.dspver >= SBVER_PRO)
  276. sb.caps |= SBMODE_STEREO;
  277. if (sb.dspver >= SBVER_16 && sb.dma16)
  278. sb.caps |= SBMODE_16BITS;
  279. if (sb.dspver < SBVER_20)
  280. sb.maxfreq_mono = 22222;
  281. else
  282. sb.maxfreq_mono = 45454;
  283. if (sb.dspver <= SBVER_16)
  284. sb.maxfreq_stereo = 22727;
  285. else
  286. sb.maxfreq_stereo = 45454;
  287. sb.ok = 1;
  288. return TRUE;
  289. }
  290. /* Reset SoundBlaster */
  291. void sb_reset()
  292. {
  293. sb_stop_dma();
  294. __sb_reset();
  295. }
  296. /* Start working with SoundBlaster */
  297. boolean sb_open()
  298. {
  299. __dpmi_meminfo struct_info;
  300. if (!sb.ok)
  301. if (!sb_detect())
  302. return FALSE;
  303. if (sb.open)
  304. return FALSE;
  305. /* Now lock the sb structure in memory */
  306. struct_info.address = __djgpp_base_address + (unsigned long)&sb;
  307. struct_info.size = sizeof(sb);
  308. if (__dpmi_lock_linear_region(&struct_info))
  309. return FALSE;
  310. /* Hook the SB IRQ */
  311. sb.irq_handle = irq_hook(sb.irq, sb_irq, (long)sb_irq_end - (long)sb_irq);
  312. if (!sb.irq_handle) {
  313. __dpmi_unlock_linear_region(&struct_info);
  314. return FALSE;
  315. }
  316. /* Enable the interrupt */
  317. irq_enable(sb.irq_handle);
  318. if (sb.irq > 7)
  319. _irq_enable(2);
  320. sb.open++;
  321. return TRUE;
  322. }
  323. /* Finish working with SoundBlaster */
  324. boolean sb_close()
  325. {
  326. __dpmi_meminfo struct_info;
  327. if (!sb.open)
  328. return FALSE;
  329. sb.open--;
  330. /* Stop/free DMA buffer */
  331. sb_stop_dma();
  332. /* Unhook IRQ */
  333. irq_unhook(sb.irq_handle);
  334. sb.irq_handle = NULL;
  335. /* Unlock the sb structure */
  336. struct_info.address = __djgpp_base_address + (unsigned long)&sb;
  337. struct_info.size = sizeof(sb);
  338. __dpmi_unlock_linear_region(&struct_info);
  339. return TRUE;
  340. }
  341. /* Enable/disable stereo DSP mode */
  342. /* Enable/disable speaker output */
  343. void sb_output(boolean enable)
  344. {
  345. __sb_dsp_out(enable ? SBDSP_SPEAKER_ENA : SBDSP_SPEAKER_DIS);
  346. }
  347. /* Start playing from DMA buffer */
  348. boolean sb_start_dma(unsigned char mode, unsigned int freq)
  349. {
  350. int dmachannel = (mode & SBMODE_16BITS) ? sb.dma16 : sb.dma8;
  351. int dmabuffsize;
  352. unsigned int tc = 0; /* timing constant (<=sbpro only) */
  353. /* Stop DMA transfer if it is enabled */
  354. sb_stop_dma();
  355. /* Sanity check */
  356. if ((mode & SBMODE_MASK & sb.caps) != (mode & SBMODE_MASK))
  357. return FALSE;
  358. /* Check this SB can perform at requested frequency */
  359. if (((mode & SBMODE_STEREO) && (freq > sb.maxfreq_stereo))
  360. || (!(mode & SBMODE_STEREO) && (freq > sb.maxfreq_mono)))
  361. return FALSE;
  362. /* Check the timing constant here to avoid failing later */
  363. if (sb.dspver < SBVER_16) {
  364. /* SBpro cannot do signed transfer */
  365. if (mode & SBMODE_SIGNED)
  366. return FALSE;
  367. /* Old SBs have a different way on setting DMA timing constant */
  368. tc = freq;
  369. if (mode & SBMODE_STEREO)
  370. tc *= 2;
  371. tc = 1000000 / tc;
  372. if (tc > 255)
  373. return FALSE;
  374. }
  375. sb.mode = mode;
  376. /* Get a DMA buffer enough for a 1/4sec interval... 4K <= dmasize <= 32K */
  377. dmabuffsize = freq;
  378. if (mode & SBMODE_STEREO)
  379. dmabuffsize *= 2;
  380. if (mode & SBMODE_16BITS)
  381. dmabuffsize *= 2;
  382. dmabuffsize >>= 2;
  383. if (dmabuffsize < 4096)
  384. dmabuffsize = 4096;
  385. if (dmabuffsize > 32768)
  386. dmabuffsize = 32768;
  387. dmabuffsize = (dmabuffsize + 255) & 0xffffff00;
  388. sb.dma_buff = dma_allocate(dmachannel, dmabuffsize);
  389. if (!sb.dma_buff)
  390. return FALSE;
  391. /* Fill DMA buffer with silence */
  392. dmabuffsize = sb.dma_buff->size;
  393. if (mode & SBMODE_SIGNED)
  394. memset(sb.dma_buff->linear, 0, dmabuffsize);
  395. else
  396. memset(sb.dma_buff->linear, 0x80, dmabuffsize);
  397. /* Prime DMA for transfer */
  398. dma_start(sb.dma_buff, dmabuffsize, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
  399. /* Tell SoundBlaster to start transfer */
  400. dmabuffsize = (dmabuffsize >> 1) - 1;
  401. if (sb.dspver >= SBVER_16) { /* SB16 */
  402. /* SoundBlaster 16 */
  403. __sb_dspreg_outwhl(SBDSP_SET_RATE, freq);
  404. /* Start DMA->DAC transfer */
  405. __sb_dspreg_out(SBM_GENDAC_AUTOINIT |
  406. ((mode & SBMODE_16BITS) ? SBDSP_DMA_GENERIC16 :
  407.  SBDSP_DMA_GENERIC8),
  408. ((mode & SBMODE_SIGNED) ? SBM_GENDAC_SIGNED : 0) |
  409. ((mode & SBMODE_STEREO) ? SBM_GENDAC_STEREO : 0));
  410. /* Write the length of transfer */
  411. __sb_dsp_out(dmabuffsize);
  412. __sb_dsp_out(dmabuffsize >> 8);
  413. } else {
  414. __sb_dspreg_out(SBDSP_SET_TIMING, 256 - tc);
  415. if (sb.dspver >= SBVER_20) { /* SB 2.0/Pro */
  416. /* Set stereo mode */
  417. __sb_stereo((mode & SBMODE_STEREO) ? TRUE : FALSE);
  418. __sb_dspreg_outwlh(SBDSP_SET_DMA_BLOCK, dmabuffsize);
  419. if (sb.dspver >= SBVER_PRO)
  420. __sb_dsp_out(SBDSP_HS_DMA_DAC8_AUTO);
  421. else
  422. __sb_dsp_out(SBDSP_DMA_PCM8_AUTO);
  423. } else { /* Original SB */
  424. /* Start DMA->DAC transfer */
  425. __sb_dspreg_outwlh(SBDSP_DMA_PCM8, dmabuffsize);
  426. }
  427. }
  428. return TRUE;
  429. }
  430. /* Stop playing from DMA buffer */
  431. void sb_stop_dma()
  432. {
  433. if (!sb.dma_buff)
  434. return;
  435. if (sb.mode & SBMODE_16BITS)
  436. __sb_dsp_out(SBDSP_DMA_HALT16);
  437. else
  438. __sb_dsp_out(SBDSP_DMA_HALT8);
  439. dma_disable(sb.dma_buff->channel);
  440. dma_free(sb.dma_buff);
  441. sb.dma_buff = NULL;
  442. }
  443. /* Query current position/total size of the DMA buffer */
  444. void sb_query_dma(unsigned int *dma_size, unsigned int *dma_pos)
  445. {
  446. unsigned int dma_left;
  447. *dma_size = sb.dma_buff->size;
  448. /* It can happen we try to read DMA count when HI/LO bytes will be
  449.    inconsistent */
  450. for (;;) {
  451. unsigned int dma_left_test;
  452. dma_clear_ff(sb.dma_buff->channel);
  453. dma_left_test = dma_get_count(sb.dma_buff->channel);
  454. dma_left = dma_get_count(sb.dma_buff->channel);
  455. if ((dma_left >= dma_left_test) && (dma_left - dma_left_test < 10))
  456. break;
  457. }
  458. *dma_pos = *dma_size - dma_left;
  459. }
  460. /* ex:set ts=4: */