home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3455 / sb.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-07  |  23.2 KB  |  1,113 lines

  1. /*
  2.  * Copyrighted as an unpublished work.
  3.  * (c) Copyright 1991 Brian Smith
  4.  * All rights reserved.
  5.  *
  6.  * Read the LICENSE file for details on distribution and use.
  7.  *
  8.  */
  9.  
  10.  
  11. #include <sys/types.h>
  12. #include <sys/param.h>
  13. #include <sys/file.h>
  14. #include <sys/ioctl.h>
  15. #include <sys/dir.h>
  16. #include <sys/buf.h>
  17. #include <sys/iobuf.h>
  18. #include <sys/signal.h>
  19. #include <sys/user.h>
  20. #include <sys/sysmacros.h>
  21. #include <sys/dma.h>
  22. #include <sys/cmn_err.h>
  23. #include <sys/errno.h>
  24. #include <sys/inline.h>
  25. #include "sb.h"
  26.  
  27. /* defs needed because of ommisions ISC! */
  28. #ifndef DMA_Rdmode
  29. #define DMA_Rdmode 0x44
  30. #endif
  31. #ifndef DMA_Wrmode
  32. #define DMA_Wrmode 0x48
  33. #endif
  34. #ifndef DMA_BLOCK
  35. #define DMA_BLOCK 0
  36. #endif
  37. #ifndef DMA_NBLOCK
  38. #define DMA_NBLOCK 1
  39. #endif
  40.  
  41. extern ushort sb_configured;
  42. extern ushort sb_dma_chan;
  43. extern ushort sb_interrupt;
  44.  
  45. /* GLOBALS */
  46. struct sb_stat_type sb_status;          /* Soundblaster Status */
  47. extern time_t lbolt;
  48.  
  49.  
  50. /*
  51.  * reset DSP chip, and return TRUE if successful
  52.  */
  53. static int dsp_reset()
  54. {
  55.     int i;
  56.     register unsigned char rc;
  57.  
  58.     /* reset dsp */
  59.     outb(DSP_RESET, 0x01);
  60.     tenmicrosec();
  61.     outb(DSP_RESET, 0x00);
  62.     for (i=0; i<200; i++)
  63.     {
  64.         rc = (unsigned char)inb(DSP_RDAVAIL);
  65.         if (rc & 128)
  66.         {
  67.             rc = inb(DSP_RDDATA);
  68.             if (rc == 0xAA)
  69.                 break;
  70.         }
  71.  
  72.         i--;
  73.         continue;
  74.     }
  75.     if (i>=200)
  76.         cmn_err(CE_WARN, "SoundBlaster(tm) DSP failed initialization\n");
  77.  
  78.     /* reset sampling speed */
  79.     dsp_speed();
  80.  
  81.     return(TRUE);
  82. }
  83.  
  84.  
  85. /*
  86.  * program the DSP's time constant: the sampling/output rate
  87.  */
  88. int dsp_speed()
  89. {
  90.     unchar time_constant;
  91.     unchar dsp_return;
  92.  
  93.     time_constant = (char)(256 - (1000000/sb_status.dsp_speed));
  94.  
  95.     /* send command SET_TIME_CONSTANT (0x40) */
  96.     do
  97.     {
  98.         dsp_return = inb(DSP_STATUS);
  99.     } while (dsp_return & (1<<7));
  100.     outb(DSP_COMMAND, 0x40);
  101.  
  102.     /* send one byte time_constant */
  103.     do
  104.     {
  105.         dsp_return = inb(DSP_STATUS);
  106.     } while (dsp_return & (1<<7));
  107.     outb(DSP_COMMAND, time_constant);
  108.  
  109.     return(TRUE);
  110. }
  111.  
  112.  
  113. /*
  114.  * called at OS startup time to initialize the SoundBlaster
  115.  */
  116. int sbinit()
  117. {
  118.     int failure = FALSE;
  119.  
  120.     if (!sb_configured)
  121.         cmn_err(CE_WARN, "sbinit(): SoundBlaster(tm) not configured\n");
  122.  
  123.     sbtab[0].b_actf = NULL;
  124.     sbtab[0].b_actl = NULL;
  125.     sbtab[0].b_active = FALSE;
  126.  
  127.     /* init cms chips' state */
  128.     sb_status.cms_open = NOT_OPEN;
  129.     sb_status.cms_waiting = 0;
  130.  
  131.     /* init fm chips' state */
  132.     sb_status.fm_open = NOT_OPEN;
  133.     sb_status.fm_waiting = 0;
  134.  
  135.     /* init dsp chip(s)' state */
  136.     sb_status.dsp_open = NOT_OPEN;
  137.     sb_status.dsp_speed = 11000;
  138.     sb_status.dsp_compression = ADCPM_8;
  139.     if (!dsp_reset())
  140.         failure = TRUE;
  141.  
  142.     /* all OK, send notification to console */
  143.     if (!failure)
  144.     {
  145.         cmn_err(CE_CONT, "SoundBlaster(tm) is recognized and initialized\n");
  146. #ifdef DEBUG
  147.         cmn_err(CE_CONT, "operating upon DMA channel %d\n", sb_dma_chan);
  148.         cmn_err(CE_CONT, "operating upon interrupt vector %d\n", sb_interrupt);
  149. #endif
  150.     }
  151.     else
  152.     {
  153.         cmn_err(CE_WARN, "SoundBlaster(tm) initialization failed\n");
  154.         sb_status.dsp_open = OPEN_READ | OPEN_WRITE;
  155.         sb_status.fm_open  = OPEN_READ | OPEN_WRITE;
  156.         sb_status.cms_open = OPEN_READ | OPEN_WRITE;
  157.     }
  158.  
  159.     return(0);
  160. }
  161.  
  162.  
  163. /*
  164.  * turn the dsp voice on if param is true
  165.  */
  166. void dsp_voice(on)
  167. int on;
  168. {
  169.     unchar dsp_return;
  170.  
  171.     do
  172.     {
  173.         dsp_return = inb(DSP_STATUS);
  174.     } while (dsp_return & (1<<7));
  175.  
  176.     if (on)
  177.     {
  178.         outb(DSP_COMMAND, 0xD1);
  179. #ifdef DEBUG
  180.         cmn_err(CE_CONT, "dsp_voice(): voice on\n");
  181. #endif
  182.     }
  183.     else
  184.     {
  185.         outb(DSP_COMMAND, 0xD3);
  186. #ifdef DEBUG
  187.         cmn_err(CE_CONT, "dsp_voice(): voice off\n");
  188. #endif
  189.     }
  190.  
  191.     return;
  192. }
  193.  
  194.  
  195. /*
  196.  * grabs the DSP chip for a process.
  197.  * sets u.u_error to EBUSY if already opened by other device
  198.  */
  199. static void dsp_open(flag)
  200. int flag;
  201. {
  202.     int old_pri;
  203.     int rc;
  204.  
  205.  
  206.     /* check if already open */
  207.     old_pri = spl6();
  208.     if (sb_status.dsp_open)
  209.     {
  210.         u.u_error = EBUSY;
  211.         splx(old_pri);
  212.         return;
  213.     }
  214.  
  215.     /* grab dma and device */
  216.     dma_alloc(SB_DMA_CHAN, DMA_BLOCK);
  217.     dsp_reset();
  218.     dsp_voice(FALSE);
  219.     if (flag & FWRITE)
  220.     {
  221.         if (flag & FREAD)
  222.         {
  223.             sb_status.dsp_open = OPEN_WRITE | OPEN_READ;
  224. #ifdef DEBUG
  225.             cmn_err(CE_CONT, "open read/write %d\n", flag);
  226. #endif
  227.         }
  228.         else
  229.         {
  230.             sb_status.dsp_open = OPEN_WRITE;
  231. #ifdef DEBUG
  232.             cmn_err(CE_CONT, "open write %d\n", flag);
  233. #endif
  234.             dsp_voice(TRUE);
  235.         }
  236.     }
  237.     else if (flag & FREAD)
  238.     {
  239.         sb_status.dsp_open = OPEN_READ;
  240. #ifdef DEBUG
  241.         cmn_err(CE_CONT, "open read/write %d\n", flag);
  242. #endif
  243.     }
  244.     else
  245.     {
  246. #ifdef DEBUG
  247.         cmn_err(CE_CONT, "unknown flags on open %d\n", flag);
  248. #endif
  249.         u.u_error = ENXIO;
  250.     }
  251.  
  252.     /* END CRITICAL */
  253.     splx(old_pri);
  254.  
  255.     return;
  256. }
  257.  
  258.  
  259. /*
  260.  * grabs the FM chips for a process.
  261.  * sets u.u_error to EBUSY if already opened by other device
  262.  */
  263. static void fm_open(flag)
  264. int flag;
  265. {
  266.     int old_pri;
  267.     int rc;
  268.  
  269.  
  270.     /* check if already open */
  271.     old_pri = spl6();
  272.     if (sb_status.fm_open != NOT_OPEN)
  273.     {
  274.         u.u_error = EBUSY;
  275.         splx(old_pri);
  276.         return;
  277.     }
  278.  
  279.     /* grab device and affirm that only openable with write permission */
  280.     fm_reset();
  281.     if (flag & FWRITE)
  282.         sb_status.fm_open = OPEN_WRITE;
  283.     else
  284.         u.u_error = ENXIO;
  285.  
  286.     /* END CRITICAL */
  287.     splx(old_pri);
  288.  
  289.     return;
  290. }
  291.  
  292.  
  293.  
  294. /*
  295.  * multiplexes opens to dsp_open(), fm_open(), and cms_open()
  296.  * depending upon which minor dev was used
  297.  */
  298. int sbopen(dev, flag)
  299. int dev;
  300. int flag;
  301. {
  302.     int minor_num;
  303.  
  304. #ifdef DEBUG
  305.     cmn_err(CE_CONT, "opened with flag %d\n", flag);
  306. #endif
  307.  
  308.     minor_num = minor(dev);
  309.     switch (minor_num)
  310.     {
  311.         case SB_CMS_NUM:
  312.             u.u_error = ENXIO;
  313.             break;
  314.         case SB_FM_NUM:
  315.             fm_open(flag);
  316.             break;
  317.         case SB_DSP_NUM:
  318.             dsp_open(flag);
  319.             break;
  320.         default:
  321.             u.u_error = ENXIO;
  322.     }
  323.  
  324.     return(0);
  325. }
  326.  
  327.  
  328. /*
  329.  * Release and reset the dsp chip
  330.  */
  331. void dsp_close()
  332. {
  333.     int old_pri;
  334.  
  335.     old_pri = spl6();
  336.     sb_status.dsp_open = NOT_OPEN;
  337.     dsp_reset();
  338.     dsp_voice(FALSE);
  339.     dma_relse(SB_DMA_CHAN);
  340.     splx(old_pri);
  341.  
  342.     return;
  343. }
  344.  
  345.  
  346. /*
  347.  * Release and reset the fm chip
  348.  */
  349. void fm_close()
  350. {
  351.     int old_pri;
  352.  
  353.     old_pri = spl6();
  354.     sb_status.fm_open = NOT_OPEN;
  355.     fm_reset();
  356.     splx(old_pri);
  357.  
  358.     return;
  359. }
  360.  
  361.  
  362. /*
  363.  * Multiplexes between the closes for dsp, fm, and cms chips
  364.  */
  365. int sbclose(dev)
  366. int dev;
  367. {
  368.     int minor_num;
  369.  
  370.     minor_num = minor(dev);
  371.     switch (minor_num)
  372.     {
  373.         case SB_CMS_NUM:
  374.             break;
  375.         case SB_FM_NUM:
  376.             fm_close();
  377.             break;
  378.         case SB_DSP_NUM:
  379.             dsp_close();
  380.             break;
  381.         default:
  382.             u.u_error = ENXIO;
  383.     }
  384.  
  385.     return(0);
  386. }
  387.  
  388.  
  389. /*
  390.  * start DMA rolling for DSP
  391.  * only used by DSP chips, so no need for multiplexing on minor num
  392.  */
  393. int sb_iostart()
  394. {
  395.     int old_pri;
  396.     paddr_t phys_address;
  397.     unsigned char tmp_byte;
  398.     unsigned int length;
  399.  
  400.     /* begin critical */
  401.     old_pri = spl6();
  402.  
  403.     /* check for invalid length of buf */
  404.     if ((sbtab[0].b_actf->b_bcount < 1) || (sbtab[0].b_actf->b_bcount > 0xFFFF))
  405.     {
  406.         cmn_err(CE_WARN, "sb_iostart(): invalid length of buf, %d\n",
  407.             sbtab[0].b_actf->b_bcount);
  408.  
  409.         /* artificially terminate */
  410.         sbtab[0].b_actf->b_resid = 0;
  411.         sbtab[0].b_actf = sbtab[0].b_actf->av_forw;
  412.         iodone(sbtab[0].b_actf);
  413.         splx(old_pri);
  414.         return(0);
  415.     }
  416.  
  417.     /* mark device in sbtab as active */
  418.     sbtab[0].b_active = TRUE;
  419.  
  420.     /* prep DMA channel */
  421.     phys_address = vtop(paddr(sbtab[0].b_actf), sbtab[0].b_actf->b_proc);
  422.     if (sbtab[0].b_actf->b_flags & B_READ)
  423.         dma_param(SB_DMA_CHAN, DMA_Rdmode, phys_address,
  424.             sbtab[0].b_actf->b_bcount);
  425.     else
  426.         dma_param(SB_DMA_CHAN, DMA_Wrmode, phys_address,
  427.             sbtab[0].b_actf->b_bcount);
  428.     dma_enable(SB_DMA_CHAN);
  429.  
  430.     /* prep SoundBlaster for 8-bit DMA */
  431.     do {
  432.         tmp_byte = inb(DSP_STATUS);
  433.     } while (tmp_byte & (1<<7));
  434.     if (sbtab[0].b_actf->b_flags & B_READ)
  435.         outb(DSP_COMMAND, 0x24);
  436.     else
  437.         outb(DSP_COMMAND, 0x14);
  438.  
  439.     /* prep SoundBlaster for length */
  440.     length = sbtab[0].b_actf->b_bcount-1;
  441.     do {
  442.         tmp_byte = inb(DSP_STATUS);
  443.     } while (tmp_byte & (1<<7));
  444.     tmp_byte = length & 0xFF;
  445.     outb(DSP_COMMAND, tmp_byte);
  446.     do {
  447.         tmp_byte = inb(DSP_STATUS);
  448.     } while (tmp_byte & (1<<7));
  449.     tmp_byte = (length & 0xFF00) >> 8;
  450.     outb(DSP_COMMAND, tmp_byte);
  451.  
  452.     /* end critical */
  453.     splx(old_pri);
  454.  
  455.     return(0);
  456. }
  457.  
  458.  
  459. /*
  460.  * write sound samples to dsp
  461.  */
  462. int sb_strategy(bufhead)
  463. register struct buf *bufhead;
  464. {
  465.     int old_pri;
  466.  
  467.     /* start critical section */
  468.     old_pri = spl6();
  469.  
  470.     /* prep buffer for addition to queue */
  471.     bufhead->b_start = lbolt;
  472.     bufhead->av_forw = NULL;
  473.  
  474.     /* add buffer to queue */
  475.     if (sbtab[0].b_actf == NULL)
  476.     {
  477.         /* add to empty queue */
  478.         sbtab[0].b_actf = bufhead;
  479.         sbtab[0].b_actl = bufhead;
  480.  
  481.         /* start io */
  482.         sb_iostart();
  483.     }
  484.     else
  485.     {
  486.         /* add to already started queue */
  487.         sbtab[0].b_actl->av_forw = bufhead;
  488.         sbtab[0].b_actl = bufhead;
  489.     }
  490.  
  491.     /* end critical section */
  492.     splx(old_pri);
  493.  
  494.     return(0);
  495. }
  496.  
  497.  
  498. /*
  499.  * breaks up io requests so that DMA can be done
  500.  */
  501. static int sb_breakup(bp)
  502. register struct buf *bp;
  503. {
  504.     dma_breakup(sb_strategy, bp);
  505.     return(0);
  506. }
  507.  
  508.  
  509. /*
  510.  * Starts the DMA write to the  Soundblaster
  511.  */
  512. int dsp_write(dev)
  513. int dev;
  514. {
  515.     physio(sb_breakup, 0, dev, B_WRITE);
  516.     return(0);
  517. }
  518.  
  519.  
  520. /*
  521.  * multiplexes writes to dsp, cm/s and fm chips
  522.  */
  523. int sbwrite(dev)
  524. int dev;
  525. {
  526.     int minor_num;
  527.  
  528.     minor_num = minor(dev);
  529.     switch (minor_num)
  530.     {
  531.         case SB_CMS_NUM:
  532.             cmn_err(CE_CONT, "sbwrite(): error, cms device accessed\n");
  533.             u.u_error = ENXIO;
  534.             break;
  535.         case SB_FM_NUM:
  536.             u.u_error = ENXIO;
  537.             break;
  538.         case SB_DSP_NUM:
  539.             dsp_write(dev);
  540.             break;
  541.         default:
  542.             cmn_err(CE_CONT, "sbwrite(): unknown minor device %d\n", minor_num);
  543.             u.u_error = ENXIO;
  544.     }
  545.     return(0);
  546. }
  547.  
  548.  
  549. /*
  550.  * Starts the DMA read from the Soundblaster
  551.  */
  552. int dsp_read(dev)
  553. int dev;
  554. {
  555.     physio(sb_breakup, 0, dev, B_READ);
  556.     return(0);
  557. }
  558.  
  559.  
  560. /*
  561.  * multiplexes read/writes to different functions
  562.  */
  563. int sbread(dev)
  564. int dev;
  565. {
  566.     int minor_num;
  567.  
  568.     minor_num = minor(dev);
  569.     switch (minor_num)
  570.     {
  571.         case SB_CMS_NUM:
  572.             cmn_err(CE_CONT, "sbread(): error, cms device accessed\n");
  573.             u.u_error = ENXIO;
  574.             break;
  575.         case SB_FM_NUM:
  576.             u.u_error = ENXIO;
  577.             break;
  578.         case SB_DSP_NUM:
  579.             dsp_read(dev);
  580.             break;
  581.         default:
  582.             cmn_err(CE_CONT, "sbread(): unknown minor device %d\n", minor_num);
  583.             u.u_error = ENXIO;
  584.     }
  585.     return(0);
  586. }
  587.  
  588.  
  589. /*
  590.  * minor control function for the dsp
  591.  */
  592. void dsp_ioctl(cmd, arg1, arg2)
  593. int cmd;
  594. caddr_t arg1, arg2;
  595. {
  596.     switch(cmd)
  597.     {
  598.         case DSP_IOCTL_RESET:
  599.             dsp_reset();
  600.             break;
  601.         case DSP_IOCTL_SPEED:
  602.             sb_status.dsp_speed = (int)arg1;
  603.             dsp_speed();
  604.             break;
  605.         case DSP_IOCTL_VOICE:
  606.             dsp_voice((int)arg1);
  607.             break;
  608.         default:
  609.             break;
  610.     }
  611.  
  612.     return;
  613. }
  614.  
  615.  
  616. /*
  617.  * turns a note/key off
  618.  */
  619. void fm_key_off(voice_num)
  620. int voice_num;
  621. {
  622.     unsigned char reg_num;
  623.     
  624.     /* error checking to avoid munching kernel */
  625.     if ((voice_num < 0) || (voice_num >= MAX_FM_NOTES))
  626.     {
  627.         u.u_error = EFAULT;
  628.         return;
  629.     }
  630.     
  631.     /* turn voice off */
  632.     reg_num = (unsigned char)0xB0 + (unsigned char)voice_num;
  633. #ifdef DEBUG
  634.     cmn_err(CE_CONT, "turning off voice for voice %d\n", voice_num);
  635.     cmn_err(CE_CONT, "reg_num is %x\n", reg_num);
  636. #endif
  637.     outb(FM_SELECT, reg_num);
  638.     tenmicrosec();
  639.     outb(FM_REG, 0);
  640.     tenmicrosec();
  641.     tenmicrosec();
  642.     tenmicrosec();
  643.  
  644.     return;
  645. }
  646.  
  647. /*
  648.  * turns a key on, with the frequency and octave so indicated in the
  649.  * low 2 bytes of the data integer
  650.  */
  651. void fm_key_on(usr_note)
  652. int usr_note;
  653. {
  654.     register unsigned char reg_num;
  655.     int tmp_int;
  656.  
  657. #ifdef DEBUG
  658.     cmn_err(CE_CONT, "turning on voice for voice %d\n", note_num(usr_note));
  659.     cmn_err(CE_CONT, "fnum_low (dec): %d\n", fnum_low(usr_note));
  660.     cmn_err(CE_CONT, "fnum_low (hex): %x\n", fnum_low(usr_note));
  661.     cmn_err(CE_CONT, "keyon_blk_fnum (dec): %d\n", keyon_blk_fnum(usr_note));
  662.     cmn_err(CE_CONT, "keyon_blk_fnum (hex): %x\n", keyon_blk_fnum(usr_note));
  663. #endif
  664.  
  665.     /* put out first byte */
  666.     reg_num = (unsigned char)0xA0 + note_num(usr_note);
  667. #ifdef DEBUG
  668.     cmn_err(CE_CONT, "reg_num is %x\n", reg_num);
  669. #endif
  670.     outb(FM_SELECT, reg_num);
  671.     tenmicrosec();
  672.     outb(FM_REG, fnum_low(usr_note));
  673.     tenmicrosec();
  674.     tenmicrosec();
  675.     tenmicrosec();
  676.  
  677.     /* put out second byte */
  678.     reg_num = (unsigned char)0xB0 + note_num(usr_note);
  679. #ifdef DEBUG
  680.     cmn_err(CE_CONT, "reg_num is %x\n", reg_num);
  681. #endif
  682.     outb(FM_SELECT, reg_num);
  683.     tenmicrosec();
  684.     outb(FM_REG, keyon_blk_fnum(usr_note));
  685.     tenmicrosec();
  686.     tenmicrosec();
  687.     tenmicrosec();
  688.     
  689.     return;
  690. }
  691.  
  692. /* at this point, it just turns all notes to off */
  693. int fm_reset()
  694. {
  695.     int i;
  696.  
  697.     /* must be initialized? */
  698.     outb(FM_SELECT, 1);
  699.     tenmicrosec();
  700.     outb(FM_REG, 0);
  701.     tenmicrosec();
  702.     tenmicrosec();
  703.     tenmicrosec();
  704.  
  705.     /* dispense for time being */
  706.     for (i=0; i<MAX_FM_NOTES; i++)
  707.         fm_key_off(i);
  708.  
  709.     return(0);
  710. }
  711.  
  712.  
  713. /*
  714.  * set characteristics on a voice
  715.  */
  716. void fm_set_voice(usr_character)
  717. sb_fm_character *usr_character;
  718. {
  719.     register unsigned char op_cell_num;
  720.     int cell_offset;
  721.     sb_fm_character voice_data;
  722.     int i;
  723.  
  724.     /* copy in characteristics */
  725.     if (copyin(usr_character, &voice_data, sizeof(sb_fm_character)) == -1)
  726.     {
  727. #ifdef DEBUG
  728.         cmn_err(CE_CONT, "fm_set_voice(): bad address\n");
  729. #endif
  730.         u.u_error = EFAULT;
  731.         return;
  732.     }
  733.  
  734.     /* echo voice characteristics */
  735. #ifdef DEBUG
  736.     cmn_err(CE_CONT, "setting voice number %d\n", voice_data.voice_num);
  737.     cmn_err(CE_CONT, "setting voice number(hex) %x\n", voice_data.voice_num);
  738.     cmn_err(CE_CONT, "data: ");
  739.     for (i=0; i<16; i++)
  740.         cmn_err(CE_CONT, "%x ", (unsigned int)voice_data.data[i]);
  741.     cmn_err(CE_CONT, "\n");
  742. #endif
  743.  
  744.     /* check on voice_num range */
  745.     if ((voice_data.voice_num >= MAX_FM_NOTES) || (voice_data.voice_num < 0))
  746.     {
  747.         cmn_err(CE_CONT, "fm_set_voice(): voice number out of range\n");
  748.         u.u_error = EFAULT;
  749.     }
  750.     cell_offset = voice_data.voice_num%3 + ((voice_data.voice_num / 3) << 3);
  751.  
  752.     /* set sound characteristic */
  753.     op_cell_num = 0x20 + (char)cell_offset;
  754. #ifdef DEBUG
  755.     cmn_err(CE_CONT, "op_cell for 20-35 = %x\n", op_cell_num);
  756. #endif
  757.     outb(FM_SELECT, op_cell_num);
  758.     tenmicrosec();
  759.     outb(FM_REG, voice_data.data[0]);
  760.     tenmicrosec();
  761.     tenmicrosec();
  762.     tenmicrosec();
  763.     op_cell_num += 3;
  764. #ifdef DEBUG
  765.     cmn_err(CE_CONT, "op_cell for 20-35 = %x\n", op_cell_num);
  766. #endif
  767.     outb(FM_SELECT, op_cell_num);
  768.     tenmicrosec();
  769.     outb(FM_REG, voice_data.data[1]);
  770.     tenmicrosec();
  771.     tenmicrosec();
  772.     tenmicrosec();
  773.  
  774.     /* set level/output */
  775.     op_cell_num = 0x40 + (char)cell_offset;
  776. #ifdef DEBUG
  777.     cmn_err(CE_CONT, "op_cell for 40-55 = %x\n", op_cell_num);
  778. #endif
  779.     outb(FM_SELECT, op_cell_num);
  780.     tenmicrosec();
  781.     outb(FM_REG, voice_data.data[2]);
  782.     tenmicrosec();
  783.     tenmicrosec();
  784.     tenmicrosec();
  785.     op_cell_num += 3;
  786. #ifdef DEBUG
  787.     cmn_err(CE_CONT, "op_cell for 40-55 = %x\n", op_cell_num);
  788. #endif
  789.     outb(FM_SELECT, op_cell_num);
  790.     tenmicrosec();
  791.     outb(FM_REG, voice_data.data[3]);
  792.     tenmicrosec();
  793.     tenmicrosec();
  794.     tenmicrosec();
  795.  
  796.     /* set Attack/Decay */
  797.     op_cell_num = 0x60 + (char)cell_offset;
  798. #ifdef DEBUG
  799.     cmn_err(CE_CONT, "op_cell for 60-75 = %x\n", op_cell_num);
  800. #endif
  801.     outb(FM_SELECT, op_cell_num);
  802.     tenmicrosec();
  803.     outb(FM_REG, voice_data.data[4]);
  804.     tenmicrosec();
  805.     tenmicrosec();
  806.     tenmicrosec();
  807.     op_cell_num += 3;
  808. #ifdef DEBUG
  809.     cmn_err(CE_CONT, "op_cell for 60-75 = %x\n", op_cell_num);
  810. #endif
  811.     outb(FM_SELECT, op_cell_num);
  812.     tenmicrosec();
  813.     outb(FM_REG, voice_data.data[5]);
  814.     tenmicrosec();
  815.     tenmicrosec();
  816.     tenmicrosec();
  817.  
  818.     /* set Sustain/Release */
  819.     op_cell_num = 0x80 + (char)cell_offset;
  820. #ifdef DEBUG
  821.     cmn_err(CE_CONT, "op_cell for 80-95 = %x\n", op_cell_num);
  822. #endif
  823.     outb(FM_SELECT, op_cell_num);
  824.     tenmicrosec();
  825.     outb(FM_REG, voice_data.data[6]);
  826.     tenmicrosec();
  827.     tenmicrosec();
  828.     tenmicrosec();
  829.     op_cell_num += 3;
  830. #ifdef DEBUG
  831.     cmn_err(CE_CONT, "op_cell for 80-95 = %x\n", op_cell_num);
  832. #endif
  833.     outb(FM_SELECT, op_cell_num);
  834.     tenmicrosec();
  835.     outb(FM_REG, voice_data.data[7]);
  836.     tenmicrosec();
  837.     tenmicrosec();
  838.     tenmicrosec();
  839.  
  840.     /* set Wave Select */
  841.     op_cell_num = 0xE0 + (char)cell_offset;
  842. #ifdef DEBUG
  843.     cmn_err(CE_CONT, "op_cell for E0-F5 = %x\n", op_cell_num);
  844. #endif
  845.     outb(FM_SELECT, op_cell_num);
  846.     tenmicrosec();
  847.     outb(FM_REG, voice_data.data[8]);
  848.     tenmicrosec();
  849.     tenmicrosec();
  850.     tenmicrosec();
  851.     op_cell_num += 3;
  852. #ifdef DEBUG
  853.     cmn_err(CE_CONT, "op_cell for E0-F5 = %x\n", op_cell_num);
  854. #endif
  855.     outb(FM_SELECT, op_cell_num);
  856.     tenmicrosec();
  857.     outb(FM_REG, voice_data.data[9]);
  858.     tenmicrosec();
  859.     tenmicrosec();
  860.     tenmicrosec();
  861.  
  862.     /* set Feedback/Selectivity */
  863.     op_cell_num = (unsigned char)0xC0 + (unsigned char)voice_data.voice_num;
  864. #ifdef DEBUG
  865.     cmn_err(CE_CONT, "op_cell for C0-C8 = %x\n", op_cell_num);
  866. #endif
  867.     outb(FM_SELECT, op_cell_num);
  868.     tenmicrosec();
  869.     outb(FM_REG, voice_data.data[10]);
  870.     tenmicrosec();
  871.     tenmicrosec();
  872.     tenmicrosec();
  873.  
  874.     return;
  875. }
  876.  
  877.  
  878. /*
  879.  * set characteristics on an opcell
  880.  */
  881. void fm_set_opcell(usr_character)
  882. sb_fm_character *usr_character;
  883. {
  884.     register unsigned char op_cell_num;
  885.     int cell_offset;
  886.     sb_fm_character voice_data;
  887.     int i;
  888.  
  889.     /* copy in characteristics */
  890.     if (copyin(usr_character, &voice_data, sizeof(sb_fm_character)) == -1)
  891.     {
  892. #ifdef DEBUG
  893.         cmn_err(CE_CONT, "bad address\n");
  894. #endif
  895.         u.u_error = EFAULT;
  896.         return;
  897.     }
  898.  
  899.     /* echo voice characteristics */
  900. #ifdef DEBUG
  901.     cmn_err(CE_CONT, "setting opcell number %d\n", voice_data.voice_num);
  902.     cmn_err(CE_CONT, "setting opcell number(hex) %x\n", voice_data.voice_num);
  903.     cmn_err(CE_CONT, "data: ");
  904.     for (i=0; i<8; i++)
  905.         cmn_err(CE_CONT, "%x ", (unsigned int)voice_data.data[i]);
  906.     cmn_err(CE_CONT, "\n");
  907. #endif
  908.  
  909.     /* check on opcell range */
  910.     if ((voice_data.voice_num >= 2*MAX_FM_NOTES) || (voice_data.voice_num < 0))
  911.     {
  912.         cmn_err(CE_CONT, "opcell number out of range\n");
  913.         u.u_error = EFAULT;
  914.     }
  915.  
  916.     /* set sound characteristic */
  917.     op_cell_num = 0x20 + (char)voice_data.voice_num;
  918. #ifdef DEBUG
  919.     cmn_err(CE_CONT, "op_cell for 20-35 = %x\n", op_cell_num);
  920. #endif
  921.     outb(FM_SELECT, op_cell_num);
  922.     tenmicrosec();
  923.     outb(FM_REG, voice_data.data[0]);
  924.     tenmicrosec();
  925.     tenmicrosec();
  926.     tenmicrosec();
  927.  
  928.     /* set level/output */
  929.     op_cell_num = 0x40 + (char)voice_data.voice_num;
  930. #ifdef DEBUG
  931.     cmn_err(CE_CONT, "op_cell for 40-55 = %x\n", op_cell_num);
  932. #endif
  933.     outb(FM_SELECT, op_cell_num);
  934.     tenmicrosec();
  935.     outb(FM_REG, voice_data.data[1]);
  936.     tenmicrosec();
  937.     tenmicrosec();
  938.     tenmicrosec();
  939.  
  940.     /* set Attack/Decay */
  941.     op_cell_num = 0x60 + (char)voice_data.voice_num;
  942. #ifdef DEBUG
  943.     cmn_err(CE_CONT, "op_cell for 60-75 = %x\n", op_cell_num);
  944. #endif
  945.     outb(FM_SELECT, op_cell_num);
  946.     tenmicrosec();
  947.     outb(FM_REG, voice_data.data[2]);
  948.     tenmicrosec();
  949.     tenmicrosec();
  950.     tenmicrosec();
  951.  
  952.     /* set Sustain/Release */
  953.     op_cell_num = 0x80 + (char)voice_data.voice_num;
  954. #ifdef DEBUG
  955.     cmn_err(CE_CONT, "op_cell for 80-95 = %x\n", op_cell_num);
  956. #endif
  957.     outb(FM_SELECT, op_cell_num);
  958.     tenmicrosec();
  959.     outb(FM_REG, voice_data.data[3]);
  960.     tenmicrosec();
  961.     tenmicrosec();
  962.     tenmicrosec();
  963.  
  964.     /* set Wave Select */
  965.     op_cell_num = 0xE0 + (char)voice_data.voice_num;
  966. #ifdef DEBUG
  967.     cmn_err(CE_CONT, "op_cell for E0-F5 = %x\n", op_cell_num);
  968. #endif
  969.     outb(FM_SELECT, op_cell_num);
  970.     tenmicrosec();
  971.     outb(FM_REG, voice_data.data[4]);
  972.     tenmicrosec();
  973.     tenmicrosec();
  974.     tenmicrosec();
  975.  
  976.     /* set Feedback/Selectivity */
  977.     op_cell_num = (unsigned char)0xC0 + (unsigned char)voice_data.voice_num;
  978. #ifdef DEBUG
  979.     cmn_err(CE_CONT, "op_cell for C0-C8 = %x\n", op_cell_num);
  980. #endif
  981.     outb(FM_SELECT, op_cell_num);
  982.     tenmicrosec();
  983.     outb(FM_REG, voice_data.data[5]);
  984.     tenmicrosec();
  985.     tenmicrosec();
  986.     tenmicrosec();
  987.  
  988.     return;
  989. }
  990.  
  991. /*
  992.  * set the register which contains the keyon/off for rhythm, and depth flags
  993.  */
  994. void fm_set_rhythm(new_rhythm)
  995. int new_rhythm;
  996. {
  997.     /* herf it in */
  998.     outb(FM_SELECT, 0xBD);
  999.     tenmicrosec();
  1000.     outb(FM_REG, lobyte(new_rhythm));
  1001.     tenmicrosec();
  1002.     tenmicrosec();
  1003.     tenmicrosec();
  1004.  
  1005.     return;
  1006. }
  1007.  
  1008.  
  1009. /*
  1010.  * The only control for the FM chips.  The rest belongs in user code.
  1011.  */
  1012. void fm_ioctl(cmd, arg1, arg2)
  1013. int cmd;
  1014. caddr_t arg1, arg2;
  1015. {
  1016.     switch(cmd)
  1017.     {
  1018.         case FM_IOCTL_RESET:
  1019.             fm_reset();
  1020.             break;
  1021.         case FM_IOCTL_NOTE_ON:
  1022.             fm_key_on((int)arg1);
  1023.             break;
  1024.         case FM_IOCTL_NOTE_OFF:
  1025.             fm_key_off((int)arg1);
  1026.             break;
  1027.         case FM_IOCTL_SET_VOICE:
  1028.             fm_set_voice((sb_fm_character *)arg1);
  1029.             break;
  1030.         case FM_IOCTL_SET_OPCELL:
  1031.             fm_set_opcell((sb_fm_character *)arg1);
  1032.             break;
  1033.         case FM_IOCTL_SET_RHYTHM:
  1034.             fm_set_rhythm((int)arg1);
  1035.             break;
  1036.         default:
  1037.             break;
  1038.     }
  1039.  
  1040.     return;
  1041. }
  1042.  
  1043.  
  1044. /*
  1045.  * multiplex ioctl to different sub-devices (minor numbers)
  1046.  */
  1047. int sbioctl(dev, cmd, arg1, arg2)
  1048. int dev;
  1049. int cmd;
  1050. caddr_t arg1, arg2;
  1051. {
  1052.     int minor_num;
  1053.  
  1054.     minor_num = minor(dev);
  1055.     switch (minor_num)
  1056.     {
  1057.         case SB_CMS_NUM:
  1058.             cmn_err(CE_CONT, "sbioctl cms\n");
  1059.             break;
  1060.         case SB_FM_NUM:
  1061.             fm_ioctl(cmd, arg1, arg2);
  1062.             break;
  1063.         case SB_DSP_NUM:
  1064.             dsp_ioctl(cmd, arg1, arg2);
  1065.             break;
  1066.         default:
  1067.             cmn_err(CE_CONT, "sbioctl unknown minor %d\n", minor_num);
  1068.             u.u_error = ENXIO;
  1069.     }
  1070.     return(0);
  1071. }
  1072.  
  1073.  
  1074. /*
  1075.  * responds to interrupt sent by DSP chips
  1076.  * and starts the next block of DMA (if one is queued)
  1077.  */
  1078. int sbintr(vect)
  1079. int vect;
  1080. {
  1081.     int old_pri;
  1082.     unsigned char tmp_byte;
  1083.  
  1084.     /* ASSUME CRITICAL PRIORITY */
  1085.     old_pri = spl6();
  1086.  
  1087.     /* check for validity of interrupt */
  1088.     if (! sbtab[0].b_active)
  1089.     {   
  1090.         cmn_err(CE_CONT, "sbintr(): spurious interrupt\n");
  1091.         splx(old_pri);
  1092.         return(0);
  1093.     }
  1094.  
  1095.     /* aknowledge interrupt */
  1096.     tmp_byte = inb(DSP_RDAVAIL);
  1097.  
  1098.     /* acknowledge as done to waiting thread and remove buf from queue */ 
  1099.     sbtab[0].b_actf->b_resid = 0;
  1100.     iodone(sbtab[0].b_actf);
  1101.     sbtab[0].b_actf = sbtab[0].b_actf->av_forw;
  1102.  
  1103.     /* mark device as inactive and service rest of queue (if not empty) */
  1104.     sbtab[0].b_active = FALSE;
  1105.     if (sbtab[0].b_actf != NULL)
  1106.         sb_iostart();
  1107.  
  1108.     /* end of critical section */
  1109.     splx(old_pri);
  1110.  
  1111.     return(0);
  1112. }
  1113.