Skip to content

Commit 42b2987

Browse files
libinyangtiwai
authored andcommitted
ALSA: hda - hdmi playback without monitor in dynamic pcm bind mode
Pulseaudio requires open pcm successfully when probing. This patch handles playback without monitor in dynamic pcm assignment mode. It tries to open/prepare/close pcm successfully even there is no pin bound to the PCM. On the meantime, it will try to find a proper converter for the PCM. As pcm is This patch introduces a pcm_lock in struct hdmi_spec. This lock is used to protect: 1. the variables in struct hdmi_spec; 2. other variables shared for dynamic pcm assignment mode 3. device entry selection. As each device entry is represented by a separate struct struct hdmi_spec_per_pin, the lock in per_pin is not enough. Please see details below. MST audio device entry operation: 1. select device entry on the pin 2. operate on the pin nid Signed-off-by: Libin Yang <[email protected]> Signed-off-by: Takashi Iwai <[email protected]>
1 parent 6590faa commit 42b2987

File tree

1 file changed

+157
-14
lines changed

1 file changed

+157
-14
lines changed

sound/pci/hda/patch_hdmi.c

Lines changed: 157 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ struct hdmi_spec {
139139
int num_pins;
140140
struct snd_array pins; /* struct hdmi_spec_per_pin */
141141
struct hda_pcm *pcm_rec[16];
142+
struct mutex pcm_lock;
142143
unsigned int channels_max; /* max over all cvts */
143144

144145
struct hdmi_eld temp_eld;
@@ -1341,6 +1342,11 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
13411342
return 0;
13421343
}
13431344

