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