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

Commit f686c74c authored by Takashi Iwai's avatar Takashi Iwai
Browse files

Merge branch 'topic/hda' into for-linus

parents 7ec298df 50e3bbf9
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -94,7 +94,7 @@ ALC662/663/272
  3stack-dig	3-stack (2-channel) with SPDIF
  3stack-6ch	 3-stack (6-channel)
  3stack-6ch-dig 3-stack (6-channel) with SPDIF
  6stack-dig	 6-stack with SPDIF
  5stack-dig	 5-stack with SPDIF
  lenovo-101e	 Lenovo laptop
  eeepc-p701	ASUS Eeepc P701
  eeepc-ep20	ASUS Eeepc EP20
+84 −13
Original line number Diff line number Diff line
@@ -307,6 +307,12 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
}
EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);

static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
				hda_nid_t *conn_list, int max_conns);
static bool add_conn_list(struct snd_array *array, hda_nid_t nid);
static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst,
			  hda_nid_t *src, int len);

/**
 * snd_hda_get_connections - get connection list
 * @codec: the HDA codec
@@ -321,6 +327,43 @@ EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);
 */
int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
			     hda_nid_t *conn_list, int max_conns)
{
	struct snd_array *array = &codec->conn_lists;
	int i, len, old_used;
	hda_nid_t list[HDA_MAX_CONNECTIONS];

	/* look up the cached results */
	for (i = 0; i < array->used; ) {
		hda_nid_t *p = snd_array_elem(array, i);
		len = p[1];
		if (nid == *p)
			return copy_conn_list(nid, conn_list, max_conns,
					      p + 2, len);
		i += len + 2;
	}

	len = _hda_get_connections(codec, nid, list, HDA_MAX_CONNECTIONS);
	if (len < 0)
		return len;

	/* add to the cache */
	old_used = array->used;
	if (!add_conn_list(array, nid) || !add_conn_list(array, len))
		goto error_add;
	for (i = 0; i < len; i++)
		if (!add_conn_list(array, list[i]))
			goto error_add;

	return copy_conn_list(nid, conn_list, max_conns, list, len);
		
 error_add:
	array->used = old_used;
	return -ENOMEM;
}
EXPORT_SYMBOL_HDA(snd_hda_get_connections);

static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
			     hda_nid_t *conn_list, int max_conns)
{
	unsigned int parm;
	int i, conn_len, conns;
@@ -417,8 +460,28 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
	}
	return conns;
}
EXPORT_SYMBOL_HDA(snd_hda_get_connections);

static bool add_conn_list(struct snd_array *array, hda_nid_t nid)
{
	hda_nid_t *p = snd_array_new(array);
	if (!p)
		return false;
	*p = nid;
	return true;
}

static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst,
			  hda_nid_t *src, int len)
{
	if (len > max_dst) {
		snd_printk(KERN_ERR "hda_codec: "
			   "Too many connections %d for NID 0x%x\n",
			   len, nid);
		return -EINVAL;
	}
	memcpy(dst, src, len * sizeof(hda_nid_t));
	return len;
}

/**
 * snd_hda_queue_unsol_event - add an unsolicited event to queue
@@ -1019,6 +1082,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
	list_del(&codec->list);
	snd_array_free(&codec->mixers);
	snd_array_free(&codec->nids);
	snd_array_free(&codec->conn_lists);
	codec->bus->caddr_tbl[codec->addr] = NULL;
	if (codec->patch_ops.free)
		codec->patch_ops.free(codec);
@@ -1079,6 +1143,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
	snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
	snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
	snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
	snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64);
	if (codec->bus->modelname) {
		codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
		if (!codec->modelname) {
@@ -2556,7 +2621,7 @@ static unsigned int convert_to_spdif_status(unsigned short val)
static void set_dig_out(struct hda_codec *codec, hda_nid_t nid,
			int verb, int val)
{
	hda_nid_t *d;
	const hda_nid_t *d;

	snd_hda_codec_write_cache(codec, nid, 0, verb, val);
	d = codec->slave_dig_outs;
@@ -3807,7 +3872,8 @@ EXPORT_SYMBOL_HDA(snd_hda_check_board_codec_sid_config);
 *
 * Returns 0 if successful, or a negative error code.
 */
