V4L/DVB (3325): WSS output interface for av7110
authorOliver Endriss <o.endriss@gmx.de>
Mon, 9 Jan 2006 20:21:37 +0000 (18:21 -0200)
committerMauro Carvalho Chehab <mchehab@brturbo.com.br>
Mon, 9 Jan 2006 20:21:37 +0000 (18:21 -0200)
- Implemented v4l2 api for sliced vbi data output
to pass WSS data from userspace to the av7110

Signed-off-by: Oliver Endriss <o.endriss@gmx.de>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
drivers/media/common/saa7146_fops.c
drivers/media/dvb/ttpci/av7110.h
drivers/media/dvb/ttpci/av7110_hw.h
drivers/media/dvb/ttpci/av7110_v4l.c
include/media/saa7146_vv.h

index a9ff5b5af1cff31fe3a5f67d2253a125059d0055..b614612be7b439252c97451ced9e9de34a93609e 100644 (file)
@@ -253,7 +253,10 @@ static int fops_open(struct inode *inode, struct file *file)
 
        if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
                DEB_S(("initializing vbi...\n"));
-               result = saa7146_vbi_uops.open(dev,file);
+               if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+                       result = saa7146_vbi_uops.open(dev,file);
+               if (dev->ext_vv_data->vbi_fops.open)
+                       dev->ext_vv_data->vbi_fops.open(inode, file);
        } else {
                DEB_S(("initializing video...\n"));
                result = saa7146_video_uops.open(dev,file);
@@ -289,7 +292,10 @@ static int fops_release(struct inode *inode, struct file *file)
                return -ERESTARTSYS;
 
        if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-               saa7146_vbi_uops.release(dev,file);
+               if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+                       saa7146_vbi_uops.release(dev,file);
+               if (dev->ext_vv_data->vbi_fops.release)
+                       dev->ext_vv_data->vbi_fops.release(inode, file);
        } else {
                saa7146_video_uops.release(dev,file);
        }
@@ -382,7 +388,10 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
                }
        case V4L2_BUF_TYPE_VBI_CAPTURE: {
 //             DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", file, data, (unsigned long)count));
-               return saa7146_vbi_uops.read(file,data,count,ppos);
+               if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+                       return saa7146_vbi_uops.read(file,data,count,ppos);
+               else
+                       return -EINVAL;
                }
                break;
        default:
@@ -391,12 +400,31 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
        }
 }
 
+static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
+{
+       struct saa7146_fh *fh = file->private_data;
+
+       switch (fh->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               return -EINVAL;
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               if (fh->dev->ext_vv_data->vbi_fops.write)
+                       return fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
+               else
+                       return -EINVAL;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+}
+
 static struct file_operations video_fops =
 {
        .owner          = THIS_MODULE,
        .open           = fops_open,
        .release        = fops_release,
        .read           = fops_read,
+       .write          = fops_write,
        .poll           = fops_poll,
        .mmap           = fops_mmap,
        .ioctl          = fops_ioctl,
@@ -468,7 +496,8 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
        memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM);
 
        saa7146_video_uops.init(dev,vv);
-       saa7146_vbi_uops.init(dev,vv);
+       if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+               saa7146_vbi_uops.init(dev,vv);
 
        dev->vv_data = vv;
        dev->vv_callback = &vv_callback;
index 6cf395e01d34adf33252120592543c0f2d2629cc..6ea30df2e823c3dc54cf10699df7d2af4609ac3b 100644 (file)
@@ -229,6 +229,9 @@ struct av7110 {
        struct dvb_video_events  video_events;
        video_size_t             video_size;
 
+       u16                     wssMode;
+       u16                     wssData;
+
        u32                     ir_config;
        u32                     ir_command;
        void                    (*ir_handler)(struct av7110 *av7110, u32 ircom);
index 2a5e87ba10521129f04738ea5d9d178598581acd..84b83299b8bec7642c931ebf65177393860517e8 100644 (file)
@@ -167,7 +167,8 @@ enum av7110_encoder_command {
        LoadVidCode,
        SetMonitorType,
        SetPanScanType,
-       SetFreezeMode
+       SetFreezeMode,
+       SetWSSConfig
 };
 
 enum av7110_rec_play_state {
index e3296b07caacf73ae5614666ba680c65d92b9b2c..94cf38c7e8a809f8f5cf5ce2bba99c9f160aea0d 100644 (file)
@@ -490,6 +490,58 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
                break;
        }
+       case VIDIOC_G_SLICED_VBI_CAP:
+       {
+               struct v4l2_sliced_vbi_cap *cap = arg;
+               dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
+               memset(cap, 0, sizeof *cap);
+               if (FW_VERSION(av7110->arm_app) >= 0x2623) {
+                       cap->service_set = V4L2_SLICED_WSS_625;
+                       cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
+               }
+               break;
+       }
+       case VIDIOC_G_FMT:
+       {
+               struct v4l2_format *f = arg;
+               dprintk(2, "VIDIOC_G_FMT:\n");
+               if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
+                   FW_VERSION(av7110->arm_app) < 0x2623)
+                       return -EAGAIN; /* handled by core driver */
+               memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+               if (av7110->wssMode) {
+                       f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
+                       f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+                       f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
+               }
+               break;
+       }
+       case VIDIOC_S_FMT:
+       {
+               struct v4l2_format *f = arg;
+               dprintk(2, "VIDIOC_S_FMT\n");
+               if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
+                   FW_VERSION(av7110->arm_app) < 0x2623)
+                       return -EAGAIN; /* handled by core driver */
+               if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
+                   f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
+                       memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+                       /* WSS controlled by firmware */
+                       av7110->wssMode = 0;
+                       av7110->wssData = 0;
+                       return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
+                                            SetWSSConfig, 1, 0);
+               } else {
+                       memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+                       f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
+                       f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+                       f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
+                       /* WSS controlled by userspace */
+                       av7110->wssMode = 1;
+                       av7110->wssData = 0;
+               }
+               break;
+       }
        default:
                printk("no such ioctl\n");
                return -ENOIOCTLCMD;
