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