[alsa-devel] patch for Dell 1210 which using stac9221 codec

Takashi Iwai tiwai at suse.de
Thu Oct 25 11:07:48 CEST 2007


At Thu, 25 Oct 2007 15:44:42 +0800,
zhejiang wrote:
> 
> On Tue, 2007-10-23 at 11:11 +0200, Takashi Iwai wrote:
> > At Mon, 22 Oct 2007 14:08:19 +0800,
> > zhejiang wrote:
> 
> > > > Ah, then it's basically similar like 3-stack model but with two
> > > > headphones instead of a pair of line-out and line-in.
> > > > 
> > > > Without your modification of pin config, how the driver detects?
> > > > Do you have an output of kernel message with debug option about auto
> > > > pin configs?
> > > > 
> > > I don't have the hardware.
> > > I have asked the bug reporter to do the experiment,
> > > I will post it here if i get any response.
> > 
> > Thanks.
> > 
> 
> According to the response from the reporter,here is the pin config of
> the original driver.
> 
> ALSA /tmp/alsa-driver-build/alsa-driver-1.0.15/pci/hda/hda_codec.c:2765:
> autoconfig: line_outs=3 (0xd/0xc/0xf/0x0/0x0)
> ALSA /tmp/alsa-driver-build/alsa-driver-1.0.15/pci/hda/hda_codec.c:2769:
> speaker_outs=0 (0x0/0x0/0x0/0x0/0x0)
> ALSA /tmp/alsa-driver-build/alsa-driver-1.0.15/pci/hda/hda_codec.c:2773:
> hp_outs=1 (0xa/0x0/0x0/0x0/0x0)
> ALSA /tmp/alsa-driver-build/alsa-driver-1.0.15/pci/hda/hda_codec.c:2781:
> inputs: mic=0x0, fmic=0x0, line=0x0, fline=0x0, cd=0x0, aux=0x0
> ALSA /tmp/alsa-driver-build/alsa-driver-1.0.15/pci/hda/../../alsa-kernel/pci/hda/patch_sigmatel.c:1652: stac92xx_add_dyn_out_pins: total dac count=4
> ALSA /tmp/alsa-driver-build/alsa-driver-1.0.15/pci/hda/../../alsa-kernel/pci/hda/patch_sigmatel.c:1775: dac_nids=3 (0x2/0x3/0x5/0x0/0x0)

Interesting.  Then the driver seems probing a fairly wrong pin
mapping.  So obviously the PCI SSID table entry for this laptop isn't
correct.


> > > > Looking through the sigmatel code, we have several known use cases:
> > > > 
> > > > 1. desktop
> > > > 1a. 3stack + front panel
> > > >     front HP, front mic, rear line-out, rear line-in, rear mic
> > > > 
> > > > 1b. 6stack + front panel
> > > >     front HP, front mic, rear line-out, rear surr, rear CLFE
> > > >     rear side, rear line-in, rear mic
> > > > and variants without front panel.
> > > > 
> > > > In the case 1a, rear line-in and rear mic can be used as surround
> > > > outputs.
> > > > 
> > > > 2. laptop
> > > > 2a. minimal
> > > >     HP, speaker, mic, built-in mic
> > > > 2b. a la desktop
> > > >     HP, speaker, line-in, mic, built-in mic
> > > > 2c. dell
> > > >     HP x 2, speaker(s), mic, built-in mic
> > > > 
> > > > Now, the case 2c requires a similar hack.  But, before going more
> > > > deeply, it's better to recheck patch_sigmatel.c again.  Basically, it
> > > > has already the code to add output sharing using line-in/mic-in.  The
> > > > problem is that it checks only limited use-cases (1a) and it adds
> > > > cfg->line_outs and thus this influences on all other places.
> > > > 
> > > 
> > > The call graph of stac92xx_parse_auto_config() :
> > > 
> > > 1.snd_hda_parse_pin_def_config()
> > > 
> > > 2.stac92xx_add_dyn_out_pins()
> > > It check the cfg->line_outs and input_pins[] to add dynamic lineouts.
> > > 
> > > 3.stac92xx_auto_fill_dac_nids()
> > > It only fills the dac_nids from the cfg->line_out_pins[],
> > > 
> > > 4.stac92xx_auto_create_multi_out_ctls()
> > > It add controls according to the cfg->line_outs.
> > > 
> > > we can see that they heavily depend on the line_outs[] info.
> > > 
> > > How about this method?
> > > 
> > > In stac92xx_add_dyn_out_pins(),we check the cfg->hp_outs,IF IT IS 2,then
> > > we switch the cfg->hp_pins[] with cfg->line_out_pins[].
> > 
> > Maybe better to check cfg->line_out_type.  I guess it's
> > AUTO_PIN_SPEAKER_OUT in the case of this Dell laptop.  The driver
> > takes speaker in prior to headphone as the primary line-out.
> > 
> > > The 2,3,4 may work without change.
> > > At the end of the stac92xx_parse_auto_config(),we restore the
> > > cfg->hp_pins[] and cfg->line_out_pins[].
> > 
> > Alternatively, instead of saving/restoring informatoin, we can fix
> > snd_hda_parse_pin_def_config() itself to check cfg->hp_outs and
> > cfg->speaker_outs to determine the primary output.  If one of them is
> > greater, take it as the primary output.
> > It's less hackish but *might* cause some regression in rare cases.
> > 
> 
> 
> I think that we need to restore the cfg->hp_pins and cfg->line_out_pins
> for the rest code,because:
> 
> 1. stac92xx_auto_init_hp_out() need to use the hp_pins to enable the
> AC_PINCTL_HP_EN

