1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * vivid-kthread-out.h - video/vbi output thread support functions. |
4 | * |
5 | * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
6 | */ |
7 | |
8 | #include <linux/module.h> |
9 | #include <linux/errno.h> |
10 | #include <linux/kernel.h> |
11 | #include <linux/init.h> |
12 | #include <linux/sched.h> |
13 | #include <linux/slab.h> |
14 | #include <linux/font.h> |
15 | #include <linux/mutex.h> |
16 | #include <linux/videodev2.h> |
17 | #include <linux/kthread.h> |
18 | #include <linux/freezer.h> |
19 | #include <linux/random.h> |
20 | #include <linux/v4l2-dv-timings.h> |
21 | #include <linux/jiffies.h> |
22 | #include <asm/div64.h> |
23 | #include <media/videobuf2-vmalloc.h> |
24 | #include <media/v4l2-dv-timings.h> |
25 | #include <media/v4l2-ioctl.h> |
26 | #include <media/v4l2-fh.h> |
27 | #include <media/v4l2-event.h> |
28 | |
29 | #include "vivid-core.h" |
30 | #include "vivid-vid-common.h" |
31 | #include "vivid-vid-cap.h" |
32 | #include "vivid-vid-out.h" |
33 | #include "vivid-radio-common.h" |
34 | #include "vivid-radio-rx.h" |
35 | #include "vivid-radio-tx.h" |
36 | #include "vivid-sdr-cap.h" |
37 | #include "vivid-vbi-cap.h" |
38 | #include "vivid-vbi-out.h" |
39 | #include "vivid-osd.h" |
40 | #include "vivid-ctrls.h" |
41 | #include "vivid-kthread-out.h" |
42 | #include "vivid-meta-out.h" |
43 | |
44 | static void vivid_thread_vid_out_tick(struct vivid_dev *dev) |
45 | { |
46 | struct vivid_buffer *vid_out_buf = NULL; |
47 | struct vivid_buffer *vbi_out_buf = NULL; |
48 | struct vivid_buffer *meta_out_buf = NULL; |
49 | |
50 | dprintk(dev, 1, "Video Output Thread Tick\n" ); |
51 | |
52 | /* Drop a certain percentage of buffers. */ |
53 | if (dev->perc_dropped_buffers && |
54 | get_random_u32_below(ceil: 100) < dev->perc_dropped_buffers) |
55 | return; |
56 | |
57 | spin_lock(lock: &dev->slock); |
58 | /* |
59 | * Only dequeue buffer if there is at least one more pending. |
60 | * This makes video loopback possible. |
61 | */ |
62 | if (!list_empty(head: &dev->vid_out_active) && |
63 | !list_is_singular(head: &dev->vid_out_active)) { |
64 | vid_out_buf = list_entry(dev->vid_out_active.next, |
65 | struct vivid_buffer, list); |
66 | list_del(entry: &vid_out_buf->list); |
67 | } |
68 | if (!list_empty(head: &dev->vbi_out_active) && |
69 | (dev->field_out != V4L2_FIELD_ALTERNATE || |
70 | (dev->vbi_out_seq_count & 1))) { |
71 | vbi_out_buf = list_entry(dev->vbi_out_active.next, |
72 | struct vivid_buffer, list); |
73 | list_del(entry: &vbi_out_buf->list); |
74 | } |
75 | if (!list_empty(head: &dev->meta_out_active)) { |
76 | meta_out_buf = list_entry(dev->meta_out_active.next, |
77 | struct vivid_buffer, list); |
78 | list_del(entry: &meta_out_buf->list); |
79 | } |
80 | spin_unlock(lock: &dev->slock); |
81 | |
82 | if (!vid_out_buf && !vbi_out_buf && !meta_out_buf) |
83 | return; |
84 | |
85 | if (vid_out_buf) { |
86 | v4l2_ctrl_request_setup(req: vid_out_buf->vb.vb2_buf.req_obj.req, |
87 | parent: &dev->ctrl_hdl_vid_out); |
88 | v4l2_ctrl_request_complete(req: vid_out_buf->vb.vb2_buf.req_obj.req, |
89 | parent: &dev->ctrl_hdl_vid_out); |
90 | vid_out_buf->vb.sequence = dev->vid_out_seq_count; |
91 | if (dev->field_out == V4L2_FIELD_ALTERNATE) { |
92 | /* |
93 | * The sequence counter counts frames, not fields. |
94 | * So divide by two. |
95 | */ |
96 | vid_out_buf->vb.sequence /= 2; |
97 | } |
98 | vid_out_buf->vb.vb2_buf.timestamp = |
99 | ktime_get_ns() + dev->time_wrap_offset; |
100 | vb2_buffer_done(vb: &vid_out_buf->vb.vb2_buf, state: dev->dqbuf_error ? |
101 | VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); |
102 | dprintk(dev, 2, "vid_out buffer %d done\n" , |
103 | vid_out_buf->vb.vb2_buf.index); |
104 | } |
105 | |
106 | if (vbi_out_buf) { |
107 | v4l2_ctrl_request_setup(req: vbi_out_buf->vb.vb2_buf.req_obj.req, |
108 | parent: &dev->ctrl_hdl_vbi_out); |
109 | v4l2_ctrl_request_complete(req: vbi_out_buf->vb.vb2_buf.req_obj.req, |
110 | parent: &dev->ctrl_hdl_vbi_out); |
111 | if (dev->stream_sliced_vbi_out) |
112 | vivid_sliced_vbi_out_process(dev, buf: vbi_out_buf); |
113 | |
114 | vbi_out_buf->vb.sequence = dev->vbi_out_seq_count; |
115 | vbi_out_buf->vb.vb2_buf.timestamp = |
116 | ktime_get_ns() + dev->time_wrap_offset; |
117 | vb2_buffer_done(vb: &vbi_out_buf->vb.vb2_buf, state: dev->dqbuf_error ? |
118 | VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); |
119 | dprintk(dev, 2, "vbi_out buffer %d done\n" , |
120 | vbi_out_buf->vb.vb2_buf.index); |
121 | } |
122 | if (meta_out_buf) { |
123 | v4l2_ctrl_request_setup(req: meta_out_buf->vb.vb2_buf.req_obj.req, |
124 | parent: &dev->ctrl_hdl_meta_out); |
125 | v4l2_ctrl_request_complete(req: meta_out_buf->vb.vb2_buf.req_obj.req, |
126 | parent: &dev->ctrl_hdl_meta_out); |
127 | vivid_meta_out_process(dev, buf: meta_out_buf); |
128 | meta_out_buf->vb.sequence = dev->meta_out_seq_count; |
129 | meta_out_buf->vb.vb2_buf.timestamp = |
130 | ktime_get_ns() + dev->time_wrap_offset; |
131 | vb2_buffer_done(vb: &meta_out_buf->vb.vb2_buf, state: dev->dqbuf_error ? |
132 | VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); |
133 | dprintk(dev, 2, "meta_out buffer %d done\n" , |
134 | meta_out_buf->vb.vb2_buf.index); |
135 | } |
136 | |
137 | dev->dqbuf_error = false; |
138 | } |
139 | |
140 | static int vivid_thread_vid_out(void *data) |
141 | { |
142 | struct vivid_dev *dev = data; |
143 | u64 numerators_since_start; |
144 | u64 buffers_since_start; |
145 | u64 next_jiffies_since_start; |
146 | unsigned long jiffies_since_start; |
147 | unsigned long cur_jiffies; |
148 | unsigned wait_jiffies; |
149 | unsigned numerator; |
150 | unsigned denominator; |
151 | |
152 | dprintk(dev, 1, "Video Output Thread Start\n" ); |
153 | |
154 | set_freezable(); |
155 | |
156 | /* Resets frame counters */ |
157 | dev->out_seq_offset = 0; |
158 | dev->out_seq_count = 0; |
159 | dev->jiffies_vid_out = jiffies; |
160 | dev->out_seq_resync = false; |
161 | if (dev->time_wrap) |
162 | dev->time_wrap_offset = dev->time_wrap - ktime_get_ns(); |
163 | else |
164 | dev->time_wrap_offset = 0; |
165 | |
166 | for (;;) { |
167 | try_to_freeze(); |
168 | if (kthread_should_stop()) |
169 | break; |
170 | |
171 | if (!mutex_trylock(lock: &dev->mutex)) { |
172 | schedule(); |
173 | continue; |
174 | } |
175 | |
176 | cur_jiffies = jiffies; |
177 | if (dev->out_seq_resync) { |
178 | dev->jiffies_vid_out = cur_jiffies; |
179 | dev->out_seq_offset = dev->out_seq_count + 1; |
180 | dev->out_seq_count = 0; |
181 | dev->out_seq_resync = false; |
182 | } |
183 | numerator = dev->timeperframe_vid_out.numerator; |
184 | denominator = dev->timeperframe_vid_out.denominator; |
185 | |
186 | if (dev->field_out == V4L2_FIELD_ALTERNATE) |
187 | denominator *= 2; |
188 | |
189 | /* Calculate the number of jiffies since we started streaming */ |
190 | jiffies_since_start = cur_jiffies - dev->jiffies_vid_out; |
191 | /* Get the number of buffers streamed since the start */ |
192 | buffers_since_start = (u64)jiffies_since_start * denominator + |
193 | (HZ * numerator) / 2; |
194 | do_div(buffers_since_start, HZ * numerator); |
195 | |
196 | /* |
197 | * After more than 0xf0000000 (rounded down to a multiple of |
198 | * 'jiffies-per-day' to ease jiffies_to_msecs calculation) |
199 | * jiffies have passed since we started streaming reset the |
200 | * counters and keep track of the sequence offset. |
201 | */ |
202 | if (jiffies_since_start > JIFFIES_RESYNC) { |
203 | dev->jiffies_vid_out = cur_jiffies; |
204 | dev->out_seq_offset = buffers_since_start; |
205 | buffers_since_start = 0; |
206 | } |
207 | dev->out_seq_count = buffers_since_start + dev->out_seq_offset; |
208 | dev->vid_out_seq_count = dev->out_seq_count - dev->vid_out_seq_start; |
209 | dev->vbi_out_seq_count = dev->out_seq_count - dev->vbi_out_seq_start; |
210 | dev->meta_out_seq_count = dev->out_seq_count - dev->meta_out_seq_start; |
211 | |
212 | vivid_thread_vid_out_tick(dev); |
213 | mutex_unlock(lock: &dev->mutex); |
214 | |
215 | /* |
216 | * Calculate the number of 'numerators' streamed since we started, |
217 | * not including the current buffer. |
218 | */ |
219 | numerators_since_start = buffers_since_start * numerator; |
220 | |
221 | /* And the number of jiffies since we started */ |
222 | jiffies_since_start = jiffies - dev->jiffies_vid_out; |
223 | |
224 | /* Increase by the 'numerator' of one buffer */ |
225 | numerators_since_start += numerator; |
226 | /* |
227 | * Calculate when that next buffer is supposed to start |
228 | * in jiffies since we started streaming. |
229 | */ |
230 | next_jiffies_since_start = numerators_since_start * HZ + |
231 | denominator / 2; |
232 | do_div(next_jiffies_since_start, denominator); |
233 | /* If it is in the past, then just schedule asap */ |
234 | if (next_jiffies_since_start < jiffies_since_start) |
235 | next_jiffies_since_start = jiffies_since_start; |
236 | |
237 | wait_jiffies = next_jiffies_since_start - jiffies_since_start; |
238 | while (time_is_after_jiffies(cur_jiffies + wait_jiffies) && |
239 | !kthread_should_stop()) |
240 | schedule(); |
241 | } |
242 | dprintk(dev, 1, "Video Output Thread End\n" ); |
243 | return 0; |
244 | } |
245 | |
246 | static void vivid_grab_controls(struct vivid_dev *dev, bool grab) |
247 | { |
248 | v4l2_ctrl_grab(ctrl: dev->ctrl_has_crop_out, grabbed: grab); |
249 | v4l2_ctrl_grab(ctrl: dev->ctrl_has_compose_out, grabbed: grab); |
250 | v4l2_ctrl_grab(ctrl: dev->ctrl_has_scaler_out, grabbed: grab); |
251 | v4l2_ctrl_grab(ctrl: dev->ctrl_tx_mode, grabbed: grab); |
252 | v4l2_ctrl_grab(ctrl: dev->ctrl_tx_rgb_range, grabbed: grab); |
253 | } |
254 | |
255 | int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming) |
256 | { |
257 | dprintk(dev, 1, "%s\n" , __func__); |
258 | |
259 | if (dev->kthread_vid_out) { |
260 | u32 seq_count = dev->out_seq_count + dev->seq_wrap * 128; |
261 | |
262 | if (pstreaming == &dev->vid_out_streaming) |
263 | dev->vid_out_seq_start = seq_count; |
264 | else if (pstreaming == &dev->vbi_out_streaming) |
265 | dev->vbi_out_seq_start = seq_count; |
266 | else |
267 | dev->meta_out_seq_start = seq_count; |
268 | *pstreaming = true; |
269 | return 0; |
270 | } |
271 | |
272 | /* Resets frame counters */ |
273 | dev->jiffies_vid_out = jiffies; |
274 | dev->vid_out_seq_start = dev->seq_wrap * 128; |
275 | dev->vbi_out_seq_start = dev->seq_wrap * 128; |
276 | dev->meta_out_seq_start = dev->seq_wrap * 128; |
277 | |
278 | dev->kthread_vid_out = kthread_run(vivid_thread_vid_out, dev, |
279 | "%s-vid-out" , dev->v4l2_dev.name); |
280 | |
281 | if (IS_ERR(ptr: dev->kthread_vid_out)) { |
282 | int err = PTR_ERR(ptr: dev->kthread_vid_out); |
283 | |
284 | dev->kthread_vid_out = NULL; |
285 | v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n" ); |
286 | return err; |
287 | } |
288 | *pstreaming = true; |
289 | vivid_grab_controls(dev, grab: true); |
290 | |
291 | dprintk(dev, 1, "returning from %s\n" , __func__); |
292 | return 0; |
293 | } |
294 | |
295 | void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming) |
296 | { |
297 | dprintk(dev, 1, "%s\n" , __func__); |
298 | |
299 | if (dev->kthread_vid_out == NULL) |
300 | return; |
301 | |
302 | *pstreaming = false; |
303 | if (pstreaming == &dev->vid_out_streaming) { |
304 | /* Release all active buffers */ |
305 | while (!list_empty(head: &dev->vid_out_active)) { |
306 | struct vivid_buffer *buf; |
307 | |
308 | buf = list_entry(dev->vid_out_active.next, |
309 | struct vivid_buffer, list); |
310 | list_del(entry: &buf->list); |
311 | v4l2_ctrl_request_complete(req: buf->vb.vb2_buf.req_obj.req, |
312 | parent: &dev->ctrl_hdl_vid_out); |
313 | vb2_buffer_done(vb: &buf->vb.vb2_buf, state: VB2_BUF_STATE_ERROR); |
314 | dprintk(dev, 2, "vid_out buffer %d done\n" , |
315 | buf->vb.vb2_buf.index); |
316 | } |
317 | } |
318 | |
319 | if (pstreaming == &dev->vbi_out_streaming) { |
320 | while (!list_empty(head: &dev->vbi_out_active)) { |
321 | struct vivid_buffer *buf; |
322 | |
323 | buf = list_entry(dev->vbi_out_active.next, |
324 | struct vivid_buffer, list); |
325 | list_del(entry: &buf->list); |
326 | v4l2_ctrl_request_complete(req: buf->vb.vb2_buf.req_obj.req, |
327 | parent: &dev->ctrl_hdl_vbi_out); |
328 | vb2_buffer_done(vb: &buf->vb.vb2_buf, state: VB2_BUF_STATE_ERROR); |
329 | dprintk(dev, 2, "vbi_out buffer %d done\n" , |
330 | buf->vb.vb2_buf.index); |
331 | } |
332 | } |
333 | |
334 | if (pstreaming == &dev->meta_out_streaming) { |
335 | while (!list_empty(head: &dev->meta_out_active)) { |
336 | struct vivid_buffer *buf; |
337 | |
338 | buf = list_entry(dev->meta_out_active.next, |
339 | struct vivid_buffer, list); |
340 | list_del(entry: &buf->list); |
341 | v4l2_ctrl_request_complete(req: buf->vb.vb2_buf.req_obj.req, |
342 | parent: &dev->ctrl_hdl_meta_out); |
343 | vb2_buffer_done(vb: &buf->vb.vb2_buf, state: VB2_BUF_STATE_ERROR); |
344 | dprintk(dev, 2, "meta_out buffer %d done\n" , |
345 | buf->vb.vb2_buf.index); |
346 | } |
347 | } |
348 | |
349 | if (dev->vid_out_streaming || dev->vbi_out_streaming || |
350 | dev->meta_out_streaming) |
351 | return; |
352 | |
353 | /* shutdown control thread */ |
354 | vivid_grab_controls(dev, grab: false); |
355 | kthread_stop(k: dev->kthread_vid_out); |
356 | dev->kthread_vid_out = NULL; |
357 | } |
358 | |