ac97_codec.c

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

C
1,915
字号
	snd_ac97_write_cache(ac97, reg, 0x8000);}static inline int printable(unsigned int x){	x &= 0xff;	if (x < ' ' || x >= 0x71) {		if (x <= 0x89)			return x - 0x71 + 'A';		return '?';	}	return x;}snd_kcontrol_t *snd_ac97_cnew(const snd_kcontrol_new_t *_template, ac97_t * ac97){	snd_kcontrol_new_t template;	memcpy(&template, _template, sizeof(template));	snd_runtime_check(!template.index, return NULL);	template.index = ac97->num;	return snd_ctl_new1(&template, ac97);}/* * create mute switch(es) for normal stereo controls */static int snd_ac97_cmute_new(snd_card_t *card, char *name, int reg, ac97_t *ac97){	snd_kcontrol_t *kctl;	int stereo = 0;	if (ac97->flags & AC97_STEREO_MUTES) {		/* check whether both mute bits work */		unsigned short val, val1;		val = snd_ac97_read(ac97, reg);		val1 = val | 0x8080;		snd_ac97_write(ac97, reg, val1);		if (val1 == snd_ac97_read(ac97, reg))			stereo = 1;		snd_ac97_write(ac97, reg, val);	}	if (stereo) {		snd_kcontrol_new_t tmp = AC97_DOUBLE(name, reg, 15, 7, 1, 1);		tmp.index = ac97->num;		kctl = snd_ctl_new1(&tmp, ac97);	} else {		snd_kcontrol_new_t tmp = AC97_SINGLE(name, reg, 15, 1, 1);		tmp.index = ac97->num;		kctl = snd_ctl_new1(&tmp, ac97);	}	return snd_ctl_add(card, kctl);}/* * create volumes for normal stereo controls */static int snd_ac97_cvol_new(snd_card_t *card, char *name, int reg, unsigned int max, ac97_t *ac97){	int err;	snd_kcontrol_new_t tmp = AC97_DOUBLE(name, reg, 8, 0, (unsigned int)max, 1);	tmp.index = ac97->num;	if ((err = snd_ctl_add(card, snd_ctl_new1(&tmp, ac97))) < 0)		return err;	snd_ac97_write_cache(ac97, reg,			     ((ac97->flags & AC97_STEREO_MUTES) ? 0x8080 : 0x8000) |			     (unsigned short)max | ((unsigned short)max << 8));	return 0;}/* * create mute-switch and volumes for normal stereo controls */static int snd_ac97_cmix_new(snd_card_t *card, const char *pfx, int reg, int check_res, ac97_t *ac97){	int err;	char name[44];	unsigned char max;	sprintf(name, "%s Switch", pfx);	if ((err = snd_ac97_cmute_new(card, name, reg, ac97)) < 0)		return err;	sprintf(name, "%s Volume", pfx);	if (check_res)		snd_ac97_change_volume_params1(ac97, reg, &max);	else		max = 31; /* 5bit */	if ((err = snd_ac97_cvol_new(card, name, reg, max, ac97)) < 0)		return err;	return 0;}static int snd_ac97_mixer_build(ac97_t * ac97){	snd_card_t *card = ac97->bus->card;	snd_kcontrol_t *kctl;	int err;	unsigned int idx;	unsigned char max;	/* build master controls */	/* AD claims to remove this control from AD1887, although spec v2.2 does not allow this */	if (snd_ac97_try_volume_mix(ac97, AC97_MASTER)) {		if ((err = snd_ac97_cmix_new(card, "Master Playback", AC97_MASTER, 1, ac97)) < 0)			return err;	}	ac97->regs[AC97_CENTER_LFE_MASTER] = 0x8080;	/* build center controls */	if (snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER)) {		if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_center[0], ac97))) < 0)			return err;		if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_center[1], ac97))) < 0)			return err;		snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 0, &max);		kctl->private_value &= ~(0xff << 16);		kctl->private_value |= (int)max << 16;		snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max);	}	/* build LFE controls */	if (snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER+1)) {		if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_lfe[0], ac97))) < 0)			return err;		if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_lfe[1], ac97))) < 0)			return err;		snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 8, &max);		kctl->private_value &= ~(0xff << 16);		kctl->private_value |= (int)max << 16;		snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max << 8);	}	/* build surround controls */	if (snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER)) {		if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_surround[0], ac97))) < 0)			return err;		if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_surround[1], ac97))) < 0)			return err;		snd_ac97_change_volume_params2(ac97, AC97_SURROUND_MASTER, 0, &max);		kctl->private_value &= ~(0xff << 16);		kctl->private_value |= (int)max << 16;		snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x8080 | max | (max << 8));	}	/* build headphone controls */	if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE) || ac97->id == AC97_ID_STAC9708) {		const char *name = ac97->id == AC97_ID_STAC9708 ? 			"Sigmatel Surround Playback" :			"Headphone Playback";		if ((err = snd_ac97_cmix_new(card, name, AC97_HEADPHONE, 1, ac97)) < 0)			return err;	}		/* build master mono controls */	if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_MONO)) {		if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_master_mono[0], ac97))) < 0)			return err;		if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_master_mono[1], ac97))) < 0)			return err;		snd_ac97_change_volume_params1(ac97, AC97_MASTER_MONO, &max);		kctl->private_value &= ~(0xff << 16);		kctl->private_value |= (int)max << 16;		snd_ac97_write_cache(ac97, AC97_MASTER_MONO, 0x8000 | max);	}		/* build master tone controls */	if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_TONE)) {		for (idx = 0; idx < 2; idx++) {			if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97))) < 0)				return err;			if (ac97->id == AC97_ID_YMF753) {				kctl->private_value &= ~(0xff << 16);				kctl->private_value |= 7 << 16;			}		}		snd_ac97_write_cache(ac97, AC97_MASTER_TONE, 0x0f0f);	}		/* build PC Speaker controls */	if ((ac97->flags & AC97_HAS_PC_BEEP) ||	    snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP)) {		for (idx = 0; idx < 2; idx++)			if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0)				return err;		snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x801e);	}		/* build Phone controls */	if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) {		if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_phone[0], ac97))) < 0)			return err;		if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_phone[1], ac97))) < 0)			return err;		snd_ac97_change_volume_params3(ac97, AC97_PHONE, &max);		kctl->private_value &= ~(0xff << 16);		kctl->private_value |= (int)max << 16;		snd_ac97_write_cache(ac97, AC97_PHONE, 0x8000 | max);	}		/* build MIC controls */	snd_ac97_change_volume_params3(ac97, AC97_MIC, &max);	for (idx = 0; idx < 3; idx++) {		if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_mic[idx], ac97))) < 0)			return err;		if (idx == 1) {		// volume			kctl->private_value &= ~(0xff << 16);			kctl->private_value |= (int)max << 16;		}	}	snd_ac97_write_cache(ac97, AC97_MIC, 0x8000 | max);	/* build Line controls */	if ((err = snd_ac97_cmix_new(card, "Line Playback", AC97_LINE, 0, ac97)) < 0)		return err;		/* build CD controls */	if ((err = snd_ac97_cmix_new(card, "CD Playback", AC97_CD, 0, ac97)) < 0)		return err;		/* build Video controls */	if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) {		if ((err = snd_ac97_cmix_new(card, "Video Playback", AC97_VIDEO, 0, ac97)) < 0)			return err;	}	/* build Aux controls */	if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) {		if ((err = snd_ac97_cmix_new(card, "Aux Playback", AC97_AUX, 0, ac97)) < 0)			return err;	}	/* build PCM controls */	if (ac97->flags & AC97_AD_MULTI) {		unsigned short init_val;		if (ac97->flags & AC97_STEREO_MUTES)			init_val = 0x9f9f;		else			init_val = 0x9f1f;		for (idx = 0; idx < 2; idx++)			if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_pcm[idx], ac97))) < 0)				return err;		ac97->spec.ad18xx.pcmreg[0] = init_val;		if (ac97->scaps & AC97_SCAP_SURROUND_DAC) {			for (idx = 0; idx < 2; idx++)				if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_surround[idx], ac97))) < 0)					return err;			ac97->spec.ad18xx.pcmreg[1] = init_val;		}		if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) {			for (idx = 0; idx < 2; idx++)				if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_center[idx], ac97))) < 0)					return err;			for (idx = 0; idx < 2; idx++)				if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_lfe[idx], ac97))) < 0)					return err;			ac97->spec.ad18xx.pcmreg[2] = init_val;		}		snd_ac97_write_cache(ac97, AC97_PCM, init_val);	} else {		if ((err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97)) < 0)			return err;		/* FIXME: C-Media chips have no PCM volume!! */		if (/*ac97->id == 0x434d4941 ||*/		    ac97->id == 0x434d4942 ||		    ac97->id == 0x434d4961)			snd_ac97_write_cache(ac97, AC97_PCM, 0x9f1f);		else {			if ((err = snd_ac97_cvol_new(card, "PCM Playback Volume", AC97_PCM, 31, ac97)) < 0)				return err;		}	}	/* build Capture controls */	if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97))) < 0)		return err;	if ((err = snd_ac97_cmute_new(card, "Capture Switch", AC97_REC_GAIN, ac97)) < 0)		return err;	if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0)		return err;	snd_ac97_write_cache(ac97, AC97_REC_SEL, 0x0000);	snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x0000);	/* build MIC Capture controls */	if (snd_ac97_try_volume_mix(ac97, AC97_REC_GAIN_MIC)) {		for (idx = 0; idx < 2; idx++)			if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_capture[idx], ac97))) < 0)				return err;		snd_ac97_write_cache(ac97, AC97_REC_GAIN_MIC, 0x0000);	}	/* build PCM out path & mute control */	if (snd_ac97_try_bit(ac97, AC97_GENERAL_PURPOSE, 15)) {		if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_PCM_OUT], ac97))) < 0)			return err;	}	/* build Simulated Stereo Enhancement control */	if (ac97->caps & 0x0008) {		if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_STEREO_ENHANCEMENT], ac97))) < 0)			return err;	}	/* build 3D Stereo Enhancement control */	if (snd_ac97_try_bit(ac97, AC97_GENERAL_PURPOSE, 13)) {		if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_3D], ac97))) < 0)			return err;	}	/* build Loudness control */	if (ac97->caps & 0x0020) {		if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_LOUDNESS], ac97))) < 0)			return err;	}	/* build Mono output select control */	if (snd_ac97_try_bit(ac97, AC97_GENERAL_PURPOSE, 9)) {		if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_MONO], ac97))) < 0)			return err;	}	/* build Mic select control */	if (snd_ac97_try_bit(ac97, AC97_GENERAL_PURPOSE, 8)) {		if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_MIC], ac97))) < 0)			return err;	}	/* build ADC/DAC loopback control */	if (enable_loopback && snd_ac97_try_bit(ac97, AC97_GENERAL_PURPOSE, 7)) {		if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_LOOPBACK], ac97))) < 0)			return err;	}	snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0x0000);	/* build 3D controls */	if (ac97->build_ops && ac97->build_ops->build_3d) {		ac97->build_ops->build_3d(ac97);	} else {		if (snd_ac97_try_volume_mix(ac97, AC97_3D_CONTROL)) {			unsigned short val;			val = 0x0707;			snd_ac97_write(ac97, AC97_3D_CONTROL, val);			val = snd_ac97_read(ac97, AC97_3D_CONTROL);			val = val == 0x0606;			if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)				return err;			if (val)				kctl->private_value = AC97_3D_CONTROL | (9 << 8) | (7 << 16);			if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[1], ac97))) < 0)				return err;			if (val)				kctl->private_value = AC97_3D_CONTROL | (1 << 8) | (7 << 16);			snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);		}	}	/* build S/PDIF controls */	if (ac97->ext_id & AC97_EI_SPDIF) {		if (ac97->build_ops && ac97->build_ops->build_spdif) {			if ((err = ac97->build_ops->build_spdif(ac97)) < 0)				return err;		} else {			for (idx = 0; idx < 5; idx++)				if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0)					return err;			if (ac97->build_ops && ac97->build_ops->build_post_spdif) {				if ((err = ac97->build_ops->build_post_spdif(ac97)) < 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_SPDIF, 0x2a20);		}		ac97->spdif_status = SNDRV_PCM_DEFAULT_CON_SPDIF;	}		/* build chip specific controls */	if (ac97->build_ops && ac97->build_ops->build_specific)		if ((err = ac97->build_ops->build_specific(ac97)) < 0)			return err;	if (snd_ac97_try_bit(ac97, AC97_POWERDOWN, 15)) {

⌨️ 快捷键说明

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