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

📄 patch_via.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		if (err < 0)			return err;	}	if (spec->dig_in_nid) {		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);		if (err < 0)			return err;	}	return 0;}static int via_build_pcms(struct hda_codec *codec){	struct via_spec *spec = codec->spec;	struct hda_pcm *info = spec->pcm_rec;	codec->num_pcms = 1;	codec->pcm_info = info;	info->name = spec->stream_name_analog;	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);	info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];	info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];	info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =		spec->multiout.max_channels;	if (spec->multiout.dig_out_nid || spec->dig_in_nid) {		codec->num_pcms++;		info++;		info->name = spec->stream_name_digital;		if (spec->multiout.dig_out_nid) {			info->stream[SNDRV_PCM_STREAM_PLAYBACK] =				*(spec->stream_digital_playback);			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =				spec->multiout.dig_out_nid;		}		if (spec->dig_in_nid) {			info->stream[SNDRV_PCM_STREAM_CAPTURE] =				*(spec->stream_digital_capture);			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =				spec->dig_in_nid;		}	}	return 0;}static void via_free(struct hda_codec *codec){	struct via_spec *spec = codec->spec;	unsigned int i;	if (!spec)		return;	if (spec->kctl_alloc) {		for (i = 0; i < spec->num_kctl_used; i++)			kfree(spec->kctl_alloc[i].name);		kfree(spec->kctl_alloc);	}	kfree(codec->spec);}static int via_init(struct hda_codec *codec){	struct via_spec *spec = codec->spec;	snd_hda_sequence_write(codec, spec->init_verbs); 	return 0;}#ifdef CONFIG_SND_HDA_POWER_SAVEstatic int via_check_power_status(struct hda_codec *codec, hda_nid_t nid){	struct via_spec *spec = codec->spec;	return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);}#endif/* */static struct hda_codec_ops via_patch_ops = {	.build_controls = via_build_controls,	.build_pcms = via_build_pcms,	.init = via_init,	.free = via_free,#ifdef CONFIG_SND_HDA_POWER_SAVE	.check_power_status = via_check_power_status,#endif};/* fill in the dac_nids table from the parsed pin configuration */static int vt1708_auto_fill_dac_nids(struct via_spec *spec,				     const struct auto_pin_cfg *cfg){	int i;	hda_nid_t nid;	spec->multiout.num_dacs = cfg->line_outs;	spec->multiout.dac_nids = spec->private_dac_nids; 		for(i = 0; i < 4; i++) {		nid = cfg->line_out_pins[i];		if (nid) {			/* config dac list */			switch (i) {			case AUTO_SEQ_FRONT:				spec->multiout.dac_nids[i] = 0x10;				break;			case AUTO_SEQ_CENLFE:				spec->multiout.dac_nids[i] = 0x12;				break;			case AUTO_SEQ_SURROUND:				spec->multiout.dac_nids[i] = 0x13;				break;			case AUTO_SEQ_SIDE:				spec->multiout.dac_nids[i] = 0x11;				break;			}		}	}	return 0;}/* add playback controls from the parsed DAC table */static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,					     const struct auto_pin_cfg *cfg){	char name[32];	static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };	hda_nid_t nid, nid_vol = 0;	int i, err;	for (i = 0; i <= AUTO_SEQ_SIDE; i++) {		nid = cfg->line_out_pins[i];		if (!nid)			continue;				if (i != AUTO_SEQ_FRONT)			nid_vol = 0x1b - i + 1;		if (i == AUTO_SEQ_CENLFE) {			/* Center/LFE */			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,					      "Center Playback Volume",					      HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));			if (err < 0)				return err;			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,					      "LFE Playback Volume",					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));			if (err < 0)				return err;			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,					      "Center Playback Switch",					      HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));			if (err < 0)				return err;			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,					      "LFE Playback Switch",					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));			if (err < 0)				return err;		} else if (i == AUTO_SEQ_FRONT){			/* add control to mixer index 0 */			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,					      "Master Front Playback Volume",					      HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT));			if (err < 0)				return err;			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,					      "Master Front Playback Switch",					      HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT));			if (err < 0)				return err;						/* add control to PW3 */			sprintf(name, "%s Playback Volume", chname[i]);			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,					      HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));			if (err < 0)				return err;			sprintf(name, "%s Playback Switch", chname[i]);			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,					      HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));			if (err < 0)				return err;		} else {			sprintf(name, "%s Playback Volume", chname[i]);			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));			if (err < 0)				return err;			sprintf(name, "%s Playback Switch", chname[i]);			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));			if (err < 0)				return err;		}	}	return 0;}static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin){	int err;	if (!pin)		return 0;	spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,			      "Headphone Playback Volume",			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));	if (err < 0)		return err;	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,			      "Headphone Playback Switch",			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));	if (err < 0)		return err;	return 0;}/* create playback/capture controls for input pins */static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,						const struct auto_pin_cfg *cfg){	static char *labels[] = {		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL	};	struct hda_input_mux *imux = &spec->private_imux;	int i, err, idx = 0;	/* for internal loopback recording select */	imux->items[imux->num_items].label = "Stereo Mixer";	imux->items[imux->num_items].index = idx;	imux->num_items++;	for (i = 0; i < AUTO_PIN_LAST; i++) {		if (!cfg->input_pins[i])			continue;		switch (cfg->input_pins[i]) {		case 0x1d: /* Mic */			idx = 2;			break;						case 0x1e: /* Line In */			idx = 3;			break;		case 0x21: /* Front Mic */			idx = 4;			break;		case 0x24: /* CD */			idx = 1;			break;		}		err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],					   idx, 0x17);		if (err < 0)			return err;		imux->items[imux->num_items].label = labels[i];		imux->items[imux->num_items].index = idx;		imux->num_items++;	}	return 0;}#ifdef CONFIG_SND_HDA_POWER_SAVEstatic struct hda_amp_list vt1708_loopbacks[] = {	{ 0x17, HDA_INPUT, 1 },	{ 0x17, HDA_INPUT, 2 },	{ 0x17, HDA_INPUT, 3 },	{ 0x17, HDA_INPUT, 4 },	{ } /* end */};#endifstatic int vt1708_parse_auto_config(struct hda_codec *codec){	struct via_spec *spec = codec->spec;	int err;	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);	if (err < 0)		return err;	err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);	if (err < 0)		return err;	if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])		return 0; /* can't find valid BIOS pin config */	err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);	if (err < 0)		return err;	err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);	if (err < 0)		return err;	err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);	if (err < 0)		return err;	spec->multiout.max_channels = spec->multiout.num_dacs * 2;	if (spec->autocfg.dig_out_pin)		spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;	if (spec->autocfg.dig_in_pin)		spec->dig_in_nid = VT1708_DIGIN_NID;	if (spec->kctl_alloc)		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;	spec->init_verbs = vt1708_volume_init_verbs;		spec->input_mux = &spec->private_imux;	return 1;}/* init callback for auto-configuration model -- overriding the default init */static int via_auto_init(struct hda_codec *codec){	via_init(codec);	via_auto_init_multi_out(codec);	via_auto_init_hp_out(codec);	via_auto_init_analog_input(codec);	return 0;}static int patch_vt1708(struct hda_codec *codec){	struct via_spec *spec;	int err;	/* create a codec specific record */	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);	if (spec == NULL)		return -ENOMEM;	codec->spec = spec;	/* automatic parse from the BIOS config */	err = vt1708_parse_auto_config(codec);	if (err < 0) {		via_free(codec);		return err;	} else if (!err) {		printk(KERN_INFO "hda_codec: Cannot set up configuration "		       "from BIOS.  Using genenic mode...\n");	}		spec->stream_name_analog = "VT1708 Analog";	spec->stream_analog_playback = &vt1708_pcm_analog_playback;	spec->stream_analog_capture = &vt1708_pcm_analog_capture;	spec->stream_name_digital = "VT1708 Digital";	spec->stream_digital_playback = &vt1708_pcm_digital_playback;	spec->stream_digital_capture = &vt1708_pcm_digital_capture;		if (!spec->adc_nids && spec->input_mux) {		spec->adc_nids = vt1708_adc_nids;		spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);		spec->mixers[spec->num_mixers] = vt1708_capture_mixer;		spec->num_mixers++;	}	codec->patch_ops = via_patch_ops;	codec->patch_ops.init = via_auto_init;#ifdef CONFIG_SND_HDA_POWER_SAVE	spec->loopback.amplist = vt1708_loopbacks;#endif	return 0;}/* capture mixer elements */static struct snd_kcontrol_new vt1709_capture_mixer[] = {	HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),	HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),	HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),	HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),	{		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		/* The multiple "Capture Source" controls confuse alsamixer		 * So call somewhat different..		 * FIXME: the controls appear in the "playback" view!		 */		/* .name = "Capture Source", */		.name = "Input Source",		.count = 1,		.info = via_mux_enum_info,		.get = via_mux_enum_get,		.put = via_mux_enum_put,	},	{ } /* end */};/* * generic initialization of ADC, input mixers and output mixers */static struct hda_verb vt1709_10ch_volume_init_verbs[] = {	/*	 * Unmute ADC0-2 and set the default input to mic-in	 */	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},	/* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback	 * mixer widget	 */	/* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* unmute master */	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},	/*	 * Set up output selector (0x1a, 0x1b, 0x29)	 */	/* set vol=0 to output mixers */	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},	/*	 *  Unmute PW3 and PW4	 */	{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},	/* Set input of PW4 as AOW4 */	{0x20, AC_VERB_SET_CONNECT_SEL, 0x1},	/* Set mic as default input of sw0 */	{0x19, AC_VERB_SET_CONNECT_SEL, 0x2},	/* PW9 Output enable */	{0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},	{ }};static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {	.substreams = 1,	.channels_min = 2,	.channels_max = 10,	.nid = 0x10, /* NID to query formats and rates */	.ops = {		.open = via_playback_pcm_open,		.prepare = via_playback_pcm_prepare,		.cleanup = via_playback_pcm_cleanup	},};static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {	.substreams = 1,	.channels_min = 2,	.channels_max = 6,	.nid = 0x10, /* NID to query formats and rates */	.ops = {

⌨️ 快捷键说明

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