In the current parser code, the input_paths[] may become inconsistent when some of detected ADCs are dropped due to incomplete inputs, since the driver rearranges only adc_nids[] but doesn't touch input_paths[].
This patch fixes the issue, and also it optimizes the reachability checks by simply referring to the parsed input_paths[] instead of calling is_reachable() again for each connection.
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/hda/hda_generic.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-)
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index aa4e639..d16ef1d 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -2002,24 +2002,24 @@ static int check_dyn_adc_switch(struct hda_codec *codec) { struct hda_gen_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->input_mux; - hda_nid_t adc_nids[ARRAY_SIZE(spec->adc_nids)]; + unsigned int ok_bits; int i, n, nums; - hda_nid_t pin, adc;
again: nums = 0; + ok_bits = 0; for (n = 0; n < spec->num_adc_nids; n++) { - adc = spec->adc_nids[n]; for (i = 0; i < imux->num_items; i++) { - pin = spec->imux_pins[i]; - if (!is_reachable_path(codec, pin, adc)) + if (!spec->input_paths[i][n]) break; } - if (i >= imux->num_items) - adc_nids[nums++] = adc; + if (i >= imux->num_items) { + ok_bits |= (1 << n); + nums++; + } }
- if (!nums) { + if (!ok_bits) { if (spec->shared_mic_hp) { spec->shared_mic_hp = 0; imux->num_items = 1; @@ -2028,10 +2028,8 @@ static int check_dyn_adc_switch(struct hda_codec *codec)
/* check whether ADC-switch is possible */ for (i = 0; i < imux->num_items; i++) { - pin = spec->imux_pins[i]; for (n = 0; n < spec->num_adc_nids; n++) { - adc = spec->adc_nids[n]; - if (is_reachable_path(codec, pin, adc)) { + if (spec->input_paths[i][n]) { spec->dyn_adc_idx[i] = n; break; } @@ -2041,7 +2039,19 @@ static int check_dyn_adc_switch(struct hda_codec *codec) snd_printdd("hda-codec: enabling ADC switching\n"); spec->dyn_adc_switch = 1; } else if (nums != spec->num_adc_nids) { - memcpy(spec->adc_nids, adc_nids, nums * sizeof(hda_nid_t)); + /* shrink the invalid adcs and input paths */ + nums = 0; + for (n = 0; n < spec->num_adc_nids; n++) { + if (!(ok_bits & (1 << n))) + continue; + if (n != nums) { + spec->adc_nids[nums] = spec->adc_nids[n]; + for (i = 0; i < imux->num_items; i++) + spec->input_paths[i][nums] = + spec->input_paths[i][n]; + } + nums++; + } spec->num_adc_nids = nums; }