1345+
/* Try to find an available converter
1346+
* If pin_idx is less then zero, just try to find an available converter.
1347+
* Otherwise, try to find an available converter and get the cvt mux index
1348+
* of the pin.
1349+
*/
13441350
static int hdmi_choose_cvt(struct hda_codec *codec,
13451351
int pin_idx, int *cvt_id, int *mux_id)
13461352
{
@@ -1349,7 +1355,11 @@ static int hdmi_choose_cvt(struct hda_codec *codec,
13491355
struct hdmi_spec_per_cvt *per_cvt = NULL;
13501356
int cvt_idx, mux_idx = 0;
13511357

1352-
per_pin = get_pin(spec, pin_idx);
1358+
/* pin_idx < 0 means no pin will be bound to the converter */
1359+
if (pin_idx < 0)
1360+
per_pin = NULL;
1361+
else
1362+
per_pin = get_pin(spec, pin_idx);
13531363

13541364
/* Dynamically assign converter to stream */
13551365
for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
@@ -1358,6 +1368,8 @@ static int hdmi_choose_cvt(struct hda_codec *codec,
13581368
/* Must not already be assigned */
13591369
if (per_cvt->assigned)
13601370
continue;
1371+
if (per_pin == NULL)
1372+
break;
13611373
/* Must be in pin's mux's list of converters */
13621374
for (mux_idx = 0; mux_idx < per_pin->num_mux_nids; mux_idx++)
13631375
if (per_pin->mux_nids[mux_idx] == per_cvt->cvt_nid)
@@ -1370,9 +1382,10 @@ static int hdmi_choose_cvt(struct hda_codec *codec,
13701382

13711383
/* No free converters */
13721384
if (cvt_idx == spec->num_cvts)
1373-
return -ENODEV;
1385+
return -EBUSY;
13741386

1375-
per_pin->mux_idx = mux_idx;
1387+
if (per_pin != NULL)
1388+
per_pin->mux_idx = mux_idx;
13761389

13771390
if (cvt_id)
13781391
*cvt_id = cvt_idx;
@@ -1398,6 +1411,20 @@ static void intel_verify_pin_cvt_connect(struct hda_codec *codec,
13981411
mux_idx);
13991412
}
14001413

1414+
/* get the mux index for the converter of the pins
1415+
* converter's mux index is the same for all pins on Intel platform
1416+
*/
1417+
static int intel_cvt_id_to_mux_idx(struct hdmi_spec *spec,
1418+
hda_nid_t cvt_nid)
1419+
{
1420+
int i;
1421+
1422+
for (i = 0; i < spec->num_cvts; i++)
1423+
if (spec->cvt_nids[i] == cvt_nid)
1424+
return i;
1425+
return -EINVAL;
1426+
}
1427+
14011428
/* Intel HDMI workaround to fix audio routing issue:
14021429
* For some Intel display codecs, pins share the same connection list.
14031430
* So a conveter can be selected by multiple pins and playback on any of these
@@ -1449,6 +1476,69 @@ static void intel_not_share_assigned_cvt(struct hda_codec *codec,
14491476
}
14501477
}
14511478

1479+
/* A wrapper of intel_not_share_asigned_cvt() */
1480+
static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
1481+
hda_nid_t pin_nid, hda_nid_t cvt_nid)
1482+
{
1483+
int mux_idx;
1484+
struct hdmi_spec *spec = codec->spec;
1485+
1486+
if (!is_haswell_plus(codec) && !is_valleyview_plus(codec))
1487+
return;
1488+
1489+
/* On Intel platform, the mapping of converter nid to
1490+
* mux index of the pins are always the same.
1491+
* The pin nid may be 0, this means all pins will not
1492+
* share the converter.
1493+
*/
1494+
mux_idx = intel_cvt_id_to_mux_idx(spec, cvt_nid);
1495+
if (mux_idx >= 0)
1496+
intel_not_share_assigned_cvt(codec, pin_nid, mux_idx);
1497+
}
1498+
1499+
/* called in hdmi_pcm_open when no pin is assigned to the PCM
1500+
* in dyn_pcm_assign mode.
1501+
*/
1502+
static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo,
1503+
struct hda_codec *codec,
1504+
struct snd_pcm_substream *substream)
1505+
{
1506+
struct hdmi_spec *spec = codec->spec;
1507+
struct snd_pcm_runtime *runtime = substream->runtime;
1508+
int cvt_idx;
1509+
struct hdmi_spec_per_cvt *per_cvt = NULL;
1510+
int err;
1511+
1512+
err = hdmi_choose_cvt(codec, -1, &cvt_idx, NULL);
1513+
if (err)
1514+
return err;
1515+
1516+
per_cvt = get_cvt(spec, cvt_idx);
1517+
per_cvt->assigned = 1;
1518+
hinfo->nid = per_cvt->cvt_nid;
1519+
1520+
intel_not_share_assigned_cvt_nid(codec, 0, per_cvt->cvt_nid);
1521+
1522+
/* todo: setup spdif ctls assign */
1523+
1524+
/* Initially set the converter's capabilities */
1525+
hinfo->channels_min = per_cvt->channels_min;
1526+
hinfo->channels_max = per_cvt->channels_max;
1527+
hinfo->rates = per_cvt->rates;
1528+
hinfo->formats = per_cvt->formats;
1529+
hinfo->maxbps = per_cvt->maxbps;
1530+
1531+
/* Store the updated parameters */
1532+
runtime->hw.channels_min = hinfo->channels_min;
1533+
runtime->hw.channels_max = hinfo->channels_max;
1534+
runtime->hw.formats = hinfo->formats;
1535+
runtime->hw.rates = hinfo->rates;
1536+
1537+
snd_pcm_hw_constraint_step(substream->runtime, 0,
1538+
SNDRV_PCM_HW_PARAM_CHANNELS, 2);
1539+
return 0;
1540+
}
1541+
14521542
/*
14531543
* HDA PCM callbacks
14541544
*/
@@ -1465,19 +1555,36 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
14651555
int err;
14661556

14671557
/* Validate hinfo */
1558+
mutex_lock(&spec->pcm_lock);
14681559
pin_idx = hinfo_to_pin_index(codec, hinfo);
1469-
if (snd_BUG_ON(pin_idx < 0))
1470-
return -EINVAL;
1471-
per_pin = get_pin(spec, pin_idx);
1472-
eld = &per_pin->sink_eld;
1560+
if (!spec->dyn_pcm_assign) {
1561+
if (snd_BUG_ON(pin_idx < 0)) {
1562+
mutex_unlock(&spec->pcm_lock);
1563+
return -EINVAL;
1564+
}
1565+
} else {
1566+
/* no pin is assigned to the PCM
1567+
* PA need pcm open successfully when probe
1568+
*/
1569+
if (pin_idx < 0) {
1570+
err = hdmi_pcm_open_no_pin(hinfo, codec, substream);
1571+
mutex_unlock(&spec->pcm_lock);
1572+
return err;
1573+
}
1574+
}
14731575

14741576
err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, &mux_idx);
1475-
if (err < 0)
1577+
if (err < 0) {
1578+
mutex_unlock(&spec->pcm_lock);
14761579
return err;
1580+
}
14771581

14781582
per_cvt = get_cvt(spec, cvt_idx);
14791583
/* Claim converter */
14801584
per_cvt->assigned = 1;
1585+
1586+
1587+
per_pin = get_pin(spec, pin_idx);
14811588
per_pin->cvt_nid = per_cvt->cvt_nid;
14821589
hinfo->nid = per_cvt->cvt_nid;
14831590

@@ -1498,6 +1605,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
14981605
hinfo->formats = per_cvt->formats;
14991606
hinfo->maxbps = per_cvt->maxbps;
15001607

