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 161*37c4fd0dSTakashi Iwai void snd_hda_jack_tbl_disconnect(struct hda_codec *codec) 162*37c4fd0dSTakashi Iwai { 163*37c4fd0dSTakashi Iwai struct hda_jack_tbl *jack = codec->jacktbl.list; 164*37c4fd0dSTakashi Iwai int i; 165*37c4fd0dSTakashi Iwai 166*37c4fd0dSTakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) { 167*37c4fd0dSTakashi Iwai if (!codec->bus->shutdown && jack->jack) 168*37c4fd0dSTakashi Iwai snd_device_disconnect(codec->card, jack->jack); 169*37c4fd0dSTakashi Iwai } 170*37c4fd0dSTakashi Iwai } 171*37c4fd0dSTakashi Iwai 1721835a0f9STakashi Iwai void snd_hda_jack_tbl_clear(struct hda_codec *codec) 1731835a0f9STakashi Iwai { 17431ef2257STakashi Iwai struct hda_jack_tbl *jack = codec->jacktbl.list; 17531ef2257STakashi Iwai int i; 1761a4f69d5STakashi Iwai 17731ef2257STakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) { 1781a4f69d5STakashi Iwai struct hda_jack_callback *cb, *next; 1792ba2dfa1SJie Yang 1801a4f69d5STakashi Iwai /* free jack instances manually when clearing/reconfiguring */ 1811a4f69d5STakashi Iwai if (!codec->bus->shutdown && jack->jack) 1826efdd851STakashi Iwai snd_device_free(codec->card, jack->jack); 1832ba2dfa1SJie Yang 1841a4f69d5STakashi Iwai for (cb = jack->callback; cb; cb = next) { 1851a4f69d5STakashi Iwai next = cb->next; 1861a4f69d5STakashi Iwai kfree(cb); 1871a4f69d5STakashi Iwai } 1881a4f69d5STakashi Iwai } 1891835a0f9STakashi Iwai snd_array_free(&codec->jacktbl); 1901835a0f9STakashi Iwai } 1911835a0f9STakashi Iwai 1920619ba8cSDylan Reid #define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE) 1930619ba8cSDylan Reid 1941835a0f9STakashi Iwai /* update the cached value and notification flag if needed */ 1951835a0f9STakashi Iwai static void jack_detect_update(struct hda_codec *codec, 1961835a0f9STakashi Iwai struct hda_jack_tbl *jack) 1971835a0f9STakashi Iwai { 19880c8bfbeSDavid Henningsson if (!jack->jack_dirty) 19980c8bfbeSDavid Henningsson return; 20080c8bfbeSDavid Henningsson 20180c8bfbeSDavid Henningsson if (jack->phantom_jack) 20280c8bfbeSDavid Henningsson jack->pin_sense = AC_PINSENSE_PRESENCE; 20380c8bfbeSDavid Henningsson else 2045204a05dSNikhil Mahale jack->pin_sense = read_pin_sense(codec, jack->nid, 2055204a05dSNikhil Mahale jack->dev_id); 20680c8bfbeSDavid Henningsson 2070619ba8cSDylan Reid /* A gating jack indicates the jack is invalid if gating is unplugged */ 2085204a05dSNikhil Mahale if (jack->gating_jack && 2095204a05dSNikhil Mahale !snd_hda_jack_detect_mst(codec, jack->gating_jack, jack->dev_id)) 2100619ba8cSDylan Reid jack->pin_sense &= ~AC_PINSENSE_PRESENCE; 2110619ba8cSDylan Reid 2121835a0f9STakashi Iwai jack->jack_dirty = 0; 2130619ba8cSDylan Reid 2140619ba8cSDylan Reid /* If a jack is gated by this one update it. */ 2150619ba8cSDylan Reid if (jack->gated_jack) { 2160619ba8cSDylan Reid struct hda_jack_tbl *gated = 2175204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, jack->gated_jack, 2185204a05dSNikhil Mahale jack->dev_id); 2190619ba8cSDylan Reid if (gated) { 2200619ba8cSDylan Reid gated->jack_dirty = 1; 2210619ba8cSDylan Reid jack_detect_update(codec, gated); 2220619ba8cSDylan Reid } 2230619ba8cSDylan Reid } 2241835a0f9STakashi Iwai } 2251835a0f9STakashi Iwai 2261835a0f9STakashi Iwai /** 2273531ba21SPierre-Louis Bossart * snd_hda_jack_set_dirty_all - Mark all the cached as dirty 228a11e9b16STakashi Iwai * @codec: the HDA codec 2291835a0f9STakashi Iwai * 2301835a0f9STakashi Iwai * This function sets the dirty flag to all entries of jack table. 2311835a0f9STakashi Iwai * It's called from the resume path in hda_codec.c. 2321835a0f9STakashi Iwai */ 2331835a0f9STakashi Iwai void snd_hda_jack_set_dirty_all(struct hda_codec *codec) 2341835a0f9STakashi Iwai { 2351835a0f9STakashi Iwai struct hda_jack_tbl *jack = codec->jacktbl.list; 2361835a0f9STakashi Iwai int i; 2371835a0f9STakashi Iwai 2381835a0f9STakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) 2391835a0f9STakashi Iwai if (jack->nid) 2401835a0f9STakashi Iwai jack->jack_dirty = 1; 2411835a0f9STakashi Iwai } 2422698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_set_dirty_all); 2431835a0f9STakashi Iwai 2441835a0f9STakashi Iwai /** 24580b917a8SNikhil Mahale * snd_hda_jack_pin_sense - execute pin sense measurement 2461835a0f9STakashi Iwai * @codec: the CODEC to sense 2471835a0f9STakashi Iwai * @nid: the pin NID to sense 2484f5c2653SPierre-Louis Bossart * @dev_id: pin device entry id 2491835a0f9STakashi Iwai * 2501835a0f9STakashi Iwai * Execute necessary pin sense measurement and return its Presence Detect, 2511835a0f9STakashi Iwai * Impedance, ELD Valid etc. status bits. 2521835a0f9STakashi Iwai */ 2535204a05dSNikhil Mahale u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id) 2541835a0f9STakashi Iwai { 2555204a05dSNikhil Mahale struct hda_jack_tbl *jack = 2565204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, nid, dev_id); 2571835a0f9STakashi Iwai if (jack) { 2581835a0f9STakashi Iwai jack_detect_update(codec, jack); 2591835a0f9STakashi Iwai return jack->pin_sense; 2601835a0f9STakashi Iwai } 2615204a05dSNikhil Mahale return read_pin_sense(codec, nid, dev_id); 2621835a0f9STakashi Iwai } 26380b917a8SNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_pin_sense); 2641835a0f9STakashi Iwai 2651835a0f9STakashi Iwai /** 2665204a05dSNikhil Mahale * snd_hda_jack_detect_state_mst - query pin Presence Detect status 2671835a0f9STakashi Iwai * @codec: the CODEC to sense 2681835a0f9STakashi Iwai * @nid: the pin NID to sense 2695204a05dSNikhil Mahale * @dev_id: pin device entry id 2701835a0f9STakashi Iwai * 27160ea8ca2STakashi Iwai * Query and return the pin's Presence Detect status, as either 27260ea8ca2STakashi Iwai * HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM. 2731835a0f9STakashi Iwai */ 2745204a05dSNikhil Mahale int snd_hda_jack_detect_state_mst(struct hda_codec *codec, 2755204a05dSNikhil Mahale hda_nid_t nid, int dev_id) 2761835a0f9STakashi Iwai { 2775204a05dSNikhil Mahale struct hda_jack_tbl *jack = 2785204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, nid, dev_id); 27960ea8ca2STakashi Iwai if (jack && jack->phantom_jack) 28060ea8ca2STakashi Iwai return HDA_JACK_PHANTOM; 2815204a05dSNikhil Mahale else if (snd_hda_jack_pin_sense(codec, nid, dev_id) & 2825204a05dSNikhil Mahale AC_PINSENSE_PRESENCE) 28360ea8ca2STakashi Iwai return HDA_JACK_PRESENT; 28460ea8ca2STakashi Iwai else 28560ea8ca2STakashi Iwai return HDA_JACK_NOT_PRESENT; 2861835a0f9STakashi Iwai } 2875204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state_mst); 2881835a0f9STakashi Iwai 289033e4040SHui Wang static struct hda_jack_callback * 290033e4040SHui Wang find_callback_from_list(struct hda_jack_tbl *jack, 291f4794c60SHui Wang hda_jack_callback_fn func) 292f4794c60SHui Wang { 293f4794c60SHui Wang struct hda_jack_callback *cb; 294f4794c60SHui Wang 295033e4040SHui Wang if (!func) 296033e4040SHui Wang return NULL; 297033e4040SHui Wang 298f4794c60SHui Wang for (cb = jack->callback; cb; cb = cb->next) { 299f4794c60SHui Wang if (cb->func == func) 300033e4040SHui Wang return cb; 301f4794c60SHui Wang } 302033e4040SHui Wang 303033e4040SHui Wang return NULL; 304f4794c60SHui Wang } 305f4794c60SHui Wang 3061835a0f9STakashi Iwai /** 3073531ba21SPierre-Louis Bossart * snd_hda_jack_detect_enable_callback_mst - enable the jack-detection 308a11e9b16STakashi Iwai * @codec: the HDA codec 309a11e9b16STakashi Iwai * @nid: pin NID to enable 310a11e9b16STakashi Iwai * @func: callback function to register 3115204a05dSNikhil Mahale * @dev_id: pin device entry id 312bda17b82STakashi Iwai * 313bda17b82STakashi Iwai * In the case of error, the return value will be a pointer embedded with 314bda17b82STakashi Iwai * errno. Check and handle the return value appropriately with standard 315bda17b82STakashi Iwai * macros such as @IS_ERR() and @PTR_ERR(). 3161835a0f9STakashi Iwai */ 3171a4f69d5STakashi Iwai struct hda_jack_callback * 3185204a05dSNikhil Mahale snd_hda_jack_detect_enable_callback_mst(struct hda_codec *codec, hda_nid_t nid, 3195204a05dSNikhil Mahale int dev_id, hda_jack_callback_fn func) 3201835a0f9STakashi Iwai { 3211a4f69d5STakashi Iwai struct hda_jack_tbl *jack; 3221a4f69d5STakashi Iwai struct hda_jack_callback *callback = NULL; 323bda17b82STakashi Iwai int err; 324bda17b82STakashi Iwai 3255204a05dSNikhil Mahale jack = snd_hda_jack_tbl_new(codec, nid, dev_id); 3261835a0f9STakashi Iwai if (!jack) 327bda17b82STakashi Iwai return ERR_PTR(-ENOMEM); 328033e4040SHui Wang 329033e4040SHui Wang callback = find_callback_from_list(jack, func); 330033e4040SHui Wang 331033e4040SHui Wang if (func && !callback) { 3321a4f69d5STakashi Iwai callback = kzalloc(sizeof(*callback), GFP_KERNEL); 3331a4f69d5STakashi Iwai if (!callback) 3341a4f69d5STakashi Iwai return ERR_PTR(-ENOMEM); 3351a4f69d5STakashi Iwai callback->func = func; 3362ebab40eSTakashi Iwai callback->nid = jack->nid; 3375204a05dSNikhil Mahale callback->dev_id = jack->dev_id; 3381a4f69d5STakashi Iwai callback->next = jack->callback; 3391a4f69d5STakashi Iwai jack->callback = callback; 3401a4f69d5STakashi Iwai } 3411a4f69d5STakashi Iwai 3423a93897eSTakashi Iwai if (jack->jack_detect) 3431a4f69d5STakashi Iwai return callback; /* already registered */ 3443a93897eSTakashi Iwai jack->jack_detect = 1; 34534a93187SDavid Henningsson if (codec->jackpoll_interval > 0) 3461a4f69d5STakashi Iwai return callback; /* No unsol if we're polling instead */ 347bda17b82STakashi Iwai err = snd_hda_codec_write_cache(codec, nid, 0, 3481835a0f9STakashi Iwai AC_VERB_SET_UNSOLICITED_ENABLE, 3493a93897eSTakashi Iwai AC_USRSP_EN | jack->tag); 350bda17b82STakashi Iwai if (err < 0) 351bda17b82STakashi Iwai return ERR_PTR(err); 3521a4f69d5STakashi Iwai return callback; 3531835a0f9STakashi Iwai } 3545204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback_mst); 355954df2a9SDavid Henningsson 35695a962c3STakashi Iwai /** 35795a962c3STakashi Iwai * snd_hda_jack_detect_enable - Enable the jack detection on the given pin 35895a962c3STakashi Iwai * @codec: the HDA codec 35995a962c3STakashi Iwai * @nid: pin NID to enable jack detection 3605204a05dSNikhil Mahale * @dev_id: pin device entry id 36195a962c3STakashi Iwai * 36295a962c3STakashi Iwai * Enable the jack detection with the default callback. Returns zero if 36395a962c3STakashi Iwai * successful or a negative error code. 36495a962c3STakashi Iwai */ 3655204a05dSNikhil Mahale int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, 3665204a05dSNikhil Mahale int dev_id) 367954df2a9SDavid Henningsson { 3685204a05dSNikhil Mahale return PTR_ERR_OR_ZERO(snd_hda_jack_detect_enable_callback_mst(codec, 3695204a05dSNikhil Mahale nid, 3705204a05dSNikhil Mahale dev_id, 3715204a05dSNikhil Mahale NULL)); 372954df2a9SDavid Henningsson } 3732698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable); 37401a61e12STakashi Iwai 37501a61e12STakashi Iwai /** 3760619ba8cSDylan Reid * snd_hda_jack_set_gating_jack - Set gating jack. 377a11e9b16STakashi Iwai * @codec: the HDA codec 378a11e9b16STakashi Iwai * @gated_nid: gated pin NID 379a11e9b16STakashi Iwai * @gating_nid: gating pin NID 3800619ba8cSDylan Reid * 3810619ba8cSDylan Reid * Indicates the gated jack is only valid when the gating jack is plugged. 3820619ba8cSDylan Reid */ 3830619ba8cSDylan Reid int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, 3840619ba8cSDylan Reid hda_nid_t gating_nid) 3850619ba8cSDylan Reid { 3865204a05dSNikhil Mahale struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid, 0); 3875204a05dSNikhil Mahale struct hda_jack_tbl *gating = 3885204a05dSNikhil Mahale snd_hda_jack_tbl_new(codec, gating_nid, 0); 3895204a05dSNikhil Mahale 3905204a05dSNikhil Mahale WARN_ON(codec->dp_mst); 3910619ba8cSDylan Reid 3920619ba8cSDylan Reid if (!gated || !gating) 3930619ba8cSDylan Reid return -EINVAL; 3940619ba8cSDylan Reid 3950619ba8cSDylan Reid gated->gating_jack = gating_nid; 3960619ba8cSDylan Reid gating->gated_jack = gated_nid; 3970619ba8cSDylan Reid 3980619ba8cSDylan Reid return 0; 3990619ba8cSDylan Reid } 4002698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_set_gating_jack); 4010619ba8cSDylan Reid 4020619ba8cSDylan Reid /** 40304f7791bSHui Wang * snd_hda_jack_bind_keymap - bind keys generated from one NID to another jack. 40404f7791bSHui Wang * @codec: the HDA codec 40504f7791bSHui Wang * @key_nid: key event is generated by this pin NID 40604f7791bSHui Wang * @keymap: map of key type and key code 40704f7791bSHui Wang * @jack_nid: key reports to the jack of this pin NID 40804f7791bSHui Wang * 40904f7791bSHui Wang * This function is used in the case of key is generated from one NID while is 41004f7791bSHui Wang * reported to the jack of another NID. 41104f7791bSHui Wang */ 41204f7791bSHui Wang int snd_hda_jack_bind_keymap(struct hda_codec *codec, hda_nid_t key_nid, 41304f7791bSHui Wang const struct hda_jack_keymap *keymap, 41404f7791bSHui Wang hda_nid_t jack_nid) 41504f7791bSHui Wang { 41604f7791bSHui Wang const struct hda_jack_keymap *map; 41704f7791bSHui Wang struct hda_jack_tbl *key_gen = snd_hda_jack_tbl_get(codec, key_nid); 41804f7791bSHui Wang struct hda_jack_tbl *report_to = snd_hda_jack_tbl_get(codec, jack_nid); 41904f7791bSHui Wang 42004f7791bSHui Wang WARN_ON(codec->dp_mst); 42104f7791bSHui Wang 42204f7791bSHui Wang if (!key_gen || !report_to || !report_to->jack) 42304f7791bSHui Wang return -EINVAL; 42404f7791bSHui Wang 42504f7791bSHui Wang key_gen->key_report_jack = jack_nid; 42604f7791bSHui Wang 42704f7791bSHui Wang if (keymap) 42804f7791bSHui Wang for (map = keymap; map->type; map++) 42904f7791bSHui Wang snd_jack_set_key(report_to->jack, map->type, map->key); 43004f7791bSHui Wang 43104f7791bSHui Wang return 0; 43204f7791bSHui Wang } 43304f7791bSHui Wang EXPORT_SYMBOL_GPL(snd_hda_jack_bind_keymap); 43404f7791bSHui Wang 43504f7791bSHui Wang /** 43604f7791bSHui Wang * snd_hda_jack_set_button_state - report button event to the hda_jack_tbl button_state. 43704f7791bSHui Wang * @codec: the HDA codec 43804f7791bSHui Wang * @jack_nid: the button event reports to the jack_tbl of this NID 43904f7791bSHui Wang * @button_state: the button event captured by codec 44004f7791bSHui Wang * 44104f7791bSHui Wang * Codec driver calls this function to report the button event. 44204f7791bSHui Wang */ 44304f7791bSHui Wang void snd_hda_jack_set_button_state(struct hda_codec *codec, hda_nid_t jack_nid, 44404f7791bSHui Wang int button_state) 44504f7791bSHui Wang { 44604f7791bSHui Wang struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, jack_nid); 44704f7791bSHui Wang 44804f7791bSHui Wang if (!jack) 44904f7791bSHui Wang return; 45004f7791bSHui Wang 45104f7791bSHui Wang if (jack->key_report_jack) { 45204f7791bSHui Wang struct hda_jack_tbl *report_to = 45304f7791bSHui Wang snd_hda_jack_tbl_get(codec, jack->key_report_jack); 45404f7791bSHui Wang 45504f7791bSHui Wang if (report_to) { 45604f7791bSHui Wang report_to->button_state = button_state; 45704f7791bSHui Wang return; 45804f7791bSHui Wang } 45904f7791bSHui Wang } 46004f7791bSHui Wang 46104f7791bSHui Wang jack->button_state = button_state; 46204f7791bSHui Wang } 46304f7791bSHui Wang EXPORT_SYMBOL_GPL(snd_hda_jack_set_button_state); 46404f7791bSHui Wang 46504f7791bSHui Wang /** 46601a61e12STakashi Iwai * snd_hda_jack_report_sync - sync the states of all jacks and report if changed 467a11e9b16STakashi Iwai * @codec: the HDA codec 46801a61e12STakashi Iwai */ 46901a61e12STakashi Iwai void snd_hda_jack_report_sync(struct hda_codec *codec) 47001a61e12STakashi Iwai { 4710619ba8cSDylan Reid struct hda_jack_tbl *jack; 47235be544aSTakashi Iwai int i, state; 47301a61e12STakashi Iwai 4740619ba8cSDylan Reid /* update all jacks at first */ 4750619ba8cSDylan Reid jack = codec->jacktbl.list; 4760619ba8cSDylan Reid for (i = 0; i < codec->jacktbl.used; i++, jack++) 4770619ba8cSDylan Reid if (jack->nid) 4780619ba8cSDylan Reid jack_detect_update(codec, jack); 4790619ba8cSDylan Reid 4800619ba8cSDylan Reid /* report the updated jacks; it's done after updating all jacks 4810619ba8cSDylan Reid * to make sure that all gating jacks properly have been set 4820619ba8cSDylan Reid */ 4830619ba8cSDylan Reid jack = codec->jacktbl.list; 48401a61e12STakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) 48501a61e12STakashi Iwai if (jack->nid) { 4862ba2dfa1SJie Yang if (!jack->jack || jack->block_report) 487cfc7c9d3STakashi Iwai continue; 488911761c2STakashi Iwai state = jack->button_state; 489911761c2STakashi Iwai if (get_jack_plug_state(jack->pin_sense)) 490911761c2STakashi Iwai state |= jack->type; 491911761c2STakashi Iwai snd_jack_report(jack->jack, state); 492911761c2STakashi Iwai if (jack->button_state) { 49331ef2257STakashi Iwai snd_jack_report(jack->jack, 494911761c2STakashi Iwai state & ~jack->button_state); 495911761c2STakashi Iwai jack->button_state = 0; /* button released */ 496911761c2STakashi Iwai } 49701a61e12STakashi Iwai } 49801a61e12STakashi Iwai } 4992698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_report_sync); 50001a61e12STakashi Iwai 50131ef2257STakashi Iwai /* guess the jack type from the pin-config */ 50231ef2257STakashi Iwai static int get_input_jack_type(struct hda_codec *codec, hda_nid_t nid) 50331ef2257STakashi Iwai { 50431ef2257STakashi Iwai unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); 50531ef2257STakashi Iwai switch (get_defcfg_device(def_conf)) { 50631ef2257STakashi Iwai case AC_JACK_LINE_OUT: 50731ef2257STakashi Iwai case AC_JACK_SPEAKER: 50831ef2257STakashi Iwai return SND_JACK_LINEOUT; 50931ef2257STakashi Iwai case AC_JACK_HP_OUT: 51031ef2257STakashi Iwai return SND_JACK_HEADPHONE; 51131ef2257STakashi Iwai case AC_JACK_SPDIF_OUT: 51231ef2257STakashi Iwai case AC_JACK_DIG_OTHER_OUT: 51331ef2257STakashi Iwai return SND_JACK_AVOUT; 51431ef2257STakashi Iwai case AC_JACK_MIC_IN: 51531ef2257STakashi Iwai return SND_JACK_MICROPHONE; 51631ef2257STakashi Iwai default: 51731ef2257STakashi Iwai return SND_JACK_LINEIN; 51831ef2257STakashi Iwai } 51931ef2257STakashi Iwai } 52031ef2257STakashi Iwai 52131ef2257STakashi Iwai static void hda_free_jack_priv(struct snd_jack *jack) 52231ef2257STakashi Iwai { 52331ef2257STakashi Iwai struct hda_jack_tbl *jacks = jack->private_data; 52431ef2257STakashi Iwai jacks->nid = 0; 52531ef2257STakashi Iwai jacks->jack = NULL; 52631ef2257STakashi Iwai } 52731ef2257STakashi Iwai 52801a61e12STakashi Iwai /** 5295204a05dSNikhil Mahale * snd_hda_jack_add_kctl_mst - Add a kctl for the given pin 530a11e9b16STakashi Iwai * @codec: the HDA codec 531a11e9b16STakashi Iwai * @nid: pin NID to assign 5325204a05dSNikhil Mahale * @dev_id : pin device entry id 533a11e9b16STakashi Iwai * @name: string name for the jack 534a11e9b16STakashi Iwai * @phantom_jack: flag to deal as a phantom jack 535911761c2STakashi Iwai * @type: jack type bits to be reported, 0 for guessing from pincfg 536911761c2STakashi Iwai * @keymap: optional jack / key mapping 53701a61e12STakashi Iwai * 53801a61e12STakashi Iwai * This assigns a jack-detection kctl to the given pin. The kcontrol 53901a61e12STakashi Iwai * will have the given name and index. 54001a61e12STakashi Iwai */ 5415204a05dSNikhil Mahale int snd_hda_jack_add_kctl_mst(struct hda_codec *codec, hda_nid_t nid, 5425204a05dSNikhil Mahale int dev_id, const char *name, bool phantom_jack, 543911761c2STakashi Iwai int type, const struct hda_jack_keymap *keymap) 54401a61e12STakashi Iwai { 54501a61e12STakashi Iwai struct hda_jack_tbl *jack; 546911761c2STakashi Iwai const struct hda_jack_keymap *map; 547911761c2STakashi Iwai int err, state, buttons; 54801a61e12STakashi Iwai 5495204a05dSNikhil Mahale jack = snd_hda_jack_tbl_new(codec, nid, dev_id); 55001a61e12STakashi Iwai if (!jack) 55101a61e12STakashi Iwai return 0; 5522ba2dfa1SJie Yang if (jack->jack) 55301a61e12STakashi Iwai return 0; /* already created */ 55480c8bfbeSDavid Henningsson 555911761c2STakashi Iwai if (!type) 5562ba2dfa1SJie Yang type = get_input_jack_type(codec, nid); 557911761c2STakashi Iwai 558911761c2STakashi Iwai buttons = 0; 559911761c2STakashi Iwai if (keymap) { 560911761c2STakashi Iwai for (map = keymap; map->type; map++) 561911761c2STakashi Iwai buttons |= map->type; 562911761c2STakashi Iwai } 563911761c2STakashi Iwai 564911761c2STakashi Iwai err = snd_jack_new(codec->card, name, type | buttons, 5652ba2dfa1SJie Yang &jack->jack, true, phantom_jack); 56631ef2257STakashi Iwai if (err < 0) 56731ef2257STakashi Iwai return err; 5682ba2dfa1SJie Yang 5692ba2dfa1SJie Yang jack->phantom_jack = !!phantom_jack; 5702ba2dfa1SJie Yang jack->type = type; 571911761c2STakashi Iwai jack->button_state = 0; 57231ef2257STakashi Iwai jack->jack->private_data = jack; 57331ef2257STakashi Iwai jack->jack->private_free = hda_free_jack_priv; 574911761c2STakashi Iwai if (keymap) { 575911761c2STakashi Iwai for (map = keymap; map->type; map++) 576911761c2STakashi Iwai snd_jack_set_key(jack->jack, map->type, map->key); 577911761c2STakashi Iwai } 578911761c2STakashi Iwai 5795204a05dSNikhil Mahale state = snd_hda_jack_detect_mst(codec, nid, dev_id); 58031ef2257STakashi Iwai snd_jack_report(jack->jack, state ? jack->type : 0); 5812ba2dfa1SJie Yang 58201a61e12STakashi Iwai return 0; 58301a61e12STakashi Iwai } 5845204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl_mst); 58501a61e12STakashi Iwai 586201e06ffSTakashi Iwai static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, 587b26b5116SDavid Henningsson const struct auto_pin_cfg *cfg, 588b26b5116SDavid Henningsson const char *base_name) 58901a61e12STakashi Iwai { 5903a93897eSTakashi Iwai unsigned int def_conf, conn; 591975cc02aSTakashi Iwai char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 5922ba2dfa1SJie Yang int err; 59380c8bfbeSDavid Henningsson bool phantom_jack; 5943a93897eSTakashi Iwai 5955204a05dSNikhil Mahale WARN_ON(codec->dp_mst); 5965204a05dSNikhil Mahale 59701a61e12STakashi Iwai if (!nid) 59801a61e12STakashi Iwai return 0; 5993a93897eSTakashi Iwai def_conf = snd_hda_codec_get_pincfg(codec, nid); 6003a93897eSTakashi Iwai conn = get_defcfg_connect(def_conf); 60180c8bfbeSDavid Henningsson if (conn == AC_JACK_PORT_NONE) 6023a93897eSTakashi Iwai return 0; 60380c8bfbeSDavid Henningsson phantom_jack = (conn != AC_JACK_PORT_COMPLEX) || 60480c8bfbeSDavid Henningsson !is_jack_detectable(codec, nid); 6053a93897eSTakashi Iwai 6062ba2dfa1SJie Yang if (base_name) 60775b1a8f9SJoe Perches strscpy(name, base_name, sizeof(name)); 6082ba2dfa1SJie Yang else 6092ba2dfa1SJie Yang snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), NULL); 61080c8bfbeSDavid Henningsson if (phantom_jack) 61180c8bfbeSDavid Henningsson /* Example final name: "Internal Mic Phantom Jack" */ 61280c8bfbeSDavid Henningsson strncat(name, " Phantom", sizeof(name) - strlen(name) - 1); 613911761c2STakashi Iwai err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack, 0, NULL); 6143a93897eSTakashi Iwai if (err < 0) 6153a93897eSTakashi Iwai return err; 61680c8bfbeSDavid Henningsson 61780c8bfbeSDavid Henningsson if (!phantom_jack) 6185204a05dSNikhil Mahale return snd_hda_jack_detect_enable(codec, nid, 0); 61980c8bfbeSDavid Henningsson return 0; 62001a61e12STakashi Iwai } 62101a61e12STakashi Iwai 62201a61e12STakashi Iwai /** 62301a61e12STakashi Iwai * snd_hda_jack_add_kctls - Add kctls for all pins included in the given pincfg 624a11e9b16STakashi Iwai * @codec: the HDA codec 625a11e9b16STakashi Iwai * @cfg: pin config table to parse 62601a61e12STakashi Iwai */ 62701a61e12STakashi Iwai int snd_hda_jack_add_kctls(struct hda_codec *codec, 62801a61e12STakashi Iwai const struct auto_pin_cfg *cfg) 62901a61e12STakashi Iwai { 63001a61e12STakashi Iwai const hda_nid_t *p; 631f46c3296STakashi Iwai int i, err; 63201a61e12STakashi Iwai 633b26b5116SDavid Henningsson for (i = 0; i < cfg->num_inputs; i++) { 634b26b5116SDavid Henningsson /* If we have headphone mics; make sure they get the right name 635b26b5116SDavid Henningsson before grabbed by output pins */ 636b26b5116SDavid Henningsson if (cfg->inputs[i].is_headphone_mic) { 637b26b5116SDavid Henningsson if (auto_cfg_hp_outs(cfg) == 1) 638b26b5116SDavid Henningsson err = add_jack_kctl(codec, auto_cfg_hp_pins(cfg)[0], 639b26b5116SDavid Henningsson cfg, "Headphone Mic"); 640b26b5116SDavid Henningsson else 641b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->inputs[i].pin, 642b26b5116SDavid Henningsson cfg, "Headphone Mic"); 643b26b5116SDavid Henningsson } else 644b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg, 645b26b5116SDavid Henningsson NULL); 646b26b5116SDavid Henningsson if (err < 0) 647b26b5116SDavid Henningsson return err; 648b26b5116SDavid Henningsson } 649b26b5116SDavid Henningsson 65001a61e12STakashi Iwai for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) { 651b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 65201a61e12STakashi Iwai if (err < 0) 65301a61e12STakashi Iwai return err; 65401a61e12STakashi Iwai } 65501a61e12STakashi Iwai for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) { 65601a61e12STakashi Iwai if (*p == *cfg->line_out_pins) /* might be duplicated */ 65701a61e12STakashi Iwai break; 658b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 65901a61e12STakashi Iwai if (err < 0) 66001a61e12STakashi Iwai return err; 66101a61e12STakashi Iwai } 66201a61e12STakashi Iwai for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) { 66301a61e12STakashi Iwai if (*p == *cfg->line_out_pins) /* might be duplicated */ 66401a61e12STakashi Iwai break; 665b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 66601a61e12STakashi Iwai if (err < 0) 66701a61e12STakashi Iwai return err; 66801a61e12STakashi Iwai } 66901a61e12STakashi Iwai for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) { 670b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 67101a61e12STakashi Iwai if (err < 0) 67201a61e12STakashi Iwai return err; 67301a61e12STakashi Iwai } 674b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->dig_in_pin, cfg, NULL); 67501a61e12STakashi Iwai if (err < 0) 67601a61e12STakashi Iwai return err; 677b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->mono_out_pin, cfg, NULL); 67801a61e12STakashi Iwai if (err < 0) 67901a61e12STakashi Iwai return err; 68001a61e12STakashi Iwai return 0; 68101a61e12STakashi Iwai } 6822698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctls); 683954df2a9SDavid Henningsson 684e6ce180fSTakashi Iwai static void call_jack_callback(struct hda_codec *codec, unsigned int res, 6850619ba8cSDylan Reid struct hda_jack_tbl *jack) 6860619ba8cSDylan Reid { 6871a4f69d5STakashi Iwai struct hda_jack_callback *cb; 6881a4f69d5STakashi Iwai 689e6ce180fSTakashi Iwai for (cb = jack->callback; cb; cb = cb->next) { 690e6ce180fSTakashi Iwai cb->jack = jack; 691e6ce180fSTakashi Iwai cb->unsol_res = res; 6921a4f69d5STakashi Iwai cb->func(codec, cb); 693e6ce180fSTakashi Iwai } 6940619ba8cSDylan Reid if (jack->gated_jack) { 6950619ba8cSDylan Reid struct hda_jack_tbl *gated = 6965204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, jack->gated_jack, 6975204a05dSNikhil Mahale jack->dev_id); 6981a4f69d5STakashi Iwai if (gated) { 699e6ce180fSTakashi Iwai for (cb = gated->callback; cb; cb = cb->next) { 700e6ce180fSTakashi Iwai cb->jack = gated; 701e6ce180fSTakashi Iwai cb->unsol_res = res; 7021a4f69d5STakashi Iwai cb->func(codec, cb); 7031a4f69d5STakashi Iwai } 7040619ba8cSDylan Reid } 7050619ba8cSDylan Reid } 706e6ce180fSTakashi Iwai } 7070619ba8cSDylan Reid 70895a962c3STakashi Iwai /** 70995a962c3STakashi Iwai * snd_hda_jack_unsol_event - Handle an unsolicited event 71095a962c3STakashi Iwai * @codec: the HDA codec 71195a962c3STakashi Iwai * @res: the unsolicited event data 71295a962c3STakashi Iwai */ 713954df2a9SDavid Henningsson void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) 714954df2a9SDavid Henningsson { 715954df2a9SDavid Henningsson struct hda_jack_tbl *event; 716c7e68a69SGuennadi Liakhovetski int tag = (res & AC_UNSOL_RES_TAG) >> AC_UNSOL_RES_TAG_SHIFT; 717954df2a9SDavid Henningsson 7185204a05dSNikhil Mahale if (codec->dp_mst) { 7195204a05dSNikhil Mahale int dev_entry = 7205204a05dSNikhil Mahale (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT; 7215204a05dSNikhil Mahale 7225204a05dSNikhil Mahale event = snd_hda_jack_tbl_get_from_tag(codec, tag, dev_entry); 7235204a05dSNikhil Mahale } else { 7245204a05dSNikhil Mahale event = snd_hda_jack_tbl_get_from_tag(codec, tag, 0); 7255204a05dSNikhil Mahale } 726954df2a9SDavid Henningsson if (!event) 727954df2a9SDavid Henningsson return; 72804f7791bSHui Wang 72904f7791bSHui Wang if (event->key_report_jack) { 73004f7791bSHui Wang struct hda_jack_tbl *report_to = 73104f7791bSHui Wang snd_hda_jack_tbl_get_mst(codec, event->key_report_jack, 73204f7791bSHui Wang event->dev_id); 73304f7791bSHui Wang if (report_to) 73404f7791bSHui Wang report_to->jack_dirty = 1; 73504f7791bSHui Wang } else 736954df2a9SDavid Henningsson event->jack_dirty = 1; 737954df2a9SDavid Henningsson 738e6ce180fSTakashi Iwai call_jack_callback(codec, res, event); 739954df2a9SDavid Henningsson snd_hda_jack_report_sync(codec); 740954df2a9SDavid Henningsson } 7412698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_unsol_event); 742954df2a9SDavid Henningsson 74395a962c3STakashi Iwai /** 74495a962c3STakashi Iwai * snd_hda_jack_poll_all - Poll all jacks 74595a962c3STakashi Iwai * @codec: the HDA codec 74695a962c3STakashi Iwai * 74795a962c3STakashi Iwai * Poll all detectable jacks with dirty flag, update the status, call 74895a962c3STakashi Iwai * callbacks and call snd_hda_jack_report_sync() if any changes are found. 74995a962c3STakashi Iwai */ 75026a6cb6cSDavid Henningsson void snd_hda_jack_poll_all(struct hda_codec *codec) 75126a6cb6cSDavid Henningsson { 75226a6cb6cSDavid Henningsson struct hda_jack_tbl *jack = codec->jacktbl.list; 75326a6cb6cSDavid Henningsson int i, changes = 0; 75426a6cb6cSDavid Henningsson 75526a6cb6cSDavid Henningsson for (i = 0; i < codec->jacktbl.used; i++, jack++) { 75626a6cb6cSDavid Henningsson unsigned int old_sense; 75726a6cb6cSDavid Henningsson if (!jack->nid || !jack->jack_dirty || jack->phantom_jack) 75826a6cb6cSDavid Henningsson continue; 75926a6cb6cSDavid Henningsson old_sense = get_jack_plug_state(jack->pin_sense); 76026a6cb6cSDavid Henningsson jack_detect_update(codec, jack); 76126a6cb6cSDavid Henningsson if (old_sense == get_jack_plug_state(jack->pin_sense)) 76226a6cb6cSDavid Henningsson continue; 76326a6cb6cSDavid Henningsson changes = 1; 764e6ce180fSTakashi Iwai call_jack_callback(codec, 0, jack); 76526a6cb6cSDavid Henningsson } 76626a6cb6cSDavid Henningsson if (changes) 76726a6cb6cSDavid Henningsson snd_hda_jack_report_sync(codec); 76826a6cb6cSDavid Henningsson } 7692698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_poll_all); 77026a6cb6cSDavid Henningsson 771