diff options
author | Felix Homann <linuxaudio@showlabor.de> | 2012-04-23 14:24:27 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-04-24 02:06:06 -0400 |
commit | d34bf1485192b9cedb7b0dec8988324099b6a0b1 (patch) | |
tree | 774696ae5d1d055b35f2339c4fb68bae17436889 /sound/usb | |
parent | cfe8f97c8243cec6614524779424f2de9c335c5c (diff) |
ALSA: usb-audio: M-Audio Fast Track Ultra: Add effect controls
This adds controls for the effects section on the FTU devices.
Some of these controls need volume quirks. They are added to
mixer.c.
[fixed missing break by tiwai]
Signed-off-by: Felix Homann <linuxaudio@showlabor.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/mixer.c | 20 | ||||
-rw-r--r-- | sound/usb/mixer_quirks.c | 299 |
2 files changed, 319 insertions, 0 deletions
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index bb56f5353fe0..3d70245ab442 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -770,6 +770,26 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, | |||
770 | struct snd_kcontrol *kctl) | 770 | struct snd_kcontrol *kctl) |
771 | { | 771 | { |
772 | switch (cval->mixer->chip->usb_id) { | 772 | switch (cval->mixer->chip->usb_id) { |
773 | case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ | ||
774 | case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */ | ||
775 | if (strcmp(kctl->id.name, "Effect Duration") == 0) { | ||
776 | snd_printk(KERN_INFO | ||
777 | "usb-audio: set quirk for FTU Effect Duration\n"); | ||
778 | cval->min = 0x0000; | ||
779 | cval->max = 0x7f00; | ||
780 | cval->res = 0x0100; | ||
781 | break; | ||
782 | } | ||
783 | if (strcmp(kctl->id.name, "Effect Volume") == 0 || | ||
784 | strcmp(kctl->id.name, "Effect Feedback Volume") == 0) { | ||
785 | snd_printk(KERN_INFO | ||
786 | "usb-audio: set quirks for FTU Effect Feedback/Volume\n"); | ||
787 | cval->min = 0x00; | ||
788 | cval->max = 0x7f; | ||
789 | break; | ||
790 | } | ||
791 | break; | ||
792 | |||
773 | case USB_ID(0x0471, 0x0101): | 793 | case USB_ID(0x0471, 0x0101): |
774 | case USB_ID(0x0471, 0x0104): | 794 | case USB_ID(0x0471, 0x0104): |
775 | case USB_ID(0x0471, 0x0105): | 795 | case USB_ID(0x0471, 0x0105): |
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 6671e64a7630..b44df6e5109b 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c | |||
@@ -574,6 +574,186 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, | |||
574 | } | 574 | } |
575 | 575 | ||
576 | /* M-Audio FastTrack Ultra quirks */ | 576 | /* M-Audio FastTrack Ultra quirks */ |
577 | /* FTU Effect switch */ | ||
578 | struct snd_ftu_eff_switch_priv_val { | ||
579 | struct usb_mixer_interface *mixer; | ||
580 | int cached_value; | ||
581 | int is_cached; | ||
582 | }; | ||
583 | |||
584 | static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol, | ||
585 | struct snd_ctl_elem_info *uinfo) | ||
586 | { | ||
587 | static const char *texts[8] = {"Room 1", | ||
588 | "Room 2", | ||
589 | "Room 3", | ||
590 | "Hall 1", | ||
591 | "Hall 2", | ||
592 | "Plate", | ||
593 | "Delay", | ||
594 | "Echo" | ||
595 | }; | ||
596 | |||
597 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
598 | uinfo->count = 1; | ||
599 | uinfo->value.enumerated.items = 8; | ||
600 | if (uinfo->value.enumerated.item > 7) | ||
601 | uinfo->value.enumerated.item = 7; | ||
602 | strcpy(uinfo->value.enumerated.name, | ||
603 | texts[uinfo->value.enumerated.item]); | ||
604 | |||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl, | ||
609 | struct snd_ctl_elem_value *ucontrol) | ||
610 | { | ||
611 | struct snd_usb_audio *chip; | ||
612 | struct usb_mixer_interface *mixer; | ||
613 | struct snd_ftu_eff_switch_priv_val *pval; | ||
614 | int err; | ||
615 | unsigned char value[2]; | ||
616 | |||
617 | const int id = 6; | ||
618 | const int validx = 1; | ||
619 | const int val_len = 2; | ||
620 | |||
621 | value[0] = 0x00; | ||
622 | value[1] = 0x00; | ||
623 | |||
624 | pval = (struct snd_ftu_eff_switch_priv_val *) | ||
625 | kctl->private_value; | ||
626 | |||
627 | if (pval->is_cached) { | ||
628 | ucontrol->value.enumerated.item[0] = pval->cached_value; | ||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | mixer = (struct usb_mixer_interface *) pval->mixer; | ||
633 | if (snd_BUG_ON(!mixer)) | ||
634 | return -EINVAL; | ||
635 | |||
636 | chip = (struct snd_usb_audio *) mixer->chip; | ||
637 | if (snd_BUG_ON(!chip)) | ||
638 | return -EINVAL; | ||
639 | |||
640 | |||
641 | err = snd_usb_ctl_msg(chip->dev, | ||
642 | usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, | ||
643 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | ||
644 | validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), | ||
645 | value, val_len); | ||
646 | if (err < 0) | ||
647 | return err; | ||
648 | |||
649 | ucontrol->value.enumerated.item[0] = value[0]; | ||
650 | pval->cached_value = value[0]; | ||
651 | pval->is_cached = 1; | ||
652 | |||
653 | return 0; | ||
654 | } | ||
655 | |||
656 | static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, | ||
657 | struct snd_ctl_elem_value *ucontrol) | ||
658 | { | ||
659 | struct snd_usb_audio *chip; | ||
660 | struct snd_ftu_eff_switch_priv_val *pval; | ||
661 | |||
662 | struct usb_mixer_interface *mixer; | ||
663 | int changed, cur_val, err, new_val; | ||
664 | unsigned char value[2]; | ||
665 | |||
666 | |||
667 | const int id = 6; | ||
668 | const int validx = 1; | ||
669 | const int val_len = 2; | ||
670 | |||
671 | changed = 0; | ||
672 | |||
673 | pval = (struct snd_ftu_eff_switch_priv_val *) | ||
674 | kctl->private_value; | ||
675 | cur_val = pval->cached_value; | ||
676 | new_val = ucontrol->value.enumerated.item[0]; | ||
677 | |||
678 | mixer = (struct usb_mixer_interface *) pval->mixer; | ||
679 | if (snd_BUG_ON(!mixer)) | ||
680 | return -EINVAL; | ||
681 | |||
682 | chip = (struct snd_usb_audio *) mixer->chip; | ||
683 | if (snd_BUG_ON(!chip)) | ||
684 | return -EINVAL; | ||
685 | |||
686 | if (!pval->is_cached) { | ||
687 | /* Read current value */ | ||
688 | err = snd_usb_ctl_msg(chip->dev, | ||
689 | usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, | ||
690 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | ||
691 | validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), | ||
692 | value, val_len); | ||
693 | if (err < 0) | ||
694 | return err; | ||
695 | |||
696 | cur_val = value[0]; | ||
697 | pval->cached_value = cur_val; | ||
698 | pval->is_cached = 1; | ||
699 | } | ||
700 | /* update value if needed */ | ||
701 | if (cur_val != new_val) { | ||
702 | value[0] = new_val; | ||
703 | value[1] = 0; | ||
704 | err = snd_usb_ctl_msg(chip->dev, | ||
705 | usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, | ||
706 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, | ||
707 | validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), | ||
708 | value, val_len); | ||
709 | if (err < 0) | ||
710 | return err; | ||
711 | |||
712 | pval->cached_value = new_val; | ||
713 | pval->is_cached = 1; | ||
714 | changed = 1; | ||
715 | } | ||
716 | |||
717 | return changed; | ||
718 | } | ||
719 | |||
720 | static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer) | ||
721 | { | ||
722 | static struct snd_kcontrol_new template = { | ||
723 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
724 | .name = "Effect Program Switch", | ||
725 | .index = 0, | ||
726 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
727 | .info = snd_ftu_eff_switch_info, | ||
728 | .get = snd_ftu_eff_switch_get, | ||
729 | .put = snd_ftu_eff_switch_put | ||
730 | }; | ||
731 | |||
732 | int err; | ||
733 | struct snd_kcontrol *kctl; | ||
734 | struct snd_ftu_eff_switch_priv_val *pval; | ||
735 | |||
736 | pval = kzalloc(sizeof(*pval), GFP_KERNEL); | ||
737 | if (!pval) | ||
738 | return -ENOMEM; | ||
739 | |||
740 | pval->cached_value = 0; | ||
741 | pval->is_cached = 0; | ||
742 | pval->mixer = mixer; | ||
743 | |||
744 | template.private_value = (unsigned long) pval; | ||
745 | kctl = snd_ctl_new1(&template, mixer->chip); | ||
746 | if (!kctl) { | ||
747 | kfree(pval); | ||
748 | return -ENOMEM; | ||
749 | } | ||
750 | |||
751 | err = snd_ctl_add(mixer->chip->card, kctl); | ||
752 | if (err < 0) | ||
753 | return err; | ||
754 | |||
755 | return 0; | ||
756 | } | ||
577 | 757 | ||
578 | /* Create volume controls for FTU devices*/ | 758 | /* Create volume controls for FTU devices*/ |
579 | static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) | 759 | static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) |
@@ -614,6 +794,102 @@ static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) | |||
614 | return 0; | 794 | return 0; |
615 | } | 795 | } |
616 | 796 | ||
797 | /* This control needs a volume quirk, see mixer.c */ | ||
798 | static int snd_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer) | ||
799 | { | ||
800 | static const char name[] = "Effect Volume"; | ||
801 | const unsigned int id = 6; | ||
802 | const int val_type = USB_MIXER_U8; | ||
803 | const unsigned int control = 2; | ||
804 | const unsigned int cmask = 0; | ||
805 | |||
806 | return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, | ||
807 | name, snd_usb_mixer_vol_tlv); | ||
808 | } | ||
809 | |||
810 | /* This control needs a volume quirk, see mixer.c */ | ||
811 | static int snd_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer) | ||
812 | { | ||
813 | static const char name[] = "Effect Duration"; | ||
814 | const unsigned int id = 6; | ||
815 | const int val_type = USB_MIXER_S16; | ||
816 | const unsigned int control = 3; | ||
817 | const unsigned int cmask = 0; | ||
818 | |||
819 | return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, | ||
820 | name, snd_usb_mixer_vol_tlv); | ||
821 | } | ||
822 | |||
823 | /* This control needs a volume quirk, see mixer.c */ | ||
824 | static int snd_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer) | ||
825 | { | ||
826 | static const char name[] = "Effect Feedback Volume"; | ||
827 | const unsigned int id = 6; | ||
828 | const int val_type = USB_MIXER_U8; | ||
829 | const unsigned int control = 4; | ||
830 | const unsigned int cmask = 0; | ||
831 | |||
832 | return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, | ||
833 | name, NULL); | ||
834 | } | ||
835 | |||
836 | static int snd_ftu_create_effect_return_ctls(struct usb_mixer_interface *mixer) | ||
837 | { | ||
838 | unsigned int cmask; | ||
839 | int err, ch; | ||
840 | char name[48]; | ||
841 | |||
842 | const unsigned int id = 7; | ||
843 | const int val_type = USB_MIXER_S16; | ||
844 | const unsigned int control = 7; | ||
845 | |||
846 | for (ch = 0; ch < 4; ++ch) { | ||
847 | cmask = 1 << ch; | ||
848 | snprintf(name, sizeof(name), | ||
849 | "Effect Return %d Volume", ch + 1); | ||
850 | err = snd_create_std_mono_ctl(mixer, id, control, | ||
851 | cmask, val_type, name, | ||
852 | snd_usb_mixer_vol_tlv); | ||
853 | if (err < 0) | ||
854 | return err; | ||
855 | } | ||
856 | |||
857 | return 0; | ||
858 | } | ||
859 | |||
860 | static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer) | ||
861 | { | ||
862 | unsigned int cmask; | ||
863 | int err, ch; | ||
864 | char name[48]; | ||
865 | |||
866 | const unsigned int id = 5; | ||
867 | const int val_type = USB_MIXER_S16; | ||
868 | const unsigned int control = 9; | ||
869 | |||
870 | for (ch = 0; ch < 8; ++ch) { | ||
871 | cmask = 1 << ch; | ||
872 | snprintf(name, sizeof(name), | ||
873 | "Effect Send AIn%d Volume", ch + 1); | ||
874 | err = snd_create_std_mono_ctl(mixer, id, control, cmask, | ||
875 | val_type, name, | ||
876 | snd_usb_mixer_vol_tlv); | ||
877 | if (err < 0) | ||
878 | return err; | ||
879 | } | ||
880 | for (ch = 8; ch < 16; ++ch) { | ||
881 | cmask = 1 << ch; | ||
882 | snprintf(name, sizeof(name), | ||
883 | "Effect Send DIn%d Volume", ch - 7); | ||
884 | err = snd_create_std_mono_ctl(mixer, id, control, cmask, | ||
885 | val_type, name, | ||
886 | snd_usb_mixer_vol_tlv); | ||
887 | if (err < 0) | ||
888 | return err; | ||
889 | } | ||
890 | return 0; | ||
891 | } | ||
892 | |||
617 | static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer) | 893 | static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer) |
618 | { | 894 | { |
619 | int err; | 895 | int err; |
@@ -622,6 +898,29 @@ static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer) | |||
622 | if (err < 0) | 898 | if (err < 0) |
623 | return err; | 899 | return err; |
624 | 900 | ||
901 | err = snd_ftu_create_effect_switch(mixer); | ||
902 | if (err < 0) | ||
903 | return err; | ||
904 | err = snd_ftu_create_effect_volume_ctl(mixer); | ||
905 | if (err < 0) | ||
906 | return err; | ||
907 | |||
908 | err = snd_ftu_create_effect_duration_ctl(mixer); | ||
909 | if (err < 0) | ||
910 | return err; | ||
911 | |||
912 | err = snd_ftu_create_effect_feedback_ctl(mixer); | ||
913 | if (err < 0) | ||
914 | return err; | ||
915 | |||
916 | err = snd_ftu_create_effect_return_ctls(mixer); | ||
917 | if (err < 0) | ||
918 | return err; | ||
919 | |||
920 | err = snd_ftu_create_effect_send_ctls(mixer); | ||
921 | if (err < 0) | ||
922 | return err; | ||
923 | |||
625 | return 0; | 924 | return 0; |
626 | } | 925 | } |
627 | 926 | ||