Commit 5b0fa4ff authored by Oliver Endriss's avatar Oliver Endriss Committed by Mauro Carvalho Chehab

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: default avatarOliver Endriss <o.endriss@gmx.de>
Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@brturbo.com.br>
parent d312a46e
...@@ -253,7 +253,10 @@ static int fops_open(struct inode *inode, struct file *file) ...@@ -253,7 +253,10 @@ static int fops_open(struct inode *inode, struct file *file)
if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
DEB_S(("initializing vbi...\n")); DEB_S(("initializing vbi...\n"));
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
result = saa7146_vbi_uops.open(dev,file); 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 { } else {
DEB_S(("initializing video...\n")); DEB_S(("initializing video...\n"));
result = saa7146_video_uops.open(dev,file); result = saa7146_video_uops.open(dev,file);
...@@ -289,7 +292,10 @@ static int fops_release(struct inode *inode, struct file *file) ...@@ -289,7 +292,10 @@ static int fops_release(struct inode *inode, struct file *file)
return -ERESTARTSYS; return -ERESTARTSYS;
if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
saa7146_vbi_uops.release(dev,file); saa7146_vbi_uops.release(dev,file);
if (dev->ext_vv_data->vbi_fops.release)
dev->ext_vv_data->vbi_fops.release(inode, file);
} else { } else {
saa7146_video_uops.release(dev,file); 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 ...@@ -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: { 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)); // DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", file, data, (unsigned long)count));
if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
return saa7146_vbi_uops.read(file,data,count,ppos); return saa7146_vbi_uops.read(file,data,count,ppos);
else
return -EINVAL;
} }
break; break;
default: default:
...@@ -391,12 +400,31 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof ...@@ -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 = static struct file_operations video_fops =
{ {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = fops_open, .open = fops_open,
.release = fops_release, .release = fops_release,
.read = fops_read, .read = fops_read,
.write = fops_write,
.poll = fops_poll, .poll = fops_poll,
.mmap = fops_mmap, .mmap = fops_mmap,
.ioctl = fops_ioctl, .ioctl = fops_ioctl,
...@@ -468,6 +496,7 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) ...@@ -468,6 +496,7 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM); memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM);
saa7146_video_uops.init(dev,vv); saa7146_video_uops.init(dev,vv);
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
saa7146_vbi_uops.init(dev,vv); saa7146_vbi_uops.init(dev,vv);
dev->vv_data = vv; dev->vv_data = vv;
......
...@@ -229,6 +229,9 @@ struct av7110 { ...@@ -229,6 +229,9 @@ struct av7110 {
struct dvb_video_events video_events; struct dvb_video_events video_events;
video_size_t video_size; video_size_t video_size;
u16 wssMode;
u16 wssData;
u32 ir_config; u32 ir_config;
u32 ir_command; u32 ir_command;
void (*ir_handler)(struct av7110 *av7110, u32 ircom); void (*ir_handler)(struct av7110 *av7110, u32 ircom);
......
...@@ -167,7 +167,8 @@ enum av7110_encoder_command { ...@@ -167,7 +167,8 @@ enum av7110_encoder_command {
LoadVidCode, LoadVidCode,
SetMonitorType, SetMonitorType,
SetPanScanType, SetPanScanType,
SetFreezeMode SetFreezeMode,
SetWSSConfig
}; };
enum av7110_rec_play_state { enum av7110_rec_play_state {
......
...@@ -490,6 +490,58 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) ...@@ -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); dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
break; 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: default:
printk("no such ioctl\n"); printk("no such ioctl\n");
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
...@@ -497,6 +549,46 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) ...@@ -497,6 +549,46 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
return 0; 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 * INITIALIZATION
...@@ -512,6 +604,9 @@ static struct saa7146_extension_ioctls ioctls[] = { ...@@ -512,6 +604,9 @@ static struct saa7146_extension_ioctls ioctls[] = {
{ VIDIOC_S_TUNER, SAA7146_EXCLUSIVE }, { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE },
{ VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE }, { VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE },
{ VIDIOC_S_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 } { 0, 0 }
}; };
...@@ -692,13 +787,12 @@ int av7110_init_v4l(struct av7110 *av7110) ...@@ -692,13 +787,12 @@ int av7110_init_v4l(struct av7110 *av7110)
saa7146_vv_release(dev); saa7146_vv_release(dev);
return -ENODEV; return -ENODEV;
} }
if (av7110->analog_tuner_flags) {
if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) { if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
ERR(("cannot register vbi v4l2 device. skipping.\n")); ERR(("cannot register vbi v4l2 device. skipping.\n"));
} else { } else {
if (av7110->analog_tuner_flags)
av7110->analog_tuner_flags |= ANALOG_TUNER_VBI; av7110->analog_tuner_flags |= ANALOG_TUNER_VBI;
} }
}
return 0; return 0;
} }
...@@ -778,7 +872,7 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) ...@@ -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 = { static struct saa7146_ext_vv av7110_vv_data_st = {
.inputs = 1, .inputs = 1,
.audios = 1, .audios = 1,
.capabilities = 0, .capabilities = V4L2_CAP_SLICED_VBI_OUTPUT,
.flags = 0, .flags = 0,
.stds = &standard[0], .stds = &standard[0],
...@@ -787,12 +881,16 @@ static struct saa7146_ext_vv av7110_vv_data_st = { ...@@ -787,12 +881,16 @@ static struct saa7146_ext_vv av7110_vv_data_st = {
.ioctls = &ioctls[0], .ioctls = &ioctls[0],
.ioctl = av7110_ioctl, .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 = { static struct saa7146_ext_vv av7110_vv_data_c = {
.inputs = 1, .inputs = 1,
.audios = 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, .flags = SAA7146_USE_PORT_B_FOR_VBI,
.stds = &standard[0], .stds = &standard[0],
...@@ -801,5 +899,9 @@ static struct saa7146_ext_vv av7110_vv_data_c = { ...@@ -801,5 +899,9 @@ static struct saa7146_ext_vv av7110_vv_data_c = {
.ioctls = &ioctls[0], .ioctls = &ioctls[0],
.ioctl = av7110_ioctl, .ioctl = av7110_ioctl,
.vbi_fops.open = av7110_vbi_reset,
.vbi_fops.release = av7110_vbi_reset,
.vbi_fops.write = av7110_vbi_write,
}; };
...@@ -178,6 +178,8 @@ struct saa7146_ext_vv ...@@ -178,6 +178,8 @@ struct saa7146_ext_vv
struct saa7146_extension_ioctls *ioctls; struct saa7146_extension_ioctls *ioctls;
int (*ioctl)(struct saa7146_fh*, unsigned int cmd, void *arg); int (*ioctl)(struct saa7146_fh*, unsigned int cmd, void *arg);
struct file_operations vbi_fops;
}; };
struct saa7146_use_ops { struct saa7146_use_ops {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment