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

📄 ac97_codec.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  Copyright (c) by Jaroslav Kysela <perex@suse.cz> *  Universal interface for Audio Codec '97 * *  For more details look to AC '97 component specification revision 2.2 *  by Intel Corporation (http://developer.intel.com). * * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA * */#include <sound/driver.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/pci.h>#include <linux/moduleparam.h>#include <sound/core.h>#include <sound/pcm.h>#include <sound/ac97_codec.h>#include <sound/asoundef.h>#include <sound/initval.h>#include "ac97_local.h"#include "ac97_id.h"#include "ac97_patch.h"MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");MODULE_DESCRIPTION("Universal interface for Audio Codec '97");MODULE_LICENSE("GPL");static int enable_loopback;module_param(enable_loopback, bool, 0444);MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control");/* */typedef struct {	unsigned int id;	unsigned int mask;	const char *name;	int (*patch)(ac97_t *ac97);	int (*mpatch)(ac97_t *ac97);	unsigned int flags;} ac97_codec_id_t;static const ac97_codec_id_t snd_ac97_codec_id_vendors[] = {{ 0x414b4d00, 0xffffff00, "Asahi Kasei",	NULL,	NULL },{ 0x41445300, 0xffffff00, "Analog Devices",	NULL,	NULL },{ 0x414c4300, 0xffffff00, "Realtek",		NULL,	NULL },{ 0x414c4700, 0xffffff00, "Realtek",		NULL,	NULL },{ 0x434d4900, 0xffffff00, "C-Media Electronics", NULL,	NULL },{ 0x43525900, 0xffffff00, "Cirrus Logic",	NULL,	NULL },{ 0x43585400, 0xffffff00, "Conexant",           NULL,	NULL },{ 0x44543000, 0xffffff00, "Diamond Technology", NULL,	NULL },{ 0x454d4300, 0xffffff00, "eMicro",		NULL,	NULL },{ 0x45838300, 0xffffff00, "ESS Technology",	NULL,	NULL },{ 0x48525300, 0xffffff00, "Intersil",		NULL,	NULL },{ 0x49434500, 0xffffff00, "ICEnsemble",		NULL,	NULL },{ 0x49544500, 0xffffff00, "ITE Tech.Inc",	NULL,	NULL },{ 0x4e534300, 0xffffff00, "National Semiconductor", NULL, NULL },{ 0x50534300, 0xffffff00, "Philips",		NULL,	NULL },{ 0x53494c00, 0xffffff00, "Silicon Laboratory",	NULL,	NULL },{ 0x54524100, 0xffffff00, "TriTech",		NULL,	NULL },{ 0x54584e00, 0xffffff00, "Texas Instruments",	NULL,	NULL },{ 0x56494100, 0xffffff00, "VIA Technologies",   NULL,	NULL },{ 0x57454300, 0xffffff00, "Winbond",		NULL,	NULL },{ 0x574d4c00, 0xffffff00, "Wolfson",		NULL,	NULL },{ 0x594d4800, 0xffffff00, "Yamaha",		NULL,	NULL },{ 0x83847600, 0xffffff00, "SigmaTel",		NULL,	NULL },{ 0,	      0, 	  NULL,			NULL,	NULL }};static const ac97_codec_id_t snd_ac97_codec_ids[] = {{ 0x414b4d00, 0xffffffff, "AK4540",		NULL,		NULL },{ 0x414b4d01, 0xffffffff, "AK4542",		NULL,		NULL },{ 0x414b4d02, 0xffffffff, "AK4543",		NULL,		NULL },{ 0x414b4d06, 0xffffffff, "AK4544A",		NULL,		NULL },{ 0x414b4d07, 0xffffffff, "AK4545",		NULL,		NULL },{ 0x41445303, 0xffffffff, "AD1819",		patch_ad1819,	NULL },{ 0x41445340, 0xffffffff, "AD1881",		patch_ad1881,	NULL },{ 0x41445348, 0xffffffff, "AD1881A",		patch_ad1881,	NULL },{ 0x41445360, 0xffffffff, "AD1885",		patch_ad1885,	NULL },{ 0x41445361, 0xffffffff, "AD1886",		patch_ad1886,	NULL },{ 0x41445362, 0xffffffff, "AD1887",		patch_ad1881,	NULL },{ 0x41445363, 0xffffffff, "AD1886A",		patch_ad1881,	NULL },{ 0x41445368, 0xffffffff, "AD1888",		patch_ad1888,	NULL },{ 0x41445370, 0xffffffff, "AD1980",		patch_ad1980,	NULL },{ 0x41445372, 0xffffffff, "AD1981A",		patch_ad1981a,	NULL },{ 0x41445374, 0xffffffff, "AD1981B",		patch_ad1981b,	NULL },{ 0x41445375, 0xffffffff, "AD1985",		patch_ad1985,	NULL },{ 0x41445378, 0xffffffff, "AD1986",		patch_ad1985,	NULL },{ 0x414c4300, 0xffffff00, "ALC100,100P", 	NULL,		NULL },{ 0x414c4710, 0xfffffff0, "ALC200,200P",	NULL,		NULL },{ 0x414c4721, 0xffffffff, "ALC650D",		NULL,	NULL }, /* already patched */{ 0x414c4722, 0xffffffff, "ALC650E",		NULL,	NULL }, /* already patched */{ 0x414c4723, 0xffffffff, "ALC650F",		NULL,	NULL }, /* already patched */{ 0x414c4720, 0xfffffff0, "ALC650",		patch_alc650,	NULL },{ 0x414c4760, 0xfffffff0, "ALC655",		patch_alc655,	NULL },{ 0x414c4781, 0xffffffff, "ALC658D",		NULL,	NULL }, /* already patched */{ 0x414c4780, 0xfffffff0, "ALC658",		patch_alc655,	NULL },{ 0x414c4790, 0xfffffff0, "ALC850",		patch_alc850,	NULL },{ 0x414c4730, 0xffffffff, "ALC101",		NULL,		NULL },{ 0x414c4740, 0xfffffff0, "ALC202",		NULL,		NULL },{ 0x414c4750, 0xfffffff0, "ALC250",		NULL,		NULL },{ 0x414c4770, 0xfffffff0, "ALC203",		NULL,		NULL },{ 0x434d4941, 0xffffffff, "CMI9738",		patch_cm9738,	NULL },{ 0x434d4961, 0xffffffff, "CMI9739",		patch_cm9739,	NULL },{ 0x434d4969, 0xffffffff, "CMI9780",		patch_cm9780,	NULL },{ 0x434d4978, 0xffffffff, "CMI9761",		patch_cm9761,	NULL },{ 0x434d4982, 0xffffffff, "CMI9761",		patch_cm9761,	NULL },{ 0x434d4983, 0xffffffff, "CMI9761",		patch_cm9761,	NULL },{ 0x43525900, 0xfffffff8, "CS4297",		NULL,		NULL },{ 0x43525910, 0xfffffff8, "CS4297A",		patch_cirrus_spdif,	NULL },{ 0x43525920, 0xfffffff8, "CS4298",		patch_cirrus_spdif,		NULL },{ 0x43525928, 0xfffffff8, "CS4294",		NULL,		NULL },{ 0x43525930, 0xfffffff8, "CS4299",		patch_cirrus_cs4299,	NULL },{ 0x43525948, 0xfffffff8, "CS4201",		NULL,		NULL },{ 0x43525958, 0xfffffff8, "CS4205",		patch_cirrus_spdif,	NULL },{ 0x43525960, 0xfffffff8, "CS4291",		NULL,		NULL },{ 0x43525970, 0xfffffff8, "CS4202",		NULL,		NULL },{ 0x43585421, 0xffffffff, "HSD11246",		NULL,		NULL },	// SmartMC II{ 0x43585428, 0xfffffff8, "Cx20468",		patch_conexant,	NULL }, // SmartAMC fixme: the mask might be different{ 0x44543031, 0xfffffff0, "DT0398",		NULL,		NULL },{ 0x454d4328, 0xffffffff, "28028",		NULL,		NULL },  // same as TR28028?{ 0x45838308, 0xffffffff, "ESS1988",		NULL,		NULL },{ 0x48525300, 0xffffff00, "HMP9701",		NULL,		NULL },{ 0x49434501, 0xffffffff, "ICE1230",		NULL,		NULL },{ 0x49434511, 0xffffffff, "ICE1232",		NULL,		NULL }, // alias VIA VT1611A?{ 0x49434514, 0xffffffff, "ICE1232A",		NULL,		NULL },{ 0x49434551, 0xffffffff, "VT1616", 		patch_vt1616,	NULL }, { 0x49434552, 0xffffffff, "VT1616i",		patch_vt1616,	NULL }, // VT1616 compatible (chipset integrated){ 0x49544520, 0xffffffff, "IT2226E",		NULL,		NULL },{ 0x49544561, 0xffffffff, "IT2646E",		patch_it2646,	NULL },{ 0x4e534300, 0xffffffff, "LM4540,43,45,46,48",	NULL,		NULL }, // only guess --jk{ 0x4e534331, 0xffffffff, "LM4549",		NULL,		NULL },{ 0x4e534350, 0xffffffff, "LM4550",		NULL,		NULL },{ 0x50534304, 0xffffffff, "UCB1400",		NULL,		NULL },{ 0x53494c20, 0xffffffe0, "Si3036,8",		mpatch_si3036,	mpatch_si3036, AC97_MODEM_PATCH },{ 0x54524102, 0xffffffff, "TR28022",		NULL,		NULL },{ 0x54524106, 0xffffffff, "TR28026",		NULL,		NULL },{ 0x54524108, 0xffffffff, "TR28028",		patch_tritech_tr28028,	NULL }, // added by xin jin [07/09/99]{ 0x54524123, 0xffffffff, "TR28602",		NULL,		NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]{ 0x54584e20, 0xffffffff, "TLC320AD9xC",	NULL,		NULL },{ 0x56494161, 0xffffffff, "VIA1612A",		NULL,		NULL }, // modified ICE1232 with S/PDIF{ 0x56494170, 0xffffffff, "VIA1617A",		patch_vt1617a,	NULL }, // modified VT1616 with S/PDIF{ 0x57454301, 0xffffffff, "W83971D",		NULL,		NULL },{ 0x574d4c00, 0xffffffff, "WM9701A",		NULL,		NULL },{ 0x574d4C03, 0xffffffff, "WM9703,WM9707,WM9708,WM9717", patch_wolfson03, NULL},{ 0x574d4C04, 0xffffffff, "WM9704M,WM9704Q",	patch_wolfson04, NULL},{ 0x574d4C05, 0xffffffff, "WM9705,WM9710",	patch_wolfson05, NULL},{ 0x574d4C09, 0xffffffff, "WM9709",		NULL,		NULL},{ 0x574d4C12, 0xffffffff, "WM9711,WM9712",	patch_wolfson11, NULL},{ 0x574d4c13, 0xffffffff, "WM9713,WM9714",	patch_wolfson13, NULL, AC97_DEFAULT_POWER_OFF},{ 0x594d4800, 0xffffffff, "YMF743",		NULL,		NULL },{ 0x594d4802, 0xffffffff, "YMF752",		NULL,		NULL },{ 0x594d4803, 0xffffffff, "YMF753",		patch_yamaha_ymf753,	NULL },{ 0x83847600, 0xffffffff, "STAC9700,83,84",	patch_sigmatel_stac9700,	NULL },{ 0x83847604, 0xffffffff, "STAC9701,3,4,5",	NULL,		NULL },{ 0x83847605, 0xffffffff, "STAC9704",		NULL,		NULL },{ 0x83847608, 0xffffffff, "STAC9708,11",	patch_sigmatel_stac9708,	NULL },{ 0x83847609, 0xffffffff, "STAC9721,23",	patch_sigmatel_stac9721,	NULL },{ 0x83847644, 0xffffffff, "STAC9744",		patch_sigmatel_stac9744,	NULL },{ 0x83847650, 0xffffffff, "STAC9750,51",	NULL,		NULL },	// patch?{ 0x83847652, 0xffffffff, "STAC9752,53",	NULL,		NULL }, // patch?{ 0x83847656, 0xffffffff, "STAC9756,57",	patch_sigmatel_stac9756,	NULL },{ 0x83847658, 0xffffffff, "STAC9758,59",	patch_sigmatel_stac9758,	NULL },{ 0x83847666, 0xffffffff, "STAC9766,67",	NULL,		NULL }, // patch?{ 0, 	      0,	  NULL,			NULL,		NULL }};const char *snd_ac97_stereo_enhancements[] ={  /*   0 */ "No 3D Stereo Enhancement",  /*   1 */ "Analog Devices Phat Stereo",  /*   2 */ "Creative Stereo Enhancement",  /*   3 */ "National Semi 3D Stereo Enhancement",  /*   4 */ "YAMAHA Ymersion",  /*   5 */ "BBE 3D Stereo Enhancement",  /*   6 */ "Crystal Semi 3D Stereo Enhancement",  /*   7 */ "Qsound QXpander",  /*   8 */ "Spatializer 3D Stereo Enhancement",  /*   9 */ "SRS 3D Stereo Enhancement",  /*  10 */ "Platform Tech 3D Stereo Enhancement",  /*  11 */ "AKM 3D Audio",  /*  12 */ "Aureal Stereo Enhancement",  /*  13 */ "Aztech 3D Enhancement",  /*  14 */ "Binaura 3D Audio Enhancement",  /*  15 */ "ESS Technology Stereo Enhancement",  /*  16 */ "Harman International VMAx",  /*  17 */ "Nvidea/IC Ensemble/KS Waves 3D Stereo Enhancement",  /*  18 */ "Philips Incredible Sound",  /*  19 */ "Texas Instruments 3D Stereo Enhancement",  /*  20 */ "VLSI Technology 3D Stereo Enhancement",  /*  21 */ "TriTech 3D Stereo Enhancement",  /*  22 */ "Realtek 3D Stereo Enhancement",  /*  23 */ "Samsung 3D Stereo Enhancement",  /*  24 */ "Wolfson Microelectronics 3D Enhancement",  /*  25 */ "Delta Integration 3D Enhancement",  /*  26 */ "SigmaTel 3D Enhancement",  /*  27 */ "IC Ensemble/KS Waves",  /*  28 */ "Rockwell 3D Stereo Enhancement",  /*  29 */ "Reserved 29",  /*  30 */ "Reserved 30",  /*  31 */ "Reserved 31"};/* *  I/O routines */static int snd_ac97_valid_reg(ac97_t *ac97, unsigned short reg){	if (ac97->limited_regs && ! test_bit(reg, ac97->reg_accessed))  		return 0;	/* filter some registers for buggy codecs */	switch (ac97->id) {	case AC97_ID_AK4540:	case AC97_ID_AK4542:		if (reg <= 0x1c || reg == 0x20 || reg == 0x26 || reg >= 0x7c)			return 1;		return 0;	case AC97_ID_AD1819:	/* AD1819 */	case AC97_ID_AD1881:	/* AD1881 */	case AC97_ID_AD1881A:	/* AD1881A */		if (reg >= 0x3a && reg <= 0x6e)	/* 0x59 */			return 0;		return 1;	case AC97_ID_AD1885:	/* AD1885 */	case AC97_ID_AD1886:	/* AD1886 */	case AC97_ID_AD1886A:	/* AD1886A - !!verify!! --jk */	case AC97_ID_AD1887:	/* AD1887 - !!verify!! --jk */		if (reg == 0x5a)			return 1;		if (reg >= 0x3c && reg <= 0x6e)	/* 0x59 */			return 0;		return 1;	case AC97_ID_STAC9700:	case AC97_ID_STAC9704:	case AC97_ID_STAC9705:	case AC97_ID_STAC9708:	case AC97_ID_STAC9721:	case AC97_ID_STAC9744:	case AC97_ID_STAC9756:		if (reg <= 0x3a || reg >= 0x5a)			return 1;		return 0;	}	return 1;}/** * snd_ac97_write - write a value on the given register * @ac97: the ac97 instance * @reg: the register to change * @value: the value to set * * Writes a value on the given register.  This will invoke the write * callback directly after the register check. * This function doesn't change the register cache unlike * #snd_ca97_write_cache(), so use this only when you don't want to * reflect the change to the suspend/resume state. */void snd_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short value){	if (!snd_ac97_valid_reg(ac97, reg))		return;	if ((ac97->id & 0xffffff00) == AC97_ID_ALC100) {		/* Fix H/W bug of ALC100/100P */		if (reg == AC97_MASTER || reg == AC97_HEADPHONE)			ac97->bus->ops->write(ac97, AC97_RESET, 0);	/* reset audio codec */	}	ac97->bus->ops->write(ac97, reg, value);}/** * snd_ac97_read - read a value from the given register *  * @ac97: the ac97 instance * @reg: the register to read * * Reads a value from the given register.  This will invoke the read * callback directly after the register check. * * Returns the read value. */unsigned short snd_ac97_read(ac97_t *ac97, unsigned short reg){	if (!snd_ac97_valid_reg(ac97, reg))		return 0;	return ac97->bus->ops->read(ac97, reg);}/* read a register - return the cached value if already read */static inline unsigned short snd_ac97_read_cache(ac97_t *ac97, unsigned short reg){	if (! test_bit(reg, ac97->reg_accessed)) {		ac97->regs[reg] = ac97->bus->ops->read(ac97, reg);		// set_bit(reg, ac97->reg_accessed);	}	return ac97->regs[reg];}/** * snd_ac97_write_cache - write a value on the given register and update the cache * @ac97: the ac97 instance * @reg: the register to change * @value: the value to set * * Writes a value on the given register and updates the register * cache.  The cached values are used for the cached-read and the * suspend/resume. */void snd_ac97_write_cache(ac97_t *ac97, unsigned short reg, unsigned short value){	if (!snd_ac97_valid_reg(ac97, reg))		return;	down(&ac97->reg_mutex);	ac97->regs[reg] = value;	ac97->bus->ops->write(ac97, reg, value);	set_bit(reg, ac97->reg_accessed);	up(&ac97->reg_mutex);}/** * snd_ac97_update - update the value on the given register * @ac97: the ac97 instance * @reg: the register to change * @value: the value to set * * Compares the value with the register cache and updates the value * only when the value is changed. * * Returns 1 if the value is changed, 0 if no change, or a negative * code on failure. */int snd_ac97_update(ac97_t *ac97, unsigned short reg, unsigned short value){	int change;	if (!snd_ac97_valid_reg(ac97, reg))		return -EINVAL;	down(&ac97->reg_mutex);	change = ac97->regs[reg] != value;	if (change) {		ac97->regs[reg] = value;		ac97->bus->ops->write(ac97, reg, value);	}	set_bit(reg, ac97->reg_accessed);	up(&ac97->reg_mutex);	return change;}/** * snd_ac97_update_bits - update the bits on the given register * @ac97: the ac97 instance * @reg: the register to change * @mask: the bit-mask to change * @value: the value to set * * Updates the masked-bits on the given register only when the value * is changed. * * Returns 1 if the bits are changed, 0 if no change, or a negative * code on failure. */int snd_ac97_update_bits(ac97_t *ac97, unsigned short reg, unsigned short mask, unsigned short value){	int change;	if (!snd_ac97_valid_reg(ac97, reg))		return -EINVAL;	down(&ac97->reg_mutex);

⌨️ 快捷键说明

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