diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-12-20 06:58:12 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2013-01-12 02:34:07 -0500 |
commit | 2ce4886abc61193a8b9dfbb8b08e3f8dff463671 (patch) | |
tree | 88c7e6181d3cb09551ba488bc0e58ce00c31aef6 /sound/pci/hda/hda_codec.c | |
parent | 8565f052c5f696ba095a078ea7dbac32460012be (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.c | 20 |
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 | */ |
1810 | static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, | 1810 | static 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 | } |