diff options
author | Takashi Iwai <tiwai@suse.de> | 2009-01-20 07:07:55 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-01-20 09:16:47 -0500 |
commit | 29fdbec2dcb1ce364812778271056aa9516ff3ed (patch) | |
tree | b5d423645023b018b7e7de4e769c2f35d28e7885 /sound/pci/hda | |
parent | 989738c4f82126207b9e04c9395b78e544f3d33c (diff) |
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 <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 45 | ||||
-rw-r--r-- | 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, | |||
1119 | u16 nid = get_amp_nid(kcontrol); | 1119 | u16 nid = get_amp_nid(kcontrol); |
1120 | u8 chs = get_amp_channels(kcontrol); | 1120 | u8 chs = get_amp_channels(kcontrol); |
1121 | int dir = get_amp_direction(kcontrol); | 1121 | int dir = get_amp_direction(kcontrol); |
1122 | unsigned int ofs = get_amp_offset(kcontrol); | ||
1122 | u32 caps; | 1123 | u32 caps; |
1123 | 1124 | ||
1124 | caps = query_amp_caps(codec, nid, dir); | 1125 | caps = query_amp_caps(codec, nid, dir); |
@@ -1130,6 +1131,8 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, | |||
1130 | kcontrol->id.name); | 1131 | kcontrol->id.name); |
1131 | return -EINVAL; | 1132 | return -EINVAL; |
1132 | } | 1133 | } |
1134 | if (ofs < caps) | ||
1135 | caps -= ofs; | ||
1133 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 1136 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
1134 | uinfo->count = chs == 3 ? 2 : 1; | 1137 | uinfo->count = chs == 3 ? 2 : 1; |
1135 | uinfo->value.integer.min = 0; | 1138 | uinfo->value.integer.min = 0; |
@@ -1138,6 +1141,32 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, | |||
1138 | } | 1141 | } |
1139 | EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info); | 1142 | EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info); |
1140 | 1143 | ||
1144 | |||
1145 | static inline unsigned int | ||
1146 | read_amp_value(struct hda_codec *codec, hda_nid_t nid, | ||
1147 | int ch, int dir, int idx, unsigned int ofs) | ||
1148 | { | ||
1149 | unsigned int val; | ||
1150 | val = snd_hda_codec_amp_read(codec, nid, ch, dir, idx); | ||
1151 | val &= HDA_AMP_VOLMASK; | ||
1152 | if (val >= ofs) | ||
1153 | val -= ofs; | ||
1154 | else | ||
1155 | val = 0; | ||
1156 | return val; | ||
1157 | } | ||
1158 | |||
1159 | static inline int | ||
1160 | update_amp_value(struct hda_codec *codec, hda_nid_t nid, | ||
1161 | int ch, int dir, int idx, unsigned int ofs, | ||
1162 | unsigned int val) | ||
1163 | { | ||
1164 | if (val > 0) | ||
1165 | val += ofs; | ||
1166 | return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, | ||
1167 | HDA_AMP_VOLMASK, val); | ||
1168 | } | ||
1169 | |||
1141 | int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, | 1170 | int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, |
1142 | struct snd_ctl_elem_value *ucontrol) | 1171 | struct snd_ctl_elem_value *ucontrol) |
1143 | { | 1172 | { |
@@ -1146,14 +1175,13 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, | |||
1146 | int chs = get_amp_channels(kcontrol); | 1175 | int chs = get_amp_channels(kcontrol); |
1147 | int dir = get_amp_direction(kcontrol); | 1176 | int dir = get_amp_direction(kcontrol); |
1148 | int idx = get_amp_index(kcontrol); | 1177 | int idx = get_amp_index(kcontrol); |
1178 | unsigned int ofs = get_amp_offset(kcontrol); | ||
1149 | long *valp = ucontrol->value.integer.value; | 1179 | long *valp = ucontrol->value.integer.value; |
1150 | 1180 | ||
1151 | if (chs & 1) | 1181 | if (chs & 1) |
1152 | *valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) | 1182 | *valp++ = read_amp_value(codec, nid, 0, dir, idx, ofs); |
1153 | & HDA_AMP_VOLMASK; | ||
1154 | if (chs & 2) | 1183 | if (chs & 2) |
1155 | *valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) | 1184 | *valp = read_amp_value(codec, nid, 1, dir, idx, ofs); |
1156 | & HDA_AMP_VOLMASK; | ||
1157 | return 0; | 1185 | return 0; |
1158 | } | 1186 | } |
1159 | EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get); | 1187 | 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 | int chs = get_amp_channels(kcontrol); | 1194 | int chs = get_amp_channels(kcontrol); |
1167 | int dir = get_amp_direction(kcontrol); | 1195 | int dir = get_amp_direction(kcontrol); |
1168 | int idx = get_amp_index(kcontrol); | 1196 | int idx = get_amp_index(kcontrol); |
1197 | unsigned int ofs = get_amp_offset(kcontrol); | ||
1169 | long *valp = ucontrol->value.integer.value; | 1198 | long *valp = ucontrol->value.integer.value; |
1170 | int change = 0; | 1199 | int change = 0; |
1171 | 1200 | ||
1172 | snd_hda_power_up(codec); | 1201 | snd_hda_power_up(codec); |
1173 | if (chs & 1) { | 1202 | if (chs & 1) { |
1174 | change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, | 1203 | change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp); |
1175 | 0x7f, *valp); | ||
1176 | valp++; | 1204 | valp++; |
1177 | } | 1205 | } |
1178 | if (chs & 2) | 1206 | if (chs & 2) |
1179 | change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, | 1207 | change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp); |
1180 | 0x7f, *valp); | ||
1181 | snd_hda_power_down(codec); | 1208 | snd_hda_power_down(codec); |
1182 | return change; | 1209 | return change; |
1183 | } | 1210 | } |
@@ -1189,6 +1216,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, | |||
1189 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 1216 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
1190 | hda_nid_t nid = get_amp_nid(kcontrol); | 1217 | hda_nid_t nid = get_amp_nid(kcontrol); |
1191 | int dir = get_amp_direction(kcontrol); | 1218 | int dir = get_amp_direction(kcontrol); |
1219 | unsigned int ofs = get_amp_offset(kcontrol); | ||
1192 | u32 caps, val1, val2; | 1220 | u32 caps, val1, val2; |
1193 | 1221 | ||
1194 | if (size < 4 * sizeof(unsigned int)) | 1222 | if (size < 4 * sizeof(unsigned int)) |
@@ -1197,6 +1225,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, | |||
1197 | val2 = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; | 1225 | val2 = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; |
1198 | val2 = (val2 + 1) * 25; | 1226 | val2 = (val2 + 1) * 25; |
1199 | val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT); | 1227 | val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT); |
1228 | val1 += ofs; | ||
1200 | val1 = ((int)val1) * ((int)val2); | 1229 | val1 = ((int)val1) * ((int)val2); |
1201 | if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv)) | 1230 | if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv)) |
1202 | return -EFAULT; | 1231 | 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 @@ | |||
26 | /* | 26 | /* |
27 | * for mixer controls | 27 | * for mixer controls |
28 | */ | 28 | */ |
29 | #define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs) \ | ||
30 | ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23)) | ||
29 | #define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \ | 31 | #define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \ |
30 | ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19)) | 32 | HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0) |
31 | /* mono volume with index (index=0,1,...) (channel=1,2) */ | 33 | /* mono volume with index (index=0,1,...) (channel=1,2) */ |
32 | #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ | 34 | #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ |
33 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ | 35 | { .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 | #define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3) | 458 | #define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3) |
457 | #define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) | 459 | #define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) |
458 | #define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) | 460 | #define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) |
461 | #define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f) | ||
459 | 462 | ||
460 | /* | 463 | /* |
461 | * CEA Short Audio Descriptor data | 464 | * CEA Short Audio Descriptor data |