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