diff options
| author | Raymond Yau <superquad.vortex2@gmail.com> | 2011-01-17 11:19:03 +0100 | 
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2011-01-18 07:43:05 +0100 | 
| commit | c66ddf32dda0d5bcf9db7b4cc42ef5da7baadd3e (patch) | |
| tree | 9072aa7a0f83c35358235e136ee69f8d5fe25503 /sound/pci/hda/patch_analog.c | |
| parent | 4fe2ca14678174d9df254ae3ba2b79bacc19e2ee (diff) | |
| download | olio-linux-3.10-c66ddf32dda0d5bcf9db7b4cc42ef5da7baadd3e.tar.xz olio-linux-3.10-c66ddf32dda0d5bcf9db7b4cc42ef5da7baadd3e.zip  | |
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>
Diffstat (limited to 'sound/pci/hda/patch_analog.c')
| -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 46780670162..34ee1169f2e 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -46,6 +46,9 @@ struct ad198x_spec {  	unsigned int cur_eapd;  	unsigned int need_dac_fix; +	hda_nid_t *alt_dac_nid; +	struct hda_pcm_stream *stream_analog_alt_playback; +  	/* capture */  	unsigned int num_adc_nids;  	hda_nid_t *adc_nids; @@ -156,6 +159,25 @@ static const char *ad_slave_sws[] = {  	NULL  }; +static const char *ad1988_6stack_fp_slave_vols[] = { +	"Front Playback Volume", +	"Surround Playback Volume", +	"Center Playback Volume", +	"LFE Playback Volume", +	"Side Playback Volume", +	"IEC958 Playback Volume", +	NULL +}; + +static const char *ad1988_6stack_fp_slave_sws[] = { +	"Front Playback Switch", +	"Surround Playback Switch", +	"Center Playback Switch", +	"LFE Playback Switch", +	"Side Playback Switch", +	"IEC958 Playback Switch", +	NULL +};  static void ad198x_free_kctls(struct hda_codec *codec);  #ifdef CONFIG_SND_HDA_INPUT_BEEP @@ -309,6 +331,38 @@ static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,  	return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);  } +static int ad198x_alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo, +				struct hda_codec *codec, +				unsigned int stream_tag, +				unsigned int format, +				struct snd_pcm_substream *substream) +{ +	struct ad198x_spec *spec = codec->spec; +	snd_hda_codec_setup_stream(codec, spec->alt_dac_nid[0], stream_tag, +					0, format); +	return 0; +} + +static int ad198x_alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, +				struct hda_codec *codec, +				struct snd_pcm_substream *substream) +{ +	struct ad198x_spec *spec = codec->spec; +	snd_hda_codec_cleanup_stream(codec, spec->alt_dac_nid[0]); +	return 0; +} + +static struct hda_pcm_stream ad198x_pcm_analog_alt_playback = { +	.substreams = 1, +	.channels_min = 2, +	.channels_max = 2, +	/* NID is set in ad198x_build_pcms */ +	.ops = { +		.prepare = ad198x_alt_playback_pcm_prepare, +		.cleanup = ad198x_alt_playback_pcm_cleanup +	}, +}; +  /*   * Digital out   */ @@ -446,6 +500,17 @@ static int ad198x_build_pcms(struct hda_codec *codec)  		}  	} +	if (spec->alt_dac_nid && spec->stream_analog_alt_playback) { +		codec->num_pcms++; +		info = spec->pcm_rec + 2; +		info->name = "AD198x Headphone"; +		info->pcm_type = HDA_PCM_TYPE_AUDIO; +		info->stream[SNDRV_PCM_STREAM_PLAYBACK] = +			*spec->stream_analog_alt_playback; +		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = +			spec->alt_dac_nid[0]; +	} +  	return 0;  } @@ -2015,6 +2080,7 @@ static int patch_ad1981(struct hda_codec *codec)  enum {  	AD1988_6STACK,  	AD1988_6STACK_DIG, +	AD1988_6STACK_DIG_FP,  	AD1988_3STACK,  	AD1988_3STACK_DIG,  	AD1988_LAPTOP, @@ -2047,6 +2113,10 @@ static hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {  	0x04, 0x05, 0x0a, 0x06  }; +static hda_nid_t ad1988_alt_dac_nid[1] = { +	0x03 +}; +  static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {  	0x04, 0x0a, 0x06  }; @@ -2166,6 +2236,35 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {  	{ } /* end */  }; +static struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = { +	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + +	HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), +	HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT), +	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT), +	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT), +	HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT), +	HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), +	HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), + +	HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), +	HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), +	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT), +	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT), +	HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), +	HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), +	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), +	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), + +	HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), +	HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), + +	HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), +	HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), + +	{ } /* end */ +}; +  /* 3-stack mode */  static struct snd_kcontrol_new ad1988_3stack_mixers1[] = {  	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), @@ -2445,6 +2544,68 @@ static struct hda_verb ad1988_6stack_init_verbs[] = {  	{ }  }; +static struct hda_verb ad1988_6stack_fp_init_verbs[] = { +	/* Front, Surround, CLFE, side DAC; unmute as default */ +	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, +	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, +	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, +	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, +	/* Headphone; unmute as default */ +	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, +	/* Port-A front headphon path */ +	{0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ +	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, +	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, +	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, +	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, +	/* Port-D line-out path */ +	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, +	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, +	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, +	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, +	/* Port-F surround path */ +	{0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, +	{0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, +	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, +	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, +	/* Port-G CLFE path */ +	{0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, +	{0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, +	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, +	{0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, +	/* Port-H side path */ +	{0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, +	{0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, +	{0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, +	{0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, +	/* Mono out path */ +	{0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ +	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, +	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, +	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, +	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ +	/* Port-B front mic-in path */ +	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, +	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, +	{0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, +	/* Port-C line-in path */ +	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, +	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +	{0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, +	{0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, +	/* Port-E mic-in path */ +	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, +	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, +	{0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, +	{0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, +	/* Analog CD Input */ +	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +	/* Analog Mix output amp */ +	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ + +	{ } +}; +  static struct hda_verb ad1988_capture_init_verbs[] = {  	/* mute analog mix */  	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -3074,13 +3235,13 @@ static int ad1988_auto_init(struct hda_codec *codec)  	return 0;  } -  /*   */  static const char *ad1988_models[AD1988_MODEL_LAST] = {  	[AD1988_6STACK]		= "6stack",  	[AD1988_6STACK_DIG]	= "6stack-dig", +	[AD1988_6STACK_DIG_FP]	= "6stack-dig-fp",  	[AD1988_3STACK]		= "3stack",  	[AD1988_3STACK_DIG]	= "3stack-dig",  	[AD1988_LAPTOP]		= "laptop", @@ -3140,6 +3301,7 @@ static int patch_ad1988(struct hda_codec *codec)  	switch (board_config) {  	case AD1988_6STACK:  	case AD1988_6STACK_DIG: +	case AD1988_6STACK_DIG_FP:  		spec->multiout.max_channels = 8;  		spec->multiout.num_dacs = 4;  		if (is_rev2(codec)) @@ -3152,10 +3314,22 @@ static int patch_ad1988(struct hda_codec *codec)  			spec->mixers[0] = ad1988_6stack_mixers1_rev2;  		else  			spec->mixers[0] = ad1988_6stack_mixers1; -		spec->mixers[1] = ad1988_6stack_mixers2; +		if (board_config == AD1988_6STACK_DIG_FP) { +			spec->mixers[1] = ad1988_6stack_fp_mixers; +			spec->slave_vols = ad1988_6stack_fp_slave_vols; +			spec->slave_sws = ad1988_6stack_fp_slave_sws; +			spec->alt_dac_nid = ad1988_alt_dac_nid; +			spec->stream_analog_alt_playback = +				&ad198x_pcm_analog_alt_playback; +		} else +			spec->mixers[1] = ad1988_6stack_mixers2;  		spec->num_init_verbs = 1; -		spec->init_verbs[0] = ad1988_6stack_init_verbs; -		if (board_config == AD1988_6STACK_DIG) { +		if (board_config == AD1988_6STACK_DIG_FP) +			spec->init_verbs[0] = ad1988_6stack_fp_init_verbs; +		else +			spec->init_verbs[0] = ad1988_6stack_init_verbs; +		if ((board_config == AD1988_6STACK_DIG) || +			(board_config == AD1988_6STACK_DIG_FP)) {  			spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;  			spec->dig_in_nid = AD1988_SPDIF_IN;  		}  |