fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / media / video / cx88 / cx88-video.c
index 073494c..8613378 100644 (file)
 #include "cx88.h"
 #include <media/v4l2-common.h>
 
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
 /* Include V4L1 specific functions. Should be removed soon */
 #include <linux/videodev.h>
+#endif
 
 MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -227,7 +229,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
                        .minimum       = 0x00,
                        .maximum       = 0xff,
                        .step          = 1,
-                       .default_value = 0,
+                       .default_value = 0x7f,
                        .type          = V4L2_CTRL_TYPE_INTEGER,
                },
                .off                   = 128,
@@ -255,7 +257,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
                        .minimum       = 0,
                        .maximum       = 0xff,
                        .step          = 1,
-                       .default_value = 0,
+                       .default_value = 0x7f,
                        .type          = V4L2_CTRL_TYPE_INTEGER,
                },
                .off                   = 128,
@@ -300,7 +302,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
                        .minimum       = 0,
                        .maximum       = 0x3f,
                        .step          = 1,
-                       .default_value = 0x1f,
+                       .default_value = 0x3f,
                        .type          = V4L2_CTRL_TYPE_INTEGER,
                },
                .reg                   = AUD_VOL_CTL,
@@ -325,6 +327,51 @@ static struct cx88_ctrl cx8800_ctls[] = {
 };
 static const int CX8800_CTLS = ARRAY_SIZE(cx8800_ctls);
 
+const u32 cx88_user_ctrls[] = {
+       V4L2_CID_USER_CLASS,
+       V4L2_CID_BRIGHTNESS,
+       V4L2_CID_CONTRAST,
+       V4L2_CID_SATURATION,
+       V4L2_CID_HUE,
+       V4L2_CID_AUDIO_VOLUME,
+       V4L2_CID_AUDIO_BALANCE,
+       V4L2_CID_AUDIO_MUTE,
+       0
+};
+EXPORT_SYMBOL(cx88_user_ctrls);
+
+static const u32 *ctrl_classes[] = {
+       cx88_user_ctrls,
+       NULL
+};
+
+int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl)
+{
+       int i;
+
+       if (qctrl->id < V4L2_CID_BASE ||
+           qctrl->id >= V4L2_CID_LASTP1)
+               return -EINVAL;
+       for (i = 0; i < CX8800_CTLS; i++)
+               if (cx8800_ctls[i].v.id == qctrl->id)
+                       break;
+       if (i == CX8800_CTLS) {
+               *qctrl = no_ctl;
+               return 0;
+       }
+       *qctrl = cx8800_ctls[i].v;
+       return 0;
+}
+EXPORT_SYMBOL(cx8800_ctrl_query);
+
+static int cx88_queryctrl(struct v4l2_queryctrl *qctrl)
+{
+       qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+       if (qctrl->id == 0)
+               return -EINVAL;
+       return cx8800_ctrl_query(qctrl);
+}
+
 /* ------------------------------------------------------------------- */
 /* resource management                                                 */
 
@@ -336,17 +383,17 @@ static int res_get(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bi
                return 1;
 
        /* is it free? */
-       down(&core->lock);
+       mutex_lock(&core->lock);
        if (dev->resources & bit) {
                /* no, someone else uses it */
-               up(&core->lock);
+               mutex_unlock(&core->lock);
                return 0;
        }
        /* it's free, grab it */
        fh->resources  |= bit;
        dev->resources |= bit;
        dprintk(1,"res: get %d\n",bit);
-       up(&core->lock);
+       mutex_unlock(&core->lock);
        return 1;
 }
 
@@ -366,14 +413,13 @@ static
 void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits)
 {
        struct cx88_core *core = dev->core;
-       if ((fh->resources & bits) != bits)
-               BUG();
+       BUG_ON((fh->resources & bits) != bits);
 
-       down(&core->lock);
+       mutex_lock(&core->lock);
        fh->resources  &= ~bits;
        dev->resources &= ~bits;
        dprintk(1,"res: put %d\n",bits);
-       up(&core->lock);
+       mutex_unlock(&core->lock);
 }
 
 /* ------------------------------------------------------------------ */
@@ -408,6 +454,14 @@ static int video_mux(struct cx88_core *core, unsigned int input)
                cx_clear(MO_FILTER_ODD,   0x00002020);
                break;
        }
+
+       if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) {
+               /* sets sound input from external adc */
+               if (INPUT(input)->extadc)
+                       cx_set(AUD_CTL, EN_I2SIN_ENABLE);
+               else
+                       cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
+       }
        return 0;
 }
 
