xref: /kernel/linux/linux-5.10/sound/pci/hda/hda_jack.c (revision 8c2ecf20)
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