Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux...
[pandora-kernel.git] / drivers / media / video / bt8xx / bttv-driver.c
index 7153577..5764a89 100644 (file)
@@ -36,6 +36,8 @@
 #include <linux/kdev_t.h>
 #include "bttvp.h"
 #include <media/v4l2-common.h>
+#include <media/tvaudio.h>
+#include <media/msp3400.h>
 
 #include <linux/dma-mapping.h>
 
@@ -926,56 +928,106 @@ video_mux(struct bttv *btv, unsigned int input)
 
 static char *audio_modes[] = {
        "audio: tuner", "audio: radio", "audio: extern",
-       "audio: intern", "audio: off"
+       "audio: intern", "audio: mute"
 };
 
 static int
-audio_mux(struct bttv *btv, int mode)
+audio_mux(struct bttv *btv, int input, int mute)
 {
-       int val,mux,i2c_mux,signal;
+       int gpio_val, signal;
+       struct v4l2_control ctrl;
+       struct i2c_client *c;
 
        gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
                   bttv_tvcards[btv->c.type].gpiomask);
        signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
 
-       switch (mode) {
-       case AUDIO_MUTE:
-               btv->audio |= AUDIO_MUTE;
-               break;
-       case AUDIO_UNMUTE:
-               btv->audio &= ~AUDIO_MUTE;
-               break;
-       case AUDIO_TUNER:
-       case AUDIO_RADIO:
-       case AUDIO_EXTERN:
-       case AUDIO_INTERN:
-               btv->audio &= AUDIO_MUTE;
-               btv->audio |= mode;
-       }
-       i2c_mux = mux = (btv->audio & AUDIO_MUTE) ? AUDIO_OFF : btv->audio;
-       if (btv->opt_automute && !signal && !btv->radio_user)
-               mux = AUDIO_OFF;
-
-       val = bttv_tvcards[btv->c.type].audiomux[mux];
-       gpio_bits(bttv_tvcards[btv->c.type].gpiomask,val);
+       btv->mute = mute;
+       btv->audio = input;
+
+       /* automute */
+       mute = mute || (btv->opt_automute && !signal && !btv->radio_user);
+
+       if (mute)
+               gpio_val = bttv_tvcards[btv->c.type].gpiomute;
+       else
+               gpio_val = bttv_tvcards[btv->c.type].gpiomux[input];
+
+       gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val);
        if (bttv_gpio)
-               bttv_gpio_tracking(btv,audio_modes[mux]);
-       if (!in_interrupt())
-               bttv_call_i2c_clients(btv,AUDC_SET_INPUT,&(i2c_mux));
+               bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]);
+       if (in_interrupt())
+               return 0;
+
+       ctrl.id = V4L2_CID_AUDIO_MUTE;
+       ctrl.value = btv->mute;
+       bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, &ctrl);
+       c = btv->i2c_msp34xx_client;
+       if (c) {
+               struct v4l2_routing route;
+
+               /* Note: the inputs tuner/radio/extern/intern are translated
+                  to msp routings. This assumes common behavior for all msp3400
+                  based TV cards. When this assumption fails, then the
+                  specific MSP routing must be added to the card table.
+                  For now this is sufficient. */
+               switch (input) {
+               case TVAUDIO_INPUT_RADIO:
+                       route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
+                                   MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
+                       break;
+               case TVAUDIO_INPUT_EXTERN:
+                       route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
+                                   MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
+                       break;
+               case TVAUDIO_INPUT_INTERN:
+                       /* Yes, this is the same input as for RADIO. I doubt
+                          if this is ever used. The only board with an INTERN
+                          input is the BTTV_BOARD_AVERMEDIA98. I wonder how
+                          that was tested. My guess is that the whole INTERN
+                          input does not work. */
+                       route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
+                                   MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
+                       break;
+               case TVAUDIO_INPUT_TUNER:
+               default:
+                       route.input = MSP_INPUT_DEFAULT;
+                       break;
+               }
+               route.output = MSP_OUTPUT_DEFAULT;
+               c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+       }
+       c = btv->i2c_tvaudio_client;
+       if (c) {
+               struct v4l2_routing route;
+
+               route.input = input;
+               route.output = 0;
+               c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+       }
        return 0;
 }
 
+static inline int
+audio_mute(struct bttv *btv, int mute)
+{
+       return audio_mux(btv, btv->audio, mute);
+}
+
+static inline int
+audio_input(struct bttv *btv, int input)
+{
+       return audio_mux(btv, input, btv->mute);
+}
+
 static void
 i2c_vidiocschan(struct bttv *btv)
 {
-       struct video_channel c;
+       v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id;
 
-       memset(&c,0,sizeof(c));
-       c.norm    = btv->tvnorm;
-       c.channel = btv->input;
-       bttv_call_i2c_clients(btv,VIDIOCSCHAN,&c);
+       bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std);
        if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
