summaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2013-11-04 15:51:00 +0100
committerTakashi Iwai <tiwai@suse.de>2013-11-05 07:48:04 +0100
commit485e3e0cdf353e2e37570eafaad7208138bb6620 (patch)
tree679eedb9338d6c7e92d1d7510d0b9f6083a4a8df /sound/pci
parentALSA: hda - Fix possible zero-division (diff)
downloadlinux-485e3e0cdf353e2e37570eafaad7208138bb6620.tar.xz
linux-485e3e0cdf353e2e37570eafaad7208138bb6620.zip
ALSA: hda - Add sanity check of vmaster slave dB steps
Check whether all vmaster slaves have the same dB steps. Otherwise the behavior would become inconsistent. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/hda/hda_codec.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 33c01d551aa4..dd5403d40830 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -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;