aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_codec.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2010-07-08 12:40:37 -0400
committerTakashi Iwai <tiwai@suse.de>2010-07-09 04:08:57 -0400
commitafbd9b8448f4b7d15673c6858012f384f18d28b8 (patch)
tree120a3b7622bcea7d3a3fea40a3b76fff2680d8ab /sound/pci/hda/hda_codec.c
parent3507e2a8f171f4322bf78f9d618a4e435de843ce (diff)
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>
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r--sound/pci/hda/hda_codec.c32
1 files changed, 21 insertions, 11 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index a3d638c8c1fd..88a1c6acbcbd 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1539,6 +1539,17 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec)
1539EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp); 1539EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp);
1540#endif /* SND_HDA_NEEDS_RESUME */ 1540#endif /* SND_HDA_NEEDS_RESUME */
1541 1541
1542static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir,
1543 unsigned int ofs)
1544{
1545 u32 caps = query_amp_caps(codec, nid, dir);
1546 /* get num steps */
1547 caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
1548 if (ofs < caps)
1549 caps -= ofs;
1550 return caps;
1551}
1552
1542/** 1553/**
1543 * snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer 1554 * snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer
1544 * 1555 *
@@ -1553,23 +1564,17 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
1553 u8 chs = get_amp_channels(kcontrol); 1564 u8 chs = get_amp_channels(kcontrol);
1554 int dir = get_amp_direction(kcontrol); 1565 int dir = get_amp_direction(kcontrol);
1555 unsigned int ofs = get_amp_offset(kcontrol); 1566 unsigned int ofs = get_amp_offset(kcontrol);
1556 u32 caps;
1557 1567
1558 caps = query_amp_caps(codec, nid, dir); 1568 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1559 /* num steps */ 1569 uinfo->count = chs == 3 ? 2 : 1;
1560 caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; 1570 uinfo->value.integer.min = 0;
1561 if (!caps) { 1571 uinfo->value.integer.max = get_amp_max_value(codec, nid, dir, ofs);
1572 if (!uinfo->value.integer.max) {
1562 printk(KERN_WARNING "hda_codec: " 1573 printk(KERN_WARNING "hda_codec: "
1563 "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid, 1574 "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid,
1564 kcontrol->id.name); 1575 kcontrol->id.name);
1565 return -EINVAL; 1576 return -EINVAL;
1566 } 1577 }
1567 if (ofs < caps)
1568 caps -= ofs;
1569 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1570 uinfo->count = chs == 3 ? 2 : 1;
1571 uinfo->value.integer.min = 0;
1572 uinfo->value.integer.max = caps;
1573 return 0; 1578 return 0;
1574} 1579}
1575EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info); 1580EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info);
@@ -1594,8 +1599,13 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid,
1594 int ch, int dir, int idx, unsigned int ofs, 1599 int ch, int dir, int idx, unsigned int ofs,
1595 unsigned int val) 1600 unsigned int val)
1596{ 1601{
1602 unsigned int maxval;
1603
1597 if (val > 0) 1604 if (val > 0)
1598 val += ofs; 1605 val += ofs;
1606 maxval = get_amp_max_value(codec, nid, dir, ofs);
1607 if (val > maxval)
1608 val = maxval;
1599 return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, 1609 return snd_hda_codec_amp_update(codec, nid, ch, dir, idx,
1600 HDA_AMP_VOLMASK, val); 1610 HDA_AMP_VOLMASK, val);
1601} 1611}