[alsa-devel] [PATCH 1/2] ALSA: hda - Fix possible zero-division
Check the TLV db scale result before actually dividing in vmaster slave init code. Also mask TLV_DB_SCALE_MUTE bit so that the right value is obtained even if this bit is set by the codec driver.
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/hda/hda_codec.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index de1a7670ba0d..33c01d551aa4 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2676,8 +2676,13 @@ static int get_kctl_0dB_offset(struct snd_kcontrol *kctl) set_fs(fs); } else if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) tlv = kctl->tlv.p; - if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE) - val = -tlv[2] / tlv[3]; + if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE) { + int step = tlv[3]; + step &= ~TLV_DB_SCALE_MUTE; + if (!step) + return -1; + val = -tlv[2] / step; + } return val; }
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 | 16 ++++++++++++---- 1 file 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;
participants (1)
-
Takashi Iwai