From 29fdbec2dcb1ce364812778271056aa9516ff3ed Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 20 Jan 2009 13:07:55 +0100 Subject: [PATCH] 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: Takashi Iwai --- sound/pci/hda/hda_codec.c | 45 ++++++++++++++++++++++++++++++++------- sound/pci/hda/hda_local.h | 5 ++++- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index b7bba7dc7cf1..0cf2424ada6a 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1119,6 +1119,7 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, u16 nid = get_amp_nid(kcontrol); u8 chs = get_amp_channels(kcontrol); int dir = get_amp_direction(kcontrol); + unsigned int ofs = get_amp_offset(kcontrol); u32 caps; caps = query_amp_caps(codec, nid, dir); @@ -1130,6 +1131,8 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, kcontrol->id.name); return -EINVAL; } + if (ofs < caps) + caps -= ofs; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = chs == 3 ? 2 : 1; uinfo->value.integer.min = 0; @@ -1138,6 +1141,32 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, } 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, struct snd_ctl_elem_value *ucontrol) { @@ -1146,14 +1175,13 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, int chs = get_amp_channels(kcontrol); int dir = get_amp_direction(kcontrol); int idx = get_amp_index(kcontrol); + unsigned int ofs = get_amp_offset(kcontrol); long *valp = ucontrol->value.integer.value; if (chs & 1) - *valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) - & HDA_AMP_VOLMASK; + *valp++ = read_amp_value(codec, nid, 0, dir, idx, ofs); if (chs & 2) - *valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) - & HDA_AMP_VOLMASK; + *valp = read_amp_value(codec, nid, 1, dir, idx, ofs); return 0; } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get); @@ -1166,18 +1194,17 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, int chs = get_amp_channels(kcontrol); int dir = get_amp_direction(kcontrol); int idx = get_amp_index(kcontrol); + unsigned int ofs = get_amp_offset(kcontrol); long *valp = ucontrol->value.integer.value; int change = 0; snd_hda_power_up(codec); if (chs & 1) { - change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, - 0x7f, *valp); + change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp); valp++; } if (chs & 2) - change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, - 0x7f, *valp); + change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp); snd_hda_power_down(codec); return change; } @@ -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); hda_nid_t nid = get_amp_nid(kcontrol); int dir = get_amp_direction(kcontrol); + unsigned int ofs = get_amp_offset(kcontrol); u32 caps, val1, val2; if (size < 4 * sizeof(unsigned int)) @@ -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 = (val2 + 1) * 25; val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT); + val1 += ofs; val1 = ((int)val1) * ((int)val2); if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv)) return -EFAULT; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 1dd8716c387f..d53ce1f85419 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -26,8 +26,10 @@ /* * 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) \ - ((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) */ #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .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, #define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3) #define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) #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 -- 2.30.2