ALSA: hda - Fix inconsistent input_paths after ADC reduction
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>
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 @@
{
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 @@
/* 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 @@
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;
}