Commit 68ea7b2f authored by Takashi Iwai's avatar Takashi Iwai Committed by Jaroslav Kysela
Browse files

[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: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarJaroslav Kysela <perex@perex.cz>
parent 7e39e227
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -2337,7 +2337,8 @@ int snd_hda_ch_mode_put(struct hda_codec *codec,
	unsigned int mode;
	unsigned int mode;


	mode = ucontrol->value.enumerated.item[0];
	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)
	if (*max_channelsp == chmode[mode].channels)
		return 0;
		return 0;
	/* change the current channel setting */
	/* change the current channel setting */
+5 −1
Original line number Original line Diff line number Diff line
@@ -370,7 +370,7 @@ static int ad198x_eapd_put(struct snd_kcontrol *kcontrol,
	int invert = (kcontrol->private_value >> 8) & 1;
	int invert = (kcontrol->private_value >> 8) & 1;
	hda_nid_t nid = kcontrol->private_value & 0xff;
	hda_nid_t nid = kcontrol->private_value & 0xff;
	unsigned int eapd;
	unsigned int eapd;
	eapd = ucontrol->value.integer.value[0];
	eapd = !!ucontrol->value.integer.value[0];
	if (invert)
	if (invert)
		eapd = !eapd;
		eapd = !eapd;
	if (eapd == spec->cur_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 hda_codec *codec = snd_kcontrol_chip(kcontrol);
	struct ad198x_spec *spec = codec->spec;
	struct ad198x_spec *spec = codec->spec;


	if (ucontrol->value.enumerated.item[0] > 1)
		return -EINVAL;
	if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
	if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
		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,
		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;
	int change;


	val = ucontrol->value.enumerated.item[0];
	val = ucontrol->value.enumerated.item[0];
	if (val > 3)
		return -EINVAL;
	if (!val) {
	if (!val) {
		sel = snd_hda_codec_read(codec, 0x1d, 0,
		sel = snd_hda_codec_read(codec, 0x1d, 0,
					 AC_VERB_GET_AMP_GAIN_MUTE,
					 AC_VERB_GET_AMP_GAIN_MUTE,
+1 −1
Original line number Original line Diff line number Diff line
@@ -373,7 +373,7 @@ static int cxt_eapd_put(struct snd_kcontrol *kcontrol,
	hda_nid_t nid = kcontrol->private_value & 0xff;
	hda_nid_t nid = kcontrol->private_value & 0xff;
	unsigned int eapd;
	unsigned int eapd;


	eapd = ucontrol->value.integer.value[0];
	eapd = !!ucontrol->value.integer.value[0];
	if (invert)
	if (invert)
		eapd = !eapd;
		eapd = !eapd;
	if (eapd == spec->cur_eapd)
	if (eapd == spec->cur_eapd)
+44 −6
Original line number Original line Diff line number Diff line
@@ -349,12 +349,13 @@ static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
	struct sigmatel_spec *spec = codec->spec;
	struct sigmatel_spec *spec = codec->spec;
	unsigned int dac_mode;
	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;
		return 0;


	spec->aloopback = ucontrol->value.integer.value[0];
	spec->aloopback = val;



	dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
	dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
		kcontrol->private_value & 0xFFFF, 0x0);
		kcontrol->private_value & 0xFFFF, 0x0);
@@ -373,6 +374,42 @@ static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
	return 1;
	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[] = {
static struct hda_verb stac9200_core_init[] = {
	/* set dac0mux for dac converter */
	/* set dac0mux for dac converter */
	{ 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
	{ 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;
	struct sigmatel_spec *spec = codec->spec;
        hda_nid_t nid = kcontrol->private_value >> 8;
        hda_nid_t nid = kcontrol->private_value >> 8;
	int io_idx = kcontrol-> private_value & 0xff;
	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;
	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 hda_codec *codec = snd_kcontrol_chip(kcontrol);
	struct sigmatel_spec *spec = codec->spec;
	struct sigmatel_spec *spec = codec->spec;
	hda_nid_t nid = kcontrol->private_value & 0xff;
	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;
		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,
	snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
		spec->clfe_swap ? 0x4 : 0x0);
		spec->clfe_swap ? 0x4 : 0x0);