@@ -451,6 +505,7 @@ static int start_video_dma(struct cx8800_dev    *dev,
        return 0;
 }
 
+#ifdef CONFIG_PM
 static int stop_video_dma(struct cx8800_dev    *dev)
 {
        struct cx88_core *core = dev->core;
@@ -466,6 +521,7 @@ static int stop_video_dma(struct cx8800_dev    *dev)
        cx_clear(MO_VID_INTMSK, 0x0f0011);
        return 0;
 }
+#endif
 
 static int restart_video_queue(struct cx8800_dev    *dev,
                               struct cx88_dmaqueue *q)
@@ -493,8 +549,7 @@ static int restart_video_queue(struct cx8800_dev    *dev,
                        return 0;
                buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
                if (NULL == prev) {
-                       list_del(&buf->vb.queue);
-                       list_add_tail(&buf->vb.queue,&q->active);
+                       list_move_tail(&buf->vb.queue, &q->active);
                        start_video_dma(dev, q, buf);
                        buf->vb.state = STATE_ACTIVE;
                        buf->count    = q->count++;
@@ -505,8 +560,7 @@ static int restart_video_queue(struct cx8800_dev    *dev,
                } else if (prev->vb.width  == buf->vb.width  &&
                           prev->vb.height == buf->vb.height &&
                           prev->fmt       == buf->fmt) {
-                       list_del(&buf->vb.queue);
-                       list_add_tail(&buf->vb.queue,&q->active);
+                       list_move_tail(&buf->vb.queue, &q->active);
                        buf->vb.state = STATE_ACTIVE;
                        buf->count    = q->count++;
                        prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
@@ -565,7 +619,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
 
        if (STATE_NEEDS_INIT == buf->vb.state) {
                init_buffer = 1;
-               if (0 != (rc = videobuf_iolock(dev->pci,&buf->vb,NULL)))
+               if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
                        goto fail;
        }
 
@@ -615,7 +669,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
        return 0;
 
  fail:
-       cx88_free_buffer(dev->pci,buf);
+       cx88_free_buffer(q,buf);
        return rc;
 }
 
@@ -672,9 +726,8 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
        struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
-       struct cx8800_fh   *fh  = q->priv_data;
 
-       cx88_free_buffer(fh->dev->pci,buf);
+       cx88_free_buffer(q,buf);
 }
 
 static struct videobuf_queue_ops cx8800_video_qops = {
@@ -909,7 +962,8 @@ static int get_control(struct cx88_core *core, struct v4l2_control *ctl)
        value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg);
        switch (ctl->id) {
        case V4L2_CID_AUDIO_BALANCE:
-               ctl->value = (value & 0x40) ? (value & 0x3f) : (0x40 - (value & 0x3f));
+               ctl->value = ((value & 0x7f) < 0x40) ? ((value & 0x7f) + 0x40)
+                                       : (0x7f - (value & 0x7f));
                break;
        case V4L2_CID_AUDIO_VOLUME:
                ctl->value = 0x3f - (value & 0x3f);
@@ -918,9 +972,9 @@ static int get_control(struct cx88_core *core, struct v4l2_control *ctl)
                ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift;
                break;
        }
-       printk("get_control id=0x%X reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
-                                       ctl->id, c->reg, ctl->value,
-                                       c->mask, c->sreg ? " [shadowed]" : "");
+       dprintk(1,"get_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
+                               ctl->id, c->v.name, ctl->value, c->reg,
+                               value,c->mask, c->sreg ? " [shadowed]" : "");
        return 0;
 }
 
@@ -946,7 +1000,7 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
        mask=c->mask;
        switch (ctl->id) {
        case V4L2_CID_AUDIO_BALANCE:
-               value = (ctl->value < 0x40) ? (0x40 - ctl->value) : ctl->value;
+               value = (ctl->value < 0x40) ? (0x7f - ctl->value) : (ctl->value - 0x40);
                break;
        case V4L2_CID_AUDIO_VOLUME:
                value = 0x3f - (ctl->value & 0x3f);
@@ -969,9 +1023,9 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
                value = ((ctl->value - c->off) << c->shift) & c->mask;
                break;
        }
