Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 071c73ad authored by Takashi Iwai's avatar Takashi Iwai Committed by Jaroslav Kysela
Browse files

[ALSA] hda-codec - Fix mic capture with generic parser



Fixed the mic capture with generic parser of hda-codec driver
- Use VREF80 for mic pins if available
- Handle multiple inputs correctly on audio-input widget node.
Confirmed on a conexant codec chip.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarJaroslav Kysela <perex@suse.cz>
parent 11b44bbd
Loading
Loading
Loading
Loading
+90 −38
Original line number Original line Diff line number Diff line
@@ -461,14 +461,19 @@ static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl)
			return "Front Line";
			return "Front Line";
		return "Line";
		return "Line";
	case AC_JACK_CD:
	case AC_JACK_CD:
#if 0
		if (pinctl)
		if (pinctl)
			*pinctl |= AC_PINCTL_VREF_GRD;
			*pinctl |= AC_PINCTL_VREF_GRD;
#endif
		return "CD";
		return "CD";
	case AC_JACK_AUX:
	case AC_JACK_AUX:
		if ((location & 0x0f) == AC_JACK_LOC_FRONT)
		if ((location & 0x0f) == AC_JACK_LOC_FRONT)
			return "Front Aux";
			return "Front Aux";
		return "Aux";
		return "Aux";
	case AC_JACK_MIC_IN:
	case AC_JACK_MIC_IN:
		if (node->pin_caps &
		    (AC_PINCAP_VREF_80 << AC_PINCAP_VREF_SHIFT))
			*pinctl |= AC_PINCTL_VREF_80;
		if ((location & 0x0f) == AC_JACK_LOC_FRONT)
		if ((location & 0x0f) == AC_JACK_LOC_FRONT)
			return "Front Mic";
			return "Front Mic";
		return "Mic";
		return "Mic";
@@ -556,6 +561,29 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
	return 1; /* found */
	return 1; /* found */
}
}


/* add a capture source element */
static void add_cap_src(struct hda_gspec *spec, int idx)
{
	struct hda_input_mux_item *csrc;
	char *buf;
	int num, ocap;

	num = spec->input_mux.num_items;
	csrc = &spec->input_mux.items[num];
	buf = spec->cap_labels[num];
	for (ocap = 0; ocap < num; ocap++) {
		if (! strcmp(buf, spec->cap_labels[ocap])) {
			/* same label already exists,
			 * put the index number to be unique
			 */
			sprintf(buf, "%s %d", spec->cap_labels[ocap], num);
			break;
		}
	}
	csrc->index = idx;
	spec->input_mux.num_items++;
}

/*
/*
 * parse input
 * parse input
 */
 */
@@ -576,28 +604,26 @@ static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node)
	 * if it reaches to a proper input PIN, add the path as the
	 * if it reaches to a proper input PIN, add the path as the
	 * input path.
	 * input path.
	 */
	 */
	/* first, check the direct connections to PIN widgets */
	for (i = 0; i < adc_node->nconns; i++) {
	for (i = 0; i < adc_node->nconns; i++) {
		node = hda_get_node(spec, adc_node->conn_list[i]);
		node = hda_get_node(spec, adc_node->conn_list[i]);
		if (! node)
		if (node && node->type == AC_WID_PIN) {
			continue;
			err = parse_adc_sub_nodes(codec, spec, node);
			err = parse_adc_sub_nodes(codec, spec, node);
			if (err < 0)
			if (err < 0)
				return err;
				return err;
		else if (err > 0) {
			else if (err > 0)
			struct hda_input_mux_item *csrc = &spec->input_mux.items[spec->input_mux.num_items];
				add_cap_src(spec, i);
			char *buf = spec->cap_labels[spec->input_mux.num_items];
			int ocap;
			for (ocap = 0; ocap < spec->input_mux.num_items; ocap++) {
				if (! strcmp(buf, spec->cap_labels[ocap])) {
					/* same label already exists,
					 * put the index number to be unique
					 */
					sprintf(buf, "%s %d", spec->cap_labels[ocap],
						spec->input_mux.num_items);
		}
		}
	}
	}
			csrc->index = i;
	/* ... then check the rests, more complicated connections */
			spec->input_mux.num_items++;
	for (i = 0; i < adc_node->nconns; i++) {
		node = hda_get_node(spec, adc_node->conn_list[i]);
		if (node && node->type != AC_WID_PIN) {
			err = parse_adc_sub_nodes(codec, spec, node);
			if (err < 0)
				return err;
			else if (err > 0)
				add_cap_src(spec, i);
		}
		}
	}
	}


