root/drivers/sound/sound_timer.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tmr2ticks
  2. reprogram_timer
  3. sound_timer_syncinterval
  4. tmr_reset
  5. timer_open
  6. timer_close
  7. timer_event
  8. timer_get_time
  9. timer_ioctl
  10. timer_arm
  11. sound_timer_interrupt
  12. sound_timer_init

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

/* [previous][next][first][last][top][bottom][index][help] */