@@ -497,6 +549,46 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
        return 0;
 }
 
+static int av7110_vbi_reset(struct inode *inode, struct file *file)
+{
+       struct saa7146_fh *fh = file->private_data;
+       struct saa7146_dev *dev = fh->dev;
+       struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
+
+       dprintk(2, "%s\n", __FUNCTION__);
+       av7110->wssMode = 0;
+       av7110->wssData = 0;
+       if (FW_VERSION(av7110->arm_app) < 0x2623)
+               return 0;
+       else
+               return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
+}
+
+static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
+{
+       struct saa7146_fh *fh = file->private_data;
+       struct saa7146_dev *dev = fh->dev;
+       struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
+       struct v4l2_sliced_vbi_data d;
+       int rc;
+
+       dprintk(2, "%s\n", __FUNCTION__);
+       if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d)
+               return -EINVAL;
+       if (copy_from_user(&d, data, count))
+               return -EFAULT;
+       if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23)
+               return -EINVAL;
+       if (d.id) {
+               av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0];
+               rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig,
+                                  2, 1, av7110->wssData);
+       } else {
+               av7110->wssData = 0;
+               rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
+       }
+       return (rc < 0) ? rc : count;
+}
 
 /****************************************************************************
  * INITIALIZATION
@@ -512,6 +604,9 @@ static struct saa7146_extension_ioctls ioctls[] = {
        { VIDIOC_S_TUNER,       SAA7146_EXCLUSIVE },
        { VIDIOC_G_AUDIO,       SAA7146_EXCLUSIVE },
        { VIDIOC_S_AUDIO,       SAA7146_EXCLUSIVE },
+       { VIDIOC_G_SLICED_VBI_CAP, SAA7146_EXCLUSIVE },
+       { VIDIOC_G_FMT,         SAA7146_BEFORE },
+       { VIDIOC_S_FMT,         SAA7146_BEFORE },
        { 0, 0 }
 };
 
@@ -692,12 +787,11 @@ int av7110_init_v4l(struct av7110 *av7110)
                saa7146_vv_release(dev);
                return -ENODEV;
        }
-       if (av7110->analog_tuner_flags) {
-               if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
-                       ERR(("cannot register vbi v4l2 device. skipping.\n"));
-               } else {
+       if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
+               ERR(("cannot register vbi v4l2 device. skipping.\n"));
+       } else {
+               if (av7110->analog_tuner_flags)
                        av7110->analog_tuner_flags |= ANALOG_TUNER_VBI;
-               }
        }
        return 0;
 }
@@ -778,7 +872,7 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
 static struct saa7146_ext_vv av7110_vv_data_st = {
        .inputs         = 1,
        .audios         = 1,
-       .capabilities   = 0,
+       .capabilities   = V4L2_CAP_SLICED_VBI_OUTPUT,
        .flags          = 0,
 
        .stds           = &standard[0],
@@ -787,12 +881,16 @@ static struct saa7146_ext_vv av7110_vv_data_st = {
 
        .ioctls         = &ioctls[0],
        .ioctl          = av7110_ioctl,
+
+       .vbi_fops.open  = av7110_vbi_reset,
+       .vbi_fops.release = av7110_vbi_reset,
+       .vbi_fops.write = av7110_vbi_write,
 };
 
 static struct saa7146_ext_vv av7110_vv_data_c = {
        .inputs         = 1,
        .audios         = 1,
-       .capabilities   = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
+       .capabilities   = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT,
        .flags          = SAA7146_USE_PORT_B_FOR_VBI,
 
        .stds           = &standard[0],
@@ -801,5 +899,9 @@ static struct saa7146_ext_vv av7110_vv_data_c = {
 
        .ioctls         = &ioctls[0],
        .ioctl          = av7110_ioctl,
+
+       .vbi_fops.open  = av7110_vbi_reset,
+       .vbi_fops.release = av7110_vbi_reset,
+       .vbi_fops.write = av7110_vbi_write,
 };
 
index 16af9299315f3da06ba07a722fb9bdaa7627e520..e5e749e984ee7baf4864ac0ceea926130ec72c75 100644 (file)
@@ -178,6 +178,8 @@ struct saa7146_ext_vv
 
        struct saa7146_extension_ioctls *ioctls;
        int (*ioctl)(struct saa7146_fh*, unsigned int cmd, void *arg);
+
+       struct file_operations vbi_fops;
 };
 
 struct saa7146_use_ops  {