linux/sound/core/seq/seq_timer.c
<<
>>
Prefs
   1/*
   2 *   ALSA sequencer Timer
   3 *   Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl>
   4 *                              Jaroslav Kysela <perex@perex.cz>
   5 *
   6 *
   7 *   This program is free software; you can redistribute it and/or modify
   8 *   it under the terms of the GNU General Public License as published by
   9 *   the Free Software Foundation; either version 2 of the License, or
  10 *   (at your option) any later version.
  11 *
  12 *   This program is distributed in the hope that it will be useful,
  13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 *   GNU General Public License for more details.
  16 *
  17 *   You should have received a copy of the GNU General Public License
  18 *   along with this program; if not, write to the Free Software
  19 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  20 *
  21 */
  22
  23#include <sound/core.h>
  24#include <linux/slab.h>
  25#include "seq_timer.h"
  26#include "seq_queue.h"
  27#include "seq_info.h"
  28
  29/* allowed sequencer timer frequencies, in Hz */
  30#define MIN_FREQUENCY           10
  31#define MAX_FREQUENCY           6250
  32#define DEFAULT_FREQUENCY       1000
  33
  34#define SKEW_BASE       0x10000 /* 16bit shift */
  35
  36static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer *tmr)
  37{
  38        if (tmr->tempo < 1000000)
  39                tmr->tick.resolution = (tmr->tempo * 1000) / tmr->ppq;
  40        else {
  41                /* might overflow.. */
  42                unsigned int s;
  43                s = tmr->tempo % tmr->ppq;
  44                s = (s * 1000) / tmr->ppq;
  45                tmr->tick.resolution = (tmr->tempo / tmr->ppq) * 1000;
  46                tmr->tick.resolution += s;
  47        }
  48        if (tmr->tick.resolution <= 0)
  49                tmr->tick.resolution = 1;
  50        snd_seq_timer_update_tick(&tmr->tick, 0);
  51}
  52
  53/* create new timer (constructor) */
  54struct snd_seq_timer *snd_seq_timer_new(void)
  55{
  56        struct snd_seq_timer *tmr;
  57        
  58        tmr = kzalloc(sizeof(*tmr), GFP_KERNEL);
  59        if (!tmr)
  60                return NULL;
  61        spin_lock_init(&tmr->lock);
  62
  63        /* reset setup to defaults */
  64        snd_seq_timer_defaults(tmr);
  65        
  66        /* reset time */
  67        snd_seq_timer_reset(tmr);
  68        
  69        return tmr;
  70}
  71
  72/* delete timer (destructor) */
  73void snd_seq_timer_delete(struct snd_seq_timer **tmr)
  74{
  75        struct snd_seq_timer *t = *tmr;
  76        *tmr = NULL;
  77
  78        if (t == NULL) {
  79                pr_debug("ALSA: seq: snd_seq_timer_delete() called with NULL timer\n");
  80                return;
  81        }
  82        t->running = 0;
  83
  84        /* reset time */
  85        snd_seq_timer_stop(t);
  86        snd_seq_timer_reset(t);
  87
  88        kfree(t);
  89}
  90
  91void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
  92{
  93        unsigned long flags;
  94
  95        spin_lock_irqsave(&tmr->lock, flags);
  96        /* setup defaults */
  97        tmr->ppq = 96;          /* 96 PPQ */
  98        tmr->tempo = 500000;    /* 120 BPM */
  99        snd_seq_timer_set_tick_resolution(tmr);
 100        tmr->running = 0;
 101
 102        tmr->type = SNDRV_SEQ_TIMER_ALSA;
 103        tmr->alsa_id.dev_class = seq_default_timer_class;
 104        tmr->alsa_id.dev_sclass = seq_default_timer_sclass;
 105        tmr->alsa_id.card = seq_default_timer_card;
 106        tmr->alsa_id.device = seq_default_timer_device;
 107        tmr->alsa_id.subdevice = seq_default_timer_subdevice;
 108        tmr->preferred_resolution = seq_default_timer_resolution;
 109
 110        tmr->skew = tmr->skew_base = SKEW_BASE;
 111        spin_unlock_irqrestore(&tmr->lock, flags);
 112}
 113
 114static void seq_timer_reset(struct snd_seq_timer *tmr)
 115{
 116        /* reset time & songposition */
 117        tmr->cur_time.tv_sec = 0;
 118        tmr->cur_time.tv_nsec = 0;
 119
 120        tmr->tick.cur_tick = 0;
 121        tmr->tick.fraction = 0;
 122}
 123
 124void snd_seq_timer_reset(struct snd_seq_timer *tmr)
 125{
 126        unsigned long flags;
 127
 128        spin_lock_irqsave(&tmr->lock, flags);
 129        seq_timer_reset(tmr);
 130        spin_unlock_irqrestore(&tmr->lock, flags);
 131}
 132
 133
 134/* called by timer interrupt routine. the period time since previous invocation is passed */
 135static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
 136                                    unsigned long resolution,
 137                                    unsigned long ticks)
 138{
 139        unsigned long flags;
 140        struct snd_seq_queue *q = timeri->callback_data;
 141        struct snd_seq_timer *tmr;
 142
 143        if (q == NULL)
 144                return;
 145        tmr = q->timer;
 146        if (tmr == NULL)
 147                return;
 148        spin_lock_irqsave(&tmr->lock, flags);
 149        if (!tmr->running) {
 150                spin_unlock_irqrestore(&tmr->lock, flags);
 151                return;
 152        }
 153
 154        resolution *= ticks;
 155        if (tmr->skew != tmr->skew_base) {
 156                /* FIXME: assuming skew_base = 0x10000 */
 157                resolution = (resolution >> 16) * tmr->skew +
 158                        (((resolution & 0xffff) * tmr->skew) >> 16);
 159        }
 160
 161        /* update timer */
 162        snd_seq_inc_time_nsec(&tmr->cur_time, resolution);
 163
 164        /* calculate current tick */
 165        snd_seq_timer_update_tick(&tmr->tick, resolution);
 166
 167        /* register actual time of this timer update */
 168        do_gettimeofday(&tmr->last_update);
 169
 170        spin_unlock_irqrestore(&tmr->lock, flags);
 171
 172        /* check queues and dispatch events */
 173        snd_seq_check_queue(q, 1, 0);
 174}
 175
 176/* set current tempo */
 177int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo)
 178{
 179        unsigned long flags;
 180
 181        if (snd_BUG_ON(!tmr))
 182                return -EINVAL;
 183        if (tempo <= 0)
 184                return -EINVAL;
 185        spin_lock_irqsave(&tmr->lock, flags);
 186        if ((unsigned int)tempo != tmr->tempo) {
 187                tmr->tempo = tempo;
 188                snd_seq_timer_set_tick_resolution(tmr);
 189        }
 190        spin_unlock_irqrestore(&tmr->lock, flags);
 191        return 0;
 192}
 193
 194/* set current ppq */
 195int snd_seq_timer_set_ppq(struct snd_seq_timer * tmr, int ppq)
 196{
 197        unsigned long flags;
 198
 199        if (snd_BUG_ON(!tmr))
 200                return -EINVAL;
 201        if (ppq <= 0)
 202                return -EINVAL;
 203        spin_lock_irqsave(&tmr->lock, flags);
 204        if (tmr->running && (ppq != tmr->ppq)) {
 205                /* refuse to change ppq on running timers */
 206                /* because it will upset the song position (ticks) */
 207                spin_unlock_irqrestore(&tmr->lock, flags);
 208                pr_debug("ALSA: seq: cannot change ppq of a running timer\n");
 209                return -EBUSY;
 210        }
 211
 212        tmr->ppq = ppq;
 213        snd_seq_timer_set_tick_resolution(tmr);
 214        spin_unlock_irqrestore(&tmr->lock, flags);
 215        return 0;
 216}
 217
 218/* set current tick position */
 219int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr,
 220                                    snd_seq_tick_time_t position)
 221{
 222        unsigned long flags;
 223
 224        if (snd_BUG_ON(!tmr))
 225                return -EINVAL;
 226
 227        spin_lock_irqsave(&tmr->lock, flags);
 228        tmr->tick.cur_tick = position;
 229        tmr->tick.fraction = 0;
 230        spin_unlock_irqrestore(&tmr->lock, flags);
 231        return 0;
 232}
 233
 234/* set current real-time position */
 235int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr,
 236                                    snd_seq_real_time_t position)
 237{
 238        unsigned long flags;
 239
 240        if (snd_BUG_ON(!tmr))
 241                return -EINVAL;
 242
 243        snd_seq_sanity_real_time(&position);
 244        spin_lock_irqsave(&tmr->lock, flags);
 245        tmr->cur_time = position;
 246        spin_unlock_irqrestore(&tmr->lock, flags);
 247        return 0;
 248}
 249
 250/* set timer skew */
 251int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew,
 252                           unsigned int base)
 253{
 254        unsigned long flags;
 255
 256        if (snd_BUG_ON(!tmr))
 257                return -EINVAL;
 258
 259        /* FIXME */
 260        if (base != SKEW_BASE) {
 261                pr_debug("ALSA: seq: invalid skew base 0x%x\n", base);
 262                return -EINVAL;
 263        }
 264        spin_lock_irqsave(&tmr->lock, flags);
 265        tmr->skew = skew;
 266        spin_unlock_irqrestore(&tmr->lock, flags);
 267        return 0;
 268}
 269
 270int snd_seq_timer_open(struct snd_seq_queue *q)
 271{
 272        struct snd_timer_instance *t;
 273        struct snd_seq_timer *tmr;
 274        char str[32];
 275        int err;
 276
 277        tmr = q->timer;
 278        if (snd_BUG_ON(!tmr))
 279                return -EINVAL;
 280        if (tmr->timeri)
 281                return -EBUSY;
 282        sprintf(str, "sequencer queue %i", q->queue);
 283        if (tmr->type != SNDRV_SEQ_TIMER_ALSA)  /* standard ALSA timer */
 284                return -EINVAL;
 285        if (tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_SLAVE)
 286                tmr->alsa_id.dev_sclass = SNDRV_TIMER_SCLASS_SEQUENCER;
 287        err = snd_timer_open(&t, str, &tmr->alsa_id, q->queue);
 288        if (err < 0 && tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_SLAVE) {
 289                if (tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_GLOBAL ||
 290                    tmr->alsa_id.device != SNDRV_TIMER_GLOBAL_SYSTEM) {
 291                        struct snd_timer_id tid;
 292                        memset(&tid, 0, sizeof(tid));
 293                        tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL;
 294                        tid.dev_sclass = SNDRV_TIMER_SCLASS_SEQUENCER;
 295                        tid.card = -1;
 296                        tid.device = SNDRV_TIMER_GLOBAL_SYSTEM;
 297                        err = snd_timer_open(&t, str, &tid, q->queue);
 298                }
 299        }
 300        if (err < 0) {
 301                pr_err("ALSA: seq fatal error: cannot create timer (%i)\n", err);
 302                return err;
 303        }
 304        t->callback = snd_seq_timer_interrupt;
 305        t->callback_data = q;
 306        t->flags |= SNDRV_TIMER_IFLG_AUTO;
 307        spin_lock_irq(&tmr->lock);
 308        tmr->timeri = t;
 309        spin_unlock_irq(&tmr->lock);
 310        return 0;
 311}
 312
 313int snd_seq_timer_close(struct snd_seq_queue *q)
 314{
 315        struct snd_seq_timer *tmr;
 316        struct snd_timer_instance *t;
 317        
 318        tmr = q->timer;
 319        if (snd_BUG_ON(!tmr))
 320                return -EINVAL;
 321        spin_lock_irq(&tmr->lock);
 322        t = tmr->timeri;
 323        tmr->timeri = NULL;
 324        spin_unlock_irq(&tmr->lock);
 325        if (t)
 326                snd_timer_close(t);
 327        return 0;
 328}
 329
 330static int seq_timer_stop(struct snd_seq_timer *tmr)
 331{
 332        if (! tmr->timeri)
 333                return -EINVAL;
 334        if (!tmr->running)
 335                return 0;
 336        tmr->running = 0;
 337        snd_timer_pause(tmr->timeri);
 338        return 0;
 339}
 340
 341int snd_seq_timer_stop(struct snd_seq_timer *tmr)
 342{
 343        unsigned long flags;
 344        int err;
 345
 346        spin_lock_irqsave(&tmr->lock, flags);
 347        err = seq_timer_stop(tmr);
 348        spin_unlock_irqrestore(&tmr->lock, flags);
 349        return err;
 350}
 351
 352static int initialize_timer(struct snd_seq_timer *tmr)
 353{
 354        struct snd_timer *t;
 355        unsigned long freq;
 356
 357        t = tmr->timeri->timer;
 358        if (snd_BUG_ON(!t))
 359                return -EINVAL;
 360
 361        freq = tmr->preferred_resolution;
 362        if (!freq)
 363                freq = DEFAULT_FREQUENCY;
 364        else if (freq < MIN_FREQUENCY)
 365                freq = MIN_FREQUENCY;
 366        else if (freq > MAX_FREQUENCY)
 367                freq = MAX_FREQUENCY;
 368
 369        tmr->ticks = 1;
 370        if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE)) {
 371                unsigned long r = t->hw.resolution;
 372                if (! r && t->hw.c_resolution)
 373                        r = t->hw.c_resolution(t);
 374                if (r) {
 375                        tmr->ticks = (unsigned int)(1000000000uL / (r * freq));
 376                        if (! tmr->ticks)
 377                                tmr->ticks = 1;
 378                }
 379        }
 380        tmr->initialized = 1;
 381        return 0;
 382}
 383
 384static int seq_timer_start(struct snd_seq_timer *tmr)
 385{
 386        if (! tmr->timeri)
 387                return -EINVAL;
 388        if (tmr->running)
 389                seq_timer_stop(tmr);
 390        seq_timer_reset(tmr);
 391        if (initialize_timer(tmr) < 0)
 392                return -EINVAL;
 393        snd_timer_start(tmr->timeri, tmr->ticks);
 394        tmr->running = 1;
 395        do_gettimeofday(&tmr->last_update);
 396        return 0;
 397}
 398
 399int snd_seq_timer_start(struct snd_seq_timer *tmr)
 400{
 401        unsigned long flags;
 402        int err;
 403
 404        spin_lock_irqsave(&tmr->lock, flags);
 405        err = seq_timer_start(tmr);
 406        spin_unlock_irqrestore(&tmr->lock, flags);
 407        return err;
 408}
 409
 410static int seq_timer_continue(struct snd_seq_timer *tmr)
 411{
 412        if (! tmr->timeri)
 413                return -EINVAL;
 414        if (tmr->running)
 415                return -EBUSY;
 416        if (! tmr->initialized) {
 417                seq_timer_reset(tmr);
 418                if (initialize_timer(tmr) < 0)
 419                        return -EINVAL;
 420        }
 421        snd_timer_start(tmr->timeri, tmr->ticks);
 422        tmr->running = 1;
 423        do_gettimeofday(&tmr->last_update);
 424        return 0;
 425}
 426
 427int snd_seq_timer_continue(struct snd_seq_timer *tmr)
 428{
 429        unsigned long flags;
 430        int err;
 431
 432        spin_lock_irqsave(&tmr->lock, flags);
 433        err = seq_timer_continue(tmr);
 434        spin_unlock_irqrestore(&tmr->lock, flags);
 435        return err;
 436}
 437
 438/* return current 'real' time. use timeofday() to get better granularity. */
 439snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr)
 440{
 441        snd_seq_real_time_t cur_time;
 442        unsigned long flags;
 443
 444        spin_lock_irqsave(&tmr->lock, flags);
 445        cur_time = tmr->cur_time;
 446        if (tmr->running) { 
 447                struct timeval tm;
 448                int usec;
 449                do_gettimeofday(&tm);
 450                usec = (int)(tm.tv_usec - tmr->last_update.tv_usec);
 451                if (usec < 0) {
 452                        cur_time.tv_nsec += (1000000 + usec) * 1000;
 453                        cur_time.tv_sec += tm.tv_sec - tmr->last_update.tv_sec - 1;
 454                } else {
 455                        cur_time.tv_nsec += usec * 1000;
 456                        cur_time.tv_sec += tm.tv_sec - tmr->last_update.tv_sec;
 457                }
 458                snd_seq_sanity_real_time(&cur_time);
 459        }
 460        spin_unlock_irqrestore(&tmr->lock, flags);
 461        return cur_time;        
 462}
 463
 464/* TODO: use interpolation on tick queue (will only be useful for very
 465 high PPQ values) */
 466snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr)
 467{
 468        return tmr->tick.cur_tick;
 469}
 470
 471
 472#ifdef CONFIG_SND_PROC_FS
 473/* exported to seq_info.c */
 474void snd_seq_info_timer_read(struct snd_info_entry *entry,
 475                             struct snd_info_buffer *buffer)
 476{
 477        int idx;
 478        struct snd_seq_queue *q;
 479        struct snd_seq_timer *tmr;
 480        struct snd_timer_instance *ti;
 481        unsigned long resolution;
 482        
 483        for (idx = 0; idx < SNDRV_SEQ_MAX_QUEUES; idx++) {
 484                q = queueptr(idx);
 485                if (q == NULL)
 486                        continue;
 487                if ((tmr = q->timer) == NULL ||
 488                    (ti = tmr->timeri) == NULL) {
 489                        queuefree(q);
 490                        continue;
 491                }
 492                snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name);
 493                resolution = snd_timer_resolution(ti) * tmr->ticks;
 494                snd_iprintf(buffer, "  Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000);
 495                snd_iprintf(buffer, "  Skew : %u / %u\n", tmr->skew, tmr->skew_base);
 496                queuefree(q);
 497        }
 498}
 499#endif /* CONFIG_SND_PROC_FS */
 500
 501