.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * motu-pcm.c - a part of driver for MOTU FireWire series |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> |
---|
5 | | - * |
---|
6 | | - * Licensed under the terms of the GNU General Public License, version 2. |
---|
7 | 6 | */ |
---|
8 | 7 | |
---|
9 | 8 | #include <sound/pcm_params.h> |
---|
.. | .. |
---|
27 | 26 | rate = snd_motu_clock_rates[i]; |
---|
28 | 27 | mode = i / 2; |
---|
29 | 28 | |
---|
30 | | - pcm_channels = formats->fixed_part_pcm_chunks[mode] + |
---|
31 | | - formats->differed_part_pcm_chunks[mode]; |
---|
| 29 | + pcm_channels = formats->pcm_chunks[mode]; |
---|
32 | 30 | if (!snd_interval_test(c, pcm_channels)) |
---|
33 | 31 | continue; |
---|
34 | 32 | |
---|
.. | .. |
---|
60 | 58 | if (!snd_interval_test(r, rate)) |
---|
61 | 59 | continue; |
---|
62 | 60 | |
---|
63 | | - pcm_channels = formats->fixed_part_pcm_chunks[mode] + |
---|
64 | | - formats->differed_part_pcm_chunks[mode]; |
---|
| 61 | + pcm_channels = formats->pcm_chunks[mode]; |
---|
65 | 62 | channels.min = min(channels.min, pcm_channels); |
---|
66 | 63 | channels.max = max(channels.max, pcm_channels); |
---|
67 | 64 | } |
---|
.. | .. |
---|
83 | 80 | rate = snd_motu_clock_rates[i]; |
---|
84 | 81 | mode = i / 2; |
---|
85 | 82 | |
---|
86 | | - pcm_channels = formats->fixed_part_pcm_chunks[mode] + |
---|
87 | | - formats->differed_part_pcm_chunks[mode]; |
---|
| 83 | + pcm_channels = formats->pcm_chunks[mode]; |
---|
88 | 84 | if (pcm_channels == 0) |
---|
89 | 85 | continue; |
---|
90 | 86 | |
---|
.. | .. |
---|
134 | 130 | static int pcm_open(struct snd_pcm_substream *substream) |
---|
135 | 131 | { |
---|
136 | 132 | struct snd_motu *motu = substream->private_data; |
---|
137 | | - const struct snd_motu_protocol *const protocol = motu->spec->protocol; |
---|
| 133 | + struct amdtp_domain *d = &motu->domain; |
---|
138 | 134 | enum snd_motu_clock_source src; |
---|
139 | | - unsigned int rate; |
---|
140 | 135 | int err; |
---|
141 | 136 | |
---|
142 | 137 | err = snd_motu_stream_lock_try(motu); |
---|
.. | .. |
---|
153 | 148 | if (err < 0) |
---|
154 | 149 | goto err_locked; |
---|
155 | 150 | |
---|
156 | | - /* |
---|
157 | | - * When source of clock is not internal or any PCM streams are running, |
---|
158 | | - * available sampling rate is limited at current sampling rate. |
---|
159 | | - */ |
---|
160 | | - err = protocol->get_clock_source(motu, &src); |
---|
| 151 | + err = snd_motu_protocol_get_clock_source(motu, &src); |
---|
161 | 152 | if (err < 0) |
---|
162 | 153 | goto err_locked; |
---|
163 | | - if (src != SND_MOTU_CLOCK_SOURCE_INTERNAL || |
---|
164 | | - amdtp_stream_pcm_running(&motu->tx_stream) || |
---|
165 | | - amdtp_stream_pcm_running(&motu->rx_stream)) { |
---|
166 | | - err = protocol->get_clock_rate(motu, &rate); |
---|
| 154 | + |
---|
| 155 | + // When source of clock is not internal or any stream is reserved for |
---|
| 156 | + // transmission of PCM frames, the available sampling rate is limited |
---|
| 157 | + // at current one. |
---|
| 158 | + if ((src != SND_MOTU_CLOCK_SOURCE_INTERNAL && |
---|
| 159 | + src != SND_MOTU_CLOCK_SOURCE_SPH) || |
---|
| 160 | + (motu->substreams_counter > 0 && d->events_per_period > 0)) { |
---|
| 161 | + unsigned int frames_per_period = d->events_per_period; |
---|
| 162 | + unsigned int frames_per_buffer = d->events_per_buffer; |
---|
| 163 | + unsigned int rate; |
---|
| 164 | + |
---|
| 165 | + err = snd_motu_protocol_get_clock_rate(motu, &rate); |
---|
167 | 166 | if (err < 0) |
---|
168 | 167 | goto err_locked; |
---|
| 168 | + |
---|
169 | 169 | substream->runtime->hw.rate_min = rate; |
---|
170 | 170 | substream->runtime->hw.rate_max = rate; |
---|
| 171 | + |
---|
| 172 | + if (frames_per_period > 0) { |
---|
| 173 | + err = snd_pcm_hw_constraint_minmax(substream->runtime, |
---|
| 174 | + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, |
---|
| 175 | + frames_per_period, frames_per_period); |
---|
| 176 | + if (err < 0) |
---|
| 177 | + goto err_locked; |
---|
| 178 | + |
---|
| 179 | + err = snd_pcm_hw_constraint_minmax(substream->runtime, |
---|
| 180 | + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, |
---|
| 181 | + frames_per_buffer, frames_per_buffer); |
---|
| 182 | + if (err < 0) |
---|
| 183 | + goto err_locked; |
---|
| 184 | + } |
---|
171 | 185 | } |
---|
172 | 186 | |
---|
173 | 187 | snd_pcm_set_sync(substream); |
---|
174 | 188 | |
---|
175 | 189 | mutex_unlock(&motu->mutex); |
---|
176 | 190 | |
---|
177 | | - return err; |
---|
| 191 | + return 0; |
---|
178 | 192 | err_locked: |
---|
179 | 193 | mutex_unlock(&motu->mutex); |
---|
180 | 194 | snd_motu_stream_lock_release(motu); |
---|
.. | .. |
---|
190 | 204 | return 0; |
---|
191 | 205 | } |
---|
192 | 206 | |
---|
193 | | -static int capture_hw_params(struct snd_pcm_substream *substream, |
---|
194 | | - struct snd_pcm_hw_params *hw_params) |
---|
| 207 | +static int pcm_hw_params(struct snd_pcm_substream *substream, |
---|
| 208 | + struct snd_pcm_hw_params *hw_params) |
---|
195 | 209 | { |
---|
196 | 210 | struct snd_motu *motu = substream->private_data; |
---|
197 | | - int err; |
---|
198 | | - |
---|
199 | | - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, |
---|
200 | | - params_buffer_bytes(hw_params)); |
---|
201 | | - if (err < 0) |
---|
202 | | - return err; |
---|
| 211 | + int err = 0; |
---|
203 | 212 | |
---|
204 | 213 | if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { |
---|
| 214 | + unsigned int rate = params_rate(hw_params); |
---|
| 215 | + unsigned int frames_per_period = params_period_size(hw_params); |
---|
| 216 | + unsigned int frames_per_buffer = params_buffer_size(hw_params); |
---|
| 217 | + |
---|
205 | 218 | mutex_lock(&motu->mutex); |
---|
206 | | - motu->capture_substreams++; |
---|
| 219 | + err = snd_motu_stream_reserve_duplex(motu, rate, |
---|
| 220 | + frames_per_period, frames_per_buffer); |
---|
| 221 | + if (err >= 0) |
---|
| 222 | + ++motu->substreams_counter; |
---|
207 | 223 | mutex_unlock(&motu->mutex); |
---|
208 | 224 | } |
---|
209 | 225 | |
---|
210 | | - return 0; |
---|
211 | | -} |
---|
212 | | -static int playback_hw_params(struct snd_pcm_substream *substream, |
---|
213 | | - struct snd_pcm_hw_params *hw_params) |
---|
214 | | -{ |
---|
215 | | - struct snd_motu *motu = substream->private_data; |
---|
216 | | - int err; |
---|
217 | | - |
---|
218 | | - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, |
---|
219 | | - params_buffer_bytes(hw_params)); |
---|
220 | | - if (err < 0) |
---|
221 | | - return err; |
---|
222 | | - |
---|
223 | | - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { |
---|
224 | | - mutex_lock(&motu->mutex); |
---|
225 | | - motu->playback_substreams++; |
---|
226 | | - mutex_unlock(&motu->mutex); |
---|
227 | | - } |
---|
228 | | - |
---|
229 | | - return 0; |
---|
| 226 | + return err; |
---|
230 | 227 | } |
---|
231 | 228 | |
---|
232 | | -static int capture_hw_free(struct snd_pcm_substream *substream) |
---|
| 229 | +static int pcm_hw_free(struct snd_pcm_substream *substream) |
---|
233 | 230 | { |
---|
234 | 231 | struct snd_motu *motu = substream->private_data; |
---|
235 | 232 | |
---|
236 | 233 | mutex_lock(&motu->mutex); |
---|
237 | 234 | |
---|
238 | 235 | if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) |
---|
239 | | - motu->capture_substreams--; |
---|
| 236 | + --motu->substreams_counter; |
---|
240 | 237 | |
---|
241 | 238 | snd_motu_stream_stop_duplex(motu); |
---|
242 | 239 | |
---|
243 | 240 | mutex_unlock(&motu->mutex); |
---|
244 | 241 | |
---|
245 | | - return snd_pcm_lib_free_vmalloc_buffer(substream); |
---|
246 | | -} |
---|
247 | | - |
---|
248 | | -static int playback_hw_free(struct snd_pcm_substream *substream) |
---|
249 | | -{ |
---|
250 | | - struct snd_motu *motu = substream->private_data; |
---|
251 | | - |
---|
252 | | - mutex_lock(&motu->mutex); |
---|
253 | | - |
---|
254 | | - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) |
---|
255 | | - motu->playback_substreams--; |
---|
256 | | - |
---|
257 | | - snd_motu_stream_stop_duplex(motu); |
---|
258 | | - |
---|
259 | | - mutex_unlock(&motu->mutex); |
---|
260 | | - |
---|
261 | | - return snd_pcm_lib_free_vmalloc_buffer(substream); |
---|
| 242 | + return 0; |
---|
262 | 243 | } |
---|
263 | 244 | |
---|
264 | 245 | static int capture_prepare(struct snd_pcm_substream *substream) |
---|
.. | .. |
---|
267 | 248 | int err; |
---|
268 | 249 | |
---|
269 | 250 | mutex_lock(&motu->mutex); |
---|
270 | | - err = snd_motu_stream_start_duplex(motu, substream->runtime->rate); |
---|
| 251 | + err = snd_motu_stream_start_duplex(motu); |
---|
271 | 252 | mutex_unlock(&motu->mutex); |
---|
272 | 253 | if (err >= 0) |
---|
273 | 254 | amdtp_stream_pcm_prepare(&motu->tx_stream); |
---|
.. | .. |
---|
280 | 261 | int err; |
---|
281 | 262 | |
---|
282 | 263 | mutex_lock(&motu->mutex); |
---|
283 | | - err = snd_motu_stream_start_duplex(motu, substream->runtime->rate); |
---|
| 264 | + err = snd_motu_stream_start_duplex(motu); |
---|
284 | 265 | mutex_unlock(&motu->mutex); |
---|
285 | 266 | if (err >= 0) |
---|
286 | 267 | amdtp_stream_pcm_prepare(&motu->rx_stream); |
---|
.. | .. |
---|
327 | 308 | { |
---|
328 | 309 | struct snd_motu *motu = substream->private_data; |
---|
329 | 310 | |
---|
330 | | - return amdtp_stream_pcm_pointer(&motu->tx_stream); |
---|
| 311 | + return amdtp_domain_stream_pcm_pointer(&motu->domain, &motu->tx_stream); |
---|
331 | 312 | } |
---|
332 | 313 | static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream) |
---|
333 | 314 | { |
---|
334 | 315 | struct snd_motu *motu = substream->private_data; |
---|
335 | 316 | |
---|
336 | | - return amdtp_stream_pcm_pointer(&motu->rx_stream); |
---|
| 317 | + return amdtp_domain_stream_pcm_pointer(&motu->domain, &motu->rx_stream); |
---|
337 | 318 | } |
---|
338 | 319 | |
---|
339 | 320 | static int capture_ack(struct snd_pcm_substream *substream) |
---|
340 | 321 | { |
---|
341 | 322 | struct snd_motu *motu = substream->private_data; |
---|
342 | 323 | |
---|
343 | | - return amdtp_stream_pcm_ack(&motu->tx_stream); |
---|
| 324 | + return amdtp_domain_stream_pcm_ack(&motu->domain, &motu->tx_stream); |
---|
344 | 325 | } |
---|
345 | 326 | |
---|
346 | 327 | static int playback_ack(struct snd_pcm_substream *substream) |
---|
347 | 328 | { |
---|
348 | 329 | struct snd_motu *motu = substream->private_data; |
---|
349 | 330 | |
---|
350 | | - return amdtp_stream_pcm_ack(&motu->rx_stream); |
---|
| 331 | + return amdtp_domain_stream_pcm_ack(&motu->domain, &motu->rx_stream); |
---|
351 | 332 | } |
---|
352 | 333 | |
---|
353 | 334 | int snd_motu_create_pcm_devices(struct snd_motu *motu) |
---|
.. | .. |
---|
355 | 336 | static const struct snd_pcm_ops capture_ops = { |
---|
356 | 337 | .open = pcm_open, |
---|
357 | 338 | .close = pcm_close, |
---|
358 | | - .ioctl = snd_pcm_lib_ioctl, |
---|
359 | | - .hw_params = capture_hw_params, |
---|
360 | | - .hw_free = capture_hw_free, |
---|
| 339 | + .hw_params = pcm_hw_params, |
---|
| 340 | + .hw_free = pcm_hw_free, |
---|
361 | 341 | .prepare = capture_prepare, |
---|
362 | 342 | .trigger = capture_trigger, |
---|
363 | 343 | .pointer = capture_pointer, |
---|
364 | 344 | .ack = capture_ack, |
---|
365 | | - .page = snd_pcm_lib_get_vmalloc_page, |
---|
366 | 345 | }; |
---|
367 | 346 | static const struct snd_pcm_ops playback_ops = { |
---|
368 | 347 | .open = pcm_open, |
---|
369 | 348 | .close = pcm_close, |
---|
370 | | - .ioctl = snd_pcm_lib_ioctl, |
---|
371 | | - .hw_params = playback_hw_params, |
---|
372 | | - .hw_free = playback_hw_free, |
---|
| 349 | + .hw_params = pcm_hw_params, |
---|
| 350 | + .hw_free = pcm_hw_free, |
---|
373 | 351 | .prepare = playback_prepare, |
---|
374 | 352 | .trigger = playback_trigger, |
---|
375 | 353 | .pointer = playback_pointer, |
---|
376 | 354 | .ack = playback_ack, |
---|
377 | | - .page = snd_pcm_lib_get_vmalloc_page, |
---|
378 | 355 | }; |
---|
379 | 356 | struct snd_pcm *pcm; |
---|
380 | 357 | int err; |
---|
.. | .. |
---|
387 | 364 | |
---|
388 | 365 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); |
---|
389 | 366 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); |
---|
| 367 | + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); |
---|
390 | 368 | |
---|
391 | 369 | return 0; |
---|
392 | 370 | } |
---|