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

📄 patch_sigmatel.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	return 0;}static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid){	if (is_in_dac_nids(spec, nid))		return 1;	if (spec->multiout.hp_nid == nid)		return 1;	return 0;}static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid){	if (!spec->multiout.hp_nid)		spec->multiout.hp_nid = nid;	else if (spec->multiout.num_dacs > 4) {		printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);		return 1;	} else {		spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;		spec->multiout.num_dacs++;	}	return 0;}/* add playback controls for Speaker and HP outputs */static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,					struct auto_pin_cfg *cfg){	struct sigmatel_spec *spec = codec->spec;	hda_nid_t nid;	int i, old_num_dacs, err;	old_num_dacs = spec->multiout.num_dacs;	for (i = 0; i < cfg->hp_outs; i++) {		unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);		if (wid_caps & AC_WCAP_UNSOL_CAP)			spec->hp_detect = 1;		nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,					 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;		if (check_in_dac_nids(spec, nid))			nid = 0;		if (! nid)			continue;		add_spec_dacs(spec, nid);	}	for (i = 0; i < cfg->speaker_outs; i++) {		nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,					 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;		if (check_in_dac_nids(spec, nid))			nid = 0;		if (! nid)			continue;		add_spec_dacs(spec, nid);	}	for (i = 0; i < cfg->line_outs; i++) {		nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,					AC_VERB_GET_CONNECT_LIST, 0) & 0xff;		if (check_in_dac_nids(spec, nid))			nid = 0;		if (! nid)			continue;		add_spec_dacs(spec, nid);	}	for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {		static const char *pfxs[] = {			"Speaker", "External Speaker", "Speaker2",		};		err = create_controls(spec, pfxs[i - old_num_dacs],				      spec->multiout.dac_nids[i], 3);		if (err < 0)			return err;	}	if (spec->multiout.hp_nid) {		const char *pfx;		if (old_num_dacs == spec->multiout.num_dacs)			pfx = "Master";		else			pfx = "Headphone";		err = create_controls(spec, pfx, spec->multiout.hp_nid, 3);		if (err < 0)			return err;	}	return 0;}/* labels for dmic mux inputs */static const char *stac92xx_dmic_labels[5] = {	"Analog Inputs", "Digital Mic 1", "Digital Mic 2",	"Digital Mic 3", "Digital Mic 4"};/* create playback/capture controls for input pins on dmic capable codecs */static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,						const struct auto_pin_cfg *cfg){	struct sigmatel_spec *spec = codec->spec;	struct hda_input_mux *dimux = &spec->private_dimux;	hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];	int i, j;	dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];	dimux->items[dimux->num_items].index = 0;	dimux->num_items++;	for (i = 0; i < spec->num_dmics; i++) {		int index;		int num_cons;		unsigned int def_conf;		def_conf = snd_hda_codec_read(codec,					      spec->dmic_nids[i],					      0,					      AC_VERB_GET_CONFIG_DEFAULT,					      0);		if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)			continue;		num_cons = snd_hda_get_connections(codec,				spec->dmux_nid,				con_lst,				HDA_MAX_NUM_INPUTS);		for (j = 0; j < num_cons; j++)			if (con_lst[j] == spec->dmic_nids[i]) {				index = j;				goto found;			}		continue;found:		dimux->items[dimux->num_items].label =			stac92xx_dmic_labels[dimux->num_items];		dimux->items[dimux->num_items].index = index;		dimux->num_items++;	}	return 0;}/* create playback/capture controls for input pins */static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg){	struct sigmatel_spec *spec = codec->spec;	struct hda_input_mux *imux = &spec->private_imux;	hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];	int i, j, k;	for (i = 0; i < AUTO_PIN_LAST; i++) {		int index;		if (!cfg->input_pins[i])			continue;		index = -1;		for (j = 0; j < spec->num_muxes; j++) {			int num_cons;			num_cons = snd_hda_get_connections(codec,							   spec->mux_nids[j],							   con_lst,							   HDA_MAX_NUM_INPUTS);			for (k = 0; k < num_cons; k++)				if (con_lst[k] == cfg->input_pins[i]) {					index = k;					goto found;				}		}		continue;	found:		imux->items[imux->num_items].label = auto_pin_cfg_labels[i];		imux->items[imux->num_items].index = index;		imux->num_items++;	}	if (imux->num_items) {		/*		 * Set the current input for the muxes.		 * The STAC9221 has two input muxes with identical source		 * NID lists.  Hopefully this won't get confused.		 */		for (i = 0; i < spec->num_muxes; i++) {			snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,						  AC_VERB_SET_CONNECT_SEL,						  imux->items[0].index);		}	}	return 0;}static void stac92xx_auto_init_multi_out(struct hda_codec *codec){	struct sigmatel_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];		stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);	}}static void stac92xx_auto_init_hp_out(struct hda_codec *codec){	struct sigmatel_spec *spec = codec->spec;	int i;	for (i = 0; i < spec->autocfg.hp_outs; i++) {		hda_nid_t pin;		pin = spec->autocfg.hp_pins[i];		if (pin) /* connect to front */			stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);	}	for (i = 0; i < spec->autocfg.speaker_outs; i++) {		hda_nid_t pin;		pin = spec->autocfg.speaker_pins[i];		if (pin) /* connect to front */			stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);	}}static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in){	struct sigmatel_spec *spec = codec->spec;	int err;	if ((err = snd_hda_parse_pin_def_config(codec,						&spec->autocfg,						spec->dmic_nids)) < 0)		return err;	if (! spec->autocfg.line_outs)		return 0; /* can't find valid pin config */	if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)		return err;	if (spec->multiout.num_dacs == 0)		if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)			return err;	err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);	if (err < 0)		return err;	err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);	if (err < 0)		return err;	err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);	if (err < 0)		return err;	if (spec->num_dmics > 0)		if ((err = stac92xx_auto_create_dmic_input_ctls(codec,						&spec->autocfg)) < 0)			return err;	spec->multiout.max_channels = spec->multiout.num_dacs * 2;	if (spec->multiout.max_channels > 2)		spec->surr_switch = 1;	if (spec->autocfg.dig_out_pin)		spec->multiout.dig_out_nid = dig_out;	if (spec->autocfg.dig_in_pin)		spec->dig_in_nid = dig_in;	if (spec->kctl_alloc)		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;	spec->input_mux = &spec->private_imux;	spec->dinput_mux = &spec->private_dimux;	return 1;}/* add playback controls for HP output */static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,					struct auto_pin_cfg *cfg){	struct sigmatel_spec *spec = codec->spec;	hda_nid_t pin = cfg->hp_pins[0];	unsigned int wid_caps;	if (! pin)		return 0;	wid_caps = get_wcaps(codec, pin);	if (wid_caps & AC_WCAP_UNSOL_CAP)		spec->hp_detect = 1;	return 0;}/* add playback controls for LFE output */static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,					struct auto_pin_cfg *cfg){	struct sigmatel_spec *spec = codec->spec;	int err;	hda_nid_t lfe_pin = 0x0;	int i;	/*	 * search speaker outs and line outs for a mono speaker pin	 * with an amp.  If one is found, add LFE controls	 * for it.	 */	for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {		hda_nid_t pin = spec->autocfg.speaker_pins[i];		unsigned long wcaps = get_wcaps(codec, pin);		wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);		if (wcaps == AC_WCAP_OUT_AMP)			/* found a mono speaker with an amp, must be lfe */			lfe_pin = pin;	}	/* if speaker_outs is 0, then speakers may be in line_outs */	if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {		for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {			hda_nid_t pin = spec->autocfg.line_out_pins[i];			unsigned long cfg;			cfg = snd_hda_codec_read(codec, pin, 0,						 AC_VERB_GET_CONFIG_DEFAULT,						 0x00);			if (get_defcfg_device(cfg) == AC_JACK_SPEAKER) {				unsigned long wcaps = get_wcaps(codec, pin);				wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);				if (wcaps == AC_WCAP_OUT_AMP)					/* found a mono speaker with an amp,					   must be lfe */					lfe_pin = pin;			}		}	}	if (lfe_pin) {		err = create_controls(spec, "LFE", lfe_pin, 1);		if (err < 0)			return err;	}	return 0;}static int stac9200_parse_auto_config(struct hda_codec *codec){	struct sigmatel_spec *spec = codec->spec;	int err;	if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)		return err;	if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)		return err;	if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)		return err;	if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)		return err;	if (spec->autocfg.dig_out_pin)		spec->multiout.dig_out_nid = 0x05;	if (spec->autocfg.dig_in_pin)		spec->dig_in_nid = 0x04;	if (spec->kctl_alloc)		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;	spec->input_mux = &spec->private_imux;	spec->dinput_mux = &spec->private_dimux;	return 1;}/* * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a * funky external mute control using GPIO pins. */static void stac922x_gpio_mute(struct hda_codec *codec, int pin, int muted){	unsigned int gpiostate, gpiomask, gpiodir;	gpiostate = snd_hda_codec_read(codec, codec->afg, 0,				       AC_VERB_GET_GPIO_DATA, 0);	if (!muted)		gpiostate |= (1 << pin);	else		gpiostate &= ~(1 << pin);	gpiomask = snd_hda_codec_read(codec, codec->afg, 0,				      AC_VERB_GET_GPIO_MASK, 0);	gpiomask |= (1 << pin);	gpiodir = snd_hda_codec_read(codec, codec->afg, 0,				     AC_VERB_GET_GPIO_DIRECTION, 0);	gpiodir |= (1 << pin);	/* AppleHDA seems to do this -- WTF is this verb?? */	snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);	snd_hda_codec_write(codec, codec->afg, 0,			    AC_VERB_SET_GPIO_MASK, gpiomask);	snd_hda_codec_write(codec, codec->afg, 0,			    AC_VERB_SET_GPIO_DIRECTION, gpiodir);	msleep(1);	snd_hda_codec_write(codec, codec->afg, 0,			    AC_VERB_SET_GPIO_DATA, gpiostate);}static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,			      unsigned int event){	if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)		snd_hda_codec_write_cache(codec, nid, 0,					  AC_VERB_SET_UNSOLICITED_ENABLE,					  (AC_USRSP_EN | event));}static int stac92xx_init(struct hda_codec *codec){	struct sigmatel_spec *spec = codec->spec;	struct auto_pin_cfg *cfg = &spec->autocfg;	int i;	snd_hda_sequence_write(codec, spec->init);	/* set up pins */	if (spec->hp_detect) {		/* Enable unsolicited responses on the HP widget */		for (i = 0; i < cfg->hp_outs; i++)			enable_pin_detect(codec, cfg->hp_pins[i],					  STAC_HP_EVENT);		/* force to enable the first line-out; the others are set up		 * in unsol_event		 */		stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],					 AC_PINCTL_OUT_EN);		stac92xx_auto_init_hp_out(codec);		/* fake event to set up pins */		codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);	} else {		

⌨️ 快捷键说明

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