1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- From f204c383ca1e309b94e7c447b1b15f1063a4d2ba Mon Sep 17 00:00:00 2001
- From: wm4 <wm4@nowhere>
- Date: Wed, 13 Jan 2016 19:42:18 +0100
- Subject: [PATCH] bcm2835: restrict channels*rate to 8*960000
- This is required at least for SPDIF. If the bitrate goes above,
- videocore will either resample the audio or corrupt it due to
- underruns. Supposedly the hardware isn't designed to output
- higher rates, but it can still resample it down to supported
- rates.
- Some code is based on ac97_pcm.c.
- ---
- sound/arm/bcm2835-pcm.c | 41 +++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 41 insertions(+)
- --- a/sound/arm/bcm2835-pcm.c
- +++ b/sound/arm/bcm2835-pcm.c
- @@ -19,6 +19,9 @@
-
- #include "bcm2835.h"
-
- +/* The hardware can not do much more num_channels*samplerate then this value */
- +#define MAX_COMBINED_RATE 768000
- +
- /* hardware definition */
- static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
- .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
- @@ -107,6 +110,31 @@ static irqreturn_t bcm2835_playback_fifo
- return IRQ_HANDLED;
- }
-
- +
- +static int rate_hw_constraint_rate(struct snd_pcm_hw_params *params,
- + struct snd_pcm_hw_rule *rule)
- +{
- + struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
- + struct snd_interval rates = {
- + .min = 8000,
- + .max = min(192000u, MAX_COMBINED_RATE / max(channels->min, 1u)),
- + };
- + struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
- + return snd_interval_refine(rate, &rates);
- +}
- +
- +static int rate_hw_constraint_channels(struct snd_pcm_hw_params *params,
- + struct snd_pcm_hw_rule *rule)
- +{
- + struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
- + struct snd_interval channels_interval = {
- + .min = 1,
- + .max = min(8u, MAX_COMBINED_RATE / max(rate->min, 1u)),
- + };
- + struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
- + return snd_interval_refine(channels, &channels_interval);
- +}
- +
- /* open callback */
- static int snd_bcm2835_playback_open_generic(
- struct snd_pcm_substream *substream, int spdif)
- @@ -188,6 +216,19 @@ static int snd_bcm2835_playback_open_gen
- snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
- 16);
-
- + /* When playing PCM, pretend that we support the full range of channels
- + * and sample rates. The GPU can't output it, but is able to resample
- + * the data to a rate the hardware can handle it. This won't work with
- + * compressed data; the resampler would just destroy it. */
- + if (spdif) {
- + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
- + rate_hw_constraint_rate, NULL,
- + SNDRV_PCM_HW_PARAM_CHANNELS, -1);
- + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- + rate_hw_constraint_channels, NULL,
- + SNDRV_PCM_HW_PARAM_RATE, -1);
- + }
- +
- chip->alsa_stream[idx] = alsa_stream;
-
- chip->opened |= (1 << idx);
|