diff options
Diffstat (limited to 'sound/usb/usbmixer.c')
-rw-r--r-- | sound/usb/usbmixer.c | 122 |
1 files changed, 70 insertions, 52 deletions
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index bc8bd00047ad..330f2fbff2d1 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c | |||
@@ -111,6 +111,8 @@ struct mixer_build { | |||
111 | const struct usbmix_selector_map *selector_map; | 111 | const struct usbmix_selector_map *selector_map; |
112 | }; | 112 | }; |
113 | 113 | ||
114 | #define MAX_CHANNELS 10 /* max logical channels */ | ||
115 | |||
114 | struct usb_mixer_elem_info { | 116 | struct usb_mixer_elem_info { |
115 | struct usb_mixer_interface *mixer; | 117 | struct usb_mixer_interface *mixer; |
116 | struct usb_mixer_elem_info *next_id_elem; /* list of controls with same id */ | 118 | struct usb_mixer_elem_info *next_id_elem; /* list of controls with same id */ |
@@ -121,6 +123,8 @@ struct usb_mixer_elem_info { | |||
121 | int channels; | 123 | int channels; |
122 | int val_type; | 124 | int val_type; |
123 | int min, max, res; | 125 | int min, max, res; |
126 | int cached; | ||
127 | int cache_val[MAX_CHANNELS]; | ||
124 | u8 initialized; | 128 | u8 initialized; |
125 | }; | 129 | }; |
126 | 130 | ||
@@ -182,8 +186,6 @@ enum { | |||
182 | USB_PROC_DCR_RELEASE = 6, | 186 | USB_PROC_DCR_RELEASE = 6, |
183 | }; | 187 | }; |
184 | 188 | ||
185 | #define MAX_CHANNELS 10 /* max logical channels */ | ||
186 | |||
187 | 189 | ||
188 | /* | 190 | /* |
189 | * manual mapping of mixer names | 191 | * manual mapping of mixer names |
@@ -377,11 +379,35 @@ static int get_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int * | |||
377 | } | 379 | } |
378 | 380 | ||
379 | /* channel = 0: master, 1 = first channel */ | 381 | /* channel = 0: master, 1 = first channel */ |
380 | static inline int get_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, int *value) | 382 | static inline int get_cur_mix_raw(struct usb_mixer_elem_info *cval, |
383 | int channel, int *value) | ||
381 | { | 384 | { |
382 | return get_ctl_value(cval, GET_CUR, (cval->control << 8) | channel, value); | 385 | return get_ctl_value(cval, GET_CUR, (cval->control << 8) | channel, value); |
383 | } | 386 | } |
384 | 387 | ||
388 | static int get_cur_mix_value(struct usb_mixer_elem_info *cval, | ||
389 | int channel, int index, int *value) | ||
390 | { | ||
391 | int err; | ||
392 | |||
393 | if (cval->cached & (1 << channel)) { | ||
394 | *value = cval->cache_val[index]; | ||
395 | return 0; | ||
396 | } | ||
397 | err = get_cur_mix_raw(cval, channel, value); | ||
398 | if (err < 0) { | ||
399 | if (!cval->mixer->ignore_ctl_error) | ||
400 | snd_printd(KERN_ERR "cannot get current value for " | ||
401 | "control %d ch %d: err = %d\n", | ||
402 | cval->control, channel, err); | ||
403 | return err; | ||
404 | } | ||
405 | cval->cached |= 1 << channel; | ||
406 | cval->cache_val[index] = *value; | ||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | |||
385 | /* | 411 | /* |
386 | * set a mixer value | 412 | * set a mixer value |
387 | */ | 413 | */ |
@@ -413,9 +439,17 @@ static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int v | |||
413 | return set_ctl_value(cval, SET_CUR, validx, value); | 439 | return set_ctl_value(cval, SET_CUR, validx, value); |
414 | } | 440 | } |
415 | 441 | ||
416 | static inline int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, int value) | 442 | static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, |
443 | int index, int value) | ||
417 | { | 444 | { |
418 | return set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, value); | 445 | int err; |
446 | err = set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, | ||
447 | value); | ||
448 | if (err < 0) | ||
449 | return err; | ||
450 | cval->cached |= 1 << channel; | ||
451 | cval->cache_val[index] = value; | ||
452 | return 0; | ||
419 | } | 453 | } |
420 | 454 | ||
421 | /* | 455 | /* |
@@ -719,7 +753,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) | |||
719 | if (cval->min + cval->res < cval->max) { | 753 | if (cval->min + cval->res < cval->max) { |
720 | int last_valid_res = cval->res; | 754 | int last_valid_res = cval->res; |
721 | int saved, test, check; | 755 | int saved, test, check; |
722 | get_cur_mix_value(cval, minchn, &saved); | 756 | get_cur_mix_raw(cval, minchn, &saved); |
723 | for (;;) { | 757 | for (;;) { |
724 | test = saved; | 758 | test = saved; |
725 | if (test < cval->max) | 759 | if (test < cval->max) |
@@ -727,8 +761,8 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) | |||
727 | else | 761 | else |
728 | test -= cval->res; | 762 | test -= cval->res; |
729 | if (test < cval->min || test > cval->max || | 763 | if (test < cval->min || test > cval->max || |
730 | set_cur_mix_value(cval, minchn, test) || | 764 | set_cur_mix_value(cval, minchn, 0, test) || |
731 | get_cur_mix_value(cval, minchn, &check)) { | 765 | get_cur_mix_raw(cval, minchn, &check)) { |
732 | cval->res = last_valid_res; | 766 | cval->res = last_valid_res; |
733 | break; | 767 | break; |
734 | } | 768 | } |
@@ -736,7 +770,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) | |||
736 | break; | 770 | break; |
737 | cval->res *= 2; | 771 | cval->res *= 2; |
738 | } | 772 | } |
739 | set_cur_mix_value(cval, minchn, saved); | 773 | set_cur_mix_value(cval, minchn, 0, saved); |
740 | } | 774 | } |
741 | 775 | ||
742 | cval->initialized = 1; | 776 | cval->initialized = 1; |
@@ -776,35 +810,25 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
776 | struct usb_mixer_elem_info *cval = kcontrol->private_data; | 810 | struct usb_mixer_elem_info *cval = kcontrol->private_data; |
777 | int c, cnt, val, err; | 811 | int c, cnt, val, err; |
778 | 812 | ||
813 | ucontrol->value.integer.value[0] = cval->min; | ||
779 | if (cval->cmask) { | 814 | if (cval->cmask) { |
780 | cnt = 0; | 815 | cnt = 0; |
781 | for (c = 0; c < MAX_CHANNELS; c++) { | 816 | for (c = 0; c < MAX_CHANNELS; c++) { |
782 | if (cval->cmask & (1 << c)) { | 817 | if (!(cval->cmask & (1 << c))) |
783 | err = get_cur_mix_value(cval, c + 1, &val); | 818 | continue; |
784 | if (err < 0) { | 819 | err = get_cur_mix_value(cval, c + 1, cnt, &val); |
785 | if (cval->mixer->ignore_ctl_error) { | 820 | if (err < 0) |
786 | ucontrol->value.integer.value[0] = cval->min; | 821 | return cval->mixer->ignore_ctl_error ? 0 : err; |
787 | return 0; | 822 | val = get_relative_value(cval, val); |
788 | } | 823 | ucontrol->value.integer.value[cnt] = val; |
789 | snd_printd(KERN_ERR "cannot get current value for control %d ch %d: err = %d\n", cval->control, c + 1, err); | 824 | cnt++; |
790 | return err; | ||
791 | } | ||
792 | val = get_relative_value(cval, val); | ||
793 | ucontrol->value.integer.value[cnt] = val; | ||
794 | cnt++; | ||
795 | } | ||
796 | } | 825 | } |
826 | return 0; | ||
797 | } else { | 827 | } else { |
798 | /* master channel */ | 828 | /* master channel */ |
799 | err = get_cur_mix_value(cval, 0, &val); | 829 | err = get_cur_mix_value(cval, 0, 0, &val); |
800 | if (err < 0) { | 830 | if (err < 0) |
801 | if (cval->mixer->ignore_ctl_error) { | 831 | return cval->mixer->ignore_ctl_error ? 0 : err; |
802 | ucontrol->value.integer.value[0] = cval->min; | ||
803 | return 0; | ||
804 | } | ||
805 | snd_printd(KERN_ERR "cannot get current value for control %d master ch: err = %d\n", cval->control, err); | ||
806 | return err; | ||
807 | } | ||
808 | val = get_relative_value(cval, val); | 832 | val = get_relative_value(cval, val); |
809 | ucontrol->value.integer.value[0] = val; | 833 | ucontrol->value.integer.value[0] = val; |
810 | } | 834 | } |
@@ -821,34 +845,28 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
821 | if (cval->cmask) { | 845 | if (cval->cmask) { |
822 | cnt = 0; | 846 | cnt = 0; |
823 | for (c = 0; c < MAX_CHANNELS; c++) { | 847 | for (c = 0; c < MAX_CHANNELS; c++) { |
824 | if (cval->cmask & (1 << c)) { | 848 | if (!(cval->cmask & (1 << c))) |
825 | err = get_cur_mix_value(cval, c + 1, &oval); | 849 | continue; |
826 | if (err < 0) { | 850 | err = get_cur_mix_value(cval, c + 1, cnt, &oval); |
827 | if (cval->mixer->ignore_ctl_error) | 851 | if (err < 0) |
828 | return 0; | 852 | return cval->mixer->ignore_ctl_error ? 0 : err; |
829 | return err; | 853 | val = ucontrol->value.integer.value[cnt]; |
830 | } | 854 | val = get_abs_value(cval, val); |
831 | val = ucontrol->value.integer.value[cnt]; | 855 | if (oval != val) { |
832 | val = get_abs_value(cval, val); | 856 | set_cur_mix_value(cval, c + 1, cnt, val); |
833 | if (oval != val) { | 857 | changed = 1; |
834 | set_cur_mix_value(cval, c + 1, val); | ||
835 | changed = 1; | ||
836 | } | ||
837 | get_cur_mix_value(cval, c + 1, &val); | ||
838 | cnt++; | ||
839 | } | 858 | } |
859 | cnt++; | ||
840 | } | 860 | } |
841 | } else { | 861 | } else { |
842 | /* master channel */ | 862 | /* master channel */ |
843 | err = get_cur_mix_value(cval, 0, &oval); | 863 | err = get_cur_mix_value(cval, 0, 0, &oval); |
844 | if (err < 0 && cval->mixer->ignore_ctl_error) | ||
845 | return 0; | ||
846 | if (err < 0) | 864 | if (err < 0) |
847 | return err; | 865 | return cval->mixer->ignore_ctl_error ? 0 : err; |
848 | val = ucontrol->value.integer.value[0]; | 866 | val = ucontrol->value.integer.value[0]; |
849 | val = get_abs_value(cval, val); | 867 | val = get_abs_value(cval, val); |
850 | if (val != oval) { | 868 | if (val != oval) { |
851 | set_cur_mix_value(cval, 0, val); | 869 | set_cur_mix_value(cval, 0, 0, val); |
852 | changed = 1; | 870 | changed = 1; |
853 | } | 871 | } |
854 | } | 872 | } |