aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/asound.h1
-rw-r--r--include/sound/pcm.h1
-rw-r--r--sound/core/pcm_lib.c89
-rw-r--r--sound/core/pcm_native.c15
4 files changed, 84 insertions, 22 deletions
diff --git a/include/sound/asound.h b/include/sound/asound.h
index 6add80fc2512..82aed3f47534 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -255,6 +255,7 @@ typedef int __bitwise snd_pcm_subformat_t;
255#define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 /* only half duplex */ 255#define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 /* only half duplex */
256#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */ 256#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */
257#define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */ 257#define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */
258#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */
258 259
259typedef int __bitwise snd_pcm_state_t; 260typedef int __bitwise snd_pcm_state_t;
260#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */ 261#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 2092274212b9..23893523dc8c 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -98,6 +98,7 @@ struct snd_pcm_ops {
98#define SNDRV_PCM_IOCTL1_INFO 1 98#define SNDRV_PCM_IOCTL1_INFO 1
99#define SNDRV_PCM_IOCTL1_CHANNEL_INFO 2 99#define SNDRV_PCM_IOCTL1_CHANNEL_INFO 2
100#define SNDRV_PCM_IOCTL1_GSTATE 3 100#define SNDRV_PCM_IOCTL1_GSTATE 3
101#define SNDRV_PCM_IOCTL1_FIFO_SIZE 4
101 102
102#define SNDRV_PCM_TRIGGER_STOP 0 103#define SNDRV_PCM_TRIGGER_STOP 0
103#define SNDRV_PCM_TRIGGER_START 1 104#define SNDRV_PCM_TRIGGER_START 1
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index a7482874c451..333e4dd29450 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -127,24 +127,37 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
127} 127}
128 128
129#ifdef CONFIG_SND_PCM_XRUN_DEBUG 129#ifdef CONFIG_SND_PCM_XRUN_DEBUG
130#define xrun_debug(substream) ((substream)->pstr->xrun_debug) 130#define xrun_debug(substream, mask) ((substream)->pstr->xrun_debug & (mask))
131#else 131#else
132#define xrun_debug(substream) 0 132#define xrun_debug(substream, mask) 0
133#endif 133#endif
134 134
135#define dump_stack_on_xrun(substream) do { \ 135#define dump_stack_on_xrun(substream) do { \
136 if (xrun_debug(substream) > 1) \ 136 if (xrun_debug(substream, 2)) \
137 dump_stack(); \ 137 dump_stack(); \
138 } while (0) 138 } while (0)
139 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
140static void xrun(struct snd_pcm_substream *substream) 150static void xrun(struct snd_pcm_substream *substream)
141{ 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);
142 snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); 156 snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
143 if (xrun_debug(substream)) { 157 if (xrun_debug(substream, 1)) {
144 snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n", 158 char name[16];
145 substream->pcm->card->number, 159 pcm_debug_name(substream, name, sizeof(name));
146 substream->pcm->device, 160 snd_printd(KERN_DEBUG "XRUN: %s\n", name);
147 substream->stream ? 'c' : 'p');
148 dump_stack_on_xrun(substream); 161 dump_stack_on_xrun(substream);
149 } 162 }
150} 163}
@@ -155,16 +168,16 @@ snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream,
155{ 168{
156 snd_pcm_uframes_t pos; 169 snd_pcm_uframes_t pos;
157 170
158 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
159 snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
160 pos = substream->ops->pointer(substream); 171 pos = substream->ops->pointer(substream);
161 if (pos == SNDRV_PCM_POS_XRUN) 172 if (pos == SNDRV_PCM_POS_XRUN)
162 return pos; /* XRUN */ 173 return pos; /* XRUN */
163 if (pos >= runtime->buffer_size) { 174 if (pos >= runtime->buffer_size) {
164 if (printk_ratelimit()) { 175 if (printk_ratelimit()) {
165 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, "
166 "buffer size = 0x%lx, period size = 0x%lx\n", 179 "buffer size = 0x%lx, period size = 0x%lx\n",
167 substream->stream, pos, runtime->buffer_size, 180 name, pos, runtime->buffer_size,
168 runtime->period_size); 181 runtime->period_size);
169 } 182 }
170 pos = 0; 183 pos = 0;
@@ -198,7 +211,7 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
198 211
199#define hw_ptr_error(substream, fmt, args...) \ 212#define hw_ptr_error(substream, fmt, args...) \
200 do { \ 213 do { \
201 if (xrun_debug(substream)) { \ 214 if (xrun_debug(substream, 1)) { \
202 if (printk_ratelimit()) { \ 215 if (printk_ratelimit()) { \
203 snd_printd("PCM: " fmt, ##args); \ 216 snd_printd("PCM: " fmt, ##args); \
204 } \ 217 } \
@@ -252,7 +265,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
252 } 265 }
253 266
254 /* Do jiffies check only in xrun_debug mode */ 267 /* Do jiffies check only in xrun_debug mode */
255 if (!xrun_debug(substream)) 268 if (!xrun_debug(substream, 4))
256 goto no_jiffies_check; 269 goto no_jiffies_check;
257 270
258 /* Skip the jiffies check for hardwares with BATCH flag. 271 /* Skip the jiffies check for hardwares with BATCH flag.
@@ -262,6 +275,9 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
262 if (runtime->hw.info & SNDRV_PCM_INFO_BATCH) 275 if (runtime->hw.info & SNDRV_PCM_INFO_BATCH)
263 goto no_jiffies_check; 276 goto no_jiffies_check;
264 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;
265 jdelta = jiffies - runtime->hw_ptr_jiffies; 281 jdelta = jiffies - runtime->hw_ptr_jiffies;
266 if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) { 282 if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) {
267 delta = jdelta / 283 delta = jdelta /
@@ -295,14 +311,20 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
295 hw_ptr_interrupt = 311 hw_ptr_interrupt =
296 new_hw_ptr - new_hw_ptr % runtime->period_size; 312 new_hw_ptr - new_hw_ptr % runtime->period_size;
297 } 313 }
314 runtime->hw_ptr_interrupt = hw_ptr_interrupt;
315
298 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && 316 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
299 runtime->silence_size > 0) 317 runtime->silence_size > 0)
300 snd_pcm_playback_silence(substream, new_hw_ptr); 318 snd_pcm_playback_silence(substream, new_hw_ptr);
301 319
320 if (runtime->status->hw_ptr == new_hw_ptr)
321 return 0;
322
302 runtime->hw_ptr_base = hw_base; 323 runtime->hw_ptr_base = hw_base;
303 runtime->status->hw_ptr = new_hw_ptr; 324 runtime->status->hw_ptr = new_hw_ptr;
304 runtime->hw_ptr_jiffies = jiffies; 325 runtime->hw_ptr_jiffies = jiffies;
305 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);
306 328
307 return snd_pcm_update_hw_ptr_post(substream, runtime); 329 return snd_pcm_update_hw_ptr_post(substream, runtime);
308} 330}
@@ -343,8 +365,12 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
343 new_hw_ptr = hw_base + pos; 365 new_hw_ptr = hw_base + pos;
344 } 366 }
345 /* Do jiffies check only in xrun_debug mode */ 367 /* Do jiffies check only in xrun_debug mode */
346 if (xrun_debug(substream) && 368 if (!xrun_debug(substream, 4))
347 ((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) {
348 hw_ptr_error(substream, 374 hw_ptr_error(substream,
349 "hw_ptr skipping! " 375 "hw_ptr skipping! "
350 "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n", 376 "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n",
@@ -353,13 +379,19 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
353 ((delta * HZ) / runtime->rate)); 379 ((delta * HZ) / runtime->rate));
354 return 0; 380 return 0;
355 } 381 }
382 no_jiffies_check:
356 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && 383 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
357 runtime->silence_size > 0) 384 runtime->silence_size > 0)
358 snd_pcm_playback_silence(substream, new_hw_ptr); 385 snd_pcm_playback_silence(substream, new_hw_ptr);
359 386
387 if (runtime->status->hw_ptr == new_hw_ptr)
388 return 0;
389
360 runtime->hw_ptr_base = hw_base; 390 runtime->hw_ptr_base = hw_base;
361 runtime->status->hw_ptr = new_hw_ptr; 391 runtime->status->hw_ptr = new_hw_ptr;
362 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);
363 395
364 return snd_pcm_update_hw_ptr_post(substream, runtime); 396 return snd_pcm_update_hw_ptr_post(substream, runtime);
365} 397}
@@ -1525,6 +1557,23 @@ static int snd_pcm_lib_ioctl_channel_info(struct snd_pcm_substream *substream,
1525 return 0; 1557 return 0;
1526} 1558}
1527 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
1528/** 1577/**
1529 * snd_pcm_lib_ioctl - a generic PCM ioctl callback 1578 * snd_pcm_lib_ioctl - a generic PCM ioctl callback
1530 * @substream: the pcm substream instance 1579 * @substream: the pcm substream instance
@@ -1546,6 +1595,8 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
1546 return snd_pcm_lib_ioctl_reset(substream, arg); 1595 return snd_pcm_lib_ioctl_reset(substream, arg);
1547 case SNDRV_PCM_IOCTL1_CHANNEL_INFO: 1596 case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
1548 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);
1549 } 1600 }
1550 return -ENXIO; 1601 return -ENXIO;
1551} 1602}
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 45dc53fcfa2f..84da3ba17c86 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -312,9 +312,18 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
312 312
313 hw = &substream->runtime->hw; 313 hw = &substream->runtime->hw;
314 if (!params->info) 314 if (!params->info)
315 params->info = hw->info; 315 params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES;
316 if (!params->fifo_size) 316 if (!params->fifo_size) {
317 params->fifo_size = hw->fifo_size; 317 if (snd_mask_min(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT]) ==
318 snd_mask_max(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT]) &&
319 snd_mask_min(&params->masks[SNDRV_PCM_HW_PARAM_CHANNELS]) ==
320 snd_mask_max(&params->masks[SNDRV_PCM_HW_PARAM_CHANNELS])) {
321 changed = substream->ops->ioctl(substream,
322 SNDRV_PCM_IOCTL1_FIFO_SIZE, params);
323 if (params < 0)
324 return changed;
325 }
326 }
318 params->rmask = 0; 327 params->rmask = 0;
319 return 0; 328 return 0;
320} 329}