aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2014-11-18 11:37:40 -0500
committerTakashi Iwai <tiwai@suse.de>2014-11-21 05:58:19 -0500
commit0b4e9cfcef055a1be9bee5a47262e9cbcf17e8cd (patch)
tree91e3017a4524115071cb9af66eb4635d56564185 /sound/usb
parentda6d276957ea56b9514aa5c8d885edf22f0b3e65 (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.c194
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) */
895struct 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
903static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol, 895static 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
914static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl, 906static 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; 929static 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; 936static 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
968static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, 961static 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
1043static void kctl_private_value_free(struct snd_kcontrol *kctl)
1044{
1045 kfree((void *)kctl->private_value);
1046} 977}
1047 978
1048static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer, 979static 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