aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb/usbmixer.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2006-03-28 10:58:28 -0500
committerJaroslav Kysela <perex@suse.cz>2006-03-31 10:59:00 -0500
commit14790f1c73cfa4d4a22ac10b4501b4831380683c (patch)
tree7c5ac876676e480df59475fd99da746467bfa404 /sound/usb/usbmixer.c
parent0b2dcd5d6a9a3e27fdd67053e526388f9f2ea33b (diff)
[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>
Diffstat (limited to 'sound/usb/usbmixer.c')
-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}