From 68ea7b2f2d8c1effd662fded04e9a589cb640da6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 15 Nov 2007 15:54:38 +0100 Subject: [PATCH] [ALSA] hda-codec - Check value range in ctl callbacks Check the value ranges in ctl put callbacks properly so that invalid values won't be stored or written to registers. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 3 +- sound/pci/hda/patch_analog.c | 6 +++- sound/pci/hda/patch_conexant.c | 2 +- sound/pci/hda/patch_sigmatel.c | 50 ++++++++++++++++++++++++++++++---- 4 files changed, 52 insertions(+), 9 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 39240e0ea568..23d3befef57b 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2337,7 +2337,8 @@ int snd_hda_ch_mode_put(struct hda_codec *codec, unsigned int mode; mode = ucontrol->value.enumerated.item[0]; - snd_assert(mode < num_chmodes, return -EINVAL); + if (mode >= num_chmodes) + return -EINVAL; if (*max_channelsp == chmode[mode].channels) return 0; /* change the current channel setting */ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index cfe064a75ca6..b2c53809603e 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -370,7 +370,7 @@ static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, int invert = (kcontrol->private_value >> 8) & 1; hda_nid_t nid = kcontrol->private_value & 0xff; unsigned int eapd; - eapd = ucontrol->value.integer.value[0]; + eapd = !!ucontrol->value.integer.value[0]; if (invert) eapd = !eapd; if (eapd == spec->cur_eapd) @@ -1021,6 +1021,8 @@ static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ad198x_spec *spec = codec->spec; + if (ucontrol->value.enumerated.item[0] > 1) + return -EINVAL; if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { spec->spdif_route = ucontrol->value.enumerated.item[0]; snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0, @@ -1966,6 +1968,8 @@ static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol, int change; val = ucontrol->value.enumerated.item[0]; + if (val > 3) + return -EINVAL; if (!val) { sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE, diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index beda2978147d..68f23b823e25 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -373,7 +373,7 @@ static int cxt_eapd_put(struct snd_kcontrol *kcontrol, hda_nid_t nid = kcontrol->private_value & 0xff; unsigned int eapd; - eapd = ucontrol->value.integer.value[0]; + eapd = !!ucontrol->value.integer.value[0]; if (invert) eapd = !eapd; if (eapd == spec->cur_eapd) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index c4447b160a5a..0817f42a7c86 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -349,12 +349,13 @@ static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol, struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; unsigned int dac_mode; + unsigned int val; - if (spec->aloopback == ucontrol->value.integer.value[0]) + val = !!ucontrol->value.integer.value[0]; + if (spec->aloopback == val) return 0; - spec->aloopback = ucontrol->value.integer.value[0]; - + spec->aloopback = val; dac_mode = snd_hda_codec_read(codec, codec->afg, 0, kcontrol->private_value & 0xFFFF, 0x0); @@ -373,6 +374,42 @@ static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol, return 1; } +static int stac92xx_volknob_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 127; + return 0; +} + +static int stac92xx_volknob_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = kcontrol->private_value & 0xff; + return 0; +} + +static int stac92xx_volknob_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int oval = kcontrol->private_value & 0xff; + unsigned int val; + + val = ucontrol->value.integer.value[0] & 0xff; + if (val == oval) + return 0; + + kcontrol->private_value &= ~0xff; + kcontrol->private_value |= val; + + snd_hda_codec_write_cache(codec, kcontrol->private_value >> 16, 0, + AC_VERB_SET_VOLUME_KNOB_CONTROL, val | 0x80); + return 1; +} + static struct hda_verb stac9200_core_init[] = { /* set dac0mux for dac converter */ { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -1588,7 +1625,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ struct sigmatel_spec *spec = codec->spec; hda_nid_t nid = kcontrol->private_value >> 8; int io_idx = kcontrol-> private_value & 0xff; - unsigned short val = ucontrol->value.integer.value[0]; + unsigned short val = !!ucontrol->value.integer.value[0]; spec->io_switch[io_idx] = val; @@ -1628,11 +1665,12 @@ static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol, struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; hda_nid_t nid = kcontrol->private_value & 0xff; + unsigned int val = !!ucontrol->value.integer.value[0]; - if (spec->clfe_swap == ucontrol->value.integer.value[0]) + if (spec->clfe_swap == val) return 0; - spec->clfe_swap = ucontrol->value.integer.value[0]; + spec->clfe_swap = val; snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, spec->clfe_swap ? 0x4 : 0x0);