stac92xx_auto_init_multi_out() should check line_out_type and sets
HP_EN appropriatley, too.

> 2. stac92xx_hp_detect() need to use the hp_outs to detect jack presense
>    and will disable line_out_pins and speaker_pins.
> 3. stac92xx_init() use the hp_pins to enable unsolicited response.

Hm, these are nasty, indeed.

OK, what about the patch below?
It doesn't change the pincfg, so it wouldn't work as is, though.


Takashi

diff -r 09088524dd7f pci/hda/hda_codec.c
--- a/pci/hda/hda_codec.c	Thu Oct 25 11:46:24 2007 +0200
+++ b/pci/hda/hda_codec.c	Thu Oct 25 12:42:00 2007 +0200
@@ -2600,11 +2600,13 @@ int snd_hda_parse_pin_def_config(struct 
 	short seq, assoc_line_out, assoc_speaker;
 	short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
 	short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
+	short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
 
 	memset(cfg, 0, sizeof(*cfg));
 
 	memset(sequences_line_out, 0, sizeof(sequences_line_out));
 	memset(sequences_speaker, 0, sizeof(sequences_speaker));
+	memset(sequences_hp, 0, sizeof(sequences_hp));
 	assoc_line_out = assoc_speaker = 0;
 
 	nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start);
@@ -2659,9 +2661,12 @@ int snd_hda_parse_pin_def_config(struct 
 			cfg->speaker_outs++;
 			break;
 		case AC_JACK_HP_OUT:
+			seq = get_defcfg_sequence(def_conf);
+			assoc = get_defcfg_association(def_conf);
 			if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins))
 				continue;
 			cfg->hp_pins[cfg->hp_outs] = nid;
+			sequences_hp[cfg->hp_outs] = (assoc << 4) | seq;
 			cfg->hp_outs++;
 			break;
 		case AC_JACK_MIC_IN: {
@@ -2705,7 +2710,24 @@ int snd_hda_parse_pin_def_config(struct 
 			      cfg->line_outs);
 	sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker,
 			      cfg->speaker_outs);
+	sort_pins_by_sequence(cfg->hp_pins, sequences_hp,
+			      cfg->hp_outs);
 	
+	/* if we have only one mic, make it AUTO_PIN_MIC */
+	if (!cfg->input_pins[AUTO_PIN_MIC] &&
+	    cfg->input_pins[AUTO_PIN_FRONT_MIC]) {
+		cfg->input_pins[AUTO_PIN_MIC] =
+			cfg->input_pins[AUTO_PIN_FRONT_MIC];
+		cfg->input_pins[AUTO_PIN_FRONT_MIC] = 0;
+	}
+	/* ditto for line-in */
+	if (!cfg->input_pins[AUTO_PIN_LINE] &&
+	    cfg->input_pins[AUTO_PIN_FRONT_LINE]) {
+		cfg->input_pins[AUTO_PIN_LINE] =
+			cfg->input_pins[AUTO_PIN_FRONT_LINE];
+		cfg->input_pins[AUTO_PIN_FRONT_LINE] = 0;
+	}
+
 	/*
 	 * FIX-UP: if no line-outs are detected, try to use speaker or HP pin
 	 * as a primary output
diff -r 09088524dd7f pci/hda/patch_sigmatel.c
--- a/pci/hda/patch_sigmatel.c	Thu Oct 25 11:46:24 2007 +0200
+++ b/pci/hda/patch_sigmatel.c	Thu Oct 25 12:42:00 2007 +0200
@@ -1649,12 +1649,14 @@ static int stac92xx_add_control(struct s
 }
 
 /* flag inputs as additional dynamic lineouts */
