Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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
+101 −2
Original line number Diff line number Diff line
@@ -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
+5 −5
Original line number Diff line number Diff line
@@ -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";
+1 −1
Original line number Diff line number Diff line
@@ -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);
+32 −1
Original line number Diff line number Diff line
@@ -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 */
Loading