Commit 02ff1324 authored by Takashi Iwai's avatar Takashi Iwai Committed by Jaroslav Kysela
Browse files

[ALSA] ak4xxx - Check value ranges in ctl callbacks



Check the value ranges in ctl put callbacks properly in ak4xxx-adda driver.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarJaroslav Kysela <perex@perex.cz>
parent d4079ac4
Loading
Loading
Loading
Loading
+34 −11
Original line number Diff line number Diff line
@@ -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,26 +516,36 @@ static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,

#define AK5365_NUM_INPUTS 5

static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
				      struct snd_ctl_elem_info *uinfo)
static int ak4xxx_capture_num_inputs(struct snd_akm4xxx *ak, int mixer_ch)
{
	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
	int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
	int num_names;
	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;
	return num_names;
}

static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
				      struct snd_ctl_elem_info *uinfo)
{
	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
	int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
	const char **input_names;
	int  num_names, idx;

	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;