.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * digi00x-pcm.c - a part of driver for Digidesign Digi 002/003 family |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2014-2015 Takashi Sakamoto |
---|
5 | | - * |
---|
6 | | - * Licensed under the terms of the GNU General Public License, version 2. |
---|
7 | 6 | */ |
---|
8 | 7 | |
---|
9 | 8 | #include "digi00x.h" |
---|
.. | .. |
---|
101 | 100 | static int pcm_open(struct snd_pcm_substream *substream) |
---|
102 | 101 | { |
---|
103 | 102 | struct snd_dg00x *dg00x = substream->private_data; |
---|
| 103 | + struct amdtp_domain *d = &dg00x->domain; |
---|
104 | 104 | enum snd_dg00x_clock clock; |
---|
105 | 105 | bool detect; |
---|
106 | | - unsigned int rate; |
---|
107 | 106 | int err; |
---|
108 | 107 | |
---|
109 | 108 | err = snd_dg00x_stream_lock_try(dg00x); |
---|
110 | 109 | if (err < 0) |
---|
111 | | - goto end; |
---|
| 110 | + return err; |
---|
112 | 111 | |
---|
113 | 112 | err = pcm_init_hw_params(dg00x, substream); |
---|
114 | 113 | if (err < 0) |
---|
.. | .. |
---|
128 | 127 | } |
---|
129 | 128 | } |
---|
130 | 129 | |
---|
| 130 | + mutex_lock(&dg00x->mutex); |
---|
| 131 | + |
---|
| 132 | + // When source of clock is not internal or any stream is reserved for |
---|
| 133 | + // transmission of PCM frames, the available sampling rate is limited |
---|
| 134 | + // at current one. |
---|
131 | 135 | if ((clock != SND_DG00X_CLOCK_INTERNAL) || |
---|
132 | | - amdtp_stream_pcm_running(&dg00x->rx_stream) || |
---|
133 | | - amdtp_stream_pcm_running(&dg00x->tx_stream)) { |
---|
| 136 | + (dg00x->substreams_counter > 0 && d->events_per_period > 0)) { |
---|
| 137 | + unsigned int frames_per_period = d->events_per_period; |
---|
| 138 | + unsigned int frames_per_buffer = d->events_per_buffer; |
---|
| 139 | + unsigned int rate; |
---|
| 140 | + |
---|
134 | 141 | err = snd_dg00x_stream_get_external_rate(dg00x, &rate); |
---|
135 | | - if (err < 0) |
---|
| 142 | + if (err < 0) { |
---|
| 143 | + mutex_unlock(&dg00x->mutex); |
---|
136 | 144 | goto err_locked; |
---|
| 145 | + } |
---|
137 | 146 | substream->runtime->hw.rate_min = rate; |
---|
138 | 147 | substream->runtime->hw.rate_max = rate; |
---|
| 148 | + |
---|
| 149 | + if (frames_per_period > 0) { |
---|
| 150 | + err = snd_pcm_hw_constraint_minmax(substream->runtime, |
---|
| 151 | + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, |
---|
| 152 | + frames_per_period, frames_per_period); |
---|
| 153 | + if (err < 0) { |
---|
| 154 | + mutex_unlock(&dg00x->mutex); |
---|
| 155 | + goto err_locked; |
---|
| 156 | + } |
---|
| 157 | + |
---|
| 158 | + err = snd_pcm_hw_constraint_minmax(substream->runtime, |
---|
| 159 | + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, |
---|
| 160 | + frames_per_buffer, frames_per_buffer); |
---|
| 161 | + if (err < 0) { |
---|
| 162 | + mutex_unlock(&dg00x->mutex); |
---|
| 163 | + goto err_locked; |
---|
| 164 | + } |
---|
| 165 | + } |
---|
139 | 166 | } |
---|
140 | 167 | |
---|
| 168 | + mutex_unlock(&dg00x->mutex); |
---|
| 169 | + |
---|
141 | 170 | snd_pcm_set_sync(substream); |
---|
142 | | -end: |
---|
143 | | - return err; |
---|
| 171 | + |
---|
| 172 | + return 0; |
---|
144 | 173 | err_locked: |
---|
145 | 174 | snd_dg00x_stream_lock_release(dg00x); |
---|
146 | 175 | return err; |
---|
.. | .. |
---|
155 | 184 | return 0; |
---|
156 | 185 | } |
---|
157 | 186 | |
---|
158 | | -static int pcm_capture_hw_params(struct snd_pcm_substream *substream, |
---|
159 | | - struct snd_pcm_hw_params *hw_params) |
---|
| 187 | +static int pcm_hw_params(struct snd_pcm_substream *substream, |
---|
| 188 | + struct snd_pcm_hw_params *hw_params) |
---|
160 | 189 | { |
---|
161 | 190 | struct snd_dg00x *dg00x = substream->private_data; |
---|
162 | | - int err; |
---|
163 | | - |
---|
164 | | - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, |
---|
165 | | - params_buffer_bytes(hw_params)); |
---|
166 | | - if (err < 0) |
---|
167 | | - return err; |
---|
| 191 | + int err = 0; |
---|
168 | 192 | |
---|
169 | 193 | if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { |
---|
| 194 | + unsigned int rate = params_rate(hw_params); |
---|
| 195 | + unsigned int frames_per_period = params_period_size(hw_params); |
---|
| 196 | + unsigned int frames_per_buffer = params_buffer_size(hw_params); |
---|
| 197 | + |
---|
170 | 198 | mutex_lock(&dg00x->mutex); |
---|
171 | | - dg00x->substreams_counter++; |
---|
| 199 | + err = snd_dg00x_stream_reserve_duplex(dg00x, rate, |
---|
| 200 | + frames_per_period, frames_per_buffer); |
---|
| 201 | + if (err >= 0) |
---|
| 202 | + ++dg00x->substreams_counter; |
---|
172 | 203 | mutex_unlock(&dg00x->mutex); |
---|
173 | 204 | } |
---|
174 | 205 | |
---|
175 | | - return 0; |
---|
| 206 | + return err; |
---|
176 | 207 | } |
---|
177 | 208 | |
---|
178 | | -static int pcm_playback_hw_params(struct snd_pcm_substream *substream, |
---|
179 | | - struct snd_pcm_hw_params *hw_params) |
---|
180 | | -{ |
---|
181 | | - struct snd_dg00x *dg00x = substream->private_data; |
---|
182 | | - int err; |
---|
183 | | - |
---|
184 | | - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, |
---|
185 | | - params_buffer_bytes(hw_params)); |
---|
186 | | - if (err < 0) |
---|
187 | | - return err; |
---|
188 | | - |
---|
189 | | - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { |
---|
190 | | - mutex_lock(&dg00x->mutex); |
---|
191 | | - dg00x->substreams_counter++; |
---|
192 | | - mutex_unlock(&dg00x->mutex); |
---|
193 | | - } |
---|
194 | | - |
---|
195 | | - return 0; |
---|
196 | | -} |
---|
197 | | - |
---|
198 | | -static int pcm_capture_hw_free(struct snd_pcm_substream *substream) |
---|
| 209 | +static int pcm_hw_free(struct snd_pcm_substream *substream) |
---|
199 | 210 | { |
---|
200 | 211 | struct snd_dg00x *dg00x = substream->private_data; |
---|
201 | 212 | |
---|
202 | 213 | mutex_lock(&dg00x->mutex); |
---|
203 | 214 | |
---|
204 | 215 | if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) |
---|
205 | | - dg00x->substreams_counter--; |
---|
| 216 | + --dg00x->substreams_counter; |
---|
206 | 217 | |
---|
207 | 218 | snd_dg00x_stream_stop_duplex(dg00x); |
---|
208 | 219 | |
---|
209 | 220 | mutex_unlock(&dg00x->mutex); |
---|
210 | 221 | |
---|
211 | | - return snd_pcm_lib_free_vmalloc_buffer(substream); |
---|
212 | | -} |
---|
213 | | - |
---|
214 | | -static int pcm_playback_hw_free(struct snd_pcm_substream *substream) |
---|
215 | | -{ |
---|
216 | | - struct snd_dg00x *dg00x = substream->private_data; |
---|
217 | | - |
---|
218 | | - mutex_lock(&dg00x->mutex); |
---|
219 | | - |
---|
220 | | - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) |
---|
221 | | - dg00x->substreams_counter--; |
---|
222 | | - |
---|
223 | | - snd_dg00x_stream_stop_duplex(dg00x); |
---|
224 | | - |
---|
225 | | - mutex_unlock(&dg00x->mutex); |
---|
226 | | - |
---|
227 | | - return snd_pcm_lib_free_vmalloc_buffer(substream); |
---|
| 222 | + return 0; |
---|
228 | 223 | } |
---|
229 | 224 | |
---|
230 | 225 | static int pcm_capture_prepare(struct snd_pcm_substream *substream) |
---|
231 | 226 | { |
---|
232 | 227 | struct snd_dg00x *dg00x = substream->private_data; |
---|
233 | | - struct snd_pcm_runtime *runtime = substream->runtime; |
---|
234 | 228 | int err; |
---|
235 | 229 | |
---|
236 | 230 | mutex_lock(&dg00x->mutex); |
---|
237 | 231 | |
---|
238 | | - err = snd_dg00x_stream_start_duplex(dg00x, runtime->rate); |
---|
| 232 | + err = snd_dg00x_stream_start_duplex(dg00x); |
---|
239 | 233 | if (err >= 0) |
---|
240 | 234 | amdtp_stream_pcm_prepare(&dg00x->tx_stream); |
---|
241 | 235 | |
---|
.. | .. |
---|
247 | 241 | static int pcm_playback_prepare(struct snd_pcm_substream *substream) |
---|
248 | 242 | { |
---|
249 | 243 | struct snd_dg00x *dg00x = substream->private_data; |
---|
250 | | - struct snd_pcm_runtime *runtime = substream->runtime; |
---|
251 | 244 | int err; |
---|
252 | 245 | |
---|
253 | 246 | mutex_lock(&dg00x->mutex); |
---|
254 | 247 | |
---|
255 | | - err = snd_dg00x_stream_start_duplex(dg00x, runtime->rate); |
---|
| 248 | + err = snd_dg00x_stream_start_duplex(dg00x); |
---|
256 | 249 | if (err >= 0) { |
---|
257 | 250 | amdtp_stream_pcm_prepare(&dg00x->rx_stream); |
---|
258 | 251 | amdtp_dot_reset(&dg00x->rx_stream); |
---|
.. | .. |
---|
303 | 296 | { |
---|
304 | 297 | struct snd_dg00x *dg00x = sbstrm->private_data; |
---|
305 | 298 | |
---|
306 | | - return amdtp_stream_pcm_pointer(&dg00x->tx_stream); |
---|
| 299 | + return amdtp_domain_stream_pcm_pointer(&dg00x->domain, &dg00x->tx_stream); |
---|
307 | 300 | } |
---|
308 | 301 | |
---|
309 | 302 | static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) |
---|
310 | 303 | { |
---|
311 | 304 | struct snd_dg00x *dg00x = sbstrm->private_data; |
---|
312 | 305 | |
---|
313 | | - return amdtp_stream_pcm_pointer(&dg00x->rx_stream); |
---|
| 306 | + return amdtp_domain_stream_pcm_pointer(&dg00x->domain, &dg00x->rx_stream); |
---|
314 | 307 | } |
---|
315 | 308 | |
---|
316 | 309 | static int pcm_capture_ack(struct snd_pcm_substream *substream) |
---|
317 | 310 | { |
---|
318 | 311 | struct snd_dg00x *dg00x = substream->private_data; |
---|
319 | 312 | |
---|
320 | | - return amdtp_stream_pcm_ack(&dg00x->tx_stream); |
---|
| 313 | + return amdtp_domain_stream_pcm_ack(&dg00x->domain, &dg00x->tx_stream); |
---|
321 | 314 | } |
---|
322 | 315 | |
---|
323 | 316 | static int pcm_playback_ack(struct snd_pcm_substream *substream) |
---|
324 | 317 | { |
---|
325 | 318 | struct snd_dg00x *dg00x = substream->private_data; |
---|
326 | 319 | |
---|
327 | | - return amdtp_stream_pcm_ack(&dg00x->rx_stream); |
---|
| 320 | + return amdtp_domain_stream_pcm_ack(&dg00x->domain, &dg00x->rx_stream); |
---|
328 | 321 | } |
---|
329 | 322 | |
---|
330 | 323 | int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x) |
---|
.. | .. |
---|
332 | 325 | static const struct snd_pcm_ops capture_ops = { |
---|
333 | 326 | .open = pcm_open, |
---|
334 | 327 | .close = pcm_close, |
---|
335 | | - .ioctl = snd_pcm_lib_ioctl, |
---|
336 | | - .hw_params = pcm_capture_hw_params, |
---|
337 | | - .hw_free = pcm_capture_hw_free, |
---|
| 328 | + .hw_params = pcm_hw_params, |
---|
| 329 | + .hw_free = pcm_hw_free, |
---|
338 | 330 | .prepare = pcm_capture_prepare, |
---|
339 | 331 | .trigger = pcm_capture_trigger, |
---|
340 | 332 | .pointer = pcm_capture_pointer, |
---|
341 | 333 | .ack = pcm_capture_ack, |
---|
342 | | - .page = snd_pcm_lib_get_vmalloc_page, |
---|
343 | 334 | }; |
---|
344 | 335 | static const struct snd_pcm_ops playback_ops = { |
---|
345 | 336 | .open = pcm_open, |
---|
346 | 337 | .close = pcm_close, |
---|
347 | | - .ioctl = snd_pcm_lib_ioctl, |
---|
348 | | - .hw_params = pcm_playback_hw_params, |
---|
349 | | - .hw_free = pcm_playback_hw_free, |
---|
| 338 | + .hw_params = pcm_hw_params, |
---|
| 339 | + .hw_free = pcm_hw_free, |
---|
350 | 340 | .prepare = pcm_playback_prepare, |
---|
351 | 341 | .trigger = pcm_playback_trigger, |
---|
352 | 342 | .pointer = pcm_playback_pointer, |
---|
353 | 343 | .ack = pcm_playback_ack, |
---|
354 | | - .page = snd_pcm_lib_get_vmalloc_page, |
---|
355 | 344 | }; |
---|
356 | 345 | struct snd_pcm *pcm; |
---|
357 | 346 | int err; |
---|
.. | .. |
---|
365 | 354 | "%s PCM", dg00x->card->shortname); |
---|
366 | 355 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); |
---|
367 | 356 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); |
---|
| 357 | + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); |
---|
368 | 358 | |
---|
369 | 359 | return 0; |
---|
370 | 360 | } |
---|