home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 5 / MA_Cover_5.iso / ppc / atari / atari800-0.8.6 / sbdrv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-05-10  |  33.2 KB  |  1,388 lines

  1. /*****************************************************************************/  
  2. /*                                                                           */ 
  3. /* Module:    SBDRV                                                          */ 
  4. /* Purpose:   Sound Blaster DAC DMA Driver V1.2                              */ 
  5. /* Author(s): Ron Fries, Neil Bradley and Bradford Mott                      */ 
  6. /*                                                                           */ 
  7. /* 02/20/97 - Initial Release                                                */ 
  8. /*                                                                           */ 
  9. /* 08/19/97 - V1.1 - Corrected problem with the auto-detect of older SB      */ 
  10. /*            cards and problem with DSP shutdown which left the auto-init   */ 
  11. /*            mode active.  Required creating a function to reset the DSP.   */ 
  12. /*            Also, added checks on the BLASTER settings to verify they      */ 
  13. /*            are possible values for either SB or SB compatibles.           */ 
  14. /*            Added several helpful information/error messages.  These can   */ 
  15. /*            be disabled by removing the SBDRV_SHOW_ERR definition.         */ 
  16. /*                                                                                                                                                       */ 
  17. /* 12/24/97 - V1.2 - Added support for DJGPP (by Bradford Mott).             */ 
  18. /*                                                                           */ 
  19. /*                                                                           */ 
  20. /*****************************************************************************/ 
  21. /*                                                                           */ 
  22. /*                 License Information and Copyright Notice                  */ 
  23. /*                 ========================================                  */ 
  24. /*                                                                           */ 
  25. /* SBDrv is Copyright(c) 1997-1998 by Ron Fries, Neil Bradley and            */ 
  26. /*       Bradford Mott                                                       */ 
  27. /*                                                                           */ 
  28. /* This library is free software; you can redistribute it and/or modify it   */ 
  29. /* under the terms of version 2 of the GNU Library General Public License    */ 
  30. /* as published by the Free Software Foundation.                             */ 
  31. /*                                                                           */ 
  32. /* This library is distributed in the hope that it will be useful, but       */ 
  33. /* WITHOUT ANY WARRANTY; without even the implied warranty of                */ 
  34. /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library */ 
  35. /* General Public License for more details.                                  */ 
  36. /* To obtain a copy of the GNU Library General Public License, write to the  */ 
  37. /* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   */ 
  38. /*                                                                           */ 
  39. /* Any permitted reproduction of these routines, in whole or in part, must   */ 
  40. /* bear this legend.                                                         */ 
  41. /*                                                                           */ 
  42. /*****************************************************************************/ 
  43.  
  44. #ifdef DJGPP
  45. #include <go32.h>
  46. #include <dpmi.h>
  47. #include <sys/movedata.h>
  48. #endif                            /* 
  49.  */
  50.  
  51. #include <dos.h>
  52. #include <stdlib.h>
  53. #include <ctype.h>
  54. #include <string.h>
  55. #include <conio.h>
  56. #include <time.h>
  57. #include <stdio.h>
  58. #include "sbdrv.h"
  59.  
  60. #define DSP_RESET         0x06
  61. #define DSP_READ          0x0a
  62. #define DSP_WRITE         0x0c
  63. #define DSP_ACK           0x0e
  64.  
  65. #define DMA_BASE          0x00
  66. #define DMA_COUNT         0x01
  67. #define DMA_MASK          0x0a
  68. #define DMA_MODE          0x0b
  69. #define DMA_FF            0x0c
  70.  
  71. #define MASTER_VOLUME     0x22
  72. #define LINE_VOLUME       0x2e
  73. #define FM_VOLUME         0x26
  74.  
  75. /* declare local global variables */ 
  76. #ifdef DJGPP
  77. static int theDOSBufferSegment;
  78.  
  79. static int theDOSBufferSelector;
  80.  
  81. #endif                            /* 
  82.  */
  83. static uint8 *Sb_buffer;
  84.  
  85. static uint16 Sb_buf_size = 200;
  86.  
  87. static uint16 Sb_offset;
  88.  
  89. static uint16 Playback_freq;
  90.  
  91. static uint8 Sb_init = 0;
  92.  
  93. static uint8 Count_low;
  94.  
  95. static uint8 Count_high;
  96.  
  97.  
  98. static uint16 IOaddr = 0x220;
  99.  
  100. static uint16 Irq = 7;
  101.  
  102. static uint16 Dma = 1;
  103.  
  104. static uint8 DMAmode = AUTO_DMA;
  105.  
  106. /*static */ uint8 DMAcount;
  107.  
  108. static void (*FillBuffer) (uint8 * buf, uint16 buf_size);
  109.  
  110.  
  111. #ifdef DJGPP
  112. static _go32_dpmi_seginfo OldIntVectInfo;
  113.  
  114. static _go32_dpmi_seginfo NewIntVectInfo;
  115.  
  116. #else                            /* 
  117.  */
  118. static void (__interrupt * OldIntVect) (void);
  119.  
  120. #endif                            /* 
  121.  */
  122.  
  123. /* function prototypes */ 
  124. #ifdef DJGPP
  125. static void newIntVect(void);
  126.  
  127. #else                            /* 
  128.  */
  129. static void interrupt newIntVect(void);
  130.  
  131. #endif                            /* 
  132.  */
  133.  
  134. static void setNewIntVect(uint16 irq);
  135.  
  136. static void setOldIntVect(uint16 irq);
  137.  
  138. static void dsp_out(uint16 port, uint8 val);
  139.  
  140. static uint8 hextodec(char c);
  141.  
  142. static void logErr(char *st);
  143.  
  144. static uint8 getBlasterEnv(void);
  145.  
  146. static uint8 dsp_in(uint16 port);
  147.  
  148.  
  149. /*****************************************************************************/ 
  150. /*                                                                           */ 
  151. /* Module:  setNewIntVect                                                    */ 
  152. /* Purpose: To set the specified interrupt vector to the sound output        */ 
  153. /*          processing interrupt.                                            */ 
  154. /* Author:  Ron Fries                                                        */ 
  155. /* Date:    January 1, 1997                                                  */ 
  156. /*                                                                           */ 
  157. /*****************************************************************************/ 
  158.  
  159. static void setNewIntVect(uint16 irq) 
  160. {
  161.     
  162.         if (irq > 7)
  163.         
  164.     {
  165.         
  166. #ifdef DJGPP
  167.             _go32_dpmi_get_protected_mode_interrupt_vector(irq + 0x68, 
  168.                                                         &OldIntVectInfo);
  169.         
  170.             NewIntVectInfo.pm_selector = _my_cs();
  171.         
  172.             NewIntVectInfo.pm_offset = (int) newIntVect;
  173.         
  174.             _go32_dpmi_allocate_iret_wrapper(&NewIntVectInfo);
  175.         
  176.             _go32_dpmi_set_protected_mode_interrupt_vector(irq + 0x68, 
  177.                                                         &NewIntVectInfo);
  178.         
  179. #else                            /* 
  180.  */
  181.             OldIntVect = _dos_getvect(irq + 0x68);
  182.         
  183.             _dos_setvect(irq + 0x68, newIntVect);
  184.         
  185. #endif                            /* 
  186.  */
  187.     }
  188.     
  189.         else
  190.         
  191.     {
  192.         
  193. #ifdef DJGPP
  194.             _go32_dpmi_get_protected_mode_interrupt_vector(irq + 0x08, 
  195.                                                         &OldIntVectInfo);
  196.         
  197.             NewIntVectInfo.pm_selector = _my_cs();
  198.         
  199.             NewIntVectInfo.pm_offset = (int) newIntVect;
  200.         
  201.             _go32_dpmi_allocate_iret_wrapper(&NewIntVectInfo);
  202.         
  203.             _go32_dpmi_set_protected_mode_interrupt_vector(irq + 0x08, 
  204.                                                         &NewIntVectInfo);
  205.         
  206. #else                            /* 
  207.  */
  208.             OldIntVect = _dos_getvect(irq + 0x08);
  209.         
  210.             _dos_setvect(irq + 0x08, newIntVect);
  211.         
  212. #endif                            /* 
  213.  */
  214.     }
  215.     
  216. }
  217.  
  218.  
  219.  
  220. /*****************************************************************************/ 
  221. /*                                                                           */ 
  222. /* Module:  setOldIntVect                                                    */ 
  223. /* Purpose: To restore the original vector                                   */ 
  224. /* Author:  Ron Fries                                                        */ 
  225. /* Date:    January 1, 1997                                                  */ 
  226. /*                                                                           */ 
  227. /*****************************************************************************/ 
  228.  
  229. static void setOldIntVect(uint16 irq) 
  230. {
  231.     
  232.         if (irq > 7)
  233.         
  234.     {
  235.         
  236. #ifdef DJGPP
  237.             _go32_dpmi_set_protected_mode_interrupt_vector(irq + 0x68, 
  238.                                                         &OldIntVectInfo);
  239.         
  240.             _go32_dpmi_free_iret_wrapper(&NewIntVectInfo);
  241.         
  242. #else                            /* 
  243.  */
  244.             _dos_setvect(irq + 0x68, OldIntVect);
  245.         
  246. #endif                            /* 
  247.  */
  248.     }
  249.     
  250.         else
  251.         
  252.     {
  253.         
  254. #ifdef DJGPP
  255.             _go32_dpmi_set_protected_mode_interrupt_vector(irq + 0x08, 
  256.                                                         &OldIntVectInfo);
  257.         
  258.             _go32_dpmi_free_iret_wrapper(&NewIntVectInfo);
  259.         
  260. #else                            /* 
  261.  */
  262.             _dos_setvect(irq + 0x08, OldIntVect);
  263.         
  264. #endif                            /* 
  265.  */
  266.     }
  267.     
  268. }
  269.  
  270.  
  271.  
  272. /*****************************************************************************/ 
  273. /*                                                                           */ 
  274. /* Module:  dsp_out                                                          */ 
  275. /* Purpose: To send a byte to the SB's DSP                                   */ 
  276. /* Author:  Ron Fries                                                        */ 
  277. /* Date:    September 10, 1996                                               */ 
  278. /*                                                                           */ 
  279. /*****************************************************************************/ 
  280.  
  281. static void dsp_out(uint16 port, uint8 val) 
  282. {
  283.     
  284.     /* wait for buffer to be free */ 
  285.         while (inp(IOaddr + DSP_WRITE) & 0x80)
  286.         
  287.     {
  288.         
  289.         /* do nothing */ 
  290.     }
  291.     
  292.         
  293.     /* transmit the next byte */ 
  294.         outp(port, val);
  295.     
  296. }
  297.  
  298.  
  299.  
  300. /*****************************************************************************/ 
  301. /*                                                                           */ 
  302. /* Module:  dsp_in                                                           */ 
  303. /* Purpose: To read a byte from the SB's DSP                                 */ 
  304. /* Author:  Ron Fries                                                        */ 
  305. /* Date:    January 26, 1997                                                 */ 
  306. /*                                                                           */ 
  307. /*****************************************************************************/ 
  308.  
  309. static uint8 dsp_in(uint16 port) 
  310. {
  311.     
  312.         uint16 x = 10000;        /* set timeout */
  313.     
  314.         
  315.     /* wait for buffer to be free */ 
  316.         while (((inp(IOaddr + 0x0E) & 0x80) == 0) && (x > 0))
  317.         
  318.     {
  319.         
  320.         /* decrement the timeout */ 
  321.             x--;
  322.         
  323.     }
  324.     
  325.         
  326.         if (x > 0)
  327.         
  328.     {
  329.         
  330.         /* read the data byte */ 
  331.             return (inp(port));
  332.         
  333.     }
  334.     
  335.         else
  336.         
  337.     {
  338.         
  339.             return (0);
  340.         
  341.     }
  342.     
  343. }
  344.  
  345.  
  346.  
  347. /*****************************************************************************/ 
  348. /*                                                                           */ 
  349. /* Module:  hextodec                                                         */ 
  350. /* Purpose: Convert the input character to hex                               */ 
  351. /* Author:  Ron Fries                                                        */ 
  352. /* Date:    September 10, 1996                                               */ 
  353. /*                                                                           */ 
  354. /*****************************************************************************/ 
  355.  
  356. uint8 hextodec(char c) 
  357. {
  358.     
  359.         uint8 retval = 0;
  360.     
  361.         
  362.         c = toupper(c);
  363.     
  364.         
  365.         if ((c >= '0') && (c <= '9'))
  366.         
  367.     {
  368.         
  369.             retval = c - '0';
  370.         
  371.     }
  372.     
  373.         else if ((c >= 'A') && (c <= 'F'))
  374.         
  375.     {
  376.         
  377.             retval = c - 'A' + 10;
  378.         
  379.     }
  380.     
  381.         
  382.         return (retval);
  383.     
  384. }
  385.  
  386.  
  387.  
  388. /*****************************************************************************/ 
  389. /*                                                                           */ 
  390. /* Module:  logErr                                                           */ 
  391. /* Purpose: Displays an error message.                                       */ 
  392. /* Author:  Ron Fries                                                        */ 
  393. /* Date:    September 24, 1996                                               */ 
  394. /*                                                                           */ 
  395. /*****************************************************************************/ 
  396.  
  397. static void logErr(char *st) 
  398. {
  399.     
  400. #ifdef SBDRV_SHOW_ERR
  401.         printf("%s", st);
  402.     
  403. #endif                            /* 
  404.  */
  405.  
  406.  
  407. /*****************************************************************************/ 
  408. /*                                                                           */ 
  409. /* Module:  getBlasterEnv                                                    */ 
  410. /* Purpose: Read the BLASTER environment variable and set the local globals  */ 
  411. /* Author:  Ron Fries                                                        */ 
  412. /* Date:    September 10, 1996                                               */ 
  413. /*                                                                           */ 
  414. /*****************************************************************************/ 
  415.  
  416. static uint8 getBlasterEnv(void) 
  417. {
  418.     
  419.         char *env;
  420.     
  421.         char *ptr;
  422.     
  423.         uint16 count = 0;
  424.     
  425.         
  426.         env = strupr(getenv("BLASTER"));
  427.     
  428.         
  429.     /* if the environment variable exists */ 
  430.         if (env)
  431.         
  432.     {
  433.         
  434.         /* search for the address setting */ 
  435.             ptr = strchr(env, 'A');
  436.         
  437.             if (ptr)
  438.             
  439.         {
  440.             
  441.             /* if valid, read and convert the IO address */ 
  442.                 IOaddr = (hextodec(ptr[1]) << 8) + 
  443.                 (hextodec(ptr[2]) << 4) + 
  444.                 (hextodec(ptr[3]));
  445.             
  446.                 
  447.             /* verify the IO address is one of the possible SB settings */ 
  448.                 switch (IOaddr)
  449.                 
  450.             {
  451.                 
  452.             case 0x210:
  453.                 
  454.             case 0x220:
  455.                 
  456.             case 0x230:
  457.                 
  458.             case 0x240:
  459.                 
  460.             case 0x250:
  461.                 
  462.             case 0x260:
  463.                 
  464.             case 0x280:
  465.                 
  466.             case 0x2A0:
  467.                 
  468.             case 0x2C0:
  469.                 
  470.             case 0x2E0:
  471.                 
  472.                 /* IO address OK so indicate one more valid item found */ 
  473.                     count++;
  474.                 
  475.                     break;
  476.                 
  477.                     
  478.             default:
  479.                 
  480.                     logErr("Invalid Sound Blaster I/O address specified.\n");
  481.                 
  482.                     logErr("Possible values are:  ");
  483.                 
  484.                     logErr("210, 220, 230, 240, 250, 260, 280, 2A0, 2C0, 2E0.\n");
  485.                 
  486.             }
  487.             
  488.         }
  489.         
  490.             else
  491.             
  492.         {
  493.             
  494.                 logErr("Unable to read Sound Blaster I/O address.\n");
  495.             
  496.         }
  497.         
  498.             
  499.         /* search for the IRQ setting */ 
  500.             ptr = strchr(env, 'I');
  501.         
  502.             if (ptr)
  503.             
  504.         {
  505.             
  506.             /* if valid, read and convert the IRQ */ 
  507.             /* if the IRQ has two digits */ 
  508.                 if ((ptr[1] == '1') && ((ptr[2] >= '0') && (ptr[2] <= '5')))
  509.                 
  510.             {
  511.                 
  512.                 /* then convert accordingly (using decimal) */ 
  513.                     Irq = hextodec(ptr[1]) * 10 + hextodec(ptr[2]);
  514.                 
  515.             }
  516.             
  517.                 else
  518.                 
  519.             {
  520.                 
  521.                 /* else convert as a single hex digit */ 
  522.                     Irq = hextodec(ptr[1]);
  523.                 
  524.             }
  525.             
  526.                 
  527.             /* verify the IRQ setting is one of the possible SB settings */ 
  528.                 switch (Irq)
  529.                 
  530.             {
  531.                 
  532.             case 2:            /* two is actually the interrupt cascade for IRQs > 7 */
  533.                 
  534.                 /* IRQ nine is the cascase for 2 */ 
  535.                     Irq = 9;
  536.                 
  537.                     
  538.                 /* IRQ OK so indicate one more valid item found */ 
  539.                     count++;
  540.                 
  541.                     break;
  542.                 
  543.                     
  544.             case 3:
  545.                 
  546.             case 4:
  547.                 
  548.             case 5:
  549.                 
  550.             case 7:
  551.                 
  552.             case 9:
  553.                 
  554.             case 10:
  555.                 
  556.             case 11:
  557.                 
  558.             case 12:
  559.                 
  560.             case 15:
  561.                 
  562.                     
  563.                 /* IRQ OK so indicate one more valid item found */ 
  564.                     count++;
  565.                 
  566.                     break;
  567.                 
  568.                     
  569.             default:
  570.                 
  571.                     logErr("Invalid Sound Blaster IRQ specified.\n");
  572.                 
  573.                     logErr("Possible values are:  ");
  574.                 
  575.                     logErr("2, 3, 4, 5, 7, 9, 10, 11, 12, 15.\n");
  576.                 
  577.             }
  578.             
  579.         }
  580.         
  581.             else
  582.             
  583.         {
  584.             
  585.                 logErr("Unable to read Sound Blaster IRQ.\n");
  586.             
  587.         }
  588.         
  589.             
  590.         /* search for the DMA setting */ 
  591.             ptr = strchr(env, 'D');
  592.         
  593.             if (ptr)
  594.             
  595.         {
  596.             
  597.             /* if valid, read and convert the DMA */ 
  598.                 Dma = hextodec(ptr[1]);
  599.             
  600.                 
  601.             /* verify the DMA setting is one of the possible 8-bit SB settings */ 
  602.                 switch (Dma)
  603.                 
  604.             {
  605.                 
  606.             case 0:
  607.                 
  608.             case 1:
  609.                 
  610.             case 3:
  611.                 
  612.                 /* DMA OK so indicate one more valid item found */ 
  613.                     count++;
  614.                 
  615.                     break;
  616.                 
  617.                     
  618.             default:
  619.                 
  620.                     logErr("Invalid Sound Blaster 8-bit DMA specified.\n");
  621.                 
  622.                     logErr("Possible values are:  ");
  623.                 
  624.                     logErr("0, 1, 3.\n");
  625.                 
  626.             }
  627.             
  628.         }
  629.         
  630.             else
  631.             
  632.         {
  633.             
  634.                 logErr("Unable to read Sound Blaster DMA setting.\n");
  635.             
  636.         }
  637.         
  638.     }
  639.     
  640.         else
  641.         
  642.     {
  643.         
  644.             logErr("BLASTER enviroment variable not configured.");
  645.         
  646.     }
  647.     
  648.         
  649.         return (count != 3);
  650.     
  651. }
  652.  
  653.  
  654.  
  655. /*****************************************************************************/ 
  656. /*                                                                           */ 
  657. /* Module:  low_malloc                                                       */ 
  658. /* Purpose: To allocate memory in the first 640K of memory                   */ 
  659. /* Author:  Neil Bradley                                                     */ 
  660. /* Date:    December 16, 1996                                                */ 
  661. /*                                                                           */ 
  662. /*****************************************************************************/ 
  663.  
  664. #ifdef __WATCOMC__
  665. void dos_memalloc(unsigned short int para, unsigned short int *seg, unsigned short int *sel);
  666.  
  667. #pragma  aux dos_memalloc = \
  668. "push  ecx" \ 
  669. "push  edx" \ 
  670. "mov   ax, 0100h" \ 
  671. "int   31h" \ 
  672. "pop   ebx" \ 
  673. "mov   [ebx], dx" \ 
  674. "pop   ebx" \ 
  675. "mov   [ebx], ax" \ 
  676. parm[bx][ecx][edx] \ 
  677. modify[ax ebx ecx edx];
  678.  
  679.  
  680. void dos_memfree(short int sel);
  681.  
  682. #pragma  aux dos_memfree =  \
  683. "mov   ax, 0101h" \ 
  684. "int   31h" \ 
  685. parm[dx] \ 
  686. modify[ax dx];
  687.  
  688.  
  689. void *low_malloc(int size) 
  690. {
  691.     
  692.         unsigned short int seg;
  693.     
  694.         unsigned short int i = 0;
  695.     
  696.         
  697.         dos_memalloc((size >> 4) + 1, &seg, &i);
  698.     
  699.         return ((char *) (seg << 4));
  700.     
  701.  
  702. #endif                            /* 
  703.  */
  704.  
  705.  
  706. /*****************************************************************************/ 
  707. /*                                                                           */ 
  708. /* Module:  Set_master_volume                                                */ 
  709. /* Purpose: To set the Sound Blaster's master volume                         */ 
  710. /* Author:  Neil Bradley                                                     */ 
  711. /* Date:    January 1, 1997                                                  */ 
  712. /*                                                                           */ 
  713. /*****************************************************************************/ 
  714.  
  715. void Set_master_volume(uint8 left, uint8 right) 
  716.  
  717. {
  718.     
  719.     /* if the SB was initialized */ 
  720.         if (Sb_init)
  721.         
  722.     {
  723.         
  724.             outp(IOaddr + 0x04, MASTER_VOLUME);
  725.         
  726.             outp(IOaddr + 0x05, ((left & 0xf) << 4) + (right & 0x0f));
  727.         
  728.     }
  729.     
  730. }
  731.  
  732.  
  733.  
  734. /*****************************************************************************/ 
  735. /*                                                                           */ 
  736. /* Module:  Set_line_volume                                                  */ 
  737. /* Purpose: To set the Sound Blaster's line level volume                     */ 
  738. /* Author:  Neil Bradley                                                     */ 
  739. /* Date:    January 1, 1997                                                  */ 
  740. /*                                                                           */ 
  741. /*****************************************************************************/ 
  742.  
  743. void Set_line_volume(uint8 left, uint8 right) 
  744. {
  745.     
  746.     /* if the SB was initialized */ 
  747.         if (Sb_init)
  748.         
  749.     {
  750.         
  751.             outp(IOaddr + 0x04, LINE_VOLUME);
  752.         
  753.             outp(IOaddr + 0x05, ((left & 0xf) << 4) + (right & 0x0f));
  754.         
  755.     }
  756.     
  757. }
  758.  
  759.  
  760.  
  761. /*****************************************************************************/ 
  762. /*                                                                           */ 
  763. /* Module:  Set_FM_volume                                                    */ 
  764. /* Purpose: To set the Sound Blaster's FM volume                             */ 
  765. /* Author:  Neil Bradley                                                     */ 
  766. /* Date:    January 1, 1997                                                  */ 
  767. /*                                                                           */ 
  768. /*****************************************************************************/ 
  769.  
  770. void Set_FM_volume(uint8 left, uint8 right) 
  771.  
  772. {
  773.     
  774.     /* if the SB was initialized */ 
  775.         if (Sb_init)
  776.         
  777.     {
  778.         
  779.             outp(IOaddr + 0x04, FM_VOLUME);
  780.         
  781.             outp(IOaddr + 0x05, ((left & 0xf) << 4) + (right & 0x0f));
  782.         
  783.     }
  784.     
  785. }
  786.  
  787.  
  788.  
  789. /*****************************************************************************/ 
  790. /*                                                                           */ 
  791. /* Module:  ResetDSP                                                         */ 
  792. /* Purpose: To reset the SB DSP.  Returns a value of zero if unsuccessful.   */ 
  793. /*          This function requires as input the SB base port address.        */ 
  794. /* Author:  Ron Fries                                                        */ 
  795. /* Date:    August 5, 1997                                                   */ 
  796. /*                                                                           */ 
  797. /*****************************************************************************/ 
  798.  
  799. uint8 ResetDSP(uint16 ioaddr) 
  800. {
  801.     
  802.         uint8 x;
  803.     
  804.         uint16 y;
  805.     
  806.         
  807.     /* assume the init was not successful */ 
  808.         Sb_init = 0;
  809.     
  810.         
  811.     /* send a DSP reset to the SB */ 
  812.         outp(ioaddr + DSP_RESET, 1);
  813.     
  814.         
  815.     /* wait a few microsec */ 
  816.         x = inp(ioaddr + DSP_RESET);
  817.     
  818.         x = inp(ioaddr + DSP_RESET);
  819.     
  820.         x = inp(ioaddr + DSP_RESET);
  821.     
  822.         x = inp(ioaddr + DSP_RESET);
  823.     
  824.         
  825.     /* clear the DSP reset */ 
  826.         outp(ioaddr + DSP_RESET, 0);
  827.     
  828.         
  829.     /* wait a bit until the SB indicates good status */ 
  830.         y = 0;
  831.     
  832.         
  833.         do
  834.         
  835.     {
  836.         
  837.             x = inp(ioaddr + DSP_READ);
  838.         
  839.             y++;
  840.         
  841.     } while ((y < 1000) && (x != 0xaa));
  842.     
  843.         
  844.     /* if we were able to successfully reset the SB */ 
  845.         if (x == 0xaa)
  846.         
  847.     {
  848.         
  849.         /* turn on speaker */ 
  850.             dsp_out(ioaddr + DSP_WRITE, 0xd1);
  851.         
  852.             
  853.         /* read to make sure DSP register is clear */ 
  854.             dsp_in(ioaddr + DSP_READ);
  855.         
  856.             
  857.         /* set time constant */ 
  858.             dsp_out(ioaddr + DSP_WRITE, 0x40);
  859.         
  860.             dsp_out(ioaddr + DSP_WRITE, 
  861.                     (unsigned char) (256 - 1000000L / Playback_freq));
  862.         
  863.             
  864.         /* indicate successful initialization */ 
  865.             Sb_init = 1;
  866.         
  867.     }
  868.     
  869.         
  870.         return (Sb_init);
  871.     
  872. }
  873.  
  874.  
  875.  
  876. /*****************************************************************************/ 
  877. /*                                                                           */ 
  878. /* Module:  OpenSB                                                           */ 
  879. /* Purpose: To reset the SB and prepare all buffers and other global         */ 
  880. /*          global variables for sound output.  Allows the user to select    */ 
  881. /*          the playback frequency, number of buffers, and size of each      */ 
  882. /*          buffer.  Returns a value of zero if unsuccessful.                */ 
  883. /* Author:  Ron Fries                                                        */ 
  884. /* Date:    January 1, 1997                                                  */ 
  885. /*                                                                           */ 
  886. /*****************************************************************************/ 
  887.  
  888. uint8 OpenSB(uint16 playback_freq, uint16 buffer_size) 
  889. {
  890.     
  891.     /* initialize local globals */ 
  892.         if (buffer_size > 0)
  893.         
  894.     {
  895.         
  896.             Sb_buf_size = buffer_size;
  897.         
  898.     }
  899.     
  900.         
  901.         Playback_freq = playback_freq;
  902.     
  903.         
  904.     /* assume the init was not successful */ 
  905.         Sb_init = 0;
  906.     
  907.         
  908.     /* attempt to read the Blaster Environment Variable */ 
  909.         if (getBlasterEnv() == 0)
  910.         
  911.     {
  912.         
  913.         /* if the DSP could be successfully reset */ 
  914.             if (ResetDSP(IOaddr) != 0)
  915.             
  916.         {
  917.             
  918.             /* setup the DSP interrupt service routine */ 
  919.                 setNewIntVect(Irq);
  920.             
  921.                 
  922.             /* Enable the interrupt used */ 
  923.                 if (Irq > 7)
  924.                 
  925.             {
  926.                 
  927.                     outp(0xa1, inp(0xa1) & (~(1 << (Irq - 8))));
  928.                 
  929.             }
  930.             
  931.                 else
  932.                 
  933.             {
  934.                 
  935.                     outp(0x21, inp(0x21) & (~(1 << Irq)));
  936.                 
  937.             }
  938.             
  939.                 
  940.             /* make sure interrupts are enabled */ 
  941.                 _enable();
  942.             
  943.                 
  944.             /* create a buffer to hold the data */ 
  945. #ifdef __WATCOMC__
  946.                 Sb_buffer = low_malloc(Sb_buf_size * 2);
  947.             
  948. #elif defined(DJGPP)
  949.                 Sb_buffer = (uint8 *) malloc(Sb_buf_size * 2);
  950.             
  951.                 theDOSBufferSegment = __dpmi_allocate_dos_memory((Sb_buf_size * 2 + 15) >> 4, 
  952.                                                   &theDOSBufferSelector);
  953.             
  954. #else                            /* 
  955.  */
  956.                 Sb_buffer = malloc(Sb_buf_size * 2);
  957.             
  958. #endif                            /* 
  959.  */
  960.                 
  961.             /* if we were unable to successfully allocate the buffer */ 
  962. #ifdef DJGPP
  963.                 if ((Sb_buffer == 0) || (theDOSBufferSegment == -1))
  964.                 
  965. #else                            /* 
  966.  */
  967.                 if (Sb_buffer == 0)
  968.                 
  969. #endif                            /* 
  970.  */
  971.             {
  972.                 
  973.                     logErr("Unable to allocate buffer for audio output.\n");
  974.                 
  975.                     
  976.                 /* close the SB */ 
  977.                     CloseSB();
  978.                 
  979.             }
  980.             
  981.         }
  982.         
  983.             else
  984.             
  985.         {
  986.             
  987.                 logErr("Unable to initialize the Sound Card.\n");
  988.             
  989.         }
  990.         
  991.             
  992.     }
  993.     
  994.         
  995.         return (Sb_init);
  996.     
  997. }
  998.  
  999.  
  1000.  
  1001. /*****************************************************************************/ 
  1002. /*                                                                           */ 
  1003. /* Module:  CloseSB                                                          */ 
  1004. /* Purpose: Closes the SB and disables the interrupts.                       */ 
  1005. /* Author:  Ron Fries                                                        */ 
  1006. /* Date:    January 1, 1997                                                  */ 
  1007. /*                                                                           */ 
  1008. /*****************************************************************************/ 
  1009.  
  1010. void CloseSB(void) 
  1011. {
  1012.     
  1013. #ifdef __WATCOMC__
  1014.         uint32 addr;
  1015.     
  1016. #endif                            /* 
  1017.  */
  1018.         
  1019.     /* if the SB was initialized */ 
  1020.         if (Sb_init)
  1021.         
  1022.     {
  1023.         
  1024.         /* turn the speaker off */ 
  1025.             dsp_out(IOaddr + DSP_WRITE, 0xd3);
  1026.         
  1027.             
  1028.         /* stop all DMA transfer */ 
  1029.             Stop_audio_output();
  1030.         
  1031.             
  1032.         /* indicate SB no longer active */ 
  1033.             Sb_init = 0;
  1034.         
  1035.             
  1036.         /* Disable the interrupt used */ 
  1037.             if (Irq > 7)
  1038.             
  1039.         {
  1040.             
  1041.                 outp(0xa1, inp(0xa1) | (1 << (Irq - 8)));
  1042.             
  1043.         }
  1044.         
  1045.             else
  1046.             
  1047.         {
  1048.             
  1049.                 outp(0x21, inp(0x21) | (1 << Irq));
  1050.             
  1051.         }
  1052.         
  1053.             
  1054.         /* restore the original interrupt routine */ 
  1055.             setOldIntVect(Irq);
  1056.         
  1057.             
  1058.         /* free any memory that had been allocated */ 
  1059.             if (Sb_buffer != 0)
  1060.             
  1061.         {
  1062.             
  1063. #ifdef __WATCOMC__
  1064.                 addr = (uint32) Sb_buffer;
  1065.             
  1066.                 dos_memfree((uint16) (addr >> 4));
  1067.             
  1068. #elif defined(DJGPP)
  1069.                 free(Sb_buffer);
  1070.             
  1071.                 __dpmi_free_dos_memory(theDOSBufferSelector);
  1072.             
  1073. #else                            /* 
  1074.  */
  1075.                 free(Sb_buffer);
  1076.             
  1077. #endif                            /* 
  1078.  */
  1079.         }
  1080.         
  1081.     }
  1082.     
  1083. }
  1084.  
  1085.  
  1086.  
  1087. /*****************************************************************************/ 
  1088. /*                                                                           */ 
  1089. /* Module:  Stop_audio_output                                                */ 
  1090. /* Purpose: Stops the SB's DMA transfer.                                     */ 
  1091. /* Author:  Ron Fries                                                        */ 
  1092. /* Date:    January 17, 1997                                                 */ 
  1093. /*                                                                           */ 
  1094. /*****************************************************************************/ 
  1095.  
  1096. void Stop_audio_output(void) 
  1097. {
  1098.     
  1099.     /* stop any transfer that may be in progress */ 
  1100.         
  1101.     /* if the SB was initialized */ 
  1102.         if (Sb_init)
  1103.         
  1104.     {
  1105.         
  1106.         /* halt DMA */ 
  1107.             dsp_out(IOaddr + DSP_WRITE, 0xd0);
  1108.         
  1109.             
  1110.         /* exit DMA operation */ 
  1111.             dsp_out(IOaddr + DSP_WRITE, 0xda);
  1112.         
  1113.             
  1114.         /* halt DMA */ 
  1115.             dsp_out(IOaddr + DSP_WRITE, 0xd0);
  1116.         
  1117.     }
  1118.     
  1119. }
  1120.  
  1121.  
  1122.  
  1123. /*****************************************************************************/ 
  1124. /*                                                                           */ 
  1125. /* Module:  Start_audio_output                                               */ 
  1126. /* Purpose: Fills all configured buffers and outputs the first.              */ 
  1127. /* Author:  Ron Fries                                                        */ 
  1128. /* Date:    February 20, 1997                                                */ 
  1129. /*                                                                           */ 
  1130. /*****************************************************************************/ 
  1131.  
  1132. uint8 Start_audio_output(uint8 dma_mode, 
  1133.                          void (*fillBuffer) (uint8 * buf, uint16 n)) 
  1134. {
  1135.     
  1136.         uint8 ret_val = 1;
  1137.     
  1138.         static uint8 pagePort[8] =
  1139.     {0x87, 0x83, 0x81, 0x82};
  1140.     
  1141.         uint8 offset_low;
  1142.     
  1143.         uint8 offset_high;
  1144.     
  1145.         uint8 page_no;
  1146.     
  1147.         uint8 count_low;
  1148.     
  1149.         uint8 count_high;
  1150.     
  1151.         uint32 addr;
  1152.     
  1153.         clock_t start_time;
  1154.     
  1155.         
  1156.     /* if the SB initialized properly */ 
  1157.         if (Sb_init)
  1158.         
  1159.     {
  1160.         
  1161.         /* set the fill buffer routine */ 
  1162.             FillBuffer = fillBuffer;
  1163.         
  1164.             
  1165.         /* keep track of the DMA selection */ 
  1166.             DMAmode = dma_mode;
  1167.         
  1168.             
  1169.         /* stop any transfer that may be in progress */ 
  1170.             Stop_audio_output();
  1171.         
  1172.             
  1173.         /* fill the buffer */ 
  1174.             FillBuffer(Sb_buffer, Sb_buf_size * 2);
  1175.         
  1176.             
  1177. #ifdef DJGPP
  1178.         /* Copy data to DOS memory buffer */ 
  1179.             dosmemput(Sb_buffer, Sb_buf_size * 2, theDOSBufferSegment << 4);
  1180.         
  1181. #endif                            /* 
  1182.  */
  1183.             
  1184.         /* calculate high, low and page addresses of buffer */ 
  1185. #ifdef __WATCOMC__
  1186.             addr = (uint32) Sb_buffer;
  1187.         
  1188. #elif defined(DJGPP)
  1189.             addr = ((uint32) theDOSBufferSegment) << 4;
  1190.         
  1191. #else                            /* 
  1192.  */
  1193.             addr = ((uint32) FP_SEG(Sb_buffer) << 4) + 
  1194.             (uint32) FP_OFF(Sb_buffer);
  1195.         
  1196. #endif                            /* 
  1197.  */
  1198.             Sb_offset = (uint16) (addr & 0x0ffff);
  1199.         
  1200.             offset_low = (uint8) (addr & 0x0ff);
  1201.         
  1202.             offset_high = (uint8) ((addr >> 8) & 0x0ff);
  1203.         
  1204.             page_no = (uint8) (addr >> 16);
  1205.         
  1206.             
  1207.             count_low = (uint8) ((Sb_buf_size * 2) - 1) & 0x0ff;
  1208.         
  1209.             count_high = (uint8) (((Sb_buf_size * 2) - 1) >> 8) & 0x0ff;
  1210.         
  1211.             
  1212.         /* program the DMAC for output transfer */ 
  1213.             outp(DMA_MASK, 0x04 | Dma);
  1214.         
  1215.             outp(DMA_FF, 0);
  1216.         
  1217.             
  1218.         /* select auto-initialize DMA mode */ 
  1219.             outp(DMA_MODE, 0x58 | Dma);
  1220.         
  1221.             outp(DMA_BASE + (Dma << 1), offset_low);
  1222.         
  1223.             outp(DMA_BASE + (Dma << 1), offset_high);
  1224.         
  1225.             outp(pagePort[Dma], page_no);
  1226.         
  1227.             outp(DMA_COUNT + (Dma << 1), count_low);
  1228.         
  1229.             outp(DMA_COUNT + (Dma << 1), count_high);
  1230.         
  1231.             outp(DMA_MASK, Dma);
  1232.         
  1233.             
  1234.         /* calculate the high/low buffer size counts */ 
  1235.             Count_low = (uint8) (Sb_buf_size - 1) & 0x0ff;
  1236.         
  1237.             Count_high = (uint8) ((Sb_buf_size - 1) >> 8) & 0x0ff;
  1238.         
  1239.             
  1240.             if (DMAmode == STANDARD_DMA)
  1241.             
  1242.         {
  1243.             
  1244.             /* start the standard DMA transfer */ 
  1245.                 dsp_out(IOaddr + DSP_WRITE, 0x14);
  1246.             
  1247.                 dsp_out(IOaddr + DSP_WRITE, Count_low);
  1248.             
  1249.                 dsp_out(IOaddr + DSP_WRITE, Count_high);
  1250.             
  1251.         }
  1252.         
  1253.             else
  1254.             
  1255.         {
  1256.             
  1257.             /* reset the DMA counter */ 
  1258.                 DMAcount = 0;
  1259.             
  1260.                 
  1261.             /* set the auto-initialize buffer size */ 
  1262.                 dsp_out(IOaddr + DSP_WRITE, 0x48);
  1263.             
  1264.                 dsp_out(IOaddr + DSP_WRITE, Count_low);
  1265.             
  1266.                 dsp_out(IOaddr + DSP_WRITE, Count_high);
  1267.             
  1268.                 
  1269.             /* and start the auto-initialize DMA transfer */ 
  1270.                 dsp_out(IOaddr + DSP_WRITE, 0x1c);
  1271.             
  1272.                 
  1273.                 start_time = clock();
  1274.             
  1275.                 
  1276.             /* Delay for a bit and wait for DMAcount to change. */ 
  1277.             /* Wait for the DMA to be called twice to make sure */ 
  1278.             /* auto-init mode is working properly. */ 
  1279.                 while ((clock() - start_time < (int) (CLK_TCK / 2)) && (DMAcount < 2))
  1280.                 
  1281.             {
  1282.                 
  1283.                 /* This routine will wait for up to 1/2 second for DMAcount */ 
  1284.                 /* to change.  The value in CLK_TCK is the number of times */ 
  1285.                 /* the clock will tick in one second. */ 
  1286.             } 
  1287.                 
  1288.             /* if the auto-init DMA is not active */ 
  1289.                 if (DMAcount < 2)
  1290.                 
  1291.             {
  1292.                 
  1293.                 /* Reset the SB DSP */ 
  1294.                     ResetDSP(IOaddr);
  1295.                 
  1296.                     
  1297.                 /* then try again with STANDARD_DMA */ 
  1298.                     Start_audio_output(STANDARD_DMA, fillBuffer);
  1299.                 
  1300.             }
  1301.             
  1302.         }
  1303.         
  1304.             
  1305.             ret_val = 0;
  1306.         
  1307.     }
  1308.     
  1309.         
  1310.         return (ret_val);
  1311.     
  1312. }
  1313.  
  1314.  
  1315.  
  1316. /*****************************************************************************/ 
  1317. /*                                                                           */ 
  1318. /* Module:  newIntVect                                                       */ 
  1319. /* Purpose: The interrupt vector to handle the DAC DMAC completed interrupt  */ 
  1320. /*          Sends the next buffer to the SB and re-fills the current buffer. */ 
  1321. /* Author:  Ron Fries                                                        */ 
  1322. /* Date:    January 1, 1997                                                  */ 
  1323. /*                                                                           */ 
  1324. /*****************************************************************************/ 
  1325. #ifdef DJGPP
  1326. static void newIntVect(void) 
  1327. #else                            /* 
  1328.  */
  1329. static void interrupt newIntVect(void) 
  1330. #endif                            /* 
  1331.  */
  1332. {
  1333.     
  1334.         uint16 addr;
  1335.     
  1336.         
  1337.         if (DMAmode == STANDARD_DMA)
  1338.         
  1339.     {
  1340.         
  1341.         /* restart standard DMA transfer */ 
  1342.             dsp_out(IOaddr + DSP_WRITE, 0x14);
  1343.         
  1344.             dsp_out(IOaddr + DSP_WRITE, Count_low);
  1345.         
  1346.             dsp_out(IOaddr + DSP_WRITE, Count_high);
  1347.         
  1348.     }
  1349.     
  1350.         
  1351.         DMAcount++;
  1352.     
  1353.         
  1354.     /* acknowledge the DSP interrupt */ 
  1355.         inp(IOaddr + DSP_ACK);
  1356.     
  1357.         
  1358.     /* determine the current playback position */ 
  1359.         addr = inp(DMA_BASE + (Dma << 1));    /* get low byte ptr */
  1360.     
  1361.         addr |= inp(DMA_BASE + (Dma << 1)) << 8;    /* and high byte ptr */
  1362.     
  1363.         
  1364.         addr -= Sb_offset;        /* subtract the offset */
  1365.     
  1366.         
  1367.     /* if we're currently playing the first half of the buffer */ 
  1368.         if (addr < Sb_buf_size)
  1369.         
  1370.     {
  1371.         
  1372.         /* reload the second half of the buffer */ 
  1373.             FillBuffer(Sb_buffer + Sb_buf_size, Sb_buf_size);
  1374.         
  1375.             
  1376. #ifdef DJGPP
  1377.         /* Copy data to DOS memory buffer */ 
  1378.             dosmemput(Sb_buffer + Sb_buf_size, Sb_buf_size, 
  1379.                       (theDOSBufferSegment << 4) + Sb_buf_size);
  1380.         
  1381. #endif                            /* 
  1382.  */
  1383.     }
  1384.     
  1385.         else
  1386.         
  1387.     {
  1388.         
  1389.         /* else reload the first half of the buffer */ 
  1390.             FillBuffer(Sb_buffer, Sb_buf_size);
  1391.         
  1392.             
  1393. #ifdef DJGPP
  1394.         /* Copy data to DOS memory buffer */ 
  1395.             dosmemput(Sb_buffer, Sb_buf_size, theDOSBufferSegment << 4);
  1396.         
  1397. #endif                            /* 
  1398.  */
  1399.     }
  1400.     
  1401.         
  1402.     /* indicate end of interrupt  */ 
  1403.         outp(0x20, 0x20);
  1404.     
  1405.         
  1406.         if (Irq > 7)
  1407.         
  1408.     {
  1409.         
  1410.             outp(0xa0, 0x20);
  1411.         
  1412.     }
  1413.     
  1414. }
  1415.  
  1416.