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

📄 hda_codec.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	hda_nid_t nid = get_amp_nid(kcontrol);	int dir = get_amp_direction(kcontrol);	u32 caps, val1, val2;	if (size < 4 * sizeof(unsigned int))		return -ENOMEM;	caps = query_amp_caps(codec, nid, dir);	val2 = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT;	val2 = (val2 + 1) * 25;	val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT);	val1 = ((int)val1) * ((int)val2);	if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv))		return -EFAULT;	if (put_user(2 * sizeof(unsigned int), _tlv + 1))		return -EFAULT;	if (put_user(val1, _tlv + 2))		return -EFAULT;	if (put_user(val2, _tlv + 3))		return -EFAULT;	return 0;}/* switch */int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol,				  struct snd_ctl_elem_info *uinfo){	int chs = get_amp_channels(kcontrol);	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;	uinfo->count = chs == 3 ? 2 : 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 1;	return 0;}int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol,				 struct snd_ctl_elem_value *ucontrol){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	hda_nid_t nid = get_amp_nid(kcontrol);	int chs = get_amp_channels(kcontrol);	int dir = get_amp_direction(kcontrol);	int idx = get_amp_index(kcontrol);	long *valp = ucontrol->value.integer.value;	if (chs & 1)		*valp++ = (snd_hda_codec_amp_read(codec, nid, 0, dir, idx) &			   HDA_AMP_MUTE) ? 0 : 1;	if (chs & 2)		*valp = (snd_hda_codec_amp_read(codec, nid, 1, dir, idx) &			 HDA_AMP_MUTE) ? 0 : 1;	return 0;}int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,				 struct snd_ctl_elem_value *ucontrol){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	hda_nid_t nid = get_amp_nid(kcontrol);	int chs = get_amp_channels(kcontrol);	int dir = get_amp_direction(kcontrol);	int idx = get_amp_index(kcontrol);	long *valp = ucontrol->value.integer.value;	int change = 0;	snd_hda_power_up(codec);	if (chs & 1) {		change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,						  HDA_AMP_MUTE,						  *valp ? 0 : HDA_AMP_MUTE);		valp++;	}	if (chs & 2)		change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,						   HDA_AMP_MUTE,						   *valp ? 0 : HDA_AMP_MUTE);#ifdef CONFIG_SND_HDA_POWER_SAVE	if (codec->patch_ops.check_power_status)		codec->patch_ops.check_power_status(codec, nid);#endif	snd_hda_power_down(codec);	return change;}/* * bound volume controls * * bind multiple volumes (# indices, from 0) */#define AMP_VAL_IDX_SHIFT	19#define AMP_VAL_IDX_MASK	(0x0f<<19)int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol,				  struct snd_ctl_elem_value *ucontrol){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	unsigned long pval;	int err;	mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */	pval = kcontrol->private_value;	kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */	err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);	kcontrol->private_value = pval;	mutex_unlock(&codec->spdif_mutex);	return err;}int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol,				  struct snd_ctl_elem_value *ucontrol){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	unsigned long pval;	int i, indices, err = 0, change = 0;	mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */	pval = kcontrol->private_value;	indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT;	for (i = 0; i < indices; i++) {		kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) |			(i << AMP_VAL_IDX_SHIFT);		err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);		if (err < 0)			break;		change |= err;	}	kcontrol->private_value = pval;	mutex_unlock(&codec->spdif_mutex);	return err < 0 ? err : change;}/* * generic bound volume/swtich controls */int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol,				 struct snd_ctl_elem_info *uinfo){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	struct hda_bind_ctls *c;	int err;	c = (struct hda_bind_ctls *)kcontrol->private_value;	mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */	kcontrol->private_value = *c->values;	err = c->ops->info(kcontrol, uinfo);	kcontrol->private_value = (long)c;	mutex_unlock(&codec->spdif_mutex);	return err;}int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol,				struct snd_ctl_elem_value *ucontrol){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	struct hda_bind_ctls *c;	int err;	c = (struct hda_bind_ctls *)kcontrol->private_value;	mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */	kcontrol->private_value = *c->values;	err = c->ops->get(kcontrol, ucontrol);	kcontrol->private_value = (long)c;	mutex_unlock(&codec->spdif_mutex);	return err;}int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol,				struct snd_ctl_elem_value *ucontrol){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	struct hda_bind_ctls *c;	unsigned long *vals;	int err = 0, change = 0;	c = (struct hda_bind_ctls *)kcontrol->private_value;	mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */	for (vals = c->values; *vals; vals++) {		kcontrol->private_value = *vals;		err = c->ops->put(kcontrol, ucontrol);		if (err < 0)			break;		change |= err;	}	kcontrol->private_value = (long)c;	mutex_unlock(&codec->spdif_mutex);	return err < 0 ? err : change;}int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag,			   unsigned int size, unsigned int __user *tlv){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	struct hda_bind_ctls *c;	int err;	c = (struct hda_bind_ctls *)kcontrol->private_value;	mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */	kcontrol->private_value = *c->values;	err = c->ops->tlv(kcontrol, op_flag, size, tlv);	kcontrol->private_value = (long)c;	mutex_unlock(&codec->spdif_mutex);	return err;}struct hda_ctl_ops snd_hda_bind_vol = {	.info = snd_hda_mixer_amp_volume_info,	.get = snd_hda_mixer_amp_volume_get,	.put = snd_hda_mixer_amp_volume_put,	.tlv = snd_hda_mixer_amp_tlv};struct hda_ctl_ops snd_hda_bind_sw = {	.info = snd_hda_mixer_amp_switch_info,	.get = snd_hda_mixer_amp_switch_get,	.put = snd_hda_mixer_amp_switch_put,	.tlv = snd_hda_mixer_amp_tlv};/* * SPDIF out controls */static int snd_hda_spdif_mask_info(struct snd_kcontrol *kcontrol,				   struct snd_ctl_elem_info *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;	uinfo->count = 1;	return 0;}static int snd_hda_spdif_cmask_get(struct snd_kcontrol *kcontrol,				   struct snd_ctl_elem_value *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;	return 0;}static int snd_hda_spdif_pmask_get(struct snd_kcontrol *kcontrol,				   struct snd_ctl_elem_value *ucontrol){	ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL |					   IEC958_AES0_NONAUDIO |					   IEC958_AES0_PRO_EMPHASIS_5015;	return 0;}static int snd_hda_spdif_default_get(struct snd_kcontrol *kcontrol,				     struct snd_ctl_elem_value *ucontrol){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	ucontrol->value.iec958.status[0] = codec->spdif_status & 0xff;	ucontrol->value.iec958.status[1] = (codec->spdif_status >> 8) & 0xff;	ucontrol->value.iec958.status[2] = (codec->spdif_status >> 16) & 0xff;	ucontrol->value.iec958.status[3] = (codec->spdif_status >> 24) & 0xff;	return 0;}/* convert from SPDIF status bits to HDA SPDIF bits * bit 0 (DigEn) is always set zero (to be filled later) */static unsigned short convert_from_spdif_status(unsigned int sbits){	unsigned short val = 0;	if (sbits & IEC958_AES0_PROFESSIONAL)		val |= AC_DIG1_PROFESSIONAL;	if (sbits & IEC958_AES0_NONAUDIO)		val |= AC_DIG1_NONAUDIO;	if (sbits & IEC958_AES0_PROFESSIONAL) {		if ((sbits & IEC958_AES0_PRO_EMPHASIS) ==		    IEC958_AES0_PRO_EMPHASIS_5015)			val |= AC_DIG1_EMPHASIS;	} else {		if ((sbits & IEC958_AES0_CON_EMPHASIS) ==		    IEC958_AES0_CON_EMPHASIS_5015)			val |= AC_DIG1_EMPHASIS;		if (!(sbits & IEC958_AES0_CON_NOT_COPYRIGHT))			val |= AC_DIG1_COPYRIGHT;		if (sbits & (IEC958_AES1_CON_ORIGINAL << 8))			val |= AC_DIG1_LEVEL;		val |= sbits & (IEC958_AES1_CON_CATEGORY << 8);	}	return val;}/* convert to SPDIF status bits from HDA SPDIF bits */static unsigned int convert_to_spdif_status(unsigned short val){	unsigned int sbits = 0;	if (val & AC_DIG1_NONAUDIO)		sbits |= IEC958_AES0_NONAUDIO;	if (val & AC_DIG1_PROFESSIONAL)		sbits |= IEC958_AES0_PROFESSIONAL;	if (sbits & IEC958_AES0_PROFESSIONAL) {		if (sbits & AC_DIG1_EMPHASIS)			sbits |= IEC958_AES0_PRO_EMPHASIS_5015;	} else {		if (val & AC_DIG1_EMPHASIS)			sbits |= IEC958_AES0_CON_EMPHASIS_5015;		if (!(val & AC_DIG1_COPYRIGHT))			sbits |= IEC958_AES0_CON_NOT_COPYRIGHT;		if (val & AC_DIG1_LEVEL)			sbits |= (IEC958_AES1_CON_ORIGINAL << 8);		sbits |= val & (0x7f << 8);	}	return sbits;}static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,				     struct snd_ctl_elem_value *ucontrol){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	hda_nid_t nid = kcontrol->private_value;	unsigned short val;	int change;	mutex_lock(&codec->spdif_mutex);	codec->spdif_status = ucontrol->value.iec958.status[0] |		((unsigned int)ucontrol->value.iec958.status[1] << 8) |		((unsigned int)ucontrol->value.iec958.status[2] << 16) |		((unsigned int)ucontrol->value.iec958.status[3] << 24);	val = convert_from_spdif_status(codec->spdif_status);	val |= codec->spdif_ctls & 1;	change = codec->spdif_ctls != val;	codec->spdif_ctls = val;	if (change) {		snd_hda_codec_write_cache(codec, nid, 0,					  AC_VERB_SET_DIGI_CONVERT_1,					  val & 0xff);		snd_hda_codec_write_cache(codec, nid, 0,					  AC_VERB_SET_DIGI_CONVERT_2,					  val >> 8);	}	mutex_unlock(&codec->spdif_mutex);	return change;}#define snd_hda_spdif_out_switch_info	snd_ctl_boolean_mono_infostatic int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol,					struct snd_ctl_elem_value *ucontrol){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	ucontrol->value.integer.value[0] = codec->spdif_ctls & AC_DIG1_ENABLE;	return 0;}static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,					struct snd_ctl_elem_value *ucontrol){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	hda_nid_t nid = kcontrol->private_value;	unsigned short val;	int change;	mutex_lock(&codec->spdif_mutex);	val = codec->spdif_ctls & ~AC_DIG1_ENABLE;	if (ucontrol->value.integer.value[0])		val |= AC_DIG1_ENABLE;	change = codec->spdif_ctls != val;	if (change) {		codec->spdif_ctls = val;		snd_hda_codec_write_cache(codec, nid, 0,					  AC_VERB_SET_DIGI_CONVERT_1,					  val & 0xff);		/* unmute amp switch (if any) */		if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&		    (val & AC_DIG1_ENABLE))			snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,						 HDA_AMP_MUTE, 0);	}	mutex_unlock(&codec->spdif_mutex);	return change;}static struct snd_kcontrol_new dig_mixes[] = {	{		.access = SNDRV_CTL_ELEM_ACCESS_READ,		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),		.info = snd_hda_spdif_mask_info,		.get = snd_hda_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_hda_spdif_mask_info,		.get = snd_hda_spdif_pmask_get,	},	{		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),		.info = snd_hda_spdif_mask_info,		.get = snd_hda_spdif_default_get,		.put = snd_hda_spdif_default_put,	},	{		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH),		.info = snd_hda_spdif_out_switch_info,		.get = snd_hda_spdif_out_switch_get,		.put = snd_hda_spdif_out_switch_put,	},	{ } /* end */};/** * snd_hda_create_spdif_out_ctls - create Output SPDIF-related controls * @codec: the HDA codec * @nid: audio out widget NID * * Creates controls related with the SPDIF output. * Called from each patch supporting the SPDIF out. * * Returns 0 if successful, or a negative error code. */int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid){	int err;	struct snd_kcontrol *kctl;	struct snd_kcontrol_new *dig_mix;	for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) {		kctl = snd_ctl_new1(dig_mix, codec);		kctl->private_value = nid;		err = snd_ctl_add(codec->bus->card, kctl);		if (err < 0)			return err;	}	codec->spdif_ctls =		snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0);	codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls);	return 0;}/* * SPDIF input */#define snd_hda_spdif_in_switch_info	snd_hda_spdif_out_switch_infostatic int snd_hda_spdif_in_switch_get(struct snd_kcontrol *kcontrol,				       struct snd_ctl_elem_value *ucontrol){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	ucontrol->value.integer.value[0] = codec->spdif_in_enable;	return 0;}static int snd_hda_spdif_in_switch_put(struct snd_kcontrol *kcontrol,				       struct snd_ctl_elem_value *ucontrol){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	hda_nid_t nid = kcontrol->private_value;	unsigned int val = !!ucontrol->value.integer.value[0];	int change;	mutex_lock(&codec->spdif_mutex);	change = codec->spdif_in_enable != val;	if (change) {		codec->spdif_in_enable = val;		snd_hda_codec_write_cache(codec, nid, 0,					  AC_VERB_SET_DIGI_CONVERT_1, val);	}	mutex_unlock(&codec->spdif_mutex);	return change;}static int snd_hda_spdif_in_status_get(struct snd_kcontrol *kcontrol,				       struct snd_ctl_elem_value *ucontrol){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	hda_nid_t nid = kcontrol->private_value;	unsigned short val;	unsigned int sbits;	val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0);	sbits = convert_to_spdif_status(val);	ucontrol->value.iec958.status[0] = sbits;	ucontrol->value.iec958.status[1] = sbits >> 8;	ucontrol->value.iec958.status[2] = sbits >> 16;

⌨️ 快捷键说明

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