static void parse_cs421x_digital(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->gen.autocfg; int i; for (i = 0; i < cfg->dig_outs; i++) { hda_nid_t nid = cfg->dig_out_pins[i]; if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { spec->spdif_detect = 1; snd_hda_jack_detect_enable_callback(codec, nid, SPDIF_EVENT, cs4210_spdif_automute); } } }
/* add a (input-boost) volume control to the given input pin */ static int add_input_volume_control(struct hda_codec *codec, struct auto_pin_cfg *cfg, int item) { hda_nid_t pin = cfg->inputs[item].pin; u32 caps; const char *label; struct snd_kcontrol *kctl; if (!(get_wcaps(codec, pin) & AC_WCAP_IN_AMP)) return 0; caps = query_amp_caps(codec, pin, HDA_INPUT); caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; if (caps <= 1) return 0; label = hda_get_autocfg_input_label(codec, cfg, item); return add_volume(codec, label, 0, HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT), 1, &kctl); }
static void init_output(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; int i; /* mute first */ for (i = 0; i < spec->multiout.num_dacs; i++) snd_hda_codec_write(codec, spec->multiout.dac_nids[i], 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); if (spec->multiout.hp_nid) snd_hda_codec_write(codec, spec->multiout.hp_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) { if (!spec->multiout.extra_out_nid[i]) break; snd_hda_codec_write(codec, spec->multiout.extra_out_nid[i], 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); } /* set appropriate pin controls */ for (i = 0; i < cfg->line_outs; i++) snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); for (i = 0; i < cfg->hp_outs; i++) { hda_nid_t nid = cfg->hp_pins[i]; snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); if (!cfg->speaker_outs) continue; if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | HP_EVENT); spec->hp_detect = 1; } } for (i = 0; i < cfg->speaker_outs; i++) snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); if (spec->hp_detect) cs_automute(codec); }
static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, unsigned int *idxp) { int i, idx; hda_nid_t nid; nid = codec->start_nid; for (i = 0; i < codec->num_nodes; i++, nid++) { unsigned int type; type = get_wcaps_type(get_wcaps(codec, nid)); if (type != AC_WID_AUD_IN) continue; idx = snd_hda_get_conn_index(codec, nid, pin, false); if (idx >= 0) { *idxp = idx; return nid; } } return 0; }
static int atihdmi_build_pcms(struct hda_codec *codec) { struct atihdmi_spec *spec = codec->spec; struct hda_pcm *info = &spec->pcm_rec; unsigned int chans; codec->num_pcms = 1; codec->pcm_info = info; info->name = "ATI HDMI"; info->pcm_type = HDA_PCM_TYPE_HDMI; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback; /* FIXME: we must check ELD and change the PCM parameters dynamically */ chans = get_wcaps(codec, CVT_NID); chans = (chans & AC_WCAP_CHAN_CNT_EXT) >> 13; chans = ((chans << 1) | 1) + 1; info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans; return 0; }
static int patch_cs4208(struct hda_codec *codec) { struct cs_spec *spec; int err; spec = cs_alloc_spec(codec, CS4208_VENDOR_NID); if (!spec) return -ENOMEM; spec->gen.automute_hook = cs_automute; /* exclude NID 0x10 (HP) from output volumes due to different steps */ spec->gen.out_vol_mask = 1ULL << 0x10; snd_hda_pick_fixup(codec, cs4208_models, cs4208_fixup_tbl, cs4208_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); snd_hda_override_wcaps(codec, 0x18, get_wcaps(codec, 0x18) | AC_WCAP_STEREO); cs4208_fix_amp_caps(codec, 0x18); cs4208_fix_amp_caps(codec, 0x1b); cs4208_fix_amp_caps(codec, 0x1c); err = cs_parse_auto_config(codec); if (err < 0) goto error; codec->patch_ops = cs_patch_ops; snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; error: cs_free(codec); return err; }
/* parse EAPDs */ static void cx_auto_parse_eapd(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; hda_nid_t nid; for_each_hda_codec_node(nid, codec) { if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) continue; if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) continue; spec->eapds[spec->num_eapds++] = nid; if (spec->num_eapds >= ARRAY_SIZE(spec->eapds)) break; } /* NOTE: below is a wild guess; if we have more than two EAPDs, * it's a new chip, where EAPDs are supposed to be associated to * pins, and we can control EAPD per pin. * OTOH, if only one or two EAPDs are found, it's an old chip, * thus it might control over all pins. */ if (spec->num_eapds > 2) spec->dynamic_eapd = 1; }
static int ca0110_build_controls(struct hda_codec *codec) { struct ca0110_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; static const char * const prefix[AUTO_CFG_MAX_OUTS] = { "Front", "Surround", NULL, "Side", "Multi" }; hda_nid_t mutenid; int i, err; for (i = 0; i < spec->multiout.num_dacs; i++) { if (get_wcaps(codec, spec->out_pins[i]) & AC_WCAP_OUT_AMP) mutenid = spec->out_pins[i]; else mutenid = spec->multiout.dac_nids[i]; if (!prefix[i]) { err = add_mono_switch(codec, mutenid, "Center", 1); if (err < 0) return err; err = add_mono_switch(codec, mutenid, "LFE", 1); if (err < 0) return err; err = add_mono_volume(codec, spec->multiout.dac_nids[i], "Center", 1); if (err < 0) return err; err = add_mono_volume(codec, spec->multiout.dac_nids[i], "LFE", 1); if (err < 0) return err; } else { err = add_out_switch(codec, mutenid, prefix[i]); if (err < 0) return err; err = add_out_volume(codec, spec->multiout.dac_nids[i], prefix[i]); if (err < 0) return err; } } if (cfg->hp_outs) { if (get_wcaps(codec, cfg->hp_pins[0]) & AC_WCAP_OUT_AMP) mutenid = cfg->hp_pins[0]; else mutenid = spec->multiout.dac_nids[i]; err = add_out_switch(codec, mutenid, "Headphone"); if (err < 0) return err; if (spec->hp_dac) { err = add_out_volume(codec, spec->hp_dac, "Headphone"); if (err < 0) return err; } } for (i = 0; i < spec->num_inputs; i++) { const char *label = spec->input_labels[i]; if (get_wcaps(codec, spec->input_pins[i]) & AC_WCAP_IN_AMP) mutenid = spec->input_pins[i]; else mutenid = spec->adcs[i]; err = add_in_switch(codec, mutenid, label); if (err < 0) return err; err = add_in_volume(codec, spec->adcs[i], label); if (err < 0) return err; } if (spec->dig_out) { err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out, spec->dig_out); 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->dig_in) { err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in); if (err < 0) return err; err = add_in_volume(codec, spec->dig_in, "IEC958"); } return 0; }
/* * Parse all pin widgets and store the useful pin nids to cfg * * The number of line-outs or any primary output is stored in line_outs, * and the corresponding output pins are assigned to line_out_pins[], * in the order of front, rear, CLFE, side, ... * * If more extra outputs (speaker and headphone) are found, the pins are * assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack * is detected, one of speaker of HP pins is assigned as the primary * output, i.e. to line_out_pins[0]. So, line_outs is always positive * if any analog output exists. * * The analog input pins are assigned to inputs array. * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, * respectively. */ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, struct auto_pin_cfg *cfg, const hda_nid_t *ignore_nids, unsigned int cond_flags) { hda_nid_t nid; short seq, assoc_line_out; struct auto_out_pin line_out[ARRAY_SIZE(cfg->line_out_pins)]; struct auto_out_pin speaker_out[ARRAY_SIZE(cfg->speaker_pins)]; struct auto_out_pin hp_out[ARRAY_SIZE(cfg->hp_pins)]; int i; if (!snd_hda_get_int_hint(codec, "parser_flags", &i)) cond_flags = i; memset(cfg, 0, sizeof(*cfg)); memset(line_out, 0, sizeof(line_out)); memset(speaker_out, 0, sizeof(speaker_out)); memset(hp_out, 0, sizeof(hp_out)); assoc_line_out = 0; for_each_hda_codec_node(nid, codec) { unsigned int wid_caps = get_wcaps(codec, nid); unsigned int wid_type = get_wcaps_type(wid_caps); unsigned int def_conf; short assoc, loc, conn, dev; /* read all default configuration for pin complex */ if (wid_type != AC_WID_PIN) continue; /* ignore the given nids (e.g. pc-beep returns error) */ if (ignore_nids && is_in_nid_list(nid, ignore_nids)) continue; def_conf = snd_hda_codec_get_pincfg(codec, nid); conn = get_defcfg_connect(def_conf); if (conn == AC_JACK_PORT_NONE) continue; loc = get_defcfg_location(def_conf); dev = get_defcfg_device(def_conf); /* workaround for buggy BIOS setups */ if (dev == AC_JACK_LINE_OUT) { if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH) dev = AC_JACK_SPEAKER; } if (!check_pincap_validity(codec, nid, dev)) continue; switch (dev) { case AC_JACK_LINE_OUT: seq = get_defcfg_sequence(def_conf); assoc = get_defcfg_association(def_conf); if (!(wid_caps & AC_WCAP_STEREO)) if (!cfg->mono_out_pin) cfg->mono_out_pin = nid; if (!assoc) continue; if (!assoc_line_out) assoc_line_out = assoc; else if (assoc_line_out != assoc) { codec_info(codec, "ignore pin 0x%x with mismatching assoc# 0x%x vs 0x%x\n", nid, assoc, assoc_line_out); continue; } if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) { codec_info(codec, "ignore pin 0x%x, too many assigned pins\n", nid); continue; } line_out[cfg->line_outs].pin = nid; line_out[cfg->line_outs].seq = seq; cfg->line_outs++; break; case AC_JACK_SPEAKER: seq = get_defcfg_sequence(def_conf); assoc = get_defcfg_association(def_conf); if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) { codec_info(codec, "ignore pin 0x%x, too many assigned pins\n", nid); continue; } speaker_out[cfg->speaker_outs].pin = nid; speaker_out[cfg->speaker_outs].seq = (assoc << 4) | seq; cfg->speaker_outs++; break; case AC_JACK_HP_OUT: seq = get_defcfg_sequence(def_conf); assoc = get_defcfg_association(def_conf); if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) { codec_info(codec, "ignore pin 0x%x, too many assigned pins\n", nid); continue; } hp_out[cfg->hp_outs].pin = nid; hp_out[cfg->hp_outs].seq = (assoc << 4) | seq; cfg->hp_outs++; break; case AC_JACK_MIC_IN: add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_MIC); break; case AC_JACK_LINE_IN: add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_LINE_IN); break; case AC_JACK_CD: add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_CD); break; case AC_JACK_AUX: add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_AUX); break; case AC_JACK_SPDIF_OUT: case AC_JACK_DIG_OTHER_OUT: if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins)) { codec_info(codec, "ignore pin 0x%x, too many assigned pins\n", nid); continue; } cfg->dig_out_pins[cfg->dig_outs] = nid; cfg->dig_out_type[cfg->dig_outs] = (loc == AC_JACK_LOC_HDMI) ? HDA_PCM_TYPE_HDMI : HDA_PCM_TYPE_SPDIF; cfg->dig_outs++; break; case AC_JACK_SPDIF_IN: case AC_JACK_DIG_OTHER_IN: cfg->dig_in_pin = nid; if (loc == AC_JACK_LOC_HDMI) cfg->dig_in_type = HDA_PCM_TYPE_HDMI; else cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; break; } }
/* * Parse all pin widgets and store the useful pin nids to cfg * * The number of line-outs or any primary output is stored in line_outs, * and the corresponding output pins are assigned to line_out_pins[], * in the order of front, rear, CLFE, side, ... * * If more extra outputs (speaker and headphone) are found, the pins are * assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack * is detected, one of speaker of HP pins is assigned as the primary * output, i.e. to line_out_pins[0]. So, line_outs is always positive * if any analog output exists. * * The analog input pins are assigned to inputs array. * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, * respectively. */ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, struct auto_pin_cfg *cfg, const hda_nid_t *ignore_nids, unsigned int cond_flags) { hda_nid_t nid, end_nid; short seq, assoc_line_out; short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)]; short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)]; short sequences_hp[ARRAY_SIZE(cfg->hp_pins)]; int i; memset(cfg, 0, sizeof(*cfg)); memset(sequences_line_out, 0, sizeof(sequences_line_out)); memset(sequences_speaker, 0, sizeof(sequences_speaker)); memset(sequences_hp, 0, sizeof(sequences_hp)); assoc_line_out = 0; 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 = get_wcaps_type(wid_caps); unsigned int def_conf; short assoc, loc, conn, dev; /* read all default configuration for pin complex */ if (wid_type != AC_WID_PIN) continue; /* ignore the given nids (e.g. pc-beep returns error) */ if (ignore_nids && is_in_nid_list(nid, ignore_nids)) continue; def_conf = snd_hda_codec_get_pincfg(codec, nid); conn = get_defcfg_connect(def_conf); if (conn == AC_JACK_PORT_NONE) continue; loc = get_defcfg_location(def_conf); dev = get_defcfg_device(def_conf); /* workaround for buggy BIOS setups */ if (dev == AC_JACK_LINE_OUT) { if (conn == AC_JACK_PORT_FIXED) dev = AC_JACK_SPEAKER; } switch (dev) { case AC_JACK_LINE_OUT: seq = get_defcfg_sequence(def_conf); assoc = get_defcfg_association(def_conf); if (!(wid_caps & AC_WCAP_STEREO)) if (!cfg->mono_out_pin) cfg->mono_out_pin = nid; if (!assoc) continue; if (!assoc_line_out) assoc_line_out = assoc; else if (assoc_line_out != assoc) continue; if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) continue; cfg->line_out_pins[cfg->line_outs] = nid; sequences_line_out[cfg->line_outs] = seq; cfg->line_outs++; break; case AC_JACK_SPEAKER: seq = get_defcfg_sequence(def_conf); assoc = get_defcfg_association(def_conf); if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) continue; cfg->speaker_pins[cfg->speaker_outs] = nid; sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq; cfg->speaker_outs++; break; case AC_JACK_HP_OUT: seq = get_defcfg_sequence(def_conf); assoc = get_defcfg_association(def_conf); if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) continue; cfg->hp_pins[cfg->hp_outs] = nid; sequences_hp[cfg->hp_outs] = (assoc << 4) | seq; cfg->hp_outs++; break; case AC_JACK_MIC_IN: add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC); break; case AC_JACK_LINE_IN: add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN); break; case AC_JACK_CD: add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD); break; case AC_JACK_AUX: add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX); break; case AC_JACK_SPDIF_OUT: case AC_JACK_DIG_OTHER_OUT: if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins)) continue; cfg->dig_out_pins[cfg->dig_outs] = nid; cfg->dig_out_type[cfg->dig_outs] = (loc == AC_JACK_LOC_HDMI) ? HDA_PCM_TYPE_HDMI : HDA_PCM_TYPE_SPDIF; cfg->dig_outs++; break; case AC_JACK_SPDIF_IN: case AC_JACK_DIG_OTHER_IN: cfg->dig_in_pin = nid; if (loc == AC_JACK_LOC_HDMI) cfg->dig_in_type = HDA_PCM_TYPE_HDMI; else cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; break; } } /* FIX-UP: * If no line-out is defined but multiple HPs are found, * some of them might be the real line-outs. */ if (!cfg->line_outs && cfg->hp_outs > 1 && !(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) { int i = 0; while (i < cfg->hp_outs) { /* The real HPs should have the sequence 0x0f */ if ((sequences_hp[i] & 0x0f) == 0x0f) { i++; continue; } /* Move it to the line-out table */ cfg->line_out_pins[cfg->line_outs] = cfg->hp_pins[i]; sequences_line_out[cfg->line_outs] = sequences_hp[i]; cfg->line_outs++; cfg->hp_outs--; memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1, sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i)); memmove(sequences_hp + i, sequences_hp + i + 1, sizeof(sequences_hp[0]) * (cfg->hp_outs - i)); } memset(cfg->hp_pins + cfg->hp_outs, 0, sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs)); if (!cfg->hp_outs) cfg->line_out_type = AUTO_PIN_HP_OUT; } /* sort by sequence */ sort_pins_by_sequence(cfg->line_out_pins, sequences_line_out, cfg->line_outs); sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker, cfg->speaker_outs); sort_pins_by_sequence(cfg->hp_pins, sequences_hp, cfg->hp_outs); /* * FIX-UP: if no line-outs are detected, try to use speaker or HP pin * as a primary output */ if (!cfg->line_outs && !(cond_flags & HDA_PINCFG_NO_LO_FIXUP)) { if (cfg->speaker_outs) { cfg->line_outs = cfg->speaker_outs; memcpy(cfg->line_out_pins, cfg->speaker_pins, sizeof(cfg->speaker_pins)); cfg->speaker_outs = 0; memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; } else if (cfg->hp_outs) { cfg->line_outs = cfg->hp_outs; memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins)); cfg->hp_outs = 0; memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); cfg->line_out_type = AUTO_PIN_HP_OUT; } } reorder_outputs(cfg->line_outs, cfg->line_out_pins); reorder_outputs(cfg->hp_outs, cfg->hp_pins); reorder_outputs(cfg->speaker_outs, cfg->speaker_pins); sort_autocfg_input_pins(cfg); /* * debug prints of the parsed results */ snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n", cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1], cfg->line_out_pins[2], cfg->line_out_pins[3], cfg->line_out_pins[4], cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" : (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ? "speaker" : "line")); snd_printd(" speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", cfg->speaker_outs, cfg->speaker_pins[0], cfg->speaker_pins[1], cfg->speaker_pins[2], cfg->speaker_pins[3], cfg->speaker_pins[4]); snd_printd(" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", cfg->hp_outs, cfg->hp_pins[0], cfg->hp_pins[1], cfg->hp_pins[2], cfg->hp_pins[3], cfg->hp_pins[4]); snd_printd(" mono: mono_out=0x%x\n", cfg->mono_out_pin); if (cfg->dig_outs) snd_printd(" dig-out=0x%x/0x%x\n", cfg->dig_out_pins[0], cfg->dig_out_pins[1]); snd_printd(" inputs:\n"); for (i = 0; i < cfg->num_inputs; i++) { snd_printd(" %s=0x%x\n", hda_get_autocfg_input_label(codec, cfg, i), cfg->inputs[i].pin); } if (cfg->dig_in_pin) snd_printd(" dig-in=0x%x\n", cfg->dig_in_pin); return 0; }
/* * Parse all pin widgets and store the useful pin nids to cfg * * The number of line-outs or any primary output is stored in line_outs, * and the corresponding output pins are assigned to line_out_pins[], * in the order of front, rear, CLFE, side, ... * * If more extra outputs (speaker and headphone) are found, the pins are * assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack * is detected, one of speaker of HP pins is assigned as the primary * output, i.e. to line_out_pins[0]. So, line_outs is always positive * if any analog output exists. * * The analog input pins are assigned to inputs array. * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, * respectively. */ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, struct auto_pin_cfg *cfg, const hda_nid_t *ignore_nids, unsigned int cond_flags) { hda_nid_t nid, end_nid; short seq, assoc_line_out; struct auto_out_pin line_out[ARRAY_SIZE(cfg->line_out_pins)]; struct auto_out_pin speaker_out[ARRAY_SIZE(cfg->speaker_pins)]; struct auto_out_pin hp_out[ARRAY_SIZE(cfg->hp_pins)]; int i; if (!snd_hda_get_int_hint(codec, "parser_flags", &i)) cond_flags = i; memset(cfg, 0, sizeof(*cfg)); memset(line_out, 0, sizeof(line_out)); memset(speaker_out, 0, sizeof(speaker_out)); memset(hp_out, 0, sizeof(hp_out)); assoc_line_out = 0; 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 = get_wcaps_type(wid_caps); unsigned int def_conf; short assoc, loc, conn, dev; /* read all default configuration for pin complex */ if (wid_type != AC_WID_PIN) continue; /* ignore the given nids (e.g. pc-beep returns error) */ if (ignore_nids && is_in_nid_list(nid, ignore_nids)) continue; def_conf = snd_hda_codec_get_pincfg(codec, nid); conn = get_defcfg_connect(def_conf); if (conn == AC_JACK_PORT_NONE) continue; loc = get_defcfg_location(def_conf); dev = get_defcfg_device(def_conf); /* workaround for buggy BIOS setups */ if (dev == AC_JACK_LINE_OUT) { if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH) dev = AC_JACK_SPEAKER; } if (!check_pincap_validity(codec, nid, dev)) continue; switch (dev) { case AC_JACK_LINE_OUT: seq = get_defcfg_sequence(def_conf); assoc = get_defcfg_association(def_conf); if (!(wid_caps & AC_WCAP_STEREO)) if (!cfg->mono_out_pin) cfg->mono_out_pin = nid; if (!assoc) continue; if (!assoc_line_out) assoc_line_out = assoc; else if (assoc_line_out != assoc) continue; if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) continue; line_out[cfg->line_outs].pin = nid; line_out[cfg->line_outs].seq = seq; cfg->line_outs++; break; case AC_JACK_SPEAKER: seq = get_defcfg_sequence(def_conf); assoc = get_defcfg_association(def_conf); if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) continue; speaker_out[cfg->speaker_outs].pin = nid; speaker_out[cfg->speaker_outs].seq = (assoc << 4) | seq; cfg->speaker_outs++; break; case AC_JACK_HP_OUT: seq = get_defcfg_sequence(def_conf); assoc = get_defcfg_association(def_conf); if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) continue; hp_out[cfg->hp_outs].pin = nid; hp_out[cfg->hp_outs].seq = (assoc << 4) | seq; cfg->hp_outs++; break; case AC_JACK_MIC_IN: add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC); break; case AC_JACK_LINE_IN: add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN); break; case AC_JACK_CD: add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD); break; case AC_JACK_AUX: add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX); break; case AC_JACK_SPDIF_OUT: case AC_JACK_DIG_OTHER_OUT: if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins)) continue; cfg->dig_out_pins[cfg->dig_outs] = nid; cfg->dig_out_type[cfg->dig_outs] = (loc == AC_JACK_LOC_HDMI) ? HDA_PCM_TYPE_HDMI : HDA_PCM_TYPE_SPDIF; cfg->dig_outs++; break; case AC_JACK_SPDIF_IN: case AC_JACK_DIG_OTHER_IN: cfg->dig_in_pin = nid; if (loc == AC_JACK_LOC_HDMI) cfg->dig_in_type = HDA_PCM_TYPE_HDMI; else cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; break; } } /* Find a pin that could be a headset or headphone mic */ if (cond_flags & HDA_PINCFG_HEADSET_MIC || cond_flags & HDA_PINCFG_HEADPHONE_MIC) { bool hsmic = !!(cond_flags & HDA_PINCFG_HEADSET_MIC); bool hpmic = !!(cond_flags & HDA_PINCFG_HEADPHONE_MIC); for (i = 0; (hsmic || hpmic) && (i < cfg->num_inputs); i++) if (hsmic && can_be_headset_mic(codec, &cfg->inputs[i], 0xc)) { cfg->inputs[i].is_headset_mic = 1; hsmic = false; } else if (hpmic && can_be_headset_mic(codec, &cfg->inputs[i], 0xd)) { cfg->inputs[i].is_headphone_mic = 1; hpmic = false; } /* If we didn't find our sequence number mark, fall back to any sequence number */ for (i = 0; (hsmic || hpmic) && (i < cfg->num_inputs); i++) { if (!can_be_headset_mic(codec, &cfg->inputs[i], -1)) continue; if (hsmic) { cfg->inputs[i].is_headset_mic = 1; hsmic = false; } else if (hpmic) { cfg->inputs[i].is_headphone_mic = 1; hpmic = false; } } if (hsmic) snd_printdd("Told to look for a headset mic, but didn't find any.\n"); if (hpmic) snd_printdd("Told to look for a headphone mic, but didn't find any.\n"); } /* FIX-UP: * If no line-out is defined but multiple HPs are found, * some of them might be the real line-outs. */ if (!cfg->line_outs && cfg->hp_outs > 1 && !(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) { int i = 0; while (i < cfg->hp_outs) { /* The real HPs should have the sequence 0x0f */ if ((hp_out[i].seq & 0x0f) == 0x0f) { i++; continue; } /* Move it to the line-out table */ line_out[cfg->line_outs++] = hp_out[i]; cfg->hp_outs--; memmove(hp_out + i, hp_out + i + 1, sizeof(hp_out[0]) * (cfg->hp_outs - i)); } memset(hp_out + cfg->hp_outs, 0, sizeof(hp_out[0]) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs)); if (!cfg->hp_outs) cfg->line_out_type = AUTO_PIN_HP_OUT; } /* sort by sequence */ sort_pins_by_sequence(cfg->line_out_pins, line_out, cfg->line_outs); sort_pins_by_sequence(cfg->speaker_pins, speaker_out, cfg->speaker_outs); sort_pins_by_sequence(cfg->hp_pins, hp_out, cfg->hp_outs); /* * FIX-UP: if no line-outs are detected, try to use speaker or HP pin * as a primary output */ if (!cfg->line_outs && !(cond_flags & HDA_PINCFG_NO_LO_FIXUP)) { if (cfg->speaker_outs) { cfg->line_outs = cfg->speaker_outs; memcpy(cfg->line_out_pins, cfg->speaker_pins, sizeof(cfg->speaker_pins)); cfg->speaker_outs = 0; memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; } else if (cfg->hp_outs) { cfg->line_outs = cfg->hp_outs; memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins)); cfg->hp_outs = 0; memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); cfg->line_out_type = AUTO_PIN_HP_OUT; } } reorder_outputs(cfg->line_outs, cfg->line_out_pins); reorder_outputs(cfg->hp_outs, cfg->hp_pins); reorder_outputs(cfg->speaker_outs, cfg->speaker_pins); /* sort inputs in the order of AUTO_PIN_* type */ sort(cfg->inputs, cfg->num_inputs, sizeof(cfg->inputs[0]), compare_input_type, NULL); /* * debug prints of the parsed results */ snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n", cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1], cfg->line_out_pins[2], cfg->line_out_pins[3], cfg->line_out_pins[4], cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" : (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ? "speaker" : "line")); snd_printd(" speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", cfg->speaker_outs, cfg->speaker_pins[0], cfg->speaker_pins[1], cfg->speaker_pins[2], cfg->speaker_pins[3], cfg->speaker_pins[4]); snd_printd(" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", cfg->hp_outs, cfg->hp_pins[0], cfg->hp_pins[1], cfg->hp_pins[2], cfg->hp_pins[3], cfg->hp_pins[4]); snd_printd(" mono: mono_out=0x%x\n", cfg->mono_out_pin); if (cfg->dig_outs) snd_printd(" dig-out=0x%x/0x%x\n", cfg->dig_out_pins[0], cfg->dig_out_pins[1]); snd_printd(" inputs:\n"); for (i = 0; i < cfg->num_inputs; i++) { snd_printd(" %s=0x%x\n", hda_get_autocfg_input_label(codec, cfg, i), cfg->inputs[i].pin); } if (cfg->dig_in_pin) snd_printd(" dig-in=0x%x\n", cfg->dig_in_pin); return 0; }