diff options
Diffstat (limited to 'sound/firewire/dice/dice-pcm.c')
-rw-r--r-- | sound/firewire/dice/dice-pcm.c | 88 |
1 files changed, 60 insertions, 28 deletions
diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 94a4dccfc381..af8a90ee40f3 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; @@ -234,18 +264,21 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_dice *dice = substream->private_data; - int err; - - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - if (err < 0) - return err; + int err = 0; 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 +300,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) mutex_unlock(&dice->mutex); - return snd_pcm_lib_free_vmalloc_buffer(substream); + return 0; } static int capture_prepare(struct snd_pcm_substream *substream) @@ -341,14 +374,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 +389,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 +397,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) @@ -372,26 +405,22 @@ int snd_dice_create_pcm(struct snd_dice *dice) static const struct snd_pcm_ops capture_ops = { .open = pcm_open, .close = pcm_close, - .ioctl = snd_pcm_lib_ioctl, .hw_params = pcm_hw_params, .hw_free = pcm_hw_free, .prepare = capture_prepare, .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, .close = pcm_close, - .ioctl = snd_pcm_lib_ioctl, .hw_params = pcm_hw_params, .hw_free = pcm_hw_free, .prepare = playback_prepare, .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 +450,9 @@ 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_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); } return 0; |