@@ -647,9 +673,6 @@ static int parse_input(struct hda_codec *codec)
/*
/*
 * create mixer controls if possible
 * create mixer controls if possible
 */
 */
#define DIR_OUT		0x1
#define DIR_IN		0x2

static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
			unsigned int index, const char *type, const char *dir_sfx)
			unsigned int index, const char *type, const char *dir_sfx)
{
{
@@ -743,16 +766,7 @@ static int build_input_controls(struct hda_codec *codec)
{
{
	struct hda_gspec *spec = codec->spec;
	struct hda_gspec *spec = codec->spec;
	struct hda_gnode *adc_node = spec->adc_node;
	struct hda_gnode *adc_node = spec->adc_node;
	int err;
	int i, err;

	if (! adc_node)
		return 0; /* not found */

	/* create capture volume and switch controls if the ADC has an amp */
	err = create_mixer(codec, adc_node, 0, NULL, "Capture");

	/* create input MUX if multiple sources are available */
	if (spec->input_mux.num_items > 1) {
	static struct snd_kcontrol_new cap_sel = {
	static struct snd_kcontrol_new cap_sel = {
		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
		.name = "Capture Source",
		.name = "Capture Source",
@@ -760,11 +774,49 @@ static int build_input_controls(struct hda_codec *codec)
		.get = capture_source_get,
		.get = capture_source_get,
		.put = capture_source_put,
		.put = capture_source_put,
	};
	};
		if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&cap_sel, codec))) < 0)

			return err;
	if (! adc_node || ! spec->input_mux.num_items)
		return 0; /* not found */

	spec->cur_cap_src = 0;
	spec->cur_cap_src = 0;
		select_input_connection(codec, adc_node, spec->input_mux.items[0].index);
	select_input_connection(codec, adc_node,
				spec->input_mux.items[0].index);

	/* create capture volume and switch controls if the ADC has an amp */
	/* do we have only a single item? */
	if (spec->input_mux.num_items == 1) {
		err = create_mixer(codec, adc_node,
				   spec->input_mux.items[0].index,
				   NULL, "Capture");
		if (err < 0)
			return err;
		return 0;
	}
	}

	/* create input MUX if multiple sources are available */
	if ((err = snd_ctl_add(codec->bus->card,
			       snd_ctl_new1(&cap_sel, codec))) < 0)
		return err;

	/* no volume control? */
	if (! (adc_node->wid_caps & AC_WCAP_IN_AMP) ||
	    ! (adc_node->amp_in_caps & AC_AMPCAP_NUM_STEPS))
		return 0;

	for (i = 0; i < spec->input_mux.num_items; i++) {
		struct snd_kcontrol_new knew;
		char name[32];
		sprintf(name, "%s Capture Volume",
			spec->input_mux.items[i].label);
		knew = (struct snd_kcontrol_new)
			HDA_CODEC_VOLUME(name, adc_node->nid,
					 spec->input_mux.items[i].index,
					 HDA_INPUT);
		if ((err = snd_ctl_add(codec->bus->card,
				       snd_ctl_new1(&knew, codec))) < 0)
			return err;
	}

	return 0;
	return 0;
}
}