aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx88
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/cx88')
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c99
-rw-r--r--drivers/media/video/cx88/cx88-cards.c7
-rw-r--r--drivers/media/video/cx88/cx88-video.c27
-rw-r--r--drivers/media/video/cx88/cx88.h6
4 files changed, 124 insertions, 15 deletions
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 54b7fcd469a8..4aaa47c0eabf 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -40,6 +40,7 @@
40#include <sound/control.h> 40#include <sound/control.h>
41#include <sound/initval.h> 41#include <sound/initval.h>
42#include <sound/tlv.h> 42#include <sound/tlv.h>
43#include <media/wm8775.h>
43 44
44#include "cx88.h" 45#include "cx88.h"
45#include "cx88-reg.h" 46#include "cx88-reg.h"
@@ -586,26 +587,47 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,
586 int left, right, v, b; 587 int left, right, v, b;
587 int changed = 0; 588 int changed = 0;
588 u32 old; 589 u32 old;
590 struct v4l2_control client_ctl;
591
592 /* Pass volume & balance onto any WM8775 */
593 if (value->value.integer.value[0] >= value->value.integer.value[1]) {
594 v = value->value.integer.value[0] << 10;
595 b = value->value.integer.value[0] ?
596 (0x8000 * value->value.integer.value[1]) / value->value.integer.value[0] :
597 0x8000;
598 } else {
599 v = value->value.integer.value[1] << 10;
600 b = value->value.integer.value[1] ?
601 0xffff - (0x8000 * value->value.integer.value[0]) / value->value.integer.value[1] :
602 0x8000;
603 }
604 client_ctl.value = v;
605 client_ctl.id = V4L2_CID_AUDIO_VOLUME;
606 call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
607
608 client_ctl.value = b;
609 client_ctl.id = V4L2_CID_AUDIO_BALANCE;
610 call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
589 611
590 left = value->value.integer.value[0] & 0x3f; 612 left = value->value.integer.value[0] & 0x3f;
591 right = value->value.integer.value[1] & 0x3f; 613 right = value->value.integer.value[1] & 0x3f;
592 b = right - left; 614 b = right - left;
593 if (b < 0) { 615 if (b < 0) {
594 v = 0x3f - left; 616 v = 0x3f - left;
595 b = (-b) | 0x40; 617 b = (-b) | 0x40;
596 } else { 618 } else {
597 v = 0x3f - right; 619 v = 0x3f - right;
598 } 620 }
599 /* Do we really know this will always be called with IRQs on? */ 621 /* Do we really know this will always be called with IRQs on? */
600 spin_lock_irq(&chip->reg_lock); 622 spin_lock_irq(&chip->reg_lock);
601 old = cx_read(AUD_VOL_CTL); 623 old = cx_read(AUD_VOL_CTL);
602 if (v != (old & 0x3f)) { 624 if (v != (old & 0x3f)) {
603 cx_write(AUD_VOL_CTL, (old & ~0x3f) | v); 625 cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, (old & ~0x3f) | v);
604 changed = 1; 626 changed = 1;
605 } 627 }
606 if (cx_read(AUD_BAL_CTL) != b) { 628 if ((cx_read(AUD_BAL_CTL) & 0x7f) != b) {
607 cx_write(AUD_BAL_CTL, b); 629 cx_write(AUD_BAL_CTL, b);
608 changed = 1; 630 changed = 1;
609 } 631 }
610 spin_unlock_irq(&chip->reg_lock); 632 spin_unlock_irq(&chip->reg_lock);
611 633
@@ -618,7 +640,7 @@ static const struct snd_kcontrol_new snd_cx88_volume = {
618 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 640 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
619 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 641 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
620 SNDRV_CTL_ELEM_ACCESS_TLV_READ, 642 SNDRV_CTL_ELEM_ACCESS_TLV_READ,
621 .name = "Playback Volume", 643 .name = "Analog-TV Volume",
622 .info = snd_cx88_volume_info, 644 .info = snd_cx88_volume_info,
623 .get = snd_cx88_volume_get, 645 .get = snd_cx88_volume_get,
624 .put = snd_cx88_volume_put, 646 .put = snd_cx88_volume_put,
@@ -649,7 +671,14 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,
649 vol = cx_read(AUD_VOL_CTL); 671 vol = cx_read(AUD_VOL_CTL);
650 if (value->value.integer.value[0] != !(vol & bit)) { 672 if (value->value.integer.value[0] != !(vol & bit)) {
651 vol ^= bit; 673 vol ^= bit;
652 cx_write(AUD_VOL_CTL, vol); 674 cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol);
675 /* Pass mute onto any WM8775 */
676 if ((1<<6) == bit) {
677 struct v4l2_control client_ctl;
678 client_ctl.value = 0 != (vol & bit);
679 client_ctl.id = V4L2_CID_AUDIO_MUTE;
680 call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
681 }
653 ret = 1; 682 ret = 1;
654 } 683 }
655 spin_unlock_irq(&chip->reg_lock); 684 spin_unlock_irq(&chip->reg_lock);
@@ -658,7 +687,7 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,
658 687
659static const struct snd_kcontrol_new snd_cx88_dac_switch = { 688static const struct snd_kcontrol_new snd_cx88_dac_switch = {
660 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 689 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
661 .name = "Playback Switch", 690 .name = "Audio-Out Switch",
662 .info = snd_ctl_boolean_mono_info, 691 .info = snd_ctl_boolean_mono_info,
663 .get = snd_cx88_switch_get, 692 .get = snd_cx88_switch_get,
664 .put = snd_cx88_switch_put, 693 .put = snd_cx88_switch_put,
@@ -667,13 +696,49 @@ static const struct snd_kcontrol_new snd_cx88_dac_switch = {
667 696
668static const struct snd_kcontrol_new snd_cx88_source_switch = { 697static const struct snd_kcontrol_new snd_cx88_source_switch = {
669 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 698 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
670 .name = "Capture Switch", 699 .name = "Analog-TV Switch",
671 .info = snd_ctl_boolean_mono_info, 700 .info = snd_ctl_boolean_mono_info,
672 .get = snd_cx88_switch_get, 701 .get = snd_cx88_switch_get,
673 .put = snd_cx88_switch_put, 702 .put = snd_cx88_switch_put,
674 .private_value = (1<<6), 703 .private_value = (1<<6),
675}; 704};
676 705
706static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol,
707 struct snd_ctl_elem_value *value)
708{
709 snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
710 struct cx88_core *core = chip->core;
711 struct v4l2_control client_ctl;
712
713 client_ctl.id = V4L2_CID_AUDIO_LOUDNESS;
714 call_hw(core, WM8775_GID, core, g_ctrl, &client_ctl);
715 value->value.integer.value[0] = client_ctl.value ? 1 : 0;
716
717 return 0;
718}
719
720static int snd_cx88_alc_put(struct snd_kcontrol *kcontrol,
721 struct snd_ctl_elem_value *value)
722{
723 snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
724 struct cx88_core *core = chip->core;
725 struct v4l2_control client_ctl;
726
727 client_ctl.value = 0 != value->value.integer.value[0];
728 client_ctl.id = V4L2_CID_AUDIO_LOUDNESS;
729 call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
730
731 return 0;
732}
733
734static struct snd_kcontrol_new snd_cx88_alc_switch = {
735 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
736 .name = "Line-In ALC Switch",
737 .info = snd_ctl_boolean_mono_info,
738 .get = snd_cx88_alc_get,
739 .put = snd_cx88_alc_put,
740};
741
677/**************************************************************************** 742/****************************************************************************
678 Basic Flow for Sound Devices 743 Basic Flow for Sound Devices
679 ****************************************************************************/ 744 ****************************************************************************/
@@ -795,6 +860,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
795{ 860{
796 struct snd_card *card; 861 struct snd_card *card;
797 snd_cx88_card_t *chip; 862 snd_cx88_card_t *chip;
863 struct v4l2_subdev *sd;
798 int err; 864 int err;
799 865
800 if (devno >= SNDRV_CARDS) 866 if (devno >= SNDRV_CARDS)
@@ -830,6 +896,15 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
830 if (err < 0) 896 if (err < 0)
831 goto error; 897 goto error;
832 898
899 /* If there's a wm8775 then add a Line-In ALC switch */
900 list_for_each_entry(sd, &chip->core->v4l2_dev.subdevs, list) {
901 if (WM8775_GID == sd->grp_id) {
902 snd_ctl_add(card, snd_ctl_new1(&snd_cx88_alc_switch,
903 chip));
904 break;
905 }
906 }
907
833 strcpy (card->driver, "CX88x"); 908 strcpy (card->driver, "CX88x");
834 sprintf(card->shortname, "Conexant CX%x", pci->device); 909 sprintf(card->shortname, "Conexant CX%x", pci->device);
835 sprintf(card->longname, "%s at %#llx", 910 sprintf(card->longname, "%s at %#llx",
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 7bfe330a8167..b26fcba8600c 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -970,15 +970,22 @@ static const struct cx88_board cx88_boards[] = {
970 .radio_type = UNSET, 970 .radio_type = UNSET,
971 .tuner_addr = ADDR_UNSET, 971 .tuner_addr = ADDR_UNSET,
972 .radio_addr = ADDR_UNSET, 972 .radio_addr = ADDR_UNSET,
973 .audio_chip = V4L2_IDENT_WM8775,
973 .input = {{ 974 .input = {{
974 .type = CX88_VMUX_DVB, 975 .type = CX88_VMUX_DVB,
975 .vmux = 0, 976 .vmux = 0,
977 /* 2: Line-In */
978 .audioroute = 2,
976 },{ 979 },{
977 .type = CX88_VMUX_COMPOSITE1, 980 .type = CX88_VMUX_COMPOSITE1,
978 .vmux = 1, 981 .vmux = 1,
982 /* 2: Line-In */
983 .audioroute = 2,
979 },{ 984 },{
980 .type = CX88_VMUX_SVIDEO, 985 .type = CX88_VMUX_SVIDEO,
981 .vmux = 2, 986 .vmux = 2,
987 /* 2: Line-In */
988 .audioroute = 2,
982 }}, 989 }},
983 .mpeg = CX88_MPEG_DVB, 990 .mpeg = CX88_MPEG_DVB,
984 }, 991 },
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index e3cff585215d..d2f159daa8b5 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -41,6 +41,7 @@
41#include "cx88.h" 41#include "cx88.h"
42#include <media/v4l2-common.h> 42#include <media/v4l2-common.h>
43#include <media/v4l2-ioctl.h> 43#include <media/v4l2-ioctl.h>
44#include <media/wm8775.h>
44 45
45MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); 46MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
46MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); 47MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -977,6 +978,7 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
977 const struct cx88_ctrl *c = NULL; 978 const struct cx88_ctrl *c = NULL;
978 u32 value,mask; 979 u32 value,mask;
979 int i; 980 int i;
981 struct v4l2_control client_ctl;
980 982
981 for (i = 0; i < CX8800_CTLS; i++) { 983 for (i = 0; i < CX8800_CTLS; i++) {
982 if (cx8800_ctls[i].v.id == ctl->id) { 984 if (cx8800_ctls[i].v.id == ctl->id) {
@@ -990,6 +992,27 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
990 ctl->value = c->v.minimum; 992 ctl->value = c->v.minimum;
991 if (ctl->value > c->v.maximum) 993 if (ctl->value > c->v.maximum)
992 ctl->value = c->v.maximum; 994 ctl->value = c->v.maximum;
995
996 /* Pass changes onto any WM8775 */
997 client_ctl.id = ctl->id;
998 switch (ctl->id) {
999 case V4L2_CID_AUDIO_MUTE:
1000 client_ctl.value = ctl->value;
1001 break;
1002 case V4L2_CID_AUDIO_VOLUME:
1003 client_ctl.value = (ctl->value) ?
1004 (0x90 + ctl->value) << 8 : 0;
1005 break;
1006 case V4L2_CID_AUDIO_BALANCE:
1007 client_ctl.value = ctl->value << 9;
1008 break;
1009 default:
1010 client_ctl.id = 0;
1011 break;
1012 }
1013 if (client_ctl.id)
1014 call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
1015
993 mask=c->mask; 1016 mask=c->mask;
994 switch (ctl->id) { 1017 switch (ctl->id) {
995 case V4L2_CID_AUDIO_BALANCE: 1018 case V4L2_CID_AUDIO_BALANCE:
@@ -1536,7 +1559,9 @@ static int radio_queryctrl (struct file *file, void *priv,
1536 if (c->id < V4L2_CID_BASE || 1559 if (c->id < V4L2_CID_BASE ||
1537 c->id >= V4L2_CID_LASTP1) 1560 c->id >= V4L2_CID_LASTP1)
1538 return -EINVAL; 1561 return -EINVAL;
1539 if (c->id == V4L2_CID_AUDIO_MUTE) { 1562 if (c->id == V4L2_CID_AUDIO_MUTE ||
1563 c->id == V4L2_CID_AUDIO_VOLUME ||
1564 c->id == V4L2_CID_AUDIO_BALANCE) {
1540 for (i = 0; i < CX8800_CTLS; i++) { 1565 for (i = 0; i < CX8800_CTLS; i++) {
1541 if (cx8800_ctls[i].v.id == c->id) 1566 if (cx8800_ctls[i].v.id == c->id)
1542 break; 1567 break;
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index c9981e77416a..e8c732e7ae4f 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -398,17 +398,19 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev)
398 return container_of(v4l2_dev, struct cx88_core, v4l2_dev); 398 return container_of(v4l2_dev, struct cx88_core, v4l2_dev);
399} 399}
400 400
401#define call_all(core, o, f, args...) \ 401#define call_hw(core, grpid, o, f, args...) \
402 do { \ 402 do { \
403 if (!core->i2c_rc) { \ 403 if (!core->i2c_rc) { \
404 if (core->gate_ctrl) \ 404 if (core->gate_ctrl) \
405 core->gate_ctrl(core, 1); \ 405 core->gate_ctrl(core, 1); \
406 v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \ 406 v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \
407 if (core->gate_ctrl) \ 407 if (core->gate_ctrl) \
408 core->gate_ctrl(core, 0); \ 408 core->gate_ctrl(core, 0); \
409 } \ 409 } \
410 } while (0) 410 } while (0)
411 411
412#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args)
413
412struct cx8800_dev; 414struct cx8800_dev;
413struct cx8802_dev; 415struct cx8802_dev;
414 416