aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2008-12-19 09:26:08 +0100
committerTakashi Iwai <tiwai@suse.de>2008-12-19 15:09:36 +0100
commitc21ca4a872697aeda4fe91bf9b6cc8380c62827c (patch)
tree9a30951ee842bb76cb6c3e8f00ee341fd9e2dc50 /sound
parent03c6901ea22bbb532586334d5b79941ccf56d5b0 (diff)
downloadkernel_samsung_smdk4412-c21ca4a872697aeda4fe91bf9b6cc8380c62827c.tar.gz
kernel_samsung_smdk4412-c21ca4a872697aeda4fe91bf9b6cc8380c62827c.tar.bz2
kernel_samsung_smdk4412-c21ca4a872697aeda4fe91bf9b6cc8380c62827c.zip
ALSA: hda - Rework on STAC/IDT auto-configuration code
The current auto-configuration code has several problems especially for the new IDT codecs, e.g. wrong assignment of pins and DACs or coupled volume for speaker and headphone. This patch is a fairly large rewrite of the auto-configuration code. Some remaks - mic_switch and line_switch contain NIDs instead of bool - dac_list isn't fixed for IDT 92HD* codecs now, they are all probed - extra HP and speakers are stored in extra_dacs[]. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/hda/patch_sigmatel.c467
1 files changed, 204 insertions, 263 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index b7b41969180..17140021632 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -157,8 +157,6 @@ struct sigmatel_spec {
int board_config;
unsigned int eapd_switch: 1;
unsigned int surr_switch: 1;
- unsigned int line_switch: 1;
- unsigned int mic_switch: 1;
unsigned int alt_switch: 1;
unsigned int hp_detect: 1;
unsigned int spdif_mute: 1;
@@ -195,6 +193,8 @@ struct sigmatel_spec {
unsigned int cur_mmux;
struct hda_multi_out multiout;
hda_nid_t dac_nids[5];
+ hda_nid_t hp_dacs[5];
+ hda_nid_t speaker_dacs[5];
/* capture */
hda_nid_t *adc_nids;
@@ -238,7 +238,9 @@ struct sigmatel_spec {
/* i/o switches */
unsigned int io_switch[2];
unsigned int clfe_swap;
- unsigned int hp_switch; /* NID of HP as line-out */
+ hda_nid_t line_switch; /* shared line-in for input and output */
+ hda_nid_t mic_switch; /* shared mic-in for input and output */
+ hda_nid_t hp_switch; /* NID of HP as line-out */
unsigned int aloopback;
struct hda_pcm pcm_rec[2]; /* PCM information */
@@ -289,9 +291,6 @@ static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
};
#define STAC92HD73_DAC_COUNT 5
-static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
- 0x15, 0x16, 0x17, 0x18, 0x19,
-};
static hda_nid_t stac92hd73xx_mux_nids[4] = {
0x28, 0x29, 0x2a, 0x2b,
@@ -310,11 +309,7 @@ static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
0x11, 0x12, 0
};
-#define STAC92HD81_DAC_COUNT 2
#define STAC92HD83_DAC_COUNT 3
-static hda_nid_t stac92hd83xxx_dac_nids[STAC92HD73_DAC_COUNT] = {
- 0x13, 0x14, 0x22,
-};
static hda_nid_t stac92hd83xxx_dmux_nids[2] = {
0x17, 0x18,
@@ -356,10 +351,6 @@ static hda_nid_t stac92hd71bxx_smux_nids[2] = {
0x24, 0x25,
};
-static hda_nid_t stac92hd71bxx_dac_nids[1] = {
- 0x10, /*0x11, */
-};
-
#define STAC92HD71BXX_NUM_DMICS 2
static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
0x18, 0x19, 0
@@ -761,10 +752,6 @@ static struct hda_verb stac9200_eapd_init[] = {
static struct hda_verb stac92hd73xx_6ch_core_init[] = {
/* set master volume and direct control */
{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
- /* setup audio connections */
- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
- { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
- { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
/* setup adcs to point to mixer */
{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
@@ -783,10 +770,6 @@ static struct hda_verb dell_eq_core_init[] = {
/* set master volume to max value without distortion
* and direct control */
{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
- /* setup audio connections */
- { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
- { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x02},
- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01},
/* setup adcs to point to mixer */
{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
@@ -800,10 +783,6 @@ static struct hda_verb dell_eq_core_init[] = {
static struct hda_verb dell_m6_core_init[] = {
{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
- /* setup audio connections */
- { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
- { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
/* setup adcs to point to mixer */
{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
@@ -818,13 +797,6 @@ static struct hda_verb dell_m6_core_init[] = {
static struct hda_verb stac92hd73xx_8ch_core_init[] = {
/* set master volume and direct control */
{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
- /* setup audio connections */
- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
- { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
- { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
- /* connect hp ports to dac3 */
- { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
- { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
/* setup adcs to point to mixer */
{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
@@ -842,15 +814,8 @@ static struct hda_verb stac92hd73xx_8ch_core_init[] = {
static struct hda_verb stac92hd73xx_10ch_core_init[] = {
/* set master volume and direct control */
{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
- /* setup audio connections */
- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
- { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
/* dac3 is connected to import3 mux */
{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
- /* connect hp ports to dac4 */
- { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
- { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
/* setup adcs to point to mixer */
{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
@@ -881,8 +846,6 @@ static struct hda_verb stac92hd83xxx_core_init[] = {
static struct hda_verb stac92hd71bxx_core_init[] = {
/* set master volume and direct control */
{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
- /* connect headphone jack to dac1 */
- { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
/* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -901,8 +864,6 @@ static struct hda_verb stac92hd71bxx_analog_core_init[] = {
/* set master volume and direct control */
{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
- /* connect headphone jack to dac1 */
- { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
/* unmute right and left channels for nodes 0x0a, 0xd */
{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -2747,70 +2708,53 @@ static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type,
return stac92xx_add_control_idx(spec, type, 0, name, val);
}
-/* flag inputs as additional dynamic lineouts */
-static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
+/* check whether the line-input can be used as line-out */
+static hda_nid_t check_line_out_switch(struct hda_codec *codec)
{
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];
- wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ hda_nid_t nid;
+ unsigned int pincap;
- if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
- num_dacs++;
- }
+ if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
+ return 0;
+ nid = cfg->input_pins[AUTO_PIN_LINE];
+ pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+ if (pincap & AC_PINCAP_OUT)
+ return nid;
+ return 0;
+}
- snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
-
- switch (cfg->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] =
- cfg->input_pins[AUTO_PIN_LINE];
- spec->line_switch = 1;
- cfg->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] =
- cfg->input_pins[AUTO_PIN_LINE];
- spec->line_switch = 1;
- cfg->line_outs++;
- }
- if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
- cfg->line_out_pins[cfg->line_outs] =
- cfg->input_pins[AUTO_PIN_MIC];
- spec->mic_switch = 1;
- cfg->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] =
- cfg->input_pins[AUTO_PIN_LINE];
- spec->line_switch = 1;
- cfg->line_outs++;
- }
- if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
- cfg->line_out_pins[cfg->line_outs] =
- cfg->input_pins[AUTO_PIN_MIC];
- spec->mic_switch = 1;
- cfg->line_outs++;
+/* check whether the mic-input can be used as line-out */
+static hda_nid_t check_mic_out_switch(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ unsigned int def_conf, pincap;
+ unsigned int mic_pin;
+
+ if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
+ return 0;
+ mic_pin = AUTO_PIN_MIC;
+ for (;;) {
+ hda_nid_t nid = cfg->input_pins[mic_pin];
+ def_conf = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_CONFIG_DEFAULT, 0);
+ /* some laptops have an internal analog microphone
+ * which can't be used as a output */
+ if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
+ pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+ if (pincap & AC_PINCAP_OUT)
+ return nid;
}
- break;
+ if (mic_pin == AUTO_PIN_MIC)
+ mic_pin = AUTO_PIN_FRONT_MIC;
+ else
+ break;
}
-
return 0;
}
-
static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
{
int i;
@@ -2823,6 +2767,52 @@ static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
return 0;
}
+static int check_all_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
+{
+ int i;
+ if (is_in_dac_nids(spec, nid))
+ return 1;
+ for (i = 0; i < spec->autocfg.hp_outs; i++)
+ if (spec->hp_dacs[i] == nid)
+ return 1;
+ for (i = 0; i < spec->autocfg.speaker_outs; i++)
+ if (spec->speaker_dacs[i] == nid)
+ return 1;
+ return 0;
+}
+
+static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ int j, conn_len;
+ hda_nid_t conn[HDA_MAX_CONNECTIONS];
+ unsigned int wcaps, wtype;
+
+ conn_len = snd_hda_get_connections(codec, nid, conn,
+ HDA_MAX_CONNECTIONS);
+ for (j = 0; j < conn_len; j++) {
+ wcaps = snd_hda_param_read(codec, conn[j],
+ AC_PAR_AUDIO_WIDGET_CAP);
+ wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+ /* we check only analog outputs */
+ if (wtype != AC_WID_AUD_OUT || (wcaps & AC_WCAP_DIGITAL))
+ continue;
+ /* if this route has a free DAC, assign it */
+ if (!check_all_dac_nids(spec, conn[j])) {
+ if (conn_len > 1) {
+ /* select this DAC in the pin's input mux */
+ snd_hda_codec_write_cache(codec, nid, 0,
+ AC_VERB_SET_CONNECT_SEL, j);
+ }
+ return conn[j];
+ }
+ }
+ return 0;
+}
+
+static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid);
+static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid);
+
/*
* Fill in the dac_nids table from the parsed pin configuration
* This function only works when every pin in line_out_pins[]
@@ -2830,31 +2820,17 @@ static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
* codecs are not connected directly to a DAC, such as the 9200
* 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)
+static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
- int i, j, conn_len = 0;
- hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
- unsigned int wcaps, wtype;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i;
+ hda_nid_t nid, dac;
for (i = 0; i < cfg->line_outs; i++) {
nid = cfg->line_out_pins[i];
- conn_len = snd_hda_get_connections(codec, nid, conn,
- HDA_MAX_CONNECTIONS);
- for (j = 0; j < conn_len; j++) {
- wcaps = snd_hda_param_read(codec, conn[j],
- AC_PAR_AUDIO_WIDGET_CAP);
- wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
- if (wtype != AC_WID_AUD_OUT ||
- (wcaps & AC_WCAP_DIGITAL))
- continue;
- /* conn[j] is a DAC routed to this line-out */
- if (!is_in_dac_nids(spec, conn[j]))
- break;
- }
-
- if (j == conn_len) {
+ dac = get_unassigned_dac(codec, nid);
+ if (!dac) {
if (spec->multiout.num_dacs > 0) {
/* we have already working output pins,
* so let's drop the broken ones again
@@ -2868,24 +2844,64 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
__func__, nid);
return -ENODEV;
}
+ add_spec_dacs(spec, dac);
+ }
- spec->multiout.dac_nids[i] = conn[j];
- spec->multiout.num_dacs++;
- if (conn_len > 1) {
- /* select this DAC in the pin's input mux */
- snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_CONNECT_SEL, j);
+ /* add line-in as output */
+ nid = check_line_out_switch(codec);
+ if (nid) {
+ dac = get_unassigned_dac(codec, nid);
+ if (dac) {
+ snd_printdd("STAC: Add line-in 0x%x as output %d\n",
+ nid, cfg->line_outs);
+ cfg->line_out_pins[cfg->line_outs] = nid;
+ cfg->line_outs++;
+ spec->line_switch = nid;
+ add_spec_dacs(spec, dac);
+ }
+ }
+ /* add mic as output */
+ nid = check_mic_out_switch(codec);
+ if (nid) {
+ dac = get_unassigned_dac(codec, nid);
+ if (dac) {
+ snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
+ nid, cfg->line_outs);
+ cfg->line_out_pins[cfg->line_outs] = nid;
+ cfg->line_outs++;
+ spec->mic_switch = nid;
+ add_spec_dacs(spec, dac);
+ }
+ }
+ for (i = 0; i < cfg->hp_outs; i++) {
+ nid = cfg->hp_pins[i];
+ dac = get_unassigned_dac(codec, nid);
+ if (dac) {
+ if (!spec->multiout.hp_nid)
+ spec->multiout.hp_nid = dac;
+ else
+ add_spec_extra_dacs(spec, dac);
}
+ spec->hp_dacs[i] = dac;
}
- snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
+ for (i = 0; i < cfg->speaker_outs; i++) {
+ nid = cfg->speaker_pins[i];
+ dac = get_unassigned_dac(codec, nid);
+ if (dac)
+ add_spec_extra_dacs(spec, dac);
+ spec->speaker_dacs[i] = dac;
+ }
+
+ snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
spec->multiout.num_dacs,
spec->multiout.dac_nids[0],
spec->multiout.dac_nids[1],
spec->multiout.dac_nids[2],
spec->multiout.dac_nids[3],
spec->multiout.dac_nids[4]);
+
return 0;
}
@@ -2910,9 +2926,7 @@ static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_
static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
{
- if (!spec->multiout.hp_nid)
- spec->multiout.hp_nid = nid;
- else if (spec->multiout.num_dacs > 4) {
+ if (spec->multiout.num_dacs > 4) {
printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
return 1;
} else {
@@ -2922,13 +2936,17 @@ static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
return 0;
}
-static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
+static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
{
- if (is_in_dac_nids(spec, nid))
- return 1;
- if (spec->multiout.hp_nid == nid)
- return 1;
- return 0;
+ int i;
+ for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) {
+ if (!spec->multiout.extra_out_nid[i]) {
+ spec->multiout.extra_out_nid[i] = nid;
+ return 0;
+ }
+ }
+ printk(KERN_WARNING "stac92xx: No space for extra DAC 0x%x\n", nid);
+ return 1;
}
/* add playback controls from the parsed DAC table */
@@ -2944,13 +2962,8 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
struct sigmatel_spec *spec = codec->spec;
unsigned int wid_caps, pincap;
-
- for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
- if (!spec->multiout.dac_nids[i])
- continue;
-
+ for (i = 0; i < cfg->line_outs && spec->multiout.dac_nids[i]; i++) {
nid = spec->multiout.dac_nids[i];
-
if (i == 2) {
/* Center/LFE */
err = create_controls(spec, "Center", nid, 1);
@@ -2978,10 +2991,6 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
}
}
- if ((spec->multiout.num_dacs - cfg->line_outs) > 0 &&
- cfg->hp_outs == 1 && !spec->multiout.hp_nid)
- spec->multiout.hp_nid = nid;
-
if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) {
err = stac92xx_add_control(spec,
STAC_CTL_WIDGET_HP_SWITCH,
@@ -2992,45 +3001,19 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
}
if (spec->line_switch) {
- nid = cfg->input_pins[AUTO_PIN_LINE];
- pincap = snd_hda_param_read(codec, nid,
- AC_PAR_PIN_CAP);
- if (pincap & AC_PINCAP_OUT) {
- err = stac92xx_add_control(spec,
- STAC_CTL_WIDGET_IO_SWITCH,
- "Line In as Output Switch", nid << 8);
- if (err < 0)
- return err;
- }
+ err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
+ "Line In as Output Switch",
+ spec->line_switch << 8);
+ if (err < 0)
+ return err;
}
if (spec->mic_switch) {
- unsigned int def_conf;
- unsigned int mic_pin = AUTO_PIN_MIC;
-again:
- nid = cfg->input_pins[mic_pin];
- def_conf = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_CONFIG_DEFAULT, 0);
- /* some laptops have an internal analog microphone
- * which can't be used as a output */
- if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
- pincap = snd_hda_param_read(codec, nid,
- AC_PAR_PIN_CAP);
- if (pincap & AC_PINCAP_OUT) {
- err = stac92xx_add_control(spec,
- STAC_CTL_WIDGET_IO_SWITCH,
- "Mic as Output Switch", (nid << 8) | 1);
- nid = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
- if (!check_in_dac_nids(spec, nid))
- add_spec_dacs(spec, nid);
- if (err < 0)
- return err;
- }
- } else if (mic_pin == AUTO_PIN_MIC) {
- mic_pin = AUTO_PIN_FRONT_MIC;
- goto again;
- }
+ err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
+ "Mic as Output Switch",
+ (spec->mic_switch << 8) | 1);
+ if (err < 0)
+ return err;
}
return 0;
@@ -3042,55 +3025,39 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
{
struct sigmatel_spec *spec = codec->spec;
hda_nid_t nid;
- int i, old_num_dacs, err;
+ int i, err, nums;
- old_num_dacs = spec->multiout.num_dacs;
+ nums = 0;
for (i = 0; i < cfg->hp_outs; i++) {
+ static const char *pfxs[] = {
+ "Headphone", "Headphone2", "Headphone3",
+ };
unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
if (wid_caps & AC_WCAP_UNSOL_CAP)
spec->hp_detect = 1;
- nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
- AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
- if (check_in_dac_nids(spec, nid))
- nid = 0;
- if (! nid)
+ if (nums >= ARRAY_SIZE(pfxs))
continue;
- add_spec_dacs(spec, nid);
- }
- for (i = 0; i < cfg->speaker_outs; i++) {
- nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
- AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
- if (check_in_dac_nids(spec, nid))
- nid = 0;
- if (! nid)
- continue;
- add_spec_dacs(spec, nid);
- }
- for (i = 0; i < cfg->line_outs; i++) {
- nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
- AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
- if (check_in_dac_nids(spec, nid))
- nid = 0;
- if (! nid)
+ nid = spec->hp_dacs[i];
+ if (!nid)
continue;
- add_spec_dacs(spec, nid);
+ err = create_controls(spec, pfxs[nums++], nid, 3);
+ if (err < 0)
+ return err;
}
- for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
+ nums = 0;
+ for (i = 0; i < cfg->speaker_outs; i++) {
static const char *pfxs[] = {
"Speaker", "External Speaker", "Speaker2",
};
- err = create_controls(spec, pfxs[i - old_num_dacs],
- spec->multiout.dac_nids[i], 3);
- if (err < 0)
- return err;
- }
- if (spec->multiout.hp_nid) {
- err = create_controls(spec, "Headphone",
- spec->multiout.hp_nid, 3);
+ if (nums >= ARRAY_SIZE(pfxs))
+ continue;
+ nid = spec->speaker_dacs[i];
+ if (!nid)
+ continue;
+ err = create_controls(spec, pfxs[nums++], nid, 3);
if (err < 0)
return err;
}
-
return 0;
}
@@ -3428,7 +3395,6 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
{
struct sigmatel_spec *spec = codec->spec;
int err;
- int hp_speaker_swap = 0;
if ((err = snd_hda_parse_pin_def_config(codec,
&spec->autocfg,
@@ -3446,13 +3412,15 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
* speaker_outs so that the following routines can handle
* HP pins as primary outputs.
*/
+ snd_printdd("stac92xx: Enabling multi-HPs workaround\n");
memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
sizeof(spec->autocfg.line_out_pins));
spec->autocfg.speaker_outs = spec->autocfg.line_outs;
memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
sizeof(spec->autocfg.hp_pins));
spec->autocfg.line_outs = spec->autocfg.hp_outs;
- hp_speaker_swap = 1;
+ spec->autocfg.line_out_type = AUTO_PIN_HP_OUT;
+ spec->autocfg.hp_outs = 0;
}
if (spec->autocfg.mono_out_pin) {
int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
@@ -3504,11 +3472,11 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
AC_PINCTL_OUT_EN);
}
- if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
- return err;
- if (spec->multiout.num_dacs == 0)
- if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
+ if (!spec->multiout.num_dacs) {
+ err = stac92xx_auto_fill_dac_nids(codec);
+ if (err < 0)
return err;
+ }
err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
@@ -3546,19 +3514,6 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
}
#endif
- if (hp_speaker_swap == 1) {
- /* Restore the hp_outs and line_outs */
- memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
- sizeof(spec->autocfg.line_out_pins));
- spec->autocfg.hp_outs = spec->autocfg.line_outs;
- memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
- sizeof(spec->autocfg.speaker_pins));
- spec->autocfg.line_outs = spec->autocfg.speaker_outs;
- memset(spec->autocfg.speaker_pins, 0,
- sizeof(spec->autocfg.speaker_pins));
- spec->autocfg.speaker_outs = 0;
- }
-
err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
if (err < 0)
@@ -3870,8 +3825,7 @@ static void stac92xx_power_down(struct hda_codec *codec)
/* power down inactive DACs */
hda_nid_t *dac;
for (dac = spec->dac_list; *dac; dac++)
- if (!is_in_dac_nids(spec, *dac) &&
- spec->multiout.hp_nid != *dac)
+ if (!check_all_dac_nids(spec, *dac))
snd_hda_codec_write(codec, *dac, 0,
AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
}
@@ -4055,10 +4009,7 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
*/
struct sigmatel_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
- if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
- spec->line_switch) ||
- (nid == cfg->input_pins[AUTO_PIN_MIC] &&
- spec->mic_switch))
+ if (nid == spec->line_switch || nid == spec->mic_switch)
return;
}
@@ -4100,11 +4051,9 @@ static int no_hp_sensing(struct sigmatel_spec *spec, int i)
struct auto_pin_cfg *cfg = &spec->autocfg;
/* ignore sensing of shared line and mic jacks */
- if (spec->line_switch &&
- cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_LINE])
+ if (cfg->hp_pins[i] == spec->line_switch)
return 1;
- if (spec->mic_switch &&
- cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_MIC])
+ if (cfg->hp_pins[i] == spec->mic_switch)
return 1;
/* ignore if the pin is set as line-out */
if (cfg->hp_pins[i] == spec->hp_switch)
@@ -4515,6 +4464,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
struct sigmatel_spec *spec;
hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
int err = 0;
+ int num_dacs;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
@@ -4541,33 +4491,29 @@ again:
return err;
}
- spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
+ num_dacs = snd_hda_get_connections(codec, 0x0a,
conn, STAC92HD73_DAC_COUNT + 2) - 1;
- if (spec->multiout.num_dacs < 0) {
+ if (num_dacs < 3 || num_dacs > 5) {
printk(KERN_WARNING "hda_codec: Could not determine "
"number of channels defaulting to DAC count\n");
- spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
+ num_dacs = STAC92HD73_DAC_COUNT;
}
-
- switch (spec->multiout.num_dacs) {
+ switch (num_dacs) {
case 0x3: /* 6 Channel */
- spec->multiout.hp_nid = 0x17;
spec->mixer = stac92hd73xx_6ch_mixer;
spec->init = stac92hd73xx_6ch_core_init;
break;
case 0x4: /* 8 Channel */
- spec->multiout.hp_nid = 0x18;
spec->mixer = stac92hd73xx_8ch_mixer;
spec->init = stac92hd73xx_8ch_core_init;
break;
case 0x5: /* 10 Channel */
- spec->multiout.hp_nid = 0x19;
spec->mixer = stac92hd73xx_10ch_mixer;
spec->init = stac92hd73xx_10ch_core_init;
- };
+ }
+ spec->multiout.dac_nids = spec->dac_nids;
- spec->multiout.dac_nids = stac92hd73xx_dac_nids;
spec->aloopback_mask = 0x01;
spec->aloopback_shift = 8;
@@ -4598,9 +4544,8 @@ again:
spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP];
spec->eapd_switch = 0;
spec->num_amps = 1;
- spec->multiout.hp_nid = 0; /* dual HPs */
- if (!spec->init)
+ if (spec->board_config != STAC_DELL_EQ)
spec->init = dell_m6_core_init;
switch (spec->board_config) {
case STAC_DELL_M6_AMIC: /* Analog Mics */
@@ -4691,17 +4636,15 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
spec->pwr_nids = stac92hd83xxx_pwr_nids;
spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
- spec->multiout.dac_nids = stac92hd83xxx_dac_nids;
+ spec->multiout.dac_nids = spec->dac_nids;
spec->init = stac92hd83xxx_core_init;
switch (codec->vendor_id) {
case 0x111d7605:
- spec->multiout.num_dacs = STAC92HD81_DAC_COUNT;
break;
default:
spec->num_pwrs--;
spec->init++; /* switch to config #2 */
- spec->multiout.num_dacs = STAC92HD83_DAC_COUNT;
}
spec->mixer = stac92hd83xxx_mixer;
@@ -4892,9 +4835,7 @@ again:
spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
};
- spec->multiout.num_dacs = 1;
- spec->multiout.hp_nid = 0x11;
- spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
+ spec->multiout.dac_nids = spec->dac_nids;
if (spec->dinput_mux)
spec->private_dimux.num_items +=
spec->num_dmics -