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

📄 ac97_codec.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
		if (extst & AC97_EA_SPDIF) {			snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */                }	}	up(&ac97->reg_mutex);	return change;}static int snd_ac97_put_spsa(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);	int reg = kcontrol->private_value & 0xff;	int shift = (kcontrol->private_value >> 8) & 0xff;	int mask = (kcontrol->private_value >> 16) & 0xff;	// int invert = (kcontrol->private_value >> 24) & 0xff;	unsigned short value, old, new;	int change;	value = (ucontrol->value.integer.value[0] & mask);	down(&ac97->reg_mutex);	mask <<= shift;	value <<= shift;	old = snd_ac97_read_cache(ac97, reg);	new = (old & ~mask) | value;	change = old != new;	if (change) {		unsigned short extst = snd_ac97_read_cache(ac97, AC97_EXTENDED_STATUS);		snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); /* turn off */		change = snd_ac97_update_bits_nolock(ac97, reg, mask, value);		if (extst & AC97_EA_SPDIF)			snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */	}	up(&ac97->reg_mutex);	return change;}const snd_kcontrol_new_t snd_ac97_controls_spdif[5] = {	{		.access = SNDRV_CTL_ELEM_ACCESS_READ,		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),		.info = snd_ac97_spdif_mask_info,		.get = snd_ac97_spdif_cmask_get,	},	{		.access = SNDRV_CTL_ELEM_ACCESS_READ,		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),		.info = snd_ac97_spdif_mask_info,		.get = snd_ac97_spdif_pmask_get,	},	{		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),		.info = snd_ac97_spdif_mask_info,		.get = snd_ac97_spdif_default_get,		.put = snd_ac97_spdif_default_put,	},	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH),AC97_EXTENDED_STATUS, 2, 1, 0),	{		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "AC97-SPSA",		.info = snd_ac97_info_volsw,		.get = snd_ac97_get_volsw,		.put = snd_ac97_put_spsa,		.private_value = AC97_SINGLE_VALUE(AC97_EXTENDED_STATUS, 4, 3, 0)	},};#define AD18XX_PCM_BITS(xname, codec, lshift, rshift, mask) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_ad18xx_pcm_info_bits, \  .get = snd_ac97_ad18xx_pcm_get_bits, .put = snd_ac97_ad18xx_pcm_put_bits, \  .private_value = (codec) | ((lshift) << 8) | ((rshift) << 12) | ((mask) << 16) }static int snd_ac97_ad18xx_pcm_info_bits(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);	int mask = (kcontrol->private_value >> 16) & 0x0f;	int lshift = (kcontrol->private_value >> 8) & 0x0f;	int rshift = (kcontrol->private_value >> 12) & 0x0f;	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;	if (lshift != rshift && (ac97->flags & AC97_STEREO_MUTES))		uinfo->count = 2;	else		uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = mask;	return 0;}static int snd_ac97_ad18xx_pcm_get_bits(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);	int codec = kcontrol->private_value & 3;	int lshift = (kcontrol->private_value >> 8) & 0x0f;	int rshift = (kcontrol->private_value >> 12) & 0x0f;	int mask = (kcontrol->private_value >> 16) & 0xff;		ucontrol->value.integer.value[0] = mask - ((ac97->spec.ad18xx.pcmreg[codec] >> lshift) & mask);	if (lshift != rshift && (ac97->flags & AC97_STEREO_MUTES))		ucontrol->value.integer.value[1] = mask - ((ac97->spec.ad18xx.pcmreg[codec] >> rshift) & mask);	return 0;}static int snd_ac97_ad18xx_pcm_put_bits(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);	int codec = kcontrol->private_value & 3;	int lshift = (kcontrol->private_value >> 8) & 0x0f;	int rshift = (kcontrol->private_value >> 12) & 0x0f;	int mask = (kcontrol->private_value >> 16) & 0xff;	unsigned short val, valmask;		val = (mask - (ucontrol->value.integer.value[0] & mask)) << lshift;	valmask = mask << lshift;	if (lshift != rshift && (ac97->flags & AC97_STEREO_MUTES)) {		val |= (mask - (ucontrol->value.integer.value[1] & mask)) << rshift;		valmask |= mask << rshift;	}	return snd_ac97_ad18xx_update_pcm_bits(ac97, codec, valmask, val);}#define AD18XX_PCM_VOLUME(xname, codec) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_ad18xx_pcm_info_volume, \  .get = snd_ac97_ad18xx_pcm_get_volume, .put = snd_ac97_ad18xx_pcm_put_volume, \  .private_value = codec }static int snd_ac97_ad18xx_pcm_info_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 2;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 31;	return 0;}static int snd_ac97_ad18xx_pcm_get_volume(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);	int codec = kcontrol->private_value & 3;		down(&ac97->page_mutex);	ucontrol->value.integer.value[0] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 0) & 31);	ucontrol->value.integer.value[1] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 8) & 31);	up(&ac97->page_mutex);	return 0;}static int snd_ac97_ad18xx_pcm_put_volume(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);	int codec = kcontrol->private_value & 3;	unsigned short val1, val2;		val1 = 31 - (ucontrol->value.integer.value[0] & 31);	val2 = 31 - (ucontrol->value.integer.value[1] & 31);	return snd_ac97_ad18xx_update_pcm_bits(ac97, codec, 0x1f1f, (val1 << 8) | val2);}static const snd_kcontrol_new_t snd_ac97_controls_ad18xx_pcm[2] = {AD18XX_PCM_BITS("PCM Playback Switch", 0, 15, 7, 1),AD18XX_PCM_VOLUME("PCM Playback Volume", 0)};static const snd_kcontrol_new_t snd_ac97_controls_ad18xx_surround[2] = {AD18XX_PCM_BITS("Surround Playback Switch", 1, 15, 7, 1),AD18XX_PCM_VOLUME("Surround Playback Volume", 1)};static const snd_kcontrol_new_t snd_ac97_controls_ad18xx_center[2] = {AD18XX_PCM_BITS("Center Playback Switch", 2, 15, 15, 1),AD18XX_PCM_BITS("Center Playback Volume", 2, 8, 8, 31)};static const snd_kcontrol_new_t snd_ac97_controls_ad18xx_lfe[2] = {AD18XX_PCM_BITS("LFE Playback Switch", 2, 7, 7, 1),AD18XX_PCM_BITS("LFE Playback Volume", 2, 0, 0, 31)};/* * */static void snd_ac97_powerdown(ac97_t *ac97);static int snd_ac97_bus_free(ac97_bus_t *bus){	if (bus) {		snd_ac97_bus_proc_done(bus);		kfree(bus->pcms);		if (bus->private_free)			bus->private_free(bus);		kfree(bus);	}	return 0;}static int snd_ac97_bus_dev_free(snd_device_t *device){	ac97_bus_t *bus = device->device_data;	return snd_ac97_bus_free(bus);}static int snd_ac97_free(ac97_t *ac97){	if (ac97) {		snd_ac97_proc_done(ac97);		if (ac97->bus)			ac97->bus->codec[ac97->num] = NULL;		if (ac97->private_free)			ac97->private_free(ac97);		kfree(ac97);	}	return 0;}static int snd_ac97_dev_free(snd_device_t *device){	ac97_t *ac97 = device->device_data;	snd_ac97_powerdown(ac97); /* for avoiding click noises during shut down */	return snd_ac97_free(ac97);}static int snd_ac97_try_volume_mix(ac97_t * ac97, int reg){	unsigned short val, mask = 0x8000;	if (! snd_ac97_valid_reg(ac97, reg))		return 0;	switch (reg) {	case AC97_MASTER_TONE:		return ac97->caps & 0x04 ? 1 : 0;	case AC97_HEADPHONE:		return ac97->caps & 0x10 ? 1 : 0;	case AC97_REC_GAIN_MIC:		return ac97->caps & 0x01 ? 1 : 0;	case AC97_3D_CONTROL:		if (ac97->caps & 0x7c00) {			val = snd_ac97_read(ac97, reg);			/* if nonzero - fixed and we can't set it */			return val == 0;		}		return 0;	case AC97_CENTER_LFE_MASTER:	/* center */		if ((ac97->ext_id & AC97_EI_CDAC) == 0)			return 0;		break;	case AC97_CENTER_LFE_MASTER+1:	/* lfe */		if ((ac97->ext_id & AC97_EI_LDAC) == 0)			return 0;		reg = AC97_CENTER_LFE_MASTER;		mask = 0x0080;		break;	case AC97_SURROUND_MASTER:		if ((ac97->ext_id & AC97_EI_SDAC) == 0)			return 0;		break;	}	if (ac97->limited_regs && test_bit(reg, ac97->reg_accessed))		return 1; /* allow without check */	val = snd_ac97_read(ac97, reg);	if (!(val & mask)) {		/* nothing seems to be here - mute flag is not set */		/* try another test */		snd_ac97_write_cache(ac97, reg, val | mask);		val = snd_ac97_read(ac97, reg);		if (!(val & mask))			return 0;	/* nothing here */	}	return 1;		/* success, useable */}static void check_volume_resolution(ac97_t *ac97, int reg, unsigned char *lo_max, unsigned char *hi_max){	unsigned short cbit[3] = { 0x20, 0x10, 0x01 };	unsigned char max[3] = { 63, 31, 15 };	int i;	*lo_max = *hi_max = 0;	for (i = 0 ; i < ARRAY_SIZE(cbit); i++) {		unsigned short val;		snd_ac97_write(ac97, reg, 0x8080 | cbit[i] | (cbit[i] << 8));		/* Do the read twice due to buffers on some ac97 codecs.		 * e.g. The STAC9704 returns exactly what you wrote the the register		 * if you read it immediately. This causes the detect routine to fail.		 */		val = snd_ac97_read(ac97, reg);		val = snd_ac97_read(ac97, reg);		if (! *lo_max && (val & 0x7f) == cbit[i])			*lo_max = max[i];		if (! *hi_max && ((val >> 8) & 0x7f) == cbit[i])			*hi_max = max[i];		if (*lo_max && *hi_max)			break;	}}int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit){	unsigned short mask, val, orig, res;	mask = 1 << bit;	orig = snd_ac97_read(ac97, reg);	val = orig ^ mask;	snd_ac97_write(ac97, reg, val);	res = snd_ac97_read(ac97, reg);	snd_ac97_write_cache(ac97, reg, orig);	return res == val;}/* check the volume resolution of center/lfe */static void snd_ac97_change_volume_params2(ac97_t * ac97, int reg, int shift, unsigned char *max){	unsigned short val, val1;	*max = 63;	val = 0x8080 | (0x20 << shift);	snd_ac97_write(ac97, reg, val);	val1 = snd_ac97_read(ac97, reg);	if (val != val1) {		*max = 31;	}	/* reset volume to zero */	snd_ac97_write_cache(ac97, reg, 0x8080);}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));	template.index = ac97->num;	return snd_ctl_new1(&template, ac97);}/* * create mute switch(es) for normal stereo controls */static int snd_ac97_cmute_new_stereo(snd_card_t *card, char *name, int reg, int check_stereo, ac97_t *ac97){	snd_kcontrol_t *kctl;	int err;	unsigned short val, val1, mute_mask;	if (! snd_ac97_valid_reg(ac97, reg))		return 0;	mute_mask = 0x8000;	val = snd_ac97_read(ac97, reg);	if (check_stereo || (ac97->flags & AC97_STEREO_MUTES)) {		/* check whether both mute bits work */		val1 = val | 0x8080;		snd_ac97_write(ac97, reg, val1);		if (val1 == snd_ac97_read(ac97, reg))			mute_mask = 0x8080;	}	if (mute_mask == 0x8080) {		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);	}	err = snd_ctl_add(card, kctl);	if (err < 0)		return err;	/* mute as default */	snd_ac97_write_cache(ac97, reg, val | mute_mask);	return 0;}

⌨️ 快捷键说明

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