From 6b43b6519a752c51657b9afa4eb844cad29d2b8c Mon Sep 17 00:00:00 2001 From: Nikhil Mahale Date: Mon, 3 Feb 2020 15:36:17 +0530 Subject: [PATCH 3/5] ALSA: hda - Fix DP-MST support for NVIDIA codecs 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 --- sound/pci/hda/patch_hdmi.c | 94 +++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 630b1f5c276d..469b25065643 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1477,6 +1477,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 */ @@ -1487,9 +1516,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) { @@ -1544,6 +1579,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; } @@ -1566,7 +1609,6 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, * the unsolicited response to avoid custom WARs. */ int present; - bool ret; bool do_repoll = false; present = snd_hda_jack_pin_sense(codec, pin_nid, dev_id); @@ -1600,45 +1642,14 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, else update_eld(codec, per_pin, eld); - ret = !repoll || !eld->monitor_present || eld->eld_valid; - jack = snd_hda_jack_tbl_get_mst(codec, pin_nid, per_pin->dev_id); if (jack) { - jack->block_report = !ret; + jack->block_report = do_repoll; jack->pin_sense = (eld->monitor_present && eld->eld_valid) ? AC_PINSENSE_PRESENCE : 0; } mutex_unlock(&per_pin->lock); - 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; + return !do_repoll; } /* update ELD and jack state via audio component */ @@ -1647,8 +1658,6 @@ static void sync_eld_via_acomp(struct hda_codec *codec, { 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); @@ -1671,17 +1680,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.25.0