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 | } |
