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

📄 ac97_patch.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
		/* VARIOUS */ 0x0040	};	static unsigned short m675_regs[4] = {		/* OUTSEL */ 0xfc70, /* CL:MX, SR:MX, LO:DS, LI:MX, MI:DS */		/* IOMISC */ 0x2102, /* HP amp on */		/* INSEL */ 0x0203, /* LI:LI, MI:FR */		/* VARIOUS */ 0x0041 /* stereo mic */	};	unsigned short *pregs = def_regs;	int i;	/* Gateway M675 notebook */	if (ac97->pci && 	    ac97->subsystem_vendor == 0x107b &&	    ac97->subsystem_device == 0x0601)	    	pregs = m675_regs;	// patch for SigmaTel	ac97->build_ops = &patch_sigmatel_stac9758_ops;	/* FIXME: assume only page 0 for writing cache */	snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, AC97_PAGE_VENDOR);	for (i = 0; i < 4; i++)		snd_ac97_write_cache(ac97, regs[i], pregs[i]);	ac97->flags |= AC97_STEREO_MUTES;	return 0;}/* * Cirrus Logic CS42xx codecs */static const snd_kcontrol_new_t snd_ac97_cirrus_controls_spdif[2] = {	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), AC97_CSR_SPDIF, 15, 1, 0),	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "AC97-SPSA", AC97_CSR_ACMODE, 0, 3, 0)};static int patch_cirrus_build_spdif(ac97_t * ac97){	int err;	/* con mask, pro mask, default */	if ((err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3)) < 0)		return err;	/* switch, spsa */	if ((err = patch_build_controls(ac97, &snd_ac97_cirrus_controls_spdif[0], 1)) < 0)		return err;	switch (ac97->id & AC97_ID_CS_MASK) {	case AC97_ID_CS4205:		if ((err = patch_build_controls(ac97, &snd_ac97_cirrus_controls_spdif[1], 1)) < 0)			return err;		break;	}	/* set default PCM S/PDIF params */	/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */	snd_ac97_write_cache(ac97, AC97_CSR_SPDIF, 0x0a20);	return 0;}static struct snd_ac97_build_ops patch_cirrus_ops = {	.build_spdif = patch_cirrus_build_spdif};int patch_cirrus_spdif(ac97_t * ac97){	/* Basically, the cs4201/cs4205/cs4297a has non-standard sp/dif registers.	   WHY CAN'T ANYONE FOLLOW THE BLOODY SPEC?  *sigh*	   - sp/dif EA ID is not set, but sp/dif is always present.	   - enable/disable is spdif register bit 15.	   - sp/dif control register is 0x68.  differs from AC97:	   - valid is bit 14 (vs 15)	   - no DRS	   - only 44.1/48k [00 = 48, 01=44,1] (AC97 is 00=44.1, 10=48)	   - sp/dif ssource select is in 0x5e bits 0,1.	*/	ac97->build_ops = &patch_cirrus_ops;	ac97->flags |= AC97_CS_SPDIF; 	ac97->rates[AC97_RATES_SPDIF] &= ~SNDRV_PCM_RATE_32000;        ac97->ext_id |= AC97_EI_SPDIF;	/* force the detection of spdif */	snd_ac97_write_cache(ac97, AC97_CSR_ACMODE, 0x0080);	return 0;}int patch_cirrus_cs4299(ac97_t * ac97){	/* force the detection of PC Beep */	ac97->flags |= AC97_HAS_PC_BEEP;		return patch_cirrus_spdif(ac97);}/* * Conexant codecs */static const snd_kcontrol_new_t snd_ac97_conexant_controls_spdif[1] = {	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), AC97_CXR_AUDIO_MISC, 3, 1, 0),};static int patch_conexant_build_spdif(ac97_t * ac97){	int err;	/* con mask, pro mask, default */	if ((err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3)) < 0)		return err;	/* switch */	if ((err = patch_build_controls(ac97, &snd_ac97_conexant_controls_spdif[0], 1)) < 0)		return err;	/* set default PCM S/PDIF params */	/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */	snd_ac97_write_cache(ac97, AC97_CXR_AUDIO_MISC,			     snd_ac97_read(ac97, AC97_CXR_AUDIO_MISC) & ~(AC97_CXR_SPDIFEN|AC97_CXR_COPYRGT|AC97_CXR_SPDIF_MASK));	return 0;}static struct snd_ac97_build_ops patch_conexant_ops = {	.build_spdif = patch_conexant_build_spdif};int patch_conexant(ac97_t * ac97){	ac97->build_ops = &patch_conexant_ops;	ac97->flags |= AC97_CX_SPDIF;        ac97->ext_id |= AC97_EI_SPDIF;	/* force the detection of spdif */	ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */	return 0;}/* * Analog Device AD18xx, AD19xx codecs */#ifdef CONFIG_PMstatic void ad18xx_resume(ac97_t *ac97){	static unsigned short setup_regs[] = {		AC97_AD_MISC, AC97_AD_SERIAL_CFG, AC97_AD_JACK_SPDIF,	};	int i, codec;	for (i = 0; i < (int)ARRAY_SIZE(setup_regs); i++) {		unsigned short reg = setup_regs[i];		if (test_bit(reg, ac97->reg_accessed)) {			snd_ac97_write(ac97, reg, ac97->regs[reg]);			snd_ac97_read(ac97, reg);		}	}	if (! (ac97->flags & AC97_AD_MULTI))		/* normal restore */		snd_ac97_restore_status(ac97);	else {		/* restore the AD18xx codec configurations */		for (codec = 0; codec < 3; codec++) {			if (! ac97->spec.ad18xx.id[codec])				continue;			/* select single codec */			snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000,					     ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);			ac97->bus->ops->write(ac97, AC97_AD_CODEC_CFG, ac97->spec.ad18xx.codec_cfg[codec]);		}		/* select all codecs */		snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);		/* restore status */		for (i = 2; i < 0x7c ; i += 2) {			if (i == AC97_POWERDOWN || i == AC97_EXTENDED_ID)				continue;			if (test_bit(i, ac97->reg_accessed)) {				/* handle multi codecs for AD18xx */				if (i == AC97_PCM) {					for (codec = 0; codec < 3; codec++) {						if (! ac97->spec.ad18xx.id[codec])							continue;						/* select single codec */						snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000,								     ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);						/* update PCM bits */						ac97->bus->ops->write(ac97, AC97_PCM, ac97->spec.ad18xx.pcmreg[codec]);					}					/* select all codecs */					snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);					continue;				} else if (i == AC97_AD_TEST ||					   i == AC97_AD_CODEC_CFG ||					   i == AC97_AD_SERIAL_CFG)					continue; /* ignore */			}			snd_ac97_write(ac97, i, ac97->regs[i]);			snd_ac97_read(ac97, i);		}	}	snd_ac97_restore_iec958(ac97);}#endifint patch_ad1819(ac97_t * ac97){	unsigned short scfg;	// patch for Analog Devices	scfg = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG);	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, scfg | 0x7000); /* select all codecs */	return 0;}static unsigned short patch_ad1881_unchained(ac97_t * 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(ac97_t * 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(ac97_t * 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 (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};int patch_ad1881(ac97_t * 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 snd_kcontrol_new_t 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 int patch_ad1885_specific(ac97_t * ac97){	int err;	if ((err = patch_build_controls(ac97, snd_ac97_controls_ad1885, ARRAY_SIZE(snd_ac97_controls_ad1885))) < 0)		return err;	return 0;}static struct snd_ac97_build_ops patch_ad1885_build_ops = {	.build_specific = &patch_ad1885_specific,#ifdef CONFIG_PM	.resume = ad18xx_resume#endif};int patch_ad1885(ac97_t * 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;}int patch_ad1886(ac97_t * ac97){	patch_ad1881(ac97);	/* Presario700 workaround */	/* for Jack Sense/SPDIF Register misetting causing */	snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, 0x0010);	return 0;}/* MISC bits */#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	/* 2.25V, 3.7V */#define AC97_AD198X_VREF_0	0x000c	/* 0V */#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 */

⌨️ 快捷键说明

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