ac97_patch.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 1,701 行 · 第 1/4 页

C
1,701
字号
        AC97_SINGLE("Analog to IEC958 Output", AC97_ALC650_MULTICH, 12, 1, 0),        AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0),};static int patch_alc650_specific(ac97_t * ac97){	int err;	if ((err = patch_build_controls(ac97, snd_ac97_controls_alc650, ARRAY_SIZE(snd_ac97_controls_alc650))) < 0)		return err;	if (ac97->ext_id & AC97_EI_SPDIF) {		if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc650, ARRAY_SIZE(snd_ac97_spdif_controls_alc650))) < 0)			return err;	}	return 0;}static struct snd_ac97_build_ops patch_alc650_ops = {	.build_specific	= patch_alc650_specific};int patch_alc650(ac97_t * ac97){	unsigned short val;	ac97->build_ops = &patch_alc650_ops;	/* revision E or F */	/* FIXME: what about revision D ? */	ac97->spec.dev_flags = (ac97->id == 0x414c4722 ||				ac97->id == 0x414c4723);	/* enable AC97_ALC650_GPIO_SETUP, AC97_ALC650_CLOCK for R/W */	snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_STATUS, 		snd_ac97_read(ac97, AC97_ALC650_GPIO_STATUS) | 0x8000);	/* Enable SPDIF-IN only on Rev.E and above */	val = snd_ac97_read(ac97, AC97_ALC650_CLOCK);	/* SPDIF IN with pin 47 */	if (ac97->spec.dev_flags)		val |= 0x03; /* enable */	else		val &= ~0x03; /* disable */	snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK, val);	/* set default: slot 3,4,7,8,6,9	   spdif-in monitor off, analog-spdif off, spdif-in off	   center on mic off, surround on line-in off	   downmix off, duplicate front off	*/	snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, 0);	/* set GPIO0 for mic bias */	/* GPIO0 pin output, no interrupt, high */	snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_SETUP,			     snd_ac97_read(ac97, AC97_ALC650_GPIO_SETUP) | 0x01);	snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_STATUS,			     (snd_ac97_read(ac97, AC97_ALC650_GPIO_STATUS) | 0x100) & ~0x10);	/* full DAC volume */	snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808);	snd_ac97_write_cache(ac97, AC97_ALC650_LFE_DAC_VOL, 0x0808);	return 0;}static int snd_ac97_alc655_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol){        ac97_t *ac97 = snd_kcontrol_chip(kcontrol);        ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1;        return 0;}static int snd_ac97_alc655_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol){        ac97_t *ac97 = snd_kcontrol_chip(kcontrol);        int change;	/* misc control; vrefout disable */	snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,			     ucontrol->value.integer.value[0] ? (1 << 12) : 0);	change = snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10,				      ucontrol->value.integer.value[0] ? (1 << 10) : 0);	return change;}static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = {	AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0),	AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0),	{		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		.name = "Mic As Center/LFE",		.info = snd_ac97_info_single,		.get = snd_ac97_alc655_mic_get,		.put = snd_ac97_alc655_mic_put,		.private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */	},};static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){	static char *texts_655[3] = { "PCM", "Analog In", "IEC958 In" };	static char *texts_658[4] = { "PCM", "Analog1 In", "Analog2 In", "IEC958 In" };	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;	uinfo->count = 1;	uinfo->value.enumerated.items = ac97->spec.dev_flags ? 4 : 3;	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;	strcpy(uinfo->value.enumerated.name,	       ac97->spec.dev_flags ?	       texts_658[uinfo->value.enumerated.item] :	       texts_655[uinfo->value.enumerated.item]);	return 0;}static int alc655_iec958_route_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);	unsigned short val;	val = ac97->regs[AC97_ALC650_MULTICH];	val = (val >> 12) & 3;	if (ac97->spec.dev_flags && val == 3)		val = 0;	ucontrol->value.enumerated.item[0] = val;	return 0;}static int alc655_iec958_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);	return snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 3 << 12,				    (unsigned short)ucontrol->value.enumerated.item[0]);}static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc655[] = {        AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0),        AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 14, 1, 0),	{		.iface  = SNDRV_CTL_ELEM_IFACE_MIXER,		.name   = "IEC958 Playback Route",		.info   = alc655_iec958_route_info,		.get    = alc655_iec958_route_get,		.put    = alc655_iec958_route_put,	},};static int patch_alc655_specific(ac97_t * ac97){	int err;	if ((err = patch_build_controls(ac97, snd_ac97_controls_alc655, ARRAY_SIZE(snd_ac97_controls_alc655))) < 0)		return err;	if (ac97->ext_id & AC97_EI_SPDIF) {		if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc655, ARRAY_SIZE(snd_ac97_spdif_controls_alc655))) < 0)			return err;	}	return 0;}static struct snd_ac97_build_ops patch_alc655_ops = {	.build_specific	= patch_alc655_specific};int patch_alc655(ac97_t * ac97){	unsigned int val;	ac97->spec.dev_flags = (ac97->id == 0x414c4780); /* ALC658 */	ac97->build_ops = &patch_alc655_ops;	/* adjust default values */	val = snd_ac97_read(ac97, 0x7a); /* misc control */	val |= (1 << 1); /* spdif input pin */	val &= ~(1 << 12); /* vref enable */	snd_ac97_write_cache(ac97, 0x7a, val);	/* set default: spdif-in enabled,	   spdif-in monitor off, spdif-in PCM off	   center on mic off, surround on line-in off	   duplicate front off	*/	snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, 1<<15);	/* full DAC volume */	snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808);	snd_ac97_write_cache(ac97, AC97_ALC650_LFE_DAC_VOL, 0x0808);	return 0;}/* * C-Media CM97xx codecs */static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = {	AC97_SINGLE("Line-In As Surround", AC97_CM9738_VENDOR_CTRL, 10, 1, 0),	AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0),};static int patch_cm9738_specific(ac97_t * ac97){	return patch_build_controls(ac97, snd_ac97_cm9738_controls, ARRAY_SIZE(snd_ac97_cm9738_controls));}static struct snd_ac97_build_ops patch_cm9738_ops = {	.build_specific	= patch_cm9738_specific};int patch_cm9738(ac97_t * ac97){	ac97->build_ops = &patch_cm9738_ops;	return 0;}static int snd_ac97_cmedia_spdif_playback_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	static char *texts[] = { "Analog", "Digital" };	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_cmedia_spdif_playback_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);	unsigned short val;	val = ac97->regs[AC97_CM9739_SPDIF_CTRL];	ucontrol->value.enumerated.item[0] = (val >> 1) & 0x01;	return 0;}static int snd_ac97_cmedia_spdif_playback_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);	return snd_ac97_update_bits(ac97, AC97_CM9739_SPDIF_CTRL,				    0x01 << 1, 				    (ucontrol->value.enumerated.item[0] & 0x01) << 1);}static const snd_kcontrol_new_t snd_ac97_cm9739_controls_spdif[] = {	/* BIT 0: SPDI_EN - always true */	{ /* BIT 1: SPDIFS */		.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,		.name	= SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",		.info	= snd_ac97_cmedia_spdif_playback_source_info,		.get	= snd_ac97_cmedia_spdif_playback_source_get,		.put	= snd_ac97_cmedia_spdif_playback_source_put,	},	/* BIT 2: IG_SPIV */	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Valid Switch", AC97_CM9739_SPDIF_CTRL, 2, 1, 0),	/* BIT 3: SPI2F */	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Monitor", AC97_CM9739_SPDIF_CTRL, 3, 1, 0), 	/* BIT 4: SPI2SDI */	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_CM9739_SPDIF_CTRL, 4, 1, 0),	/* BIT 8: SPD32 - 32bit SPDIF - not supported yet */};static int snd_ac97_cm9739_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);	if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x1000)		ucontrol->value.integer.value[0] = 1;	else		ucontrol->value.integer.value[0] = 0;	return 0;}static int snd_ac97_cm9739_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);	return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000,				    ucontrol->value.integer.value[0] ? 				    0x1000 : 0x2000);}static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = {	AC97_SINGLE("Line-In As Surround", AC97_CM9739_MULTI_CHAN, 10, 1, 0),	{		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		.name = "Mic As Center/LFE",		.info = snd_ac97_info_single,		.get = snd_ac97_cm9739_center_mic_get,		.put = snd_ac97_cm9739_center_mic_put,		.private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */	},};static int patch_cm9739_specific(ac97_t * ac97){	return patch_build_controls(ac97, snd_ac97_cm9739_controls, ARRAY_SIZE(snd_ac97_cm9739_controls));}static int patch_cm9739_post_spdif(ac97_t * ac97){	return patch_build_controls(ac97, snd_ac97_cm9739_controls_spdif, ARRAY_SIZE(snd_ac97_cm9739_controls_spdif));}static struct snd_ac97_build_ops patch_cm9739_ops = {	.build_specific	= patch_cm9739_specific,	.build_post_spdif = patch_cm9739_post_spdif};int patch_cm9739(ac97_t * ac97){	unsigned short val;	ac97->build_ops = &patch_cm9739_ops;	/* check spdif */	val = snd_ac97_read(ac97, AC97_EXTENDED_STATUS);	if (val & AC97_EA_SPCV) {		/* enable spdif in */		snd_ac97_write_cache(ac97, AC97_CM9739_SPDIF_CTRL,				     snd_ac97_read(ac97, AC97_CM9739_SPDIF_CTRL) | 0x01);	} else {		ac97->ext_id &= ~AC97_EI_SPDIF; /* disable extended-id */	}	/* set-up multi channel */	/* bit 14: 0 = SPDIF, 1 = EAPD */	/* bit 13: enable internal vref output for mic */	/* bit 12: disable center/lfe (swithable) */	/* bit 10: disable surround/line (switchable) */	/* bit 9: mix 2 surround off */	/* bit 0: dB */	val = (1 << 13);	if (! (ac97->ext_id & AC97_EI_SPDIF))		val |= (1 << 14);	snd_ac97_write_cache(ac97, AC97_CM9739_MULTI_CHAN, val);	/* FIXME: set up GPIO */	snd_ac97_write_cache(ac97, 0x70, 0x0100);	snd_ac97_write_cache(ac97, 0x72, 0x0020);	return 0;}/* * VIA VT1616 codec */static const snd_kcontrol_new_t snd_ac97_controls_vt1616[] = {AC97_SINGLE("DC Offset removal", 0x5a, 10, 1, 0),AC97_SINGLE("Alternate Level to Surround Out", 0x5a, 15, 1, 0),AC97_SINGLE("Downmix LFE and Center to Front", 0x5a, 12, 1, 0),AC97_SINGLE("Downmix Surround to Front", 0x5a, 11, 1, 0),};static int patch_vt1616_specific(ac97_t * ac97){	int err;	if (snd_ac97_try_bit(ac97, 0x5a, 9))		if ((err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[0], 1)) < 0)			return err;	if ((err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[1], ARRAY_SIZE(snd_ac97_controls_vt1616) - 1)) < 0)		return err;	return 0;}static struct snd_ac97_build_ops patch_vt1616_ops = {	.build_specific	= patch_vt1616_specific};int patch_vt1616(ac97_t * ac97){	ac97->build_ops = &patch_vt1616_ops;	return 0;}static const snd_kcontrol_new_t snd_ac97_controls_it2646[] = {	AC97_SINGLE("Line-In As Surround", 0x76, 9, 1, 0),	AC97_SINGLE("Mic As Center/LFE", 0x76, 10, 1, 0),};static const snd_kcontrol_new_t snd_ac97_spdif_controls_it2646[] = {	AC97_SINGLE("IEC958 Capture Switch", 0x76, 11, 1, 0),	AC97_SINGLE("Analog to IEC958 Output", 0x76, 12, 1, 0),	AC97_SINGLE("IEC958 Input Monitor", 0x76, 13, 1, 0),};static int patch_it2646_specific(ac97_t * ac97){	int err;	if ((err = patch_build_controls(ac97, snd_ac97_controls_it2646, ARRAY_SIZE(snd_ac97_controls_it2646))) < 0)		return err;	if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_it2646, ARRAY_SIZE(snd_ac97_spdif_controls_it2646))) < 0)		return err;	return 0;}static struct snd_ac97_build_ops patch_it2646_ops = {	.build_specific	= patch_it2646_specific};int patch_it2646(ac97_t * ac97){	ac97->build_ops = &patch_it2646_ops;	/* full DAC volume */	snd_ac97_write_cache(ac97, 0x5E, 0x0808);	snd_ac97_write_cache(ac97, 0x7A, 0x0808);	return 0;}/* Si3036/8 specific registers */#define AC97_SI3036_CHIP_ID     0x5aint mpatch_si3036(ac97_t * ac97){	//printk("mpatch_si3036: chip id = %x\n", snd_ac97_read(ac97, 0x5a));	snd_ac97_write_cache(ac97, 0x5c, 0xf210 );	snd_ac97_write_cache(ac97, 0x68, 0);	return 0;}

⌨️ 快捷键说明

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