diff options
author | Takashi Iwai <tiwai@suse.de> | 2009-09-04 02:45:11 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-09-04 02:45:11 -0400 |
commit | b5d10781731ece07bb2049e7743907194a5cc3f1 (patch) | |
tree | ac13416d9e7ec24a155f4d71e3c9134204973eef /sound/drivers | |
parent | 30681bcf2b15a601b9460e6ddab22077998b8d4c (diff) |
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 <tiwai@suse.de>
Diffstat (limited to 'sound/drivers')
-rw-r--r-- | sound/drivers/dummy.c | 29 |
1 files changed, 21 insertions, 8 deletions
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 { | |||
207 | struct timer_list timer; | 207 | struct timer_list timer; |
208 | unsigned long base_time; | 208 | unsigned long base_time; |
209 | unsigned int frac_pos; /* fractional sample position (based HZ) */ | 209 | unsigned int frac_pos; /* fractional sample position (based HZ) */ |
210 | unsigned int frac_period_rest; | ||
210 | unsigned int frac_buffer_size; /* buffer_size * HZ */ | 211 | unsigned int frac_buffer_size; /* buffer_size * HZ */ |
211 | unsigned int frac_period_size; /* period_size * HZ */ | 212 | unsigned int frac_period_size; /* period_size * HZ */ |
212 | unsigned int rate; | 213 | unsigned int rate; |
214 | int elapsed; | ||
213 | struct snd_pcm_substream *substream; | 215 | struct snd_pcm_substream *substream; |
214 | }; | 216 | }; |
215 | 217 | ||
216 | static void dummy_systimer_rearm(struct dummy_systimer_pcm *dpcm) | 218 | static void dummy_systimer_rearm(struct dummy_systimer_pcm *dpcm) |
217 | { | 219 | { |
218 | unsigned long frac; | ||
219 | |||
220 | frac = dpcm->frac_pos % dpcm->frac_period_size; | ||
221 | dpcm->timer.expires = jiffies + | 220 | dpcm->timer.expires = jiffies + |
222 | (dpcm->frac_period_size + dpcm->rate - 1) / dpcm->rate; | 221 | (dpcm->frac_period_rest + dpcm->rate - 1) / dpcm->rate; |
223 | add_timer(&dpcm->timer); | 222 | add_timer(&dpcm->timer); |
224 | } | 223 | } |
225 | 224 | ||
@@ -230,10 +229,16 @@ static void dummy_systimer_update(struct dummy_systimer_pcm *dpcm) | |||
230 | delta = jiffies - dpcm->base_time; | 229 | delta = jiffies - dpcm->base_time; |
231 | if (!delta) | 230 | if (!delta) |
232 | return; | 231 | return; |
233 | dpcm->base_time = jiffies; | 232 | dpcm->base_time += delta; |
234 | dpcm->frac_pos += delta * dpcm->rate; | 233 | delta *= dpcm->rate; |
234 | dpcm->frac_pos += delta; | ||
235 | while (dpcm->frac_pos >= dpcm->frac_buffer_size) | 235 | while (dpcm->frac_pos >= dpcm->frac_buffer_size) |
236 | dpcm->frac_pos -= dpcm->frac_buffer_size; | 236 | dpcm->frac_pos -= dpcm->frac_buffer_size; |
237 | while (dpcm->frac_period_rest <= delta) { | ||
238 | dpcm->elapsed++; | ||
239 | dpcm->frac_period_rest += dpcm->frac_period_size; | ||
240 | } | ||
241 | dpcm->frac_period_rest -= delta; | ||
237 | } | 242 | } |
238 | 243 | ||
239 | static int dummy_systimer_start(struct snd_pcm_substream *substream) | 244 | static int dummy_systimer_start(struct snd_pcm_substream *substream) |
@@ -264,6 +269,8 @@ static int dummy_systimer_prepare(struct snd_pcm_substream *substream) | |||
264 | dpcm->rate = runtime->rate; | 269 | dpcm->rate = runtime->rate; |
265 | dpcm->frac_buffer_size = runtime->buffer_size * HZ; | 270 | dpcm->frac_buffer_size = runtime->buffer_size * HZ; |
266 | dpcm->frac_period_size = runtime->period_size * HZ; | 271 | dpcm->frac_period_size = runtime->period_size * HZ; |
272 | dpcm->frac_period_rest = dpcm->frac_period_size; | ||
273 | dpcm->elapsed = 0; | ||
267 | 274 | ||
268 | return 0; | 275 | return 0; |
269 | } | 276 | } |
@@ -272,23 +279,29 @@ static void dummy_systimer_callback(unsigned long data) | |||
272 | { | 279 | { |
273 | struct dummy_systimer_pcm *dpcm = (struct dummy_systimer_pcm *)data; | 280 | struct dummy_systimer_pcm *dpcm = (struct dummy_systimer_pcm *)data; |
274 | unsigned long flags; | 281 | unsigned long flags; |
282 | int elapsed = 0; | ||
275 | 283 | ||
276 | spin_lock_irqsave(&dpcm->lock, flags); | 284 | spin_lock_irqsave(&dpcm->lock, flags); |
277 | dummy_systimer_update(dpcm); | 285 | dummy_systimer_update(dpcm); |
278 | dummy_systimer_rearm(dpcm); | 286 | dummy_systimer_rearm(dpcm); |
287 | elapsed = dpcm->elapsed; | ||
288 | dpcm->elapsed = 0; | ||
279 | spin_unlock_irqrestore(&dpcm->lock, flags); | 289 | spin_unlock_irqrestore(&dpcm->lock, flags); |
280 | snd_pcm_period_elapsed(dpcm->substream); | 290 | if (elapsed) |
291 | snd_pcm_period_elapsed(dpcm->substream); | ||
281 | } | 292 | } |
282 | 293 | ||
283 | static snd_pcm_uframes_t | 294 | static snd_pcm_uframes_t |
284 | dummy_systimer_pointer(struct snd_pcm_substream *substream) | 295 | dummy_systimer_pointer(struct snd_pcm_substream *substream) |
285 | { | 296 | { |
286 | struct dummy_systimer_pcm *dpcm = substream->runtime->private_data; | 297 | struct dummy_systimer_pcm *dpcm = substream->runtime->private_data; |
298 | snd_pcm_uframes_t pos; | ||
287 | 299 | ||
288 | spin_lock(&dpcm->lock); | 300 | spin_lock(&dpcm->lock); |
289 | dummy_systimer_update(dpcm); | 301 | dummy_systimer_update(dpcm); |
302 | pos = dpcm->frac_pos / HZ; | ||
290 | spin_unlock(&dpcm->lock); | 303 | spin_unlock(&dpcm->lock); |
291 | return dpcm->frac_pos / HZ; | 304 | return pos; |
292 | } | 305 | } |
293 | 306 | ||
294 | static int dummy_systimer_create(struct snd_pcm_substream *substream) | 307 | static int dummy_systimer_create(struct snd_pcm_substream *substream) |