diff options
author | Takashi Iwai <tiwai@suse.de> | 2005-06-13 14:16:38 +0200 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2005-06-22 12:28:59 +0200 |
commit | e9edcee061a80181f0d6e7cada07e1898c14718e (patch) | |
tree | b8ce3f0430ef436cbfbe98736f1ef6bc86fd8c94 | |
parent | b636a71d9b9525ee51ca872d461817a5bd5c39fd (diff) |
[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: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | Documentation/sound/alsa/ALSA-Configuration.txt | 4 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 103 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.c | 10 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 2 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 33 | ||||
-rw-r--r-- | sound/pci/hda/patch_cmedia.c | 236 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 1909 |
7 files changed, 1205 insertions, 1092 deletions
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index ced9a6eac56..104a994b828 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -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 w810 3-jack z71v 3-jack (HP shared SPDIF) + asus 3-jack + uniwill 3-jack + F1734 2-jack CMI9880 minimal 3-jack in back @@ -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_dig 6-jack in back, 2-jack in front, SPDIF I/O 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 position_fix=1 or 2. position_fix=1 will use the SD_LPIB diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f62d1d5eb7f..e2cf0238728 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1520,9 +1520,9 @@ int snd_hda_build_pcms(struct hda_bus *bus) * * 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) { 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 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 /* * power management diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index bfbeff2e0d0..2d046abb591 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -68,8 +68,8 @@ struct hda_gspec { /* * 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 get_defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) +#define defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) +#define defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) /* * destructor @@ -323,7 +323,7 @@ static struct hda_gnode *parse_output_jack(struct hda_codec *codec, if (! (node->pin_caps & AC_PINCAP_OUT)) continue; if (jack_type >= 0) { - if (jack_type != get_defcfg_type(node)) + if (jack_type != defcfg_type(node)) continue; if (node->wid_caps & AC_WCAP_DIGITAL) continue; /* skip SPDIF */ @@ -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) { - unsigned int location = get_defcfg_location(node); - switch (get_defcfg_type(node)) { + unsigned int location = defcfg_location(node); + switch (defcfg_type(node)) { case AC_JACK_LINE_IN: if ((location & 0x0f) == AC_JACK_LOC_FRONT) return "Front Line"; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d8984919742..5e0cca36ed5 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1458,7 +1458,7 @@ static struct pci_device_id azx_ids[] = { { 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 */ { 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, } }; MODULE_DEVICE_TABLE(pci, azx_ids); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index b8fbbc4901d..810cfd2d9bb 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -130,7 +130,7 @@ struct hda_board_config { 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); /* @@ -158,4 +158,35 @@ struct hda_bus_unsolicited { 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 */ diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 087230ca20a..2d6e3e3d0a3 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -51,6 +51,7 @@ struct cmi_spec { /* playback */ struct hda_multi_out multiout; hda_nid_t dac_nids[4]; /* NID for each DAC */ + int num_dacs; /* capture */ hda_nid_t *adc_nids; @@ -77,6 +78,19 @@ struct cmi_spec { struct hda_verb multi_init[9]; /* 2 verbs for each pin + terminator */ }; +/* amp values */ +#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) +#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) +#define AMP_OUT_MUTE 0xb080 +#define AMP_OUT_UNMUTE 0xb000 +#define AMP_OUT_ZERO 0xb000 +/* pinctl values */ +#define PIN_IN 0x20 +#define PIN_VREF80 0x24 +#define PIN_VREF50 0x21 +#define PIN_OUT 0x40 +#define PIN_HP 0xc0 + /* * input MUX */ @@ -114,9 +128,9 @@ static int cmi_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucon /* 3-stack / 2 channel */ static struct hda_verb cmi9880_ch2_init[] = { /* set line-in PIN for input */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* set mic PIN for input, also enable vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* route front PCM (DAC1) to HP */ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, {} @@ -125,9 +139,9 @@ static struct hda_verb cmi9880_ch2_init[] = { /* 3-stack / 6 channel */ static struct hda_verb cmi9880_ch6_init[] = { /* set line-in PIN for output */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* set mic PIN for output */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* route front PCM (DAC1) to HP */ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, {} @@ -136,9 +150,9 @@ static struct hda_verb cmi9880_ch6_init[] = { /* 3-stack+front / 8 channel */ static struct hda_verb cmi9880_ch8_init[] = { /* set line-in PIN for output */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* set mic PIN for output */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* route rear-surround PCM (DAC4) to HP */ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 }, {} @@ -281,27 +295,27 @@ static hda_nid_t cmi9880_adc_nids[2] = { */ static struct hda_verb cmi9880_basic_init[] = { /* port-D for line out (rear panel) */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* route front PCM to HP */ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, /* port-A for surround (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* route front mic to ADC1/2 */ { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, @@ -310,27 +324,27 @@ static struct hda_verb cmi9880_basic_init[] = { static struct hda_verb cmi9880_allout_init[] = { /* port-D for line out (rear panel) */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* route front PCM to HP */ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, /* port-A for side (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, /* port-C for surround (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* route front mic to ADC1/2 */ { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, @@ -365,101 +379,9 @@ static int cmi9880_build_controls(struct hda_codec *codec) return 0; } -#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_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE) - -/* get all pin default configuration in def_conf */ -static int cmi9880_get_pin_def_config(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - hda_nid_t nid, nid_start; - int i = 0, nodes; - - 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; - /* read all default configuration for pin complex */ - if (wid_type == AC_WID_PIN) { - spec->pin_nid[i] = nid; - spec->def_conf[i] = - snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); - i++; - } - } - spec->pin_def_confs = i; - return 0; -} - -/* get a pin default configuration of nid in def_conf */ -static unsigned int cmi9880_get_def_config(struct hda_codec *codec, hda_nid_t nid) -{ - struct cmi_spec *spec = codec->spec; - int i = 0; - - while (spec->pin_nid[i] != nid && i < spec->pin_def_confs) - i++; - if (i == spec->pin_def_confs) - return (unsigned int) -1; - else - return spec->def_conf[i]; -} - -/* decide what pins to use for multichannel playback */ -static int cmi9880_get_multich_pins(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - int i, j, pins, seq[4]; - int max_channel = 0; - unsigned int def_conf, sequence; - hda_nid_t nid; - - memset(spec->multich_pin, 0, sizeof(spec->multich_pin)); - for (pins = 0, i = 0; i < spec->pin_def_confs && pins < 4; i++) { - def_conf = spec->def_conf[i]; - /* skip pin not connected */ - if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) - continue; - /* get the sequence if association == 1 */ - /* the other pins have association = 0, incorrect in spec 1.0 */ - if (get_defcfg_association(def_conf) == 1) { - sequence = get_defcfg_sequence(def_conf); - seq[pins] = sequence; - spec->multich_pin[pins] = spec->pin_nid[i]; - pins++; // ready for next slot - max_channel += 2; - } - } - /* sort by sequence, data collected here will be for Windows */ - for (i = 0; i < pins; i++) { - for (j = i + 1; j < pins; j++) { - if (seq[j] < seq[i]) { - sequence = seq[j]; - nid = spec->multich_pin[j]; - seq[j] = seq[i]; - spec->multich_pin[j] = spec->multich_pin[i]; - seq[i] = sequence; - spec->multich_pin[i] = nid; - } - } - } - /* the pin assignment is for front, C/LFE, surround and back */ - if (max_channel >= 6) { - hda_nid_t temp; - /* exchange pin of C/LFE and surround */ - temp = spec->multich_pin[1]; - spec->multich_pin[1] = spec->multich_pin[2]; - spec->multich_pin[2] = temp; - } - return max_channel; -} - /* fill in the multi_dac_nids table, which will decide which audio widget to use for each channel */ -static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec) +static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { struct cmi_spec *spec = codec->spec; hda_nid_t nid; @@ -470,32 +392,34 @@ static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec) memset(spec->dac_nids, 0, sizeof(spec->dac_nids)); memset(assigned, 0, sizeof(assigned)); /* check the pins we found */ - for (i = 0; i < spec->multiout.max_channels / 2; i++) { - nid = spec->multich_pin[i]; + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; /* nid 0x0b~0x0e is hardwired to audio widget 0x3~0x6 */ - if (nid <= 0x0e && nid >= 0x0b) { - spec->dac_nids[i] = nid - 0x08; + if (nid >= 0x0b && nid <= 0x0e) { + spec->dac_nids[i] = (nid - 0x0b) + 0x03; assigned[nid - 0x0b] = 1; } } /* left pin can be connect to any audio widget */ - for (i = 0; i < spec->multiout.max_channels / 2; i++) { - if (!assigned[i]) { - /* search for an empty channel */ - /* I should also check the pin type */ - for (j = 0; j < ARRAY_SIZE(spec->dac_nids); j++) - if (! spec->dac_nids[j]) { - spec->dac_nids[j] = i + 3; - assigned[i] = 1; - break; - } + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + if (nid <= 0x0e) + continue; + /* search for an empty channel */ + for (j = 0; j < cfg->line_outs; j++) { + if (! assigned[j]) { + spec->dac_nids[i] = i + 0x03; + assigned[j] = 1; + break; + } } } + spec->num_dacs = cfg->line_outs; return 0; } /* create multi_init table, which is used for multichannel initialization */ -static int cmi9880_fill_multi_init(struct hda_codec *codec) +static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { struct cmi_spec *spec = codec->spec; hda_nid_t nid; @@ -503,29 +427,26 @@ static int cmi9880_fill_multi_init(struct hda_codec *codec) /* clear the table, only one c-media dac assumed here */ memset(spec->multi_init, 0, sizeof(spec->multi_init)); - for (j = 0, i = 0; i < spec->multiout.max_channels / 2; i++) { + for (j = 0, i = 0; i < cfg->line_outs; i++) { hda_nid_t conn[4]; - nid = spec->multich_pin[i]; + nid = cfg->line_out_pins[i]; /* set as output */ spec->multi_init[j].nid = nid; spec->multi_init[j].verb = AC_VERB_SET_PIN_WIDGET_CONTROL; - spec->multi_init[j].param = 0xc0; + spec->multi_init[j].param = PIN_OUT; j++; - /* nid 0x0f,0x10,0x1f,0x20 are needed to set connection */ - switch (nid) { - case 0x0f: - case 0x10: - case 0x1f: - case 0x20: + if (nid > 0x0e) { /* set connection */ spec->multi_init[j].nid = nid; spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL; + spec->multi_init[j].param = 0; /* find the index in connect list */ len = snd_hda_get_connections(codec, nid, conn, 4); for (k = 0; k < len; k++) - if (conn[k] == spec->dac_nids[i]) + if (conn[k] == spec->dac_nids[i]) { + spec->multi_init[j].param = j; break; - spec->multi_init[j].param = k < len ? k : 0; + } j++; break; } @@ -759,6 +680,7 @@ static int patch_cmi9880(struct hda_codec *codec) /* copy default DAC NIDs */ memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids)); + spec->num_dacs = 4; switch (spec->board_config) { case CMI_MINIMAL: @@ -795,18 +717,16 @@ static int patch_cmi9880(struct hda_codec *codec) { unsigned int port_e, port_f, port_g, port_h; unsigned int port_spdifi, port_spdifo; - int max_channels; + struct auto_pin_cfg cfg; + /* collect pin default configuration */ - cmi9880_get_pin_def_config(codec); - port_e = cmi9880_get_def_config(codec, 0x0f); - port_f = cmi9880_get_def_config(codec, 0x10); - port_g = cmi9880_get_def_config(codec, 0x1f); - port_h = cmi9880_get_def_config(codec, 0x20); - port_spdifi = cmi9880_get_def_config(codec, 0x13); - port_spdifo = cmi9880_get_def_config(codec, 0x12); + port_e = snd_hda_codec_read(codec, 0x0f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + port_f = snd_hda_codec_read(codec, 0x10, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); spec->front_panel = 1; if (get_defcfg_connect(port_e) == AC_JACK_PORT_NONE || get_defcfg_connect(port_f) == AC_JACK_PORT_NONE) { + port_g = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + port_h = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); spec->surr_switch = 1; /* no front panel */ if (get_defcfg_connect(port_g) == AC_JACK_PORT_NONE || @@ -824,24 +744,26 @@ static int patch_cmi9880(struct hda_codec *codec) spec->multiout.max_channels = cmi9880_channel_modes[0].channels; } else { spec->input_mux = &cmi9880_basic_mux; + port_spdifi = snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + port_spdifo = snd_hda_codec_read(codec, 0x12, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); if (get_defcfg_connect(port_spdifo) != AC_JACK_PORT_NONE) spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; if (get_defcfg_connect(port_spdifi) != AC_JACK_PORT_NONE) spec->dig_in_nid = CMI_DIG_IN_NID; spec->multiout.max_channels = 8; } - max_channels = cmi9880_get_multich_pins(codec); - if (max_channels > 0) { - spec->multiout.max_channels = max_channels; - cmi9880_fill_multi_dac_nids(codec); - cmi9880_fill_multi_init(codec); + snd_hda_parse_pin_def_config(codec, &cfg); + if (cfg.line_outs) { + spec->multiout.max_channels = cfg.line_outs * 2; + cmi9880_fill_multi_dac_nids(codec, &cfg); + cmi9880_fill_multi_init(codec, &cfg); } else snd_printd("patch_cmedia: cannot detect association in defcfg\n"); break; } } - spec->multiout.num_dacs = 4; + spec->multiout.num_dacs = spec->num_dacs; spec->multiout.dac_nids = spec->dac_nids; spec->adc_nids = cmi9880_adc_nids; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ce280c006be..9edd558d6bd 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -39,13 +39,16 @@ enum { ALC880_5ST_DIG, ALC880_W810, ALC880_Z71V, - ALC880_TEST, + ALC880_AUTO, ALC880_6ST_DIG, ALC880_F1734, ALC880_ASUS, ALC880_ASUS_DIG, ALC880_ASUS_W1V, ALC880_UNIWILL_DIG, +#ifdef CONFIG_SND_DEBUG + ALC880_TEST, +#endif ALC880_MODEL_LAST /* last tag */ }; @@ -56,19 +59,28 @@ enum { ALC260_MODEL_LAST /* last tag */ }; +/* amp values */ +#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) +#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) +#define AMP_OUT_MUTE 0xb080 +#define AMP_OUT_UNMUTE 0xb000 +#define AMP_OUT_ZERO 0xb000 +/* pinctl values */ +#define PIN_IN 0x20 +#define PIN_VREF80 0x24 +#define PIN_VREF50 0x21 +#define PIN_OUT 0x40 +#define PIN_HP 0xc0 + struct alc_spec { /* codec parameterization */ - unsigned int front_panel: 1; /* indicates the board has a front panel; - * not referred currently for any purpose, - * though... - */ - - snd_kcontrol_new_t *mixers[2]; /* mixer arrays */ + snd_kcontrol_new_t *mixers[3]; /* mixer arrays */ unsigned int num_mixers; - struct hda_verb *init_verbs; /* initialization verbs - * don't forget NULL termination! - */ + const struct hda_verb *init_verbs[3]; /* initialization verbs + * don't forget NULL termination! + */ + unsigned int num_init_verbs; char *stream_name_analog; /* analog PCM stream */ struct hda_pcm_stream *stream_analog_playback; @@ -101,96 +113,14 @@ struct alc_spec { struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */ struct semaphore bind_mutex; /* for bound controls */ -}; - -/* DAC/ADC assignment */ - -static hda_nid_t alc880_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x05, 0x04, 0x03 -}; - -static hda_nid_t alc880_6st_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x03, 0x04, 0x05 -}; - -static hda_nid_t alc880_w810_dac_nids[3] = { - /* front, rear/surround, clfe */ - 0x02, 0x03, 0x04 -}; - -static hda_nid_t alc880_z71v_dac_nids[1] = { - /* front only? */ - 0x02 -}; - -#if 0 -/* The datasheet says the node 0x07 is connected from inputs, - * but it shows zero connection in the real implementation on some devices. - */ -static hda_nid_t alc880_adc_nids[3] = { - /* ADC0-2 */ - 0x07, 0x08, 0x09, -}; -#else -static hda_nid_t alc880_adc_nids[2] = { - /* ADC1-2 */ - 0x08, 0x09, -}; -#endif - -#define ALC880_DIGOUT_NID 0x06 -#define ALC880_DIGIN_NID 0x0a - -static hda_nid_t alc260_dac_nids[1] = { - /* front */ - 0x02, -}; - -static hda_nid_t alc260_adc_nids[1] = { - /* ADC0 */ - 0x04, -}; - -static hda_nid_t alc260_hp_adc_nids[1] = { - /* ADC1 */ - 0x05, -}; -#define ALC260_DIGOUT_NID 0x03 -#define ALC260_DIGIN_NID 0x06 - -static struct hda_input_mux alc880_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x3 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, + /* dynamic controls, init_verbs and input_mux */ + struct auto_pin_cfg autocfg; + unsigned int num_kctl_alloc, num_kctl_used; + snd_kcontrol_new_t *kctl_alloc; + struct hda_input_mux private_imux; }; -//pshou 05/24/05 -static struct hda_input_mux alc880_6stack_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static struct hda_input_mux alc260_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; /* * input MUX handling @@ -221,6 +151,7 @@ static int alc_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucon spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]); } + /* * channel mode setting */ @@ -229,133 +160,6 @@ struct alc_channel_mode { const struct hda_verb *sequence; }; - -/* - * channel source setting (2/6 channel selection for 3-stack) - */ - -/* - * set the path ways for 2 channel output - * need to set the codec line out and mic 1 pin widgets to inputs - */ -static struct hda_verb alc880_threestack_ch2_init[] = { - /* set pin widget 1Ah (line in) for input */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* set pin widget 18h (mic1) for input, for mic also enable the vref */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* mute the output for Line In PW */ - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, - /* mute for Mic1 PW */ - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, - { } /* end */ -}; - -/* - * 6ch mode - * need to set the codec line out and mic 1 pin widgets to outputs - */ -static struct hda_verb alc880_threestack_ch6_init[] = { - /* set pin widget 1Ah (line in) for output */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* set pin widget 18h (mic1) for output */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* unmute the output for Line In PW */ - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 }, - /* unmute for Mic1 PW */ - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 }, - /* for rear channel output using Line In 1 - * set select widget connection (nid = 0x12) - to summer node - * for rear NID = 0x0f...offset 3 in connection list - */ - { 0x12, AC_VERB_SET_CONNECT_SEL, 0x3 }, - /* for Mic1 - retask for center/lfe */ - /* set select widget connection (nid = 0x10) - to summer node for - * front CLFE NID = 0x0e...offset 2 in connection list - */ - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x2 }, - { } /* end */ -}; - -static struct alc_channel_mode alc880_threestack_modes[2] = { - { 2, alc880_threestack_ch2_init }, - { 6, alc880_threestack_ch6_init }, -}; - - -/* - * channel source setting (6/8 channel selection for 5-stack) - */ - -/* set the path ways for 6 channel output - * need to set the codec line out and mic 1 pin widgets to inputs - */ -static struct hda_verb alc880_fivestack_ch6_init[] = { - /* set pin widget 1Ah (line in) for input */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* mute the output for Line In PW */ - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, - { } /* end */ -}; - -/* need to set the codec line out and mic 1 pin widgets to outputs */ -static struct hda_verb alc880_fivestack_ch8_init[] = { - /* set pin widget 1Ah (line in) for output */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* unmute the output for Line In PW */ - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 }, - /* output for surround channel output using Line In 1 */ - /* set select widget connection (nid = 0x12) - to summer node - * for surr_rear NID = 0x0d...offset 1 in connection list - */ - { 0x12, AC_VERB_SET_CONNECT_SEL, 0x1 }, - { } /* end */ -}; - -static struct alc_channel_mode alc880_fivestack_modes[2] = { - { 6, alc880_fivestack_ch6_init }, - { 8, alc880_fivestack_ch8_init }, -}; - -/* - * channel source setting for W810 system - * - * W810 has rear IO for: - * Front (DAC 02) - * Surround (DAC 03) - * Center/LFE (DAC 04) - * Digital out (06) - * - * The system also has a pair of internal speakers, and a headphone jack. - * These are both connected to Line2 on the codec, hence to DAC 02. - * - * There is a variable resistor to control the speaker or headphone - * volume. This is a hardware-only device without a software API. - * - * Plugging headphones in will disable the internal speakers. This is - * implemented in hardware, not via the driver using jack sense. In - * a similar fashion, plugging into the rear socket marked "front" will - * disable both the speakers and headphones. - * - * For input, there's a microphone jack, and an "audio in" jack. - * These may not do anything useful with this driver yet, because I - * haven't setup any initialization verbs for these yet... - */ - -static struct alc_channel_mode alc880_w810_modes[1] = { - { 6, NULL } -}; - -static struct alc_channel_mode alc880_z71v_modes[1] = { - { 2, NULL } -}; - -//pshou 05/19/05 -static struct alc_channel_mode alc880_sixstack_modes[1] = { - { 8, NULL }, -}; - -/* - */ static int alc880_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); @@ -478,67 +282,75 @@ static int alc_bind_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u #define ALC_BIND_MUTE(xname,nid,indices,dir) ALC_BIND_MUTE_MONO(xname,nid,3,indices,dir) + /* + * ALC880 3-stack model + * + * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e) + * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18, F-Mic = 0x1b + * HP = 0x19 */ -/* 3-stack mode - * Pin assignment: Front=0x14, Line-In/Rear=0x1a, Mic/CLFE=0x18, F-Mic=0x1b - * HP=0x19 +static hda_nid_t alc880_dac_nids[4] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x05, 0x04, 0x03 +}; + +static hda_nid_t alc880_adc_nids[3] = { + /* ADC0-2 */ + 0x07, 0x08, 0x09, +}; + +/* The datasheet says the node 0x07 is connected from inputs, + * but it shows zero connection in the real implementation on some devices. */ -static snd_kcontrol_new_t alc880_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Surround Playback Switch", 0x1a, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT) |