diff --git a/[refs] b/[refs] index 3f70b753bd67..f60fa8b8e232 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: cd9d95a55550555da8e587ead9cbba5f98a371a3 +refs/heads/master: 709350506567029021b8a38ee7e65bc246fceabc diff --git a/trunk/include/sound/pcm.h b/trunk/include/sound/pcm.h index e26fb3c58037..c83a4a79f16b 100644 --- a/trunk/include/sound/pcm.h +++ b/trunk/include/sound/pcm.h @@ -262,8 +262,6 @@ struct snd_pcm_hw_constraint_list { unsigned int mask; }; -struct snd_pcm_hwptr_log; - struct snd_pcm_runtime { /* -- Status -- */ struct snd_pcm_substream *trigger_master; @@ -271,6 +269,7 @@ struct snd_pcm_runtime { int overrange; snd_pcm_uframes_t avail_max; snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ + snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */ unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */ snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */ @@ -311,7 +310,6 @@ struct snd_pcm_runtime { struct snd_pcm_mmap_control *control; /* -- locking / scheduling -- */ - unsigned int nowake: 1; /* no wakeup (data-copy in progress) */ wait_queue_head_t sleep; struct fasync_struct *fasync; @@ -342,10 +340,6 @@ struct snd_pcm_runtime { /* -- OSS things -- */ struct snd_pcm_oss_runtime oss; #endif - -#ifdef CONFIG_SND_PCM_XRUN_DEBUG - struct snd_pcm_hwptr_log *hwptr_log; -#endif }; struct snd_pcm_group { /* keep linked substreams */ @@ -840,8 +834,6 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream); int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream); int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg); -int snd_pcm_update_state(struct snd_pcm_substream *substream, - struct snd_pcm_runtime *runtime); int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); int snd_pcm_playback_xrun_check(struct snd_pcm_substream *substream); int snd_pcm_capture_xrun_check(struct snd_pcm_substream *substream); diff --git a/trunk/include/sound/pcm_oss.h b/trunk/include/sound/pcm_oss.h index 760c969d885d..cc4e226f35fd 100644 --- a/trunk/include/sound/pcm_oss.h +++ b/trunk/include/sound/pcm_oss.h @@ -61,7 +61,7 @@ struct snd_pcm_oss_runtime { struct snd_pcm_plugin *plugin_first; struct snd_pcm_plugin *plugin_last; #endif - unsigned int prev_hw_ptr_period; + unsigned int prev_hw_ptr_interrupt; }; struct snd_pcm_oss_file { diff --git a/trunk/include/sound/version.h b/trunk/include/sound/version.h index 7fed23442db8..22939142dd23 100644 --- a/trunk/include/sound/version.h +++ b/trunk/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h */ -#define CONFIG_SND_VERSION "1.0.22.1" +#define CONFIG_SND_VERSION "1.0.21" #define CONFIG_SND_DATE "" diff --git a/trunk/sound/core/oss/pcm_oss.c b/trunk/sound/core/oss/pcm_oss.c index 255ad910077a..d9c96353121a 100644 --- a/trunk/sound/core/oss/pcm_oss.c +++ b/trunk/sound/core/oss/pcm_oss.c @@ -632,13 +632,6 @@ static long snd_pcm_alsa_frames(struct snd_pcm_substream *substream, long bytes) return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes); } -static inline -snd_pcm_uframes_t get_hw_ptr_period(struct snd_pcm_runtime *runtime) -{ - snd_pcm_uframes_t ptr = runtime->status->hw_ptr; - return ptr - (ptr % runtime->period_size); -} - /* define extended formats in the recent OSS versions (if any) */ /* linear formats */ #define AFMT_S32_LE 0x00001000 @@ -1109,7 +1102,7 @@ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream) return err; } runtime->oss.prepare = 0; - runtime->oss.prev_hw_ptr_period = 0; + runtime->oss.prev_hw_ptr_interrupt = 0; runtime->oss.period_ptr = 0; runtime->oss.buffer_used = 0; @@ -1957,8 +1950,7 @@ static int snd_pcm_oss_get_caps(struct snd_pcm_oss_file *pcm_oss_file) return result; } -static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream, - snd_pcm_uframes_t hw_ptr) +static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream, snd_pcm_uframes_t hw_ptr) { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t appl_ptr; @@ -1994,8 +1986,7 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr if (runtime->oss.trigger) goto _skip1; if (atomic_read(&psubstream->mmap_count)) - snd_pcm_oss_simulate_fill(psubstream, - get_hw_ptr_period(runtime)); + snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt); runtime->oss.trigger = 1; runtime->start_threshold = 1; cmd = SNDRV_PCM_IOCTL_START; @@ -2114,12 +2105,11 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size); if (atomic_read(&substream->mmap_count)) { snd_pcm_sframes_t n; - delay = get_hw_ptr_period(runtime); - n = delay - runtime->oss.prev_hw_ptr_period; + n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt; if (n < 0) n += runtime->boundary; info.blocks = n / runtime->period_size; - runtime->oss.prev_hw_ptr_period = delay; + runtime->oss.prev_hw_ptr_interrupt = delay; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) snd_pcm_oss_simulate_fill(substream, delay); info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX; @@ -2683,22 +2673,18 @@ static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; if (atomic_read(&substream->mmap_count)) - return runtime->oss.prev_hw_ptr_period != - get_hw_ptr_period(runtime); + return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; else - return snd_pcm_playback_avail(runtime) >= - runtime->oss.period_frames; + return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames; } static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; if (atomic_read(&substream->mmap_count)) - return runtime->oss.prev_hw_ptr_period != - get_hw_ptr_period(runtime); + return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; else - return snd_pcm_capture_avail(runtime) >= - runtime->oss.period_frames; + return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames; } static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait) diff --git a/trunk/sound/core/pcm.c b/trunk/sound/core/pcm.c index df57a0e30bf2..6884ae031f6f 100644 --- a/trunk/sound/core/pcm.c +++ b/trunk/sound/core/pcm.c @@ -921,10 +921,6 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) snd_free_pages((void*)runtime->control, PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))); kfree(runtime->hw_constraints.rules); -#ifdef CONFIG_SND_PCM_XRUN_DEBUG - if (runtime->hwptr_log) - kfree(runtime->hwptr_log); -#endif kfree(runtime); substream->runtime = NULL; put_pid(substream->pid); diff --git a/trunk/sound/core/pcm_lib.c b/trunk/sound/core/pcm_lib.c index c7b35b20e659..30f410832a25 100644 --- a/trunk/sound/core/pcm_lib.c +++ b/trunk/sound/core/pcm_lib.c @@ -126,6 +126,17 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram } } +#ifdef CONFIG_SND_PCM_XRUN_DEBUG +#define xrun_debug(substream, mask) ((substream)->pstr->xrun_debug & (mask)) +#else +#define xrun_debug(substream, mask) 0 +#endif + +#define dump_stack_on_xrun(substream) do { \ + if (xrun_debug(substream, 2)) \ + dump_stack(); \ + } while (0) + static void pcm_debug_name(struct snd_pcm_substream *substream, char *name, size_t len) { @@ -136,24 +147,6 @@ static void pcm_debug_name(struct snd_pcm_substream *substream, substream->number); } -#define XRUN_DEBUG_BASIC (1<<0) -#define XRUN_DEBUG_STACK (1<<1) /* dump also stack */ -#define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */ -#define XRUN_DEBUG_PERIODUPDATE (1<<3) /* full period update info */ -#define XRUN_DEBUG_HWPTRUPDATE (1<<4) /* full hwptr update info */ -#define XRUN_DEBUG_LOG (1<<5) /* show last 10 positions on err */ -#define XRUN_DEBUG_LOGONCE (1<<6) /* do above only once */ - -#ifdef CONFIG_SND_PCM_XRUN_DEBUG - -#define xrun_debug(substream, mask) \ - ((substream)->pstr->xrun_debug & (mask)) - -#define dump_stack_on_xrun(substream) do { \ - if (xrun_debug(substream, XRUN_DEBUG_STACK)) \ - dump_stack(); \ - } while (0) - static void xrun(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -161,7 +154,7 @@ static void xrun(struct snd_pcm_substream *substream) if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { + if (xrun_debug(substream, 1)) { char name[16]; pcm_debug_name(substream, name, sizeof(name)); snd_printd(KERN_DEBUG "XRUN: %s\n", name); @@ -169,102 +162,32 @@ static void xrun(struct snd_pcm_substream *substream) } } -#define hw_ptr_error(substream, fmt, args...) \ - do { \ - if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ - xrun_log_show(substream); \ - if (printk_ratelimit()) { \ - snd_printd("PCM: " fmt, ##args); \ - } \ - dump_stack_on_xrun(substream); \ - } \ - } while (0) - -#define XRUN_LOG_CNT 10 - -struct hwptr_log_entry { - unsigned long jiffies; - snd_pcm_uframes_t pos; - snd_pcm_uframes_t period_size; - snd_pcm_uframes_t buffer_size; - snd_pcm_uframes_t old_hw_ptr; - snd_pcm_uframes_t hw_ptr_base; -}; - -struct snd_pcm_hwptr_log { - unsigned int idx; - unsigned int hit: 1; - struct hwptr_log_entry entries[XRUN_LOG_CNT]; -}; - -static void xrun_log(struct snd_pcm_substream *substream, - snd_pcm_uframes_t pos) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_pcm_hwptr_log *log = runtime->hwptr_log; - struct hwptr_log_entry *entry; - - if (log == NULL) { - log = kzalloc(sizeof(*log), GFP_ATOMIC); - if (log == NULL) - return; - runtime->hwptr_log = log; - } else { - if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) - return; - } - entry = &log->entries[log->idx]; - entry->jiffies = jiffies; - entry->pos = pos; - entry->period_size = runtime->period_size; - entry->buffer_size = runtime->buffer_size;; - entry->old_hw_ptr = runtime->status->hw_ptr; - entry->hw_ptr_base = runtime->hw_ptr_base; - log->idx = (log->idx + 1) % XRUN_LOG_CNT; -} - -static void xrun_log_show(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t +snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream, + struct snd_pcm_runtime *runtime) { - struct snd_pcm_hwptr_log *log = substream->runtime->hwptr_log; - struct hwptr_log_entry *entry; - char name[16]; - unsigned int idx; - int cnt; + snd_pcm_uframes_t pos; - if (log == NULL) - return; - if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) - return; - pcm_debug_name(substream, name, sizeof(name)); - for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) { - entry = &log->entries[idx]; - if (entry->period_size == 0) - break; - snd_printd("hwptr log: %s: j=%lu, pos=%ld/%ld/%ld, " - "hwptr=%ld/%ld\n", - name, entry->jiffies, (unsigned long)entry->pos, - (unsigned long)entry->period_size, - (unsigned long)entry->buffer_size, - (unsigned long)entry->old_hw_ptr, - (unsigned long)entry->hw_ptr_base); - idx++; - idx %= XRUN_LOG_CNT; + pos = substream->ops->pointer(substream); + if (pos == SNDRV_PCM_POS_XRUN) + return pos; /* XRUN */ + if (pos >= runtime->buffer_size) { + if (printk_ratelimit()) { + char name[16]; + pcm_debug_name(substream, name, sizeof(name)); + snd_printd(KERN_ERR "BUG: %s, pos = 0x%lx, " + "buffer size = 0x%lx, period size = 0x%lx\n", + name, pos, runtime->buffer_size, + runtime->period_size); + } + pos = 0; } - log->hit = 1; + pos -= pos % runtime->min_align; + return pos; } -#else /* ! CONFIG_SND_PCM_XRUN_DEBUG */ - -#define xrun_debug(substream, mask) 0 -#define xrun(substream) do { } while (0) -#define hw_ptr_error(substream, fmt, args...) do { } while (0) -#define xrun_log(substream, pos) do { } while (0) -#define xrun_log_show(substream) do { } while (0) - -#endif - -int snd_pcm_update_state(struct snd_pcm_substream *substream, - struct snd_pcm_runtime *runtime) +static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, + struct snd_pcm_runtime *runtime) { snd_pcm_uframes_t avail; @@ -285,96 +208,89 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream, return -EPIPE; } } - if (!runtime->nowake && avail >= runtime->control->avail_min) + if (avail >= runtime->control->avail_min) wake_up(&runtime->sleep); return 0; } -static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, - unsigned int in_interrupt) +#define hw_ptr_error(substream, fmt, args...) \ + do { \ + if (xrun_debug(substream, 1)) { \ + if (printk_ratelimit()) { \ + snd_printd("PCM: " fmt, ##args); \ + } \ + dump_stack_on_xrun(substream); \ + } \ + } while (0) + +static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t pos; - snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base; + snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_ptr_interrupt, hw_base; snd_pcm_sframes_t hdelta, delta; unsigned long jdelta; old_hw_ptr = runtime->status->hw_ptr; - pos = substream->ops->pointer(substream); + pos = snd_pcm_update_hw_ptr_pos(substream, runtime); if (pos == SNDRV_PCM_POS_XRUN) { xrun(substream); return -EPIPE; } - if (pos >= runtime->buffer_size) { - if (printk_ratelimit()) { - char name[16]; - pcm_debug_name(substream, name, sizeof(name)); - xrun_log_show(substream); - snd_printd(KERN_ERR "BUG: %s, pos = %ld, " - "buffer size = %ld, period size = %ld\n", - name, pos, runtime->buffer_size, - runtime->period_size); - } - pos = 0; + if (xrun_debug(substream, 8)) { + char name[16]; + pcm_debug_name(substream, name, sizeof(name)); + snd_printd("period_update: %s: pos=0x%x/0x%x/0x%x, " + "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n", + name, (unsigned int)pos, + (unsigned int)runtime->period_size, + (unsigned int)runtime->buffer_size, + (unsigned long)old_hw_ptr, + (unsigned long)runtime->hw_ptr_base, + (unsigned long)runtime->hw_ptr_interrupt); } - pos -= pos % runtime->min_align; - if (xrun_debug(substream, XRUN_DEBUG_LOG)) - xrun_log(substream, pos); hw_base = runtime->hw_ptr_base; new_hw_ptr = hw_base + pos; - if (in_interrupt) { - /* we know that one period was processed */ - /* delta = "expected next hw_ptr" for in_interrupt != 0 */ - delta = old_hw_ptr - (old_hw_ptr % runtime->period_size) - + runtime->period_size; - if (delta > new_hw_ptr) { + hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size; + delta = new_hw_ptr - hw_ptr_interrupt; + if (hw_ptr_interrupt >= runtime->boundary) { + hw_ptr_interrupt -= runtime->boundary; + if (hw_base < runtime->boundary / 2) + /* hw_base was already lapped; recalc delta */ + delta = new_hw_ptr - hw_ptr_interrupt; + } + if (delta < 0) { + if (runtime->periods == 1 || new_hw_ptr < old_hw_ptr) + delta += runtime->buffer_size; + if (delta < 0) { + hw_ptr_error(substream, + "Unexpected hw_pointer value " + "(stream=%i, pos=%ld, intr_ptr=%ld)\n", + substream->stream, (long)pos, + (long)hw_ptr_interrupt); +#if 1 + /* simply skipping the hwptr update seems more + * robust in some cases, e.g. on VMware with + * inaccurate timer source + */ + return 0; /* skip this update */ +#else + /* rebase to interrupt position */ + hw_base = new_hw_ptr = hw_ptr_interrupt; + /* align hw_base to buffer_size */ + hw_base -= hw_base % runtime->buffer_size; + delta = 0; +#endif + } else { hw_base += runtime->buffer_size; if (hw_base >= runtime->boundary) hw_base = 0; new_hw_ptr = hw_base + pos; - goto __delta; } } - /* new_hw_ptr might be lower than old_hw_ptr in case when */ - /* pointer crosses the end of the ring buffer */ - if (new_hw_ptr < old_hw_ptr) { - hw_base += runtime->buffer_size; - if (hw_base >= runtime->boundary) - hw_base = 0; - new_hw_ptr = hw_base + pos; - } - __delta: - delta = (new_hw_ptr - old_hw_ptr) % runtime->boundary; - if (xrun_debug(substream, in_interrupt ? - XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) { - char name[16]; - pcm_debug_name(substream, name, sizeof(name)); - snd_printd("%s_update: %s: pos=%u/%u/%u, " - "hwptr=%ld/%ld/%ld/%ld\n", - in_interrupt ? "period" : "hwptr", - name, - (unsigned int)pos, - (unsigned int)runtime->period_size, - (unsigned int)runtime->buffer_size, - (unsigned long)delta, - (unsigned long)old_hw_ptr, - (unsigned long)new_hw_ptr, - (unsigned long)runtime->hw_ptr_base); - } - /* something must be really wrong */ - if (delta >= runtime->buffer_size + runtime->period_size) { - hw_ptr_error(substream, - "Unexpected hw_pointer value %s" - "(stream=%i, pos=%ld, new_hw_ptr=%ld, " - "old_hw_ptr=%ld)\n", - in_interrupt ? "[Q] " : "[P]", - substream->stream, (long)pos, - (long)new_hw_ptr, (long)old_hw_ptr); - return 0; - } /* Do jiffies check only in xrun_debug mode */ - if (!xrun_debug(substream, XRUN_DEBUG_JIFFIESCHECK)) + if (!xrun_debug(substream, 4)) goto no_jiffies_check; /* Skip the jiffies check for hardwares with BATCH flag. @@ -383,7 +299,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, */ if (runtime->hw.info & SNDRV_PCM_INFO_BATCH) goto no_jiffies_check; - hdelta = delta; + hdelta = new_hw_ptr - old_hw_ptr; if (hdelta < runtime->delay) goto no_jiffies_check; hdelta -= runtime->delay; @@ -392,62 +308,130 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, delta = jdelta / (((runtime->period_size * HZ) / runtime->rate) + HZ/100); - /* move new_hw_ptr according jiffies not pos variable */ - new_hw_ptr = old_hw_ptr; - /* use loop to avoid checks for delta overflows */ - /* the delta value is small or zero in most cases */ - while (delta > 0) { - new_hw_ptr += runtime->period_size; - if (new_hw_ptr >= runtime->boundary) - new_hw_ptr -= runtime->boundary; - delta--; - } - /* align hw_base to buffer_size */ - hw_base = new_hw_ptr - (new_hw_ptr % runtime->buffer_size); - delta = 0; hw_ptr_error(substream, - "hw_ptr skipping! %s" + "hw_ptr skipping! [Q] " "(pos=%ld, delta=%ld, period=%ld, " - "jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n", - in_interrupt ? "[Q] " : "", + "jdelta=%lu/%lu/%lu)\n", (long)pos, (long)hdelta, (long)runtime->period_size, jdelta, - ((hdelta * HZ) / runtime->rate), delta, - (unsigned long)old_hw_ptr, - (unsigned long)new_hw_ptr); + ((hdelta * HZ) / runtime->rate), delta); + hw_ptr_interrupt = runtime->hw_ptr_interrupt + + runtime->period_size * delta; + if (hw_ptr_interrupt >= runtime->boundary) + hw_ptr_interrupt -= runtime->boundary; + /* rebase to interrupt position */ + hw_base = new_hw_ptr = hw_ptr_interrupt; + /* align hw_base to buffer_size */ + hw_base -= hw_base % runtime->buffer_size; + delta = 0; } no_jiffies_check: if (delta > runtime->period_size + runtime->period_size / 2) { hw_ptr_error(substream, - "Lost interrupts? %s" - "(stream=%i, delta=%ld, new_hw_ptr=%ld, " - "old_hw_ptr=%ld)\n", - in_interrupt ? "[Q] " : "", + "Lost interrupts? " + "(stream=%i, delta=%ld, intr_ptr=%ld)\n", substream->stream, (long)delta, - (long)new_hw_ptr, - (long)old_hw_ptr); + (long)hw_ptr_interrupt); + /* rebase hw_ptr_interrupt */ + hw_ptr_interrupt = + new_hw_ptr - new_hw_ptr % runtime->period_size; } - - if (runtime->status->hw_ptr == new_hw_ptr) - return 0; + runtime->hw_ptr_interrupt = hw_ptr_interrupt; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, new_hw_ptr); + if (runtime->status->hw_ptr == new_hw_ptr) + return 0; + runtime->hw_ptr_base = hw_base; runtime->status->hw_ptr = new_hw_ptr; runtime->hw_ptr_jiffies = jiffies; if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); - return snd_pcm_update_state(substream, runtime); + return snd_pcm_update_hw_ptr_post(substream, runtime); } /* CAUTION: call it with irq disabled */ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) { - return snd_pcm_update_hw_ptr0(substream, 0); + struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_uframes_t pos; + snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base; + snd_pcm_sframes_t delta; + unsigned long jdelta; + + old_hw_ptr = runtime->status->hw_ptr; + pos = snd_pcm_update_hw_ptr_pos(substream, runtime); + if (pos == SNDRV_PCM_POS_XRUN) { + xrun(substream); + return -EPIPE; + } + if (xrun_debug(substream, 16)) { + char name[16]; + pcm_debug_name(substream, name, sizeof(name)); + snd_printd("hw_update: %s: pos=0x%x/0x%x/0x%x, " + "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n", + name, (unsigned int)pos, + (unsigned int)runtime->period_size, + (unsigned int)runtime->buffer_size, + (unsigned long)old_hw_ptr, + (unsigned long)runtime->hw_ptr_base, + (unsigned long)runtime->hw_ptr_interrupt); + } + + hw_base = runtime->hw_ptr_base; + new_hw_ptr = hw_base + pos; + + delta = new_hw_ptr - old_hw_ptr; + jdelta = jiffies - runtime->hw_ptr_jiffies; + if (delta < 0) { + delta += runtime->buffer_size; + if (delta < 0) { + hw_ptr_error(substream, + "Unexpected hw_pointer value [2] " + "(stream=%i, pos=%ld, old_ptr=%ld, jdelta=%li)\n", + substream->stream, (long)pos, + (long)old_hw_ptr, jdelta); + return 0; + } + hw_base += runtime->buffer_size; + if (hw_base >= runtime->boundary) + hw_base = 0; + new_hw_ptr = hw_base + pos; + } + /* Do jiffies check only in xrun_debug mode */ + if (!xrun_debug(substream, 4)) + goto no_jiffies_check; + if (delta < runtime->delay) + goto no_jiffies_check; + delta -= runtime->delay; + if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) { + hw_ptr_error(substream, + "hw_ptr skipping! " + "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n", + (long)pos, (long)delta, + (long)runtime->period_size, jdelta, + ((delta * HZ) / runtime->rate)); + return 0; + } + no_jiffies_check: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && + runtime->silence_size > 0) + snd_pcm_playback_silence(substream, new_hw_ptr); + + if (runtime->status->hw_ptr == new_hw_ptr) + return 0; + + runtime->hw_ptr_base = hw_base; + runtime->status->hw_ptr = new_hw_ptr; + runtime->hw_ptr_jiffies = jiffies; + if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) + snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); + + return snd_pcm_update_hw_ptr_post(substream, runtime); } /** @@ -1659,7 +1643,7 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) snd_pcm_stream_lock_irqsave(substream, flags); if (!snd_pcm_running(substream) || - snd_pcm_update_hw_ptr0(substream, 1) < 0) + snd_pcm_update_hw_ptr_interrupt(substream) < 0) goto _end; if (substream->timer_running) @@ -1792,7 +1776,6 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, goto _end_unlock; } - runtime->nowake = 1; while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t avail; @@ -1814,17 +1797,15 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, if (frames > cont) frames = cont; if (snd_BUG_ON(!frames)) { - runtime->nowake = 0; snd_pcm_stream_unlock_irq(substream); return -EINVAL; } appl_ptr = runtime->control->appl_ptr; appl_ofs = appl_ptr % runtime->buffer_size; snd_pcm_stream_unlock_irq(substream); - err = transfer(substream, appl_ofs, data, offset, frames); + if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0) + goto _end; snd_pcm_stream_lock_irq(substream); - if (err < 0) - goto _end_unlock; switch (runtime->status->state) { case SNDRV_PCM_STATE_XRUN: err = -EPIPE; @@ -1853,10 +1834,8 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, } } _end_unlock: - runtime->nowake = 0; - if (xfer > 0 && err >= 0) - snd_pcm_update_state(substream, runtime); snd_pcm_stream_unlock_irq(substream); + _end: return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; } @@ -2014,7 +1993,6 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, goto _end_unlock; } - runtime->nowake = 1; while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t avail; @@ -2043,17 +2021,15 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, if (frames > cont) frames = cont; if (snd_BUG_ON(!frames)) { - runtime->nowake = 0; snd_pcm_stream_unlock_irq(substream); return -EINVAL; } appl_ptr = runtime->control->appl_ptr; appl_ofs = appl_ptr % runtime->buffer_size; snd_pcm_stream_unlock_irq(substream); - err = transfer(substream, appl_ofs, data, offset, frames); + if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0) + goto _end; snd_pcm_stream_lock_irq(substream); - if (err < 0) - goto _end_unlock; switch (runtime->status->state) { case SNDRV_PCM_STATE_XRUN: err = -EPIPE; @@ -2076,10 +2052,8 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, xfer += frames; } _end_unlock: - runtime->nowake = 0; - if (xfer > 0 && err >= 0) - snd_pcm_update_state(substream, runtime); snd_pcm_stream_unlock_irq(substream); + _end: return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; } diff --git a/trunk/sound/core/pcm_native.c b/trunk/sound/core/pcm_native.c index 27284f628361..29ab46a12e11 100644 --- a/trunk/sound/core/pcm_native.c +++ b/trunk/sound/core/pcm_native.c @@ -516,7 +516,6 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, struct snd_pcm_sw_params *params) { struct snd_pcm_runtime *runtime; - int err; if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; @@ -541,7 +540,6 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, if (params->silence_threshold > runtime->buffer_size) return -EINVAL; } - err = 0; snd_pcm_stream_lock_irq(substream); runtime->tstamp_mode = params->tstamp_mode; runtime->period_step = params->period_step; @@ -555,10 +553,10 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, ULONG_MAX); - err = snd_pcm_update_state(substream, runtime); + wake_up(&runtime->sleep); } snd_pcm_stream_unlock_irq(substream); - return err; + return 0; } static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream, @@ -1249,6 +1247,8 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state) if (err < 0) return err; runtime->hw_ptr_base = 0; + runtime->hw_ptr_interrupt = runtime->status->hw_ptr - + runtime->status->hw_ptr % runtime->period_size; runtime->silence_start = runtime->status->hw_ptr; runtime->silence_filled = 0; return 0; diff --git a/trunk/sound/isa/gus/gus_mem.c b/trunk/sound/isa/gus/gus_mem.c index 661205c4dcea..af888a022fc0 100644 --- a/trunk/sound/isa/gus/gus_mem.c +++ b/trunk/sound/isa/gus/gus_mem.c @@ -127,7 +127,8 @@ static struct snd_gf1_mem_block *snd_gf1_mem_share(struct snd_gf1_mem * alloc, !share_id[2] && !share_id[3]) return NULL; for (block = alloc->first; block; block = block->next) - if (!memcmp(share_id, block->share_id, sizeof(share_id))) + if (!memcmp(share_id, block->share_id, + sizeof(block->share_id))) return block; return NULL; } diff --git a/trunk/sound/pci/ac97/ac97_codec.c b/trunk/sound/pci/ac97/ac97_codec.c index 20cb60afb200..c11920623009 100644 --- a/trunk/sound/pci/ac97/ac97_codec.c +++ b/trunk/sound/pci/ac97/ac97_codec.c @@ -2122,7 +2122,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, } /* nothing should be in powerdown mode */ snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0); - end_time = jiffies + msecs_to_jiffies(120); + end_time = jiffies + msecs_to_jiffies(5000); do { if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0f) == 0x0f) goto __ready_ok; diff --git a/trunk/sound/pci/ac97/ac97_patch.c b/trunk/sound/pci/ac97/ac97_patch.c index e288a5595f34..139cf3b2b9d7 100644 --- a/trunk/sound/pci/ac97/ac97_patch.c +++ b/trunk/sound/pci/ac97/ac97_patch.c @@ -544,10 +544,25 @@ static int patch_wolfson04(struct snd_ac97 * ac97) return 0; } +static int patch_wolfson_wm9705_specific(struct snd_ac97 * ac97) +{ + int err, i; + for (i = 0; i < ARRAY_SIZE(wm97xx_snd_ac97_controls); i++) { + if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm97xx_snd_ac97_controls[i], ac97))) < 0) + return err; + } + snd_ac97_write_cache(ac97, 0x72, 0x0808); + return 0; +} + +static struct snd_ac97_build_ops patch_wolfson_wm9705_ops = { + .build_specific = patch_wolfson_wm9705_specific, +}; + static int patch_wolfson05(struct snd_ac97 * ac97) { /* WM9705, WM9710 */ - ac97->build_ops = &patch_wolfson_wm9703_ops; + ac97->build_ops = &patch_wolfson_wm9705_ops; #ifdef CONFIG_TOUCHSCREEN_WM9705 /* WM9705 touchscreen uses AUX and VIDEO for touch */ ac97->flags |= AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX; diff --git a/trunk/sound/pci/hda/hda_intel.c b/trunk/sound/pci/hda/hda_intel.c index e54420e691ae..9b56f937913e 100644 --- a/trunk/sound/pci/hda/hda_intel.c +++ b/trunk/sound/pci/hda/hda_intel.c @@ -2713,6 +2713,9 @@ static struct pci_device_id azx_ids[] = { { PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA }, { PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA }, { PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA }, + { PCI_DEVICE(0x10de, 0x0be2), .driver_data = AZX_DRIVER_NVIDIA }, + { PCI_DEVICE(0x10de, 0x0be3), .driver_data = AZX_DRIVER_NVIDIA }, + { PCI_DEVICE(0x10de, 0x0be4), .driver_data = AZX_DRIVER_NVIDIA }, { PCI_DEVICE(0x10de, 0x0d94), .driver_data = AZX_DRIVER_NVIDIA }, { PCI_DEVICE(0x10de, 0x0d95), .driver_data = AZX_DRIVER_NVIDIA }, { PCI_DEVICE(0x10de, 0x0d96), .driver_data = AZX_DRIVER_NVIDIA }, diff --git a/trunk/sound/pci/hda/patch_analog.c b/trunk/sound/pci/hda/patch_analog.c index e75b5e5a1d55..92b72d4f3984 100644 --- a/trunk/sound/pci/hda/patch_analog.c +++ b/trunk/sound/pci/hda/patch_analog.c @@ -1813,6 +1813,14 @@ static int patch_ad1981(struct hda_codec *codec) codec->patch_ops.init = ad1981_hp_init; codec->patch_ops.unsol_event = ad1981_hp_unsol_event; + /* set the upper-limit for mixer amp to 0dB for avoiding the + * possible damage by overloading + */ + snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT, + (0x17 << AC_AMPCAP_OFFSET_SHIFT) | + (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (1 << AC_AMPCAP_MUTE_SHIFT)); break; case AD1981_THINKPAD: spec->mixers[0] = ad1981_thinkpad_mixers; diff --git a/trunk/sound/pci/hda/patch_conexant.c b/trunk/sound/pci/hda/patch_conexant.c index b20c640f7502..1ab2958a290b 100644 --- a/trunk/sound/pci/hda/patch_conexant.c +++ b/trunk/sound/pci/hda/patch_conexant.c @@ -1720,22 +1720,6 @@ static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { {} }; -static struct snd_kcontrol_new cxt5051_f700_mixers[] = { - HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5051_hp_master_sw_put, - .private_value = 0x1a, - }, - - {} -}; - static struct hda_verb cxt5051_init_verbs[] = { /* Line in, Mic */ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, @@ -1826,32 +1810,6 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { { } /* end */ }; -static struct hda_verb cxt5051_f700_init_verbs[] = { - /* Line in, Mic */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x03}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, - /* SPK */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP, Amp */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Record selector: Int mic */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* SPDIF route: PCM */ - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* EAPD */ - {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, - {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, - { } /* end */ -}; - /* initialize jack-sensing, too */ static int cxt5051_init(struct hda_codec *codec) { @@ -1871,7 +1829,6 @@ enum { CXT5051_HP, /* no docking */ CXT5051_HP_DV6736, /* HP without mic switch */ CXT5051_LENOVO_X200, /* Lenovo X200 laptop */ - CXT5051_F700, /* HP Compaq Presario F700 */ CXT5051_MODELS }; @@ -1880,7 +1837,6 @@ static const char *cxt5051_models[CXT5051_MODELS] = { [CXT5051_HP] = "hp", [CXT5051_HP_DV6736] = "hp-dv6736", [CXT5051_LENOVO_X200] = "lenovo-x200", - [CXT5051_F700] = "hp 700" }; static struct snd_pci_quirk cxt5051_cfg_tbl[] = { @@ -1890,7 +1846,6 @@ static struct snd_pci_quirk cxt5051_cfg_tbl[] = { CXT5051_LAPTOP), SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200), - SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700), {} }; @@ -1941,11 +1896,6 @@ static int patch_cxt5051(struct hda_codec *codec) case CXT5051_LENOVO_X200: spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; break; - case CXT5051_F700: - spec->init_verbs[0] = cxt5051_f700_init_verbs; - spec->mixers[0] = cxt5051_f700_mixers; - spec->no_auto_mic = 1; - break; } return 0; diff --git a/trunk/sound/pci/hda/patch_realtek.c b/trunk/sound/pci/hda/patch_realtek.c index cb7679551bdc..f88577897e46 100644 --- a/trunk/sound/pci/hda/patch_realtek.c +++ b/trunk/sound/pci/hda/patch_realtek.c @@ -6334,6 +6334,7 @@ static const char *alc260_models[ALC260_MODEL_LAST] = { static struct snd_pci_quirk alc260_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER), + SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL), SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100), SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), diff --git a/trunk/sound/soc/codecs/wm8900.c b/trunk/sound/soc/codecs/wm8900.c index c9438dd62df3..dbc368c08263 100644 --- a/trunk/sound/soc/codecs/wm8900.c +++ b/trunk/sound/soc/codecs/wm8900.c @@ -199,7 +199,7 @@ static void wm8900_reset(struct snd_soc_codec *codec) snd_soc_write(codec, WM8900_REG_RESET, 0); memcpy(codec->reg_cache, wm8900_reg_defaults, - sizeof(codec->reg_cache)); + sizeof(wm8900_reg_defaults)); } static int wm8900_hp_event(struct snd_soc_dapm_widget *w,