[alsa-devel] [RFC PATCH] HDA: Generic input jack handling

David Henningsson david.henningsson at canonical.com
Fri Oct 7 13:49:46 CEST 2011


So, this is what I had in mind for 3.2. Assuming positive feedback from 
Takashi I'll go ahead and make a real patch out of this, and to clean up 
the Realtek implementation, as well as probably add this method for more 
codecs.

Thoughts:

1) The unsol event tags vary wildly between different vendors. How about 
standardising that as well?

2) If alc_init_jacks would call the new method, that might regress 
model-based (non auto) parsers. Is that a big deal these days?

3) Todo for realtek parser is to clean up all other calls to 
snd_input_jack_report so that jacks are not reported twice.

diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index e9b039c..69390fd 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -5284,6 +5284,142 @@ int snd_hda_input_jack_add(struct hda_codec 
*codec, hda_nid_t nid, int type,
  }
  EXPORT_SYMBOL_HDA(snd_hda_input_jack_add);

+/**
+ * snd_hda_input_auto_jack_add - Add relevant input jacks based on
+ * auto pin configuration.
+ * @param unsol_tags lists of jack types to enable, terminate with
+ * list entry with jack_type set to 0. If unsol_tag is set to 0,
+ * unsol events will not be enabled for that jack type.
+ * @return 0 or error code
+ */
+int snd_hda_input_auto_jack_add(struct hda_codec *codec,
+				const struct auto_pin_cfg *cfg,
+				const struct hda_unsol_jack_tag* unsol_tags)
+{
+	for (; unsol_tags->jack_type; unsol_tags++) {
+		hda_nid_t nid_list_storage[AUTO_CFG_MAX_INS];
+		const hda_nid_t *nid_list;
+		int nid_count = 0;
+		int i;
+		int input_match = AUTO_PIN_MIC;
+
+		switch (unsol_tags->jack_type) {
+		case SND_JACK_LINEIN:
+			input_match = AUTO_PIN_LINE_IN;
+			/* Fall through */
+		case SND_JACK_MICROPHONE:
+			for (i = 0; i < cfg->num_inputs; i++) {
+				if (cfg->inputs[i].type == input_match)
+					nid_list_storage[nid_count++] = cfg->inputs[i].pin;
+			}
+			nid_list = nid_list_storage;
+			break;
+		case SND_JACK_HEADPHONE:
+			if (cfg->line_out_type == AUTO_PIN_HP_OUT) {
+				nid_list = cfg->line_out_pins;
+				nid_count = cfg->line_outs;
+			} else {
+				nid_list = cfg->hp_pins;
+				nid_count = cfg->hp_outs;
+			}
+			break;
+		case SND_JACK_LINEOUT:
+			if (cfg->line_out_type == AUTO_PIN_LINE_OUT) {
+				nid_list = cfg->line_out_pins;
+				nid_count = cfg->line_outs;
+			}
+			break;			
+		}
+
+		for (i = 0; i < nid_count; i++) {
+			int pin = nid_list[i];
+			int err;
+			if (!is_jack_detectable(codec, pin))
+				continue;
+
+			if (unsol_tags->unsol_tag) {
+				err = snd_hda_codec_write(codec, pin, 0,
+					AC_VERB_SET_UNSOLICITED_ENABLE,
+					AC_USRSP_EN | unsol_tags->unsol_tag);
+				if (err)
+					return err;
+			}
+
+			err = snd_hda_input_jack_add(codec, pin,
+					unsol_tags->jack_type, NULL);
+			if (err)
+				return err;
+			snd_hda_input_jack_report(codec, pin);
+		}
+	}
+	return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_input_auto_jack_add);
+
+void snd_hda_input_jack_report_type(struct hda_codec *codec, int jack_type)
+{
+	struct hda_jack_item *jacks = codec->jacks.list;
+	int i;
+
+	if (!jacks)
+		return;
+
+	for (i = 0; i < codec->jacks.used; i++, jacks++)
+		if (jacks->type == jack_type)
+			snd_hda_input_jack_report(codec, jacks->nid);
+}
+EXPORT_SYMBOL_HDA(snd_hda_input_jack_report_type);
+
+
  void snd_hda_input_jack_report(struct hda_codec *codec, hda_nid_t nid)
  {
  	struct hda_jack_item *jacks = codec->jacks.list;
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 46c581c..bb59a3f 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -678,11 +678,21 @@ void snd_print_channel_allocation(int spk_alloc, 
char *buf, int buflen);
  /*
   * Input-jack notification support
   */
+
+struct hda_unsol_jack_tag {
+	int jack_type; /* SND_JACK_xxx constant */
+	int unsol_tag; /* event tag */
+};
+
  #ifdef CONFIG_SND_HDA_INPUT_JACK
  int snd_hda_input_jack_add(struct hda_codec *codec, hda_nid_t nid, int 
type,
  			   const char *name);
  void snd_hda_input_jack_report(struct hda_codec *codec, hda_nid_t nid);
+void snd_hda_input_jack_report_type(struct hda_codec *codec, int 
jack_type);
  void snd_hda_input_jack_free(struct hda_codec *codec);
+int snd_hda_input_auto_jack_add(struct hda_codec *codec,
+				const struct auto_pin_cfg *cfg,
+				const struct hda_unsol_jack_tag *unsol_tags);
  #else /* CONFIG_SND_HDA_INPUT_JACK */
  static inline int snd_hda_input_jack_add(struct hda_codec *codec,
  					 hda_nid_t nid, int type,
@@ -694,9 +704,19 @@ static inline void snd_hda_input_jack_report(struct 
hda_codec *codec,
  					     hda_nid_t nid)
  {
  }
+static inline void snd_hda_input_jack_report_type(struct hda_codec *codec,
+						  int jack_type)
+{
+}
  static inline void snd_hda_input_jack_free(struct hda_codec *codec)
  {
  }
+static inline int snd_hda_input_auto_jack_add(struct hda_codec *codec,
+				const struct auto_pin_cfg *cfg,
+				const struct hda_unsol_jack_tag *unsol_tags)
+{
+	return 0;
+}
  #endif /* CONFIG_SND_HDA_INPUT_JACK */

  #endif /* __SOUND_HDA_LOCAL_H */
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index bf53663..90cdd6c 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -38,6 +38,7 @@
  #define ALC_DCVOL_EVENT		0x02
  #define ALC_HP_EVENT		0x04
  #define ALC_MIC_EVENT		0x08
+#define ALC_LINEIN_EVENT	0x10

  /* for GPIO Poll */
  #define GPIO_MASK	0x03
@@ -441,11 +442,21 @@ static void alc_fix_pll_init(struct hda_codec 
*codec, hda_nid_t nid,
   * Jack-reporting via input-jack layer
   */

+static const struct hda_unsol_jack_tag unsol_tags[] = {
+	{.jack_type = SND_JACK_HEADPHONE, .unsol_tag = ALC_HP_EVENT },
+	{.jack_type = SND_JACK_LINEOUT, .unsol_tag = ALC_FRONT_EVENT },
+	{.jack_type = SND_JACK_MICROPHONE, .unsol_tag = ALC_MIC_EVENT },
+	{.jack_type = SND_JACK_LINEIN, .unsol_tag = ALC_LINEIN_EVENT },
+	{} /* Zero terminator */
+};
+
  /* initialization of jacks; currently checks only a few known pins */
  static int alc_init_jacks(struct hda_codec *codec)
  {
  #ifdef CONFIG_SND_HDA_INPUT_JACK
  	struct alc_spec *spec = codec->spec;
+	snd_hda_input_auto_jack_add(codec, &spec->autocfg, unsol_tags);
+/*	;
  	int err;
  	unsigned int hp_nid = spec->autocfg.hp_pins[0];
  	unsigned int mic_nid = spec->ext_mic_pin;
@@ -472,7 +483,7 @@ static int alc_init_jacks(struct hda_codec *codec)
  		if (err < 0)
  			return err;
  		snd_hda_input_jack_report(codec, dock_nid);
-	}
+	}*/
  #endif /* CONFIG_SND_HDA_INPUT_JACK */
  	return 0;
  }
@@ -645,12 +656,18 @@ static void alc_sku_unsol_event(struct hda_codec 
*codec, unsigned int res)
  	switch (res) {
  	case ALC_HP_EVENT:
  		alc_hp_automute(codec);
+		snd_hda_input_jack_report_type(codec, SND_JACK_HEADPHONE);
  		break;
  	case ALC_FRONT_EVENT:
  		alc_line_automute(codec);
+		snd_hda_input_jack_report_type(codec, SND_JACK_LINEOUT);
  		break;
  	case ALC_MIC_EVENT:
  		alc_mic_automute(codec);
+		snd_hda_input_jack_report_type(codec, SND_JACK_MICROPHONE);
+		break;
+	case ALC_LINEIN_EVENT:
+		snd_hda_input_jack_report_type(codec, SND_JACK_LINEIN);
  		break;
  	}
  }

-- 
David Henningsson, Canonical Ltd.
http://launchpad.net/~diwic


More information about the Alsa-devel mailing list