]> xenbits.xensource.com Git - people/aperard/linux-chromebook.git/commitdiff
BACKPORT: ALSA: hda - Allow jack state to depend on another jack
authorDylan Reid <dgreid@chromium.org>
Mon, 19 Nov 2012 18:48:07 +0000 (19:48 +0100)
committerGerrit <chrome-bot@google.com>
Wed, 5 Dec 2012 23:51:29 +0000 (15:51 -0800)
Introduce the concept of a "gated" jack.  The gated jack's pin sense
is
only valid when the "gating" jack is plugged.  This requires checking
the gating jack when the gated jack changes and re-checking the gated
jack when the gating jack is plugged/unplugged.

This allows handling of devices where the mic jack detect floats when
the headphone jack is unplugged.

[Rewritten for fixing the possible snd_array reallocation, covering
 the missing callback calls and jack sync operations, as well as some
 code cleanups -- tiwai]

Signed-off-by: Dylan Reid <dgreid@chromium.org>
(cherry picked from commit 0619ba8c17b121ef0273be181198659b17d84247)

Conflicts:
sound/pci/hda/hda_jack.c
sound/pci/hda/hda_jack.h

[Removed callbacks not present in 3.4, and resolved conflicts
generated by non-existant phantom jacks. -- dgreid ]

Change-Id: I293240e6bac8b0fc828abd3e46968531562a66ac
Reviewed-on: https://gerrit.chromium.org/gerrit/38485
Reviewed-by: Chih-Chung Chang <chihchung@chromium.org>
Reviewed-by: Hsinyu Chao <hychao@chromium.org>
Reviewed-by: Olof Johansson <olofj@chromium.org>
Commit-Ready: Dylan Reid <dgreid@chromium.org>
Tested-by: Dylan Reid <dgreid@chromium.org>
sound/pci/hda/hda_jack.c
sound/pci/hda/hda_jack.h

index d68948499fbc15d7342ba0c9a63675d769b95a92..f81a89074f8c7672dd4ad65aed898af09df123b8 100644 (file)
@@ -122,13 +122,31 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec)
        snd_array_free(&codec->jacktbl);
 }
 
+#define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE)
+
 /* update the cached value and notification flag if needed */
 static void jack_detect_update(struct hda_codec *codec,
                               struct hda_jack_tbl *jack)
 {
-       if (jack->jack_dirty || !jack->jack_detect) {
-               jack->pin_sense = read_pin_sense(codec, jack->nid);
-               jack->jack_dirty = 0;
+       if (!jack->jack_dirty)
+               return;
+
+       jack->pin_sense = read_pin_sense(codec, jack->nid);
+
+       /* A gating jack indicates the jack is invalid if gating is unplugged */
+       if (jack->gating_jack && !snd_hda_jack_detect(codec, jack->gating_jack))
+               jack->pin_sense &= ~AC_PINSENSE_PRESENCE;
+
+       jack->jack_dirty = 0;
+
+       /* If a jack is gated by this one update it. */
+       if (jack->gated_jack) {
+               struct hda_jack_tbl *gated =
+                       snd_hda_jack_tbl_get(codec, jack->gated_jack);
+               if (gated) {
+                       gated->jack_dirty = 1;
+                       jack_detect_update(codec, gated);
+               }
        }
 }
 
@@ -168,8 +186,6 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid)
 }
 EXPORT_SYMBOL_HDA(snd_hda_pin_sense);
 
-#define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE)
-
 /**
  * snd_hda_jack_detect - query pin Presence Detect status
  * @codec: the CODEC to sense
@@ -204,17 +220,47 @@ int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
 }
 EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable);
 
+/**
+ * snd_hda_jack_set_gating_jack - Set gating jack.
+ *
+ * Indicates the gated jack is only valid when the gating jack is plugged.
+ */
+int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
+                                hda_nid_t gating_nid)
+{
+       struct hda_jack_tbl *gated = snd_hda_jack_tbl_get(codec, gated_nid);
+       struct hda_jack_tbl *gating = snd_hda_jack_tbl_get(codec, gating_nid);
+
+       if (!gated || !gating)
+               return -EINVAL;
+
+       gated->gating_jack = gating_nid;
+       gating->gated_jack = gated_nid;
+
+       return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_jack_set_gating_jack);
+
 /**
  * snd_hda_jack_report_sync - sync the states of all jacks and report if changed
  */
 void snd_hda_jack_report_sync(struct hda_codec *codec)
 {
-       struct hda_jack_tbl *jack = codec->jacktbl.list;
+       struct hda_jack_tbl *jack;
        int i, state;
 
+       /* update all jacks at first */
+       jack = codec->jacktbl.list;
        for (i = 0; i < codec->jacktbl.used; i++, jack++)
-               if (jack->nid) {
+               if (jack->nid)
                        jack_detect_update(codec, jack);
+
+       /* report the updated jacks; it's done after updating all jacks
+        * to make sure that all gating jacks properly have been set
+        */
+       jack = codec->jacktbl.list;
+       for (i = 0; i < codec->jacktbl.used; i++, jack++)
+               if (jack->nid) {
                        if (!jack->kctl)
                                continue;
                        state = get_jack_plug_state(jack->pin_sense);
index c66655cf413a1bc074f62ac91e0ed6e3907e342d..6009fef50bfde1b89694b8a5a1537f714cd1604f 100644 (file)
@@ -21,6 +21,8 @@ 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? */
+       hda_nid_t gating_jack;          /* valid when gating jack plugged */
+       hda_nid_t gated_jack;           /* gated is dependent on this jack */
        struct snd_kcontrol *kctl;      /* assigned kctl for jack-detection */
 #ifdef CONFIG_SND_HDA_INPUT_JACK
        int type;
@@ -59,6 +61,9 @@ 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 char action);
 
+int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
+                                hda_nid_t gating_nid);
+
 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);