int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
int snd_hda_add_new_ctls(struct hda_codec *codec,
			 const struct snd_kcontrol_new *knew)
{
	int err;

@@ -3950,7 +4016,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
				 struct hda_loopback_check *check,
				 hda_nid_t nid)
{
	struct hda_amp_list *p;
	const struct hda_amp_list *p;
	int ch, v;

	if (!check->amplist)
@@ -4118,7 +4184,7 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
				    -1);
	snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
	if (codec->slave_dig_outs) {
		hda_nid_t *d;
		const hda_nid_t *d;
		for (d = codec->slave_dig_outs; *d; d++)
			snd_hda_codec_setup_stream(codec, *d, stream_tag, 0,
						   format);
@@ -4133,7 +4199,7 @@ static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid)
{
	snd_hda_codec_cleanup_stream(codec, nid);
	if (codec->slave_dig_outs) {
		hda_nid_t *d;
		const hda_nid_t *d;
		for (d = codec->slave_dig_outs; *d; d++)
			snd_hda_codec_cleanup_stream(codec, *d);
	}
@@ -4280,7 +4346,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
				     unsigned int format,
				     struct snd_pcm_substream *substream)
{
	hda_nid_t *nids = mout->dac_nids;
	const hda_nid_t *nids = mout->dac_nids;
	int chs = substream->runtime->channels;
	int i;

@@ -4335,7 +4401,7 @@ EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_prepare);
int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
				     struct hda_multi_out *mout)
{
	hda_nid_t *nids = mout->dac_nids;
	const hda_nid_t *nids = mout->dac_nids;
	int i;

	for (i = 0; i < mout->num_dacs; i++)
@@ -4360,7 +4426,7 @@ EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_cleanup);
 * Helper for automatic pin configuration
 */

static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list)
static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list)
{
	for (; *list; list++)
		if (*list == nid)
@@ -4441,7 +4507,7 @@ static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
 */
int snd_hda_parse_pin_def_config(struct hda_codec *codec,
				 struct auto_pin_cfg *cfg,
				 hda_nid_t *ignore_nids)
				 const hda_nid_t *ignore_nids)
{
	hda_nid_t nid, end_nid;
	short seq, assoc_line_out, assoc_speaker;
@@ -4632,10 +4698,13 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
	/*
	 * debug prints of the parsed results
	 */
	snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
	snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
		   cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],
		   cfg->line_out_pins[2], cfg->line_out_pins[3],
		   cfg->line_out_pins[4]);
		   cfg->line_out_pins[4],
		   cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" :
		   (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ?
		    "speaker" : "line"));
	snd_printd("   speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
		   cfg->speaker_outs, cfg->speaker_pins[0],
		   cfg->speaker_pins[1], cfg->speaker_pins[2],
@@ -4986,6 +5055,8 @@ static const char *get_jack_default_name(struct hda_codec *codec, hda_nid_t nid,
		return "Line-out";
	case SND_JACK_HEADSET:
		return "Headset";
	case SND_JACK_VIDEOOUT:
		return "HDMI/DP";
	default:
		return "Misc";
	}
+3 −1
Original line number Diff line number Diff line
@@ -825,12 +825,14 @@ struct hda_codec {
	struct hda_cache_rec amp_cache;	/* cache for amp access */
	struct hda_cache_rec cmd_cache;	/* cache for other commands */

	struct snd_array conn_lists;	/* connection-list array */

	struct mutex spdif_mutex;
	struct mutex control_mutex;
	unsigned int spdif_status;	/* IEC958 status bits */
	unsigned short spdif_ctls;	/* SPDIF control bits */
	unsigned int spdif_in_enable;	/* SPDIF input enable? */
	hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
	const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
	struct snd_array init_pins;	/* initial (BIOS) pin configurations */
	struct snd_array driver_pins;	/* pin configs set by codec parser */
	struct snd_array cvt_setups;	/* audio convert setups */
+36 −2
Original line number Diff line number Diff line
@@ -126,6 +126,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
			 "{Intel, ICH10},"
			 "{Intel, PCH},"
			 "{Intel, CPT},"
			 "{Intel, PPT},"
			 "{Intel, PBG},"
			 "{Intel, SCH},"
			 "{ATI, SB450},"
@@ -1091,7 +1092,13 @@ static void azx_init_pci(struct azx *chip)
				? "Failed" : "OK");
		}
		break;

	default:
		/* AMD Hudson needs the similar snoop, as it seems... */
		if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
			update_pci_byte(chip->pci,
				ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR,
				0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP);
		break;
        }
}

