ALSA: hda - Add sanity check of vmaster slave dB steps
authorTakashi Iwai <tiwai@suse.de>
Mon, 4 Nov 2013 14:51:00 +0000 (15:51 +0100)
committerTakashi Iwai <tiwai@suse.de>
Tue, 5 Nov 2013 06:48:04 +0000 (07:48 +0100)
Check whether all vmaster slaves have the same dB steps.  Otherwise
the behavior would become inconsistent.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/hda_codec.c

index 33c01d551aa482fffc1c07d18792b6453a330e90..dd5403d40830bfa2d97e6012b767fff52d64fddf 100644 (file)
@@ -2661,7 +2661,7 @@ static int check_slave_present(void *data, struct snd_kcontrol *sctl)
 }
 
 /* guess the value corresponding to 0dB */
-static int get_kctl_0dB_offset(struct snd_kcontrol *kctl)
+static int get_kctl_0dB_offset(struct snd_kcontrol *kctl, int *step_to_check)
 {
        int _tlv[4];
        const int *tlv = NULL;
@@ -2681,6 +2681,12 @@ static int get_kctl_0dB_offset(struct snd_kcontrol *kctl)
                step &= ~TLV_DB_SCALE_MUTE;
                if (!step)
                        return -1;
+               if (*step_to_check && *step_to_check != step) {
+                       snd_printk(KERN_ERR "hda_codec: Mismatching dB step for vmaster slave (%d!=%d)\n",
+                                  *step_to_check, step);
+                       return -1;
+               }
+               *step_to_check = step;
                val = -tlv[2] / step;
        }
        return val;
@@ -2703,7 +2709,7 @@ static int put_kctl_with_value(struct snd_kcontrol *kctl, int val)
 /* initialize the slave volume with 0dB */
 static int init_slave_0dB(void *data, struct snd_kcontrol *slave)
 {
-       int offset = get_kctl_0dB_offset(slave);
+       int offset = get_kctl_0dB_offset(slave, data);
        if (offset > 0)
                put_kctl_with_value(slave, offset);
        return 0;
@@ -2764,9 +2770,11 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
 
        /* init with master mute & zero volume */
        put_kctl_with_value(kctl, 0);
-       if (init_slave_vol)
+       if (init_slave_vol) {
+               int step = 0;
                map_slaves(codec, slaves, suffix,
-                          tlv ? init_slave_0dB : init_slave_unmute, kctl);
+                          tlv ? init_slave_0dB : init_slave_unmute, &step);
+       }
 
        if (ctl_ret)
                *ctl_ret = kctl;