aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-09-03 10:01:06 -0400
committerTakashi Iwai <tiwai@suse.de>2009-09-03 10:01:06 -0400
commitb142037b4c1edf5ad0b2871c518d4f14ac1cd470 (patch)
tree5393c246984683fbdad90be7a80b70b111610dbc
parentc631d03c6873b9e17906556e84fcafc42f26a7c2 (diff)
ALSA: dummy - Better jiffies handling
In the system-timer mode, snd-dummy driver issues each tick to update the position. This is highly inefficient and even inaccurate if the timer can't be triggered at each tick. Now rewritten to wake up only at the period boundary. The position is calculated from the current jiffies. Signed-off-by: Takashi Iwai <tiwai@suse.de>
-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)