Skip to content

Commit c7e661a

Browse files
nmahaletiwai
authored andcommitted
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(). Update hdmi_present_sense_via_verbs() to report plug state of pcm jack object. Unlike sync_eld_via_acomp(), for !acomp drivers the pcm jack's plug state must be consistent with plug state of pin's jack. Fixes: 5398e94 ("ALSA: hda - Add DP-MST support for NVIDIA codecs") Reported-and-tested-by: Martin Regner <[email protected]> Signed-off-by: Nikhil Mahale <[email protected]> Reviewed-by: Kai Vehmanen <[email protected]> Cc: <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent 112e3f5 commit c7e661a

File tree

1 file changed

+63
-31
lines changed

1 file changed

+63
-31
lines changed

sound/pci/hda/patch_hdmi.c

Lines changed: 63 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1550,6 +1550,34 @@ static bool update_eld(struct hda_codec *codec,
15501550
return eld_changed;
15511551
}
15521552

1553+
static struct snd_jack *pin_idx_to_pcm_jack(struct hda_codec *codec,
1554+
struct hdmi_spec_per_pin *per_pin)
1555+
{
1556+
struct hdmi_spec *spec = codec->spec;
1557+
struct snd_jack *jack = NULL;
1558+
struct hda_jack_tbl *jack_tbl;
1559+
1560+
/* if !dyn_pcm_assign, get jack from hda_jack_tbl
1561+
* in !dyn_pcm_assign case, spec->pcm_rec[].jack is not
1562+
* NULL even after snd_hda_jack_tbl_clear() is called to
1563+
* free snd_jack. This may cause access invalid memory
1564+
* when calling snd_jack_report
1565+
*/
1566+
if (per_pin->pcm_idx >= 0 && spec->dyn_pcm_assign) {
1567+
jack = spec->pcm_rec[per_pin->pcm_idx].jack;
1568+
} else if (!spec->dyn_pcm_assign) {
1569+
/*
1570+
* jack tbl doesn't support DP MST
1571+
* DP MST will use dyn_pcm_assign,
1572+
* so DP MST will never come here
1573+
*/
1574+
jack_tbl = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid,
1575+
per_pin->dev_id);
1576+
if (jack_tbl)
1577+
jack = jack_tbl->jack;
1578+
}
1579+
return jack;
1580+
}
15531581
/* update ELD and jack state via HD-audio verbs */
15541582
static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
15551583
int repoll)
@@ -1571,6 +1599,7 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
15711599
int present;
15721600
bool ret;
15731601
bool do_repoll = false;
1602+
struct snd_jack *pcm_jack = NULL;
15741603

15751604
present = snd_hda_jack_pin_sense(codec, pin_nid, dev_id);
15761605

@@ -1598,10 +1627,19 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
15981627
do_repoll = true;
15991628
}
16001629

1601-
if (do_repoll)
1630+
if (do_repoll) {
16021631
schedule_delayed_work(&per_pin->work, msecs_to_jiffies(300));
1603-
else
1632+
} else {
1633+
/*
1634+
* pcm_idx >=0 before update_eld() means it is in monitor
1635+
* disconnected event. Jack must be fetched before
1636+
* update_eld().
1637+
*/
1638+
pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
16041639
update_eld(codec, per_pin, eld);
1640+
if (!pcm_jack)
1641+
pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
1642+
}
16051643

16061644
ret = !repoll || !eld->monitor_present || eld->eld_valid;
16071645

@@ -1610,38 +1648,32 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
16101648
jack->block_report = !ret;
16111649
jack->pin_sense = (eld->monitor_present && eld->eld_valid) ?
16121650
AC_PINSENSE_PRESENCE : 0;
1613-
}
1614-
mutex_unlock(&per_pin->lock);
1615-
return ret;
1616-
}
16171651

1618-
static struct snd_jack *pin_idx_to_jack(struct hda_codec *codec,
1619-
struct hdmi_spec_per_pin *per_pin)
1620-
{
1621-
struct hdmi_spec *spec = codec->spec;
1622-
struct snd_jack *jack = NULL;
1623-
struct hda_jack_tbl *jack_tbl;
1652+
if (spec->dyn_pcm_assign && pcm_jack && !do_repoll) {
1653+
int state = 0;
1654+
1655+
if (jack->pin_sense & AC_PINSENSE_PRESENCE)
1656+
state = SND_JACK_AVOUT;
1657+
snd_jack_report(pcm_jack, state);
1658+
}
16241659

1625-
/* if !dyn_pcm_assign, get jack from hda_jack_tbl
1626-
* in !dyn_pcm_assign case, spec->pcm_rec[].jack is not
1627-
* NULL even after snd_hda_jack_tbl_clear() is called to
1628-
* free snd_jack. This may cause access invalid memory
1629-
* when calling snd_jack_report
1630-
*/
1631-
if (per_pin->pcm_idx >= 0 && spec->dyn_pcm_assign)
1632-
jack = spec->pcm_rec[per_pin->pcm_idx].jack;
1633-
else if (!spec->dyn_pcm_assign) {
16341660
/*
1635-
* jack tbl doesn't support DP MST
1636-
* DP MST will use dyn_pcm_assign,
1637-
* so DP MST will never come here
1661+
* snd_hda_jack_pin_sense() call at the beginning of this
1662+
* function, updates jack->pins_sense and clears
1663+
* jack->jack_dirty, therefore snd_hda_jack_report_sync() will
1664+
* not override the jack->pin_sense.
1665+
*
1666+
* snd_hda_jack_report_sync() is superfluous for dyn_pcm_assign
1667+
* case. The jack->pin_sense update was already performed, and
1668+
* hda_jack->jack is NULL for dyn_pcm_assign.
1669+
*
1670+
* Don't call snd_hda_jack_report_sync() for
1671+
* dyn_pcm_assign.
16381672
*/
1639-
jack_tbl = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid,
1640-
per_pin->dev_id);
1641-
if (jack_tbl)
1642-
jack = jack_tbl->jack;
1673+
ret = ret && !spec->dyn_pcm_assign;
16431674
}
1644-
return jack;
1675+
mutex_unlock(&per_pin->lock);
1676+
return ret;
16451677
}
16461678

16471679
/* update ELD and jack state via audio component */
@@ -1677,10 +1709,10 @@ static void sync_eld_via_acomp(struct hda_codec *codec,
16771709
/* pcm_idx >=0 before update_eld() means it is in monitor
16781710
* disconnected event. Jack must be fetched before update_eld()
16791711
*/
1680-
jack = pin_idx_to_jack(codec, per_pin);
1712+
jack = pin_idx_to_pcm_jack(codec, per_pin);
16811713
changed = update_eld(codec, per_pin, eld);
16821714
if (jack == NULL)
1683-
jack = pin_idx_to_jack(codec, per_pin);
1715+
jack = pin_idx_to_pcm_jack(codec, per_pin);
16841716
if (changed && jack)
16851717
snd_jack_report(jack,
16861718
(eld->monitor_present && eld->eld_valid) ?

0 commit comments

Comments
 (0)