Skip to content

Commit f785f5e

Browse files
committed
ALSA: hda/hdmi: Preserve the previous PCM device upon re-enablement
When a DRM driver turns on or off the screen with the audio capability, it notifies the ELD to HD-audio HDMI codec driver via component ops. HDMI codec driver, in turn, attaches or detaches the PCM stream for the given port on the fly. The problem is that, since the recent code change, the HDMI driver always treats the PCM stream assignment dynamically; this ended up the confusion of the PCM device appearance. e.g. when a screen goes once off and on again, it may appear on a different PCM device before the screen-off. Although the application should treat such a change, it doesn't seem working gracefully with the current pipewire (maybe PulseAudio, too). As a workaround, this patch changes the HDMI codec driver behavior slightly to be more consistent. Now it remembers the previous PCM slot for the given port and try to assign to it. That is, if a port is re-enabled, the driver tries to use the same PCM slot that was assigned to that port previously. If it conflicts, a new slot is searched and used like before, instead. Note that multiple monitor connections are the only typical case where the PCM slot preservation is effective. As long as only a single monitor is connected, the behavior isn't changed, and the first PCM slot is still assigned always. Fixes: ef6f549 ("ALSA: hda/hdmi: Use only dynamic PCM device allocation") Reviewed-by: Jaroslav Kysela <[email protected]> Link: https://bugzilla.kernel.org/show_bug.cgi?id=217259 Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent 36d4d21 commit f785f5e

File tree

1 file changed

+11
-0
lines changed

1 file changed

+11
-0
lines changed

sound/pci/hda/patch_hdmi.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ struct hdmi_spec_per_pin {
8181
struct delayed_work work;
8282
struct hdmi_pcm *pcm; /* pointer to spec->pcm_rec[n] dynamically*/
8383
int pcm_idx; /* which pcm is attached. -1 means no pcm is attached */
84+
int prev_pcm_idx; /* previously assigned pcm index */
8485
int repoll_count;
8586
bool setup; /* the stream has been set up by prepare callback */
8687
bool silent_stream;
@@ -1380,9 +1381,17 @@ static void hdmi_attach_hda_pcm(struct hdmi_spec *spec,
13801381
/* pcm already be attached to the pin */
13811382
if (per_pin->pcm)
13821383
return;
1384+
/* try the previously used slot at first */
1385+
idx = per_pin->prev_pcm_idx;
1386+
if (idx >= 0) {
1387+
if (!test_bit(idx, &spec->pcm_bitmap))
1388+
goto found;
1389+
per_pin->prev_pcm_idx = -1; /* no longer valid, clear it */
1390+
}
13831391
idx = hdmi_find_pcm_slot(spec, per_pin);
13841392
if (idx == -EBUSY)
13851393
return;
1394+
found:
13861395
per_pin->pcm_idx = idx;
13871396
per_pin->pcm = get_hdmi_pcm(spec, idx);
13881397
set_bit(idx, &spec->pcm_bitmap);
@@ -1398,6 +1407,7 @@ static void hdmi_detach_hda_pcm(struct hdmi_spec *spec,
13981407
return;
13991408
idx = per_pin->pcm_idx;
14001409
per_pin->pcm_idx = -1;
1410+
per_pin->prev_pcm_idx = idx; /* remember the previous index */
14011411
per_pin->pcm = NULL;
14021412
if (idx >= 0 && idx < spec->pcm_used)
14031413
clear_bit(idx, &spec->pcm_bitmap);
@@ -1924,6 +1934,7 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
19241934

19251935
per_pin->pcm = NULL;
19261936
per_pin->pcm_idx = -1;
1937+
per_pin->prev_pcm_idx = -1;
19271938
per_pin->pin_nid = pin_nid;
19281939
per_pin->pin_nid_idx = spec->num_nids;
19291940
per_pin->dev_id = i;

0 commit comments

Comments
 (0)