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

📄 ac97_codec.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
	change = snd_ac97_update_bits_nolock(ac97, reg, mask, value);	up(&ac97->reg_mutex);	return change;}/* no lock version - see snd_ac97_updat_bits() */int snd_ac97_update_bits_nolock(ac97_t *ac97, unsigned short reg,				unsigned short mask, unsigned short value){	int change;	unsigned short old, new;	old = snd_ac97_read_cache(ac97, reg);	new = (old & ~mask) | value;	change = old != new;	if (change) {		ac97->regs[reg] = new;		ac97->bus->ops->write(ac97, reg, new);	}	set_bit(reg, ac97->reg_accessed);	return change;}static int snd_ac97_ad18xx_update_pcm_bits(ac97_t *ac97, int codec, unsigned short mask, unsigned short value){	int change;	unsigned short old, new, cfg;	down(&ac97->page_mutex);	old = ac97->spec.ad18xx.pcmreg[codec];	new = (old & ~mask) | value;	change = old != new;	if (change) {		down(&ac97->reg_mutex);		cfg = snd_ac97_read_cache(ac97, AC97_AD_SERIAL_CFG);		ac97->spec.ad18xx.pcmreg[codec] = new;		/* select single codec */		ac97->bus->ops->write(ac97, AC97_AD_SERIAL_CFG,				 (cfg & ~0x7000) |				 ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);		/* update PCM bits */		ac97->bus->ops->write(ac97, AC97_PCM, new);		/* select all codecs */		ac97->bus->ops->write(ac97, AC97_AD_SERIAL_CFG,				 cfg | 0x7000);		up(&ac97->reg_mutex);	}	up(&ac97->page_mutex);	return change;}/* * Controls */int snd_ac97_info_enum_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value;		uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;	uinfo->count = e->shift_l == e->shift_r ? 1 : 2;	uinfo->value.enumerated.items = e->mask;		if (uinfo->value.enumerated.item > e->mask - 1)		uinfo->value.enumerated.item = e->mask - 1;	strcpy(uinfo->value.enumerated.name, e->texts[uinfo->value.enumerated.item]);	return 0;}int snd_ac97_get_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);	struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value;	unsigned short val, bitmask;		for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)		;	val = snd_ac97_read_cache(ac97, e->reg);	ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);	if (e->shift_l != e->shift_r)		ucontrol->value.enumerated.item[1] = (val >> e->shift_r) & (bitmask - 1);	return 0;}int snd_ac97_put_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);	struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value;	unsigned short val;	unsigned short mask, bitmask;		for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)		;	if (ucontrol->value.enumerated.item[0] > e->mask - 1)		return -EINVAL;	val = ucontrol->value.enumerated.item[0] << e->shift_l;	mask = (bitmask - 1) << e->shift_l;	if (e->shift_l != e->shift_r) {		if (ucontrol->value.enumerated.item[1] > e->mask - 1)			return -EINVAL;		val |= ucontrol->value.enumerated.item[1] << e->shift_r;		mask |= (bitmask - 1) << e->shift_r;	}	return snd_ac97_update_bits(ac97, e->reg, mask, val);}/* save/restore ac97 v2.3 paging */static int snd_ac97_page_save(ac97_t *ac97, int reg, snd_kcontrol_t *kcontrol){	int page_save = -1;	if ((kcontrol->private_value & (1<<25)) &&	    (ac97->ext_id & AC97_EI_REV_MASK) >= AC97_EI_REV_23 &&	    (reg >= 0x60 && reg < 0x70)) {		unsigned short page = (kcontrol->private_value >> 26) & 0x0f;		down(&ac97->page_mutex); /* lock paging */		page_save = snd_ac97_read(ac97, AC97_INT_PAGING) & AC97_PAGE_MASK;		snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page);	}	return page_save;}static void snd_ac97_page_restore(ac97_t *ac97, int page_save){	if (page_save >= 0) {		snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save);		up(&ac97->page_mutex); /* unlock paging */	}}/* volume and switch controls */int snd_ac97_info_volsw(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	int mask = (kcontrol->private_value >> 16) & 0xff;	int shift = (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;	uinfo->count = shift == rshift ? 1 : 2;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = mask;	return 0;}int snd_ac97_get_volsw(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) & 0x0f;	int rshift = (kcontrol->private_value >> 12) & 0x0f;	int mask = (kcontrol->private_value >> 16) & 0xff;	int invert = (kcontrol->private_value >> 24) & 0x01;	int page_save;	page_save = snd_ac97_page_save(ac97, reg, kcontrol);	ucontrol->value.integer.value[0] = (snd_ac97_read_cache(ac97, reg) >> shift) & mask;	if (shift != rshift)		ucontrol->value.integer.value[1] = (snd_ac97_read_cache(ac97, reg) >> rshift) & mask;	if (invert) {		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];		if (shift != rshift)			ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];	}	snd_ac97_page_restore(ac97, page_save);	return 0;}int snd_ac97_put_volsw(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) & 0x0f;	int rshift = (kcontrol->private_value >> 12) & 0x0f;	int mask = (kcontrol->private_value >> 16) & 0xff;	int invert = (kcontrol->private_value >> 24) & 0x01;	int err, page_save;	unsigned short val, val2, val_mask;		page_save = snd_ac97_page_save(ac97, reg, kcontrol);	val = (ucontrol->value.integer.value[0] & mask);	if (invert)		val = mask - val;	val_mask = mask << shift;	val = val << shift;	if (shift != rshift) {		val2 = (ucontrol->value.integer.value[1] & mask);		if (invert)			val2 = mask - val2;		val_mask |= mask << rshift;		val |= val2 << rshift;	}	err = snd_ac97_update_bits(ac97, reg, val_mask, val);	snd_ac97_page_restore(ac97, page_save);	return err;}static const snd_kcontrol_new_t snd_ac97_controls_master_mono[2] = {AC97_SINGLE("Master Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1),AC97_SINGLE("Master Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1)};static const snd_kcontrol_new_t snd_ac97_controls_tone[2] = {AC97_SINGLE("Tone Control - Bass", AC97_MASTER_TONE, 8, 15, 1),AC97_SINGLE("Tone Control - Treble", AC97_MASTER_TONE, 0, 15, 1)};static const snd_kcontrol_new_t snd_ac97_controls_pc_beep[2] = {AC97_SINGLE("PC Speaker Playback Switch", AC97_PC_BEEP, 15, 1, 1),AC97_SINGLE("PC Speaker Playback Volume", AC97_PC_BEEP, 1, 15, 1)};static const snd_kcontrol_new_t snd_ac97_controls_mic_boost =	AC97_SINGLE("Mic Boost (+20dB)", AC97_MIC, 6, 1, 0);static const char* std_rec_sel[] = {"Mic", "CD", "Video", "Aux", "Line", "Mix", "Mix Mono", "Phone"};static const char* std_3d_path[] = {"pre 3D", "post 3D"};static const char* std_mix[] = {"Mix", "Mic"};static const char* std_mic[] = {"Mic1", "Mic2"};static const struct ac97_enum std_enum[] = {AC97_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 8, std_rec_sel),AC97_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, std_3d_path),AC97_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 9, 2, std_mix),AC97_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, std_mic),};static const snd_kcontrol_new_t snd_ac97_control_capture_src = AC97_ENUM("Capture Source", std_enum[0]); static const snd_kcontrol_new_t snd_ac97_control_capture_vol =AC97_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 15, 0);static const snd_kcontrol_new_t snd_ac97_controls_mic_capture[2] = {AC97_SINGLE("Mic Capture Switch", AC97_REC_GAIN_MIC, 15, 1, 1),AC97_SINGLE("Mic Capture Volume", AC97_REC_GAIN_MIC, 0, 15, 0)};typedef enum {	AC97_GENERAL_PCM_OUT = 0,	AC97_GENERAL_STEREO_ENHANCEMENT,	AC97_GENERAL_3D,	AC97_GENERAL_LOUDNESS,	AC97_GENERAL_MONO,	AC97_GENERAL_MIC,	AC97_GENERAL_LOOPBACK} ac97_general_index_t;static const snd_kcontrol_new_t snd_ac97_controls_general[7] = {AC97_ENUM("PCM Out Path & Mute", std_enum[1]),AC97_SINGLE("Simulated Stereo Enhancement", AC97_GENERAL_PURPOSE, 14, 1, 0),AC97_SINGLE("3D Control - Switch", AC97_GENERAL_PURPOSE, 13, 1, 0),AC97_SINGLE("Loudness (bass boost)", AC97_GENERAL_PURPOSE, 12, 1, 0),AC97_ENUM("Mono Output Select", std_enum[2]),AC97_ENUM("Mic Select", std_enum[3]),AC97_SINGLE("ADC/DAC Loopback", AC97_GENERAL_PURPOSE, 7, 1, 0)};const snd_kcontrol_new_t snd_ac97_controls_3d[2] = {AC97_SINGLE("3D Control - Center", AC97_3D_CONTROL, 8, 15, 0),AC97_SINGLE("3D Control - Depth", AC97_3D_CONTROL, 0, 15, 0)};static const snd_kcontrol_new_t snd_ac97_controls_center[2] = {AC97_SINGLE("Center Playback Switch", AC97_CENTER_LFE_MASTER, 7, 1, 1),AC97_SINGLE("Center Playback Volume", AC97_CENTER_LFE_MASTER, 0, 31, 1)};static const snd_kcontrol_new_t snd_ac97_controls_lfe[2] = {AC97_SINGLE("LFE Playback Switch", AC97_CENTER_LFE_MASTER, 15, 1, 1),AC97_SINGLE("LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 31, 1)};static const snd_kcontrol_new_t snd_ac97_control_eapd =AC97_SINGLE("External Amplifier", AC97_POWERDOWN, 15, 1, 1);static const snd_kcontrol_new_t snd_ac97_controls_modem_switches[2] = {AC97_SINGLE("Off-hook Switch", AC97_GPIO_STATUS, 0, 1, 0),AC97_SINGLE("Caller ID Switch", AC97_GPIO_STATUS, 2, 1, 0)};/* change the existing EAPD control as inverted */static void set_inv_eapd(ac97_t *ac97, snd_kcontrol_t *kctl){	kctl->private_value = AC97_SINGLE_VALUE(AC97_POWERDOWN, 15, 1, 0);	snd_ac97_update_bits(ac97, AC97_POWERDOWN, (1<<15), (1<<15)); /* EAPD up */	ac97->scaps |= AC97_SCAP_INV_EAPD;}static int snd_ac97_spdif_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;	uinfo->count = 1;	return 0;}                        static int snd_ac97_spdif_cmask_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol){	ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL |					   IEC958_AES0_NONAUDIO |					   IEC958_AES0_CON_EMPHASIS_5015 |					   IEC958_AES0_CON_NOT_COPYRIGHT;	ucontrol->value.iec958.status[1] = IEC958_AES1_CON_CATEGORY |					   IEC958_AES1_CON_ORIGINAL;	ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS;	return 0;}                        static int snd_ac97_spdif_pmask_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol){	/* FIXME: AC'97 spec doesn't say which bits are used for what */	ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL |					   IEC958_AES0_NONAUDIO |					   IEC958_AES0_PRO_FS |					   IEC958_AES0_PRO_EMPHASIS_5015;	return 0;}static int snd_ac97_spdif_default_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol){	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);	down(&ac97->reg_mutex);	ucontrol->value.iec958.status[0] = ac97->spdif_status & 0xff;	ucontrol->value.iec958.status[1] = (ac97->spdif_status >> 8) & 0xff;	ucontrol->value.iec958.status[2] = (ac97->spdif_status >> 16) & 0xff;	ucontrol->value.iec958.status[3] = (ac97->spdif_status >> 24) & 0xff;	up(&ac97->reg_mutex);	return 0;}                        static int snd_ac97_spdif_default_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol){	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);	unsigned int new = 0;	unsigned short val = 0;	int change;	new = val = ucontrol->value.iec958.status[0] & (IEC958_AES0_PROFESSIONAL|IEC958_AES0_NONAUDIO);	if (ucontrol->value.iec958.status[0] & IEC958_AES0_PROFESSIONAL) {		new |= ucontrol->value.iec958.status[0] & (IEC958_AES0_PRO_FS|IEC958_AES0_PRO_EMPHASIS_5015);		switch (new & IEC958_AES0_PRO_FS) {		case IEC958_AES0_PRO_FS_44100: val |= 0<<12; break;		case IEC958_AES0_PRO_FS_48000: val |= 2<<12; break;		case IEC958_AES0_PRO_FS_32000: val |= 3<<12; break;		default:		       val |= 1<<12; break;		}		if ((new & IEC958_AES0_PRO_EMPHASIS) == IEC958_AES0_PRO_EMPHASIS_5015)			val |= 1<<3;	} else {		new |= ucontrol->value.iec958.status[0] & (IEC958_AES0_CON_EMPHASIS_5015|IEC958_AES0_CON_NOT_COPYRIGHT);		new |= ((ucontrol->value.iec958.status[1] & (IEC958_AES1_CON_CATEGORY|IEC958_AES1_CON_ORIGINAL)) << 8);		new |= ((ucontrol->value.iec958.status[3] & IEC958_AES3_CON_FS) << 24);		if ((new & IEC958_AES0_CON_EMPHASIS) == IEC958_AES0_CON_EMPHASIS_5015)			val |= 1<<3;		if (!(new & IEC958_AES0_CON_NOT_COPYRIGHT))			val |= 1<<2;		val |= ((new >> 8) & 0xff) << 4;	// category + original		switch ((new >> 24) & 0xff) {		case IEC958_AES3_CON_FS_44100: val |= 0<<12; break;		case IEC958_AES3_CON_FS_48000: val |= 2<<12; break;		case IEC958_AES3_CON_FS_32000: val |= 3<<12; break;		default:		       val |= 1<<12; break;		}	}	down(&ac97->reg_mutex);	change = ac97->spdif_status != new;	ac97->spdif_status = new;	if (ac97->flags & AC97_CS_SPDIF) {		int x = (val >> 12) & 0x03;		switch (x) {		case 0: x = 1; break;  // 44.1		case 2: x = 0; break;  // 48.0		default: x = 0; break; // illegal.		}		change |= snd_ac97_update_bits_nolock(ac97, AC97_CSR_SPDIF, 0x3fff, ((val & 0xcfff) | (x << 12)));	} else if (ac97->flags & AC97_CX_SPDIF) {		int v;		v = new & (IEC958_AES0_CON_EMPHASIS_5015|IEC958_AES0_CON_NOT_COPYRIGHT) ? 0 : AC97_CXR_COPYRGT;		v |= new & IEC958_AES0_NONAUDIO ? AC97_CXR_SPDIF_AC3 : AC97_CXR_SPDIF_PCM;		change |= snd_ac97_update_bits_nolock(ac97, AC97_CXR_AUDIO_MISC, 						      AC97_CXR_SPDIF_MASK | AC97_CXR_COPYRGT,						      v);	} else {		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, AC97_SPDIF, 0x3fff, val);

⌨️ 快捷键说明

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