ALSA: hda - Fix inconsistent input_paths after ADC reduction
authorTakashi Iwai <tiwai@suse.de>
Wed, 9 Jan 2013 08:06:18 +0000 (09:06 +0100)
committerTakashi Iwai <tiwai@suse.de>
Sat, 12 Jan 2013 07:44:20 +0000 (08:44 +0100)
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

index aa4e6398e3b479bde04a2685625c5ecc288f4d77..d16ef1d490fbf9f86ab66cb83d33c6ae56d983c9 100644 (file)
@@ -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;
        }