Patch "ALSA: hda - Re-setup HDMI pin and audio infoframe on stream switches" has been added to the 3.10-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    ALSA: hda - Re-setup HDMI pin and audio infoframe on stream switches

to the 3.10-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     alsa-hda-re-setup-hdmi-pin-and-audio-infoframe-on-stream-switches.patch
and it can be found in the queue-3.10 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.


>From b054087dbacee30a9dddaef2c9a96312146be04e Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@xxxxxxx>
Date: Mon, 2 Sep 2013 12:33:02 +0200
Subject: ALSA: hda - Re-setup HDMI pin and audio infoframe on stream switches

From: Takashi Iwai <tiwai@xxxxxxx>

commit b054087dbacee30a9dddaef2c9a96312146be04e upstream.

When the transcoder:port mapping on Haswell HDMI/DP audio is changed
during the stream playback, the sound gets lost.  Typically this
problem is seen when the user switches the graphics mode from eDP+DP
to DP-only configuration, where CRTC 1 is used for DP in the former
while CRTC 0 is used for the latter.

The graphics controller notifies the change via the normal ELD update
procedure, so we get the intrinsic event.  For enabling the sound
again, the HDMI audio driver needs to reset the pin and set up the
audio infoframe again.

This patch achieves it by:
- keep the current status of channels and info frame setup in per_pin
  struct,
- check the reconnection in the intrinsic event handler,
- reset the pin and the re-invoke hdmi_setup_audio_infoframe()
  accordingly.

The hdmi_setup_audio_infoframe() function has been changed, too, so
that it can be invoked without passing the substream instance.

The patch is mostly based on the work by Mengdong Lin.

Cc: Mengdong Lin <mengdong.lin@xxxxxxxxx>
Signed-off-by: Takashi Iwai <tiwai@xxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>

---
 sound/pci/hda/patch_hdmi.c |   41 +++++++++++++++++++++++++++++++----------
 1 file changed, 31 insertions(+), 10 deletions(-)

--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -67,6 +67,8 @@ struct hdmi_spec_per_pin {
 	struct delayed_work work;
 	struct snd_kcontrol *eld_ctl;
 	int repoll_count;
+	bool setup; /* the stream has been set up by prepare callback */
+	int channels; /* current number of channels */
 	bool non_pcm;
 	bool chmap_set;		/* channel-map override by ALSA API? */
 	unsigned char chmap[8]; /* ALSA API channel-map */
@@ -868,18 +870,19 @@ static bool hdmi_infoframe_uptodate(stru
 	return true;
 }
 
-static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
-				       bool non_pcm,
-				       struct snd_pcm_substream *substream)
+static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
+				       struct hdmi_spec_per_pin *per_pin,
+				       bool non_pcm)
 {
-	struct hdmi_spec *spec = codec->spec;
-	struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
 	hda_nid_t pin_nid = per_pin->pin_nid;
-	int channels = substream->runtime->channels;
+	int channels = per_pin->channels;
 	struct hdmi_eld *eld;
 	int ca;
 	union audio_infoframe ai;
 
+	if (!channels)
+		return;
+
 	eld = &per_pin->sink_eld;
 	if (!eld->monitor_present)
 		return;
@@ -1263,6 +1266,7 @@ static void hdmi_present_sense(struct hd
 		eld_changed = true;
 	}
 	if (update_eld) {
+		bool old_eld_valid = pin_eld->eld_valid;
 		pin_eld->eld_valid = eld->eld_valid;
 		eld_changed = pin_eld->eld_size != eld->eld_size ||
 			      memcmp(pin_eld->eld_buffer, eld->eld_buffer,
@@ -1272,6 +1276,18 @@ static void hdmi_present_sense(struct hd
 			       eld->eld_size);
 		pin_eld->eld_size = eld->eld_size;
 		pin_eld->info = eld->info;
+
+		/* Haswell-specific workaround: re-setup when the transcoder is
+		 * changed during the stream playback
+		 */
+		if (codec->vendor_id == 0x80862807 &&
+		    eld->eld_valid && !old_eld_valid && per_pin->setup) {
+			snd_hda_codec_write(codec, pin_nid, 0,
+					    AC_VERB_SET_AMP_GAIN_MUTE,
+					    AMP_OUT_UNMUTE);
+			hdmi_setup_audio_infoframe(codec, per_pin,
+						   per_pin->non_pcm);
+		}
 	}
 	mutex_unlock(&pin_eld->lock);
 
@@ -1444,14 +1460,17 @@ static int generic_hdmi_playback_pcm_pre
 	hda_nid_t cvt_nid = hinfo->nid;
 	struct hdmi_spec *spec = codec->spec;
 	int pin_idx = hinfo_to_pin_index(spec, hinfo);
-	hda_nid_t pin_nid = get_pin(spec, pin_idx)->pin_nid;
+	struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+	hda_nid_t pin_nid = per_pin->pin_nid;
 	bool non_pcm;
 
 	non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
+	per_pin->channels = substream->runtime->channels;
+	per_pin->setup = true;
 
 	hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels);
 
-	hdmi_setup_audio_infoframe(codec, pin_idx, non_pcm, substream);
+	hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
 
 	return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
 }
@@ -1491,6 +1510,9 @@ static int hdmi_pcm_close(struct hda_pcm
 		snd_hda_spdif_ctls_unassign(codec, pin_idx);
 		per_pin->chmap_set = false;
 		memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
+
+		per_pin->setup = false;
+		per_pin->channels = 0;
 	}
 
 	return 0;
@@ -1626,8 +1648,7 @@ static int hdmi_chmap_ctl_put(struct snd
 	per_pin->chmap_set = true;
 	memcpy(per_pin->chmap, chmap, sizeof(chmap));
 	if (prepared)
-		hdmi_setup_audio_infoframe(codec, pin_idx, per_pin->non_pcm,
-					   substream);
+		hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
 
 	return 0;
 }


Patches currently in stable-queue which might be from tiwai@xxxxxxx are

queue-3.10/alsa-hda-add-toshiba-satellite-c870-to-msi-blacklist.patch
queue-3.10/alsa-hda-re-setup-hdmi-pin-and-audio-infoframe-on-stream-switches.patch
queue-3.10/alsa-hda-hdmi-fallback-to-alsa-allocation-when-selecting-ca.patch
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]