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