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 #ifdef CONFIGURE_SOUNDCARD
  32 
  33 #if !defined(EXCLUDE_SEQUENCER)
  34 
  35 static volatile int initialized = 0, opened = 0, tmr_running = 0;
  36 static volatile time_t tmr_offs, tmr_ctr;
  37 static volatile unsigned long ticks_offs;
  38 static volatile int curr_tempo, curr_timebase;
  39 static volatile unsigned long curr_ticks;
  40 static volatile unsigned long next_event_time;
  41 static unsigned long prev_event_time;
  42 static volatile unsigned long usecs_per_tmr;    /* Length of the current interval */
  43 
  44 static struct sound_lowlev_timer *tmr = NULL;
  45 
  46 static unsigned long
  47 tmr2ticks (int tmr_value)
     /* [previous][next][first][last][top][bottom][index][help] */
  48 {
  49   /*
  50      *    Convert timer ticks to MIDI ticks
  51    */
  52 
  53   unsigned long   tmp;
  54   unsigned long   scale;
  55 
  56   tmp = tmr_value * usecs_per_tmr;      /* Convert to usecs */
  57 
  58   scale = (60 * 1000000) / (curr_tempo * curr_timebase);        /* usecs per MIDI tick */
  59 
  60   return (tmp + (scale / 2)) / scale;
  61 }
  62 
  63 static void
  64 reprogram_timer (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  65 {
  66   unsigned long   usecs_per_tick;
  67 
  68   usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase);
  69 
  70   /*
  71      * Don't kill the system by setting too high timer rate
  72    */
  73   if (usecs_per_tick < 2000)
  74     usecs_per_tick = 2000;
  75 
  76   usecs_per_tmr = tmr->tmr_start (tmr->dev, usecs_per_tick);
  77 }
  78 
  79 void
  80 sound_timer_syncinterval (unsigned int new_usecs)
     /* [previous][next][first][last][top][bottom][index][help] */
  81 {
  82 /*
  83  *    This routine is called by the hardware level if
  84  *      the clock frequency has changed for some reason.
  85  */
  86   tmr_offs = tmr_ctr;
  87   ticks_offs += tmr2ticks (tmr_ctr);
  88   tmr_ctr = 0;
  89 
  90   usecs_per_tmr = new_usecs;
  91 }
  92 
  93 static void
  94 tmr_reset (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  95 {
  96   unsigned long   flags;
  97 
  98   save_flags (flags);
  99   cli ();
 100   tmr_offs = 0;
 101   ticks_offs = 0;
 102   tmr_ctr = 0;
 103   next_event_time = 0xffffffff;
 104   prev_event_time = 0;
 105   curr_ticks = 0;
 106   restore_flags (flags);
 107 }
 108 
 109 static int
 110 timer_open (int dev, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 111 {
 112   if (opened)
 113     return -EBUSY;
 114 
 115   tmr_reset ();
 116   curr_tempo = 60;
 117   curr_timebase = HZ;
 118   opened = 1;
 119   reprogram_timer ();
 120 
 121   return 0;
 122 }
 123 
 124 static void
 125 timer_close (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 126 {
 127   opened = tmr_running = 0;
 128   tmr->tmr_disable (tmr->dev);
 129 }
 130 
 131 static int
 132 timer_event (int dev, unsigned char *event)
     /* [previous][next][first][last][top][bottom][index][help] */
 133 {
 134   unsigned char   cmd = event[1];
 135   unsigned long   parm = *(int *) &event[4];
 136 
 137   switch (cmd)
 138     {
 139     case TMR_WAIT_REL:
 140       parm += prev_event_time;
 141     case TMR_WAIT_ABS:
 142       if (parm > 0)
 143         {
 144           long            time;
 145 
 146           if (parm <= curr_ticks)       /* It's the time */
 147             return TIMER_NOT_ARMED;
 148 
 149           time = parm;
 150           next_event_time = prev_event_time = time;
 151 
 152           return TIMER_ARMED;
 153         }
 154       break;
 155 
 156     case TMR_START:
 157       tmr_reset ();
 158       tmr_running = 1;
 159       reprogram_timer ();
 160       break;
 161 
 162     case TMR_STOP:
 163       tmr_running = 0;
 164       break;
 165 
 166     case TMR_CONTINUE:
 167       tmr_running = 1;
 168       reprogram_timer ();
 169       break;
 170 
 171     case TMR_TEMPO:
 172       if (parm)
 173         {
 174           if (parm < 8)
 175             parm = 8;
 176           if (parm > 250)
 177             parm = 250;
 178           tmr_offs = tmr_ctr;
 179           ticks_offs += tmr2ticks (tmr_ctr);
 180           tmr_ctr = 0;
 181           curr_tempo = parm;
 182           reprogram_timer ();
 183         }
 184       break;
 185 
 186     case TMR_ECHO:
 187       seq_copy_to_input (event, 8);
 188       break;
 189 
 190     default:;
 191     }
 192 
 193   return TIMER_NOT_ARMED;
 194 }
 195 
 196 static unsigned long
 197 timer_get_time (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 198 {
 199   if (!opened)
 200     return 0;
 201 
 202   return curr_ticks;
 203 }
 204 
 205 static int
 206 timer_ioctl (int dev,
     /* [previous][next][first][last][top][bottom][index][help] */
 207              unsigned int cmd, ioctl_arg arg)
 208 {
 209   switch (cmd)
 210     {
 211     case SNDCTL_TMR_SOURCE:
 212       return snd_ioctl_return ((int *) arg, TMR_INTERNAL);
 213       break;
 214 
 215     case SNDCTL_TMR_START:
 216       tmr_reset ();
 217       tmr_running = 1;
 218       return 0;
 219       break;
 220 
 221     case SNDCTL_TMR_STOP:
 222       tmr_running = 0;
 223       return 0;
 224       break;
 225 
 226     case SNDCTL_TMR_CONTINUE:
 227       tmr_running = 1;
 228       return 0;
 229       break;
 230 
 231     case SNDCTL_TMR_TIMEBASE:
 232       {
 233         int             val = get_fs_long ((long *) arg);
 234 
 235         if (val)
 236           {
 237             if (val < 1)
 238               val = 1;
 239             if (val > 1000)
 240               val = 1000;
 241             curr_timebase = val;
 242           }
 243 
 244         return snd_ioctl_return ((int *) arg, curr_timebase);
 245       }
 246       break;
 247 
 248     case SNDCTL_TMR_TEMPO:
 249       {
 250         int             val = get_fs_long ((long *) arg);
 251 
 252         if (val)
 253           {
 254             if (val < 8)
 255               val = 8;
 256             if (val > 250)
 257               val = 250;
 258             tmr_offs = tmr_ctr;
 259             ticks_offs += tmr2ticks (tmr_ctr);
 260             tmr_ctr = 0;
 261             curr_tempo = val;
 262             reprogram_timer ();
 263           }
 264 
 265         return snd_ioctl_return ((int *) arg, curr_tempo);
 266       }
 267       break;
 268 
 269     case SNDCTL_SEQ_CTRLRATE:
 270       if (get_fs_long ((long *) arg) != 0)      /* Can't change */
 271         return -EINVAL;
 272 
 273       return snd_ioctl_return ((int *) arg, ((curr_tempo * curr_timebase) + 30) / 60);
 274       break;
 275 
 276     case SNDCTL_TMR_METRONOME:
 277       /* NOP */
 278       break;
 279 
 280     default:;
 281     }
 282 
 283   return -EINVAL;
 284 }
 285 
 286 static void
 287 timer_arm (int dev, long time)
     /* [previous][next][first][last][top][bottom][index][help] */
 288 {
 289   if (time < 0)
 290     time = curr_ticks + 1;
 291   else if (time <= curr_ticks)  /* It's the time */
 292     return;
 293 
 294   next_event_time = prev_event_time = time;
 295 
 296   return;
 297 }
 298 
 299 static struct sound_timer_operations sound_timer =
 300 {
 301   {"GUS Timer", 0},
 302   1,                            /* Priority */
 303   0,                            /* Local device link */
 304   timer_open,
 305   timer_close,
 306   timer_event,
 307   timer_get_time,
 308   timer_ioctl,
 309   timer_arm
 310 };
 311 
 312 void
 313 sound_timer_interrupt (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 314 {
 315   if (!opened)
 316     return;
 317 
 318   tmr->tmr_restart (tmr->dev);
 319 
 320   if (!tmr_running)
 321     return;
 322 
 323   tmr_ctr++;
 324   curr_ticks = ticks_offs + tmr2ticks (tmr_ctr);
 325 
 326   if (curr_ticks >= next_event_time)
 327     {
 328       next_event_time = 0xffffffff;
 329       sequencer_timer (0);
 330     }
 331 }
 332 
 333 void
 334 sound_timer_init (struct sound_lowlev_timer *t, char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 335 {
 336   int             n;
 337 
 338   if (initialized || t == NULL)
 339     return;                     /* There is already a similar timer */
 340 
 341   initialized = 1;
 342   tmr = t;
 343 
 344   if (num_sound_timers >= MAX_TIMER_DEV)
 345     n = 0;                      /* Overwrite the system timer */
 346   else
 347     n = num_sound_timers++;
 348 
 349   strcpy (sound_timer.info.name, name);
 350 
 351   sound_timer_devs[n] = &sound_timer;
 352 }
 353 
 354 #endif
 355 #endif

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