[ALSA] Test volume resolution of usb audio at initialization

Test the volume of usb audio whether actually it works and adjusts
the resolution value according to it.

Some USB audio devices report a lower resolution than it reacts.
The only possible check is to write and read a volume value.

Signed-off-by: Takashi Iwai <tiwai@suse.de>

authored by

Takashi Iwai and committed by
Jaroslav Kysela
14790f1c 0b2dcd5d

+34 -3
+34 -3
sound/usb/usbmixer.c
··· 306 cval->res = 1; 307 if (val < cval->min) 308 return 0; 309 - else if (val > cval->max) 310 - return (cval->max - cval->min) / cval->res; 311 else 312 return (val - cval->min) / cval->res; 313 } ··· 670 } 671 if (cval->res == 0) 672 cval->res = 1; 673 cval->initialized = 1; 674 } 675 return 0; ··· 725 if (! cval->initialized) 726 get_min_max(cval, 0); 727 uinfo->value.integer.min = 0; 728 - uinfo->value.integer.max = (cval->max - cval->min) / cval->res; 729 } 730 return 0; 731 }
··· 306 cval->res = 1; 307 if (val < cval->min) 308 return 0; 309 + else if (val >= cval->max) 310 + return (cval->max - cval->min + cval->res - 1) / cval->res; 311 else 312 return (val - cval->min) / cval->res; 313 } ··· 670 } 671 if (cval->res == 0) 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 + 703 cval->initialized = 1; 704 } 705 return 0; ··· 695 if (! cval->initialized) 696 get_min_max(cval, 0); 697 uinfo->value.integer.min = 0; 698 + uinfo->value.integer.max = 699 + (cval->max - cval->min + cval->res - 1) / cval->res; 700 } 701 return 0; 702 }