diff options
author | Trent Piepho <xyzzy@speakeasy.org> | 2007-09-06 23:02:23 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-10-09 22:08:31 -0300 |
commit | 82896f29d47d945e331873c7295da9e3a47d709d (patch) | |
tree | 7c237b70408049f5cf8ae0073ce1a33a5adb1e7f /drivers/media/video/cx88/cx88-alsa.c | |
parent | 6fcecce7e1a5223be450031fa446323b08d1ec41 (diff) | |
download | linux-82896f29d47d945e331873c7295da9e3a47d709d.tar.gz linux-82896f29d47d945e331873c7295da9e3a47d709d.tar.bz2 linux-82896f29d47d945e331873c7295da9e3a47d709d.zip |
V4L/DVB (6184): cx88-alsa: Make volume control stereo
Use the balance control to make the mono volume control stereo.
Note that full range isn't supported. The balance control attenuates one
channel by 0 to -63 dB, and the volume control provides additional attenuation
to both channels by another 0 to -63 dB.
So the channel with the most attenuation has a range of 0 to -126 dB, while
the other channel only has a range of 0 to -63 dB. ALSA volume controls don't
appear to support this concept. I just limited the range to 0 to -63 total.
Once you get to -63 dB, you're already at silence, so additional attenuation
is pretty much pointless anyway.
Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/cx88/cx88-alsa.c')
-rw-r--r-- | drivers/media/video/cx88/cx88-alsa.c | 61 |
1 files changed, 37 insertions, 24 deletions
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 85d632224f3a..25de25fb8052 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -552,7 +552,7 @@ static int snd_cx88_capture_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info) { info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = 1; + info->count = 2; info->value.integer.min = 0; info->value.integer.max = 0x3f; @@ -565,8 +565,12 @@ static int snd_cx88_capture_volume_get(struct snd_kcontrol *kcontrol, { snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core=chip->core; + int vol = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f), + bal = cx_read(AUD_BAL_CTL); - value->value.integer.value[0] = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f); + value->value.integer.value[(bal & 0x40) ? 0 : 1] = vol; + vol -= (bal & 0x3f); + value->value.integer.value[(bal & 0x40) ? 1 : 0] = vol < 0 ? 0 : vol; return 0; } @@ -577,19 +581,31 @@ static int snd_cx88_capture_volume_put(struct snd_kcontrol *kcontrol, { snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core=chip->core; - int v; - u32 old_control; - + int v, b; + int changed = 0; + u32 old; + + b = value->value.integer.value[1] - value->value.integer.value[0]; + if (b < 0) { + v = 0x3f - value->value.integer.value[0]; + b = (-b) | 0x40; + } else { + v = 0x3f - value->value.integer.value[1]; + } /* Do we really know this will always be called with IRQs on? */ spin_lock_irq(&chip->reg_lock); - - old_control = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f); - v = 0x3f - (value->value.integer.value[0] & 0x3f); - cx_andor(AUD_VOL_CTL, 0x3f, v); - + old = cx_read(AUD_VOL_CTL); + if (v != (old & 0x3f)) { + cx_write(AUD_VOL_CTL, (old & ~0x3f) | v); + changed = 1; + } + if (cx_read(AUD_BAL_CTL) != b) { + cx_write(AUD_BAL_CTL, b); + changed = 1; + } spin_unlock_irq(&chip->reg_lock); - return v != old_control; + return changed; } static struct snd_kcontrol_new snd_cx88_capture_volume = { @@ -746,17 +762,12 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, return (err); err = snd_cx88_pcm(chip, 0, "CX88 Digital"); - - if (err < 0) { - snd_card_free(card); - return (err); - } + if (err < 0) + goto error; err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_capture_volume, chip)); - if (err < 0) { - snd_card_free(card); - return (err); - } + if (err < 0) + goto error; strcpy (card->driver, "CX88x"); sprintf(card->shortname, "Conexant CX%x", pci->device); @@ -768,14 +779,16 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, card->driver,devno); err = snd_card_register(card); - if (err < 0) { - snd_card_free(card); - return (err); - } + if (err < 0) + goto error; pci_set_drvdata(pci,card); devno++; return 0; + +error: + snd_card_free(card); + return err; } /* * ALSA destructor |