summary refs log tree commit diff
path: root/sound/i2c/other/ak4xxx-adda.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2007-11-15 16:15:29 +0100
committerJaroslav Kysela <perex@perex.cz>2008-01-31 17:29:25 +0100
commit02ff1324930675599694bb1285afc4341f98a7a1 (patch)
treed0907abb1526a32eb0268eeb4fe31da6752eb7a9 /sound/i2c/other/ak4xxx-adda.c
parentd4079ac49a08e36d6839a9ceb26aec8c24c9ed82 (diff)
downloadlinux-02ff1324930675599694bb1285afc4341f98a7a1.tar.gz
[ALSA] ak4xxx - Check value ranges in ctl callbacks
Check the value ranges in ctl put callbacks properly in ak4xxx-adda driver.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/i2c/other/ak4xxx-adda.c')
-rw-r--r--sound/i2c/other/ak4xxx-adda.c45
1 files changed, 34 insertions, 11 deletions
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index de03f689fa2e..39bb03add7e1 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -377,8 +377,11 @@ static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr,
 static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_value *ucontrol)
 {
-	return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value),
-			  ucontrol->value.integer.value[0]);
+	unsigned int mask = AK_GET_MASK(kcontrol->private_value);
+	unsigned int val = ucontrol->value.integer.value[0];
+	if (val > mask)
+		return -EINVAL;
+	return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value), val);
 }
 
 static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
@@ -409,11 +412,16 @@ static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
 					 struct snd_ctl_elem_value *ucontrol)
 {
 	int addr = AK_GET_ADDR(kcontrol->private_value);
+	unsigned int mask = AK_GET_MASK(kcontrol->private_value);
+	unsigned int val[2];
 	int change;
 
-	change = put_ak_reg(kcontrol, addr, ucontrol->value.integer.value[0]);
-	change |= put_ak_reg(kcontrol, addr + 1,
-			     ucontrol->value.integer.value[1]);
+	val[0] = ucontrol->value.integer.value[0];
+	val[1] = ucontrol->value.integer.value[1];
+	if (val[0] > mask || val[1] > mask)
+		return -EINVAL;
+	change = put_ak_reg(kcontrol, addr, val[0]);
+	change |= put_ak_reg(kcontrol, addr + 1, val[1]);
 	return change;
 }
 
@@ -508,6 +516,18 @@ static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
 
 #define AK5365_NUM_INPUTS 5
 
+static int ak4xxx_capture_num_inputs(struct snd_akm4xxx *ak, int mixer_ch)
+{
+	int num_names;
+	const char **input_names;
+
+	input_names = ak->adc_info[mixer_ch].input_names;
+	num_names = 0;
+	while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
+		++num_names;
+	return num_names;
+}
+
 static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
 				      struct snd_ctl_elem_info *uinfo)
 {
@@ -516,18 +536,16 @@ static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
 	const char **input_names;
 	int  num_names, idx;
 
-	input_names = ak->adc_info[mixer_ch].input_names;
-
-	num_names = 0;
-	while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
-		++num_names;
-	
+	num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
+	if (!num_names)
+		return -EINVAL;
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
 	uinfo->value.enumerated.items = num_names;
 	idx = uinfo->value.enumerated.item;
 	if (idx >= num_names)
 		return -EINVAL;
+	input_names = ak->adc_info[mixer_ch].input_names;
 	strncpy(uinfo->value.enumerated.name, input_names[idx],
 		sizeof(uinfo->value.enumerated.name));
 	return 0;
@@ -551,10 +569,15 @@ static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol,
 				     struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+	int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
 	int chip = AK_GET_CHIP(kcontrol->private_value);
 	int addr = AK_GET_ADDR(kcontrol->private_value);
 	int mask = AK_GET_MASK(kcontrol->private_value);
 	unsigned char oval, val;
+	int num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
+
+	if (ucontrol->value.enumerated.item[0] >= num_names)
+		return -EINVAL;
 
 	oval = snd_akm4xxx_get(ak, chip, addr);
 	val = oval & ~mask;