[alsa-devel] [PATCH] ALSA: hda - Fix DP-MST support for NVIDIA codecs
Nikhil Mahale
nmahale at nvidia.com
Mon Feb 3 11:06:17 CET 2020
If dyn_pcm_assign is set, different jack objects are being created
for pcm and pins.
If dyn_pcm_assign is set, generic_hdmi_build_jack() calls into
add_hdmi_jack_kctl() to create and track separate jack object for
pcm. Like sync_eld_via_acomp(), hdmi_present_sense_via_verbs() also
need to report status change of the pcm jack.
Rename pin_idx_to_jack() to pin_idx_to_pcm_jack(). The code to
report status change of pcm jack, move it to update_eld() which is
common for acomp and !acomp code paths.
Fixes: 5398e94fb753 ALSA: hda - Add DP-MST support for NVIDIA codecs
Signed-off-by: Nikhil Mahale <nmahale at nvidia.com>
---
sound/pci/hda/patch_hdmi.c | 87 ++++++++++++++++++++++++----------------------
1 file changed, 45 insertions(+), 42 deletions(-)
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 48bddc218829..7b5360037217 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1480,6 +1480,35 @@ static void hdmi_pcm_reset_pin(struct hdmi_spec *spec,
per_pin->channels = 0;
}
+static struct snd_jack *pin_idx_to_pcm_jack(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct snd_jack *jack = NULL;
+ struct hda_jack_tbl *jack_tbl;
+
+ /* if !dyn_pcm_assign, get jack from hda_jack_tbl
+ * in !dyn_pcm_assign case, spec->pcm_rec[].jack is not
+ * NULL even after snd_hda_jack_tbl_clear() is called to
+ * free snd_jack. This may cause access invalid memory
+ * when calling snd_jack_report
+ */
+ if (per_pin->pcm_idx >= 0 && spec->dyn_pcm_assign) {
+ jack = spec->pcm_rec[per_pin->pcm_idx].jack;
+ } else if (!spec->dyn_pcm_assign) {
+ /*
+ * jack tbl doesn't support DP MST
+ * DP MST will use dyn_pcm_assign,
+ * so DP MST will never come here
+ */
+ jack_tbl = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid,
+ per_pin->dev_id);
+ if (jack_tbl)
+ jack = jack_tbl->jack;
+ }
+ return jack;
+}
+
/* update per_pin ELD from the given new ELD;
* setup info frame and notification accordingly
*/
@@ -1490,9 +1519,15 @@ static bool update_eld(struct hda_codec *codec,
struct hdmi_eld *pin_eld = &per_pin->sink_eld;
struct hdmi_spec *spec = codec->spec;
bool old_eld_valid = pin_eld->eld_valid;
+ struct snd_jack *pcm_jack;
bool eld_changed;
int pcm_idx;
+ /* pcm_idx >=0 before update_eld() means it is in monitor
+ * disconnected event. Jack must be fetched before update_eld()
+ */
+ pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
+
/* for monitor disconnection, save pcm_idx firstly */
pcm_idx = per_pin->pcm_idx;
if (spec->dyn_pcm_assign) {
@@ -1547,6 +1582,14 @@ static bool update_eld(struct hda_codec *codec,
SNDRV_CTL_EVENT_MASK_VALUE |
SNDRV_CTL_EVENT_MASK_INFO,
&get_hdmi_pcm(spec, pcm_idx)->eld_ctl->id);
+
+ if (!pcm_jack)
+ pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
+ if (eld_changed && pcm_jack)
+ snd_jack_report(pcm_jack,
+ (eld->monitor_present && eld->eld_valid) ?
+ SND_JACK_AVOUT : 0);
+
return eld_changed;
}
@@ -1615,43 +1658,12 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
return ret;
}
-static struct snd_jack *pin_idx_to_jack(struct hda_codec *codec,
- struct hdmi_spec_per_pin *per_pin)
-{
- struct hdmi_spec *spec = codec->spec;
- struct snd_jack *jack = NULL;
- struct hda_jack_tbl *jack_tbl;
-
- /* if !dyn_pcm_assign, get jack from hda_jack_tbl
- * in !dyn_pcm_assign case, spec->pcm_rec[].jack is not
- * NULL even after snd_hda_jack_tbl_clear() is called to
- * free snd_jack. This may cause access invalid memory
- * when calling snd_jack_report
- */
- if (per_pin->pcm_idx >= 0 && spec->dyn_pcm_assign)
- jack = spec->pcm_rec[per_pin->pcm_idx].jack;
- else if (!spec->dyn_pcm_assign) {
- /*
- * jack tbl doesn't support DP MST
- * DP MST will use dyn_pcm_assign,
- * so DP MST will never come here
- */
- jack_tbl = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid,
- per_pin->dev_id);
- if (jack_tbl)
- jack = jack_tbl->jack;
- }
- return jack;
-}
-
/* update ELD and jack state via audio component */
static void sync_eld_via_acomp(struct hda_codec *codec,
struct hdmi_spec_per_pin *per_pin)
{
struct hdmi_spec *spec = codec->spec;
struct hdmi_eld *eld = &spec->temp_eld;
- struct snd_jack *jack = NULL;
- bool changed;
int size;
mutex_lock(&per_pin->lock);
@@ -1674,17 +1686,8 @@ static void sync_eld_via_acomp(struct hda_codec *codec,
eld->eld_size = 0;
}
- /* pcm_idx >=0 before update_eld() means it is in monitor
- * disconnected event. Jack must be fetched before update_eld()
- */
- jack = pin_idx_to_jack(codec, per_pin);
- changed = update_eld(codec, per_pin, eld);
- if (jack == NULL)
- jack = pin_idx_to_jack(codec, per_pin);
- if (changed && jack)
- snd_jack_report(jack,
- (eld->monitor_present && eld->eld_valid) ?
- SND_JACK_AVOUT : 0);
+ update_eld(codec, per_pin, eld);
+
mutex_unlock(&per_pin->lock);
}
--
2.16.4
More information about the Alsa-devel
mailing list