11a59d1b8SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-or-later */
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * ALSA sequencer Timer
41da177e4SLinus Torvalds * Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl>
51da177e4SLinus Torvalds */
61da177e4SLinus Torvalds #ifndef __SND_SEQ_TIMER_H
71da177e4SLinus Torvalds #define __SND_SEQ_TIMER_H
81da177e4SLinus Torvalds
91da177e4SLinus Torvalds #include <sound/timer.h>
101da177e4SLinus Torvalds #include <sound/seq_kernel.h>
111da177e4SLinus Torvalds
12c7e0b5bfSTakashi Iwai struct snd_seq_timer_tick {
131da177e4SLinus Torvalds snd_seq_tick_time_t cur_tick; /* current tick */
141da177e4SLinus Torvalds unsigned long resolution; /* time per tick in nsec */
151da177e4SLinus Torvalds unsigned long fraction; /* current time per tick in nsec */
16c7e0b5bfSTakashi Iwai };
171da177e4SLinus Torvalds
18c7e0b5bfSTakashi Iwai struct snd_seq_timer {
191da177e4SLinus Torvalds /* ... tempo / offset / running state */
201da177e4SLinus Torvalds
211da177e4SLinus Torvalds unsigned int running:1, /* running state of queue */
221da177e4SLinus Torvalds initialized:1; /* timer is initialized */
231da177e4SLinus Torvalds
241da177e4SLinus Torvalds unsigned int tempo; /* current tempo, us/tick */
251da177e4SLinus Torvalds int ppq; /* time resolution, ticks/quarter */
261da177e4SLinus Torvalds
271da177e4SLinus Torvalds snd_seq_real_time_t cur_time; /* current time */
28c7e0b5bfSTakashi Iwai struct snd_seq_timer_tick tick; /* current tick */
291da177e4SLinus Torvalds int tick_updated;
301da177e4SLinus Torvalds
311da177e4SLinus Torvalds int type; /* timer type */
32c7e0b5bfSTakashi Iwai struct snd_timer_id alsa_id; /* ALSA's timer ID */
33c7e0b5bfSTakashi Iwai struct snd_timer_instance *timeri; /* timer instance */
341da177e4SLinus Torvalds unsigned int ticks;
351da177e4SLinus Torvalds unsigned long preferred_resolution; /* timer resolution, ticks/sec */
361da177e4SLinus Torvalds
371da177e4SLinus Torvalds unsigned int skew;
381da177e4SLinus Torvalds unsigned int skew_base;
391da177e4SLinus Torvalds
403915bf29SArnd Bergmann struct timespec64 last_update; /* time of last clock update, used for interpolation */
411da177e4SLinus Torvalds
421da177e4SLinus Torvalds spinlock_t lock;
43c7e0b5bfSTakashi Iwai };
441da177e4SLinus Torvalds
451da177e4SLinus Torvalds
461da177e4SLinus Torvalds /* create new timer (constructor) */
47c7e0b5bfSTakashi Iwai struct snd_seq_timer *snd_seq_timer_new(void);
481da177e4SLinus Torvalds
491da177e4SLinus Torvalds /* delete timer (destructor) */
50c7e0b5bfSTakashi Iwai void snd_seq_timer_delete(struct snd_seq_timer **tmr);
511da177e4SLinus Torvalds
521da177e4SLinus Torvalds /* */
snd_seq_timer_update_tick(struct snd_seq_timer_tick * tick,unsigned long resolution)53c7e0b5bfSTakashi Iwai static inline void snd_seq_timer_update_tick(struct snd_seq_timer_tick *tick,
54c7e0b5bfSTakashi Iwai unsigned long resolution)
551da177e4SLinus Torvalds {
561da177e4SLinus Torvalds if (tick->resolution > 0) {
571da177e4SLinus Torvalds tick->fraction += resolution;
581da177e4SLinus Torvalds tick->cur_tick += (unsigned int)(tick->fraction / tick->resolution);
591da177e4SLinus Torvalds tick->fraction %= tick->resolution;
601da177e4SLinus Torvalds }
611da177e4SLinus Torvalds }
621da177e4SLinus Torvalds
631da177e4SLinus Torvalds
641da177e4SLinus Torvalds /* compare timestamp between events */
651da177e4SLinus Torvalds /* return 1 if a >= b; otherwise return 0 */
snd_seq_compare_tick_time(snd_seq_tick_time_t * a,snd_seq_tick_time_t * b)661da177e4SLinus Torvalds static inline int snd_seq_compare_tick_time(snd_seq_tick_time_t *a, snd_seq_tick_time_t *b)
671da177e4SLinus Torvalds {
681da177e4SLinus Torvalds /* compare ticks */
691da177e4SLinus Torvalds return (*a >= *b);
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds
snd_seq_compare_real_time(snd_seq_real_time_t * a,snd_seq_real_time_t * b)721da177e4SLinus Torvalds static inline int snd_seq_compare_real_time(snd_seq_real_time_t *a, snd_seq_real_time_t *b)
731da177e4SLinus Torvalds {
741da177e4SLinus Torvalds /* compare real time */
751da177e4SLinus Torvalds if (a->tv_sec > b->tv_sec)
761da177e4SLinus Torvalds return 1;
771da177e4SLinus Torvalds if ((a->tv_sec == b->tv_sec) && (a->tv_nsec >= b->tv_nsec))
781da177e4SLinus Torvalds return 1;
791da177e4SLinus Torvalds return 0;
801da177e4SLinus Torvalds }
811da177e4SLinus Torvalds
821da177e4SLinus Torvalds
snd_seq_sanity_real_time(snd_seq_real_time_t * tm)831da177e4SLinus Torvalds static inline void snd_seq_sanity_real_time(snd_seq_real_time_t *tm)
841da177e4SLinus Torvalds {
851da177e4SLinus Torvalds while (tm->tv_nsec >= 1000000000) {
861da177e4SLinus Torvalds /* roll-over */
871da177e4SLinus Torvalds tm->tv_nsec -= 1000000000;
881da177e4SLinus Torvalds tm->tv_sec++;
891da177e4SLinus Torvalds }
901da177e4SLinus Torvalds }
911da177e4SLinus Torvalds
921da177e4SLinus Torvalds
931da177e4SLinus Torvalds /* increment timestamp */
snd_seq_inc_real_time(snd_seq_real_time_t * tm,snd_seq_real_time_t * inc)941da177e4SLinus Torvalds static inline void snd_seq_inc_real_time(snd_seq_real_time_t *tm, snd_seq_real_time_t *inc)
951da177e4SLinus Torvalds {
961da177e4SLinus Torvalds tm->tv_sec += inc->tv_sec;
971da177e4SLinus Torvalds tm->tv_nsec += inc->tv_nsec;
981da177e4SLinus Torvalds snd_seq_sanity_real_time(tm);
991da177e4SLinus Torvalds }
1001da177e4SLinus Torvalds
snd_seq_inc_time_nsec(snd_seq_real_time_t * tm,unsigned long nsec)1011da177e4SLinus Torvalds static inline void snd_seq_inc_time_nsec(snd_seq_real_time_t *tm, unsigned long nsec)
1021da177e4SLinus Torvalds {
1031da177e4SLinus Torvalds tm->tv_nsec += nsec;
1041da177e4SLinus Torvalds snd_seq_sanity_real_time(tm);
1051da177e4SLinus Torvalds }
1061da177e4SLinus Torvalds
1071da177e4SLinus Torvalds /* called by timer isr */
108c7e0b5bfSTakashi Iwai struct snd_seq_queue;
109c7e0b5bfSTakashi Iwai int snd_seq_timer_open(struct snd_seq_queue *q);
110c7e0b5bfSTakashi Iwai int snd_seq_timer_close(struct snd_seq_queue *q);
111c7e0b5bfSTakashi Iwai int snd_seq_timer_midi_open(struct snd_seq_queue *q);
112c7e0b5bfSTakashi Iwai int snd_seq_timer_midi_close(struct snd_seq_queue *q);
113c7e0b5bfSTakashi Iwai void snd_seq_timer_defaults(struct snd_seq_timer *tmr);
114c7e0b5bfSTakashi Iwai void snd_seq_timer_reset(struct snd_seq_timer *tmr);
115c7e0b5bfSTakashi Iwai int snd_seq_timer_stop(struct snd_seq_timer *tmr);
116c7e0b5bfSTakashi Iwai int snd_seq_timer_start(struct snd_seq_timer *tmr);
117c7e0b5bfSTakashi Iwai int snd_seq_timer_continue(struct snd_seq_timer *tmr);
118c7e0b5bfSTakashi Iwai int snd_seq_timer_set_tempo(struct snd_seq_timer *tmr, int tempo);
119671ec859STakashi Iwai int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq);
120c7e0b5bfSTakashi Iwai int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr, snd_seq_tick_time_t position);
121c7e0b5bfSTakashi Iwai int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr, snd_seq_real_time_t position);
122c7e0b5bfSTakashi Iwai int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew, unsigned int base);
123*dc749779STakashi Iwai snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr,
124*dc749779STakashi Iwai bool adjust_ktime);
125c7e0b5bfSTakashi Iwai snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr);
1261da177e4SLinus Torvalds
1273b378e1fSMarcin Ślusarz extern int seq_default_timer_class;
1283b378e1fSMarcin Ślusarz extern int seq_default_timer_sclass;
1293b378e1fSMarcin Ślusarz extern int seq_default_timer_card;
1303b378e1fSMarcin Ślusarz extern int seq_default_timer_device;
1313b378e1fSMarcin Ślusarz extern int seq_default_timer_subdevice;
1323b378e1fSMarcin Ślusarz extern int seq_default_timer_resolution;
1333b378e1fSMarcin Ślusarz
1341da177e4SLinus Torvalds #endif
135