aboutsummaryrefslogtreecommitdiffstats
path: root/sound/firewire/dice/dice-pcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/firewire/dice/dice-pcm.c')
-rw-r--r--sound/firewire/dice/dice-pcm.c83
1 files changed, 61 insertions, 22 deletions
diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c
index 94a4dccfc381..be79d659eedf 100644
--- a/sound/firewire/dice/dice-pcm.c
+++ b/sound/firewire/dice/dice-pcm.c
@@ -164,13 +164,14 @@ static int init_hw_info(struct snd_dice *dice,
static int pcm_open(struct snd_pcm_substream *substream)
{
struct snd_dice *dice = substream->private_data;
+ struct amdtp_domain *d = &dice->domain;
unsigned int source;
bool internal;
int err;
err = snd_dice_stream_lock_try(dice);
if (err < 0)
- goto end;
+ return err;
err = init_hw_info(dice, substream);
if (err < 0)
@@ -195,27 +196,56 @@ static int pcm_open(struct snd_pcm_substream *substream)
break;
}
- /*
- * When source of clock is not internal or any PCM streams are running,
- * available sampling rate is limited at current sampling rate.
- */
+ mutex_lock(&dice->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 (!internal ||
- amdtp_stream_pcm_running(&dice->tx_stream[0]) ||
- amdtp_stream_pcm_running(&dice->tx_stream[1]) ||
- amdtp_stream_pcm_running(&dice->rx_stream[0]) ||
- amdtp_stream_pcm_running(&dice->rx_stream[1])) {
+ (dice->substreams_counter > 0 && d->events_per_period > 0)) {
+ unsigned int frames_per_period = d->events_per_period;
+ unsigned int frames_per_buffer = d->events_per_buffer;
unsigned int rate;
err = snd_dice_transaction_get_rate(dice, &rate);
- if (err < 0)
+ if (err < 0) {
+ mutex_unlock(&dice->mutex);
goto err_locked;
+ }
+
substream->runtime->hw.rate_min = rate;
substream->runtime->hw.rate_max = rate;
+
+ if (frames_per_period > 0) {
+ // For double_pcm_frame quirk.
+ if (rate > 96000) {
+ frames_per_period *= 2;
+ frames_per_buffer *= 2;
+ }
+
+ err = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ frames_per_period, frames_per_period);
+ if (err < 0) {
+ mutex_unlock(&dice->mutex);
+ 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) {
+ mutex_unlock(&dice->mutex);
+ goto err_locked;
+ }
+ }
}
+ mutex_unlock(&dice->mutex);
+
snd_pcm_set_sync(substream);
-end:
- return err;
+
+ return 0;
err_locked:
snd_dice_stream_lock_release(dice);
return err;
@@ -236,16 +266,23 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_dice *dice = substream->private_data;
int err;
- err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
- params_buffer_bytes(hw_params));
+ err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
if (err < 0)
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
unsigned int rate = params_rate(hw_params);
+ unsigned int events_per_period = params_period_size(hw_params);
+ unsigned int events_per_buffer = params_buffer_size(hw_params);
mutex_lock(&dice->mutex);
- err = snd_dice_stream_reserve_duplex(dice, rate);
+ // For double_pcm_frame quirk.
+ if (rate > 96000) {
+ events_per_period /= 2;
+ events_per_buffer /= 2;
+ }
+ err = snd_dice_stream_reserve_duplex(dice, rate,
+ events_per_period, events_per_buffer);
if (err >= 0)
++dice->substreams_counter;
mutex_unlock(&dice->mutex);
@@ -267,7 +304,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
mutex_unlock(&dice->mutex);
- return snd_pcm_lib_free_vmalloc_buffer(substream);
+ return snd_pcm_lib_free_pages(substream);
}
static int capture_prepare(struct snd_pcm_substream *substream)
@@ -341,14 +378,14 @@ static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
struct snd_dice *dice = substream->private_data;
struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
- return amdtp_stream_pcm_pointer(stream);
+ return amdtp_domain_stream_pcm_pointer(&dice->domain, stream);
}
static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
{
struct snd_dice *dice = substream->private_data;
struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
- return amdtp_stream_pcm_pointer(stream);
+ return amdtp_domain_stream_pcm_pointer(&dice->domain, stream);
}
static int capture_ack(struct snd_pcm_substream *substream)
@@ -356,7 +393,7 @@ static int capture_ack(struct snd_pcm_substream *substream)
struct snd_dice *dice = substream->private_data;
struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
- return amdtp_stream_pcm_ack(stream);
+ return amdtp_domain_stream_pcm_ack(&dice->domain, stream);
}
static int playback_ack(struct snd_pcm_substream *substream)
@@ -364,7 +401,7 @@ static int playback_ack(struct snd_pcm_substream *substream)
struct snd_dice *dice = substream->private_data;
struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
- return amdtp_stream_pcm_ack(stream);
+ return amdtp_domain_stream_pcm_ack(&dice->domain, stream);
}
int snd_dice_create_pcm(struct snd_dice *dice)
@@ -379,7 +416,6 @@ int snd_dice_create_pcm(struct snd_dice *dice)
.trigger = capture_trigger,
.pointer = capture_pointer,
.ack = capture_ack,
- .page = snd_pcm_lib_get_vmalloc_page,
};
static const struct snd_pcm_ops playback_ops = {
.open = pcm_open,
@@ -391,7 +427,6 @@ int snd_dice_create_pcm(struct snd_dice *dice)
.trigger = playback_trigger,
.pointer = playback_pointer,
.ack = playback_ack,
- .page = snd_pcm_lib_get_vmalloc_page,
};
struct snd_pcm *pcm;
unsigned int capture, playback;
@@ -421,6 +456,10 @@ int snd_dice_create_pcm(struct snd_dice *dice)
if (playback > 0)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
&playback_ops);
+
+ snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_VMALLOC,
+ NULL, 0, 0);
}
return 0;