diff options
author | Raymond Yau <superquad.vortex2@gmail.com> | 2011-01-17 05:19:03 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-01-18 01:43:05 -0500 |
commit | c66ddf32dda0d5bcf9db7b4cc42ef5da7baadd3e (patch) | |
tree | 9072aa7a0f83c35358235e136ee69f8d5fe25503 | |
parent | 4fe2ca14678174d9df254ae3ba2b79bacc19e2ee (diff) |
ALSA: hda - Add add multi-streaming playback for AD1988
Attached a patch which add a new model to support multi-streaming
playback for ad1988.
playback another stereo stream through the front panel headphone on
device 2 while playback through the speakers connected to rear panel
on device 0 at the same time.
Tested with ad1988a rev2 codec on asus P5B-V motherboard.
Signed-off-by: Raymond Yau <superquad.vortex2@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/pci/hda/patch_analog.c | 182 |
1 files changed, 178 insertions, 4 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 46780670162b..34ee1169f2e0 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -46,6 +46,9 @@ struct ad198x_spec { | |||
46 | unsigned int cur_eapd; | 46 | unsigned int cur_eapd; |
47 | unsigned int need_dac_fix; | 47 | unsigned int need_dac_fix; |
48 | 48 | ||
49 | hda_nid_t *alt_dac_nid; | ||
50 | struct hda_pcm_stream *stream_analog_alt_playback; | ||
51 | |||
49 | /* capture */ | 52 | /* capture */ |
50 | unsigned int num_adc_nids; | 53 | unsigned int num_adc_nids; |
51 | hda_nid_t *adc_nids; | 54 | hda_nid_t *adc_nids; |
@@ -156,6 +159,25 @@ static const char *ad_slave_sws[] = { | |||
156 | NULL | 159 | NULL |
157 | }; | 160 | }; |
158 | 161 | ||
162 | static const char *ad1988_6stack_fp_slave_vols[] = { | ||
163 | "Front Playback Volume", | ||
164 | "Surround Playback Volume", | ||
165 | "Center Playback Volume", | ||
166 | "LFE Playback Volume", | ||
167 | "Side Playback Volume", | ||
168 | "IEC958 Playback Volume", | ||
169 | NULL | ||
170 | }; | ||
171 | |||
172 | static const char *ad1988_6stack_fp_slave_sws[] = { | ||
173 | "Front Playback Switch", | ||
174 | "Surround Playback Switch", | ||
175 | "Center Playback Switch", | ||
176 | "LFE Playback Switch", | ||
177 | "Side Playback Switch", | ||
178 | "IEC958 Playback Switch", | ||
179 | NULL | ||
180 | }; | ||
159 | static void ad198x_free_kctls(struct hda_codec *codec); | 181 | static void ad198x_free_kctls(struct hda_codec *codec); |
160 | 182 | ||
161 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | 183 | #ifdef CONFIG_SND_HDA_INPUT_BEEP |
@@ -309,6 +331,38 @@ static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
309 | return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); | 331 | return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); |
310 | } | 332 | } |
311 | 333 | ||
334 | static int ad198x_alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
335 | struct hda_codec *codec, | ||
336 | unsigned int stream_tag, | ||
337 | unsigned int format, | ||
338 | struct snd_pcm_substream *substream) | ||
339 | { | ||
340 | struct ad198x_spec *spec = codec->spec; | ||
341 | snd_hda_codec_setup_stream(codec, spec->alt_dac_nid[0], stream_tag, | ||
342 | 0, format); | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static int ad198x_alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
347 | struct hda_codec *codec, | ||
348 | struct snd_pcm_substream *substream) | ||
349 | { | ||
350 | struct ad198x_spec *spec = codec->spec; | ||
351 | snd_hda_codec_cleanup_stream(codec, spec->alt_dac_nid[0]); | ||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | static struct hda_pcm_stream ad198x_pcm_analog_alt_playback = { | ||
356 | .substreams = 1, | ||
357 | .channels_min = 2, | ||
358 | .channels_max = 2, | ||
359 | /* NID is set in ad198x_build_pcms */ | ||
360 | .ops = { | ||
361 | .prepare = ad198x_alt_playback_pcm_prepare, | ||
362 | .cleanup = ad198x_alt_playback_pcm_cleanup | ||
363 | }, | ||
364 | }; | ||
365 | |||
312 | /* | 366 | /* |
313 | * Digital out | 367 | * Digital out |
314 | */ | 368 | */ |
@@ -446,6 +500,17 @@ static int ad198x_build_pcms(struct hda_codec *codec) | |||
446 | } | 500 | } |
447 | } | 501 | } |
448 | 502 | ||
503 | if (spec->alt_dac_nid && spec->stream_analog_alt_playback) { | ||
504 | codec->num_pcms++; | ||
505 | info = spec->pcm_rec + 2; | ||
506 | info->name = "AD198x Headphone"; | ||
507 | info->pcm_type = HDA_PCM_TYPE_AUDIO; | ||
508 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = | ||
509 | *spec->stream_analog_alt_playback; | ||
510 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = | ||
511 | spec->alt_dac_nid[0]; | ||
512 | } | ||
513 | |||
449 | return 0; | 514 | return 0; |
450 | } | 515 | } |
451 | 516 | ||
@@ -2015,6 +2080,7 @@ static int patch_ad1981(struct hda_codec *codec) | |||
2015 | enum { | 2080 | enum { |
2016 | AD1988_6STACK, | 2081 | AD1988_6STACK, |
2017 | AD1988_6STACK_DIG, | 2082 | AD1988_6STACK_DIG, |
2083 | AD1988_6STACK_DIG_FP, | ||
2018 | AD1988_3STACK, | 2084 | AD1988_3STACK, |
2019 | AD1988_3STACK_DIG, | 2085 | AD1988_3STACK_DIG, |
2020 | AD1988_LAPTOP, | 2086 | AD1988_LAPTOP, |
@@ -2047,6 +2113,10 @@ static hda_nid_t ad1988_6stack_dac_nids_rev2[4] = { | |||
2047 | 0x04, 0x05, 0x0a, 0x06 | 2113 | 0x04, 0x05, 0x0a, 0x06 |
2048 | }; | 2114 | }; |
2049 | 2115 | ||
2116 | static hda_nid_t ad1988_alt_dac_nid[1] = { | ||
2117 | 0x03 | ||
2118 | }; | ||
2119 | |||
2050 | static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = { | 2120 | static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = { |
2051 | 0x04, 0x0a, 0x06 | 2121 | 0x04, 0x0a, 0x06 |
2052 | }; | 2122 | }; |
@@ -2166,6 +2236,35 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = { | |||
2166 | { } /* end */ | 2236 | { } /* end */ |
2167 | }; | 2237 | }; |
2168 | 2238 | ||
2239 | static struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = { | ||
2240 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
2241 | |||
2242 | HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), | ||
2243 | HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT), | ||
2244 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT), | ||
2245 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT), | ||
2246 | HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT), | ||
2247 | HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), | ||
2248 | HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), | ||
2249 | |||
2250 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), | ||
2251 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), | ||
2252 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT), | ||
2253 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT), | ||
2254 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), | ||
2255 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), | ||
2256 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), | ||
2257 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), | ||
2258 | |||
2259 | HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
2260 | HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
2261 | |||
2262 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), | ||
2263 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), | ||
2264 | |||
2265 | { } /* end */ | ||
2266 | }; | ||
2267 | |||
2169 | /* 3-stack mode */ | 2268 | /* 3-stack mode */ |
2170 | static struct snd_kcontrol_new ad1988_3stack_mixers1[] = { | 2269 | static struct snd_kcontrol_new ad1988_3stack_mixers1[] = { |
2171 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | 2270 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), |
@@ -2445,6 +2544,68 @@ static struct hda_verb ad1988_6stack_init_verbs[] = { | |||
2445 | { } | 2544 | { } |
2446 | }; | 2545 | }; |
2447 | 2546 | ||
2547 | static struct hda_verb ad1988_6stack_fp_init_verbs[] = { | ||
2548 | /* Front, Surround, CLFE, side DAC; unmute as default */ | ||
2549 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2550 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2551 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2552 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2553 | /* Headphone; unmute as default */ | ||
2554 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2555 | /* Port-A front headphon path */ | ||
2556 | {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ | ||
2557 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2558 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2559 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2560 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
2561 | /* Port-D line-out path */ | ||
2562 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2563 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2564 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2565 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2566 | /* Port-F surround path */ | ||
2567 | {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2568 | {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2569 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2570 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2571 | /* Port-G CLFE path */ | ||
2572 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2573 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2574 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2575 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2576 | /* Port-H side path */ | ||
2577 | {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2578 | {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2579 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2580 | {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2581 | /* Mono out path */ | ||
2582 | {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ | ||
2583 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2584 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2585 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2586 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ | ||
2587 | /* Port-B front mic-in path */ | ||
2588 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
2589 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
2590 | {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2591 | /* Port-C line-in path */ | ||
2592 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
2593 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
2594 | {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2595 | {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2596 | /* Port-E mic-in path */ | ||
2597 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
2598 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
2599 | {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2600 | {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2601 | /* Analog CD Input */ | ||
2602 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
2603 | /* Analog Mix output amp */ | ||
2604 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ | ||
2605 | |||
2606 | { } | ||
2607 | }; | ||
2608 | |||
2448 | static struct hda_verb ad1988_capture_init_verbs[] = { | 2609 | static struct hda_verb ad1988_capture_init_verbs[] = { |
2449 | /* mute analog mix */ | 2610 | /* mute analog mix */ |
2450 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | 2611 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
@@ -3074,13 +3235,13 @@ static int ad1988_auto_init(struct hda_codec *codec) | |||
3074 | return 0; | 3235 | return 0; |
3075 | } | 3236 | } |
3076 | 3237 | ||
3077 | |||
3078 | /* | 3238 | /* |
3079 | */ | 3239 | */ |
3080 | 3240 | ||
3081 | static const char *ad1988_models[AD1988_MODEL_LAST] = { | 3241 | static const char *ad1988_models[AD1988_MODEL_LAST] = { |
3082 | [AD1988_6STACK] = "6stack", | 3242 | [AD1988_6STACK] = "6stack", |
3083 | [AD1988_6STACK_DIG] = "6stack-dig", | 3243 | [AD1988_6STACK_DIG] = "6stack-dig", |
3244 | [AD1988_6STACK_DIG_FP] = "6stack-dig-fp", | ||
3084 | [AD1988_3STACK] = "3stack", | 3245 | [AD1988_3STACK] = "3stack", |
3085 | [AD1988_3STACK_DIG] = "3stack-dig", | 3246 | [AD1988_3STACK_DIG] = "3stack-dig", |
3086 | [AD1988_LAPTOP] = "laptop", | 3247 | [AD1988_LAPTOP] = "laptop", |
@@ -3140,6 +3301,7 @@ static int patch_ad1988(struct hda_codec *codec) | |||
3140 | switch (board_config) { | 3301 | switch (board_config) { |
3141 | case AD1988_6STACK: | 3302 | case AD1988_6STACK: |
3142 | case AD1988_6STACK_DIG: | 3303 | case AD1988_6STACK_DIG: |
3304 | case AD1988_6STACK_DIG_FP: | ||
3143 | spec->multiout.max_channels = 8; | 3305 | spec->multiout.max_channels = 8; |
3144 | spec->multiout.num_dacs = 4; | 3306 | spec->multiout.num_dacs = 4; |
3145 | if (is_rev2(codec)) | 3307 | if (is_rev2(codec)) |
@@ -3152,10 +3314,22 @@ static int patch_ad1988(struct hda_codec *codec) | |||
3152 | spec->mixers[0] = ad1988_6stack_mixers1_rev2; | 3314 | spec->mixers[0] = ad1988_6stack_mixers1_rev2; |
3153 | else | 3315 | else |
3154 | spec->mixers[0] = ad1988_6stack_mixers1; | 3316 | spec->mixers[0] = ad1988_6stack_mixers1; |
3155 | spec->mixers[1] = ad1988_6stack_mixers2; | 3317 | if (board_config == AD1988_6STACK_DIG_FP) { |
3318 | spec->mixers[1] = ad1988_6stack_fp_mixers; | ||
3319 | spec->slave_vols = ad1988_6stack_fp_slave_vols; | ||
3320 | spec->slave_sws = ad1988_6stack_fp_slave_sws; | ||
3321 | spec->alt_dac_nid = ad1988_alt_dac_nid; | ||
3322 | spec->stream_analog_alt_playback = | ||
3323 | &ad198x_pcm_analog_alt_playback; | ||
3324 | } else | ||
3325 | spec->mixers[1] = ad1988_6stack_mixers2; | ||
3156 | spec->num_init_verbs = 1; | 3326 | spec->num_init_verbs = 1; |
3157 | spec->init_verbs[0] = ad1988_6stack_init_verbs; | 3327 | if (board_config == AD1988_6STACK_DIG_FP) |
3158 | if (board_config == AD1988_6STACK_DIG) { | 3328 | spec->init_verbs[0] = ad1988_6stack_fp_init_verbs; |
3329 | else | ||
3330 | spec->init_verbs[0] = ad1988_6stack_init_verbs; | ||
3331 | if ((board_config == AD1988_6STACK_DIG) || | ||
3332 | (board_config == AD1988_6STACK_DIG_FP)) { | ||
3159 | spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; | 3333 | spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; |
3160 | spec->dig_in_nid = AD1988_SPDIF_IN; | 3334 | spec->dig_in_nid = AD1988_SPDIF_IN; |
3161 | } | 3335 | } |