[alsa-devel] Problems with ALC882

Takashi Iwai tiwai at suse.de
Fri Jan 18 18:29:36 CET 2008


At Fri, 18 Jan 2008 18:11:05 +0100,
Christophe Osuna wrote:
> 
> 2008/1/18, Takashi Iwai <tiwai at suse.de>:
> > At Fri, 18 Jan 2008 17:50:38 +0100,
> > Christophe Osuna wrote:
> > >
> > > 2008/1/18, Takashi Iwai <tiwai at suse.de>:
> > > > Looks like your board disables the third ADC.  The driver probes it
> > > > and the codec returns it's no audio-input widget.  Check codec#* proc
> > > > output.
> > > >
> > >
> > > I have copied the contents of /proc/asound/card0/codec#2 at the end of
> > > this message. Notice that there are three nodes (0x07, 0x08 and 0x09)
> > > which claim to support PCM input.
> >
> > Ah, then it's in patch_realtek.c where alc880_pcm_analog_capture
> > claims substreams = 2.  Feel free to fix it.
> 
> OK.
> 
> That's not the kind of things I want to try on a Friday before leaving
> work, so I will try that next week and report results here.

Just deeper looking at the code, I found it's indeed buggy for the
secondary ADCs.  The patch below should fix it.

The second and third ADCs are assigned to PCM#2 while the first ADC is
to PCM#0.  This is for avoiding the confusion of dsnoop and
multi-streams.

Give it a try and check whether it doesn't break, at least, for
recording the first ADC.  If it's OK, I'll apply it to the HG tree
later.


BTW, the patch also includes a code snippet to support the alt
playback stream, e.g. for VoIP, but not fully implemented.


Takashi

---
diff -r a035d5e4801c pci/hda/patch_realtek.c
--- a/pci/hda/patch_realtek.c	Fri Jan 18 15:32:32 2008 +0100
+++ b/pci/hda/patch_realtek.c	Fri Jan 18 18:25:24 2008 +0100
@@ -220,6 +220,8 @@ struct alc_spec {
 	char *stream_name_analog;	/* analog PCM stream */
 	struct hda_pcm_stream *stream_analog_playback;
 	struct hda_pcm_stream *stream_analog_capture;
+	struct hda_pcm_stream *stream_analog_alt_playback;
+	struct hda_pcm_stream *stream_analog_alt_capture;
 
 	char *stream_name_digital;	/* digital PCM stream */
 	struct hda_pcm_stream *stream_digital_playback;
@@ -230,6 +232,7 @@ struct alc_spec {
 					 * max_channels, dacs must be set
 					 * dig_out_nid and hp_nid are optional
 					 */
+	hda_nid_t alt_dac_nid;
 
 	/* capture */
 	unsigned int num_adc_nids;
@@ -2370,7 +2373,7 @@ static int alc880_dig_playback_pcm_close
 /*
  * Analog capture
  */
-static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
 				      struct hda_codec *codec,
 				      unsigned int stream_tag,
 				      unsigned int format,
@@ -2378,18 +2381,18 @@ static int alc880_capture_pcm_prepare(st
 {
 	struct alc_spec *spec = codec->spec;
 
-	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
 				   stream_tag, 0, format);
 	return 0;
 }
 
-static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 				      struct hda_codec *codec,
 				      struct snd_pcm_substream *substream)
 {
 	struct alc_spec *spec = codec->spec;
 
-	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
 				   0, 0, 0);
 	return 0;
 }
@@ -2410,13 +2413,27 @@ static struct hda_pcm_stream alc880_pcm_
 };
 
 static struct hda_pcm_stream alc880_pcm_analog_capture = {
-	.substreams = 2,
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in alc_build_pcms */
+};
+
+static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in alc_build_pcms */
+};
+
+static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
+	.substreams = 2, /* can be overridden */
 	.channels_min = 2,
 	.channels_max = 2,
 	/* NID is set in alc_build_pcms */
 	.ops = {
-		.prepare = alc880_capture_pcm_prepare,
-		.cleanup = alc880_capture_pcm_cleanup
+		.prepare = alc880_alt_capture_pcm_prepare,
+		.cleanup = alc880_alt_capture_pcm_cleanup
 	},
 };
 
@@ -2440,7 +2457,7 @@ static struct hda_pcm_stream alc880_pcm_
 };
 
 /* Used by alc_build_pcms to flag that a PCM has no playback stream */
