diff options
author | David S. Miller <davem@davemloft.net> | 2009-03-26 15:23:24 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-26 15:23:24 -0700 |
commit | 08abe18af1f78ee80c3c3a5ac47c3e0ae0beadf6 (patch) | |
tree | 2be39bf8942edca1bcec735145e144a682ca9cd3 /sound/pci/hda/patch_realtek.c | |
parent | f0de70f8bb56952f6e016a65a8a8d006918f5bf6 (diff) | |
parent | 0384e2959127a56d0640505d004d8dd92f9c29f5 (diff) |
Merge branch 'master' of /home/davem/src/GIT/linux-2.6/
Conflicts:
drivers/net/wimax/i2400m/usb-notif.c
Diffstat (limited to 'sound/pci/hda/patch_realtek.c')
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 1194 |
1 files changed, 797 insertions, 397 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6c26afcb826..82097790f6f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -30,6 +30,7 @@ #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_beep.h" #define ALC880_FRONT_EVENT 0x01 #define ALC880_DCVOL_EVENT 0x02 @@ -77,6 +78,7 @@ enum { ALC260_ACER, ALC260_WILL, ALC260_REPLACER_672V, + ALC260_FAVORIT100, #ifdef CONFIG_SND_DEBUG ALC260_TEST, #endif @@ -103,6 +105,7 @@ enum { ALC262_NEC, ALC262_TOSHIBA_S06, ALC262_TOSHIBA_RX1, + ALC262_TYAN, ALC262_AUTO, ALC262_MODEL_LAST /* last tag */ }; @@ -238,6 +241,13 @@ enum { ALC883_MODEL_LAST, }; +/* styles of capture selection */ +enum { + CAPT_MUX = 0, /* only mux based */ + CAPT_MIX, /* only mixer based */ + CAPT_1MUX_MIX, /* first mux and other mixers */ +}; + /* for GPIO Poll */ #define GPIO_MASK 0x03 @@ -246,6 +256,7 @@ struct alc_spec { struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ unsigned int num_mixers; struct snd_kcontrol_new *cap_mixer; /* capture mixer */ + unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ const struct hda_verb *init_verbs[5]; /* initialization verbs * don't forget NULL @@ -269,13 +280,15 @@ struct alc_spec { * dig_out_nid and hp_nid are optional */ hda_nid_t alt_dac_nid; + hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */ + int dig_out_type; /* capture */ unsigned int num_adc_nids; hda_nid_t *adc_nids; hda_nid_t *capsrc_nids; hda_nid_t dig_in_nid; /* digital-in NID; optional */ - unsigned char is_mix_capture; /* matrix-style capture (non-mux) */ + int capture_style; /* capture style (CAPT_*) */ /* capture source */ unsigned int num_mux_defs; @@ -293,7 +306,7 @@ struct alc_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; struct snd_array kctls; - struct hda_input_mux private_imux; + struct hda_input_mux private_imux[3]; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; /* hooks */ @@ -305,6 +318,9 @@ struct alc_spec { unsigned int jack_present: 1; unsigned int master_sw: 1; + /* other flags */ + unsigned int no_analog :1; /* digital I/O only */ + /* for virtual master */ hda_nid_t vmaster_nid; #ifdef CONFIG_SND_HDA_POWER_SAVE @@ -314,13 +330,6 @@ struct alc_spec { /* for PLL fix */ hda_nid_t pll_nid; unsigned int pll_coef_idx, pll_coef_bit; - -#ifdef SND_HDA_NEEDS_RESUME -#define ALC_MAX_PINS 16 - unsigned int num_pins; - hda_nid_t pin_nids[ALC_MAX_PINS]; - unsigned int pin_cfgs[ALC_MAX_PINS]; -#endif }; /* @@ -336,6 +345,7 @@ struct alc_config_preset { hda_nid_t *dac_nids; hda_nid_t dig_out_nid; /* optional */ hda_nid_t hp_nid; /* optional */ + hda_nid_t *slave_dig_outs; unsigned int num_adc_nids; hda_nid_t *adc_nids; hda_nid_t *capsrc_nids; @@ -392,7 +402,8 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; imux = &spec->input_mux[mux_idx]; - if (spec->is_mix_capture) { + if (spec->capture_style && + !(spec->capture_style == CAPT_1MUX_MIX && !adc_idx)) { /* Matrix-mixer style (e.g. ALC882) */ unsigned int *cur_val = &spec->cur_mux[adc_idx]; unsigned int i, idx; @@ -750,6 +761,24 @@ static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol, #endif /* CONFIG_SND_DEBUG */ /* + * set up the input pin config (depending on the given auto-pin type) + */ +static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid, + int auto_pin_type) +{ + unsigned int val = PIN_IN; + + if (auto_pin_type <= AUTO_PIN_FRONT_MIC) { + unsigned int pincap; + pincap = snd_hda_query_pin_caps(codec, nid); + pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; + if (pincap & AC_PINCAP_VREF_80) + val = PIN_VREF80; + } + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); +} + +/* */ static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix) { @@ -810,6 +839,7 @@ static void setup_preset(struct alc_spec *spec, spec->multiout.num_dacs = preset->num_dacs; spec->multiout.dac_nids = preset->dac_nids; spec->multiout.dig_out_nid = preset->dig_out_nid; + spec->multiout.slave_dig_outs = preset->slave_dig_outs; spec->multiout.hp_nid = preset->hp_nid; spec->num_mux_defs = preset->num_mux_defs; @@ -921,7 +951,7 @@ static void alc_mic_automute(struct hda_codec *codec) HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } #else -#define alc_mic_automute(codec) /* NOP */ +#define alc_mic_automute(codec) do {} while(0) /* NOP */ #endif /* disabled */ /* unsolicited event for HP jack sensing */ @@ -952,7 +982,7 @@ static void alc888_coef_init(struct hda_codec *codec) snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0); tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7); - if ((tmp & 0xf0) == 2) + if ((tmp & 0xf0) == 0x20) /* alc888S-VC */ snd_hda_codec_read(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, 0x830); @@ -991,8 +1021,7 @@ static void alc_subsystem_id(struct hda_codec *codec, nid = 0x1d; if (codec->vendor_id == 0x10ec0260) nid = 0x17; - ass = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); + ass = snd_hda_codec_get_pincfg(codec, nid); if (!(ass & 1) && !(ass & 0x100000)) return; if ((ass >> 30) != 1) /* no physical connection */ @@ -1166,16 +1195,8 @@ static void alc_fix_pincfg(struct hda_codec *codec, return; cfg = pinfix[quirk->value]; - for (; cfg->nid; cfg++) { - int i; - u32 val = cfg->val; - for (i = 0; i < 4; i++) { - snd_hda_codec_write(codec, cfg->nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i, - val & 0xff); - val >>= 8; - } - } + for (; cfg->nid; cfg++) + snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); } /* @@ -1375,8 +1396,6 @@ static struct snd_kcontrol_new alc888_base_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), { } /* end */ }; @@ -1483,8 +1502,6 @@ static struct snd_kcontrol_new alc880_three_stack_mixer[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -1578,8 +1595,7 @@ static int alc_cap_sw_put(struct snd_kcontrol *kcontrol, snd_hda_mixer_amp_switch_put); } -#define DEFINE_CAPMIX(num) \ -static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \ +#define _DEFINE_CAPMIX(num) \ { \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = "Capture Switch", \ @@ -1600,7 +1616,9 @@ static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \ .get = alc_cap_vol_get, \ .put = alc_cap_vol_put, \ .tlv = { .c = alc_cap_vol_tlv }, \ - }, \ + } + +#define _DEFINE_CAPSRC(num) \ { \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ /* .name = "Capture Source", */ \ @@ -1609,15 +1627,28 @@ static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \ .info = alc_mux_enum_info, \ .get = alc_mux_enum_get, \ .put = alc_mux_enum_put, \ - }, \ - { } /* end */ \ + } + +#define DEFINE_CAPMIX(num) \ +static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \ + _DEFINE_CAPMIX(num), \ + _DEFINE_CAPSRC(num), \ + { } /* end */ \ +} + +#define DEFINE_CAPMIX_NOSRC(num) \ +static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \ + _DEFINE_CAPMIX(num), \ + { } /* end */ \ } /* up to three ADCs */ DEFINE_CAPMIX(1); DEFINE_CAPMIX(2); DEFINE_CAPMIX(3); - +DEFINE_CAPMIX_NOSRC(1); +DEFINE_CAPMIX_NOSRC(2); +DEFINE_CAPMIX_NOSRC(3); /* * ALC880 5-stack model @@ -1706,8 +1737,6 @@ static struct snd_kcontrol_new alc880_six_stack_mixer[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -1884,13 +1913,6 @@ static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = { { } /* end */ }; -/* additional mixers to alc880_asus_mixer */ -static struct snd_kcontrol_new alc880_pcbeep_mixer[] = { - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - { } /* end */ -}; - /* TCL S700 */ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), @@ -1923,8 +1945,6 @@ static struct snd_kcontrol_new alc880_uniwill_mixer[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -1999,6 +2019,13 @@ static const char *alc_slave_sws[] = { static void alc_free_kctls(struct hda_codec *codec); +/* additional beep mixers; the actual parameters are overwritten at build */ +static struct snd_kcontrol_new alc_beep_mixer[] = { + HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT), + HDA_CODEC_MUTE("Beep Playback Switch", 0, 0, HDA_INPUT), + { } /* end */ +}; + static int alc_build_controls(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -2020,11 +2047,13 @@ static int alc_build_controls(struct hda_codec *codec) spec->multiout.dig_out_nid); if (err < 0) return err; - err = snd_hda_create_spdif_share_sw(codec, - &spec->multiout); - if (err < 0) - return err; - spec->multiout.share_spdif = 1; + if (!spec->no_analog) { + err = snd_hda_create_spdif_share_sw(codec, + &spec->multiout); + if (err < 0) + return err; + spec->multiout.share_spdif = 1; + } } if (spec->dig_in_nid) { err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); @@ -2032,8 +2061,24 @@ static int alc_build_controls(struct hda_codec *codec) return err; } + /* create beep controls if needed */ + if (spec->beep_amp) { + struct snd_kcontrol_new *knew; + for (knew = alc_beep_mixer; knew->name; knew++) { + struct snd_kcontrol *kctl; + kctl = snd_ctl_new1(knew, codec); + if (!kctl) + return -ENOMEM; + kctl->private_value = spec->beep_amp; + err = snd_hda_ctl_add(codec, kctl); + if (err < 0) + return err; + } + } + /* if we have no master control, let's create it */ - if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { + if (!spec->no_analog && + !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { unsigned int vmaster_tlv[4]; snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, HDA_OUTPUT, vmaster_tlv); @@ -2042,7 +2087,8 @@ static int alc_build_controls(struct hda_codec *codec) if (err < 0) return err; } - if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { + if (!spec->no_analog && + !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { err = snd_hda_add_vmaster(codec, "Master Playback Switch", NULL, alc_slave_sws); if (err < 0) @@ -2951,6 +2997,14 @@ static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, stream_tag, format, substream); } +static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); +} + static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) @@ -3034,7 +3088,8 @@ static struct hda_pcm_stream alc880_pcm_digital_playback = { .ops = { .open = alc880_dig_playback_pcm_open, .close = alc880_dig_playback_pcm_close, - .prepare = alc880_dig_playback_pcm_prepare + .prepare = alc880_dig_playback_pcm_prepare, + .cleanup = alc880_dig_playback_pcm_cleanup }, }; @@ -3061,6 +3116,9 @@ static int alc_build_pcms(struct hda_codec *codec) codec->num_pcms = 1; codec->pcm_info = info; + if (spec->no_analog) + goto skip_analog; + info->name = spec->stream_name_analog; if (spec->stream_analog_playback) { if (snd_BUG_ON(!spec->multiout.dac_nids)) @@ -3084,12 +3142,17 @@ static int alc_build_pcms(struct hda_codec *codec) } } + skip_analog: /* SPDIF for stream index #1 */ if (spec->multiout.dig_out_nid || spec->dig_in_nid) { codec->num_pcms = 2; + codec->slave_dig_outs = spec->multiout.slave_dig_outs; info = spec->pcm_rec + 1; info->name = spec->stream_name_digital; - info->pcm_type = HDA_PCM_TYPE_SPDIF; + if (spec->dig_out_type) + info->pcm_type = spec->dig_out_type; + else + info->pcm_type = HDA_PCM_TYPE_SPDIF; if (spec->multiout.dig_out_nid && spec->stream_digital_playback) { info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback); @@ -3104,6 +3167,9 @@ static int alc_build_pcms(struct hda_codec *codec) codec->spdif_status_reset = 1; } + if (spec->no_analog) + return 0; + /* If the use of more than one ADC is requested for the current * model, configure a second analog capture-only PCM. */ @@ -3162,65 +3228,17 @@ static void alc_free(struct hda_codec *codec) alc_free_kctls(codec); kfree(spec); - codec->spec = NULL; /* to be sure */ + snd_hda_detach_beep_device(codec); } #ifdef SND_HDA_NEEDS_RESUME -static void store_pin_configs(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid, end_nid; - - end_nid = codec->start_nid + codec->num_nodes; - for (nid = codec->start_nid; nid < end_nid; nid++) { - unsigned int wid_caps = get_wcaps(codec, nid); - unsigned int wid_type = - (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - if (wid_type != AC_WID_PIN) - continue; - if (spec->num_pins >= ARRAY_SIZE(spec->pin_nids)) - break; - spec->pin_nids[spec->num_pins] = nid; - spec->pin_cfgs[spec->num_pins] = - snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); - spec->num_pins++; - } -} - -static void resume_pin_configs(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->num_pins; i++) { - hda_nid_t pin_nid = spec->pin_nids[i]; - unsigned int pin_config = spec->pin_cfgs[i]; - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, - pin_config & 0x000000ff); - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, - (pin_config & 0x0000ff00) >> 8); - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, - (pin_config & 0x00ff0000) >> 16); - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, - pin_config >> 24); - } -} - static int alc_resume(struct hda_codec *codec) { - resume_pin_configs(codec); codec->patch_ops.init(codec); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); return 0; } -#else -#define store_pin_configs(codec) #endif /* @@ -3559,7 +3577,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG), SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST), SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST), - SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */ + SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */ SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST), SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST), SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST), @@ -3602,7 +3620,8 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = { SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG), SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG), SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */ + /* default Intel */ + SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST), SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG), SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG), {} @@ -3782,7 +3801,7 @@ static struct alc_config_preset alc880_presets[] = { .input_mux = &alc880_capture_source, }, [ALC880_UNIWILL_DIG] = { - .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer }, + .mixers = { alc880_asus_mixer }, .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), @@ -3820,8 +3839,7 @@ static struct alc_config_preset alc880_presets[] = { .init_hook = alc880_uniwill_p53_hp_automute, }, [ALC880_FUJITSU] = { - .mixers = { alc880_fujitsu_mixer, - alc880_pcbeep_mixer, }, + .mixers = { alc880_fujitsu_mixer }, .init_verbs = { alc880_volume_init_verbs, alc880_uniwill_p53_init_verbs, alc880_beep_init_verbs }, @@ -4114,7 +4132,7 @@ static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) { - struct hda_input_mux *imux = &spec->private_imux; + struct hda_input_mux *imux = &spec->private_imux[0]; int i, err, idx; for (i = 0; i < AUTO_PIN_LAST; i++) { @@ -4202,11 +4220,9 @@ static void alc880_auto_init_analog_input(struct hda_codec *codec) for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = spec->autocfg.input_pins[i]; if (alc880_is_input_pin(nid)) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - i <= AUTO_PIN_FRONT_MIC ? - PIN_VREF80 : PIN_IN); - if (nid != ALC880_PIN_CD_NID) + alc_set_input_pin(codec, nid, i); + if (nid != ALC880_PIN_CD_NID && + (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); @@ -4221,7 +4237,7 @@ static void alc880_auto_init_analog_input(struct hda_codec *codec) static int alc880_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - int err; + int i, err; static hda_nid_t alc880_ignore[] = { 0x1d, 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, @@ -4252,8 +4268,23 @@ static int alc880_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = spec->multiout.num_dacs * 2; - if (spec->autocfg.dig_out_pin) - spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; + /* check multiple SPDIF-out (for recent codecs) */ + for (i = 0; i < spec->autocfg.dig_outs; i++) { + hda_nid_t dig_nid; + err = snd_hda_get_connections(codec, + spec->autocfg.dig_out_pins[i], + &dig_nid, 1); + if (err < 0) + continue; + if (!i) + spec->multiout.dig_out_nid = dig_nid; + else { + spec->multiout.slave_dig_outs = spec->slave_dig_outs; + spec->slave_dig_outs[i - 1] = dig_nid; + if (i == ARRAY_SIZE(spec->slave_dig_outs) - 1) + break; + } + } if (spec->autocfg.dig_in_pin) spec->dig_in_nid = ALC880_DIGIN_NID; @@ -4263,9 +4294,8 @@ static int alc880_parse_auto_config(struct hda_codec *codec) add_verb(spec, alc880_volume_init_verbs); spec->num_mux_defs = 1; - spec->input_mux = &spec->private_imux; + spec->input_mux = &spec->private_imux[0]; - store_pin_configs(codec); return 1; } @@ -4280,21 +4310,33 @@ static void alc880_auto_init(struct hda_codec *codec) alc_inithook(codec); } -/* - * OK, here we have finally the patch for ALC880 - */ - static void set_capture_mixer(struct alc_spec *spec) { - static struct snd_kcontrol_new *caps[3] = { - alc_capture_mixer1, - alc_capture_mixer2, - alc_capture_mixer3, + static struct snd_kcontrol_new *caps[2][3] = { + { alc_capture_mixer_nosrc1, + alc_capture_mixer_nosrc2, + alc_capture_mixer_nosrc3 }, + { alc_capture_mixer1, + alc_capture_mixer2, + alc_capture_mixer3 }, }; - if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) - spec->cap_mixer = caps[spec->num_adc_nids - 1]; + if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) { + int mux; + if (spec->input_mux && spec->input_mux->num_items > 1) + mux = 1; + else + mux = 0; + spec->cap_mixer = caps[mux][spec->num_adc_nids - 1]; + } } +#define set_beep_amp(spec, nid, idx, dir) \ + ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir)) + +/* + * OK, here we have finally the patch for ALC880 + */ + static int patch_alc880(struct hda_codec *codec) { struct alc_spec *spec; @@ -4330,6 +4372,12 @@ static int patch_alc880(struct hda_codec *codec) } } + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + if (board_config != ALC880_AUTO) setup_preset(spec, &alc880_presets[board_config]); @@ -4356,6 +4404,7 @@ static int patch_alc880(struct hda_codec *codec) } } set_capture_mixer(spec); + set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); spec->vmaster_nid = 0x0c; @@ -4463,6 +4512,26 @@ static struct hda_input_mux alc260_acer_capture_sources[2] = { }, }, }; + +/* Maxdata Favorit 100XS */ +static struct hda_input_mux alc260_favorit100_capture_sources[2] = { + { + .num_items = 2, + .items = { + { "Line/Mic", 0x0 }, + { "CD", 0x4 }, + }, + }, + { + .num_items = 3, + .items = { + { "Line/Mic", 0x0 }, + { "CD", 0x4 }, + { "Mixer", 0x5 }, + }, + }, +}; + /* * This is just place-holder, so there's something for alc_build_pcms to look * at when it calculates the maximum number of channels. ALC260 has no mixer @@ -4505,12 +4574,6 @@ static struct snd_kcontrol_new alc260_input_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc260_pc_beep_mixer[] = { - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT), - { } /* end */ -}; - /* update HP, line and mono out pins according to the master switch */ static void alc260_hp_master_update(struct hda_codec *codec, hda_nid_t hp, hda_nid_t line, @@ -4702,8 +4765,6 @@ static struct snd_kcontrol_new alc260_fujitsu_mixer[] = { HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT), ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN), - HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT), { } /* end */ @@ -4748,8 +4809,18 @@ static struct snd_kcontrol_new alc260_acer_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), - HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT), + { } /* end */ +}; + +/* Maxdata Favorit 100XS: one output and one input (0x12) jack + */ +static struct snd_kcontrol_new alc260_favorit100_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), + ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), + HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT), + ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), { } /* end */ }; @@ -4767,8 +4838,6 @@ static struct snd_kcontrol_new alc260_will_mixer[] = { ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT), { } /* end */ }; @@ -5126,6 +5195,89 @@ static struct hda_verb alc260_acer_init_verbs[] = { { } }; +/* Initialisation sequence for Maxdata Favorit 100XS + * (adapted from Acer init verbs). + */ +static struct hda_verb alc260_favorit100_init_verbs[] = { + /* GPIO 0 enables the output jack. + * Turn this on and rely on the standard mute + * methods whenever the user wants to turn these outputs off. + */ + {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, + /* Line/Mic input jack is connected to Mic1 pin */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + /* Ensure all other unused pins are disabled and muted. */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Disable digital (SPDIF) pins */ + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + + /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum + * bus when acting as outputs. + */ + {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Start with output sum widgets muted and their output gains at min */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Unmute Line-out pin widget amp left and right + * (no equiv mixer ctrl) + */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute Mic1 and Line1 pin widget input buffers since they start as + * inputs. If the pin mode is changed by the user the pin mode control + * will take care of enabling the pin's input/output buffers as needed. + * Therefore there's no need to enable the input buffer at this + * stage. + */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Set ADC connection select to match default mixer setting - mic + * (on mic1 pin) + */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Do similar with the second ADC: mute capture input amp and + * set ADC connection to mic to match ALSA's default state. + */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mute all inputs to mixer widget (even unconnected ones) */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ + + { } +}; + static struct hda_verb alc260_will_verbs[] = { {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -5272,8 +5424,6 @@ static struct snd_kcontrol_new alc260_test_mixer[] = { HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT), HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT), HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT), HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT), @@ -5471,7 +5621,7 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec, static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) { - struct hda_input_mux *imux = &spec->private_imux; + struct hda_input_mux *imux = &spec->private_imux[0]; int i, err, idx; for (i = 0; i < AUTO_PIN_LAST; i++) { @@ -5546,11 +5696,9 @@ static void alc260_auto_init_analog_input(struct hda_codec *codec) for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = spec->autocfg.input_pins[i]; if (nid >= 0x12) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - i <= AUTO_PIN_FRONT_MIC ? - PIN_VREF80 : PIN_IN); - if (nid != ALC260_PIN_CD_NID) + alc_set_input_pin(codec, nid, i); + if (nid != ALC260_PIN_CD_NID && + (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); @@ -5623,7 +5771,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = 2; - if (spec->autocfg.dig_out_pin) + if (spec->autocfg.dig_outs) spec->multiout.dig_out_nid = ALC260_DIGOUT_NID; if (spec->kctls.list) add_mixer(spec, spec->kctls.list); @@ -5631,9 +5779,8 @@ static int alc260_parse_auto_config(struct hda_codec *codec) add_verb(spec, alc260_volume_init_verbs); spec->num_mux_defs = 1; - spec->input_mux = &spec->private_imux; + spec->input_mux = &spec->private_imux[0]; - store_pin_configs(codec); return 1; } @@ -5670,6 +5817,7 @@ static const char *alc260_models[ALC260_MODEL_LAST] = { [ALC260_ACER] = "acer", [ALC260_WILL] = "will", [ALC260_REPLACER_672V] = "replacer", + [ALC260_FAVORIT100] = "favorit100", #ifdef CONFIG_SND_DEBUG [ALC260_TEST] = "test", #endif @@ -5679,6 +5827,7 @@ static const char *alc260_models[ALC260_MODEL_LAST] = { static struct snd_pci_quirk alc260_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER), SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), + SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100), SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013), SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), @@ -5701,8 +5850,7 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = { static struct alc_config_preset alc260_presets[] = { [ALC260_BASIC] = { .mixers = { alc260_base_output_mixer, - alc260_input_mixer, - alc260_pc_beep_mixer }, + alc260_input_mixer }, .init_verbs = { alc260_init_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, @@ -5781,6 +5929,18 @@ static struct alc_config_preset alc260_presets[] = { .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources), .input_mux = alc260_acer_capture_sources, }, + [ALC260_FAVORIT100] = { + .mixers = { alc260_favorit100_mixer }, + .init_verbs = { alc260_favorit100_init_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), + .adc_nids = alc260_dual_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources), + .input_mux = alc260_favorit100_capture_sources, + }, [ALC260_WILL] = { .mixers = { alc260_will_mixer }, .init_verbs = { alc260_init_verbs, alc260_will_verbs }, @@ -5857,6 +6017,12 @@ static int patch_alc260(struct hda_codec *codec) } } + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + if (board_config != ALC260_AUTO) setup_preset(spec, &alc260_presets[board_config]); @@ -5882,6 +6048,7 @@ static int patch_alc260(struct hda_codec *codec) } } set_capture_mixer(spec); + set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); spec->vmaster_nid = 0x08; @@ -6053,8 +6220,6 @@ static struct snd_kcontrol_new alc882_base_mixer[] = { HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), { } /* end */ }; @@ -6081,8 +6246,6 @@ static struct snd_kcontrol_new alc882_w2jc_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), { } /* end */ }; @@ -6134,8 +6297,6 @@ static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), { } /* end */ }; @@ -6244,8 +6405,10 @@ static struct snd_kcontrol_new alc882_macpro_mixer[] = { HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), + /* FIXME: this looks suspicious... HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT), + */ { } /* end */ }; @@ -6877,19 +7040,9 @@ static void alc882_auto_init_analog_input(struct hda_codec *codec) for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = spec->autocfg.input_pins[i]; - unsigned int vref; if (!nid) continue; - vref = PIN_IN; - if (1 /*i <= AUTO_PIN_FRONT_MIC*/) { - unsigned int pincap; - pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); - if ((pincap >> AC_PINCAP_VREF_SHIFT) & - AC_PINCAP_VREF_80) - vref = PIN_VREF80; - } - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, vref); + alc_set_input_pin(codec, nid, AUTO_PIN_FRONT_MIC /*i*/); if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, @@ -6900,18 +7053,21 @@ static void alc882_auto_init_analog_input(struct hda_codec *codec) static void alc882_auto_init_input_src(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - const struct hda_input_mux *imux = spec->input_mux; int c; for (c = 0; c < spec->num_adc_nids; c++) { hda_nid_t conn_list[HDA_MAX_NUM_INPUTS]; hda_nid_t nid = spec->capsrc_nids[c]; + unsigned int mux_idx; + const struct hda_input_mux *imux; int conns, mute, idx, item; conns = snd_hda_get_connections(codec, nid, conn_list, ARRAY_SIZE(conn_list)); if (conns < 0) continue; + mux_idx = c >= spec->num_mux_defs ? 0 : c; + imux = &spec->input_mux[mux_idx]; for (idx = 0; idx < conns; idx++) { /* if the current connection is the selected one, * unmute it as default - otherwise mute it @@ -6924,8 +7080,20 @@ static void alc882_auto_init_input_src(struct hda_codec *codec) break; } } - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, mute); + /* check if we have a selector or mixer + * we could check for the widget type instead, but + * just check for Amp-In presence (in case of mixer + * without amp-in there is something wrong, this + * function shouldn't be used or capsrc nid is wrong) + */ + if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + mute); + else if (mute != AMP_IN_MUTE(idx)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, + idx); } } } @@ -7054,6 +7222,12 @@ static int patch_alc882(struct hda_codec *codec) } } + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + if (board_config != ALC882_AUTO) setup_preset(spec, &alc882_presets[board_config]); @@ -7074,7 +7248,7 @@ static int patch_alc882(struct hda_codec *codec) spec->stream_digital_playback = &alc882_pcm_digital_playback; spec->stream_digital_capture = &alc882_pcm_digital_capture; - spec->is_mix_capture = 1; /* matrix-style capture */ + spec->capture_style = CAPT_MIX; /* matrix-style capture */ if (!spec->adc_nids && spec->input_mux) { /* check whether NID 0x07 is valid */ unsigned int wcap = get_wcaps(codec, 0x07); @@ -7091,6 +7265,7 @@ static int patch_alc882(struct hda_codec *codec) } } set_capture_mixer(spec); + set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); spec->vmaster_nid = 0x0c; @@ -7142,10 +7317,14 @@ static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 }; +#define alc889_adc_nids alc880_adc_nids + static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 }; static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 }; +#define alc889_capsrc_nids alc882_capsrc_nids + /* input MUX */ /* FIXME: should be a matrix-type input source selection */ @@ -7363,8 +7542,6 @@ static struct snd_kcontrol_new alc883_base_mixer[] = { HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), { } /* end */ }; @@ -7427,8 +7604,6 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), { } /* end */ }; @@ -7452,8 +7627,6 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), { } /* end */ }; @@ -7478,8 +7651,6 @@ static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), { } /* end */ }; @@ -7503,8 +7674,6 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = { HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), { } /* end */ }; @@ -7912,36 +8081,83 @@ static struct hda_verb alc888_lenovo_sky_verbs[] = { { } /* end */ }; +static struct hda_verb alc888_6st_dell_verbs[] = { + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } +}; + +static void alc888_3st_hp_front_automute(struct hda_codec *codec) +{ + unsigned int present, bits; + + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); +} + +static void alc888_3st_hp_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + switch (res >> 26) { + case ALC880_HP_EVENT: + alc888_3st_hp_front_automute(codec); + break; + } +} + static struct hda_verb alc888_3st_hp_verbs[] = { {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */ {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */ {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */ - { } -}; - -static struct hda_verb alc888_6st_dell_verbs[] = { {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, - { } + { } /* end */ }; +/* + * 2ch mode + */ static struct hda_verb alc888_3st_hp_2ch_init[] = { { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } + { } /* end */ +}; + +/* + * 4ch mode + */ +static struct hda_verb alc888_3st_hp_4ch_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ }; +/* + * 6ch mode + */ static struct hda_verb alc888_3st_hp_6ch_init[] = { { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { } + { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ }; -static struct hda_channel_mode alc888_3st_hp_modes[2] = { +static struct hda_channel_mode alc888_3st_hp_modes[3] = { { 2, alc888_3st_hp_2ch_init }, + { 4, alc888_3st_hp_4ch_init }, { 6, alc888_3st_hp_6ch_init }, }; @@ -8202,7 +8418,7 @@ static void alc888_6st_dell_unsol_event(struct hda_codec *codec, { switch (res >> 26) { case ALC880_HP_EVENT: - printk("hp_event\n"); + /* printk(KERN_DEBUG "hp_event\n"); */ alc888_6st_dell_front_automute(codec); break; } @@ -8461,6 +8677,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG), SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE), @@ -8468,17 +8685,21 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { ALC888_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G", ALC888_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO), + SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO), SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", ALC888_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G", ALC888_ACER_ASPIRE_4930G), - SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */ + /* default Acer */ + SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG), SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG), SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP), + SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP), SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V), SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG), @@ -8518,7 +8739,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720), SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720), - SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD), + SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD), SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), SND_PCI_QUIRK(0x1734, 0x1107, "FSC AMILO Xi2550", @@ -8543,6 +8764,10 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { {} }; +static hda_nid_t alc1200_slave_dig_outs[] = { + ALC883_DIGOUT_NID, 0, +}; + static struct alc_config_preset alc883_presets[] = { [ALC883_3ST_2ch_DIG] = { .mixers = { alc883_3ST_2ch_mixer }, @@ -8778,6 +9003,8 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc888_3st_hp_modes, .need_dac_fix = 1, .input_mux = &alc883_capture_source, + .unsol_event = alc888_3st_hp_unsol_event, + .init_hook = alc888_3st_hp_front_automute, }, [ALC888_6ST_DELL] = { .mixers = { alc883_base_mixer, alc883_chmode_mixer }, @@ -8883,6 +9110,7 @@ static struct alc_config_preset alc883_presets[] = { .dac_nids = alc883_dac_nids, .dig_out_nid = ALC1200_DIGOUT_NID, .dig_in_nid = ALC883_DIGIN_NID, + .slave_dig_outs = alc1200_slave_dig_outs, .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), .channel_mode = alc883_sixstack_modes, .input_mux = &alc883_capture_source, @@ -8950,11 +9178,9 @@ static void alc883_auto_init_analog_input(struct hda_codec *codec) for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = spec->autocfg.input_pins[i]; if (alc883_is_input_pin(nid)) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - (i <= AUTO_PIN_FRONT_MIC ? - PIN_VREF80 : PIN_IN)); - if (nid != ALC883_PIN_CD_NID) + alc_set_input_pin(codec, nid, i); + if (nid != ALC883_PIN_CD_NID && + (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); @@ -8969,6 +9195,8 @@ static int alc883_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err = alc880_parse_auto_config(codec); + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; if (err < 0) return err; @@ -8982,6 +9210,26 @@ static int alc883_parse_auto_config(struct hda_codec *codec) /* hack - override the init verbs */ spec->init_verbs[0] = alc883_auto_init_verbs; + /* setup input_mux for ALC889 */ + if (codec->vendor_id == 0x10ec0889) { + /* digital-mic input pin is excluded in alc880_auto_create..() + * because it's under 0x18 + */ + if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 || + cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) { + struct hda_input_mux *imux = &spec->private_imux[0]; + for (i = 1; i < 3; i++) + memcpy(&spec->private_imux[i], + &spec->private_imux[0], + sizeof(spec->private_imux[0])); + imux->items[imux->num_items].label = "Int DMic"; + imux->items[imux->num_items].index = 0x0b; + imux->num_items++; + spec->num_mux_defs = 3; + spec->input_mux = spec->private_imux; + } + } + return 1; /* config found */ } @@ -9033,6 +9281,12 @@ static int patch_alc883(struct hda_codec *codec) } } + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + if (board_config != ALC883_AUTO) setup_preset(spec, &alc883_presets[board_config]); @@ -9045,14 +9299,36 @@ static int patch_alc883(struct hda_codec *codec) spec->stream_name_analog = "ALC888 Analog"; spec->stream_name_digital = "ALC888 Digital"; } + if (!spec->num_adc_nids) { + spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); + spec->adc_nids = alc883_adc_nids; + } + if (!spec->capsrc_nids) + spec->capsrc_nids = alc883_capsrc_nids; + spec->capture_style = CAPT_MIX; /* matrix-style capture */ break; case 0x10ec0889: spec->stream_name_analog = "ALC889 Analog"; spec->stream_name_digital = "ALC889 Digital"; + if (!spec->num_adc_nids) { + spec->num_adc_nids = ARRAY_SIZE(alc889_adc_nids); + spec->adc_nids = alc889_adc_nids; + } + if (!spec->capsrc_nids) + spec->capsrc_nids = alc889_capsrc_nids; + spec->capture_style = CAPT_1MUX_MIX; /* 1mux/Nmix-style + capture */ break; default: spec->stream_name_analog = "ALC883 Analog"; spec->stream_name_digital = "ALC883 Digital"; + if (!spec->num_adc_nids) { + spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); + spec->adc_nids = alc883_adc_nids; + } + if (!spec->capsrc_nids) + spec->capsrc_nids = alc883_capsrc_nids; + spec->capture_style = CAPT_MIX; /* matrix-style capture */ break; } @@ -9063,15 +9339,9 @@ static int patch_alc883(struct hda_codec *codec) spec->stream_digital_playback = &alc883_pcm_digital_playback; spec->stream_digital_capture = &alc883_pcm_digital_capture; - if (!spec->num_adc_nids) { - spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); - spec->adc_nids = alc883_adc_nids; - } - if (!spec->capsrc_nids) - spec->capsrc_nids = alc883_capsrc_nids; - spec->is_mix_capture = 1; /* matrix-style capture */ if (!spec->cap_mixer) set_capture_mixer(spec); + set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); spec->vmaster_nid = 0x0c; @@ -9124,8 +9394,6 @@ static struct snd_kcontrol_new alc262_base_mixer[] = { HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), - /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), @@ -9146,8 +9414,6 @@ static struct snd_kcontrol_new alc262_hippo1_mixer[] = { HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), - /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */ /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/ HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), { } /* end */ @@ -9256,8 +9522,6 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT), HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT), { } /* end */ @@ -9286,8 +9550,6 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), { } /* end */ }; @@ -9435,6 +9697,67 @@ static struct snd_kcontrol_new alc262_benq_t31_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc262_tyan_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT), + HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +static struct hda_verb alc262_tyan_verbs[] = { + /* Headphone automute */ + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* P11 AUX_IN, white 4-pin connector */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1}, + {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93}, + {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19}, + + {} +}; + +/* unsolicited event for HP jack sensing */ +static void alc262_tyan_automute(struct hda_codec *codec) +{ + unsigned int mute; + unsigned int present; + + snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0); + present = (present & 0x80000000) != 0; + if (present) { + /* mute line output on ATX panel */ + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + } else { + /* unmute line output if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + } +} + +static void alc262_tyan_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc262_tyan_automute(codec); +} + #define alc262_capture_mixer alc882_capture_mixer #define alc262_capture_alt_mixer alc882_capture_alt_mixer @@ -9901,8 +10224,6 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { }, HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Switch", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), @@ -10474,8 +10795,14 @@ static int alc262_parse_auto_config(struct hda_codec *codec) alc262_ignore); if (err < 0) return err; - if (!spec->autocfg.line_outs) + if (!spec->autocfg.line_outs) { + if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) { + spec->multiout.max_channels = 2; + spec->no_analog = 1; + goto dig_only; + } return 0; /* can't find valid BIOS pin config */ + } err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg); if (err < 0) return err; @@ -10485,8 +10812,11 @@ static int alc262_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = spec->multiout.num_dacs * 2; - if (spec->autocfg.dig_out_pin) + dig_only: + if (spec->autocfg.dig_outs) { spec->multiout.dig_out_nid = ALC262_DIGOUT_NID; + spec->dig_out_type = spec->autocfg.dig_out_type[0]; + } if (spec->autocfg.dig_in_pin) spec->dig_in_nid = ALC262_DIGIN_NID; @@ -10495,13 +10825,12 @@ static int alc262_parse_auto_config(struct hda_codec *codec) add_verb(spec, alc262_volume_init_verbs); spec->num_mux_defs = 1; - spec->input_mux = &spec->private_imux; + spec->input_mux = &spec->private_imux[0]; err = alc_auto_add_mic_boost(codec); if (err < 0) return err; - store_pin_configs(codec); return 1; } @@ -10543,21 +10872,19 @@ static const char *alc262_models[ALC262_MODEL_LAST] = { [ALC262_ULTRA] = "ultra", [ALC262_LENOVO_3000] = "lenovo-3000", [ALC262_NEC] = "nec", + [ALC262_TYAN] = "tyan", [ALC262_AUTO] = "auto", }; static struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO), SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC), - SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x170b, "HP xw*", ALC262_HP_BPC), + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series", + ALC262_HP_BPC), + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series", + ALC262_HP_BPC), + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series", + ALC262_HP_BPC), SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL), SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF), SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL), @@ -10575,17 +10902,17 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO), SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), - SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), - SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), - SND_PCI_QUIRK(0x104d, 0x9033, "Sony VAIO VGN-SR19XN", - ALC262_SONY_ASSAMD), + SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */ + SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO", + ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", ALC262_TOSHIBA_RX1), SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06), SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU), SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU), - SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA), - SND_PCI_QUIRK(0x144d, 0xc039, "Samsung Q1U EL", ALC262_ULTRA), + SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN), + SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1", + ALC262_ULTRA), SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO), SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000), SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8), @@ -10802,6 +11129,19 @@ static struct alc_config_preset alc262_presets[] = { .unsol_event = alc262_hippo_unsol_event, .init_hook = alc262_hippo_automute, }, + [ALC262_TYAN] = { + .mixers = { alc262_tyan_mixer }, + .init_verbs = { alc262_init_verbs, alc262_tyan_verbs}, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x02, + .dig_out_nid = ALC262_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + .unsol_event = alc262_tyan_unsol_event, + .init_hook = alc262_tyan_automute, + }, }; static int patch_alc262(struct hda_codec *codec) @@ -10854,6 +11194,14 @@ static int patch_alc262(struct hda_codec *codec) } } + if (!spec->no_analog) { + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + } + if (board_config != ALC262_AUTO) setup_preset(spec, &alc262_presets[board_config]); @@ -10865,7 +11213,7 @@ static int patch_alc262(struct hda_codec *codec) spec->stream_digital_playback = &alc262_pcm_digital_playback; spec->stream_digital_capture = &alc262_pcm_digital_capture; - spec->is_mix_capture = 1; + spec->capture_style = CAPT_MIX; if (!spec->adc_nids && spec->input_mux) { /* check whether NID 0x07 is valid */ unsigned int wcap = get_wcaps(codec, 0x07); @@ -10882,8 +11230,10 @@ static int patch_alc262(struct hda_codec *codec) spec->capsrc_nids = alc262_capsrc_nids; } } - if (!spec->cap_mixer) + if (!spec->cap_mixer && !spec->no_analog) set_capture_mixer(spec); + if (!spec->no_analog) + set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); spec->vmaster_nid = 0x0c; @@ -11263,19 +11613,13 @@ static void alc267_quanta_il1_unsol_event(struct hda_codec *codec, static struct hda_verb alc268_base_init_verbs[] = { /* Unmute DAC0-1 and set vol = 0 */ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, /* * Set up output mixers (0x0c - 0x0e) */ /* set vol=0 to output mixers */ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -11294,9 +11638,7 @@ static struct hda_verb alc268_base_init_verbs[] = { {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* set PCBEEP vol = 0, mute connections */ {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -11318,10 +11660,8 @@ static struct hda_verb alc268_base_init_verbs[] = { */ static struct hda_verb alc268_volume_init_verbs[] = { /* set output DAC */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, @@ -11329,16 +11669,12 @@ static struct hda_verb alc268_volume_init_verbs[] = { {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* set PCBEEP vol = 0, mute connections */ {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -11537,7 +11873,7 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec, static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) { - struct hda_input_mux *imux = &spec->private_imux; + struct hda_input_mux *imux = &spec->private_imux[0]; int i, idx1; for (i = 0; i < AUTO_PIN_LAST; i++) { @@ -11631,9 +11967,14 @@ static int alc268_parse_auto_config(struct hda_codec *codec) alc268_ignore); if (err < 0) return err; - if (!spec->autocfg.line_outs) + if (!spec->autocfg.line_outs) { + if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) { + spec->multiout.max_channels = 2; + spec->no_analog = 1; + goto dig_only; + } return 0; /* can't find valid BIOS pin config */ - + } err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg); if (err < 0) return err; @@ -11643,25 +11984,26 @@ static int alc268_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = 2; + dig_only: /* digital only support output */ - if (spec->autocfg.dig_out_pin) + if (spec->autocfg.dig_outs) { spec->multiout.dig_out_nid = ALC268_DIGOUT_NID; - + spec->dig_out_type = spec->autocfg.dig_out_type[0]; + } if (spec->kctls.list) add_mixer(spec, spec->kctls.list); - if (spec->autocfg.speaker_pins[0] != 0x1d) + if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) add_mixer(spec, alc268_beep_mixer); add_verb(spec, alc268_volume_init_verbs); spec->num_mux_defs = 1; - spec->input_mux = &spec->private_imux; + spec->input_mux = &spec->private_imux[0]; err = alc_auto_add_mic_boost(codec); if (err < 0) return err; - store_pin_configs(codec); return 1; } @@ -11723,7 +12065,7 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = { static struct alc_config_preset alc268_presets[] = { [ALC267_QUANTA_IL1] = { - .mixers = { alc267_quanta_il1_mixer }, + .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer }, .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, alc267_quanta_il1_verbs }, .num_dacs = ARRAY_SIZE(alc268_dac_nids), @@ -11805,7 +12147,8 @@ static struct alc_config_preset alc268_presets[] = { }, [ALC268_ACER_ASPIRE_ONE] = { .mixers = { alc268_acer_aspire_one_mixer, - alc268_capture_alt_mixer }, + alc268_beep_mixer, + alc268_capture_alt_mixer }, .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, alc268_acer_aspire_one_verbs }, .num_dacs = ARRAY_SIZE(alc268_dac_nids), @@ -11874,7 +12217,7 @@ static int patch_alc268(struct hda_codec *codec) { struct alc_spec *spec; int board_config; - int err; + int i, has_beep, err; spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -11923,15 +12266,30 @@ static int patch_alc268(struct hda_codec *codec) spec->stream_digital_playback = &alc268_pcm_digital_playback; - if (!query_amp_caps(codec, 0x1d, HDA_INPUT)) - /* override the amp caps for beep generator */ - snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT, + has_beep = 0; + for (i = 0; i < spec->num_mixers; i++) { + if (spec->mixers[i] == alc268_beep_mixer) { + has_beep = 1; + break; + } + } + + if (has_beep) { + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + if (!query_amp_caps(codec, 0x1d, HDA_INPUT)) + /* override the amp caps for beep generator */ + snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT, (0x0c << AC_AMPCAP_OFFSET_SHIFT) | (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) | (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) | (0 << AC_AMPCAP_MUTE_SHIFT)); + } - if (!spec->adc_nids && spec->input_mux) { + if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { /* check whether NID 0x07 is valid */ unsigned int wcap = get_wcaps(codec, 0x07); int i; @@ -12012,8 +12370,6 @@ static struct snd_kcontrol_new alc269_base_mixer[] = { HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), @@ -12040,8 +12396,6 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT), { } }; @@ -12065,8 +12419,6 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = { HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT), HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT), HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT), { } }; @@ -12103,13 +12455,6 @@ static struct snd_kcontrol_new alc269_fujitsu_mixer[] = { { } /* end */ }; -/* beep control */ -static struct snd_kcontrol_new alc269_beep_mixer[] = { - HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT), - { } /* end */ -}; - static struct hda_verb alc269_quanta_fl1_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, @@ -12509,7 +12854,7 @@ static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec, */ if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 || cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) { - struct hda_input_mux *imux = &spec->private_imux; + struct hda_input_mux *imux = &spec->private_imux[0]; imux->items[imux->num_items].label = "Int Mic"; imux->items[imux->num_items].index = 0x05; imux->num_items++; @@ -12527,13 +12872,34 @@ static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec, #define alc269_pcm_digital_playback alc880_pcm_digital_playback #define alc269_pcm_digital_capture alc880_pcm_digital_capture +static struct hda_pcm_stream alc269_44k_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_44100, /* fixed rate */ + /* NID is set in alc_build_pcms */ + .ops = { + .open = alc880_playback_pcm_open, + .prepare = alc880_playback_pcm_prepare, + .cleanup = alc880_playback_pcm_cleanup + }, +}; + +static struct hda_pcm_stream alc269_44k_pcm_analog_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_44100, /* fixed rate */ + /* NID is set in alc_build_pcms */ +}; + /* * BIOS auto configuration */ static int alc269_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - int i, err; + int err; static hda_nid_t alc269_ignore[] = { 0x1d, 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, @@ -12550,22 +12916,15 @@ static int alc269_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = spec->multiout.num_dacs * 2; - if (spec->autocfg.dig_out_pin) + if (spec->autocfg.dig_outs) spec->multiout.dig_out_nid = ALC269_DIGOUT_NID; if (spec->kctls.list) add_mixer(spec, spec->kctls.list); - /* create a beep mixer control if the pin 0x1d isn't assigned */ - for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++) - if (spec->autocfg.input_pins[i] == 0x1d) - break; - if (i >= ARRAY_SIZE(spec->autocfg.input_pins)) - add_mixer(spec, alc269_beep_mixer); - add_verb(spec, alc269_init_verbs); spec->num_mux_defs = 1; - spec->input_mux = &spec->private_imux; + spec->input_mux = &spec->private_imux[0]; /* set default input source */ snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0], 0, AC_VERB_SET_CONNECT_SEL, @@ -12575,10 +12934,9 @@ static int alc269_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - if (!spec->cap_mixer) + if (!spec->cap_mixer && !spec->no_analog) set_capture_mixer(spec); - store_pin_configs(codec); return 1; } @@ -12675,7 +13033,7 @@ static struct alc_config_preset alc269_presets[] = { .init_hook = alc269_eeepc_dmic_inithook, }, [ALC269_FUJITSU] = { - .mixers = { alc269_fujitsu_mixer, alc269_beep_mixer }, + .mixers = { alc269_fujitsu_mixer }, .cap_mixer = alc269_epc_capture_mixer, .init_verbs = { alc269_init_verbs, alc269_eeepc_dmic_init_verbs }, @@ -12740,13 +13098,26 @@ static int patch_alc269(struct hda_codec *codec) } } + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + if (board_config != ALC269_AUTO) setup_preset(spec, &alc269_presets[board_config]); spec->stream_name_analog = "ALC269 Analog"; - spec->stream_analog_playback = &alc269_pcm_analog_playback; - spec->stream_analog_capture = &alc269_pcm_analog_capture; - + if (codec->subsystem_id == 0x17aa3bf8) { + /* Due to a hardware problem on Lenovo Ideadpad, we need to + * fix the sample rate of analog I/O to 44.1kHz + */ + spec->stream_analog_playback = &alc269_44k_pcm_analog_playback; + spec->stream_analog_capture = &alc269_44k_pcm_analog_capture; + } else { + spec->stream_analog_playback = &alc269_pcm_analog_playback; + spec->stream_analog_capture = &alc269_pcm_analog_capture; + } spec->stream_name_digital = "ALC269 Digital"; spec->stream_digital_playback = &alc269_pcm_digital_playback; spec->stream_digital_capture = &alc269_pcm_digital_capture; @@ -12756,6 +13127,7 @@ static int patch_alc269(struct hda_codec *codec) spec->capsrc_nids = alc269_capsrc_nids; if (!spec->cap_mixer) set_capture_mixer(spec); + set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); codec->patch_ops = alc_patch_ops; if (board_config == ALC269_AUTO) @@ -13006,8 +13378,6 @@ static struct snd_kcontrol_new alc861_asus_mixer[] = { static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = { HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT), { } }; @@ -13481,7 +13851,7 @@ static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin) static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) { - struct hda_input_mux *imux = &spec->private_imux; + struct hda_input_mux *imux = &spec->private_imux[0]; int i, err, idx, idx1; for (i = 0; i < AUTO_PIN_LAST; i++) { @@ -13568,12 +13938,8 @@ static void alc861_auto_init_analog_input(struct hda_codec *codec) for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = spec->autocfg.input_pins[i]; - if (nid >= 0x0c && nid <= 0x11) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - i <= AUTO_PIN_FRONT_MIC ? - PIN_VREF80 : PIN_IN); - } + if (nid >= 0x0c && nid <= 0x11) + alc_set_input_pin(codec, nid, i); } } @@ -13609,7 +13975,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = spec->multiout.num_dacs * 2; - if (spec->autocfg.dig_out_pin) + if (spec->autocfg.dig_outs) spec->multiout.dig_out_nid = ALC861_DIGOUT_NID; if (spec->kctls.list) @@ -13618,13 +13984,12 @@ static int alc861_parse_auto_config(struct hda_codec *codec) add_verb(spec, alc861_auto_init_verbs); spec->num_mux_defs = 1; - spec->input_mux = &spec->private_imux; + spec->input_mux = &spec->private_imux[0]; spec->adc_nids = alc861_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); set_capture_mixer(spec); - store_pin_configs(codec); return 1; } @@ -13833,6 +14198,12 @@ static int patch_alc861(struct hda_codec *codec) } } + err = snd_hda_attach_beep_device(codec, 0x23); + if (err < 0) { + alc_free(codec); + return err; + } + if (board_config != ALC861_AUTO) setup_preset(spec, &alc861_presets[board_config]); @@ -13844,6 +14215,8 @@ static int patch_alc861(struct hda_codec *codec) spec->stream_digital_playback = &alc861_pcm_digital_playback; spec->stream_digital_capture = &alc861_pcm_digital_capture; + set_beep_amp(spec, 0x23, 0, HDA_OUTPUT); + spec->vmaster_nid = 0x03; codec->patch_ops = alc_patch_ops; @@ -14000,9 +14373,6 @@ static struct snd_kcontrol_new alc861vd_6st_mixer[] = { HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - { } /* end */ }; @@ -14026,9 +14396,6 @@ static struct snd_kcontrol_new alc861vd_3st_mixer[] = { HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - { } /* end */ }; @@ -14067,8 +14434,6 @@ static struct snd_kcontrol_new alc861vd_dallas_mixer[] = { HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("PC Beep Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Beep Switch", 0x0b, 0x05, HDA_INPUT), { } /* end */ }; @@ -14379,9 +14744,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = { SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO), SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS), SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), - SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), - SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO), - SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 N200", ALC861VD_LENOVO), + SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO), SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), {} }; @@ -14543,11 +14906,9 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec) for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = spec->autocfg.input_pins[i]; if (alc861vd_is_input_pin(nid)) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - i <= AUTO_PIN_FRONT_MIC ? - PIN_VREF80 : PIN_IN); - if (nid != ALC861VD_PIN_CD_NID) + alc_set_input_pin(codec, nid, i); + if (nid != ALC861VD_PIN_CD_NID && + (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); @@ -14713,7 +15074,7 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = spec->multiout.num_dacs * 2; - if (spec->autocfg.dig_out_pin) + if (spec->autocfg.dig_outs) spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID; if (spec->kctls.list) @@ -14722,13 +15083,12 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) add_verb(spec, alc861vd_volume_init_verbs); spec->num_mux_defs = 1; - spec->input_mux = &spec->private_imux; + spec->input_mux = &spec->private_imux[0]; err = alc_auto_add_mic_boost(codec); if (err < 0) return err; - store_pin_configs(codec); return 1; } @@ -14779,6 +15139,12 @@ static int patch_alc861vd(struct hda_codec *codec) } } + err = snd_hda_attach_beep_device(codec, 0x23); + if (err < 0) { + alc_free(codec); + return err; + } + if (board_config != ALC861VD_AUTO) setup_preset(spec, &alc861vd_presets[board_config]); @@ -14801,9 +15167,10 @@ static int patch_alc861vd(struct hda_codec *codec) spec->adc_nids = alc861vd_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids); spec->capsrc_nids = alc861vd_capsrc_nids; - spec->is_mix_capture = 1; + spec->capture_style = CAPT_MIX; set_capture_mixer(spec); + set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); spec->vmaster_nid = 0x02; @@ -14992,8 +15359,6 @@ static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), { } /* end */ }; @@ -15015,8 +15380,6 @@ static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), { } /* end */ }; @@ -15992,56 +16355,55 @@ static const char *alc662_models[ALC662_MODEL_LAST] = { }; static struct snd_pci_quirk alc662_cfg_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA), - SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V), - SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG), - SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), - SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20), - SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS), SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3), SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2), SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2), SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6), + SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6), + SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2), SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5), + SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6), + SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2), SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA), + /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/ SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3), SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V), + /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/ + SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1), SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4), - SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5), - SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6), - SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6), - SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6), + SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), + SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20), + SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS), SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K", ALC662_3ST_6ch_DIG), - SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), - SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS), - SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS), SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", ALC662_3ST_6ch_DIG), SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0", ALC662_3ST_6ch_DIG), - SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13), - SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13), - SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13), + SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x", + ALC663_ASUS_H13), {} }; @@ -16361,7 +16723,7 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, if (alc880_is_fixed_pin(pin)) { nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); - /* printk("DAC nid=%x\n",nid); */ + /* printk(KERN_DEBUG "DAC nid=%x\n",nid); */ /* specify the DAC as the extra output */ if (!spec->multiout.hp_nid) spec->multiout.hp_nid = nid; @@ -16391,26 +16753,58 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, return 0; } +/* return the index of the src widget from the connection list of the nid. + * return -1 if not found + */ +static int alc662_input_pin_idx(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t src) +{ + hda_nid_t conn_list[HDA_MAX_CONNECTIONS]; + int i, conns; + + conns = snd_hda_get_connections(codec, nid, conn_list, + ARRAY_SIZE(conn_list)); + if (conns < 0) + return -1; + for (i = 0; i < conns; i++) + if (conn_list[i] == src) + return i; + return -1; +} + +static int alc662_is_input_pin(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int pincap = snd_hda_query_pin_caps(codec, nid); + return (pincap & AC_PINCAP_IN) != 0; +} + /* create playback/capture controls for input pins */ -static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec, +static int alc662_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - struct hda_input_mux *imux = &spec->private_imux; + struct alc_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->private_imux[0]; int i, err, idx; for (i = 0; i < AUTO_PIN_LAST; i++) { - if (alc880_is_input_pin(cfg->input_pins[i])) { - idx = alc880_input_pin_idx(cfg->input_pins[i]); - err = new_analog_input(spec, cfg->input_pins[i], - auto_pin_cfg_labels[i], - idx, 0x0b); - if (err < 0) - return err; - imux->items[imux->num_items].label = - auto_pin_cfg_labels[i]; - imux->items[imux->num_items].index = - alc880_input_pin_idx(cfg->input_pins[i]); - imux->num_items++; + if (alc662_is_input_pin(codec, cfg->input_pins[i])) { + idx = alc662_input_pin_idx(codec, 0x0b, + cfg->input_pins[i]); + if (idx >= 0) { + err = new_analog_input(spec, cfg->input_pins[i], + auto_pin_cfg_labels[i], + idx, 0x0b); + if (err < 0) + return err; + } + idx = alc662_input_pin_idx(codec, 0x22, + cfg->input_pins[i]); + if (idx >= 0) { + imux->items[imux->num_items].label = + auto_pin_cfg_labels[i]; + imux->items[imux->num_items].index = idx; + imux->num_items++; + } } } return 0; @@ -16460,7 +16854,6 @@ static void alc662_auto_init_hp_out(struct hda_codec *codec) alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); } -#define alc662_is_input_pin(nid) alc880_is_input_pin(nid) #define ALC662_PIN_CD_NID ALC880_PIN_CD_NID static void alc662_auto_init_analog_input(struct hda_codec *codec) @@ -16470,12 +16863,10 @@ static void alc662_auto_init_analog_input(struct hda_codec *codec) for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = spec->autocfg.input_pins[i]; - if (alc662_is_input_pin(nid)) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - (i <= AUTO_PIN_FRONT_MIC ? - PIN_VREF80 : PIN_IN)); - if (nid != ALC662_PIN_CD_NID) + if (alc662_is_input_pin(codec, nid)) { + alc_set_input_pin(codec, nid, i); + if (nid != ALC662_PIN_CD_NID && + (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); @@ -16513,20 +16904,20 @@ static int alc662_parse_auto_config(struct hda_codec *codec) "Headphone"); if (err < 0) return err; - err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg); + err = alc662_auto_create_analog_input_ctls(codec, &spec->autocfg); if (err < 0) return err; spec->multiout.max_channels = spec->multiout.num_dacs * 2; - if (spec->autocfg.dig_out_pin) + if (spec->autocfg.dig_outs) spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; if (spec->kctls.list) add_mixer(spec, spec->kctls.list); spec->num_mux_defs = 1; - spec->input_mux = &spec->private_imux; + spec->input_mux = &spec->private_imux[0]; add_verb(spec, alc662_auto_init_verbs); if (codec->vendor_id == 0x10ec0663) @@ -16536,7 +16927,6 @@ static int alc662_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - store_pin_configs(codec); return 1; } @@ -16588,6 +16978,12 @@ static int patch_alc662(struct hda_codec *codec) } } + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + if (board_config != ALC662_AUTO) setup_preset(spec, &alc662_presets[board_config]); @@ -16611,10 +17007,14 @@ static int patch_alc662(struct hda_codec *codec) spec->adc_nids = alc662_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); spec->capsrc_nids = alc662_capsrc_nids; - spec->is_mix_capture = 1; + spec->capture_style = CAPT_MIX; if (!spec->cap_mixer) set_capture_mixer(spec); + if (codec->vendor_id == 0x10ec0662) + set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + else + set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); spec->vmaster_nid = 0x02; |