aboutsummaryrefslogtreecommitdiffstats
path: root/sound/drivers/dummy.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/drivers/dummy.c')
-rw-r--r--sound/drivers/dummy.c78
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 {
205struct dummy_systimer_pcm { 205struct 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
216static 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
226static 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
217static int dummy_systimer_start(struct snd_pcm_substream *substream) 239static 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
277static snd_pcm_uframes_t 283static snd_pcm_uframes_t
278dummy_systimer_pointer(struct snd_pcm_substream *substream) 284dummy_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
286static int dummy_systimer_create(struct snd_pcm_substream *substream) 294static int dummy_systimer_create(struct snd_pcm_substream *substream)