.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * bebob_pcm.c - a part of driver for BeBoB based devices |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2013-2014 Takashi Sakamoto |
---|
5 | | - * |
---|
6 | | - * Licensed under the terms of the GNU General Public License, version 2. |
---|
7 | 6 | */ |
---|
8 | 7 | |
---|
9 | 8 | #include "./bebob.h" |
---|
.. | .. |
---|
130 | 129 | return err; |
---|
131 | 130 | } |
---|
132 | 131 | |
---|
133 | | -static int |
---|
134 | | -pcm_open(struct snd_pcm_substream *substream) |
---|
| 132 | +static int pcm_open(struct snd_pcm_substream *substream) |
---|
135 | 133 | { |
---|
136 | 134 | struct snd_bebob *bebob = substream->private_data; |
---|
137 | 135 | const struct snd_bebob_rate_spec *spec = bebob->spec->rate; |
---|
138 | | - unsigned int sampling_rate; |
---|
| 136 | + struct amdtp_domain *d = &bebob->domain; |
---|
139 | 137 | enum snd_bebob_clock_type src; |
---|
140 | 138 | int err; |
---|
141 | 139 | |
---|
142 | 140 | err = snd_bebob_stream_lock_try(bebob); |
---|
143 | 141 | if (err < 0) |
---|
144 | | - goto end; |
---|
| 142 | + return err; |
---|
145 | 143 | |
---|
146 | 144 | err = pcm_init_hw_params(bebob, substream); |
---|
147 | 145 | if (err < 0) |
---|
.. | .. |
---|
151 | 149 | if (err < 0) |
---|
152 | 150 | goto err_locked; |
---|
153 | 151 | |
---|
154 | | - /* |
---|
155 | | - * When source of clock is internal or any PCM stream are running, |
---|
156 | | - * the available sampling rate is limited at current sampling rate. |
---|
157 | | - */ |
---|
| 152 | + mutex_lock(&bebob->mutex); |
---|
| 153 | + |
---|
| 154 | + // When source of clock is not internal or any stream is reserved for |
---|
| 155 | + // transmission of PCM frames, the available sampling rate is limited |
---|
| 156 | + // at current one. |
---|
158 | 157 | if (src == SND_BEBOB_CLOCK_TYPE_EXTERNAL || |
---|
159 | | - amdtp_stream_pcm_running(&bebob->tx_stream) || |
---|
160 | | - amdtp_stream_pcm_running(&bebob->rx_stream)) { |
---|
| 158 | + (bebob->substreams_counter > 0 && d->events_per_period > 0)) { |
---|
| 159 | + unsigned int frames_per_period = d->events_per_period; |
---|
| 160 | + unsigned int frames_per_buffer = d->events_per_buffer; |
---|
| 161 | + unsigned int sampling_rate; |
---|
| 162 | + |
---|
161 | 163 | err = spec->get(bebob, &sampling_rate); |
---|
162 | 164 | if (err < 0) { |
---|
| 165 | + mutex_unlock(&bebob->mutex); |
---|
163 | 166 | dev_err(&bebob->unit->device, |
---|
164 | 167 | "fail to get sampling rate: %d\n", err); |
---|
165 | 168 | goto err_locked; |
---|
.. | .. |
---|
167 | 170 | |
---|
168 | 171 | substream->runtime->hw.rate_min = sampling_rate; |
---|
169 | 172 | substream->runtime->hw.rate_max = sampling_rate; |
---|
| 173 | + |
---|
| 174 | + if (frames_per_period > 0) { |
---|
| 175 | + err = snd_pcm_hw_constraint_minmax(substream->runtime, |
---|
| 176 | + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, |
---|
| 177 | + frames_per_period, frames_per_period); |
---|
| 178 | + if (err < 0) { |
---|
| 179 | + mutex_unlock(&bebob->mutex); |
---|
| 180 | + goto err_locked; |
---|
| 181 | + } |
---|
| 182 | + |
---|
| 183 | + err = snd_pcm_hw_constraint_minmax(substream->runtime, |
---|
| 184 | + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, |
---|
| 185 | + frames_per_buffer, frames_per_buffer); |
---|
| 186 | + if (err < 0) { |
---|
| 187 | + mutex_unlock(&bebob->mutex); |
---|
| 188 | + goto err_locked; |
---|
| 189 | + } |
---|
| 190 | + } |
---|
170 | 191 | } |
---|
171 | 192 | |
---|
| 193 | + mutex_unlock(&bebob->mutex); |
---|
| 194 | + |
---|
172 | 195 | snd_pcm_set_sync(substream); |
---|
173 | | -end: |
---|
174 | | - return err; |
---|
| 196 | + |
---|
| 197 | + return 0; |
---|
175 | 198 | err_locked: |
---|
176 | 199 | snd_bebob_stream_lock_release(bebob); |
---|
177 | 200 | return err; |
---|
.. | .. |
---|
185 | 208 | return 0; |
---|
186 | 209 | } |
---|
187 | 210 | |
---|
188 | | -static int |
---|
189 | | -pcm_capture_hw_params(struct snd_pcm_substream *substream, |
---|
190 | | - struct snd_pcm_hw_params *hw_params) |
---|
| 211 | +static int pcm_hw_params(struct snd_pcm_substream *substream, |
---|
| 212 | + struct snd_pcm_hw_params *hw_params) |
---|
191 | 213 | { |
---|
192 | 214 | struct snd_bebob *bebob = substream->private_data; |
---|
193 | | - int err; |
---|
194 | | - |
---|
195 | | - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, |
---|
196 | | - params_buffer_bytes(hw_params)); |
---|
197 | | - if (err < 0) |
---|
198 | | - return err; |
---|
| 215 | + int err = 0; |
---|
199 | 216 | |
---|
200 | 217 | if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { |
---|
| 218 | + unsigned int rate = params_rate(hw_params); |
---|
| 219 | + unsigned int frames_per_period = params_period_size(hw_params); |
---|
| 220 | + unsigned int frames_per_buffer = params_buffer_size(hw_params); |
---|
| 221 | + |
---|
201 | 222 | mutex_lock(&bebob->mutex); |
---|
202 | | - bebob->substreams_counter++; |
---|
| 223 | + err = snd_bebob_stream_reserve_duplex(bebob, rate, |
---|
| 224 | + frames_per_period, frames_per_buffer); |
---|
| 225 | + if (err >= 0) |
---|
| 226 | + ++bebob->substreams_counter; |
---|
203 | 227 | mutex_unlock(&bebob->mutex); |
---|
204 | 228 | } |
---|
205 | 229 | |
---|
206 | | - return 0; |
---|
207 | | -} |
---|
208 | | -static int |
---|
209 | | -pcm_playback_hw_params(struct snd_pcm_substream *substream, |
---|
210 | | - struct snd_pcm_hw_params *hw_params) |
---|
211 | | -{ |
---|
212 | | - struct snd_bebob *bebob = substream->private_data; |
---|
213 | | - int err; |
---|
214 | | - |
---|
215 | | - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, |
---|
216 | | - params_buffer_bytes(hw_params)); |
---|
217 | | - if (err < 0) |
---|
218 | | - return err; |
---|
219 | | - |
---|
220 | | - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { |
---|
221 | | - mutex_lock(&bebob->mutex); |
---|
222 | | - bebob->substreams_counter++; |
---|
223 | | - mutex_unlock(&bebob->mutex); |
---|
224 | | - } |
---|
225 | | - |
---|
226 | | - return 0; |
---|
| 230 | + return err; |
---|
227 | 231 | } |
---|
228 | 232 | |
---|
229 | | -static int |
---|
230 | | -pcm_capture_hw_free(struct snd_pcm_substream *substream) |
---|
| 233 | +static int pcm_hw_free(struct snd_pcm_substream *substream) |
---|
231 | 234 | { |
---|
232 | 235 | struct snd_bebob *bebob = substream->private_data; |
---|
233 | 236 | |
---|
234 | | - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) { |
---|
235 | | - mutex_lock(&bebob->mutex); |
---|
| 237 | + mutex_lock(&bebob->mutex); |
---|
| 238 | + |
---|
| 239 | + if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) |
---|
236 | 240 | bebob->substreams_counter--; |
---|
237 | | - mutex_unlock(&bebob->mutex); |
---|
238 | | - } |
---|
239 | 241 | |
---|
240 | 242 | snd_bebob_stream_stop_duplex(bebob); |
---|
241 | 243 | |
---|
242 | | - return snd_pcm_lib_free_vmalloc_buffer(substream); |
---|
243 | | -} |
---|
244 | | -static int |
---|
245 | | -pcm_playback_hw_free(struct snd_pcm_substream *substream) |
---|
246 | | -{ |
---|
247 | | - struct snd_bebob *bebob = substream->private_data; |
---|
| 244 | + mutex_unlock(&bebob->mutex); |
---|
248 | 245 | |
---|
249 | | - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) { |
---|
250 | | - mutex_lock(&bebob->mutex); |
---|
251 | | - bebob->substreams_counter--; |
---|
252 | | - mutex_unlock(&bebob->mutex); |
---|
253 | | - } |
---|
254 | | - |
---|
255 | | - snd_bebob_stream_stop_duplex(bebob); |
---|
256 | | - |
---|
257 | | - return snd_pcm_lib_free_vmalloc_buffer(substream); |
---|
| 246 | + return 0; |
---|
258 | 247 | } |
---|
259 | 248 | |
---|
260 | 249 | static int |
---|
261 | 250 | pcm_capture_prepare(struct snd_pcm_substream *substream) |
---|
262 | 251 | { |
---|
263 | 252 | struct snd_bebob *bebob = substream->private_data; |
---|
264 | | - struct snd_pcm_runtime *runtime = substream->runtime; |
---|
265 | 253 | int err; |
---|
266 | 254 | |
---|
267 | | - err = snd_bebob_stream_start_duplex(bebob, runtime->rate); |
---|
| 255 | + err = snd_bebob_stream_start_duplex(bebob); |
---|
268 | 256 | if (err >= 0) |
---|
269 | 257 | amdtp_stream_pcm_prepare(&bebob->tx_stream); |
---|
270 | 258 | |
---|
.. | .. |
---|
274 | 262 | pcm_playback_prepare(struct snd_pcm_substream *substream) |
---|
275 | 263 | { |
---|
276 | 264 | struct snd_bebob *bebob = substream->private_data; |
---|
277 | | - struct snd_pcm_runtime *runtime = substream->runtime; |
---|
278 | 265 | int err; |
---|
279 | 266 | |
---|
280 | | - err = snd_bebob_stream_start_duplex(bebob, runtime->rate); |
---|
| 267 | + err = snd_bebob_stream_start_duplex(bebob); |
---|
281 | 268 | if (err >= 0) |
---|
282 | 269 | amdtp_stream_pcm_prepare(&bebob->rx_stream); |
---|
283 | 270 | |
---|
.. | .. |
---|
321 | 308 | return 0; |
---|
322 | 309 | } |
---|
323 | 310 | |
---|
324 | | -static snd_pcm_uframes_t |
---|
325 | | -pcm_capture_pointer(struct snd_pcm_substream *sbstrm) |
---|
| 311 | +static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm) |
---|
326 | 312 | { |
---|
327 | 313 | struct snd_bebob *bebob = sbstrm->private_data; |
---|
328 | | - return amdtp_stream_pcm_pointer(&bebob->tx_stream); |
---|
| 314 | + |
---|
| 315 | + return amdtp_domain_stream_pcm_pointer(&bebob->domain, |
---|
| 316 | + &bebob->tx_stream); |
---|
329 | 317 | } |
---|
330 | | -static snd_pcm_uframes_t |
---|
331 | | -pcm_playback_pointer(struct snd_pcm_substream *sbstrm) |
---|
| 318 | +static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) |
---|
332 | 319 | { |
---|
333 | 320 | struct snd_bebob *bebob = sbstrm->private_data; |
---|
334 | | - return amdtp_stream_pcm_pointer(&bebob->rx_stream); |
---|
| 321 | + |
---|
| 322 | + return amdtp_domain_stream_pcm_pointer(&bebob->domain, |
---|
| 323 | + &bebob->rx_stream); |
---|
335 | 324 | } |
---|
336 | 325 | |
---|
337 | 326 | static int pcm_capture_ack(struct snd_pcm_substream *substream) |
---|
338 | 327 | { |
---|
339 | 328 | struct snd_bebob *bebob = substream->private_data; |
---|
340 | 329 | |
---|
341 | | - return amdtp_stream_pcm_ack(&bebob->tx_stream); |
---|
| 330 | + return amdtp_domain_stream_pcm_ack(&bebob->domain, &bebob->tx_stream); |
---|
342 | 331 | } |
---|
343 | 332 | |
---|
344 | 333 | static int pcm_playback_ack(struct snd_pcm_substream *substream) |
---|
345 | 334 | { |
---|
346 | 335 | struct snd_bebob *bebob = substream->private_data; |
---|
347 | 336 | |
---|
348 | | - return amdtp_stream_pcm_ack(&bebob->rx_stream); |
---|
| 337 | + return amdtp_domain_stream_pcm_ack(&bebob->domain, &bebob->rx_stream); |
---|
349 | 338 | } |
---|
350 | 339 | |
---|
351 | 340 | int snd_bebob_create_pcm_devices(struct snd_bebob *bebob) |
---|
.. | .. |
---|
353 | 342 | static const struct snd_pcm_ops capture_ops = { |
---|
354 | 343 | .open = pcm_open, |
---|
355 | 344 | .close = pcm_close, |
---|
356 | | - .ioctl = snd_pcm_lib_ioctl, |
---|
357 | | - .hw_params = pcm_capture_hw_params, |
---|
358 | | - .hw_free = pcm_capture_hw_free, |
---|
| 345 | + .hw_params = pcm_hw_params, |
---|
| 346 | + .hw_free = pcm_hw_free, |
---|
359 | 347 | .prepare = pcm_capture_prepare, |
---|
360 | 348 | .trigger = pcm_capture_trigger, |
---|
361 | 349 | .pointer = pcm_capture_pointer, |
---|
362 | 350 | .ack = pcm_capture_ack, |
---|
363 | | - .page = snd_pcm_lib_get_vmalloc_page, |
---|
364 | 351 | }; |
---|
365 | 352 | static const struct snd_pcm_ops playback_ops = { |
---|
366 | 353 | .open = pcm_open, |
---|
367 | 354 | .close = pcm_close, |
---|
368 | | - .ioctl = snd_pcm_lib_ioctl, |
---|
369 | | - .hw_params = pcm_playback_hw_params, |
---|
370 | | - .hw_free = pcm_playback_hw_free, |
---|
| 355 | + .hw_params = pcm_hw_params, |
---|
| 356 | + .hw_free = pcm_hw_free, |
---|
371 | 357 | .prepare = pcm_playback_prepare, |
---|
372 | 358 | .trigger = pcm_playback_trigger, |
---|
373 | 359 | .pointer = pcm_playback_pointer, |
---|
374 | 360 | .ack = pcm_playback_ack, |
---|
375 | | - .page = snd_pcm_lib_get_vmalloc_page, |
---|
376 | 361 | }; |
---|
377 | 362 | struct snd_pcm *pcm; |
---|
378 | 363 | int err; |
---|
.. | .. |
---|
386 | 371 | "%s PCM", bebob->card->shortname); |
---|
387 | 372 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); |
---|
388 | 373 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); |
---|
| 374 | + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); |
---|
389 | 375 | end: |
---|
390 | 376 | return err; |
---|
391 | 377 | } |
---|