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 | |
16 | static 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 | |
41 | static 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 | |
66 | static 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 | |
79 | static 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 */ |
107 | static 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 | |
115 | static 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 | |
122 | const 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 | |
133 | int 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 | |
149 | int 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 | |
163 | void 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 | |