Commit 1ee2a322b058f6399dc900603f9ebb392037ff77
1 parent
64931a4be0
Exists in
master
and in
39 other branches
ALSA: ps3: Add support for SPDIF/HDMI passthru
Add support for SPDIF/HDMI pass-through support of PS3 audio driver. Signed-off-by: Masakazu Mokuno <mokuno@sm.sony.co.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Showing 2 changed files with 91 additions and 6 deletions Side-by-side Diff
sound/ppc/snd_ps3.c
... | ... | @@ -666,6 +666,7 @@ |
666 | 666 | card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; |
667 | 667 | card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM; |
668 | 668 | card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL; |
669 | + memcpy(card->avs.avs_cs_info, ps3av_mode_cs_info, 8); | |
669 | 670 | |
670 | 671 | ret = snd_ps3_change_avsetting(card); |
671 | 672 | |
... | ... | @@ -685,6 +686,7 @@ |
685 | 686 | { |
686 | 687 | struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); |
687 | 688 | struct snd_ps3_avsetting_info avs; |
689 | + int ret; | |
688 | 690 | |
689 | 691 | avs = card->avs; |
690 | 692 | |
691 | 693 | |
692 | 694 | |
693 | 695 | |
694 | 696 | |
695 | 697 | |
... | ... | @@ -729,19 +731,92 @@ |
729 | 731 | return 1; |
730 | 732 | } |
731 | 733 | |
732 | - if ((card->avs.avs_audio_width != avs.avs_audio_width) || | |
733 | - (card->avs.avs_audio_rate != avs.avs_audio_rate)) { | |
734 | - card->avs = avs; | |
735 | - snd_ps3_change_avsetting(card); | |
734 | + memcpy(avs.avs_cs_info, ps3av_mode_cs_info, 8); | |
736 | 735 | |
736 | + if (memcmp(&card->avs, &avs, sizeof(avs))) { | |
737 | 737 | pr_debug("%s: after freq=%d width=%d\n", __func__, |
738 | 738 | card->avs.avs_audio_rate, card->avs.avs_audio_width); |
739 | 739 | |
740 | - return 0; | |
740 | + card->avs = avs; | |
741 | + snd_ps3_change_avsetting(card); | |
742 | + ret = 0; | |
741 | 743 | } else |
744 | + ret = 1; | |
745 | + | |
746 | + /* check CS non-audio bit and mute accordingly */ | |
747 | + if (avs.avs_cs_info[0] & 0x02) | |
748 | + ps3av_audio_mute_analog(1); /* mute if non-audio */ | |
749 | + else | |
750 | + ps3av_audio_mute_analog(0); | |
751 | + | |
752 | + return ret; | |
753 | +} | |
754 | + | |
755 | +/* | |
756 | + * SPDIF status bits controls | |
757 | + */ | |
758 | +static int snd_ps3_spdif_mask_info(struct snd_kcontrol *kcontrol, | |
759 | + struct snd_ctl_elem_info *uinfo) | |
760 | +{ | |
761 | + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | |
762 | + uinfo->count = 1; | |
763 | + return 0; | |
764 | +} | |
765 | + | |
766 | +/* FIXME: ps3av_set_audio_mode() assumes only consumer mode */ | |
767 | +static int snd_ps3_spdif_cmask_get(struct snd_kcontrol *kcontrol, | |
768 | + struct snd_ctl_elem_value *ucontrol) | |
769 | +{ | |
770 | + memset(ucontrol->value.iec958.status, 0xff, 8); | |
771 | + return 0; | |
772 | +} | |
773 | + | |
774 | +static int snd_ps3_spdif_pmask_get(struct snd_kcontrol *kcontrol, | |
775 | + struct snd_ctl_elem_value *ucontrol) | |
776 | +{ | |
777 | + return 0; | |
778 | +} | |
779 | + | |
780 | +static int snd_ps3_spdif_default_get(struct snd_kcontrol *kcontrol, | |
781 | + struct snd_ctl_elem_value *ucontrol) | |
782 | +{ | |
783 | + memcpy(ucontrol->value.iec958.status, ps3av_mode_cs_info, 8); | |
784 | + return 0; | |
785 | +} | |
786 | + | |
787 | +static int snd_ps3_spdif_default_put(struct snd_kcontrol *kcontrol, | |
788 | + struct snd_ctl_elem_value *ucontrol) | |
789 | +{ | |
790 | + if (memcmp(ps3av_mode_cs_info, ucontrol->value.iec958.status, 8)) { | |
791 | + memcpy(ps3av_mode_cs_info, ucontrol->value.iec958.status, 8); | |
742 | 792 | return 1; |
793 | + } | |
794 | + return 0; | |
743 | 795 | } |
744 | 796 | |
797 | +static struct snd_kcontrol_new spdif_ctls[] = { | |
798 | + { | |
799 | + .access = SNDRV_CTL_ELEM_ACCESS_READ, | |
800 | + .iface = SNDRV_CTL_ELEM_IFACE_PCM, | |
801 | + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), | |
802 | + .info = snd_ps3_spdif_mask_info, | |
803 | + .get = snd_ps3_spdif_cmask_get, | |
804 | + }, | |
805 | + { | |
806 | + .access = SNDRV_CTL_ELEM_ACCESS_READ, | |
807 | + .iface = SNDRV_CTL_ELEM_IFACE_PCM, | |
808 | + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK), | |
809 | + .info = snd_ps3_spdif_mask_info, | |
810 | + .get = snd_ps3_spdif_pmask_get, | |
811 | + }, | |
812 | + { | |
813 | + .iface = SNDRV_CTL_ELEM_IFACE_PCM, | |
814 | + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), | |
815 | + .info = snd_ps3_spdif_mask_info, | |
816 | + .get = snd_ps3_spdif_default_get, | |
817 | + .put = snd_ps3_spdif_default_put, | |
818 | + }, | |
819 | +}; | |
745 | 820 | |
746 | 821 | |
747 | 822 | static int snd_ps3_map_mmio(void) |
... | ... | @@ -842,7 +917,7 @@ |
842 | 917 | |
843 | 918 | static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev) |
844 | 919 | { |
845 | - int ret; | |
920 | + int i, ret; | |
846 | 921 | u64 lpar_addr, lpar_size; |
847 | 922 | |
848 | 923 | BUG_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1)); |
... | ... | @@ -903,6 +978,15 @@ |
903 | 978 | strcpy(the_card.card->driver, "PS3"); |
904 | 979 | strcpy(the_card.card->shortname, "PS3"); |
905 | 980 | strcpy(the_card.card->longname, "PS3 sound"); |
981 | + | |
982 | + /* create control elements */ | |
983 | + for (i = 0; i < ARRAY_SIZE(spdif_ctls); i++) { | |
984 | + ret = snd_ctl_add(the_card.card, | |
985 | + snd_ctl_new1(&spdif_ctls[i], &the_card)); | |
986 | + if (ret < 0) | |
987 | + goto clean_card; | |
988 | + } | |
989 | + | |
906 | 990 | /* create PCM devices instance */ |
907 | 991 | /* NOTE:this driver works assuming pcm:substream = 1:1 */ |
908 | 992 | ret = snd_pcm_new(the_card.card, |