-       printk("set_control id=0x%X reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
-                                       ctl->id, c->reg, value,
-                                       mask, c->sreg ? " [shadowed]" : "");
+       dprintk(1,"set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
+                               ctl->id, c->v.name, ctl->value, c->reg, value,
+                               mask, c->sreg ? " [shadowed]" : "");
        if (c->sreg) {
                cx_sandor(c->sreg, c->reg, mask, value);
        } else {
@@ -987,8 +1041,7 @@ static void init_controls(struct cx88_core *core)
 
        for (i = 0; i < CX8800_CTLS; i++) {
                ctrl.id=cx8800_ctls[i].v.id;
-               ctrl.value=cx8800_ctls[i].v.default_value
-                               +cx8800_ctls[i].off;
+               ctrl.value=cx8800_ctls[i].v.default_value;
                set_control(core, &ctrl);
        }
 }
@@ -1137,7 +1190,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                        V4L2_CAP_READWRITE     |
                        V4L2_CAP_STREAMING     |
                        V4L2_CAP_VBI_CAPTURE   |
-                       V4L2_CAP_VIDEO_OVERLAY |
                        0;
                if (UNSET != core->tuner_type)
                        cap->capabilities |= V4L2_CAP_TUNER;
@@ -1183,7 +1235,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                struct v4l2_format *f = arg;
                return cx8800_try_fmt(dev,fh,f);
        }
-#ifdef HAVE_V4L1
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
        /* --- streaming capture ------------------------------------- */
        case VIDIOCGMBUF:
        {
@@ -1252,9 +1304,17 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
 {
        int err;
 
-       dprintk( 1, "CORE IOCTL: 0x%x\n", cmd );
-       if (video_debug > 1)
-               v4l_print_ioctl(core->name,cmd);
+       if (video_debug) {
+              if (video_debug > 1) {
+                      if (_IOC_DIR(cmd) & _IOC_WRITE)
+                              v4l_printk_ioctl_arg("cx88(w)",cmd, arg);
+                      else if (!_IOC_DIR(cmd) & _IOC_READ) {
+                              v4l_print_ioctl("cx88", cmd);
+                      }
+              } else
+                      v4l_print_ioctl(core->name,cmd);
+
+       }
 
        switch (cmd) {
        /* ---------- tv norms ---------- */
@@ -1291,9 +1351,9 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
                if (i == ARRAY_SIZE(tvnorms))
                        return -EINVAL;
 
-               down(&core->lock);
+               mutex_lock(&core->lock);
                cx88_set_tvnorm(core,&tvnorms[i]);
-               up(&core->lock);
+               mutex_unlock(&core->lock);
                return 0;
        }
 
@@ -1343,10 +1403,10 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
 
                if (*i >= 4)
                        return -EINVAL;
-               down(&core->lock);
+               mutex_lock(&core->lock);
                cx88_newstation(core);
                video_mux(core,*i);
-               up(&core->lock);
+               mutex_unlock(&core->lock);
                return 0;
        }
 
@@ -1356,20 +1416,8 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
        case VIDIOC_QUERYCTRL:
        {
                struct v4l2_queryctrl *c = arg;
-               int i;
 
-               if (c->id <  V4L2_CID_BASE ||
-                   c->id >= V4L2_CID_LASTP1)
-                       return -EINVAL;
-               for (i = 0; i < CX8800_CTLS; i++)
-                       if (cx8800_ctls[i].v.id == c->id)
-                               break;
-               if (i == CX8800_CTLS) {
-                       *c = no_ctl;
-                       return 0;
-               }
-               *c = cx8800_ctls[i].v;
-               return 0;
+               return cx88_queryctrl(c);
        }
        case VIDIOC_G_CTRL:
                return get_control(core,arg);
@@ -1438,7 +1486,7 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
                        return -EINVAL;
                if (1 == radio && f->type != V4L2_TUNER_RADIO)
                        return -EINVAL;
-               down(&core->lock);
+               mutex_lock(&core->lock);
                core->freq = f->frequency;
                cx88_newstation(core);
                cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f);
@@ -1447,9 +1495,33 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
                msleep (10);
                cx88_set_tvaudio(core);
 
-               up(&core->lock);
+               mutex_unlock(&core->lock);
+               return 0;
+       }
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       /* ioctls to allow direct acces to the cx2388x registers */
+       case VIDIOC_INT_G_REGISTER:
+       {
+               struct v4l2_register *reg = arg;
+
+               if (reg->i2c_id != 0)
+                       return -EINVAL;
+               /* cx2388x has a 24-bit register space */
+               reg->val = cx_read(reg->reg&0xffffff);
+               return 0;
+       }
+       case VIDIOC_INT_S_REGISTER:
+       {
+               struct v4l2_register *reg = arg;
+
+               if (reg->i2c_id != 0)
+                       return -EINVAL;
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               cx_write(reg->reg&0xffffff, reg->val);
                return 0;
        }
