diff options
author | Takashi Iwai <tiwai@suse.de> | 2008-02-18 06:23:13 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2008-04-24 06:00:11 -0400 |
commit | 4235a31784f59c9be5ff71534743c055091f9735 (patch) | |
tree | 87080055fed0c3f25a3c816c182a6db5739430b6 /sound | |
parent | 2eef1258e54722b1c4efac6e5760d2153f96c4b4 (diff) |
[ALSA] intel8x0 - Add support of 8 channel sound
Added the support of 8 channel sound for codecs that are known to work.
So far, only ALC850 is marked as a 8ch-support codec.
This fix is a modified version of the patch on ALSA BTS#2097 by
Martin Ellis:
https://bugtrack.alsa-project.org/alsa-bug/view.php?id=2097
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/ac97/ac97_patch.c | 46 | ||||
-rw-r--r-- | sound/pci/intel8x0.c | 28 |
2 files changed, 58 insertions, 16 deletions
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 50c637e55ffa..39198e505b12 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
@@ -114,10 +114,9 @@ static int ac97_surround_jack_mode_put(struct snd_kcontrol *kcontrol, struct snd | |||
114 | 114 | ||
115 | static int ac97_channel_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 115 | static int ac97_channel_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
116 | { | 116 | { |
117 | static const char *texts[] = { "2ch", "4ch", "6ch" }; | 117 | static const char *texts[] = { "2ch", "4ch", "6ch", "8ch" }; |
118 | if (kcontrol->private_value) | 118 | return ac97_enum_text_info(kcontrol, uinfo, texts, |
119 | return ac97_enum_text_info(kcontrol, uinfo, texts, 2); /* 4ch only */ | 119 | kcontrol->private_value); |
120 | return ac97_enum_text_info(kcontrol, uinfo, texts, 3); | ||
121 | } | 120 | } |
122 | 121 | ||
123 | static int ac97_channel_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 122 | static int ac97_channel_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
@@ -133,13 +132,8 @@ static int ac97_channel_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
133 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | 132 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); |
134 | unsigned char mode = ucontrol->value.enumerated.item[0]; | 133 | unsigned char mode = ucontrol->value.enumerated.item[0]; |
135 | 134 | ||
136 | if (kcontrol->private_value) { | 135 | if (mode >= kcontrol->private_value) |
137 | if (mode >= 2) | 136 | return -EINVAL; |
138 | return -EINVAL; | ||
139 | } else { | ||
140 | if (mode >= 3) | ||
141 | return -EINVAL; | ||
142 | } | ||
143 | 137 | ||
144 | if (mode != ac97->channel_mode) { | 138 | if (mode != ac97->channel_mode) { |
145 | ac97->channel_mode = mode; | 139 | ac97->channel_mode = mode; |
@@ -158,6 +152,7 @@ static int ac97_channel_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
158 | .get = ac97_surround_jack_mode_get, \ | 152 | .get = ac97_surround_jack_mode_get, \ |
159 | .put = ac97_surround_jack_mode_put, \ | 153 | .put = ac97_surround_jack_mode_put, \ |
160 | } | 154 | } |
155 | /* 6ch */ | ||
161 | #define AC97_CHANNEL_MODE_CTL \ | 156 | #define AC97_CHANNEL_MODE_CTL \ |
162 | { \ | 157 | { \ |
163 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 158 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
@@ -165,7 +160,9 @@ static int ac97_channel_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
165 | .info = ac97_channel_mode_info, \ | 160 | .info = ac97_channel_mode_info, \ |
166 | .get = ac97_channel_mode_get, \ | 161 | .get = ac97_channel_mode_get, \ |
167 | .put = ac97_channel_mode_put, \ | 162 | .put = ac97_channel_mode_put, \ |
163 | .private_value = 3, \ | ||
168 | } | 164 | } |
165 | /* 4ch */ | ||
169 | #define AC97_CHANNEL_MODE_4CH_CTL \ | 166 | #define AC97_CHANNEL_MODE_4CH_CTL \ |
170 | { \ | 167 | { \ |
171 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 168 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
@@ -173,7 +170,17 @@ static int ac97_channel_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
173 | .info = ac97_channel_mode_info, \ | 170 | .info = ac97_channel_mode_info, \ |
174 | .get = ac97_channel_mode_get, \ | 171 | .get = ac97_channel_mode_get, \ |
175 | .put = ac97_channel_mode_put, \ | 172 | .put = ac97_channel_mode_put, \ |
176 | .private_value = 1, \ | 173 | .private_value = 2, \ |
174 | } | ||
175 | /* 8ch */ | ||
176 | #define AC97_CHANNEL_MODE_8CH_CTL \ | ||
177 | { \ | ||
178 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
179 | .name = "Channel Mode", \ | ||
180 | .info = ac97_channel_mode_info, \ | ||
181 | .get = ac97_channel_mode_get, \ | ||
182 | .put = ac97_channel_mode_put, \ | ||
183 | .private_value = 4, \ | ||
177 | } | 184 | } |
178 | 185 | ||
179 | static inline int is_surround_on(struct snd_ac97 *ac97) | 186 | static inline int is_surround_on(struct snd_ac97 *ac97) |
@@ -210,6 +217,10 @@ static inline int is_shared_micin(struct snd_ac97 *ac97) | |||
210 | return !ac97->indep_surround && !is_clfe_on(ac97); | 217 | return !ac97->indep_surround && !is_clfe_on(ac97); |
211 | } | 218 | } |
212 | 219 | ||
220 | static inline int alc850_is_aux_back_surround(struct snd_ac97 *ac97) | ||
221 | { | ||
222 | return is_surround_on(ac97); | ||
223 | } | ||
213 | 224 | ||
214 | /* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */ | 225 | /* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */ |
215 | /* Modified for YMF743 by Keita Maehara <maehara@debian.org> */ | 226 | /* Modified for YMF743 by Keita Maehara <maehara@debian.org> */ |
@@ -2816,10 +2827,12 @@ static int patch_alc655(struct snd_ac97 * ac97) | |||
2816 | 2827 | ||
2817 | #define AC97_ALC850_JACK_SELECT 0x76 | 2828 | #define AC97_ALC850_JACK_SELECT 0x76 |
2818 | #define AC97_ALC850_MISC1 0x7a | 2829 | #define AC97_ALC850_MISC1 0x7a |
2830 | #define AC97_ALC850_MULTICH 0x6a | ||
2819 | 2831 | ||
2820 | static void alc850_update_jacks(struct snd_ac97 *ac97) | 2832 | static void alc850_update_jacks(struct snd_ac97 *ac97) |
2821 | { | 2833 | { |
2822 | int shared; | 2834 | int shared; |
2835 | int aux_is_back_surround; | ||
2823 | 2836 | ||
2824 | /* shared Line-In / Surround Out */ | 2837 | /* shared Line-In / Surround Out */ |
2825 | shared = is_shared_surrout(ac97); | 2838 | shared = is_shared_surrout(ac97); |
@@ -2837,13 +2850,18 @@ static void alc850_update_jacks(struct snd_ac97 *ac97) | |||
2837 | /* MIC-IN = 1, CENTER-LFE = 5 */ | 2850 | /* MIC-IN = 1, CENTER-LFE = 5 */ |
2838 | snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4, | 2851 | snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4, |
2839 | shared ? (5<<4) : (1<<4)); | 2852 | shared ? (5<<4) : (1<<4)); |
2853 | |||
2854 | aux_is_back_surround = alc850_is_aux_back_surround(ac97); | ||
2855 | /* Aux is Back Surround */ | ||
2856 | snd_ac97_update_bits(ac97, AC97_ALC850_MULTICH, 1 << 10, | ||
2857 | aux_is_back_surround ? (1<<10) : (0<<10)); | ||
2840 | } | 2858 | } |
2841 | 2859 | ||
2842 | static const struct snd_kcontrol_new snd_ac97_controls_alc850[] = { | 2860 | static const struct snd_kcontrol_new snd_ac97_controls_alc850[] = { |
2843 | AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), | 2861 | AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), |
2844 | AC97_SINGLE("Mic Front Input Switch", AC97_ALC850_JACK_SELECT, 15, 1, 1), | 2862 | AC97_SINGLE("Mic Front Input Switch", AC97_ALC850_JACK_SELECT, 15, 1, 1), |
2845 | AC97_SURROUND_JACK_MODE_CTL, | 2863 | AC97_SURROUND_JACK_MODE_CTL, |
2846 | AC97_CHANNEL_MODE_CTL, | 2864 | AC97_CHANNEL_MODE_8CH_CTL, |
2847 | }; | 2865 | }; |
2848 | 2866 | ||
2849 | static int patch_alc850_specific(struct snd_ac97 *ac97) | 2867 | static int patch_alc850_specific(struct snd_ac97 *ac97) |
@@ -2869,6 +2887,7 @@ static int patch_alc850(struct snd_ac97 *ac97) | |||
2869 | ac97->build_ops = &patch_alc850_ops; | 2887 | ac97->build_ops = &patch_alc850_ops; |
2870 | 2888 | ||
2871 | ac97->spec.dev_flags = 0; /* for IEC958 playback route - ALC655 compatible */ | 2889 | ac97->spec.dev_flags = 0; /* for IEC958 playback route - ALC655 compatible */ |
2890 | ac97->flags |= AC97_HAS_8CH; | ||
2872 | 2891 | ||
2873 | /* assume only page 0 for writing cache */ | 2892 | /* assume only page 0 for writing cache */ |
2874 | snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, AC97_PAGE_VENDOR); | 2893 | snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, AC97_PAGE_VENDOR); |
@@ -2878,6 +2897,7 @@ static int patch_alc850(struct snd_ac97 *ac97) | |||
2878 | spdif-in monitor off, spdif-in PCM off | 2897 | spdif-in monitor off, spdif-in PCM off |
2879 | center on mic off, surround on line-in off | 2898 | center on mic off, surround on line-in off |
2880 | duplicate front off | 2899 | duplicate front off |
2900 | NB default bit 10=0 = Aux is Capture, not Back Surround | ||
2881 | */ | 2901 | */ |
2882 | snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, 1<<15); | 2902 | snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, 1<<15); |
2883 | /* SURR_OUT: on, Surr 1kOhm: on, Surr Amp: off, Front 1kOhm: off | 2903 | /* SURR_OUT: on, Surr 1kOhm: on, Surr Amp: off, Front 1kOhm: off |
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index c52abd0bf22e..07782ba9c74d 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c | |||
@@ -155,7 +155,8 @@ DEFINE_REGSET(SP, 0x60); /* SPDIF out */ | |||
155 | #define ICH_PCM_SPDIF_69 0x80000000 /* s/pdif pcm on slots 6&9 */ | 155 | #define ICH_PCM_SPDIF_69 0x80000000 /* s/pdif pcm on slots 6&9 */ |
156 | #define ICH_PCM_SPDIF_1011 0xc0000000 /* s/pdif pcm on slots 10&11 */ | 156 | #define ICH_PCM_SPDIF_1011 0xc0000000 /* s/pdif pcm on slots 10&11 */ |
157 | #define ICH_PCM_20BIT 0x00400000 /* 20-bit samples (ICH4) */ | 157 | #define ICH_PCM_20BIT 0x00400000 /* 20-bit samples (ICH4) */ |
158 | #define ICH_PCM_246_MASK 0x00300000 /* 6 channels (not all chips) */ | 158 | #define ICH_PCM_246_MASK 0x00300000 /* chan mask (not all chips) */ |
159 | #define ICH_PCM_8 0x00300000 /* 8 channels (not all chips) */ | ||
159 | #define ICH_PCM_6 0x00200000 /* 6 channels (not all chips) */ | 160 | #define ICH_PCM_6 0x00200000 /* 6 channels (not all chips) */ |
160 | #define ICH_PCM_4 0x00100000 /* 4 channels (not all chips) */ | 161 | #define ICH_PCM_4 0x00100000 /* 4 channels (not all chips) */ |
161 | #define ICH_PCM_2 0x00000000 /* 2 channels (stereo) */ | 162 | #define ICH_PCM_2 0x00000000 /* 2 channels (stereo) */ |
@@ -382,6 +383,7 @@ struct intel8x0 { | |||
382 | 383 | ||
383 | unsigned multi4: 1, | 384 | unsigned multi4: 1, |
384 | multi6: 1, | 385 | multi6: 1, |
386 | multi8 :1, | ||
385 | dra: 1, | 387 | dra: 1, |
386 | smp20bit: 1; | 388 | smp20bit: 1; |
387 | unsigned in_ac97_init: 1, | 389 | unsigned in_ac97_init: 1, |
@@ -997,6 +999,8 @@ static void snd_intel8x0_setup_pcm_out(struct intel8x0 *chip, | |||
997 | cnt |= ICH_PCM_4; | 999 | cnt |= ICH_PCM_4; |
998 | else if (runtime->channels == 6) | 1000 | else if (runtime->channels == 6) |
999 | cnt |= ICH_PCM_6; | 1001 | cnt |= ICH_PCM_6; |
1002 | else if (runtime->channels == 8) | ||
1003 | cnt |= ICH_PCM_8; | ||
1000 | if (chip->device_type == DEVICE_NFORCE) { | 1004 | if (chip->device_type == DEVICE_NFORCE) { |
1001 | /* reset to 2ch once to keep the 6 channel data in alignment, | 1005 | /* reset to 2ch once to keep the 6 channel data in alignment, |
1002 | * to start from Front Left always | 1006 | * to start from Front Left always |
@@ -1106,6 +1110,16 @@ static struct snd_pcm_hw_constraint_list hw_constraints_channels6 = { | |||
1106 | .mask = 0, | 1110 | .mask = 0, |
1107 | }; | 1111 | }; |
1108 | 1112 | ||
1113 | static unsigned int channels8[] = { | ||
1114 | 2, 4, 6, 8, | ||
1115 | }; | ||
1116 | |||
1117 | static struct snd_pcm_hw_constraint_list hw_constraints_channels8 = { | ||
1118 | .count = ARRAY_SIZE(channels8), | ||
1119 | .list = channels8, | ||
1120 | .mask = 0, | ||
1121 | }; | ||
1122 | |||
1109 | static int snd_intel8x0_pcm_open(struct snd_pcm_substream *substream, struct ichdev *ichdev) | 1123 | static int snd_intel8x0_pcm_open(struct snd_pcm_substream *substream, struct ichdev *ichdev) |
1110 | { | 1124 | { |
1111 | struct intel8x0 *chip = snd_pcm_substream_chip(substream); | 1125 | struct intel8x0 *chip = snd_pcm_substream_chip(substream); |
@@ -1136,7 +1150,12 @@ static int snd_intel8x0_playback_open(struct snd_pcm_substream *substream) | |||
1136 | if (err < 0) | 1150 | if (err < 0) |
1137 | return err; | 1151 | return err; |
1138 | 1152 | ||
1139 | if (chip->multi6) { | 1153 | if (chip->multi8) { |
1154 | runtime->hw.channels_max = 8; | ||
1155 | snd_pcm_hw_constraint_list(runtime, 0, | ||
1156 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1157 | &hw_constraints_channels8); | ||
1158 | } else if (chip->multi6) { | ||
1140 | runtime->hw.channels_max = 6; | 1159 | runtime->hw.channels_max = 6; |
1141 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | 1160 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
1142 | &hw_constraints_channels6); | 1161 | &hw_constraints_channels6); |
@@ -2203,8 +2222,11 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, | |||
2203 | } | 2222 | } |
2204 | if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_PCM_SLEFT)) { | 2223 | if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_PCM_SLEFT)) { |
2205 | chip->multi4 = 1; | 2224 | chip->multi4 = 1; |
2206 | if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_LFE)) | 2225 | if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_LFE)) { |
2207 | chip->multi6 = 1; | 2226 | chip->multi6 = 1; |
2227 | if (chip->ac97[0]->flags & AC97_HAS_8CH) | ||
2228 | chip->multi8 = 1; | ||
2229 | } | ||
2208 | } | 2230 | } |
2209 | if (pbus->pcms[0].r[1].rslots[0]) { | 2231 | if (pbus->pcms[0].r[1].rslots[0]) { |
2210 | chip->dra = 1; | 2232 | chip->dra = 1; |