162810dbdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21835a0f9STakashi Iwai /* 31835a0f9STakashi Iwai * Jack-detection handling for HD-audio 41835a0f9STakashi Iwai * 51835a0f9STakashi Iwai * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> 61835a0f9STakashi Iwai */ 71835a0f9STakashi Iwai 81835a0f9STakashi Iwai #include <linux/init.h> 91835a0f9STakashi Iwai #include <linux/slab.h> 10bf815bf0STakashi Iwai #include <linux/export.h> 111835a0f9STakashi Iwai #include <sound/core.h> 1201a61e12STakashi Iwai #include <sound/control.h> 13aad37dbdSTakashi Iwai #include <sound/jack.h> 14be57bfffSPierre-Louis Bossart #include <sound/hda_codec.h> 151835a0f9STakashi Iwai #include "hda_local.h" 16128bc4baSTakashi Iwai #include "hda_auto_parser.h" 171835a0f9STakashi Iwai #include "hda_jack.h" 181835a0f9STakashi Iwai 1995a962c3STakashi Iwai /** 2095a962c3STakashi Iwai * is_jack_detectable - Check whether the given pin is jack-detectable 2195a962c3STakashi Iwai * @codec: the HDA codec 2295a962c3STakashi Iwai * @nid: pin NID 2395a962c3STakashi Iwai * 2495a962c3STakashi Iwai * Check whether the given pin is capable to report the jack detection. 2595a962c3STakashi Iwai * The jack detection might not work by various reasons, e.g. the jack 2695a962c3STakashi Iwai * detection is prohibited in the codec level, the pin config has 2795a962c3STakashi Iwai * AC_DEFCFG_MISC_NO_PRESENCE bit, no unsol support, etc. 2895a962c3STakashi Iwai */ 29a9c74173STakashi Iwai bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) 30a9c74173STakashi Iwai { 3171b1e9e4STakashi Iwai if (codec->no_jack_detect) 3271b1e9e4STakashi Iwai return false; 33a9c74173STakashi Iwai if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT)) 34a9c74173STakashi Iwai return false; 355fe8e1e6SDavid Henningsson if (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & 365fe8e1e6SDavid Henningsson AC_DEFCFG_MISC_NO_PRESENCE) 37a9c74173STakashi Iwai return false; 3876a19c69STakashi Iwai if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) && 3976a19c69STakashi Iwai !codec->jackpoll_interval) 40a9c74173STakashi Iwai return false; 41a9c74173STakashi Iwai return true; 42a9c74173STakashi Iwai } 432698ea98STakashi Iwai EXPORT_SYMBOL_GPL(is_jack_detectable); 44a9c74173STakashi Iwai 451835a0f9STakashi Iwai /* execute pin sense measurement */ 465204a05dSNikhil Mahale static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id) 471835a0f9STakashi Iwai { 481835a0f9STakashi Iwai u32 pincap; 499cc159c6STakashi Iwai u32 val; 501835a0f9STakashi Iwai 511835a0f9STakashi Iwai if (!codec->no_trigger_sense) { 521835a0f9STakashi Iwai pincap = snd_hda_query_pin_caps(codec, nid); 531835a0f9STakashi Iwai if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */ 541835a0f9STakashi Iwai snd_hda_codec_read(codec, nid, 0, 551835a0f9STakashi Iwai AC_VERB_SET_PIN_SENSE, 0); 561835a0f9STakashi Iwai } 579cc159c6STakashi Iwai val = snd_hda_codec_read(codec, nid, 0, 585204a05dSNikhil Mahale AC_VERB_GET_PIN_SENSE, dev_id); 599cc159c6STakashi Iwai if (codec->inv_jack_detect) 609cc159c6STakashi Iwai val ^= AC_PINSENSE_PRESENCE; 619cc159c6STakashi Iwai return val; 621835a0f9STakashi Iwai } 631835a0f9STakashi Iwai 641835a0f9STakashi Iwai /** 655204a05dSNikhil Mahale * snd_hda_jack_tbl_get_mst - query the jack-table entry for the given NID 66a11e9b16STakashi Iwai * @codec: the HDA codec 67a11e9b16STakashi Iwai * @nid: pin NID to refer to 685204a05dSNikhil Mahale * @dev_id: pin device entry id 691835a0f9STakashi Iwai */ 701835a0f9STakashi Iwai struct hda_jack_tbl * 715204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(struct hda_codec *codec, hda_nid_t nid, int dev_id) 725204a05dSNikhil Mahale { 735204a05dSNikhil Mahale struct hda_jack_tbl *jack = codec->jacktbl.list; 745204a05dSNikhil Mahale int i; 755204a05dSNikhil Mahale 765204a05dSNikhil Mahale if (!nid || !jack) 775204a05dSNikhil Mahale return NULL; 785204a05dSNikhil Mahale for (i = 0; i < codec->jacktbl.used; i++, jack++) 795204a05dSNikhil Mahale if (jack->nid == nid && jack->dev_id == dev_id) 805204a05dSNikhil Mahale return jack; 815204a05dSNikhil Mahale return NULL; 825204a05dSNikhil Mahale } 835204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_mst); 845204a05dSNikhil Mahale 855204a05dSNikhil Mahale /** 865204a05dSNikhil Mahale * snd_hda_jack_tbl_get_from_tag - query the jack-table entry for the given tag 875204a05dSNikhil Mahale * @codec: the HDA codec 885204a05dSNikhil Mahale * @tag: tag value to refer to 895204a05dSNikhil Mahale * @dev_id: pin device entry id 905204a05dSNikhil Mahale */ 915204a05dSNikhil Mahale struct hda_jack_tbl * 925204a05dSNikhil Mahale snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, 935204a05dSNikhil Mahale unsigned char tag, int dev_id) 945204a05dSNikhil Mahale { 955204a05dSNikhil Mahale struct hda_jack_tbl *jack = codec->jacktbl.list; 965204a05dSNikhil Mahale int i; 975204a05dSNikhil Mahale 985204a05dSNikhil Mahale if (!tag || !jack) 995204a05dSNikhil Mahale return NULL; 1005204a05dSNikhil Mahale for (i = 0; i < codec->jacktbl.used; i++, jack++) 1015204a05dSNikhil Mahale if (jack->tag == tag && jack->dev_id == dev_id) 1025204a05dSNikhil Mahale return jack; 1035204a05dSNikhil Mahale return NULL; 1045204a05dSNikhil Mahale } 1055204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_from_tag); 1065204a05dSNikhil Mahale 1075204a05dSNikhil Mahale static struct hda_jack_tbl * 1085204a05dSNikhil Mahale any_jack_tbl_get_from_nid(struct hda_codec *codec, hda_nid_t nid) 1091835a0f9STakashi Iwai { 1101835a0f9STakashi Iwai struct hda_jack_tbl *jack = codec->jacktbl.list; 1111835a0f9STakashi Iwai int i; 1121835a0f9STakashi Iwai 1131835a0f9STakashi Iwai if (!nid || !jack) 1141835a0f9STakashi Iwai return NULL; 1151835a0f9STakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) 1161835a0f9STakashi Iwai if (jack->nid == nid) 1171835a0f9STakashi Iwai return jack; 1181835a0f9STakashi Iwai return NULL; 1191835a0f9STakashi Iwai } 1203a93897eSTakashi Iwai 1213a93897eSTakashi Iwai /** 1221835a0f9STakashi Iwai * snd_hda_jack_tbl_new - create a jack-table entry for the given NID 123a11e9b16STakashi Iwai * @codec: the HDA codec 124a11e9b16STakashi Iwai * @nid: pin NID to assign 1254f5c2653SPierre-Louis Bossart * @dev_id: pin device entry id 1261835a0f9STakashi Iwai */ 12781965f1fSTakashi Iwai static struct hda_jack_tbl * 1285204a05dSNikhil Mahale snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid, int dev_id) 1291835a0f9STakashi Iwai { 1305204a05dSNikhil Mahale struct hda_jack_tbl *jack = 1315204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, nid, dev_id); 1325204a05dSNikhil Mahale struct hda_jack_tbl *existing_nid_jack = 1335204a05dSNikhil Mahale any_jack_tbl_get_from_nid(codec, nid); 1345204a05dSNikhil Mahale 1355204a05dSNikhil Mahale WARN_ON(dev_id != 0 && !codec->dp_mst); 1365204a05dSNikhil Mahale 1371835a0f9STakashi Iwai if (jack) 1381835a0f9STakashi Iwai return jack; 1391835a0f9STakashi Iwai jack = snd_array_new(&codec->jacktbl); 1401835a0f9STakashi Iwai if (!jack) 1411835a0f9STakashi Iwai return NULL; 1421835a0f9STakashi Iwai jack->nid = nid; 1435204a05dSNikhil Mahale jack->dev_id = dev_id; 1441835a0f9STakashi Iwai jack->jack_dirty = 1; 1455204a05dSNikhil Mahale if (existing_nid_jack) { 1465204a05dSNikhil Mahale jack->tag = existing_nid_jack->tag; 1475204a05dSNikhil Mahale 1485204a05dSNikhil Mahale /* 1495204a05dSNikhil Mahale * Copy jack_detect from existing_nid_jack to avoid 1505204a05dSNikhil Mahale * snd_hda_jack_detect_enable_callback_mst() making multiple 1515204a05dSNikhil Mahale * SET_UNSOLICITED_ENABLE calls on the same pin. 1525204a05dSNikhil Mahale */ 1535204a05dSNikhil Mahale jack->jack_detect = existing_nid_jack->jack_detect; 1545204a05dSNikhil Mahale } else { 1553a93897eSTakashi Iwai jack->tag = codec->jacktbl.used; 1565204a05dSNikhil Mahale } 1575204a05dSNikhil Mahale 1581835a0f9STakashi Iwai return jack; 1591835a0f9STakashi Iwai } 1601835a0f9STakashi Iwai 1611835a0f9STakashi Iwai void snd_hda_jack_tbl_clear(struct hda_codec *codec) 1621835a0f9STakashi Iwai { 16331ef2257STakashi Iwai struct hda_jack_tbl *jack = codec->jacktbl.list; 16431ef2257STakashi Iwai int i; 1651a4f69d5STakashi Iwai 16631ef2257STakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) { 1671a4f69d5STakashi Iwai struct hda_jack_callback *cb, *next; 1682ba2dfa1SJie Yang 1691a4f69d5STakashi Iwai /* free jack instances manually when clearing/reconfiguring */ 1701a4f69d5STakashi Iwai if (!codec->bus->shutdown && jack->jack) 1716efdd851STakashi Iwai snd_device_free(codec->card, jack->jack); 1722ba2dfa1SJie Yang 1731a4f69d5STakashi Iwai for (cb = jack->callback; cb; cb = next) { 1741a4f69d5STakashi Iwai next = cb->next; 1751a4f69d5STakashi Iwai kfree(cb); 1761a4f69d5STakashi Iwai } 1771a4f69d5STakashi Iwai } 1781835a0f9STakashi Iwai snd_array_free(&codec->jacktbl); 1791835a0f9STakashi Iwai } 1801835a0f9STakashi Iwai 1810619ba8cSDylan Reid #define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE) 1820619ba8cSDylan Reid 1831835a0f9STakashi Iwai /* update the cached value and notification flag if needed */ 1841835a0f9STakashi Iwai static void jack_detect_update(struct hda_codec *codec, 1851835a0f9STakashi Iwai struct hda_jack_tbl *jack) 1861835a0f9STakashi Iwai { 18780c8bfbeSDavid Henningsson if (!jack->jack_dirty) 18880c8bfbeSDavid Henningsson return; 18980c8bfbeSDavid Henningsson 19080c8bfbeSDavid Henningsson if (jack->phantom_jack) 19180c8bfbeSDavid Henningsson jack->pin_sense = AC_PINSENSE_PRESENCE; 19280c8bfbeSDavid Henningsson else 1935204a05dSNikhil Mahale jack->pin_sense = read_pin_sense(codec, jack->nid, 1945204a05dSNikhil Mahale jack->dev_id); 19580c8bfbeSDavid Henningsson 1960619ba8cSDylan Reid /* A gating jack indicates the jack is invalid if gating is unplugged */ 1975204a05dSNikhil Mahale if (jack->gating_jack && 1985204a05dSNikhil Mahale !snd_hda_jack_detect_mst(codec, jack->gating_jack, jack->dev_id)) 1990619ba8cSDylan Reid jack->pin_sense &= ~AC_PINSENSE_PRESENCE; 2000619ba8cSDylan Reid 2011835a0f9STakashi Iwai jack->jack_dirty = 0; 2020619ba8cSDylan Reid 2030619ba8cSDylan Reid /* If a jack is gated by this one update it. */ 2040619ba8cSDylan Reid if (jack->gated_jack) { 2050619ba8cSDylan Reid struct hda_jack_tbl *gated = 2065204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, jack->gated_jack, 2075204a05dSNikhil Mahale jack->dev_id); 2080619ba8cSDylan Reid if (gated) { 2090619ba8cSDylan Reid gated->jack_dirty = 1; 2100619ba8cSDylan Reid jack_detect_update(codec, gated); 2110619ba8cSDylan Reid } 2120619ba8cSDylan Reid } 2131835a0f9STakashi Iwai } 2141835a0f9STakashi Iwai 2151835a0f9STakashi Iwai /** 2161835a0f9STakashi Iwai * snd_hda_set_dirty_all - Mark all the cached as dirty 217a11e9b16STakashi Iwai * @codec: the HDA codec 2181835a0f9STakashi Iwai * 2191835a0f9STakashi Iwai * This function sets the dirty flag to all entries of jack table. 2201835a0f9STakashi Iwai * It's called from the resume path in hda_codec.c. 2211835a0f9STakashi Iwai */ 2221835a0f9STakashi Iwai void snd_hda_jack_set_dirty_all(struct hda_codec *codec) 2231835a0f9STakashi Iwai { 2241835a0f9STakashi Iwai struct hda_jack_tbl *jack = codec->jacktbl.list; 2251835a0f9STakashi Iwai int i; 2261835a0f9STakashi Iwai 2271835a0f9STakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) 2281835a0f9STakashi Iwai if (jack->nid) 2291835a0f9STakashi Iwai jack->jack_dirty = 1; 2301835a0f9STakashi Iwai } 2312698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_set_dirty_all); 2321835a0f9STakashi Iwai 2331835a0f9STakashi Iwai /** 23480b917a8SNikhil Mahale * snd_hda_jack_pin_sense - execute pin sense measurement 2351835a0f9STakashi Iwai * @codec: the CODEC to sense 2361835a0f9STakashi Iwai * @nid: the pin NID to sense 2374f5c2653SPierre-Louis Bossart * @dev_id: pin device entry id 2381835a0f9STakashi Iwai * 2391835a0f9STakashi Iwai * Execute necessary pin sense measurement and return its Presence Detect, 2401835a0f9STakashi Iwai * Impedance, ELD Valid etc. status bits. 2411835a0f9STakashi Iwai */ 2425204a05dSNikhil Mahale u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id) 2431835a0f9STakashi Iwai { 2445204a05dSNikhil Mahale struct hda_jack_tbl *jack = 2455204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, nid, dev_id); 2461835a0f9STakashi Iwai if (jack) { 2471835a0f9STakashi Iwai jack_detect_update(codec, jack); 2481835a0f9STakashi Iwai return jack->pin_sense; 2491835a0f9STakashi Iwai } 2505204a05dSNikhil Mahale return read_pin_sense(codec, nid, dev_id); 2511835a0f9STakashi Iwai } 25280b917a8SNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_pin_sense); 2531835a0f9STakashi Iwai 2541835a0f9STakashi Iwai /** 2555204a05dSNikhil Mahale * snd_hda_jack_detect_state_mst - query pin Presence Detect status 2561835a0f9STakashi Iwai * @codec: the CODEC to sense 2571835a0f9STakashi Iwai * @nid: the pin NID to sense 2585204a05dSNikhil Mahale * @dev_id: pin device entry id 2591835a0f9STakashi Iwai * 26060ea8ca2STakashi Iwai * Query and return the pin's Presence Detect status, as either 26160ea8ca2STakashi Iwai * HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM. 2621835a0f9STakashi Iwai */ 2635204a05dSNikhil Mahale int snd_hda_jack_detect_state_mst(struct hda_codec *codec, 2645204a05dSNikhil Mahale hda_nid_t nid, int dev_id) 2651835a0f9STakashi Iwai { 2665204a05dSNikhil Mahale struct hda_jack_tbl *jack = 2675204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, nid, dev_id); 26860ea8ca2STakashi Iwai if (jack && jack->phantom_jack) 26960ea8ca2STakashi Iwai return HDA_JACK_PHANTOM; 2705204a05dSNikhil Mahale else if (snd_hda_jack_pin_sense(codec, nid, dev_id) & 2715204a05dSNikhil Mahale AC_PINSENSE_PRESENCE) 27260ea8ca2STakashi Iwai return HDA_JACK_PRESENT; 27360ea8ca2STakashi Iwai else 27460ea8ca2STakashi Iwai return HDA_JACK_NOT_PRESENT; 2751835a0f9STakashi Iwai } 2765204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state_mst); 2771835a0f9STakashi Iwai 278033e4040SHui Wang static struct hda_jack_callback * 279033e4040SHui Wang find_callback_from_list(struct hda_jack_tbl *jack, 280f4794c60SHui Wang hda_jack_callback_fn func) 281f4794c60SHui Wang { 282f4794c60SHui Wang struct hda_jack_callback *cb; 283f4794c60SHui Wang 284033e4040SHui Wang if (!func) 285033e4040SHui Wang return NULL; 286033e4040SHui Wang 287f4794c60SHui Wang for (cb = jack->callback; cb; cb = cb->next) { 288f4794c60SHui Wang if (cb->func == func) 289033e4040SHui Wang return cb; 290f4794c60SHui Wang } 291033e4040SHui Wang 292033e4040SHui Wang return NULL; 293f4794c60SHui Wang } 294f4794c60SHui Wang 2951835a0f9STakashi Iwai /** 2965204a05dSNikhil Mahale * snd_hda_jack_detect_enable_mst - enable the jack-detection 297a11e9b16STakashi Iwai * @codec: the HDA codec 298a11e9b16STakashi Iwai * @nid: pin NID to enable 299a11e9b16STakashi Iwai * @func: callback function to register 3005204a05dSNikhil Mahale * @dev_id: pin device entry id 301bda17b82STakashi Iwai * 302bda17b82STakashi Iwai * In the case of error, the return value will be a pointer embedded with 303bda17b82STakashi Iwai * errno. Check and handle the return value appropriately with standard 304bda17b82STakashi Iwai * macros such as @IS_ERR() and @PTR_ERR(). 3051835a0f9STakashi Iwai */ 3061a4f69d5STakashi Iwai struct hda_jack_callback * 3075204a05dSNikhil Mahale snd_hda_jack_detect_enable_callback_mst(struct hda_codec *codec, hda_nid_t nid, 3085204a05dSNikhil Mahale int dev_id, hda_jack_callback_fn func) 3091835a0f9STakashi Iwai { 3101a4f69d5STakashi Iwai struct hda_jack_tbl *jack; 3111a4f69d5STakashi Iwai struct hda_jack_callback *callback = NULL; 312bda17b82STakashi Iwai int err; 313bda17b82STakashi Iwai 3145204a05dSNikhil Mahale jack = snd_hda_jack_tbl_new(codec, nid, dev_id); 3151835a0f9STakashi Iwai if (!jack) 316bda17b82STakashi Iwai return ERR_PTR(-ENOMEM); 317033e4040SHui Wang 318033e4040SHui Wang callback = find_callback_from_list(jack, func); 319033e4040SHui Wang 320033e4040SHui Wang if (func && !callback) { 3211a4f69d5STakashi Iwai callback = kzalloc(sizeof(*callback), GFP_KERNEL); 3221a4f69d5STakashi Iwai if (!callback) 3231a4f69d5STakashi Iwai return ERR_PTR(-ENOMEM); 3241a4f69d5STakashi Iwai callback->func = func; 3252ebab40eSTakashi Iwai callback->nid = jack->nid; 3265204a05dSNikhil Mahale callback->dev_id = jack->dev_id; 3271a4f69d5STakashi Iwai callback->next = jack->callback; 3281a4f69d5STakashi Iwai jack->callback = callback; 3291a4f69d5STakashi Iwai } 3301a4f69d5STakashi Iwai 3313a93897eSTakashi Iwai if (jack->jack_detect) 3321a4f69d5STakashi Iwai return callback; /* already registered */ 3333a93897eSTakashi Iwai jack->jack_detect = 1; 33434a93187SDavid Henningsson if (codec->jackpoll_interval > 0) 3351a4f69d5STakashi Iwai return callback; /* No unsol if we're polling instead */ 336bda17b82STakashi Iwai err = snd_hda_codec_write_cache(codec, nid, 0, 3371835a0f9STakashi Iwai AC_VERB_SET_UNSOLICITED_ENABLE, 3383a93897eSTakashi Iwai AC_USRSP_EN | jack->tag); 339bda17b82STakashi Iwai if (err < 0) 340bda17b82STakashi Iwai return ERR_PTR(err); 3411a4f69d5STakashi Iwai return callback; 3421835a0f9STakashi Iwai } 3435204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback_mst); 344954df2a9SDavid Henningsson 34595a962c3STakashi Iwai /** 34695a962c3STakashi Iwai * snd_hda_jack_detect_enable - Enable the jack detection on the given pin 34795a962c3STakashi Iwai * @codec: the HDA codec 34895a962c3STakashi Iwai * @nid: pin NID to enable jack detection 3495204a05dSNikhil Mahale * @dev_id: pin device entry id 35095a962c3STakashi Iwai * 35195a962c3STakashi Iwai * Enable the jack detection with the default callback. Returns zero if 35295a962c3STakashi Iwai * successful or a negative error code. 35395a962c3STakashi Iwai */ 3545204a05dSNikhil Mahale int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, 3555204a05dSNikhil Mahale int dev_id) 356954df2a9SDavid Henningsson { 3575204a05dSNikhil Mahale return PTR_ERR_OR_ZERO(snd_hda_jack_detect_enable_callback_mst(codec, 3585204a05dSNikhil Mahale nid, 3595204a05dSNikhil Mahale dev_id, 3605204a05dSNikhil Mahale NULL)); 361954df2a9SDavid Henningsson } 3622698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable); 36301a61e12STakashi Iwai 36401a61e12STakashi Iwai /** 3650619ba8cSDylan Reid * snd_hda_jack_set_gating_jack - Set gating jack. 366a11e9b16STakashi Iwai * @codec: the HDA codec 367a11e9b16STakashi Iwai * @gated_nid: gated pin NID 368a11e9b16STakashi Iwai * @gating_nid: gating pin NID 3690619ba8cSDylan Reid * 3700619ba8cSDylan Reid * Indicates the gated jack is only valid when the gating jack is plugged. 3710619ba8cSDylan Reid */ 3720619ba8cSDylan Reid int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, 3730619ba8cSDylan Reid hda_nid_t gating_nid) 3740619ba8cSDylan Reid { 3755204a05dSNikhil Mahale struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid, 0); 3765204a05dSNikhil Mahale struct hda_jack_tbl *gating = 3775204a05dSNikhil Mahale snd_hda_jack_tbl_new(codec, gating_nid, 0); 3785204a05dSNikhil Mahale 3795204a05dSNikhil Mahale WARN_ON(codec->dp_mst); 3800619ba8cSDylan Reid 3810619ba8cSDylan Reid if (!gated || !gating) 3820619ba8cSDylan Reid return -EINVAL; 3830619ba8cSDylan Reid 3840619ba8cSDylan Reid gated->gating_jack = gating_nid; 3850619ba8cSDylan Reid gating->gated_jack = gated_nid; 3860619ba8cSDylan Reid 3870619ba8cSDylan Reid return 0; 3880619ba8cSDylan Reid } 3892698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_set_gating_jack); 3900619ba8cSDylan Reid 3910619ba8cSDylan Reid /** 392*04f7791bSHui Wang * snd_hda_jack_bind_keymap - bind keys generated from one NID to another jack. 393*04f7791bSHui Wang * @codec: the HDA codec 394*04f7791bSHui Wang * @key_nid: key event is generated by this pin NID 395*04f7791bSHui Wang * @keymap: map of key type and key code 396*04f7791bSHui Wang * @jack_nid: key reports to the jack of this pin NID 397*04f7791bSHui Wang * 398*04f7791bSHui Wang * This function is used in the case of key is generated from one NID while is 399*04f7791bSHui Wang * reported to the jack of another NID. 400*04f7791bSHui Wang */ 401*04f7791bSHui Wang int snd_hda_jack_bind_keymap(struct hda_codec *codec, hda_nid_t key_nid, 402*04f7791bSHui Wang const struct hda_jack_keymap *keymap, 403*04f7791bSHui Wang hda_nid_t jack_nid) 404*04f7791bSHui Wang { 405*04f7791bSHui Wang const struct hda_jack_keymap *map; 406*04f7791bSHui Wang struct hda_jack_tbl *key_gen = snd_hda_jack_tbl_get(codec, key_nid); 407*04f7791bSHui Wang struct hda_jack_tbl *report_to = snd_hda_jack_tbl_get(codec, jack_nid); 408*04f7791bSHui Wang 409*04f7791bSHui Wang WARN_ON(codec->dp_mst); 410*04f7791bSHui Wang 411*04f7791bSHui Wang if (!key_gen || !report_to || !report_to->jack) 412*04f7791bSHui Wang return -EINVAL; 413*04f7791bSHui Wang 414*04f7791bSHui Wang key_gen->key_report_jack = jack_nid; 415*04f7791bSHui Wang 416*04f7791bSHui Wang if (keymap) 417*04f7791bSHui Wang for (map = keymap; map->type; map++) 418*04f7791bSHui Wang snd_jack_set_key(report_to->jack, map->type, map->key); 419*04f7791bSHui Wang 420*04f7791bSHui Wang return 0; 421*04f7791bSHui Wang } 422*04f7791bSHui Wang EXPORT_SYMBOL_GPL(snd_hda_jack_bind_keymap); 423*04f7791bSHui Wang 424*04f7791bSHui Wang /** 425*04f7791bSHui Wang * snd_hda_jack_set_button_state - report button event to the hda_jack_tbl button_state. 426*04f7791bSHui Wang * @codec: the HDA codec 427*04f7791bSHui Wang * @jack_nid: the button event reports to the jack_tbl of this NID 428*04f7791bSHui Wang * @button_state: the button event captured by codec 429*04f7791bSHui Wang * 430*04f7791bSHui Wang * Codec driver calls this function to report the button event. 431*04f7791bSHui Wang */ 432*04f7791bSHui Wang void snd_hda_jack_set_button_state(struct hda_codec *codec, hda_nid_t jack_nid, 433*04f7791bSHui Wang int button_state) 434*04f7791bSHui Wang { 435*04f7791bSHui Wang struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, jack_nid); 436*04f7791bSHui Wang 437*04f7791bSHui Wang if (!jack) 438*04f7791bSHui Wang return; 439*04f7791bSHui Wang 440*04f7791bSHui Wang if (jack->key_report_jack) { 441*04f7791bSHui Wang struct hda_jack_tbl *report_to = 442*04f7791bSHui Wang snd_hda_jack_tbl_get(codec, jack->key_report_jack); 443*04f7791bSHui Wang 444*04f7791bSHui Wang if (report_to) { 445*04f7791bSHui Wang report_to->button_state = button_state; 446*04f7791bSHui Wang return; 447*04f7791bSHui Wang } 448*04f7791bSHui Wang } 449*04f7791bSHui Wang 450*04f7791bSHui Wang jack->button_state = button_state; 451*04f7791bSHui Wang } 452*04f7791bSHui Wang EXPORT_SYMBOL_GPL(snd_hda_jack_set_button_state); 453*04f7791bSHui Wang 454*04f7791bSHui Wang /** 45501a61e12STakashi Iwai * snd_hda_jack_report_sync - sync the states of all jacks and report if changed 456a11e9b16STakashi Iwai * @codec: the HDA codec 45701a61e12STakashi Iwai */ 45801a61e12STakashi Iwai void snd_hda_jack_report_sync(struct hda_codec *codec) 45901a61e12STakashi Iwai { 4600619ba8cSDylan Reid struct hda_jack_tbl *jack; 46135be544aSTakashi Iwai int i, state; 46201a61e12STakashi Iwai 4630619ba8cSDylan Reid /* update all jacks at first */ 4640619ba8cSDylan Reid jack = codec->jacktbl.list; 4650619ba8cSDylan Reid for (i = 0; i < codec->jacktbl.used; i++, jack++) 4660619ba8cSDylan Reid if (jack->nid) 4670619ba8cSDylan Reid jack_detect_update(codec, jack); 4680619ba8cSDylan Reid 4690619ba8cSDylan Reid /* report the updated jacks; it's done after updating all jacks 4700619ba8cSDylan Reid * to make sure that all gating jacks properly have been set 4710619ba8cSDylan Reid */ 4720619ba8cSDylan Reid jack = codec->jacktbl.list; 47301a61e12STakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) 47401a61e12STakashi Iwai if (jack->nid) { 4752ba2dfa1SJie Yang if (!jack->jack || jack->block_report) 476cfc7c9d3STakashi Iwai continue; 477911761c2STakashi Iwai state = jack->button_state; 478911761c2STakashi Iwai if (get_jack_plug_state(jack->pin_sense)) 479911761c2STakashi Iwai state |= jack->type; 480911761c2STakashi Iwai snd_jack_report(jack->jack, state); 481911761c2STakashi Iwai if (jack->button_state) { 48231ef2257STakashi Iwai snd_jack_report(jack->jack, 483911761c2STakashi Iwai state & ~jack->button_state); 484911761c2STakashi Iwai jack->button_state = 0; /* button released */ 485911761c2STakashi Iwai } 48601a61e12STakashi Iwai } 48701a61e12STakashi Iwai } 4882698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_report_sync); 48901a61e12STakashi Iwai 49031ef2257STakashi Iwai /* guess the jack type from the pin-config */ 49131ef2257STakashi Iwai static int get_input_jack_type(struct hda_codec *codec, hda_nid_t nid) 49231ef2257STakashi Iwai { 49331ef2257STakashi Iwai unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); 49431ef2257STakashi Iwai switch (get_defcfg_device(def_conf)) { 49531ef2257STakashi Iwai case AC_JACK_LINE_OUT: 49631ef2257STakashi Iwai case AC_JACK_SPEAKER: 49731ef2257STakashi Iwai return SND_JACK_LINEOUT; 49831ef2257STakashi Iwai case AC_JACK_HP_OUT: 49931ef2257STakashi Iwai return SND_JACK_HEADPHONE; 50031ef2257STakashi Iwai case AC_JACK_SPDIF_OUT: 50131ef2257STakashi Iwai case AC_JACK_DIG_OTHER_OUT: 50231ef2257STakashi Iwai return SND_JACK_AVOUT; 50331ef2257STakashi Iwai case AC_JACK_MIC_IN: 50431ef2257STakashi Iwai return SND_JACK_MICROPHONE; 50531ef2257STakashi Iwai default: 50631ef2257STakashi Iwai return SND_JACK_LINEIN; 50731ef2257STakashi Iwai } 50831ef2257STakashi Iwai } 50931ef2257STakashi Iwai 51031ef2257STakashi Iwai static void hda_free_jack_priv(struct snd_jack *jack) 51131ef2257STakashi Iwai { 51231ef2257STakashi Iwai struct hda_jack_tbl *jacks = jack->private_data; 51331ef2257STakashi Iwai jacks->nid = 0; 51431ef2257STakashi Iwai jacks->jack = NULL; 51531ef2257STakashi Iwai } 51631ef2257STakashi Iwai 51701a61e12STakashi Iwai /** 5185204a05dSNikhil Mahale * snd_hda_jack_add_kctl_mst - Add a kctl for the given pin 519a11e9b16STakashi Iwai * @codec: the HDA codec 520a11e9b16STakashi Iwai * @nid: pin NID to assign 5215204a05dSNikhil Mahale * @dev_id : pin device entry id 522a11e9b16STakashi Iwai * @name: string name for the jack 523a11e9b16STakashi Iwai * @phantom_jack: flag to deal as a phantom jack 524911761c2STakashi Iwai * @type: jack type bits to be reported, 0 for guessing from pincfg 525911761c2STakashi Iwai * @keymap: optional jack / key mapping 52601a61e12STakashi Iwai * 52701a61e12STakashi Iwai * This assigns a jack-detection kctl to the given pin. The kcontrol 52801a61e12STakashi Iwai * will have the given name and index. 52901a61e12STakashi Iwai */ 5305204a05dSNikhil Mahale int snd_hda_jack_add_kctl_mst(struct hda_codec *codec, hda_nid_t nid, 5315204a05dSNikhil Mahale int dev_id, const char *name, bool phantom_jack, 532911761c2STakashi Iwai int type, const struct hda_jack_keymap *keymap) 53301a61e12STakashi Iwai { 53401a61e12STakashi Iwai struct hda_jack_tbl *jack; 535911761c2STakashi Iwai const struct hda_jack_keymap *map; 536911761c2STakashi Iwai int err, state, buttons; 53701a61e12STakashi Iwai 5385204a05dSNikhil Mahale jack = snd_hda_jack_tbl_new(codec, nid, dev_id); 53901a61e12STakashi Iwai if (!jack) 54001a61e12STakashi Iwai return 0; 5412ba2dfa1SJie Yang if (jack->jack) 54201a61e12STakashi Iwai return 0; /* already created */ 54380c8bfbeSDavid Henningsson 544911761c2STakashi Iwai if (!type) 5452ba2dfa1SJie Yang type = get_input_jack_type(codec, nid); 546911761c2STakashi Iwai 547911761c2STakashi Iwai buttons = 0; 548911761c2STakashi Iwai if (keymap) { 549911761c2STakashi Iwai for (map = keymap; map->type; map++) 550911761c2STakashi Iwai buttons |= map->type; 551911761c2STakashi Iwai } 552911761c2STakashi Iwai 553911761c2STakashi Iwai err = snd_jack_new(codec->card, name, type | buttons, 5542ba2dfa1SJie Yang &jack->jack, true, phantom_jack); 55531ef2257STakashi Iwai if (err < 0) 55631ef2257STakashi Iwai return err; 5572ba2dfa1SJie Yang 5582ba2dfa1SJie Yang jack->phantom_jack = !!phantom_jack; 5592ba2dfa1SJie Yang jack->type = type; 560911761c2STakashi Iwai jack->button_state = 0; 56131ef2257STakashi Iwai jack->jack->private_data = jack; 56231ef2257STakashi Iwai jack->jack->private_free = hda_free_jack_priv; 563911761c2STakashi Iwai if (keymap) { 564911761c2STakashi Iwai for (map = keymap; map->type; map++) 565911761c2STakashi Iwai snd_jack_set_key(jack->jack, map->type, map->key); 566911761c2STakashi Iwai } 567911761c2STakashi Iwai 5685204a05dSNikhil Mahale state = snd_hda_jack_detect_mst(codec, nid, dev_id); 56931ef2257STakashi Iwai snd_jack_report(jack->jack, state ? jack->type : 0); 5702ba2dfa1SJie Yang 57101a61e12STakashi Iwai return 0; 57201a61e12STakashi Iwai } 5735204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl_mst); 57401a61e12STakashi Iwai 575201e06ffSTakashi Iwai static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, 576b26b5116SDavid Henningsson const struct auto_pin_cfg *cfg, 577b26b5116SDavid Henningsson const char *base_name) 57801a61e12STakashi Iwai { 5793a93897eSTakashi Iwai unsigned int def_conf, conn; 580975cc02aSTakashi Iwai char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 5812ba2dfa1SJie Yang int err; 58280c8bfbeSDavid Henningsson bool phantom_jack; 5833a93897eSTakashi Iwai 5845204a05dSNikhil Mahale WARN_ON(codec->dp_mst); 5855204a05dSNikhil Mahale 58601a61e12STakashi Iwai if (!nid) 58701a61e12STakashi Iwai return 0; 5883a93897eSTakashi Iwai def_conf = snd_hda_codec_get_pincfg(codec, nid); 5893a93897eSTakashi Iwai conn = get_defcfg_connect(def_conf); 59080c8bfbeSDavid Henningsson if (conn == AC_JACK_PORT_NONE) 5913a93897eSTakashi Iwai return 0; 59280c8bfbeSDavid Henningsson phantom_jack = (conn != AC_JACK_PORT_COMPLEX) || 59380c8bfbeSDavid Henningsson !is_jack_detectable(codec, nid); 5943a93897eSTakashi Iwai 5952ba2dfa1SJie Yang if (base_name) 59675b1a8f9SJoe Perches strscpy(name, base_name, sizeof(name)); 5972ba2dfa1SJie Yang else 5982ba2dfa1SJie Yang snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), NULL); 59980c8bfbeSDavid Henningsson if (phantom_jack) 60080c8bfbeSDavid Henningsson /* Example final name: "Internal Mic Phantom Jack" */ 60180c8bfbeSDavid Henningsson strncat(name, " Phantom", sizeof(name) - strlen(name) - 1); 602911761c2STakashi Iwai err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack, 0, NULL); 6033a93897eSTakashi Iwai if (err < 0) 6043a93897eSTakashi Iwai return err; 60580c8bfbeSDavid Henningsson 60680c8bfbeSDavid Henningsson if (!phantom_jack) 6075204a05dSNikhil Mahale return snd_hda_jack_detect_enable(codec, nid, 0); 60880c8bfbeSDavid Henningsson return 0; 60901a61e12STakashi Iwai } 61001a61e12STakashi Iwai 61101a61e12STakashi Iwai /** 61201a61e12STakashi Iwai * snd_hda_jack_add_kctls - Add kctls for all pins included in the given pincfg 613a11e9b16STakashi Iwai * @codec: the HDA codec 614a11e9b16STakashi Iwai * @cfg: pin config table to parse 61501a61e12STakashi Iwai */ 61601a61e12STakashi Iwai int snd_hda_jack_add_kctls(struct hda_codec *codec, 61701a61e12STakashi Iwai const struct auto_pin_cfg *cfg) 61801a61e12STakashi Iwai { 61901a61e12STakashi Iwai const hda_nid_t *p; 620f46c3296STakashi Iwai int i, err; 62101a61e12STakashi Iwai 622b26b5116SDavid Henningsson for (i = 0; i < cfg->num_inputs; i++) { 623b26b5116SDavid Henningsson /* If we have headphone mics; make sure they get the right name 624b26b5116SDavid Henningsson before grabbed by output pins */ 625b26b5116SDavid Henningsson if (cfg->inputs[i].is_headphone_mic) { 626b26b5116SDavid Henningsson if (auto_cfg_hp_outs(cfg) == 1) 627b26b5116SDavid Henningsson err = add_jack_kctl(codec, auto_cfg_hp_pins(cfg)[0], 628b26b5116SDavid Henningsson cfg, "Headphone Mic"); 629b26b5116SDavid Henningsson else 630b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->inputs[i].pin, 631b26b5116SDavid Henningsson cfg, "Headphone Mic"); 632b26b5116SDavid Henningsson } else 633b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg, 634b26b5116SDavid Henningsson NULL); 635b26b5116SDavid Henningsson if (err < 0) 636b26b5116SDavid Henningsson return err; 637b26b5116SDavid Henningsson } 638b26b5116SDavid Henningsson 63901a61e12STakashi Iwai for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) { 640b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 64101a61e12STakashi Iwai if (err < 0) 64201a61e12STakashi Iwai return err; 64301a61e12STakashi Iwai } 64401a61e12STakashi Iwai for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) { 64501a61e12STakashi Iwai if (*p == *cfg->line_out_pins) /* might be duplicated */ 64601a61e12STakashi Iwai break; 647b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 64801a61e12STakashi Iwai if (err < 0) 64901a61e12STakashi Iwai return err; 65001a61e12STakashi Iwai } 65101a61e12STakashi Iwai for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) { 65201a61e12STakashi Iwai if (*p == *cfg->line_out_pins) /* might be duplicated */ 65301a61e12STakashi Iwai break; 654b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 65501a61e12STakashi Iwai if (err < 0) 65601a61e12STakashi Iwai return err; 65701a61e12STakashi Iwai } 65801a61e12STakashi Iwai for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) { 659b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 66001a61e12STakashi Iwai if (err < 0) 66101a61e12STakashi Iwai return err; 66201a61e12STakashi Iwai } 663b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->dig_in_pin, cfg, NULL); 66401a61e12STakashi Iwai if (err < 0) 66501a61e12STakashi Iwai return err; 666b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->mono_out_pin, cfg, NULL); 66701a61e12STakashi Iwai if (err < 0) 66801a61e12STakashi Iwai return err; 66901a61e12STakashi Iwai return 0; 67001a61e12STakashi Iwai } 6712698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctls); 672954df2a9SDavid Henningsson 673e6ce180fSTakashi Iwai static void call_jack_callback(struct hda_codec *codec, unsigned int res, 6740619ba8cSDylan Reid struct hda_jack_tbl *jack) 6750619ba8cSDylan Reid { 6761a4f69d5STakashi Iwai struct hda_jack_callback *cb; 6771a4f69d5STakashi Iwai 678e6ce180fSTakashi Iwai for (cb = jack->callback; cb; cb = cb->next) { 679e6ce180fSTakashi Iwai cb->jack = jack; 680e6ce180fSTakashi Iwai cb->unsol_res = res; 6811a4f69d5STakashi Iwai cb->func(codec, cb); 682e6ce180fSTakashi Iwai } 6830619ba8cSDylan Reid if (jack->gated_jack) { 6840619ba8cSDylan Reid struct hda_jack_tbl *gated = 6855204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, jack->gated_jack, 6865204a05dSNikhil Mahale jack->dev_id); 6871a4f69d5STakashi Iwai if (gated) { 688e6ce180fSTakashi Iwai for (cb = gated->callback; cb; cb = cb->next) { 689e6ce180fSTakashi Iwai cb->jack = gated; 690e6ce180fSTakashi Iwai cb->unsol_res = res; 6911a4f69d5STakashi Iwai cb->func(codec, cb); 6921a4f69d5STakashi Iwai } 6930619ba8cSDylan Reid } 6940619ba8cSDylan Reid } 695e6ce180fSTakashi Iwai } 6960619ba8cSDylan Reid 69795a962c3STakashi Iwai /** 69895a962c3STakashi Iwai * snd_hda_jack_unsol_event - Handle an unsolicited event 69995a962c3STakashi Iwai * @codec: the HDA codec 70095a962c3STakashi Iwai * @res: the unsolicited event data 70195a962c3STakashi Iwai */ 702954df2a9SDavid Henningsson void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) 703954df2a9SDavid Henningsson { 704954df2a9SDavid Henningsson struct hda_jack_tbl *event; 705c7e68a69SGuennadi Liakhovetski int tag = (res & AC_UNSOL_RES_TAG) >> AC_UNSOL_RES_TAG_SHIFT; 706954df2a9SDavid Henningsson 7075204a05dSNikhil Mahale if (codec->dp_mst) { 7085204a05dSNikhil Mahale int dev_entry = 7095204a05dSNikhil Mahale (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT; 7105204a05dSNikhil Mahale 7115204a05dSNikhil Mahale event = snd_hda_jack_tbl_get_from_tag(codec, tag, dev_entry); 7125204a05dSNikhil Mahale } else { 7135204a05dSNikhil Mahale event = snd_hda_jack_tbl_get_from_tag(codec, tag, 0); 7145204a05dSNikhil Mahale } 715954df2a9SDavid Henningsson if (!event) 716954df2a9SDavid Henningsson return; 717*04f7791bSHui Wang 718*04f7791bSHui Wang if (event->key_report_jack) { 719*04f7791bSHui Wang struct hda_jack_tbl *report_to = 720*04f7791bSHui Wang snd_hda_jack_tbl_get_mst(codec, event->key_report_jack, 721*04f7791bSHui Wang event->dev_id); 722*04f7791bSHui Wang if (report_to) 723*04f7791bSHui Wang report_to->jack_dirty = 1; 724*04f7791bSHui Wang } else 725954df2a9SDavid Henningsson event->jack_dirty = 1; 726954df2a9SDavid Henningsson 727e6ce180fSTakashi Iwai call_jack_callback(codec, res, event); 728954df2a9SDavid Henningsson snd_hda_jack_report_sync(codec); 729954df2a9SDavid Henningsson } 7302698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_unsol_event); 731954df2a9SDavid Henningsson 73295a962c3STakashi Iwai /** 73395a962c3STakashi Iwai * snd_hda_jack_poll_all - Poll all jacks 73495a962c3STakashi Iwai * @codec: the HDA codec 73595a962c3STakashi Iwai * 73695a962c3STakashi Iwai * Poll all detectable jacks with dirty flag, update the status, call 73795a962c3STakashi Iwai * callbacks and call snd_hda_jack_report_sync() if any changes are found. 73895a962c3STakashi Iwai */ 73926a6cb6cSDavid Henningsson void snd_hda_jack_poll_all(struct hda_codec *codec) 74026a6cb6cSDavid Henningsson { 74126a6cb6cSDavid Henningsson struct hda_jack_tbl *jack = codec->jacktbl.list; 74226a6cb6cSDavid Henningsson int i, changes = 0; 74326a6cb6cSDavid Henningsson 74426a6cb6cSDavid Henningsson for (i = 0; i < codec->jacktbl.used; i++, jack++) { 74526a6cb6cSDavid Henningsson unsigned int old_sense; 74626a6cb6cSDavid Henningsson if (!jack->nid || !jack->jack_dirty || jack->phantom_jack) 74726a6cb6cSDavid Henningsson continue; 74826a6cb6cSDavid Henningsson old_sense = get_jack_plug_state(jack->pin_sense); 74926a6cb6cSDavid Henningsson jack_detect_update(codec, jack); 75026a6cb6cSDavid Henningsson if (old_sense == get_jack_plug_state(jack->pin_sense)) 75126a6cb6cSDavid Henningsson continue; 75226a6cb6cSDavid Henningsson changes = 1; 753e6ce180fSTakashi Iwai call_jack_callback(codec, 0, jack); 75426a6cb6cSDavid Henningsson } 75526a6cb6cSDavid Henningsson if (changes) 75626a6cb6cSDavid Henningsson snd_hda_jack_report_sync(codec); 75726a6cb6cSDavid Henningsson } 7582698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_poll_all); 75926a6cb6cSDavid Henningsson 760