-               bttv_tda9880_setnorm(btv,c.norm);
+               bttv_tda9880_setnorm(btv,btv->tvnorm);
 }
 
 static int
@@ -1023,8 +1075,8 @@ set_input(struct bttv *btv, unsigned int input)
        } else {
                video_mux(btv,input);
        }
-       audio_mux(btv,(input == bttv_tvcards[btv->c.type].tuner ?
-                      AUDIO_TUNER : AUDIO_EXTERN));
+       audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ?
+                      TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN));
        set_tvnorm(btv,btv->tvnorm);
        i2c_vidiocschan(btv);
 }
@@ -1129,11 +1181,27 @@ static int get_control(struct bttv *btv, struct v4l2_control *c)
                        break;
        if (i == BTTV_CTLS)
                return -EINVAL;
-       if (i >= 4 && i <= 8) {
+       if (btv->audio_hook && i >= 4 && i <= 8) {
                memset(&va,0,sizeof(va));
-               bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
-               if (btv->audio_hook)
-                       btv->audio_hook(btv,&va,0);
+               btv->audio_hook(btv,&va,0);
+               switch (c->id) {
+               case V4L2_CID_AUDIO_MUTE:
+                       c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
+                       break;
+               case V4L2_CID_AUDIO_VOLUME:
+                       c->value = va.volume;
+                       break;
+               case V4L2_CID_AUDIO_BALANCE:
+                       c->value = va.balance;
+                       break;
+               case V4L2_CID_AUDIO_BASS:
+                       c->value = va.bass;
+                       break;
+               case V4L2_CID_AUDIO_TREBLE:
+                       c->value = va.treble;
+                       break;
+               }
+               return 0;
        }
        switch (c->id) {
        case V4L2_CID_BRIGHTNESS:
@@ -1150,19 +1218,11 @@ static int get_control(struct bttv *btv, struct v4l2_control *c)
                break;
 
        case V4L2_CID_AUDIO_MUTE:
-               c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
-               break;
        case V4L2_CID_AUDIO_VOLUME:
-               c->value = va.volume;
-               break;
        case V4L2_CID_AUDIO_BALANCE:
-               c->value = va.balance;
-               break;
        case V4L2_CID_AUDIO_BASS:
-               c->value = va.bass;
-               break;
        case V4L2_CID_AUDIO_TREBLE:
-               c->value = va.treble;
+               bttv_call_i2c_clients(btv,VIDIOC_G_CTRL,c);
                break;
 
        case V4L2_CID_PRIVATE_CHROMA_AGC:
@@ -1214,11 +1274,35 @@ static int set_control(struct bttv *btv, struct v4l2_control *c)
                        break;
        if (i == BTTV_CTLS)
                return -EINVAL;
-       if (i >= 4 && i <= 8) {
+       if (btv->audio_hook && i >= 4 && i <= 8) {
                memset(&va,0,sizeof(va));
-               bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
-               if (btv->audio_hook)
-                       btv->audio_hook(btv,&va,0);
+               btv->audio_hook(btv,&va,0);
+               switch (c->id) {
+               case V4L2_CID_AUDIO_MUTE:
+                       if (c->value) {
+                               va.flags |= VIDEO_AUDIO_MUTE;
+                               audio_mute(btv, 1);
+                       } else {
+                               va.flags &= ~VIDEO_AUDIO_MUTE;
+                               audio_mute(btv, 0);
+                       }
+                       break;
+
+               case V4L2_CID_AUDIO_VOLUME:
+                       va.volume = c->value;
+                       break;
+               case V4L2_CID_AUDIO_BALANCE:
+                       va.balance = c->value;
+                       break;
+               case V4L2_CID_AUDIO_BASS:
+                       va.bass = c->value;
+                       break;
+               case V4L2_CID_AUDIO_TREBLE:
+                       va.treble = c->value;
+                       break;
+               }
+               btv->audio_hook(btv,&va,1);
+               return 0;
        }
        switch (c->id) {
        case V4L2_CID_BRIGHTNESS:
@@ -1234,26 +1318,13 @@ static int set_control(struct bttv *btv, struct v4l2_control *c)
                bt848_sat(btv,c->value);
                break;
        case V4L2_CID_AUDIO_MUTE:
-               if (c->value) {
-                       va.flags |= VIDEO_AUDIO_MUTE;
-                       audio_mux(btv, AUDIO_MUTE);
-               } else {
-                       va.flags &= ~VIDEO_AUDIO_MUTE;
-                       audio_mux(btv, AUDIO_UNMUTE);
-               }
-               break;
-
+               audio_mute(btv, c->value);
+               /* fall through */
        case V4L2_CID_AUDIO_VOLUME:
-               va.volume = c->value;
-               break;
        case V4L2_CID_AUDIO_BALANCE:
-               va.balance = c->value;
-               break;
        case V4L2_CID_AUDIO_BASS:
-               va.bass = c->value;
-               break;
        case V4L2_CID_AUDIO_TREBLE:
-               va.treble = c->value;
+               bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c);
                break;
 
        case V4L2_CID_PRIVATE_CHROMA_AGC:
@@ -1309,11 +1380,6 @@ static int set_control(struct bttv *btv, struct v4l2_control *c)
        default:
                return -EINVAL;
        }
-       if (i >= 4 && i <= 8) {
-               bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
-               if (btv->audio_hook)
-                       btv->audio_hook(btv,&va,1);
-       }
        return 0;
 }
 
@@ -1536,12 +1602,16 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
        }
        case VIDIOCSFREQ:
        {
-               unsigned long *freq = arg;
+               struct v4l2_frequency freq;
+
+               memset(&freq, 0, sizeof(freq));
+               freq.frequency = *(unsigned long *)arg;
                mutex_lock(&btv->lock);
-               btv->freq=*freq;
-               bttv_call_i2c_clients(btv,VIDIOCSFREQ,freq);
+               freq.type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+               btv->freq = *(unsigned long *)arg;
+               bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,&freq);
                if (btv->has_matchbox && btv->radio_user)
