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

📄 patch_analog.c

📁 linux2.6.16版本
💻 C
📖 第 1 页 / 共 5 页
字号:
{	static hda_nid_t idx_to_dac[8] = {		/* A     B     C     D     E     F     G     H */		0x04, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a	};	static hda_nid_t idx_to_dac_rev2[8] = {		/* A     B     C     D     E     F     G     H */		0x04, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06	};	if (codec->revision_id == AD1988A_REV2)		return idx_to_dac_rev2[idx];	else		return idx_to_dac[idx];}static hda_nid_t ad1988_boost_nids[8] = {	0x38, 0x39, 0x3a, 0x3d, 0x3c, 0x3b, 0, 0};static int ad1988_pin_idx(hda_nid_t nid){	static hda_nid_t ad1988_io_pins[8] = {		0x11, 0x14, 0x15, 0x12, 0x17, 0x16, 0x24, 0x25	};	int i;	for (i = 0; i < ARRAY_SIZE(ad1988_io_pins); i++)		if (ad1988_io_pins[i] == nid)			return i;	return 0; /* should be -1 */}static int ad1988_pin_to_loopback_idx(hda_nid_t nid){	static int loopback_idx[8] = {		2, 0, 1, 3, 4, 5, 1, 4	};	switch (nid) {	case AD1988_PIN_CD_NID:		return 6;	default:		return loopback_idx[ad1988_pin_idx(nid)];	}}static int ad1988_pin_to_adc_idx(hda_nid_t nid){	static int adc_idx[8] = {		0, 1, 2, 8, 4, 3, 6, 7	};	switch (nid) {	case AD1988_PIN_CD_NID:		return 5;	default:		return adc_idx[ad1988_pin_idx(nid)];	}}/* fill in the dac_nids table from the parsed pin configuration */static int ad1988_auto_fill_dac_nids(struct hda_codec *codec,				     const struct auto_pin_cfg *cfg){	struct ad198x_spec *spec = codec->spec;	int i, idx;	spec->multiout.dac_nids = spec->private_dac_nids;	/* check the pins hardwired to audio widget */	for (i = 0; i < cfg->line_outs; i++) {		idx = ad1988_pin_idx(cfg->line_out_pins[i]);		spec->multiout.dac_nids[i] = ad1988_idx_to_dac(codec, idx);	}	spec->multiout.num_dacs = cfg->line_outs;	return 0;}/* add playback controls from the parsed DAC table */static int ad1988_auto_create_multi_out_ctls(struct ad198x_spec *spec,					     const struct auto_pin_cfg *cfg){	char name[32];	static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };	hda_nid_t nid;	int i, err;	for (i = 0; i < cfg->line_outs; i++) {		hda_nid_t dac = spec->multiout.dac_nids[i];		if (! dac)			continue;		nid = ad1988_mixer_nids[ad1988_pin_idx(cfg->line_out_pins[i])];		if (i == 2) {			/* Center/LFE */			err = add_control(spec, AD_CTL_WIDGET_VOL,					  "Center Playback Volume",					  HDA_COMPOSE_AMP_VAL(dac, 1, 0, HDA_OUTPUT));			if (err < 0)				return err;			err = add_control(spec, AD_CTL_WIDGET_VOL,					  "LFE Playback Volume",					  HDA_COMPOSE_AMP_VAL(dac, 2, 0, HDA_OUTPUT));			if (err < 0)				return err;			err = add_control(spec, AD_CTL_BIND_MUTE,					  "Center Playback Switch",					  HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT));			if (err < 0)				return err;			err = add_control(spec, AD_CTL_BIND_MUTE,					  "LFE Playback Switch",					  HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT));			if (err < 0)				return err;		} else {			sprintf(name, "%s Playback Volume", chname[i]);			err = add_control(spec, AD_CTL_WIDGET_VOL, name,					  HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT));			if (err < 0)				return err;			sprintf(name, "%s Playback Switch", chname[i]);			err = add_control(spec, AD_CTL_BIND_MUTE, name,					  HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));			if (err < 0)				return err;		}	}	return 0;}/* add playback controls for speaker and HP outputs */static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,					const char *pfx){	struct ad198x_spec *spec = codec->spec;	hda_nid_t nid;	int idx, err;	char name[32];	if (! pin)		return 0;	idx = ad1988_pin_idx(pin);	nid = ad1988_idx_to_dac(codec, idx);	if (! spec->multiout.dac_nids[0]) {		/* use this as the primary output */		spec->multiout.dac_nids[0] = nid;		if (! spec->multiout.num_dacs)			spec->multiout.num_dacs = 1;	} else 		/* specify the DAC as the extra output */		spec->multiout.hp_nid = nid;	/* control HP volume/switch on the output mixer amp */	sprintf(name, "%s Playback Volume", pfx);	if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name,			       HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)		return err;	nid = ad1988_mixer_nids[idx];	sprintf(name, "%s Playback Switch", pfx);	if ((err = add_control(spec, AD_CTL_BIND_MUTE, name,			       HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0)		return err;	return 0;}/* create input playback/capture controls for the given pin */static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,			    const char *ctlname, int boost){	char name[32];	int err, idx;	sprintf(name, "%s Playback Volume", ctlname);	idx = ad1988_pin_to_loopback_idx(pin);	if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name,			       HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0)		return err;	sprintf(name, "%s Playback Switch", ctlname);	if ((err = add_control(spec, AD_CTL_WIDGET_MUTE, name,			       HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0)		return err;	if (boost) {		hda_nid_t bnid;		idx = ad1988_pin_idx(pin);		bnid = ad1988_boost_nids[idx];		if (bnid) {			sprintf(name, "%s Boost", ctlname);			return add_control(spec, AD_CTL_WIDGET_VOL, name,					   HDA_COMPOSE_AMP_VAL(bnid, 3, idx, HDA_OUTPUT));		}	}	return 0;}/* create playback/capture controls for input pins */static int ad1988_auto_create_analog_input_ctls(struct ad198x_spec *spec,						const struct auto_pin_cfg *cfg){	struct hda_input_mux *imux = &spec->private_imux;	int i, err;	for (i = 0; i < AUTO_PIN_LAST; i++) {		err = new_analog_input(spec, cfg->input_pins[i],				       auto_pin_cfg_labels[i],				       i <= AUTO_PIN_FRONT_MIC);		if (err < 0)			return err;		imux->items[imux->num_items].label = auto_pin_cfg_labels[i];		imux->items[imux->num_items].index = ad1988_pin_to_adc_idx(cfg->input_pins[i]);		imux->num_items++;	}	imux->items[imux->num_items].label = "Mix";	imux->items[imux->num_items].index = 9;	imux->num_items++;	if ((err = add_control(spec, AD_CTL_WIDGET_VOL,			       "Analog Mix Playback Volume",			       HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0)		return err;	if ((err = add_control(spec, AD_CTL_WIDGET_MUTE,			       "Analog Mix Playback Switch",			       HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0)		return err;	return 0;}static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec,					      hda_nid_t nid, int pin_type,					      int dac_idx){	/* set as output */	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);	switch (nid) {	case 0x11: /* port-A - DAC 04 */		snd_hda_codec_write(codec, 0x37, 0, AC_VERB_SET_CONNECT_SEL, 0x01);		break;	case 0x14: /* port-B - DAC 06 */		snd_hda_codec_write(codec, 0x30, 0, AC_VERB_SET_CONNECT_SEL, 0x02);		break;	case 0x15: /* port-C - DAC 05 */		snd_hda_codec_write(codec, 0x31, 0, AC_VERB_SET_CONNECT_SEL, 0x00);		break;	case 0x17: /* port-E - DAC 0a */		snd_hda_codec_write(codec, 0x32, 0, AC_VERB_SET_CONNECT_SEL, 0x01);		break;	case 0x13: /* mono - DAC 04 */		snd_hda_codec_write(codec, 0x36, 0, AC_VERB_SET_CONNECT_SEL, 0x01);		break;	}}static void ad1988_auto_init_multi_out(struct hda_codec *codec){	struct ad198x_spec *spec = codec->spec;	int i;	for (i = 0; i < spec->autocfg.line_outs; i++) {		hda_nid_t nid = spec->autocfg.line_out_pins[i];		ad1988_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);	}}static void ad1988_auto_init_extra_out(struct hda_codec *codec){	struct ad198x_spec *spec = codec->spec;	hda_nid_t pin;	pin = spec->autocfg.speaker_pin;	if (pin) /* connect to front */		ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);	pin = spec->autocfg.hp_pin;	if (pin) /* connect to front */		ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);}static void ad1988_auto_init_analog_input(struct hda_codec *codec){	struct ad198x_spec *spec = codec->spec;	int i, idx;	for (i = 0; i < AUTO_PIN_LAST; i++) {		hda_nid_t nid = spec->autocfg.input_pins[i];		if (! nid)			continue;		switch (nid) {		case 0x15: /* port-C */			snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);			break;		case 0x17: /* port-E */			snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_CONNECT_SEL, 0x0);			break;		}		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,				    i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);		if (nid != AD1988_PIN_CD_NID)			snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,					    AMP_OUT_MUTE);		idx = ad1988_pin_idx(nid);		if (ad1988_boost_nids[idx])			snd_hda_codec_write(codec, ad1988_boost_nids[idx], 0,					    AC_VERB_SET_AMP_GAIN_MUTE,					    AMP_OUT_ZERO);	}}/* parse the BIOS configuration and set up the alc_spec *//* return 1 if successful, 0 if the proper config is not found, or a negative error code */static int ad1988_parse_auto_config(struct hda_codec *codec){	struct ad198x_spec *spec = codec->spec;	int err;	if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)		return err;	if ((err = ad1988_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)		return err;	if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin &&	    ! spec->autocfg.hp_pin)		return 0; /* can't find valid BIOS pin config */	if ((err = ad1988_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||	    (err = ad1988_auto_create_extra_out(codec, spec->autocfg.speaker_pin,						"Speaker")) < 0 ||	    (err = ad1988_auto_create_extra_out(codec, spec->autocfg.speaker_pin,						"Headphone")) < 0 ||	    (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)		return err;	spec->multiout.max_channels = spec->multiout.num_dacs * 2;	if (spec->autocfg.dig_out_pin)		spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;	if (spec->autocfg.dig_in_pin)		spec->dig_in_nid = AD1988_SPDIF_IN;	if (spec->kctl_alloc)		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;	spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs;	spec->input_mux = &spec->private_imux;	return 1;}/* init callback for auto-configuration model -- overriding the default init */static int ad1988_auto_init(struct hda_codec *codec){	ad198x_init(codec);	ad1988_auto_init_multi_out(codec);	ad1988_auto_init_extra_out(codec);	ad1988_auto_init_analog_input(codec);	return 0;}/* */static struct hda_board_config ad1988_cfg_tbl[] = {	{ .modelname = "6stack",	.config = AD1988_6STACK },	{ .modelname = "6stack-dig",	.config = AD1988_6STACK_DIG },	{ .modelname = "3stack",	.config = AD1988_3STACK },	{ .modelname = "3stack-dig",	.config = AD1988_3STACK_DIG },	{ .modelname = "laptop",	.config = AD1988_LAPTOP },	{ .modelname = "laptop-dig",	.config = AD1988_LAPTOP_DIG },	{ .modelname = "auto",		.config = AD1988_AUTO },	{}};static int patch_ad1988(struct hda_codec *codec){	struct ad198x_spec *spec;	int board_config;	spec = kzalloc(sizeof(*spec), GFP_KERNEL);	if (spec == NULL)		return -ENOMEM;	init_MUTEX(&spec->amp_mutex);	codec->spec = spec;	if (codec->revision_id == AD1988A_REV2)		snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n");	board_config = snd_hda_check_board_config(codec, ad1988_cfg_tbl);	if (board_config < 0 || board_config >= AD1988_MODEL_LAST) {		printk(KERN_INFO "hda_codec: Unknown model for AD1988, trying auto-probe from BIOS...\n");		board_config = AD1988_AUTO;	}	if (board_config == AD1988_AUTO) {		/* automatic parse from the BIOS config */		int err = ad1988_parse_auto_config(codec);		if (err < 0) {			ad198x_free(codec);			return err;		} else if (! err) {			printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS.  Using 6-stack mode...\n");			board_config = AD1988_6STACK;		}	}	switch (board_config) {	case AD1988_6STACK:	case AD1988_6STACK_DIG:		spec->multiout.max_channels = 8;		spec->multiout.num_dacs = 4;		if (codec->revision_id == AD1988A_REV2)			spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2;		else			spec->multiout.dac_nids = ad1988_6stack_

⌨️ 快捷键说明

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