diff options
author | Takashi Iwai <tiwai@suse.de> | 2014-11-18 11:37:40 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-11-21 05:58:19 -0500 |
commit | 0b4e9cfcef055a1be9bee5a47262e9cbcf17e8cd (patch) | |
tree | 91e3017a4524115071cb9af66eb4635d56564185 /sound/usb | |
parent | da6d276957ea56b9514aa5c8d885edf22f0b3e65 (diff) |
ALSA: usb-audio: Add resume support for FTU controls
A few FTU mixer controls have the own value handling, so they have to
be rewritten to follow the support for resume callbacks. This ended
up in a fair amount of refactoring. Its own struct is now removed,
instead the values are embedded in kctl private_value totally.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/mixer_quirks.c | 194 |
1 files changed, 54 insertions, 140 deletions
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index e11b4f3e1215..fcb7ae5131a9 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c | |||
@@ -892,14 +892,6 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, | |||
892 | 892 | ||
893 | /* M-Audio FastTrack Ultra quirks */ | 893 | /* M-Audio FastTrack Ultra quirks */ |
894 | /* FTU Effect switch (also used by C400/C600) */ | 894 | /* FTU Effect switch (also used by C400/C600) */ |
895 | struct snd_ftu_eff_switch_priv_val { | ||
896 | struct usb_mixer_interface *mixer; | ||
897 | int cached_value; | ||
898 | int is_cached; | ||
899 | int bUnitID; | ||
900 | int validx; | ||
901 | }; | ||
902 | |||
903 | static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol, | 895 | static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol, |
904 | struct snd_ctl_elem_info *uinfo) | 896 | struct snd_ctl_elem_info *uinfo) |
905 | { | 897 | { |
@@ -911,138 +903,77 @@ static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol, | |||
911 | return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); | 903 | return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); |
912 | } | 904 | } |
913 | 905 | ||
914 | static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl, | 906 | static int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer, |
915 | struct snd_ctl_elem_value *ucontrol) | 907 | struct snd_kcontrol *kctl) |
916 | { | 908 | { |
917 | struct snd_usb_audio *chip; | 909 | struct usb_device *dev = mixer->chip->dev; |
918 | struct usb_mixer_interface *mixer; | 910 | unsigned int pval = kctl->private_value; |
919 | struct snd_ftu_eff_switch_priv_val *pval; | ||
920 | int err; | 911 | int err; |
921 | unsigned char value[2]; | 912 | unsigned char value[2]; |
922 | int id, validx; | ||
923 | |||
924 | const int val_len = 2; | ||
925 | 913 | ||
926 | value[0] = 0x00; | 914 | value[0] = 0x00; |
927 | value[1] = 0x00; | 915 | value[1] = 0x00; |
928 | 916 | ||
929 | pval = (struct snd_ftu_eff_switch_priv_val *) | 917 | err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, |
930 | kctl->private_value; | 918 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, |
919 | pval & 0xff00, | ||
920 | snd_usb_ctrl_intf(mixer->chip) | ((pval & 0xff) << 8), | ||
921 | value, 2); | ||
922 | if (err < 0) | ||
923 | return err; | ||
931 | 924 | ||
932 | if (pval->is_cached) { | 925 | kctl->private_value |= value[0] << 24; |
933 | ucontrol->value.enumerated.item[0] = pval->cached_value; | 926 | return 0; |
934 | return 0; | 927 | } |
935 | } | ||
936 | 928 | ||
937 | mixer = (struct usb_mixer_interface *) pval->mixer; | 929 | static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl, |
938 | if (snd_BUG_ON(!mixer)) | 930 | struct snd_ctl_elem_value *ucontrol) |
939 | return -EINVAL; | 931 | { |
932 | ucontrol->value.enumerated.item[0] = kctl->private_value >> 24; | ||
933 | return 0; | ||
934 | } | ||
940 | 935 | ||
941 | chip = (struct snd_usb_audio *) mixer->chip; | 936 | static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list) |
942 | if (snd_BUG_ON(!chip)) | 937 | { |
943 | return -EINVAL; | 938 | struct snd_usb_audio *chip = list->mixer->chip; |
939 | unsigned int pval = list->kctl->private_value; | ||
940 | unsigned char value[2]; | ||
941 | int err; | ||
944 | 942 | ||
945 | id = pval->bUnitID; | 943 | value[0] = pval >> 24; |
946 | validx = pval->validx; | 944 | value[1] = 0; |
947 | 945 | ||
948 | down_read(&mixer->chip->shutdown_rwsem); | 946 | down_read(&chip->shutdown_rwsem); |
949 | if (mixer->chip->shutdown) | 947 | if (chip->shutdown) |
950 | err = -ENODEV; | 948 | err = -ENODEV; |
951 | else | 949 | else |
952 | err = snd_usb_ctl_msg(chip->dev, | 950 | err = snd_usb_ctl_msg(chip->dev, |
953 | usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, | 951 | usb_sndctrlpipe(chip->dev, 0), |
954 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | 952 | UAC_SET_CUR, |
955 | validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), | 953 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, |
956 | value, val_len); | 954 | pval & 0xff00, |
957 | up_read(&mixer->chip->shutdown_rwsem); | 955 | snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8), |
958 | if (err < 0) | 956 | value, 2); |
959 | return err; | 957 | up_read(&chip->shutdown_rwsem); |
960 | 958 | return err; | |
961 | ucontrol->value.enumerated.item[0] = value[0]; | ||
962 | pval->cached_value = value[0]; | ||
963 | pval->is_cached = 1; | ||
964 | |||
965 | return 0; | ||
966 | } | 959 | } |
967 | 960 | ||
968 | static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, | 961 | static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, |
969 | struct snd_ctl_elem_value *ucontrol) | 962 | struct snd_ctl_elem_value *ucontrol) |
970 | { | 963 | { |
971 | struct snd_usb_audio *chip; | 964 | struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl); |
972 | struct snd_ftu_eff_switch_priv_val *pval; | 965 | unsigned int pval = list->kctl->private_value; |
973 | 966 | int cur_val, err, new_val; | |
974 | struct usb_mixer_interface *mixer; | ||
975 | int changed, cur_val, err, new_val; | ||
976 | unsigned char value[2]; | ||
977 | int id, validx; | ||
978 | |||
979 | const int val_len = 2; | ||
980 | |||
981 | changed = 0; | ||
982 | 967 | ||
983 | pval = (struct snd_ftu_eff_switch_priv_val *) | 968 | cur_val = pval >> 24; |
984 | kctl->private_value; | ||
985 | cur_val = pval->cached_value; | ||
986 | new_val = ucontrol->value.enumerated.item[0]; | 969 | new_val = ucontrol->value.enumerated.item[0]; |
970 | if (cur_val == new_val) | ||
971 | return 0; | ||
987 | 972 | ||
988 | mixer = (struct usb_mixer_interface *) pval->mixer; | 973 | kctl->private_value &= ~(0xff << 24); |
989 | if (snd_BUG_ON(!mixer)) | 974 | kctl->private_value |= new_val << 24; |
990 | return -EINVAL; | 975 | err = snd_ftu_eff_switch_update(list); |
991 | 976 | return err < 0 ? err : 1; | |
992 | chip = (struct snd_usb_audio *) mixer->chip; | ||
993 | if (snd_BUG_ON(!chip)) | ||
994 | return -EINVAL; | ||
995 | |||
996 | id = pval->bUnitID; | ||
997 | validx = pval->validx; | ||
998 | |||
999 | if (!pval->is_cached) { | ||
1000 | /* Read current value */ | ||
1001 | down_read(&mixer->chip->shutdown_rwsem); | ||
1002 | if (mixer->chip->shutdown) | ||
1003 | err = -ENODEV; | ||
1004 | else | ||
1005 | err = snd_usb_ctl_msg(chip->dev, | ||
1006 | usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, | ||
1007 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | ||
1008 | validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), | ||
1009 | value, val_len); | ||
1010 | up_read(&mixer->chip->shutdown_rwsem); | ||
1011 | if (err < 0) | ||
1012 | return err; | ||
1013 | |||
1014 | cur_val = value[0]; | ||
1015 | pval->cached_value = cur_val; | ||
1016 | pval->is_cached = 1; | ||
1017 | } | ||
1018 | /* update value if needed */ | ||
1019 | if (cur_val != new_val) { | ||
1020 | value[0] = new_val; | ||
1021 | value[1] = 0; | ||
1022 | down_read(&mixer->chip->shutdown_rwsem); | ||
1023 | if (mixer->chip->shutdown) | ||
1024 | err = -ENODEV; | ||
1025 | else | ||
1026 | err = snd_usb_ctl_msg(chip->dev, | ||
1027 | usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, | ||
1028 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, | ||
1029 | validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), | ||
1030 | value, val_len); | ||
1031 | up_read(&mixer->chip->shutdown_rwsem); | ||
1032 | if (err < 0) | ||
1033 | return err; | ||
1034 | |||
1035 | pval->cached_value = new_val; | ||
1036 | pval->is_cached = 1; | ||
1037 | changed = 1; | ||
1038 | } | ||
1039 | |||
1040 | return changed; | ||
1041 | } | ||
1042 | |||
1043 | static void kctl_private_value_free(struct snd_kcontrol *kctl) | ||
1044 | { | ||
1045 | kfree((void *)kctl->private_value); | ||
1046 | } | 977 | } |
1047 | 978 | ||
1048 | static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer, | 979 | static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer, |
@@ -1057,33 +988,16 @@ static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer, | |||
1057 | .get = snd_ftu_eff_switch_get, | 988 | .get = snd_ftu_eff_switch_get, |
1058 | .put = snd_ftu_eff_switch_put | 989 | .put = snd_ftu_eff_switch_put |
1059 | }; | 990 | }; |
1060 | 991 | struct usb_mixer_elem_list *list; | |
1061 | int err; | 992 | int err; |
1062 | struct snd_kcontrol *kctl; | ||
1063 | struct snd_ftu_eff_switch_priv_val *pval; | ||
1064 | |||
1065 | pval = kzalloc(sizeof(*pval), GFP_KERNEL); | ||
1066 | if (!pval) | ||
1067 | return -ENOMEM; | ||
1068 | |||
1069 | pval->cached_value = 0; | ||
1070 | pval->is_cached = 0; | ||
1071 | pval->mixer = mixer; | ||
1072 | pval->bUnitID = bUnitID; | ||
1073 | pval->validx = validx; | ||
1074 | 993 | ||
1075 | template.private_value = (unsigned long) pval; | 994 | err = add_single_ctl_with_resume(mixer, bUnitID, |
1076 | kctl = snd_ctl_new1(&template, mixer->chip); | 995 | snd_ftu_eff_switch_update, |
1077 | if (!kctl) { | 996 | &template, &list); |
1078 | kfree(pval); | ||
1079 | return -ENOMEM; | ||
1080 | } | ||
1081 | |||
1082 | kctl->private_free = kctl_private_value_free; | ||
1083 | err = snd_ctl_add(mixer->chip->card, kctl); | ||
1084 | if (err < 0) | 997 | if (err < 0) |
1085 | return err; | 998 | return err; |
1086 | 999 | list->kctl->private_value = (validx << 8) | bUnitID; | |
1000 | snd_ftu_eff_switch_init(mixer, list->kctl); | ||
1087 | return 0; | 1001 | return 0; |
1088 | } | 1002 | } |
1089 | 1003 | ||