Commit ae127005 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

Merge branch 'test/hda-gen-parser' into test/hda-migrate

* test/hda-gen-parser:
  ALSA: hda - Make sure fill_all_dac_nids is called for digital only codecs
  ALSA: hda - force different capture controls if amp caps differ
  ALSA: hda - do not add non-existing Mic boost controls
  ALSA: hda - initialize channel counts correctly
  ALSA: hda - fix wrong adc_idx in generic parser
  ALSA: hda - Check array bounds in get_input_path
  ALSA: hda - Add prefer_hp_amp flag to hda_gen_spec
  ALSA: hda - fix OOPS in hda_mark_cmd_cache_dirty
  ALSA: hda - Check pincap while parsing the configuration
parents 9b473e85 6fc4cb97
Loading
Loading
Loading
Loading
+25 −0
Original line number Original line Diff line number Diff line
@@ -97,6 +97,28 @@ static void reorder_outputs(unsigned int nums, hda_nid_t *pins)
	}
	}
}
}


/* check whether the given pin has a proper pin I/O capability bit */
static bool check_pincap_validity(struct hda_codec *codec, hda_nid_t pin,
				  unsigned int dev)
{
	unsigned int pincap = snd_hda_query_pin_caps(codec, pin);

	/* some old hardware don't return the proper pincaps */
	if (!pincap)
		return true;

	switch (dev) {
	case AC_JACK_LINE_OUT:
	case AC_JACK_SPEAKER:
	case AC_JACK_HP_OUT:
	case AC_JACK_SPDIF_OUT:
	case AC_JACK_DIG_OTHER_OUT:
		return !!(pincap & AC_PINCAP_OUT);
	default:
		return !!(pincap & AC_PINCAP_IN);
	}
}

/*
/*
 * Parse all pin widgets and store the useful pin nids to cfg
 * Parse all pin widgets and store the useful pin nids to cfg
 *
 *
@@ -164,6 +186,9 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
				dev = AC_JACK_SPEAKER;
				dev = AC_JACK_SPEAKER;
		}
		}


		if (!check_pincap_validity(codec, nid, dev))
			continue;

		switch (dev) {
		switch (dev) {
		case AC_JACK_LINE_OUT:
		case AC_JACK_LINE_OUT:
			seq = get_defcfg_sequence(def_conf);
			seq = get_defcfg_sequence(def_conf);
+1 −1
Original line number Original line Diff line number Diff line
@@ -3794,7 +3794,7 @@ static void hda_mark_cmd_cache_dirty(struct hda_codec *codec)
	}
	}
	for (i = 0; i < codec->amp_cache.buf.used; i++) {
	for (i = 0; i < codec->amp_cache.buf.used; i++) {
		struct hda_amp_info *amp;
		struct hda_amp_info *amp;
		amp = snd_array_elem(&codec->cmd_cache.buf, i);
		amp = snd_array_elem(&codec->amp_cache.buf, i);
		amp->head.dirty = 1;
		amp->head.dirty = 1;
	}
	}
}
}
+48 −13
Original line number Original line Diff line number Diff line
@@ -484,6 +484,15 @@ static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
	return false;
	return false;
}
}


static bool same_amp_caps(struct hda_codec *codec, hda_nid_t nid1,
			  hda_nid_t nid2, int dir)
{
	if (!(get_wcaps(codec, nid1) & (1 << (dir + 1))))
		return !(get_wcaps(codec, nid2) & (1 << (dir + 1)));
	return (query_amp_caps(codec, nid1, dir) ==
		query_amp_caps(codec, nid2, dir));
}

#define nid_has_mute(codec, nid, dir) \
#define nid_has_mute(codec, nid, dir) \
	check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE)
	check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE)
#define nid_has_volume(codec, nid, dir) \
#define nid_has_volume(codec, nid, dir) \
@@ -1284,6 +1293,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
	struct hda_gen_spec *spec = codec->spec;
	struct hda_gen_spec *spec = codec->spec;
	struct auto_pin_cfg *cfg = &spec->autocfg;
	struct auto_pin_cfg *cfg = &spec->autocfg;
	int i, err, badness;
	int i, err, badness;
	unsigned int val;


	/* set num_dacs once to full for look_for_dac() */
	/* set num_dacs once to full for look_for_dac() */
	spec->multiout.num_dacs = cfg->line_outs;
	spec->multiout.num_dacs = cfg->line_outs;
