[alsa-devel] Acer Ferrari 5000

Takashi Iwai tiwai at suse.de
Tue Mar 24 00:27:45 CET 2009


At Mon, 23 Mar 2009 16:12:38 -0700,
Russ Dill wrote:
> 
> On Mon, Mar 23, 2009 at 3:55 PM, Takashi Iwai <tiwai at suse.de> wrote:
> > At Mon, 23 Mar 2009 15:48:19 -0700,
> > Russ Dill wrote:
> >>
> >> On Mon, Mar 23, 2009 at 3:45 PM, Takashi Iwai <tiwai at suse.de> wrote:
> >> > At Mon, 23 Mar 2009 15:28:57 -0700,
> >> > Russ Dill wrote:
> >> >>
> >> >> >> > BTW, I found why model=auto doesn't work well on your machine.
> >> >> >> > It's because (again) of BIOS.  It doesn't set the codec SSID properly
> >> >> >> > so the driver doesn't accept the HP auto-toggle and other features.
> >> >> >> >
> >> >> >> > So, in your case, using model=acer-aspire would be likely the best
> >> >> >> > choice (supposing it matches with most functionality).  If you have no
> >> >> >> > problem (at least regressions) with this model, I'll add the entry to
> >> >> >> > point to model=acer-aspire
> >> >> >>
> >> >> >> Add Acer Ferrar 5000 Quirk to Intel HDA driver
> >> >> >
> >> >> > Thanks, a similar fix was already merged now.
> >> >>
> >> >> It all works for a while, but eventually I'll get a "azx_get_response
> >> >> timeout, switching to polling mode: last cmd=0x10bb2001" and it no
> >> >> longer responds to headphone plug events without an unload/reload of
> >> >> the module.
> >> >
> >> > Did you try my test patch?
> >>
> >> It is with the patch:
> >>
> >> [16877.337044] hda_intel: azx_get_response timeout, switching to
> >> polling mode: last cmd=0x106f000a
> >> [16878.341056] hda_intel: azx_get_response timeout (ERROR): last cmd=0x106f000a
> >> [16879.345036] hda_intel: azx_get_response timeout (ERROR): last cmd=0x106f000a
> >> [16880.380016] hda_intel: azx_get_response timeout (ERROR): last cmd=0x106f000a
> >> [16881.384022] hda_intel: azx_get_response timeout (ERROR): last cmd=0x106f000a
> >
> > Interesting, this is again the same verb.
> > So, there seems something unstable regarding the digital PCM...
> >
> > And do you still have the problem with HP plugging?
> >
> 
> There seems to be some confusion. All I'm doing right now is playing
> audio through the analog PCM. After a while, I get that dmesg output
> and HP plugging stops working.

Yes, that's what I understood, too.  The driver still queries the PCM
parameter for the digital output widget because you turn on "IEC958
Default PCM" switch, thus the signal is still routed to the digital,
too.


The below is another test patch to reduce this problem (hopefully).
It basically caches the parameter values to avoid superfluous
queries.  It's against the very latest alsa-driver snapshot.
Apply it in addition to the previous test patch.


thanks,

Takashi

---

diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index a4e5e59..1d88e2f 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1053,6 +1053,8 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream);
 /* FIXME: more better hash key? */
 #define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24))
 #define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24))
+#define HDA_HASH_PARPCM_KEY(nid) (u32)((nid) + (0x03 << 24))
+#define HDA_HASH_PARSTR_KEY(nid) (u32)((nid) + (0x04 << 24))
 #define INFO_AMP_CAPS	(1<<0)
 #define INFO_AMP_VOL(ch)	(1 << (1 + (ch)))
 
@@ -1143,7 +1145,9 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
 }
 EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps);
 
-u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
+static unsigned int
+query_caps_hash(struct hda_codec *codec, hda_nid_t nid, u32 key,
+		unsigned int (*func)(struct hda_codec *, hda_nid_t))
 {
 	struct hda_amp_info *info;
 
@@ -1151,11 +1155,22 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
 	if (!info)
 		return 0;
 	if (!info->head.val) {
-		info->amp_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
 		info->head.val |= INFO_AMP_CAPS;
+		info->amp_caps = func(codec, nid);
 	}
 	return info->amp_caps;
 }
+
+static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid)
+{
+	return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+}
+
+u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
+{
+	return query_caps_hash(codec, nid, HDA_HASH_PINCAP_KEY(nid),
+			       read_pin_cap);
+}
 EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps);
 
 /*
@@ -2538,6 +2553,41 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
 }
 EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format);
 
+static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int val = 0;
+	if (nid != codec->afg &&
+	    (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD))
+		val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
+	if (!val || val == -1)
+		val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
+	if (!val || val == -1)
+		return 0;
+	return val;
+}
+
+static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid)
+{
+	return query_caps_hash(codec, nid, HDA_HASH_PARPCM_KEY(nid),
+			       get_pcm_param);
+}
+
+static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
+	if (!streams || streams == -1)
+		streams = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM);
+	if (!streams || streams == -1)
+		return 0;
+	return streams;
+}
+
+static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid)
+{
+	return query_caps_hash(codec, nid, HDA_HASH_PARSTR_KEY(nid),
+			       get_stream_param);
+}
+
 /**
  * snd_hda_query_supported_pcm - query the supported PCM rates and formats
  * @codec: the HDA codec
@@ -2556,15 +2606,8 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
 {
 	unsigned int i, val, wcaps;
 
-	val = 0;
 	wcaps = get_wcaps(codec, nid);
-	if (nid != codec->afg && (wcaps & AC_WCAP_FORMAT_OVRD)) {
-		val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
-		if (val == -1)
-			return -EIO;
-	}
-	if (!val)
-		val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
+	val = query_pcm_param(codec, nid);
 
 	if (ratesp) {
 		u32 rates = 0;
@@ -2586,15 +2629,9 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
 		u64 formats = 0;
 		unsigned int streams, bps;
 
-		streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
-		if (streams == -1)
+		streams = query_stream_param(codec, nid);
+		if (!streams)
 			return -EIO;
-		if (!streams) {
-			streams = snd_hda_param_read(codec, codec->afg,
-						     AC_PAR_STREAM);
-			if (streams == -1)
-				return -EIO;
-		}
 
 		bps = 0;
 		if (streams & AC_SUPFMT_PCM) {
@@ -2668,17 +2705,9 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
 	int i;
 	unsigned int val = 0, rate, stream;
 
-	if (nid != codec->afg &&
-	    (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) {
-		val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
-		if (val == -1)
-			return 0;
-	}
-	if (!val) {
-		val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
-		if (val == -1)
-			return 0;
-	}
+	val = query_pcm_param(codec, nid);
+	if (!val)
+		return 0;
 
 	rate = format & 0xff00;
 	for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++)
@@ -2690,12 +2719,8 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
 	if (i >= AC_PAR_PCM_RATE_BITS)
 		return 0;
 
-	stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
-	if (stream == -1)
-		return 0;
-	if (!stream && nid != codec->afg)
-		stream = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM);
-	if (!stream || stream == -1)
+	stream = query_stream_param(codec, nid);
+	if (!stream)
 		return 0;
 
 	if (stream & AC_SUPFMT_PCM) {


More information about the Alsa-devel mailing list