.. | .. |
---|
19 | 19 | #include <linux/workqueue.h> |
---|
20 | 20 | #include <linux/export.h> |
---|
21 | 21 | #include <linux/debugfs.h> |
---|
22 | | -#include <linux/dma-mapping.h> |
---|
23 | 22 | #include <sound/core.h> |
---|
24 | 23 | #include <sound/pcm.h> |
---|
25 | 24 | #include <sound/pcm_params.h> |
---|
26 | 25 | #include <sound/soc.h> |
---|
27 | 26 | #include <sound/soc-dpcm.h> |
---|
| 27 | +#include <sound/soc-link.h> |
---|
28 | 28 | #include <sound/initval.h> |
---|
| 29 | +#include <trace/hooks/sound.h> |
---|
29 | 30 | |
---|
30 | 31 | #define DPCM_MAX_BE_USERS 8 |
---|
31 | 32 | |
---|
32 | | -/* |
---|
33 | | - * ASoC no host IO hardware. |
---|
34 | | - * TODO: fine tune these values for all host less transfers. |
---|
35 | | - */ |
---|
36 | | -static const struct snd_pcm_hardware no_host_hardware = { |
---|
37 | | - .info = SNDRV_PCM_INFO_MMAP | |
---|
38 | | - SNDRV_PCM_INFO_MMAP_VALID | |
---|
39 | | - SNDRV_PCM_INFO_INTERLEAVED | |
---|
40 | | - SNDRV_PCM_INFO_PAUSE | |
---|
41 | | - SNDRV_PCM_INFO_RESUME, |
---|
42 | | - .formats = SNDRV_PCM_FMTBIT_S16_LE | |
---|
43 | | - SNDRV_PCM_FMTBIT_S32_LE, |
---|
44 | | - .period_bytes_min = PAGE_SIZE >> 2, |
---|
45 | | - .period_bytes_max = PAGE_SIZE >> 1, |
---|
46 | | - .periods_min = 2, |
---|
47 | | - .periods_max = 4, |
---|
48 | | - /* |
---|
49 | | - * Increase the max buffer bytes as PAGE_SIZE bytes is |
---|
50 | | - * not enough to encompass all the scenarios sent by |
---|
51 | | - * userspapce. |
---|
52 | | - */ |
---|
53 | | - .buffer_bytes_max = PAGE_SIZE * 4, |
---|
| 33 | +#ifdef CONFIG_DEBUG_FS |
---|
| 34 | +static const char *dpcm_state_string(enum snd_soc_dpcm_state state) |
---|
| 35 | +{ |
---|
| 36 | + switch (state) { |
---|
| 37 | + case SND_SOC_DPCM_STATE_NEW: |
---|
| 38 | + return "new"; |
---|
| 39 | + case SND_SOC_DPCM_STATE_OPEN: |
---|
| 40 | + return "open"; |
---|
| 41 | + case SND_SOC_DPCM_STATE_HW_PARAMS: |
---|
| 42 | + return "hw_params"; |
---|
| 43 | + case SND_SOC_DPCM_STATE_PREPARE: |
---|
| 44 | + return "prepare"; |
---|
| 45 | + case SND_SOC_DPCM_STATE_START: |
---|
| 46 | + return "start"; |
---|
| 47 | + case SND_SOC_DPCM_STATE_STOP: |
---|
| 48 | + return "stop"; |
---|
| 49 | + case SND_SOC_DPCM_STATE_SUSPEND: |
---|
| 50 | + return "suspend"; |
---|
| 51 | + case SND_SOC_DPCM_STATE_PAUSED: |
---|
| 52 | + return "paused"; |
---|
| 53 | + case SND_SOC_DPCM_STATE_HW_FREE: |
---|
| 54 | + return "hw_free"; |
---|
| 55 | + case SND_SOC_DPCM_STATE_CLOSE: |
---|
| 56 | + return "close"; |
---|
| 57 | + } |
---|
| 58 | + |
---|
| 59 | + return "unknown"; |
---|
| 60 | +} |
---|
| 61 | + |
---|
| 62 | +static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, |
---|
| 63 | + int stream, char *buf, size_t size) |
---|
| 64 | +{ |
---|
| 65 | + struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params; |
---|
| 66 | + struct snd_soc_dpcm *dpcm; |
---|
| 67 | + ssize_t offset = 0; |
---|
| 68 | + unsigned long flags; |
---|
| 69 | + |
---|
| 70 | + /* FE state */ |
---|
| 71 | + offset += scnprintf(buf + offset, size - offset, |
---|
| 72 | + "[%s - %s]\n", fe->dai_link->name, |
---|
| 73 | + stream ? "Capture" : "Playback"); |
---|
| 74 | + |
---|
| 75 | + offset += scnprintf(buf + offset, size - offset, "State: %s\n", |
---|
| 76 | + dpcm_state_string(fe->dpcm[stream].state)); |
---|
| 77 | + |
---|
| 78 | + if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) && |
---|
| 79 | + (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP)) |
---|
| 80 | + offset += scnprintf(buf + offset, size - offset, |
---|
| 81 | + "Hardware Params: " |
---|
| 82 | + "Format = %s, Channels = %d, Rate = %d\n", |
---|
| 83 | + snd_pcm_format_name(params_format(params)), |
---|
| 84 | + params_channels(params), |
---|
| 85 | + params_rate(params)); |
---|
| 86 | + |
---|
| 87 | + /* BEs state */ |
---|
| 88 | + offset += scnprintf(buf + offset, size - offset, "Backends:\n"); |
---|
| 89 | + |
---|
| 90 | + if (list_empty(&fe->dpcm[stream].be_clients)) { |
---|
| 91 | + offset += scnprintf(buf + offset, size - offset, |
---|
| 92 | + " No active DSP links\n"); |
---|
| 93 | + goto out; |
---|
| 94 | + } |
---|
| 95 | + |
---|
| 96 | + spin_lock_irqsave(&fe->card->dpcm_lock, flags); |
---|
| 97 | + for_each_dpcm_be(fe, stream, dpcm) { |
---|
| 98 | + struct snd_soc_pcm_runtime *be = dpcm->be; |
---|
| 99 | + params = &dpcm->hw_params; |
---|
| 100 | + |
---|
| 101 | + offset += scnprintf(buf + offset, size - offset, |
---|
| 102 | + "- %s\n", be->dai_link->name); |
---|
| 103 | + |
---|
| 104 | + offset += scnprintf(buf + offset, size - offset, |
---|
| 105 | + " State: %s\n", |
---|
| 106 | + dpcm_state_string(be->dpcm[stream].state)); |
---|
| 107 | + |
---|
| 108 | + if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) && |
---|
| 109 | + (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP)) |
---|
| 110 | + offset += scnprintf(buf + offset, size - offset, |
---|
| 111 | + " Hardware Params: " |
---|
| 112 | + "Format = %s, Channels = %d, Rate = %d\n", |
---|
| 113 | + snd_pcm_format_name(params_format(params)), |
---|
| 114 | + params_channels(params), |
---|
| 115 | + params_rate(params)); |
---|
| 116 | + } |
---|
| 117 | + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); |
---|
| 118 | +out: |
---|
| 119 | + return offset; |
---|
| 120 | +} |
---|
| 121 | + |
---|
| 122 | +static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf, |
---|
| 123 | + size_t count, loff_t *ppos) |
---|
| 124 | +{ |
---|
| 125 | + struct snd_soc_pcm_runtime *fe = file->private_data; |
---|
| 126 | + ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0; |
---|
| 127 | + int stream; |
---|
| 128 | + char *buf; |
---|
| 129 | + |
---|
| 130 | + if (fe->num_cpus > 1) { |
---|
| 131 | + dev_err(fe->dev, |
---|
| 132 | + "%s doesn't support Multi CPU yet\n", __func__); |
---|
| 133 | + return -EINVAL; |
---|
| 134 | + } |
---|
| 135 | + |
---|
| 136 | + buf = kmalloc(out_count, GFP_KERNEL); |
---|
| 137 | + if (!buf) |
---|
| 138 | + return -ENOMEM; |
---|
| 139 | + |
---|
| 140 | + for_each_pcm_streams(stream) |
---|
| 141 | + if (snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0), stream)) |
---|
| 142 | + offset += dpcm_show_state(fe, stream, |
---|
| 143 | + buf + offset, |
---|
| 144 | + out_count - offset); |
---|
| 145 | + |
---|
| 146 | + ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset); |
---|
| 147 | + |
---|
| 148 | + kfree(buf); |
---|
| 149 | + return ret; |
---|
| 150 | +} |
---|
| 151 | + |
---|
| 152 | +static const struct file_operations dpcm_state_fops = { |
---|
| 153 | + .open = simple_open, |
---|
| 154 | + .read = dpcm_state_read_file, |
---|
| 155 | + .llseek = default_llseek, |
---|
54 | 156 | }; |
---|
55 | 157 | |
---|
56 | | -/* |
---|
57 | | - * snd_soc_dai_stream_valid() - check if a DAI supports the given stream |
---|
58 | | - * |
---|
59 | | - * Returns true if the DAI supports the indicated stream type. |
---|
60 | | - */ |
---|
61 | | -static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream) |
---|
| 158 | +void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd) |
---|
62 | 159 | { |
---|
63 | | - struct snd_soc_pcm_stream *codec_stream; |
---|
| 160 | + if (!rtd->dai_link) |
---|
| 161 | + return; |
---|
64 | 162 | |
---|
65 | | - if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
66 | | - codec_stream = &dai->driver->playback; |
---|
67 | | - else |
---|
68 | | - codec_stream = &dai->driver->capture; |
---|
| 163 | + if (!rtd->dai_link->dynamic) |
---|
| 164 | + return; |
---|
69 | 165 | |
---|
70 | | - /* If the codec specifies any channels at all, it supports the stream */ |
---|
71 | | - return codec_stream->channels_min; |
---|
| 166 | + if (!rtd->card->debugfs_card_root) |
---|
| 167 | + return; |
---|
| 168 | + |
---|
| 169 | + rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name, |
---|
| 170 | + rtd->card->debugfs_card_root); |
---|
| 171 | + |
---|
| 172 | + debugfs_create_file("state", 0444, rtd->debugfs_dpcm_root, |
---|
| 173 | + rtd, &dpcm_state_fops); |
---|
72 | 174 | } |
---|
73 | 175 | |
---|
| 176 | +static void dpcm_create_debugfs_state(struct snd_soc_dpcm *dpcm, int stream) |
---|
| 177 | +{ |
---|
| 178 | + char *name; |
---|
| 179 | + |
---|
| 180 | + name = kasprintf(GFP_KERNEL, "%s:%s", dpcm->be->dai_link->name, |
---|
| 181 | + stream ? "capture" : "playback"); |
---|
| 182 | + if (name) { |
---|
| 183 | + dpcm->debugfs_state = debugfs_create_dir( |
---|
| 184 | + name, dpcm->fe->debugfs_dpcm_root); |
---|
| 185 | + debugfs_create_u32("state", 0644, dpcm->debugfs_state, |
---|
| 186 | + &dpcm->state); |
---|
| 187 | + kfree(name); |
---|
| 188 | + } |
---|
| 189 | +} |
---|
| 190 | + |
---|
| 191 | +static void dpcm_remove_debugfs_state(struct snd_soc_dpcm *dpcm) |
---|
| 192 | +{ |
---|
| 193 | + debugfs_remove_recursive(dpcm->debugfs_state); |
---|
| 194 | +} |
---|
| 195 | + |
---|
| 196 | +#else |
---|
| 197 | +static inline void dpcm_create_debugfs_state(struct snd_soc_dpcm *dpcm, |
---|
| 198 | + int stream) |
---|
| 199 | +{ |
---|
| 200 | +} |
---|
| 201 | + |
---|
| 202 | +static inline void dpcm_remove_debugfs_state(struct snd_soc_dpcm *dpcm) |
---|
| 203 | +{ |
---|
| 204 | +} |
---|
| 205 | +#endif |
---|
| 206 | + |
---|
74 | 207 | /** |
---|
75 | | - * snd_soc_runtime_activate() - Increment active count for PCM runtime components |
---|
| 208 | + * snd_soc_runtime_action() - Increment/Decrement active count for |
---|
| 209 | + * PCM runtime components |
---|
76 | 210 | * @rtd: ASoC PCM runtime that is activated |
---|
77 | 211 | * @stream: Direction of the PCM stream |
---|
| 212 | + * @action: Activate stream if 1. Deactivate if -1. |
---|
78 | 213 | * |
---|
79 | | - * Increments the active count for all the DAIs and components attached to a PCM |
---|
80 | | - * runtime. Should typically be called when a stream is opened. |
---|
| 214 | + * Increments/Decrements the active count for all the DAIs and components |
---|
| 215 | + * attached to a PCM runtime. |
---|
| 216 | + * Should typically be called when a stream is opened. |
---|
81 | 217 | * |
---|
82 | | - * Must be called with the rtd->pcm_mutex being held |
---|
| 218 | + * Must be called with the rtd->card->pcm_mutex being held |
---|
83 | 219 | */ |
---|
84 | | -void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) |
---|
| 220 | +void snd_soc_runtime_action(struct snd_soc_pcm_runtime *rtd, |
---|
| 221 | + int stream, int action) |
---|
85 | 222 | { |
---|
86 | | - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
---|
| 223 | + struct snd_soc_dai *dai; |
---|
87 | 224 | int i; |
---|
88 | 225 | |
---|
89 | | - lockdep_assert_held(&rtd->pcm_mutex); |
---|
| 226 | + lockdep_assert_held(&rtd->card->pcm_mutex); |
---|
90 | 227 | |
---|
91 | | - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
---|
92 | | - cpu_dai->playback_active++; |
---|
93 | | - for (i = 0; i < rtd->num_codecs; i++) |
---|
94 | | - rtd->codec_dais[i]->playback_active++; |
---|
95 | | - } else { |
---|
96 | | - cpu_dai->capture_active++; |
---|
97 | | - for (i = 0; i < rtd->num_codecs; i++) |
---|
98 | | - rtd->codec_dais[i]->capture_active++; |
---|
99 | | - } |
---|
100 | | - |
---|
101 | | - cpu_dai->active++; |
---|
102 | | - cpu_dai->component->active++; |
---|
103 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
104 | | - rtd->codec_dais[i]->active++; |
---|
105 | | - rtd->codec_dais[i]->component->active++; |
---|
106 | | - } |
---|
| 228 | + for_each_rtd_dais(rtd, i, dai) |
---|
| 229 | + snd_soc_dai_action(dai, stream, action); |
---|
107 | 230 | } |
---|
108 | | - |
---|
109 | | -/** |
---|
110 | | - * snd_soc_runtime_deactivate() - Decrement active count for PCM runtime components |
---|
111 | | - * @rtd: ASoC PCM runtime that is deactivated |
---|
112 | | - * @stream: Direction of the PCM stream |
---|
113 | | - * |
---|
114 | | - * Decrements the active count for all the DAIs and components attached to a PCM |
---|
115 | | - * runtime. Should typically be called when a stream is closed. |
---|
116 | | - * |
---|
117 | | - * Must be called with the rtd->pcm_mutex being held |
---|
118 | | - */ |
---|
119 | | -void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) |
---|
120 | | -{ |
---|
121 | | - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
---|
122 | | - int i; |
---|
123 | | - |
---|
124 | | - lockdep_assert_held(&rtd->pcm_mutex); |
---|
125 | | - |
---|
126 | | - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
---|
127 | | - cpu_dai->playback_active--; |
---|
128 | | - for (i = 0; i < rtd->num_codecs; i++) |
---|
129 | | - rtd->codec_dais[i]->playback_active--; |
---|
130 | | - } else { |
---|
131 | | - cpu_dai->capture_active--; |
---|
132 | | - for (i = 0; i < rtd->num_codecs; i++) |
---|
133 | | - rtd->codec_dais[i]->capture_active--; |
---|
134 | | - } |
---|
135 | | - |
---|
136 | | - cpu_dai->active--; |
---|
137 | | - cpu_dai->component->active--; |
---|
138 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
139 | | - rtd->codec_dais[i]->component->active--; |
---|
140 | | - rtd->codec_dais[i]->active--; |
---|
141 | | - } |
---|
142 | | -} |
---|
| 231 | +EXPORT_SYMBOL_GPL(snd_soc_runtime_action); |
---|
143 | 232 | |
---|
144 | 233 | /** |
---|
145 | 234 | * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay |
---|
.. | .. |
---|
152 | 241 | */ |
---|
153 | 242 | bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd) |
---|
154 | 243 | { |
---|
155 | | - struct snd_soc_rtdcom_list *rtdcom; |
---|
156 | 244 | struct snd_soc_component *component; |
---|
157 | 245 | bool ignore = true; |
---|
| 246 | + int i; |
---|
158 | 247 | |
---|
159 | 248 | if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time) |
---|
160 | 249 | return true; |
---|
161 | 250 | |
---|
162 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
163 | | - component = rtdcom->component; |
---|
164 | | - |
---|
| 251 | + for_each_rtd_components(rtd, i, component) |
---|
165 | 252 | ignore &= !component->driver->use_pmdown_time; |
---|
166 | | - } |
---|
167 | 253 | |
---|
168 | 254 | return ignore; |
---|
169 | 255 | } |
---|
.. | .. |
---|
179 | 265 | const struct snd_pcm_hardware *hw) |
---|
180 | 266 | { |
---|
181 | 267 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
182 | | - if (!runtime) |
---|
183 | | - return 0; |
---|
184 | 268 | runtime->hw.info = hw->info; |
---|
185 | 269 | runtime->hw.formats = hw->formats; |
---|
186 | 270 | runtime->hw.period_bytes_min = hw->period_bytes_min; |
---|
.. | .. |
---|
199 | 283 | { |
---|
200 | 284 | struct snd_soc_dpcm *dpcm; |
---|
201 | 285 | |
---|
202 | | - list_for_each_entry(dpcm, &fe->dpcm[dir].be_clients, list_be) { |
---|
| 286 | + for_each_dpcm_be(fe, dir, dpcm) { |
---|
203 | 287 | |
---|
204 | 288 | struct snd_soc_pcm_runtime *be = dpcm->be; |
---|
205 | 289 | |
---|
.. | .. |
---|
221 | 305 | static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, |
---|
222 | 306 | struct snd_soc_dai *soc_dai) |
---|
223 | 307 | { |
---|
224 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
| 308 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
225 | 309 | int ret; |
---|
226 | 310 | |
---|
227 | 311 | if (soc_dai->rate && (soc_dai->driver->symmetric_rates || |
---|
.. | .. |
---|
278 | 362 | static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, |
---|
279 | 363 | struct snd_pcm_hw_params *params) |
---|
280 | 364 | { |
---|
281 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
282 | | - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
---|
| 365 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
| 366 | + struct snd_soc_dai *dai; |
---|
| 367 | + struct snd_soc_dai *cpu_dai; |
---|
283 | 368 | unsigned int rate, channels, sample_bits, symmetry, i; |
---|
284 | 369 | |
---|
285 | 370 | rate = params_rate(params); |
---|
.. | .. |
---|
287 | 372 | sample_bits = snd_pcm_format_physical_width(params_format(params)); |
---|
288 | 373 | |
---|
289 | 374 | /* reject unmatched parameters when applying symmetry */ |
---|
290 | | - symmetry = cpu_dai->driver->symmetric_rates || |
---|
291 | | - rtd->dai_link->symmetric_rates; |
---|
| 375 | + symmetry = rtd->dai_link->symmetric_rates; |
---|
292 | 376 | |
---|
293 | | - for (i = 0; i < rtd->num_codecs; i++) |
---|
294 | | - symmetry |= rtd->codec_dais[i]->driver->symmetric_rates; |
---|
| 377 | + for_each_rtd_cpu_dais(rtd, i, dai) |
---|
| 378 | + symmetry |= dai->driver->symmetric_rates; |
---|
295 | 379 | |
---|
296 | | - if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) { |
---|
297 | | - dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n", |
---|
298 | | - cpu_dai->rate, rate); |
---|
299 | | - return -EINVAL; |
---|
| 380 | + if (symmetry) { |
---|
| 381 | + for_each_rtd_cpu_dais(rtd, i, cpu_dai) { |
---|
| 382 | + if (cpu_dai->rate && cpu_dai->rate != rate) { |
---|
| 383 | + dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n", |
---|
| 384 | + cpu_dai->rate, rate); |
---|
| 385 | + return -EINVAL; |
---|
| 386 | + } |
---|
| 387 | + } |
---|
300 | 388 | } |
---|
301 | 389 | |
---|
302 | | - symmetry = cpu_dai->driver->symmetric_channels || |
---|
303 | | - rtd->dai_link->symmetric_channels; |
---|
| 390 | + symmetry = rtd->dai_link->symmetric_channels; |
---|
304 | 391 | |
---|
305 | | - for (i = 0; i < rtd->num_codecs; i++) |
---|
306 | | - symmetry |= rtd->codec_dais[i]->driver->symmetric_channels; |
---|
| 392 | + for_each_rtd_dais(rtd, i, dai) |
---|
| 393 | + symmetry |= dai->driver->symmetric_channels; |
---|
307 | 394 | |
---|
308 | | - if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) { |
---|
309 | | - dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n", |
---|
310 | | - cpu_dai->channels, channels); |
---|
311 | | - return -EINVAL; |
---|
| 395 | + if (symmetry) { |
---|
| 396 | + for_each_rtd_cpu_dais(rtd, i, cpu_dai) { |
---|
| 397 | + if (cpu_dai->channels && |
---|
| 398 | + cpu_dai->channels != channels) { |
---|
| 399 | + dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n", |
---|
| 400 | + cpu_dai->channels, channels); |
---|
| 401 | + return -EINVAL; |
---|
| 402 | + } |
---|
| 403 | + } |
---|
312 | 404 | } |
---|
313 | 405 | |
---|
314 | | - symmetry = cpu_dai->driver->symmetric_samplebits || |
---|
315 | | - rtd->dai_link->symmetric_samplebits; |
---|
| 406 | + symmetry = rtd->dai_link->symmetric_samplebits; |
---|
316 | 407 | |
---|
317 | | - for (i = 0; i < rtd->num_codecs; i++) |
---|
318 | | - symmetry |= rtd->codec_dais[i]->driver->symmetric_samplebits; |
---|
| 408 | + for_each_rtd_dais(rtd, i, dai) |
---|
| 409 | + symmetry |= dai->driver->symmetric_samplebits; |
---|
319 | 410 | |
---|
320 | | - if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) { |
---|
321 | | - dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n", |
---|
322 | | - cpu_dai->sample_bits, sample_bits); |
---|
323 | | - return -EINVAL; |
---|
| 411 | + if (symmetry) { |
---|
| 412 | + for_each_rtd_cpu_dais(rtd, i, cpu_dai) { |
---|
| 413 | + if (cpu_dai->sample_bits && |
---|
| 414 | + cpu_dai->sample_bits != sample_bits) { |
---|
| 415 | + dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n", |
---|
| 416 | + cpu_dai->sample_bits, sample_bits); |
---|
| 417 | + return -EINVAL; |
---|
| 418 | + } |
---|
| 419 | + } |
---|
324 | 420 | } |
---|
325 | 421 | |
---|
326 | 422 | return 0; |
---|
.. | .. |
---|
328 | 424 | |
---|
329 | 425 | static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream) |
---|
330 | 426 | { |
---|
331 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
332 | | - struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver; |
---|
| 427 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
333 | 428 | struct snd_soc_dai_link *link = rtd->dai_link; |
---|
| 429 | + struct snd_soc_dai *dai; |
---|
334 | 430 | unsigned int symmetry, i; |
---|
335 | 431 | |
---|
336 | | - symmetry = cpu_driver->symmetric_rates || link->symmetric_rates || |
---|
337 | | - cpu_driver->symmetric_channels || link->symmetric_channels || |
---|
338 | | - cpu_driver->symmetric_samplebits || link->symmetric_samplebits; |
---|
| 432 | + symmetry = link->symmetric_rates || |
---|
| 433 | + link->symmetric_channels || |
---|
| 434 | + link->symmetric_samplebits; |
---|
339 | 435 | |
---|
340 | | - for (i = 0; i < rtd->num_codecs; i++) |
---|
| 436 | + for_each_rtd_dais(rtd, i, dai) |
---|
341 | 437 | symmetry = symmetry || |
---|
342 | | - rtd->codec_dais[i]->driver->symmetric_rates || |
---|
343 | | - rtd->codec_dais[i]->driver->symmetric_channels || |
---|
344 | | - rtd->codec_dais[i]->driver->symmetric_samplebits; |
---|
| 438 | + dai->driver->symmetric_rates || |
---|
| 439 | + dai->driver->symmetric_channels || |
---|
| 440 | + dai->driver->symmetric_samplebits; |
---|
345 | 441 | |
---|
346 | 442 | return symmetry; |
---|
347 | 443 | } |
---|
348 | 444 | |
---|
349 | 445 | static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits) |
---|
350 | 446 | { |
---|
351 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
| 447 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
352 | 448 | int ret; |
---|
353 | 449 | |
---|
354 | 450 | if (!bits) |
---|
.. | .. |
---|
362 | 458 | |
---|
363 | 459 | static void soc_pcm_apply_msb(struct snd_pcm_substream *substream) |
---|
364 | 460 | { |
---|
365 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
366 | | - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
---|
| 461 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
| 462 | + struct snd_soc_dai *cpu_dai; |
---|
367 | 463 | struct snd_soc_dai *codec_dai; |
---|
| 464 | + struct snd_soc_pcm_stream *pcm_codec, *pcm_cpu; |
---|
| 465 | + int stream = substream->stream; |
---|
368 | 466 | int i; |
---|
369 | | - unsigned int bits = 0, cpu_bits; |
---|
| 467 | + unsigned int bits = 0, cpu_bits = 0; |
---|
370 | 468 | |
---|
371 | | - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
---|
372 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
373 | | - codec_dai = rtd->codec_dais[i]; |
---|
374 | | - if (codec_dai->driver->playback.sig_bits == 0) { |
---|
375 | | - bits = 0; |
---|
376 | | - break; |
---|
377 | | - } |
---|
378 | | - bits = max(codec_dai->driver->playback.sig_bits, bits); |
---|
| 469 | + for_each_rtd_codec_dais(rtd, i, codec_dai) { |
---|
| 470 | + pcm_codec = snd_soc_dai_get_pcm_stream(codec_dai, stream); |
---|
| 471 | + |
---|
| 472 | + if (pcm_codec->sig_bits == 0) { |
---|
| 473 | + bits = 0; |
---|
| 474 | + break; |
---|
379 | 475 | } |
---|
380 | | - cpu_bits = cpu_dai->driver->playback.sig_bits; |
---|
381 | | - } else { |
---|
382 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
383 | | - codec_dai = rtd->codec_dais[i]; |
---|
384 | | - if (codec_dai->driver->capture.sig_bits == 0) { |
---|
385 | | - bits = 0; |
---|
386 | | - break; |
---|
387 | | - } |
---|
388 | | - bits = max(codec_dai->driver->capture.sig_bits, bits); |
---|
| 476 | + bits = max(pcm_codec->sig_bits, bits); |
---|
| 477 | + } |
---|
| 478 | + |
---|
| 479 | + for_each_rtd_cpu_dais(rtd, i, cpu_dai) { |
---|
| 480 | + pcm_cpu = snd_soc_dai_get_pcm_stream(cpu_dai, stream); |
---|
| 481 | + |
---|
| 482 | + if (pcm_cpu->sig_bits == 0) { |
---|
| 483 | + cpu_bits = 0; |
---|
| 484 | + break; |
---|
389 | 485 | } |
---|
390 | | - cpu_bits = cpu_dai->driver->capture.sig_bits; |
---|
| 486 | + cpu_bits = max(pcm_cpu->sig_bits, cpu_bits); |
---|
391 | 487 | } |
---|
392 | 488 | |
---|
393 | 489 | soc_pcm_set_msb(substream, bits); |
---|
394 | 490 | soc_pcm_set_msb(substream, cpu_bits); |
---|
395 | 491 | } |
---|
396 | 492 | |
---|
397 | | -static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream) |
---|
| 493 | +/** |
---|
| 494 | + * snd_soc_runtime_calc_hw() - Calculate hw limits for a PCM stream |
---|
| 495 | + * @rtd: ASoC PCM runtime |
---|
| 496 | + * @hw: PCM hardware parameters (output) |
---|
| 497 | + * @stream: Direction of the PCM stream |
---|
| 498 | + * |
---|
| 499 | + * Calculates the subset of stream parameters supported by all DAIs |
---|
| 500 | + * associated with the PCM stream. |
---|
| 501 | + */ |
---|
| 502 | +int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd, |
---|
| 503 | + struct snd_pcm_hardware *hw, int stream) |
---|
398 | 504 | { |
---|
399 | | - struct snd_pcm_runtime *runtime = substream->runtime; |
---|
400 | | - struct snd_pcm_hardware *hw = &runtime->hw; |
---|
401 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
402 | | - struct snd_soc_dai_driver *cpu_dai_drv = rtd->cpu_dai->driver; |
---|
403 | | - struct snd_soc_dai_driver *codec_dai_drv; |
---|
| 505 | + struct snd_soc_dai *codec_dai; |
---|
| 506 | + struct snd_soc_dai *cpu_dai; |
---|
404 | 507 | struct snd_soc_pcm_stream *codec_stream; |
---|
405 | 508 | struct snd_soc_pcm_stream *cpu_stream; |
---|
406 | 509 | unsigned int chan_min = 0, chan_max = UINT_MAX; |
---|
| 510 | + unsigned int cpu_chan_min = 0, cpu_chan_max = UINT_MAX; |
---|
407 | 511 | unsigned int rate_min = 0, rate_max = UINT_MAX; |
---|
408 | | - unsigned int rates = UINT_MAX; |
---|
| 512 | + unsigned int cpu_rate_min = 0, cpu_rate_max = UINT_MAX; |
---|
| 513 | + unsigned int rates = UINT_MAX, cpu_rates = UINT_MAX; |
---|
409 | 514 | u64 formats = ULLONG_MAX; |
---|
410 | 515 | int i; |
---|
411 | 516 | |
---|
412 | | - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
413 | | - cpu_stream = &cpu_dai_drv->playback; |
---|
414 | | - else |
---|
415 | | - cpu_stream = &cpu_dai_drv->capture; |
---|
| 517 | + /* first calculate min/max only for CPUs in the DAI link */ |
---|
| 518 | + for_each_rtd_cpu_dais(rtd, i, cpu_dai) { |
---|
416 | 519 | |
---|
417 | | - /* first calculate min/max only for CODECs in the DAI link */ |
---|
418 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
| 520 | + /* |
---|
| 521 | + * Skip CPUs which don't support the current stream type. |
---|
| 522 | + * Otherwise, since the rate, channel, and format values will |
---|
| 523 | + * zero in that case, we would have no usable settings left, |
---|
| 524 | + * causing the resulting setup to fail. |
---|
| 525 | + */ |
---|
| 526 | + if (!snd_soc_dai_stream_valid(cpu_dai, stream)) |
---|
| 527 | + continue; |
---|
| 528 | + |
---|
| 529 | + cpu_stream = snd_soc_dai_get_pcm_stream(cpu_dai, stream); |
---|
| 530 | + |
---|
| 531 | + cpu_chan_min = max(cpu_chan_min, cpu_stream->channels_min); |
---|
| 532 | + cpu_chan_max = min(cpu_chan_max, cpu_stream->channels_max); |
---|
| 533 | + cpu_rate_min = max(cpu_rate_min, cpu_stream->rate_min); |
---|
| 534 | + cpu_rate_max = min_not_zero(cpu_rate_max, cpu_stream->rate_max); |
---|
| 535 | + formats &= cpu_stream->formats; |
---|
| 536 | + cpu_rates = snd_pcm_rate_mask_intersect(cpu_stream->rates, |
---|
| 537 | + cpu_rates); |
---|
| 538 | + } |
---|
| 539 | + |
---|
| 540 | + /* second calculate min/max only for CODECs in the DAI link */ |
---|
| 541 | + for_each_rtd_codec_dais(rtd, i, codec_dai) { |
---|
419 | 542 | |
---|
420 | 543 | /* |
---|
421 | 544 | * Skip CODECs which don't support the current stream type. |
---|
422 | 545 | * Otherwise, since the rate, channel, and format values will |
---|
423 | 546 | * zero in that case, we would have no usable settings left, |
---|
424 | 547 | * causing the resulting setup to fail. |
---|
425 | | - * At least one CODEC should match, otherwise we should have |
---|
426 | | - * bailed out on a higher level, since there would be no |
---|
427 | | - * CODEC to support the transfer direction in that case. |
---|
428 | 548 | */ |
---|
429 | | - if (!snd_soc_dai_stream_valid(rtd->codec_dais[i], |
---|
430 | | - substream->stream)) |
---|
| 549 | + if (!snd_soc_dai_stream_valid(codec_dai, stream)) |
---|
431 | 550 | continue; |
---|
432 | 551 | |
---|
433 | | - codec_dai_drv = rtd->codec_dais[i]->driver; |
---|
434 | | - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
435 | | - codec_stream = &codec_dai_drv->playback; |
---|
436 | | - else |
---|
437 | | - codec_stream = &codec_dai_drv->capture; |
---|
| 552 | + codec_stream = snd_soc_dai_get_pcm_stream(codec_dai, stream); |
---|
| 553 | + |
---|
438 | 554 | chan_min = max(chan_min, codec_stream->channels_min); |
---|
439 | 555 | chan_max = min(chan_max, codec_stream->channels_max); |
---|
440 | 556 | rate_min = max(rate_min, codec_stream->rate_min); |
---|
.. | .. |
---|
443 | 559 | rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates); |
---|
444 | 560 | } |
---|
445 | 561 | |
---|
| 562 | + /* Verify both a valid CPU DAI and a valid CODEC DAI were found */ |
---|
| 563 | + if (!chan_min || !cpu_chan_min) |
---|
| 564 | + return -EINVAL; |
---|
| 565 | + |
---|
446 | 566 | /* |
---|
447 | 567 | * chan min/max cannot be enforced if there are multiple CODEC DAIs |
---|
448 | | - * connected to a single CPU DAI, use CPU DAI's directly and let |
---|
| 568 | + * connected to CPU DAI(s), use CPU DAI's directly and let |
---|
449 | 569 | * channel allocation be fixed up later |
---|
450 | 570 | */ |
---|
451 | 571 | if (rtd->num_codecs > 1) { |
---|
452 | | - chan_min = cpu_stream->channels_min; |
---|
453 | | - chan_max = cpu_stream->channels_max; |
---|
| 572 | + chan_min = cpu_chan_min; |
---|
| 573 | + chan_max = cpu_chan_max; |
---|
454 | 574 | } |
---|
455 | 575 | |
---|
456 | | - hw->channels_min = max(chan_min, cpu_stream->channels_min); |
---|
457 | | - hw->channels_max = min(chan_max, cpu_stream->channels_max); |
---|
458 | | - if (hw->formats) |
---|
459 | | - hw->formats &= formats & cpu_stream->formats; |
---|
460 | | - else |
---|
461 | | - hw->formats = formats & cpu_stream->formats; |
---|
462 | | - hw->rates = snd_pcm_rate_mask_intersect(rates, cpu_stream->rates); |
---|
| 576 | + /* finally find a intersection between CODECs and CPUs */ |
---|
| 577 | + hw->channels_min = max(chan_min, cpu_chan_min); |
---|
| 578 | + hw->channels_max = min(chan_max, cpu_chan_max); |
---|
| 579 | + hw->formats = formats; |
---|
| 580 | + hw->rates = snd_pcm_rate_mask_intersect(rates, cpu_rates); |
---|
463 | 581 | |
---|
464 | | - snd_pcm_limit_hw_rates(runtime); |
---|
| 582 | + snd_pcm_hw_limit_rates(hw); |
---|
465 | 583 | |
---|
466 | | - hw->rate_min = max(hw->rate_min, cpu_stream->rate_min); |
---|
| 584 | + hw->rate_min = max(hw->rate_min, cpu_rate_min); |
---|
467 | 585 | hw->rate_min = max(hw->rate_min, rate_min); |
---|
468 | | - hw->rate_max = min_not_zero(hw->rate_max, cpu_stream->rate_max); |
---|
| 586 | + hw->rate_max = min_not_zero(hw->rate_max, cpu_rate_max); |
---|
469 | 587 | hw->rate_max = min_not_zero(hw->rate_max, rate_max); |
---|
| 588 | + |
---|
| 589 | + return 0; |
---|
| 590 | +} |
---|
| 591 | +EXPORT_SYMBOL_GPL(snd_soc_runtime_calc_hw); |
---|
| 592 | + |
---|
| 593 | +static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream) |
---|
| 594 | +{ |
---|
| 595 | + struct snd_pcm_hardware *hw = &substream->runtime->hw; |
---|
| 596 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
| 597 | + u64 formats = hw->formats; |
---|
| 598 | + |
---|
| 599 | + /* |
---|
| 600 | + * At least one CPU and one CODEC should match. Otherwise, we should |
---|
| 601 | + * have bailed out on a higher level, since there would be no CPU or |
---|
| 602 | + * CODEC to support the transfer direction in that case. |
---|
| 603 | + */ |
---|
| 604 | + snd_soc_runtime_calc_hw(rtd, hw, substream->stream); |
---|
| 605 | + |
---|
| 606 | + if (formats) |
---|
| 607 | + hw->formats &= formats; |
---|
| 608 | +} |
---|
| 609 | + |
---|
| 610 | +static int soc_pcm_components_open(struct snd_pcm_substream *substream) |
---|
| 611 | +{ |
---|
| 612 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
| 613 | + struct snd_soc_component *component; |
---|
| 614 | + int i, ret = 0; |
---|
| 615 | + |
---|
| 616 | + for_each_rtd_components(rtd, i, component) { |
---|
| 617 | + ret = snd_soc_component_module_get_when_open(component, substream); |
---|
| 618 | + if (ret < 0) |
---|
| 619 | + break; |
---|
| 620 | + |
---|
| 621 | + ret = snd_soc_component_open(component, substream); |
---|
| 622 | + if (ret < 0) |
---|
| 623 | + break; |
---|
| 624 | + } |
---|
| 625 | + |
---|
| 626 | + return ret; |
---|
470 | 627 | } |
---|
471 | 628 | |
---|
472 | 629 | static int soc_pcm_components_close(struct snd_pcm_substream *substream, |
---|
473 | | - struct snd_soc_component *last) |
---|
| 630 | + int rollback) |
---|
474 | 631 | { |
---|
475 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
476 | | - struct snd_soc_rtdcom_list *rtdcom; |
---|
| 632 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
477 | 633 | struct snd_soc_component *component; |
---|
| 634 | + int i, r, ret = 0; |
---|
478 | 635 | |
---|
479 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
480 | | - component = rtdcom->component; |
---|
| 636 | + for_each_rtd_components(rtd, i, component) { |
---|
| 637 | + r = snd_soc_component_close(component, substream, rollback); |
---|
| 638 | + if (r < 0) |
---|
| 639 | + ret = r; /* use last ret */ |
---|
481 | 640 | |
---|
482 | | - if (component == last) |
---|
483 | | - break; |
---|
484 | | - |
---|
485 | | - if (!component->driver->ops || |
---|
486 | | - !component->driver->ops->close) |
---|
487 | | - continue; |
---|
488 | | - |
---|
489 | | - component->driver->ops->close(substream); |
---|
| 641 | + snd_soc_component_module_put_when_close(component, substream, rollback); |
---|
490 | 642 | } |
---|
491 | 643 | |
---|
| 644 | + return ret; |
---|
| 645 | +} |
---|
| 646 | + |
---|
| 647 | +static int soc_pcm_clean(struct snd_pcm_substream *substream, int rollback) |
---|
| 648 | +{ |
---|
| 649 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
| 650 | + struct snd_soc_component *component; |
---|
| 651 | + struct snd_soc_dai *dai; |
---|
| 652 | + int i; |
---|
| 653 | + |
---|
| 654 | + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); |
---|
| 655 | + |
---|
| 656 | + if (!rollback) |
---|
| 657 | + snd_soc_runtime_deactivate(rtd, substream->stream); |
---|
| 658 | + |
---|
| 659 | + for_each_rtd_dais(rtd, i, dai) |
---|
| 660 | + snd_soc_dai_shutdown(dai, substream, rollback); |
---|
| 661 | + |
---|
| 662 | + snd_soc_link_shutdown(substream, rollback); |
---|
| 663 | + |
---|
| 664 | + soc_pcm_components_close(substream, rollback); |
---|
| 665 | + |
---|
| 666 | + if (!rollback) |
---|
| 667 | + snd_soc_dapm_stream_stop(rtd, substream->stream); |
---|
| 668 | + |
---|
| 669 | + mutex_unlock(&rtd->card->pcm_mutex); |
---|
| 670 | + |
---|
| 671 | + snd_soc_pcm_component_pm_runtime_put(rtd, substream, rollback); |
---|
| 672 | + |
---|
| 673 | + for_each_rtd_components(rtd, i, component) |
---|
| 674 | + if (!snd_soc_component_active(component)) |
---|
| 675 | + pinctrl_pm_select_sleep_state(component->dev); |
---|
| 676 | + |
---|
492 | 677 | return 0; |
---|
| 678 | +} |
---|
| 679 | + |
---|
| 680 | +/* |
---|
| 681 | + * Called by ALSA when a PCM substream is closed. Private data can be |
---|
| 682 | + * freed here. The cpu DAI, codec DAI, machine and components are also |
---|
| 683 | + * shutdown. |
---|
| 684 | + */ |
---|
| 685 | +static int soc_pcm_close(struct snd_pcm_substream *substream) |
---|
| 686 | +{ |
---|
| 687 | + return soc_pcm_clean(substream, 0); |
---|
493 | 688 | } |
---|
494 | 689 | |
---|
495 | 690 | /* |
---|
.. | .. |
---|
499 | 694 | */ |
---|
500 | 695 | static int soc_pcm_open(struct snd_pcm_substream *substream) |
---|
501 | 696 | { |
---|
502 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
| 697 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
503 | 698 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
504 | 699 | struct snd_soc_component *component; |
---|
505 | | - struct snd_soc_rtdcom_list *rtdcom; |
---|
506 | | - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
---|
507 | | - struct snd_soc_dai *codec_dai; |
---|
| 700 | + struct snd_soc_dai *dai; |
---|
508 | 701 | const char *codec_dai_name = "multicodec"; |
---|
| 702 | + const char *cpu_dai_name = "multicpu"; |
---|
509 | 703 | int i, ret = 0; |
---|
510 | 704 | |
---|
511 | | - pinctrl_pm_select_default_state(cpu_dai->dev); |
---|
512 | | - for (i = 0; i < rtd->num_codecs; i++) |
---|
513 | | - pinctrl_pm_select_default_state(rtd->codec_dais[i]->dev); |
---|
| 705 | + for_each_rtd_components(rtd, i, component) |
---|
| 706 | + pinctrl_pm_select_default_state(component->dev); |
---|
514 | 707 | |
---|
515 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
516 | | - component = rtdcom->component; |
---|
| 708 | + ret = snd_soc_pcm_component_pm_runtime_get(rtd, substream); |
---|
| 709 | + if (ret < 0) |
---|
| 710 | + goto pm_err; |
---|
517 | 711 | |
---|
518 | | - pm_runtime_get_sync(component->dev); |
---|
519 | | - } |
---|
| 712 | + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); |
---|
520 | 713 | |
---|
521 | | - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
---|
| 714 | + ret = soc_pcm_components_open(substream); |
---|
| 715 | + if (ret < 0) |
---|
| 716 | + goto err; |
---|
522 | 717 | |
---|
523 | | - if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST) |
---|
524 | | - snd_soc_set_runtime_hwparams(substream, &no_host_hardware); |
---|
| 718 | + ret = snd_soc_link_startup(substream); |
---|
| 719 | + if (ret < 0) |
---|
| 720 | + goto err; |
---|
525 | 721 | |
---|
526 | 722 | /* startup the audio subsystem */ |
---|
527 | | - if (cpu_dai->driver->ops->startup) { |
---|
528 | | - ret = cpu_dai->driver->ops->startup(substream, cpu_dai); |
---|
529 | | - if (ret < 0) { |
---|
530 | | - dev_err(cpu_dai->dev, "ASoC: can't open interface" |
---|
531 | | - " %s: %d\n", cpu_dai->name, ret); |
---|
532 | | - goto out; |
---|
533 | | - } |
---|
534 | | - } |
---|
535 | | - |
---|
536 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
537 | | - component = rtdcom->component; |
---|
538 | | - |
---|
539 | | - if (!component->driver->ops || |
---|
540 | | - !component->driver->ops->open) |
---|
541 | | - continue; |
---|
542 | | - |
---|
543 | | - ret = component->driver->ops->open(substream); |
---|
544 | | - if (ret < 0) { |
---|
545 | | - dev_err(component->dev, |
---|
546 | | - "ASoC: can't open component %s: %d\n", |
---|
547 | | - component->name, ret); |
---|
548 | | - goto component_err; |
---|
549 | | - } |
---|
550 | | - } |
---|
551 | | - component = NULL; |
---|
552 | | - |
---|
553 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
554 | | - codec_dai = rtd->codec_dais[i]; |
---|
555 | | - if (codec_dai->driver->ops->startup) { |
---|
556 | | - ret = codec_dai->driver->ops->startup(substream, |
---|
557 | | - codec_dai); |
---|
558 | | - if (ret < 0) { |
---|
559 | | - dev_err(codec_dai->dev, |
---|
560 | | - "ASoC: can't open codec %s: %d\n", |
---|
561 | | - codec_dai->name, ret); |
---|
562 | | - goto codec_dai_err; |
---|
563 | | - } |
---|
564 | | - } |
---|
565 | | - |
---|
566 | | - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
567 | | - codec_dai->tx_mask = 0; |
---|
568 | | - else |
---|
569 | | - codec_dai->rx_mask = 0; |
---|
570 | | - } |
---|
571 | | - |
---|
572 | | - if (rtd->dai_link->ops->startup) { |
---|
573 | | - ret = rtd->dai_link->ops->startup(substream); |
---|
574 | | - if (ret < 0) { |
---|
575 | | - pr_err("ASoC: %s startup failed: %d\n", |
---|
576 | | - rtd->dai_link->name, ret); |
---|
577 | | - goto machine_err; |
---|
578 | | - } |
---|
| 723 | + for_each_rtd_dais(rtd, i, dai) { |
---|
| 724 | + ret = snd_soc_dai_startup(dai, substream); |
---|
| 725 | + if (ret < 0) |
---|
| 726 | + goto err; |
---|
579 | 727 | } |
---|
580 | 728 | |
---|
581 | 729 | /* Dynamic PCM DAI links compat checks use dynamic capabilities */ |
---|
.. | .. |
---|
586 | 734 | soc_pcm_init_runtime_hw(substream); |
---|
587 | 735 | |
---|
588 | 736 | if (rtd->num_codecs == 1) |
---|
589 | | - codec_dai_name = rtd->codec_dai->name; |
---|
| 737 | + codec_dai_name = asoc_rtd_to_codec(rtd, 0)->name; |
---|
| 738 | + |
---|
| 739 | + if (rtd->num_cpus == 1) |
---|
| 740 | + cpu_dai_name = asoc_rtd_to_cpu(rtd, 0)->name; |
---|
590 | 741 | |
---|
591 | 742 | if (soc_pcm_has_symmetry(substream)) |
---|
592 | 743 | runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; |
---|
.. | .. |
---|
594 | 745 | ret = -EINVAL; |
---|
595 | 746 | if (!runtime->hw.rates) { |
---|
596 | 747 | printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n", |
---|
597 | | - codec_dai_name, cpu_dai->name); |
---|
598 | | - goto config_err; |
---|
| 748 | + codec_dai_name, cpu_dai_name); |
---|
| 749 | + goto err; |
---|
599 | 750 | } |
---|
600 | 751 | if (!runtime->hw.formats) { |
---|
601 | 752 | printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n", |
---|
602 | | - codec_dai_name, cpu_dai->name); |
---|
603 | | - goto config_err; |
---|
| 753 | + codec_dai_name, cpu_dai_name); |
---|
| 754 | + goto err; |
---|
604 | 755 | } |
---|
605 | 756 | if (!runtime->hw.channels_min || !runtime->hw.channels_max || |
---|
606 | 757 | runtime->hw.channels_min > runtime->hw.channels_max) { |
---|
607 | 758 | printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n", |
---|
608 | | - codec_dai_name, cpu_dai->name); |
---|
609 | | - goto config_err; |
---|
| 759 | + codec_dai_name, cpu_dai_name); |
---|
| 760 | + goto err; |
---|
610 | 761 | } |
---|
611 | 762 | |
---|
612 | 763 | soc_pcm_apply_msb(substream); |
---|
613 | 764 | |
---|
614 | 765 | /* Symmetry only applies if we've already got an active stream. */ |
---|
615 | | - if (cpu_dai->active) { |
---|
616 | | - ret = soc_pcm_apply_symmetry(substream, cpu_dai); |
---|
617 | | - if (ret != 0) |
---|
618 | | - goto config_err; |
---|
619 | | - } |
---|
620 | | - |
---|
621 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
622 | | - if (rtd->codec_dais[i]->active) { |
---|
623 | | - ret = soc_pcm_apply_symmetry(substream, |
---|
624 | | - rtd->codec_dais[i]); |
---|
| 766 | + for_each_rtd_dais(rtd, i, dai) { |
---|
| 767 | + if (snd_soc_dai_active(dai)) { |
---|
| 768 | + ret = soc_pcm_apply_symmetry(substream, dai); |
---|
625 | 769 | if (ret != 0) |
---|
626 | | - goto config_err; |
---|
| 770 | + goto err; |
---|
627 | 771 | } |
---|
628 | 772 | } |
---|
629 | 773 | |
---|
630 | 774 | pr_debug("ASoC: %s <-> %s info:\n", |
---|
631 | | - codec_dai_name, cpu_dai->name); |
---|
| 775 | + codec_dai_name, cpu_dai_name); |
---|
632 | 776 | pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates); |
---|
633 | 777 | pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min, |
---|
634 | 778 | runtime->hw.channels_max); |
---|
635 | 779 | pr_debug("ASoC: min rate %d max rate %d\n", runtime->hw.rate_min, |
---|
636 | 780 | runtime->hw.rate_max); |
---|
637 | | - |
---|
638 | 781 | dynamic: |
---|
639 | | - |
---|
640 | 782 | snd_soc_runtime_activate(rtd, substream->stream); |
---|
641 | | - |
---|
642 | | - mutex_unlock(&rtd->pcm_mutex); |
---|
643 | | - return 0; |
---|
644 | | - |
---|
645 | | -config_err: |
---|
646 | | - if (rtd->dai_link->ops->shutdown) |
---|
647 | | - rtd->dai_link->ops->shutdown(substream); |
---|
648 | | - |
---|
649 | | -machine_err: |
---|
650 | | - i = rtd->num_codecs; |
---|
651 | | - |
---|
652 | | -codec_dai_err: |
---|
653 | | - while (--i >= 0) { |
---|
654 | | - codec_dai = rtd->codec_dais[i]; |
---|
655 | | - if (codec_dai->driver->ops->shutdown) |
---|
656 | | - codec_dai->driver->ops->shutdown(substream, codec_dai); |
---|
657 | | - } |
---|
658 | | - |
---|
659 | | -component_err: |
---|
660 | | - soc_pcm_components_close(substream, component); |
---|
661 | | - |
---|
662 | | - if (cpu_dai->driver->ops->shutdown) |
---|
663 | | - cpu_dai->driver->ops->shutdown(substream, cpu_dai); |
---|
664 | | -out: |
---|
665 | | - mutex_unlock(&rtd->pcm_mutex); |
---|
666 | | - |
---|
667 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
668 | | - component = rtdcom->component; |
---|
669 | | - |
---|
670 | | - pm_runtime_mark_last_busy(component->dev); |
---|
671 | | - pm_runtime_put_autosuspend(component->dev); |
---|
672 | | - } |
---|
673 | | - |
---|
674 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
675 | | - if (!rtd->codec_dais[i]->active) |
---|
676 | | - pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev); |
---|
677 | | - } |
---|
678 | | - if (!cpu_dai->active) |
---|
679 | | - pinctrl_pm_select_sleep_state(cpu_dai->dev); |
---|
| 783 | + ret = 0; |
---|
| 784 | +err: |
---|
| 785 | + mutex_unlock(&rtd->card->pcm_mutex); |
---|
| 786 | +pm_err: |
---|
| 787 | + if (ret < 0) |
---|
| 788 | + soc_pcm_clean(substream, 1); |
---|
680 | 789 | |
---|
681 | 790 | return ret; |
---|
682 | 791 | } |
---|
683 | 792 | |
---|
684 | | -/* |
---|
685 | | - * Power down the audio subsystem pmdown_time msecs after close is called. |
---|
686 | | - * This is to ensure there are no pops or clicks in between any music tracks |
---|
687 | | - * due to DAPM power cycling. |
---|
688 | | - */ |
---|
689 | | -static void close_delayed_work(struct work_struct *work) |
---|
| 793 | +static void codec2codec_close_delayed_work(struct snd_soc_pcm_runtime *rtd) |
---|
690 | 794 | { |
---|
691 | | - struct snd_soc_pcm_runtime *rtd = |
---|
692 | | - container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); |
---|
693 | | - struct snd_soc_dai *codec_dai = rtd->codec_dais[0]; |
---|
694 | | - |
---|
695 | | - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
---|
696 | | - |
---|
697 | | - dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n", |
---|
698 | | - codec_dai->driver->playback.stream_name, |
---|
699 | | - codec_dai->playback_active ? "active" : "inactive", |
---|
700 | | - rtd->pop_wait ? "yes" : "no"); |
---|
701 | | - |
---|
702 | | - /* are we waiting on this codec DAI stream */ |
---|
703 | | - if (rtd->pop_wait == 1) { |
---|
704 | | - rtd->pop_wait = 0; |
---|
705 | | - snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, |
---|
706 | | - SND_SOC_DAPM_STREAM_STOP); |
---|
707 | | - } |
---|
708 | | - |
---|
709 | | - mutex_unlock(&rtd->pcm_mutex); |
---|
710 | | -} |
---|
711 | | - |
---|
712 | | -/* |
---|
713 | | - * Called by ALSA when a PCM substream is closed. Private data can be |
---|
714 | | - * freed here. The cpu DAI, codec DAI, machine and components are also |
---|
715 | | - * shutdown. |
---|
716 | | - */ |
---|
717 | | -static int soc_pcm_close(struct snd_pcm_substream *substream) |
---|
718 | | -{ |
---|
719 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
720 | | - struct snd_soc_component *component; |
---|
721 | | - struct snd_soc_rtdcom_list *rtdcom; |
---|
722 | | - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
---|
723 | | - struct snd_soc_dai *codec_dai; |
---|
724 | | - int i; |
---|
725 | | - |
---|
726 | | - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
---|
727 | | - |
---|
728 | | - snd_soc_runtime_deactivate(rtd, substream->stream); |
---|
729 | | - |
---|
730 | | - /* clear the corresponding DAIs rate when inactive */ |
---|
731 | | - if (!cpu_dai->active) |
---|
732 | | - cpu_dai->rate = 0; |
---|
733 | | - |
---|
734 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
735 | | - codec_dai = rtd->codec_dais[i]; |
---|
736 | | - if (!codec_dai->active) |
---|
737 | | - codec_dai->rate = 0; |
---|
738 | | - } |
---|
739 | | - |
---|
740 | | - snd_soc_dai_digital_mute(cpu_dai, 1, substream->stream); |
---|
741 | | - |
---|
742 | | - if (cpu_dai->driver->ops->shutdown) |
---|
743 | | - cpu_dai->driver->ops->shutdown(substream, cpu_dai); |
---|
744 | | - |
---|
745 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
746 | | - codec_dai = rtd->codec_dais[i]; |
---|
747 | | - if (codec_dai->driver->ops->shutdown) |
---|
748 | | - codec_dai->driver->ops->shutdown(substream, codec_dai); |
---|
749 | | - } |
---|
750 | | - |
---|
751 | | - if (rtd->dai_link->ops->shutdown) |
---|
752 | | - rtd->dai_link->ops->shutdown(substream); |
---|
753 | | - |
---|
754 | | - soc_pcm_components_close(substream, NULL); |
---|
755 | | - |
---|
756 | | - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
---|
757 | | - if (snd_soc_runtime_ignore_pmdown_time(rtd)) { |
---|
758 | | - /* powered down playback stream now */ |
---|
759 | | - snd_soc_dapm_stream_event(rtd, |
---|
760 | | - SNDRV_PCM_STREAM_PLAYBACK, |
---|
761 | | - SND_SOC_DAPM_STREAM_STOP); |
---|
762 | | - } else { |
---|
763 | | - /* start delayed pop wq here for playback streams */ |
---|
764 | | - rtd->pop_wait = 1; |
---|
765 | | - queue_delayed_work(system_power_efficient_wq, |
---|
766 | | - &rtd->delayed_work, |
---|
767 | | - msecs_to_jiffies(rtd->pmdown_time)); |
---|
768 | | - } |
---|
769 | | - } else { |
---|
770 | | - /* capture streams can be powered down now */ |
---|
771 | | - snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, |
---|
772 | | - SND_SOC_DAPM_STREAM_STOP); |
---|
773 | | - } |
---|
774 | | - |
---|
775 | | - mutex_unlock(&rtd->pcm_mutex); |
---|
776 | | - |
---|
777 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
778 | | - component = rtdcom->component; |
---|
779 | | - |
---|
780 | | - pm_runtime_mark_last_busy(component->dev); |
---|
781 | | - pm_runtime_put_autosuspend(component->dev); |
---|
782 | | - } |
---|
783 | | - |
---|
784 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
785 | | - if (!rtd->codec_dais[i]->active) |
---|
786 | | - pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev); |
---|
787 | | - } |
---|
788 | | - if (!cpu_dai->active) |
---|
789 | | - pinctrl_pm_select_sleep_state(cpu_dai->dev); |
---|
790 | | - |
---|
791 | | - return 0; |
---|
| 795 | + /* |
---|
| 796 | + * Currently nothing to do for c2c links |
---|
| 797 | + * Since c2c links are internal nodes in the DAPM graph and |
---|
| 798 | + * don't interface with the outside world or application layer |
---|
| 799 | + * we don't have to do any special handling on close. |
---|
| 800 | + */ |
---|
792 | 801 | } |
---|
793 | 802 | |
---|
794 | 803 | /* |
---|
.. | .. |
---|
798 | 807 | */ |
---|
799 | 808 | static int soc_pcm_prepare(struct snd_pcm_substream *substream) |
---|
800 | 809 | { |
---|
801 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
802 | | - struct snd_soc_component *component; |
---|
803 | | - struct snd_soc_rtdcom_list *rtdcom; |
---|
804 | | - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
---|
805 | | - struct snd_soc_dai *codec_dai; |
---|
| 810 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
| 811 | + struct snd_soc_dai *dai; |
---|
806 | 812 | int i, ret = 0; |
---|
807 | 813 | |
---|
808 | | - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
---|
| 814 | + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); |
---|
809 | 815 | |
---|
810 | | - if (rtd->dai_link->ops->prepare) { |
---|
811 | | - ret = rtd->dai_link->ops->prepare(substream); |
---|
812 | | - if (ret < 0) { |
---|
813 | | - dev_err(rtd->card->dev, "ASoC: machine prepare error:" |
---|
814 | | - " %d\n", ret); |
---|
815 | | - goto out; |
---|
816 | | - } |
---|
817 | | - } |
---|
| 816 | + ret = snd_soc_link_prepare(substream); |
---|
| 817 | + if (ret < 0) |
---|
| 818 | + goto out; |
---|
818 | 819 | |
---|
819 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
820 | | - component = rtdcom->component; |
---|
| 820 | + ret = snd_soc_pcm_component_prepare(substream); |
---|
| 821 | + if (ret < 0) |
---|
| 822 | + goto out; |
---|
821 | 823 | |
---|
822 | | - if (!component->driver->ops || |
---|
823 | | - !component->driver->ops->prepare) |
---|
824 | | - continue; |
---|
825 | | - |
---|
826 | | - ret = component->driver->ops->prepare(substream); |
---|
827 | | - if (ret < 0) { |
---|
828 | | - dev_err(component->dev, |
---|
829 | | - "ASoC: platform prepare error: %d\n", ret); |
---|
830 | | - goto out; |
---|
831 | | - } |
---|
832 | | - } |
---|
833 | | - |
---|
834 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
835 | | - codec_dai = rtd->codec_dais[i]; |
---|
836 | | - if (codec_dai->driver->ops->prepare) { |
---|
837 | | - ret = codec_dai->driver->ops->prepare(substream, |
---|
838 | | - codec_dai); |
---|
839 | | - if (ret < 0) { |
---|
840 | | - dev_err(codec_dai->dev, |
---|
841 | | - "ASoC: codec DAI prepare error: %d\n", |
---|
842 | | - ret); |
---|
843 | | - goto out; |
---|
844 | | - } |
---|
845 | | - } |
---|
846 | | - } |
---|
847 | | - |
---|
848 | | - if (cpu_dai->driver->ops->prepare) { |
---|
849 | | - ret = cpu_dai->driver->ops->prepare(substream, cpu_dai); |
---|
850 | | - if (ret < 0) { |
---|
851 | | - dev_err(cpu_dai->dev, |
---|
852 | | - "ASoC: cpu DAI prepare error: %d\n", ret); |
---|
853 | | - goto out; |
---|
854 | | - } |
---|
| 824 | + ret = snd_soc_pcm_dai_prepare(substream); |
---|
| 825 | + if (ret < 0) { |
---|
| 826 | + dev_err(rtd->dev, "ASoC: DAI prepare error: %d\n", ret); |
---|
| 827 | + goto out; |
---|
855 | 828 | } |
---|
856 | 829 | |
---|
857 | 830 | /* cancel any delayed stream shutdown that is pending */ |
---|
.. | .. |
---|
864 | 837 | snd_soc_dapm_stream_event(rtd, substream->stream, |
---|
865 | 838 | SND_SOC_DAPM_STREAM_START); |
---|
866 | 839 | |
---|
867 | | - for (i = 0; i < rtd->num_codecs; i++) |
---|
868 | | - snd_soc_dai_digital_mute(rtd->codec_dais[i], 0, |
---|
869 | | - substream->stream); |
---|
870 | | - snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream); |
---|
| 840 | + for_each_rtd_dais(rtd, i, dai) |
---|
| 841 | + snd_soc_dai_digital_mute(dai, 0, substream->stream); |
---|
871 | 842 | |
---|
872 | 843 | out: |
---|
873 | | - mutex_unlock(&rtd->pcm_mutex); |
---|
| 844 | + mutex_unlock(&rtd->card->pcm_mutex); |
---|
874 | 845 | return ret; |
---|
875 | 846 | } |
---|
876 | 847 | |
---|
.. | .. |
---|
885 | 856 | interval->max = channels; |
---|
886 | 857 | } |
---|
887 | 858 | |
---|
888 | | -int soc_dai_hw_params(struct snd_pcm_substream *substream, |
---|
889 | | - struct snd_pcm_hw_params *params, |
---|
890 | | - struct snd_soc_dai *dai) |
---|
891 | | -{ |
---|
892 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
893 | | - int ret; |
---|
894 | | - |
---|
895 | | - /* perform any topology hw_params fixups before DAI */ |
---|
896 | | - if (rtd->dai_link->be_hw_params_fixup) { |
---|
897 | | - ret = rtd->dai_link->be_hw_params_fixup(rtd, params); |
---|
898 | | - if (ret < 0) { |
---|
899 | | - dev_err(rtd->dev, |
---|
900 | | - "ASoC: hw_params topology fixup failed %d\n", |
---|
901 | | - ret); |
---|
902 | | - return ret; |
---|
903 | | - } |
---|
904 | | - } |
---|
905 | | - |
---|
906 | | - if (dai->driver->ops->hw_params) { |
---|
907 | | - ret = dai->driver->ops->hw_params(substream, params, dai); |
---|
908 | | - if (ret < 0) { |
---|
909 | | - dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n", |
---|
910 | | - dai->name, ret); |
---|
911 | | - return ret; |
---|
912 | | - } |
---|
913 | | - } |
---|
914 | | - |
---|
915 | | - return 0; |
---|
916 | | -} |
---|
917 | | - |
---|
918 | | -static int soc_pcm_components_hw_free(struct snd_pcm_substream *substream, |
---|
919 | | - struct snd_soc_component *last) |
---|
920 | | -{ |
---|
921 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
922 | | - struct snd_soc_rtdcom_list *rtdcom; |
---|
923 | | - struct snd_soc_component *component; |
---|
924 | | - |
---|
925 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
926 | | - component = rtdcom->component; |
---|
927 | | - |
---|
928 | | - if (component == last) |
---|
929 | | - break; |
---|
930 | | - |
---|
931 | | - if (!component->driver->ops || |
---|
932 | | - !component->driver->ops->hw_free) |
---|
933 | | - continue; |
---|
934 | | - |
---|
935 | | - component->driver->ops->hw_free(substream); |
---|
936 | | - } |
---|
937 | | - |
---|
938 | | - return 0; |
---|
939 | | -} |
---|
940 | | - |
---|
941 | 859 | /* |
---|
942 | 860 | * Called by ALSA when the hardware params are set by application. This |
---|
943 | 861 | * function can also be called multiple times and can allocate buffers |
---|
.. | .. |
---|
946 | 864 | static int soc_pcm_hw_params(struct snd_pcm_substream *substream, |
---|
947 | 865 | struct snd_pcm_hw_params *params) |
---|
948 | 866 | { |
---|
949 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
| 867 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
950 | 868 | struct snd_soc_component *component; |
---|
951 | | - struct snd_soc_rtdcom_list *rtdcom; |
---|
952 | | - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
---|
| 869 | + struct snd_soc_dai *cpu_dai; |
---|
| 870 | + struct snd_soc_dai *codec_dai; |
---|
953 | 871 | int i, ret = 0; |
---|
954 | 872 | |
---|
955 | | - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
---|
| 873 | + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); |
---|
956 | 874 | |
---|
957 | | - /* perform any hw_params fixups */ |
---|
958 | | - if ((rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST) && |
---|
959 | | - rtd->dai_link->be_hw_params_fixup) { |
---|
960 | | - ret = rtd->dai_link->be_hw_params_fixup(rtd, |
---|
961 | | - params); |
---|
962 | | - if (ret < 0) |
---|
963 | | - dev_err(rtd->card->dev, "ASoC: fixup failed for %s\n", |
---|
964 | | - rtd->dai_link->name); |
---|
965 | | - } |
---|
| 875 | + ret = soc_pcm_params_symmetry(substream, params); |
---|
| 876 | + if (ret) |
---|
| 877 | + goto out; |
---|
966 | 878 | |
---|
967 | | - if (rtd->dai_link->ops->hw_params) { |
---|
968 | | - ret = rtd->dai_link->ops->hw_params(substream, params); |
---|
969 | | - if (ret < 0) { |
---|
970 | | - dev_err(rtd->card->dev, "ASoC: machine hw_params" |
---|
971 | | - " failed: %d\n", ret); |
---|
972 | | - goto out; |
---|
973 | | - } |
---|
974 | | - } |
---|
| 879 | + ret = snd_soc_link_hw_params(substream, params); |
---|
| 880 | + if (ret < 0) |
---|
| 881 | + goto out; |
---|
975 | 882 | |
---|
976 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
977 | | - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; |
---|
| 883 | + for_each_rtd_codec_dais(rtd, i, codec_dai) { |
---|
978 | 884 | struct snd_pcm_hw_params codec_params; |
---|
979 | 885 | |
---|
980 | 886 | /* |
---|
.. | .. |
---|
1008 | 914 | soc_pcm_codec_params_fixup(&codec_params, |
---|
1009 | 915 | codec_dai->rx_mask); |
---|
1010 | 916 | |
---|
1011 | | - ret = soc_dai_hw_params(substream, &codec_params, codec_dai); |
---|
| 917 | + ret = snd_soc_dai_hw_params(codec_dai, substream, |
---|
| 918 | + &codec_params); |
---|
1012 | 919 | if(ret < 0) |
---|
1013 | 920 | goto codec_err; |
---|
1014 | 921 | |
---|
.. | .. |
---|
1016 | 923 | codec_dai->channels = params_channels(&codec_params); |
---|
1017 | 924 | codec_dai->sample_bits = snd_pcm_format_physical_width( |
---|
1018 | 925 | params_format(&codec_params)); |
---|
| 926 | + |
---|
| 927 | + snd_soc_dapm_update_dai(substream, &codec_params, codec_dai); |
---|
1019 | 928 | } |
---|
1020 | 929 | |
---|
1021 | | - ret = soc_dai_hw_params(substream, params, cpu_dai); |
---|
1022 | | - if (ret < 0) |
---|
1023 | | - goto interface_err; |
---|
1024 | | - |
---|
1025 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
1026 | | - component = rtdcom->component; |
---|
1027 | | - |
---|
1028 | | - if (!component->driver->ops || |
---|
1029 | | - !component->driver->ops->hw_params) |
---|
| 930 | + for_each_rtd_cpu_dais(rtd, i, cpu_dai) { |
---|
| 931 | + /* |
---|
| 932 | + * Skip CPUs which don't support the current stream |
---|
| 933 | + * type. See soc_pcm_init_runtime_hw() for more details |
---|
| 934 | + */ |
---|
| 935 | + if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream)) |
---|
1030 | 936 | continue; |
---|
1031 | 937 | |
---|
1032 | | - ret = component->driver->ops->hw_params(substream, params); |
---|
1033 | | - if (ret < 0) { |
---|
1034 | | - dev_err(component->dev, |
---|
1035 | | - "ASoC: %s hw params failed: %d\n", |
---|
1036 | | - component->name, ret); |
---|
1037 | | - goto component_err; |
---|
1038 | | - } |
---|
| 938 | + ret = snd_soc_dai_hw_params(cpu_dai, substream, params); |
---|
| 939 | + if (ret < 0) |
---|
| 940 | + goto interface_err; |
---|
| 941 | + |
---|
| 942 | + /* store the parameters for each DAI */ |
---|
| 943 | + cpu_dai->rate = params_rate(params); |
---|
| 944 | + cpu_dai->channels = params_channels(params); |
---|
| 945 | + cpu_dai->sample_bits = |
---|
| 946 | + snd_pcm_format_physical_width(params_format(params)); |
---|
| 947 | + |
---|
| 948 | + snd_soc_dapm_update_dai(substream, params, cpu_dai); |
---|
1039 | 949 | } |
---|
1040 | | - component = NULL; |
---|
1041 | 950 | |
---|
1042 | | - /* store the parameters for each DAIs */ |
---|
1043 | | - cpu_dai->rate = params_rate(params); |
---|
1044 | | - cpu_dai->channels = params_channels(params); |
---|
1045 | | - cpu_dai->sample_bits = |
---|
1046 | | - snd_pcm_format_physical_width(params_format(params)); |
---|
1047 | | - |
---|
1048 | | - ret = soc_pcm_params_symmetry(substream, params); |
---|
1049 | | - if (ret) |
---|
| 951 | + ret = snd_soc_pcm_component_hw_params(substream, params, &component); |
---|
| 952 | + if (ret < 0) |
---|
1050 | 953 | goto component_err; |
---|
1051 | 954 | |
---|
1052 | | - /* malloc a page for hostless IO. |
---|
1053 | | - * FIXME: rework with alsa-lib changes so that this malloc is |
---|
1054 | | - * not required. |
---|
1055 | | - */ |
---|
1056 | | - if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST) { |
---|
1057 | | - substream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV; |
---|
1058 | | - substream->dma_buffer.dev.dev = rtd->dev; |
---|
1059 | | - substream->dma_buffer.dev.dev->coherent_dma_mask = |
---|
1060 | | - DMA_BIT_MASK(sizeof(dma_addr_t) * 8); |
---|
1061 | | - substream->dma_buffer.private_data = NULL; |
---|
1062 | | - |
---|
1063 | | - arch_setup_dma_ops(substream->dma_buffer.dev.dev, |
---|
1064 | | - 0, 0, NULL, 0); |
---|
1065 | | - ret = snd_pcm_lib_malloc_pages(substream, PAGE_SIZE); |
---|
1066 | | - if (ret < 0) |
---|
1067 | | - goto component_err; |
---|
1068 | | - } |
---|
1069 | 955 | out: |
---|
1070 | | - mutex_unlock(&rtd->pcm_mutex); |
---|
| 956 | + mutex_unlock(&rtd->card->pcm_mutex); |
---|
1071 | 957 | return ret; |
---|
1072 | 958 | |
---|
1073 | 959 | component_err: |
---|
1074 | | - soc_pcm_components_hw_free(substream, component); |
---|
| 960 | + snd_soc_pcm_component_hw_free(substream, component); |
---|
1075 | 961 | |
---|
1076 | | - if (cpu_dai->driver->ops->hw_free) |
---|
1077 | | - cpu_dai->driver->ops->hw_free(substream, cpu_dai); |
---|
| 962 | + i = rtd->num_cpus; |
---|
1078 | 963 | |
---|
1079 | 964 | interface_err: |
---|
| 965 | + for_each_rtd_cpu_dais_rollback(rtd, i, cpu_dai) { |
---|
| 966 | + if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream)) |
---|
| 967 | + continue; |
---|
| 968 | + |
---|
| 969 | + snd_soc_dai_hw_free(cpu_dai, substream); |
---|
| 970 | + cpu_dai->rate = 0; |
---|
| 971 | + } |
---|
| 972 | + |
---|
1080 | 973 | i = rtd->num_codecs; |
---|
1081 | 974 | |
---|
1082 | 975 | codec_err: |
---|
1083 | | - while (--i >= 0) { |
---|
1084 | | - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; |
---|
1085 | | - if (codec_dai->driver->ops->hw_free) |
---|
1086 | | - codec_dai->driver->ops->hw_free(substream, codec_dai); |
---|
| 976 | + for_each_rtd_codec_dais_rollback(rtd, i, codec_dai) { |
---|
| 977 | + if (!snd_soc_dai_stream_valid(codec_dai, substream->stream)) |
---|
| 978 | + continue; |
---|
| 979 | + |
---|
| 980 | + snd_soc_dai_hw_free(codec_dai, substream); |
---|
1087 | 981 | codec_dai->rate = 0; |
---|
1088 | 982 | } |
---|
1089 | 983 | |
---|
1090 | | - if (rtd->dai_link->ops->hw_free) |
---|
1091 | | - rtd->dai_link->ops->hw_free(substream); |
---|
| 984 | + snd_soc_link_hw_free(substream); |
---|
1092 | 985 | |
---|
1093 | | - mutex_unlock(&rtd->pcm_mutex); |
---|
| 986 | + mutex_unlock(&rtd->card->pcm_mutex); |
---|
1094 | 987 | return ret; |
---|
1095 | 988 | } |
---|
1096 | 989 | |
---|
.. | .. |
---|
1099 | 992 | */ |
---|
1100 | 993 | static int soc_pcm_hw_free(struct snd_pcm_substream *substream) |
---|
1101 | 994 | { |
---|
1102 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
1103 | | - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
---|
1104 | | - struct snd_soc_dai *codec_dai; |
---|
1105 | | - bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
---|
| 995 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
| 996 | + struct snd_soc_dai *dai; |
---|
1106 | 997 | int i; |
---|
1107 | 998 | |
---|
1108 | | - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
---|
| 999 | + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); |
---|
1109 | 1000 | |
---|
1110 | 1001 | /* clear the corresponding DAIs parameters when going to be inactive */ |
---|
1111 | | - if (cpu_dai->active == 1) { |
---|
1112 | | - cpu_dai->rate = 0; |
---|
1113 | | - cpu_dai->channels = 0; |
---|
1114 | | - cpu_dai->sample_bits = 0; |
---|
1115 | | - } |
---|
| 1002 | + for_each_rtd_dais(rtd, i, dai) { |
---|
| 1003 | + int active = snd_soc_dai_stream_active(dai, substream->stream); |
---|
1116 | 1004 | |
---|
1117 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
1118 | | - codec_dai = rtd->codec_dais[i]; |
---|
1119 | | - if (codec_dai->active == 1) { |
---|
1120 | | - codec_dai->rate = 0; |
---|
1121 | | - codec_dai->channels = 0; |
---|
1122 | | - codec_dai->sample_bits = 0; |
---|
| 1005 | + if (snd_soc_dai_active(dai) == 1) { |
---|
| 1006 | + dai->rate = 0; |
---|
| 1007 | + dai->channels = 0; |
---|
| 1008 | + dai->sample_bits = 0; |
---|
1123 | 1009 | } |
---|
1124 | | - } |
---|
1125 | 1010 | |
---|
1126 | | - /* apply codec digital mute */ |
---|
1127 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
1128 | | - if ((playback && rtd->codec_dais[i]->playback_active == 1) || |
---|
1129 | | - (!playback && rtd->codec_dais[i]->capture_active == 1)) |
---|
1130 | | - snd_soc_dai_digital_mute(rtd->codec_dais[i], 1, |
---|
1131 | | - substream->stream); |
---|
| 1011 | + if (active == 1) |
---|
| 1012 | + snd_soc_dai_digital_mute(dai, 1, substream->stream); |
---|
1132 | 1013 | } |
---|
1133 | 1014 | |
---|
1134 | 1015 | /* free any machine hw params */ |
---|
1135 | | - if (rtd->dai_link->ops->hw_free) |
---|
1136 | | - rtd->dai_link->ops->hw_free(substream); |
---|
| 1016 | + snd_soc_link_hw_free(substream); |
---|
1137 | 1017 | |
---|
1138 | 1018 | /* free any component resources */ |
---|
1139 | | - soc_pcm_components_hw_free(substream, NULL); |
---|
| 1019 | + snd_soc_pcm_component_hw_free(substream, NULL); |
---|
1140 | 1020 | |
---|
1141 | 1021 | /* now free hw params for the DAIs */ |
---|
1142 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
1143 | | - codec_dai = rtd->codec_dais[i]; |
---|
1144 | | - if (codec_dai->driver->ops->hw_free) |
---|
1145 | | - codec_dai->driver->ops->hw_free(substream, codec_dai); |
---|
| 1022 | + for_each_rtd_dais(rtd, i, dai) { |
---|
| 1023 | + if (!snd_soc_dai_stream_valid(dai, substream->stream)) |
---|
| 1024 | + continue; |
---|
| 1025 | + |
---|
| 1026 | + snd_soc_dai_hw_free(dai, substream); |
---|
1146 | 1027 | } |
---|
1147 | 1028 | |
---|
1148 | | - if (cpu_dai->driver->ops->hw_free) |
---|
1149 | | - cpu_dai->driver->ops->hw_free(substream, cpu_dai); |
---|
1150 | | - |
---|
1151 | | - if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST) |
---|
1152 | | - snd_pcm_lib_free_pages(substream); |
---|
1153 | | - mutex_unlock(&rtd->pcm_mutex); |
---|
| 1029 | + mutex_unlock(&rtd->card->pcm_mutex); |
---|
1154 | 1030 | return 0; |
---|
1155 | 1031 | } |
---|
1156 | 1032 | |
---|
1157 | 1033 | static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) |
---|
1158 | 1034 | { |
---|
1159 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
1160 | | - struct snd_soc_component *component; |
---|
1161 | | - struct snd_soc_rtdcom_list *rtdcom; |
---|
1162 | | - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
---|
1163 | | - struct snd_soc_dai *codec_dai; |
---|
1164 | | - int i, ret; |
---|
| 1035 | + int ret = -EINVAL; |
---|
1165 | 1036 | |
---|
1166 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
1167 | | - codec_dai = rtd->codec_dais[i]; |
---|
1168 | | - if (codec_dai->driver->ops->trigger) { |
---|
1169 | | - ret = codec_dai->driver->ops->trigger(substream, |
---|
1170 | | - cmd, codec_dai); |
---|
1171 | | - if (ret < 0) |
---|
1172 | | - return ret; |
---|
1173 | | - } |
---|
1174 | | - } |
---|
1175 | | - |
---|
1176 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
1177 | | - component = rtdcom->component; |
---|
1178 | | - |
---|
1179 | | - if (!component->driver->ops || |
---|
1180 | | - !component->driver->ops->trigger) |
---|
1181 | | - continue; |
---|
1182 | | - |
---|
1183 | | - ret = component->driver->ops->trigger(substream, cmd); |
---|
| 1037 | + switch (cmd) { |
---|
| 1038 | + case SNDRV_PCM_TRIGGER_START: |
---|
| 1039 | + case SNDRV_PCM_TRIGGER_RESUME: |
---|
| 1040 | + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
---|
| 1041 | + ret = snd_soc_link_trigger(substream, cmd); |
---|
1184 | 1042 | if (ret < 0) |
---|
1185 | | - return ret; |
---|
1186 | | - } |
---|
| 1043 | + break; |
---|
1187 | 1044 | |
---|
1188 | | - if (cpu_dai->driver->ops->trigger) { |
---|
1189 | | - ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai); |
---|
| 1045 | + ret = snd_soc_pcm_component_trigger(substream, cmd); |
---|
1190 | 1046 | if (ret < 0) |
---|
1191 | | - return ret; |
---|
1192 | | - } |
---|
| 1047 | + break; |
---|
1193 | 1048 | |
---|
1194 | | - if (rtd->dai_link->ops->trigger) { |
---|
1195 | | - ret = rtd->dai_link->ops->trigger(substream, cmd); |
---|
| 1049 | + ret = snd_soc_pcm_dai_trigger(substream, cmd); |
---|
| 1050 | + break; |
---|
| 1051 | + case SNDRV_PCM_TRIGGER_STOP: |
---|
| 1052 | + case SNDRV_PCM_TRIGGER_SUSPEND: |
---|
| 1053 | + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
---|
| 1054 | + ret = snd_soc_pcm_dai_trigger(substream, cmd); |
---|
1196 | 1055 | if (ret < 0) |
---|
1197 | | - return ret; |
---|
| 1056 | + break; |
---|
| 1057 | + |
---|
| 1058 | + ret = snd_soc_pcm_component_trigger(substream, cmd); |
---|
| 1059 | + if (ret < 0) |
---|
| 1060 | + break; |
---|
| 1061 | + |
---|
| 1062 | + ret = snd_soc_link_trigger(substream, cmd); |
---|
| 1063 | + break; |
---|
1198 | 1064 | } |
---|
1199 | 1065 | |
---|
1200 | | - return 0; |
---|
| 1066 | + return ret; |
---|
1201 | 1067 | } |
---|
1202 | 1068 | |
---|
1203 | | -static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, |
---|
1204 | | - int cmd) |
---|
1205 | | -{ |
---|
1206 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
1207 | | - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
---|
1208 | | - struct snd_soc_dai *codec_dai; |
---|
1209 | | - int i, ret; |
---|
1210 | | - |
---|
1211 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
1212 | | - codec_dai = rtd->codec_dais[i]; |
---|
1213 | | - if (codec_dai->driver->ops->bespoke_trigger) { |
---|
1214 | | - ret = codec_dai->driver->ops->bespoke_trigger(substream, |
---|
1215 | | - cmd, codec_dai); |
---|
1216 | | - if (ret < 0) |
---|
1217 | | - return ret; |
---|
1218 | | - } |
---|
1219 | | - } |
---|
1220 | | - |
---|
1221 | | - if (cpu_dai->driver->ops->bespoke_trigger) { |
---|
1222 | | - ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai); |
---|
1223 | | - if (ret < 0) |
---|
1224 | | - return ret; |
---|
1225 | | - } |
---|
1226 | | - return 0; |
---|
1227 | | -} |
---|
1228 | 1069 | /* |
---|
1229 | 1070 | * soc level wrapper for pointer callback |
---|
1230 | 1071 | * If cpu_dai, codec_dai, component driver has the delay callback, then |
---|
.. | .. |
---|
1232 | 1073 | */ |
---|
1233 | 1074 | static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) |
---|
1234 | 1075 | { |
---|
1235 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
1236 | | - struct snd_soc_component *component; |
---|
1237 | | - struct snd_soc_rtdcom_list *rtdcom; |
---|
1238 | | - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
---|
| 1076 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
| 1077 | + struct snd_soc_dai *cpu_dai; |
---|
1239 | 1078 | struct snd_soc_dai *codec_dai; |
---|
1240 | 1079 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
1241 | 1080 | snd_pcm_uframes_t offset = 0; |
---|
1242 | 1081 | snd_pcm_sframes_t delay = 0; |
---|
1243 | 1082 | snd_pcm_sframes_t codec_delay = 0; |
---|
| 1083 | + snd_pcm_sframes_t cpu_delay = 0; |
---|
1244 | 1084 | int i; |
---|
1245 | 1085 | |
---|
1246 | 1086 | /* clearing the previous total delay */ |
---|
1247 | 1087 | runtime->delay = 0; |
---|
1248 | 1088 | |
---|
1249 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
1250 | | - component = rtdcom->component; |
---|
| 1089 | + offset = snd_soc_pcm_component_pointer(substream); |
---|
1251 | 1090 | |
---|
1252 | | - if (!component->driver->ops || |
---|
1253 | | - !component->driver->ops->pointer) |
---|
1254 | | - continue; |
---|
1255 | | - |
---|
1256 | | - /* FIXME: use 1st pointer */ |
---|
1257 | | - offset = component->driver->ops->pointer(substream); |
---|
1258 | | - break; |
---|
1259 | | - } |
---|
1260 | 1091 | /* base delay if assigned in pointer callback */ |
---|
1261 | 1092 | delay = runtime->delay; |
---|
1262 | 1093 | |
---|
1263 | | - if (cpu_dai->driver->ops->delay) |
---|
1264 | | - delay += cpu_dai->driver->ops->delay(substream, cpu_dai); |
---|
| 1094 | + for_each_rtd_cpu_dais(rtd, i, cpu_dai) { |
---|
| 1095 | + cpu_delay = max(cpu_delay, |
---|
| 1096 | + snd_soc_dai_delay(cpu_dai, substream)); |
---|
| 1097 | + } |
---|
| 1098 | + delay += cpu_delay; |
---|
1265 | 1099 | |
---|
1266 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
1267 | | - codec_dai = rtd->codec_dais[i]; |
---|
1268 | | - if (codec_dai->driver->ops->delay) |
---|
1269 | | - codec_delay = max(codec_delay, |
---|
1270 | | - codec_dai->driver->ops->delay(substream, |
---|
1271 | | - codec_dai)); |
---|
| 1100 | + for_each_rtd_codec_dais(rtd, i, codec_dai) { |
---|
| 1101 | + codec_delay = max(codec_delay, |
---|
| 1102 | + snd_soc_dai_delay(codec_dai, substream)); |
---|
1272 | 1103 | } |
---|
1273 | 1104 | delay += codec_delay; |
---|
1274 | 1105 | |
---|
.. | .. |
---|
1282 | 1113 | struct snd_soc_pcm_runtime *be, int stream) |
---|
1283 | 1114 | { |
---|
1284 | 1115 | struct snd_soc_dpcm *dpcm; |
---|
| 1116 | + unsigned long flags; |
---|
1285 | 1117 | |
---|
1286 | 1118 | /* only add new dpcms */ |
---|
1287 | | - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
---|
| 1119 | + for_each_dpcm_be(fe, stream, dpcm) { |
---|
1288 | 1120 | if (dpcm->be == be && dpcm->fe == fe) |
---|
1289 | 1121 | return 0; |
---|
1290 | 1122 | } |
---|
.. | .. |
---|
1297 | 1129 | dpcm->fe = fe; |
---|
1298 | 1130 | be->dpcm[stream].runtime = fe->dpcm[stream].runtime; |
---|
1299 | 1131 | dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW; |
---|
| 1132 | + spin_lock_irqsave(&fe->card->dpcm_lock, flags); |
---|
1300 | 1133 | list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients); |
---|
1301 | 1134 | list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients); |
---|
| 1135 | + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); |
---|
1302 | 1136 | |
---|
1303 | 1137 | dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n", |
---|
1304 | 1138 | stream ? "capture" : "playback", fe->dai_link->name, |
---|
1305 | 1139 | stream ? "<-" : "->", be->dai_link->name); |
---|
1306 | 1140 | |
---|
1307 | | -#ifdef CONFIG_DEBUG_FS |
---|
1308 | | - if (fe->debugfs_dpcm_root) |
---|
1309 | | - dpcm->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644, |
---|
1310 | | - fe->debugfs_dpcm_root, &dpcm->state); |
---|
1311 | | -#endif |
---|
| 1141 | + dpcm_create_debugfs_state(dpcm, stream); |
---|
| 1142 | + |
---|
1312 | 1143 | return 1; |
---|
1313 | 1144 | } |
---|
1314 | 1145 | |
---|
.. | .. |
---|
1324 | 1155 | return; |
---|
1325 | 1156 | |
---|
1326 | 1157 | be_substream = snd_soc_dpcm_get_substream(be, stream); |
---|
| 1158 | + if (!be_substream) |
---|
| 1159 | + return; |
---|
1327 | 1160 | |
---|
1328 | | - list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { |
---|
| 1161 | + for_each_dpcm_fe(be, stream, dpcm) { |
---|
1329 | 1162 | if (dpcm->fe == fe) |
---|
1330 | 1163 | continue; |
---|
1331 | 1164 | |
---|
.. | .. |
---|
1344 | 1177 | void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) |
---|
1345 | 1178 | { |
---|
1346 | 1179 | struct snd_soc_dpcm *dpcm, *d; |
---|
| 1180 | + unsigned long flags; |
---|
1347 | 1181 | |
---|
1348 | | - list_for_each_entry_safe(dpcm, d, &fe->dpcm[stream].be_clients, list_be) { |
---|
| 1182 | + for_each_dpcm_be_safe(fe, stream, dpcm, d) { |
---|
1349 | 1183 | dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n", |
---|
1350 | 1184 | stream ? "capture" : "playback", |
---|
1351 | 1185 | dpcm->be->dai_link->name); |
---|
.. | .. |
---|
1360 | 1194 | /* BEs still alive need new FE */ |
---|
1361 | 1195 | dpcm_be_reparent(fe, dpcm->be, stream); |
---|
1362 | 1196 | |
---|
1363 | | -#ifdef CONFIG_DEBUG_FS |
---|
1364 | | - debugfs_remove(dpcm->debugfs_state); |
---|
1365 | | -#endif |
---|
| 1197 | + dpcm_remove_debugfs_state(dpcm); |
---|
| 1198 | + |
---|
| 1199 | + spin_lock_irqsave(&fe->card->dpcm_lock, flags); |
---|
1366 | 1200 | list_del(&dpcm->list_be); |
---|
1367 | 1201 | list_del(&dpcm->list_fe); |
---|
| 1202 | + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); |
---|
1368 | 1203 | kfree(dpcm); |
---|
1369 | 1204 | } |
---|
1370 | 1205 | } |
---|
.. | .. |
---|
1374 | 1209 | struct snd_soc_dapm_widget *widget, int stream) |
---|
1375 | 1210 | { |
---|
1376 | 1211 | struct snd_soc_pcm_runtime *be; |
---|
| 1212 | + struct snd_soc_dapm_widget *w; |
---|
| 1213 | + struct snd_soc_dai *dai; |
---|
1377 | 1214 | int i; |
---|
1378 | 1215 | |
---|
1379 | 1216 | dev_dbg(card->dev, "ASoC: find BE for widget %s\n", widget->name); |
---|
1380 | 1217 | |
---|
1381 | | - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
---|
1382 | | - list_for_each_entry(be, &card->rtd_list, list) { |
---|
| 1218 | + for_each_card_rtds(card, be) { |
---|
1383 | 1219 | |
---|
1384 | | - if (!be->dai_link->no_pcm) |
---|
1385 | | - continue; |
---|
| 1220 | + if (!be->dai_link->no_pcm) |
---|
| 1221 | + continue; |
---|
| 1222 | + |
---|
| 1223 | + for_each_rtd_dais(be, i, dai) { |
---|
| 1224 | + w = snd_soc_dai_get_widget(dai, stream); |
---|
1386 | 1225 | |
---|
1387 | 1226 | dev_dbg(card->dev, "ASoC: try BE : %s\n", |
---|
1388 | | - be->cpu_dai->playback_widget ? |
---|
1389 | | - be->cpu_dai->playback_widget->name : "(not set)"); |
---|
| 1227 | + w ? w->name : "(not set)"); |
---|
1390 | 1228 | |
---|
1391 | | - if (be->cpu_dai->playback_widget == widget) |
---|
| 1229 | + if (w == widget) |
---|
1392 | 1230 | return be; |
---|
1393 | | - |
---|
1394 | | - for (i = 0; i < be->num_codecs; i++) { |
---|
1395 | | - struct snd_soc_dai *dai = be->codec_dais[i]; |
---|
1396 | | - if (dai->playback_widget == widget) |
---|
1397 | | - return be; |
---|
1398 | | - } |
---|
1399 | | - } |
---|
1400 | | - } else { |
---|
1401 | | - |
---|
1402 | | - list_for_each_entry(be, &card->rtd_list, list) { |
---|
1403 | | - |
---|
1404 | | - if (!be->dai_link->no_pcm) |
---|
1405 | | - continue; |
---|
1406 | | - |
---|
1407 | | - dev_dbg(card->dev, "ASoC: try BE %s\n", |
---|
1408 | | - be->cpu_dai->capture_widget ? |
---|
1409 | | - be->cpu_dai->capture_widget->name : "(not set)"); |
---|
1410 | | - |
---|
1411 | | - if (be->cpu_dai->capture_widget == widget) |
---|
1412 | | - return be; |
---|
1413 | | - |
---|
1414 | | - for (i = 0; i < be->num_codecs; i++) { |
---|
1415 | | - struct snd_soc_dai *dai = be->codec_dais[i]; |
---|
1416 | | - if (dai->capture_widget == widget) |
---|
1417 | | - return be; |
---|
1418 | | - } |
---|
1419 | 1231 | } |
---|
1420 | 1232 | } |
---|
1421 | 1233 | |
---|
1422 | | - /* dai link name and stream name set correctly ? */ |
---|
1423 | | - dev_err(card->dev, "ASoC: can't get %s BE for %s\n", |
---|
1424 | | - stream ? "capture" : "playback", widget->name); |
---|
| 1234 | + /* Widget provided is not a BE */ |
---|
1425 | 1235 | return NULL; |
---|
1426 | | -} |
---|
1427 | | - |
---|
1428 | | -static inline struct snd_soc_dapm_widget * |
---|
1429 | | - dai_get_widget(struct snd_soc_dai *dai, int stream) |
---|
1430 | | -{ |
---|
1431 | | - if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
1432 | | - return dai->playback_widget; |
---|
1433 | | - else |
---|
1434 | | - return dai->capture_widget; |
---|
1435 | 1236 | } |
---|
1436 | 1237 | |
---|
1437 | 1238 | static int widget_in_list(struct snd_soc_dapm_widget_list *list, |
---|
1438 | 1239 | struct snd_soc_dapm_widget *widget) |
---|
1439 | 1240 | { |
---|
| 1241 | + struct snd_soc_dapm_widget *w; |
---|
1440 | 1242 | int i; |
---|
1441 | 1243 | |
---|
1442 | | - for (i = 0; i < list->num_widgets; i++) { |
---|
1443 | | - if (widget == list->widgets[i]) |
---|
| 1244 | + for_each_dapm_widgets(list, i, w) |
---|
| 1245 | + if (widget == w) |
---|
1444 | 1246 | return 1; |
---|
1445 | | - } |
---|
1446 | 1247 | |
---|
1447 | 1248 | return 0; |
---|
1448 | 1249 | } |
---|
.. | .. |
---|
1452 | 1253 | { |
---|
1453 | 1254 | struct snd_soc_card *card = widget->dapm->card; |
---|
1454 | 1255 | struct snd_soc_pcm_runtime *rtd; |
---|
1455 | | - int i; |
---|
| 1256 | + int stream; |
---|
1456 | 1257 | |
---|
1457 | | - if (dir == SND_SOC_DAPM_DIR_OUT) { |
---|
1458 | | - list_for_each_entry(rtd, &card->rtd_list, list) { |
---|
1459 | | - if (!rtd->dai_link->no_pcm) |
---|
1460 | | - continue; |
---|
| 1258 | + /* adjust dir to stream */ |
---|
| 1259 | + if (dir == SND_SOC_DAPM_DIR_OUT) |
---|
| 1260 | + stream = SNDRV_PCM_STREAM_PLAYBACK; |
---|
| 1261 | + else |
---|
| 1262 | + stream = SNDRV_PCM_STREAM_CAPTURE; |
---|
1461 | 1263 | |
---|
1462 | | - if (rtd->cpu_dai->playback_widget == widget) |
---|
1463 | | - return true; |
---|
1464 | | - |
---|
1465 | | - for (i = 0; i < rtd->num_codecs; ++i) { |
---|
1466 | | - struct snd_soc_dai *dai = rtd->codec_dais[i]; |
---|
1467 | | - if (dai->playback_widget == widget) |
---|
1468 | | - return true; |
---|
1469 | | - } |
---|
1470 | | - } |
---|
1471 | | - } else { /* SND_SOC_DAPM_DIR_IN */ |
---|
1472 | | - list_for_each_entry(rtd, &card->rtd_list, list) { |
---|
1473 | | - if (!rtd->dai_link->no_pcm) |
---|
1474 | | - continue; |
---|
1475 | | - |
---|
1476 | | - if (rtd->cpu_dai->capture_widget == widget) |
---|
1477 | | - return true; |
---|
1478 | | - |
---|
1479 | | - for (i = 0; i < rtd->num_codecs; ++i) { |
---|
1480 | | - struct snd_soc_dai *dai = rtd->codec_dais[i]; |
---|
1481 | | - if (dai->capture_widget == widget) |
---|
1482 | | - return true; |
---|
1483 | | - } |
---|
1484 | | - } |
---|
1485 | | - } |
---|
| 1264 | + rtd = dpcm_get_be(card, widget, stream); |
---|
| 1265 | + if (rtd) |
---|
| 1266 | + return true; |
---|
1486 | 1267 | |
---|
1487 | 1268 | return false; |
---|
1488 | 1269 | } |
---|
.. | .. |
---|
1490 | 1271 | int dpcm_path_get(struct snd_soc_pcm_runtime *fe, |
---|
1491 | 1272 | int stream, struct snd_soc_dapm_widget_list **list) |
---|
1492 | 1273 | { |
---|
1493 | | - struct snd_soc_dai *cpu_dai = fe->cpu_dai; |
---|
| 1274 | + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0); |
---|
1494 | 1275 | int paths; |
---|
| 1276 | + bool chaining = false; |
---|
| 1277 | + |
---|
| 1278 | + if (fe->num_cpus > 1) { |
---|
| 1279 | + dev_err(fe->dev, |
---|
| 1280 | + "%s doesn't support Multi CPU yet\n", __func__); |
---|
| 1281 | + return -EINVAL; |
---|
| 1282 | + } |
---|
| 1283 | + |
---|
| 1284 | + trace_android_vh_snd_soc_card_get_comp_chain(&chaining); |
---|
1495 | 1285 | |
---|
1496 | 1286 | /* get number of valid DAI paths and their widgets */ |
---|
1497 | 1287 | paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list, |
---|
1498 | | - dpcm_end_walk_at_be); |
---|
| 1288 | + chaining ? NULL : dpcm_end_walk_at_be); |
---|
1499 | 1289 | |
---|
1500 | 1290 | dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths, |
---|
1501 | 1291 | stream ? "capture" : "playback"); |
---|
.. | .. |
---|
1503 | 1293 | return paths; |
---|
1504 | 1294 | } |
---|
1505 | 1295 | |
---|
| 1296 | +void dpcm_path_put(struct snd_soc_dapm_widget_list **list) |
---|
| 1297 | +{ |
---|
| 1298 | + snd_soc_dapm_dai_free_widgets(list); |
---|
| 1299 | +} |
---|
| 1300 | + |
---|
| 1301 | +static bool dpcm_be_is_active(struct snd_soc_dpcm *dpcm, int stream, |
---|
| 1302 | + struct snd_soc_dapm_widget_list *list) |
---|
| 1303 | +{ |
---|
| 1304 | + struct snd_soc_dapm_widget *widget; |
---|
| 1305 | + struct snd_soc_dai *dai; |
---|
| 1306 | + unsigned int i; |
---|
| 1307 | + |
---|
| 1308 | + /* is there a valid DAI widget for this BE */ |
---|
| 1309 | + for_each_rtd_dais(dpcm->be, i, dai) { |
---|
| 1310 | + widget = snd_soc_dai_get_widget(dai, stream); |
---|
| 1311 | + |
---|
| 1312 | + /* |
---|
| 1313 | + * The BE is pruned only if none of the dai |
---|
| 1314 | + * widgets are in the active list. |
---|
| 1315 | + */ |
---|
| 1316 | + if (widget && widget_in_list(list, widget)) |
---|
| 1317 | + return true; |
---|
| 1318 | + } |
---|
| 1319 | + |
---|
| 1320 | + return false; |
---|
| 1321 | +} |
---|
| 1322 | + |
---|
1506 | 1323 | static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, |
---|
1507 | | - struct snd_soc_dapm_widget_list **list_) |
---|
| 1324 | + struct snd_soc_dapm_widget_list **list_) |
---|
1508 | 1325 | { |
---|
1509 | 1326 | struct snd_soc_dpcm *dpcm; |
---|
1510 | | - struct snd_soc_dapm_widget_list *list = *list_; |
---|
1511 | | - struct snd_soc_dapm_widget *widget; |
---|
1512 | 1327 | int prune = 0; |
---|
1513 | 1328 | |
---|
1514 | 1329 | /* Destroy any old FE <--> BE connections */ |
---|
1515 | | - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
---|
1516 | | - unsigned int i; |
---|
1517 | | - |
---|
1518 | | - /* is there a valid CPU DAI widget for this BE */ |
---|
1519 | | - widget = dai_get_widget(dpcm->be->cpu_dai, stream); |
---|
1520 | | - |
---|
1521 | | - /* prune the BE if it's no longer in our active list */ |
---|
1522 | | - if (widget && widget_in_list(list, widget)) |
---|
| 1330 | + for_each_dpcm_be(fe, stream, dpcm) { |
---|
| 1331 | + if (dpcm_be_is_active(dpcm, stream, *list_)) |
---|
1523 | 1332 | continue; |
---|
1524 | | - |
---|
1525 | | - /* is there a valid CODEC DAI widget for this BE */ |
---|
1526 | | - for (i = 0; i < dpcm->be->num_codecs; i++) { |
---|
1527 | | - struct snd_soc_dai *dai = dpcm->be->codec_dais[i]; |
---|
1528 | | - widget = dai_get_widget(dai, stream); |
---|
1529 | | - |
---|
1530 | | - /* prune the BE if it's no longer in our active list */ |
---|
1531 | | - if (widget && widget_in_list(list, widget)) |
---|
1532 | | - continue; |
---|
1533 | | - } |
---|
1534 | 1333 | |
---|
1535 | 1334 | dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n", |
---|
1536 | 1335 | stream ? "capture" : "playback", |
---|
.. | .. |
---|
1550 | 1349 | struct snd_soc_card *card = fe->card; |
---|
1551 | 1350 | struct snd_soc_dapm_widget_list *list = *list_; |
---|
1552 | 1351 | struct snd_soc_pcm_runtime *be; |
---|
| 1352 | + struct snd_soc_dapm_widget *widget; |
---|
1553 | 1353 | int i, new = 0, err; |
---|
1554 | 1354 | |
---|
1555 | 1355 | /* Create any new FE <--> BE connections */ |
---|
1556 | | - for (i = 0; i < list->num_widgets; i++) { |
---|
| 1356 | + for_each_dapm_widgets(list, i, widget) { |
---|
1557 | 1357 | |
---|
1558 | | - switch (list->widgets[i]->id) { |
---|
| 1358 | + switch (widget->id) { |
---|
1559 | 1359 | case snd_soc_dapm_dai_in: |
---|
1560 | 1360 | if (stream != SNDRV_PCM_STREAM_PLAYBACK) |
---|
1561 | 1361 | continue; |
---|
.. | .. |
---|
1569 | 1369 | } |
---|
1570 | 1370 | |
---|
1571 | 1371 | /* is there a valid BE rtd for this widget */ |
---|
1572 | | - be = dpcm_get_be(card, list->widgets[i], stream); |
---|
| 1372 | + be = dpcm_get_be(card, widget, stream); |
---|
1573 | 1373 | if (!be) { |
---|
1574 | 1374 | dev_err(fe->dev, "ASoC: no BE found for %s\n", |
---|
1575 | | - list->widgets[i]->name); |
---|
| 1375 | + widget->name); |
---|
1576 | 1376 | continue; |
---|
1577 | 1377 | } |
---|
1578 | | - |
---|
1579 | | - /* make sure BE is a real BE */ |
---|
1580 | | - if (!be->dai_link->no_pcm) |
---|
1581 | | - continue; |
---|
1582 | 1378 | |
---|
1583 | 1379 | /* don't connect if FE is not running */ |
---|
1584 | 1380 | if (!fe->dpcm[stream].runtime && !fe->fe_compr) |
---|
.. | .. |
---|
1588 | 1384 | err = dpcm_be_connect(fe, be, stream); |
---|
1589 | 1385 | if (err < 0) { |
---|
1590 | 1386 | dev_err(fe->dev, "ASoC: can't connect %s\n", |
---|
1591 | | - list->widgets[i]->name); |
---|
| 1387 | + widget->name); |
---|
1592 | 1388 | break; |
---|
1593 | 1389 | } else if (err == 0) /* already connected */ |
---|
1594 | 1390 | continue; |
---|
.. | .. |
---|
1618 | 1414 | void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream) |
---|
1619 | 1415 | { |
---|
1620 | 1416 | struct snd_soc_dpcm *dpcm; |
---|
| 1417 | + unsigned long flags; |
---|
1621 | 1418 | |
---|
1622 | | - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) |
---|
| 1419 | + spin_lock_irqsave(&fe->card->dpcm_lock, flags); |
---|
| 1420 | + for_each_dpcm_be(fe, stream, dpcm) |
---|
1623 | 1421 | dpcm->be->dpcm[stream].runtime_update = |
---|
1624 | 1422 | SND_SOC_DPCM_UPDATE_NO; |
---|
| 1423 | + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); |
---|
1625 | 1424 | } |
---|
1626 | 1425 | |
---|
1627 | 1426 | static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe, |
---|
.. | .. |
---|
1630 | 1429 | struct snd_soc_dpcm *dpcm; |
---|
1631 | 1430 | |
---|
1632 | 1431 | /* disable any enabled and non active backends */ |
---|
1633 | | - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
---|
| 1432 | + for_each_dpcm_be(fe, stream, dpcm) { |
---|
1634 | 1433 | |
---|
1635 | 1434 | struct snd_soc_pcm_runtime *be = dpcm->be; |
---|
1636 | 1435 | struct snd_pcm_substream *be_substream = |
---|
.. | .. |
---|
1659 | 1458 | int err, count = 0; |
---|
1660 | 1459 | |
---|
1661 | 1460 | /* only startup BE DAIs that are either sinks or sources to this FE DAI */ |
---|
1662 | | - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
---|
| 1461 | + for_each_dpcm_be(fe, stream, dpcm) { |
---|
1663 | 1462 | |
---|
1664 | 1463 | struct snd_soc_pcm_runtime *be = dpcm->be; |
---|
1665 | 1464 | struct snd_pcm_substream *be_substream = |
---|
.. | .. |
---|
1713 | 1512 | |
---|
1714 | 1513 | unwind: |
---|
1715 | 1514 | /* disable any enabled and non active backends */ |
---|
1716 | | - list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
---|
| 1515 | + for_each_dpcm_be_rollback(fe, stream, dpcm) { |
---|
1717 | 1516 | struct snd_soc_pcm_runtime *be = dpcm->be; |
---|
1718 | 1517 | struct snd_pcm_substream *be_substream = |
---|
1719 | 1518 | snd_soc_dpcm_get_substream(be, stream); |
---|
.. | .. |
---|
1757 | 1556 | static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream, |
---|
1758 | 1557 | u64 *formats) |
---|
1759 | 1558 | { |
---|
1760 | | - struct snd_soc_pcm_runtime *fe = substream->private_data; |
---|
| 1559 | + struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); |
---|
1761 | 1560 | struct snd_soc_dpcm *dpcm; |
---|
| 1561 | + struct snd_soc_dai *dai; |
---|
1762 | 1562 | int stream = substream->stream; |
---|
1763 | 1563 | |
---|
1764 | 1564 | if (!fe->dai_link->dpcm_merged_format) |
---|
.. | .. |
---|
1769 | 1569 | * if FE want to use it (= dpcm_merged_format) |
---|
1770 | 1570 | */ |
---|
1771 | 1571 | |
---|
1772 | | - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
---|
| 1572 | + for_each_dpcm_be(fe, stream, dpcm) { |
---|
1773 | 1573 | struct snd_soc_pcm_runtime *be = dpcm->be; |
---|
1774 | | - struct snd_soc_dai_driver *codec_dai_drv; |
---|
1775 | 1574 | struct snd_soc_pcm_stream *codec_stream; |
---|
1776 | 1575 | int i; |
---|
1777 | 1576 | |
---|
1778 | | - for (i = 0; i < be->num_codecs; i++) { |
---|
| 1577 | + for_each_rtd_codec_dais(be, i, dai) { |
---|
1779 | 1578 | /* |
---|
1780 | 1579 | * Skip CODECs which don't support the current stream |
---|
1781 | 1580 | * type. See soc_pcm_init_runtime_hw() for more details |
---|
1782 | 1581 | */ |
---|
1783 | | - if (!snd_soc_dai_stream_valid(be->codec_dais[i], |
---|
1784 | | - stream)) |
---|
| 1582 | + if (!snd_soc_dai_stream_valid(dai, stream)) |
---|
1785 | 1583 | continue; |
---|
1786 | 1584 | |
---|
1787 | | - codec_dai_drv = be->codec_dais[i]->driver; |
---|
1788 | | - if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
1789 | | - codec_stream = &codec_dai_drv->playback; |
---|
1790 | | - else |
---|
1791 | | - codec_stream = &codec_dai_drv->capture; |
---|
| 1585 | + codec_stream = snd_soc_dai_get_pcm_stream(dai, stream); |
---|
1792 | 1586 | |
---|
1793 | 1587 | *formats &= codec_stream->formats; |
---|
1794 | 1588 | } |
---|
.. | .. |
---|
1799 | 1593 | unsigned int *channels_min, |
---|
1800 | 1594 | unsigned int *channels_max) |
---|
1801 | 1595 | { |
---|
1802 | | - struct snd_soc_pcm_runtime *fe = substream->private_data; |
---|
| 1596 | + struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); |
---|
1803 | 1597 | struct snd_soc_dpcm *dpcm; |
---|
1804 | 1598 | int stream = substream->stream; |
---|
1805 | 1599 | |
---|
.. | .. |
---|
1811 | 1605 | * if FE want to use it (= dpcm_merged_chan) |
---|
1812 | 1606 | */ |
---|
1813 | 1607 | |
---|
1814 | | - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
---|
| 1608 | + for_each_dpcm_be(fe, stream, dpcm) { |
---|
1815 | 1609 | struct snd_soc_pcm_runtime *be = dpcm->be; |
---|
1816 | | - struct snd_soc_dai_driver *cpu_dai_drv = be->cpu_dai->driver; |
---|
1817 | | - struct snd_soc_dai_driver *codec_dai_drv; |
---|
1818 | 1610 | struct snd_soc_pcm_stream *codec_stream; |
---|
1819 | 1611 | struct snd_soc_pcm_stream *cpu_stream; |
---|
| 1612 | + struct snd_soc_dai *dai; |
---|
| 1613 | + int i; |
---|
1820 | 1614 | |
---|
1821 | | - if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
1822 | | - cpu_stream = &cpu_dai_drv->playback; |
---|
1823 | | - else |
---|
1824 | | - cpu_stream = &cpu_dai_drv->capture; |
---|
| 1615 | + for_each_rtd_cpu_dais(be, i, dai) { |
---|
| 1616 | + /* |
---|
| 1617 | + * Skip CPUs which don't support the current stream |
---|
| 1618 | + * type. See soc_pcm_init_runtime_hw() for more details |
---|
| 1619 | + */ |
---|
| 1620 | + if (!snd_soc_dai_stream_valid(dai, stream)) |
---|
| 1621 | + continue; |
---|
1825 | 1622 | |
---|
1826 | | - *channels_min = max(*channels_min, cpu_stream->channels_min); |
---|
1827 | | - *channels_max = min(*channels_max, cpu_stream->channels_max); |
---|
| 1623 | + cpu_stream = snd_soc_dai_get_pcm_stream(dai, stream); |
---|
| 1624 | + |
---|
| 1625 | + *channels_min = max(*channels_min, |
---|
| 1626 | + cpu_stream->channels_min); |
---|
| 1627 | + *channels_max = min(*channels_max, |
---|
| 1628 | + cpu_stream->channels_max); |
---|
| 1629 | + } |
---|
1828 | 1630 | |
---|
1829 | 1631 | /* |
---|
1830 | 1632 | * chan min/max cannot be enforced if there are multiple CODEC |
---|
1831 | 1633 | * DAIs connected to a single CPU DAI, use CPU DAI's directly |
---|
1832 | 1634 | */ |
---|
1833 | 1635 | if (be->num_codecs == 1) { |
---|
1834 | | - codec_dai_drv = be->codec_dais[0]->driver; |
---|
1835 | | - |
---|
1836 | | - if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
1837 | | - codec_stream = &codec_dai_drv->playback; |
---|
1838 | | - else |
---|
1839 | | - codec_stream = &codec_dai_drv->capture; |
---|
| 1636 | + codec_stream = snd_soc_dai_get_pcm_stream(asoc_rtd_to_codec(be, 0), stream); |
---|
1840 | 1637 | |
---|
1841 | 1638 | *channels_min = max(*channels_min, |
---|
1842 | 1639 | codec_stream->channels_min); |
---|
.. | .. |
---|
1851 | 1648 | unsigned int *rate_min, |
---|
1852 | 1649 | unsigned int *rate_max) |
---|
1853 | 1650 | { |
---|
1854 | | - struct snd_soc_pcm_runtime *fe = substream->private_data; |
---|
| 1651 | + struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); |
---|
1855 | 1652 | struct snd_soc_dpcm *dpcm; |
---|
1856 | 1653 | int stream = substream->stream; |
---|
1857 | 1654 | |
---|
.. | .. |
---|
1863 | 1660 | * if FE want to use it (= dpcm_merged_chan) |
---|
1864 | 1661 | */ |
---|
1865 | 1662 | |
---|
1866 | | - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
---|
| 1663 | + for_each_dpcm_be(fe, stream, dpcm) { |
---|
1867 | 1664 | struct snd_soc_pcm_runtime *be = dpcm->be; |
---|
1868 | | - struct snd_soc_dai_driver *cpu_dai_drv = be->cpu_dai->driver; |
---|
1869 | | - struct snd_soc_dai_driver *codec_dai_drv; |
---|
1870 | | - struct snd_soc_pcm_stream *codec_stream; |
---|
1871 | | - struct snd_soc_pcm_stream *cpu_stream; |
---|
| 1665 | + struct snd_soc_pcm_stream *pcm; |
---|
| 1666 | + struct snd_soc_dai *dai; |
---|
1872 | 1667 | int i; |
---|
1873 | 1668 | |
---|
1874 | | - if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
1875 | | - cpu_stream = &cpu_dai_drv->playback; |
---|
1876 | | - else |
---|
1877 | | - cpu_stream = &cpu_dai_drv->capture; |
---|
1878 | | - |
---|
1879 | | - *rate_min = max(*rate_min, cpu_stream->rate_min); |
---|
1880 | | - *rate_max = min_not_zero(*rate_max, cpu_stream->rate_max); |
---|
1881 | | - *rates = snd_pcm_rate_mask_intersect(*rates, cpu_stream->rates); |
---|
1882 | | - |
---|
1883 | | - for (i = 0; i < be->num_codecs; i++) { |
---|
| 1669 | + for_each_rtd_dais(be, i, dai) { |
---|
1884 | 1670 | /* |
---|
1885 | | - * Skip CODECs which don't support the current stream |
---|
| 1671 | + * Skip DAIs which don't support the current stream |
---|
1886 | 1672 | * type. See soc_pcm_init_runtime_hw() for more details |
---|
1887 | 1673 | */ |
---|
1888 | | - if (!snd_soc_dai_stream_valid(be->codec_dais[i], |
---|
1889 | | - stream)) |
---|
| 1674 | + if (!snd_soc_dai_stream_valid(dai, stream)) |
---|
1890 | 1675 | continue; |
---|
1891 | 1676 | |
---|
1892 | | - codec_dai_drv = be->codec_dais[i]->driver; |
---|
1893 | | - if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
1894 | | - codec_stream = &codec_dai_drv->playback; |
---|
1895 | | - else |
---|
1896 | | - codec_stream = &codec_dai_drv->capture; |
---|
| 1677 | + pcm = snd_soc_dai_get_pcm_stream(dai, stream); |
---|
1897 | 1678 | |
---|
1898 | | - *rate_min = max(*rate_min, codec_stream->rate_min); |
---|
1899 | | - *rate_max = min_not_zero(*rate_max, |
---|
1900 | | - codec_stream->rate_max); |
---|
1901 | | - *rates = snd_pcm_rate_mask_intersect(*rates, |
---|
1902 | | - codec_stream->rates); |
---|
| 1679 | + *rate_min = max(*rate_min, pcm->rate_min); |
---|
| 1680 | + *rate_max = min_not_zero(*rate_max, pcm->rate_max); |
---|
| 1681 | + *rates = snd_pcm_rate_mask_intersect(*rates, pcm->rates); |
---|
1903 | 1682 | } |
---|
1904 | 1683 | } |
---|
1905 | 1684 | } |
---|
.. | .. |
---|
1907 | 1686 | static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream) |
---|
1908 | 1687 | { |
---|
1909 | 1688 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
1910 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
1911 | | - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
---|
1912 | | - struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver; |
---|
| 1689 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
| 1690 | + struct snd_soc_dai *cpu_dai; |
---|
| 1691 | + int i; |
---|
1913 | 1692 | |
---|
1914 | | - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
1915 | | - dpcm_init_runtime_hw(runtime, &cpu_dai_drv->playback); |
---|
1916 | | - else |
---|
1917 | | - dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture); |
---|
| 1693 | + for_each_rtd_cpu_dais(rtd, i, cpu_dai) { |
---|
| 1694 | + /* |
---|
| 1695 | + * Skip CPUs which don't support the current stream |
---|
| 1696 | + * type. See soc_pcm_init_runtime_hw() for more details |
---|
| 1697 | + */ |
---|
| 1698 | + if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream)) |
---|
| 1699 | + continue; |
---|
| 1700 | + |
---|
| 1701 | + dpcm_init_runtime_hw(runtime, |
---|
| 1702 | + snd_soc_dai_get_pcm_stream(cpu_dai, |
---|
| 1703 | + substream->stream)); |
---|
| 1704 | + } |
---|
1918 | 1705 | |
---|
1919 | 1706 | dpcm_runtime_merge_format(substream, &runtime->hw.formats); |
---|
1920 | 1707 | dpcm_runtime_merge_chan(substream, &runtime->hw.channels_min, |
---|
.. | .. |
---|
1950 | 1737 | int stream) |
---|
1951 | 1738 | { |
---|
1952 | 1739 | struct snd_soc_dpcm *dpcm; |
---|
1953 | | - struct snd_soc_pcm_runtime *fe = fe_substream->private_data; |
---|
1954 | | - struct snd_soc_dai *fe_cpu_dai = fe->cpu_dai; |
---|
1955 | | - int err; |
---|
| 1740 | + struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream); |
---|
| 1741 | + struct snd_soc_dai *fe_cpu_dai; |
---|
| 1742 | + int err = 0; |
---|
| 1743 | + int i; |
---|
1956 | 1744 | |
---|
1957 | 1745 | /* apply symmetry for FE */ |
---|
1958 | 1746 | if (soc_pcm_has_symmetry(fe_substream)) |
---|
1959 | 1747 | fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; |
---|
1960 | 1748 | |
---|
1961 | | - /* Symmetry only applies if we've got an active stream. */ |
---|
1962 | | - if (fe_cpu_dai->active) { |
---|
1963 | | - err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai); |
---|
1964 | | - if (err < 0) |
---|
1965 | | - return err; |
---|
| 1749 | + for_each_rtd_cpu_dais (fe, i, fe_cpu_dai) { |
---|
| 1750 | + /* Symmetry only applies if we've got an active stream. */ |
---|
| 1751 | + if (snd_soc_dai_active(fe_cpu_dai)) { |
---|
| 1752 | + err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai); |
---|
| 1753 | + if (err < 0) |
---|
| 1754 | + return err; |
---|
| 1755 | + } |
---|
1966 | 1756 | } |
---|
1967 | 1757 | |
---|
1968 | 1758 | /* apply symmetry for BE */ |
---|
1969 | | - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
---|
| 1759 | + for_each_dpcm_be(fe, stream, dpcm) { |
---|
1970 | 1760 | struct snd_soc_pcm_runtime *be = dpcm->be; |
---|
1971 | 1761 | struct snd_pcm_substream *be_substream = |
---|
1972 | 1762 | snd_soc_dpcm_get_substream(be, stream); |
---|
1973 | | - struct snd_soc_pcm_runtime *rtd = be_substream->private_data; |
---|
| 1763 | + struct snd_soc_pcm_runtime *rtd; |
---|
| 1764 | + struct snd_soc_dai *dai; |
---|
1974 | 1765 | int i; |
---|
1975 | 1766 | |
---|
| 1767 | + /* A backend may not have the requested substream */ |
---|
| 1768 | + if (!be_substream) |
---|
| 1769 | + continue; |
---|
| 1770 | + |
---|
| 1771 | + rtd = asoc_substream_to_rtd(be_substream); |
---|
1976 | 1772 | if (rtd->dai_link->be_hw_params_fixup) |
---|
1977 | 1773 | continue; |
---|
1978 | 1774 | |
---|
.. | .. |
---|
1980 | 1776 | be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; |
---|
1981 | 1777 | |
---|
1982 | 1778 | /* Symmetry only applies if we've got an active stream. */ |
---|
1983 | | - if (rtd->cpu_dai->active) { |
---|
1984 | | - err = soc_pcm_apply_symmetry(fe_substream, |
---|
1985 | | - rtd->cpu_dai); |
---|
1986 | | - if (err < 0) |
---|
1987 | | - return err; |
---|
1988 | | - } |
---|
1989 | | - |
---|
1990 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
1991 | | - if (rtd->codec_dais[i]->active) { |
---|
1992 | | - err = soc_pcm_apply_symmetry(fe_substream, |
---|
1993 | | - rtd->codec_dais[i]); |
---|
| 1779 | + for_each_rtd_dais(rtd, i, dai) { |
---|
| 1780 | + if (snd_soc_dai_active(dai)) { |
---|
| 1781 | + err = soc_pcm_apply_symmetry(fe_substream, dai); |
---|
1994 | 1782 | if (err < 0) |
---|
1995 | 1783 | return err; |
---|
1996 | 1784 | } |
---|
.. | .. |
---|
2002 | 1790 | |
---|
2003 | 1791 | static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) |
---|
2004 | 1792 | { |
---|
2005 | | - struct snd_soc_pcm_runtime *fe = fe_substream->private_data; |
---|
| 1793 | + struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream); |
---|
2006 | 1794 | struct snd_pcm_runtime *runtime = fe_substream->runtime; |
---|
2007 | 1795 | int stream = fe_substream->stream, ret = 0; |
---|
2008 | 1796 | |
---|
2009 | 1797 | dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE); |
---|
2010 | 1798 | |
---|
2011 | | - ret = dpcm_be_dai_startup(fe, fe_substream->stream); |
---|
| 1799 | + ret = dpcm_be_dai_startup(fe, stream); |
---|
2012 | 1800 | if (ret < 0) { |
---|
2013 | 1801 | dev_err(fe->dev,"ASoC: failed to start some BEs %d\n", ret); |
---|
2014 | 1802 | goto be_err; |
---|
.. | .. |
---|
2029 | 1817 | snd_pcm_limit_hw_rates(runtime); |
---|
2030 | 1818 | |
---|
2031 | 1819 | ret = dpcm_apply_symmetry(fe_substream, stream); |
---|
2032 | | - if (ret < 0) { |
---|
| 1820 | + if (ret < 0) |
---|
2033 | 1821 | dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n", |
---|
2034 | 1822 | ret); |
---|
2035 | | - goto unwind; |
---|
2036 | | - } |
---|
2037 | | - |
---|
2038 | | - dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); |
---|
2039 | | - return 0; |
---|
2040 | 1823 | |
---|
2041 | 1824 | unwind: |
---|
2042 | | - dpcm_be_dai_startup_unwind(fe, fe_substream->stream); |
---|
| 1825 | + if (ret < 0) |
---|
| 1826 | + dpcm_be_dai_startup_unwind(fe, stream); |
---|
2043 | 1827 | be_err: |
---|
2044 | 1828 | dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); |
---|
2045 | 1829 | return ret; |
---|
.. | .. |
---|
2050 | 1834 | struct snd_soc_dpcm *dpcm; |
---|
2051 | 1835 | |
---|
2052 | 1836 | /* only shutdown BEs that are either sinks or sources to this FE DAI */ |
---|
2053 | | - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
---|
| 1837 | + for_each_dpcm_be(fe, stream, dpcm) { |
---|
2054 | 1838 | |
---|
2055 | 1839 | struct snd_soc_pcm_runtime *be = dpcm->be; |
---|
2056 | 1840 | struct snd_pcm_substream *be_substream = |
---|
.. | .. |
---|
2087 | 1871 | |
---|
2088 | 1872 | static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream) |
---|
2089 | 1873 | { |
---|
2090 | | - struct snd_soc_pcm_runtime *fe = substream->private_data; |
---|
| 1874 | + struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); |
---|
2091 | 1875 | int stream = substream->stream; |
---|
2092 | 1876 | |
---|
2093 | 1877 | dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE); |
---|
2094 | 1878 | |
---|
2095 | 1879 | /* shutdown the BEs */ |
---|
2096 | | - dpcm_be_dai_shutdown(fe, substream->stream); |
---|
| 1880 | + dpcm_be_dai_shutdown(fe, stream); |
---|
2097 | 1881 | |
---|
2098 | 1882 | dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name); |
---|
2099 | 1883 | |
---|
.. | .. |
---|
2114 | 1898 | |
---|
2115 | 1899 | /* only hw_params backends that are either sinks or sources |
---|
2116 | 1900 | * to this frontend DAI */ |
---|
2117 | | - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
---|
| 1901 | + for_each_dpcm_be(fe, stream, dpcm) { |
---|
2118 | 1902 | |
---|
2119 | 1903 | struct snd_soc_pcm_runtime *be = dpcm->be; |
---|
2120 | 1904 | struct snd_pcm_substream *be_substream = |
---|
.. | .. |
---|
2153 | 1937 | |
---|
2154 | 1938 | static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream) |
---|
2155 | 1939 | { |
---|
2156 | | - struct snd_soc_pcm_runtime *fe = substream->private_data; |
---|
| 1940 | + struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); |
---|
2157 | 1941 | int err, stream = substream->stream; |
---|
2158 | 1942 | |
---|
2159 | 1943 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
---|
.. | .. |
---|
2183 | 1967 | struct snd_soc_dpcm *dpcm; |
---|
2184 | 1968 | int ret; |
---|
2185 | 1969 | |
---|
2186 | | - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
---|
| 1970 | + for_each_dpcm_be(fe, stream, dpcm) { |
---|
2187 | 1971 | |
---|
2188 | 1972 | struct snd_soc_pcm_runtime *be = dpcm->be; |
---|
2189 | 1973 | struct snd_pcm_substream *be_substream = |
---|
.. | .. |
---|
2198 | 1982 | sizeof(struct snd_pcm_hw_params)); |
---|
2199 | 1983 | |
---|
2200 | 1984 | /* perform any hw_params fixups */ |
---|
2201 | | - if (be->dai_link->be_hw_params_fixup) { |
---|
2202 | | - ret = be->dai_link->be_hw_params_fixup(be, |
---|
2203 | | - &dpcm->hw_params); |
---|
2204 | | - if (ret < 0) { |
---|
2205 | | - dev_err(be->dev, |
---|
2206 | | - "ASoC: hw_params BE fixup failed %d\n", |
---|
2207 | | - ret); |
---|
2208 | | - goto unwind; |
---|
2209 | | - } |
---|
2210 | | - } |
---|
| 1985 | + ret = snd_soc_link_be_hw_params_fixup(be, &dpcm->hw_params); |
---|
| 1986 | + if (ret < 0) |
---|
| 1987 | + goto unwind; |
---|
| 1988 | + |
---|
| 1989 | + /* copy the fixed-up hw params for BE dai */ |
---|
| 1990 | + memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params, |
---|
| 1991 | + sizeof(struct snd_pcm_hw_params)); |
---|
2211 | 1992 | |
---|
2212 | 1993 | /* only allow hw_params() if no connected FEs are running */ |
---|
2213 | 1994 | if (!snd_soc_dpcm_can_be_params(fe, be, stream)) |
---|
.. | .. |
---|
2234 | 2015 | |
---|
2235 | 2016 | unwind: |
---|
2236 | 2017 | /* disable any enabled and non active backends */ |
---|
2237 | | - list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
---|
| 2018 | + for_each_dpcm_be_rollback(fe, stream, dpcm) { |
---|
2238 | 2019 | struct snd_soc_pcm_runtime *be = dpcm->be; |
---|
2239 | 2020 | struct snd_pcm_substream *be_substream = |
---|
2240 | 2021 | snd_soc_dpcm_get_substream(be, stream); |
---|
.. | .. |
---|
2261 | 2042 | static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream, |
---|
2262 | 2043 | struct snd_pcm_hw_params *params) |
---|
2263 | 2044 | { |
---|
2264 | | - struct snd_soc_pcm_runtime *fe = substream->private_data; |
---|
| 2045 | + struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); |
---|
2265 | 2046 | int ret, stream = substream->stream; |
---|
2266 | 2047 | |
---|
2267 | 2048 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
---|
2268 | 2049 | dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE); |
---|
2269 | 2050 | |
---|
2270 | | - memcpy(&fe->dpcm[substream->stream].hw_params, params, |
---|
| 2051 | + memcpy(&fe->dpcm[stream].hw_params, params, |
---|
2271 | 2052 | sizeof(struct snd_pcm_hw_params)); |
---|
2272 | | - ret = dpcm_be_dai_hw_params(fe, substream->stream); |
---|
| 2053 | + ret = dpcm_be_dai_hw_params(fe, stream); |
---|
2273 | 2054 | if (ret < 0) { |
---|
2274 | 2055 | dev_err(fe->dev,"ASoC: hw_params BE failed %d\n", ret); |
---|
2275 | 2056 | goto out; |
---|
.. | .. |
---|
2314 | 2095 | struct snd_soc_dpcm *dpcm; |
---|
2315 | 2096 | int ret = 0; |
---|
2316 | 2097 | |
---|
2317 | | - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
---|
| 2098 | + for_each_dpcm_be(fe, stream, dpcm) { |
---|
2318 | 2099 | |
---|
2319 | 2100 | struct snd_soc_pcm_runtime *be = dpcm->be; |
---|
2320 | 2101 | struct snd_pcm_substream *be_substream = |
---|
.. | .. |
---|
2407 | 2188 | static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream, |
---|
2408 | 2189 | int cmd, bool fe_first) |
---|
2409 | 2190 | { |
---|
2410 | | - struct snd_soc_pcm_runtime *fe = substream->private_data; |
---|
| 2191 | + struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); |
---|
2411 | 2192 | int ret; |
---|
2412 | 2193 | |
---|
2413 | 2194 | /* call trigger on the frontend before the backend. */ |
---|
.. | .. |
---|
2438 | 2219 | |
---|
2439 | 2220 | static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) |
---|
2440 | 2221 | { |
---|
2441 | | - struct snd_soc_pcm_runtime *fe = substream->private_data; |
---|
| 2222 | + struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); |
---|
2442 | 2223 | int stream = substream->stream; |
---|
2443 | 2224 | int ret = 0; |
---|
2444 | 2225 | enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; |
---|
.. | .. |
---|
2488 | 2269 | dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n", |
---|
2489 | 2270 | fe->dai_link->name, cmd); |
---|
2490 | 2271 | |
---|
2491 | | - ret = soc_pcm_bespoke_trigger(substream, cmd); |
---|
| 2272 | + ret = snd_soc_pcm_dai_bespoke_trigger(substream, cmd); |
---|
2492 | 2273 | break; |
---|
2493 | 2274 | default: |
---|
2494 | 2275 | dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd, |
---|
.. | .. |
---|
2525 | 2306 | |
---|
2526 | 2307 | static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd) |
---|
2527 | 2308 | { |
---|
2528 | | - struct snd_soc_pcm_runtime *fe = substream->private_data; |
---|
| 2309 | + struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); |
---|
2529 | 2310 | int stream = substream->stream; |
---|
2530 | 2311 | |
---|
2531 | 2312 | /* if FE's runtime_update is already set, we're in race; |
---|
.. | .. |
---|
2545 | 2326 | struct snd_soc_dpcm *dpcm; |
---|
2546 | 2327 | int ret = 0; |
---|
2547 | 2328 | |
---|
2548 | | - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
---|
| 2329 | + for_each_dpcm_be(fe, stream, dpcm) { |
---|
2549 | 2330 | |
---|
2550 | 2331 | struct snd_soc_pcm_runtime *be = dpcm->be; |
---|
2551 | 2332 | struct snd_pcm_substream *be_substream = |
---|
.. | .. |
---|
2553 | 2334 | |
---|
2554 | 2335 | /* is this op for this BE ? */ |
---|
2555 | 2336 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) |
---|
| 2337 | + continue; |
---|
| 2338 | + |
---|
| 2339 | + if (!snd_soc_dpcm_can_be_prepared(fe, be, stream)) |
---|
2556 | 2340 | continue; |
---|
2557 | 2341 | |
---|
2558 | 2342 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && |
---|
.. | .. |
---|
2578 | 2362 | |
---|
2579 | 2363 | static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) |
---|
2580 | 2364 | { |
---|
2581 | | - struct snd_soc_pcm_runtime *fe = substream->private_data; |
---|
| 2365 | + struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); |
---|
2582 | 2366 | int stream = substream->stream, ret = 0; |
---|
2583 | 2367 | |
---|
2584 | 2368 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
---|
.. | .. |
---|
2595 | 2379 | goto out; |
---|
2596 | 2380 | } |
---|
2597 | 2381 | |
---|
2598 | | - ret = dpcm_be_dai_prepare(fe, substream->stream); |
---|
| 2382 | + ret = dpcm_be_dai_prepare(fe, stream); |
---|
2599 | 2383 | if (ret < 0) |
---|
2600 | 2384 | goto out; |
---|
2601 | 2385 | |
---|
.. | .. |
---|
2618 | 2402 | return ret; |
---|
2619 | 2403 | } |
---|
2620 | 2404 | |
---|
2621 | | -static int soc_pcm_ioctl(struct snd_pcm_substream *substream, |
---|
2622 | | - unsigned int cmd, void *arg) |
---|
2623 | | -{ |
---|
2624 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
2625 | | - struct snd_soc_component *component; |
---|
2626 | | - struct snd_soc_rtdcom_list *rtdcom; |
---|
2627 | | - |
---|
2628 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
2629 | | - component = rtdcom->component; |
---|
2630 | | - |
---|
2631 | | - if (!component->driver->ops || |
---|
2632 | | - !component->driver->ops->ioctl) |
---|
2633 | | - continue; |
---|
2634 | | - |
---|
2635 | | - /* FIXME: use 1st ioctl */ |
---|
2636 | | - return component->driver->ops->ioctl(substream, cmd, arg); |
---|
2637 | | - } |
---|
2638 | | - |
---|
2639 | | - return snd_pcm_lib_ioctl(substream, cmd, arg); |
---|
2640 | | -} |
---|
2641 | | - |
---|
2642 | 2405 | static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) |
---|
2643 | 2406 | { |
---|
2644 | 2407 | struct snd_pcm_substream *substream = |
---|
.. | .. |
---|
2654 | 2417 | dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n", |
---|
2655 | 2418 | fe->dai_link->name); |
---|
2656 | 2419 | |
---|
2657 | | - err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP); |
---|
| 2420 | + err = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP); |
---|
2658 | 2421 | if (err < 0) |
---|
2659 | 2422 | dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err); |
---|
2660 | 2423 | } else { |
---|
.. | .. |
---|
2687 | 2450 | struct snd_soc_dpcm *dpcm; |
---|
2688 | 2451 | enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; |
---|
2689 | 2452 | int ret; |
---|
| 2453 | + unsigned long flags; |
---|
2690 | 2454 | |
---|
2691 | 2455 | dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n", |
---|
2692 | 2456 | stream ? "capture" : "playback", fe->dai_link->name); |
---|
.. | .. |
---|
2731 | 2495 | dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n", |
---|
2732 | 2496 | fe->dai_link->name); |
---|
2733 | 2497 | |
---|
2734 | | - ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START); |
---|
| 2498 | + ret = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START); |
---|
2735 | 2499 | if (ret < 0) { |
---|
2736 | 2500 | dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret); |
---|
2737 | 2501 | goto hw_free; |
---|
.. | .. |
---|
2755 | 2519 | close: |
---|
2756 | 2520 | dpcm_be_dai_shutdown(fe, stream); |
---|
2757 | 2521 | disconnect: |
---|
2758 | | - /* disconnect any non started BEs */ |
---|
2759 | | - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
---|
| 2522 | + /* disconnect any closed BEs */ |
---|
| 2523 | + spin_lock_irqsave(&fe->card->dpcm_lock, flags); |
---|
| 2524 | + for_each_dpcm_be(fe, stream, dpcm) { |
---|
2760 | 2525 | struct snd_soc_pcm_runtime *be = dpcm->be; |
---|
2761 | | - if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) |
---|
2762 | | - dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; |
---|
| 2526 | + if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE) |
---|
| 2527 | + dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; |
---|
2763 | 2528 | } |
---|
2764 | | - |
---|
2765 | | - return ret; |
---|
2766 | | -} |
---|
2767 | | - |
---|
2768 | | -static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream) |
---|
2769 | | -{ |
---|
2770 | | - int ret; |
---|
2771 | | - |
---|
2772 | | - dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE); |
---|
2773 | | - ret = dpcm_run_update_startup(fe, stream); |
---|
2774 | | - if (ret < 0) |
---|
2775 | | - dev_err(fe->dev, "ASoC: failed to startup some BEs\n"); |
---|
2776 | | - dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); |
---|
2777 | | - |
---|
2778 | | - return ret; |
---|
2779 | | -} |
---|
2780 | | - |
---|
2781 | | -static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream) |
---|
2782 | | -{ |
---|
2783 | | - int ret; |
---|
2784 | | - |
---|
2785 | | - dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE); |
---|
2786 | | - ret = dpcm_run_update_shutdown(fe, stream); |
---|
2787 | | - if (ret < 0) |
---|
2788 | | - dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n"); |
---|
2789 | | - dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); |
---|
| 2529 | + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); |
---|
2790 | 2530 | |
---|
2791 | 2531 | return ret; |
---|
2792 | 2532 | } |
---|
.. | .. |
---|
2794 | 2534 | static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new) |
---|
2795 | 2535 | { |
---|
2796 | 2536 | struct snd_soc_dapm_widget_list *list; |
---|
| 2537 | + int stream; |
---|
2797 | 2538 | int count, paths; |
---|
| 2539 | + int ret; |
---|
2798 | 2540 | |
---|
2799 | 2541 | if (!fe->dai_link->dynamic) |
---|
2800 | 2542 | return 0; |
---|
2801 | 2543 | |
---|
| 2544 | + if (fe->num_cpus > 1) { |
---|
| 2545 | + dev_err(fe->dev, |
---|
| 2546 | + "%s doesn't support Multi CPU yet\n", __func__); |
---|
| 2547 | + return -EINVAL; |
---|
| 2548 | + } |
---|
| 2549 | + |
---|
2802 | 2550 | /* only check active links */ |
---|
2803 | | - if (!fe->cpu_dai->active) |
---|
| 2551 | + if (!snd_soc_dai_active(asoc_rtd_to_cpu(fe, 0))) |
---|
2804 | 2552 | return 0; |
---|
2805 | 2553 | |
---|
2806 | 2554 | /* DAPM sync will call this to update DSP paths */ |
---|
2807 | 2555 | dev_dbg(fe->dev, "ASoC: DPCM %s runtime update for FE %s\n", |
---|
2808 | 2556 | new ? "new" : "old", fe->dai_link->name); |
---|
2809 | 2557 | |
---|
2810 | | - /* skip if FE doesn't have playback capability */ |
---|
2811 | | - if (!fe->cpu_dai->driver->playback.channels_min || |
---|
2812 | | - !fe->codec_dai->driver->playback.channels_min) |
---|
2813 | | - goto capture; |
---|
| 2558 | + for_each_pcm_streams(stream) { |
---|
2814 | 2559 | |
---|
2815 | | - /* skip if FE isn't currently playing */ |
---|
2816 | | - if (!fe->cpu_dai->playback_active || !fe->codec_dai->playback_active) |
---|
2817 | | - goto capture; |
---|
| 2560 | + /* skip if FE doesn't have playback/capture capability */ |
---|
| 2561 | + if (!snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0), stream) || |
---|
| 2562 | + !snd_soc_dai_stream_valid(asoc_rtd_to_codec(fe, 0), stream)) |
---|
| 2563 | + continue; |
---|
2818 | 2564 | |
---|
2819 | | - paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list); |
---|
2820 | | - if (paths < 0) { |
---|
2821 | | - dev_warn(fe->dev, "ASoC: %s no valid %s path\n", |
---|
2822 | | - fe->dai_link->name, "playback"); |
---|
2823 | | - return paths; |
---|
| 2565 | + /* skip if FE isn't currently playing/capturing */ |
---|
| 2566 | + if (!snd_soc_dai_stream_active(asoc_rtd_to_cpu(fe, 0), stream) || |
---|
| 2567 | + !snd_soc_dai_stream_active(asoc_rtd_to_codec(fe, 0), stream)) |
---|
| 2568 | + continue; |
---|
| 2569 | + |
---|
| 2570 | + paths = dpcm_path_get(fe, stream, &list); |
---|
| 2571 | + if (paths < 0) { |
---|
| 2572 | + dev_warn(fe->dev, "ASoC: %s no valid %s path\n", |
---|
| 2573 | + fe->dai_link->name, |
---|
| 2574 | + stream == SNDRV_PCM_STREAM_PLAYBACK ? |
---|
| 2575 | + "playback" : "capture"); |
---|
| 2576 | + return paths; |
---|
| 2577 | + } |
---|
| 2578 | + |
---|
| 2579 | + /* update any playback/capture paths */ |
---|
| 2580 | + count = dpcm_process_paths(fe, stream, &list, new); |
---|
| 2581 | + if (count) { |
---|
| 2582 | + dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE); |
---|
| 2583 | + if (new) |
---|
| 2584 | + ret = dpcm_run_update_startup(fe, stream); |
---|
| 2585 | + else |
---|
| 2586 | + ret = dpcm_run_update_shutdown(fe, stream); |
---|
| 2587 | + if (ret < 0) |
---|
| 2588 | + dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n"); |
---|
| 2589 | + dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); |
---|
| 2590 | + |
---|
| 2591 | + dpcm_clear_pending_state(fe, stream); |
---|
| 2592 | + dpcm_be_disconnect(fe, stream); |
---|
| 2593 | + } |
---|
| 2594 | + |
---|
| 2595 | + dpcm_path_put(&list); |
---|
2824 | 2596 | } |
---|
2825 | | - |
---|
2826 | | - /* update any playback paths */ |
---|
2827 | | - count = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, new); |
---|
2828 | | - if (count) { |
---|
2829 | | - if (new) |
---|
2830 | | - dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK); |
---|
2831 | | - else |
---|
2832 | | - dpcm_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK); |
---|
2833 | | - |
---|
2834 | | - dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK); |
---|
2835 | | - dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK); |
---|
2836 | | - } |
---|
2837 | | - |
---|
2838 | | - dpcm_path_put(&list); |
---|
2839 | | - |
---|
2840 | | -capture: |
---|
2841 | | - /* skip if FE doesn't have capture capability */ |
---|
2842 | | - if (!fe->cpu_dai->driver->capture.channels_min || |
---|
2843 | | - !fe->codec_dai->driver->capture.channels_min) |
---|
2844 | | - return 0; |
---|
2845 | | - |
---|
2846 | | - /* skip if FE isn't currently capturing */ |
---|
2847 | | - if (!fe->cpu_dai->capture_active || !fe->codec_dai->capture_active) |
---|
2848 | | - return 0; |
---|
2849 | | - |
---|
2850 | | - paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list); |
---|
2851 | | - if (paths < 0) { |
---|
2852 | | - dev_warn(fe->dev, "ASoC: %s no valid %s path\n", |
---|
2853 | | - fe->dai_link->name, "capture"); |
---|
2854 | | - return paths; |
---|
2855 | | - } |
---|
2856 | | - |
---|
2857 | | - /* update any old capture paths */ |
---|
2858 | | - count = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, new); |
---|
2859 | | - if (count) { |
---|
2860 | | - if (new) |
---|
2861 | | - dpcm_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE); |
---|
2862 | | - else |
---|
2863 | | - dpcm_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE); |
---|
2864 | | - |
---|
2865 | | - dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE); |
---|
2866 | | - dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE); |
---|
2867 | | - } |
---|
2868 | | - |
---|
2869 | | - dpcm_path_put(&list); |
---|
2870 | 2597 | |
---|
2871 | 2598 | return 0; |
---|
2872 | 2599 | } |
---|
.. | .. |
---|
2874 | 2601 | /* Called by DAPM mixer/mux changes to update audio routing between PCMs and |
---|
2875 | 2602 | * any DAI links. |
---|
2876 | 2603 | */ |
---|
2877 | | -int soc_dpcm_runtime_update(struct snd_soc_card *card) |
---|
| 2604 | +int snd_soc_dpcm_runtime_update(struct snd_soc_card *card) |
---|
2878 | 2605 | { |
---|
2879 | 2606 | struct snd_soc_pcm_runtime *fe; |
---|
2880 | 2607 | int ret = 0; |
---|
2881 | 2608 | |
---|
2882 | 2609 | mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
---|
2883 | 2610 | /* shutdown all old paths first */ |
---|
2884 | | - list_for_each_entry(fe, &card->rtd_list, list) { |
---|
| 2611 | + for_each_card_rtds(card, fe) { |
---|
2885 | 2612 | ret = soc_dpcm_fe_runtime_update(fe, 0); |
---|
2886 | 2613 | if (ret) |
---|
2887 | 2614 | goto out; |
---|
2888 | 2615 | } |
---|
2889 | 2616 | |
---|
2890 | 2617 | /* bring new paths up */ |
---|
2891 | | - list_for_each_entry(fe, &card->rtd_list, list) { |
---|
| 2618 | + for_each_card_rtds(card, fe) { |
---|
2892 | 2619 | ret = soc_dpcm_fe_runtime_update(fe, 1); |
---|
2893 | 2620 | if (ret) |
---|
2894 | 2621 | goto out; |
---|
.. | .. |
---|
2898 | 2625 | mutex_unlock(&card->mutex); |
---|
2899 | 2626 | return ret; |
---|
2900 | 2627 | } |
---|
2901 | | -int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) |
---|
| 2628 | +EXPORT_SYMBOL_GPL(snd_soc_dpcm_runtime_update); |
---|
| 2629 | + |
---|
| 2630 | +static void dpcm_fe_dai_cleanup(struct snd_pcm_substream *fe_substream) |
---|
2902 | 2631 | { |
---|
| 2632 | + struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream); |
---|
2903 | 2633 | struct snd_soc_dpcm *dpcm; |
---|
2904 | | - struct list_head *clients = |
---|
2905 | | - &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients; |
---|
| 2634 | + int stream = fe_substream->stream; |
---|
2906 | 2635 | |
---|
2907 | | - list_for_each_entry(dpcm, clients, list_be) { |
---|
| 2636 | + /* mark FE's links ready to prune */ |
---|
| 2637 | + for_each_dpcm_be(fe, stream, dpcm) |
---|
| 2638 | + dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; |
---|
2908 | 2639 | |
---|
2909 | | - struct snd_soc_pcm_runtime *be = dpcm->be; |
---|
2910 | | - int i; |
---|
| 2640 | + dpcm_be_disconnect(fe, stream); |
---|
2911 | 2641 | |
---|
2912 | | - if (be->dai_link->ignore_suspend) |
---|
2913 | | - continue; |
---|
| 2642 | + fe->dpcm[stream].runtime = NULL; |
---|
| 2643 | +} |
---|
2914 | 2644 | |
---|
2915 | | - for (i = 0; i < be->num_codecs; i++) { |
---|
2916 | | - struct snd_soc_dai *dai = be->codec_dais[i]; |
---|
2917 | | - struct snd_soc_dai_driver *drv = dai->driver; |
---|
| 2645 | +static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) |
---|
| 2646 | +{ |
---|
| 2647 | + struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream); |
---|
| 2648 | + int ret; |
---|
2918 | 2649 | |
---|
2919 | | - dev_dbg(be->dev, "ASoC: BE digital mute %s\n", |
---|
2920 | | - be->dai_link->name); |
---|
| 2650 | + mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
---|
| 2651 | + ret = dpcm_fe_dai_shutdown(fe_substream); |
---|
2921 | 2652 | |
---|
2922 | | - if (drv->ops && drv->ops->digital_mute && |
---|
2923 | | - dai->playback_active) |
---|
2924 | | - drv->ops->digital_mute(dai, mute); |
---|
2925 | | - } |
---|
2926 | | - } |
---|
| 2653 | + dpcm_fe_dai_cleanup(fe_substream); |
---|
2927 | 2654 | |
---|
2928 | | - return 0; |
---|
| 2655 | + mutex_unlock(&fe->card->mutex); |
---|
| 2656 | + return ret; |
---|
2929 | 2657 | } |
---|
2930 | 2658 | |
---|
2931 | 2659 | static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) |
---|
2932 | 2660 | { |
---|
2933 | | - struct snd_soc_pcm_runtime *fe = fe_substream->private_data; |
---|
2934 | | - struct snd_soc_dpcm *dpcm; |
---|
| 2661 | + struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream); |
---|
2935 | 2662 | struct snd_soc_dapm_widget_list *list; |
---|
2936 | 2663 | int ret; |
---|
2937 | 2664 | int stream = fe_substream->stream; |
---|
.. | .. |
---|
2941 | 2668 | |
---|
2942 | 2669 | ret = dpcm_path_get(fe, stream, &list); |
---|
2943 | 2670 | if (ret < 0) { |
---|
2944 | | - mutex_unlock(&fe->card->mutex); |
---|
2945 | | - return ret; |
---|
| 2671 | + goto open_end; |
---|
2946 | 2672 | } else if (ret == 0) { |
---|
2947 | 2673 | dev_dbg(fe->dev, "ASoC: %s no valid %s route\n", |
---|
2948 | 2674 | fe->dai_link->name, stream ? "capture" : "playback"); |
---|
.. | .. |
---|
2952 | 2678 | dpcm_process_paths(fe, stream, &list, 1); |
---|
2953 | 2679 | |
---|
2954 | 2680 | ret = dpcm_fe_dai_startup(fe_substream); |
---|
2955 | | - if (ret < 0) { |
---|
2956 | | - /* clean up all links */ |
---|
2957 | | - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) |
---|
2958 | | - dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; |
---|
2959 | | - |
---|
2960 | | - dpcm_be_disconnect(fe, stream); |
---|
2961 | | - fe->dpcm[stream].runtime = NULL; |
---|
2962 | | - } |
---|
| 2681 | + if (ret < 0) |
---|
| 2682 | + dpcm_fe_dai_cleanup(fe_substream); |
---|
2963 | 2683 | |
---|
2964 | 2684 | dpcm_clear_pending_state(fe, stream); |
---|
2965 | 2685 | dpcm_path_put(&list); |
---|
| 2686 | +open_end: |
---|
2966 | 2687 | mutex_unlock(&fe->card->mutex); |
---|
2967 | 2688 | return ret; |
---|
2968 | | -} |
---|
2969 | | - |
---|
2970 | | -static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) |
---|
2971 | | -{ |
---|
2972 | | - struct snd_soc_pcm_runtime *fe = fe_substream->private_data; |
---|
2973 | | - struct snd_soc_dpcm *dpcm; |
---|
2974 | | - int stream = fe_substream->stream, ret; |
---|
2975 | | - |
---|
2976 | | - mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
---|
2977 | | - ret = dpcm_fe_dai_shutdown(fe_substream); |
---|
2978 | | - |
---|
2979 | | - /* mark FE's links ready to prune */ |
---|
2980 | | - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) |
---|
2981 | | - dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; |
---|
2982 | | - |
---|
2983 | | - dpcm_be_disconnect(fe, stream); |
---|
2984 | | - |
---|
2985 | | - fe->dpcm[stream].runtime = NULL; |
---|
2986 | | - mutex_unlock(&fe->card->mutex); |
---|
2987 | | - return ret; |
---|
2988 | | -} |
---|
2989 | | - |
---|
2990 | | -static void soc_pcm_private_free(struct snd_pcm *pcm) |
---|
2991 | | -{ |
---|
2992 | | - struct snd_soc_pcm_runtime *rtd = pcm->private_data; |
---|
2993 | | - struct snd_soc_rtdcom_list *rtdcom; |
---|
2994 | | - struct snd_soc_component *component; |
---|
2995 | | - |
---|
2996 | | - /* need to sync the delayed work before releasing resources */ |
---|
2997 | | - flush_delayed_work(&rtd->delayed_work); |
---|
2998 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
2999 | | - component = rtdcom->component; |
---|
3000 | | - |
---|
3001 | | - if (component->driver->pcm_free) |
---|
3002 | | - component->driver->pcm_free(pcm); |
---|
3003 | | - } |
---|
3004 | | -} |
---|
3005 | | - |
---|
3006 | | -static int soc_rtdcom_ack(struct snd_pcm_substream *substream) |
---|
3007 | | -{ |
---|
3008 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
3009 | | - struct snd_soc_rtdcom_list *rtdcom; |
---|
3010 | | - struct snd_soc_component *component; |
---|
3011 | | - |
---|
3012 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
3013 | | - component = rtdcom->component; |
---|
3014 | | - |
---|
3015 | | - if (!component->driver->ops || |
---|
3016 | | - !component->driver->ops->ack) |
---|
3017 | | - continue; |
---|
3018 | | - |
---|
3019 | | - /* FIXME. it returns 1st ask now */ |
---|
3020 | | - return component->driver->ops->ack(substream); |
---|
3021 | | - } |
---|
3022 | | - |
---|
3023 | | - return -EINVAL; |
---|
3024 | | -} |
---|
3025 | | - |
---|
3026 | | -static int soc_rtdcom_copy_user(struct snd_pcm_substream *substream, int channel, |
---|
3027 | | - unsigned long pos, void __user *buf, |
---|
3028 | | - unsigned long bytes) |
---|
3029 | | -{ |
---|
3030 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
3031 | | - struct snd_soc_rtdcom_list *rtdcom; |
---|
3032 | | - struct snd_soc_component *component; |
---|
3033 | | - |
---|
3034 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
3035 | | - component = rtdcom->component; |
---|
3036 | | - |
---|
3037 | | - if (!component->driver->ops || |
---|
3038 | | - !component->driver->ops->copy_user) |
---|
3039 | | - continue; |
---|
3040 | | - |
---|
3041 | | - /* FIXME. it returns 1st copy now */ |
---|
3042 | | - return component->driver->ops->copy_user(substream, channel, |
---|
3043 | | - pos, buf, bytes); |
---|
3044 | | - } |
---|
3045 | | - |
---|
3046 | | - return -EINVAL; |
---|
3047 | | -} |
---|
3048 | | - |
---|
3049 | | -static int soc_rtdcom_copy_kernel(struct snd_pcm_substream *substream, int channel, |
---|
3050 | | - unsigned long pos, void *buf, unsigned long bytes) |
---|
3051 | | -{ |
---|
3052 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
3053 | | - struct snd_soc_rtdcom_list *rtdcom; |
---|
3054 | | - struct snd_soc_component *component; |
---|
3055 | | - |
---|
3056 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
3057 | | - component = rtdcom->component; |
---|
3058 | | - |
---|
3059 | | - if (!component->driver->ops || |
---|
3060 | | - !component->driver->ops->copy_kernel) |
---|
3061 | | - continue; |
---|
3062 | | - |
---|
3063 | | - /* FIXME. it returns 1st copy now */ |
---|
3064 | | - return component->driver->ops->copy_kernel(substream, channel, |
---|
3065 | | - pos, buf, bytes); |
---|
3066 | | - } |
---|
3067 | | - |
---|
3068 | | - return -EINVAL; |
---|
3069 | | -} |
---|
3070 | | - |
---|
3071 | | -static int soc_rtdcom_fill_silence(struct snd_pcm_substream *substream, int channel, |
---|
3072 | | - unsigned long pos, unsigned long bytes) |
---|
3073 | | -{ |
---|
3074 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
3075 | | - struct snd_soc_rtdcom_list *rtdcom; |
---|
3076 | | - struct snd_soc_component *component; |
---|
3077 | | - |
---|
3078 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
3079 | | - component = rtdcom->component; |
---|
3080 | | - |
---|
3081 | | - if (!component->driver->ops || |
---|
3082 | | - !component->driver->ops->fill_silence) |
---|
3083 | | - continue; |
---|
3084 | | - |
---|
3085 | | - /* FIXME. it returns 1st silence now */ |
---|
3086 | | - return component->driver->ops->fill_silence(substream, channel, |
---|
3087 | | - pos, bytes); |
---|
3088 | | - } |
---|
3089 | | - |
---|
3090 | | - return -EINVAL; |
---|
3091 | | -} |
---|
3092 | | - |
---|
3093 | | -static struct page *soc_rtdcom_page(struct snd_pcm_substream *substream, |
---|
3094 | | - unsigned long offset) |
---|
3095 | | -{ |
---|
3096 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
3097 | | - struct snd_soc_rtdcom_list *rtdcom; |
---|
3098 | | - struct snd_soc_component *component; |
---|
3099 | | - struct page *page; |
---|
3100 | | - |
---|
3101 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
3102 | | - component = rtdcom->component; |
---|
3103 | | - |
---|
3104 | | - if (!component->driver->ops || |
---|
3105 | | - !component->driver->ops->page) |
---|
3106 | | - continue; |
---|
3107 | | - |
---|
3108 | | - /* FIXME. it returns 1st page now */ |
---|
3109 | | - page = component->driver->ops->page(substream, offset); |
---|
3110 | | - if (page) |
---|
3111 | | - return page; |
---|
3112 | | - } |
---|
3113 | | - |
---|
3114 | | - return NULL; |
---|
3115 | | -} |
---|
3116 | | - |
---|
3117 | | -static int soc_rtdcom_mmap(struct snd_pcm_substream *substream, |
---|
3118 | | - struct vm_area_struct *vma) |
---|
3119 | | -{ |
---|
3120 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
3121 | | - struct snd_soc_rtdcom_list *rtdcom; |
---|
3122 | | - struct snd_soc_component *component; |
---|
3123 | | - |
---|
3124 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
3125 | | - component = rtdcom->component; |
---|
3126 | | - |
---|
3127 | | - if (!component->driver->ops || |
---|
3128 | | - !component->driver->ops->mmap) |
---|
3129 | | - continue; |
---|
3130 | | - |
---|
3131 | | - /* FIXME. it returns 1st mmap now */ |
---|
3132 | | - return component->driver->ops->mmap(substream, vma); |
---|
3133 | | - } |
---|
3134 | | - |
---|
3135 | | - return -EINVAL; |
---|
3136 | 2689 | } |
---|
3137 | 2690 | |
---|
3138 | 2691 | /* create a new pcm */ |
---|
3139 | 2692 | int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) |
---|
3140 | 2693 | { |
---|
3141 | 2694 | struct snd_soc_dai *codec_dai; |
---|
3142 | | - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
---|
| 2695 | + struct snd_soc_dai *cpu_dai; |
---|
3143 | 2696 | struct snd_soc_component *component; |
---|
3144 | | - struct snd_soc_rtdcom_list *rtdcom; |
---|
3145 | 2697 | struct snd_pcm *pcm; |
---|
3146 | | - struct snd_pcm_str *stream; |
---|
3147 | 2698 | char new_name[64]; |
---|
3148 | 2699 | int ret = 0, playback = 0, capture = 0; |
---|
| 2700 | + int stream; |
---|
3149 | 2701 | int i; |
---|
3150 | 2702 | |
---|
| 2703 | + if (rtd->dai_link->dynamic && rtd->num_cpus > 1) { |
---|
| 2704 | + dev_err(rtd->dev, |
---|
| 2705 | + "DPCM doesn't support Multi CPU for Front-Ends yet\n"); |
---|
| 2706 | + return -EINVAL; |
---|
| 2707 | + } |
---|
| 2708 | + |
---|
3151 | 2709 | if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) { |
---|
3152 | | - playback = rtd->dai_link->dpcm_playback; |
---|
3153 | | - capture = rtd->dai_link->dpcm_capture; |
---|
| 2710 | + if (rtd->dai_link->dpcm_playback) { |
---|
| 2711 | + stream = SNDRV_PCM_STREAM_PLAYBACK; |
---|
| 2712 | + |
---|
| 2713 | + for_each_rtd_cpu_dais(rtd, i, cpu_dai) { |
---|
| 2714 | + if (snd_soc_dai_stream_valid(cpu_dai, stream)) { |
---|
| 2715 | + playback = 1; |
---|
| 2716 | + break; |
---|
| 2717 | + } |
---|
| 2718 | + } |
---|
| 2719 | + |
---|
| 2720 | + if (!playback) { |
---|
| 2721 | + dev_err(rtd->card->dev, |
---|
| 2722 | + "No CPU DAIs support playback for stream %s\n", |
---|
| 2723 | + rtd->dai_link->stream_name); |
---|
| 2724 | + return -EINVAL; |
---|
| 2725 | + } |
---|
| 2726 | + } |
---|
| 2727 | + if (rtd->dai_link->dpcm_capture) { |
---|
| 2728 | + stream = SNDRV_PCM_STREAM_CAPTURE; |
---|
| 2729 | + |
---|
| 2730 | + for_each_rtd_cpu_dais(rtd, i, cpu_dai) { |
---|
| 2731 | + if (snd_soc_dai_stream_valid(cpu_dai, stream)) { |
---|
| 2732 | + capture = 1; |
---|
| 2733 | + break; |
---|
| 2734 | + } |
---|
| 2735 | + } |
---|
| 2736 | + |
---|
| 2737 | + if (!capture) { |
---|
| 2738 | + dev_err(rtd->card->dev, |
---|
| 2739 | + "No CPU DAIs support capture for stream %s\n", |
---|
| 2740 | + rtd->dai_link->stream_name); |
---|
| 2741 | + return -EINVAL; |
---|
| 2742 | + } |
---|
| 2743 | + } |
---|
3154 | 2744 | } else { |
---|
3155 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
3156 | | - codec_dai = rtd->codec_dais[i]; |
---|
3157 | | - if (codec_dai->driver->playback.channels_min) |
---|
| 2745 | + /* Adapt stream for codec2codec links */ |
---|
| 2746 | + int cpu_capture = rtd->dai_link->params ? |
---|
| 2747 | + SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; |
---|
| 2748 | + int cpu_playback = rtd->dai_link->params ? |
---|
| 2749 | + SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; |
---|
| 2750 | + |
---|
| 2751 | + for_each_rtd_codec_dais(rtd, i, codec_dai) { |
---|
| 2752 | + if (rtd->num_cpus == 1) { |
---|
| 2753 | + cpu_dai = asoc_rtd_to_cpu(rtd, 0); |
---|
| 2754 | + } else if (rtd->num_cpus == rtd->num_codecs) { |
---|
| 2755 | + cpu_dai = asoc_rtd_to_cpu(rtd, i); |
---|
| 2756 | + } else { |
---|
| 2757 | + dev_err(rtd->card->dev, |
---|
| 2758 | + "N cpus to M codecs link is not supported yet\n"); |
---|
| 2759 | + return -EINVAL; |
---|
| 2760 | + } |
---|
| 2761 | + |
---|
| 2762 | + if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && |
---|
| 2763 | + snd_soc_dai_stream_valid(cpu_dai, cpu_playback)) |
---|
3158 | 2764 | playback = 1; |
---|
3159 | | - if (codec_dai->driver->capture.channels_min) |
---|
| 2765 | + if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) && |
---|
| 2766 | + snd_soc_dai_stream_valid(cpu_dai, cpu_capture)) |
---|
3160 | 2767 | capture = 1; |
---|
3161 | 2768 | } |
---|
3162 | | - |
---|
3163 | | - capture = capture && cpu_dai->driver->capture.channels_min; |
---|
3164 | | - playback = playback && cpu_dai->driver->playback.channels_min; |
---|
3165 | 2769 | } |
---|
3166 | 2770 | |
---|
3167 | 2771 | if (rtd->dai_link->playback_only) { |
---|
.. | .. |
---|
3175 | 2779 | } |
---|
3176 | 2780 | |
---|
3177 | 2781 | /* create the PCM */ |
---|
3178 | | - if (rtd->dai_link->no_pcm) { |
---|
| 2782 | + if (rtd->dai_link->params) { |
---|
| 2783 | + snprintf(new_name, sizeof(new_name), "codec2codec(%s)", |
---|
| 2784 | + rtd->dai_link->stream_name); |
---|
| 2785 | + |
---|
| 2786 | + ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num, |
---|
| 2787 | + playback, capture, &pcm); |
---|
| 2788 | + } else if (rtd->dai_link->no_pcm) { |
---|
3179 | 2789 | snprintf(new_name, sizeof(new_name), "(%s)", |
---|
3180 | 2790 | rtd->dai_link->stream_name); |
---|
3181 | 2791 | |
---|
.. | .. |
---|
3189 | 2799 | snprintf(new_name, sizeof(new_name), "%s %s-%d", |
---|
3190 | 2800 | rtd->dai_link->stream_name, |
---|
3191 | 2801 | (rtd->num_codecs > 1) ? |
---|
3192 | | - "multicodec" : rtd->codec_dai->name, num); |
---|
| 2802 | + "multicodec" : asoc_rtd_to_codec(rtd, 0)->name, num); |
---|
3193 | 2803 | |
---|
3194 | 2804 | ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback, |
---|
3195 | 2805 | capture, &pcm); |
---|
3196 | 2806 | } |
---|
3197 | 2807 | if (ret < 0) { |
---|
3198 | | - dev_err(rtd->card->dev, "ASoC: can't create pcm for %s\n", |
---|
3199 | | - rtd->dai_link->name); |
---|
| 2808 | + dev_err(rtd->card->dev, "ASoC: can't create pcm %s for dailink %s: %d\n", |
---|
| 2809 | + new_name, rtd->dai_link->name, ret); |
---|
3200 | 2810 | return ret; |
---|
3201 | 2811 | } |
---|
3202 | 2812 | dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name); |
---|
3203 | 2813 | |
---|
3204 | 2814 | /* DAPM dai link stream work */ |
---|
3205 | | - INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); |
---|
| 2815 | + if (rtd->dai_link->params) |
---|
| 2816 | + rtd->close_delayed_work_func = codec2codec_close_delayed_work; |
---|
| 2817 | + else |
---|
| 2818 | + rtd->close_delayed_work_func = snd_soc_close_delayed_work; |
---|
3206 | 2819 | |
---|
3207 | 2820 | pcm->nonatomic = rtd->dai_link->nonatomic; |
---|
3208 | 2821 | rtd->pcm = pcm; |
---|
3209 | 2822 | pcm->private_data = rtd; |
---|
3210 | 2823 | |
---|
3211 | | - if (rtd->dai_link->no_pcm) { |
---|
| 2824 | + if (rtd->dai_link->no_pcm || rtd->dai_link->params) { |
---|
3212 | 2825 | if (playback) |
---|
3213 | 2826 | pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd; |
---|
3214 | 2827 | if (capture) |
---|
3215 | 2828 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd; |
---|
3216 | 2829 | goto out; |
---|
3217 | | - } |
---|
3218 | | - |
---|
3219 | | - /* setup any hostless PCMs - i.e. no host IO is performed */ |
---|
3220 | | - if (rtd->dai_link->no_host_mode) { |
---|
3221 | | - if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { |
---|
3222 | | - stream = &pcm->streams[SNDRV_PCM_STREAM_PLAYBACK]; |
---|
3223 | | - stream->substream->hw_no_buffer = 1; |
---|
3224 | | - snd_soc_set_runtime_hwparams(stream->substream, |
---|
3225 | | - &no_host_hardware); |
---|
3226 | | - } |
---|
3227 | | - if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { |
---|
3228 | | - stream = &pcm->streams[SNDRV_PCM_STREAM_CAPTURE]; |
---|
3229 | | - stream->substream->hw_no_buffer = 1; |
---|
3230 | | - snd_soc_set_runtime_hwparams(stream->substream, |
---|
3231 | | - &no_host_hardware); |
---|
3232 | | - } |
---|
3233 | 2830 | } |
---|
3234 | 2831 | |
---|
3235 | 2832 | /* ASoC PCM operations */ |
---|
.. | .. |
---|
3241 | 2838 | rtd->ops.hw_free = dpcm_fe_dai_hw_free; |
---|
3242 | 2839 | rtd->ops.close = dpcm_fe_dai_close; |
---|
3243 | 2840 | rtd->ops.pointer = soc_pcm_pointer; |
---|
3244 | | - rtd->ops.ioctl = soc_pcm_ioctl; |
---|
3245 | 2841 | } else { |
---|
3246 | 2842 | rtd->ops.open = soc_pcm_open; |
---|
3247 | 2843 | rtd->ops.hw_params = soc_pcm_hw_params; |
---|
.. | .. |
---|
3250 | 2846 | rtd->ops.hw_free = soc_pcm_hw_free; |
---|
3251 | 2847 | rtd->ops.close = soc_pcm_close; |
---|
3252 | 2848 | rtd->ops.pointer = soc_pcm_pointer; |
---|
3253 | | - rtd->ops.ioctl = soc_pcm_ioctl; |
---|
3254 | 2849 | } |
---|
3255 | 2850 | |
---|
3256 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
3257 | | - const struct snd_pcm_ops *ops = rtdcom->component->driver->ops; |
---|
| 2851 | + for_each_rtd_components(rtd, i, component) { |
---|
| 2852 | + const struct snd_soc_component_driver *drv = component->driver; |
---|
3258 | 2853 | |
---|
3259 | | - if (!ops) |
---|
3260 | | - continue; |
---|
3261 | | - |
---|
3262 | | - if (ops->ack) |
---|
3263 | | - rtd->ops.ack = soc_rtdcom_ack; |
---|
3264 | | - if (ops->copy_user) |
---|
3265 | | - rtd->ops.copy_user = soc_rtdcom_copy_user; |
---|
3266 | | - if (ops->copy_kernel) |
---|
3267 | | - rtd->ops.copy_kernel = soc_rtdcom_copy_kernel; |
---|
3268 | | - if (ops->fill_silence) |
---|
3269 | | - rtd->ops.fill_silence = soc_rtdcom_fill_silence; |
---|
3270 | | - if (ops->page) |
---|
3271 | | - rtd->ops.page = soc_rtdcom_page; |
---|
3272 | | - if (ops->mmap) |
---|
3273 | | - rtd->ops.mmap = soc_rtdcom_mmap; |
---|
| 2854 | + if (drv->ioctl) |
---|
| 2855 | + rtd->ops.ioctl = snd_soc_pcm_component_ioctl; |
---|
| 2856 | + if (drv->sync_stop) |
---|
| 2857 | + rtd->ops.sync_stop = snd_soc_pcm_component_sync_stop; |
---|
| 2858 | + if (drv->copy_user) |
---|
| 2859 | + rtd->ops.copy_user = snd_soc_pcm_component_copy_user; |
---|
| 2860 | + if (drv->page) |
---|
| 2861 | + rtd->ops.page = snd_soc_pcm_component_page; |
---|
| 2862 | + if (drv->mmap) |
---|
| 2863 | + rtd->ops.mmap = snd_soc_pcm_component_mmap; |
---|
| 2864 | + if (drv->ack) |
---|
| 2865 | + rtd->ops.ack = snd_soc_pcm_component_ack; |
---|
3274 | 2866 | } |
---|
3275 | 2867 | |
---|
3276 | 2868 | if (playback) |
---|
.. | .. |
---|
3279 | 2871 | if (capture) |
---|
3280 | 2872 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops); |
---|
3281 | 2873 | |
---|
3282 | | - for_each_rtdcom(rtd, rtdcom) { |
---|
3283 | | - component = rtdcom->component; |
---|
3284 | | - |
---|
3285 | | - if (!component->driver->pcm_new) |
---|
3286 | | - continue; |
---|
3287 | | - |
---|
3288 | | - ret = component->driver->pcm_new(rtd); |
---|
3289 | | - if (ret < 0) { |
---|
3290 | | - dev_err(component->dev, |
---|
3291 | | - "ASoC: pcm constructor failed: %d\n", |
---|
3292 | | - ret); |
---|
3293 | | - return ret; |
---|
3294 | | - } |
---|
| 2874 | + ret = snd_soc_pcm_component_new(rtd); |
---|
| 2875 | + if (ret < 0) { |
---|
| 2876 | + dev_err(rtd->dev, "ASoC: pcm %s constructor failed for dailink %s: %d\n", |
---|
| 2877 | + new_name, rtd->dai_link->name, ret); |
---|
| 2878 | + return ret; |
---|
3295 | 2879 | } |
---|
3296 | 2880 | |
---|
3297 | | - pcm->private_free = soc_pcm_private_free; |
---|
| 2881 | + pcm->no_device_suspend = true; |
---|
3298 | 2882 | out: |
---|
3299 | | - dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", |
---|
3300 | | - (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name, |
---|
3301 | | - cpu_dai->name); |
---|
| 2883 | + dev_dbg(rtd->card->dev, "%s <-> %s mapping ok\n", |
---|
| 2884 | + (rtd->num_codecs > 1) ? "multicodec" : asoc_rtd_to_codec(rtd, 0)->name, |
---|
| 2885 | + (rtd->num_cpus > 1) ? "multicpu" : asoc_rtd_to_cpu(rtd, 0)->name); |
---|
3302 | 2886 | return ret; |
---|
3303 | 2887 | } |
---|
3304 | 2888 | |
---|
.. | .. |
---|
3331 | 2915 | } |
---|
3332 | 2916 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream); |
---|
3333 | 2917 | |
---|
3334 | | -/* get the BE runtime state */ |
---|
3335 | | -enum snd_soc_dpcm_state |
---|
3336 | | - snd_soc_dpcm_be_get_state(struct snd_soc_pcm_runtime *be, int stream) |
---|
| 2918 | +static int snd_soc_dpcm_check_state(struct snd_soc_pcm_runtime *fe, |
---|
| 2919 | + struct snd_soc_pcm_runtime *be, |
---|
| 2920 | + int stream, |
---|
| 2921 | + const enum snd_soc_dpcm_state *states, |
---|
| 2922 | + int num_states) |
---|
3337 | 2923 | { |
---|
3338 | | - return be->dpcm[stream].state; |
---|
3339 | | -} |
---|
3340 | | -EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_get_state); |
---|
| 2924 | + struct snd_soc_dpcm *dpcm; |
---|
| 2925 | + int state; |
---|
| 2926 | + int ret = 1; |
---|
| 2927 | + unsigned long flags; |
---|
| 2928 | + int i; |
---|
3341 | 2929 | |
---|
3342 | | -/* set the BE runtime state */ |
---|
3343 | | -void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be, |
---|
3344 | | - int stream, enum snd_soc_dpcm_state state) |
---|
3345 | | -{ |
---|
3346 | | - be->dpcm[stream].state = state; |
---|
| 2930 | + spin_lock_irqsave(&fe->card->dpcm_lock, flags); |
---|
| 2931 | + for_each_dpcm_fe(be, stream, dpcm) { |
---|
| 2932 | + |
---|
| 2933 | + if (dpcm->fe == fe) |
---|
| 2934 | + continue; |
---|
| 2935 | + |
---|
| 2936 | + state = dpcm->fe->dpcm[stream].state; |
---|
| 2937 | + for (i = 0; i < num_states; i++) { |
---|
| 2938 | + if (state == states[i]) { |
---|
| 2939 | + ret = 0; |
---|
| 2940 | + break; |
---|
| 2941 | + } |
---|
| 2942 | + } |
---|
| 2943 | + } |
---|
| 2944 | + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); |
---|
| 2945 | + |
---|
| 2946 | + /* it's safe to do this BE DAI */ |
---|
| 2947 | + return ret; |
---|
3347 | 2948 | } |
---|
3348 | | -EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_set_state); |
---|
3349 | 2949 | |
---|
3350 | 2950 | /* |
---|
3351 | 2951 | * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE |
---|
.. | .. |
---|
3354 | 2954 | int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, |
---|
3355 | 2955 | struct snd_soc_pcm_runtime *be, int stream) |
---|
3356 | 2956 | { |
---|
3357 | | - struct snd_soc_dpcm *dpcm; |
---|
3358 | | - int state; |
---|
| 2957 | + const enum snd_soc_dpcm_state state[] = { |
---|
| 2958 | + SND_SOC_DPCM_STATE_START, |
---|
| 2959 | + SND_SOC_DPCM_STATE_PAUSED, |
---|
| 2960 | + SND_SOC_DPCM_STATE_SUSPEND, |
---|
| 2961 | + }; |
---|
3359 | 2962 | |
---|
3360 | | - list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { |
---|
3361 | | - |
---|
3362 | | - if (dpcm->fe == fe) |
---|
3363 | | - continue; |
---|
3364 | | - |
---|
3365 | | - state = dpcm->fe->dpcm[stream].state; |
---|
3366 | | - if (state == SND_SOC_DPCM_STATE_START || |
---|
3367 | | - state == SND_SOC_DPCM_STATE_PAUSED || |
---|
3368 | | - state == SND_SOC_DPCM_STATE_SUSPEND) |
---|
3369 | | - return 0; |
---|
3370 | | - } |
---|
3371 | | - |
---|
3372 | | - /* it's safe to free/stop this BE DAI */ |
---|
3373 | | - return 1; |
---|
| 2963 | + return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state)); |
---|
3374 | 2964 | } |
---|
3375 | 2965 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop); |
---|
3376 | 2966 | |
---|
.. | .. |
---|
3381 | 2971 | int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe, |
---|
3382 | 2972 | struct snd_soc_pcm_runtime *be, int stream) |
---|
3383 | 2973 | { |
---|
3384 | | - struct snd_soc_dpcm *dpcm; |
---|
3385 | | - int state; |
---|
| 2974 | + const enum snd_soc_dpcm_state state[] = { |
---|
| 2975 | + SND_SOC_DPCM_STATE_START, |
---|
| 2976 | + SND_SOC_DPCM_STATE_PAUSED, |
---|
| 2977 | + SND_SOC_DPCM_STATE_SUSPEND, |
---|
| 2978 | + SND_SOC_DPCM_STATE_PREPARE, |
---|
| 2979 | + }; |
---|
3386 | 2980 | |
---|
3387 | | - list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { |
---|
3388 | | - |
---|
3389 | | - if (dpcm->fe == fe) |
---|
3390 | | - continue; |
---|
3391 | | - |
---|
3392 | | - state = dpcm->fe->dpcm[stream].state; |
---|
3393 | | - if (state == SND_SOC_DPCM_STATE_START || |
---|
3394 | | - state == SND_SOC_DPCM_STATE_PAUSED || |
---|
3395 | | - state == SND_SOC_DPCM_STATE_SUSPEND || |
---|
3396 | | - state == SND_SOC_DPCM_STATE_PREPARE) |
---|
3397 | | - return 0; |
---|
3398 | | - } |
---|
3399 | | - |
---|
3400 | | - /* it's safe to change hw_params */ |
---|
3401 | | - return 1; |
---|
| 2981 | + return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state)); |
---|
3402 | 2982 | } |
---|
3403 | 2983 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params); |
---|
3404 | 2984 | |
---|
3405 | | -#ifdef CONFIG_DEBUG_FS |
---|
3406 | | -static const char *dpcm_state_string(enum snd_soc_dpcm_state state) |
---|
| 2985 | +/* |
---|
| 2986 | + * We can only prepare a BE DAI if any of it's FE are not prepared, |
---|
| 2987 | + * running or paused for the specified stream direction. |
---|
| 2988 | + */ |
---|
| 2989 | +int snd_soc_dpcm_can_be_prepared(struct snd_soc_pcm_runtime *fe, |
---|
| 2990 | + struct snd_soc_pcm_runtime *be, int stream) |
---|
3407 | 2991 | { |
---|
3408 | | - switch (state) { |
---|
3409 | | - case SND_SOC_DPCM_STATE_NEW: |
---|
3410 | | - return "new"; |
---|
3411 | | - case SND_SOC_DPCM_STATE_OPEN: |
---|
3412 | | - return "open"; |
---|
3413 | | - case SND_SOC_DPCM_STATE_HW_PARAMS: |
---|
3414 | | - return "hw_params"; |
---|
3415 | | - case SND_SOC_DPCM_STATE_PREPARE: |
---|
3416 | | - return "prepare"; |
---|
3417 | | - case SND_SOC_DPCM_STATE_START: |
---|
3418 | | - return "start"; |
---|
3419 | | - case SND_SOC_DPCM_STATE_STOP: |
---|
3420 | | - return "stop"; |
---|
3421 | | - case SND_SOC_DPCM_STATE_SUSPEND: |
---|
3422 | | - return "suspend"; |
---|
3423 | | - case SND_SOC_DPCM_STATE_PAUSED: |
---|
3424 | | - return "paused"; |
---|
3425 | | - case SND_SOC_DPCM_STATE_HW_FREE: |
---|
3426 | | - return "hw_free"; |
---|
3427 | | - case SND_SOC_DPCM_STATE_CLOSE: |
---|
3428 | | - return "close"; |
---|
3429 | | - } |
---|
| 2992 | + const enum snd_soc_dpcm_state state[] = { |
---|
| 2993 | + SND_SOC_DPCM_STATE_START, |
---|
| 2994 | + SND_SOC_DPCM_STATE_PAUSED, |
---|
| 2995 | + SND_SOC_DPCM_STATE_PREPARE, |
---|
| 2996 | + }; |
---|
3430 | 2997 | |
---|
3431 | | - return "unknown"; |
---|
| 2998 | + return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state)); |
---|
3432 | 2999 | } |
---|
3433 | | - |
---|
3434 | | -static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, |
---|
3435 | | - int stream, char *buf, size_t size) |
---|
3436 | | -{ |
---|
3437 | | - struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params; |
---|
3438 | | - struct snd_soc_dpcm *dpcm; |
---|
3439 | | - ssize_t offset = 0; |
---|
3440 | | - |
---|
3441 | | - /* FE state */ |
---|
3442 | | - offset += scnprintf(buf + offset, size - offset, |
---|
3443 | | - "[%s - %s]\n", fe->dai_link->name, |
---|
3444 | | - stream ? "Capture" : "Playback"); |
---|
3445 | | - |
---|
3446 | | - offset += scnprintf(buf + offset, size - offset, "State: %s\n", |
---|
3447 | | - dpcm_state_string(fe->dpcm[stream].state)); |
---|
3448 | | - |
---|
3449 | | - if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) && |
---|
3450 | | - (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP)) |
---|
3451 | | - offset += scnprintf(buf + offset, size - offset, |
---|
3452 | | - "Hardware Params: " |
---|
3453 | | - "Format = %s, Channels = %d, Rate = %d\n", |
---|
3454 | | - snd_pcm_format_name(params_format(params)), |
---|
3455 | | - params_channels(params), |
---|
3456 | | - params_rate(params)); |
---|
3457 | | - |
---|
3458 | | - /* BEs state */ |
---|
3459 | | - offset += scnprintf(buf + offset, size - offset, "Backends:\n"); |
---|
3460 | | - |
---|
3461 | | - if (list_empty(&fe->dpcm[stream].be_clients)) { |
---|
3462 | | - offset += scnprintf(buf + offset, size - offset, |
---|
3463 | | - " No active DSP links\n"); |
---|
3464 | | - goto out; |
---|
3465 | | - } |
---|
3466 | | - |
---|
3467 | | - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
---|
3468 | | - struct snd_soc_pcm_runtime *be = dpcm->be; |
---|
3469 | | - params = &dpcm->hw_params; |
---|
3470 | | - |
---|
3471 | | - offset += scnprintf(buf + offset, size - offset, |
---|
3472 | | - "- %s\n", be->dai_link->name); |
---|
3473 | | - |
---|
3474 | | - offset += scnprintf(buf + offset, size - offset, |
---|
3475 | | - " State: %s\n", |
---|
3476 | | - dpcm_state_string(be->dpcm[stream].state)); |
---|
3477 | | - |
---|
3478 | | - if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) && |
---|
3479 | | - (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP)) |
---|
3480 | | - offset += scnprintf(buf + offset, size - offset, |
---|
3481 | | - " Hardware Params: " |
---|
3482 | | - "Format = %s, Channels = %d, Rate = %d\n", |
---|
3483 | | - snd_pcm_format_name(params_format(params)), |
---|
3484 | | - params_channels(params), |
---|
3485 | | - params_rate(params)); |
---|
3486 | | - } |
---|
3487 | | - |
---|
3488 | | -out: |
---|
3489 | | - return offset; |
---|
3490 | | -} |
---|
3491 | | - |
---|
3492 | | -static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf, |
---|
3493 | | - size_t count, loff_t *ppos) |
---|
3494 | | -{ |
---|
3495 | | - struct snd_soc_pcm_runtime *fe = file->private_data; |
---|
3496 | | - ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0; |
---|
3497 | | - char *buf; |
---|
3498 | | - |
---|
3499 | | - buf = kmalloc(out_count, GFP_KERNEL); |
---|
3500 | | - if (!buf) |
---|
3501 | | - return -ENOMEM; |
---|
3502 | | - |
---|
3503 | | - if (fe->cpu_dai->driver->playback.channels_min) |
---|
3504 | | - offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_PLAYBACK, |
---|
3505 | | - buf + offset, out_count - offset); |
---|
3506 | | - |
---|
3507 | | - if (fe->cpu_dai->driver->capture.channels_min) |
---|
3508 | | - offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_CAPTURE, |
---|
3509 | | - buf + offset, out_count - offset); |
---|
3510 | | - |
---|
3511 | | - ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset); |
---|
3512 | | - |
---|
3513 | | - kfree(buf); |
---|
3514 | | - return ret; |
---|
3515 | | -} |
---|
3516 | | - |
---|
3517 | | -static const struct file_operations dpcm_state_fops = { |
---|
3518 | | - .open = simple_open, |
---|
3519 | | - .read = dpcm_state_read_file, |
---|
3520 | | - .llseek = default_llseek, |
---|
3521 | | -}; |
---|
3522 | | - |
---|
3523 | | -void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd) |
---|
3524 | | -{ |
---|
3525 | | - if (!rtd->dai_link) |
---|
3526 | | - return; |
---|
3527 | | - |
---|
3528 | | - if (!rtd->card->debugfs_card_root) |
---|
3529 | | - return; |
---|
3530 | | - |
---|
3531 | | - rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name, |
---|
3532 | | - rtd->card->debugfs_card_root); |
---|
3533 | | - if (!rtd->debugfs_dpcm_root) { |
---|
3534 | | - dev_dbg(rtd->dev, |
---|
3535 | | - "ASoC: Failed to create dpcm debugfs directory %s\n", |
---|
3536 | | - rtd->dai_link->name); |
---|
3537 | | - return; |
---|
3538 | | - } |
---|
3539 | | - |
---|
3540 | | - debugfs_create_file("state", 0444, rtd->debugfs_dpcm_root, |
---|
3541 | | - rtd, &dpcm_state_fops); |
---|
3542 | | -} |
---|
3543 | | -#endif |
---|
| 3000 | +EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_prepared); |
---|