@@ -1399,7 +1409,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
	}
	}


	spec->ext_channel_count = spec->min_channel_count =
	spec->ext_channel_count = spec->min_channel_count =
		spec->multiout.num_dacs;
		spec->multiout.num_dacs * 2;


	if (spec->multi_ios == 2) {
	if (spec->multi_ios == 2) {
		for (i = 0; i < 2; i++)
		for (i = 0; i < 2; i++)
@@ -1421,13 +1431,18 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
				   spec->speaker_paths);
				   spec->speaker_paths);


	/* set initial pinctl targets */
	/* set initial pinctl targets */
	set_pin_targets(codec, cfg->line_outs, cfg->line_out_pins,
	if (spec->prefer_hp_amp || cfg->line_out_type == AUTO_PIN_HP_OUT)
			cfg->line_out_type == AUTO_PIN_HP_OUT ? PIN_HP : PIN_OUT);
		val = PIN_HP;
	else
		val = PIN_OUT;
	set_pin_targets(codec, cfg->line_outs, cfg->line_out_pins, val);
	if (cfg->line_out_type != AUTO_PIN_HP_OUT)
	if (cfg->line_out_type != AUTO_PIN_HP_OUT)
		set_pin_targets(codec, cfg->hp_outs, cfg->hp_pins, PIN_HP);
		set_pin_targets(codec, cfg->hp_outs, cfg->hp_pins, PIN_HP);
	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
		val = spec->prefer_hp_amp ? PIN_HP : PIN_OUT;
		set_pin_targets(codec, cfg->speaker_outs,
		set_pin_targets(codec, cfg->speaker_outs,
				cfg->speaker_pins, PIN_OUT);
				cfg->speaker_pins, val);
	}


	return badness;
	return badness;
}
}
@@ -1501,8 +1516,6 @@ static int parse_output_paths(struct hda_codec *codec)
	bool best_wired = true, best_mio = true;
	bool best_wired = true, best_mio = true;
	bool hp_spk_swapped = false;
	bool hp_spk_swapped = false;


	fill_all_dac_nids(codec);

	best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL);
	best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL);
	if (!best_cfg)
	if (!best_cfg)
		return -ENOMEM;
		return -ENOMEM;
@@ -2397,8 +2410,16 @@ static int create_input_ctls(struct hda_codec *codec)
static struct nid_path *get_input_path(struct hda_codec *codec, int adc_idx, int imux_idx)
static struct nid_path *get_input_path(struct hda_codec *codec, int adc_idx, int imux_idx)
{
{
	struct hda_gen_spec *spec = codec->spec;
	struct hda_gen_spec *spec = codec->spec;
	if (imux_idx < 0 || imux_idx >= HDA_MAX_NUM_INPUTS) {
		snd_BUG();
		return NULL;
	}
	if (spec->dyn_adc_switch)
	if (spec->dyn_adc_switch)
		adc_idx = spec->dyn_adc_idx[imux_idx];
		adc_idx = spec->dyn_adc_idx[imux_idx];
	if (adc_idx < 0 || adc_idx >= AUTO_CFG_MAX_OUTS) {
		snd_BUG();
		return NULL;
	}
	return snd_hda_get_path_from_idx(codec, spec->input_paths[imux_idx][adc_idx]);
	return snd_hda_get_path_from_idx(codec, spec->input_paths[imux_idx][adc_idx]);
}
}


