diff options
author | Takashi Iwai <tiwai@suse.de> | 2008-01-10 10:53:55 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-01-31 11:29:54 -0500 |
commit | 2134ea4f37d36addbe86d4901f6c67a22a5db006 (patch) | |
tree | 804d187d5c46d71246db2d8919a59e2e7feef956 /sound/pci/hda/hda_codec.c | |
parent | 3b0a5f22d4649433a5842ffc7313803292e95718 (diff) |
[ALSA] hda-codec - Add virtual master controls
Add master controls using vmaster to codecs that have no real hardware
master volume registers.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index a2b40dc372c9..caacc58c0813 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -1012,6 +1012,66 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, | |||
1012 | return 0; | 1012 | return 0; |
1013 | } | 1013 | } |
1014 | 1014 | ||
1015 | /* | ||
1016 | * set (static) TLV for virtual master volume; recalculated as max 0dB | ||
1017 | */ | ||
1018 | void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, | ||
1019 | unsigned int *tlv) | ||
1020 | { | ||
1021 | u32 caps; | ||
1022 | int nums, step; | ||
1023 | |||
1024 | caps = query_amp_caps(codec, nid, dir); | ||
1025 | nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; | ||
1026 | step = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; | ||
1027 | step = (step + 1) * 25; | ||
1028 | tlv[0] = SNDRV_CTL_TLVT_DB_SCALE; | ||
1029 | tlv[1] = 2 * sizeof(unsigned int); | ||
1030 | tlv[2] = -nums * step; | ||
1031 | tlv[3] = step; | ||
1032 | } | ||
1033 | |||
1034 | /* find a mixer control element with the given name */ | ||
1035 | struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, | ||
1036 | const char *name) | ||
1037 | { | ||
1038 | struct snd_ctl_elem_id id; | ||
1039 | memset(&id, 0, sizeof(id)); | ||
1040 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
1041 | strcpy(id.name, name); | ||
1042 | return snd_ctl_find_id(codec->bus->card, &id); | ||
1043 | } | ||
1044 | |||
1045 | /* create a virtual master control and add slaves */ | ||
1046 | int snd_hda_add_vmaster(struct hda_codec *codec, char *name, | ||
1047 | unsigned int *tlv, const char **slaves) | ||
1048 | { | ||
1049 | struct snd_kcontrol *kctl; | ||
1050 | const char **s; | ||
1051 | int err; | ||
1052 | |||
1053 | kctl = snd_ctl_make_virtual_master(name, tlv); | ||
1054 | if (!kctl) | ||
1055 | return -ENOMEM; | ||
1056 | err = snd_ctl_add(codec->bus->card, kctl); | ||
1057 | if (err < 0) | ||
1058 | return err; | ||
1059 | |||
1060 | for (s = slaves; *s; s++) { | ||
1061 | struct snd_kcontrol *sctl; | ||
1062 | |||
1063 | sctl = snd_hda_find_mixer_ctl(codec, *s); | ||
1064 | if (!sctl) { | ||
1065 | snd_printdd("Cannot find slave %s, skipped\n", *s); | ||
1066 | continue; | ||
1067 | } | ||
1068 | err = snd_ctl_add_slave(kctl, sctl); | ||
1069 | if (err < 0) | ||
1070 | return err; | ||
1071 | } | ||
1072 | return 0; | ||
1073 | } | ||
1074 | |||
1015 | /* switch */ | 1075 | /* switch */ |
1016 | int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, | 1076 | int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, |
1017 | struct snd_ctl_elem_info *uinfo) | 1077 | struct snd_ctl_elem_info *uinfo) |