-static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
+static int stac92xx_add_dyn_out_pins(struct hda_codec *codec,
+				     struct auto_pin_cfg *cfg,
+				     int line_outs, hda_nid_t *line_out_pins)
 {
 	struct sigmatel_spec *spec = codec->spec;
 	unsigned int wcaps, wtype;
 	int i, num_dacs = 0;
-	
+
 	/* use the wcaps cache to count all DACs available for line-outs */
 	for (i = 0; i < codec->num_nodes; i++) {
 		wcaps = codec->wcaps[i];
@@ -1665,49 +1667,48 @@ static int stac92xx_add_dyn_out_pins(str
 
 	snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
 	
-	switch (cfg->line_outs) {
+	switch (line_outs) {
 	case 3:
 		/* add line-in as side */
 		if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
-			cfg->line_out_pins[cfg->line_outs] =
+			line_out_pins[line_outs] =
 				cfg->input_pins[AUTO_PIN_LINE];
 			spec->line_switch = 1;
-			cfg->line_outs++;
+			line_outs++;
 		}
 		break;
 	case 2:
 		/* add line-in as clfe and mic as side */
 		if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
-			cfg->line_out_pins[cfg->line_outs] =
+			line_out_pins[line_outs] =
 				cfg->input_pins[AUTO_PIN_LINE];
 			spec->line_switch = 1;
-			cfg->line_outs++;
+			line_outs++;
 		}
 		if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
-			cfg->line_out_pins[cfg->line_outs] =
+			line_out_pins[line_outs] =
 				cfg->input_pins[AUTO_PIN_MIC];
 			spec->mic_switch = 1;
-			cfg->line_outs++;
+			line_outs++;
 		}
 		break;
 	case 1:
 		/* add line-in as surr and mic as clfe */
 		if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
-			cfg->line_out_pins[cfg->line_outs] =
+			line_out_pins[line_outs] =
 				cfg->input_pins[AUTO_PIN_LINE];
 			spec->line_switch = 1;
-			cfg->line_outs++;
+			line_outs++;
 		}
 		if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
-			cfg->line_out_pins[cfg->line_outs] =
+			line_out_pins[line_outs] =
 				cfg->input_pins[AUTO_PIN_MIC];
 			spec->mic_switch = 1;
-			cfg->line_outs++;
+			line_outs++;
 		}
 		break;
 	}
-
-	return 0;
+	return line_outs;
 }
 
 
@@ -1731,15 +1732,16 @@ static int is_in_dac_nids(struct sigmate
  * and 9202/925x. For those, dac_nids[] must be hard-coded.
  */
 static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
-				       struct auto_pin_cfg *cfg)
+				       struct auto_pin_cfg *cfg,
+				       int line_outs, hda_nid_t *line_out_pins)
 {
 	struct sigmatel_spec *spec = codec->spec;
 	int i, j, conn_len = 0; 
 	hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
 	unsigned int wcaps, wtype;
 	
-	for (i = 0; i < cfg->line_outs; i++) {
-		nid = cfg->line_out_pins[i];
+	for (i = 0; i < line_outs; i++) {
+		nid = line_out_pins[i];
 		conn_len = snd_hda_get_connections(codec, nid, conn,
 						   HDA_MAX_CONNECTIONS);
 		for (j = 0; j < conn_len; j++) {
@@ -1760,7 +1762,7 @@ static int stac92xx_auto_fill_dac_nids(s
 				/* we have already working output pins,
 				 * so let's drop the broken ones again
 				 */
-				cfg->line_outs = spec->multiout.num_dacs;
+				line_outs = spec->multiout.num_dacs;
 				break;
 			}
 			/* error out, no available DAC found */
@@ -1787,7 +1789,8 @@ static int stac92xx_auto_fill_dac_nids(s
 		   spec->multiout.dac_nids[2],
 		   spec->multiout.dac_nids[3],
 		   spec->multiout.dac_nids[4]);
-	return 0;
+
+	return line_outs;
 }
 
 /* create volume control/switch for the given prefx type */
@@ -2087,6 +2090,8 @@ static int stac92xx_parse_auto_config(st
 static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in)
 {
 	struct sigmatel_spec *spec = codec->spec;
+	int line_outs, *line_out_p;
+	hda_nid_t *line_out_pins;
 	int err;
 
 	if ((err = snd_hda_parse_pin_def_config(codec,
@@ -2096,11 +2101,32 @@ static int stac92xx_parse_auto_config(st
 	if (! spec->autocfg.line_outs)
 		return 0; /* can't find valid pin config */
 
-	if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
+	/* if we have multiple headphones and no line-outs,
+	 * let's set up headphones as primary outputs and allow
+	 * surround outputs
+	 */
+	if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
+	    spec->autocfg.hp_outs > 1) {
+		line_out_p = &spec->autocfg.hp_outs;
+		line_out_pins = spec->autocfg.hp_pins;
+	} else {
+		line_out_p = &spec->autocfg.line_outs;
+		line_out_pins = spec->autocfg.line_out_pins;
+	}
+	line_outs = *line_out_p;
+	err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg,
+					line_outs, line_out_pins);
+	if (err < 0)
 		return err;
-	if (spec->multiout.num_dacs == 0)
-		if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
+	line_outs = err;
+	if (spec->multiout.num_dacs == 0) {
+		err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg,
+						  line_outs, line_out_pins);
+		if (err < 0)
 			return err;
+		line_outs = err;
+	}
+	*line_out_p = line_outs; /* store back to autocfg */
 
 	err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
 


More information about the Alsa-devel mailing list