diff options
author | Takashi Iwai <tiwai@suse.de> | 2009-01-15 11:05:24 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-01-15 11:58:18 -0500 |
commit | 641b4879444c0edb276fedca5c2fcbd2e5c70044 (patch) | |
tree | bb06447cf1023e199f44780041d0c7b978aeb4a6 | |
parent | 37a76bd4f1b716949fc38a6842e89f0ccb8384d0 (diff) |
ALSA: usb-audio - Cache mixer values
Cache mixer values in usb-audio driver to reduce too excessive
accesses to the hardware.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-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 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 | |||
113 | struct usb_mixer_elem_info { | 115 | struct 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 */ |
379 | static inline int get_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, int *value) | 381 | static 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 | ||
387 | static 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 | ||
415 | static inline int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, int value) | 441 | static 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 | } |