diff options
-rw-r--r-- | sound/usb/usbmixer.c | 37 |
1 files changed, 34 insertions, 3 deletions
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 8d08b34a1cb5..ce86283ee0fa 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c | |||
@@ -306,8 +306,8 @@ static int get_relative_value(struct usb_mixer_elem_info *cval, int val) | |||
306 | cval->res = 1; | 306 | cval->res = 1; |
307 | if (val < cval->min) | 307 | if (val < cval->min) |
308 | return 0; | 308 | return 0; |
309 | else if (val > cval->max) | 309 | else if (val >= cval->max) |
310 | return (cval->max - cval->min) / cval->res; | 310 | return (cval->max - cval->min + cval->res - 1) / cval->res; |
311 | else | 311 | else |
312 | return (val - cval->min) / cval->res; | 312 | return (val - cval->min) / cval->res; |
313 | } | 313 | } |
@@ -670,6 +670,36 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) | |||
670 | } | 670 | } |
671 | if (cval->res == 0) | 671 | if (cval->res == 0) |
672 | cval->res = 1; | 672 | cval->res = 1; |
673 | |||
674 | /* Additional checks for the proper resolution | ||
675 | * | ||
676 | * Some devices report smaller resolutions than actually | ||
677 | * reacting. They don't return errors but simply clip | ||
678 | * to the lower aligned value. | ||
679 | */ | ||
680 | if (cval->min + cval->res < cval->max) { | ||
681 | int last_valid_res = cval->res; | ||
682 | int saved, test, check; | ||
683 | get_cur_mix_value(cval, minchn, &saved); | ||
684 | for (;;) { | ||
685 | test = saved; | ||
686 | if (test < cval->max) | ||
687 | test += cval->res; | ||
688 | else | ||
689 | test -= cval->res; | ||
690 | if (test < cval->min || test > cval->max || | ||
691 | set_cur_mix_value(cval, minchn, test) || | ||
692 | get_cur_mix_value(cval, minchn, &check)) { | ||
693 | cval->res = last_valid_res; | ||
694 | break; | ||
695 | } | ||
696 | if (test == check) | ||
697 | break; | ||
698 | cval->res *= 2; | ||
699 | } | ||
700 | set_cur_mix_value(cval, minchn, saved); | ||
701 | } | ||
702 | |||
673 | cval->initialized = 1; | 703 | cval->initialized = 1; |
674 | } | 704 | } |
675 | return 0; | 705 | return 0; |
@@ -695,7 +725,8 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
695 | if (! cval->initialized) | 725 | if (! cval->initialized) |
696 | get_min_max(cval, 0); | 726 | get_min_max(cval, 0); |
697 | uinfo->value.integer.min = 0; | 727 | uinfo->value.integer.min = 0; |
698 | uinfo->value.integer.max = (cval->max - cval->min) / cval->res; | 728 | uinfo->value.integer.max = |
729 | (cval->max - cval->min + cval->res - 1) / cval->res; | ||
699 | } | 730 | } |
700 | return 0; | 731 | return 0; |
701 | } | 732 | } |