Commit 29fdbec2 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Add extra volume offset to standard volume amp macros

Added the volume offset to base for the standard volume controls
to handle elements with too big volume scales like -96dB..0dB.
For such elements, you can set the base volume to reduce the range.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 989738c4
...@@ -1119,6 +1119,7 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, ...@@ -1119,6 +1119,7 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
u16 nid = get_amp_nid(kcontrol); u16 nid = get_amp_nid(kcontrol);
u8 chs = get_amp_channels(kcontrol); u8 chs = get_amp_channels(kcontrol);
int dir = get_amp_direction(kcontrol); int dir = get_amp_direction(kcontrol);
unsigned int ofs = get_amp_offset(kcontrol);
u32 caps; u32 caps;
caps = query_amp_caps(codec, nid, dir); caps = query_amp_caps(codec, nid, dir);
...@@ -1130,6 +1131,8 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, ...@@ -1130,6 +1131,8 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
kcontrol->id.name); kcontrol->id.name);
return -EINVAL; return -EINVAL;
} }
if (ofs < caps)
caps -= ofs;
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = chs == 3 ? 2 : 1; uinfo->count = chs == 3 ? 2 : 1;
uinfo->value.integer.min = 0; uinfo->value.integer.min = 0;
...@@ -1138,6 +1141,32 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, ...@@ -1138,6 +1141,32 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
} }
EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info); EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info);
static inline unsigned int
read_amp_value(struct hda_codec *codec, hda_nid_t nid,
int ch, int dir, int idx, unsigned int ofs)
{
unsigned int val;
val = snd_hda_codec_amp_read(codec, nid, ch, dir, idx);
val &= HDA_AMP_VOLMASK;
if (val >= ofs)
val -= ofs;
else
val = 0;
return val;
}
static inline int
update_amp_value(struct hda_codec *codec, hda_nid_t nid,
int ch, int dir, int idx, unsigned int ofs,
unsigned int val)
{
if (val > 0)
val += ofs;
return snd_hda_codec_amp_update(codec, nid, ch, dir, idx,
HDA_AMP_VOLMASK, val);
}
int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
...@@ -1146,14 +1175,13 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, ...@@ -1146,14 +1175,13 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol,
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);
unsigned int ofs = get_amp_offset(kcontrol);
long *valp = ucontrol->value.integer.value; long *valp = ucontrol->value.integer.value;
if (chs & 1) if (chs & 1)
*valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) *valp++ = read_amp_value(codec, nid, 0, dir, idx, ofs);
& HDA_AMP_VOLMASK;
if (chs & 2) if (chs & 2)
*valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) *valp = read_amp_value(codec, nid, 1, dir, idx, ofs);
& HDA_AMP_VOLMASK;
return 0; return 0;
} }
EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get); EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get);
...@@ -1166,18 +1194,17 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, ...@@ -1166,18 +1194,17 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol,
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);
unsigned int ofs = get_amp_offset(kcontrol);
long *valp = ucontrol->value.integer.value; long *valp = ucontrol->value.integer.value;
int change = 0; int change = 0;
snd_hda_power_up(codec); snd_hda_power_up(codec);
if (chs & 1) { if (chs & 1) {
change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp);
0x7f, *valp);
valp++; valp++;
} }
if (chs & 2) if (chs & 2)
change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp);
0x7f, *valp);
snd_hda_power_down(codec); snd_hda_power_down(codec);
return change; return change;
} }
...@@ -1189,6 +1216,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, ...@@ -1189,6 +1216,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
hda_nid_t nid = get_amp_nid(kcontrol); hda_nid_t nid = get_amp_nid(kcontrol);
int dir = get_amp_direction(kcontrol); int dir = get_amp_direction(kcontrol);
unsigned int ofs = get_amp_offset(kcontrol);
u32 caps, val1, val2; u32 caps, val1, val2;
if (size < 4 * sizeof(unsigned int)) if (size < 4 * sizeof(unsigned int))
...@@ -1197,6 +1225,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, ...@@ -1197,6 +1225,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
val2 = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; val2 = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT;
val2 = (val2 + 1) * 25; val2 = (val2 + 1) * 25;
val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT); val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT);
val1 += ofs;
val1 = ((int)val1) * ((int)val2); val1 = ((int)val1) * ((int)val2);
if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv)) if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv))
return -EFAULT; return -EFAULT;
......
...@@ -26,8 +26,10 @@ ...@@ -26,8 +26,10 @@
/* /*
* for mixer controls * for mixer controls
*/ */
#define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs) \
((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23))
#define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \ #define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \
((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19)) HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0)
/* mono volume with index (index=0,1,...) (channel=1,2) */ /* mono volume with index (index=0,1,...) (channel=1,2) */
#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
...@@ -456,6 +458,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, ...@@ -456,6 +458,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
#define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3) #define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3)
#define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) #define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1)
#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) #define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf)
#define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f)
/* /*
* CEA Short Audio Descriptor data * CEA Short Audio Descriptor data
......
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