diff options
author | Takashi Iwai <tiwai@suse.de> | 2008-10-20 02:06:39 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2008-10-20 02:06:39 -0400 |
commit | 1ee2a322b058f6399dc900603f9ebb392037ff77 (patch) | |
tree | 9863bfe8311a091737fff6883984f5d6559f0c81 | |
parent | 64931a4be03dbc49bd50d10d211592cf98b523bb (diff) |
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>
-rw-r--r-- | sound/ppc/snd_ps3.c | 96 | ||||
-rw-r--r-- | sound/ppc/snd_ps3.h | 1 |
2 files changed, 91 insertions, 6 deletions
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index 20d0e328288a..8f9e3859c37c 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c | |||
@@ -666,6 +666,7 @@ static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card) | |||
666 | card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; | 666 | card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; |
667 | card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM; | 667 | card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM; |
668 | card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL; | 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 | ret = snd_ps3_change_avsetting(card); | 671 | ret = snd_ps3_change_avsetting(card); |
671 | 672 | ||
@@ -685,6 +686,7 @@ static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream) | |||
685 | { | 686 | { |
686 | struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); | 687 | struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); |
687 | struct snd_ps3_avsetting_info avs; | 688 | struct snd_ps3_avsetting_info avs; |
689 | int ret; | ||
688 | 690 | ||
689 | avs = card->avs; | 691 | avs = card->avs; |
690 | 692 | ||
@@ -729,19 +731,92 @@ static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream) | |||
729 | return 1; | 731 | return 1; |
730 | } | 732 | } |
731 | 733 | ||
732 | if ((card->avs.avs_audio_width != avs.avs_audio_width) || | 734 | memcpy(avs.avs_cs_info, ps3av_mode_cs_info, 8); |
733 | (card->avs.avs_audio_rate != avs.avs_audio_rate)) { | ||
734 | card->avs = avs; | ||
735 | snd_ps3_change_avsetting(card); | ||
736 | 735 | ||
736 | if (memcmp(&card->avs, &avs, sizeof(avs))) { | ||
737 | pr_debug("%s: after freq=%d width=%d\n", __func__, | 737 | pr_debug("%s: after freq=%d width=%d\n", __func__, |
738 | card->avs.avs_audio_rate, card->avs.avs_audio_width); | 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 | } else | 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 | return 1; | 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 | static int snd_ps3_map_mmio(void) | 822 | static int snd_ps3_map_mmio(void) |
@@ -842,7 +917,7 @@ static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start) | |||
842 | 917 | ||
843 | static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev) | 918 | static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev) |
844 | { | 919 | { |
845 | int ret; | 920 | int i, ret; |
846 | u64 lpar_addr, lpar_size; | 921 | u64 lpar_addr, lpar_size; |
847 | 922 | ||
848 | BUG_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1)); | 923 | BUG_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1)); |
@@ -903,6 +978,15 @@ static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev) | |||
903 | strcpy(the_card.card->driver, "PS3"); | 978 | strcpy(the_card.card->driver, "PS3"); |
904 | strcpy(the_card.card->shortname, "PS3"); | 979 | strcpy(the_card.card->shortname, "PS3"); |
905 | strcpy(the_card.card->longname, "PS3 sound"); | 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 | /* create PCM devices instance */ | 990 | /* create PCM devices instance */ |
907 | /* NOTE:this driver works assuming pcm:substream = 1:1 */ | 991 | /* NOTE:this driver works assuming pcm:substream = 1:1 */ |
908 | ret = snd_pcm_new(the_card.card, | 992 | ret = snd_pcm_new(the_card.card, |
diff --git a/sound/ppc/snd_ps3.h b/sound/ppc/snd_ps3.h index 4b7e6fbbe500..326fb29e82d8 100644 --- a/sound/ppc/snd_ps3.h +++ b/sound/ppc/snd_ps3.h | |||
@@ -51,6 +51,7 @@ struct snd_ps3_avsetting_info { | |||
51 | uint32_t avs_audio_width; | 51 | uint32_t avs_audio_width; |
52 | uint32_t avs_audio_format; /* fixed */ | 52 | uint32_t avs_audio_format; /* fixed */ |
53 | uint32_t avs_audio_source; /* fixed */ | 53 | uint32_t avs_audio_source; /* fixed */ |
54 | unsigned char avs_cs_info[8]; | ||
54 | }; | 55 | }; |
55 | /* | 56 | /* |
56 | * PS3 audio 'card' instance | 57 | * PS3 audio 'card' instance |