Commit e9edcee0 authored by Takashi Iwai's avatar Takashi Iwai Committed by Jaroslav Kysela

[ALSA] hda-codec - More fix of ALC880 codec support

Documentation,HDA Codec driver,HDA generic driver,HDA Intel driver
- Fix some invalid configurations, typos in the last patch
- Make init_verbs chainable, so that different configs can share the same
  init_verbs
- Reorder and clean up the source codes in patch_realtek.c
- Add the pin default configuration parser, used commonly in cmedia
  and realtek patch codes.
- Add 'auto' model to ALC880 for auto-configuration from BIOS
  Use this model as default, and 3-stack as fallback
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent b636a71d
...@@ -638,6 +638,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ...@@ -638,6 +638,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
5stack-digout 5-jack in back, 2-jack in front, a SPDIF out 5stack-digout 5-jack in back, 2-jack in front, a SPDIF out
w810 3-jack w810 3-jack
z71v 3-jack (HP shared SPDIF) z71v 3-jack (HP shared SPDIF)
asus 3-jack
uniwill 3-jack
F1734 2-jack
CMI9880 CMI9880
minimal 3-jack in back minimal 3-jack in back
...@@ -645,6 +648,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ...@@ -645,6 +648,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
full 6-jack in back, 2-jack in front full 6-jack in back, 2-jack in front
full_dig 6-jack in back, 2-jack in front, SPDIF I/O full_dig 6-jack in back, 2-jack in front, SPDIF I/O
allout 5-jack in back, 2-jack in front, SPDIF out allout 5-jack in back, 2-jack in front, SPDIF out
auto auto-config reading BIOS (default)
Note 2: If you get click noises on output, try the module option Note 2: If you get click noises on output, try the module option
position_fix=1 or 2. position_fix=1 will use the SD_LPIB position_fix=1 or 2. position_fix=1 will use the SD_LPIB
......
...@@ -1520,9 +1520,9 @@ int snd_hda_build_pcms(struct hda_bus *bus) ...@@ -1520,9 +1520,9 @@ int snd_hda_build_pcms(struct hda_bus *bus)
* *
* If no entries are matching, the function returns a negative value. * If no entries are matching, the function returns a negative value.
*/ */
int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config *tbl) int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl)
{ {
struct hda_board_config *c; const struct hda_board_config *c;
if (codec->bus->modelname) { if (codec->bus->modelname) {
for (c = tbl; c->modelname || c->pci_subvendor; c++) { for (c = tbl; c->modelname || c->pci_subvendor; c++) {
...@@ -1714,6 +1714,105 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_o ...@@ -1714,6 +1714,105 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_o
return 0; return 0;
} }
/*
* Helper for automatic ping configuration
*/
/* parse all pin widgets and store the useful pin nids to cfg */
int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg)
{
hda_nid_t nid, nid_start;
int i, j, nodes;
short seq, sequences[4], assoc_line_out;
memset(cfg, 0, sizeof(*cfg));
memset(sequences, 0, sizeof(sequences));
assoc_line_out = 0;
nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start);
for (nid = nid_start; nid < nodes + nid_start; nid++) {
unsigned int wid_caps = snd_hda_param_read(codec, nid,
AC_PAR_AUDIO_WIDGET_CAP);
unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
unsigned int def_conf;
short assoc, loc;
/* read all default configuration for pin complex */
if (wid_type != AC_WID_PIN)
continue;
def_conf = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
continue;
loc = get_defcfg_location(def_conf);
switch (get_defcfg_device(def_conf)) {
case AC_JACK_LINE_OUT:
case AC_JACK_SPEAKER:
seq = get_defcfg_sequence(def_conf);
assoc = get_defcfg_association(def_conf);
if (! assoc)
continue;
if (! assoc_line_out)
assoc_line_out = assoc;
else if (assoc_line_out != assoc)
continue;
if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins))
continue;
cfg->line_out_pins[cfg->line_outs] = nid;
sequences[cfg->line_outs] = seq;
cfg->line_outs++;
break;
case AC_JACK_HP_OUT:
cfg->hp_pin = nid;
break;
case AC_JACK_MIC_IN:
if (loc == AC_JACK_LOC_FRONT)
cfg->input_pins[AUTO_PIN_FRONT_MIC] = nid;
else
cfg->input_pins[AUTO_PIN_MIC] = nid;
break;
case AC_JACK_LINE_IN:
if (loc == AC_JACK_LOC_FRONT)
cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid;
else
cfg->input_pins[AUTO_PIN_LINE] = nid;
break;
case AC_JACK_CD:
cfg->input_pins[AUTO_PIN_CD] = nid;
break;
case AC_JACK_AUX:
cfg->input_pins[AUTO_PIN_AUX] = nid;
break;
case AC_JACK_SPDIF_OUT:
cfg->dig_out_pin = nid;
break;
case AC_JACK_SPDIF_IN:
cfg->dig_in_pin = nid;
break;
}
}
/* sort by sequence */
for (i = 0; i < cfg->line_outs; i++)
for (j = i + 1; j < cfg->line_outs; j++)
if (sequences[i] > sequences[j]) {
seq = sequences[i];
sequences[i] = sequences[j];
sequences[j] = seq;
nid = cfg->line_out_pins[i];
cfg->line_out_pins[i] = cfg->line_out_pins[j];
cfg->line_out_pins[j] = nid;
}
/* Swap surround and CLFE: the association order is front/CLFE/surr/back */
if (cfg->line_outs >= 3) {
nid = cfg->line_out_pins[1];
cfg->line_out_pins[1] = cfg->line_out_pins[2];
cfg->line_out_pins[2] = nid;
}
return 0;
}
#ifdef CONFIG_PM #ifdef CONFIG_PM
/* /*
* power management * power management
......
...@@ -68,8 +68,8 @@ struct hda_gspec { ...@@ -68,8 +68,8 @@ struct hda_gspec {
/* /*
* retrieve the default device type from the default config value * retrieve the default device type from the default config value
*/ */
#define get_defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) #define defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT)
#define get_defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) #define defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT)
/* /*
* destructor * destructor
...@@ -323,7 +323,7 @@ static struct hda_gnode *parse_output_jack(struct hda_codec *codec, ...@@ -323,7 +323,7 @@ static struct hda_gnode *parse_output_jack(struct hda_codec *codec,
if (! (node->pin_caps & AC_PINCAP_OUT)) if (! (node->pin_caps & AC_PINCAP_OUT))
continue; continue;
if (jack_type >= 0) { if (jack_type >= 0) {
if (jack_type != get_defcfg_type(node)) if (jack_type != defcfg_type(node))
continue; continue;
if (node->wid_caps & AC_WCAP_DIGITAL) if (node->wid_caps & AC_WCAP_DIGITAL)
continue; /* skip SPDIF */ continue; /* skip SPDIF */
...@@ -418,8 +418,8 @@ static int capture_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc ...@@ -418,8 +418,8 @@ static int capture_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc
*/ */
static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl) static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl)
{ {
unsigned int location = get_defcfg_location(node); unsigned int location = defcfg_location(node);
switch (get_defcfg_type(node)) { switch (defcfg_type(node)) {
case AC_JACK_LINE_IN: case AC_JACK_LINE_IN:
if ((location & 0x0f) == AC_JACK_LOC_FRONT) if ((location & 0x0f) == AC_JACK_LOC_FRONT)
return "Front Line"; return "Front Line";
......
...@@ -1458,7 +1458,7 @@ static struct pci_device_id azx_ids[] = { ...@@ -1458,7 +1458,7 @@ static struct pci_device_id azx_ids[] = {
{ 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ESB2 */ { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ESB2 */
{ 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ATI SB450 */ { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ATI SB450 */
{ 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* VIA VT8251/VT8237A */ { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* VIA VT8251/VT8237A */
{ 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ULI */ { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ALI 5461? */
{ 0, } { 0, }
}; };
MODULE_DEVICE_TABLE(pci, azx_ids); MODULE_DEVICE_TABLE(pci, azx_ids);
......
...@@ -130,7 +130,7 @@ struct hda_board_config { ...@@ -130,7 +130,7 @@ struct hda_board_config {
unsigned short pci_subdevice; unsigned short pci_subdevice;
}; };
int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config *tbl); int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl);
int snd_hda_add_new_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew); int snd_hda_add_new_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew);
/* /*
...@@ -158,4 +158,35 @@ struct hda_bus_unsolicited { ...@@ -158,4 +158,35 @@ struct hda_bus_unsolicited {
struct work_struct work; struct work_struct work;
}; };
/*
* Helper for automatic ping configuration
*/
enum {
AUTO_PIN_MIC,
AUTO_PIN_FRONT_MIC,
AUTO_PIN_LINE,
AUTO_PIN_FRONT_LINE,
AUTO_PIN_CD,
AUTO_PIN_AUX,
AUTO_PIN_LAST
};
struct auto_pin_cfg {
int line_outs;
hda_nid_t line_out_pins[4]; /* sorted in the order of Front/Surr/CLFE/Side */
hda_nid_t hp_pin;
hda_nid_t input_pins[AUTO_PIN_LAST];
hda_nid_t dig_out_pin;
hda_nid_t dig_in_pin;
};
#define get_defcfg_connect(cfg) ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT)
#define get_defcfg_association(cfg) ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT)
#define get_defcfg_location(cfg) ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT)
#define get_defcfg_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE)
#define get_defcfg_device(cfg) ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT)
int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg);
#endif /* __SOUND_HDA_LOCAL_H */ #endif /* __SOUND_HDA_LOCAL_H */
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment