1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * vivid-meta-out.c - meta output support functions.
4 */
5
6#include <linux/errno.h>
7#include <linux/kernel.h>
8#include <linux/videodev2.h>
9#include <media/v4l2-common.h>
10#include <linux/usb/video.h>
11
12#include "vivid-core.h"
13#include "vivid-kthread-out.h"
14#include "vivid-meta-out.h"
15
16static int meta_out_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
17 unsigned int *nplanes, unsigned int sizes[],
18 struct device *alloc_devs[])
19{
20 struct vivid_dev *dev = vb2_get_drv_priv(q: vq);
21 unsigned int q_num_bufs = vb2_get_num_buffers(q: vq);
22 unsigned int size = sizeof(struct vivid_meta_out_buf);
23
24 if (!vivid_is_webcam(dev))
25 return -EINVAL;
26
27 if (*nplanes) {
28 if (sizes[0] < size)
29 return -EINVAL;
30 } else {
31 sizes[0] = size;
32 }
33
34 if (q_num_bufs + *nbuffers < 2)
35 *nbuffers = 2 - q_num_bufs;
36
37 *nplanes = 1;
38 return 0;
39}
40
41static int meta_out_buf_prepare(struct vb2_buffer *vb)
42{
43 struct vivid_dev *dev = vb2_get_drv_priv(q: vb->vb2_queue);
44 unsigned int size = sizeof(struct vivid_meta_out_buf);
45
46 dprintk(dev, 1, "%s\n", __func__);
47
48 if (dev->buf_prepare_error) {
49 /*
50 * Error injection: test what happens if buf_prepare() returns
51 * an error.
52 */
53 dev->buf_prepare_error = false;
54 return -EINVAL;
55 }
56 if (vb2_plane_size(vb, plane_no: 0) < size) {
57 dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n",
58 __func__, vb2_plane_size(vb, 0), size);
59 return -EINVAL;
60 }
61 vb2_set_plane_payload(vb, plane_no: 0, size);
62
63 return 0;
64}
65
66static void meta_out_buf_queue(struct vb2_buffer *vb)
67{
68 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
69 struct vivid_dev *dev = vb2_get_drv_priv(q: vb->vb2_queue);
70 struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb);
71
72 dprintk(dev, 1, "%s\n", __func__);
73
74 spin_lock(lock: &dev->slock);
75 list_add_tail(new: &buf->list, head: &dev->meta_out_active);
76 spin_unlock(lock: &dev->slock);
77}
78
79static int meta_out_start_streaming(struct vb2_queue *vq, unsigned int count)
80{
81 struct vivid_dev *dev = vb2_get_drv_priv(q: vq);
82 int err;
83
84 dprintk(dev, 1, "%s\n", __func__);
85 dev->meta_out_seq_count = 0;
86 if (dev->start_streaming_error) {
87 dev->start_streaming_error = false;
88 err = -EINVAL;
89 } else {
90 err = vivid_start_generating_vid_out(dev,
91 pstreaming: &dev->meta_out_streaming);
92 }
93 if (err) {
94 struct vivid_buffer *buf, *tmp;
95
96 list_for_each_entry_safe(buf, tmp,
97 &dev->meta_out_active, list) {
98 list_del(entry: &buf->list);
99 vb2_buffer_done(vb: &buf->vb.vb2_buf,
100 state: VB2_BUF_STATE_QUEUED);
101 }
102 }
103 return err;
104}
105
106/* abort streaming and wait for last buffer */
107static void meta_out_stop_streaming(struct vb2_queue *vq)
108{
109 struct vivid_dev *dev = vb2_get_drv_priv(q: vq);
110
111 dprintk(dev, 1, "%s\n", __func__);
112 vivid_stop_generating_vid_out(dev, pstreaming: &dev->meta_out_streaming);
113}
114
115static void meta_out_buf_request_complete(struct vb2_buffer *vb)
116{
117 struct vivid_dev *dev = vb2_get_drv_priv(q: vb->vb2_queue);
118
119 v4l2_ctrl_request_complete(req: vb->req_obj.req, parent: &dev->ctrl_hdl_meta_out);
120}
121
122const struct vb2_ops vivid_meta_out_qops = {
123 .queue_setup = meta_out_queue_setup,
124 .buf_prepare = meta_out_buf_prepare,
125 .buf_queue = meta_out_buf_queue,
126 .start_streaming = meta_out_start_streaming,
127 .stop_streaming = meta_out_stop_streaming,
128 .buf_request_complete = meta_out_buf_request_complete,
129 .wait_prepare = vb2_ops_wait_prepare,
130 .wait_finish = vb2_ops_wait_finish,
131};
132
133int vidioc_enum_fmt_meta_out(struct file *file, void *priv,
134 struct v4l2_fmtdesc *f)
135{
136 struct vivid_dev *dev = video_drvdata(file);
137
138 if (!vivid_is_webcam(dev))
139 return -EINVAL;
140
141 if (f->index > 0)
142 return -EINVAL;
143
144 f->type = V4L2_BUF_TYPE_META_OUTPUT;
145 f->pixelformat = V4L2_META_FMT_VIVID;
146 return 0;
147}
148
149int vidioc_g_fmt_meta_out(struct file *file, void *priv,
150 struct v4l2_format *f)
151{
152 struct vivid_dev *dev = video_drvdata(file);
153 struct v4l2_meta_format *meta = &f->fmt.meta;
154
155 if (!vivid_is_webcam(dev) || !dev->has_meta_out)
156 return -EINVAL;
157
158 meta->dataformat = V4L2_META_FMT_VIVID;
159 meta->buffersize = sizeof(struct vivid_meta_out_buf);
160 return 0;
161}
162
163void vivid_meta_out_process(struct vivid_dev *dev,
164 struct vivid_buffer *buf)
165{
166 struct vivid_meta_out_buf *meta = vb2_plane_vaddr(vb: &buf->vb.vb2_buf, plane_no: 0);
167
168 v4l2_ctrl_s_ctrl(ctrl: dev->brightness, val: meta->brightness);
169 v4l2_ctrl_s_ctrl(ctrl: dev->contrast, val: meta->contrast);
170 v4l2_ctrl_s_ctrl(ctrl: dev->saturation, val: meta->saturation);
171 v4l2_ctrl_s_ctrl(ctrl: dev->hue, val: meta->hue);
172
173 dprintk(dev, 2, " %s brightness %u contrast %u saturation %u hue %d\n",
174 __func__, meta->brightness, meta->contrast,
175 meta->saturation, meta->hue);
176}
177

source code of linux/drivers/media/test-drivers/vivid/vivid-meta-out.c