ALSA: usb-audio: Add resume support for FTU controls
authorTakashi Iwai <tiwai@suse.de>
Tue, 18 Nov 2014 16:37:40 +0000 (17:37 +0100)
committerTakashi Iwai <tiwai@suse.de>
Fri, 21 Nov 2014 10:58:19 +0000 (11:58 +0100)
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>
sound/usb/mixer_quirks.c

index e11b4f3e12154618b293bf92c5fb0e0cca2cf5a5..fcb7ae5131a912efb5f0e1a6044e2e67380b9c33 100644 (file)
@@ -892,14 +892,6 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
 
 /* M-Audio FastTrack Ultra quirks */
 /* FTU Effect switch (also used by C400/C600) */
-struct snd_ftu_eff_switch_priv_val {
-       struct usb_mixer_interface *mixer;
-       int cached_value;
-       int is_cached;
-       int bUnitID;
-       int validx;
-};
-
 static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol,
                                        struct snd_ctl_elem_info *uinfo)
 {
@@ -911,138 +903,77 @@ static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol,
        return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
 }
 
-static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl,
-                                       struct snd_ctl_elem_value *ucontrol)
+static int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer,
+                                  struct snd_kcontrol *kctl)
 {
-       struct snd_usb_audio *chip;
-       struct usb_mixer_interface *mixer;
-       struct snd_ftu_eff_switch_priv_val *pval;
+       struct usb_device *dev = mixer->chip->dev;
+       unsigned int pval = kctl->private_value;
        int err;
        unsigned char value[2];
-       int id, validx;
-
-       const int val_len = 2;
 
        value[0] = 0x00;
        value[1] = 0x00;
 
-       pval = (struct snd_ftu_eff_switch_priv_val *)
-               kctl->private_value;
+       err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
+                             USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+                             pval & 0xff00,
+                             snd_usb_ctrl_intf(mixer->chip) | ((pval & 0xff) << 8),
+                             value, 2);
+       if (err < 0)
+               return err;
 
-       if (pval->is_cached) {
-               ucontrol->value.enumerated.item[0] = pval->cached_value;
-               return 0;
-       }
+       kctl->private_value |= value[0] << 24;
+       return 0;
+}
 
-       mixer = (struct usb_mixer_interface *) pval->mixer;
-       if (snd_BUG_ON(!mixer))
-               return -EINVAL;
+static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.enumerated.item[0] = kctl->private_value >> 24;
+       return 0;
+}
 
-       chip = (struct snd_usb_audio *) mixer->chip;
-       if (snd_BUG_ON(!chip))
-               return -EINVAL;
+static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list)
+{
+       struct snd_usb_audio *chip = list->mixer->chip;
+       unsigned int pval = list->kctl->private_value;
+       unsigned char value[2];
+       int err;
 
-       id = pval->bUnitID;
-       validx = pval->validx;
+       value[0] = pval >> 24;
+       value[1] = 0;
 
-       down_read(&mixer->chip->shutdown_rwsem);
-       if (mixer->chip->shutdown)
+       down_read(&chip->shutdown_rwsem);
+       if (chip->shutdown)
                err = -ENODEV;
        else
                err = snd_usb_ctl_msg(chip->dev,
-                       usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
-                       USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-                       validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
-                       value, val_len);
-       up_read(&mixer->chip->shutdown_rwsem);
-       if (err < 0)
-               return err;
-
-       ucontrol->value.enumerated.item[0] = value[0];
-       pval->cached_value = value[0];
-       pval->is_cached = 1;
-
-       return 0;
+                                     usb_sndctrlpipe(chip->dev, 0),
+                                     UAC_SET_CUR,
+                                     USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+                                     pval & 0xff00,
+                                     snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8),
+                                     value, 2);
+       up_read(&chip->shutdown_rwsem);
+       return err;
 }
 
 static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl,
                                        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_usb_audio *chip;
