| .. | .. |
|---|
| 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 | } |
|---|