aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_codec.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-12-20 06:58:12 -0500
committerTakashi Iwai <tiwai@suse.de>2013-01-12 02:34:07 -0500
commit2ce4886abc61193a8b9dfbb8b08e3f8dff463671 (patch)
tree88c7e6181d3cb09551ba488bc0e58ce00c31aef6 /sound/pci/hda/hda_codec.c
parent8565f052c5f696ba095a078ea7dbac32460012be (diff)
ALSA: hda - Avoid access of amp cache element outside mutex
The access to a cache array element could be invalid outside the mutex, so copy locally for the later references. 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.c20
1 files changed, 12 insertions, 8 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index febadc9ed593..5689393f8da7 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1807,7 +1807,7 @@ update_amp_hash(struct hda_codec *codec, hda_nid_t nid, int ch,
1807/* 1807/*
1808 * write the current volume in info to the h/w 1808 * write the current volume in info to the h/w
1809 */ 1809 */
1810static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, 1810static void put_vol_mute(struct hda_codec *codec, unsigned int amp_caps,
1811 hda_nid_t nid, int ch, int direction, int index, 1811 hda_nid_t nid, int ch, int direction, int index,
1812 int val) 1812 int val)
1813{ 1813{
@@ -1816,8 +1816,8 @@ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
1816 parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT; 1816 parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT;
1817 parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT; 1817 parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT;
1818 parm |= index << AC_AMP_SET_INDEX_SHIFT; 1818 parm |= index << AC_AMP_SET_INDEX_SHIFT;
1819 if ((val & HDA_AMP_MUTE) && !(info->amp_caps & AC_AMPCAP_MUTE) && 1819 if ((val & HDA_AMP_MUTE) && !(amp_caps & AC_AMPCAP_MUTE) &&
1820 (info->amp_caps & AC_AMPCAP_MIN_MUTE)) 1820 (amp_caps & AC_AMPCAP_MIN_MUTE))
1821 ; /* set the zero value as a fake mute */ 1821 ; /* set the zero value as a fake mute */
1822 else 1822 else
1823 parm |= val; 1823 parm |= val;
@@ -1854,6 +1854,7 @@ static int codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
1854 bool init_only) 1854 bool init_only)
1855{ 1855{
1856 struct hda_amp_info *info; 1856 struct hda_amp_info *info;
1857 unsigned int caps;
1857 unsigned int cache_only; 1858 unsigned int cache_only;
1858 1859
1859 if (snd_BUG_ON(mask & ~0xff)) 1860 if (snd_BUG_ON(mask & ~0xff))
@@ -1873,9 +1874,10 @@ static int codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
1873 } 1874 }
1874 info->vol[ch] = val; 1875 info->vol[ch] = val;
1875 cache_only = info->head.dirty = codec->cached_write; 1876 cache_only = info->head.dirty = codec->cached_write;
1877 caps = info->amp_caps;
1876 mutex_unlock(&codec->hash_mutex); 1878 mutex_unlock(&codec->hash_mutex);
1877 if (!cache_only) 1879 if (!cache_only)
1878 put_vol_mute(codec, info, nid, ch, direction, idx, val); 1880 put_vol_mute(codec, caps, nid, ch, direction, idx, val);
1879 return 1; 1881 return 1;
1880} 1882}
1881 1883
@@ -1967,23 +1969,25 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec)
1967 u32 key; 1969 u32 key;
1968 hda_nid_t nid; 1970 hda_nid_t nid;
1969 unsigned int idx, dir, ch; 1971 unsigned int idx, dir, ch;
1972 struct hda_amp_info info;
1970 1973
1971 buffer = snd_array_elem(&codec->amp_cache.buf, i); 1974 buffer = snd_array_elem(&codec->amp_cache.buf, i);
1972 if (!buffer->head.dirty) 1975 if (!buffer->head.dirty)
1973 continue; 1976 continue;
1974 buffer->head.dirty = 0; 1977 buffer->head.dirty = 0;
1975 key = buffer->head.key; 1978 info = *buffer;
1979 key = info.head.key;
1976 if (!key) 1980 if (!key)
1977 continue; 1981 continue;
1978 nid = key & 0xff; 1982 nid = key & 0xff;
1979 idx = (key >> 16) & 0xff; 1983 idx = (key >> 16) & 0xff;
1980 dir = (key >> 24) & 0xff; 1984 dir = (key >> 24) & 0xff;
1981 for (ch = 0; ch < 2; ch++) { 1985 for (ch = 0; ch < 2; ch++) {
1982 if (!(buffer->head.val & INFO_AMP_VOL(ch))) 1986 if (!(info.head.val & INFO_AMP_VOL(ch)))
1983 continue; 1987 continue;
1984 mutex_unlock(&codec->hash_mutex); 1988 mutex_unlock(&codec->hash_mutex);
1985 put_vol_mute(codec, buffer, nid, ch, dir, idx, 1989 put_vol_mute(codec, info.amp_caps, nid, ch, dir, idx,
1986 buffer->vol[ch]); 1990 info.vol[ch]);
1987 mutex_lock(&codec->hash_mutex); 1991 mutex_lock(&codec->hash_mutex);
1988 } 1992 }
1989 } 1993 }