aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/usb/usbmixer.c37
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}