-                       tea5757_set_freq(btv,*freq);
+                       tea5757_set_freq(btv,*(unsigned long *)arg);
                mutex_unlock(&btv->lock);
                return 0;
        }
@@ -1654,7 +1724,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
                        return -EINVAL;
 
                mutex_lock(&btv->lock);
-               audio_mux(btv, (v->flags&VIDEO_AUDIO_MUTE) ? AUDIO_MUTE : AUDIO_UNMUTE);
+               audio_mute(btv, (v->flags&VIDEO_AUDIO_MUTE) ? 1 : 0);
                bttv_call_i2c_clients(btv,cmd,v);
 
                /* card specific hooks */
@@ -1772,33 +1842,26 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
                        return -EINVAL;
                mutex_lock(&btv->lock);
                memset(t,0,sizeof(*t));
+               t->rxsubchans = V4L2_TUNER_SUB_MONO;
+               bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
                strcpy(t->name, "Television");
-               t->type       = V4L2_TUNER_ANALOG_TV;
                t->capability = V4L2_TUNER_CAP_NORM;
-               t->rxsubchans = V4L2_TUNER_SUB_MONO;
+               t->type       = V4L2_TUNER_ANALOG_TV;
                if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
                        t->signal = 0xffff;
-               {
-                       struct video_tuner tuner;
-
-                       memset(&tuner, 0, sizeof (tuner));
-                       tuner.rangehigh = 0xffffffffUL;
-                       bttv_call_i2c_clients(btv, VIDIOCGTUNER, &tuner);
-                       t->rangelow = tuner.rangelow;
-                       t->rangehigh = tuner.rangehigh;
-               }
-               {
+
+               if (btv->audio_hook) {
                        /* Hmmm ... */
                        struct video_audio va;
                        memset(&va, 0, sizeof(struct video_audio));
-                       bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
-                       if (btv->audio_hook)
-                               btv->audio_hook(btv,&va,0);
+                       btv->audio_hook(btv,&va,0);
+                       t->audmode    = V4L2_TUNER_MODE_MONO;
+                       t->rxsubchans = V4L2_TUNER_SUB_MONO;
                        if(va.mode & VIDEO_SOUND_STEREO) {
-                               t->audmode     = V4L2_TUNER_MODE_STEREO;
-                               t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+                               t->audmode    = V4L2_TUNER_MODE_STEREO;
+                               t->rxsubchans = V4L2_TUNER_SUB_STEREO;
                        }
-                       if(va.mode & VIDEO_SOUND_LANG1) {
+                       if(va.mode & VIDEO_SOUND_LANG2) {
                                t->audmode    = V4L2_TUNER_MODE_LANG1;
                                t->rxsubchans = V4L2_TUNER_SUB_LANG1
                                        | V4L2_TUNER_SUB_LANG2;
@@ -1817,21 +1880,20 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
                if (0 != t->index)
                        return -EINVAL;
                mutex_lock(&btv->lock);
-               {
+               bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
+               if (btv->audio_hook) {
                        struct video_audio va;
                        memset(&va, 0, sizeof(struct video_audio));
-                       bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
                        if (t->audmode == V4L2_TUNER_MODE_MONO)
                                va.mode = VIDEO_SOUND_MONO;
-                       else if (t->audmode == V4L2_TUNER_MODE_STEREO)
+                       else if (t->audmode == V4L2_TUNER_MODE_STEREO ||
+                                t->audmode == V4L2_TUNER_MODE_LANG1_LANG2)
                                va.mode = VIDEO_SOUND_STEREO;
                        else if (t->audmode == V4L2_TUNER_MODE_LANG1)
                                va.mode = VIDEO_SOUND_LANG1;
                        else if (t->audmode == V4L2_TUNER_MODE_LANG2)
                                va.mode = VIDEO_SOUND_LANG2;
-                       bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
-                       if (btv->audio_hook)
-                               btv->audio_hook(btv,&va,1);
+                       btv->audio_hook(btv,&va,1);
                }
                mutex_unlock(&btv->lock);
                return 0;
@@ -1856,7 +1918,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
                        return -EINVAL;
                mutex_lock(&btv->lock);
                btv->freq = f->frequency;
-               bttv_call_i2c_clients(btv,VIDIOCSFREQ,&btv->freq);
+               bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,f);
                if (btv->has_matchbox && btv->radio_user)
                        tea5757_set_freq(btv,btv->freq);
                mutex_unlock(&btv->lock);
@@ -1864,7 +1926,9 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
        }
        case VIDIOC_LOG_STATUS:
        {
+               printk(KERN_INFO "bttv%d: =================  START STATUS CARD #%d  =================\n", btv->c.nr, btv->c.nr);
                bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
+               printk(KERN_INFO "bttv%d: ==================  END STATUS CARD #%d  ==================\n", btv->c.nr, btv->c.nr);
                return 0;
        }
 
@@ -2814,12 +2878,10 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                        return 0;
                }
                *c = bttv_ctls[i];
-               if (i >= 4 && i <= 8) {
+               if (btv->audio_hook && i >= 4 && i <= 8) {
                        struct video_audio va;
                        memset(&va,0,sizeof(va));
-                       bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
-                       if (btv->audio_hook)
-                               btv->audio_hook(btv,&va,0);
+                       btv->audio_hook(btv,&va,0);
                        switch (bttv_ctls[i].id) {
                        case V4L2_CID_AUDIO_VOLUME:
                                if (!(va.flags & VIDEO_AUDIO_VOLUME))
@@ -3163,8 +3225,8 @@ static int radio_open(struct inode *inode, struct file *file)
 
        file->private_data = btv;
 
-       bttv_call_i2c_clients(btv,AUDC_SET_RADIO,&btv->tuner_type);
-       audio_mux(btv,AUDIO_RADIO);
+       bttv_call_i2c_clients(btv,AUDC_SET_RADIO,NULL);
+       audio_input(btv,TVAUDIO_INPUT_RADIO);
 
        mutex_unlock(&btv->lock);
        return 0;
@@ -3750,7 +3812,7 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
                        bttv_irq_switch_video(btv);
 
                if ((astat & BT848_INT_HLOCK)  &&  btv->opt_automute)
-                       audio_mux(btv, -1);
+                       audio_mute(btv, btv->mute);  /* trigger automute */
 
                if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) {
                        printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr,
@@ -3957,8 +4019,9 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        if (!request_mem_region(pci_resource_start(dev,0),
                                pci_resource_len(dev,0),
                                btv->c.name)) {
-               printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
-                      btv->c.nr, pci_resource_start(dev,0));
+               printk(KERN_WARNING "bttv%d: can't request iomem (0x%llx).\n",
+                      btv->c.nr,
+                      (unsigned long long)pci_resource_start(dev,0));
                return -EBUSY;
        }
        pci_set_master(dev);
@@ -3969,8 +4032,9 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
        printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
               bttv_num,btv->id, btv->revision, pci_name(dev));
-       printk("irq: %d, latency: %d, mmio: 0x%lx\n",
-              btv->c.pci->irq, lat, pci_resource_start(dev,0));
+       printk("irq: %d, latency: %d, mmio: 0x%llx\n",
+              btv->c.pci->irq, lat,
+              (unsigned long long)pci_resource_start(dev,0));
        schedule();
 
        btv->bt848_mmio=ioremap(pci_resource_start(dev,0), 0x1000);
@@ -3986,7 +4050,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        /* disable irqs, register irq handler */
        btwrite(0, BT848_INT_MASK);
        result = request_irq(btv->c.pci->irq, bttv_irq,
-                            SA_SHIRQ | SA_INTERRUPT,btv->c.name,(void *)btv);
+                            IRQF_SHARED | IRQF_DISABLED,btv->c.name,(void *)btv);
        if (result < 0) {
                printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
                       bttv_num,btv->c.pci->irq);
@@ -4051,7 +4115,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
                bt848_contrast(btv,32768);
                bt848_hue(btv,32768);
                bt848_sat(btv,32768);
-               audio_mux(btv,AUDIO_MUTE);
+               audio_mute(btv, 1);
                set_input(btv,0);
        }