diff options
author | Takashi Iwai <tiwai@suse.de> | 2010-01-12 03:40:08 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-01-12 03:40:08 -0500 |
commit | a29fb94ff48cba620e1ac1317f5eef5920ead3ff (patch) | |
tree | 2fb8e026712bdf7848ea400e25118f6a58824a02 /sound/core | |
parent | 52a7a5835173af61b9f6c3038212370d9717526f (diff) | |
parent | dd3533eca859a6debb1565503ec03e68354e08e0 (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.c | 32 | ||||
-rw-r--r-- | sound/core/pcm.c | 4 | ||||
-rw-r--r-- | sound/core/pcm_lib.c | 418 | ||||
-rw-r--r-- | sound/core/pcm_native.c | 8 |
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 | ||
635 | static inline | ||
636 | snd_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 | ||
1953 | static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream, snd_pcm_uframes_t hw_ptr) | 1960 | static 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 | ||
2681 | static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream) | 2693 | static 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 | ||
2690 | static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait) | 2704 | static 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 | |||
140 | static void pcm_debug_name(struct snd_pcm_substream *substream, | 129 | static 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 | |||
150 | static void xrun(struct snd_pcm_substream *substream) | 157 | static 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 | ||
165 | static snd_pcm_uframes_t | 172 | #define hw_ptr_error(substream, fmt, args...) \ |
166 | snd_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 | |||
185 | struct 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); | 194 | struct 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)); | 200 | static 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 | ||
189 | static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, | 226 | static 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 | |||
266 | int 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...) \ | 293 | static 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 | |||
226 | static 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 */ |
358 | int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) | 448 | int 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 | ||
562 | static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream, | 564 | static 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; |