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