diff options
Diffstat (limited to 'sound/firewire/oxfw/oxfw-pcm.c')
| -rw-r--r-- | sound/firewire/oxfw/oxfw-pcm.c | 168 |
1 files changed, 90 insertions, 78 deletions
diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index b3f6503dd34d..774b8a763795 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -1,8 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * oxfw_pcm.c - a part of driver for OXFW970/971 based devices * * Copyright (c) Clemens Ladisch <clemens@ladisch.de> - * Licensed under the terms of the GNU General Public License, version 2. */ #include "oxfw.h" @@ -170,30 +170,48 @@ end: static int pcm_open(struct snd_pcm_substream *substream) { struct snd_oxfw *oxfw = substream->private_data; + struct amdtp_domain *d = &oxfw->domain; int err; err = snd_oxfw_stream_lock_try(oxfw); if (err < 0) - goto end; + return err; err = init_hw_params(oxfw, substream); if (err < 0) goto err_locked; - /* - * When any PCM streams are already running, the available sampling - * rate is limited at current value. - */ - if (amdtp_stream_pcm_running(&oxfw->tx_stream) || - amdtp_stream_pcm_running(&oxfw->rx_stream)) { - err = limit_to_current_params(substream); - if (err < 0) - goto end; + scoped_guard(mutex, &oxfw->mutex) { + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. + if (oxfw->substreams_count > 0 && d->events_per_period > 0) { + unsigned int frames_per_period = d->events_per_period; + unsigned int frames_per_buffer = d->events_per_buffer; + + err = limit_to_current_params(substream); + if (err < 0) + goto err_locked; + + if (frames_per_period > 0) { + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) + goto err_locked; + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + frames_per_buffer, frames_per_buffer); + if (err < 0) + goto err_locked; + } + } } snd_pcm_set_sync(substream); -end: - return err; + + return 0; err_locked: snd_oxfw_stream_lock_release(oxfw); return err; @@ -211,105 +229,101 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_oxfw *oxfw = substream->private_data; - int err; - - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - if (err < 0) - return err; - - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { - mutex_lock(&oxfw->mutex); - oxfw->capture_substreams++; - mutex_unlock(&oxfw->mutex); + int err = 0; + + if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) { + unsigned int rate = params_rate(hw_params); + unsigned int channels = params_channels(hw_params); + unsigned int frames_per_period = params_period_size(hw_params); + unsigned int frames_per_buffer = params_buffer_size(hw_params); + + guard(mutex)(&oxfw->mutex); + err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, + rate, channels, frames_per_period, + frames_per_buffer); + if (err >= 0) + ++oxfw->substreams_count; } - return 0; + return err; } static int pcm_playback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_oxfw *oxfw = substream->private_data; - int err; - - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - if (err < 0) - return err; - - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { - mutex_lock(&oxfw->mutex); - oxfw->playback_substreams++; - mutex_unlock(&oxfw->mutex); + int err = 0; + + if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) { + unsigned int rate = params_rate(hw_params); + unsigned int channels = params_channels(hw_params); + unsigned int frames_per_period = params_period_size(hw_params); + unsigned int frames_per_buffer = params_buffer_size(hw_params); + + guard(mutex)(&oxfw->mutex); + err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, + rate, channels, frames_per_period, + frames_per_buffer); + if (err >= 0) + ++oxfw->substreams_count; } - return 0; + return err; } static int pcm_capture_hw_free(struct snd_pcm_substream *substream) { struct snd_oxfw *oxfw = substream->private_data; - mutex_lock(&oxfw->mutex); - - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) - oxfw->capture_substreams--; + guard(mutex)(&oxfw->mutex); - snd_oxfw_stream_stop_simplex(oxfw, &oxfw->tx_stream); + if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) + --oxfw->substreams_count; - mutex_unlock(&oxfw->mutex); + snd_oxfw_stream_stop_duplex(oxfw); - return snd_pcm_lib_free_vmalloc_buffer(substream); + return 0; } static int pcm_playback_hw_free(struct snd_pcm_substream *substream) { struct snd_oxfw *oxfw = substream->private_data; - mutex_lock(&oxfw->mutex); + guard(mutex)(&oxfw->mutex); - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) - oxfw->playback_substreams--; + if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) + --oxfw->substreams_count; - snd_oxfw_stream_stop_simplex(oxfw, &oxfw->rx_stream); + snd_oxfw_stream_stop_duplex(oxfw); - mutex_unlock(&oxfw->mutex); - - return snd_pcm_lib_free_vmalloc_buffer(substream); + return 0; } static int pcm_capture_prepare(struct snd_pcm_substream *substream) { struct snd_oxfw *oxfw = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; int err; - mutex_lock(&oxfw->mutex); - err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->tx_stream, - runtime->rate, runtime->channels); - mutex_unlock(&oxfw->mutex); - if (err < 0) - goto end; + scoped_guard(mutex, &oxfw->mutex) { + err = snd_oxfw_stream_start_duplex(oxfw); + if (err < 0) + return err; + } amdtp_stream_pcm_prepare(&oxfw->tx_stream); -end: - return err; + return 0; } static int pcm_playback_prepare(struct snd_pcm_substream *substream) { struct snd_oxfw *oxfw = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; int err; - mutex_lock(&oxfw->mutex); - err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->rx_stream, - runtime->rate, runtime->channels); - mutex_unlock(&oxfw->mutex); - if (err < 0) - goto end; + scoped_guard(mutex, &oxfw->mutex) { + err = snd_oxfw_stream_start_duplex(oxfw); + if (err < 0) + return err; + } amdtp_stream_pcm_prepare(&oxfw->rx_stream); -end: - return err; + return 0; } static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) @@ -353,27 +367,27 @@ static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstm) { struct snd_oxfw *oxfw = sbstm->private_data; - return amdtp_stream_pcm_pointer(&oxfw->tx_stream); + return amdtp_domain_stream_pcm_pointer(&oxfw->domain, &oxfw->tx_stream); } static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstm) { struct snd_oxfw *oxfw = sbstm->private_data; - return amdtp_stream_pcm_pointer(&oxfw->rx_stream); + return amdtp_domain_stream_pcm_pointer(&oxfw->domain, &oxfw->rx_stream); } static int pcm_capture_ack(struct snd_pcm_substream *substream) { struct snd_oxfw *oxfw = substream->private_data; - return amdtp_stream_pcm_ack(&oxfw->tx_stream); + return amdtp_domain_stream_pcm_ack(&oxfw->domain, &oxfw->tx_stream); } static int pcm_playback_ack(struct snd_pcm_substream *substream) { struct snd_oxfw *oxfw = substream->private_data; - return amdtp_stream_pcm_ack(&oxfw->rx_stream); + return amdtp_domain_stream_pcm_ack(&oxfw->domain, &oxfw->rx_stream); } int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) @@ -381,26 +395,22 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) static const struct snd_pcm_ops capture_ops = { .open = pcm_open, .close = pcm_close, - .ioctl = snd_pcm_lib_ioctl, .hw_params = pcm_capture_hw_params, .hw_free = pcm_capture_hw_free, .prepare = pcm_capture_prepare, .trigger = pcm_capture_trigger, .pointer = pcm_capture_pointer, .ack = pcm_capture_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; static const struct snd_pcm_ops playback_ops = { .open = pcm_open, .close = pcm_close, - .ioctl = snd_pcm_lib_ioctl, .hw_params = pcm_playback_hw_params, .hw_free = pcm_playback_hw_free, .prepare = pcm_playback_prepare, .trigger = pcm_playback_trigger, .pointer = pcm_playback_pointer, .ack = pcm_playback_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; struct snd_pcm *pcm; unsigned int cap = 0; @@ -414,10 +424,12 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) return err; pcm->private_data = oxfw; - strcpy(pcm->name, oxfw->card->shortname); + pcm->nonatomic = true; + strscpy(pcm->name, oxfw->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); if (cap > 0) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); return 0; } |
