diff options
Diffstat (limited to 'sound/core/pcm_lib.c')
| -rw-r--r-- | sound/core/pcm_lib.c | 100 | 
1 files changed, 98 insertions, 2 deletions
| diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index ec9e7866177f..ffd656012ab8 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1015,6 +1015,60 @@ int snd_interval_list(struct snd_interval *i, unsigned int count,  EXPORT_SYMBOL(snd_interval_list); +/** + * snd_interval_ranges - refine the interval value from the list of ranges + * @i: the interval value to refine + * @count: the number of elements in the list of ranges + * @ranges: the ranges list + * @mask: the bit-mask to evaluate + * + * Refines the interval value from the list of ranges. + * When mask is non-zero, only the elements corresponding to bit 1 are + * evaluated. + * + * Return: Positive if the value is changed, zero if it's not changed, or a + * negative error code. + */ +int snd_interval_ranges(struct snd_interval *i, unsigned int count, +			const struct snd_interval *ranges, unsigned int mask) +{ +	unsigned int k; +	struct snd_interval range_union; +	struct snd_interval range; + +	if (!count) { +		snd_interval_none(i); +		return -EINVAL; +	} +	snd_interval_any(&range_union); +	range_union.min = UINT_MAX; +	range_union.max = 0; +	for (k = 0; k < count; k++) { +		if (mask && !(mask & (1 << k))) +			continue; +		snd_interval_copy(&range, &ranges[k]); +		if (snd_interval_refine(&range, i) < 0) +			continue; +		if (snd_interval_empty(&range)) +			continue; + +		if (range.min < range_union.min) { +			range_union.min = range.min; +			range_union.openmin = 1; +		} +		if (range.min == range_union.min && !range.openmin) +			range_union.openmin = 0; +		if (range.max > range_union.max) { +			range_union.max = range.max; +			range_union.openmax = 1; +		} +		if (range.max == range_union.max && !range.openmax) +			range_union.openmax = 0; +	} +	return snd_interval_refine(i, &range_union); +} +EXPORT_SYMBOL(snd_interval_ranges); +  static int snd_interval_step(struct snd_interval *i, unsigned int step)  {  	unsigned int n; @@ -1221,6 +1275,37 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,  EXPORT_SYMBOL(snd_pcm_hw_constraint_list); +static int snd_pcm_hw_rule_ranges(struct snd_pcm_hw_params *params, +				  struct snd_pcm_hw_rule *rule) +{ +	struct snd_pcm_hw_constraint_ranges *r = rule->private; +	return snd_interval_ranges(hw_param_interval(params, rule->var), +				   r->count, r->ranges, r->mask); +} + + +/** + * snd_pcm_hw_constraint_ranges - apply list of range constraints to a parameter + * @runtime: PCM runtime instance + * @cond: condition bits + * @var: hw_params variable to apply the list of range constraints + * @r: ranges + * + * Apply the list of range constraints to an interval parameter. + * + * Return: Zero if successful, or a negative error code on failure. + */ +int snd_pcm_hw_constraint_ranges(struct snd_pcm_runtime *runtime, +				 unsigned int cond, +				 snd_pcm_hw_param_t var, +				 const struct snd_pcm_hw_constraint_ranges *r) +{ +	return snd_pcm_hw_rule_add(runtime, cond, var, +				   snd_pcm_hw_rule_ranges, (void *)r, +				   var, -1); +} +EXPORT_SYMBOL(snd_pcm_hw_constraint_ranges); +  static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params,  				   struct snd_pcm_hw_rule *rule)  { @@ -1299,8 +1384,14 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,  	int width = l & 0xffff;  	unsigned int msbits = l >> 16;  	struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); -	if (snd_interval_single(i) && snd_interval_value(i) == width) -		params->msbits = msbits; + +	if (!snd_interval_single(i)) +		return 0; + +	if ((snd_interval_value(i) == width) || +	    (width == 0 && snd_interval_value(i) > msbits)) +		params->msbits = min_not_zero(params->msbits, msbits); +  	return 0;  } @@ -1311,6 +1402,11 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,   * @width: sample bits width   * @msbits: msbits width   * + * This constraint will set the number of most significant bits (msbits) if a + * sample format with the specified width has been select. If width is set to 0 + * the msbits will be set for any sample format with a width larger than the + * specified msbits. + *   * Return: Zero if successful, or a negative error code on failure.   */  int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime,  |