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: Takashi Iwai <tiwai@suse.de>
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index a3d638c..88a1c6a 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1539,6 +1539,17 @@
EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp);
#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
*
@@ -1553,23 +1564,17 @@
u8 chs = get_amp_channels(kcontrol);
int dir = get_amp_direction(kcontrol);
unsigned int ofs = get_amp_offset(kcontrol);
- u32 caps;
- caps = query_amp_caps(codec, nid, dir);
- /* num steps */
- caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
- if (!caps) {
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = chs == 3 ? 2 : 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = get_amp_max_value(codec, nid, dir, ofs);
+ if (!uinfo->value.integer.max) {
printk(KERN_WARNING "hda_codec: "
"num_steps = 0 for NID=0x%x (ctl = %s)\n", nid,
kcontrol->id.name);
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;
}
EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info);
@@ -1594,8 +1599,13 @@
int ch, int dir, int idx, unsigned int ofs,
unsigned int val)
{
+ unsigned int maxval;
+
if (val > 0)
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,
HDA_AMP_VOLMASK, val);
}