diff options
author | Jani Alinikula <janialinikula@gmail.com> | 2006-06-27 15:00:55 +0200 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-06-28 19:31:03 +0200 |
commit | c83c0c470565a0aed2f6fcbaa6c80a98ef250586 (patch) | |
tree | 5f6810822c019af78dcb95f67565101cb97198c0 | |
parent | be7ee27822975cee5dabb2cfd7f03e7fde38e3f4 (diff) |
[ALSA] Stereo controls for M-Audio Revolution cards
This patch adds stereo controls to revo cards by making the ak4xxx
driver mixers configurable from the card driver.
Signed-off-by: Jani Alinikula <janialinikula@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
-rw-r--r-- | include/sound/ak4xxx-adda.h | 2 | ||||
-rw-r--r-- | sound/i2c/other/ak4xxx-adda.c | 89 | ||||
-rw-r--r-- | sound/pci/ice1712/revo.c | 23 |
3 files changed, 105 insertions, 9 deletions
diff --git a/include/sound/ak4xxx-adda.h b/include/sound/ak4xxx-adda.h index 3bf5911fe827..acf8cc1292e0 100644 --- a/include/sound/ak4xxx-adda.h +++ b/include/sound/ak4xxx-adda.h @@ -53,6 +53,8 @@ struct snd_akm4xxx { SND_AK4524, SND_AK4528, SND_AK4529, SND_AK4355, SND_AK4358, SND_AK4381 } type; + unsigned int *num_stereo; /* array of combined counts for the mixer */ + char **channel_names; /* array of mixer channel names */ struct snd_ak4xxx_ops ops; }; diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index 045e32a311e0..f68bd740e1a1 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c @@ -292,6 +292,64 @@ static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol, return change; } +static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + unsigned int mask = AK_GET_MASK(kcontrol->private_value); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mask; + return 0; +} + +static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); + int chip = AK_GET_CHIP(kcontrol->private_value); + int addr = AK_GET_ADDR(kcontrol->private_value); + int invert = AK_GET_INVERT(kcontrol->private_value); + unsigned int mask = AK_GET_MASK(kcontrol->private_value); + unsigned char val = snd_akm4xxx_get(ak, chip, addr); + + ucontrol->value.integer.value[0] = invert ? mask - val : val; + + val = snd_akm4xxx_get(ak, chip, addr+1); + ucontrol->value.integer.value[1] = invert ? mask - val : val; + + return 0; +} + +static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); + int chip = AK_GET_CHIP(kcontrol->private_value); + int addr = AK_GET_ADDR(kcontrol->private_value); + int invert = AK_GET_INVERT(kcontrol->private_value); + unsigned int mask = AK_GET_MASK(kcontrol->private_value); + unsigned char nval = ucontrol->value.integer.value[0] % (mask+1); + int change0, change1; + + if (invert) + nval = mask - nval; + change0 = snd_akm4xxx_get(ak, chip, addr) != nval; + if (change0) + snd_akm4xxx_write(ak, chip, addr, nval); + + nval = ucontrol->value.integer.value[1] % (mask+1); + if (invert) + nval = mask - nval; + change1 = snd_akm4xxx_get(ak, chip, addr+1) != nval; + if (change1) + snd_akm4xxx_write(ak, chip, addr+1, nval); + + + return change0 || change1; +} + static int snd_akm4xxx_ipga_gain_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -377,20 +435,35 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak) unsigned int idx, num_emphs; struct snd_kcontrol *ctl; int err; + int mixer_ch = 0; + int num_stereo; ctl = kmalloc(sizeof(*ctl), GFP_KERNEL); if (! ctl) return -ENOMEM; - for (idx = 0; idx < ak->num_dacs; ++idx) { + for (idx = 0; idx < ak->num_dacs; ) { memset(ctl, 0, sizeof(*ctl)); - strcpy(ctl->id.name, "DAC Volume"); - ctl->id.index = idx + ak->idx_offset * 2; + if (ak->channel_names == NULL) { + strcpy(ctl->id.name, "DAC Volume"); + num_stereo = 1; + ctl->id.index = mixer_ch + ak->idx_offset * 2; + } else { + strcpy(ctl->id.name, ak->channel_names[mixer_ch]); + num_stereo = ak->num_stereo[mixer_ch]; + ctl->id.index = 0; //mixer_ch + ak->idx_offset * 2; + } ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; ctl->count = 1; - ctl->info = snd_akm4xxx_volume_info; - ctl->get = snd_akm4xxx_volume_get; - ctl->put = snd_akm4xxx_volume_put; + if (num_stereo == 2) { + ctl->info = snd_akm4xxx_stereo_volume_info; + ctl->get = snd_akm4xxx_stereo_volume_get; + ctl->put = snd_akm4xxx_stereo_volume_put; + } else { + ctl->info = snd_akm4xxx_volume_info; + ctl->get = snd_akm4xxx_volume_get; + ctl->put = snd_akm4xxx_volume_put; + } switch (ak->type) { case SND_AK4524: ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127); /* register 6 & 7 */ @@ -419,9 +492,13 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak) err = -EINVAL; goto __error; } + ctl->private_data = ak; if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) goto __error; + + idx += num_stereo; + mixer_ch++; } for (idx = 0; idx < ak->num_adcs && ak->type == SND_AK4524; ++idx) { memset(ctl, 0, sizeof(*ctl)); diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c index b5754b32b802..fec9440cb310 100644 --- a/sound/pci/ice1712/revo.c +++ b/sound/pci/ice1712/revo.c @@ -87,12 +87,25 @@ static void revo_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) * initialize the chips on M-Audio Revolution cards */ +static unsigned int revo71_num_stereo_front[] = {2}; +static char *revo71_channel_names_front[] = {"PCM Playback Volume"}; + +static unsigned int revo71_num_stereo_surround[] = {1, 1, 2, 2}; +static char *revo71_channel_names_surround[] = {"PCM Center Playback Volume", "PCM LFE Playback Volume", + "PCM Side Playback Volume", "PCM Rear Playback Volume"}; + +static unsigned int revo51_num_stereo[] = {2, 1, 1, 2}; +static char *revo51_channel_names[] = {"PCM Playback Volume", "PCM Center Playback Volume", + "PCM LFE Playback Volume", "PCM Rear Playback Volume"}; + static struct snd_akm4xxx akm_revo_front __devinitdata = { .type = SND_AK4381, .num_dacs = 2, .ops = { .set_rate_val = revo_set_rate_val - } + }, + .num_stereo = revo71_num_stereo_front, + .channel_names = revo71_channel_names_front }; static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = { @@ -113,7 +126,9 @@ static struct snd_akm4xxx akm_revo_surround __devinitdata = { .num_dacs = 6, .ops = { .set_rate_val = revo_set_rate_val - } + }, + .num_stereo = revo71_num_stereo_surround, + .channel_names = revo71_channel_names_surround }; static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = { @@ -133,7 +148,9 @@ static struct snd_akm4xxx akm_revo51 __devinitdata = { .num_dacs = 6, .ops = { .set_rate_val = revo_set_rate_val - } + }, + .num_stereo = revo51_num_stereo, + .channel_names = revo51_channel_names }; static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = { |