Commit afbd9b84 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Limit the amp value to write

Check the amp max value at put callbacks and set the upper limit
so that the driver won't write any invalid value over the defined
range.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 3507e2a8
...@@ -1539,6 +1539,17 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) ...@@ -1539,6 +1539,17 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec)
EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp); EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp);
#endif /* SND_HDA_NEEDS_RESUME */ #endif /* SND_HDA_NEEDS_RESUME */
static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int ofs)
{
u32 caps = query_amp_caps(codec, nid, dir);
/* get num steps */
caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
if (ofs < caps)
caps -= ofs;
return caps;
}
/** /**
* snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer * snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer
* *
...@@ -1553,23 +1564,17 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, ...@@ -1553,23 +1564,17 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
u8 chs = get_amp_channels(kcontrol); u8 chs = get_amp_channels(kcontrol);
int dir = get_amp_direction(kcontrol); int dir = get_amp_direction(kcontrol);
unsigned int ofs = get_amp_offset(kcontrol); unsigned int ofs = get_amp_offset(kcontrol);
u32 caps;
caps = query_amp_caps(codec, nid, dir); uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
/* num steps */ uinfo->count = chs == 3 ? 2 : 1;
caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; uinfo->value.integer.min = 0;
if (!caps) { uinfo->value.integer.max = get_amp_max_value(codec, nid, dir, ofs);
if (!uinfo->value.integer.max) {
printk(KERN_WARNING "hda_codec: " printk(KERN_WARNING "hda_codec: "
"num_steps = 0 for NID=0x%x (ctl = %s)\n", nid, "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid,
kcontrol->id.name); kcontrol->id.name);
return -EINVAL; return -EINVAL;
} }
if (ofs < caps)
caps -= ofs;
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = chs == 3 ? 2 : 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = caps;
return 0; return 0;
} }
EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info); EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info);
...@@ -1594,8 +1599,13 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid, ...@@ -1594,8 +1599,13 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid,
int ch, int dir, int idx, unsigned int ofs, int ch, int dir, int idx, unsigned int ofs,
unsigned int val) unsigned int val)
{ {
unsigned int maxval;
if (val > 0) if (val > 0)
val += ofs; val += ofs;
maxval = get_amp_max_value(codec, nid, dir, ofs);
if (val > maxval)
val = maxval;
return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, return snd_hda_codec_amp_update(codec, nid, ch, dir, idx,
HDA_AMP_VOLMASK, val); HDA_AMP_VOLMASK, val);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment