162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Jack-detection handling for HD-audio 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/init.h> 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include <linux/export.h> 1162306a36Sopenharmony_ci#include <sound/core.h> 1262306a36Sopenharmony_ci#include <sound/control.h> 1362306a36Sopenharmony_ci#include <sound/jack.h> 1462306a36Sopenharmony_ci#include <sound/hda_codec.h> 1562306a36Sopenharmony_ci#include "hda_local.h" 1662306a36Sopenharmony_ci#include "hda_auto_parser.h" 1762306a36Sopenharmony_ci#include "hda_jack.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/** 2062306a36Sopenharmony_ci * is_jack_detectable - Check whether the given pin is jack-detectable 2162306a36Sopenharmony_ci * @codec: the HDA codec 2262306a36Sopenharmony_ci * @nid: pin NID 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Check whether the given pin is capable to report the jack detection. 2562306a36Sopenharmony_ci * The jack detection might not work by various reasons, e.g. the jack 2662306a36Sopenharmony_ci * detection is prohibited in the codec level, the pin config has 2762306a36Sopenharmony_ci * AC_DEFCFG_MISC_NO_PRESENCE bit, no unsol support, etc. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_cibool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci if (codec->no_jack_detect) 3262306a36Sopenharmony_ci return false; 3362306a36Sopenharmony_ci if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT)) 3462306a36Sopenharmony_ci return false; 3562306a36Sopenharmony_ci if (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & 3662306a36Sopenharmony_ci AC_DEFCFG_MISC_NO_PRESENCE) 3762306a36Sopenharmony_ci return false; 3862306a36Sopenharmony_ci if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) && 3962306a36Sopenharmony_ci !codec->jackpoll_interval) 4062306a36Sopenharmony_ci return false; 4162306a36Sopenharmony_ci return true; 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(is_jack_detectable); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* execute pin sense measurement */ 4662306a36Sopenharmony_cistatic u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci u32 pincap; 4962306a36Sopenharmony_ci u32 val; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci if (!codec->no_trigger_sense) { 5262306a36Sopenharmony_ci pincap = snd_hda_query_pin_caps(codec, nid); 5362306a36Sopenharmony_ci if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */ 5462306a36Sopenharmony_ci snd_hda_codec_read(codec, nid, 0, 5562306a36Sopenharmony_ci AC_VERB_SET_PIN_SENSE, 0); 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci val = snd_hda_codec_read(codec, nid, 0, 5862306a36Sopenharmony_ci AC_VERB_GET_PIN_SENSE, dev_id); 5962306a36Sopenharmony_ci if (codec->inv_jack_detect) 6062306a36Sopenharmony_ci val ^= AC_PINSENSE_PRESENCE; 6162306a36Sopenharmony_ci return val; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/** 6562306a36Sopenharmony_ci * snd_hda_jack_tbl_get_mst - query the jack-table entry for the given NID 6662306a36Sopenharmony_ci * @codec: the HDA codec 6762306a36Sopenharmony_ci * @nid: pin NID to refer to 6862306a36Sopenharmony_ci * @dev_id: pin device entry id 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_cistruct hda_jack_tbl * 7162306a36Sopenharmony_cisnd_hda_jack_tbl_get_mst(struct hda_codec *codec, hda_nid_t nid, int dev_id) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct hda_jack_tbl *jack = codec->jacktbl.list; 7462306a36Sopenharmony_ci int i; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (!nid || !jack) 7762306a36Sopenharmony_ci return NULL; 7862306a36Sopenharmony_ci for (i = 0; i < codec->jacktbl.used; i++, jack++) 7962306a36Sopenharmony_ci if (jack->nid == nid && jack->dev_id == dev_id) 8062306a36Sopenharmony_ci return jack; 8162306a36Sopenharmony_ci return NULL; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_mst); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/** 8662306a36Sopenharmony_ci * snd_hda_jack_tbl_get_from_tag - query the jack-table entry for the given tag 8762306a36Sopenharmony_ci * @codec: the HDA codec 8862306a36Sopenharmony_ci * @tag: tag value to refer to 8962306a36Sopenharmony_ci * @dev_id: pin device entry id 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_cistruct hda_jack_tbl * 9262306a36Sopenharmony_cisnd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, 9362306a36Sopenharmony_ci unsigned char tag, int dev_id) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct hda_jack_tbl *jack = codec->jacktbl.list; 9662306a36Sopenharmony_ci int i; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (!tag || !jack) 9962306a36Sopenharmony_ci return NULL; 10062306a36Sopenharmony_ci for (i = 0; i < codec->jacktbl.used; i++, jack++) 10162306a36Sopenharmony_ci if (jack->tag == tag && jack->dev_id == dev_id) 10262306a36Sopenharmony_ci return jack; 10362306a36Sopenharmony_ci return NULL; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_from_tag); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic struct hda_jack_tbl * 10862306a36Sopenharmony_ciany_jack_tbl_get_from_nid(struct hda_codec *codec, hda_nid_t nid) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct hda_jack_tbl *jack = codec->jacktbl.list; 11162306a36Sopenharmony_ci int i; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (!nid || !jack) 11462306a36Sopenharmony_ci return NULL; 11562306a36Sopenharmony_ci for (i = 0; i < codec->jacktbl.used; i++, jack++) 11662306a36Sopenharmony_ci if (jack->nid == nid) 11762306a36Sopenharmony_ci return jack; 11862306a36Sopenharmony_ci return NULL; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/** 12262306a36Sopenharmony_ci * snd_hda_jack_tbl_new - create a jack-table entry for the given NID 12362306a36Sopenharmony_ci * @codec: the HDA codec 12462306a36Sopenharmony_ci * @nid: pin NID to assign 12562306a36Sopenharmony_ci * @dev_id: pin device entry id 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_cistatic struct hda_jack_tbl * 12862306a36Sopenharmony_cisnd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid, int dev_id) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct hda_jack_tbl *jack = 13162306a36Sopenharmony_ci snd_hda_jack_tbl_get_mst(codec, nid, dev_id); 13262306a36Sopenharmony_ci struct hda_jack_tbl *existing_nid_jack = 13362306a36Sopenharmony_ci any_jack_tbl_get_from_nid(codec, nid); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci WARN_ON(dev_id != 0 && !codec->dp_mst); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (jack) 13862306a36Sopenharmony_ci return jack; 13962306a36Sopenharmony_ci jack = snd_array_new(&codec->jacktbl); 14062306a36Sopenharmony_ci if (!jack) 14162306a36Sopenharmony_ci return NULL; 14262306a36Sopenharmony_ci jack->nid = nid; 14362306a36Sopenharmony_ci jack->dev_id = dev_id; 14462306a36Sopenharmony_ci jack->jack_dirty = 1; 14562306a36Sopenharmony_ci if (existing_nid_jack) { 14662306a36Sopenharmony_ci jack->tag = existing_nid_jack->tag; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* 14962306a36Sopenharmony_ci * Copy jack_detect from existing_nid_jack to avoid 15062306a36Sopenharmony_ci * snd_hda_jack_detect_enable_callback_mst() making multiple 15162306a36Sopenharmony_ci * SET_UNSOLICITED_ENABLE calls on the same pin. 15262306a36Sopenharmony_ci */ 15362306a36Sopenharmony_ci jack->jack_detect = existing_nid_jack->jack_detect; 15462306a36Sopenharmony_ci } else { 15562306a36Sopenharmony_ci jack->tag = codec->jacktbl.used; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return jack; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_civoid snd_hda_jack_tbl_disconnect(struct hda_codec *codec) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct hda_jack_tbl *jack = codec->jacktbl.list; 16462306a36Sopenharmony_ci int i; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci for (i = 0; i < codec->jacktbl.used; i++, jack++) { 16762306a36Sopenharmony_ci if (!codec->bus->shutdown && jack->jack) 16862306a36Sopenharmony_ci snd_device_disconnect(codec->card, jack->jack); 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_civoid snd_hda_jack_tbl_clear(struct hda_codec *codec) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct hda_jack_tbl *jack = codec->jacktbl.list; 17562306a36Sopenharmony_ci int i; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci for (i = 0; i < codec->jacktbl.used; i++, jack++) { 17862306a36Sopenharmony_ci struct hda_jack_callback *cb, *next; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* free jack instances manually when clearing/reconfiguring */ 18162306a36Sopenharmony_ci if (!codec->bus->shutdown && jack->jack) 18262306a36Sopenharmony_ci snd_device_free(codec->card, jack->jack); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci for (cb = jack->callback; cb; cb = next) { 18562306a36Sopenharmony_ci next = cb->next; 18662306a36Sopenharmony_ci kfree(cb); 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci snd_array_free(&codec->jacktbl); 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci#define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE) 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci/* update the cached value and notification flag if needed */ 19562306a36Sopenharmony_cistatic void jack_detect_update(struct hda_codec *codec, 19662306a36Sopenharmony_ci struct hda_jack_tbl *jack) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci if (!jack->jack_dirty) 19962306a36Sopenharmony_ci return; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (jack->phantom_jack) 20262306a36Sopenharmony_ci jack->pin_sense = AC_PINSENSE_PRESENCE; 20362306a36Sopenharmony_ci else 20462306a36Sopenharmony_ci jack->pin_sense = read_pin_sense(codec, jack->nid, 20562306a36Sopenharmony_ci jack->dev_id); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* A gating jack indicates the jack is invalid if gating is unplugged */ 20862306a36Sopenharmony_ci if (jack->gating_jack && 20962306a36Sopenharmony_ci !snd_hda_jack_detect_mst(codec, jack->gating_jack, jack->dev_id)) 21062306a36Sopenharmony_ci jack->pin_sense &= ~AC_PINSENSE_PRESENCE; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci jack->jack_dirty = 0; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* If a jack is gated by this one update it. */ 21562306a36Sopenharmony_ci if (jack->gated_jack) { 21662306a36Sopenharmony_ci struct hda_jack_tbl *gated = 21762306a36Sopenharmony_ci snd_hda_jack_tbl_get_mst(codec, jack->gated_jack, 21862306a36Sopenharmony_ci jack->dev_id); 21962306a36Sopenharmony_ci if (gated) { 22062306a36Sopenharmony_ci gated->jack_dirty = 1; 22162306a36Sopenharmony_ci jack_detect_update(codec, gated); 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci/** 22762306a36Sopenharmony_ci * snd_hda_jack_set_dirty_all - Mark all the cached as dirty 22862306a36Sopenharmony_ci * @codec: the HDA codec 22962306a36Sopenharmony_ci * 23062306a36Sopenharmony_ci * This function sets the dirty flag to all entries of jack table. 23162306a36Sopenharmony_ci * It's called from the resume path in hda_codec.c. 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_civoid snd_hda_jack_set_dirty_all(struct hda_codec *codec) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci struct hda_jack_tbl *jack = codec->jacktbl.list; 23662306a36Sopenharmony_ci int i; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci for (i = 0; i < codec->jacktbl.used; i++, jack++) 23962306a36Sopenharmony_ci if (jack->nid) 24062306a36Sopenharmony_ci jack->jack_dirty = 1; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_set_dirty_all); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci/** 24562306a36Sopenharmony_ci * snd_hda_jack_pin_sense - execute pin sense measurement 24662306a36Sopenharmony_ci * @codec: the CODEC to sense 24762306a36Sopenharmony_ci * @nid: the pin NID to sense 24862306a36Sopenharmony_ci * @dev_id: pin device entry id 24962306a36Sopenharmony_ci * 25062306a36Sopenharmony_ci * Execute necessary pin sense measurement and return its Presence Detect, 25162306a36Sopenharmony_ci * Impedance, ELD Valid etc. status bits. 25262306a36Sopenharmony_ci */ 25362306a36Sopenharmony_ciu32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct hda_jack_tbl *jack = 25662306a36Sopenharmony_ci snd_hda_jack_tbl_get_mst(codec, nid, dev_id); 25762306a36Sopenharmony_ci if (jack) { 25862306a36Sopenharmony_ci jack_detect_update(codec, jack); 25962306a36Sopenharmony_ci return jack->pin_sense; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci return read_pin_sense(codec, nid, dev_id); 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_pin_sense); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci/** 26662306a36Sopenharmony_ci * snd_hda_jack_detect_state_mst - query pin Presence Detect status 26762306a36Sopenharmony_ci * @codec: the CODEC to sense 26862306a36Sopenharmony_ci * @nid: the pin NID to sense 26962306a36Sopenharmony_ci * @dev_id: pin device entry id 27062306a36Sopenharmony_ci * 27162306a36Sopenharmony_ci * Query and return the pin's Presence Detect status, as either 27262306a36Sopenharmony_ci * HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM. 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_ciint snd_hda_jack_detect_state_mst(struct hda_codec *codec, 27562306a36Sopenharmony_ci hda_nid_t nid, int dev_id) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci struct hda_jack_tbl *jack = 27862306a36Sopenharmony_ci snd_hda_jack_tbl_get_mst(codec, nid, dev_id); 27962306a36Sopenharmony_ci if (jack && jack->phantom_jack) 28062306a36Sopenharmony_ci return HDA_JACK_PHANTOM; 28162306a36Sopenharmony_ci else if (snd_hda_jack_pin_sense(codec, nid, dev_id) & 28262306a36Sopenharmony_ci AC_PINSENSE_PRESENCE) 28362306a36Sopenharmony_ci return HDA_JACK_PRESENT; 28462306a36Sopenharmony_ci else 28562306a36Sopenharmony_ci return HDA_JACK_NOT_PRESENT; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_detect_state_mst); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic struct hda_jack_callback * 29062306a36Sopenharmony_cifind_callback_from_list(struct hda_jack_tbl *jack, 29162306a36Sopenharmony_ci hda_jack_callback_fn func) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci struct hda_jack_callback *cb; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (!func) 29662306a36Sopenharmony_ci return NULL; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci for (cb = jack->callback; cb; cb = cb->next) { 29962306a36Sopenharmony_ci if (cb->func == func) 30062306a36Sopenharmony_ci return cb; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci return NULL; 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci/** 30762306a36Sopenharmony_ci * snd_hda_jack_detect_enable_callback_mst - enable the jack-detection 30862306a36Sopenharmony_ci * @codec: the HDA codec 30962306a36Sopenharmony_ci * @nid: pin NID to enable 31062306a36Sopenharmony_ci * @func: callback function to register 31162306a36Sopenharmony_ci * @dev_id: pin device entry id 31262306a36Sopenharmony_ci * 31362306a36Sopenharmony_ci * In the case of error, the return value will be a pointer embedded with 31462306a36Sopenharmony_ci * errno. Check and handle the return value appropriately with standard 31562306a36Sopenharmony_ci * macros such as @IS_ERR() and @PTR_ERR(). 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_cistruct hda_jack_callback * 31862306a36Sopenharmony_cisnd_hda_jack_detect_enable_callback_mst(struct hda_codec *codec, hda_nid_t nid, 31962306a36Sopenharmony_ci int dev_id, hda_jack_callback_fn func) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci struct hda_jack_tbl *jack; 32262306a36Sopenharmony_ci struct hda_jack_callback *callback = NULL; 32362306a36Sopenharmony_ci int err; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci jack = snd_hda_jack_tbl_new(codec, nid, dev_id); 32662306a36Sopenharmony_ci if (!jack) 32762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci callback = find_callback_from_list(jack, func); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (func && !callback) { 33262306a36Sopenharmony_ci callback = kzalloc(sizeof(*callback), GFP_KERNEL); 33362306a36Sopenharmony_ci if (!callback) 33462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 33562306a36Sopenharmony_ci callback->func = func; 33662306a36Sopenharmony_ci callback->nid = jack->nid; 33762306a36Sopenharmony_ci callback->dev_id = jack->dev_id; 33862306a36Sopenharmony_ci callback->next = jack->callback; 33962306a36Sopenharmony_ci jack->callback = callback; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (jack->jack_detect) 34362306a36Sopenharmony_ci return callback; /* already registered */ 34462306a36Sopenharmony_ci jack->jack_detect = 1; 34562306a36Sopenharmony_ci if (codec->jackpoll_interval > 0) 34662306a36Sopenharmony_ci return callback; /* No unsol if we're polling instead */ 34762306a36Sopenharmony_ci err = snd_hda_codec_write_cache(codec, nid, 0, 34862306a36Sopenharmony_ci AC_VERB_SET_UNSOLICITED_ENABLE, 34962306a36Sopenharmony_ci AC_USRSP_EN | jack->tag); 35062306a36Sopenharmony_ci if (err < 0) 35162306a36Sopenharmony_ci return ERR_PTR(err); 35262306a36Sopenharmony_ci return callback; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback_mst); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci/** 35762306a36Sopenharmony_ci * snd_hda_jack_detect_enable - Enable the jack detection on the given pin 35862306a36Sopenharmony_ci * @codec: the HDA codec 35962306a36Sopenharmony_ci * @nid: pin NID to enable jack detection 36062306a36Sopenharmony_ci * @dev_id: pin device entry id 36162306a36Sopenharmony_ci * 36262306a36Sopenharmony_ci * Enable the jack detection with the default callback. Returns zero if 36362306a36Sopenharmony_ci * successful or a negative error code. 36462306a36Sopenharmony_ci */ 36562306a36Sopenharmony_ciint snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, 36662306a36Sopenharmony_ci int dev_id) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(snd_hda_jack_detect_enable_callback_mst(codec, 36962306a36Sopenharmony_ci nid, 37062306a36Sopenharmony_ci dev_id, 37162306a36Sopenharmony_ci NULL)); 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci/** 37662306a36Sopenharmony_ci * snd_hda_jack_set_gating_jack - Set gating jack. 37762306a36Sopenharmony_ci * @codec: the HDA codec 37862306a36Sopenharmony_ci * @gated_nid: gated pin NID 37962306a36Sopenharmony_ci * @gating_nid: gating pin NID 38062306a36Sopenharmony_ci * 38162306a36Sopenharmony_ci * Indicates the gated jack is only valid when the gating jack is plugged. 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_ciint snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, 38462306a36Sopenharmony_ci hda_nid_t gating_nid) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid, 0); 38762306a36Sopenharmony_ci struct hda_jack_tbl *gating = 38862306a36Sopenharmony_ci snd_hda_jack_tbl_new(codec, gating_nid, 0); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci WARN_ON(codec->dp_mst); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (!gated || !gating) 39362306a36Sopenharmony_ci return -EINVAL; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci gated->gating_jack = gating_nid; 39662306a36Sopenharmony_ci gating->gated_jack = gated_nid; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci return 0; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_set_gating_jack); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci/** 40362306a36Sopenharmony_ci * snd_hda_jack_bind_keymap - bind keys generated from one NID to another jack. 40462306a36Sopenharmony_ci * @codec: the HDA codec 40562306a36Sopenharmony_ci * @key_nid: key event is generated by this pin NID 40662306a36Sopenharmony_ci * @keymap: map of key type and key code 40762306a36Sopenharmony_ci * @jack_nid: key reports to the jack of this pin NID 40862306a36Sopenharmony_ci * 40962306a36Sopenharmony_ci * This function is used in the case of key is generated from one NID while is 41062306a36Sopenharmony_ci * reported to the jack of another NID. 41162306a36Sopenharmony_ci */ 41262306a36Sopenharmony_ciint snd_hda_jack_bind_keymap(struct hda_codec *codec, hda_nid_t key_nid, 41362306a36Sopenharmony_ci const struct hda_jack_keymap *keymap, 41462306a36Sopenharmony_ci hda_nid_t jack_nid) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci const struct hda_jack_keymap *map; 41762306a36Sopenharmony_ci struct hda_jack_tbl *key_gen = snd_hda_jack_tbl_get(codec, key_nid); 41862306a36Sopenharmony_ci struct hda_jack_tbl *report_to = snd_hda_jack_tbl_get(codec, jack_nid); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci WARN_ON(codec->dp_mst); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (!key_gen || !report_to || !report_to->jack) 42362306a36Sopenharmony_ci return -EINVAL; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci key_gen->key_report_jack = jack_nid; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci if (keymap) 42862306a36Sopenharmony_ci for (map = keymap; map->type; map++) 42962306a36Sopenharmony_ci snd_jack_set_key(report_to->jack, map->type, map->key); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci return 0; 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_bind_keymap); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci/** 43662306a36Sopenharmony_ci * snd_hda_jack_set_button_state - report button event to the hda_jack_tbl button_state. 43762306a36Sopenharmony_ci * @codec: the HDA codec 43862306a36Sopenharmony_ci * @jack_nid: the button event reports to the jack_tbl of this NID 43962306a36Sopenharmony_ci * @button_state: the button event captured by codec 44062306a36Sopenharmony_ci * 44162306a36Sopenharmony_ci * Codec driver calls this function to report the button event. 44262306a36Sopenharmony_ci */ 44362306a36Sopenharmony_civoid snd_hda_jack_set_button_state(struct hda_codec *codec, hda_nid_t jack_nid, 44462306a36Sopenharmony_ci int button_state) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, jack_nid); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (!jack) 44962306a36Sopenharmony_ci return; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (jack->key_report_jack) { 45262306a36Sopenharmony_ci struct hda_jack_tbl *report_to = 45362306a36Sopenharmony_ci snd_hda_jack_tbl_get(codec, jack->key_report_jack); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (report_to) { 45662306a36Sopenharmony_ci report_to->button_state = button_state; 45762306a36Sopenharmony_ci return; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci jack->button_state = button_state; 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_set_button_state); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci/** 46662306a36Sopenharmony_ci * snd_hda_jack_report_sync - sync the states of all jacks and report if changed 46762306a36Sopenharmony_ci * @codec: the HDA codec 46862306a36Sopenharmony_ci */ 46962306a36Sopenharmony_civoid snd_hda_jack_report_sync(struct hda_codec *codec) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct hda_jack_tbl *jack; 47262306a36Sopenharmony_ci int i, state; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci /* update all jacks at first */ 47562306a36Sopenharmony_ci jack = codec->jacktbl.list; 47662306a36Sopenharmony_ci for (i = 0; i < codec->jacktbl.used; i++, jack++) 47762306a36Sopenharmony_ci if (jack->nid) 47862306a36Sopenharmony_ci jack_detect_update(codec, jack); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* report the updated jacks; it's done after updating all jacks 48162306a36Sopenharmony_ci * to make sure that all gating jacks properly have been set 48262306a36Sopenharmony_ci */ 48362306a36Sopenharmony_ci jack = codec->jacktbl.list; 48462306a36Sopenharmony_ci for (i = 0; i < codec->jacktbl.used; i++, jack++) 48562306a36Sopenharmony_ci if (jack->nid) { 48662306a36Sopenharmony_ci if (!jack->jack || jack->block_report) 48762306a36Sopenharmony_ci continue; 48862306a36Sopenharmony_ci state = jack->button_state; 48962306a36Sopenharmony_ci if (get_jack_plug_state(jack->pin_sense)) 49062306a36Sopenharmony_ci state |= jack->type; 49162306a36Sopenharmony_ci snd_jack_report(jack->jack, state); 49262306a36Sopenharmony_ci if (jack->button_state) { 49362306a36Sopenharmony_ci snd_jack_report(jack->jack, 49462306a36Sopenharmony_ci state & ~jack->button_state); 49562306a36Sopenharmony_ci jack->button_state = 0; /* button released */ 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_report_sync); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci/* guess the jack type from the pin-config */ 50262306a36Sopenharmony_cistatic int get_input_jack_type(struct hda_codec *codec, hda_nid_t nid) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); 50562306a36Sopenharmony_ci switch (get_defcfg_device(def_conf)) { 50662306a36Sopenharmony_ci case AC_JACK_LINE_OUT: 50762306a36Sopenharmony_ci case AC_JACK_SPEAKER: 50862306a36Sopenharmony_ci return SND_JACK_LINEOUT; 50962306a36Sopenharmony_ci case AC_JACK_HP_OUT: 51062306a36Sopenharmony_ci return SND_JACK_HEADPHONE; 51162306a36Sopenharmony_ci case AC_JACK_SPDIF_OUT: 51262306a36Sopenharmony_ci case AC_JACK_DIG_OTHER_OUT: 51362306a36Sopenharmony_ci return SND_JACK_AVOUT; 51462306a36Sopenharmony_ci case AC_JACK_MIC_IN: 51562306a36Sopenharmony_ci return SND_JACK_MICROPHONE; 51662306a36Sopenharmony_ci default: 51762306a36Sopenharmony_ci return SND_JACK_LINEIN; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic void hda_free_jack_priv(struct snd_jack *jack) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci struct hda_jack_tbl *jacks = jack->private_data; 52462306a36Sopenharmony_ci jacks->nid = 0; 52562306a36Sopenharmony_ci jacks->jack = NULL; 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci/** 52962306a36Sopenharmony_ci * snd_hda_jack_add_kctl_mst - Add a kctl for the given pin 53062306a36Sopenharmony_ci * @codec: the HDA codec 53162306a36Sopenharmony_ci * @nid: pin NID to assign 53262306a36Sopenharmony_ci * @dev_id : pin device entry id 53362306a36Sopenharmony_ci * @name: string name for the jack 53462306a36Sopenharmony_ci * @phantom_jack: flag to deal as a phantom jack 53562306a36Sopenharmony_ci * @type: jack type bits to be reported, 0 for guessing from pincfg 53662306a36Sopenharmony_ci * @keymap: optional jack / key mapping 53762306a36Sopenharmony_ci * 53862306a36Sopenharmony_ci * This assigns a jack-detection kctl to the given pin. The kcontrol 53962306a36Sopenharmony_ci * will have the given name and index. 54062306a36Sopenharmony_ci */ 54162306a36Sopenharmony_ciint snd_hda_jack_add_kctl_mst(struct hda_codec *codec, hda_nid_t nid, 54262306a36Sopenharmony_ci int dev_id, const char *name, bool phantom_jack, 54362306a36Sopenharmony_ci int type, const struct hda_jack_keymap *keymap) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci struct hda_jack_tbl *jack; 54662306a36Sopenharmony_ci const struct hda_jack_keymap *map; 54762306a36Sopenharmony_ci int err, state, buttons; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci jack = snd_hda_jack_tbl_new(codec, nid, dev_id); 55062306a36Sopenharmony_ci if (!jack) 55162306a36Sopenharmony_ci return 0; 55262306a36Sopenharmony_ci if (jack->jack) 55362306a36Sopenharmony_ci return 0; /* already created */ 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (!type) 55662306a36Sopenharmony_ci type = get_input_jack_type(codec, nid); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci buttons = 0; 55962306a36Sopenharmony_ci if (keymap) { 56062306a36Sopenharmony_ci for (map = keymap; map->type; map++) 56162306a36Sopenharmony_ci buttons |= map->type; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci err = snd_jack_new(codec->card, name, type | buttons, 56562306a36Sopenharmony_ci &jack->jack, true, phantom_jack); 56662306a36Sopenharmony_ci if (err < 0) 56762306a36Sopenharmony_ci return err; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci jack->phantom_jack = !!phantom_jack; 57062306a36Sopenharmony_ci jack->type = type; 57162306a36Sopenharmony_ci jack->button_state = 0; 57262306a36Sopenharmony_ci jack->jack->private_data = jack; 57362306a36Sopenharmony_ci jack->jack->private_free = hda_free_jack_priv; 57462306a36Sopenharmony_ci if (keymap) { 57562306a36Sopenharmony_ci for (map = keymap; map->type; map++) 57662306a36Sopenharmony_ci snd_jack_set_key(jack->jack, map->type, map->key); 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci state = snd_hda_jack_detect_mst(codec, nid, dev_id); 58062306a36Sopenharmony_ci snd_jack_report(jack->jack, state ? jack->type : 0); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci return 0; 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl_mst); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, 58762306a36Sopenharmony_ci const struct auto_pin_cfg *cfg, 58862306a36Sopenharmony_ci const char *base_name) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci unsigned int def_conf, conn; 59162306a36Sopenharmony_ci char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 59262306a36Sopenharmony_ci int err; 59362306a36Sopenharmony_ci bool phantom_jack; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci WARN_ON(codec->dp_mst); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (!nid) 59862306a36Sopenharmony_ci return 0; 59962306a36Sopenharmony_ci def_conf = snd_hda_codec_get_pincfg(codec, nid); 60062306a36Sopenharmony_ci conn = get_defcfg_connect(def_conf); 60162306a36Sopenharmony_ci if (conn == AC_JACK_PORT_NONE) 60262306a36Sopenharmony_ci return 0; 60362306a36Sopenharmony_ci phantom_jack = (conn != AC_JACK_PORT_COMPLEX) || 60462306a36Sopenharmony_ci !is_jack_detectable(codec, nid); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci if (base_name) 60762306a36Sopenharmony_ci strscpy(name, base_name, sizeof(name)); 60862306a36Sopenharmony_ci else 60962306a36Sopenharmony_ci snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), NULL); 61062306a36Sopenharmony_ci if (phantom_jack) 61162306a36Sopenharmony_ci /* Example final name: "Internal Mic Phantom Jack" */ 61262306a36Sopenharmony_ci strncat(name, " Phantom", sizeof(name) - strlen(name) - 1); 61362306a36Sopenharmony_ci err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack, 0, NULL); 61462306a36Sopenharmony_ci if (err < 0) 61562306a36Sopenharmony_ci return err; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci if (!phantom_jack) 61862306a36Sopenharmony_ci return snd_hda_jack_detect_enable(codec, nid, 0); 61962306a36Sopenharmony_ci return 0; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci/** 62362306a36Sopenharmony_ci * snd_hda_jack_add_kctls - Add kctls for all pins included in the given pincfg 62462306a36Sopenharmony_ci * @codec: the HDA codec 62562306a36Sopenharmony_ci * @cfg: pin config table to parse 62662306a36Sopenharmony_ci */ 62762306a36Sopenharmony_ciint snd_hda_jack_add_kctls(struct hda_codec *codec, 62862306a36Sopenharmony_ci const struct auto_pin_cfg *cfg) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci const hda_nid_t *p; 63162306a36Sopenharmony_ci int i, err; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci for (i = 0; i < cfg->num_inputs; i++) { 63462306a36Sopenharmony_ci /* If we have headphone mics; make sure they get the right name 63562306a36Sopenharmony_ci before grabbed by output pins */ 63662306a36Sopenharmony_ci if (cfg->inputs[i].is_headphone_mic) { 63762306a36Sopenharmony_ci if (auto_cfg_hp_outs(cfg) == 1) 63862306a36Sopenharmony_ci err = add_jack_kctl(codec, auto_cfg_hp_pins(cfg)[0], 63962306a36Sopenharmony_ci cfg, "Headphone Mic"); 64062306a36Sopenharmony_ci else 64162306a36Sopenharmony_ci err = add_jack_kctl(codec, cfg->inputs[i].pin, 64262306a36Sopenharmony_ci cfg, "Headphone Mic"); 64362306a36Sopenharmony_ci } else 64462306a36Sopenharmony_ci err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg, 64562306a36Sopenharmony_ci NULL); 64662306a36Sopenharmony_ci if (err < 0) 64762306a36Sopenharmony_ci return err; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) { 65162306a36Sopenharmony_ci err = add_jack_kctl(codec, *p, cfg, NULL); 65262306a36Sopenharmony_ci if (err < 0) 65362306a36Sopenharmony_ci return err; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) { 65662306a36Sopenharmony_ci if (*p == *cfg->line_out_pins) /* might be duplicated */ 65762306a36Sopenharmony_ci break; 65862306a36Sopenharmony_ci err = add_jack_kctl(codec, *p, cfg, NULL); 65962306a36Sopenharmony_ci if (err < 0) 66062306a36Sopenharmony_ci return err; 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) { 66362306a36Sopenharmony_ci if (*p == *cfg->line_out_pins) /* might be duplicated */ 66462306a36Sopenharmony_ci break; 66562306a36Sopenharmony_ci err = add_jack_kctl(codec, *p, cfg, NULL); 66662306a36Sopenharmony_ci if (err < 0) 66762306a36Sopenharmony_ci return err; 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) { 67062306a36Sopenharmony_ci err = add_jack_kctl(codec, *p, cfg, NULL); 67162306a36Sopenharmony_ci if (err < 0) 67262306a36Sopenharmony_ci return err; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci err = add_jack_kctl(codec, cfg->dig_in_pin, cfg, NULL); 67562306a36Sopenharmony_ci if (err < 0) 67662306a36Sopenharmony_ci return err; 67762306a36Sopenharmony_ci err = add_jack_kctl(codec, cfg->mono_out_pin, cfg, NULL); 67862306a36Sopenharmony_ci if (err < 0) 67962306a36Sopenharmony_ci return err; 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_add_kctls); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_cistatic void call_jack_callback(struct hda_codec *codec, unsigned int res, 68562306a36Sopenharmony_ci struct hda_jack_tbl *jack) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci struct hda_jack_callback *cb; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci for (cb = jack->callback; cb; cb = cb->next) { 69062306a36Sopenharmony_ci cb->jack = jack; 69162306a36Sopenharmony_ci cb->unsol_res = res; 69262306a36Sopenharmony_ci cb->func(codec, cb); 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci if (jack->gated_jack) { 69562306a36Sopenharmony_ci struct hda_jack_tbl *gated = 69662306a36Sopenharmony_ci snd_hda_jack_tbl_get_mst(codec, jack->gated_jack, 69762306a36Sopenharmony_ci jack->dev_id); 69862306a36Sopenharmony_ci if (gated) { 69962306a36Sopenharmony_ci for (cb = gated->callback; cb; cb = cb->next) { 70062306a36Sopenharmony_ci cb->jack = gated; 70162306a36Sopenharmony_ci cb->unsol_res = res; 70262306a36Sopenharmony_ci cb->func(codec, cb); 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci/** 70962306a36Sopenharmony_ci * snd_hda_jack_unsol_event - Handle an unsolicited event 71062306a36Sopenharmony_ci * @codec: the HDA codec 71162306a36Sopenharmony_ci * @res: the unsolicited event data 71262306a36Sopenharmony_ci */ 71362306a36Sopenharmony_civoid snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci struct hda_jack_tbl *event; 71662306a36Sopenharmony_ci int tag = (res & AC_UNSOL_RES_TAG) >> AC_UNSOL_RES_TAG_SHIFT; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci if (codec->dp_mst) { 71962306a36Sopenharmony_ci int dev_entry = 72062306a36Sopenharmony_ci (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci event = snd_hda_jack_tbl_get_from_tag(codec, tag, dev_entry); 72362306a36Sopenharmony_ci } else { 72462306a36Sopenharmony_ci event = snd_hda_jack_tbl_get_from_tag(codec, tag, 0); 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci if (!event) 72762306a36Sopenharmony_ci return; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci if (event->key_report_jack) { 73062306a36Sopenharmony_ci struct hda_jack_tbl *report_to = 73162306a36Sopenharmony_ci snd_hda_jack_tbl_get_mst(codec, event->key_report_jack, 73262306a36Sopenharmony_ci event->dev_id); 73362306a36Sopenharmony_ci if (report_to) 73462306a36Sopenharmony_ci report_to->jack_dirty = 1; 73562306a36Sopenharmony_ci } else 73662306a36Sopenharmony_ci event->jack_dirty = 1; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci call_jack_callback(codec, res, event); 73962306a36Sopenharmony_ci snd_hda_jack_report_sync(codec); 74062306a36Sopenharmony_ci} 74162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_unsol_event); 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci/** 74462306a36Sopenharmony_ci * snd_hda_jack_poll_all - Poll all jacks 74562306a36Sopenharmony_ci * @codec: the HDA codec 74662306a36Sopenharmony_ci * 74762306a36Sopenharmony_ci * Poll all detectable jacks with dirty flag, update the status, call 74862306a36Sopenharmony_ci * callbacks and call snd_hda_jack_report_sync() if any changes are found. 74962306a36Sopenharmony_ci */ 75062306a36Sopenharmony_civoid snd_hda_jack_poll_all(struct hda_codec *codec) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci struct hda_jack_tbl *jack = codec->jacktbl.list; 75362306a36Sopenharmony_ci int i, changes = 0; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci for (i = 0; i < codec->jacktbl.used; i++, jack++) { 75662306a36Sopenharmony_ci unsigned int old_sense; 75762306a36Sopenharmony_ci if (!jack->nid || !jack->jack_dirty || jack->phantom_jack) 75862306a36Sopenharmony_ci continue; 75962306a36Sopenharmony_ci old_sense = get_jack_plug_state(jack->pin_sense); 76062306a36Sopenharmony_ci jack_detect_update(codec, jack); 76162306a36Sopenharmony_ci if (old_sense == get_jack_plug_state(jack->pin_sense)) 76262306a36Sopenharmony_ci continue; 76362306a36Sopenharmony_ci changes = 1; 76462306a36Sopenharmony_ci call_jack_callback(codec, 0, jack); 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci if (changes) 76762306a36Sopenharmony_ci snd_hda_jack_report_sync(codec); 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_poll_all); 77062306a36Sopenharmony_ci 771