-       struct snd_ftu_eff_switch_priv_val *pval;
-
-       struct usb_mixer_interface *mixer;
-       int changed, cur_val, err, new_val;
-       unsigned char value[2];
-       int id, validx;
-
-       const int val_len = 2;
-
-       changed = 0;
+       struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl);
+       unsigned int pval = list->kctl->private_value;
+       int cur_val, err, new_val;
 
-       pval = (struct snd_ftu_eff_switch_priv_val *)
-               kctl->private_value;
-       cur_val = pval->cached_value;
+       cur_val = pval >> 24;
        new_val = ucontrol->value.enumerated.item[0];
+       if (cur_val == new_val)
+               return 0;
 
-       mixer = (struct usb_mixer_interface *) pval->mixer;
-       if (snd_BUG_ON(!mixer))
-               return -EINVAL;
-
-       chip = (struct snd_usb_audio *) mixer->chip;
-       if (snd_BUG_ON(!chip))
-               return -EINVAL;
-
-       id = pval->bUnitID;
-       validx = pval->validx;
-
-       if (!pval->is_cached) {
-               /* Read current value */
-               down_read(&mixer->chip->shutdown_rwsem);
-               if (mixer->chip->shutdown)
-                       err = -ENODEV;
-               else
-                       err = snd_usb_ctl_msg(chip->dev,
-                               usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
-                               USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-                               validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
-                               value, val_len);
-               up_read(&mixer->chip->shutdown_rwsem);
-               if (err < 0)
-                       return err;
-
-               cur_val = value[0];
-               pval->cached_value = cur_val;
-               pval->is_cached = 1;
-       }
-       /* update value if needed */
-       if (cur_val != new_val) {
-               value[0] = new_val;
-               value[1] = 0;
-               down_read(&mixer->chip->shutdown_rwsem);
-               if (mixer->chip->shutdown)
-                       err = -ENODEV;
-               else
-                       err = snd_usb_ctl_msg(chip->dev,
-                               usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
-                               USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-                               validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
-                               value, val_len);
-               up_read(&mixer->chip->shutdown_rwsem);
-               if (err < 0)
-                       return err;
-
-               pval->cached_value = new_val;
-               pval->is_cached = 1;
-               changed = 1;
-       }
-
-       return changed;
-}
-
-static void kctl_private_value_free(struct snd_kcontrol *kctl)
-{
-       kfree((void *)kctl->private_value);
+       kctl->private_value &= ~(0xff << 24);
+       kctl->private_value |= new_val << 24;
+       err = snd_ftu_eff_switch_update(list);
+       return err < 0 ? err : 1;
 }
 
 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,
                .get = snd_ftu_eff_switch_get,
                .put = snd_ftu_eff_switch_put
        };
-
+       struct usb_mixer_elem_list *list;
        int err;
-       struct snd_kcontrol *kctl;
-       struct snd_ftu_eff_switch_priv_val *pval;
-
-       pval = kzalloc(sizeof(*pval), GFP_KERNEL);
-       if (!pval)
-               return -ENOMEM;
-
-       pval->cached_value = 0;
-       pval->is_cached = 0;
-       pval->mixer = mixer;
-       pval->bUnitID = bUnitID;
-       pval->validx = validx;
 
-       template.private_value = (unsigned long) pval;
-       kctl = snd_ctl_new1(&template, mixer->chip);
-       if (!kctl) {
-               kfree(pval);
-               return -ENOMEM;
-       }
-
-       kctl->private_free = kctl_private_value_free;
-       err = snd_ctl_add(mixer->chip->card, kctl);
+       err = add_single_ctl_with_resume(mixer, bUnitID,
+                                        snd_ftu_eff_switch_update,
+                                        &template, &list);
        if (err < 0)
                return err;
-
+       list->kctl->private_value = (validx << 8) | bUnitID;
+       snd_ftu_eff_switch_init(mixer, list->kctl);
        return 0;
 }