home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / drivers / sound / sound_timer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-18  |  8.2 KB  |  407 lines

  1. /*
  2.  * sound/sound_timer.c
  3.  *
  4.  * Timer for the level 2 interface of the /dev/sequencer. Uses the
  5.  * 80 and 320 usec timers of OPL-3 (PAS16 only) and GUS.
  6.  *
  7.  * Copyright by Hannu Savolainen 1993
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions are
  11.  * met: 1. Redistributions of source code must retain the above copyright
  12.  * notice, this list of conditions and the following disclaimer. 2.
  13.  * Redistributions in binary form must reproduce the above copyright notice,
  14.  * this list of conditions and the following disclaimer in the documentation
  15.  * and/or other materials provided with the distribution.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
  18.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20.  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  21.  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  23.  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  24.  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27.  * SUCH DAMAGE.
  28.  *
  29.  */
  30.  
  31. #define SEQUENCER_C
  32. #include "sound_config.h"
  33.  
  34. #ifdef CONFIGURE_SOUNDCARD
  35.  
  36. #if !defined(EXCLUDE_SEQUENCER) && (!defined(EXCLUDE_GUS) || (!defined(EXCLUDE_PAS) && !defined(EXCLUDE_YM3812)))
  37.  
  38. static volatile int initialized = 0, opened = 0, tmr_running = 0;
  39. static volatile time_t tmr_offs, tmr_ctr;
  40. static volatile unsigned long ticks_offs;
  41. static volatile int curr_tempo, curr_timebase;
  42. static volatile unsigned long curr_ticks;
  43. static volatile unsigned long next_event_time;
  44. static unsigned long prev_event_time;
  45. static volatile int select_addr, data_addr;
  46. static volatile int curr_timer = 0;
  47. static volatile unsigned long usecs_per_tmr;    /* Length of the current interval */
  48.  
  49.  
  50. static void
  51. timer_command (unsigned int addr, unsigned int val)
  52. {
  53.   int             i;
  54.  
  55.   OUTB ((unsigned char) (addr & 0xff), select_addr);
  56.  
  57.   for (i = 0; i < 2; i++)
  58.     INB (select_addr);
  59.  
  60.   OUTB ((unsigned char) (val & 0xff), data_addr);
  61.  
  62.   for (i = 0; i < 2; i++)
  63.     INB (select_addr);
  64. }
  65.  
  66. static void
  67. arm_timer (int timer, unsigned int interval)
  68. {
  69.  
  70.   curr_timer = timer;
  71.  
  72.   if (timer == 1)
  73.     {
  74.       gus_write8 (0x46, 256 - interval);    /* Set counter for timer 1 */
  75.       gus_write8 (0x45, 0x04);    /* Enable timer 1 IRQ */
  76.       timer_command (0x04, 0x01);    /* Start timer 1 */
  77.     }
  78.   else
  79.     {
  80.       gus_write8 (0x47, 256 - interval);    /* Set counter for timer 2 */
  81.       gus_write8 (0x45, 0x08);    /* Enable timer 2 IRQ */
  82.       timer_command (0x04, 0x02);    /* Start timer 2 */
  83.     }
  84. }
  85.  
  86. static unsigned long
  87. tmr2ticks (int tmr_value)
  88. {
  89.   /*
  90.  *    Convert timer ticks to MIDI ticks
  91.  */
  92.  
  93.   unsigned long   tmp;
  94.   unsigned long   scale;
  95.  
  96.   tmp = tmr_value * usecs_per_tmr;    /* Convert to usecs */
  97.  
  98.   scale = (60 * 1000000) / (curr_tempo * curr_timebase);    /* usecs per MIDI tick */
  99.  
  100.   return (tmp + (scale / 2)) / scale;
  101. }
  102.  
  103. static void
  104. reprogram_timer (void)
  105. {
  106.   unsigned long   usecs_per_tick;
  107.   int             timer_no, resolution;
  108.   int             divisor;
  109.  
  110.   usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase);
  111.  
  112.   /*
  113.  * Don't kill the system by setting too high timer rate
  114.  */
  115.   if (usecs_per_tick < 2000)
  116.     usecs_per_tick = 2000;
  117.  
  118.   if (usecs_per_tick > (256 * 80))
  119.     {
  120.       timer_no = 2;
  121.       resolution = 320;        /* usec */
  122.     }
  123.   else
  124.     {
  125.       timer_no = 1;
  126.       resolution = 80;        /* usec */
  127.     }
  128.  
  129.   divisor = (usecs_per_tick + (resolution / 2)) / resolution;
  130.   usecs_per_tmr = divisor * resolution;
  131.  
  132.   arm_timer (timer_no, divisor);
  133. }
  134.  
  135. static void
  136. tmr_reset (void)
  137. {
  138.   unsigned long   flags;
  139.  
  140.   DISABLE_INTR (flags);
  141.   tmr_offs = 0;
  142.   ticks_offs = 0;
  143.   tmr_ctr = 0;
  144.   next_event_time = 0xffffffff;
  145.   prev_event_time = 0;
  146.   curr_ticks = 0;
  147.   RESTORE_INTR (flags);
  148. }
  149.  
  150. static int
  151. timer_open (int dev, int mode)
  152. {
  153.   if (opened)
  154.     return RET_ERROR (EBUSY);
  155.  
  156.   tmr_reset ();
  157.   curr_tempo = 60;
  158.   curr_timebase = HZ;
  159.   opened = 1;
  160.   reprogram_timer ();
  161.  
  162.   return 0;
  163. }
  164.  
  165. static void
  166. timer_close (int dev)
  167. {
  168.   opened = tmr_running = 0;
  169.   gus_write8 (0x45, 0);        /* Disable both timers */
  170. }
  171.  
  172. static int
  173. timer_event (int dev, unsigned char *event)
  174. {
  175.   unsigned char   cmd = event[1];
  176.   unsigned long   parm = *(int *) &event[4];
  177.  
  178.   switch (cmd)
  179.     {
  180.     case TMR_WAIT_REL:
  181.       parm += prev_event_time;
  182.     case TMR_WAIT_ABS:
  183.       if (parm > 0)
  184.     {
  185.       long            time;
  186.  
  187.       if (parm <= curr_ticks)    /* It's the time */
  188.         return TIMER_NOT_ARMED;
  189.  
  190.       time = parm;
  191.       next_event_time = prev_event_time = time;
  192.  
  193.       return TIMER_ARMED;
  194.     }
  195.       break;
  196.  
  197.     case TMR_START:
  198.       tmr_reset ();
  199.       tmr_running = 1;
  200.       reprogram_timer ();
  201.       break;
  202.  
  203.     case TMR_STOP:
  204.       tmr_running = 0;
  205.       break;
  206.  
  207.     case TMR_CONTINUE:
  208.       tmr_running = 1;
  209.       reprogram_timer ();
  210.       break;
  211.  
  212.     case TMR_TEMPO:
  213.       if (parm)
  214.     {
  215.       if (parm < 8)
  216.         parm = 8;
  217.       if (parm > 250)
  218.         parm = 250;
  219.       tmr_offs = tmr_ctr;
  220.       ticks_offs += tmr2ticks (tmr_ctr);
  221.       tmr_ctr = 0;
  222.       curr_tempo = parm;
  223.       reprogram_timer ();
  224.     }
  225.       break;
  226.  
  227.     case TMR_ECHO:
  228.       seq_copy_to_input (event, 8);
  229.       break;
  230.  
  231.     default:;
  232.     }
  233.  
  234.   return TIMER_NOT_ARMED;
  235. }
  236.  
  237. static unsigned long
  238. timer_get_time (int dev)
  239. {
  240.   if (!opened)
  241.     return 0;
  242.  
  243.   return curr_ticks;
  244. }
  245.  
  246. static int
  247. timer_ioctl (int dev,
  248.          unsigned int cmd, unsigned int arg)
  249. {
  250.   switch (cmd)
  251.     {
  252.     case SNDCTL_TMR_SOURCE:
  253.       return IOCTL_OUT (arg, TMR_INTERNAL);
  254.       break;
  255.  
  256.     case SNDCTL_TMR_START:
  257.       tmr_reset ();
  258.       tmr_running = 1;
  259.       return 0;
  260.       break;
  261.  
  262.     case SNDCTL_TMR_STOP:
  263.       tmr_running = 0;
  264.       return 0;
  265.       break;
  266.  
  267.     case SNDCTL_TMR_CONTINUE:
  268.       tmr_running = 1;
  269.       return 0;
  270.       break;
  271.  
  272.     case SNDCTL_TMR_TIMEBASE:
  273.       {
  274.     int             val = IOCTL_IN (arg);
  275.  
  276.     if (val)
  277.       {
  278.         if (val < 1)
  279.           val = 1;
  280.         if (val > 1000)
  281.           val = 1000;
  282.         curr_timebase = val;
  283.       }
  284.  
  285.     return IOCTL_OUT (arg, curr_timebase);
  286.       }
  287.       break;
  288.  
  289.     case SNDCTL_TMR_TEMPO:
  290.       {
  291.     int             val = IOCTL_IN (arg);
  292.  
  293.     if (val)
  294.       {
  295.         if (val < 8)
  296.           val = 8;
  297.         if (val > 250)
  298.           val = 250;
  299.         tmr_offs = tmr_ctr;
  300.         ticks_offs += tmr2ticks (tmr_ctr);
  301.         tmr_ctr = 0;
  302.         curr_tempo = val;
  303.         reprogram_timer ();
  304.       }
  305.  
  306.     return IOCTL_OUT (arg, curr_tempo);
  307.       }
  308.       break;
  309.  
  310.     case SNDCTL_SEQ_CTRLRATE:
  311.       if (IOCTL_IN (arg) != 0)    /* Can't change */
  312.     return RET_ERROR (EINVAL);
  313.  
  314.       return IOCTL_OUT (arg, ((curr_tempo * curr_timebase) + 30) / 60);
  315.       break;
  316.  
  317.     case SNDCTL_TMR_METRONOME:
  318.       /* NOP */
  319.       break;
  320.  
  321.     default:
  322.     }
  323.  
  324.   return RET_ERROR (EINVAL);
  325. }
  326.  
  327. static void
  328. timer_arm (int dev, long time)
  329. {
  330.   if (time < 0)
  331.     time = curr_ticks + 1;
  332.   else if (time <= curr_ticks)    /* It's the time */
  333.     return;
  334.  
  335.   next_event_time = prev_event_time = time;
  336.  
  337.   return;
  338. }
  339.  
  340. static struct sound_timer_operations sound_timer =
  341. {
  342.   {"OPL-3/GUS Timer", 0},
  343.   1,                /* Priority */
  344.   0,                /* Local device link */
  345.   timer_open,
  346.   timer_close,
  347.   timer_event,
  348.   timer_get_time,
  349.   timer_ioctl,
  350.   timer_arm
  351. };
  352.  
  353. void
  354. sound_timer_interrupt (void)
  355. {
  356.   gus_write8 (0x45, 0);        /* Ack IRQ */
  357.   timer_command (4, 0x80);    /* Reset IRQ flags */
  358.  
  359.   if (!opened)
  360.     return;
  361.  
  362.   if (curr_timer == 1)
  363.     gus_write8 (0x45, 0x04);    /* Start timer 1 again */
  364.   else
  365.     gus_write8 (0x45, 0x08);    /* Start timer 2 again */
  366.  
  367.   if (!tmr_running)
  368.     return;
  369.  
  370.   tmr_ctr++;
  371.   curr_ticks = ticks_offs + tmr2ticks (tmr_ctr);
  372.  
  373.   if (curr_ticks >= next_event_time)
  374.     {
  375.       next_event_time = 0xffffffff;
  376.       sequencer_timer ();
  377.     }
  378. }
  379.  
  380. void
  381. sound_timer_init (int io_base)
  382. {
  383.   int             n;
  384.  
  385.   if (initialized)
  386.     return;            /* There is already a similar timer */
  387.  
  388.   select_addr = io_base;
  389.   data_addr = io_base + 1;
  390.  
  391.   initialized = 1;
  392.  
  393. #if 1
  394.   if (num_sound_timers >= MAX_TIMER_DEV)
  395.     n = 0;            /* Overwrite the system timer */
  396.   else
  397.     n = num_sound_timers++;
  398. #else
  399.   n = 0;
  400. #endif
  401.  
  402.   sound_timer_devs[n] = &sound_timer;
  403. }
  404.  
  405. #endif
  406. #endif
  407.