Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+33 −4
Original line number Diff line number Diff line
@@ -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"));
		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) {
		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));
		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,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);

	saa7146_video_uops.init(dev,vv);
	if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
		saa7146_vbi_uops.init(dev,vv);

	dev->vv_data = vv;
+3 −0
Original line number Diff line number Diff line
@@ -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);
+2 −1
Original line number Diff line number Diff line
@@ -167,7 +167,8 @@ enum av7110_encoder_command {
	LoadVidCode,
	SetMonitorType,
	SetPanScanType,
	SetFreezeMode
	SetFreezeMode,
	SetWSSConfig
};

enum av7110_rec_play_state {
+109 −7
Original line number Diff line number Diff line
@@ -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,13 +787,12 @@ 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 (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,
};
+2 −0
Original line number Diff line number Diff line
@@ -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  {