[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 <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 39240e0..23d3bef 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -2337,7 +2337,8 @@
 	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 cfe064a..b2c5380 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -370,7 +370,7 @@
 	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 @@
 	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 @@
 	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 beda297..68f23b8 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -373,7 +373,7 @@
 	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 c4447b1..0817f42 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -349,12 +349,13 @@
 	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 @@
 	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 @@
 	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 @@
 	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);