Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3a93897e authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: hda - Manage unsol tags in hda_jack.c



Manage the tags assigned for unsolicited events dynamically together
with the jack-detection routines.  Basically this is almost same as what
we've done in patch_sigmatel.c.  Assign the new tag number for each new
unsol event, associate with the given NID and the action type, etc.

With this change, now all pins looked over in snd_hda_jack_add_kctls()
are actually enabled for detection now even if the pins aren't used for
jack-retasking by the driver.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 01a61e12
Loading
Loading
Loading
Loading
+39 −22
Original line number Diff line number Diff line
@@ -50,6 +50,24 @@ snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid)
}
EXPORT_SYMBOL_HDA(snd_hda_jack_tbl_get);

/**
 * snd_hda_jack_tbl_get_from_tag - query the jack-table entry for the given tag
 */
struct hda_jack_tbl *
snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag)
{
	struct hda_jack_tbl *jack = codec->jacktbl.list;
	int i;

	if (!tag || !jack)
		return NULL;
	for (i = 0; i < codec->jacktbl.used; i++, jack++)
		if (jack->tag == tag)
			return jack;
	return NULL;
}
EXPORT_SYMBOL_HDA(snd_hda_jack_tbl_get_from_tag);

/**
 * snd_hda_jack_tbl_new - create a jack-table entry for the given NID
 */
@@ -65,6 +83,7 @@ snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid)
		return NULL;
	jack->nid = nid;
	jack->jack_dirty = 1;
	jack->tag = codec->jacktbl.used;
	return jack;
}

@@ -77,7 +96,7 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec)
static void jack_detect_update(struct hda_codec *codec,
			       struct hda_jack_tbl *jack)
{
	if (jack->jack_dirty || !jack->jack_cachable) {
	if (jack->jack_dirty || !jack->jack_detect) {
		unsigned int val = read_pin_sense(codec, jack->nid);
		jack->jack_dirty = 0;
		if (val != jack->pin_sense) {
@@ -141,17 +160,19 @@ EXPORT_SYMBOL_HDA(snd_hda_jack_detect);
 * snd_hda_jack_detect_enable - enable the jack-detection
 */
int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
			       unsigned int tag)
			       unsigned char action)
{
	struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid);
	if (!jack)
		return -ENOMEM;
	if (jack->jack_cachable)
	if (jack->jack_detect)
		return 0; /* already registered */
	jack->jack_cachable = 1;
	jack->jack_detect = 1;
	if (action)
		jack->action = action;
	return snd_hda_codec_write_cache(codec, nid, 0,
					 AC_VERB_SET_UNSOLICITED_ENABLE,
					 AC_USRSP_EN | tag);
					 AC_USRSP_EN | jack->tag);
}
EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable);

@@ -167,18 +188,6 @@ static void jack_detect_report(struct hda_codec *codec,
	}
}

/**
 * snd_hda_jack_report - notify kctl when the jack state was changed
 */
void snd_hda_jack_report(struct hda_codec *codec, hda_nid_t nid)
{
	struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);

	if (jack)
		jack_detect_report(codec, jack);
}
EXPORT_SYMBOL_HDA(snd_hda_jack_report);

/**
 * snd_hda_jack_report_sync - sync the states of all jacks and report if changed
 */
@@ -231,7 +240,7 @@ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
	struct hda_jack_tbl *jack;
	struct snd_kcontrol *kctl;

	jack = snd_hda_jack_tbl_get(codec, nid);
	jack = snd_hda_jack_tbl_new(codec, nid);
	if (!jack)
		return 0;
	if (jack->kctl)
@@ -251,20 +260,28 @@ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, int idx,
			 const struct auto_pin_cfg *cfg)
{
	unsigned int def_conf, conn;
	int err;

	if (!nid)
		return 0;
	if (!is_jack_detectable(codec, nid))
		return 0;
	return snd_hda_jack_add_kctl(codec, nid,
	def_conf = snd_hda_codec_get_pincfg(codec, nid);
	conn = get_defcfg_connect(def_conf);
	if (conn != AC_JACK_PORT_COMPLEX)
		return 0;

	err = snd_hda_jack_add_kctl(codec, nid,
				     snd_hda_get_pin_label(codec, nid, cfg),
				     idx);
	if (err < 0)
		return err;
	return snd_hda_jack_detect_enable(codec, nid, 0);
}

/**
 * snd_hda_jack_add_kctls - Add kctls for all pins included in the given pincfg
 *
 * As of now, it assigns only to the pins that enabled the detection.
 * Usually this is called at the end of build_controls callback.
 */
int snd_hda_jack_add_kctls(struct hda_codec *codec,
			   const struct auto_pin_cfg *cfg)
+18 −10
Original line number Diff line number Diff line
@@ -14,8 +14,12 @@

struct hda_jack_tbl {
	hda_nid_t nid;
	unsigned char action;		/* event action (0 = none) */
	unsigned char tag;		/* unsol event tag */
	unsigned int private_data;	/* arbitrary data */
	/* jack-detection stuff */
	unsigned int pin_sense;		/* cached pin-sense value */
	unsigned int jack_cachable:1;	/* can be updated via unsol events */
	unsigned int jack_detect:1;	/* capable of jack-detection? */
	unsigned int jack_dirty:1;	/* needs to update? */
	unsigned int need_notify:1;	/* to be notified? */
	struct snd_kcontrol *kctl;	/* assigned kctl for jack-detection */
@@ -23,29 +27,34 @@ struct hda_jack_tbl {

struct hda_jack_tbl *
snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid);
struct hda_jack_tbl *
snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag);

struct hda_jack_tbl *
snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid);
void snd_hda_jack_tbl_clear(struct hda_codec *codec);

