d657ba8a5a320104f8f4cac2710136ec51f6be34
[AGL/meta-agl-devel.git] / meta-egvirt / recipes-kernel / kernel-module-virtio-video / files / virtio_video_cam.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /* Capture for virtio video device.
3  *
4  * Copyright 2021 OpenSynergy GmbH.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <linux/version.h>
21 #include <media/v4l2-event.h>
22 #include <media/v4l2-ioctl.h>
23
24 #include "virtio_video.h"
25
26 static int virtio_video_cam_start_streaming(struct vb2_queue *vq,
27                                             unsigned int count)
28 {
29         struct virtio_video_stream *stream = vb2_get_drv_priv(vq);
30
31         if (virtio_video_state(stream) == STREAM_STATE_ERROR)
32                 return -EIO;
33
34         if (virtio_video_state(stream) >= STREAM_STATE_INIT)
35                 virtio_video_state_update(stream, STREAM_STATE_RUNNING);
36
37         return 0;
38 }
39
40 static void virtio_video_cam_stop_streaming(struct vb2_queue *vq)
41 {
42         struct virtio_video_stream *stream = vb2_get_drv_priv(vq);
43
44         virtio_video_queue_release_buffers(stream,
45                                            VIRTIO_VIDEO_QUEUE_TYPE_OUTPUT);
46
47         vb2_wait_for_all_buffers(vq);
48 }
49
50 static const struct vb2_ops virtio_video_cam_qops = {
51         .queue_setup     = virtio_video_queue_setup,
52         .buf_init        = virtio_video_buf_init,
53         .buf_cleanup     = virtio_video_buf_cleanup,
54         .buf_queue       = virtio_video_buf_queue,
55         .start_streaming = virtio_video_cam_start_streaming,
56         .stop_streaming  = virtio_video_cam_stop_streaming,
57         .wait_prepare    = vb2_ops_wait_prepare,
58         .wait_finish     = vb2_ops_wait_finish,
59 };
60
61 static int virtio_video_cam_g_ctrl(struct v4l2_ctrl *ctrl)
62 {
63         int ret = 0;
64         struct virtio_video_stream *stream = ctrl2stream(ctrl);
65
66         if (virtio_video_state(stream) == STREAM_STATE_ERROR)
67                 return -EIO;
68
69         switch (ctrl->id) {
70         case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
71                 if (virtio_video_state(stream) >=
72                     STREAM_STATE_DYNAMIC_RES_CHANGE)
73                         ctrl->val = stream->out_info.min_buffers;
74                 else
75                         ctrl->val = 0;
76                 break;
77         default:
78                 ret = -EINVAL;
79                 break;
80         }
81
82         return ret;
83 }
84
85 static const struct v4l2_ctrl_ops virtio_video_cam_ctrl_ops = {
86         .g_volatile_ctrl = virtio_video_cam_g_ctrl,
87 };
88
89 int virtio_video_cam_init_ctrls(struct virtio_video_stream *stream)
90 {
91         struct v4l2_ctrl *ctrl;
92
93         v4l2_ctrl_handler_init(&stream->ctrl_handler, 2);
94
95         ctrl = v4l2_ctrl_new_std(&stream->ctrl_handler,
96                                  &virtio_video_cam_ctrl_ops,
97                                  V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
98                                  MIN_BUFS_MIN, MIN_BUFS_MAX, MIN_BUFS_STEP,
99                                  MIN_BUFS_DEF);
100
101         if (ctrl)
102                 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
103
104         if (stream->ctrl_handler.error)
105                 return stream->ctrl_handler.error;
106
107         v4l2_ctrl_handler_setup(&stream->ctrl_handler);
108
109         return 0;
110 }
111
112 int virtio_video_cam_init_queues(void *priv, struct vb2_queue *src_vq,
113                                  struct vb2_queue *dst_vq)
114 {
115         struct virtio_video_stream *stream = priv;
116         struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev);
117         struct device *dev = vvd->v4l2_dev.dev;
118         int vq_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
119
120         if (!vvd->is_mplane_cam)
121                 vq_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
122
123         dst_vq->type = vq_type;
124         dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
125         dst_vq->drv_priv = stream;
126         dst_vq->buf_struct_size = sizeof(struct virtio_video_buffer);
127         dst_vq->ops = &virtio_video_cam_qops;
128         dst_vq->mem_ops = virtio_video_mem_ops(vvd);
129         dst_vq->min_buffers_needed = stream->out_info.min_buffers;
130         dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
131         dst_vq->lock = &stream->vq_mutex;
132         dst_vq->gfp_flags = virtio_video_gfp_flags(vvd);
133         dst_vq->dev = dev;
134
135         return vb2_queue_init(dst_vq);
136 }
137
138 int virtio_video_cam_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
139 {
140         struct virtio_video_stream *stream = file2stream(file);
141         struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev);
142         struct v4l2_format *fmt_try = f;
143         struct v4l2_format fmt_mp = { 0 };
144         int ret;
145
146         if (!vvd->is_mplane_cam) {
147                 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
148                         return -EINVAL;
149
150                 fmt_mp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
151                 fmt_try = &fmt_mp;
152
153                 virtio_video_pix_fmt_sp2mp(&f->fmt.pix, &fmt_try->fmt.pix_mp);
154         }
155
156         ret = virtio_video_try_fmt(stream, fmt_try);
157         if (ret)
158                 return ret;
159
160         if (!vvd->is_mplane_cam) {
161                 if (fmt_try->fmt.pix_mp.num_planes != 1)
162                         return -EINVAL;
163
164                 virtio_video_pix_fmt_mp2sp(&fmt_try->fmt.pix_mp, &f->fmt.pix);
165         }
166
167         return 0;
168 }
169
170 static int virtio_video_cam_enum_fmt_vid_cap(struct file *file, void *fh,
171                                              struct v4l2_fmtdesc *f)
172 {
173         struct virtio_video_stream *stream = file2stream(file);
174         struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev);
175         struct video_format *fmt;
176         int idx = 0;
177
178         if (virtio_video_state(stream) == STREAM_STATE_ERROR)
179                 return -EIO;
180
181         if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
182             f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
183                 return -EINVAL;
184
185         if (f->index >= vvd->num_output_fmts)
186                 return -EINVAL;
187
188         list_for_each_entry(fmt, &vvd->output_fmt_list, formats_list_entry) {
189                 if (f->index == idx) {
190                         f->pixelformat = fmt->desc.format;
191                         return 0;
192                 }
193                 idx++;
194         }
195         return -EINVAL;
196 }
197
198 static int virtio_video_cam_g_fmt(struct file *file, void *fh,
199                                   struct v4l2_format *f)
200 {
201         struct virtio_video_stream *stream = file2stream(file);
202         struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev);
203         struct v4l2_format fmt_mp = { 0 };
204         struct v4l2_format *fmt_get = f;
205         int ret;
206
207         if (!vvd->is_mplane_cam) {
208                 fmt_mp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
209                 fmt_get = &fmt_mp;
210         }
211
212         ret = virtio_video_g_fmt(file, fh, fmt_get);
213         if (ret)
214                 return ret;
215
216         if (virtio_video_state(stream) == STREAM_STATE_IDLE)
217                 virtio_video_state_update(stream, STREAM_STATE_INIT);
218
219         if (!vvd->is_mplane_cam) {
220                 if (fmt_get->fmt.pix_mp.num_planes != 1)
221                         return -EINVAL;
222
223                 virtio_video_pix_fmt_mp2sp(&fmt_get->fmt.pix_mp, &f->fmt.pix);
224         }
225
226         return 0;
227 }
228
229 static int virtio_video_cam_s_fmt(struct file *file, void *fh,
230                                   struct v4l2_format *f)
231 {
232         int ret;
233         struct virtio_video_stream *stream = file2stream(file);
234         struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev);
235         struct v4l2_format fmt_mp = { 0 };
236         struct v4l2_format *fmt_set = f;
237
238         if (!vvd->is_mplane_cam) {
239                 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
240                         return -EINVAL;
241
242                 fmt_mp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
243                 fmt_set = &fmt_mp;
244
245                 virtio_video_pix_fmt_sp2mp(&f->fmt.pix, &fmt_set->fmt.pix_mp);
246         }
247
248         ret = virtio_video_s_fmt(file, fh, fmt_set);
249         if (ret)
250                 return ret;
251
252         if (virtio_video_state(stream) == STREAM_STATE_IDLE)
253                 virtio_video_state_update(stream, STREAM_STATE_INIT);
254
255         if (!vvd->is_mplane_cam) {
256                 if (fmt_set->fmt.pix_mp.num_planes != 1)
257                         return -EINVAL;
258
259                 virtio_video_pix_fmt_mp2sp(&fmt_set->fmt.pix_mp, &f->fmt.pix);
260         }
261
262         return 0;
263 }
264
265 static int virtio_video_cam_s_selection(struct file *file, void *fh,
266                                         struct v4l2_selection *sel)
267 {
268         struct virtio_video_stream *stream = file2stream(file);
269         struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev);
270         int ret;
271
272         if (V4L2_TYPE_IS_OUTPUT(sel->type))
273                 return -EINVAL;
274
275         switch (sel->target) {
276         case V4L2_SEL_TGT_CROP:
277                 stream->out_info.crop.top = sel->r.top;
278                 stream->out_info.crop.left = sel->r.left;
279                 stream->out_info.crop.width = sel->r.width;
280                 stream->out_info.crop.height = sel->r.height;
281                 v4l2_info(&vvd->v4l2_dev,
282                           "Set : top:%d, left:%d, w:%d, h:%d\n",
283                           sel->r.top, sel->r.left, sel->r.width, sel->r.height);
284                 break;
285         default:
286                 return -EINVAL;
287         }
288
289         ret = virtio_video_cmd_set_params(vvd, stream,  &stream->out_info,
290                                           VIRTIO_VIDEO_QUEUE_TYPE_OUTPUT);
291         if (ret)
292                 return -EINVAL;
293
294         ret = virtio_video_cmd_get_params(vvd, stream,
295                                           VIRTIO_VIDEO_QUEUE_TYPE_OUTPUT);
296         return ret;
297 }
298
299 static const struct v4l2_ioctl_ops virtio_video_cam_ioctl_ops = {
300         .vidioc_querycap                = virtio_video_querycap,
301
302 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0))
303         .vidioc_enum_fmt_vid_cap_mplane = virtio_video_cam_enum_fmt_vid_cap,
304 #endif
305         .vidioc_try_fmt_vid_cap_mplane  = virtio_video_cam_try_fmt,
306         .vidioc_g_fmt_vid_cap_mplane    = virtio_video_cam_g_fmt,
307         .vidioc_s_fmt_vid_cap_mplane    = virtio_video_cam_s_fmt,
308
309         .vidioc_enum_fmt_vid_cap        = virtio_video_cam_enum_fmt_vid_cap,
310         .vidioc_try_fmt_vid_cap         = virtio_video_cam_try_fmt,
311         .vidioc_g_fmt_vid_cap           = virtio_video_cam_g_fmt,
312         .vidioc_s_fmt_vid_cap           = virtio_video_cam_s_fmt,
313
314         .vidioc_g_selection             = virtio_video_g_selection,
315         .vidioc_s_selection             = virtio_video_cam_s_selection,
316
317         .vidioc_enum_frameintervals     = virtio_video_enum_framemintervals,
318         .vidioc_enum_framesizes         = virtio_video_enum_framesizes,
319
320         .vidioc_reqbufs         = virtio_video_reqbufs,
321         .vidioc_querybuf        = vb2_ioctl_querybuf,
322         .vidioc_qbuf            = virtio_video_qbuf,
323         .vidioc_dqbuf           = virtio_video_dqbuf,
324         .vidioc_prepare_buf     = vb2_ioctl_prepare_buf,
325         .vidioc_create_bufs     = vb2_ioctl_create_bufs,
326         .vidioc_expbuf          = vb2_ioctl_expbuf,
327
328         .vidioc_streamon        = vb2_ioctl_streamon,
329         .vidioc_streamoff       = vb2_ioctl_streamoff,
330
331         .vidioc_subscribe_event   = virtio_video_subscribe_event,
332         .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
333 };
334
335 void *virtio_video_cam_get_fmt_list(struct virtio_video_device *vvd)
336 {
337         return &vvd->output_fmt_list;
338 }
339
340 static struct virtio_video_device_ops virtio_video_cam_ops = {
341         .init_ctrls = virtio_video_cam_init_ctrls,
342         .init_queues = virtio_video_cam_init_queues,
343         .get_fmt_list = virtio_video_cam_get_fmt_list,
344 };
345
346 int virtio_video_cam_init(struct virtio_video_device *vvd)
347 {
348         ssize_t num;
349         struct video_device *vd = &vvd->video_dev;
350
351         vd->ioctl_ops = &virtio_video_cam_ioctl_ops;
352         vvd->ops = &virtio_video_cam_ops;
353
354         num = strscpy(vd->name, "camera", sizeof(vd->name));
355         if (num < 0)
356                 return num;
357
358         return 0;
359 }