Commit 2ce4886a authored by Takashi Iwai's avatar Takashi Iwai

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: default avatarTakashi Iwai <tiwai@suse.de>
parent 8565f052
...@@ -1807,7 +1807,7 @@ update_amp_hash(struct hda_codec *codec, hda_nid_t nid, int ch, ...@@ -1807,7 +1807,7 @@ update_amp_hash(struct hda_codec *codec, hda_nid_t nid, int ch,
/* /*
* write the current volume in info to the h/w * write the current volume in info to the h/w
*/ */
static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, static void put_vol_mute(struct hda_codec *codec, unsigned int amp_caps,
hda_nid_t nid, int ch, int direction, int index, hda_nid_t nid, int ch, int direction, int index,
int val) int val)
{ {
...@@ -1816,8 +1816,8 @@ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, ...@@ -1816,8 +1816,8 @@ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT; parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT;
parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT; parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT;
parm |= index << AC_AMP_SET_INDEX_SHIFT; parm |= index << AC_AMP_SET_INDEX_SHIFT;
if ((val & HDA_AMP_MUTE) && !(info->amp_caps & AC_AMPCAP_MUTE) && if ((val & HDA_AMP_MUTE) && !(amp_caps & AC_AMPCAP_MUTE) &&
(info->amp_caps & AC_AMPCAP_MIN_MUTE)) (amp_caps & AC_AMPCAP_MIN_MUTE))
; /* set the zero value as a fake mute */ ; /* set the zero value as a fake mute */
else else
parm |= val; parm |= val;
...@@ -1854,6 +1854,7 @@ static int codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, ...@@ -1854,6 +1854,7 @@ static int codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
bool init_only) bool init_only)
{ {
struct hda_amp_info *info; struct hda_amp_info *info;
unsigned int caps;
unsigned int cache_only; unsigned int cache_only;
if (snd_BUG_ON(mask & ~0xff)) 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,9 +1874,10 @@ static int codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
} }
info->vol[ch] = val; info->vol[ch] = val;
cache_only = info->head.dirty = codec->cached_write; cache_only = info->head.dirty = codec->cached_write;
caps = info->amp_caps;
mutex_unlock(&codec->hash_mutex); mutex_unlock(&codec->hash_mutex);
if (!cache_only) if (!cache_only)
put_vol_mute(codec, info, nid, ch, direction, idx, val); put_vol_mute(codec, caps, nid, ch, direction, idx, val);
return 1; return 1;
} }
...@@ -1967,23 +1969,25 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) ...@@ -1967,23 +1969,25 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec)
u32 key; u32 key;
hda_nid_t nid; hda_nid_t nid;
unsigned int idx, dir, ch; unsigned int idx, dir, ch;
struct hda_amp_info info;
buffer = snd_array_elem(&codec->amp_cache.buf, i); buffer = snd_array_elem(&codec->amp_cache.buf, i);
if (!buffer->head.dirty) if (!buffer->head.dirty)
continue; continue;
buffer->head.dirty = 0; buffer->head.dirty = 0;
key = buffer->head.key; info = *buffer;
key = info.head.key;
if (!key) if (!key)
continue; continue;
nid = key & 0xff; nid = key & 0xff;
idx = (key >> 16) & 0xff; idx = (key >> 16) & 0xff;
dir = (key >> 24) & 0xff; dir = (key >> 24) & 0xff;
for (ch = 0; ch < 2; ch++) { for (ch = 0; ch < 2; ch++) {
if (!(buffer->head.val & INFO_AMP_VOL(ch))) if (!(info.head.val & INFO_AMP_VOL(ch)))
continue; continue;
mutex_unlock(&codec->hash_mutex); mutex_unlock(&codec->hash_mutex);
put_vol_mute(codec, buffer, nid, ch, dir, idx, put_vol_mute(codec, info.amp_caps, nid, ch, dir, idx,
buffer->vol[ch]); info.vol[ch]);
mutex_lock(&codec->hash_mutex); mutex_lock(&codec->hash_mutex);
} }
} }
......
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