diff options
author | Takashi Iwai <tiwai@suse.de> | 2014-11-18 10:59:47 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-11-21 05:58:14 -0500 |
commit | da6d276957ea56b9514aa5c8d885edf22f0b3e65 (patch) | |
tree | 2c0528ae77eb36953a84830078d23b710a0cd854 | |
parent | 25a9a4f91b909822fa07cbc9939c99a8c67d8960 (diff) |
ALSA: usb-audio: Add resume support for Native Instruments controls
The changes at this time are a bit more wider than previous ones.
Firstly, the NI controls didn't cache the values, so I had to
implement the caching. It's stored in bit 24 of private_value.
In addition to that, the initial values have to be read from
registers.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/usb/mixer_quirks.c | 99 |
1 files changed, 52 insertions, 47 deletions
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index f7ad2078c0cf..e11b4f3e1215 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c | |||
@@ -742,64 +742,68 @@ static int snd_mbox1_create_sync_switch(struct usb_mixer_interface *mixer) | |||
742 | 742 | ||
743 | #define _MAKE_NI_CONTROL(bRequest,wIndex) ((bRequest) << 16 | (wIndex)) | 743 | #define _MAKE_NI_CONTROL(bRequest,wIndex) ((bRequest) << 16 | (wIndex)) |
744 | 744 | ||
745 | static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol, | 745 | static int snd_ni_control_init_val(struct usb_mixer_interface *mixer, |
746 | struct snd_ctl_elem_value *ucontrol) | 746 | struct snd_kcontrol *kctl) |
747 | { | 747 | { |
748 | struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); | ||
749 | struct usb_device *dev = mixer->chip->dev; | 748 | struct usb_device *dev = mixer->chip->dev; |
750 | u8 bRequest = (kcontrol->private_value >> 16) & 0xff; | 749 | unsigned int pval = kctl->private_value; |
751 | u16 wIndex = kcontrol->private_value & 0xffff; | 750 | u8 value; |
752 | u8 tmp; | 751 | int err; |
753 | int ret; | ||
754 | |||
755 | down_read(&mixer->chip->shutdown_rwsem); | ||
756 | if (mixer->chip->shutdown) | ||
757 | ret = -ENODEV; | ||
758 | else | ||
759 | ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest, | ||
760 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
761 | 0, wIndex, | ||
762 | &tmp, sizeof(tmp)); | ||
763 | up_read(&mixer->chip->shutdown_rwsem); | ||
764 | 752 | ||
765 | if (ret < 0) { | 753 | err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), |
754 | (pval >> 16) & 0xff, | ||
755 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
756 | 0, pval & 0xffff, &value, 1); | ||
757 | if (err < 0) { | ||
766 | dev_err(&dev->dev, | 758 | dev_err(&dev->dev, |
767 | "unable to issue vendor read request (ret = %d)", ret); | 759 | "unable to issue vendor read request (ret = %d)", err); |
768 | return ret; | 760 | return err; |
769 | } | 761 | } |
770 | 762 | ||
771 | ucontrol->value.integer.value[0] = tmp; | 763 | kctl->private_value |= (value << 24); |
772 | |||
773 | return 0; | 764 | return 0; |
774 | } | 765 | } |
775 | 766 | ||
776 | static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, | 767 | static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol, |
777 | struct snd_ctl_elem_value *ucontrol) | 768 | struct snd_ctl_elem_value *ucontrol) |
778 | { | 769 | { |
779 | struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); | 770 | ucontrol->value.integer.value[0] = kcontrol->private_value >> 24; |
780 | struct usb_device *dev = mixer->chip->dev; | 771 | return 0; |
781 | u8 bRequest = (kcontrol->private_value >> 16) & 0xff; | 772 | } |
782 | u16 wIndex = kcontrol->private_value & 0xffff; | ||
783 | u16 wValue = ucontrol->value.integer.value[0]; | ||
784 | int ret; | ||
785 | 773 | ||
786 | down_read(&mixer->chip->shutdown_rwsem); | 774 | static int snd_ni_update_cur_val(struct usb_mixer_elem_list *list) |
787 | if (mixer->chip->shutdown) | 775 | { |
788 | ret = -ENODEV; | 776 | struct snd_usb_audio *chip = list->mixer->chip; |
777 | unsigned int pval = list->kctl->private_value; | ||
778 | int err; | ||
779 | |||
780 | down_read(&chip->shutdown_rwsem); | ||
781 | if (chip->shutdown) | ||
782 | err = -ENODEV; | ||
789 | else | 783 | else |
790 | ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest, | 784 | err = usb_control_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), |
791 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | 785 | (pval >> 16) & 0xff, |
792 | wValue, wIndex, | 786 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, |
793 | NULL, 0, 1000); | 787 | pval >> 24, pval & 0xffff, NULL, 0, 1000); |
794 | up_read(&mixer->chip->shutdown_rwsem); | 788 | up_read(&chip->shutdown_rwsem); |
789 | return err; | ||
790 | } | ||
795 | 791 | ||
796 | if (ret < 0) { | 792 | static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, |
797 | dev_err(&dev->dev, | 793 | struct snd_ctl_elem_value *ucontrol) |
798 | "unable to issue vendor write request (ret = %d)", ret); | 794 | { |
799 | return ret; | 795 | struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); |
800 | } | 796 | u8 oldval = (kcontrol->private_value >> 24) & 0xff; |
797 | u8 newval = ucontrol->value.integer.value[0]; | ||
798 | int err; | ||
801 | 799 | ||
802 | return 0; | 800 | if (oldval == newval) |
801 | return 0; | ||
802 | |||
803 | kcontrol->private_value &= ~(0xff << 24); | ||
804 | kcontrol->private_value |= newval; | ||
805 | err = snd_ni_update_cur_val(list); | ||
806 | return err < 0 ? err : 1; | ||
803 | } | 807 | } |
804 | 808 | ||
805 | static struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = { | 809 | static struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = { |
@@ -870,16 +874,17 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, | |||
870 | }; | 874 | }; |
871 | 875 | ||
872 | for (i = 0; i < count; i++) { | 876 | for (i = 0; i < count; i++) { |
873 | struct snd_kcontrol *c; | 877 | struct usb_mixer_elem_list *list; |
874 | 878 | ||
875 | template.name = kc[i].name; | 879 | template.name = kc[i].name; |
876 | template.private_value = kc[i].private_value; | 880 | template.private_value = kc[i].private_value; |
877 | 881 | ||
878 | c = snd_ctl_new1(&template, mixer); | 882 | err = add_single_ctl_with_resume(mixer, 0, |
879 | err = snd_ctl_add(mixer->chip->card, c); | 883 | snd_ni_update_cur_val, |
880 | 884 | &template, &list); | |
881 | if (err < 0) | 885 | if (err < 0) |
882 | break; | 886 | break; |
887 | snd_ni_control_init_val(mixer, list->kctl); | ||
883 | } | 888 | } |
884 | 889 | ||
885 | return err; | 890 | return err; |