diff options
Diffstat (limited to 'sound/pci/hda/hda_generic.c')
-rw-r--r-- | sound/pci/hda/hda_generic.c | 433 |
1 files changed, 320 insertions, 113 deletions
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 2dbe767be16..ac079f93c53 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -34,6 +34,7 @@ #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" +#include "hda_beep.h" #include "hda_generic.h" @@ -150,15 +151,25 @@ static void parse_user_hints(struct hda_codec *codec) val = snd_hda_get_bool_hint(codec, "add_stereo_mix_input"); if (val >= 0) spec->add_stereo_mix_input = !!val; + /* the following two are just for compatibility */ val = snd_hda_get_bool_hint(codec, "add_out_jack_modes"); if (val >= 0) - spec->add_out_jack_modes = !!val; + spec->add_jack_modes = !!val; val = snd_hda_get_bool_hint(codec, "add_in_jack_modes"); if (val >= 0) - spec->add_in_jack_modes = !!val; + spec->add_jack_modes = !!val; + val = snd_hda_get_bool_hint(codec, "add_jack_modes"); + if (val >= 0) + spec->add_jack_modes = !!val; val = snd_hda_get_bool_hint(codec, "power_down_unused"); if (val >= 0) spec->power_down_unused = !!val; + val = snd_hda_get_bool_hint(codec, "add_hp_mic"); + if (val >= 0) + spec->hp_mic = !!val; + val = snd_hda_get_bool_hint(codec, "hp_mic_detect"); + if (val >= 0) + spec->suppress_hp_mic_detect = !val; if (!snd_hda_get_int_hint(codec, "mixer_nid", &val)) spec->mixer_nid = val; @@ -996,7 +1007,7 @@ enum { /* Primary DAC shared with main surrounds */ BAD_SHARED_SURROUND = 0x100, /* No independent HP possible */ - BAD_NO_INDEP_HP = 0x40, + BAD_NO_INDEP_HP = 0x10, /* Primary DAC shared with main CLFE */ BAD_SHARED_CLFE = 0x10, /* Primary DAC shared with extra surrounds */ @@ -1051,16 +1062,7 @@ static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path) return badness; } -struct badness_table { - int no_primary_dac; /* no primary DAC */ - int no_dac; /* no secondary DACs */ - int shared_primary; /* primary DAC is shared with main output */ - int shared_surr; /* secondary DAC shared with main or primary */ - int shared_clfe; /* third DAC shared with main or primary */ - int shared_surr_main; /* secondary DAC sahred with main/DAC0 */ -}; - -static struct badness_table main_out_badness = { +const struct badness_table hda_main_out_badness = { .no_primary_dac = BAD_NO_PRIMARY_DAC, .no_dac = BAD_NO_DAC, .shared_primary = BAD_NO_PRIMARY_DAC, @@ -1068,8 +1070,9 @@ static struct badness_table main_out_badness = { .shared_clfe = BAD_SHARED_CLFE, .shared_surr_main = BAD_SHARED_SURROUND, }; +EXPORT_SYMBOL_HDA(hda_main_out_badness); -static struct badness_table extra_out_badness = { +const struct badness_table hda_extra_out_badness = { .no_primary_dac = BAD_NO_DAC, .no_dac = BAD_NO_DAC, .shared_primary = BAD_NO_EXTRA_DAC, @@ -1077,6 +1080,7 @@ static struct badness_table extra_out_badness = { .shared_clfe = BAD_SHARED_EXTRA_SURROUND, .shared_surr_main = BAD_NO_EXTRA_SURR_DAC, }; +EXPORT_SYMBOL_HDA(hda_extra_out_badness); /* get the DAC of the primary output corresponding to the given array index */ static hda_nid_t get_primary_out(struct hda_codec *codec, int idx) @@ -1367,22 +1371,25 @@ static int check_aamix_out_path(struct hda_codec *codec, int path_idx) { struct hda_gen_spec *spec = codec->spec; struct nid_path *path; - hda_nid_t dac, pin; + hda_nid_t path_dac, dac, pin; path = snd_hda_get_path_from_idx(codec, path_idx); if (!path || !path->depth || is_nid_contained(path, spec->mixer_nid)) return 0; - dac = path->path[0]; + path_dac = path->path[0]; + dac = spec->private_dac_nids[0]; pin = path->path[path->depth - 1]; path = snd_hda_add_new_path(codec, dac, pin, spec->mixer_nid); if (!path) { - if (dac != spec->multiout.dac_nids[0]) - dac = spec->multiout.dac_nids[0]; + if (dac != path_dac) + dac = path_dac; else if (spec->multiout.hp_out_nid[0]) dac = spec->multiout.hp_out_nid[0]; else if (spec->multiout.extra_out_nid[0]) dac = spec->multiout.extra_out_nid[0]; + else + dac = 0; if (dac) path = snd_hda_add_new_path(codec, dac, pin, spec->mixer_nid); @@ -1507,7 +1514,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec, badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins, spec->private_dac_nids, spec->out_paths, - &main_out_badness); + spec->main_out_badness); if (fill_mio_first && cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { @@ -1522,7 +1529,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec, err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins, spec->multiout.hp_out_nid, spec->hp_paths, - &extra_out_badness); + spec->extra_out_badness); if (err < 0) return err; badness += err; @@ -1532,7 +1539,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec, cfg->speaker_pins, spec->multiout.extra_out_nid, spec->speaker_paths, - &extra_out_badness); + spec->extra_out_badness); if (err < 0) return err; badness += err; @@ -1926,6 +1933,17 @@ static int create_speaker_out_ctls(struct hda_codec *codec) * independent HP controls */ +/* update HP auto-mute state too */ +static void update_hp_automute_hook(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + + if (spec->hp_automute_hook) + spec->hp_automute_hook(codec, NULL); + else + snd_hda_gen_hp_automute(codec, NULL); +} + static int indep_hp_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1986,12 +2004,7 @@ static int indep_hp_put(struct snd_kcontrol *kcontrol, else *dacp = spec->alt_dac_nid; - /* update HP auto-mute state too */ - if (spec->hp_automute_hook) - spec->hp_automute_hook(codec, NULL); - else - snd_hda_gen_hp_automute(codec, NULL); - + update_hp_automute_hook(codec); ret = 1; } unlock: @@ -2072,6 +2085,14 @@ get_multiio_path(struct hda_codec *codec, int idx) static void update_automute_all(struct hda_codec *codec); +/* Default value to be passed as aamix argument for snd_hda_activate_path(); + * used for output paths + */ +static bool aamix_default(struct hda_gen_spec *spec) +{ + return !spec->have_aamix_ctl || spec->aamix_mode; +} + static int set_multi_io(struct hda_codec *codec, int idx, bool output) { struct hda_gen_spec *spec = codec->spec; @@ -2087,11 +2108,11 @@ static int set_multi_io(struct hda_codec *codec, int idx, bool output) if (output) { set_pin_target(codec, nid, PIN_OUT, true); - snd_hda_activate_path(codec, path, true, true); + snd_hda_activate_path(codec, path, true, aamix_default(spec)); set_pin_eapd(codec, nid, true); } else { set_pin_eapd(codec, nid, false); - snd_hda_activate_path(codec, path, false, true); + snd_hda_activate_path(codec, path, false, aamix_default(spec)); set_pin_target(codec, nid, spec->multi_io[idx].ctl_in, true); path_power_down_sync(codec, path); } @@ -2182,8 +2203,8 @@ static void update_aamix_paths(struct hda_codec *codec, bool do_mix, snd_hda_activate_path(codec, mix_path, true, true); path_power_down_sync(codec, nomix_path); } else { - snd_hda_activate_path(codec, mix_path, false, true); - snd_hda_activate_path(codec, nomix_path, true, true); + snd_hda_activate_path(codec, mix_path, false, false); + snd_hda_activate_path(codec, nomix_path, true, false); path_power_down_sync(codec, mix_path); } } @@ -2240,63 +2261,95 @@ static int create_loopback_mixing_ctl(struct hda_codec *codec) static void call_update_outputs(struct hda_codec *codec); /* for shared I/O, change the pin-control accordingly */ -static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic) +static void update_hp_mic(struct hda_codec *codec, int adc_mux, bool force) { struct hda_gen_spec *spec = codec->spec; + bool as_mic; unsigned int val; - hda_nid_t pin = spec->autocfg.inputs[1].pin; - /* NOTE: this assumes that there are only two inputs, the - * first is the real internal mic and the second is HP/mic jack. - */ + hda_nid_t pin; - val = snd_hda_get_default_vref(codec, pin); + pin = spec->hp_mic_pin; + as_mic = spec->cur_mux[adc_mux] == spec->hp_mic_mux_idx; + + if (!force) { + val = snd_hda_codec_get_pin_target(codec, pin); + if (as_mic) { + if (val & PIN_IN) + return; + } else { + if (val & PIN_OUT) + return; + } + } - /* This pin does not have vref caps - let's enable vref on pin 0x18 - instead, as suggested by Realtek */ + val = snd_hda_get_default_vref(codec, pin); + /* if the HP pin doesn't support VREF and the codec driver gives an + * alternative pin, set up the VREF on that pin instead + */ if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) { const hda_nid_t vref_pin = spec->shared_mic_vref_pin; unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin); if (vref_val != AC_PINCTL_VREF_HIZ) snd_hda_set_pin_ctl_cache(codec, vref_pin, - PIN_IN | (set_as_mic ? vref_val : 0)); + PIN_IN | (as_mic ? vref_val : 0)); } - val = set_as_mic ? val | PIN_IN : PIN_HP; - set_pin_target(codec, pin, val, true); - - spec->automute_speaker = !set_as_mic; - call_update_outputs(codec); + if (!spec->hp_mic_jack_modes) { + if (as_mic) + val |= PIN_IN; + else + val = PIN_HP; + set_pin_target(codec, pin, val, true); + update_hp_automute_hook(codec); + } } /* create a shared input with the headphone out */ -static int create_shared_input(struct hda_codec *codec) +static int create_hp_mic(struct hda_codec *codec) { struct hda_gen_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; unsigned int defcfg; hda_nid_t nid; - /* only one internal input pin? */ - if (cfg->num_inputs != 1) - return 0; - defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin); - if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) + if (!spec->hp_mic) { + if (spec->suppress_hp_mic_detect) + return 0; + /* automatic detection: only if no input or a single internal + * input pin is found, try to detect the shared hp/mic + */ + if (cfg->num_inputs > 1) + return 0; + else if (cfg->num_inputs == 1) { + defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin); + if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) + return 0; + } + } + + spec->hp_mic = 0; /* clear once */ + if (cfg->num_inputs >= AUTO_CFG_MAX_INS) return 0; - if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) - nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */ - else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT) - nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */ - else - return 0; /* both not available */ + nid = 0; + if (cfg->line_out_type == AUTO_PIN_HP_OUT && cfg->line_outs > 0) + nid = cfg->line_out_pins[0]; + else if (cfg->hp_outs > 0) + nid = cfg->hp_pins[0]; + if (!nid) + return 0; if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN)) return 0; /* no input */ - cfg->inputs[1].pin = nid; - cfg->inputs[1].type = AUTO_PIN_MIC; - cfg->num_inputs = 2; - spec->shared_mic_hp = 1; + cfg->inputs[cfg->num_inputs].pin = nid; + cfg->inputs[cfg->num_inputs].type = AUTO_PIN_MIC; + cfg->inputs[cfg->num_inputs].is_headphone_mic = 1; + cfg->num_inputs++; + spec->hp_mic = 1; + spec->hp_mic_pin = nid; + /* we can't handle auto-mic together with HP-mic */ + spec->suppress_auto_mic = 1; snd_printdd("hda-codec: Enable shared I/O jack on NID 0x%x\n", nid); return 0; } @@ -2304,13 +2357,17 @@ static int create_shared_input(struct hda_codec *codec) /* * output jack mode */ + +static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin); + +static const char * const out_jack_texts[] = { + "Line Out", "Headphone Out", +}; + static int out_jack_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char * const texts[] = { - "Line Out", "Headphone Out", - }; - return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts); + return snd_hda_enum_helper_info(kcontrol, uinfo, 2, out_jack_texts); } static int out_jack_mode_get(struct snd_kcontrol *kcontrol, @@ -2372,6 +2429,17 @@ static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin, ; } +static int get_out_jack_num_items(struct hda_codec *codec, hda_nid_t pin) +{ + struct hda_gen_spec *spec = codec->spec; + if (spec->add_jack_modes) { + unsigned int pincap = snd_hda_query_pin_caps(codec, pin); + if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV)) + return 2; + } + return 1; +} + static int create_out_jack_modes(struct hda_codec *codec, int num_pins, hda_nid_t *pins) { @@ -2380,8 +2448,13 @@ static int create_out_jack_modes(struct hda_codec *codec, int num_pins, for (i = 0; i < num_pins; i++) { hda_nid_t pin = pins[i]; - unsigned int pincap = snd_hda_query_pin_caps(codec, pin); - if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV)) { + if (pin == spec->hp_mic_pin) { + int ret = create_hp_mic_jack_mode(codec, pin); + if (ret < 0) + return ret; + continue; + } + if (get_out_jack_num_items(codec, pin) > 1) { struct snd_kcontrol_new *knew; char name[44]; get_jack_mode_name(codec, pin, name, sizeof(name)); @@ -2502,12 +2575,24 @@ static const struct snd_kcontrol_new in_jack_mode_enum = { .put = in_jack_mode_put, }; +static int get_in_jack_num_items(struct hda_codec *codec, hda_nid_t pin) +{ + struct hda_gen_spec *spec = codec->spec; + int nitems = 0; + if (spec->add_jack_modes) + nitems = hweight32(get_vref_caps(codec, pin)); + return nitems ? nitems : 1; +} + static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin) { struct hda_gen_spec *spec = codec->spec; - unsigned int defcfg; struct snd_kcontrol_new *knew; char name[44]; + unsigned int defcfg; + + if (pin == spec->hp_mic_pin) + return 0; /* already done in create_out_jack_mode() */ /* no jack mode for fixed pins */ defcfg = snd_hda_codec_get_pincfg(codec, pin); @@ -2515,7 +2600,7 @@ static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin) return 0; /* no multiple vref caps? */ - if (hweight32(get_vref_caps(codec, pin)) <= 1) + if (get_in_jack_num_items(codec, pin) <= 1) return 0; get_jack_mode_name(codec, pin, name, sizeof(name)); @@ -2526,6 +2611,132 @@ static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin) return 0; } +/* + * HP/mic shared jack mode + */ +static int hp_mic_jack_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + int out_jacks = get_out_jack_num_items(codec, nid); + int in_jacks = get_in_jack_num_items(codec, nid); + const char *text = NULL; + int idx; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = out_jacks + in_jacks; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + idx = uinfo->value.enumerated.item; + if (idx < out_jacks) { + if (out_jacks > 1) + text = out_jack_texts[idx]; + else + text = "Headphone Out"; + } else { + idx -= out_jacks; + if (in_jacks > 1) { + unsigned int vref_caps = get_vref_caps(codec, nid); + text = vref_texts[get_vref_idx(vref_caps, idx)]; + } else + text = "Mic In"; + } + + strcpy(uinfo->value.enumerated.name, text); + return 0; +} + +static int get_cur_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t nid) +{ + int out_jacks = get_out_jack_num_items(codec, nid); + int in_jacks = get_in_jack_num_items(codec, nid); + unsigned int val = snd_hda_codec_get_pin_target(codec, nid); + int idx = 0; + + if (val & PIN_OUT) { + if (out_jacks > 1 && val == PIN_HP) + idx = 1; + } else if (val & PIN_IN) { + idx = out_jacks; + if (in_jacks > 1) { + unsigned int vref_caps = get_vref_caps(codec, nid); + val &= AC_PINCTL_VREFEN; + idx += cvt_from_vref_idx(vref_caps, val); + } + } + return idx; +} + +static int hp_mic_jack_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + ucontrol->value.enumerated.item[0] = + get_cur_hp_mic_jack_mode(codec, nid); + return 0; +} + +static int hp_mic_jack_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + int out_jacks = get_out_jack_num_items(codec, nid); + int in_jacks = get_in_jack_num_items(codec, nid); + unsigned int val, oldval, idx; + + oldval = get_cur_hp_mic_jack_mode(codec, nid); + idx = ucontrol->value.enumerated.item[0]; + if (oldval == idx) + return 0; + + if (idx < out_jacks) { + if (out_jacks > 1) + val = idx ? PIN_HP : PIN_OUT; + else + val = PIN_HP; + } else { + idx -= out_jacks; + if (in_jacks > 1) { + unsigned int vref_caps = get_vref_caps(codec, nid); + val = snd_hda_codec_get_pin_target(codec, nid); + val &= ~(AC_PINCTL_VREFEN | PIN_HP); + val |= get_vref_idx(vref_caps, idx) | PIN_IN; + } else + val = snd_hda_get_default_vref(codec, nid); + } + snd_hda_set_pin_ctl_cache(codec, nid, val); + update_hp_automute_hook(codec); + + return 1; +} + +static const struct snd_kcontrol_new hp_mic_jack_mode_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = hp_mic_jack_mode_info, + .get = hp_mic_jack_mode_get, + .put = hp_mic_jack_mode_put, +}; + +static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin) +{ + struct hda_gen_spec *spec = codec->spec; + struct snd_kcontrol_new *knew; + + if (get_out_jack_num_items(codec, pin) <= 1 && + get_in_jack_num_items(codec, pin) <= 1) + return 0; /* no need */ + knew = snd_hda_gen_add_kctl(spec, "Headphone Mic Jack Mode", + &hp_mic_jack_mode_enum); + if (!knew) + return -ENOMEM; + knew->private_value = pin; + spec->hp_mic_jack_modes = 1; + return 0; +} /* * Parse input paths @@ -2648,7 +2859,6 @@ static int check_dyn_adc_switch(struct hda_codec *codec) unsigned int ok_bits; int i, n, nums; - again: nums = 0; ok_bits = 0; for (n = 0; n < spec->num_adc_nids; n++) { @@ -2663,12 +2873,6 @@ static int check_dyn_adc_switch(struct hda_codec *codec) } if (!ok_bits) { - if (spec->shared_mic_hp) { - spec->shared_mic_hp = 0; - imux->num_items = 1; - goto again; - } - /* check whether ADC-switch is possible */ for (i = 0; i < imux->num_items; i++) { for (n = 0; n < spec->num_adc_nids; n++) { @@ -2701,7 +2905,8 @@ static int check_dyn_adc_switch(struct hda_codec *codec) spec->num_adc_nids = nums; } - if (imux->num_items == 1 || spec->shared_mic_hp) { + if (imux->num_items == 1 || + (imux->num_items == 2 && spec->hp_mic)) { snd_printdd("hda-codec: reducing to a single ADC\n"); spec->num_adc_nids = 1; /* reduce to a single ADC */ } @@ -2738,6 +2943,8 @@ static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin, snd_hda_get_path_idx(codec, path); if (!imux_added) { + if (spec->hp_mic_pin == pin) + spec->hp_mic_mux_idx = imux->num_items; spec->imux_pins[imux->num_items] = pin; snd_hda_add_imux_item(imux, label, cfg_idx, NULL); imux_added = true; @@ -2812,7 +3019,8 @@ static int create_input_ctls(struct hda_codec *codec) val = PIN_IN; if (cfg->inputs[i].type == AUTO_PIN_MIC) val |= snd_hda_get_default_vref(codec, pin); - set_pin_target(codec, pin, val, false); + if (pin != spec->hp_mic_pin) + set_pin_target(codec, pin, val, false); if (mixer) { if (is_reachable_path(codec, pin, mixer)) { @@ -2830,7 +3038,7 @@ static int create_input_ctls(struct hda_codec *codec) if (err < 0) return err; - if (spec->add_in_jack_modes) { + if (spec->add_jack_modes) { err = create_in_jack_mode(codec, pin); if (err < 0) return err; @@ -3462,8 +3670,8 @@ static int mux_select(struct hda_codec *codec, unsigned int adc_idx, spec->cur_mux[adc_idx] = idx; - if (spec->shared_mic_hp) - update_shared_mic_hp(codec, spec->cur_mux[adc_idx]); + if (spec->hp_mic) + update_hp_mic(codec, adc_idx, false); if (spec->dyn_adc_switch) dyn_adc_pcm_resetup(codec, idx); @@ -3511,18 +3719,21 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, for (i = 0; i < num_pins; i++) { hda_nid_t nid = pins[i]; - unsigned int val; + unsigned int val, oldval; if (!nid) break; + oldval = snd_hda_codec_get_pin_target(codec, nid); + if (oldval & PIN_IN) + continue; /* no mute for inputs */ /* don't reset VREF value in case it's controlling * the amp (see alc861_fixup_asus_amp_vref_0f()) */ if (spec->keep_vref_in_automute) - val = snd_hda_codec_get_pin_target(codec, nid) & ~PIN_HP; + val = oldval & ~PIN_HP; else val = 0; if (!mute) - val |= snd_hda_codec_get_pin_target(codec, nid); + val |= oldval; /* here we call update_pin_ctl() so that the pinctl is changed * without changing the pinctl target value; * the original target value will be still referred at the @@ -3543,8 +3754,7 @@ void snd_hda_gen_update_outputs(struct hda_codec *codec) * in general, HP pins/amps control should be enabled in all cases, * but currently set only for master_mute, just to be safe */ - if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */ - do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), + do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), spec->autocfg.hp_pins, spec->master_mute); if (!spec->automute_speaker) @@ -3649,10 +3859,7 @@ static void update_automute_all(struct hda_codec *codec) { struct hda_gen_spec *spec = codec->spec; - if (spec->hp_automute_hook) - spec->hp_automute_hook(codec, NULL); - else - snd_hda_gen_hp_automute(codec, NULL); + update_hp_automute_hook(codec); if (spec->line_automute_hook) spec->line_automute_hook(codec, NULL); else @@ -3978,6 +4185,11 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, cfg = &spec->autocfg; } + if (!spec->main_out_badness) + spec->main_out_badness = &hda_main_out_badness; + if (!spec->extra_out_badness) + spec->extra_out_badness = &hda_extra_out_badness; + fill_all_dac_nids(codec); if (!cfg->line_outs) { @@ -4024,7 +4236,7 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, err = create_loopback_mixing_ctl(codec); if (err < 0) return err; - err = create_shared_input(codec); + err = create_hp_mic(codec); if (err < 0) return err; err = create_input_ctls(codec); @@ -4050,11 +4262,9 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, if (err < 0) return err; - if (!spec->shared_mic_hp) { - err = check_auto_mic_availability(codec); - if (err < 0) - return err; - } + err = check_auto_mic_availability(codec); + if (err < 0) + return err; err = create_capture_mixers(codec); if (err < 0) @@ -4064,7 +4274,7 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, if (err < 0) return err; - if (spec->add_out_jack_modes) { + if (spec->add_jack_modes) { if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { err = create_out_jack_modes(codec, cfg->line_outs, cfg->line_out_pins); @@ -4085,6 +4295,12 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, if (spec->power_down_unused) codec->power_filter = snd_hda_gen_path_power_filter; + if (!spec->no_analog && spec->beep_nid) { + err = snd_hda_attach_beep_device(codec, spec->beep_nid); + if (err < 0) + return err; + } + return 1; } EXPORT_SYMBOL_HDA(snd_hda_gen_parse_auto_config); @@ -4161,17 +4377,6 @@ int snd_hda_gen_build_controls(struct hda_codec *codec) free_kctls(spec); /* no longer needed */ - if (spec->shared_mic_hp) { - int err; - int nid = spec->autocfg.inputs[1].pin; - err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0); - if (err < 0) - return err; - err = snd_hda_jack_detect_enable(codec, nid, 0); - if (err < 0) - return err; - } - err = snd_hda_jack_add_kctls(codec, &spec->autocfg); if (err < 0) return err; @@ -4729,7 +4934,8 @@ static void set_output_and_unmute(struct hda_codec *codec, int path_idx) return; pin = path->path[path->depth - 1]; restore_pin_ctl(codec, pin); - snd_hda_activate_path(codec, path, path->active, true); + snd_hda_activate_path(codec, path, path->active, + aamix_default(codec->spec)); set_pin_eapd(codec, pin, path->active); } @@ -4779,7 +4985,8 @@ static void init_multi_io(struct hda_codec *codec) if (!spec->multi_io[i].ctl_in) spec->multi_io[i].ctl_in = snd_hda_codec_get_pin_target(codec, pin); - snd_hda_activate_path(codec, path, path->active, true); + snd_hda_activate_path(codec, path, path->active, + aamix_default(spec)); } } @@ -4826,11 +5033,10 @@ static void init_input_src(struct hda_codec *codec) snd_hda_activate_path(codec, path, active, false); } } + if (spec->hp_mic) + update_hp_mic(codec, c, true); } - if (spec->shared_mic_hp) - update_shared_mic_hp(codec, spec->cur_mux[0]); - if (spec->cap_sync_hook) spec->cap_sync_hook(codec, NULL); } @@ -4911,6 +5117,7 @@ EXPORT_SYMBOL_HDA(snd_hda_gen_init); */ void snd_hda_gen_free(struct hda_codec *codec) { + snd_hda_detach_beep_device(codec); snd_hda_gen_spec_free(codec->spec); kfree(codec->spec); codec->spec = NULL; |