@@ -1446,6 +1453,17 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
		}
	}

	/* AMD chipsets often cause the communication stalls upon certain
	 * sequence like the pin-detection.  It seems that forcing the synced
	 * access works around the stall.  Grrr...
	 */
	if (chip->pci->vendor == PCI_VENDOR_ID_AMD ||
	    chip->pci->vendor == PCI_VENDOR_ID_ATI) {
		snd_printk(KERN_INFO SFX "Enable sync_write for AMD chipset\n");
		chip->bus->sync_write = 1;
		chip->bus->allow_bus_reset = 1;
	}

	/* Then create codec instances */
	for (c = 0; c < max_slots; c++) {
		if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
@@ -2349,9 +2367,16 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
	/* Check VIA/ATI HD Audio Controller exist */
	switch (chip->driver_type) {
	case AZX_DRIVER_VIA:
	case AZX_DRIVER_ATI:
		/* Use link position directly, avoid any transfer problem. */
		return POS_FIX_VIACOMBO;
	case AZX_DRIVER_ATI:
		/* ATI chipsets don't work well with position-buffer */
		return POS_FIX_LPIB;
	case AZX_DRIVER_GENERIC:
		/* AMD chipsets also don't work with position-buffer */
		if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
			return POS_FIX_LPIB;
		break;
	}

	return POS_FIX_AUTO;
@@ -2549,6 +2574,13 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
				gcap &= ~ICH6_GCAP_64OK;
			pci_dev_put(p_smbus);
		}
	} else {
		/* FIXME: not sure whether this is really needed, but
		 * Hudson isn't stable enough for allowing everything...
		 * let's check later again.
		 */
		if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
			gcap &= ~ICH6_GCAP_64OK;
	}

	/* disable 64bit DMA address for Teradici */
@@ -2759,6 +2791,8 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
	{ PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH },
	/* PBG */
	{ PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH },
	/* Panther Point */
	{ PCI_DEVICE(0x8086, 0x1e20), .driver_data = AZX_DRIVER_PCH },
	/* SCH */
	{ PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
	/* Generic Intel */
+11 −5
Original line number Diff line number Diff line
@@ -267,11 +267,11 @@ enum { HDA_DIG_NONE, HDA_DIG_EXCLUSIVE, HDA_DIG_ANALOG_DUP }; /* dig_out_used */

struct hda_multi_out {
	int num_dacs;		/* # of DACs, must be more than 1 */
	hda_nid_t *dac_nids;	/* DAC list */
	const hda_nid_t *dac_nids;	/* DAC list */
	hda_nid_t hp_nid;	/* optional DAC for HP, 0 when not exists */
	hda_nid_t extra_out_nid[3];	/* optional DACs, 0 when not exists */
	hda_nid_t dig_out_nid;	/* digital out audio widget */
	hda_nid_t *slave_dig_outs;
	const hda_nid_t *slave_dig_outs;
	int max_channels;	/* currently supported analog channels */
	int dig_out_used;	/* current usage of digital out (HDA_DIG_XXX) */
	int no_share_stream;	/* don't share a stream with multiple pins */
@@ -347,7 +347,7 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
                               int num_configs, const char * const *models,
                               const struct snd_pci_quirk *tbl);
int snd_hda_add_new_ctls(struct hda_codec *codec,
			 struct snd_kcontrol_new *knew);
			 const struct snd_kcontrol_new *knew);

/*
 * unsolicited event handler
@@ -443,7 +443,7 @@ struct auto_pin_cfg {

int snd_hda_parse_pin_def_config(struct hda_codec *codec,
				 struct auto_pin_cfg *cfg,
				 hda_nid_t *ignore_nids);
				 const hda_nid_t *ignore_nids);

/* amp values */
#define AMP_IN_MUTE(idx)	(0x7080 | ((idx)<<8))
@@ -493,6 +493,12 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);
u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);

static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
{
	return (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT) &&
		(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP);
}

/* flags for hda_nid_item */
#define HDA_NID_ITEM_AMP	(1<<0)

@@ -567,7 +573,7 @@ struct hda_amp_list {
};

struct hda_loopback_check {
	struct hda_amp_list *amplist;
	const struct hda_amp_list *amplist;
	int power_on;
};

Loading