diff options
-rw-r--r-- | sound/drivers/dummy.c | 78 |
1 files changed, 43 insertions, 35 deletions
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index f387d53e5039..0a798bde0d03 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c | |||
@@ -205,21 +205,43 @@ struct snd_dummy { | |||
205 | struct dummy_systimer_pcm { | 205 | struct dummy_systimer_pcm { |
206 | spinlock_t lock; | 206 | spinlock_t lock; |
207 | struct timer_list timer; | 207 | struct timer_list timer; |
208 | unsigned int pcm_buffer_size; | 208 | unsigned long base_time; |
209 | unsigned int pcm_period_size; | 209 | unsigned int frac_pos; /* fractional sample position (based HZ) */ |
210 | unsigned int pcm_bps; /* bytes per second */ | 210 | unsigned int frac_buffer_size; /* buffer_size * HZ */ |
211 | unsigned int pcm_hz; /* HZ */ | 211 | unsigned int frac_period_size; /* period_size * HZ */ |
212 | unsigned int pcm_irq_pos; /* IRQ position */ | 212 | unsigned int rate; |
213 | unsigned int pcm_buf_pos; /* position in buffer */ | ||
214 | struct snd_pcm_substream *substream; | 213 | struct snd_pcm_substream *substream; |
215 | }; | 214 | }; |
216 | 215 | ||
216 | static void dummy_systimer_rearm(struct dummy_systimer_pcm *dpcm) | ||
217 | { | ||
218 | unsigned long frac; | ||
219 | |||
220 | frac = dpcm->frac_pos % dpcm->frac_period_size; | ||
221 | dpcm->timer.expires = jiffies + | ||
222 | (dpcm->frac_period_size + dpcm->rate - 1) / dpcm->rate; | ||
223 | add_timer(&dpcm->timer); | ||
224 | } | ||
225 | |||
226 | static void dummy_systimer_update(struct dummy_systimer_pcm *dpcm) | ||
227 | { | ||
228 | unsigned long delta; | ||
229 | |||
230 | delta = jiffies - dpcm->base_time; | ||
231 | if (!delta) | ||
232 | return; | ||
233 | dpcm->base_time = jiffies; | ||
234 | dpcm->frac_pos += delta * dpcm->rate; | ||
235 | while (dpcm->frac_pos >= dpcm->frac_buffer_size) | ||
236 | dpcm->frac_pos -= dpcm->frac_buffer_size; | ||
237 | } | ||
238 | |||
217 | static int dummy_systimer_start(struct snd_pcm_substream *substream) | 239 | static int dummy_systimer_start(struct snd_pcm_substream *substream) |
218 | { | 240 | { |
219 | struct dummy_systimer_pcm *dpcm = substream->runtime->private_data; | 241 | struct dummy_systimer_pcm *dpcm = substream->runtime->private_data; |
220 | spin_lock(&dpcm->lock); | 242 | spin_lock(&dpcm->lock); |
221 | dpcm->timer.expires = 1 + jiffies; | 243 | dpcm->base_time = jiffies; |
222 | add_timer(&dpcm->timer); | 244 | dummy_systimer_rearm(dpcm); |
223 | spin_unlock(&dpcm->lock); | 245 | spin_unlock(&dpcm->lock); |
224 | return 0; | 246 | return 0; |
225 | } | 247 | } |
@@ -237,20 +259,11 @@ static int dummy_systimer_prepare(struct snd_pcm_substream *substream) | |||
237 | { | 259 | { |
238 | struct snd_pcm_runtime *runtime = substream->runtime; | 260 | struct snd_pcm_runtime *runtime = substream->runtime; |
239 | struct dummy_systimer_pcm *dpcm = runtime->private_data; | 261 | struct dummy_systimer_pcm *dpcm = runtime->private_data; |
240 | int bps; | ||
241 | 262 | ||
242 | bps = snd_pcm_format_width(runtime->format) * runtime->rate * | 263 | dpcm->frac_pos = 0; |
243 | runtime->channels / 8; | 264 | dpcm->rate = runtime->rate; |
244 | 265 | dpcm->frac_buffer_size = runtime->buffer_size * HZ; | |
245 | if (bps <= 0) | 266 | dpcm->frac_period_size = runtime->period_size * HZ; |
246 | return -EINVAL; | ||
247 | |||
248 | dpcm->pcm_bps = bps; | ||
249 | dpcm->pcm_hz = HZ; | ||
250 | dpcm->pcm_buffer_size = snd_pcm_lib_buffer_bytes(substream); | ||
251 | dpcm->pcm_period_size = snd_pcm_lib_period_bytes(substream); | ||
252 | dpcm->pcm_irq_pos = 0; | ||
253 | dpcm->pcm_buf_pos = 0; | ||
254 | 267 | ||
255 | return 0; | 268 | return 0; |
256 | } | 269 | } |
@@ -261,26 +274,21 @@ static void dummy_systimer_callback(unsigned long data) | |||
261 | unsigned long flags; | 274 | unsigned long flags; |
262 | 275 | ||
263 | spin_lock_irqsave(&dpcm->lock, flags); | 276 | spin_lock_irqsave(&dpcm->lock, flags); |
264 | dpcm->timer.expires = 1 + jiffies; | 277 | dummy_systimer_update(dpcm); |
265 | add_timer(&dpcm->timer); | 278 | dummy_systimer_rearm(dpcm); |
266 | dpcm->pcm_irq_pos += dpcm->pcm_bps; | 279 | spin_unlock_irqrestore(&dpcm->lock, flags); |
267 | dpcm->pcm_buf_pos += dpcm->pcm_bps; | 280 | snd_pcm_period_elapsed(dpcm->substream); |
268 | dpcm->pcm_buf_pos %= dpcm->pcm_buffer_size * dpcm->pcm_hz; | ||
269 | if (dpcm->pcm_irq_pos >= dpcm->pcm_period_size * dpcm->pcm_hz) { | ||
270 | dpcm->pcm_irq_pos %= dpcm->pcm_period_size * dpcm->pcm_hz; | ||
271 | spin_unlock_irqrestore(&dpcm->lock, flags); | ||
272 | snd_pcm_period_elapsed(dpcm->substream); | ||
273 | } else | ||
274 | spin_unlock_irqrestore(&dpcm->lock, flags); | ||
275 | } | 281 | } |
276 | 282 | ||
277 | static snd_pcm_uframes_t | 283 | static snd_pcm_uframes_t |
278 | dummy_systimer_pointer(struct snd_pcm_substream *substream) | 284 | dummy_systimer_pointer(struct snd_pcm_substream *substream) |
279 | { | 285 | { |
280 | struct snd_pcm_runtime *runtime = substream->runtime; | 286 | struct dummy_systimer_pcm *dpcm = substream->runtime->private_data; |
281 | struct dummy_systimer_pcm *dpcm = runtime->private_data; | ||
282 | 287 | ||
283 | return bytes_to_frames(runtime, dpcm->pcm_buf_pos / dpcm->pcm_hz); | 288 | spin_lock(&dpcm->lock); |
289 | dummy_systimer_update(dpcm); | ||
290 | spin_unlock(&dpcm->lock); | ||
291 | return dpcm->frac_pos / HZ; | ||
284 | } | 292 | } |
285 | 293 | ||
286 | static int dummy_systimer_create(struct snd_pcm_substream *substream) | 294 | static int dummy_systimer_create(struct snd_pcm_substream *substream) |