1608+
eld = &per_pin->sink_eld;
15011609
/* Restrict capabilities by ELD if this isn't disabled */
15021610
if (!static_hdmi_pcm && eld->eld_valid) {
15031611
snd_hdmi_eld_update_pcm_info(&eld->info, hinfo);
@@ -1506,10 +1614,12 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
15061614
per_cvt->assigned = 0;
15071615
hinfo->nid = 0;
15081616
snd_hda_spdif_ctls_unassign(codec, pin_idx);
1617+
mutex_unlock(&spec->pcm_lock);
15091618
return -ENODEV;
15101619
}
15111620
}
15121621

1622+
mutex_unlock(&spec->pcm_lock);
15131623
/* Store the updated parameters */
15141624
runtime->hw.channels_min = hinfo->channels_min;
15151625
runtime->hw.channels_max = hinfo->channels_max;
@@ -1854,13 +1964,34 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
18541964
{
18551965
hda_nid_t cvt_nid = hinfo->nid;
18561966
struct hdmi_spec *spec = codec->spec;
1857-
int pin_idx = hinfo_to_pin_index(codec, hinfo);
1858-
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
1859-
hda_nid_t pin_nid = per_pin->pin_nid;
1967+
int pin_idx;
1968+
struct hdmi_spec_per_pin *per_pin;
1969+
hda_nid_t pin_nid;
18601970
struct snd_pcm_runtime *runtime = substream->runtime;
18611971
bool non_pcm;
18621972
int pinctl;
1973+
int err;
1974+
1975+
mutex_lock(&spec->pcm_lock);
1976+
pin_idx = hinfo_to_pin_index(codec, hinfo);
1977+
if (spec->dyn_pcm_assign && pin_idx < 0) {
1978+
/* when dyn_pcm_assign and pcm is not bound to a pin
1979+
* skip pin setup and return 0 to make audio playback
1980+
* be ongoing
1981+
*/
1982+
intel_not_share_assigned_cvt_nid(codec, 0, cvt_nid);
1983+
snd_hda_codec_setup_stream(codec, cvt_nid,
1984+
stream_tag, 0, format);
1985+
mutex_unlock(&spec->pcm_lock);
1986+
return 0;
1987+
}
18631988

1989+
if (snd_BUG_ON(pin_idx < 0)) {
1990+
mutex_unlock(&spec->pcm_lock);
1991+
return -EINVAL;
1992+
}
1993+
per_pin = get_pin(spec, pin_idx);
1994+
pin_nid = per_pin->pin_nid;
18641995
if (is_haswell_plus(codec) || is_valleyview_plus(codec)) {
18651996
/* Verify pin:cvt selections to avoid silent audio after S3.
18661997
* After S3, the audio driver restores pin:cvt selections
@@ -1885,7 +2016,6 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
18852016

18862017
hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
18872018
mutex_unlock(&per_pin->lock);
1888-
18892019
if (spec->dyn_pin_out) {
18902020
pinctl = snd_hda_codec_read(codec, pin_nid, 0,
18912021
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
@@ -1894,7 +2024,10 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
18942024
pinctl | PIN_OUT);
18952025
}
18962026

1897-
return spec->ops.setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
2027+
err = spec->ops.setup_stream(codec, cvt_nid, pin_nid,
2028+
stream_tag, format);
2029+
mutex_unlock(&spec->pcm_lock);
2030+
return err;
18982031
}
18992032

19002033
static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
@@ -1925,9 +2058,17 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
19252058
per_cvt->assigned = 0;
19262059
hinfo->nid = 0;
19272060

2061+
mutex_lock(&spec->pcm_lock);
19282062
pin_idx = hinfo_to_pin_index(codec, hinfo);
1929-
if (snd_BUG_ON(pin_idx < 0))
2063+
if (spec->dyn_pcm_assign && pin_idx < 0) {
2064+
mutex_unlock(&spec->pcm_lock);
2065+
return 0;
2066+
}
2067+
2068+
if (snd_BUG_ON(pin_idx < 0)) {
2069+
mutex_unlock(&spec->pcm_lock);
19302070
return -EINVAL;
2071+
}
19312072
per_pin = get_pin(spec, pin_idx);
19322073

19332074
if (spec->dyn_pin_out) {
@@ -1947,6 +2088,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
19472088
per_pin->setup = false;
19482089
per_pin->channels = 0;
19492090
mutex_unlock(&per_pin->lock);
2091+
mutex_unlock(&spec->pcm_lock);
19502092
}
19512093

19522094
return 0;
@@ -2461,6 +2603,7 @@ static int patch_generic_hdmi(struct hda_codec *codec)
24612603
return -ENOMEM;
24622604

24632605
spec->ops = generic_standard_hdmi_ops;
2606+
mutex_init(&spec->pcm_lock);
24642607
codec->spec = spec;
24652608
hdmi_array_init(spec, 4);
24662609

0 commit comments

Comments
 (0)