提交 4a19faee 编写于 作者: T Takashi Iwai 提交者: Jaroslav Kysela

[ALSA] Fix the handling of amp cache in hda-codec

HDA Codec driver
Fixed the handling of amp cache in hda-codec driver.
The confliction of cache values with different indices should be fixed now.
Signed-off-by: NTakashi Iwai <tiwai@suse.de>
上级 96d07815
...@@ -566,9 +566,10 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stre ...@@ -566,9 +566,10 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stre
* amp access functions * amp access functions
*/ */
#define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + (idx) * 32 + (dir) * 64) /* FIXME: more better hash key? */
#define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24))
#define INFO_AMP_CAPS (1<<0) #define INFO_AMP_CAPS (1<<0)
#define INFO_AMP_VOL (1<<1) #define INFO_AMP_VOL(ch) (1 << (1 + (ch)))
/* initialize the hash table */ /* initialize the hash table */
static void init_amp_hash(struct hda_codec *codec) static void init_amp_hash(struct hda_codec *codec)
...@@ -627,28 +628,29 @@ static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) ...@@ -627,28 +628,29 @@ static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
/* /*
* read the current volume to info * read the current volume to info
* if the cache exists, read from the cache. * if the cache exists, read the cache value.
*/ */
static void get_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, static unsigned int get_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
hda_nid_t nid, int ch, int direction, int index) hda_nid_t nid, int ch, int direction, int index)
{ {
u32 val, parm; u32 val, parm;
if (info->status & (INFO_AMP_VOL << ch)) if (info->status & INFO_AMP_VOL(ch))
return; return info->vol[ch];
parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT; parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT;
parm |= direction == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; parm |= direction == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
parm |= index; parm |= index;
val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, parm); val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, parm);
info->vol[ch] = val & 0xff; info->vol[ch] = val & 0xff;
info->status |= INFO_AMP_VOL << ch; info->status |= INFO_AMP_VOL(ch);
return info->vol[ch];
} }
/* /*
* write the current volume in info to the h/w * write the current volume in info to the h/w and update the cache
*/ */
static void put_vol_mute(struct hda_codec *codec, static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
hda_nid_t nid, int ch, int direction, int index, int val) hda_nid_t nid, int ch, int direction, int index, int val)
{ {
u32 parm; u32 parm;
...@@ -658,30 +660,34 @@ static void put_vol_mute(struct hda_codec *codec, ...@@ -658,30 +660,34 @@ static void put_vol_mute(struct hda_codec *codec,
parm |= index << AC_AMP_SET_INDEX_SHIFT; parm |= index << AC_AMP_SET_INDEX_SHIFT;
parm |= val; parm |= val;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm); snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm);
info->vol[ch] = val;
} }
/* /*
* read/write AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. * read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit.
*/ */
static int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index) static int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index)
{ {
struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index)); struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index));
if (! info) if (! info)
return 0; return 0;
get_vol_mute(codec, info, nid, ch, direction, index); return get_vol_mute(codec, info, nid, ch, direction, index);
return info->vol[ch];
} }
static int snd_hda_codec_amp_write(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int val) /*
* update the AMP value, mask = bit mask to set, val = the value
*/
static int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val)
{ {
struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx)); struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx));
if (! info) if (! info)
return 0; return 0;
get_vol_mute(codec, info, nid, ch, direction, idx); val &= mask;
val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask;
if (info->vol[ch] == val && ! codec->in_resume) if (info->vol[ch] == val && ! codec->in_resume)
return 0; return 0;
put_vol_mute(codec, nid, ch, direction, idx, val); put_vol_mute(codec, info, nid, ch, direction, idx, val);
info->vol[ch] = val;
return 1; return 1;
} }
...@@ -740,21 +746,15 @@ int snd_hda_mixer_amp_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t ...@@ -740,21 +746,15 @@ int snd_hda_mixer_amp_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
int chs = get_amp_channels(kcontrol); int chs = get_amp_channels(kcontrol);
int dir = get_amp_direction(kcontrol); int dir = get_amp_direction(kcontrol);
int idx = get_amp_index(kcontrol); int idx = get_amp_index(kcontrol);
int val;
long *valp = ucontrol->value.integer.value; long *valp = ucontrol->value.integer.value;
int change = 0; int change = 0;
if (chs & 1) { if (chs & 1)
val = *valp & 0x7f; change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
val |= snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x80; 0x7f, *valp);
change = snd_hda_codec_amp_write(codec, nid, 0, dir, idx, val); if (chs & 2)
valp++; change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
} 0x7f, valp[1]);
if (chs & 2) {
val = *valp & 0x7f;
val |= snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x80;
change |= snd_hda_codec_amp_write(codec, nid, 1, dir, idx, val);
}
return change; return change;
} }
...@@ -793,21 +793,15 @@ int snd_hda_mixer_amp_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t ...@@ -793,21 +793,15 @@ int snd_hda_mixer_amp_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
int chs = get_amp_channels(kcontrol); int chs = get_amp_channels(kcontrol);
int dir = get_amp_direction(kcontrol); int dir = get_amp_direction(kcontrol);
int idx = get_amp_index(kcontrol); int idx = get_amp_index(kcontrol);
int val;
long *valp = ucontrol->value.integer.value; long *valp = ucontrol->value.integer.value;
int change = 0; int change = 0;
if (chs & 1) { if (chs & 1)
val = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x7f; change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
val |= *valp ? 0 : 0x80; 0x80, *valp ? 0 : 0x80);
change = snd_hda_codec_amp_write(codec, nid, 0, dir, idx, val); if (chs & 2)
valp++; change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
} 0x80, valp[1] ? 0 : 0x80);
if (chs & 2) {
val = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x7f;
val |= *valp ? 0 : 0x80;
change = snd_hda_codec_amp_write(codec, nid, 1, dir, idx, val);
}
return change; return change;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册