diff options
author | Takashi Iwai <tiwai@suse.de> | 2015-04-21 14:55:21 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2015-04-21 14:55:21 +0200 |
commit | 2953b9ed72b3e14fbec70ff65af225ea580af3ca (patch) | |
tree | a8024b980b202eb29c79013f79e3f1222e1123ee | |
parent | 4cfbd65e9f24766d2ed034fb970a46abf340a714 (diff) | |
download | salsa-lib-2953b9ed72b3e14fbec70ff65af225ea580af3ca.tar.gz |
tlv: improve raw value range handling
This makes snd_tlv_convert_from_dB() more robust wrt DB_SCALE type
by consistently parsing the ranges.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | src/control.c | 39 |
1 files changed, 17 insertions, 22 deletions
diff --git a/src/control.c b/src/control.c index a677b59..4a7666f 100644 --- a/src/control.c +++ b/src/control.c @@ -630,40 +630,35 @@ static int tlv_from_dB_range(unsigned int *tlv, long rangemin, long rangemax, long db_gain, long *value, int xdir) { unsigned int pos, len; - long dbmin, dbmax, prev_rangemax; + long dbmin, dbmax, prev_submax; len = int_index(tlv[1]); - if (len > MAX_TLV_RANGE_SIZE) - return -EINVAL; - if (snd_tlv_get_dB_range(tlv, rangemin, rangemax, &dbmin, &dbmax)) + if (len < 6 || len > MAX_TLV_RANGE_SIZE) return -EINVAL; - if (db_gain <= dbmin) { - *value = rangemin; - return 0; - } else if (db_gain >= dbmax) { - *value = rangemax; - return 0; - } pos = 2; - prev_rangemax = 0; + prev_submax = 0; while (pos + 4 <= len) { - rangemin = (int)tlv[pos++]; - rangemax = (int)tlv[pos++]; - if (!snd_tlv_get_dB_range(tlv + pos, rangemin, rangemax, + long submin = (int)tlv[pos++]; + long submax = (int)tlv[pos++]; + if (rangemax < submax) + submax = rangemax; + if (!snd_tlv_get_dB_range(tlv + pos + 2, submin, submax, &dbmin, &dbmax) && db_gain >= dbmin && db_gain <= dbmax) - return snd_tlv_convert_from_dB(tlv + pos, - rangemin, rangemax, + return snd_tlv_convert_from_dB(tlv + pos + 2, + submin, submax, db_gain, value, xdir); else if (db_gain < dbmin) { - *value = xdir ? rangemin : prev_rangemax; + *value = xdir > 0 || pos == 2 ? submin : prev_submax; return 0; } - prev_rangemax = rangemax; - pos++; - pos += int_index(tlv[pos]) + 1; + prev_submax = submax; + if (rangemax == submax) + break; + pos += int_index(tlv[pos + 3]) + 4; } - return -EINVAL; + *value = prev_submax; + return 0; } static void _tlv_from_dB_minmax(long rangemin, long rangemax, |