diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 80275aa0bcca..422ee4629698 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -267,6 +267,8 @@ static int constrain_mask_params(struct snd_pcm_substream *substream, m = hw_param_mask(params, k); if (snd_mask_empty(m)) return -EINVAL; + + /* This parameter is not requested to change by a caller. */ if (!(params->rmask & (1 << k))) continue; @@ -277,6 +279,7 @@ static int constrain_mask_params(struct snd_pcm_substream *substream, trace_hw_mask_param(substream, k, 0, &old_mask, m); + /* Set corresponding flag so that the caller gets it. */ if (changed) params->cmask |= 1 << k; if (changed < 0) @@ -300,6 +303,8 @@ static int constrain_interval_params(struct snd_pcm_substream *substream, i = hw_param_interval(params, k); if (snd_interval_empty(i)) return -EINVAL; + + /* This parameter is not requested to change by a caller. */ if (!(params->rmask & (1 << k))) continue; @@ -310,6 +315,7 @@ static int constrain_interval_params(struct snd_pcm_substream *substream, trace_hw_interval_param(substream, k, 0, &old_interval, i); + /* Set corresponding flag so that the caller gets it. */ if (changed) params->cmask |= 1 << k; if (changed < 0) @@ -327,7 +333,7 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream, unsigned int k; unsigned int rstamps[constrs->rules_num]; unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; - unsigned int stamp = 2; + unsigned int stamp; struct snd_pcm_hw_rule *r; unsigned int d; struct snd_mask old_mask; @@ -335,16 +341,54 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream, bool again; int changed; + /* + * Each application of rule has own sequence number. + * + * Each member of 'rstamps' array represents the sequence number of + * recent application of corresponding rule. + */ for (k = 0; k < constrs->rules_num; k++) rstamps[k] = 0; + + /* + * Each member of 'vstamps' array represents the sequence number of + * recent application of rule in which corresponding parameters were + * changed. + * + * In initial state, elements corresponding to parameters requested by + * a caller is 1. For unrequested parameters, corresponding members + * have 0 so that the parameters are never changed anymore. + */ for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0; + + /* Due to the above design, actual sequence number starts at 2. */ + stamp = 2; retry: + /* Apply all rules in order. */ again = false; for (k = 0; k < constrs->rules_num; k++) { r = &constrs->rules[k]; + + /* + * Check condition bits of this rule. When the rule has + * some condition bits, parameter without the bits is + * never processed. SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP + * is an example of the condition bits. + */ if (r->cond && !(r->cond & params->flags)) continue; + + /* + * The 'deps' array includes maximum three dependencies + * to SNDRV_PCM_HW_PARAM_XXXs for this rule. The fourth + * member of this array is a sentinel and should be + * negative value. + * + * This rule should be processed in this time when dependent + * parameters were changed at former applications of the other + * rules. + */ for (d = 0; r->deps[d] >= 0; d++) { if (vstamps[r->deps[d]] > rstamps[k]) break; @@ -373,6 +417,12 @@ retry: } rstamps[k] = stamp; + + /* + * When the parameters is changed, notify it to the caller + * by corresponding returned bit, then preparing for next + * iteration. + */ if (changed && r->var >= 0) { params->cmask |= (1 << r->var); vstamps[r->var] = stamp; @@ -383,6 +433,7 @@ retry: stamp++; } + /* Iterate to evaluate all rules till no parameters are changed. */ if (again) goto retry;