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

📄 hda_codec.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
 *//* * open the digital out in the exclusive mode */int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout){	mutex_lock(&codec->spdif_mutex);	if (mout->dig_out_used) {		mutex_unlock(&codec->spdif_mutex);		return -EBUSY; /* already being used */	}	mout->dig_out_used = HDA_DIG_EXCLUSIVE;	mutex_unlock(&codec->spdif_mutex);	return 0;}/* * release the digital out */int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout){	mutex_lock(&codec->spdif_mutex);	mout->dig_out_used = 0;	mutex_unlock(&codec->spdif_mutex);	return 0;}/* * set up more restrictions for analog out */int snd_hda_multi_out_analog_open(struct hda_codec *codec, struct hda_multi_out *mout,				  struct snd_pcm_substream *substream){	substream->runtime->hw.channels_max = mout->max_channels;	return snd_pcm_hw_constraint_step(substream->runtime, 0,					  SNDRV_PCM_HW_PARAM_CHANNELS, 2);}/* * set up the i/o for analog out * when the digital out is available, copy the front out to digital out, too. */int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout,				     unsigned int stream_tag,				     unsigned int format,				     struct snd_pcm_substream *substream){	hda_nid_t *nids = mout->dac_nids;	int chs = substream->runtime->channels;	int i;	mutex_lock(&codec->spdif_mutex);	if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {		if (chs == 2 &&		    snd_hda_is_supported_format(codec, mout->dig_out_nid, format) &&		    ! (codec->spdif_status & IEC958_AES0_NONAUDIO)) {			mout->dig_out_used = HDA_DIG_ANALOG_DUP;			/* setup digital receiver */			snd_hda_codec_setup_stream(codec, mout->dig_out_nid,						   stream_tag, 0, format);		} else {			mout->dig_out_used = 0;			snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0);		}	}	mutex_unlock(&codec->spdif_mutex);	/* front */	snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 0, format);	if (mout->hp_nid)		/* headphone out will just decode front left/right (stereo) */		snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format);	/* extra outputs copied from front */	for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)		if (mout->extra_out_nid[i])			snd_hda_codec_setup_stream(codec,						   mout->extra_out_nid[i],						   stream_tag, 0, format);	/* surrounds */	for (i = 1; i < mout->num_dacs; i++) {		if (chs >= (i + 1) * 2) /* independent out */			snd_hda_codec_setup_stream(codec, nids[i], stream_tag, i * 2,						   format);		else /* copy front */			snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 0,						   format);	}	return 0;}/* * clean up the setting for analog out */int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_out *mout){	hda_nid_t *nids = mout->dac_nids;	int i;	for (i = 0; i < mout->num_dacs; i++)		snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);	if (mout->hp_nid)		snd_hda_codec_setup_stream(codec, mout->hp_nid, 0, 0, 0);	for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)		if (mout->extra_out_nid[i])			snd_hda_codec_setup_stream(codec,						   mout->extra_out_nid[i],						   0, 0, 0);	mutex_lock(&codec->spdif_mutex);	if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) {		snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0);		mout->dig_out_used = 0;	}	mutex_unlock(&codec->spdif_mutex);	return 0;}/* * Helper for automatic ping configuration */static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list){	for (; *list; list++)		if (*list == nid)			return 1;	return 0;}/* * Parse all pin widgets and store the useful pin nids to cfg * * The number of line-outs or any primary output is stored in line_outs, * and the corresponding output pins are assigned to line_out_pins[], * in the order of front, rear, CLFE, side, ... * * If more extra outputs (speaker and headphone) are found, the pins are * assisnged to hp_pin and speaker_pins[], respectively.  If no line-out jack * is detected, one of speaker of HP pins is assigned as the primary * output, i.e. to line_out_pins[0].  So, line_outs is always positive * if any analog output exists. *  * The analog input pins are assigned to input_pins array. * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, * respectively. */int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg,				 hda_nid_t *ignore_nids){	hda_nid_t nid, nid_start;	int i, j, nodes;	short seq, assoc_line_out, sequences[ARRAY_SIZE(cfg->line_out_pins)];	memset(cfg, 0, sizeof(*cfg));	memset(sequences, 0, sizeof(sequences));	assoc_line_out = 0;	nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start);	for (nid = nid_start; nid < nodes + nid_start; nid++) {		unsigned int wid_caps = get_wcaps(codec, nid);		unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;		unsigned int def_conf;		short assoc, loc;		/* read all default configuration for pin complex */		if (wid_type != AC_WID_PIN)			continue;		/* ignore the given nids (e.g. pc-beep returns error) */		if (ignore_nids && is_in_nid_list(nid, ignore_nids))			continue;		def_conf = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);		if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)			continue;		loc = get_defcfg_location(def_conf);		switch (get_defcfg_device(def_conf)) {		case AC_JACK_LINE_OUT:			seq = get_defcfg_sequence(def_conf);			assoc = get_defcfg_association(def_conf);			if (! assoc)				continue;			if (! assoc_line_out)				assoc_line_out = assoc;			else if (assoc_line_out != assoc)				continue;			if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins))				continue;			cfg->line_out_pins[cfg->line_outs] = nid;			sequences[cfg->line_outs] = seq;			cfg->line_outs++;			break;		case AC_JACK_SPEAKER:			if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins))				continue;			cfg->speaker_pins[cfg->speaker_outs] = nid;			cfg->speaker_outs++;			break;		case AC_JACK_HP_OUT:			cfg->hp_pin = nid;			break;		case AC_JACK_MIC_IN:			if (loc == AC_JACK_LOC_FRONT)				cfg->input_pins[AUTO_PIN_FRONT_MIC] = nid;			else				cfg->input_pins[AUTO_PIN_MIC] = nid;			break;		case AC_JACK_LINE_IN:			if (loc == AC_JACK_LOC_FRONT)				cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid;			else				cfg->input_pins[AUTO_PIN_LINE] = nid;			break;		case AC_JACK_CD:			cfg->input_pins[AUTO_PIN_CD] = nid;			break;		case AC_JACK_AUX:			cfg->input_pins[AUTO_PIN_AUX] = nid;			break;		case AC_JACK_SPDIF_OUT:			cfg->dig_out_pin = nid;			break;		case AC_JACK_SPDIF_IN:			cfg->dig_in_pin = nid;			break;		}	}	/* sort by sequence */	for (i = 0; i < cfg->line_outs; i++)		for (j = i + 1; j < cfg->line_outs; j++)			if (sequences[i] > sequences[j]) {				seq = sequences[i];				sequences[i] = sequences[j];				sequences[j] = seq;				nid = cfg->line_out_pins[i];				cfg->line_out_pins[i] = cfg->line_out_pins[j];				cfg->line_out_pins[j] = nid;			}	/* Reorder the surround channels	 * ALSA sequence is front/surr/clfe/side	 * HDA sequence is:	 *    4-ch: front/surr  =>  OK as it is	 *    6-ch: front/clfe/surr	 *    8-ch: front/clfe/side/surr	 */	switch (cfg->line_outs) {	case 3:		nid = cfg->line_out_pins[1];		cfg->line_out_pins[1] = cfg->line_out_pins[2];		cfg->line_out_pins[2] = nid;		break;	case 4:		nid = cfg->line_out_pins[1];		cfg->line_out_pins[1] = cfg->line_out_pins[3];		cfg->line_out_pins[3] = cfg->line_out_pins[2];		cfg->line_out_pins[2] = nid;		break;	}	/*	 * debug prints of the parsed results	 */	snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",		   cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],		   cfg->line_out_pins[2], cfg->line_out_pins[3],		   cfg->line_out_pins[4]);	snd_printd("   speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",		   cfg->speaker_outs, cfg->speaker_pins[0],		   cfg->speaker_pins[1], cfg->speaker_pins[2],		   cfg->speaker_pins[3], cfg->speaker_pins[4]);	snd_printd("   hp=0x%x, dig_out=0x%x, din_in=0x%x\n",		   cfg->hp_pin, cfg->dig_out_pin, cfg->dig_in_pin);	snd_printd("   inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x,"		   " cd=0x%x, aux=0x%x\n",		   cfg->input_pins[AUTO_PIN_MIC],		   cfg->input_pins[AUTO_PIN_FRONT_MIC],		   cfg->input_pins[AUTO_PIN_LINE],		   cfg->input_pins[AUTO_PIN_FRONT_LINE],		   cfg->input_pins[AUTO_PIN_CD],		   cfg->input_pins[AUTO_PIN_AUX]);	/*	 * FIX-UP: if no line-outs are detected, try to use speaker or HP pin	 * as a primary output	 */	if (! cfg->line_outs) {		if (cfg->speaker_outs) {			cfg->line_outs = cfg->speaker_outs;			memcpy(cfg->line_out_pins, cfg->speaker_pins,			       sizeof(cfg->speaker_pins));			cfg->speaker_outs = 0;			memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));		} else if (cfg->hp_pin) {			cfg->line_outs = 1;			cfg->line_out_pins[0] = cfg->hp_pin;			cfg->hp_pin = 0;		}	}	return 0;}/* labels for input pins */const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = {	"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux"};#ifdef CONFIG_PM/* * power management *//** * snd_hda_suspend - suspend the codecs * @bus: the HDA bus * @state: suspsend state * * Returns 0 if successful. */int snd_hda_suspend(struct hda_bus *bus, pm_message_t state){	struct list_head *p;	/* FIXME: should handle power widget capabilities */	list_for_each(p, &bus->codec_list) {		struct hda_codec *codec = list_entry(p, struct hda_codec, list);		if (codec->patch_ops.suspend)			codec->patch_ops.suspend(codec, state);		hda_set_power_state(codec,				    codec->afg ? codec->afg : codec->mfg,				    AC_PWRST_D3);	}	return 0;}/** * snd_hda_resume - resume the codecs * @bus: the HDA bus * @state: resume state * * Returns 0 if successful. */int snd_hda_resume(struct hda_bus *bus){	struct list_head *p;	list_for_each(p, &bus->codec_list) {		struct hda_codec *codec = list_entry(p, struct hda_codec, list);		hda_set_power_state(codec,				    codec->afg ? codec->afg : codec->mfg,				    AC_PWRST_D0);		if (codec->patch_ops.resume)			codec->patch_ops.resume(codec);	}	return 0;}/** * snd_hda_resume_ctls - resume controls in the new control list * @codec: the HDA codec * @knew: the array of struct snd_kcontrol_new * * This function resumes the mixer controls in the struct snd_kcontrol_new array, * originally for snd_hda_add_new_ctls(). * The array must be terminated with an empty entry as terminator. */int snd_hda_resume_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew){	struct snd_ctl_elem_value *val;	val = kmalloc(sizeof(*val), GFP_KERNEL);	if (! val)		return -ENOMEM;	codec->in_resume = 1;	for (; knew->name; knew++) {		int i, count;		count = knew->count ? knew->count : 1;		for (i = 0; i < count; i++) {			memset(val, 0, sizeof(*val));			val->id.iface = knew->iface;			val->id.device = knew->device;			val->id.subdevice = knew->subdevice;			strcpy(val->id.name, knew->name);			val->id.index = knew->index ? knew->index : i;			/* Assume that get callback reads only from cache,			 * not accessing to the real hardware			 */			if (snd_ctl_elem_read(codec->bus->card, val) < 0)				continue;			snd_ctl_elem_write(codec->bus->card, NULL, val);		}	}	codec->in_resume = 0;	kfree(val);	return 0;}/** * snd_hda_resume_spdif_out - resume the digital out * @codec: the HDA codec */int snd_hda_resume_spdif_out(struct hda_codec *codec){	return snd_hda_resume_ctls(codec, dig_mixes);}/** * snd_hda_resume_spdif_in - resume the digital in * @codec: the HDA codec */int snd_hda_resume_spdif_in(struct hda_codec *codec){	return snd_hda_resume_ctls(codec, dig_in_ctls);}#endif/* * symbols exported for controller modules */EXPORT_SYMBOL(snd_hda_codec_read);EXPORT_SYMBOL(snd_hda_codec_write);EXPORT_SYMBOL(snd_hda_sequence_write);EXPORT_SYMBOL(snd_hda_get_sub_nodes);EXPORT_SYMBOL(snd_hda_queue_unsol_event);EXPORT_SYMBOL(snd_hda_bus_new);EXPORT_SYMBOL(snd_hda_codec_new);EXPORT_SYMBOL(snd_hda_codec_setup_stream);EXPORT_SYMBOL(snd_hda_calc_stream_format);EXPORT_SYMBOL(snd_hda_build_pcms);EXPORT_SYMBOL(snd_hda_build_controls);#ifdef CONFIG_PMEXPORT_SYMBOL(snd_hda_suspend);EXPORT_SYMBOL(snd_hda_resume);#endif/* *  INIT part */static int __init alsa_hda_init(void){	return 0;}static void __exit alsa_hda_exit(void){}module_init(alsa_hda_init)module_exit(alsa_hda_exit)

⌨️ 快捷键说明

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