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