static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, const struct auto_pin_cfg *cfg, const char *base_name) { unsigned int def_conf, conn; char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; int idx, err; bool phantom_jack; if (!nid) return 0; def_conf = snd_hda_codec_get_pincfg(codec, nid); conn = get_defcfg_connect(def_conf); if (conn == AC_JACK_PORT_NONE) return 0; phantom_jack = (conn != AC_JACK_PORT_COMPLEX) || !is_jack_detectable(codec, nid); if (base_name) { strlcpy(name, base_name, sizeof(name)); idx = 0; } else snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), &idx); if (phantom_jack) /* Example final name: "Internal Mic Phantom Jack" */ strncat(name, " Phantom", sizeof(name) - strlen(name) - 1); idx = get_unique_index(codec, name, idx); err = __snd_hda_jack_add_kctl(codec, nid, name, idx, phantom_jack); if (err < 0) return err; if (!phantom_jack) return snd_hda_jack_detect_enable(codec, nid); return 0; }
static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, const struct auto_pin_cfg *cfg, char *lastname, int *lastidx) { unsigned int def_conf, conn; char name[44]; int idx, err; if (!nid) return 0; if (!is_jack_detectable(codec, nid)) return 0; def_conf = snd_hda_codec_get_pincfg(codec, nid); conn = get_defcfg_connect(def_conf); if (conn != AC_JACK_PORT_COMPLEX) return 0; snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), &idx); if (!strcmp(name, lastname) && idx == *lastidx) idx++; strncpy(lastname, name, 44); *lastidx = idx; err = snd_hda_jack_add_kctl(codec, nid, name, idx); if (err < 0) return err; return snd_hda_jack_detect_enable(codec, nid, 0); }
static void cs_automute(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; unsigned int hp_present; hda_nid_t nid; int i; hp_present = 0; for (i = 0; i < cfg->hp_outs; i++) { nid = cfg->hp_pins[i]; if (!is_jack_detectable(codec, nid)) continue; hp_present = snd_hda_jack_detect(codec, nid); if (hp_present) break; } for (i = 0; i < cfg->speaker_outs; i++) { nid = cfg->speaker_pins[i]; snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, hp_present ? 0 : PIN_OUT); } if (spec->board_config == CS420X_MBP53 || spec->board_config == CS420X_MBP55 || spec->board_config == CS420X_IMAC27) { unsigned int gpio = hp_present ? 0x02 : 0x08; snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, gpio); } }
static int is_ext_mic(struct hda_codec *codec, unsigned int idx) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; hda_nid_t pin = cfg->inputs[idx].pin; unsigned int val; if (!is_jack_detectable(codec, pin)) return 0; val = snd_hda_codec_get_pincfg(codec, pin); return (snd_hda_get_input_pin_attr(val) != INPUT_PIN_ATTR_INT); }
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 (is_jack_detectable(codec, nid)) { 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 void cs_automute(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; unsigned int hp_present; unsigned int spdif_present; hda_nid_t nid; int i; spdif_present = 0; if (cfg->dig_outs) { nid = cfg->dig_out_pins[0]; if (is_jack_detectable(codec, nid)) { /* TODO: SPDIF output redirect when SENSE_B is enabled. Shared (SENSE_A) jack (e.g HP/mini-TOSLINK) assumed. */ if (snd_hda_jack_detect(codec, nid) /* && spec->sense_b */) spdif_present = 1; } } hp_present = 0; for (i = 0; i < cfg->hp_outs; i++) { nid = cfg->hp_pins[i]; if (!is_jack_detectable(codec, nid)) continue; hp_present = snd_hda_jack_detect(codec, nid); if (hp_present) break; } /* mute speakers if spdif or hp jack is plugged in */ for (i = 0; i < cfg->speaker_outs; i++) { nid = cfg->speaker_pins[i]; snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, hp_present ? 0 : PIN_OUT); /* detect on spdif is specific to CS421x */ if (spec->vendor_nid == CS421X_VENDOR_NID) { snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, spdif_present ? 0 : PIN_OUT); } } if (spec->board_config == CS420X_MBP53 || spec->board_config == CS420X_MBP55 || spec->board_config == CS420X_IMAC27) { unsigned int gpio = hp_present ? 0x02 : 0x08; snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, gpio); } /* specific to CS421x */ if (spec->vendor_nid == CS421X_VENDOR_NID) { /* mute HPs if spdif jack (SENSE_B) is present */ for (i = 0; i < cfg->hp_outs; i++) { nid = cfg->hp_pins[i]; snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, (spdif_present && spec->sense_b) ? 0 : PIN_HP); } /* SPDIF TX on/off */ if (cfg->dig_outs) { nid = cfg->dig_out_pins[0]; snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, spdif_present ? PIN_OUT : 0); } /* Update board GPIOs if neccessary ... */ } }