Linux Audio

Check our new training course

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