| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * tascam-pcm.c - a part of driver for TASCAM FireWire series |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (c) 2015 Takashi Sakamoto |
|---|
| 5 | | - * |
|---|
| 6 | | - * Licensed under the terms of the GNU General Public License, version 2. |
|---|
| 7 | 6 | */ |
|---|
| 8 | 7 | |
|---|
| 9 | 8 | #include "tascam.h" |
|---|
| .. | .. |
|---|
| 44 | 43 | static int pcm_open(struct snd_pcm_substream *substream) |
|---|
| 45 | 44 | { |
|---|
| 46 | 45 | struct snd_tscm *tscm = substream->private_data; |
|---|
| 46 | + struct amdtp_domain *d = &tscm->domain; |
|---|
| 47 | 47 | enum snd_tscm_clock clock; |
|---|
| 48 | | - unsigned int rate; |
|---|
| 49 | 48 | int err; |
|---|
| 50 | 49 | |
|---|
| 51 | 50 | err = snd_tscm_stream_lock_try(tscm); |
|---|
| 52 | 51 | if (err < 0) |
|---|
| 53 | | - goto end; |
|---|
| 52 | + return err; |
|---|
| 54 | 53 | |
|---|
| 55 | 54 | err = pcm_init_hw_params(tscm, substream); |
|---|
| 56 | 55 | if (err < 0) |
|---|
| .. | .. |
|---|
| 60 | 59 | if (err < 0) |
|---|
| 61 | 60 | goto err_locked; |
|---|
| 62 | 61 | |
|---|
| 63 | | - if (clock != SND_TSCM_CLOCK_INTERNAL || |
|---|
| 64 | | - amdtp_stream_pcm_running(&tscm->rx_stream) || |
|---|
| 65 | | - amdtp_stream_pcm_running(&tscm->tx_stream)) { |
|---|
| 62 | + mutex_lock(&tscm->mutex); |
|---|
| 63 | + |
|---|
| 64 | + // When source of clock is not internal or any stream is reserved for |
|---|
| 65 | + // transmission of PCM frames, the available sampling rate is limited |
|---|
| 66 | + // at current one. |
|---|
| 67 | + if (clock != SND_TSCM_CLOCK_INTERNAL || tscm->substreams_counter > 0) { |
|---|
| 68 | + unsigned int frames_per_period = d->events_per_period; |
|---|
| 69 | + unsigned int frames_per_buffer = d->events_per_buffer; |
|---|
| 70 | + unsigned int rate; |
|---|
| 71 | + |
|---|
| 66 | 72 | err = snd_tscm_stream_get_rate(tscm, &rate); |
|---|
| 67 | | - if (err < 0) |
|---|
| 73 | + if (err < 0) { |
|---|
| 74 | + mutex_unlock(&tscm->mutex); |
|---|
| 68 | 75 | goto err_locked; |
|---|
| 76 | + } |
|---|
| 69 | 77 | substream->runtime->hw.rate_min = rate; |
|---|
| 70 | 78 | substream->runtime->hw.rate_max = rate; |
|---|
| 79 | + |
|---|
| 80 | + err = snd_pcm_hw_constraint_minmax(substream->runtime, |
|---|
| 81 | + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, |
|---|
| 82 | + frames_per_period, frames_per_period); |
|---|
| 83 | + if (err < 0) { |
|---|
| 84 | + mutex_unlock(&tscm->mutex); |
|---|
| 85 | + goto err_locked; |
|---|
| 86 | + } |
|---|
| 87 | + |
|---|
| 88 | + err = snd_pcm_hw_constraint_minmax(substream->runtime, |
|---|
| 89 | + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, |
|---|
| 90 | + frames_per_buffer, frames_per_buffer); |
|---|
| 91 | + if (err < 0) { |
|---|
| 92 | + mutex_unlock(&tscm->mutex); |
|---|
| 93 | + goto err_locked; |
|---|
| 94 | + } |
|---|
| 71 | 95 | } |
|---|
| 72 | 96 | |
|---|
| 97 | + mutex_unlock(&tscm->mutex); |
|---|
| 98 | + |
|---|
| 73 | 99 | snd_pcm_set_sync(substream); |
|---|
| 74 | | -end: |
|---|
| 75 | | - return err; |
|---|
| 100 | + |
|---|
| 101 | + return 0; |
|---|
| 76 | 102 | err_locked: |
|---|
| 77 | 103 | snd_tscm_stream_lock_release(tscm); |
|---|
| 78 | 104 | return err; |
|---|
| .. | .. |
|---|
| 87 | 113 | return 0; |
|---|
| 88 | 114 | } |
|---|
| 89 | 115 | |
|---|
| 90 | | -static int pcm_capture_hw_params(struct snd_pcm_substream *substream, |
|---|
| 91 | | - struct snd_pcm_hw_params *hw_params) |
|---|
| 116 | +static int pcm_hw_params(struct snd_pcm_substream *substream, |
|---|
| 117 | + struct snd_pcm_hw_params *hw_params) |
|---|
| 92 | 118 | { |
|---|
| 93 | 119 | struct snd_tscm *tscm = substream->private_data; |
|---|
| 94 | | - int err; |
|---|
| 95 | | - |
|---|
| 96 | | - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, |
|---|
| 97 | | - params_buffer_bytes(hw_params)); |
|---|
| 98 | | - if (err < 0) |
|---|
| 99 | | - return err; |
|---|
| 120 | + int err = 0; |
|---|
| 100 | 121 | |
|---|
| 101 | 122 | if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { |
|---|
| 123 | + unsigned int rate = params_rate(hw_params); |
|---|
| 124 | + unsigned int frames_per_period = params_period_size(hw_params); |
|---|
| 125 | + unsigned int frames_per_buffer = params_buffer_size(hw_params); |
|---|
| 126 | + |
|---|
| 102 | 127 | mutex_lock(&tscm->mutex); |
|---|
| 103 | | - tscm->substreams_counter++; |
|---|
| 128 | + err = snd_tscm_stream_reserve_duplex(tscm, rate, |
|---|
| 129 | + frames_per_period, frames_per_buffer); |
|---|
| 130 | + if (err >= 0) |
|---|
| 131 | + ++tscm->substreams_counter; |
|---|
| 104 | 132 | mutex_unlock(&tscm->mutex); |
|---|
| 105 | 133 | } |
|---|
| 106 | 134 | |
|---|
| 107 | | - return 0; |
|---|
| 135 | + return err; |
|---|
| 108 | 136 | } |
|---|
| 109 | 137 | |
|---|
| 110 | | -static int pcm_playback_hw_params(struct snd_pcm_substream *substream, |
|---|
| 111 | | - struct snd_pcm_hw_params *hw_params) |
|---|
| 112 | | -{ |
|---|
| 113 | | - struct snd_tscm *tscm = substream->private_data; |
|---|
| 114 | | - int err; |
|---|
| 115 | | - |
|---|
| 116 | | - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, |
|---|
| 117 | | - params_buffer_bytes(hw_params)); |
|---|
| 118 | | - if (err < 0) |
|---|
| 119 | | - return err; |
|---|
| 120 | | - |
|---|
| 121 | | - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { |
|---|
| 122 | | - mutex_lock(&tscm->mutex); |
|---|
| 123 | | - tscm->substreams_counter++; |
|---|
| 124 | | - mutex_unlock(&tscm->mutex); |
|---|
| 125 | | - } |
|---|
| 126 | | - |
|---|
| 127 | | - return 0; |
|---|
| 128 | | -} |
|---|
| 129 | | - |
|---|
| 130 | | -static int pcm_capture_hw_free(struct snd_pcm_substream *substream) |
|---|
| 138 | +static int pcm_hw_free(struct snd_pcm_substream *substream) |
|---|
| 131 | 139 | { |
|---|
| 132 | 140 | struct snd_tscm *tscm = substream->private_data; |
|---|
| 133 | 141 | |
|---|
| 134 | 142 | mutex_lock(&tscm->mutex); |
|---|
| 135 | 143 | |
|---|
| 136 | 144 | if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) |
|---|
| 137 | | - tscm->substreams_counter--; |
|---|
| 145 | + --tscm->substreams_counter; |
|---|
| 138 | 146 | |
|---|
| 139 | 147 | snd_tscm_stream_stop_duplex(tscm); |
|---|
| 140 | 148 | |
|---|
| 141 | 149 | mutex_unlock(&tscm->mutex); |
|---|
| 142 | 150 | |
|---|
| 143 | | - return snd_pcm_lib_free_vmalloc_buffer(substream); |
|---|
| 144 | | -} |
|---|
| 145 | | - |
|---|
| 146 | | -static int pcm_playback_hw_free(struct snd_pcm_substream *substream) |
|---|
| 147 | | -{ |
|---|
| 148 | | - struct snd_tscm *tscm = substream->private_data; |
|---|
| 149 | | - |
|---|
| 150 | | - mutex_lock(&tscm->mutex); |
|---|
| 151 | | - |
|---|
| 152 | | - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) |
|---|
| 153 | | - tscm->substreams_counter--; |
|---|
| 154 | | - |
|---|
| 155 | | - snd_tscm_stream_stop_duplex(tscm); |
|---|
| 156 | | - |
|---|
| 157 | | - mutex_unlock(&tscm->mutex); |
|---|
| 158 | | - |
|---|
| 159 | | - return snd_pcm_lib_free_vmalloc_buffer(substream); |
|---|
| 151 | + return 0; |
|---|
| 160 | 152 | } |
|---|
| 161 | 153 | |
|---|
| 162 | 154 | static int pcm_capture_prepare(struct snd_pcm_substream *substream) |
|---|
| .. | .. |
|---|
| 233 | 225 | { |
|---|
| 234 | 226 | struct snd_tscm *tscm = sbstrm->private_data; |
|---|
| 235 | 227 | |
|---|
| 236 | | - return amdtp_stream_pcm_pointer(&tscm->tx_stream); |
|---|
| 228 | + return amdtp_domain_stream_pcm_pointer(&tscm->domain, &tscm->tx_stream); |
|---|
| 237 | 229 | } |
|---|
| 238 | 230 | |
|---|
| 239 | 231 | static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) |
|---|
| 240 | 232 | { |
|---|
| 241 | 233 | struct snd_tscm *tscm = sbstrm->private_data; |
|---|
| 242 | 234 | |
|---|
| 243 | | - return amdtp_stream_pcm_pointer(&tscm->rx_stream); |
|---|
| 235 | + return amdtp_domain_stream_pcm_pointer(&tscm->domain, &tscm->rx_stream); |
|---|
| 244 | 236 | } |
|---|
| 245 | 237 | |
|---|
| 246 | 238 | static int pcm_capture_ack(struct snd_pcm_substream *substream) |
|---|
| 247 | 239 | { |
|---|
| 248 | 240 | struct snd_tscm *tscm = substream->private_data; |
|---|
| 249 | 241 | |
|---|
| 250 | | - return amdtp_stream_pcm_ack(&tscm->tx_stream); |
|---|
| 242 | + return amdtp_domain_stream_pcm_ack(&tscm->domain, &tscm->tx_stream); |
|---|
| 251 | 243 | } |
|---|
| 252 | 244 | |
|---|
| 253 | 245 | static int pcm_playback_ack(struct snd_pcm_substream *substream) |
|---|
| 254 | 246 | { |
|---|
| 255 | 247 | struct snd_tscm *tscm = substream->private_data; |
|---|
| 256 | 248 | |
|---|
| 257 | | - return amdtp_stream_pcm_ack(&tscm->rx_stream); |
|---|
| 249 | + return amdtp_domain_stream_pcm_ack(&tscm->domain, &tscm->rx_stream); |
|---|
| 258 | 250 | } |
|---|
| 259 | 251 | |
|---|
| 260 | 252 | int snd_tscm_create_pcm_devices(struct snd_tscm *tscm) |
|---|
| .. | .. |
|---|
| 262 | 254 | static const struct snd_pcm_ops capture_ops = { |
|---|
| 263 | 255 | .open = pcm_open, |
|---|
| 264 | 256 | .close = pcm_close, |
|---|
| 265 | | - .ioctl = snd_pcm_lib_ioctl, |
|---|
| 266 | | - .hw_params = pcm_capture_hw_params, |
|---|
| 267 | | - .hw_free = pcm_capture_hw_free, |
|---|
| 257 | + .hw_params = pcm_hw_params, |
|---|
| 258 | + .hw_free = pcm_hw_free, |
|---|
| 268 | 259 | .prepare = pcm_capture_prepare, |
|---|
| 269 | 260 | .trigger = pcm_capture_trigger, |
|---|
| 270 | 261 | .pointer = pcm_capture_pointer, |
|---|
| 271 | 262 | .ack = pcm_capture_ack, |
|---|
| 272 | | - .page = snd_pcm_lib_get_vmalloc_page, |
|---|
| 273 | 263 | }; |
|---|
| 274 | 264 | static const struct snd_pcm_ops playback_ops = { |
|---|
| 275 | 265 | .open = pcm_open, |
|---|
| 276 | 266 | .close = pcm_close, |
|---|
| 277 | | - .ioctl = snd_pcm_lib_ioctl, |
|---|
| 278 | | - .hw_params = pcm_playback_hw_params, |
|---|
| 279 | | - .hw_free = pcm_playback_hw_free, |
|---|
| 267 | + .hw_params = pcm_hw_params, |
|---|
| 268 | + .hw_free = pcm_hw_free, |
|---|
| 280 | 269 | .prepare = pcm_playback_prepare, |
|---|
| 281 | 270 | .trigger = pcm_playback_trigger, |
|---|
| 282 | 271 | .pointer = pcm_playback_pointer, |
|---|
| 283 | 272 | .ack = pcm_playback_ack, |
|---|
| 284 | | - .page = snd_pcm_lib_get_vmalloc_page, |
|---|
| 285 | 273 | }; |
|---|
| 286 | 274 | struct snd_pcm *pcm; |
|---|
| 287 | 275 | int err; |
|---|
| .. | .. |
|---|
| 295 | 283 | "%s PCM", tscm->card->shortname); |
|---|
| 296 | 284 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); |
|---|
| 297 | 285 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); |
|---|
| 286 | + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); |
|---|
| 298 | 287 | |
|---|
| 299 | 288 | return 0; |
|---|
| 300 | 289 | } |
|---|