/**
 * snd_hda_jack_set_dirty - set the dirty flag for the given jack-entry
 * snd_hda_jack_get_action - get jack-tbl entry for the tag
 *
 * Call this function when a pin-state may change, e.g. when the hardware
 * notifies via an unsolicited event.
 * Call this from the unsol event handler to get the assigned action for the
 * event.  This will mark the dirty flag for the later reporting, too.
 */
static inline void snd_hda_jack_set_dirty(struct hda_codec *codec,
					  hda_nid_t nid)
static inline unsigned char
snd_hda_jack_get_action(struct hda_codec *codec, unsigned int tag)
{
	struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
	if (jack)
	struct hda_jack_tbl *jack = snd_hda_jack_tbl_get_from_tag(codec, tag);
	if (jack) {
		jack->jack_dirty = 1;
		return jack->action;
	}
	return 0;
}

void snd_hda_jack_set_dirty_all(struct hda_codec *codec);

int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
			       unsigned int tag);
			       unsigned char action);

u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
@@ -68,7 +77,6 @@ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
int snd_hda_jack_add_kctls(struct hda_codec *codec,
			   const struct auto_pin_cfg *cfg);

void snd_hda_jack_report(struct hda_codec *codec, hda_nid_t nid);
void snd_hda_jack_report_sync(struct hda_codec *codec);


+2 −6
Original line number Diff line number Diff line
@@ -1235,9 +1235,7 @@ static void cs_free(struct hda_codec *codec)

static void cs_unsol_event(struct hda_codec *codec, unsigned int res)
{
	snd_hda_jack_set_dirty_all(codec); /* FIXME: to be more fine-grained */

	switch ((res >> 26) & 0x7f) {
	switch (snd_hda_jack_get_action(codec, res >> 26)) {
	case HP_EVENT:
		cs_automute(codec);
		break;
@@ -1824,9 +1822,7 @@ static int cs421x_build_controls(struct hda_codec *codec)

static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res)
{
	snd_hda_jack_set_dirty_all(codec); /* FIXME: to be more fine-grained */

	switch ((res >> 26) & 0x3f) {
	switch (snd_hda_jack_get_action(codec, res >> 26)) {
	case HP_EVENT:
	case SPDIF_EVENT:
		cs_automute(codec);
+4 −4
Original line number Diff line number Diff line
@@ -3757,8 +3757,8 @@ static void cx_auto_automic(struct hda_codec *codec)
static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
{
	int nid = (res & AC_UNSOL_RES_SUBTAG) >> 20;
	snd_hda_jack_set_dirty(codec, nid);
	switch (res >> 26) {

	switch (snd_hda_jack_get_action(codec, res >> 26)) {
	case CONEXANT_HP_EVENT:
		cx_auto_hp_automute(codec);
		break;
@@ -3982,11 +3982,11 @@ static void mute_outputs(struct hda_codec *codec, int num_nids,
}

static void enable_unsol_pins(struct hda_codec *codec, int num_pins,
			      hda_nid_t *pins, unsigned int tag)
			      hda_nid_t *pins, unsigned int action)
{
	int i;
	for (i = 0; i < num_pins; i++)
		snd_hda_jack_detect_enable(codec, pins[i], tag);
		snd_hda_jack_detect_enable(codec, pins[i], action);
}

static void cx_auto_init_output(struct hda_codec *codec)
+10 −3
Original line number Diff line number Diff line
@@ -754,10 +754,18 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, bool retry);
static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
{
	struct hdmi_spec *spec = codec->spec;
	int pin_nid = res >> AC_UNSOL_RES_TAG_SHIFT;
	int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
	int pin_nid;
	int pd = !!(res & AC_UNSOL_RES_PD);
	int eldv = !!(res & AC_UNSOL_RES_ELDV);
	int pin_idx;
	struct hda_jack_tbl *jack;

	jack = snd_hda_jack_tbl_get_from_tag(codec, tag);
	if (!jack)
		return;
	pin_nid = jack->nid;
	jack->jack_dirty = 1;

	printk(KERN_INFO
		"HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
@@ -767,7 +775,6 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
	if (pin_idx < 0)
		return;

	snd_hda_jack_set_dirty(codec, pin_nid);
	hdmi_present_sense(&spec->pins[pin_idx], true);
	snd_hda_jack_report_sync(codec);
}
@@ -801,7 +808,7 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
	int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
	int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;

	if (pin_nid_to_pin_index(spec, tag) < 0) {
	if (!snd_hda_jack_tbl_get_from_tag(codec, tag)) {
		snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag);
		return;
	}
Loading