From 302e9c5af4fb3ea258917ee6a32e9e45f578b231 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 5 Jul 2006 17:39:49 +0200 Subject: [ALSA] HDA codec & CA0106 - add/fix TLV support Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_analog.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'sound/pci/hda/patch_analog.c') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 6823f2bc10b..54506d4e57d 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -452,6 +452,19 @@ static int ad1986a_pcm_amp_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl return change; } +static int ad1986a_pcm_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *_tlv) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ad198x_spec *ad = codec->spec; + + mutex_lock(&ad->amp_mutex); + snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, _tlv); + mutex_unlock(&ad->amp_mutex); + return 0; +} + + #define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_switch_info static int ad1986a_pcm_amp_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -488,9 +501,13 @@ static struct snd_kcontrol_new ad1986a_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Volume", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, .info = ad1986a_pcm_amp_vol_info, .get = ad1986a_pcm_amp_vol_get, .put = ad1986a_pcm_amp_vol_put, + .tlv.c = ad1986a_pcm_amp_tlv, .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) }, { -- cgit v1.2.3-70-g09d2 From 0a197f005a27766f5c9e0d960e7650748ec1ee4f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Jul 2006 14:51:14 +0200 Subject: [ALSA] Add model entry for Samsung X10 laptop Added the proper model entry (laptop-eapd) for Samsung X10-T2300 Culesa laptop with AD1986A codec. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_analog.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/pci/hda/patch_analog.c') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 54506d4e57d..e547442e6fe 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -820,6 +820,8 @@ static struct hda_board_config ad1986a_cfg_tbl[] = { .config = AD1986A_LAPTOP_EAPD }, /* Samsung X60 Chane */ { .pci_subvendor = 0x144d, .pci_subdevice = 0xc024, .config = AD1986A_LAPTOP_EAPD }, /* Samsung R65-T2300 Charis */ + { .pci_subvendor = 0x144d, .pci_subdevice = 0xc026, + .config = AD1986A_LAPTOP_EAPD }, /* Samsung X10-T2300 Culesa */ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1153, .config = AD1986A_LAPTOP_EAPD }, /* ASUS M9 */ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1213, -- cgit v1.2.3-70-g09d2 From 827a56ea3d9c3d5f80c5520ba9d487f9b7069238 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Jul 2006 14:51:16 +0200 Subject: [ALSA] Added model for ASUS M2NPV-VM mobo Added the proper model (3stack) for ASUS M2NPV-VM mobo with AD1986A codec. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_analog.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/pci/hda/patch_analog.c') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index e547442e6fe..8955397cca6 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -808,6 +808,8 @@ static struct hda_board_config ad1986a_cfg_tbl[] = { .config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */ { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b3, .config = AD1986A_3STACK }, /* ASUS P5RD2-VM / P5GPL-X SE */ + { .pci_subvendor = 0x1043, .pci_subdevice = 0x81cb, + .config = AD1986A_3STACK }, /* ASUS M2NPV-VM */ { .modelname = "laptop", .config = AD1986A_LAPTOP }, { .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e, .config = AD1986A_LAPTOP }, /* FSC V2060 */ -- cgit v1.2.3-70-g09d2 From 4e195a7b78618c89b06547f3140e67a69ec23272 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Jul 2006 14:47:34 +0200 Subject: [ALSA] Fix noisy output with shared channel mode with hd-audio - Fix the wrong initialization of num_dacs when changing the channel mode between 2 and multi-channel modes. It must be evaluated after calling snd_hda_ch_mode_put() - Added the similar check of num_dacs fix in Realtek code. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_analog.c | 8 +++++--- sound/pci/hda/patch_realtek.c | 27 ++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) (limited to 'sound/pci/hda/patch_analog.c') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 8955397cca6..077f1ce01ee 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -1647,10 +1647,12 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ad198x_spec *spec = codec->spec; - if (spec->need_dac_fix) + int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, + spec->num_channel_mode, + &spec->multiout.max_channels); + if (! err && spec->need_dac_fix) spec->multiout.num_dacs = spec->multiout.max_channels / 2; - return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, &spec->multiout.max_channels); + return err; } /* 6-stack mode */ diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 378e5f111e3..991f1079116 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -155,6 +155,7 @@ struct alc_spec { /* channel model */ const struct hda_channel_mode *channel_mode; int num_channel_mode; + int need_dac_fix; /* PCM information */ struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ @@ -192,6 +193,7 @@ struct alc_config_preset { hda_nid_t dig_in_nid; unsigned int num_channel_mode; const struct hda_channel_mode *channel_mode; + int need_dac_fix; unsigned int num_mux_defs; const struct hda_input_mux *input_mux; void (*unsol_event)(struct hda_codec *, unsigned int); @@ -264,9 +266,12 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - &spec->multiout.max_channels); + int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, + spec->num_channel_mode, + &spec->multiout.max_channels); + if (! err && spec->need_dac_fix) + spec->multiout.num_dacs = spec->multiout.max_channels / 2; + return err; } /* @@ -546,6 +551,7 @@ static void setup_preset(struct alc_spec *spec, spec->channel_mode = preset->channel_mode; spec->num_channel_mode = preset->num_channel_mode; + spec->need_dac_fix = preset->need_dac_fix; spec->multiout.max_channels = spec->channel_mode[0].channels; @@ -2278,6 +2284,7 @@ static struct alc_config_preset alc880_presets[] = { .dac_nids = alc880_dac_nids, .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, .input_mux = &alc880_capture_source, }, [ALC880_3ST_DIG] = { @@ -2288,6 +2295,7 @@ static struct alc_config_preset alc880_presets[] = { .dig_out_nid = ALC880_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, .input_mux = &alc880_capture_source, }, [ALC880_TCL_S700] = { @@ -2380,6 +2388,7 @@ static struct alc_config_preset alc880_presets[] = { .dac_nids = alc880_asus_dac_nids, .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, .input_mux = &alc880_capture_source, }, [ALC880_ASUS_DIG] = { @@ -2391,6 +2400,7 @@ static struct alc_config_preset alc880_presets[] = { .dig_out_nid = ALC880_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, .input_mux = &alc880_capture_source, }, [ALC880_ASUS_DIG2] = { @@ -2402,6 +2412,7 @@ static struct alc_config_preset alc880_presets[] = { .dig_out_nid = ALC880_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, .input_mux = &alc880_capture_source, }, [ALC880_ASUS_W1V] = { @@ -2413,6 +2424,7 @@ static struct alc_config_preset alc880_presets[] = { .dig_out_nid = ALC880_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, .input_mux = &alc880_capture_source, }, [ALC880_UNIWILL_DIG] = { @@ -2423,6 +2435,7 @@ static struct alc_config_preset alc880_presets[] = { .dig_out_nid = ALC880_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, .input_mux = &alc880_capture_source, }, [ALC880_CLEVO] = { @@ -2434,6 +2447,7 @@ static struct alc_config_preset alc880_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, .input_mux = &alc880_capture_source, }, [ALC880_LG] = { @@ -2445,6 +2459,7 @@ static struct alc_config_preset alc880_presets[] = { .dig_out_nid = ALC880_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes), .channel_mode = alc880_lg_ch_modes, + .need_dac_fix = 1, .input_mux = &alc880_lg_capture_source, .unsol_event = alc880_lg_unsol_event, .init_hook = alc880_lg_automute, @@ -4437,6 +4452,7 @@ static struct alc_config_preset alc882_presets[] = { .dig_in_nid = ALC882_DIGIN_NID, .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), .channel_mode = alc882_ch_modes, + .need_dac_fix = 1, .input_mux = &alc882_capture_source, }, [ALC882_6ST_DIG] = { @@ -5075,6 +5091,7 @@ static struct alc_config_preset alc883_presets[] = { .dig_in_nid = ALC883_DIGIN_NID, .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, .input_mux = &alc883_capture_source, }, [ALC883_3ST_6ch] = { @@ -5086,6 +5103,7 @@ static struct alc_config_preset alc883_presets[] = { .adc_nids = alc883_adc_nids, .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, .input_mux = &alc883_capture_source, }, [ALC883_6ST_DIG] = { @@ -6554,6 +6572,7 @@ static struct alc_config_preset alc861_presets[] = { .dac_nids = alc861_dac_nids, .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), .channel_mode = alc861_threestack_modes, + .need_dac_fix = 1, .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), .adc_nids = alc861_adc_nids, .input_mux = &alc861_capture_source, @@ -6566,6 +6585,7 @@ static struct alc_config_preset alc861_presets[] = { .dig_out_nid = ALC861_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), .channel_mode = alc861_threestack_modes, + .need_dac_fix = 1, .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), .adc_nids = alc861_adc_nids, .input_mux = &alc861_capture_source, @@ -6589,6 +6609,7 @@ static struct alc_config_preset alc861_presets[] = { .dac_nids = alc660_dac_nids, .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), .channel_mode = alc861_threestack_modes, + .need_dac_fix = 1, .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), .adc_nids = alc861_adc_nids, .input_mux = &alc861_capture_source, -- cgit v1.2.3-70-g09d2 From 7cf0a95310f21f3c986288a483801b1d5694dee1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 17 Aug 2006 16:23:07 +0200 Subject: [ALSA] Fix compile errors with older gcc Fixed compile errors with older gcc for initialization of a union. sound/pci/ca0106/ca0106_mixer.c: At top level: sound/pci/ca0106/ca0106_mixer.c:499: unknown field 'p' specified in initializer sound/pci/ca0106/ca0106_mixer.c:499: warning: missing braces around initializer sound/pci/ca0106/ca0106_mixer.c:499: warning: (near initialization for 'snd_ca0106_volume_ctls[0].tlv') Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/ca0106/ca0106_mixer.c | 4 ++-- sound/pci/emu10k1/p16v.c | 2 +- sound/pci/hda/hda_local.h | 2 +- sound/pci/hda/patch_analog.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'sound/pci/hda/patch_analog.c') diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 6d64438cecc..9855f528ea7 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -478,7 +478,7 @@ static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol, .info = snd_ca0106_volume_info, \ .get = snd_ca0106_volume_get, \ .put = snd_ca0106_volume_put, \ - .tlv.p = snd_ca0106_db_scale1, \ + .tlv = { .p = snd_ca0106_db_scale1 }, \ .private_value = ((chid) << 8) | (reg) \ } @@ -490,7 +490,7 @@ static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol, .info = snd_ca0106_i2c_volume_info, \ .get = snd_ca0106_i2c_volume_get, \ .put = snd_ca0106_i2c_volume_put, \ - .tlv.p = snd_ca0106_db_scale2, \ + .tlv = { .p = snd_ca0106_db_scale2 }, \ .private_value = chid \ } diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 1e44714b862..4e0f95438f4 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -794,7 +794,7 @@ static DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1); .info = snd_p16v_volume_info, \ .get = snd_p16v_volume_get, \ .put = snd_p16v_volume_put, \ - .tlv.p = snd_p16v_db_scale1, \ + .tlv = { .p = snd_p16v_db_scale1 }, \ .private_value = ((xreg) | ((xhl) << 8)) \ } diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 0f0ae685a9c..ff24266fe35 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -36,7 +36,7 @@ .info = snd_hda_mixer_amp_volume_info, \ .get = snd_hda_mixer_amp_volume_get, \ .put = snd_hda_mixer_amp_volume_put, \ - .tlv.c = snd_hda_mixer_amp_tlv, \ + .tlv = { .c = snd_hda_mixer_amp_tlv }, \ .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) } /* stereo volume with index */ #define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 077f1ce01ee..043256c67d1 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -507,7 +507,7 @@ static struct snd_kcontrol_new ad1986a_mixers[] = { .info = ad1986a_pcm_amp_vol_info, .get = ad1986a_pcm_amp_vol_get, .put = ad1986a_pcm_amp_vol_put, - .tlv.c = ad1986a_pcm_amp_tlv, + .tlv = { .c = ad1986a_pcm_amp_tlv }, .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) }, { -- cgit v1.2.3-70-g09d2 From c256652466127872f1b2e510431dc25524ba40ba Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 17 Aug 2006 18:21:36 +0200 Subject: [ALSA] Add missing TLV callbacks for HD-audio codecs Added missing TLV callbacks for HD-audio codec supports. Also cleaned up the tlv callback for ad1986a (no mutex is needed there). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_analog.c | 16 ++-------------- sound/pci/hda/patch_realtek.c | 1 + sound/pci/hda/patch_sigmatel.c | 1 + 3 files changed, 4 insertions(+), 14 deletions(-) (limited to 'sound/pci/hda/patch_analog.c') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 043256c67d1..71abc2aa61a 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -452,19 +452,6 @@ static int ad1986a_pcm_amp_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl return change; } -static int ad1986a_pcm_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, - unsigned int size, unsigned int __user *_tlv) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *ad = codec->spec; - - mutex_lock(&ad->amp_mutex); - snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, _tlv); - mutex_unlock(&ad->amp_mutex); - return 0; -} - - #define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_switch_info static int ad1986a_pcm_amp_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -507,7 +494,7 @@ static struct snd_kcontrol_new ad1986a_mixers[] = { .info = ad1986a_pcm_amp_vol_info, .get = ad1986a_pcm_amp_vol_get, .put = ad1986a_pcm_amp_vol_put, - .tlv = { .c = ad1986a_pcm_amp_tlv }, + .tlv = { .c = snd_hda_mixer_amp_tlv }, .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) }, { @@ -654,6 +641,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { .info = snd_hda_mixer_amp_volume_info, .get = snd_hda_mixer_amp_volume_get, .put = ad1986a_laptop_master_vol_put, + .tlv = { .c = snd_hda_mixer_amp_tlv }, .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), }, { diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f857e963ff4..79d361260b2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5540,6 +5540,7 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { .info = snd_hda_mixer_amp_volume_info, .get = snd_hda_mixer_amp_volume_get, .put = alc262_fujitsu_master_vol_put, + .tlv = { .c = snd_hda_mixer_amp_tlv }, .private_value = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), }, { diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 7eaf755b014..887b52e96ec 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1528,6 +1528,7 @@ static struct snd_kcontrol_new vaio_mixer[] = { .info = snd_hda_mixer_amp_volume_info, .get = snd_hda_mixer_amp_volume_get, .put = vaio_master_vol_put, + .tlv = { .c = snd_hda_mixer_amp_tlv }, .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), }, { -- cgit v1.2.3-70-g09d2 From eb06ed8f4c2440558ebf465e8baeac6367d90201 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 20 Sep 2006 17:10:27 +0200 Subject: [ALSA] hda-codec - Support multiple headphone pins Some machines have multiple headpohne pins (usually on the lpatop and on the docking station) while the current hda-codec driver assumes a single headphone pin. Now it supports multiple hp pins (at least for detection). The sigmatel 92xx code supports this new multiple hp pins. It detects all hp pins for auto-muting, too. Also, the driver checks speaker pins in addition. In some cases, all line-out, speaker and hp-pins coexist. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 23 +++-- sound/pci/hda/hda_local.h | 3 +- sound/pci/hda/patch_analog.c | 4 +- sound/pci/hda/patch_realtek.c | 18 ++-- sound/pci/hda/patch_sigmatel.c | 202 +++++++++++++++++++++++++++-------------- 5 files changed, 164 insertions(+), 86 deletions(-) (limited to 'sound/pci/hda/patch_analog.c') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 8b2c080c85a..07360996caa 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2012,7 +2012,7 @@ static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list) * in the order of front, rear, CLFE, side, ... * * If more extra outputs (speaker and headphone) are found, the pins are - * assisnged to hp_pin and speaker_pins[], respectively. If no line-out jack + * assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack * is detected, one of speaker of HP pins is assigned as the primary * output, i.e. to line_out_pins[0]. So, line_outs is always positive * if any analog output exists. @@ -2074,7 +2074,10 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c cfg->speaker_outs++; break; case AC_JACK_HP_OUT: - cfg->hp_pin = nid; + if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) + continue; + cfg->hp_pins[cfg->hp_outs] = nid; + cfg->hp_outs++; break; case AC_JACK_MIC_IN: if (loc == AC_JACK_LOC_FRONT) @@ -2147,8 +2150,10 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c cfg->speaker_outs, cfg->speaker_pins[0], cfg->speaker_pins[1], cfg->speaker_pins[2], cfg->speaker_pins[3], cfg->speaker_pins[4]); - snd_printd(" hp=0x%x, dig_out=0x%x, din_in=0x%x\n", - cfg->hp_pin, cfg->dig_out_pin, cfg->dig_in_pin); + snd_printd(" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", + cfg->hp_outs, cfg->hp_pins[0], + cfg->hp_pins[1], cfg->hp_pins[2], + cfg->hp_pins[3], cfg->hp_pins[4]); snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x," " cd=0x%x, aux=0x%x\n", cfg->input_pins[AUTO_PIN_MIC], @@ -2169,10 +2174,12 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c sizeof(cfg->speaker_pins)); cfg->speaker_outs = 0; memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); - } else if (cfg->hp_pin) { - cfg->line_outs = 1; - cfg->line_out_pins[0] = cfg->hp_pin; - cfg->hp_pin = 0; + } else if (cfg->hp_outs) { + cfg->line_outs = cfg->hp_outs; + memcpy(cfg->line_out_pins, cfg->hp_pins, + sizeof(cfg->hp_pins)); + cfg->hp_outs = 0; + memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); } } diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index ff24266fe35..f9416c36396 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -229,7 +229,8 @@ struct auto_pin_cfg { hda_nid_t line_out_pins[5]; /* sorted in the order of Front/Surr/CLFE/Side */ int speaker_outs; hda_nid_t speaker_pins[5]; - hda_nid_t hp_pin; + int hp_outs; + hda_nid_t hp_pins[5]; hda_nid_t input_pins[AUTO_PIN_LAST]; hda_nid_t dig_out_pin; hda_nid_t dig_in_pin; diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 71abc2aa61a..511df07fa2a 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -2471,7 +2471,7 @@ static void ad1988_auto_init_extra_out(struct hda_codec *codec) pin = spec->autocfg.speaker_pins[0]; if (pin) /* connect to front */ ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); - pin = spec->autocfg.hp_pin; + pin = spec->autocfg.hp_pins[0]; if (pin) /* connect to front */ ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); } @@ -2523,7 +2523,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) (err = ad1988_auto_create_extra_out(codec, spec->autocfg.speaker_pins[0], "Speaker")) < 0 || - (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pin, + (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], "Headphone")) < 0 || (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) return err; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ba9e050e201..d08d2e399c8 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2753,7 +2753,7 @@ static void alc880_auto_init_extra_out(struct hda_codec *codec) pin = spec->autocfg.speaker_pins[0]; if (pin) /* connect to front */ alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); - pin = spec->autocfg.hp_pin; + pin = spec->autocfg.hp_pins[0]; if (pin) /* connect to front */ alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); } @@ -2794,7 +2794,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec) (err = alc880_auto_create_extra_out(spec, spec->autocfg.speaker_pins[0], "Speaker")) < 0 || - (err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pin, + (err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0], "Headphone")) < 0 || (err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) return err; @@ -3736,7 +3736,7 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec, return err; } - nid = cfg->hp_pin; + nid = cfg->hp_pins[0]; if (nid) { err = alc260_add_playback_controls(spec, nid, "Headphone"); if (err < 0) @@ -3806,7 +3806,7 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec) if (nid) alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); - nid = spec->autocfg.hp_pin; + nid = spec->autocfg.hp_pins[0]; if (nid) alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); } @@ -4526,7 +4526,7 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; hda_nid_t pin; - pin = spec->autocfg.hp_pin; + pin = spec->autocfg.hp_pins[0]; if (pin) /* connect to front */ alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); /* use dac 0 */ } @@ -5207,7 +5207,7 @@ static void alc883_auto_init_hp_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; hda_nid_t pin; - pin = spec->autocfg.hp_pin; + pin = spec->autocfg.hp_pins[0]; if (pin) /* connect to front */ /* use dac 0 */ alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); @@ -5630,7 +5630,7 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct return err; } } - nid = cfg->hp_pin; + nid = cfg->hp_pins[0]; if (nid) { /* spec->multiout.hp_nid = 2; */ if (nid == 0x16) { @@ -6630,7 +6630,7 @@ static void alc861_auto_init_hp_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; hda_nid_t pin; - pin = spec->autocfg.hp_pin; + pin = spec->autocfg.hp_pins[0]; if (pin) /* connect to front */ alc861_auto_set_output_and_unmute(codec, pin, PIN_HP, spec->multiout.dac_nids[0]); } @@ -6665,7 +6665,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec) if ((err = alc861_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 || (err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || - (err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pin)) < 0 || + (err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0])) < 0 || (err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) return err; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index bcbbe111ab9..7cc06426520 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1011,11 +1011,29 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, return 0; } +/* create volume control/switch for the given prefx type */ +static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs) +{ + char name[32]; + int err; + + sprintf(name, "%s Playback Volume", pfx); + err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", pfx); + err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); + if (err < 0) + return err; + return 0; +} + /* add playback controls from the parsed DAC table */ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, const struct auto_pin_cfg *cfg) { - char name[32]; static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; @@ -1030,26 +1048,15 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, if (i == 2) { /* Center/LFE */ - if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "Center Playback Volume", - HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) + err = create_controls(spec, "Center", nid, 1); + if (err < 0) return err; - if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "LFE Playback Volume", - HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) - return err; - if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "Center Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) - return err; - if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "LFE Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) + err = create_controls(spec, "LFE", nid, 2); + if (err < 0) return err; } else { - sprintf(name, "%s Playback Volume", chname[i]); - if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) - return err; - sprintf(name, "%s Playback Switch", chname[i]); - if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) + err = create_controls(spec, chname[i], nid, 3); + if (err < 0) return err; } } @@ -1065,39 +1072,85 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, return 0; } -/* add playback controls for HP output */ -static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin_cfg *cfg) +static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) { - struct sigmatel_spec *spec = codec->spec; - hda_nid_t pin = cfg->hp_pin; - hda_nid_t nid; - int i, err; - unsigned int wid_caps; + int i; - if (! pin) - return 0; + for (i = 0; i < spec->multiout.num_dacs; i++) { + if (spec->multiout.dac_nids[i] == nid) + return 1; + } + if (spec->multiout.hp_nid == nid) + return 1; + return 0; +} - wid_caps = get_wcaps(codec, pin); - if (wid_caps & AC_WCAP_UNSOL_CAP) - spec->hp_detect = 1; +static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid) +{ + if (!spec->multiout.hp_nid) + spec->multiout.hp_nid = nid; + else if (spec->multiout.num_dacs > 4) { + printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid); + return 1; + } else { + spec->multiout.dac_nids[spec->multiout.num_dacs] = nid; + spec->multiout.num_dacs++; + } + return 0; +} - nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff; - for (i = 0; i < cfg->line_outs; i++) { - if (! spec->multiout.dac_nids[i]) +/* add playback controls for Speaker and HP outputs */ +static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, + struct auto_pin_cfg *cfg) +{ + struct sigmatel_spec *spec = codec->spec; + hda_nid_t nid; + int i, old_num_dacs, err; + + old_num_dacs = spec->multiout.num_dacs; + for (i = 0; i < cfg->hp_outs; i++) { + unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]); + if (wid_caps & AC_WCAP_UNSOL_CAP) + spec->hp_detect = 1; + nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0, + AC_VERB_GET_CONNECT_LIST, 0) & 0xff; + if (check_in_dac_nids(spec, nid)) + nid = 0; + if (! nid) continue; - if (spec->multiout.dac_nids[i] == nid) - return 0; + add_spec_dacs(spec, nid); + } + for (i = 0; i < cfg->speaker_outs; i++) { + nid = snd_hda_codec_read(codec, cfg->speaker_pins[0], 0, + AC_VERB_GET_CONNECT_LIST, 0) & 0xff; + if (check_in_dac_nids(spec, nid)) + nid = 0; + if (check_in_dac_nids(spec, nid)) + nid = 0; + if (! nid) + continue; + add_spec_dacs(spec, nid); } - spec->multiout.hp_nid = nid; - - /* control HP volume/switch on the output mixer amp */ - if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "Headphone Playback Volume", - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) - return err; - if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "Headphone Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) - return err; + for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) { + static const char *pfxs[] = { + "Speaker", "External Speaker", "Speaker2", + }; + err = create_controls(spec, pfxs[i - old_num_dacs], + spec->multiout.dac_nids[i], 3); + if (err < 0) + return err; + } + if (spec->multiout.hp_nid) { + const char *pfx; + if (old_num_dacs == spec->multiout.num_dacs) + pfx = "Master"; + else + pfx = "Headphone"; + err = create_controls(spec, pfx, spec->multiout.hp_nid, 3); + if (err < 0) + return err; + } return 0; } @@ -1160,11 +1213,20 @@ static void stac92xx_auto_init_multi_out(struct hda_codec *codec) static void stac92xx_auto_init_hp_out(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - hda_nid_t pin; + int i; - pin = spec->autocfg.hp_pin; - if (pin) /* connect to front */ - stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); + for (i = 0; i < spec->autocfg.hp_outs; i++) { + hda_nid_t pin; + pin = spec->autocfg.hp_pins[i]; + if (pin) /* connect to front */ + stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); + } + for (i = 0; i < spec->autocfg.speaker_outs; i++) { + hda_nid_t pin; + pin = spec->autocfg.speaker_pins[i]; + if (pin) /* connect to front */ + stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN); + } } static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in) @@ -1210,7 +1272,7 @@ static int stac9200_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin_cfg *cfg) { struct sigmatel_spec *spec = codec->spec; - hda_nid_t pin = cfg->hp_pin; + hda_nid_t pin = cfg->hp_pins[0]; unsigned int wid_caps; if (! pin) @@ -1266,16 +1328,7 @@ static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec, } if (lfe_pin) { - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, - "LFE Playback Volume", - HDA_COMPOSE_AMP_VAL(lfe_pin, 1, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, - "LFE Playback Switch", - HDA_COMPOSE_AMP_VAL(lfe_pin, 1, 0, - HDA_OUTPUT)); + err = create_controls(spec, "LFE", lfe_pin, 1); if (err < 0) return err; } @@ -1363,9 +1416,11 @@ static int stac92xx_init(struct hda_codec *codec) /* set up pins */ if (spec->hp_detect) { /* Enable unsolicited responses on the HP widget */ - snd_hda_codec_write(codec, cfg->hp_pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - STAC_UNSOL_ENABLE); + for (i = 0; i < cfg->hp_outs; i++) + if (get_wcaps(codec, cfg->hp_pins[i]) & AC_WCAP_UNSOL_CAP) + snd_hda_codec_write(codec, cfg->hp_pins[i], 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + STAC_UNSOL_ENABLE); /* fake event to set up pins */ codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); /* enable the headphones by default. If/when unsol_event detection works, this will be ignored */ @@ -1447,21 +1502,36 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) if ((res >> 26) != STAC_HP_EVENT) return; - presence = snd_hda_codec_read(codec, cfg->hp_pin, 0, - AC_VERB_GET_PIN_SENSE, 0x00) >> 31; + presence = 0; + for (i = 0; i < cfg->hp_outs; i++) { + int p = snd_hda_codec_read(codec, cfg->hp_pins[i], 0, + AC_VERB_GET_PIN_SENSE, 0x00); + if (p & (1 << 31)) + presence++; + } if (presence) { /* disable lineouts, enable hp */ for (i = 0; i < cfg->line_outs; i++) stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], AC_PINCTL_OUT_EN); - stac92xx_set_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN); + for (i = 0; i < cfg->speaker_outs; i++) + stac92xx_reset_pinctl(codec, cfg->speaker_pins[i], + AC_PINCTL_OUT_EN); + for (i = 0; i < cfg->hp_outs; i++) + stac92xx_set_pinctl(codec, cfg->hp_pins[i], + AC_PINCTL_OUT_EN); } else { /* enable lineouts, disable hp */ for (i = 0; i < cfg->line_outs; i++) stac92xx_set_pinctl(codec, cfg->line_out_pins[i], AC_PINCTL_OUT_EN); - stac92xx_reset_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN); + for (i = 0; i < cfg->speaker_outs; i++) + stac92xx_set_pinctl(codec, cfg->speaker_pins[i], + AC_PINCTL_OUT_EN); + for (i = 0; i < cfg->hp_outs; i++) + stac92xx_reset_pinctl(codec, cfg->hp_pins[i], + AC_PINCTL_OUT_EN); } } -- cgit v1.2.3-70-g09d2