-static struct hda_pcm_stream alc_pcm_null_playback = {
+static struct hda_pcm_stream alc_pcm_null_stream = {
 	.substreams = 0,
 	.channels_min = 0,
 	.channels_max = 0,
@@ -2497,17 +2514,32 @@ static int alc_build_pcms(struct hda_cod
 	 * model, configure a second analog capture-only PCM.
 	 */
 	/* Additional Analaog capture for index #2 */
-	if (spec->num_adc_nids > 1 && spec->stream_analog_capture &&
-	    spec->adc_nids) {
+	if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
+	    (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
 		codec->num_pcms = 3;
 		info = spec->pcm_rec + 2;
 		info->name = spec->stream_name_analog;
-		/* No playback stream for second PCM */
-		info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback;
-		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
-		if (spec->stream_analog_capture) {
-			info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
-			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1];
+		if (spec->alt_dac_nid) {
+			info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+				*spec->stream_analog_alt_playback;
+			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+				spec->alt_dac_nid;
+		} else {
+			info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+				alc_pcm_null_stream;
+			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
+		}
+		if (spec->num_adc_nids > 1) {
+			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+				*spec->stream_analog_alt_capture;
+			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
+				spec->adc_nids[1];
+			info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
+				spec->num_adc_nids - 1;
+		} else {
+			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+				alc_pcm_null_stream;
+			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
 		}
 	}
 
@@ -3615,6 +3647,7 @@ static int patch_alc880(struct hda_codec
 	spec->stream_name_analog = "ALC880 Analog";
 	spec->stream_analog_playback = &alc880_pcm_analog_playback;
 	spec->stream_analog_capture = &alc880_pcm_analog_capture;
+	spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
 
 	spec->stream_name_digital = "ALC880 Digital";
 	spec->stream_digital_playback = &alc880_pcm_digital_playback;
@@ -4527,17 +4560,8 @@ static struct hda_verb alc260_test_init_
 };
 #endif
 
-static struct hda_pcm_stream alc260_pcm_analog_playback = {
-	.substreams = 1,
-	.channels_min = 2,
-	.channels_max = 2,
-};
-
-static struct hda_pcm_stream alc260_pcm_analog_capture = {
-	.substreams = 1,
-	.channels_min = 2,
-	.channels_max = 2,
-};
+#define alc260_pcm_analog_playback	alc880_pcm_analog_alt_playback
+#define alc260_pcm_analog_capture	alc880_pcm_analog_capture
 
 #define alc260_pcm_digital_playback	alc880_pcm_digital_playback
 #define alc260_pcm_digital_capture	alc880_pcm_digital_capture
@@ -6204,6 +6228,9 @@ static int patch_alc882(struct hda_codec
 	spec->stream_name_analog = "ALC882 Analog";
 	spec->stream_analog_playback = &alc882_pcm_analog_playback;
 	spec->stream_analog_capture = &alc882_pcm_analog_capture;
+	/* FIXME: setup DAC5 */
+	/*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
+	spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
 
 	spec->stream_name_digital = "ALC882 Digital";
 	spec->stream_digital_playback = &alc882_pcm_digital_playback;
@@ -7409,6 +7436,7 @@ static struct snd_kcontrol_new alc883_ca
 /* pcm configuration: identiacal with ALC880 */
 #define alc883_pcm_analog_playback	alc880_pcm_analog_playback
 #define alc883_pcm_analog_capture	alc880_pcm_analog_capture
+#define alc883_pcm_analog_alt_capture	alc880_pcm_analog_alt_capture
 #define alc883_pcm_digital_playback	alc880_pcm_digital_playback
 #define alc883_pcm_digital_capture	alc880_pcm_digital_capture
 
@@ -7894,6 +7922,7 @@ static int patch_alc883(struct hda_codec
 	spec->stream_name_analog = "ALC883 Analog";
 	spec->stream_analog_playback = &alc883_pcm_analog_playback;
 	spec->stream_analog_capture = &alc883_pcm_analog_capture;
+	spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
 
 	spec->stream_name_digital = "ALC883 Digital";
 	spec->stream_digital_playback = &alc883_pcm_digital_playback;
@@ -9821,6 +9850,7 @@ static void alc268_auto_init_mono_speake
 /* pcm configuration: identiacal with ALC880 */
 #define alc268_pcm_analog_playback	alc880_pcm_analog_playback
 #define alc268_pcm_analog_capture	alc880_pcm_analog_capture
+#define alc268_pcm_analog_alt_capture	alc880_pcm_analog_alt_capture
 #define alc268_pcm_digital_playback	alc880_pcm_digital_playback
 
 /*
@@ -10022,6 +10052,7 @@ static int patch_alc268(struct hda_codec
 	spec->stream_name_analog = "ALC268 Analog";
 	spec->stream_analog_playback = &alc268_pcm_analog_playback;
 	spec->stream_analog_capture = &alc268_pcm_analog_capture;
+	spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
 
 	spec->stream_name_digital = "ALC268 Digital";
 	spec->stream_digital_playback = &alc268_pcm_digital_playback;


More information about the Alsa-devel mailing list