18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Jack-detection handling for HD-audio 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/init.h> 98c2ecf20Sopenharmony_ci#include <linux/slab.h> 108c2ecf20Sopenharmony_ci#include <linux/export.h> 118c2ecf20Sopenharmony_ci#include <sound/core.h> 128c2ecf20Sopenharmony_ci#include <sound/control.h> 138c2ecf20Sopenharmony_ci#include <sound/jack.h> 148c2ecf20Sopenharmony_ci#include <sound/hda_codec.h> 158c2ecf20Sopenharmony_ci#include "hda_local.h" 168c2ecf20Sopenharmony_ci#include "hda_auto_parser.h" 178c2ecf20Sopenharmony_ci#include "hda_jack.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/** 208c2ecf20Sopenharmony_ci * is_jack_detectable - Check whether the given pin is jack-detectable 218c2ecf20Sopenharmony_ci * @codec: the HDA codec 228c2ecf20Sopenharmony_ci * @nid: pin NID 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Check whether the given pin is capable to report the jack detection. 258c2ecf20Sopenharmony_ci * The jack detection might not work by various reasons, e.g. the jack 268c2ecf20Sopenharmony_ci * detection is prohibited in the codec level, the pin config has 278c2ecf20Sopenharmony_ci * AC_DEFCFG_MISC_NO_PRESENCE bit, no unsol support, etc. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_cibool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci if (codec->no_jack_detect) 328c2ecf20Sopenharmony_ci return false; 338c2ecf20Sopenharmony_ci if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT)) 348c2ecf20Sopenharmony_ci return false; 358c2ecf20Sopenharmony_ci if (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & 368c2ecf20Sopenharmony_ci AC_DEFCFG_MISC_NO_PRESENCE) 378c2ecf20Sopenharmony_ci return false; 388c2ecf20Sopenharmony_ci if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) && 398c2ecf20Sopenharmony_ci !codec->jackpoll_interval) 408c2ecf20Sopenharmony_ci return false; 418c2ecf20Sopenharmony_ci return true; 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(is_jack_detectable); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* execute pin sense measurement */ 468c2ecf20Sopenharmony_cistatic u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci u32 pincap; 498c2ecf20Sopenharmony_ci u32 val; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (!codec->no_trigger_sense) { 528c2ecf20Sopenharmony_ci pincap = snd_hda_query_pin_caps(codec, nid); 538c2ecf20Sopenharmony_ci if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */ 548c2ecf20Sopenharmony_ci snd_hda_codec_read(codec, nid, 0, 558c2ecf20Sopenharmony_ci AC_VERB_SET_PIN_SENSE, 0); 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci val = snd_hda_codec_read(codec, nid, 0, 588c2ecf20Sopenharmony_ci AC_VERB_GET_PIN_SENSE, dev_id); 598c2ecf20Sopenharmony_ci if (codec->inv_jack_detect) 608c2ecf20Sopenharmony_ci val ^= AC_PINSENSE_PRESENCE; 618c2ecf20Sopenharmony_ci return val; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/** 658c2ecf20Sopenharmony_ci * snd_hda_jack_tbl_get_mst - query the jack-table entry for the given NID 668c2ecf20Sopenharmony_ci * @codec: the HDA codec 678c2ecf20Sopenharmony_ci * @nid: pin NID to refer to 688c2ecf20Sopenharmony_ci * @dev_id: pin device entry id 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_cistruct hda_jack_tbl * 718c2ecf20Sopenharmony_cisnd_hda_jack_tbl_get_mst(struct hda_codec *codec, hda_nid_t nid, int dev_id) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct hda_jack_tbl *jack = codec->jacktbl.list; 748c2ecf20Sopenharmony_ci int i; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (!nid || !jack) 778c2ecf20Sopenharmony_ci return NULL; 788c2ecf20Sopenharmony_ci for (i = 0; i < codec->jacktbl.used; i++, jack++) 798c2ecf20Sopenharmony_ci if (jack->nid == nid && jack->dev_id == dev_id) 808c2ecf20Sopenharmony_ci return jack; 818c2ecf20Sopenharmony_ci return NULL; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_mst); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/** 868c2ecf20Sopenharmony_ci * snd_hda_jack_tbl_get_from_tag - query the jack-table entry for the given tag 878c2ecf20Sopenharmony_ci * @codec: the HDA codec 888c2ecf20Sopenharmony_ci * @tag: tag value to refer to 898c2ecf20Sopenharmony_ci * @dev_id: pin device entry id 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_cistruct hda_jack_tbl * 928c2ecf20Sopenharmony_cisnd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, 938c2ecf20Sopenharmony_ci unsigned char tag, int dev_id) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct hda_jack_tbl *jack = codec->jacktbl.list; 968c2ecf20Sopenharmony_ci int i; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (!tag || !jack) 998c2ecf20Sopenharmony_ci return NULL; 1008c2ecf20Sopenharmony_ci for (i = 0; i < codec->jacktbl.used; i++, jack++) 1018c2ecf20Sopenharmony_ci if (jack->tag == tag && jack->dev_id == dev_id) 1028c2ecf20Sopenharmony_ci return jack; 1038c2ecf20Sopenharmony_ci return NULL; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_from_tag); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic struct hda_jack_tbl * 1088c2ecf20Sopenharmony_ciany_jack_tbl_get_from_nid(struct hda_codec *codec, hda_nid_t nid) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci struct hda_jack_tbl *jack = codec->jacktbl.list; 1118c2ecf20Sopenharmony_ci int i; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (!nid || !jack) 1148c2ecf20Sopenharmony_ci return NULL; 1158c2ecf20Sopenharmony_ci for (i = 0; i < codec->jacktbl.used; i++, jack++) 1168c2ecf20Sopenharmony_ci if (jack->nid == nid) 1178c2ecf20Sopenharmony_ci return jack; 1188c2ecf20Sopenharmony_ci return NULL; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/** 1228c2ecf20Sopenharmony_ci * snd_hda_jack_tbl_new - create a jack-table entry for the given NID 1238c2ecf20Sopenharmony_ci * @codec: the HDA codec 1248c2ecf20Sopenharmony_ci * @nid: pin NID to assign 1258c2ecf20Sopenharmony_ci * @dev_id: pin device entry id 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_cistatic struct hda_jack_tbl * 1288c2ecf20Sopenharmony_cisnd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid, int dev_id) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci struct hda_jack_tbl *jack = 1318c2ecf20Sopenharmony_ci snd_hda_jack_tbl_get_mst(codec, nid, dev_id); 1328c2ecf20Sopenharmony_ci struct hda_jack_tbl *existing_nid_jack = 1338c2ecf20Sopenharmony_ci any_jack_tbl_get_from_nid(codec, nid); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci WARN_ON(dev_id != 0 && !codec->dp_mst); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (jack) 1388c2ecf20Sopenharmony_ci return jack; 1398c2ecf20Sopenharmony_ci jack = snd_array_new(&codec->jacktbl); 1408c2ecf20Sopenharmony_ci if (!jack) 1418c2ecf20Sopenharmony_ci return NULL; 1428c2ecf20Sopenharmony_ci jack->nid = nid; 1438c2ecf20Sopenharmony_ci jack->dev_id = dev_id; 1448c2ecf20Sopenharmony_ci jack->jack_dirty = 1; 1458c2ecf20Sopenharmony_ci if (existing_nid_jack) { 1468c2ecf20Sopenharmony_ci jack->tag = existing_nid_jack->tag; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* 1498c2ecf20Sopenharmony_ci * Copy jack_detect from existing_nid_jack to avoid 1508c2ecf20Sopenharmony_ci * snd_hda_jack_detect_enable_callback_mst() making multiple 1518c2ecf20Sopenharmony_ci * SET_UNSOLICITED_ENABLE calls on the same pin. 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_ci jack->jack_detect = existing_nid_jack->jack_detect; 1548c2ecf20Sopenharmony_ci } else { 1558c2ecf20Sopenharmony_ci jack->tag = codec->jacktbl.used; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci return jack; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_civoid snd_hda_jack_tbl_clear(struct hda_codec *codec) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci struct hda_jack_tbl *jack = codec->jacktbl.list; 1648c2ecf20Sopenharmony_ci int i; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci for (i = 0; i < codec->jacktbl.used; i++, jack++) { 1678c2ecf20Sopenharmony_ci struct hda_jack_callback *cb, *next; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* free jack instances manually when clearing/reconfiguring */ 1708c2ecf20Sopenharmony_ci if (!codec->bus->shutdown && jack->jack) 1718c2ecf20Sopenharmony_ci snd_device_free(codec->card, jack->jack); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci for (cb = jack->callback; cb; cb = next) { 1748c2ecf20Sopenharmony_ci next = cb->next; 1758c2ecf20Sopenharmony_ci kfree(cb); 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci snd_array_free(&codec->jacktbl); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci#define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE) 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/* update the cached value and notification flag if needed */ 1848c2ecf20Sopenharmony_cistatic void jack_detect_update(struct hda_codec *codec, 1858c2ecf20Sopenharmony_ci struct hda_jack_tbl *jack) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci if (!jack->jack_dirty) 1888c2ecf20Sopenharmony_ci return; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (jack->phantom_jack) 1918c2ecf20Sopenharmony_ci jack->pin_sense = AC_PINSENSE_PRESENCE; 1928c2ecf20Sopenharmony_ci else 1938c2ecf20Sopenharmony_ci jack->pin_sense = read_pin_sense(codec, jack->nid, 1948c2ecf20Sopenharmony_ci jack->dev_id); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* A gating jack indicates the jack is invalid if gating is unplugged */ 1978c2ecf20Sopenharmony_ci if (jack->gating_jack && 1988c2ecf20Sopenharmony_ci !snd_hda_jack_detect_mst(codec, jack->gating_jack, jack->dev_id)) 1998c2ecf20Sopenharmony_ci jack->pin_sense &= ~AC_PINSENSE_PRESENCE; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci jack->jack_dirty = 0; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* If a jack is gated by this one update it. */ 2048c2ecf20Sopenharmony_ci if (jack->gated_jack) { 2058c2ecf20Sopenharmony_ci struct hda_jack_tbl *gated = 2068c2ecf20Sopenharmony_ci snd_hda_jack_tbl_get_mst(codec, jack->gated_jack, 2078c2ecf20Sopenharmony_ci jack->dev_id); 2088c2ecf20Sopenharmony_ci if (gated) { 2098c2ecf20Sopenharmony_ci gated->jack_dirty = 1; 2108c2ecf20Sopenharmony_ci jack_detect_update(codec, gated); 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci/** 2168c2ecf20Sopenharmony_ci * snd_hda_set_dirty_all - Mark all the cached as dirty 2178c2ecf20Sopenharmony_ci * @codec: the HDA codec 2188c2ecf20Sopenharmony_ci * 2198c2ecf20Sopenharmony_ci * This function sets the dirty flag to all entries of jack table. 2208c2ecf20Sopenharmony_ci * It's called from the resume path in hda_codec.c. 2218c2ecf20Sopenharmony_ci */ 2228c2ecf20Sopenharmony_civoid snd_hda_jack_set_dirty_all(struct hda_codec *codec) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct hda_jack_tbl *jack = codec->jacktbl.list; 2258c2ecf20Sopenharmony_ci int i; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci for (i = 0; i < codec->jacktbl.used; i++, jack++) 2288c2ecf20Sopenharmony_ci if (jack->nid) 2298c2ecf20Sopenharmony_ci jack->jack_dirty = 1; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_set_dirty_all); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci/** 2348c2ecf20Sopenharmony_ci * snd_hda_jack_pin_sense - execute pin sense measurement 2358c2ecf20Sopenharmony_ci * @codec: the CODEC to sense 2368c2ecf20Sopenharmony_ci * @nid: the pin NID to sense 2378c2ecf20Sopenharmony_ci * @dev_id: pin device entry id 2388c2ecf20Sopenharmony_ci * 2398c2ecf20Sopenharmony_ci * Execute necessary pin sense measurement and return its Presence Detect, 2408c2ecf20Sopenharmony_ci * Impedance, ELD Valid etc. status bits. 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_ciu32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci struct hda_jack_tbl *jack = 2458c2ecf20Sopenharmony_ci snd_hda_jack_tbl_get_mst(codec, nid, dev_id); 2468c2ecf20Sopenharmony_ci if (jack) { 2478c2ecf20Sopenharmony_ci jack_detect_update(codec, jack); 2488c2ecf20Sopenharmony_ci return jack->pin_sense; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci return read_pin_sense(codec, nid, dev_id); 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_pin_sense); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci/** 2558c2ecf20Sopenharmony_ci * snd_hda_jack_detect_state_mst - query pin Presence Detect status 2568c2ecf20Sopenharmony_ci * @codec: the CODEC to sense 2578c2ecf20Sopenharmony_ci * @nid: the pin NID to sense 2588c2ecf20Sopenharmony_ci * @dev_id: pin device entry id 2598c2ecf20Sopenharmony_ci * 2608c2ecf20Sopenharmony_ci * Query and return the pin's Presence Detect status, as either 2618c2ecf20Sopenharmony_ci * HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM. 2628c2ecf20Sopenharmony_ci */ 2638c2ecf20Sopenharmony_ciint snd_hda_jack_detect_state_mst(struct hda_codec *codec, 2648c2ecf20Sopenharmony_ci hda_nid_t nid, int dev_id) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct hda_jack_tbl *jack = 2678c2ecf20Sopenharmony_ci snd_hda_jack_tbl_get_mst(codec, nid, dev_id); 2688c2ecf20Sopenharmony_ci if (jack && jack->phantom_jack) 2698c2ecf20Sopenharmony_ci return HDA_JACK_PHANTOM; 2708c2ecf20Sopenharmony_ci else if (snd_hda_jack_pin_sense(codec, nid, dev_id) & 2718c2ecf20Sopenharmony_ci AC_PINSENSE_PRESENCE) 2728c2ecf20Sopenharmony_ci return HDA_JACK_PRESENT; 2738c2ecf20Sopenharmony_ci else 2748c2ecf20Sopenharmony_ci return HDA_JACK_NOT_PRESENT; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_detect_state_mst); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic struct hda_jack_callback * 2798c2ecf20Sopenharmony_cifind_callback_from_list(struct hda_jack_tbl *jack, 2808c2ecf20Sopenharmony_ci hda_jack_callback_fn func) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci struct hda_jack_callback *cb; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (!func) 2858c2ecf20Sopenharmony_ci return NULL; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci for (cb = jack->callback; cb; cb = cb->next) { 2888c2ecf20Sopenharmony_ci if (cb->func == func) 2898c2ecf20Sopenharmony_ci return cb; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return NULL; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci/** 2968c2ecf20Sopenharmony_ci * snd_hda_jack_detect_enable_mst - enable the jack-detection 2978c2ecf20Sopenharmony_ci * @codec: the HDA codec 2988c2ecf20Sopenharmony_ci * @nid: pin NID to enable 2998c2ecf20Sopenharmony_ci * @func: callback function to register 3008c2ecf20Sopenharmony_ci * @dev_id: pin device entry id 3018c2ecf20Sopenharmony_ci * 3028c2ecf20Sopenharmony_ci * In the case of error, the return value will be a pointer embedded with 3038c2ecf20Sopenharmony_ci * errno. Check and handle the return value appropriately with standard 3048c2ecf20Sopenharmony_ci * macros such as @IS_ERR() and @PTR_ERR(). 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_cistruct hda_jack_callback * 3078c2ecf20Sopenharmony_cisnd_hda_jack_detect_enable_callback_mst(struct hda_codec *codec, hda_nid_t nid, 3088c2ecf20Sopenharmony_ci int dev_id, hda_jack_callback_fn func) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct hda_jack_tbl *jack; 3118c2ecf20Sopenharmony_ci struct hda_jack_callback *callback = NULL; 3128c2ecf20Sopenharmony_ci int err; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci jack = snd_hda_jack_tbl_new(codec, nid, dev_id); 3158c2ecf20Sopenharmony_ci if (!jack) 3168c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci callback = find_callback_from_list(jack, func); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (func && !callback) { 3218c2ecf20Sopenharmony_ci callback = kzalloc(sizeof(*callback), GFP_KERNEL); 3228c2ecf20Sopenharmony_ci if (!callback) 3238c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3248c2ecf20Sopenharmony_ci callback->func = func; 3258c2ecf20Sopenharmony_ci callback->nid = jack->nid; 3268c2ecf20Sopenharmony_ci callback->dev_id = jack->dev_id; 3278c2ecf20Sopenharmony_ci callback->next = jack->callback; 3288c2ecf20Sopenharmony_ci jack->callback = callback; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (jack->jack_detect) 3328c2ecf20Sopenharmony_ci return callback; /* already registered */ 3338c2ecf20Sopenharmony_ci jack->jack_detect = 1; 3348c2ecf20Sopenharmony_ci if (codec->jackpoll_interval > 0) 3358c2ecf20Sopenharmony_ci return callback; /* No unsol if we're polling instead */ 3368c2ecf20Sopenharmony_ci err = snd_hda_codec_write_cache(codec, nid, 0, 3378c2ecf20Sopenharmony_ci AC_VERB_SET_UNSOLICITED_ENABLE, 3388c2ecf20Sopenharmony_ci AC_USRSP_EN | jack->tag); 3398c2ecf20Sopenharmony_ci if (err < 0) 3408c2ecf20Sopenharmony_ci return ERR_PTR(err); 3418c2ecf20Sopenharmony_ci return callback; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback_mst); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci/** 3468c2ecf20Sopenharmony_ci * snd_hda_jack_detect_enable - Enable the jack detection on the given pin 3478c2ecf20Sopenharmony_ci * @codec: the HDA codec 3488c2ecf20Sopenharmony_ci * @nid: pin NID to enable jack detection 3498c2ecf20Sopenharmony_ci * @dev_id: pin device entry id 3508c2ecf20Sopenharmony_ci * 3518c2ecf20Sopenharmony_ci * Enable the jack detection with the default callback. Returns zero if 3528c2ecf20Sopenharmony_ci * successful or a negative error code. 3538c2ecf20Sopenharmony_ci */ 3548c2ecf20Sopenharmony_ciint snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, 3558c2ecf20Sopenharmony_ci int dev_id) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(snd_hda_jack_detect_enable_callback_mst(codec, 3588c2ecf20Sopenharmony_ci nid, 3598c2ecf20Sopenharmony_ci dev_id, 3608c2ecf20Sopenharmony_ci NULL)); 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci/** 3658c2ecf20Sopenharmony_ci * snd_hda_jack_set_gating_jack - Set gating jack. 3668c2ecf20Sopenharmony_ci * @codec: the HDA codec 3678c2ecf20Sopenharmony_ci * @gated_nid: gated pin NID 3688c2ecf20Sopenharmony_ci * @gating_nid: gating pin NID 3698c2ecf20Sopenharmony_ci * 3708c2ecf20Sopenharmony_ci * Indicates the gated jack is only valid when the gating jack is plugged. 3718c2ecf20Sopenharmony_ci */ 3728c2ecf20Sopenharmony_ciint snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, 3738c2ecf20Sopenharmony_ci hda_nid_t gating_nid) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid, 0); 3768c2ecf20Sopenharmony_ci struct hda_jack_tbl *gating = 3778c2ecf20Sopenharmony_ci snd_hda_jack_tbl_new(codec, gating_nid, 0); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci WARN_ON(codec->dp_mst); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (!gated || !gating) 3828c2ecf20Sopenharmony_ci return -EINVAL; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci gated->gating_jack = gating_nid; 3858c2ecf20Sopenharmony_ci gating->gated_jack = gated_nid; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci return 0; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_set_gating_jack); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci/** 3928c2ecf20Sopenharmony_ci * snd_hda_jack_report_sync - sync the states of all jacks and report if changed 3938c2ecf20Sopenharmony_ci * @codec: the HDA codec 3948c2ecf20Sopenharmony_ci */ 3958c2ecf20Sopenharmony_civoid snd_hda_jack_report_sync(struct hda_codec *codec) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci struct hda_jack_tbl *jack; 3988c2ecf20Sopenharmony_ci int i, state; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* update all jacks at first */ 4018c2ecf20Sopenharmony_ci jack = codec->jacktbl.list; 4028c2ecf20Sopenharmony_ci for (i = 0; i < codec->jacktbl.used; i++, jack++) 4038c2ecf20Sopenharmony_ci if (jack->nid) 4048c2ecf20Sopenharmony_ci jack_detect_update(codec, jack); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci /* report the updated jacks; it's done after updating all jacks 4078c2ecf20Sopenharmony_ci * to make sure that all gating jacks properly have been set 4088c2ecf20Sopenharmony_ci */ 4098c2ecf20Sopenharmony_ci jack = codec->jacktbl.list; 4108c2ecf20Sopenharmony_ci for (i = 0; i < codec->jacktbl.used; i++, jack++) 4118c2ecf20Sopenharmony_ci if (jack->nid) { 4128c2ecf20Sopenharmony_ci if (!jack->jack || jack->block_report) 4138c2ecf20Sopenharmony_ci continue; 4148c2ecf20Sopenharmony_ci state = jack->button_state; 4158c2ecf20Sopenharmony_ci if (get_jack_plug_state(jack->pin_sense)) 4168c2ecf20Sopenharmony_ci state |= jack->type; 4178c2ecf20Sopenharmony_ci snd_jack_report(jack->jack, state); 4188c2ecf20Sopenharmony_ci if (jack->button_state) { 4198c2ecf20Sopenharmony_ci snd_jack_report(jack->jack, 4208c2ecf20Sopenharmony_ci state & ~jack->button_state); 4218c2ecf20Sopenharmony_ci jack->button_state = 0; /* button released */ 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_report_sync); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci/* guess the jack type from the pin-config */ 4288c2ecf20Sopenharmony_cistatic int get_input_jack_type(struct hda_codec *codec, hda_nid_t nid) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); 4318c2ecf20Sopenharmony_ci switch (get_defcfg_device(def_conf)) { 4328c2ecf20Sopenharmony_ci case AC_JACK_LINE_OUT: 4338c2ecf20Sopenharmony_ci case AC_JACK_SPEAKER: 4348c2ecf20Sopenharmony_ci return SND_JACK_LINEOUT; 4358c2ecf20Sopenharmony_ci case AC_JACK_HP_OUT: 4368c2ecf20Sopenharmony_ci return SND_JACK_HEADPHONE; 4378c2ecf20Sopenharmony_ci case AC_JACK_SPDIF_OUT: 4388c2ecf20Sopenharmony_ci case AC_JACK_DIG_OTHER_OUT: 4398c2ecf20Sopenharmony_ci return SND_JACK_AVOUT; 4408c2ecf20Sopenharmony_ci case AC_JACK_MIC_IN: 4418c2ecf20Sopenharmony_ci return SND_JACK_MICROPHONE; 4428c2ecf20Sopenharmony_ci default: 4438c2ecf20Sopenharmony_ci return SND_JACK_LINEIN; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic void hda_free_jack_priv(struct snd_jack *jack) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci struct hda_jack_tbl *jacks = jack->private_data; 4508c2ecf20Sopenharmony_ci jacks->nid = 0; 4518c2ecf20Sopenharmony_ci jacks->jack = NULL; 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci/** 4558c2ecf20Sopenharmony_ci * snd_hda_jack_add_kctl_mst - Add a kctl for the given pin 4568c2ecf20Sopenharmony_ci * @codec: the HDA codec 4578c2ecf20Sopenharmony_ci * @nid: pin NID to assign 4588c2ecf20Sopenharmony_ci * @dev_id : pin device entry id 4598c2ecf20Sopenharmony_ci * @name: string name for the jack 4608c2ecf20Sopenharmony_ci * @phantom_jack: flag to deal as a phantom jack 4618c2ecf20Sopenharmony_ci * @type: jack type bits to be reported, 0 for guessing from pincfg 4628c2ecf20Sopenharmony_ci * @keymap: optional jack / key mapping 4638c2ecf20Sopenharmony_ci * 4648c2ecf20Sopenharmony_ci * This assigns a jack-detection kctl to the given pin. The kcontrol 4658c2ecf20Sopenharmony_ci * will have the given name and index. 4668c2ecf20Sopenharmony_ci */ 4678c2ecf20Sopenharmony_ciint snd_hda_jack_add_kctl_mst(struct hda_codec *codec, hda_nid_t nid, 4688c2ecf20Sopenharmony_ci int dev_id, const char *name, bool phantom_jack, 4698c2ecf20Sopenharmony_ci int type, const struct hda_jack_keymap *keymap) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci struct hda_jack_tbl *jack; 4728c2ecf20Sopenharmony_ci const struct hda_jack_keymap *map; 4738c2ecf20Sopenharmony_ci int err, state, buttons; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci jack = snd_hda_jack_tbl_new(codec, nid, dev_id); 4768c2ecf20Sopenharmony_ci if (!jack) 4778c2ecf20Sopenharmony_ci return 0; 4788c2ecf20Sopenharmony_ci if (jack->jack) 4798c2ecf20Sopenharmony_ci return 0; /* already created */ 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (!type) 4828c2ecf20Sopenharmony_ci type = get_input_jack_type(codec, nid); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci buttons = 0; 4858c2ecf20Sopenharmony_ci if (keymap) { 4868c2ecf20Sopenharmony_ci for (map = keymap; map->type; map++) 4878c2ecf20Sopenharmony_ci buttons |= map->type; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci err = snd_jack_new(codec->card, name, type | buttons, 4918c2ecf20Sopenharmony_ci &jack->jack, true, phantom_jack); 4928c2ecf20Sopenharmony_ci if (err < 0) 4938c2ecf20Sopenharmony_ci return err; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci jack->phantom_jack = !!phantom_jack; 4968c2ecf20Sopenharmony_ci jack->type = type; 4978c2ecf20Sopenharmony_ci jack->button_state = 0; 4988c2ecf20Sopenharmony_ci jack->jack->private_data = jack; 4998c2ecf20Sopenharmony_ci jack->jack->private_free = hda_free_jack_priv; 5008c2ecf20Sopenharmony_ci if (keymap) { 5018c2ecf20Sopenharmony_ci for (map = keymap; map->type; map++) 5028c2ecf20Sopenharmony_ci snd_jack_set_key(jack->jack, map->type, map->key); 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci state = snd_hda_jack_detect_mst(codec, nid, dev_id); 5068c2ecf20Sopenharmony_ci snd_jack_report(jack->jack, state ? jack->type : 0); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci return 0; 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl_mst); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, 5138c2ecf20Sopenharmony_ci const struct auto_pin_cfg *cfg, 5148c2ecf20Sopenharmony_ci const char *base_name) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci unsigned int def_conf, conn; 5178c2ecf20Sopenharmony_ci char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 5188c2ecf20Sopenharmony_ci int err; 5198c2ecf20Sopenharmony_ci bool phantom_jack; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci WARN_ON(codec->dp_mst); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (!nid) 5248c2ecf20Sopenharmony_ci return 0; 5258c2ecf20Sopenharmony_ci def_conf = snd_hda_codec_get_pincfg(codec, nid); 5268c2ecf20Sopenharmony_ci conn = get_defcfg_connect(def_conf); 5278c2ecf20Sopenharmony_ci if (conn == AC_JACK_PORT_NONE) 5288c2ecf20Sopenharmony_ci return 0; 5298c2ecf20Sopenharmony_ci phantom_jack = (conn != AC_JACK_PORT_COMPLEX) || 5308c2ecf20Sopenharmony_ci !is_jack_detectable(codec, nid); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (base_name) 5338c2ecf20Sopenharmony_ci strlcpy(name, base_name, sizeof(name)); 5348c2ecf20Sopenharmony_ci else 5358c2ecf20Sopenharmony_ci snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), NULL); 5368c2ecf20Sopenharmony_ci if (phantom_jack) 5378c2ecf20Sopenharmony_ci /* Example final name: "Internal Mic Phantom Jack" */ 5388c2ecf20Sopenharmony_ci strncat(name, " Phantom", sizeof(name) - strlen(name) - 1); 5398c2ecf20Sopenharmony_ci err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack, 0, NULL); 5408c2ecf20Sopenharmony_ci if (err < 0) 5418c2ecf20Sopenharmony_ci return err; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if (!phantom_jack) 5448c2ecf20Sopenharmony_ci return snd_hda_jack_detect_enable(codec, nid, 0); 5458c2ecf20Sopenharmony_ci return 0; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci/** 5498c2ecf20Sopenharmony_ci * snd_hda_jack_add_kctls - Add kctls for all pins included in the given pincfg 5508c2ecf20Sopenharmony_ci * @codec: the HDA codec 5518c2ecf20Sopenharmony_ci * @cfg: pin config table to parse 5528c2ecf20Sopenharmony_ci */ 5538c2ecf20Sopenharmony_ciint snd_hda_jack_add_kctls(struct hda_codec *codec, 5548c2ecf20Sopenharmony_ci const struct auto_pin_cfg *cfg) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci const hda_nid_t *p; 5578c2ecf20Sopenharmony_ci int i, err; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci for (i = 0; i < cfg->num_inputs; i++) { 5608c2ecf20Sopenharmony_ci /* If we have headphone mics; make sure they get the right name 5618c2ecf20Sopenharmony_ci before grabbed by output pins */ 5628c2ecf20Sopenharmony_ci if (cfg->inputs[i].is_headphone_mic) { 5638c2ecf20Sopenharmony_ci if (auto_cfg_hp_outs(cfg) == 1) 5648c2ecf20Sopenharmony_ci err = add_jack_kctl(codec, auto_cfg_hp_pins(cfg)[0], 5658c2ecf20Sopenharmony_ci cfg, "Headphone Mic"); 5668c2ecf20Sopenharmony_ci else 5678c2ecf20Sopenharmony_ci err = add_jack_kctl(codec, cfg->inputs[i].pin, 5688c2ecf20Sopenharmony_ci cfg, "Headphone Mic"); 5698c2ecf20Sopenharmony_ci } else 5708c2ecf20Sopenharmony_ci err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg, 5718c2ecf20Sopenharmony_ci NULL); 5728c2ecf20Sopenharmony_ci if (err < 0) 5738c2ecf20Sopenharmony_ci return err; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) { 5778c2ecf20Sopenharmony_ci err = add_jack_kctl(codec, *p, cfg, NULL); 5788c2ecf20Sopenharmony_ci if (err < 0) 5798c2ecf20Sopenharmony_ci return err; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) { 5828c2ecf20Sopenharmony_ci if (*p == *cfg->line_out_pins) /* might be duplicated */ 5838c2ecf20Sopenharmony_ci break; 5848c2ecf20Sopenharmony_ci err = add_jack_kctl(codec, *p, cfg, NULL); 5858c2ecf20Sopenharmony_ci if (err < 0) 5868c2ecf20Sopenharmony_ci return err; 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) { 5898c2ecf20Sopenharmony_ci if (*p == *cfg->line_out_pins) /* might be duplicated */ 5908c2ecf20Sopenharmony_ci break; 5918c2ecf20Sopenharmony_ci err = add_jack_kctl(codec, *p, cfg, NULL); 5928c2ecf20Sopenharmony_ci if (err < 0) 5938c2ecf20Sopenharmony_ci return err; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) { 5968c2ecf20Sopenharmony_ci err = add_jack_kctl(codec, *p, cfg, NULL); 5978c2ecf20Sopenharmony_ci if (err < 0) 5988c2ecf20Sopenharmony_ci return err; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci err = add_jack_kctl(codec, cfg->dig_in_pin, cfg, NULL); 6018c2ecf20Sopenharmony_ci if (err < 0) 6028c2ecf20Sopenharmony_ci return err; 6038c2ecf20Sopenharmony_ci err = add_jack_kctl(codec, cfg->mono_out_pin, cfg, NULL); 6048c2ecf20Sopenharmony_ci if (err < 0) 6058c2ecf20Sopenharmony_ci return err; 6068c2ecf20Sopenharmony_ci return 0; 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_add_kctls); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic void call_jack_callback(struct hda_codec *codec, unsigned int res, 6118c2ecf20Sopenharmony_ci struct hda_jack_tbl *jack) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci struct hda_jack_callback *cb; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci for (cb = jack->callback; cb; cb = cb->next) { 6168c2ecf20Sopenharmony_ci cb->jack = jack; 6178c2ecf20Sopenharmony_ci cb->unsol_res = res; 6188c2ecf20Sopenharmony_ci cb->func(codec, cb); 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci if (jack->gated_jack) { 6218c2ecf20Sopenharmony_ci struct hda_jack_tbl *gated = 6228c2ecf20Sopenharmony_ci snd_hda_jack_tbl_get_mst(codec, jack->gated_jack, 6238c2ecf20Sopenharmony_ci jack->dev_id); 6248c2ecf20Sopenharmony_ci if (gated) { 6258c2ecf20Sopenharmony_ci for (cb = gated->callback; cb; cb = cb->next) { 6268c2ecf20Sopenharmony_ci cb->jack = gated; 6278c2ecf20Sopenharmony_ci cb->unsol_res = res; 6288c2ecf20Sopenharmony_ci cb->func(codec, cb); 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci/** 6358c2ecf20Sopenharmony_ci * snd_hda_jack_unsol_event - Handle an unsolicited event 6368c2ecf20Sopenharmony_ci * @codec: the HDA codec 6378c2ecf20Sopenharmony_ci * @res: the unsolicited event data 6388c2ecf20Sopenharmony_ci */ 6398c2ecf20Sopenharmony_civoid snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci struct hda_jack_tbl *event; 6428c2ecf20Sopenharmony_ci int tag = (res & AC_UNSOL_RES_TAG) >> AC_UNSOL_RES_TAG_SHIFT; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (codec->dp_mst) { 6458c2ecf20Sopenharmony_ci int dev_entry = 6468c2ecf20Sopenharmony_ci (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci event = snd_hda_jack_tbl_get_from_tag(codec, tag, dev_entry); 6498c2ecf20Sopenharmony_ci } else { 6508c2ecf20Sopenharmony_ci event = snd_hda_jack_tbl_get_from_tag(codec, tag, 0); 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci if (!event) 6538c2ecf20Sopenharmony_ci return; 6548c2ecf20Sopenharmony_ci event->jack_dirty = 1; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci call_jack_callback(codec, res, event); 6578c2ecf20Sopenharmony_ci snd_hda_jack_report_sync(codec); 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_unsol_event); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci/** 6628c2ecf20Sopenharmony_ci * snd_hda_jack_poll_all - Poll all jacks 6638c2ecf20Sopenharmony_ci * @codec: the HDA codec 6648c2ecf20Sopenharmony_ci * 6658c2ecf20Sopenharmony_ci * Poll all detectable jacks with dirty flag, update the status, call 6668c2ecf20Sopenharmony_ci * callbacks and call snd_hda_jack_report_sync() if any changes are found. 6678c2ecf20Sopenharmony_ci */ 6688c2ecf20Sopenharmony_civoid snd_hda_jack_poll_all(struct hda_codec *codec) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci struct hda_jack_tbl *jack = codec->jacktbl.list; 6718c2ecf20Sopenharmony_ci int i, changes = 0; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci for (i = 0; i < codec->jacktbl.used; i++, jack++) { 6748c2ecf20Sopenharmony_ci unsigned int old_sense; 6758c2ecf20Sopenharmony_ci if (!jack->nid || !jack->jack_dirty || jack->phantom_jack) 6768c2ecf20Sopenharmony_ci continue; 6778c2ecf20Sopenharmony_ci old_sense = get_jack_plug_state(jack->pin_sense); 6788c2ecf20Sopenharmony_ci jack_detect_update(codec, jack); 6798c2ecf20Sopenharmony_ci if (old_sense == get_jack_plug_state(jack->pin_sense)) 6808c2ecf20Sopenharmony_ci continue; 6818c2ecf20Sopenharmony_ci changes = 1; 6828c2ecf20Sopenharmony_ci call_jack_callback(codec, 0, jack); 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci if (changes) 6858c2ecf20Sopenharmony_ci snd_hda_jack_report_sync(codec); 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_jack_poll_all); 6888c2ecf20Sopenharmony_ci 689