.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * dice_pcm.c - a part of driver for DICE based devices |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> |
---|
5 | 6 | * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp> |
---|
6 | | - * |
---|
7 | | - * Licensed under the terms of the GNU General Public License, version 2. |
---|
8 | 7 | */ |
---|
9 | 8 | |
---|
10 | 9 | #include "dice.h" |
---|
.. | .. |
---|
165 | 164 | static int pcm_open(struct snd_pcm_substream *substream) |
---|
166 | 165 | { |
---|
167 | 166 | struct snd_dice *dice = substream->private_data; |
---|
| 167 | + struct amdtp_domain *d = &dice->domain; |
---|
168 | 168 | unsigned int source; |
---|
169 | 169 | bool internal; |
---|
170 | 170 | int err; |
---|
171 | 171 | |
---|
172 | 172 | err = snd_dice_stream_lock_try(dice); |
---|
173 | 173 | if (err < 0) |
---|
174 | | - goto end; |
---|
| 174 | + return err; |
---|
175 | 175 | |
---|
176 | 176 | err = init_hw_info(dice, substream); |
---|
177 | 177 | if (err < 0) |
---|
.. | .. |
---|
196 | 196 | break; |
---|
197 | 197 | } |
---|
198 | 198 | |
---|
199 | | - /* |
---|
200 | | - * When source of clock is not internal or any PCM streams are running, |
---|
201 | | - * available sampling rate is limited at current sampling rate. |
---|
202 | | - */ |
---|
| 199 | + mutex_lock(&dice->mutex); |
---|
| 200 | + |
---|
| 201 | + // When source of clock is not internal or any stream is reserved for |
---|
| 202 | + // transmission of PCM frames, the available sampling rate is limited |
---|
| 203 | + // at current one. |
---|
203 | 204 | if (!internal || |
---|
204 | | - amdtp_stream_pcm_running(&dice->tx_stream[0]) || |
---|
205 | | - amdtp_stream_pcm_running(&dice->tx_stream[1]) || |
---|
206 | | - amdtp_stream_pcm_running(&dice->rx_stream[0]) || |
---|
207 | | - amdtp_stream_pcm_running(&dice->rx_stream[1])) { |
---|
| 205 | + (dice->substreams_counter > 0 && d->events_per_period > 0)) { |
---|
| 206 | + unsigned int frames_per_period = d->events_per_period; |
---|
| 207 | + unsigned int frames_per_buffer = d->events_per_buffer; |
---|
208 | 208 | unsigned int rate; |
---|
209 | 209 | |
---|
210 | 210 | err = snd_dice_transaction_get_rate(dice, &rate); |
---|
211 | | - if (err < 0) |
---|
| 211 | + if (err < 0) { |
---|
| 212 | + mutex_unlock(&dice->mutex); |
---|
212 | 213 | goto err_locked; |
---|
| 214 | + } |
---|
| 215 | + |
---|
213 | 216 | substream->runtime->hw.rate_min = rate; |
---|
214 | 217 | substream->runtime->hw.rate_max = rate; |
---|
| 218 | + |
---|
| 219 | + if (frames_per_period > 0) { |
---|
| 220 | + // For double_pcm_frame quirk. |
---|
| 221 | + if (rate > 96000) { |
---|
| 222 | + frames_per_period *= 2; |
---|
| 223 | + frames_per_buffer *= 2; |
---|
| 224 | + } |
---|
| 225 | + |
---|
| 226 | + err = snd_pcm_hw_constraint_minmax(substream->runtime, |
---|
| 227 | + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, |
---|
| 228 | + frames_per_period, frames_per_period); |
---|
| 229 | + if (err < 0) { |
---|
| 230 | + mutex_unlock(&dice->mutex); |
---|
| 231 | + goto err_locked; |
---|
| 232 | + } |
---|
| 233 | + |
---|
| 234 | + err = snd_pcm_hw_constraint_minmax(substream->runtime, |
---|
| 235 | + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, |
---|
| 236 | + frames_per_buffer, frames_per_buffer); |
---|
| 237 | + if (err < 0) { |
---|
| 238 | + mutex_unlock(&dice->mutex); |
---|
| 239 | + goto err_locked; |
---|
| 240 | + } |
---|
| 241 | + } |
---|
215 | 242 | } |
---|
216 | 243 | |
---|
| 244 | + mutex_unlock(&dice->mutex); |
---|
| 245 | + |
---|
217 | 246 | snd_pcm_set_sync(substream); |
---|
218 | | -end: |
---|
219 | | - return err; |
---|
| 247 | + |
---|
| 248 | + return 0; |
---|
220 | 249 | err_locked: |
---|
221 | 250 | snd_dice_stream_lock_release(dice); |
---|
222 | 251 | return err; |
---|
.. | .. |
---|
231 | 260 | return 0; |
---|
232 | 261 | } |
---|
233 | 262 | |
---|
234 | | -static int capture_hw_params(struct snd_pcm_substream *substream, |
---|
235 | | - struct snd_pcm_hw_params *hw_params) |
---|
| 263 | +static int pcm_hw_params(struct snd_pcm_substream *substream, |
---|
| 264 | + struct snd_pcm_hw_params *hw_params) |
---|
236 | 265 | { |
---|
237 | 266 | struct snd_dice *dice = substream->private_data; |
---|
238 | | - int err; |
---|
239 | | - |
---|
240 | | - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, |
---|
241 | | - params_buffer_bytes(hw_params)); |
---|
242 | | - if (err < 0) |
---|
243 | | - return err; |
---|
| 267 | + int err = 0; |
---|
244 | 268 | |
---|
245 | 269 | if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { |
---|
| 270 | + unsigned int rate = params_rate(hw_params); |
---|
| 271 | + unsigned int events_per_period = params_period_size(hw_params); |
---|
| 272 | + unsigned int events_per_buffer = params_buffer_size(hw_params); |
---|
| 273 | + |
---|
246 | 274 | mutex_lock(&dice->mutex); |
---|
247 | | - dice->substreams_counter++; |
---|
| 275 | + // For double_pcm_frame quirk. |
---|
| 276 | + if (rate > 96000) { |
---|
| 277 | + events_per_period /= 2; |
---|
| 278 | + events_per_buffer /= 2; |
---|
| 279 | + } |
---|
| 280 | + err = snd_dice_stream_reserve_duplex(dice, rate, |
---|
| 281 | + events_per_period, events_per_buffer); |
---|
| 282 | + if (err >= 0) |
---|
| 283 | + ++dice->substreams_counter; |
---|
248 | 284 | mutex_unlock(&dice->mutex); |
---|
249 | 285 | } |
---|
250 | 286 | |
---|
251 | | - return 0; |
---|
252 | | -} |
---|
253 | | -static int playback_hw_params(struct snd_pcm_substream *substream, |
---|
254 | | - struct snd_pcm_hw_params *hw_params) |
---|
255 | | -{ |
---|
256 | | - struct snd_dice *dice = substream->private_data; |
---|
257 | | - int err; |
---|
258 | | - |
---|
259 | | - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, |
---|
260 | | - params_buffer_bytes(hw_params)); |
---|
261 | | - if (err < 0) |
---|
262 | | - return err; |
---|
263 | | - |
---|
264 | | - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { |
---|
265 | | - mutex_lock(&dice->mutex); |
---|
266 | | - dice->substreams_counter++; |
---|
267 | | - mutex_unlock(&dice->mutex); |
---|
268 | | - } |
---|
269 | | - |
---|
270 | | - return 0; |
---|
| 287 | + return err; |
---|
271 | 288 | } |
---|
272 | 289 | |
---|
273 | | -static int capture_hw_free(struct snd_pcm_substream *substream) |
---|
| 290 | +static int pcm_hw_free(struct snd_pcm_substream *substream) |
---|
274 | 291 | { |
---|
275 | 292 | struct snd_dice *dice = substream->private_data; |
---|
276 | 293 | |
---|
277 | 294 | mutex_lock(&dice->mutex); |
---|
278 | 295 | |
---|
279 | 296 | if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) |
---|
280 | | - dice->substreams_counter--; |
---|
| 297 | + --dice->substreams_counter; |
---|
281 | 298 | |
---|
282 | 299 | snd_dice_stream_stop_duplex(dice); |
---|
283 | 300 | |
---|
284 | 301 | mutex_unlock(&dice->mutex); |
---|
285 | 302 | |
---|
286 | | - return snd_pcm_lib_free_vmalloc_buffer(substream); |
---|
287 | | -} |
---|
288 | | - |
---|
289 | | -static int playback_hw_free(struct snd_pcm_substream *substream) |
---|
290 | | -{ |
---|
291 | | - struct snd_dice *dice = substream->private_data; |
---|
292 | | - |
---|
293 | | - mutex_lock(&dice->mutex); |
---|
294 | | - |
---|
295 | | - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) |
---|
296 | | - dice->substreams_counter--; |
---|
297 | | - |
---|
298 | | - snd_dice_stream_stop_duplex(dice); |
---|
299 | | - |
---|
300 | | - mutex_unlock(&dice->mutex); |
---|
301 | | - |
---|
302 | | - return snd_pcm_lib_free_vmalloc_buffer(substream); |
---|
| 303 | + return 0; |
---|
303 | 304 | } |
---|
304 | 305 | |
---|
305 | 306 | static int capture_prepare(struct snd_pcm_substream *substream) |
---|
.. | .. |
---|
309 | 310 | int err; |
---|
310 | 311 | |
---|
311 | 312 | mutex_lock(&dice->mutex); |
---|
312 | | - err = snd_dice_stream_start_duplex(dice, substream->runtime->rate); |
---|
| 313 | + err = snd_dice_stream_start_duplex(dice); |
---|
313 | 314 | mutex_unlock(&dice->mutex); |
---|
314 | 315 | if (err >= 0) |
---|
315 | 316 | amdtp_stream_pcm_prepare(stream); |
---|
.. | .. |
---|
323 | 324 | int err; |
---|
324 | 325 | |
---|
325 | 326 | mutex_lock(&dice->mutex); |
---|
326 | | - err = snd_dice_stream_start_duplex(dice, substream->runtime->rate); |
---|
| 327 | + err = snd_dice_stream_start_duplex(dice); |
---|
327 | 328 | mutex_unlock(&dice->mutex); |
---|
328 | 329 | if (err >= 0) |
---|
329 | 330 | amdtp_stream_pcm_prepare(stream); |
---|
.. | .. |
---|
373 | 374 | struct snd_dice *dice = substream->private_data; |
---|
374 | 375 | struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; |
---|
375 | 376 | |
---|
376 | | - return amdtp_stream_pcm_pointer(stream); |
---|
| 377 | + return amdtp_domain_stream_pcm_pointer(&dice->domain, stream); |
---|
377 | 378 | } |
---|
378 | 379 | static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream) |
---|
379 | 380 | { |
---|
380 | 381 | struct snd_dice *dice = substream->private_data; |
---|
381 | 382 | struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; |
---|
382 | 383 | |
---|
383 | | - return amdtp_stream_pcm_pointer(stream); |
---|
| 384 | + return amdtp_domain_stream_pcm_pointer(&dice->domain, stream); |
---|
384 | 385 | } |
---|
385 | 386 | |
---|
386 | 387 | static int capture_ack(struct snd_pcm_substream *substream) |
---|
.. | .. |
---|
388 | 389 | struct snd_dice *dice = substream->private_data; |
---|
389 | 390 | struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; |
---|
390 | 391 | |
---|
391 | | - return amdtp_stream_pcm_ack(stream); |
---|
| 392 | + return amdtp_domain_stream_pcm_ack(&dice->domain, stream); |
---|
392 | 393 | } |
---|
393 | 394 | |
---|
394 | 395 | static int playback_ack(struct snd_pcm_substream *substream) |
---|
.. | .. |
---|
396 | 397 | struct snd_dice *dice = substream->private_data; |
---|
397 | 398 | struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; |
---|
398 | 399 | |
---|
399 | | - return amdtp_stream_pcm_ack(stream); |
---|
| 400 | + return amdtp_domain_stream_pcm_ack(&dice->domain, stream); |
---|
400 | 401 | } |
---|
401 | 402 | |
---|
402 | 403 | int snd_dice_create_pcm(struct snd_dice *dice) |
---|
.. | .. |
---|
404 | 405 | static const struct snd_pcm_ops capture_ops = { |
---|
405 | 406 | .open = pcm_open, |
---|
406 | 407 | .close = pcm_close, |
---|
407 | | - .ioctl = snd_pcm_lib_ioctl, |
---|
408 | | - .hw_params = capture_hw_params, |
---|
409 | | - .hw_free = capture_hw_free, |
---|
| 408 | + .hw_params = pcm_hw_params, |
---|
| 409 | + .hw_free = pcm_hw_free, |
---|
410 | 410 | .prepare = capture_prepare, |
---|
411 | 411 | .trigger = capture_trigger, |
---|
412 | 412 | .pointer = capture_pointer, |
---|
413 | 413 | .ack = capture_ack, |
---|
414 | | - .page = snd_pcm_lib_get_vmalloc_page, |
---|
415 | 414 | }; |
---|
416 | 415 | static const struct snd_pcm_ops playback_ops = { |
---|
417 | 416 | .open = pcm_open, |
---|
418 | 417 | .close = pcm_close, |
---|
419 | | - .ioctl = snd_pcm_lib_ioctl, |
---|
420 | | - .hw_params = playback_hw_params, |
---|
421 | | - .hw_free = playback_hw_free, |
---|
| 418 | + .hw_params = pcm_hw_params, |
---|
| 419 | + .hw_free = pcm_hw_free, |
---|
422 | 420 | .prepare = playback_prepare, |
---|
423 | 421 | .trigger = playback_trigger, |
---|
424 | 422 | .pointer = playback_pointer, |
---|
425 | 423 | .ack = playback_ack, |
---|
426 | | - .page = snd_pcm_lib_get_vmalloc_page, |
---|
427 | 424 | }; |
---|
428 | 425 | struct snd_pcm *pcm; |
---|
429 | 426 | unsigned int capture, playback; |
---|
.. | .. |
---|
453 | 450 | if (playback > 0) |
---|
454 | 451 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, |
---|
455 | 452 | &playback_ops); |
---|
| 453 | + |
---|
| 454 | + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, |
---|
| 455 | + NULL, 0, 0); |
---|
456 | 456 | } |
---|
457 | 457 | |
---|
458 | 458 | return 0; |
---|