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 |
