diff options
author | Peter Rosin | 2015-01-28 15:16:06 +0100 |
---|---|---|
committer | Mark Brown | 2015-01-28 19:27:15 +0000 |
commit | f66f898e953d56779367a6cbc39cbb4808b208c0 (patch) | |
tree | d0a7c9d3d6f9349080d5beca852723cd1574a1f6 /sound/core | |
parent | ba5295e55dd941425b10924f4f5c7af6eac4a1cb (diff) |
ALSA: pcm: Add snd_interval_ranges() and snd_pcm_hw_constraint_ranges()
Add helper functions to allow drivers to specify several disjoint
ranges for a variable. In particular, there is a codec (PCM512x) that
has a hole in its supported range of rates, due to PLL and divider
restrictions.
This is like snd_pcm_hw_constraint_list(), but for ranges instead of
points.
Signed-off-by: Peter Rosin <peda@axentia.se>
Reviewed-by: Lars-Peter Clausen <lars@metafoo.de>
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/core')
-rw-r--r-- | sound/core/pcm_lib.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index ec9e7866177f..446c00bd908b 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) { |