Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+92 -7
+91 -7
sound/ppc/snd_ps3.c
··· 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 ··· 686 685 { 687 686 struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); 688 687 struct snd_ps3_avsetting_info avs; 688 + int ret; 689 689 690 690 avs = card->avs; 691 691 ··· 731 729 return 1; 732 730 } 733 731 734 - if ((card->avs.avs_audio_width != avs.avs_audio_width) || 735 - (card->avs.avs_audio_rate != avs.avs_audio_rate)) { 736 - card->avs = avs; 737 - snd_ps3_change_avsetting(card); 732 + memcpy(avs.avs_cs_info, ps3av_mode_cs_info, 8); 738 733 734 + if (memcmp(&card->avs, &avs, sizeof(avs))) { 739 735 pr_debug("%s: after freq=%d width=%d\n", __func__, 740 736 card->avs.avs_audio_rate, card->avs.avs_audio_width); 741 737 742 - return 0; 738 + card->avs = avs; 739 + snd_ps3_change_avsetting(card); 740 + ret = 0; 743 741 } else 744 - return 1; 742 + ret = 1; 743 + 744 + /* check CS non-audio bit and mute accordingly */ 745 + if (avs.avs_cs_info[0] & 0x02) 746 + ps3av_audio_mute_analog(1); /* mute if non-audio */ 747 + else 748 + ps3av_audio_mute_analog(0); 749 + 750 + return ret; 745 751 } 746 752 753 + /* 754 + * SPDIF status bits controls 755 + */ 756 + static int snd_ps3_spdif_mask_info(struct snd_kcontrol *kcontrol, 757 + struct snd_ctl_elem_info *uinfo) 758 + { 759 + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 760 + uinfo->count = 1; 761 + return 0; 762 + } 763 + 764 + /* FIXME: ps3av_set_audio_mode() assumes only consumer mode */ 765 + static int snd_ps3_spdif_cmask_get(struct snd_kcontrol *kcontrol, 766 + struct snd_ctl_elem_value *ucontrol) 767 + { 768 + memset(ucontrol->value.iec958.status, 0xff, 8); 769 + return 0; 770 + } 771 + 772 + static int snd_ps3_spdif_pmask_get(struct snd_kcontrol *kcontrol, 773 + struct snd_ctl_elem_value *ucontrol) 774 + { 775 + return 0; 776 + } 777 + 778 + static int snd_ps3_spdif_default_get(struct snd_kcontrol *kcontrol, 779 + struct snd_ctl_elem_value *ucontrol) 780 + { 781 + memcpy(ucontrol->value.iec958.status, ps3av_mode_cs_info, 8); 782 + return 0; 783 + } 784 + 785 + static int snd_ps3_spdif_default_put(struct snd_kcontrol *kcontrol, 786 + struct snd_ctl_elem_value *ucontrol) 787 + { 788 + if (memcmp(ps3av_mode_cs_info, ucontrol->value.iec958.status, 8)) { 789 + memcpy(ps3av_mode_cs_info, ucontrol->value.iec958.status, 8); 790 + return 1; 791 + } 792 + return 0; 793 + } 794 + 795 + static struct snd_kcontrol_new spdif_ctls[] = { 796 + { 797 + .access = SNDRV_CTL_ELEM_ACCESS_READ, 798 + .iface = SNDRV_CTL_ELEM_IFACE_PCM, 799 + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), 800 + .info = snd_ps3_spdif_mask_info, 801 + .get = snd_ps3_spdif_cmask_get, 802 + }, 803 + { 804 + .access = SNDRV_CTL_ELEM_ACCESS_READ, 805 + .iface = SNDRV_CTL_ELEM_IFACE_PCM, 806 + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK), 807 + .info = snd_ps3_spdif_mask_info, 808 + .get = snd_ps3_spdif_pmask_get, 809 + }, 810 + { 811 + .iface = SNDRV_CTL_ELEM_IFACE_PCM, 812 + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 813 + .info = snd_ps3_spdif_mask_info, 814 + .get = snd_ps3_spdif_default_get, 815 + .put = snd_ps3_spdif_default_put, 816 + }, 817 + }; 747 818 748 819 749 820 static int snd_ps3_map_mmio(void) ··· 917 842 918 843 static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev) 919 844 { 920 - int ret; 845 + int i, ret; 921 846 u64 lpar_addr, lpar_size; 922 847 923 848 BUG_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1)); ··· 978 903 strcpy(the_card.card->driver, "PS3"); 979 904 strcpy(the_card.card->shortname, "PS3"); 980 905 strcpy(the_card.card->longname, "PS3 sound"); 906 + 907 + /* create control elements */ 908 + for (i = 0; i < ARRAY_SIZE(spdif_ctls); i++) { 909 + ret = snd_ctl_add(the_card.card, 910 + snd_ctl_new1(&spdif_ctls[i], &the_card)); 911 + if (ret < 0) 912 + goto clean_card; 913 + } 914 + 981 915 /* create PCM devices instance */ 982 916 /* NOTE:this driver works assuming pcm:substream = 1:1 */ 983 917 ret = snd_pcm_new(the_card.card,
+1
sound/ppc/snd_ps3.h
··· 51 51 uint32_t avs_audio_width; 52 52 uint32_t avs_audio_format; /* fixed */ 53 53 uint32_t avs_audio_source; /* fixed */ 54 + unsigned char avs_cs_info[8]; 54 55 }; 55 56 /* 56 57 * PS3 audio 'card' instance