From 5b0fa4fff17d944b6a0d4cb35d8e8b5ad0ac3669 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 9 Jan 2006 18:21:37 -0200 Subject: [PATCH] V4L/DVB (3325): WSS output interface for av7110 - Implemented v4l2 api for sliced vbi data output to pass WSS data from userspace to the av7110 Signed-off-by: Oliver Endriss Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_fops.c | 37 ++++++++- drivers/media/dvb/ttpci/av7110.h | 3 + drivers/media/dvb/ttpci/av7110_hw.h | 3 +- drivers/media/dvb/ttpci/av7110_v4l.c | 116 +++++++++++++++++++++++++-- include/media/saa7146_vv.h | 2 + 5 files changed, 149 insertions(+), 12 deletions(-) diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index a9ff5b5af1cf..b614612be7b4 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -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; diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index 6cf395e01d34..6ea30df2e823 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -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); diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h index 2a5e87ba1052..84b83299b8be 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.h +++ b/drivers/media/dvb/ttpci/av7110_hw.h @@ -167,7 +167,8 @@ enum av7110_encoder_command { LoadVidCode, SetMonitorType, SetPanScanType, - SetFreezeMode + SetFreezeMode, + SetWSSConfig }; enum av7110_rec_play_state { diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index e3296b07caac..94cf38c7e8a8 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -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, }; diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h index 16af9299315f..e5e749e984ee 100644 --- a/include/media/saa7146_vv.h +++ b/include/media/saa7146_vv.h @@ -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 { -- 2.20.1