diff options
author | Peter Ujfalusi <peter.ujfalusi@nokia.com> | 2009-04-17 08:55:08 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-04-17 11:02:23 -0400 |
commit | 6b87a91f5417226c7fe62100b0e7217e7096b789 (patch) | |
tree | 4982bad86c6346c014028806a0bdc3989fde688d | |
parent | 8d98f2246d7c622198ae0b8ca66f1c82b8a25377 (diff) |
ASoC: TWL4030: Fix for the constraint handling
The original implementation of the constraints were good against sane
applications.
If the opening sequence is:
stream1_open, stream1_hw_params, stream2_open, stream2_hw_params -> the
constraints are set correctly for stream2.
But if the sequence is:
stream1_open, stream2_open, stream2_hw_params, stream1_hw_params -> than stream2
would receive constraint rate = 0, sample_bits = 0, since the stream1 has not
yet called hw_params...
The command to trigger this event:
gst-launch-0.10 alsasrc device=hw:0 ! alsasink device=hw:0 sync=false
This patch does some 'black magic' in order to always set the correct
constraints and sets it only when it is needed for the other stream.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r-- | sound/soc/codecs/twl4030.c | 85 |
1 files changed, 66 insertions, 19 deletions
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 921b205de28a..a1b76d7fd130 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
@@ -125,6 +125,11 @@ struct twl4030_priv { | |||
125 | 125 | ||
126 | struct snd_pcm_substream *master_substream; | 126 | struct snd_pcm_substream *master_substream; |
127 | struct snd_pcm_substream *slave_substream; | 127 | struct snd_pcm_substream *slave_substream; |
128 | |||
129 | unsigned int configured; | ||
130 | unsigned int rate; | ||
131 | unsigned int sample_bits; | ||
132 | unsigned int channels; | ||
128 | }; | 133 | }; |
129 | 134 | ||
130 | /* | 135 | /* |
@@ -1220,6 +1225,36 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec, | |||
1220 | return 0; | 1225 | return 0; |
1221 | } | 1226 | } |
1222 | 1227 | ||
1228 | static void twl4030_constraints(struct twl4030_priv *twl4030, | ||
1229 | struct snd_pcm_substream *mst_substream) | ||
1230 | { | ||
1231 | struct snd_pcm_substream *slv_substream; | ||
1232 | |||
1233 | /* Pick the stream, which need to be constrained */ | ||
1234 | if (mst_substream == twl4030->master_substream) | ||
1235 | slv_substream = twl4030->slave_substream; | ||
1236 | else if (mst_substream == twl4030->slave_substream) | ||
1237 | slv_substream = twl4030->master_substream; | ||
1238 | else /* This should not happen.. */ | ||
1239 | return; | ||
1240 | |||
1241 | /* Set the constraints according to the already configured stream */ | ||
1242 | snd_pcm_hw_constraint_minmax(slv_substream->runtime, | ||
1243 | SNDRV_PCM_HW_PARAM_RATE, | ||
1244 | twl4030->rate, | ||
1245 | twl4030->rate); | ||
1246 | |||
1247 | snd_pcm_hw_constraint_minmax(slv_substream->runtime, | ||
1248 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, | ||
1249 | twl4030->sample_bits, | ||
1250 | twl4030->sample_bits); | ||
1251 | |||
1252 | snd_pcm_hw_constraint_minmax(slv_substream->runtime, | ||
1253 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1254 | twl4030->channels, | ||
1255 | twl4030->channels); | ||
1256 | } | ||
1257 | |||
1223 | static int twl4030_startup(struct snd_pcm_substream *substream, | 1258 | static int twl4030_startup(struct snd_pcm_substream *substream, |
1224 | struct snd_soc_dai *dai) | 1259 | struct snd_soc_dai *dai) |
1225 | { | 1260 | { |
@@ -1228,26 +1263,16 @@ static int twl4030_startup(struct snd_pcm_substream *substream, | |||
1228 | struct snd_soc_codec *codec = socdev->card->codec; | 1263 | struct snd_soc_codec *codec = socdev->card->codec; |
1229 | struct twl4030_priv *twl4030 = codec->private_data; | 1264 | struct twl4030_priv *twl4030 = codec->private_data; |
1230 | 1265 | ||
1231 | /* If we already have a playback or capture going then constrain | ||
1232 | * this substream to match it. | ||
1233 | */ | ||
1234 | if (twl4030->master_substream) { | 1266 | if (twl4030->master_substream) { |
1235 | struct snd_pcm_runtime *master_runtime; | ||
1236 | master_runtime = twl4030->master_substream->runtime; | ||
1237 | |||
1238 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
1239 | SNDRV_PCM_HW_PARAM_RATE, | ||
1240 | master_runtime->rate, | ||
1241 | master_runtime->rate); | ||
1242 | |||
1243 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
1244 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, | ||
1245 | master_runtime->sample_bits, | ||
1246 | master_runtime->sample_bits); | ||
1247 | |||
1248 | twl4030->slave_substream = substream; | 1267 | twl4030->slave_substream = substream; |
1249 | } else | 1268 | /* The DAI has one configuration for playback and capture, so |
1269 | * if the DAI has been already configured then constrain this | ||
1270 | * substream to match it. */ | ||
1271 | if (twl4030->configured) | ||
1272 | twl4030_constraints(twl4030, twl4030->master_substream); | ||
1273 | } else { | ||
1250 | twl4030->master_substream = substream; | 1274 | twl4030->master_substream = substream; |
1275 | } | ||
1251 | 1276 | ||
1252 | return 0; | 1277 | return 0; |
1253 | } | 1278 | } |
@@ -1264,6 +1289,13 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream, | |||
1264 | twl4030->master_substream = twl4030->slave_substream; | 1289 | twl4030->master_substream = twl4030->slave_substream; |
1265 | 1290 | ||
1266 | twl4030->slave_substream = NULL; | 1291 | twl4030->slave_substream = NULL; |
1292 | |||
1293 | /* If all streams are closed, or the remaining stream has not yet | ||
1294 | * been configured than set the DAI as not configured. */ | ||
1295 | if (!twl4030->master_substream) | ||
1296 | twl4030->configured = 0; | ||
1297 | else if (!twl4030->master_substream->runtime->channels) | ||
1298 | twl4030->configured = 0; | ||
1267 | } | 1299 | } |
1268 | 1300 | ||
1269 | static int twl4030_hw_params(struct snd_pcm_substream *substream, | 1301 | static int twl4030_hw_params(struct snd_pcm_substream *substream, |
@@ -1276,8 +1308,8 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, | |||
1276 | struct twl4030_priv *twl4030 = codec->private_data; | 1308 | struct twl4030_priv *twl4030 = codec->private_data; |
1277 | u8 mode, old_mode, format, old_format; | 1309 | u8 mode, old_mode, format, old_format; |
1278 | 1310 | ||
1279 | if (substream == twl4030->slave_substream) | 1311 | if (twl4030->configured) |
1280 | /* Ignoring hw_params for slave substream */ | 1312 | /* Ignoring hw_params for already configured DAI */ |
1281 | return 0; | 1313 | return 0; |
1282 | 1314 | ||
1283 | /* bit rate */ | 1315 | /* bit rate */ |
@@ -1357,6 +1389,21 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, | |||
1357 | /* set CODECPDZ afterwards */ | 1389 | /* set CODECPDZ afterwards */ |
1358 | twl4030_codec_enable(codec, 1); | 1390 | twl4030_codec_enable(codec, 1); |
1359 | } | 1391 | } |
1392 | |||
1393 | /* Store the important parameters for the DAI configuration and set | ||
1394 | * the DAI as configured */ | ||
1395 | twl4030->configured = 1; | ||
1396 | twl4030->rate = params_rate(params); | ||
1397 | twl4030->sample_bits = hw_param_interval(params, | ||
1398 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min; | ||
1399 | twl4030->channels = params_channels(params); | ||
1400 | |||
1401 | /* If both playback and capture streams are open, and one of them | ||
1402 | * is setting the hw parameters right now (since we are here), set | ||
1403 | * constraints to the other stream to match the current one. */ | ||
1404 | if (twl4030->slave_substream) | ||
1405 | twl4030_constraints(twl4030, substream); | ||
1406 | |||
1360 | return 0; | 1407 | return 0; |
1361 | } | 1408 | } |
1362 | 1409 | ||