summaryrefslogtreecommitdiff
path: root/sound/firewire/oxfw/oxfw-pcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/firewire/oxfw/oxfw-pcm.c')
-rw-r--r--sound/firewire/oxfw/oxfw-pcm.c168
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;
}