+#endif
 
        default:
                return v4l_compat_translate_ioctl(inode,file,cmd,arg,
@@ -1461,7 +1533,19 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
 static int video_ioctl(struct inode *inode, struct file *file,
                       unsigned int cmd, unsigned long arg)
 {
-       return video_usercopy(inode, file, cmd, arg, video_do_ioctl);
+       int retval;
+
+       retval=video_usercopy(inode, file, cmd, arg, video_do_ioctl);
+
+       if (video_debug > 1) {
+              if (retval < 0) {
+                      v4l_print_ioctl("cx88(err)", cmd);
+                      printk(KERN_DEBUG "cx88(err): errcode=%d\n",retval);
+              } else if (_IOC_DIR(cmd) & _IOC_READ)
+                      v4l_printk_ioctl_arg("cx88(r)",cmd, (void *)arg);
+       }
+
+       return retval;
 }
 
 /* ----------------------------------------------------------- */
@@ -1534,7 +1618,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
                *id = 0;
                return 0;
        }
-#ifdef HAVE_V4L1
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
        case VIDIOCSTUNER:
        {
                struct video_tuner *v = arg;
@@ -1692,7 +1776,7 @@ static void cx8800_vid_irq(struct cx8800_dev *dev)
        }
 }
 
-static irqreturn_t cx8800_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t cx8800_irq(int irq, void *dev_id)
 {
        struct cx8800_dev *dev = dev_id;
        struct cx88_core *core = dev->core;
@@ -1829,9 +1913,9 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
        pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
        printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
-              "latency: %d, mmio: 0x%lx\n", core->name,
+              "latency: %d, mmio: 0x%llx\n", core->name,
               pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
-              dev->pci_lat,pci_resource_start(pci_dev,0));
+              dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0));
 
        pci_set_master(pci_dev);
        if (!pci_dma_supported(pci_dev,0xffffffff)) {
@@ -1864,7 +1948,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
 
        /* get irq */
        err = request_irq(pci_dev->irq, cx8800_irq,
-                         SA_SHIRQ | SA_INTERRUPT, core->name, dev);
+                         IRQF_SHARED | IRQF_DISABLED, core->name, dev);
        if (err < 0) {
                printk(KERN_ERR "%s: can't get IRQ %d\n",
                       core->name,pci_dev->irq);
@@ -1875,8 +1959,9 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
        /* load and configure helper modules */
        if (TUNER_ABSENT != core->tuner_type)
                request_module("tuner");
-       if (core->tda9887_conf)
-               request_module("tda9887");
+
+       if (cx88_boards[ core->board ].audio_chip == AUDIO_CHIP_WM8775)
+               request_module("wm8775");
 
        /* register v4l devices */
        dev->video_dev = cx88_vdev_init(core,dev->pci,
@@ -1921,11 +2006,11 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
        pci_set_drvdata(pci_dev,dev);
 
        /* initial device configuration */
-       down(&core->lock);
+       mutex_lock(&core->lock);
        cx88_set_tvnorm(core,tvnorms);
        init_controls(core);
        video_mux(core,0);
-       up(&core->lock);
+       mutex_unlock(&core->lock);
 
        /* start tvaudio thread */
        if (core->tuner_type != TUNER_ABSENT)
@@ -1969,6 +2054,7 @@ static void __devexit cx8800_finidev(struct pci_dev *pci_dev)
        kfree(dev);
 }
 
+#ifdef CONFIG_PM
 static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
 {
        struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
@@ -2044,6 +2130,7 @@ static int cx8800_resume(struct pci_dev *pci_dev)
 
        return 0;
 }
+#endif
 
 /* ----------------------------------------------------------- */
 
@@ -2064,9 +2151,10 @@ static struct pci_driver cx8800_pci_driver = {
        .id_table = cx8800_pci_tbl,
        .probe    = cx8800_initdev,
        .remove   = __devexit_p(cx8800_finidev),
-
+#ifdef CONFIG_PM
        .suspend  = cx8800_suspend,
        .resume   = cx8800_resume,
+#endif
 };
 
 static int cx8800_init(void)