/* update the cached value and notification flag if needed */ static void jack_detect_update(struct hda_codec *codec, struct hda_jack_tbl *jack) { if (!jack->jack_dirty) return; if (jack->phantom_jack) jack->pin_sense = AC_PINSENSE_PRESENCE; else jack->pin_sense = read_pin_sense(codec, jack->nid); /* A gating jack indicates the jack is invalid if gating is unplugged */ if (jack->gating_jack && !snd_hda_jack_detect(codec, jack->gating_jack)) jack->pin_sense &= ~AC_PINSENSE_PRESENCE; jack->jack_dirty = 0; /* If a jack is gated by this one update it. */ if (jack->gated_jack) { struct hda_jack_tbl *gated = snd_hda_jack_tbl_get(codec, jack->gated_jack); if (gated) { gated->jack_dirty = 1; jack_detect_update(codec, gated); } } }
/** * snd_hda_jack_add_kctl - Add a kctl for the given pin * * This assigns a jack-detection kctl to the given pin. The kcontrol * will have the given name and index. */ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, const char *name, int idx) { struct hda_jack_tbl *jack; struct snd_kcontrol *kctl; int err, state; jack = snd_hda_jack_tbl_new(codec, nid); if (!jack) return 0; if (jack->kctl) return 0; /* already created */ kctl = snd_kctl_jack_new(name, idx, codec); if (!kctl) return -ENOMEM; err = snd_hda_ctl_add(codec, nid, kctl); if (err < 0) return err; jack->kctl = kctl; state = snd_hda_jack_detect(codec, nid); snd_kctl_jack_report(codec->bus->card, kctl, state); #ifdef CONFIG_SND_HDA_INPUT_JACK jack->type = get_input_jack_type(codec, nid); err = snd_jack_new(codec->bus->card, name, jack->type, &jack->jack); if (err < 0) return err; jack->jack->private_data = jack; jack->jack->private_free = hda_free_jack_priv; snd_jack_report(jack->jack, state ? jack->type : 0); #endif return 0; }
static void cxt_update_headset_mode(struct hda_codec *codec) { /* The verbs used in this function were tested on a Conexant CX20751/2 codec. */ int i; bool mic_mode = false; struct conexant_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->gen.autocfg; hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]]; for (i = 0; i < cfg->num_inputs; i++) if (cfg->inputs[i].pin == mux_pin) { mic_mode = !!cfg->inputs[i].is_headphone_mic; break; } if (mic_mode) { snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x7c); /* enable merged mode for analog int-mic */ spec->gen.hp_jack_present = false; } else { snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x54); /* disable merged mode for analog int-mic */ spec->gen.hp_jack_present = snd_hda_jack_detect(codec, spec->gen.autocfg.hp_pins[0]); } snd_hda_gen_update_outputs(codec); }
static void cs_automic(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; hda_nid_t nid; unsigned int present; nid = cfg->inputs[spec->automic_idx].pin; present = snd_hda_jack_detect(codec, nid); /* specific to CS421x, single ADC */ if (spec->vendor_nid == CS421X_VENDOR_NID) { if (present) { spec->last_input = spec->cur_input; spec->cur_input = spec->automic_idx; } else { spec->cur_input = spec->last_input; } snd_hda_codec_write_cache(codec, spec->cur_adc, 0, AC_VERB_SET_CONNECT_SEL, spec->adc_idx[spec->cur_input]); } else { if (present) change_cur_input(codec, spec->automic_idx, 0); else change_cur_input(codec, !spec->automic_idx, 0); } }
static void cs_automute(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; unsigned int caps, hp_present; hda_nid_t nid; int i; hp_present = 0; for (i = 0; i < cfg->hp_outs; i++) { nid = cfg->hp_pins[i]; caps = snd_hda_query_pin_caps(codec, nid); if (!(caps & AC_PINCAP_PRES_DETECT)) 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_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 void cs_automic(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; hda_nid_t nid; unsigned int present; nid = cfg->inputs[spec->automic_idx].pin; present = snd_hda_jack_detect(codec, nid); if (present) change_cur_input(codec, spec->automic_idx, 0); else change_cur_input(codec, !spec->automic_idx, 0); }
static void cs_automic(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; hda_nid_t nid; unsigned int present; nid = cfg->input_pins[spec->automic_idx]; present = snd_hda_jack_detect(codec, nid); if (present) change_cur_input(codec, spec->automic_idx, 0); else { unsigned int imic = (spec->automic_idx == AUTO_PIN_MIC) ? AUTO_PIN_FRONT_MIC : AUTO_PIN_MIC; change_cur_input(codec, imic, 0); } }
/** * snd_hda_jack_add_kctl - Add a kctl for the given pin * @codec: the HDA codec * @nid: pin NID to assign * @name: string name for the jack * @phantom_jack: flag to deal as a phantom jack * @type: jack type bits to be reported, 0 for guessing from pincfg * @keymap: optional jack / key mapping * * This assigns a jack-detection kctl to the given pin. The kcontrol * will have the given name and index. */ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, const char *name, bool phantom_jack, int type, const struct hda_jack_keymap *keymap) { struct hda_jack_tbl *jack; const struct hda_jack_keymap *map; int err, state, buttons; jack = snd_hda_jack_tbl_new(codec, nid); if (!jack) return 0; if (jack->jack) return 0; /* already created */ if (!type) type = get_input_jack_type(codec, nid); buttons = 0; if (keymap) { for (map = keymap; map->type; map++) buttons |= map->type; } err = snd_jack_new(codec->card, name, type | buttons, &jack->jack, true, phantom_jack); if (err < 0) return err; jack->phantom_jack = !!phantom_jack; jack->type = type; jack->button_state = 0; jack->jack->private_data = jack; jack->jack->private_free = hda_free_jack_priv; if (keymap) { for (map = keymap; map->type; map++) snd_jack_set_key(jack->jack, map->type, map->key); } state = snd_hda_jack_detect(codec, nid); snd_jack_report(jack->jack, state ? jack->type : 0); return 0; }
static void cs4210_spdif_automute(struct hda_codec *codec, struct hda_jack_callback *tbl) { struct cs_spec *spec = codec->spec; bool spdif_present = false; hda_nid_t spdif_pin = spec->gen.autocfg.dig_out_pins[0]; /* detect on spdif is specific to CS4210 */ if (!spec->spdif_detect || spec->vendor_nid != CS4210_VENDOR_NID) return; spdif_present = snd_hda_jack_detect(codec, spdif_pin); if (spdif_present == spec->spdif_present) return; spec->spdif_present = spdif_present; /* SPDIF TX on/off */ snd_hda_set_pin_ctl(codec, spdif_pin, spdif_present ? PIN_OUT : 0); 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 ... */ } }