diff options
author | Takashi Iwai <tiwai@suse.de> | 2008-01-10 16:53:55 +0100 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-01-31 17:29:54 +0100 |
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 a2b40dc372c..caacc58c081 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, return 0; } +/* + * set (static) TLV for virtual master volume; recalculated as max 0dB + */ +void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, + unsigned int *tlv) +{ + u32 caps; + int nums, step; + + caps = query_amp_caps(codec, nid, dir); + nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; + step = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; + step = (step + 1) * 25; + tlv[0] = SNDRV_CTL_TLVT_DB_SCALE; + tlv[1] = 2 * sizeof(unsigned int); + tlv[2] = -nums * step; + tlv[3] = step; +} + +/* find a mixer control element with the given name */ +struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, + const char *name) +{ + struct snd_ctl_elem_id id; + memset(&id, 0, sizeof(id)); + id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + strcpy(id.name, name); + return snd_ctl_find_id(codec->bus->card, &id); +} + +/* create a virtual master control and add slaves */ +int snd_hda_add_vmaster(struct hda_codec *codec, char *name, + unsigned int *tlv, const char **slaves) +{ + struct snd_kcontrol *kctl; + const char **s; + int err; + + kctl = snd_ctl_make_virtual_master(name, tlv); + if (!kctl) + return -ENOMEM; + err = snd_ctl_add(codec->bus->card, kctl); + if (err < 0) + return err; + + for (s = slaves; *s; s++) { + struct snd_kcontrol *sctl; + + sctl = snd_hda_find_mixer_ctl(codec, *s); + if (!sctl) { + snd_printdd("Cannot find slave %s, skipped\n", *s); + continue; + } + err = snd_ctl_add_slave(kctl, sctl); + if (err < 0) + return err; + } + return 0; +} + /* switch */ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |