diff options
-rw-r--r-- | include/sound/pcm.h | 10 | ||||
-rw-r--r-- | include/sound/pcm_oss.h | 2 | ||||
-rw-r--r-- | include/sound/version.h | 2 | ||||
-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 | ||||
-rw-r--r-- | sound/pci/ac97/ac97_patch.c | 17 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 79 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 1 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.c | 3 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 16 | ||||
-rw-r--r-- | sound/pci/hda/hda_proc.c | 31 | ||||
-rw-r--r-- | sound/pci/hda/patch_analog.c | 37 | ||||
-rw-r--r-- | sound/pci/hda/patch_cirrus.c | 10 | ||||
-rw-r--r-- | sound/pci/hda/patch_cmedia.c | 12 | ||||
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 1 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 125 | ||||
-rw-r--r-- | sound/pci/hda/patch_si3054.c | 1 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 7 | ||||
-rw-r--r-- | sound/pci/hda/patch_via.c | 275 |
21 files changed, 720 insertions, 371 deletions
diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 0ad2d28f2360..1d4ca2aae50d 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h | |||
@@ -262,6 +262,8 @@ struct snd_pcm_hw_constraint_list { | |||
262 | unsigned int mask; | 262 | unsigned int mask; |
263 | }; | 263 | }; |
264 | 264 | ||
265 | struct snd_pcm_hwptr_log; | ||
266 | |||
265 | struct snd_pcm_runtime { | 267 | struct snd_pcm_runtime { |
266 | /* -- Status -- */ | 268 | /* -- Status -- */ |
267 | struct snd_pcm_substream *trigger_master; | 269 | struct snd_pcm_substream *trigger_master; |
@@ -269,7 +271,6 @@ struct snd_pcm_runtime { | |||
269 | int overrange; | 271 | int overrange; |
270 | snd_pcm_uframes_t avail_max; | 272 | snd_pcm_uframes_t avail_max; |
271 | snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ | 273 | snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ |
272 | snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */ | ||
273 | unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */ | 274 | unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */ |
274 | snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */ | 275 | snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */ |
275 | 276 | ||
@@ -310,6 +311,7 @@ struct snd_pcm_runtime { | |||
310 | struct snd_pcm_mmap_control *control; | 311 | struct snd_pcm_mmap_control *control; |
311 | 312 | ||
312 | /* -- locking / scheduling -- */ | 313 | /* -- locking / scheduling -- */ |
314 | unsigned int nowake: 1; /* no wakeup (data-copy in progress) */ | ||
313 | wait_queue_head_t sleep; | 315 | wait_queue_head_t sleep; |
314 | struct fasync_struct *fasync; | 316 | struct fasync_struct *fasync; |
315 | 317 | ||
@@ -340,6 +342,10 @@ struct snd_pcm_runtime { | |||
340 | /* -- OSS things -- */ | 342 | /* -- OSS things -- */ |
341 | struct snd_pcm_oss_runtime oss; | 343 | struct snd_pcm_oss_runtime oss; |
342 | #endif | 344 | #endif |
345 | |||
346 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | ||
347 | struct snd_pcm_hwptr_log *hwptr_log; | ||
348 | #endif | ||
343 | }; | 349 | }; |
344 | 350 | ||
345 | struct snd_pcm_group { /* keep linked substreams */ | 351 | struct snd_pcm_group { /* keep linked substreams */ |
@@ -834,6 +840,8 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream); | |||
834 | int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream); | 840 | int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream); |
835 | int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, | 841 | int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, |
836 | unsigned int cmd, void *arg); | 842 | unsigned int cmd, void *arg); |
843 | int snd_pcm_update_state(struct snd_pcm_substream *substream, | ||
844 | struct snd_pcm_runtime *runtime); | ||
837 | int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); | 845 | int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); |
838 | int snd_pcm_playback_xrun_check(struct snd_pcm_substream *substream); | 846 | int snd_pcm_playback_xrun_check(struct snd_pcm_substream *substream); |
839 | int snd_pcm_capture_xrun_check(struct snd_pcm_substream *substream); | 847 | int snd_pcm_capture_xrun_check(struct snd_pcm_substream *substream); |
diff --git a/include/sound/pcm_oss.h b/include/sound/pcm_oss.h index cc4e226f35fd..760c969d885d 100644 --- a/include/sound/pcm_oss.h +++ b/include/sound/pcm_oss.h | |||
@@ -61,7 +61,7 @@ struct snd_pcm_oss_runtime { | |||
61 | struct snd_pcm_plugin *plugin_first; | 61 | struct snd_pcm_plugin *plugin_first; |
62 | struct snd_pcm_plugin *plugin_last; | 62 | struct snd_pcm_plugin *plugin_last; |
63 | #endif | 63 | #endif |
64 | unsigned int prev_hw_ptr_interrupt; | 64 | unsigned int prev_hw_ptr_period; |
65 | }; | 65 | }; |
66 | 66 | ||
67 | struct snd_pcm_oss_file { | 67 | struct snd_pcm_oss_file { |
diff --git a/include/sound/version.h b/include/sound/version.h index 1f5d4872d623..7fed23442db8 100644 --- a/include/sound/version.h +++ b/include/sound/version.h | |||
@@ -1,3 +1,3 @@ | |||
1 | /* include/version.h */ | 1 | /* include/version.h */ |
2 | #define CONFIG_SND_VERSION "1.0.22" | 2 | #define CONFIG_SND_VERSION "1.0.22.1" |
3 | #define CONFIG_SND_DATE "" | 3 | #define CONFIG_SND_DATE "" |
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; |
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 139cf3b2b9d7..e288a5595f34 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
@@ -544,25 +544,10 @@ static int patch_wolfson04(struct snd_ac97 * ac97) | |||
544 | return 0; | 544 | return 0; |
545 | } | 545 | } |
546 | 546 | ||
547 | static int patch_wolfson_wm9705_specific(struct snd_ac97 * ac97) | ||
548 | { | ||
549 | int err, i; | ||
550 | for (i = 0; i < ARRAY_SIZE(wm97xx_snd_ac97_controls); i++) { | ||
551 | if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm97xx_snd_ac97_controls[i], ac97))) < 0) | ||
552 | return err; | ||
553 | } | ||
554 | snd_ac97_write_cache(ac97, 0x72, 0x0808); | ||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | static struct snd_ac97_build_ops patch_wolfson_wm9705_ops = { | ||
559 | .build_specific = patch_wolfson_wm9705_specific, | ||
560 | }; | ||
561 | |||
562 | static int patch_wolfson05(struct snd_ac97 * ac97) | 547 | static int patch_wolfson05(struct snd_ac97 * ac97) |
563 | { | 548 | { |
564 | /* WM9705, WM9710 */ | 549 | /* WM9705, WM9710 */ |
565 | ac97->build_ops = &patch_wolfson_wm9705_ops; | 550 | ac97->build_ops = &patch_wolfson_wm9703_ops; |
566 | #ifdef CONFIG_TOUCHSCREEN_WM9705 | 551 | #ifdef CONFIG_TOUCHSCREEN_WM9705 |
567 | /* WM9705 touchscreen uses AUX and VIDEO for touch */ | 552 | /* WM9705 touchscreen uses AUX and VIDEO for touch */ |
568 | ac97->flags |= AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX; | 553 | ac97->flags |= AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX; |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 950ee5cfcacf..d2f10b1c3a8a 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -931,6 +931,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) | |||
931 | #endif | 931 | #endif |
932 | list_del(&codec->list); | 932 | list_del(&codec->list); |
933 | snd_array_free(&codec->mixers); | 933 | snd_array_free(&codec->mixers); |
934 | snd_array_free(&codec->nids); | ||
934 | codec->bus->caddr_tbl[codec->addr] = NULL; | 935 | codec->bus->caddr_tbl[codec->addr] = NULL; |
935 | if (codec->patch_ops.free) | 936 | if (codec->patch_ops.free) |
936 | codec->patch_ops.free(codec); | 937 | codec->patch_ops.free(codec); |
@@ -985,7 +986,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr | |||
985 | mutex_init(&codec->control_mutex); | 986 | mutex_init(&codec->control_mutex); |
986 | init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); | 987 | init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); |
987 | init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); | 988 | init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); |
988 | snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 60); | 989 | snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32); |
990 | snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32); | ||
989 | snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); | 991 | snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); |
990 | snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); | 992 | snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); |
991 | if (codec->bus->modelname) { | 993 | if (codec->bus->modelname) { |
@@ -1706,7 +1708,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, | |||
1706 | EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); | 1708 | EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); |
1707 | 1709 | ||
1708 | /** | 1710 | /** |
1709 | * snd_hda_ctl-add - Add a control element and assign to the codec | 1711 | * snd_hda_ctl_add - Add a control element and assign to the codec |
1710 | * @codec: HD-audio codec | 1712 | * @codec: HD-audio codec |
1711 | * @nid: corresponding NID (optional) | 1713 | * @nid: corresponding NID (optional) |
1712 | * @kctl: the control element to assign | 1714 | * @kctl: the control element to assign |
@@ -1721,19 +1723,25 @@ EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); | |||
1721 | * | 1723 | * |
1722 | * snd_hda_ctl_add() checks the control subdev id field whether | 1724 | * snd_hda_ctl_add() checks the control subdev id field whether |
1723 | * #HDA_SUBDEV_NID_FLAG bit is set. If set (and @nid is zero), the lower | 1725 | * #HDA_SUBDEV_NID_FLAG bit is set. If set (and @nid is zero), the lower |
1724 | * bits value is taken as the NID to assign. | 1726 | * bits value is taken as the NID to assign. The #HDA_NID_ITEM_AMP bit |
1727 | * specifies if kctl->private_value is a HDA amplifier value. | ||
1725 | */ | 1728 | */ |
1726 | int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, | 1729 | int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, |
1727 | struct snd_kcontrol *kctl) | 1730 | struct snd_kcontrol *kctl) |
1728 | { | 1731 | { |
1729 | int err; | 1732 | int err; |
1733 | unsigned short flags = 0; | ||
1730 | struct hda_nid_item *item; | 1734 | struct hda_nid_item *item; |
1731 | 1735 | ||
1732 | if (kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) { | 1736 | if (kctl->id.subdevice & HDA_SUBDEV_AMP_FLAG) { |
1737 | flags |= HDA_NID_ITEM_AMP; | ||
1733 | if (nid == 0) | 1738 | if (nid == 0) |
1734 | nid = kctl->id.subdevice & 0xffff; | 1739 | nid = get_amp_nid_(kctl->private_value); |
1735 | kctl->id.subdevice = 0; | ||
1736 | } | 1740 | } |
1741 | if ((kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) != 0 && nid == 0) | ||
1742 | nid = kctl->id.subdevice & 0xffff; | ||
1743 | if (kctl->id.subdevice & (HDA_SUBDEV_NID_FLAG|HDA_SUBDEV_AMP_FLAG)) | ||
1744 | kctl->id.subdevice = 0; | ||
1737 | err = snd_ctl_add(codec->bus->card, kctl); | 1745 | err = snd_ctl_add(codec->bus->card, kctl); |
1738 | if (err < 0) | 1746 | if (err < 0) |
1739 | return err; | 1747 | return err; |
@@ -1742,11 +1750,41 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, | |||
1742 | return -ENOMEM; | 1750 | return -ENOMEM; |
1743 | item->kctl = kctl; | 1751 | item->kctl = kctl; |
1744 | item->nid = nid; | 1752 | item->nid = nid; |
1753 | item->flags = flags; | ||
1745 | return 0; | 1754 | return 0; |
1746 | } | 1755 | } |
1747 | EXPORT_SYMBOL_HDA(snd_hda_ctl_add); | 1756 | EXPORT_SYMBOL_HDA(snd_hda_ctl_add); |
1748 | 1757 | ||
1749 | /** | 1758 | /** |
1759 | * snd_hda_add_nid - Assign a NID to a control element | ||
1760 | * @codec: HD-audio codec | ||
1761 | * @nid: corresponding NID (optional) | ||
1762 | * @kctl: the control element to assign | ||
1763 | * @index: index to kctl | ||
1764 | * | ||
1765 | * Add the given control element to an array inside the codec instance. | ||
1766 | * This function is used when #snd_hda_ctl_add cannot be used for 1:1 | ||
1767 | * NID:KCTL mapping - for example "Capture Source" selector. | ||
1768 | */ | ||
1769 | int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl, | ||
1770 | unsigned int index, hda_nid_t nid) | ||
1771 | { | ||
1772 | struct hda_nid_item *item; | ||
1773 | |||
1774 | if (nid > 0) { | ||
1775 | item = snd_array_new(&codec->nids); | ||
1776 | if (!item) | ||
1777 | return -ENOMEM; | ||
1778 | item->kctl = kctl; | ||
1779 | item->index = index; | ||
1780 | item->nid = nid; | ||
1781 | return 0; | ||
1782 | } | ||
1783 | return -EINVAL; | ||
1784 | } | ||
1785 | EXPORT_SYMBOL_HDA(snd_hda_add_nid); | ||
1786 | |||
1787 | /** | ||
1750 | * snd_hda_ctls_clear - Clear all controls assigned to the given codec | 1788 | * snd_hda_ctls_clear - Clear all controls assigned to the given codec |
1751 | * @codec: HD-audio codec | 1789 | * @codec: HD-audio codec |
1752 | */ | 1790 | */ |
@@ -1757,6 +1795,7 @@ void snd_hda_ctls_clear(struct hda_codec *codec) | |||
1757 | for (i = 0; i < codec->mixers.used; i++) | 1795 | for (i = 0; i < codec->mixers.used; i++) |
1758 | snd_ctl_remove(codec->bus->card, items[i].kctl); | 1796 | snd_ctl_remove(codec->bus->card, items[i].kctl); |
1759 | snd_array_free(&codec->mixers); | 1797 | snd_array_free(&codec->mixers); |
1798 | snd_array_free(&codec->nids); | ||
1760 | } | 1799 | } |
1761 | 1800 | ||
1762 | /* pseudo device locking | 1801 | /* pseudo device locking |
@@ -3476,6 +3515,8 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) | |||
3476 | 3515 | ||
3477 | for (; knew->name; knew++) { | 3516 | for (; knew->name; knew++) { |
3478 | struct snd_kcontrol *kctl; | 3517 | struct snd_kcontrol *kctl; |
3518 | if (knew->iface == -1) /* skip this codec private value */ | ||
3519 | continue; | ||
3479 | kctl = snd_ctl_new1(knew, codec); | 3520 | kctl = snd_ctl_new1(knew, codec); |
3480 | if (!kctl) | 3521 | if (!kctl) |
3481 | return -ENOMEM; | 3522 | return -ENOMEM; |
@@ -3496,6 +3537,32 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) | |||
3496 | } | 3537 | } |
3497 | EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls); | 3538 | EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls); |
3498 | 3539 | ||
3540 | /** | ||
3541 | * snd_hda_add_nids - assign nids to controls from the array | ||
3542 | * @codec: the HDA codec | ||
3543 | * @kctl: struct snd_kcontrol | ||
3544 | * @index: index to kctl | ||
3545 | * @nids: the array of hda_nid_t | ||
3546 | * @size: count of hda_nid_t items | ||
3547 | * | ||
3548 | * This helper function assigns NIDs in the given array to a control element. | ||
3549 | * | ||
3550 | * Returns 0 if successful, or a negative error code. | ||
3551 | */ | ||
3552 | int snd_hda_add_nids(struct hda_codec *codec, struct snd_kcontrol *kctl, | ||
3553 | unsigned int index, hda_nid_t *nids, unsigned int size) | ||
3554 | { | ||
3555 | int err; | ||
3556 | |||
3557 | for ( ; size > 0; size--, nids++) { | ||
3558 | err = snd_hda_add_nid(codec, kctl, index, *nids); | ||
3559 | if (err < 0) | ||
3560 | return err; | ||
3561 | } | ||
3562 | return 0; | ||
3563 | } | ||
3564 | EXPORT_SYMBOL_HDA(snd_hda_add_nids); | ||
3565 | |||
3499 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 3566 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
3500 | static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | 3567 | static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, |
3501 | unsigned int power_state); | 3568 | unsigned int power_state); |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 1d541b7f5547..0d08ad5bd898 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -789,6 +789,7 @@ struct hda_codec { | |||
789 | u32 *wcaps; | 789 | u32 *wcaps; |
790 | 790 | ||
791 | struct snd_array mixers; /* list of assigned mixer elements */ | 791 | struct snd_array mixers; /* list of assigned mixer elements */ |
792 | struct snd_array nids; /* list of mapped mixer elements */ | ||
792 | 793 | ||
793 | struct hda_cache_rec amp_cache; /* cache for amp access */ | 794 | struct hda_cache_rec amp_cache; /* cache for amp access */ |
794 | struct hda_cache_rec cmd_cache; /* cache for other commands */ | 795 | struct hda_cache_rec cmd_cache; /* cache for other commands */ |
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 092c6a7c2ff3..5ea21285ee1f 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -861,7 +861,8 @@ static int build_input_controls(struct hda_codec *codec) | |||
861 | } | 861 | } |
862 | 862 | ||
863 | /* create input MUX if multiple sources are available */ | 863 | /* create input MUX if multiple sources are available */ |
864 | err = snd_hda_ctl_add(codec, 0, snd_ctl_new1(&cap_sel, codec)); | 864 | err = snd_hda_ctl_add(codec, spec->adc_node->nid, |
865 | snd_ctl_new1(&cap_sel, codec)); | ||
865 | if (err < 0) | 866 | if (err < 0) |
866 | return err; | 867 | return err; |
867 | 868 | ||
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 5778ae882b83..d505d052972e 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -31,6 +31,7 @@ | |||
31 | * in snd_hda_ctl_add(), so that this value won't appear in the outside. | 31 | * in snd_hda_ctl_add(), so that this value won't appear in the outside. |
32 | */ | 32 | */ |
33 | #define HDA_SUBDEV_NID_FLAG (1U << 31) | 33 | #define HDA_SUBDEV_NID_FLAG (1U << 31) |
34 | #define HDA_SUBDEV_AMP_FLAG (1U << 30) | ||
34 | 35 | ||
35 | /* | 36 | /* |
36 | * for mixer controls | 37 | * for mixer controls |
@@ -42,7 +43,7 @@ | |||
42 | /* mono volume with index (index=0,1,...) (channel=1,2) */ | 43 | /* mono volume with index (index=0,1,...) (channel=1,2) */ |
43 | #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ | 44 | #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ |
44 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ | 45 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ |
45 | .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \ | 46 | .subdevice = HDA_SUBDEV_AMP_FLAG, \ |
46 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | 47 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ |
47 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | 48 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
48 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ | 49 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ |
@@ -63,7 +64,7 @@ | |||
63 | /* mono mute switch with index (index=0,1,...) (channel=1,2) */ | 64 | /* mono mute switch with index (index=0,1,...) (channel=1,2) */ |
64 | #define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ | 65 | #define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ |
65 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ | 66 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ |
66 | .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \ | 67 | .subdevice = HDA_SUBDEV_AMP_FLAG, \ |
67 | .info = snd_hda_mixer_amp_switch_info, \ | 68 | .info = snd_hda_mixer_amp_switch_info, \ |
68 | .get = snd_hda_mixer_amp_switch_get, \ | 69 | .get = snd_hda_mixer_amp_switch_get, \ |
69 | .put = snd_hda_mixer_amp_switch_put, \ | 70 | .put = snd_hda_mixer_amp_switch_put, \ |
@@ -81,7 +82,7 @@ | |||
81 | /* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */ | 82 | /* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */ |
82 | #define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ | 83 | #define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ |
83 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ | 84 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ |
84 | .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \ | 85 | .subdevice = HDA_SUBDEV_AMP_FLAG, \ |
85 | .info = snd_hda_mixer_amp_switch_info, \ | 86 | .info = snd_hda_mixer_amp_switch_info, \ |
86 | .get = snd_hda_mixer_amp_switch_get, \ | 87 | .get = snd_hda_mixer_amp_switch_get, \ |
87 | .put = snd_hda_mixer_amp_switch_put_beep, \ | 88 | .put = snd_hda_mixer_amp_switch_put_beep, \ |
@@ -342,6 +343,8 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, | |||
342 | const struct snd_pci_quirk *tbl); | 343 | const struct snd_pci_quirk *tbl); |
343 | int snd_hda_add_new_ctls(struct hda_codec *codec, | 344 | int snd_hda_add_new_ctls(struct hda_codec *codec, |
344 | struct snd_kcontrol_new *knew); | 345 | struct snd_kcontrol_new *knew); |
346 | int snd_hda_add_nids(struct hda_codec *codec, struct snd_kcontrol *kctl, | ||
347 | unsigned int index, hda_nid_t *nids, unsigned int size); | ||
345 | 348 | ||
346 | /* | 349 | /* |
347 | * unsolicited event handler | 350 | * unsolicited event handler |
@@ -464,13 +467,20 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid); | |||
464 | u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); | 467 | u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); |
465 | int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); | 468 | int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); |
466 | 469 | ||
470 | /* flags for hda_nid_item */ | ||
471 | #define HDA_NID_ITEM_AMP (1<<0) | ||
472 | |||
467 | struct hda_nid_item { | 473 | struct hda_nid_item { |
468 | struct snd_kcontrol *kctl; | 474 | struct snd_kcontrol *kctl; |
475 | unsigned int index; | ||
469 | hda_nid_t nid; | 476 | hda_nid_t nid; |
477 | unsigned short flags; | ||
470 | }; | 478 | }; |
471 | 479 | ||
472 | int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, | 480 | int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, |
473 | struct snd_kcontrol *kctl); | 481 | struct snd_kcontrol *kctl); |
482 | int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl, | ||
483 | unsigned int index, hda_nid_t nid); | ||
474 | void snd_hda_ctls_clear(struct hda_codec *codec); | 484 | void snd_hda_ctls_clear(struct hda_codec *codec); |
475 | 485 | ||
476 | /* | 486 | /* |
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index c9afc04adac8..f97d35de66c4 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c | |||
@@ -61,18 +61,29 @@ static const char *get_wid_type_name(unsigned int wid_value) | |||
61 | return "UNKNOWN Widget"; | 61 | return "UNKNOWN Widget"; |
62 | } | 62 | } |
63 | 63 | ||
64 | static void print_nid_mixers(struct snd_info_buffer *buffer, | 64 | static void print_nid_array(struct snd_info_buffer *buffer, |
65 | struct hda_codec *codec, hda_nid_t nid) | 65 | struct hda_codec *codec, hda_nid_t nid, |
66 | struct snd_array *array) | ||
66 | { | 67 | { |
67 | int i; | 68 | int i; |
68 | struct hda_nid_item *items = codec->mixers.list; | 69 | struct hda_nid_item *items = array->list, *item; |
69 | struct snd_kcontrol *kctl; | 70 | struct snd_kcontrol *kctl; |
70 | for (i = 0; i < codec->mixers.used; i++) { | 71 | for (i = 0; i < array->used; i++) { |
71 | if (items[i].nid == nid) { | 72 | item = &items[i]; |
72 | kctl = items[i].kctl; | 73 | if (item->nid == nid) { |
74 | kctl = item->kctl; | ||
73 | snd_iprintf(buffer, | 75 | snd_iprintf(buffer, |
74 | " Control: name=\"%s\", index=%i, device=%i\n", | 76 | " Control: name=\"%s\", index=%i, device=%i\n", |
75 | kctl->id.name, kctl->id.index, kctl->id.device); | 77 | kctl->id.name, kctl->id.index + item->index, |
78 | kctl->id.device); | ||
79 | if (item->flags & HDA_NID_ITEM_AMP) | ||
80 | snd_iprintf(buffer, | ||
81 | " ControlAmp: chs=%lu, dir=%s, " | ||
82 | "idx=%lu, ofs=%lu\n", | ||
83 | get_amp_channels(kctl), | ||
84 | get_amp_direction(kctl) ? "Out" : "In", | ||
85 | get_amp_index(kctl), | ||
86 | get_amp_offset(kctl)); | ||
76 | } | 87 | } |
77 | } | 88 | } |
78 | } | 89 | } |
@@ -528,7 +539,8 @@ static void print_gpio(struct snd_info_buffer *buffer, | |||
528 | (data & (1<<i)) ? 1 : 0, | 539 | (data & (1<<i)) ? 1 : 0, |
529 | (unsol & (1<<i)) ? 1 : 0); | 540 | (unsol & (1<<i)) ? 1 : 0); |
530 | /* FIXME: add GPO and GPI pin information */ | 541 | /* FIXME: add GPO and GPI pin information */ |
531 | print_nid_mixers(buffer, codec, nid); | 542 | print_nid_array(buffer, codec, nid, &codec->mixers); |
543 | print_nid_array(buffer, codec, nid, &codec->nids); | ||
532 | } | 544 | } |
533 | 545 | ||
534 | static void print_codec_info(struct snd_info_entry *entry, | 546 | static void print_codec_info(struct snd_info_entry *entry, |
@@ -608,7 +620,8 @@ static void print_codec_info(struct snd_info_entry *entry, | |||
608 | snd_iprintf(buffer, " CP"); | 620 | snd_iprintf(buffer, " CP"); |
609 | snd_iprintf(buffer, "\n"); | 621 | snd_iprintf(buffer, "\n"); |
610 | 622 | ||
611 | print_nid_mixers(buffer, codec, nid); | 623 | print_nid_array(buffer, codec, nid, &codec->mixers); |
624 | print_nid_array(buffer, codec, nid, &codec->nids); | ||
612 | print_nid_pcms(buffer, codec, nid); | 625 | print_nid_pcms(buffer, codec, nid); |
613 | 626 | ||
614 | /* volume knob is a special widget that always have connection | 627 | /* volume knob is a special widget that always have connection |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 1a36137e13ec..92b72d4f3984 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -174,6 +174,7 @@ static struct snd_kcontrol_new ad_beep_mixer[] = { | |||
174 | static int ad198x_build_controls(struct hda_codec *codec) | 174 | static int ad198x_build_controls(struct hda_codec *codec) |
175 | { | 175 | { |
176 | struct ad198x_spec *spec = codec->spec; | 176 | struct ad198x_spec *spec = codec->spec; |
177 | struct snd_kcontrol *kctl; | ||
177 | unsigned int i; | 178 | unsigned int i; |
178 | int err; | 179 | int err; |
179 | 180 | ||
@@ -208,9 +209,7 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
208 | if (!kctl) | 209 | if (!kctl) |
209 | return -ENOMEM; | 210 | return -ENOMEM; |
210 | kctl->private_value = spec->beep_amp; | 211 | kctl->private_value = spec->beep_amp; |
211 | err = snd_hda_ctl_add(codec, | 212 | err = snd_hda_ctl_add(codec, 0, kctl); |
212 | get_amp_nid_(spec->beep_amp), | ||
213 | kctl); | ||
214 | if (err < 0) | 213 | if (err < 0) |
215 | return err; | 214 | return err; |
216 | } | 215 | } |
@@ -239,6 +238,28 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
239 | } | 238 | } |
240 | 239 | ||
241 | ad198x_free_kctls(codec); /* no longer needed */ | 240 | ad198x_free_kctls(codec); /* no longer needed */ |
241 | |||
242 | /* assign Capture Source enums to NID */ | ||
243 | kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); | ||
244 | if (!kctl) | ||
245 | kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); | ||
246 | for (i = 0; kctl && i < kctl->count; i++) { | ||
247 | err = snd_hda_add_nids(codec, kctl, i, spec->capsrc_nids, | ||
248 | spec->input_mux->num_items); | ||
249 | if (err < 0) | ||
250 | return err; | ||
251 | } | ||
252 | |||
253 | /* assign IEC958 enums to NID */ | ||
254 | kctl = snd_hda_find_mixer_ctl(codec, | ||
255 | SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source"); | ||
256 | if (kctl) { | ||
257 | err = snd_hda_add_nid(codec, kctl, 0, | ||
258 | spec->multiout.dig_out_nid); | ||
259 | if (err < 0) | ||
260 | return err; | ||
261 | } | ||
262 | |||
242 | return 0; | 263 | return 0; |
243 | } | 264 | } |
244 | 265 | ||
@@ -701,6 +722,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | |||
701 | { | 722 | { |
702 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 723 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
703 | .name = "External Amplifier", | 724 | .name = "External Amplifier", |
725 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, | ||
704 | .info = ad198x_eapd_info, | 726 | .info = ad198x_eapd_info, |
705 | .get = ad198x_eapd_get, | 727 | .get = ad198x_eapd_get, |
706 | .put = ad198x_eapd_put, | 728 | .put = ad198x_eapd_put, |
@@ -808,6 +830,7 @@ static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { | |||
808 | { | 830 | { |
809 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 831 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
810 | .name = "Master Playback Switch", | 832 | .name = "Master Playback Switch", |
833 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
811 | .info = snd_hda_mixer_amp_switch_info, | 834 | .info = snd_hda_mixer_amp_switch_info, |
812 | .get = snd_hda_mixer_amp_switch_get, | 835 | .get = snd_hda_mixer_amp_switch_get, |
813 | .put = ad1986a_hp_master_sw_put, | 836 | .put = ad1986a_hp_master_sw_put, |
@@ -1608,6 +1631,7 @@ static struct snd_kcontrol_new ad1981_hp_mixers[] = { | |||
1608 | HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), | 1631 | HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), |
1609 | { | 1632 | { |
1610 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1633 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1634 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x05, | ||
1611 | .name = "Master Playback Switch", | 1635 | .name = "Master Playback Switch", |
1612 | .info = ad198x_eapd_info, | 1636 | .info = ad198x_eapd_info, |
1613 | .get = ad198x_eapd_get, | 1637 | .get = ad198x_eapd_get, |
@@ -2129,6 +2153,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = { | |||
2129 | { | 2153 | { |
2130 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2154 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2131 | .name = "External Amplifier", | 2155 | .name = "External Amplifier", |
2156 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x12, | ||
2132 | .info = ad198x_eapd_info, | 2157 | .info = ad198x_eapd_info, |
2133 | .get = ad198x_eapd_get, | 2158 | .get = ad198x_eapd_get, |
2134 | .put = ad198x_eapd_put, | 2159 | .put = ad198x_eapd_put, |
@@ -2250,6 +2275,7 @@ static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = { | |||
2250 | { | 2275 | { |
2251 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2276 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2252 | .name = "IEC958 Playback Source", | 2277 | .name = "IEC958 Playback Source", |
2278 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, | ||
2253 | .info = ad1988_spdif_playback_source_info, | 2279 | .info = ad1988_spdif_playback_source_info, |
2254 | .get = ad1988_spdif_playback_source_get, | 2280 | .get = ad1988_spdif_playback_source_get, |
2255 | .put = ad1988_spdif_playback_source_put, | 2281 | .put = ad1988_spdif_playback_source_put, |
@@ -2582,7 +2608,7 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name, | |||
2582 | if (! knew->name) | 2608 | if (! knew->name) |
2583 | return -ENOMEM; | 2609 | return -ENOMEM; |
2584 | if (get_amp_nid_(val)) | 2610 | if (get_amp_nid_(val)) |
2585 | knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val); | 2611 | knew->subdevice = HDA_SUBDEV_AMP_FLAG; |
2586 | knew->private_value = val; | 2612 | knew->private_value = val; |
2587 | return 0; | 2613 | return 0; |
2588 | } | 2614 | } |
@@ -3736,6 +3762,7 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { | |||
3736 | { | 3762 | { |
3737 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 3763 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
3738 | .name = "Master Playback Switch", | 3764 | .name = "Master Playback Switch", |
3765 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
3739 | .info = snd_hda_mixer_amp_switch_info, | 3766 | .info = snd_hda_mixer_amp_switch_info, |
3740 | .get = snd_hda_mixer_amp_switch_get, | 3767 | .get = snd_hda_mixer_amp_switch_get, |
3741 | .put = ad1884a_mobile_master_sw_put, | 3768 | .put = ad1884a_mobile_master_sw_put, |
@@ -3764,6 +3791,7 @@ static struct snd_kcontrol_new ad1884a_mobile_mixers[] = { | |||
3764 | { | 3791 | { |
3765 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 3792 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
3766 | .name = "Master Playback Switch", | 3793 | .name = "Master Playback Switch", |
3794 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
3767 | .info = snd_hda_mixer_amp_switch_info, | 3795 | .info = snd_hda_mixer_amp_switch_info, |
3768 | .get = snd_hda_mixer_amp_switch_get, | 3796 | .get = snd_hda_mixer_amp_switch_get, |
3769 | .put = ad1884a_mobile_master_sw_put, | 3797 | .put = ad1884a_mobile_master_sw_put, |
@@ -4105,6 +4133,7 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { | |||
4105 | /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ | 4133 | /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ |
4106 | { | 4134 | { |
4107 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 4135 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
4136 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
4108 | .name = "Master Playback Switch", | 4137 | .name = "Master Playback Switch", |
4109 | .info = snd_hda_mixer_amp_switch_info, | 4138 | .info = snd_hda_mixer_amp_switch_info, |
4110 | .get = snd_hda_mixer_amp_switch_get, | 4139 | .get = snd_hda_mixer_amp_switch_get, |
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index fe0423c39598..093cfbb55e9e 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c | |||
@@ -501,7 +501,8 @@ static int add_mute(struct hda_codec *codec, const char *name, int index, | |||
501 | knew.private_value = pval; | 501 | knew.private_value = pval; |
502 | snprintf(tmp, sizeof(tmp), "%s %s Switch", name, dir_sfx[dir]); | 502 | snprintf(tmp, sizeof(tmp), "%s %s Switch", name, dir_sfx[dir]); |
503 | *kctlp = snd_ctl_new1(&knew, codec); | 503 | *kctlp = snd_ctl_new1(&knew, codec); |
504 | return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp); | 504 | (*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG; |
505 | return snd_hda_ctl_add(codec, 0, *kctlp); | ||
505 | } | 506 | } |
506 | 507 | ||
507 | static int add_volume(struct hda_codec *codec, const char *name, | 508 | static int add_volume(struct hda_codec *codec, const char *name, |
@@ -514,7 +515,8 @@ static int add_volume(struct hda_codec *codec, const char *name, | |||
514 | knew.private_value = pval; | 515 | knew.private_value = pval; |
515 | snprintf(tmp, sizeof(tmp), "%s %s Volume", name, dir_sfx[dir]); | 516 | snprintf(tmp, sizeof(tmp), "%s %s Volume", name, dir_sfx[dir]); |
516 | *kctlp = snd_ctl_new1(&knew, codec); | 517 | *kctlp = snd_ctl_new1(&knew, codec); |
517 | return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp); | 518 | (*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG; |
519 | return snd_hda_ctl_add(codec, 0, *kctlp); | ||
518 | } | 520 | } |
519 | 521 | ||
520 | static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac) | 522 | static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac) |
@@ -760,6 +762,10 @@ static int build_input(struct hda_codec *codec) | |||
760 | err = snd_hda_ctl_add(codec, 0, kctl); | 762 | err = snd_hda_ctl_add(codec, 0, kctl); |
761 | if (err < 0) | 763 | if (err < 0) |
762 | return err; | 764 | return err; |
765 | err = snd_hda_add_nids(codec, kctl, 0, spec->adc_nid, | ||
766 | spec->num_inputs); | ||
767 | if (err < 0) | ||
768 | return err; | ||
763 | } | 769 | } |
764 | 770 | ||
765 | if (spec->num_inputs > 1 && !spec->mic_detect) { | 771 | if (spec->num_inputs > 1 && !spec->mic_detect) { |
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index a45c1169762b..cc1c22370a60 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c | |||
@@ -315,7 +315,8 @@ static struct hda_verb cmi9880_allout_init[] = { | |||
315 | static int cmi9880_build_controls(struct hda_codec *codec) | 315 | static int cmi9880_build_controls(struct hda_codec *codec) |
316 | { | 316 | { |
317 | struct cmi_spec *spec = codec->spec; | 317 | struct cmi_spec *spec = codec->spec; |
318 | int err; | 318 | struct snd_kcontrol *kctl; |
319 | int i, err; | ||
319 | 320 | ||
320 | err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer); | 321 | err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer); |
321 | if (err < 0) | 322 | if (err < 0) |
@@ -340,6 +341,15 @@ static int cmi9880_build_controls(struct hda_codec *codec) | |||
340 | if (err < 0) | 341 | if (err < 0) |
341 | return err; | 342 | return err; |
342 | } | 343 | } |
344 | |||
345 | /* assign Capture Source enums to NID */ | ||
346 | kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); | ||
347 | for (i = 0; kctl && i < kctl->count; i++) { | ||
348 | err = snd_hda_add_nids(codec, kctl, i, spec->adc_nids, | ||
349 | spec->input_mux->num_items); | ||
350 | if (err < 0) | ||
351 | return err; | ||
352 | } | ||
343 | return 0; | 353 | return 0; |
344 | } | 354 | } |
345 | 355 | ||
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index c578c28f368e..947785f43b28 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -2187,6 +2187,7 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { | |||
2187 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | 2187 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | |
2188 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | 2188 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | |
2189 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, | 2189 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, |
2190 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
2190 | .info = snd_hda_mixer_amp_volume_info, | 2191 | .info = snd_hda_mixer_amp_volume_info, |
2191 | .get = snd_hda_mixer_amp_volume_get, | 2192 | .get = snd_hda_mixer_amp_volume_get, |
2192 | .put = snd_hda_mixer_amp_volume_put, | 2193 | .put = snd_hda_mixer_amp_volume_put, |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c7465053d6bb..aeb23ef6afe5 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -633,6 +633,7 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, | |||
633 | 633 | ||
634 | #define ALC_PIN_MODE(xname, nid, dir) \ | 634 | #define ALC_PIN_MODE(xname, nid, dir) \ |
635 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ | 635 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ |
636 | .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ | ||
636 | .info = alc_pin_mode_info, \ | 637 | .info = alc_pin_mode_info, \ |
637 | .get = alc_pin_mode_get, \ | 638 | .get = alc_pin_mode_get, \ |
638 | .put = alc_pin_mode_put, \ | 639 | .put = alc_pin_mode_put, \ |
@@ -684,6 +685,7 @@ static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, | |||
684 | } | 685 | } |
685 | #define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \ | 686 | #define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \ |
686 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ | 687 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ |
688 | .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ | ||
687 | .info = alc_gpio_data_info, \ | 689 | .info = alc_gpio_data_info, \ |
688 | .get = alc_gpio_data_get, \ | 690 | .get = alc_gpio_data_get, \ |
689 | .put = alc_gpio_data_put, \ | 691 | .put = alc_gpio_data_put, \ |
@@ -738,6 +740,7 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, | |||
738 | } | 740 | } |
739 | #define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \ | 741 | #define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \ |
740 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ | 742 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ |
743 | .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ | ||
741 | .info = alc_spdif_ctrl_info, \ | 744 | .info = alc_spdif_ctrl_info, \ |
742 | .get = alc_spdif_ctrl_get, \ | 745 | .get = alc_spdif_ctrl_get, \ |
743 | .put = alc_spdif_ctrl_put, \ | 746 | .put = alc_spdif_ctrl_put, \ |
@@ -791,6 +794,7 @@ static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol, | |||
791 | 794 | ||
792 | #define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \ | 795 | #define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \ |
793 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ | 796 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ |
797 | .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ | ||
794 | .info = alc_eapd_ctrl_info, \ | 798 | .info = alc_eapd_ctrl_info, \ |
795 | .get = alc_eapd_ctrl_get, \ | 799 | .get = alc_eapd_ctrl_get, \ |
796 | .put = alc_eapd_ctrl_put, \ | 800 | .put = alc_eapd_ctrl_put, \ |
@@ -2443,6 +2447,15 @@ static const char *alc_slave_sws[] = { | |||
2443 | * build control elements | 2447 | * build control elements |
2444 | */ | 2448 | */ |
2445 | 2449 | ||
2450 | #define NID_MAPPING (-1) | ||
2451 | |||
2452 | #define SUBDEV_SPEAKER_ (0 << 6) | ||
2453 | #define SUBDEV_HP_ (1 << 6) | ||
2454 | #define SUBDEV_LINE_ (2 << 6) | ||
2455 | #define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f)) | ||
2456 | #define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f)) | ||
2457 | #define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f)) | ||
2458 | |||
2446 | static void alc_free_kctls(struct hda_codec *codec); | 2459 | static void alc_free_kctls(struct hda_codec *codec); |
2447 | 2460 | ||
2448 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | 2461 | #ifdef CONFIG_SND_HDA_INPUT_BEEP |
@@ -2457,8 +2470,11 @@ static struct snd_kcontrol_new alc_beep_mixer[] = { | |||
2457 | static int alc_build_controls(struct hda_codec *codec) | 2470 | static int alc_build_controls(struct hda_codec *codec) |
2458 | { | 2471 | { |
2459 | struct alc_spec *spec = codec->spec; | 2472 | struct alc_spec *spec = codec->spec; |
2460 | int err; | 2473 | struct snd_kcontrol *kctl; |
2461 | int i; | 2474 | struct snd_kcontrol_new *knew; |
2475 | int i, j, err; | ||
2476 | unsigned int u; | ||
2477 | hda_nid_t nid; | ||
2462 | 2478 | ||
2463 | for (i = 0; i < spec->num_mixers; i++) { | 2479 | for (i = 0; i < spec->num_mixers; i++) { |
2464 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); | 2480 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); |
@@ -2499,8 +2515,7 @@ static int alc_build_controls(struct hda_codec *codec) | |||
2499 | if (!kctl) | 2515 | if (!kctl) |
2500 | return -ENOMEM; | 2516 | return -ENOMEM; |
2501 | kctl->private_value = spec->beep_amp; | 2517 | kctl->private_value = spec->beep_amp; |
2502 | err = snd_hda_ctl_add(codec, | 2518 | err = snd_hda_ctl_add(codec, 0, kctl); |
2503 | get_amp_nid_(spec->beep_amp), kctl); | ||
2504 | if (err < 0) | 2519 | if (err < 0) |
2505 | return err; | 2520 | return err; |
2506 | } | 2521 | } |
@@ -2527,6 +2542,73 @@ static int alc_build_controls(struct hda_codec *codec) | |||
2527 | } | 2542 | } |
2528 | 2543 | ||
2529 | alc_free_kctls(codec); /* no longer needed */ | 2544 | alc_free_kctls(codec); /* no longer needed */ |
2545 | |||
2546 | /* assign Capture Source enums to NID */ | ||
2547 | kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); | ||
2548 | if (!kctl) | ||
2549 | kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); | ||
2550 | for (i = 0; kctl && i < kctl->count; i++) { | ||
2551 | err = snd_hda_add_nids(codec, kctl, i, spec->capsrc_nids, | ||
2552 | spec->input_mux->num_items); | ||
2553 | if (err < 0) | ||
2554 | return err; | ||
2555 | } | ||
2556 | if (spec->cap_mixer) { | ||
2557 | const char *kname = kctl ? kctl->id.name : NULL; | ||
2558 | for (knew = spec->cap_mixer; knew->name; knew++) { | ||
2559 | if (kname && strcmp(knew->name, kname) == 0) | ||
2560 | continue; | ||
2561 | kctl = snd_hda_find_mixer_ctl(codec, knew->name); | ||
2562 | for (i = 0; kctl && i < kctl->count; i++) { | ||
2563 | err = snd_hda_add_nid(codec, kctl, i, | ||
2564 | spec->adc_nids[i]); | ||
2565 | if (err < 0) | ||
2566 | return err; | ||
2567 | } | ||
2568 | } | ||
2569 | } | ||
2570 | |||
2571 | /* other nid->control mapping */ | ||
2572 | for (i = 0; i < spec->num_mixers; i++) { | ||
2573 | for (knew = spec->mixers[i]; knew->name; knew++) { | ||
2574 | if (knew->iface != NID_MAPPING) | ||
2575 | continue; | ||
2576 | kctl = snd_hda_find_mixer_ctl(codec, knew->name); | ||
2577 | if (kctl == NULL) | ||
2578 | continue; | ||
2579 | u = knew->subdevice; | ||
2580 | for (j = 0; j < 4; j++, u >>= 8) { | ||
2581 | nid = u & 0x3f; | ||
2582 | if (nid == 0) | ||
2583 | continue; | ||
2584 | switch (u & 0xc0) { | ||
2585 | case SUBDEV_SPEAKER_: | ||
2586 | nid = spec->autocfg.speaker_pins[nid]; | ||
2587 | break; | ||
2588 | case SUBDEV_LINE_: | ||
2589 | nid = spec->autocfg.line_out_pins[nid]; | ||
2590 | break; | ||
2591 | case SUBDEV_HP_: | ||
2592 | nid = spec->autocfg.hp_pins[nid]; | ||
2593 | break; | ||
2594 | default: | ||
2595 | continue; | ||
2596 | } | ||
2597 | err = snd_hda_add_nid(codec, kctl, 0, nid); | ||
2598 | if (err < 0) | ||
2599 | return err; | ||
2600 | } | ||
2601 | u = knew->private_value; | ||
2602 | for (j = 0; j < 4; j++, u >>= 8) { | ||
2603 | nid = u & 0xff; | ||
2604 | if (nid == 0) | ||
2605 | continue; | ||
2606 | err = snd_hda_add_nid(codec, kctl, 0, nid); | ||
2607 | if (err < 0) | ||
2608 | return err; | ||
2609 | } | ||
2610 | } | ||
2611 | } | ||
2530 | return 0; | 2612 | return 0; |
2531 | } | 2613 | } |
2532 | 2614 | ||
@@ -3832,6 +3914,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, | |||
3832 | #define PIN_CTL_TEST(xname,nid) { \ | 3914 | #define PIN_CTL_TEST(xname,nid) { \ |
3833 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 3915 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
3834 | .name = xname, \ | 3916 | .name = xname, \ |
3917 | .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ | ||
3835 | .info = alc_test_pin_ctl_info, \ | 3918 | .info = alc_test_pin_ctl_info, \ |
3836 | .get = alc_test_pin_ctl_get, \ | 3919 | .get = alc_test_pin_ctl_get, \ |
3837 | .put = alc_test_pin_ctl_put, \ | 3920 | .put = alc_test_pin_ctl_put, \ |
@@ -3841,6 +3924,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, | |||
3841 | #define PIN_SRC_TEST(xname,nid) { \ | 3924 | #define PIN_SRC_TEST(xname,nid) { \ |
3842 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 3925 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
3843 | .name = xname, \ | 3926 | .name = xname, \ |
3927 | .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ | ||
3844 | .info = alc_test_pin_src_info, \ | 3928 | .info = alc_test_pin_src_info, \ |
3845 | .get = alc_test_pin_src_get, \ | 3929 | .get = alc_test_pin_src_get, \ |
3846 | .put = alc_test_pin_src_put, \ | 3930 | .put = alc_test_pin_src_put, \ |
@@ -4380,7 +4464,7 @@ static int add_control(struct alc_spec *spec, int type, const char *name, | |||
4380 | if (!knew->name) | 4464 | if (!knew->name) |
4381 | return -ENOMEM; | 4465 | return -ENOMEM; |
4382 | if (get_amp_nid_(val)) | 4466 | if (get_amp_nid_(val)) |
4383 | knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val); | 4467 | knew->subdevice = HDA_SUBDEV_AMP_FLAG; |
4384 | knew->private_value = val; | 4468 | knew->private_value = val; |
4385 | return 0; | 4469 | return 0; |
4386 | } | 4470 | } |
@@ -5131,6 +5215,7 @@ static struct snd_kcontrol_new alc260_hp_output_mixer[] = { | |||
5131 | { | 5215 | { |
5132 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 5216 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
5133 | .name = "Master Playback Switch", | 5217 | .name = "Master Playback Switch", |
5218 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, | ||
5134 | .info = snd_ctl_boolean_mono_info, | 5219 | .info = snd_ctl_boolean_mono_info, |
5135 | .get = alc260_hp_master_sw_get, | 5220 | .get = alc260_hp_master_sw_get, |
5136 | .put = alc260_hp_master_sw_put, | 5221 | .put = alc260_hp_master_sw_put, |
@@ -5169,6 +5254,7 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { | |||
5169 | { | 5254 | { |
5170 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 5255 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
5171 | .name = "Master Playback Switch", | 5256 | .name = "Master Playback Switch", |
5257 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, | ||
5172 | .info = snd_ctl_boolean_mono_info, | 5258 | .info = snd_ctl_boolean_mono_info, |
5173 | .get = alc260_hp_master_sw_get, | 5259 | .get = alc260_hp_master_sw_get, |
5174 | .put = alc260_hp_master_sw_put, | 5260 | .put = alc260_hp_master_sw_put, |
@@ -10248,8 +10334,14 @@ static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, | |||
10248 | .info = snd_ctl_boolean_mono_info, \ | 10334 | .info = snd_ctl_boolean_mono_info, \ |
10249 | .get = alc262_hp_master_sw_get, \ | 10335 | .get = alc262_hp_master_sw_get, \ |
10250 | .put = alc262_hp_master_sw_put, \ | 10336 | .put = alc262_hp_master_sw_put, \ |
10337 | }, \ | ||
10338 | { \ | ||
10339 | .iface = NID_MAPPING, \ | ||
10340 | .name = "Master Playback Switch", \ | ||
10341 | .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \ | ||
10251 | } | 10342 | } |
10252 | 10343 | ||
10344 | |||
10253 | static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { | 10345 | static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { |
10254 | ALC262_HP_MASTER_SWITCH, | 10346 | ALC262_HP_MASTER_SWITCH, |
10255 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 10347 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
@@ -10407,6 +10499,12 @@ static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol, | |||
10407 | .info = snd_ctl_boolean_mono_info, \ | 10499 | .info = snd_ctl_boolean_mono_info, \ |
10408 | .get = alc262_hippo_master_sw_get, \ | 10500 | .get = alc262_hippo_master_sw_get, \ |
10409 | .put = alc262_hippo_master_sw_put, \ | 10501 | .put = alc262_hippo_master_sw_put, \ |
10502 | }, \ | ||
10503 | { \ | ||
10504 | .iface = NID_MAPPING, \ | ||
10505 | .name = "Master Playback Switch", \ | ||
10506 | .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \ | ||
10507 | (SUBDEV_SPEAKER(0) << 16), \ | ||
10410 | } | 10508 | } |
10411 | 10509 | ||
10412 | static struct snd_kcontrol_new alc262_hippo_mixer[] = { | 10510 | static struct snd_kcontrol_new alc262_hippo_mixer[] = { |
@@ -10887,11 +10985,17 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { | |||
10887 | { | 10985 | { |
10888 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 10986 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
10889 | .name = "Master Playback Switch", | 10987 | .name = "Master Playback Switch", |
10988 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
10890 | .info = snd_hda_mixer_amp_switch_info, | 10989 | .info = snd_hda_mixer_amp_switch_info, |
10891 | .get = snd_hda_mixer_amp_switch_get, | 10990 | .get = snd_hda_mixer_amp_switch_get, |
10892 | .put = alc262_fujitsu_master_sw_put, | 10991 | .put = alc262_fujitsu_master_sw_put, |
10893 | .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), | 10992 | .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), |
10894 | }, | 10993 | }, |
10994 | { | ||
10995 | .iface = NID_MAPPING, | ||
10996 | .name = "Master Playback Switch", | ||
10997 | .private_value = 0x1b, | ||
10998 | }, | ||
10895 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | 10999 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), |
10896 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | 11000 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), |
10897 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | 11001 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), |
@@ -10922,6 +11026,7 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { | |||
10922 | { | 11026 | { |
10923 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 11027 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
10924 | .name = "Master Playback Switch", | 11028 | .name = "Master Playback Switch", |
11029 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
10925 | .info = snd_hda_mixer_amp_switch_info, | 11030 | .info = snd_hda_mixer_amp_switch_info, |
10926 | .get = snd_hda_mixer_amp_switch_get, | 11031 | .get = snd_hda_mixer_amp_switch_get, |
10927 | .put = alc262_lenovo_3000_master_sw_put, | 11032 | .put = alc262_lenovo_3000_master_sw_put, |
@@ -11076,6 +11181,11 @@ static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = { | |||
11076 | .get = alc_mux_enum_get, | 11181 | .get = alc_mux_enum_get, |
11077 | .put = alc262_ultra_mux_enum_put, | 11182 | .put = alc262_ultra_mux_enum_put, |
11078 | }, | 11183 | }, |
11184 | { | ||
11185 | .iface = NID_MAPPING, | ||
11186 | .name = "Capture Source", | ||
11187 | .private_value = 0x15, | ||
11188 | }, | ||
11079 | { } /* end */ | 11189 | { } /* end */ |
11080 | }; | 11190 | }; |
11081 | 11191 | ||
@@ -12094,6 +12204,7 @@ static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = { | |||
12094 | { | 12204 | { |
12095 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 12205 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
12096 | .name = "Master Playback Switch", | 12206 | .name = "Master Playback Switch", |
12207 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
12097 | .info = snd_hda_mixer_amp_switch_info, | 12208 | .info = snd_hda_mixer_amp_switch_info, |
12098 | .get = snd_hda_mixer_amp_switch_get, | 12209 | .get = snd_hda_mixer_amp_switch_get, |
12099 | .put = alc268_acer_master_sw_put, | 12210 | .put = alc268_acer_master_sw_put, |
@@ -12109,6 +12220,7 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = { | |||
12109 | { | 12220 | { |
12110 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 12221 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
12111 | .name = "Master Playback Switch", | 12222 | .name = "Master Playback Switch", |
12223 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
12112 | .info = snd_hda_mixer_amp_switch_info, | 12224 | .info = snd_hda_mixer_amp_switch_info, |
12113 | .get = snd_hda_mixer_amp_switch_get, | 12225 | .get = snd_hda_mixer_amp_switch_get, |
12114 | .put = alc268_acer_master_sw_put, | 12226 | .put = alc268_acer_master_sw_put, |
@@ -12126,6 +12238,7 @@ static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { | |||
12126 | { | 12238 | { |
12127 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 12239 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
12128 | .name = "Master Playback Switch", | 12240 | .name = "Master Playback Switch", |
12241 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
12129 | .info = snd_hda_mixer_amp_switch_info, | 12242 | .info = snd_hda_mixer_amp_switch_info, |
12130 | .get = snd_hda_mixer_amp_switch_get, | 12243 | .get = snd_hda_mixer_amp_switch_get, |
12131 | .put = alc268_acer_master_sw_put, | 12244 | .put = alc268_acer_master_sw_put, |
@@ -13078,6 +13191,7 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { | |||
13078 | { | 13191 | { |
13079 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 13192 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
13080 | .name = "Master Playback Switch", | 13193 | .name = "Master Playback Switch", |
13194 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
13081 | .info = snd_hda_mixer_amp_switch_info, | 13195 | .info = snd_hda_mixer_amp_switch_info, |
13082 | .get = snd_hda_mixer_amp_switch_get, | 13196 | .get = snd_hda_mixer_amp_switch_get, |
13083 | .put = alc268_acer_master_sw_put, | 13197 | .put = alc268_acer_master_sw_put, |
@@ -13098,6 +13212,7 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = { | |||
13098 | { | 13212 | { |
13099 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 13213 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
13100 | .name = "Master Playback Switch", | 13214 | .name = "Master Playback Switch", |
13215 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
13101 | .info = snd_hda_mixer_amp_switch_info, | 13216 | .info = snd_hda_mixer_amp_switch_info, |
13102 | .get = snd_hda_mixer_amp_switch_get, | 13217 | .get = snd_hda_mixer_amp_switch_get, |
13103 | .put = alc268_acer_master_sw_put, | 13218 | .put = alc268_acer_master_sw_put, |
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 43b436c5d01b..f419ee8d75f0 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c | |||
@@ -122,6 +122,7 @@ static int si3054_switch_put(struct snd_kcontrol *kcontrol, | |||
122 | #define SI3054_KCONTROL(kname,reg,mask) { \ | 122 | #define SI3054_KCONTROL(kname,reg,mask) { \ |
123 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 123 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
124 | .name = kname, \ | 124 | .name = kname, \ |
125 | .subdevice = HDA_SUBDEV_NID_FLAG | reg, \ | ||
125 | .info = si3054_switch_info, \ | 126 | .info = si3054_switch_info, \ |
126 | .get = si3054_switch_get, \ | 127 | .get = si3054_switch_get, \ |
127 | .put = si3054_switch_put, \ | 128 | .put = si3054_switch_put, \ |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index eeda7beeb57a..74d5d333ed6c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -2688,7 +2688,7 @@ static struct snd_kcontrol_new * | |||
2688 | stac_control_new(struct sigmatel_spec *spec, | 2688 | stac_control_new(struct sigmatel_spec *spec, |
2689 | struct snd_kcontrol_new *ktemp, | 2689 | struct snd_kcontrol_new *ktemp, |
2690 | const char *name, | 2690 | const char *name, |
2691 | hda_nid_t nid) | 2691 | unsigned int subdev) |
2692 | { | 2692 | { |
2693 | struct snd_kcontrol_new *knew; | 2693 | struct snd_kcontrol_new *knew; |
2694 | 2694 | ||
@@ -2704,8 +2704,7 @@ stac_control_new(struct sigmatel_spec *spec, | |||
2704 | spec->kctls.alloced--; | 2704 | spec->kctls.alloced--; |
2705 | return NULL; | 2705 | return NULL; |
2706 | } | 2706 | } |
2707 | if (nid) | 2707 | knew->subdevice = subdev; |
2708 | knew->subdevice = HDA_SUBDEV_NID_FLAG | nid; | ||
2709 | return knew; | 2708 | return knew; |
2710 | } | 2709 | } |
2711 | 2710 | ||
@@ -2715,7 +2714,7 @@ static int stac92xx_add_control_temp(struct sigmatel_spec *spec, | |||
2715 | unsigned long val) | 2714 | unsigned long val) |
2716 | { | 2715 | { |
2717 | struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name, | 2716 | struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name, |
2718 | get_amp_nid_(val)); | 2717 | HDA_SUBDEV_AMP_FLAG); |
2719 | if (!knew) | 2718 | if (!knew) |
2720 | return -ENOMEM; | 2719 | return -ENOMEM; |
2721 | knew->index = idx; | 2720 | knew->index = idx; |
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index b70e26ad263f..de4839e46762 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -54,6 +54,8 @@ | |||
54 | #include "hda_codec.h" | 54 | #include "hda_codec.h" |
55 | #include "hda_local.h" | 55 | #include "hda_local.h" |
56 | 56 | ||
57 | #define NID_MAPPING (-1) | ||
58 | |||
57 | /* amp values */ | 59 | /* amp values */ |
58 | #define AMP_VAL_IDX_SHIFT 19 | 60 | #define AMP_VAL_IDX_SHIFT 19 |
59 | #define AMP_VAL_IDX_MASK (0x0f<<19) | 61 | #define AMP_VAL_IDX_MASK (0x0f<<19) |
@@ -157,6 +159,19 @@ struct via_spec { | |||
157 | #endif | 159 | #endif |
158 | }; | 160 | }; |
159 | 161 | ||
162 | static struct via_spec * via_new_spec(struct hda_codec *codec) | ||
163 | { | ||
164 | struct via_spec *spec; | ||
165 | |||
166 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
167 | if (spec == NULL) | ||
168 | return NULL; | ||
169 | |||
170 | codec->spec = spec; | ||
171 | spec->codec = codec; | ||
172 | return spec; | ||
173 | } | ||
174 | |||
160 | static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) | 175 | static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) |
161 | { | 176 | { |
162 | u32 vendor_id = codec->vendor_id; | 177 | u32 vendor_id = codec->vendor_id; |
@@ -443,11 +458,27 @@ static int via_add_control(struct via_spec *spec, int type, const char *name, | |||
443 | if (!knew->name) | 458 | if (!knew->name) |
444 | return -ENOMEM; | 459 | return -ENOMEM; |
445 | if (get_amp_nid_(val)) | 460 | if (get_amp_nid_(val)) |
446 | knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val); | 461 | knew->subdevice = HDA_SUBDEV_AMP_FLAG; |
447 | knew->private_value = val; | 462 | knew->private_value = val; |
448 | return 0; | 463 | return 0; |
449 | } | 464 | } |
450 | 465 | ||
466 | static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec, | ||
467 | struct snd_kcontrol_new *tmpl) | ||
468 | { | ||
469 | struct snd_kcontrol_new *knew; | ||
470 | |||
471 | snd_array_init(&spec->kctls, sizeof(*knew), 32); | ||
472 | knew = snd_array_new(&spec->kctls); | ||
473 | if (!knew) | ||
474 | return NULL; | ||
475 | *knew = *tmpl; | ||
476 | knew->name = kstrdup(tmpl->name, GFP_KERNEL); | ||
477 | if (!knew->name) | ||
478 | return NULL; | ||
479 | return 0; | ||
480 | } | ||
481 | |||
451 | static void via_free_kctls(struct hda_codec *codec) | 482 | static void via_free_kctls(struct hda_codec *codec) |
452 | { | 483 | { |
453 | struct via_spec *spec = codec->spec; | 484 | struct via_spec *spec = codec->spec; |
@@ -1088,24 +1119,9 @@ static int via_independent_hp_get(struct snd_kcontrol *kcontrol, | |||
1088 | struct snd_ctl_elem_value *ucontrol) | 1119 | struct snd_ctl_elem_value *ucontrol) |
1089 | { | 1120 | { |
1090 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 1121 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
1091 | struct via_spec *spec = codec->spec; | 1122 | hda_nid_t nid = kcontrol->private_value; |
1092 | hda_nid_t nid; | ||
1093 | unsigned int pinsel; | 1123 | unsigned int pinsel; |
1094 | 1124 | ||
1095 | switch (spec->codec_type) { | ||
1096 | case VT1718S: | ||
1097 | nid = 0x34; | ||
1098 | break; | ||
1099 | case VT2002P: | ||
1100 | nid = 0x35; | ||
1101 | break; | ||
1102 | case VT1812: | ||
1103 | nid = 0x3d; | ||
1104 | break; | ||
1105 | default: | ||
1106 | nid = spec->autocfg.hp_pins[0]; | ||
1107 | break; | ||
1108 | } | ||
1109 | /* use !! to translate conn sel 2 for VT1718S */ | 1125 | /* use !! to translate conn sel 2 for VT1718S */ |
1110 | pinsel = !!snd_hda_codec_read(codec, nid, 0, | 1126 | pinsel = !!snd_hda_codec_read(codec, nid, 0, |
1111 | AC_VERB_GET_CONNECT_SEL, | 1127 | AC_VERB_GET_CONNECT_SEL, |
@@ -1127,29 +1143,24 @@ static void activate_ctl(struct hda_codec *codec, const char *name, int active) | |||
1127 | } | 1143 | } |
1128 | } | 1144 | } |
1129 | 1145 | ||
1146 | static hda_nid_t side_mute_channel(struct via_spec *spec) | ||
1147 | { | ||
1148 | switch (spec->codec_type) { | ||
1149 | case VT1708: return 0x1b; | ||
1150 | case VT1709_10CH: return 0x29; | ||
1151 | case VT1708B_8CH: /* fall thru */ | ||
1152 | case VT1708S: return 0x27; | ||
1153 | default: return 0; | ||
1154 | } | ||
1155 | } | ||
1156 | |||
1130 | static int update_side_mute_status(struct hda_codec *codec) | 1157 | static int update_side_mute_status(struct hda_codec *codec) |
1131 | { | 1158 | { |
1132 | /* mute side channel */ | 1159 | /* mute side channel */ |
1133 | struct via_spec *spec = codec->spec; | 1160 | struct via_spec *spec = codec->spec; |
1134 | unsigned int parm = spec->hp_independent_mode | 1161 | unsigned int parm = spec->hp_independent_mode |
1135 | ? AMP_OUT_MUTE : AMP_OUT_UNMUTE; | 1162 | ? AMP_OUT_MUTE : AMP_OUT_UNMUTE; |
1136 | hda_nid_t sw3; | 1163 | hda_nid_t sw3 = side_mute_channel(spec); |
1137 | |||
1138 | switch (spec->codec_type) { | ||
1139 | case VT1708: | ||
1140 | sw3 = 0x1b; | ||
1141 | break; | ||
1142 | case VT1709_10CH: | ||
1143 | sw3 = 0x29; | ||
1144 | break; | ||
1145 | case VT1708B_8CH: | ||
1146 | case VT1708S: | ||
1147 | sw3 = 0x27; | ||
1148 | break; | ||
1149 | default: | ||
1150 | sw3 = 0; | ||
1151 | break; | ||
1152 | } | ||
1153 | 1164 | ||
1154 | if (sw3) | 1165 | if (sw3) |
1155 | snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE, | 1166 | snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE, |
@@ -1162,28 +1173,11 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, | |||
1162 | { | 1173 | { |
1163 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 1174 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
1164 | struct via_spec *spec = codec->spec; | 1175 | struct via_spec *spec = codec->spec; |
1165 | hda_nid_t nid = spec->autocfg.hp_pins[0]; | 1176 | hda_nid_t nid = kcontrol->private_value; |
1166 | unsigned int pinsel = ucontrol->value.enumerated.item[0]; | 1177 | unsigned int pinsel = ucontrol->value.enumerated.item[0]; |
1167 | /* Get Independent Mode index of headphone pin widget */ | 1178 | /* Get Independent Mode index of headphone pin widget */ |
1168 | spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel | 1179 | spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel |
1169 | ? 1 : 0; | 1180 | ? 1 : 0; |
1170 | |||
1171 | switch (spec->codec_type) { | ||
1172 | case VT1718S: | ||
1173 | nid = 0x34; | ||
1174 | pinsel = pinsel ? 2 : 0; /* indep HP use AOW4 (index 2) */ | ||
1175 | spec->multiout.num_dacs = 4; | ||
1176 | break; | ||
1177 | case VT2002P: | ||
1178 | nid = 0x35; | ||
1179 | break; | ||
1180 | case VT1812: | ||
1181 | nid = 0x3d; | ||
1182 | break; | ||
1183 | default: | ||
1184 | nid = spec->autocfg.hp_pins[0]; | ||
1185 | break; | ||
1186 | } | ||
1187 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel); | 1181 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel); |
1188 | 1182 | ||
1189 | if (spec->multiout.hp_nid && spec->multiout.hp_nid | 1183 | if (spec->multiout.hp_nid && spec->multiout.hp_nid |
@@ -1207,18 +1201,55 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, | |||
1207 | return 0; | 1201 | return 0; |
1208 | } | 1202 | } |
1209 | 1203 | ||
1210 | static struct snd_kcontrol_new via_hp_mixer[] = { | 1204 | static struct snd_kcontrol_new via_hp_mixer[2] = { |
1211 | { | 1205 | { |
1212 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1206 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1213 | .name = "Independent HP", | 1207 | .name = "Independent HP", |
1214 | .count = 1, | ||
1215 | .info = via_independent_hp_info, | 1208 | .info = via_independent_hp_info, |
1216 | .get = via_independent_hp_get, | 1209 | .get = via_independent_hp_get, |
1217 | .put = via_independent_hp_put, | 1210 | .put = via_independent_hp_put, |
1218 | }, | 1211 | }, |
1219 | { } /* end */ | 1212 | { |
1213 | .iface = NID_MAPPING, | ||
1214 | .name = "Independent HP", | ||
1215 | }, | ||
1220 | }; | 1216 | }; |
1221 | 1217 | ||
1218 | static int via_hp_build(struct via_spec *spec) | ||
1219 | { | ||
1220 | struct snd_kcontrol_new *knew; | ||
1221 | hda_nid_t nid; | ||
1222 | |||
1223 | knew = via_clone_control(spec, &via_hp_mixer[0]); | ||
1224 | if (knew == NULL) | ||
1225 | return -ENOMEM; | ||
1226 | |||
1227 | switch (spec->codec_type) { | ||
1228 | case VT1718S: | ||
1229 | nid = 0x34; | ||
1230 | break; | ||
1231 | case VT2002P: | ||
1232 | nid = 0x35; | ||
1233 | break; | ||
1234 | case VT1812: | ||
1235 | nid = 0x3d; | ||
1236 | break; | ||
1237 | default: | ||
1238 | nid = spec->autocfg.hp_pins[0]; | ||
1239 | break; | ||
1240 | } | ||
1241 | |||
1242 | knew->subdevice = HDA_SUBDEV_NID_FLAG | nid; | ||
1243 | knew->private_value = nid; | ||
1244 | |||
1245 | knew = via_clone_control(spec, &via_hp_mixer[1]); | ||
1246 | if (knew == NULL) | ||
1247 | return -ENOMEM; | ||
1248 | knew->subdevice = side_mute_channel(spec); | ||
1249 | |||
1250 | return 0; | ||
1251 | } | ||
1252 | |||
1222 | static void notify_aa_path_ctls(struct hda_codec *codec) | 1253 | static void notify_aa_path_ctls(struct hda_codec *codec) |
1223 | { | 1254 | { |
1224 | int i; | 1255 | int i; |
@@ -1376,7 +1407,7 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, | |||
1376 | return 1; | 1407 | return 1; |
1377 | } | 1408 | } |
1378 | 1409 | ||
1379 | static struct snd_kcontrol_new via_smart51_mixer[] = { | 1410 | static struct snd_kcontrol_new via_smart51_mixer[2] = { |
1380 | { | 1411 | { |
1381 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1412 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1382 | .name = "Smart 5.1", | 1413 | .name = "Smart 5.1", |
@@ -1385,9 +1416,36 @@ static struct snd_kcontrol_new via_smart51_mixer[] = { | |||
1385 | .get = via_smart51_get, | 1416 | .get = via_smart51_get, |
1386 | .put = via_smart51_put, | 1417 | .put = via_smart51_put, |
1387 | }, | 1418 | }, |
1388 | {} /* end */ | 1419 | { |
1420 | .iface = NID_MAPPING, | ||
1421 | .name = "Smart 5.1", | ||
1422 | } | ||
1389 | }; | 1423 | }; |
1390 | 1424 | ||
1425 | static int via_smart51_build(struct via_spec *spec) | ||
1426 | { | ||
1427 | struct snd_kcontrol_new *knew; | ||
1428 | int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE }; | ||
1429 | hda_nid_t nid; | ||
1430 | int i; | ||
1431 | |||
1432 | knew = via_clone_control(spec, &via_smart51_mixer[0]); | ||
1433 | if (knew == NULL) | ||
1434 | return -ENOMEM; | ||
1435 | |||
1436 | for (i = 0; i < ARRAY_SIZE(index); i++) { | ||
1437 | nid = spec->autocfg.input_pins[index[i]]; | ||
1438 | if (nid) { | ||
1439 | knew = via_clone_control(spec, &via_smart51_mixer[1]); | ||
1440 | if (knew == NULL) | ||
1441 | return -ENOMEM; | ||
1442 | knew->subdevice = nid; | ||
1443 | } | ||
1444 | } | ||
1445 | |||
1446 | return 0; | ||
1447 | } | ||
1448 | |||
1391 | /* capture mixer elements */ | 1449 | /* capture mixer elements */ |
1392 | static struct snd_kcontrol_new vt1708_capture_mixer[] = { | 1450 | static struct snd_kcontrol_new vt1708_capture_mixer[] = { |
1393 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), | 1451 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), |
@@ -1819,8 +1877,9 @@ static struct hda_pcm_stream vt1708_pcm_digital_capture = { | |||
1819 | static int via_build_controls(struct hda_codec *codec) | 1877 | static int via_build_controls(struct hda_codec *codec) |
1820 | { | 1878 | { |
1821 | struct via_spec *spec = codec->spec; | 1879 | struct via_spec *spec = codec->spec; |
1822 | int err; | 1880 | struct snd_kcontrol *kctl; |
1823 | int i; | 1881 | struct snd_kcontrol_new *knew; |
1882 | int err, i; | ||
1824 | 1883 | ||
1825 | for (i = 0; i < spec->num_mixers; i++) { | 1884 | for (i = 0; i < spec->num_mixers; i++) { |
1826 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); | 1885 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); |
@@ -1845,6 +1904,28 @@ static int via_build_controls(struct hda_codec *codec) | |||
1845 | return err; | 1904 | return err; |
1846 | } | 1905 | } |
1847 | 1906 | ||
1907 | /* assign Capture Source enums to NID */ | ||
1908 | kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); | ||
1909 | for (i = 0; kctl && i < kctl->count; i++) { | ||
1910 | err = snd_hda_add_nids(codec, kctl, i, spec->mux_nids, | ||
1911 | spec->input_mux->num_items); | ||
1912 | if (err < 0) | ||
1913 | return err; | ||
1914 | } | ||
1915 | |||
1916 | /* other nid->control mapping */ | ||
1917 | for (i = 0; i < spec->num_mixers; i++) { | ||
1918 | for (knew = spec->mixers[i]; knew->name; knew++) { | ||
1919 | if (knew->iface != NID_MAPPING) | ||
1920 | continue; | ||
1921 | kctl = snd_hda_find_mixer_ctl(codec, knew->name); | ||
1922 | if (kctl == NULL) | ||
1923 | continue; | ||
1924 | err = snd_hda_add_nid(codec, kctl, 0, | ||
1925 | knew->subdevice); | ||
1926 | } | ||
1927 | } | ||
1928 | |||
1848 | /* init power states */ | 1929 | /* init power states */ |
1849 | set_jack_power_state(codec); | 1930 | set_jack_power_state(codec); |
1850 | analog_low_current_mode(codec, 1); | 1931 | analog_low_current_mode(codec, 1); |
@@ -2481,9 +2562,9 @@ static int vt1708_parse_auto_config(struct hda_codec *codec) | |||
2481 | spec->input_mux = &spec->private_imux[0]; | 2562 | spec->input_mux = &spec->private_imux[0]; |
2482 | 2563 | ||
2483 | if (spec->hp_mux) | 2564 | if (spec->hp_mux) |
2484 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 2565 | via_hp_build(spec); |
2485 | 2566 | ||
2486 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | 2567 | via_smart51_build(spec); |
2487 | return 1; | 2568 | return 1; |
2488 | } | 2569 | } |
2489 | 2570 | ||
@@ -2554,12 +2635,10 @@ static int patch_vt1708(struct hda_codec *codec) | |||
2554 | int err; | 2635 | int err; |
2555 | 2636 | ||
2556 | /* create a codec specific record */ | 2637 | /* create a codec specific record */ |
2557 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 2638 | spec = via_new_spec(codec); |
2558 | if (spec == NULL) | 2639 | if (spec == NULL) |
2559 | return -ENOMEM; | 2640 | return -ENOMEM; |
2560 | 2641 | ||
2561 | codec->spec = spec; | ||
2562 | |||
2563 | /* automatic parse from the BIOS config */ | 2642 | /* automatic parse from the BIOS config */ |
2564 | err = vt1708_parse_auto_config(codec); | 2643 | err = vt1708_parse_auto_config(codec); |
2565 | if (err < 0) { | 2644 | if (err < 0) { |
@@ -2597,7 +2676,6 @@ static int patch_vt1708(struct hda_codec *codec) | |||
2597 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 2676 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
2598 | spec->loopback.amplist = vt1708_loopbacks; | 2677 | spec->loopback.amplist = vt1708_loopbacks; |
2599 | #endif | 2678 | #endif |
2600 | spec->codec = codec; | ||
2601 | INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state); | 2679 | INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state); |
2602 | return 0; | 2680 | return 0; |
2603 | } | 2681 | } |
@@ -3010,9 +3088,9 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) | |||
3010 | spec->input_mux = &spec->private_imux[0]; | 3088 | spec->input_mux = &spec->private_imux[0]; |
3011 | 3089 | ||
3012 | if (spec->hp_mux) | 3090 | if (spec->hp_mux) |
3013 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 3091 | via_hp_build(spec); |
3014 | 3092 | ||
3015 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | 3093 | via_smart51_build(spec); |
3016 | return 1; | 3094 | return 1; |
3017 | } | 3095 | } |
3018 | 3096 | ||
@@ -3032,12 +3110,10 @@ static int patch_vt1709_10ch(struct hda_codec *codec) | |||
3032 | int err; | 3110 | int err; |
3033 | 3111 | ||
3034 | /* create a codec specific record */ | 3112 | /* create a codec specific record */ |
3035 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 3113 | spec = via_new_spec(codec); |
3036 | if (spec == NULL) | 3114 | if (spec == NULL) |
3037 | return -ENOMEM; | 3115 | return -ENOMEM; |
3038 | 3116 | ||
3039 | codec->spec = spec; | ||
3040 | |||
3041 | err = vt1709_parse_auto_config(codec); | 3117 | err = vt1709_parse_auto_config(codec); |
3042 | if (err < 0) { | 3118 | if (err < 0) { |
3043 | via_free(codec); | 3119 | via_free(codec); |
@@ -3126,12 +3202,10 @@ static int patch_vt1709_6ch(struct hda_codec *codec) | |||
3126 | int err; | 3202 | int err; |
3127 | 3203 | ||
3128 | /* create a codec specific record */ | 3204 | /* create a codec specific record */ |
3129 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 3205 | spec = via_new_spec(codec); |
3130 | if (spec == NULL) | 3206 | if (spec == NULL) |
3131 | return -ENOMEM; | 3207 | return -ENOMEM; |
3132 | 3208 | ||
3133 | codec->spec = spec; | ||
3134 | |||
3135 | err = vt1709_parse_auto_config(codec); | 3209 | err = vt1709_parse_auto_config(codec); |
3136 | if (err < 0) { | 3210 | if (err < 0) { |
3137 | via_free(codec); | 3211 | via_free(codec); |
@@ -3581,9 +3655,9 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec) | |||
3581 | spec->input_mux = &spec->private_imux[0]; | 3655 | spec->input_mux = &spec->private_imux[0]; |
3582 | 3656 | ||
3583 | if (spec->hp_mux) | 3657 | if (spec->hp_mux) |
3584 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 3658 | via_hp_build(spec); |
3585 | 3659 | ||
3586 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | 3660 | via_smart51_build(spec); |
3587 | return 1; | 3661 | return 1; |
3588 | } | 3662 | } |
3589 | 3663 | ||
@@ -3605,12 +3679,10 @@ static int patch_vt1708B_8ch(struct hda_codec *codec) | |||
3605 | if (get_codec_type(codec) == VT1708BCE) | 3679 | if (get_codec_type(codec) == VT1708BCE) |
3606 | return patch_vt1708S(codec); | 3680 | return patch_vt1708S(codec); |
3607 | /* create a codec specific record */ | 3681 | /* create a codec specific record */ |
3608 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 3682 | spec = via_new_spec(codec); |
3609 | if (spec == NULL) | 3683 | if (spec == NULL) |
3610 | return -ENOMEM; | 3684 | return -ENOMEM; |
3611 | 3685 | ||
3612 | codec->spec = spec; | ||
3613 | |||
3614 | /* automatic parse from the BIOS config */ | 3686 | /* automatic parse from the BIOS config */ |
3615 | err = vt1708B_parse_auto_config(codec); | 3687 | err = vt1708B_parse_auto_config(codec); |
3616 | if (err < 0) { | 3688 | if (err < 0) { |
@@ -3657,12 +3729,10 @@ static int patch_vt1708B_4ch(struct hda_codec *codec) | |||
3657 | int err; | 3729 | int err; |
3658 | 3730 | ||
3659 | /* create a codec specific record */ | 3731 | /* create a codec specific record */ |
3660 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 3732 | spec = via_new_spec(codec); |
3661 | if (spec == NULL) | 3733 | if (spec == NULL) |
3662 | return -ENOMEM; | 3734 | return -ENOMEM; |
3663 | 3735 | ||
3664 | codec->spec = spec; | ||
3665 | |||
3666 | /* automatic parse from the BIOS config */ | 3736 | /* automatic parse from the BIOS config */ |
3667 | err = vt1708B_parse_auto_config(codec); | 3737 | err = vt1708B_parse_auto_config(codec); |
3668 | if (err < 0) { | 3738 | if (err < 0) { |
@@ -4071,9 +4141,9 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) | |||
4071 | spec->input_mux = &spec->private_imux[0]; | 4141 | spec->input_mux = &spec->private_imux[0]; |
4072 | 4142 | ||
4073 | if (spec->hp_mux) | 4143 | if (spec->hp_mux) |
4074 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 4144 | via_hp_build(spec); |
4075 | 4145 | ||
4076 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | 4146 | via_smart51_build(spec); |
4077 | return 1; | 4147 | return 1; |
4078 | } | 4148 | } |
4079 | 4149 | ||
@@ -4103,12 +4173,10 @@ static int patch_vt1708S(struct hda_codec *codec) | |||
4103 | int err; | 4173 | int err; |
4104 | 4174 | ||
4105 | /* create a codec specific record */ | 4175 | /* create a codec specific record */ |
4106 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 4176 | spec = via_new_spec(codec); |
4107 | if (spec == NULL) | 4177 | if (spec == NULL) |
4108 | return -ENOMEM; | 4178 | return -ENOMEM; |
4109 | 4179 | ||
4110 | codec->spec = spec; | ||
4111 | |||
4112 | /* automatic parse from the BIOS config */ | 4180 | /* automatic parse from the BIOS config */ |
4113 | err = vt1708S_parse_auto_config(codec); | 4181 | err = vt1708S_parse_auto_config(codec); |
4114 | if (err < 0) { | 4182 | if (err < 0) { |
@@ -4443,7 +4511,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) | |||
4443 | spec->input_mux = &spec->private_imux[0]; | 4511 | spec->input_mux = &spec->private_imux[0]; |
4444 | 4512 | ||
4445 | if (spec->hp_mux) | 4513 | if (spec->hp_mux) |
4446 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 4514 | via_hp_build(spec); |
4447 | 4515 | ||
4448 | return 1; | 4516 | return 1; |
4449 | } | 4517 | } |
@@ -4464,12 +4532,10 @@ static int patch_vt1702(struct hda_codec *codec) | |||
4464 | int err; | 4532 | int err; |
4465 | 4533 | ||
4466 | /* create a codec specific record */ | 4534 | /* create a codec specific record */ |
4467 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 4535 | spec = via_new_spec(codec); |
4468 | if (spec == NULL) | 4536 | if (spec == NULL) |
4469 | return -ENOMEM; | 4537 | return -ENOMEM; |
4470 | 4538 | ||
4471 | codec->spec = spec; | ||
4472 | |||
4473 | /* automatic parse from the BIOS config */ | 4539 | /* automatic parse from the BIOS config */ |
4474 | err = vt1702_parse_auto_config(codec); | 4540 | err = vt1702_parse_auto_config(codec); |
4475 | if (err < 0) { | 4541 | if (err < 0) { |
@@ -4865,9 +4931,9 @@ static int vt1718S_parse_auto_config(struct hda_codec *codec) | |||
4865 | spec->input_mux = &spec->private_imux[0]; | 4931 | spec->input_mux = &spec->private_imux[0]; |
4866 | 4932 | ||
4867 | if (spec->hp_mux) | 4933 | if (spec->hp_mux) |
4868 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 4934 | via_hp_build(spec); |
4869 | 4935 | ||
4870 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | 4936 | via_smart51_build(spec); |
4871 | 4937 | ||
4872 | return 1; | 4938 | return 1; |
4873 | } | 4939 | } |
@@ -4888,12 +4954,10 @@ static int patch_vt1718S(struct hda_codec *codec) | |||
4888 | int err; | 4954 | int err; |
4889 | 4955 | ||
4890 | /* create a codec specific record */ | 4956 | /* create a codec specific record */ |
4891 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 4957 | spec = via_new_spec(codec); |
4892 | if (spec == NULL) | 4958 | if (spec == NULL) |
4893 | return -ENOMEM; | 4959 | return -ENOMEM; |
4894 | 4960 | ||
4895 | codec->spec = spec; | ||
4896 | |||
4897 | /* automatic parse from the BIOS config */ | 4961 | /* automatic parse from the BIOS config */ |
4898 | err = vt1718S_parse_auto_config(codec); | 4962 | err = vt1718S_parse_auto_config(codec); |
4899 | if (err < 0) { | 4963 | if (err < 0) { |
@@ -5014,6 +5078,7 @@ static struct snd_kcontrol_new vt1716s_dmic_mixer[] = { | |||
5014 | { | 5078 | { |
5015 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 5079 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
5016 | .name = "Digital Mic Capture Switch", | 5080 | .name = "Digital Mic Capture Switch", |
5081 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x26, | ||
5017 | .count = 1, | 5082 | .count = 1, |
5018 | .info = vt1716s_dmic_info, | 5083 | .info = vt1716s_dmic_info, |
5019 | .get = vt1716s_dmic_get, | 5084 | .get = vt1716s_dmic_get, |
@@ -5361,9 +5426,9 @@ static int vt1716S_parse_auto_config(struct hda_codec *codec) | |||
5361 | spec->input_mux = &spec->private_imux[0]; | 5426 | spec->input_mux = &spec->private_imux[0]; |
5362 | 5427 | ||
5363 | if (spec->hp_mux) | 5428 | if (spec->hp_mux) |
5364 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 5429 | via_hp_build(spec); |
5365 | 5430 | ||
5366 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | 5431 | via_smart51_build(spec); |
5367 | 5432 | ||
5368 | return 1; | 5433 | return 1; |
5369 | } | 5434 | } |
@@ -5384,12 +5449,10 @@ static int patch_vt1716S(struct hda_codec *codec) | |||
5384 | int err; | 5449 | int err; |
5385 | 5450 | ||
5386 | /* create a codec specific record */ | 5451 | /* create a codec specific record */ |
5387 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 5452 | spec = via_new_spec(codec); |
5388 | if (spec == NULL) | 5453 | if (spec == NULL) |
5389 | return -ENOMEM; | 5454 | return -ENOMEM; |
5390 | 5455 | ||
5391 | codec->spec = spec; | ||
5392 | |||
5393 | /* automatic parse from the BIOS config */ | 5456 | /* automatic parse from the BIOS config */ |
5394 | err = vt1716S_parse_auto_config(codec); | 5457 | err = vt1716S_parse_auto_config(codec); |
5395 | if (err < 0) { | 5458 | if (err < 0) { |
@@ -5719,7 +5782,7 @@ static int vt2002P_parse_auto_config(struct hda_codec *codec) | |||
5719 | spec->input_mux = &spec->private_imux[0]; | 5782 | spec->input_mux = &spec->private_imux[0]; |
5720 | 5783 | ||
5721 | if (spec->hp_mux) | 5784 | if (spec->hp_mux) |
5722 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 5785 | via_hp_build(spec); |
5723 | 5786 | ||
5724 | return 1; | 5787 | return 1; |
5725 | } | 5788 | } |
@@ -5741,12 +5804,10 @@ static int patch_vt2002P(struct hda_codec *codec) | |||
5741 | int err; | 5804 | int err; |
5742 | 5805 | ||
5743 | /* create a codec specific record */ | 5806 | /* create a codec specific record */ |
5744 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 5807 | spec = via_new_spec(codec); |
5745 | if (spec == NULL) | 5808 | if (spec == NULL) |
5746 | return -ENOMEM; | 5809 | return -ENOMEM; |
5747 | 5810 | ||
5748 | codec->spec = spec; | ||
5749 | |||
5750 | /* automatic parse from the BIOS config */ | 5811 | /* automatic parse from the BIOS config */ |
5751 | err = vt2002P_parse_auto_config(codec); | 5812 | err = vt2002P_parse_auto_config(codec); |
5752 | if (err < 0) { | 5813 | if (err < 0) { |
@@ -6070,7 +6131,7 @@ static int vt1812_parse_auto_config(struct hda_codec *codec) | |||
6070 | spec->input_mux = &spec->private_imux[0]; | 6131 | spec->input_mux = &spec->private_imux[0]; |
6071 | 6132 | ||
6072 | if (spec->hp_mux) | 6133 | if (spec->hp_mux) |
6073 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 6134 | via_hp_build(spec); |
6074 | 6135 | ||
6075 | return 1; | 6136 | return 1; |
6076 | } | 6137 | } |
@@ -6092,12 +6153,10 @@ static int patch_vt1812(struct hda_codec *codec) | |||
6092 | int err; | 6153 | int err; |
6093 | 6154 | ||
6094 | /* create a codec specific record */ | 6155 | /* create a codec specific record */ |
6095 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 6156 | spec = via_new_spec(codec); |
6096 | if (spec == NULL) | 6157 | if (spec == NULL) |
6097 | return -ENOMEM; | 6158 | return -ENOMEM; |
6098 | 6159 | ||
6099 | codec->spec = spec; | ||
6100 | |||
6101 | /* automatic parse from the BIOS config */ | 6160 | /* automatic parse from the BIOS config */ |
6102 | err = vt1812_parse_auto_config(codec); | 6161 | err = vt1812_parse_auto_config(codec); |
6103 | if (err < 0) { | 6162 | if (err < 0) { |