aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/pcm_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/pcm_lib.c')
-rw-r--r--sound/core/pcm_lib.c92
1 files changed, 72 insertions, 20 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index d659995ac3a..333e4dd2945 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -22,6 +22,7 @@
22 22
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include <linux/time.h> 24#include <linux/time.h>
25#include <linux/math64.h>
25#include <sound/core.h> 26#include <sound/core.h>
26#include <sound/control.h> 27#include <sound/control.h>
27#include <sound/info.h> 28#include <sound/info.h>
@@ -126,24 +127,37 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
126} 127}
127 128
128#ifdef CONFIG_SND_PCM_XRUN_DEBUG 129#ifdef CONFIG_SND_PCM_XRUN_DEBUG
129#define xrun_debug(substream) ((substream)->pstr->xrun_debug) 130#define xrun_debug(substream, mask) ((substream)->pstr->xrun_debug & (mask))
130#else 131#else
131#define xrun_debug(substream) 0 132#define xrun_debug(substream, mask) 0
132#endif 133#endif
133 134
134#define dump_stack_on_xrun(substream) do { \ 135#define dump_stack_on_xrun(substream) do { \
135 if (xrun_debug(substream) > 1) \ 136 if (xrun_debug(substream, 2)) \
136 dump_stack(); \ 137 dump_stack(); \
137 } while (0) 138 } while (0)
138 139
140static void pcm_debug_name(struct snd_pcm_substream *substream,
141 char *name, size_t len)
142{
143 snprintf(name, len, "pcmC%dD%d%c:%d",
144 substream->pcm->card->number,
145 substream->pcm->device,
146 substream->stream ? 'c' : 'p',
147 substream->number);
148}
149
139static void xrun(struct snd_pcm_substream *substream) 150static void xrun(struct snd_pcm_substream *substream)
140{ 151{
152 struct snd_pcm_runtime *runtime = substream->runtime;
153
154 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
155 snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
141 snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); 156 snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
142 if (xrun_debug(substream)) { 157 if (xrun_debug(substream, 1)) {
143 snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n", 158 char name[16];
144 substream->pcm->card->number, 159 pcm_debug_name(substream, name, sizeof(name));
145 substream->pcm->device, 160 snd_printd(KERN_DEBUG "XRUN: %s\n", name);
146 substream->stream ? 'c' : 'p');
147 dump_stack_on_xrun(substream); 161 dump_stack_on_xrun(substream);
148 } 162 }
149} 163}
@@ -154,16 +168,16 @@ snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream,
154{ 168{
155 snd_pcm_uframes_t pos; 169 snd_pcm_uframes_t pos;
156 170
157 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
158 snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
159 pos = substream->ops->pointer(substream); 171 pos = substream->ops->pointer(substream);
160 if (pos == SNDRV_PCM_POS_XRUN) 172 if (pos == SNDRV_PCM_POS_XRUN)
161 return pos; /* XRUN */ 173 return pos; /* XRUN */
162 if (pos >= runtime->buffer_size) { 174 if (pos >= runtime->buffer_size) {
163 if (printk_ratelimit()) { 175 if (printk_ratelimit()) {
164 snd_printd(KERN_ERR "BUG: stream = %i, pos = 0x%lx, " 176 char name[16];
177 pcm_debug_name(substream, name, sizeof(name));
178 snd_printd(KERN_ERR "BUG: %s, pos = 0x%lx, "
165 "buffer size = 0x%lx, period size = 0x%lx\n", 179 "buffer size = 0x%lx, period size = 0x%lx\n",
166 substream->stream, pos, runtime->buffer_size, 180 name, pos, runtime->buffer_size,
167 runtime->period_size); 181 runtime->period_size);
168 } 182 }
169 pos = 0; 183 pos = 0;
@@ -197,7 +211,7 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
197 211
198#define hw_ptr_error(substream, fmt, args...) \ 212#define hw_ptr_error(substream, fmt, args...) \
199 do { \ 213 do { \
200 if (xrun_debug(substream)) { \ 214 if (xrun_debug(substream, 1)) { \
201 if (printk_ratelimit()) { \ 215 if (printk_ratelimit()) { \
202 snd_printd("PCM: " fmt, ##args); \ 216 snd_printd("PCM: " fmt, ##args); \
203 } \ 217 } \
@@ -251,7 +265,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
251 } 265 }
252 266
253 /* Do jiffies check only in xrun_debug mode */ 267 /* Do jiffies check only in xrun_debug mode */
254 if (!xrun_debug(substream)) 268 if (!xrun_debug(substream, 4))
255 goto no_jiffies_check; 269 goto no_jiffies_check;
256 270
257 /* Skip the jiffies check for hardwares with BATCH flag. 271 /* Skip the jiffies check for hardwares with BATCH flag.
@@ -261,6 +275,9 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
261 if (runtime->hw.info & SNDRV_PCM_INFO_BATCH) 275 if (runtime->hw.info & SNDRV_PCM_INFO_BATCH)
262 goto no_jiffies_check; 276 goto no_jiffies_check;
263 hdelta = new_hw_ptr - old_hw_ptr; 277 hdelta = new_hw_ptr - old_hw_ptr;
278 if (hdelta < runtime->delay)
279 goto no_jiffies_check;
280 hdelta -= runtime->delay;
264 jdelta = jiffies - runtime->hw_ptr_jiffies; 281 jdelta = jiffies - runtime->hw_ptr_jiffies;
265 if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) { 282 if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) {
266 delta = jdelta / 283 delta = jdelta /
@@ -294,14 +311,20 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
294 hw_ptr_interrupt = 311 hw_ptr_interrupt =
295 new_hw_ptr - new_hw_ptr % runtime->period_size; 312 new_hw_ptr - new_hw_ptr % runtime->period_size;
296 } 313 }
314 runtime->hw_ptr_interrupt = hw_ptr_interrupt;
315
297 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && 316 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
298 runtime->silence_size > 0) 317 runtime->silence_size > 0)
299 snd_pcm_playback_silence(substream, new_hw_ptr); 318 snd_pcm_playback_silence(substream, new_hw_ptr);
300 319
320 if (runtime->status->hw_ptr == new_hw_ptr)
321 return 0;
322
301 runtime->hw_ptr_base = hw_base; 323 runtime->hw_ptr_base = hw_base;
302 runtime->status->hw_ptr = new_hw_ptr; 324 runtime->status->hw_ptr = new_hw_ptr;
303 runtime->hw_ptr_jiffies = jiffies; 325 runtime->hw_ptr_jiffies = jiffies;
304 runtime->hw_ptr_interrupt = hw_ptr_interrupt; 326 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
327 snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
305 328
306 return snd_pcm_update_hw_ptr_post(substream, runtime); 329 return snd_pcm_update_hw_ptr_post(substream, runtime);
307} 330}
@@ -342,8 +365,12 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
342 new_hw_ptr = hw_base + pos; 365 new_hw_ptr = hw_base + pos;
343 } 366 }
344 /* Do jiffies check only in xrun_debug mode */ 367 /* Do jiffies check only in xrun_debug mode */
345 if (xrun_debug(substream) && 368 if (!xrun_debug(substream, 4))
346 ((delta * HZ) / runtime->rate) > jdelta + HZ/100) { 369 goto no_jiffies_check;
370 if (delta < runtime->delay)
371 goto no_jiffies_check;
372 delta -= runtime->delay;
373 if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) {
347 hw_ptr_error(substream, 374 hw_ptr_error(substream,
348 "hw_ptr skipping! " 375 "hw_ptr skipping! "
349 "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n", 376 "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n",
@@ -352,13 +379,19 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
352 ((delta * HZ) / runtime->rate)); 379 ((delta * HZ) / runtime->rate));
353 return 0; 380 return 0;
354 } 381 }
382 no_jiffies_check:
355 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && 383 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
356 runtime->silence_size > 0) 384 runtime->silence_size > 0)
357 snd_pcm_playback_silence(substream, new_hw_ptr); 385 snd_pcm_playback_silence(substream, new_hw_ptr);
358 386
387 if (runtime->status->hw_ptr == new_hw_ptr)
388 return 0;
389
359 runtime->hw_ptr_base = hw_base; 390 runtime->hw_ptr_base = hw_base;
360 runtime->status->hw_ptr = new_hw_ptr; 391 runtime->status->hw_ptr = new_hw_ptr;
361 runtime->hw_ptr_jiffies = jiffies; 392 runtime->hw_ptr_jiffies = jiffies;
393 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
394 snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
362 395
363 return snd_pcm_update_hw_ptr_post(substream, runtime); 396 return snd_pcm_update_hw_ptr_post(substream, runtime);
364} 397}
@@ -452,7 +485,7 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b,
452 *r = 0; 485 *r = 0;
453 return UINT_MAX; 486 return UINT_MAX;
454 } 487 }
455 div64_32(&n, c, r); 488 n = div_u64_rem(n, c, r);
456 if (n >= UINT_MAX) { 489 if (n >= UINT_MAX) {
457 *r = 0; 490 *r = 0;
458 return UINT_MAX; 491 return UINT_MAX;
@@ -1524,6 +1557,23 @@ static int snd_pcm_lib_ioctl_channel_info(struct snd_pcm_substream *substream,
1524 return 0; 1557 return 0;
1525} 1558}
1526 1559
1560static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream,
1561 void *arg)
1562{
1563 struct snd_pcm_hw_params *params = arg;
1564 snd_pcm_format_t format;
1565 int channels, width;
1566
1567 params->fifo_size = substream->runtime->hw.fifo_size;
1568 if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_FIFO_IN_FRAMES)) {
1569 format = params_format(params);
1570 channels = params_channels(params);
1571 width = snd_pcm_format_physical_width(format);
1572 params->fifo_size /= width * channels;
1573 }
1574 return 0;
1575}
1576
1527/** 1577/**
1528 * snd_pcm_lib_ioctl - a generic PCM ioctl callback 1578 * snd_pcm_lib_ioctl - a generic PCM ioctl callback
1529 * @substream: the pcm substream instance 1579 * @substream: the pcm substream instance
@@ -1545,6 +1595,8 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
1545 return snd_pcm_lib_ioctl_reset(substream, arg); 1595 return snd_pcm_lib_ioctl_reset(substream, arg);
1546 case SNDRV_PCM_IOCTL1_CHANNEL_INFO: 1596 case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
1547 return snd_pcm_lib_ioctl_channel_info(substream, arg); 1597 return snd_pcm_lib_ioctl_channel_info(substream, arg);
1598 case SNDRV_PCM_IOCTL1_FIFO_SIZE:
1599 return snd_pcm_lib_ioctl_fifo_size(substream, arg);
1548 } 1600 }
1549 return -ENXIO; 1601 return -ENXIO;
1550} 1602}