@@ -2418,7 +2439,7 @@ static int mux_enum_get(struct snd_kcontrol *kcontrol,
{
{
	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
	struct hda_gen_spec *spec = codec->spec;
	struct hda_gen_spec *spec = codec->spec;
	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
	unsigned int adc_idx = kcontrol->id.index;


	ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
	ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
	return 0;
	return 0;
@@ -2428,7 +2449,7 @@ static int mux_enum_put(struct snd_kcontrol *kcontrol,
			    struct snd_ctl_elem_value *ucontrol)
			    struct snd_ctl_elem_value *ucontrol)
{
{
	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
	unsigned int adc_idx = kcontrol->id.index;
	return mux_select(codec, adc_idx,
	return mux_select(codec, adc_idx,
			  ucontrol->value.enumerated.item[0]);
			  ucontrol->value.enumerated.item[0]);
}
}
@@ -2460,7 +2481,7 @@ static int cap_put_caller(struct snd_kcontrol *kcontrol,
	int i, adc_idx, err = 0;
	int i, adc_idx, err = 0;


	imux = &spec->input_mux;
	imux = &spec->input_mux;
	adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
	adc_idx = kcontrol->id.index;
	mutex_lock(&codec->control_mutex);
	mutex_lock(&codec->control_mutex);
	/* we use the cache-only update at first since multiple input paths
	/* we use the cache-only update at first since multiple input paths
	 * may shared the same amp; by updating only caches, the redundant
	 * may shared the same amp; by updating only caches, the redundant
@@ -2754,6 +2775,7 @@ static int create_capture_mixers(struct hda_codec *codec)


	for (n = 0; n < nums; n++) {
	for (n = 0; n < nums; n++) {
		bool multi = false;
		bool multi = false;
		bool multi_cap_vol = spec->multi_cap_vol;
		bool inv_dmic = false;
		bool inv_dmic = false;
		int vol, sw;
		int vol, sw;


@@ -2766,12 +2788,20 @@ static int create_capture_mixers(struct hda_codec *codec)
			parse_capvol_in_path(codec, path);
			parse_capvol_in_path(codec, path);
			if (!vol)
			if (!vol)
				vol = path->ctls[NID_PATH_VOL_CTL];
				vol = path->ctls[NID_PATH_VOL_CTL];
			else if (vol != path->ctls[NID_PATH_VOL_CTL])
			else if (vol != path->ctls[NID_PATH_VOL_CTL]) {
				multi = true;
				multi = true;
				if (!same_amp_caps(codec, vol,
				    path->ctls[NID_PATH_VOL_CTL], HDA_INPUT))
					multi_cap_vol = true;
			}
			if (!sw)
			if (!sw)
				sw = path->ctls[NID_PATH_MUTE_CTL];
				sw = path->ctls[NID_PATH_MUTE_CTL];
			else if (sw != path->ctls[NID_PATH_MUTE_CTL])
			else if (sw != path->ctls[NID_PATH_MUTE_CTL]) {
				multi = true;
				multi = true;
				if (!same_amp_caps(codec, sw,
				    path->ctls[NID_PATH_MUTE_CTL], HDA_INPUT))
					multi_cap_vol = true;
			}
			if (is_inv_dmic_pin(codec, spec->imux_pins[i]))
			if (is_inv_dmic_pin(codec, spec->imux_pins[i]))
				inv_dmic = true;
				inv_dmic = true;
		}
		}
@@ -2779,7 +2809,7 @@ static int create_capture_mixers(struct hda_codec *codec)
		if (!multi)
		if (!multi)
			err = create_single_cap_vol_ctl(codec, n, vol, sw,
			err = create_single_cap_vol_ctl(codec, n, vol, sw,
							inv_dmic);
							inv_dmic);
		else if (!spec->multi_cap_vol)
		else if (!multi_cap_vol)
			err = create_bind_cap_vol_ctl(codec, n, vol, sw);
			err = create_bind_cap_vol_ctl(codec, n, vol, sw);
		else
		else
			err = create_multi_cap_vol_ctl(codec);
			err = create_multi_cap_vol_ctl(codec);
@@ -2812,6 +2842,9 @@ static int parse_mic_boost(struct hda_codec *codec)
			struct nid_path *path;
			struct nid_path *path;
			unsigned int val;
			unsigned int val;


			if (!nid_has_volume(codec, nid, HDA_INPUT))
				continue;

			label = hda_get_autocfg_input_label(codec, cfg, i);
			label = hda_get_autocfg_input_label(codec, cfg, i);
			if (prev_label && !strcmp(label, prev_label))
			if (prev_label && !strcmp(label, prev_label))
				type_idx++;
				type_idx++;
@@ -3393,6 +3426,8 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
		cfg = &spec->autocfg;
		cfg = &spec->autocfg;
	}
	}


	fill_all_dac_nids(codec);

	if (!cfg->line_outs) {
	if (!cfg->line_outs) {
		if (cfg->dig_outs || cfg->dig_in_pin) {
		if (cfg->dig_outs || cfg->dig_in_pin) {
			spec->multiout.max_channels = 2;
			spec->multiout.max_channels = 2;
+1 −0
Original line number Original line Diff line number Diff line
@@ -190,6 +190,7 @@ struct hda_gen_spec {
	unsigned int vmaster_mute_enum:1; /* add vmaster mute mode enum */
	unsigned int vmaster_mute_enum:1; /* add vmaster mute mode enum */
	unsigned int indep_hp:1; /* independent HP supported */
	unsigned int indep_hp:1; /* independent HP supported */
	unsigned int indep_hp_enabled:1; /* independent HP enabled */
	unsigned int indep_hp_enabled:1; /* independent HP enabled */
	unsigned int prefer_hp_amp:1; /* enable HP amp for speaker if any */
	unsigned int add_stereo_mix_input:1; /* add aamix as a capture src */
	unsigned int add_stereo_mix_input:1; /* add aamix as a capture src */
	unsigned int add_out_jack_modes:1; /* add output jack mode enum ctls */
	unsigned int add_out_jack_modes:1; /* add output jack mode enum ctls */


+5 −2
Original line number Original line Diff line number Diff line
@@ -1506,8 +1506,6 @@ static void alc260_fixup_fsc_s7020(struct hda_codec *codec,


	if (action == HDA_FIXUP_ACT_PRE_PROBE)
	if (action == HDA_FIXUP_ACT_PRE_PROBE)
		spec->gen.add_out_jack_modes = 1;
		spec->gen.add_out_jack_modes = 1;
	else if (action == HDA_FIXUP_ACT_PROBE)
		snd_hda_set_pin_ctl_cache(codec, 0x10, PIN_HP);
}
}


static const struct hda_fixup alc260_fixups[] = {
static const struct hda_fixup alc260_fixups[] = {
@@ -1597,6 +1595,11 @@ static int patch_alc260(struct hda_codec *codec)
		return err;
		return err;


	spec = codec->spec;
	spec = codec->spec;
	/* as quite a few machines require HP amp for speaker outputs,
	 * it's easier to enable it unconditionally; even if it's unneeded,
	 * it's almost harmless.
	 */
	spec->gen.prefer_hp_amp = 1;


	snd_hda_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
	snd_hda_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);