ALSA: pcm: calculate non-mask/non-interval parameters always when possible

A structure for parameters of PCM runtime has parameters which are
not classified as mask/interval type. They are decided only when
corresponding normal parameters have unique values.
 * struct snd_pcm_hw_params.msbits
 * struct snd_pcm_hw_params.rate_num
 * struct snd_pcm_hw_params.rate_den
 * struct snd_pcm_hw_params.fifo_size

Current implementation of hw_params ioctl sometimes doesn't decide these
parameters even if corresponding parameters are fixed, because these
parameters are evaluated before a call of snd_pcm_hw_params_choose().

This commit adds a helper function to process the parameters and call it
in proper positions.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Sakamoto 2017-06-09 09:34:39 +09:00 committed by Takashi Iwai
parent e02de47e3c
commit f9a076bff0
1 changed files with 44 additions and 26 deletions

View File

@ -440,12 +440,45 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
return 0; return 0;
} }
static int fixup_unreferenced_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
const struct snd_interval *i;
const struct snd_mask *m;
int err;
if (!params->msbits) {
i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
if (snd_interval_single(i))
params->msbits = snd_interval_value(i);
}
if (!params->rate_den) {
i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
if (snd_interval_single(i)) {
params->rate_num = snd_interval_value(i);
params->rate_den = 1;
}
}
if (!params->fifo_size) {
m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
if (snd_mask_single(m) && snd_interval_single(i)) {
err = substream->ops->ioctl(substream,
SNDRV_PCM_IOCTL1_FIFO_SIZE, params);
if (err < 0)
return err;
}
}
return 0;
}
int snd_pcm_hw_refine(struct snd_pcm_substream *substream, int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
struct snd_pcm_hardware *hw; struct snd_pcm_hardware *hw;
const struct snd_interval *i;
const struct snd_mask *m;
int err; int err;
params->info = 0; params->info = 0;
@ -469,20 +502,6 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
if (err < 0) if (err < 0)
return err; return err;
if (!params->msbits) {
i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
if (snd_interval_single(i))
params->msbits = snd_interval_value(i);
}
if (!params->rate_den) {
i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
if (snd_interval_single(i)) {
params->rate_num = snd_interval_value(i);
params->rate_den = 1;
}
}
hw = &substream->runtime->hw; hw = &substream->runtime->hw;
if (!params->info) { if (!params->info) {
params->info = hw->info & ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES | params->info = hw->info & ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES |
@ -491,16 +510,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
params->info &= ~(SNDRV_PCM_INFO_MMAP | params->info &= ~(SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID); SNDRV_PCM_INFO_MMAP_VALID);
} }
if (!params->fifo_size) {
m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
if (snd_mask_single(m) && snd_interval_single(i)) {
err = substream->ops->ioctl(substream,
SNDRV_PCM_IOCTL1_FIFO_SIZE, params);
if (err < 0)
return err;
}
}
params->rmask = 0; params->rmask = 0;
return 0; return 0;
} }
@ -517,6 +527,8 @@ static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
return PTR_ERR(params); return PTR_ERR(params);
err = snd_pcm_hw_refine(substream, params); err = snd_pcm_hw_refine(substream, params);
if (err >= 0)
err = fixup_unreferenced_params(substream, params);
if (copy_to_user(_params, params, sizeof(*params))) { if (copy_to_user(_params, params, sizeof(*params))) {
if (!err) if (!err)
err = -EFAULT; err = -EFAULT;
@ -596,6 +608,10 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
if (err < 0) if (err < 0)
goto _error; goto _error;
err = fixup_unreferenced_params(substream, params);
if (err < 0)
goto _error;
if (substream->ops->hw_params != NULL) { if (substream->ops->hw_params != NULL) {
err = substream->ops->hw_params(substream, params); err = substream->ops->hw_params(substream, params);
if (err < 0) if (err < 0)
@ -3621,6 +3637,8 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
} }
snd_pcm_hw_convert_from_old_params(params, oparams); snd_pcm_hw_convert_from_old_params(params, oparams);
err = snd_pcm_hw_refine(substream, params); err = snd_pcm_hw_refine(substream, params);
if (err >= 0)
err = fixup_unreferenced_params(substream, params);
snd_pcm_hw_convert_to_old_params(oparams, params); snd_pcm_hw_convert_to_old_params(oparams, params);
if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { if (copy_to_user(_oparams, oparams, sizeof(*oparams))) {
if (!err) if (!err)