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

📄 hda_codec.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
			break;		change |= err;	}	kcontrol->private_value = pval;	mutex_unlock(&codec->spdif_mutex);	return err < 0 ? err : change;}/* * 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 |= 1 << 6;	if (sbits & IEC958_AES0_NONAUDIO)		val |= 1 << 5;	if (sbits & IEC958_AES0_PROFESSIONAL) {		if ((sbits & IEC958_AES0_PRO_EMPHASIS) == IEC958_AES0_PRO_EMPHASIS_5015)			val |= 1 << 3;	} else {		if ((sbits & IEC958_AES0_CON_EMPHASIS) == IEC958_AES0_CON_EMPHASIS_5015)			val |= 1 << 3;		if (! (sbits & IEC958_AES0_CON_NOT_COPYRIGHT))			val |= 1 << 4;		if (sbits & (IEC958_AES1_CON_ORIGINAL << 8))			val |= 1 << 7;		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 & (1 << 5))		sbits |= IEC958_AES0_NONAUDIO;	if (val & (1 << 6))		sbits |= IEC958_AES0_PROFESSIONAL;	if (sbits & IEC958_AES0_PROFESSIONAL) {		if (sbits & (1 << 3))			sbits |= IEC958_AES0_PRO_EMPHASIS_5015;	} else {		if (val & (1 << 3))			sbits |= IEC958_AES0_CON_EMPHASIS_5015;		if (! (val & (1 << 4)))			sbits |= IEC958_AES0_CON_NOT_COPYRIGHT;		if (val & (1 << 7))			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 || codec->in_resume) {		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, val & 0xff);		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_2, val >> 8);	}	mutex_unlock(&codec->spdif_mutex);	return change;}static int snd_hda_spdif_out_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 1;	return 0;}static 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 & 1;	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 & ~1;	if (ucontrol->value.integer.value[0])		val |= 1;	change = codec->spdif_ctls != val;	if (change || codec->in_resume) {		codec->spdif_ctls = val;		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, val & 0xff);		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,				    AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT |				    AC_AMP_SET_OUTPUT | ((val & 1) ? 0 : 0x80));	}	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;		if ((err = snd_ctl_add(codec->bus->card, kctl)) < 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->in_resume) {		codec->spdif_in_enable = val;		snd_hda_codec_write(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;	ucontrol->value.iec958.status[3] = sbits >> 24;	return 0;}static struct snd_kcontrol_new dig_in_ctls[] = {	{		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		.name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH),		.info = snd_hda_spdif_in_switch_info,		.get = snd_hda_spdif_in_switch_get,		.put = snd_hda_spdif_in_switch_put,	},	{		.access = SNDRV_CTL_ELEM_ACCESS_READ,		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		.name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT),		.info = snd_hda_spdif_mask_info,		.get = snd_hda_spdif_in_status_get,	},	{ } /* end */};/** * snd_hda_create_spdif_in_ctls - create Input SPDIF-related controls * @codec: the HDA codec * @nid: audio in widget NID * * Creates controls related with the SPDIF input. * Called from each patch supporting the SPDIF in. * * Returns 0 if successful, or a negative error code. */int snd_hda_create_spdif_in_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_in_ctls; dig_mix->name; dig_mix++) {		kctl = snd_ctl_new1(dig_mix, codec);		kctl->private_value = nid;		if ((err = snd_ctl_add(codec->bus->card, kctl)) < 0)			return err;	}	codec->spdif_in_enable = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0) & 1;	return 0;}/* * set power state of the codec */static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,				unsigned int power_state){	hda_nid_t nid, nid_start;	int nodes;	snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE,			    power_state);	nodes = snd_hda_get_sub_nodes(codec, fg, &nid_start);	for (nid = nid_start; nid < nodes + nid_start; nid++) {		if (get_wcaps(codec, nid) & AC_WCAP_POWER)			snd_hda_codec_write(codec, nid, 0,					    AC_VERB_SET_POWER_STATE,					    power_state);	}	if (power_state == AC_PWRST_D0)		msleep(10);}/** * snd_hda_build_controls - build mixer controls * @bus: the BUS * * Creates mixer controls for each codec included in the bus. * * Returns 0 if successful, otherwise a negative error code. */int snd_hda_build_controls(struct hda_bus *bus){	struct list_head *p;	/* build controls */	list_for_each(p, &bus->codec_list) {		struct hda_codec *codec = list_entry(p, struct hda_codec, list);		int err;		if (! codec->patch_ops.build_controls)			continue;		err = codec->patch_ops.build_controls(codec);		if (err < 0)			return err;	}	/* initialize */	list_for_each(p, &bus->codec_list) {		struct hda_codec *codec = list_entry(p, struct hda_codec, list);		int err;		hda_set_power_state(codec,				    codec->afg ? codec->afg : codec->mfg,				    AC_PWRST_D0);		if (! codec->patch_ops.init)			continue;		err = codec->patch_ops.init(codec);		if (err < 0)			return err;	}	return 0;}/* * stream formats */struct hda_rate_tbl {	unsigned int hz;	unsigned int alsa_bits;	unsigned int hda_fmt;};static struct hda_rate_tbl rate_bits[] = {	/* rate in Hz, ALSA rate bitmask, HDA format value */	/* autodetected value used in snd_hda_query_supported_pcm */	{ 8000, SNDRV_PCM_RATE_8000, 0x0500 }, /* 1/6 x 48 */	{ 11025, SNDRV_PCM_RATE_11025, 0x4300 }, /* 1/4 x 44 */	{ 16000, SNDRV_PCM_RATE_16000, 0x0200 }, /* 1/3 x 48 */	{ 22050, SNDRV_PCM_RATE_22050, 0x4100 }, /* 1/2 x 44 */	{ 32000, SNDRV_PCM_RATE_32000, 0x0a00 }, /* 2/3 x 48 */	{ 44100, SNDRV_PCM_RATE_44100, 0x4000 }, /* 44 */	{ 48000, SNDRV_PCM_RATE_48000, 0x0000 }, /* 48 */	{ 88200, SNDRV_PCM_RATE_88200, 0x4800 }, /* 2 x 44 */	{ 96000, SNDRV_PCM_RATE_96000, 0x0800 }, /* 2 x 48 */	{ 176400, SNDRV_PCM_RATE_176400, 0x5800 },/* 4 x 44 */	{ 192000, SNDRV_PCM_RATE_192000, 0x1800 }, /* 4 x 48 */	/* not autodetected value */	{ 9600, SNDRV_PCM_RATE_KNOT, 0x0400 }, /* 1/5 x 48 */	{ 0 } /* terminator */};/** * snd_hda_calc_stream_format - calculate format bitset * @rate: the sample rate * @channels: the number of channels * @format: the PCM format (SNDRV_PCM_FORMAT_XXX) * @maxbps: the max. bps * * Calculate the format bitset from the given rate, channels and th PCM format. * * Return zero if invalid. */unsigned int snd_hda_calc_stream_format(unsigned int rate,					unsigned int channels,					unsigned int format,					unsigned int maxbps){	int i;	unsigned int val = 0;	for (i = 0; rate_bits[i].hz; i++)		if (rate_bits[i].hz == rate) {			val = rate_bits[i].hda_fmt;			break;		}	if (! rate_bits[i].hz) {		snd_printdd("invalid rate %d\n", rate);		return 0;	}	if (channels == 0 || channels > 8) {		snd_printdd("invalid channels %d\n", channels);		return 0;	}	val |= channels - 1;	switch (snd_pcm_format_width(format)) {	case 8:  val |= 0x00; break;	case 16: val |= 0x10; break;	case 20:	case 24:	case 32:		if (maxbps >= 32)			val |= 0x40;

⌨️ 快捷键说明

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