⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ac97_patch.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	scfg = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG);	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, scfg | 0x7000); /* select all codecs */	ac97->res_table = ad1819_restbl;	return 0;}static unsigned short patch_ad1881_unchained(struct snd_ac97 * ac97, int idx, unsigned short mask){	unsigned short val;	// test for unchained codec	snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, mask);	snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0000);	/* ID0C, ID1C, SDIE = off */	val = snd_ac97_read(ac97, AC97_VENDOR_ID2);	if ((val & 0xff40) != 0x5340)		return 0;	ac97->spec.ad18xx.unchained[idx] = mask;	ac97->spec.ad18xx.id[idx] = val;	ac97->spec.ad18xx.codec_cfg[idx] = 0x0000;	return mask;}static int patch_ad1881_chained1(struct snd_ac97 * ac97, int idx, unsigned short codec_bits){	static int cfg_bits[3] = { 1<<12, 1<<14, 1<<13 };	unsigned short val;		snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, cfg_bits[idx]);	snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0004);	// SDIE	val = snd_ac97_read(ac97, AC97_VENDOR_ID2);	if ((val & 0xff40) != 0x5340)		return 0;	if (codec_bits)		snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, codec_bits);	ac97->spec.ad18xx.chained[idx] = cfg_bits[idx];	ac97->spec.ad18xx.id[idx] = val;	ac97->spec.ad18xx.codec_cfg[idx] = codec_bits ? codec_bits : 0x0004;	return 1;}static void patch_ad1881_chained(struct snd_ac97 * ac97, int unchained_idx, int cidx1, int cidx2){	// already detected?	if (ac97->spec.ad18xx.unchained[cidx1] || ac97->spec.ad18xx.chained[cidx1])		cidx1 = -1;	if (ac97->spec.ad18xx.unchained[cidx2] || ac97->spec.ad18xx.chained[cidx2])		cidx2 = -1;	if (cidx1 < 0 && cidx2 < 0)		return;	// test for chained codecs	snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000,			     ac97->spec.ad18xx.unchained[unchained_idx]);	snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0002);		// ID1C	ac97->spec.ad18xx.codec_cfg[unchained_idx] = 0x0002;	if (cidx1 >= 0) {		if (cidx2 < 0)			patch_ad1881_chained1(ac97, cidx1, 0);		else if (patch_ad1881_chained1(ac97, cidx1, 0x0006))	// SDIE | ID1C			patch_ad1881_chained1(ac97, cidx2, 0);		else if (patch_ad1881_chained1(ac97, cidx2, 0x0006))	// SDIE | ID1C			patch_ad1881_chained1(ac97, cidx1, 0);	} else if (cidx2 >= 0) {		patch_ad1881_chained1(ac97, cidx2, 0);	}}static struct snd_ac97_build_ops patch_ad1881_build_ops = {#ifdef CONFIG_PM	.resume = ad18xx_resume#endif};static int patch_ad1881(struct snd_ac97 * ac97){	static const char cfg_idxs[3][2] = {		{2, 1},		{0, 2},		{0, 1}	};		// patch for Analog Devices	unsigned short codecs[3];	unsigned short val;	int idx, num;	val = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG);	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, val);	codecs[0] = patch_ad1881_unchained(ac97, 0, (1<<12));	codecs[1] = patch_ad1881_unchained(ac97, 1, (1<<14));	codecs[2] = patch_ad1881_unchained(ac97, 2, (1<<13));	if (! (codecs[0] || codecs[1] || codecs[2]))		goto __end;	for (idx = 0; idx < 3; idx++)		if (ac97->spec.ad18xx.unchained[idx])			patch_ad1881_chained(ac97, idx, cfg_idxs[idx][0], cfg_idxs[idx][1]);	if (ac97->spec.ad18xx.id[1]) {		ac97->flags |= AC97_AD_MULTI;		ac97->scaps |= AC97_SCAP_SURROUND_DAC;	}	if (ac97->spec.ad18xx.id[2]) {		ac97->flags |= AC97_AD_MULTI;		ac97->scaps |= AC97_SCAP_CENTER_LFE_DAC;	}      __end:	/* select all codecs */	snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);	/* check if only one codec is present */	for (idx = num = 0; idx < 3; idx++)		if (ac97->spec.ad18xx.id[idx])			num++;	if (num == 1) {		/* ok, deselect all ID bits */		snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0000);		ac97->spec.ad18xx.codec_cfg[0] = 			ac97->spec.ad18xx.codec_cfg[1] = 			ac97->spec.ad18xx.codec_cfg[2] = 0x0000;	}	/* required for AD1886/AD1885 combination */	ac97->ext_id = snd_ac97_read(ac97, AC97_EXTENDED_ID);	if (ac97->spec.ad18xx.id[0]) {		ac97->id &= 0xffff0000;		ac97->id |= ac97->spec.ad18xx.id[0];	}	ac97->build_ops = &patch_ad1881_build_ops;	return 0;}static const struct snd_kcontrol_new snd_ac97_controls_ad1885[] = {	AC97_SINGLE("Digital Mono Direct", AC97_AD_MISC, 11, 1, 0),	/* AC97_SINGLE("Digital Audio Mode", AC97_AD_MISC, 12, 1, 0), */ /* seems problematic */	AC97_SINGLE("Low Power Mixer", AC97_AD_MISC, 14, 1, 0),	AC97_SINGLE("Zero Fill DAC", AC97_AD_MISC, 15, 1, 0),	AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 9, 1, 1), /* inverted */	AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 8, 1, 1), /* inverted */};static const DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0);static int patch_ad1885_specific(struct snd_ac97 * ac97){	int err;	if ((err = patch_build_controls(ac97, snd_ac97_controls_ad1885, ARRAY_SIZE(snd_ac97_controls_ad1885))) < 0)		return err;	reset_tlv(ac97, "Headphone Playback Volume",		  db_scale_6bit_6db_max);	return 0;}static struct snd_ac97_build_ops patch_ad1885_build_ops = {	.build_specific = &patch_ad1885_specific,#ifdef CONFIG_PM	.resume = ad18xx_resume#endif};static int patch_ad1885(struct snd_ac97 * ac97){	patch_ad1881(ac97);	/* This is required to deal with the Intel D815EEAL2 */	/* i.e. Line out is actually headphone out from codec */	/* set default */	snd_ac97_write_cache(ac97, AC97_AD_MISC, 0x0404);	ac97->build_ops = &patch_ad1885_build_ops;	return 0;}static int patch_ad1886_specific(struct snd_ac97 * ac97){	reset_tlv(ac97, "Headphone Playback Volume",		  db_scale_6bit_6db_max);	return 0;}static struct snd_ac97_build_ops patch_ad1886_build_ops = {	.build_specific = &patch_ad1886_specific,#ifdef CONFIG_PM	.resume = ad18xx_resume#endif};static int patch_ad1886(struct snd_ac97 * ac97){	patch_ad1881(ac97);	/* Presario700 workaround */	/* for Jack Sense/SPDIF Register misetting causing */	snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, 0x0010);	ac97->build_ops = &patch_ad1886_build_ops;	return 0;}/* MISC bits (AD1888/AD1980/AD1985 register 0x76) */#define AC97_AD198X_MBC		0x0003	/* mic boost */#define AC97_AD198X_MBC_20	0x0000	/* +20dB */#define AC97_AD198X_MBC_10	0x0001	/* +10dB */#define AC97_AD198X_MBC_30	0x0002	/* +30dB */#define AC97_AD198X_VREFD	0x0004	/* VREF high-Z */#define AC97_AD198X_VREFH	0x0008	/* 0=2.25V, 1=3.7V */#define AC97_AD198X_VREF_0	0x000c	/* 0V (AD1985 only) */#define AC97_AD198X_VREF_MASK	(AC97_AD198X_VREFH | AC97_AD198X_VREFD)#define AC97_AD198X_VREF_SHIFT	2#define AC97_AD198X_SRU		0x0010	/* sample rate unlock */#define AC97_AD198X_LOSEL	0x0020	/* LINE_OUT amplifiers input select */#define AC97_AD198X_2MIC	0x0040	/* 2-channel mic select */#define AC97_AD198X_SPRD	0x0080	/* SPREAD enable */#define AC97_AD198X_DMIX0	0x0100	/* downmix mode: */					/*  0 = 6-to-4, 1 = 6-to-2 downmix */#define AC97_AD198X_DMIX1	0x0200	/* downmix mode: 1 = enabled */#define AC97_AD198X_HPSEL	0x0400	/* headphone amplifier input select */#define AC97_AD198X_CLDIS	0x0800	/* center/lfe disable */#define AC97_AD198X_LODIS	0x1000	/* LINE_OUT disable */#define AC97_AD198X_MSPLT	0x2000	/* mute split */#define AC97_AD198X_AC97NC	0x4000	/* AC97 no compatible mode */#define AC97_AD198X_DACZ	0x8000	/* DAC zero-fill mode *//* MISC 1 bits (AD1986 register 0x76) */#define AC97_AD1986_MBC		0x0003	/* mic boost */#define AC97_AD1986_MBC_20	0x0000	/* +20dB */#define AC97_AD1986_MBC_10	0x0001	/* +10dB */#define AC97_AD1986_MBC_30	0x0002	/* +30dB */#define AC97_AD1986_LISEL0	0x0004	/* LINE_IN select bit 0 */#define AC97_AD1986_LISEL1	0x0008	/* LINE_IN select bit 1 */#define AC97_AD1986_LISEL_MASK	(AC97_AD1986_LISEL1 | AC97_AD1986_LISEL0)#define AC97_AD1986_LISEL_LI	0x0000  /* LINE_IN pins as LINE_IN source */#define AC97_AD1986_LISEL_SURR	0x0004  /* SURROUND pins as LINE_IN source */#define AC97_AD1986_LISEL_MIC	0x0008  /* MIC_1/2 pins as LINE_IN source */#define AC97_AD1986_SRU		0x0010	/* sample rate unlock */#define AC97_AD1986_SOSEL	0x0020	/* SURROUND_OUT amplifiers input sel */#define AC97_AD1986_2MIC	0x0040	/* 2-channel mic select */#define AC97_AD1986_SPRD	0x0080	/* SPREAD enable */#define AC97_AD1986_DMIX0	0x0100	/* downmix mode: */					/*  0 = 6-to-4, 1 = 6-to-2 downmix */#define AC97_AD1986_DMIX1	0x0200	/* downmix mode: 1 = enabled */#define AC97_AD1986_CLDIS	0x0800	/* center/lfe disable */#define AC97_AD1986_SODIS	0x1000	/* SURROUND_OUT disable */#define AC97_AD1986_MSPLT	0x2000	/* mute split (read only 1) */#define AC97_AD1986_AC97NC	0x4000	/* AC97 no compatible mode (r/o 1) */#define AC97_AD1986_DACZ	0x8000	/* DAC zero-fill mode *//* MISC 2 bits (AD1986 register 0x70) */#define AC97_AD_MISC2		0x70	/* Misc Control Bits 2 (AD1986) */#define AC97_AD1986_CVREF0	0x0004	/* C/LFE VREF_OUT 2.25V */#define AC97_AD1986_CVREF1	0x0008	/* C/LFE VREF_OUT 0V */#define AC97_AD1986_CVREF2	0x0010	/* C/LFE VREF_OUT 3.7V */#define AC97_AD1986_CVREF_MASK \	(AC97_AD1986_CVREF2 | AC97_AD1986_CVREF1 | AC97_AD1986_CVREF0)#define AC97_AD1986_JSMAP	0x0020	/* Jack Sense Mapping 1 = alternate */#define AC97_AD1986_MMDIS	0x0080	/* Mono Mute Disable */#define AC97_AD1986_MVREF0	0x0400	/* MIC VREF_OUT 2.25V */#define AC97_AD1986_MVREF1	0x0800	/* MIC VREF_OUT 0V */#define AC97_AD1986_MVREF2	0x1000	/* MIC VREF_OUT 3.7V */#define AC97_AD1986_MVREF_MASK \	(AC97_AD1986_MVREF2 | AC97_AD1986_MVREF1 | AC97_AD1986_MVREF0)/* MISC 3 bits (AD1986 register 0x7a) */#define AC97_AD_MISC3		0x7a	/* Misc Control Bits 3 (AD1986) */#define AC97_AD1986_MMIX	0x0004	/* Mic Mix, left/right */#define AC97_AD1986_GPO		0x0008	/* General Purpose Out */#define AC97_AD1986_LOHPEN	0x0010	/* LINE_OUT headphone drive */#define AC97_AD1986_LVREF0	0x0100	/* LINE_OUT VREF_OUT 2.25V */#define AC97_AD1986_LVREF1	0x0200	/* LINE_OUT VREF_OUT 0V */#define AC97_AD1986_LVREF2	0x0400	/* LINE_OUT VREF_OUT 3.7V */#define AC97_AD1986_LVREF_MASK \	(AC97_AD1986_LVREF2 | AC97_AD1986_LVREF1 | AC97_AD1986_LVREF0)#define AC97_AD1986_JSINVA	0x0800	/* Jack Sense Invert SENSE_A */#define AC97_AD1986_LOSEL	0x1000	/* LINE_OUT amplifiers input select */#define AC97_AD1986_HPSEL0	0x2000	/* Headphone amplifiers */					/*   input select Surround DACs */#define AC97_AD1986_HPSEL1	0x4000	/* Headphone amplifiers input */					/*   select C/LFE DACs */#define AC97_AD1986_JSINVB	0x8000	/* Jack Sense Invert SENSE_B *//* Serial Config bits (AD1986 register 0x74) (incomplete) */#define AC97_AD1986_OMS0	0x0100	/* Optional Mic Selector bit 0 */#define AC97_AD1986_OMS1	0x0200	/* Optional Mic Selector bit 1 */#define AC97_AD1986_OMS2	0x0400	/* Optional Mic Selector bit 2 */#define AC97_AD1986_OMS_MASK \	(AC97_AD1986_OMS2 | AC97_AD1986_OMS1 | AC97_AD1986_OMS0)#define AC97_AD1986_OMS_M	0x0000  /* MIC_1/2 pins are MIC sources */#define AC97_AD1986_OMS_L	0x0100  /* LINE_IN pins are MIC sources */#define AC97_AD1986_OMS_C	0x0200  /* Center/LFE pins are MCI sources */#define AC97_AD1986_OMS_MC	0x0400  /* Mix of MIC and C/LFE pins */					/*   are MIC sources */#define AC97_AD1986_OMS_ML	0x0500  /* MIX of MIC and LINE_IN pins */					/*   are MIC sources */#define AC97_AD1986_OMS_LC	0x0600  /* MIX of LINE_IN and C/LFE pins */					/*   are MIC sources */#define AC97_AD1986_OMS_MLC	0x0700  /* MIX of MIC, LINE_IN, C/LFE pins */					/*   are MIC sources */static int snd_ac97_ad198x_spdif_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){	static char *texts[2] = { "AC-Link", "A/D Converter" };	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;	uinfo->count = 1;	uinfo->value.enumerated.items = 2;	if (uinfo->value.enumerated.item > 1)		uinfo->value.enumerated.item = 1;	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);	return 0;}static int snd_ac97_ad198x_spdif_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);	unsigned short val;	val = ac97->regs[AC97_AD_SERIAL_CFG];	ucontrol->value.enumerated.item[0] = (val >> 2) & 1;	return 0;}static int snd_ac97_ad198x_spdif_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);	unsigned short val;	if (ucontrol->value.enumerated.item[0] > 1)		return -EINVAL;	val = ucontrol->value.enumerated.item[0] << 2;	return snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x0004, val);}static const struct snd_kcontrol_new snd_ac97_ad198x_spdif_source = {	.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,	.name	= SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",	.info	= snd_ac97_ad198x_spdif_source_info,	.get	= snd_ac97_ad198x_spdif_source_get,	.put	= snd_ac97_ad198x_spdif_source_put,};static int patch_ad198x_post_spdif(struct snd_ac97 * ac97){ 	return patch_build_controls(ac97, &snd_ac97_ad198x_spdif_source, 1);}static const struct snd_kcontrol_new snd_ac97_ad1981x_jack_sense[] = {	AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 11, 1, 0),	AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0),};/* black list to avoid HP/Line jack-sense controls * (SS vendor << 16 | device) */static unsigned int ad1981_jacks_blacklist[] = {	0x10140523, /* Thinkpad R40 */	0x10140534, /* Thinkpad X31 */	0x10140537, /* Thinkpad T41p */	0x10140554, /* Thinkpad T42p/R50p */	0x10140567, /* Thinkpad T43p 2668-G7U */	0x10140581, /* Thinkpad X41-2527 */	0x104380b0, /* Asus A7V8X-MX */	0x11790241, /* Toshiba Satellite A-15 S127 */	0x144dc01a, /* Samsung NP-X20C004/SEG */	0 /* end */};static int c

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -