aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2010-01-12 03:40:08 -0500
committerTakashi Iwai <tiwai@suse.de>2010-01-12 03:40:08 -0500
commita29fb94ff48cba620e1ac1317f5eef5920ead3ff (patch)
tree2fb8e026712bdf7848ea400e25118f6a58824a02 /sound/core
parent52a7a5835173af61b9f6c3038212370d9717526f (diff)
parentdd3533eca859a6debb1565503ec03e68354e08e0 (diff)
Merge commit alsa/devel into topic/misc
Conflicts: include/sound/version.h
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/oss/pcm_oss.c32
-rw-r--r--sound/core/pcm.c4
-rw-r--r--sound/core/pcm_lib.c418
-rw-r--r--sound/core/pcm_native.c8
4 files changed, 253 insertions, 209 deletions
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index d9c96353121a..255ad910077a 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -632,6 +632,13 @@ static long snd_pcm_alsa_frames(struct snd_pcm_substream *substream, long bytes)
632 return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes); 632 return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes);
633} 633}
634 634
635static inline
636snd_pcm_uframes_t get_hw_ptr_period(struct snd_pcm_runtime *runtime)
637{
638 snd_pcm_uframes_t ptr = runtime->status->hw_ptr;
639 return ptr - (ptr % runtime->period_size);
640}
641
635/* define extended formats in the recent OSS versions (if any) */ 642/* define extended formats in the recent OSS versions (if any) */
636/* linear formats */ 643/* linear formats */
637#define AFMT_S32_LE 0x00001000 644#define AFMT_S32_LE 0x00001000
@@ -1102,7 +1109,7 @@ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
1102 return err; 1109 return err;
1103 } 1110 }
1104 runtime->oss.prepare = 0; 1111 runtime->oss.prepare = 0;
1105 runtime->oss.prev_hw_ptr_interrupt = 0; 1112 runtime->oss.prev_hw_ptr_period = 0;
1106 runtime->oss.period_ptr = 0; 1113 runtime->oss.period_ptr = 0;
1107 runtime->oss.buffer_used = 0; 1114 runtime->oss.buffer_used = 0;
1108 1115
@@ -1950,7 +1957,8 @@ static int snd_pcm_oss_get_caps(struct snd_pcm_oss_file *pcm_oss_file)
1950 return result; 1957 return result;
1951} 1958}
1952 1959
1953static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream, snd_pcm_uframes_t hw_ptr) 1960static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream,
1961 snd_pcm_uframes_t hw_ptr)
1954{ 1962{
1955 struct snd_pcm_runtime *runtime = substream->runtime; 1963 struct snd_pcm_runtime *runtime = substream->runtime;
1956 snd_pcm_uframes_t appl_ptr; 1964 snd_pcm_uframes_t appl_ptr;
@@ -1986,7 +1994,8 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
1986 if (runtime->oss.trigger) 1994 if (runtime->oss.trigger)
1987 goto _skip1; 1995 goto _skip1;
1988 if (atomic_read(&psubstream->mmap_count)) 1996 if (atomic_read(&psubstream->mmap_count))
1989 snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt); 1997 snd_pcm_oss_simulate_fill(psubstream,
1998 get_hw_ptr_period(runtime));
1990 runtime->oss.trigger = 1; 1999 runtime->oss.trigger = 1;
1991 runtime->start_threshold = 1; 2000 runtime->start_threshold = 1;
1992 cmd = SNDRV_PCM_IOCTL_START; 2001 cmd = SNDRV_PCM_IOCTL_START;
@@ -2105,11 +2114,12 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream
2105 info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size); 2114 info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size);
2106 if (atomic_read(&substream->mmap_count)) { 2115 if (atomic_read(&substream->mmap_count)) {
2107 snd_pcm_sframes_t n; 2116 snd_pcm_sframes_t n;
2108 n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt; 2117 delay = get_hw_ptr_period(runtime);
2118 n = delay - runtime->oss.prev_hw_ptr_period;
2109 if (n < 0) 2119 if (n < 0)
2110 n += runtime->boundary; 2120 n += runtime->boundary;
2111 info.blocks = n / runtime->period_size; 2121 info.blocks = n / runtime->period_size;
2112 runtime->oss.prev_hw_ptr_interrupt = delay; 2122 runtime->oss.prev_hw_ptr_period = delay;
2113 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 2123 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
2114 snd_pcm_oss_simulate_fill(substream, delay); 2124 snd_pcm_oss_simulate_fill(substream, delay);
2115 info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX; 2125 info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX;
@@ -2673,18 +2683,22 @@ static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream)
2673{ 2683{
2674 struct snd_pcm_runtime *runtime = substream->runtime; 2684 struct snd_pcm_runtime *runtime = substream->runtime;
2675 if (atomic_read(&substream->mmap_count)) 2685 if (atomic_read(&substream->mmap_count))
2676 return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; 2686 return runtime->oss.prev_hw_ptr_period !=
2687 get_hw_ptr_period(runtime);
2677 else 2688 else
2678 return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames; 2689 return snd_pcm_playback_avail(runtime) >=
2690 runtime->oss.period_frames;
2679} 2691}
2680 2692
2681static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream) 2693static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream)
2682{ 2694{
2683 struct snd_pcm_runtime *runtime = substream->runtime; 2695 struct snd_pcm_runtime *runtime = substream->runtime;
2684 if (atomic_read(&substream->mmap_count)) 2696 if (atomic_read(&substream->mmap_count))
2685 return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; 2697 return runtime->oss.prev_hw_ptr_period !=
2698 get_hw_ptr_period(runtime);
2686 else 2699 else
2687 return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames; 2700 return snd_pcm_capture_avail(runtime) >=
2701 runtime->oss.period_frames;
2688} 2702}
2689 2703
2690static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait) 2704static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait)
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 6884ae031f6f..df57a0e30bf2 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -921,6 +921,10 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
921 snd_free_pages((void*)runtime->control, 921 snd_free_pages((void*)runtime->control,
922 PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))); 922 PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
923 kfree(runtime->hw_constraints.rules); 923 kfree(runtime->hw_constraints.rules);
924#ifdef CONFIG_SND_PCM_XRUN_DEBUG
925 if (runtime->hwptr_log)
926 kfree(runtime->hwptr_log);
927#endif
924 kfree(runtime); 928 kfree(runtime);
925 substream->runtime = NULL; 929 substream->runtime = NULL;
926 put_pid(substream->pid); 930 put_pid(substream->pid);
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index b07cc361afb1..0403a7d55f0c 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -126,17 +126,6 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
126 } 126 }
127} 127}
128 128
129#ifdef CONFIG_SND_PCM_XRUN_DEBUG
130#define xrun_debug(substream, mask) ((substream)->pstr->xrun_debug & (mask))
131#else
132#define xrun_debug(substream, mask) 0
133#endif
134
135#define dump_stack_on_xrun(substream) do { \
136 if (xrun_debug(substream, 2)) \
137 dump_stack(); \
138 } while (0)
139
140static void pcm_debug_name(struct snd_pcm_substream *substream, 129static void pcm_debug_name(struct snd_pcm_substream *substream,
141 char *name, size_t len) 130 char *name, size_t len)
142{ 131{
@@ -147,6 +136,24 @@ static void pcm_debug_name(struct snd_pcm_substream *substream,
147 substream->number); 136 substream->number);
148} 137}
149 138
139#define XRUN_DEBUG_BASIC (1<<0)
140#define XRUN_DEBUG_STACK (1<<1) /* dump also stack */
141#define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */
142#define XRUN_DEBUG_PERIODUPDATE (1<<3) /* full period update info */
143#define XRUN_DEBUG_HWPTRUPDATE (1<<4) /* full hwptr update info */
144#define XRUN_DEBUG_LOG (1<<5) /* show last 10 positions on err */
145#define XRUN_DEBUG_LOGONCE (1<<6) /* do above only once */
146
147#ifdef CONFIG_SND_PCM_XRUN_DEBUG
148
149#define xrun_debug(substream, mask) \
150 ((substream)->pstr->xrun_debug & (mask))
151
152#define dump_stack_on_xrun(substream) do { \
153 if (xrun_debug(substream, XRUN_DEBUG_STACK)) \
154 dump_stack(); \
155 } while (0)
156
150static void xrun(struct snd_pcm_substream *substream) 157static void xrun(struct snd_pcm_substream *substream)
151{ 158{
152 struct snd_pcm_runtime *runtime = substream->runtime; 159 struct snd_pcm_runtime *runtime = substream->runtime;
@@ -154,7 +161,7 @@ static void xrun(struct snd_pcm_substream *substream)
154 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) 161 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
155 snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); 162 snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
156 snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); 163 snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
157 if (xrun_debug(substream, 1)) { 164 if (xrun_debug(substream, XRUN_DEBUG_BASIC)) {
158 char name[16]; 165 char name[16];
159 pcm_debug_name(substream, name, sizeof(name)); 166 pcm_debug_name(substream, name, sizeof(name));
160 snd_printd(KERN_DEBUG "XRUN: %s\n", name); 167 snd_printd(KERN_DEBUG "XRUN: %s\n", name);
@@ -162,32 +169,102 @@ static void xrun(struct snd_pcm_substream *substream)
162 } 169 }
163} 170}
164 171
165static snd_pcm_uframes_t 172#define hw_ptr_error(substream, fmt, args...) \
166snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream, 173 do { \
167 struct snd_pcm_runtime *runtime) 174 if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \
168{ 175 xrun_log_show(substream); \
176 if (printk_ratelimit()) { \
177 snd_printd("PCM: " fmt, ##args); \
178 } \
179 dump_stack_on_xrun(substream); \
180 } \
181 } while (0)
182
183#define XRUN_LOG_CNT 10
184
185struct hwptr_log_entry {
186 unsigned long jiffies;
169 snd_pcm_uframes_t pos; 187 snd_pcm_uframes_t pos;
188 snd_pcm_uframes_t period_size;
189 snd_pcm_uframes_t buffer_size;
190 snd_pcm_uframes_t old_hw_ptr;
191 snd_pcm_uframes_t hw_ptr_base;
192};
170 193
171 pos = substream->ops->pointer(substream); 194struct snd_pcm_hwptr_log {
172 if (pos == SNDRV_PCM_POS_XRUN) 195 unsigned int idx;
173 return pos; /* XRUN */ 196 unsigned int hit: 1;
174 if (pos >= runtime->buffer_size) { 197 struct hwptr_log_entry entries[XRUN_LOG_CNT];
175 if (printk_ratelimit()) { 198};
176 char name[16]; 199
177 pcm_debug_name(substream, name, sizeof(name)); 200static void xrun_log(struct snd_pcm_substream *substream,
178 snd_printd(KERN_ERR "BUG: %s, pos = 0x%lx, " 201 snd_pcm_uframes_t pos)
179 "buffer size = 0x%lx, period size = 0x%lx\n", 202{
180 name, pos, runtime->buffer_size, 203 struct snd_pcm_runtime *runtime = substream->runtime;
181 runtime->period_size); 204 struct snd_pcm_hwptr_log *log = runtime->hwptr_log;
182 } 205 struct hwptr_log_entry *entry;
183 pos = 0; 206
207 if (log == NULL) {
208 log = kzalloc(sizeof(*log), GFP_ATOMIC);
209 if (log == NULL)
210 return;
211 runtime->hwptr_log = log;
212 } else {
213 if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit)
214 return;
184 } 215 }
185 pos -= pos % runtime->min_align; 216 entry = &log->entries[log->idx];
186 return pos; 217 entry->jiffies = jiffies;
218 entry->pos = pos;
219 entry->period_size = runtime->period_size;
220 entry->buffer_size = runtime->buffer_size;;
221 entry->old_hw_ptr = runtime->status->hw_ptr;
222 entry->hw_ptr_base = runtime->hw_ptr_base;
223 log->idx = (log->idx + 1) % XRUN_LOG_CNT;
187} 224}
188 225
189static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, 226static void xrun_log_show(struct snd_pcm_substream *substream)
190 struct snd_pcm_runtime *runtime) 227{
228 struct snd_pcm_hwptr_log *log = substream->runtime->hwptr_log;
229 struct hwptr_log_entry *entry;
230 char name[16];
231 unsigned int idx;
232 int cnt;
233
234 if (log == NULL)
235 return;
236 if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit)
237 return;
238 pcm_debug_name(substream, name, sizeof(name));
239 for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) {
240 entry = &log->entries[idx];
241 if (entry->period_size == 0)
242 break;
243 snd_printd("hwptr log: %s: j=%lu, pos=%ld/%ld/%ld, "
244 "hwptr=%ld/%ld\n",
245 name, entry->jiffies, (unsigned long)entry->pos,
246 (unsigned long)entry->period_size,
247 (unsigned long)entry->buffer_size,
248 (unsigned long)entry->old_hw_ptr,
249 (unsigned long)entry->hw_ptr_base);
250 idx++;
251 idx %= XRUN_LOG_CNT;
252 }
253 log->hit = 1;
254}
255
256#else /* ! CONFIG_SND_PCM_XRUN_DEBUG */
257
258#define xrun_debug(substream, mask) 0
259#define xrun(substream) do { } while (0)
260#define hw_ptr_error(substream, fmt, args...) do { } while (0)
261#define xrun_log(substream, pos) do { } while (0)
262#define xrun_log_show(substream) do { } while (0)
263
264#endif
265
266int snd_pcm_update_state(struct snd_pcm_substream *substream,
267 struct snd_pcm_runtime *runtime)
191{ 268{
192 snd_pcm_uframes_t avail; 269 snd_pcm_uframes_t avail;
193 270
@@ -208,89 +285,96 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
208 return -EPIPE; 285 return -EPIPE;
209 } 286 }
210 } 287 }
211 if (avail >= runtime->control->avail_min) 288 if (!runtime->nowake && avail >= runtime->control->avail_min)
212 wake_up(&runtime->sleep); 289 wake_up(&runtime->sleep);
213 return 0; 290 return 0;
214} 291}
215 292
216#define hw_ptr_error(substream, fmt, args...) \ 293static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
217 do { \ 294 unsigned int in_interrupt)
218 if (xrun_debug(substream, 1)) { \
219 if (printk_ratelimit()) { \
220 snd_printd("PCM: " fmt, ##args); \
221 } \
222 dump_stack_on_xrun(substream); \
223 } \
224 } while (0)
225
226static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
227{ 295{
228 struct snd_pcm_runtime *runtime = substream->runtime; 296 struct snd_pcm_runtime *runtime = substream->runtime;
229 snd_pcm_uframes_t pos; 297 snd_pcm_uframes_t pos;
230 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_ptr_interrupt, hw_base; 298 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
231 snd_pcm_sframes_t hdelta, delta; 299 snd_pcm_sframes_t hdelta, delta;
232 unsigned long jdelta; 300 unsigned long jdelta;
233 301
234 old_hw_ptr = runtime->status->hw_ptr; 302 old_hw_ptr = runtime->status->hw_ptr;
235 pos = snd_pcm_update_hw_ptr_pos(substream, runtime); 303 pos = substream->ops->pointer(substream);
236 if (pos == SNDRV_PCM_POS_XRUN) { 304 if (pos == SNDRV_PCM_POS_XRUN) {
237 xrun(substream); 305 xrun(substream);
238 return -EPIPE; 306 return -EPIPE;
239 } 307 }
240 if (xrun_debug(substream, 8)) { 308 if (pos >= runtime->buffer_size) {
241 char name[16]; 309 if (printk_ratelimit()) {
242 pcm_debug_name(substream, name, sizeof(name)); 310 char name[16];
243 snd_printd("period_update: %s: pos=0x%x/0x%x/0x%x, " 311 pcm_debug_name(substream, name, sizeof(name));
244 "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n", 312 xrun_log_show(substream);
245 name, (unsigned int)pos, 313 snd_printd(KERN_ERR "BUG: %s, pos = %ld, "
246 (unsigned int)runtime->period_size, 314 "buffer size = %ld, period size = %ld\n",
247 (unsigned int)runtime->buffer_size, 315 name, pos, runtime->buffer_size,
248 (unsigned long)old_hw_ptr, 316 runtime->period_size);
249 (unsigned long)runtime->hw_ptr_base, 317 }
250 (unsigned long)runtime->hw_ptr_interrupt); 318 pos = 0;
251 } 319 }
320 pos -= pos % runtime->min_align;
321 if (xrun_debug(substream, XRUN_DEBUG_LOG))
322 xrun_log(substream, pos);
252 hw_base = runtime->hw_ptr_base; 323 hw_base = runtime->hw_ptr_base;
253 new_hw_ptr = hw_base + pos; 324 new_hw_ptr = hw_base + pos;
254 hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size; 325 if (in_interrupt) {
255 delta = new_hw_ptr - hw_ptr_interrupt; 326 /* we know that one period was processed */
256 if (hw_ptr_interrupt >= runtime->boundary) { 327 /* delta = "expected next hw_ptr" for in_interrupt != 0 */
257 hw_ptr_interrupt -= runtime->boundary; 328 delta = old_hw_ptr - (old_hw_ptr % runtime->period_size)
258 if (hw_base < runtime->boundary / 2) 329 + runtime->period_size;
259 /* hw_base was already lapped; recalc delta */ 330 if (delta > new_hw_ptr) {
260 delta = new_hw_ptr - hw_ptr_interrupt;
261 }
262 if (delta < 0) {
263 if (runtime->periods == 1 || new_hw_ptr < old_hw_ptr)
264 delta += runtime->buffer_size;
265 if (delta < 0) {
266 hw_ptr_error(substream,
267 "Unexpected hw_pointer value "
268 "(stream=%i, pos=%ld, intr_ptr=%ld)\n",
269 substream->stream, (long)pos,
270 (long)hw_ptr_interrupt);
271#if 1
272 /* simply skipping the hwptr update seems more
273 * robust in some cases, e.g. on VMware with
274 * inaccurate timer source
275 */
276 return 0; /* skip this update */
277#else
278 /* rebase to interrupt position */
279 hw_base = new_hw_ptr = hw_ptr_interrupt;
280 /* align hw_base to buffer_size */
281 hw_base -= hw_base % runtime->buffer_size;
282 delta = 0;
283#endif
284 } else {
285 hw_base += runtime->buffer_size; 331 hw_base += runtime->buffer_size;
286 if (hw_base >= runtime->boundary) 332 if (hw_base >= runtime->boundary)
287 hw_base = 0; 333 hw_base = 0;
288 new_hw_ptr = hw_base + pos; 334 new_hw_ptr = hw_base + pos;
335 goto __delta;
289 } 336 }
290 } 337 }
338 /* new_hw_ptr might be lower than old_hw_ptr in case when */
339 /* pointer crosses the end of the ring buffer */
340 if (new_hw_ptr < old_hw_ptr) {
341 hw_base += runtime->buffer_size;
342 if (hw_base >= runtime->boundary)
343 hw_base = 0;
344 new_hw_ptr = hw_base + pos;
345 }
346 __delta:
347 delta = (new_hw_ptr - old_hw_ptr) % runtime->boundary;
348 if (xrun_debug(substream, in_interrupt ?
349 XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) {
350 char name[16];
351 pcm_debug_name(substream, name, sizeof(name));
352 snd_printd("%s_update: %s: pos=%u/%u/%u, "
353 "hwptr=%ld/%ld/%ld/%ld\n",
354 in_interrupt ? "period" : "hwptr",
355 name,
356 (unsigned int)pos,
357 (unsigned int)runtime->period_size,
358 (unsigned int)runtime->buffer_size,
359 (unsigned long)delta,
360 (unsigned long)old_hw_ptr,
361 (unsigned long)new_hw_ptr,
362 (unsigned long)runtime->hw_ptr_base);
363 }
364 /* something must be really wrong */
365 if (delta >= runtime->buffer_size + runtime->period_size) {
366 hw_ptr_error(substream,
367 "Unexpected hw_pointer value %s"
368 "(stream=%i, pos=%ld, new_hw_ptr=%ld, "
369 "old_hw_ptr=%ld)\n",
370 in_interrupt ? "[Q] " : "[P]",
371 substream->stream, (long)pos,
372 (long)new_hw_ptr, (long)old_hw_ptr);
373 return 0;
374 }
291 375
292 /* Do jiffies check only in xrun_debug mode */ 376 /* Do jiffies check only in xrun_debug mode */
293 if (!xrun_debug(substream, 4)) 377 if (!xrun_debug(substream, XRUN_DEBUG_JIFFIESCHECK))
294 goto no_jiffies_check; 378 goto no_jiffies_check;
295 379
296 /* Skip the jiffies check for hardwares with BATCH flag. 380 /* Skip the jiffies check for hardwares with BATCH flag.
@@ -299,7 +383,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
299 */ 383 */
300 if (runtime->hw.info & SNDRV_PCM_INFO_BATCH) 384 if (runtime->hw.info & SNDRV_PCM_INFO_BATCH)
301 goto no_jiffies_check; 385 goto no_jiffies_check;
302 hdelta = new_hw_ptr - old_hw_ptr; 386 hdelta = delta;
303 if (hdelta < runtime->delay) 387 if (hdelta < runtime->delay)
304 goto no_jiffies_check; 388 goto no_jiffies_check;
305 hdelta -= runtime->delay; 389 hdelta -= runtime->delay;
@@ -308,130 +392,62 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
308 delta = jdelta / 392 delta = jdelta /
309 (((runtime->period_size * HZ) / runtime->rate) 393 (((runtime->period_size * HZ) / runtime->rate)
310 + HZ/100); 394 + HZ/100);
395 /* move new_hw_ptr according jiffies not pos variable */
396 new_hw_ptr = old_hw_ptr;
397 /* use loop to avoid checks for delta overflows */
398 /* the delta value is small or zero in most cases */
399 while (delta > 0) {
400 new_hw_ptr += runtime->period_size;
401 if (new_hw_ptr >= runtime->boundary)
402 new_hw_ptr -= runtime->boundary;
403 delta--;
404 }
405 /* align hw_base to buffer_size */
406 hw_base = new_hw_ptr - (new_hw_ptr % runtime->buffer_size);
407 delta = 0;
311 hw_ptr_error(substream, 408 hw_ptr_error(substream,
312 "hw_ptr skipping! [Q] " 409 "hw_ptr skipping! %s"
313 "(pos=%ld, delta=%ld, period=%ld, " 410 "(pos=%ld, delta=%ld, period=%ld, "
314 "jdelta=%lu/%lu/%lu)\n", 411 "jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n",
412 in_interrupt ? "[Q] " : "",
315 (long)pos, (long)hdelta, 413 (long)pos, (long)hdelta,
316 (long)runtime->period_size, jdelta, 414 (long)runtime->period_size, jdelta,
317 ((hdelta * HZ) / runtime->rate), delta); 415 ((hdelta * HZ) / runtime->rate), delta,
318 hw_ptr_interrupt = runtime->hw_ptr_interrupt + 416 (unsigned long)old_hw_ptr,
319 runtime->period_size * delta; 417 (unsigned long)new_hw_ptr);
320 if (hw_ptr_interrupt >= runtime->boundary)
321 hw_ptr_interrupt -= runtime->boundary;
322 /* rebase to interrupt position */
323 hw_base = new_hw_ptr = hw_ptr_interrupt;
324 /* align hw_base to buffer_size */
325 hw_base -= hw_base % runtime->buffer_size;
326 delta = 0;
327 } 418 }
328 no_jiffies_check: 419 no_jiffies_check:
329 if (delta > runtime->period_size + runtime->period_size / 2) { 420 if (delta > runtime->period_size + runtime->period_size / 2) {
330 hw_ptr_error(substream, 421 hw_ptr_error(substream,
331 "Lost interrupts? " 422 "Lost interrupts? %s"
332 "(stream=%i, delta=%ld, intr_ptr=%ld)\n", 423 "(stream=%i, delta=%ld, new_hw_ptr=%ld, "
424 "old_hw_ptr=%ld)\n",
425 in_interrupt ? "[Q] " : "",
333 substream->stream, (long)delta, 426 substream->stream, (long)delta,
334 (long)hw_ptr_interrupt); 427 (long)new_hw_ptr,
335 /* rebase hw_ptr_interrupt */ 428 (long)old_hw_ptr);
336 hw_ptr_interrupt =
337 new_hw_ptr - new_hw_ptr % runtime->period_size;
338 } 429 }
339 runtime->hw_ptr_interrupt = hw_ptr_interrupt; 430
431 if (runtime->status->hw_ptr == new_hw_ptr)
432 return 0;
340 433
341 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && 434 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
342 runtime->silence_size > 0) 435 runtime->silence_size > 0)
343 snd_pcm_playback_silence(substream, new_hw_ptr); 436 snd_pcm_playback_silence(substream, new_hw_ptr);
344 437
345 if (runtime->status->hw_ptr == new_hw_ptr)
346 return 0;
347
348 runtime->hw_ptr_base = hw_base; 438 runtime->hw_ptr_base = hw_base;
349 runtime->status->hw_ptr = new_hw_ptr; 439 runtime->status->hw_ptr = new_hw_ptr;
350 runtime->hw_ptr_jiffies = jiffies; 440 runtime->hw_ptr_jiffies = jiffies;
351 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) 441 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
352 snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); 442 snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
353 443
354 return snd_pcm_update_hw_ptr_post(substream, runtime); 444 return snd_pcm_update_state(substream, runtime);
355} 445}
356 446
357/* CAUTION: call it with irq disabled */ 447/* CAUTION: call it with irq disabled */
358int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) 448int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
359{ 449{
360 struct snd_pcm_runtime *runtime = substream->runtime; 450 return snd_pcm_update_hw_ptr0(substream, 0);
361 snd_pcm_uframes_t pos;
362 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
363 snd_pcm_sframes_t delta;
364 unsigned long jdelta;
365
366 old_hw_ptr = runtime->status->hw_ptr;
367 pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
368 if (pos == SNDRV_PCM_POS_XRUN) {
369 xrun(substream);
370 return -EPIPE;
371 }
372 if (xrun_debug(substream, 16)) {
373 char name[16];
374 pcm_debug_name(substream, name, sizeof(name));
375 snd_printd("hw_update: %s: pos=0x%x/0x%x/0x%x, "
376 "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n",
377 name, (unsigned int)pos,
378 (unsigned int)runtime->period_size,
379 (unsigned int)runtime->buffer_size,
380 (unsigned long)old_hw_ptr,
381 (unsigned long)runtime->hw_ptr_base,
382 (unsigned long)runtime->hw_ptr_interrupt);
383 }
384
385 hw_base = runtime->hw_ptr_base;
386 new_hw_ptr = hw_base + pos;
387
388 delta = new_hw_ptr - old_hw_ptr;
389 jdelta = jiffies - runtime->hw_ptr_jiffies;
390 if (delta < 0) {
391 delta += runtime->buffer_size;
392 if (delta < 0) {
393 hw_ptr_error(substream,
394 "Unexpected hw_pointer value [2] "
395 "(stream=%i, pos=%ld, old_ptr=%ld, jdelta=%li)\n",
396 substream->stream, (long)pos,
397 (long)old_hw_ptr, jdelta);
398 return 0;
399 }
400 hw_base += runtime->buffer_size;
401 if (hw_base >= runtime->boundary)
402 hw_base = 0;
403 new_hw_ptr = hw_base + pos;
404 }
405 /* Do jiffies check only in xrun_debug mode */
406 if (!xrun_debug(substream, 4))
407 goto no_jiffies_check;
408 if (delta < runtime->delay)
409 goto no_jiffies_check;
410 delta -= runtime->delay;
411 if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) {
412 hw_ptr_error(substream,
413 "hw_ptr skipping! "
414 "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n",
415 (long)pos, (long)delta,
416 (long)runtime->period_size, jdelta,
417 ((delta * HZ) / runtime->rate));
418 return 0;
419 }
420 no_jiffies_check:
421 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
422 runtime->silence_size > 0)
423 snd_pcm_playback_silence(substream, new_hw_ptr);
424
425 if (runtime->status->hw_ptr == new_hw_ptr)
426 return 0;
427
428 runtime->hw_ptr_base = hw_base;
429 runtime->status->hw_ptr = new_hw_ptr;
430 runtime->hw_ptr_jiffies = jiffies;
431 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
432 snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
433
434 return snd_pcm_update_hw_ptr_post(substream, runtime);
435} 451}
436 452
437/** 453/**
@@ -1657,7 +1673,7 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
1657 1673
1658 snd_pcm_stream_lock_irqsave(substream, flags); 1674 snd_pcm_stream_lock_irqsave(substream, flags);
1659 if (!snd_pcm_running(substream) || 1675 if (!snd_pcm_running(substream) ||
1660 snd_pcm_update_hw_ptr_interrupt(substream) < 0) 1676 snd_pcm_update_hw_ptr0(substream, 1) < 0)
1661 goto _end; 1677 goto _end;
1662 1678
1663 if (substream->timer_running) 1679 if (substream->timer_running)
@@ -1790,6 +1806,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
1790 goto _end_unlock; 1806 goto _end_unlock;
1791 } 1807 }
1792 1808
1809 runtime->nowake = 1;
1793 while (size > 0) { 1810 while (size > 0) {
1794 snd_pcm_uframes_t frames, appl_ptr, appl_ofs; 1811 snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
1795 snd_pcm_uframes_t avail; 1812 snd_pcm_uframes_t avail;
@@ -1811,15 +1828,17 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
1811 if (frames > cont) 1828 if (frames > cont)
1812 frames = cont; 1829 frames = cont;
1813 if (snd_BUG_ON(!frames)) { 1830 if (snd_BUG_ON(!frames)) {
1831 runtime->nowake = 0;
1814 snd_pcm_stream_unlock_irq(substream); 1832 snd_pcm_stream_unlock_irq(substream);
1815 return -EINVAL; 1833 return -EINVAL;
1816 } 1834 }
1817 appl_ptr = runtime->control->appl_ptr; 1835 appl_ptr = runtime->control->appl_ptr;
1818 appl_ofs = appl_ptr % runtime->buffer_size; 1836 appl_ofs = appl_ptr % runtime->buffer_size;
1819 snd_pcm_stream_unlock_irq(substream); 1837 snd_pcm_stream_unlock_irq(substream);
1820 if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0) 1838 err = transfer(substream, appl_ofs, data, offset, frames);
1821 goto _end;
1822 snd_pcm_stream_lock_irq(substream); 1839 snd_pcm_stream_lock_irq(substream);
1840 if (err < 0)
1841 goto _end_unlock;
1823 switch (runtime->status->state) { 1842 switch (runtime->status->state) {
1824 case SNDRV_PCM_STATE_XRUN: 1843 case SNDRV_PCM_STATE_XRUN:
1825 err = -EPIPE; 1844 err = -EPIPE;
@@ -1848,8 +1867,10 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
1848 } 1867 }
1849 } 1868 }
1850 _end_unlock: 1869 _end_unlock:
1870 runtime->nowake = 0;
1871 if (xfer > 0 && err >= 0)
1872 snd_pcm_update_state(substream, runtime);
1851 snd_pcm_stream_unlock_irq(substream); 1873 snd_pcm_stream_unlock_irq(substream);
1852 _end:
1853 return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; 1874 return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
1854} 1875}
1855 1876
@@ -2007,6 +2028,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
2007 goto _end_unlock; 2028 goto _end_unlock;
2008 } 2029 }
2009 2030
2031 runtime->nowake = 1;
2010 while (size > 0) { 2032 while (size > 0) {
2011 snd_pcm_uframes_t frames, appl_ptr, appl_ofs; 2033 snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
2012 snd_pcm_uframes_t avail; 2034 snd_pcm_uframes_t avail;
@@ -2035,15 +2057,17 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
2035 if (frames > cont) 2057 if (frames > cont)
2036 frames = cont; 2058 frames = cont;
2037 if (snd_BUG_ON(!frames)) { 2059 if (snd_BUG_ON(!frames)) {
2060 runtime->nowake = 0;
2038 snd_pcm_stream_unlock_irq(substream); 2061 snd_pcm_stream_unlock_irq(substream);
2039 return -EINVAL; 2062 return -EINVAL;
2040 } 2063 }
2041 appl_ptr = runtime->control->appl_ptr; 2064 appl_ptr = runtime->control->appl_ptr;
2042 appl_ofs = appl_ptr % runtime->buffer_size; 2065 appl_ofs = appl_ptr % runtime->buffer_size;
2043 snd_pcm_stream_unlock_irq(substream); 2066 snd_pcm_stream_unlock_irq(substream);
2044 if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0) 2067 err = transfer(substream, appl_ofs, data, offset, frames);
2045 goto _end;
2046 snd_pcm_stream_lock_irq(substream); 2068 snd_pcm_stream_lock_irq(substream);
2069 if (err < 0)
2070 goto _end_unlock;
2047 switch (runtime->status->state) { 2071 switch (runtime->status->state) {
2048 case SNDRV_PCM_STATE_XRUN: 2072 case SNDRV_PCM_STATE_XRUN:
2049 err = -EPIPE; 2073 err = -EPIPE;
@@ -2066,8 +2090,10 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
2066 xfer += frames; 2090 xfer += frames;
2067 } 2091 }
2068 _end_unlock: 2092 _end_unlock:
2093 runtime->nowake = 0;
2094 if (xfer > 0 && err >= 0)
2095 snd_pcm_update_state(substream, runtime);
2069 snd_pcm_stream_unlock_irq(substream); 2096 snd_pcm_stream_unlock_irq(substream);
2070 _end:
2071 return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; 2097 return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
2072} 2098}
2073 2099
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 25b0641e6b8c..a870fe696578 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -516,6 +516,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
516 struct snd_pcm_sw_params *params) 516 struct snd_pcm_sw_params *params)
517{ 517{
518 struct snd_pcm_runtime *runtime; 518 struct snd_pcm_runtime *runtime;
519 int err;
519 520
520 if (PCM_RUNTIME_CHECK(substream)) 521 if (PCM_RUNTIME_CHECK(substream))
521 return -ENXIO; 522 return -ENXIO;
@@ -540,6 +541,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
540 if (params->silence_threshold > runtime->buffer_size) 541 if (params->silence_threshold > runtime->buffer_size)
541 return -EINVAL; 542 return -EINVAL;
542 } 543 }
544 err = 0;
543 snd_pcm_stream_lock_irq(substream); 545 snd_pcm_stream_lock_irq(substream);
544 runtime->tstamp_mode = params->tstamp_mode; 546 runtime->tstamp_mode = params->tstamp_mode;
545 runtime->period_step = params->period_step; 547 runtime->period_step = params->period_step;
@@ -553,10 +555,10 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
553 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && 555 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
554 runtime->silence_size > 0) 556 runtime->silence_size > 0)
555 snd_pcm_playback_silence(substream, ULONG_MAX); 557 snd_pcm_playback_silence(substream, ULONG_MAX);
556 wake_up(&runtime->sleep); 558 err = snd_pcm_update_state(substream, runtime);
557 } 559 }
558 snd_pcm_stream_unlock_irq(substream); 560 snd_pcm_stream_unlock_irq(substream);
559 return 0; 561 return err;
560} 562}
561 563
562static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream, 564static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream,
@@ -1247,8 +1249,6 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state)
1247 if (err < 0) 1249 if (err < 0)
1248 return err; 1250 return err;
1249 runtime->hw_ptr_base = 0; 1251 runtime->hw_ptr_base = 0;
1250 runtime->hw_ptr_interrupt = runtime->status->hw_ptr -
1251 runtime->status->hw_ptr % runtime->period_size;
1252 runtime->silence_start = runtime->status->hw_ptr; 1252 runtime->silence_start = runtime->status->hw_ptr;
1253 runtime->silence_filled = 0; 1253 runtime->silence_filled = 0;
1254 return 0; 1254 return 0;