media: rcar-vin: use different v4l2 operations in media controller mode

When the driver runs in media controller mode it should not directly
control the subdevice instead userspace will be responsible for
configuring the pipeline. To be able to run in this mode a different set
of v4l2 operations needs to be used.

Add a new set of v4l2 operations to support operation without directly
interacting with the source subdevice.

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
This commit is contained in:
Niklas Söderlund
2018-04-14 07:57:15 -04:00
committed by Mauro Carvalho Chehab
szülő 47ba5bbfd9
commit 5e7c623632
2 fájl változott, egészen pontosan 156 új sor hozzáadva és 4 régi sor törölve

Fájl megtekintése

@@ -18,12 +18,16 @@
#include <media/v4l2-event.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-mc.h>
#include <media/v4l2-rect.h>
#include "rcar-vin.h"
#define RVIN_DEFAULT_FORMAT V4L2_PIX_FMT_YUYV
#define RVIN_DEFAULT_WIDTH 800
#define RVIN_DEFAULT_HEIGHT 600
#define RVIN_DEFAULT_FIELD V4L2_FIELD_NONE
#define RVIN_DEFAULT_COLORSPACE V4L2_COLORSPACE_SRGB
/* -----------------------------------------------------------------------------
* Format Conversions
@@ -654,6 +658,73 @@ static const struct v4l2_ioctl_ops rvin_ioctl_ops = {
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
/* -----------------------------------------------------------------------------
* V4L2 Media Controller
*/
static int rvin_mc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct rvin_dev *vin = video_drvdata(file);
rvin_format_align(vin, &f->fmt.pix);
return 0;
}
static int rvin_mc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct rvin_dev *vin = video_drvdata(file);
if (vb2_is_busy(&vin->queue))
return -EBUSY;
rvin_format_align(vin, &f->fmt.pix);
vin->format = f->fmt.pix;
return 0;
}
static int rvin_mc_enum_input(struct file *file, void *priv,
struct v4l2_input *i)
{
if (i->index != 0)
return -EINVAL;
i->type = V4L2_INPUT_TYPE_CAMERA;
strlcpy(i->name, "Camera", sizeof(i->name));
return 0;
}
static const struct v4l2_ioctl_ops rvin_mc_ioctl_ops = {
.vidioc_querycap = rvin_querycap,
.vidioc_try_fmt_vid_cap = rvin_mc_try_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = rvin_g_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = rvin_mc_s_fmt_vid_cap,
.vidioc_enum_fmt_vid_cap = rvin_enum_fmt_vid_cap,
.vidioc_enum_input = rvin_mc_enum_input,
.vidioc_g_input = rvin_g_input,
.vidioc_s_input = rvin_s_input,
.vidioc_reqbufs = vb2_ioctl_reqbufs,
.vidioc_create_bufs = vb2_ioctl_create_bufs,
.vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_qbuf = vb2_ioctl_qbuf,
.vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_expbuf = vb2_ioctl_expbuf,
.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_log_status = v4l2_ctrl_log_status,
.vidioc_subscribe_event = rvin_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
/* -----------------------------------------------------------------------------
* File Operations
*/
@@ -797,6 +868,74 @@ static const struct v4l2_file_operations rvin_fops = {
.read = vb2_fop_read,
};
/* -----------------------------------------------------------------------------
* Media controller file operations
*/
static int rvin_mc_open(struct file *file)
{
struct rvin_dev *vin = video_drvdata(file);
int ret;
ret = mutex_lock_interruptible(&vin->lock);
if (ret)
return ret;
ret = pm_runtime_get_sync(vin->dev);
if (ret < 0)
goto err_unlock;
ret = v4l2_pipeline_pm_use(&vin->vdev.entity, 1);
if (ret < 0)
goto err_pm;
file->private_data = vin;
ret = v4l2_fh_open(file);
if (ret)
goto err_v4l2pm;
mutex_unlock(&vin->lock);
return 0;
err_v4l2pm:
v4l2_pipeline_pm_use(&vin->vdev.entity, 0);
err_pm:
pm_runtime_put(vin->dev);
err_unlock:
mutex_unlock(&vin->lock);
return ret;
}
static int rvin_mc_release(struct file *file)
{
struct rvin_dev *vin = video_drvdata(file);
int ret;
mutex_lock(&vin->lock);
/* the release helper will cleanup any on-going streaming. */
ret = _vb2_fop_release(file, NULL);
v4l2_pipeline_pm_use(&vin->vdev.entity, 0);
pm_runtime_put(vin->dev);
mutex_unlock(&vin->lock);
return ret;
}
static const struct v4l2_file_operations rvin_mc_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = video_ioctl2,
.open = rvin_mc_open,
.release = rvin_mc_release,
.poll = vb2_fop_poll,
.mmap = vb2_fop_mmap,
.read = vb2_fop_read,
};
void rvin_v4l2_unregister(struct rvin_dev *vin)
{
if (!video_is_registered(&vin->vdev))
@@ -832,18 +971,31 @@ int rvin_v4l2_register(struct rvin_dev *vin)
vin->v4l2_dev.notify = rvin_notify;
/* video node */
vdev->fops = &rvin_fops;
vdev->v4l2_dev = &vin->v4l2_dev;
vdev->queue = &vin->queue;
strlcpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name));
vdev->release = video_device_release_empty;
vdev->ioctl_ops = &rvin_ioctl_ops;
vdev->lock = &vin->lock;
vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
V4L2_CAP_READWRITE;
/* Set a default format */
vin->format.pixelformat = RVIN_DEFAULT_FORMAT;
rvin_reset_format(vin);
vin->format.width = RVIN_DEFAULT_WIDTH;
vin->format.height = RVIN_DEFAULT_HEIGHT;
vin->format.field = RVIN_DEFAULT_FIELD;
vin->format.colorspace = RVIN_DEFAULT_COLORSPACE;
if (vin->info->use_mc) {
vdev->fops = &rvin_mc_fops;
vdev->ioctl_ops = &rvin_mc_ioctl_ops;
} else {
vdev->fops = &rvin_fops;
vdev->ioctl_ops = &rvin_ioctl_ops;
rvin_reset_format(vin);
}
rvin_format_align(vin, &vin->format);
ret = video_register_device(&vin->vdev, VFL_TYPE_GRABBER, -1);
if (ret) {