diff options
author | Trent Piepho <xyzzy@speakeasy.org> | 2007-09-06 22:02:23 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-10-09 21:08:31 -0400 |
commit | 82896f29d47d945e331873c7295da9e3a47d709d (patch) | |
tree | 7c237b70408049f5cf8ae0073ce1a33a5adb1e7f /drivers/media/video/cx88/cx88-alsa.c | |
parent | 6fcecce7e1a5223be450031fa446323b08d1ec41 (diff) |
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, | |||
552 | struct snd_ctl_elem_info *info) | 552 | struct snd_ctl_elem_info *info) |
553 | { | 553 | { |
554 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 554 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
555 | info->count = 1; | 555 | info->count = 2; |
556 | info->value.integer.min = 0; | 556 | info->value.integer.min = 0; |
557 | info->value.integer.max = 0x3f; | 557 | info->value.integer.max = 0x3f; |
558 | 558 | ||
@@ -565,8 +565,12 @@ static int snd_cx88_capture_volume_get(struct snd_kcontrol *kcontrol, | |||
565 | { | 565 | { |
566 | snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); | 566 | snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); |
567 | struct cx88_core *core=chip->core; | 567 | struct cx88_core *core=chip->core; |
568 | int vol = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f), | ||
569 | bal = cx_read(AUD_BAL_CTL); | ||
568 | 570 | ||
569 | value->value.integer.value[0] = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f); | 571 | value->value.integer.value[(bal & 0x40) ? 0 : 1] = vol; |
572 | vol -= (bal & 0x3f); | ||
573 | value->value.integer.value[(bal & 0x40) ? 1 : 0] = vol < 0 ? 0 : vol; | ||
570 | 574 | ||
571 | return 0; | 575 | return 0; |
572 | } | 576 | } |
@@ -577,19 +581,31 @@ static int snd_cx88_capture_volume_put(struct snd_kcontrol *kcontrol, | |||
577 | { | 581 | { |
578 | snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); | 582 | snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); |
579 | struct cx88_core *core=chip->core; | 583 | struct cx88_core *core=chip->core; |
580 | int v; | 584 | int v, b; |
581 | u32 old_control; | 585 | int changed = 0; |
582 | 586 | u32 old; | |
587 | |||
588 | b = value->value.integer.value[1] - value->value.integer.value[0]; | ||
589 | if (b < 0) { | ||
590 | v = 0x3f - value->value.integer.value[0]; | ||
591 | b = (-b) | 0x40; | ||
592 | } else { | ||
593 | v = 0x3f - value->value.integer.value[1]; | ||
594 | } | ||
583 | /* Do we really know this will always be called with IRQs on? */ | 595 | /* Do we really know this will always be called with IRQs on? */ |
584 | spin_lock_irq(&chip->reg_lock); | 596 | spin_lock_irq(&chip->reg_lock); |
585 | 597 | old = cx_read(AUD_VOL_CTL); | |
586 | old_control = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f); | 598 | if (v != (old & 0x3f)) { |
587 | v = 0x3f - (value->value.integer.value[0] & 0x3f); | 599 | cx_write(AUD_VOL_CTL, (old & ~0x3f) | v); |
588 | cx_andor(AUD_VOL_CTL, 0x3f, v); | 600 | changed = 1; |
589 | 601 | } | |
602 | if (cx_read(AUD_BAL_CTL) != b) { | ||
603 | cx_write(AUD_BAL_CTL, b); | ||
604 | changed = 1; | ||
605 | } | ||
590 | spin_unlock_irq(&chip->reg_lock); | 606 | spin_unlock_irq(&chip->reg_lock); |
591 | 607 | ||
592 | return v != old_control; | 608 | return changed; |
593 | } | 609 | } |
594 | 610 | ||
595 | static struct snd_kcontrol_new snd_cx88_capture_volume = { | 611 | static struct snd_kcontrol_new snd_cx88_capture_volume = { |
@@ -746,17 +762,12 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, | |||
746 | return (err); | 762 | return (err); |
747 | 763 | ||
748 | err = snd_cx88_pcm(chip, 0, "CX88 Digital"); | 764 | err = snd_cx88_pcm(chip, 0, "CX88 Digital"); |
749 | 765 | if (err < 0) | |
750 | if (err < 0) { | 766 | goto error; |
751 | snd_card_free(card); | ||
752 | return (err); | ||
753 | } | ||
754 | 767 | ||
755 | err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_capture_volume, chip)); | 768 | err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_capture_volume, chip)); |
756 | if (err < 0) { | 769 | if (err < 0) |
757 | snd_card_free(card); | 770 | goto error; |
758 | return (err); | ||
759 | } | ||
760 | 771 | ||
761 | strcpy (card->driver, "CX88x"); | 772 | strcpy (card->driver, "CX88x"); |
762 | sprintf(card->shortname, "Conexant CX%x", pci->device); | 773 | sprintf(card->shortname, "Conexant CX%x", pci->device); |
@@ -768,14 +779,16 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, | |||
768 | card->driver,devno); | 779 | card->driver,devno); |
769 | 780 | ||
770 | err = snd_card_register(card); | 781 | err = snd_card_register(card); |
771 | if (err < 0) { | 782 | if (err < 0) |
772 | snd_card_free(card); | 783 | goto error; |
773 | return (err); | ||
774 | } | ||
775 | pci_set_drvdata(pci,card); | 784 | pci_set_drvdata(pci,card); |
776 | 785 | ||
777 | devno++; | 786 | devno++; |
778 | return 0; | 787 | return 0; |
788 | |||
789 | error: | ||
790 | snd_card_free(card); | ||
791 | return err; | ||
779 | } | 792 | } |
780 | /* | 793 | /* |
781 | * ALSA destructor | 794 | * ALSA destructor |