summaryrefslogtreecommitdiffstats
path: root/meta-egvirt/recipes-kernel/kernel-module-virtio-video/files/virtio_video_cam.c
blob: d657ba8a5a320104f8f4cac2710136ec51f6be34 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
}
SUMMARY = "The packages of middlewares for AGL IVI profile"
DESCRIPTION = "The set of packages required by Operating System and Common libraries Subsystem"
LICENSE = "MIT"

inherit packagegroup

PACKAGES = "\
    packagegroup-agl-core-os-commonlibs \
    "

ALLOW_EMPTY_${PN} = "1"

RDEPENDS_${PN} += "\
    "
a id='n351' href='#n351'>351 352 353 354 355 356 357 358 359
// SPDX-License-Identifier: GPL-2.0+
/* Capture for virtio video device.
 *
 * Copyright 2021 OpenSynergy GmbH.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/version.h>
#include <media/v4l2-event.h>
#include <media/v4l2-ioctl.h>

#include "virtio_video.h"

static int virtio_video_cam_start_streaming(struct vb2_queue *vq,
					    unsigned int count)
{
	struct virtio_video_stream *stream = vb2_get_drv_priv(vq);

	if (virtio_video_state(stream) == STREAM_STATE_ERROR)
		return -EIO;

	if (virtio_video_state(stream) >= STREAM_STATE_INIT)
		virtio_video_state_update(stream, STREAM_STATE_RUNNING);

	return 0;
}

static void virtio_video_cam_stop_streaming(struct vb2_queue *vq)
{
	struct virtio_video_stream *stream = vb2_get_drv_priv(vq);

	virtio_video_queue_release_buffers(stream,
					   VIRTIO_VIDEO_QUEUE_TYPE_OUTPUT);

	vb2_wait_for_all_buffers(vq);
}

static const struct vb2_ops virtio_video_cam_qops = {
	.queue_setup	 = virtio_video_queue_setup,
	.buf_init	 = virtio_video_buf_init,
	.buf_cleanup	 = virtio_video_buf_cleanup,
	.buf_queue	 = virtio_video_buf_queue,
	.start_streaming = virtio_video_cam_start_streaming,
	.stop_streaming  = virtio_video_cam_stop_streaming,
	.wait_prepare	 = vb2_ops_wait_prepare,
	.wait_finish	 = vb2_ops_wait_finish,
};

static int virtio_video_cam_g_ctrl(struct v4l2_ctrl *ctrl)
{
	int ret = 0;
	struct virtio_video_stream *stream = ctrl2stream(ctrl);

	if (virtio_video_state(stream) == STREAM_STATE_ERROR)
		return -EIO;

	switch (ctrl->id) {
	case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
		if (virtio_video_state(stream) >=
		    STREAM_STATE_DYNAMIC_RES_CHANGE)
			ctrl->val = stream->out_info.min_buffers;
		else
			ctrl->val = 0;
		break;
	default:
		ret = -EINVAL;
		break;
	}

	return ret;
}

static const struct v4l2_ctrl_ops virtio_video_cam_ctrl_ops = {
	.g_volatile_ctrl = virtio_video_cam_g_ctrl,
};

int virtio_video_cam_init_ctrls(struct virtio_video_stream *stream)
{
	struct v4l2_ctrl *ctrl;

	v4l2_ctrl_handler_init(&stream->ctrl_handler, 2);

	ctrl = v4l2_ctrl_new_std(&stream->ctrl_handler,
				 &virtio_video_cam_ctrl_ops,
				 V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
				 MIN_BUFS_MIN, MIN_BUFS_MAX, MIN_BUFS_STEP,
				 MIN_BUFS_DEF);

	if (ctrl)
		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;

	if (stream->ctrl_handler.error)
		return stream->ctrl_handler.error;

	v4l2_ctrl_handler_setup(&stream->ctrl_handler);

	return 0;
}

int virtio_video_cam_init_queues(void *priv, struct vb2_queue *src_vq,
				 struct vb2_queue *dst_vq)
{
	struct virtio_video_stream *stream = priv;
	struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev);
	struct device *dev = vvd->v4l2_dev.dev;
	int vq_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;

	if (!vvd->is_mplane_cam)
		vq_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

	dst_vq->type = vq_type;
	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
	dst_vq->drv_priv = stream;
	dst_vq->buf_struct_size = sizeof(struct virtio_video_buffer);
	dst_vq->ops = &virtio_video_cam_qops;
	dst_vq->mem_ops = virtio_video_mem_ops(vvd);
	dst_vq->min_buffers_needed = stream->out_info.min_buffers;
	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
	dst_vq->lock = &stream->vq_mutex;
	dst_vq->gfp_flags = virtio_video_gfp_flags(vvd);
	dst_vq->dev = dev;

	return vb2_queue_init(dst_vq);
}

int virtio_video_cam_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
{
	struct virtio_video_stream *stream = file2stream(file);
	struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev);
	struct v4l2_format *fmt_try = f;
	struct v4l2_format fmt_mp = { 0 };
	int ret;

	if (!vvd->is_mplane_cam) {
		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
			return -EINVAL;

		fmt_mp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
		fmt_try = &fmt_mp;

		virtio_video_pix_fmt_sp2mp(&f->fmt.pix, &fmt_try->fmt.pix_mp);
	}

	ret = virtio_video_try_fmt(stream, fmt_try);
	if (ret)
		return ret;

	if (!vvd->is_mplane_cam) {
		if (fmt_try->fmt.pix_mp.num_planes != 1)
			return -EINVAL;

		virtio_video_pix_fmt_mp2sp(&fmt_try->fmt.pix_mp, &f->fmt.pix);
	}

	return 0;
}

static int virtio_video_cam_enum_fmt_vid_cap(struct file *file, void *fh,
					     struct v4l2_fmtdesc *f)
{
	struct virtio_video_stream *stream = file2stream(file);
	struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev);
	struct video_format *fmt;
	int idx = 0;

	if (virtio_video_state(stream) == STREAM_STATE_ERROR)
		return -EIO;

	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
	    f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
		return -EINVAL;

	if (f->index >= vvd->num_output_fmts)
		return -EINVAL;

	list_for_each_entry(fmt, &vvd->output_fmt_list, formats_list_entry) {
		if (f->index == idx) {
			f->pixelformat = fmt->desc.format;
			return 0;
		}
		idx++;
	}
	return -EINVAL;
}

static int virtio_video_cam_g_fmt(struct file *file, void *fh,
				  struct v4l2_format *f)
{
	struct virtio_video_stream *stream = file2stream(file);
	struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev);
	struct v4l2_format fmt_mp = { 0 };
	struct v4l2_format *fmt_get = f;
	int ret;

	if (!vvd->is_mplane_cam) {
		fmt_mp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
		fmt_get = &fmt_mp;
	}

	ret = virtio_video_g_fmt(file, fh, fmt_get);
	if (ret)
		return ret;

	if (virtio_video_state(stream) == STREAM_STATE_IDLE)
		virtio_video_state_update(stream, STREAM_STATE_INIT);

	if (!vvd->is_mplane_cam) {
		if (fmt_get->fmt.pix_mp.num_planes != 1)
			return -EINVAL;

		virtio_video_pix_fmt_mp2sp(&fmt_get->fmt.pix_mp, &f->fmt.pix);
	}

	return 0;
}

static int virtio_video_cam_s_fmt(struct file *file, void *fh,
				  struct v4l2_format *f)
{
	int ret;
	struct virtio_video_stream *stream = file2stream(file);
	struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev);
	struct v4l2_format fmt_mp = { 0 };
	struct v4l2_format *fmt_set = f;

	if (!vvd->is_mplane_cam) {
		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
			return -EINVAL;

		fmt_mp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
		fmt_set = &fmt_mp;

		virtio_video_pix_fmt_sp2mp(&f->fmt.pix, &fmt_set->fmt.pix_mp);
	}

	ret = virtio_video_s_fmt(file, fh, fmt_set);
	if (ret)
		return ret;

	if (virtio_video_state(stream) == STREAM_STATE_IDLE)
		virtio_video_state_update(stream, STREAM_STATE_INIT);

	if (!vvd->is_mplane_cam) {
		if (fmt_set->fmt.pix_mp.num_planes != 1)
			return -EINVAL;

		virtio_video_pix_fmt_mp2sp(&fmt_set->fmt.pix_mp, &f->fmt.pix);
	}

	return 0;
}

static int virtio_video_cam_s_selection(struct file *file, void *fh,
					struct v4l2_selection *sel)
{
	struct virtio_video_stream *stream = file2stream(file);
	struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev);
	int ret;

	if (V4L2_TYPE_IS_OUTPUT(sel->type))
		return -EINVAL;

	switch (sel->target) {
	case V4L2_SEL_TGT_CROP:
		stream->out_info.crop.top = sel->r.top;
		stream->out_info.crop.left = sel->r.left;
		stream->out_info.crop.width = sel->r.width;
		stream->out_info.crop.height = sel->r.height;
		v4l2_info(&vvd->v4l2_dev,
			  "Set : top:%d, left:%d, w:%d, h:%d\n",
			  sel->r.top, sel->r.left, sel->r.width, sel->r.height);
		break;
	default:
		return -EINVAL;
	}

	ret = virtio_video_cmd_set_params(vvd, stream,  &stream->out_info,
					  VIRTIO_VIDEO_QUEUE_TYPE_OUTPUT);
	if (ret)
		return -EINVAL;

	ret = virtio_video_cmd_get_params(vvd, stream,
					  VIRTIO_VIDEO_QUEUE_TYPE_OUTPUT);
	return ret;
}

static const struct v4l2_ioctl_ops virtio_video_cam_ioctl_ops = {
	.vidioc_querycap		= virtio_video_querycap,

#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0))
	.vidioc_enum_fmt_vid_cap_mplane = virtio_video_cam_enum_fmt_vid_cap,
#endif
	.vidioc_try_fmt_vid_cap_mplane  = virtio_video_cam_try_fmt,
	.vidioc_g_fmt_vid_cap_mplane	= virtio_video_cam_g_fmt,
	.vidioc_s_fmt_vid_cap_mplane	= virtio_video_cam_s_fmt,

	.vidioc_enum_fmt_vid_cap	= virtio_video_cam_enum_fmt_vid_cap,
	.vidioc_try_fmt_vid_cap		= virtio_video_cam_try_fmt,
	.vidioc_g_fmt_vid_cap		= virtio_video_cam_g_fmt,
	.vidioc_s_fmt_vid_cap		= virtio_video_cam_s_fmt,

	.vidioc_g_selection		= virtio_video_g_selection,
	.vidioc_s_selection		= virtio_video_cam_s_selection,

	.vidioc_enum_frameintervals	= virtio_video_enum_framemintervals,
	.vidioc_enum_framesizes		= virtio_video_enum_framesizes,

	.vidioc_reqbufs		= virtio_video_reqbufs,
	.vidioc_querybuf	= vb2_ioctl_querybuf,
	.vidioc_qbuf		= virtio_video_qbuf,
	.vidioc_dqbuf		= virtio_video_dqbuf,
	.vidioc_prepare_buf	= vb2_ioctl_prepare_buf,
	.vidioc_create_bufs	= vb2_ioctl_create_bufs,
	.vidioc_expbuf		= vb2_ioctl_expbuf,

	.vidioc_streamon	= vb2_ioctl_streamon,
	.vidioc_streamoff	= vb2_ioctl_streamoff,

	.vidioc_subscribe_event   = virtio_video_subscribe_event,
	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};

void *virtio_video_cam_get_fmt_list(struct virtio_video_device *vvd)
{
	return &vvd->output_fmt_list;
}

static struct virtio_video_device_ops virtio_video_cam_ops = {
	.init_ctrls = virtio_video_cam_init_ctrls,
	.init_queues = virtio_video_cam_init_queues,
	.get_fmt_list = virtio_video_cam_get_fmt_list,
};

int virtio_video_cam_init(struct virtio_video_device *vvd)
{
	ssize_t num;
	struct video_device *vd = &vvd->video_dev;

	vd->ioctl_ops = &virtio_video_cam_ioctl_ops;
	vvd->ops = &virtio_video_cam_ops;

	num = strscpy(vd->name, "camera", sizeof(vd->name));
	if (num < 0)
		return num;

	return 0;
}