From 80c8bfbe76869bfd6bdf3d260d316e7a32f318c3 Mon Sep 17 00:00:00 2001
From: David Henningsson <david.henningsson@canonical.com>
Date: Mon, 4 Jun 2012 09:33:51 +0200
Subject: [PATCH] ALSA: HDA: Create phantom jacks for fixed inputs and outputs
Git-commit: 80c8bfbe76869bfd6bdf3d260d316e7a32f318c3
Patch-mainline: 3.6-rc1
References: FATE#313695

PulseAudio sometimes have difficulties knowing that there is a
"Speaker" or "Internal Mic", if they have no individual volume
controls or selectors. As a result, only e g "Headphone" might
be created for a laptop, but no "Speaker".
To help out, create phantom jacks (that are always present,
at least for now) for "Speaker", "Internal Mic" etc, in case we
detect them.
The naming convention is e g "Speaker Phantom Jack".

In order not to pollute the /dev/input namespace with even more
devices, these are added to the kcontrols only, not the input devices.

Signed-off-by: David Henningsson <david.henningsson@canonical.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

---
 sound/pci/hda/hda_jack.c |   59 ++++++++++++++++++++++++++++++++---------------
 sound/pci/hda/hda_jack.h |    1 
 2 files changed, 42 insertions(+), 18 deletions(-)

--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -126,10 +126,15 @@ void snd_hda_jack_tbl_clear(struct hda_c
 static void jack_detect_update(struct hda_codec *codec,
 			       struct hda_jack_tbl *jack)
 {
-	if (jack->jack_dirty || !jack->jack_detect) {
+	if (!jack->jack_dirty)
+		return;
+
+	if (jack->phantom_jack)
+		jack->pin_sense = AC_PINSENSE_PRESENCE;
+	else
 		jack->pin_sense = read_pin_sense(codec, jack->nid);
-		jack->jack_dirty = 0;
-	}
+
+	jack->jack_dirty = 0;
 }
 
 /**
@@ -263,8 +268,8 @@ static void hda_free_jack_priv(struct sn
  * This assigns a jack-detection kctl to the given pin.  The kcontrol
  * will have the given name and index.
  */
-int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
-			  const char *name, int idx)
+static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
+			  const char *name, int idx, bool phantom_jack)
 {
 	struct hda_jack_tbl *jack;
 	struct snd_kcontrol *kctl;
@@ -282,19 +287,30 @@ int snd_hda_jack_add_kctl(struct hda_cod
 	if (err < 0)
 		return err;
 	jack->kctl = kctl;
+	jack->phantom_jack = !!phantom_jack;
+
 	state = snd_hda_jack_detect(codec, nid);
 	snd_kctl_jack_report(codec->bus->card, kctl, state);
 #ifdef CONFIG_SND_HDA_INPUT_JACK
-	jack->type = get_input_jack_type(codec, nid);
-	err = snd_jack_new(codec->bus->card, name, jack->type, &jack->jack);
-	if (err < 0)
-		return err;
-	jack->jack->private_data = jack;
-	jack->jack->private_free = hda_free_jack_priv;
-	snd_jack_report(jack->jack, state ? jack->type : 0);
+	if (!phantom_jack) {
+		jack->type = get_input_jack_type(codec, nid);
+		err = snd_jack_new(codec->bus->card, name, jack->type,
+				   &jack->jack);
+		if (err < 0)
+			return err;
+		jack->jack->private_data = jack;
+		jack->jack->private_free = hda_free_jack_priv;
+		snd_jack_report(jack->jack, state ? jack->type : 0);
+	}
 #endif
 	return 0;
 }
+
+int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
+			  const char *name, int idx)
+{
+	return __snd_hda_jack_add_kctl(codec, nid, name, idx, false);
+}
 EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctl);
 
 static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
@@ -304,25 +320,32 @@ static int add_jack_kctl(struct hda_code
 	unsigned int def_conf, conn;
 	char name[44];
 	int idx, err;
+	bool phantom_jack;
 
 	if (!nid)
 		return 0;
-	if (!is_jack_detectable(codec, nid))
-		return 0;
 	def_conf = snd_hda_codec_get_pincfg(codec, nid);
 	conn = get_defcfg_connect(def_conf);
-	if (conn != AC_JACK_PORT_COMPLEX)
+	if (conn == AC_JACK_PORT_NONE)
 		return 0;
+	phantom_jack = (conn != AC_JACK_PORT_COMPLEX) ||
+		       !is_jack_detectable(codec, nid);
 
 	snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), &idx);
+	if (phantom_jack)
+		/* Example final name: "Internal Mic Phantom Jack" */
+		strncat(name, " Phantom", sizeof(name) - strlen(name) - 1);
 	if (!strcmp(name, lastname) && idx == *lastidx)
 		idx++;
-	strncpy(lastname, name, 44);
+	strncpy(lastname, name, sizeof(name));
 	*lastidx = idx;
-	err = snd_hda_jack_add_kctl(codec, nid, name, idx);
+	err = __snd_hda_jack_add_kctl(codec, nid, name, idx, phantom_jack);
 	if (err < 0)
 		return err;
-	return snd_hda_jack_detect_enable(codec, nid, 0);
+
+	if (!phantom_jack)
+		return snd_hda_jack_detect_enable(codec, nid, 0);
+	return 0;
 }
 
 /**
--- a/sound/pci/hda/hda_jack.h
+++ b/sound/pci/hda/hda_jack.h
@@ -23,6 +23,7 @@ struct hda_jack_tbl {
 	unsigned int pin_sense;		/* cached pin-sense value */
 	unsigned int jack_detect:1;	/* capable of jack-detection? */
 	unsigned int jack_dirty:1;	/* needs to update? */
+	unsigned int phantom_jack:1;    /* a fixed, always present port? */
 	struct snd_kcontrol *kctl;	/* assigned kctl for jack-detection */
 #ifdef CONFIG_SND_HDA_INPUT_JACK
 	int type;
