From b5d10781731ece07bb2049e7743907194a5cc3f1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 4 Sep 2009 08:45:11 +0200 Subject: ALSA: dummy - Fix the timer calculation in systimer mode Fix the expire-time calculation in the systimer mode when the buffer size isn't aligned to the period size. Signed-off-by: Takashi Iwai --- sound/drivers/dummy.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 0a798bde0d03..e8e29bfb85ec 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -207,19 +207,18 @@ struct dummy_systimer_pcm { struct timer_list timer; unsigned long base_time; unsigned int frac_pos; /* fractional sample position (based HZ) */ + unsigned int frac_period_rest; unsigned int frac_buffer_size; /* buffer_size * HZ */ unsigned int frac_period_size; /* period_size * HZ */ unsigned int rate; + int elapsed; struct snd_pcm_substream *substream; }; static void dummy_systimer_rearm(struct dummy_systimer_pcm *dpcm) { - unsigned long frac; - - frac = dpcm->frac_pos % dpcm->frac_period_size; dpcm->timer.expires = jiffies + - (dpcm->frac_period_size + dpcm->rate - 1) / dpcm->rate; + (dpcm->frac_period_rest + dpcm->rate - 1) / dpcm->rate; add_timer(&dpcm->timer); } @@ -230,10 +229,16 @@ static void dummy_systimer_update(struct dummy_systimer_pcm *dpcm) delta = jiffies - dpcm->base_time; if (!delta) return; - dpcm->base_time = jiffies; - dpcm->frac_pos += delta * dpcm->rate; + dpcm->base_time += delta; + delta *= dpcm->rate; + dpcm->frac_pos += delta; while (dpcm->frac_pos >= dpcm->frac_buffer_size) dpcm->frac_pos -= dpcm->frac_buffer_size; + while (dpcm->frac_period_rest <= delta) { + dpcm->elapsed++; + dpcm->frac_period_rest += dpcm->frac_period_size; + } + dpcm->frac_period_rest -= delta; } static int dummy_systimer_start(struct snd_pcm_substream *substream) @@ -264,6 +269,8 @@ static int dummy_systimer_prepare(struct snd_pcm_substream *substream) dpcm->rate = runtime->rate; dpcm->frac_buffer_size = runtime->buffer_size * HZ; dpcm->frac_period_size = runtime->period_size * HZ; + dpcm->frac_period_rest = dpcm->frac_period_size; + dpcm->elapsed = 0; return 0; } @@ -272,23 +279,29 @@ static void dummy_systimer_callback(unsigned long data) { struct dummy_systimer_pcm *dpcm = (struct dummy_systimer_pcm *)data; unsigned long flags; + int elapsed = 0; spin_lock_irqsave(&dpcm->lock, flags); dummy_systimer_update(dpcm); dummy_systimer_rearm(dpcm); + elapsed = dpcm->elapsed; + dpcm->elapsed = 0; spin_unlock_irqrestore(&dpcm->lock, flags); - snd_pcm_period_elapsed(dpcm->substream); + if (elapsed) + snd_pcm_period_elapsed(dpcm->substream); } static snd_pcm_uframes_t dummy_systimer_pointer(struct snd_pcm_substream *substream) { struct dummy_systimer_pcm *dpcm = substream->runtime->private_data; + snd_pcm_uframes_t pos; spin_lock(&dpcm->lock); dummy_systimer_update(dpcm); + pos = dpcm->frac_pos / HZ; spin_unlock(&dpcm->lock); - return dpcm->frac_pos / HZ; + return pos; } static int dummy_systimer_create(struct snd_pcm_substream *substream) -- cgit v1.2.3