1dacca5f0SHans Verkuil // SPDX-License-Identifier: GPL-2.0-only
2dacca5f0SHans Verkuil /*
3dacca5f0SHans Verkuil * vivid-kthread-cap.h - video/vbi capture thread support functions.
4dacca5f0SHans Verkuil *
5dacca5f0SHans Verkuil * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6dacca5f0SHans Verkuil */
7dacca5f0SHans Verkuil
8dacca5f0SHans Verkuil #include <linux/module.h>
9dacca5f0SHans Verkuil #include <linux/errno.h>
10dacca5f0SHans Verkuil #include <linux/kernel.h>
11dacca5f0SHans Verkuil #include <linux/init.h>
12dacca5f0SHans Verkuil #include <linux/sched.h>
13dacca5f0SHans Verkuil #include <linux/slab.h>
14dacca5f0SHans Verkuil #include <linux/font.h>
15dacca5f0SHans Verkuil #include <linux/mutex.h>
16dacca5f0SHans Verkuil #include <linux/videodev2.h>
17dacca5f0SHans Verkuil #include <linux/kthread.h>
18dacca5f0SHans Verkuil #include <linux/freezer.h>
19dacca5f0SHans Verkuil #include <linux/random.h>
20dacca5f0SHans Verkuil #include <linux/v4l2-dv-timings.h>
2184db51f5SWang Qing #include <linux/jiffies.h>
22dacca5f0SHans Verkuil #include <asm/div64.h>
23dacca5f0SHans Verkuil #include <media/videobuf2-vmalloc.h>
24dacca5f0SHans Verkuil #include <media/v4l2-dv-timings.h>
25dacca5f0SHans Verkuil #include <media/v4l2-ioctl.h>
26dacca5f0SHans Verkuil #include <media/v4l2-fh.h>
27dacca5f0SHans Verkuil #include <media/v4l2-event.h>
28dacca5f0SHans Verkuil #include <media/v4l2-rect.h>
29dacca5f0SHans Verkuil
30dacca5f0SHans Verkuil #include "vivid-core.h"
31dacca5f0SHans Verkuil #include "vivid-vid-common.h"
32dacca5f0SHans Verkuil #include "vivid-vid-cap.h"
33dacca5f0SHans Verkuil #include "vivid-vid-out.h"
34dacca5f0SHans Verkuil #include "vivid-radio-common.h"
35dacca5f0SHans Verkuil #include "vivid-radio-rx.h"
36dacca5f0SHans Verkuil #include "vivid-radio-tx.h"
37dacca5f0SHans Verkuil #include "vivid-sdr-cap.h"
38dacca5f0SHans Verkuil #include "vivid-vbi-cap.h"
39dacca5f0SHans Verkuil #include "vivid-vbi-out.h"
40dacca5f0SHans Verkuil #include "vivid-osd.h"
41dacca5f0SHans Verkuil #include "vivid-ctrls.h"
42dacca5f0SHans Verkuil #include "vivid-kthread-cap.h"
43dacca5f0SHans Verkuil #include "vivid-meta-cap.h"
44dacca5f0SHans Verkuil
vivid_get_std_cap(const struct vivid_dev * dev)45dacca5f0SHans Verkuil static inline v4l2_std_id vivid_get_std_cap(const struct vivid_dev *dev)
46dacca5f0SHans Verkuil {
47dacca5f0SHans Verkuil if (vivid_is_sdtv_cap(dev))
48dacca5f0SHans Verkuil return dev->std_cap[dev->input];
49dacca5f0SHans Verkuil return 0;
50dacca5f0SHans Verkuil }
51dacca5f0SHans Verkuil
copy_pix(struct vivid_dev * dev,int win_y,int win_x,u16 * cap,const u16 * osd)52dacca5f0SHans Verkuil static void copy_pix(struct vivid_dev *dev, int win_y, int win_x,
53dacca5f0SHans Verkuil u16 *cap, const u16 *osd)
54dacca5f0SHans Verkuil {
55dacca5f0SHans Verkuil u16 out;
56dacca5f0SHans Verkuil
57dacca5f0SHans Verkuil out = *cap;
58dacca5f0SHans Verkuil *cap = *osd;
59dacca5f0SHans Verkuil
60dacca5f0SHans Verkuil if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_CHROMAKEY) &&
61dacca5f0SHans Verkuil *osd != dev->chromakey_out)
62dacca5f0SHans Verkuil return;
63dacca5f0SHans Verkuil if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) &&
64dacca5f0SHans Verkuil out == dev->chromakey_out)
65dacca5f0SHans Verkuil return;
66dacca5f0SHans Verkuil if (dev->fmt_cap->alpha_mask) {
67dacca5f0SHans Verkuil if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) &&
68dacca5f0SHans Verkuil dev->global_alpha_out)
69dacca5f0SHans Verkuil return;
70dacca5f0SHans Verkuil if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) &&
71dacca5f0SHans Verkuil *cap & dev->fmt_cap->alpha_mask)
72dacca5f0SHans Verkuil return;
73dacca5f0SHans Verkuil if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_LOCAL_INV_ALPHA) &&
74dacca5f0SHans Verkuil !(*cap & dev->fmt_cap->alpha_mask))
75dacca5f0SHans Verkuil return;
76dacca5f0SHans Verkuil }
77dacca5f0SHans Verkuil *cap = out;
78dacca5f0SHans Verkuil }
79dacca5f0SHans Verkuil
blend_line(struct vivid_dev * dev,unsigned y_offset,unsigned x_offset,u8 * vcapbuf,const u8 * vosdbuf,unsigned width,unsigned pixsize)80dacca5f0SHans Verkuil static void blend_line(struct vivid_dev *dev, unsigned y_offset, unsigned x_offset,
81dacca5f0SHans Verkuil u8 *vcapbuf, const u8 *vosdbuf,
82dacca5f0SHans Verkuil unsigned width, unsigned pixsize)
83dacca5f0SHans Verkuil {
84dacca5f0SHans Verkuil unsigned x;
85dacca5f0SHans Verkuil
86dacca5f0SHans Verkuil for (x = 0; x < width; x++, vcapbuf += pixsize, vosdbuf += pixsize) {
87dacca5f0SHans Verkuil copy_pix(dev, y_offset, x_offset + x,
88dacca5f0SHans Verkuil (u16 *)vcapbuf, (const u16 *)vosdbuf);
89dacca5f0SHans Verkuil }
90dacca5f0SHans Verkuil }
91dacca5f0SHans Verkuil
scale_line(const u8 * src,u8 * dst,unsigned srcw,unsigned dstw,unsigned twopixsize)92dacca5f0SHans Verkuil static void scale_line(const u8 *src, u8 *dst, unsigned srcw, unsigned dstw, unsigned twopixsize)
93dacca5f0SHans Verkuil {
94dacca5f0SHans Verkuil /* Coarse scaling with Bresenham */
95dacca5f0SHans Verkuil unsigned int_part;
96dacca5f0SHans Verkuil unsigned fract_part;
97dacca5f0SHans Verkuil unsigned src_x = 0;
98dacca5f0SHans Verkuil unsigned error = 0;
99dacca5f0SHans Verkuil unsigned x;
100dacca5f0SHans Verkuil
101dacca5f0SHans Verkuil /*
102dacca5f0SHans Verkuil * We always combine two pixels to prevent color bleed in the packed
103dacca5f0SHans Verkuil * yuv case.
104dacca5f0SHans Verkuil */
105dacca5f0SHans Verkuil srcw /= 2;
106dacca5f0SHans Verkuil dstw /= 2;
107dacca5f0SHans Verkuil int_part = srcw / dstw;
108dacca5f0SHans Verkuil fract_part = srcw % dstw;
109dacca5f0SHans Verkuil for (x = 0; x < dstw; x++, dst += twopixsize) {
110dacca5f0SHans Verkuil memcpy(dst, src + src_x * twopixsize, twopixsize);
111dacca5f0SHans Verkuil src_x += int_part;
112dacca5f0SHans Verkuil error += fract_part;
113dacca5f0SHans Verkuil if (error >= dstw) {
114dacca5f0SHans Verkuil error -= dstw;
115dacca5f0SHans Verkuil src_x++;
116dacca5f0SHans Verkuil }
117dacca5f0SHans Verkuil }
118dacca5f0SHans Verkuil }
119dacca5f0SHans Verkuil
120dacca5f0SHans Verkuil /*
121dacca5f0SHans Verkuil * Precalculate the rectangles needed to perform video looping:
122dacca5f0SHans Verkuil *
123dacca5f0SHans Verkuil * The nominal pipeline is that the video output buffer is cropped by
124dacca5f0SHans Verkuil * crop_out, scaled to compose_out, overlaid with the output overlay,
125dacca5f0SHans Verkuil * cropped on the capture side by crop_cap and scaled again to the video
126dacca5f0SHans Verkuil * capture buffer using compose_cap.
127dacca5f0SHans Verkuil *
128dacca5f0SHans Verkuil * To keep things efficient we calculate the intersection of compose_out
129dacca5f0SHans Verkuil * and crop_cap (since that's the only part of the video that will
130dacca5f0SHans Verkuil * actually end up in the capture buffer), determine which part of the
131dacca5f0SHans Verkuil * video output buffer that is and which part of the video capture buffer
132dacca5f0SHans Verkuil * so we can scale the video straight from the output buffer to the capture
133dacca5f0SHans Verkuil * buffer without any intermediate steps.
134dacca5f0SHans Verkuil *
135dacca5f0SHans Verkuil * If we need to deal with an output overlay, then there is no choice and
136dacca5f0SHans Verkuil * that intermediate step still has to be taken. For the output overlay
137dacca5f0SHans Verkuil * support we calculate the intersection of the framebuffer and the overlay
138dacca5f0SHans Verkuil * window (which may be partially or wholly outside of the framebuffer
139dacca5f0SHans Verkuil * itself) and the intersection of that with loop_vid_copy (i.e. the part of
140dacca5f0SHans Verkuil * the actual looped video that will be overlaid). The result is calculated
141dacca5f0SHans Verkuil * both in framebuffer coordinates (loop_fb_copy) and compose_out coordinates
142dacca5f0SHans Verkuil * (loop_vid_overlay). Finally calculate the part of the capture buffer that
143dacca5f0SHans Verkuil * will receive that overlaid video.
144dacca5f0SHans Verkuil */
vivid_precalc_copy_rects(struct vivid_dev * dev)145dacca5f0SHans Verkuil static void vivid_precalc_copy_rects(struct vivid_dev *dev)
146dacca5f0SHans Verkuil {
147dacca5f0SHans Verkuil /* Framebuffer rectangle */
148dacca5f0SHans Verkuil struct v4l2_rect r_fb = {
149dacca5f0SHans Verkuil 0, 0, dev->display_width, dev->display_height
150dacca5f0SHans Verkuil };
151dacca5f0SHans Verkuil /* Overlay window rectangle in framebuffer coordinates */
152dacca5f0SHans Verkuil struct v4l2_rect r_overlay = {
153dacca5f0SHans Verkuil dev->overlay_out_left, dev->overlay_out_top,
154dacca5f0SHans Verkuil dev->compose_out.width, dev->compose_out.height
155dacca5f0SHans Verkuil };
156dacca5f0SHans Verkuil
157dacca5f0SHans Verkuil v4l2_rect_intersect(&dev->loop_vid_copy, &dev->crop_cap, &dev->compose_out);
158dacca5f0SHans Verkuil
159dacca5f0SHans Verkuil dev->loop_vid_out = dev->loop_vid_copy;
160dacca5f0SHans Verkuil v4l2_rect_scale(&dev->loop_vid_out, &dev->compose_out, &dev->crop_out);
161dacca5f0SHans Verkuil dev->loop_vid_out.left += dev->crop_out.left;
162dacca5f0SHans Verkuil dev->loop_vid_out.top += dev->crop_out.top;
163dacca5f0SHans Verkuil
164dacca5f0SHans Verkuil dev->loop_vid_cap = dev->loop_vid_copy;
165dacca5f0SHans Verkuil v4l2_rect_scale(&dev->loop_vid_cap, &dev->crop_cap, &dev->compose_cap);
166dacca5f0SHans Verkuil
167dacca5f0SHans Verkuil dprintk(dev, 1,
168dacca5f0SHans Verkuil "loop_vid_copy: %dx%d@%dx%d loop_vid_out: %dx%d@%dx%d loop_vid_cap: %dx%d@%dx%d\n",
169dacca5f0SHans Verkuil dev->loop_vid_copy.width, dev->loop_vid_copy.height,
170dacca5f0SHans Verkuil dev->loop_vid_copy.left, dev->loop_vid_copy.top,
171dacca5f0SHans Verkuil dev->loop_vid_out.width, dev->loop_vid_out.height,
172dacca5f0SHans Verkuil dev->loop_vid_out.left, dev->loop_vid_out.top,
173dacca5f0SHans Verkuil dev->loop_vid_cap.width, dev->loop_vid_cap.height,
174dacca5f0SHans Verkuil dev->loop_vid_cap.left, dev->loop_vid_cap.top);
175dacca5f0SHans Verkuil
176dacca5f0SHans Verkuil v4l2_rect_intersect(&r_overlay, &r_fb, &r_overlay);
177dacca5f0SHans Verkuil
178dacca5f0SHans Verkuil /* shift r_overlay to the same origin as compose_out */
179dacca5f0SHans Verkuil r_overlay.left += dev->compose_out.left - dev->overlay_out_left;
180dacca5f0SHans Verkuil r_overlay.top += dev->compose_out.top - dev->overlay_out_top;
181dacca5f0SHans Verkuil
182dacca5f0SHans Verkuil v4l2_rect_intersect(&dev->loop_vid_overlay, &r_overlay, &dev->loop_vid_copy);
183dacca5f0SHans Verkuil dev->loop_fb_copy = dev->loop_vid_overlay;
184dacca5f0SHans Verkuil
185dacca5f0SHans Verkuil /* shift dev->loop_fb_copy back again to the fb origin */
186dacca5f0SHans Verkuil dev->loop_fb_copy.left -= dev->compose_out.left - dev->overlay_out_left;
187dacca5f0SHans Verkuil dev->loop_fb_copy.top -= dev->compose_out.top - dev->overlay_out_top;
188dacca5f0SHans Verkuil
189dacca5f0SHans Verkuil dev->loop_vid_overlay_cap = dev->loop_vid_overlay;
190dacca5f0SHans Verkuil v4l2_rect_scale(&dev->loop_vid_overlay_cap, &dev->crop_cap, &dev->compose_cap);
191dacca5f0SHans Verkuil
192dacca5f0SHans Verkuil dprintk(dev, 1,
193dacca5f0SHans Verkuil "loop_fb_copy: %dx%d@%dx%d loop_vid_overlay: %dx%d@%dx%d loop_vid_overlay_cap: %dx%d@%dx%d\n",
194dacca5f0SHans Verkuil dev->loop_fb_copy.width, dev->loop_fb_copy.height,
195dacca5f0SHans Verkuil dev->loop_fb_copy.left, dev->loop_fb_copy.top,
196dacca5f0SHans Verkuil dev->loop_vid_overlay.width, dev->loop_vid_overlay.height,
197dacca5f0SHans Verkuil dev->loop_vid_overlay.left, dev->loop_vid_overlay.top,
198dacca5f0SHans Verkuil dev->loop_vid_overlay_cap.width, dev->loop_vid_overlay_cap.height,
199dacca5f0SHans Verkuil dev->loop_vid_overlay_cap.left, dev->loop_vid_overlay_cap.top);
200dacca5f0SHans Verkuil }
201dacca5f0SHans Verkuil
plane_vaddr(struct tpg_data * tpg,struct vivid_buffer * buf,unsigned p,unsigned bpl[TPG_MAX_PLANES],unsigned h)202dacca5f0SHans Verkuil static void *plane_vaddr(struct tpg_data *tpg, struct vivid_buffer *buf,
203dacca5f0SHans Verkuil unsigned p, unsigned bpl[TPG_MAX_PLANES], unsigned h)
204dacca5f0SHans Verkuil {
205dacca5f0SHans Verkuil unsigned i;
206dacca5f0SHans Verkuil void *vbuf;
207dacca5f0SHans Verkuil
208dacca5f0SHans Verkuil if (p == 0 || tpg_g_buffers(tpg) > 1)
209dacca5f0SHans Verkuil return vb2_plane_vaddr(&buf->vb.vb2_buf, p);
210dacca5f0SHans Verkuil vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
211dacca5f0SHans Verkuil for (i = 0; i < p; i++)
212dacca5f0SHans Verkuil vbuf += bpl[i] * h / tpg->vdownsampling[i];
213dacca5f0SHans Verkuil return vbuf;
214dacca5f0SHans Verkuil }
215dacca5f0SHans Verkuil
vivid_copy_buffer(struct vivid_dev * dev,unsigned p,u8 * vcapbuf,struct vivid_buffer * vid_cap_buf)216dacca5f0SHans Verkuil static noinline_for_stack int vivid_copy_buffer(struct vivid_dev *dev, unsigned p,
217dacca5f0SHans Verkuil u8 *vcapbuf, struct vivid_buffer *vid_cap_buf)
218dacca5f0SHans Verkuil {
219dacca5f0SHans Verkuil bool blank = dev->must_blank[vid_cap_buf->vb.vb2_buf.index];
220dacca5f0SHans Verkuil struct tpg_data *tpg = &dev->tpg;
221dacca5f0SHans Verkuil struct vivid_buffer *vid_out_buf = NULL;
222dacca5f0SHans Verkuil unsigned vdiv = dev->fmt_out->vdownsampling[p];
223dacca5f0SHans Verkuil unsigned twopixsize = tpg_g_twopixelsize(tpg, p);
224dacca5f0SHans Verkuil unsigned img_width = tpg_hdiv(tpg, p, dev->compose_cap.width);
225dacca5f0SHans Verkuil unsigned img_height = dev->compose_cap.height;
226dacca5f0SHans Verkuil unsigned stride_cap = tpg->bytesperline[p];
227dacca5f0SHans Verkuil unsigned stride_out = dev->bytesperline_out[p];
228dacca5f0SHans Verkuil unsigned stride_osd = dev->display_byte_stride;
229dacca5f0SHans Verkuil unsigned hmax = (img_height * tpg->perc_fill) / 100;
230dacca5f0SHans Verkuil u8 *voutbuf;
231dacca5f0SHans Verkuil u8 *vosdbuf = NULL;
232dacca5f0SHans Verkuil unsigned y;
233*2e19bfc8SHans Verkuil bool blend = dev->fbuf_out_flags;
234dacca5f0SHans Verkuil /* Coarse scaling with Bresenham */
235dacca5f0SHans Verkuil unsigned vid_out_int_part;
236dacca5f0SHans Verkuil unsigned vid_out_fract_part;
237dacca5f0SHans Verkuil unsigned vid_out_y = 0;
238dacca5f0SHans Verkuil unsigned vid_out_error = 0;
239dacca5f0SHans Verkuil unsigned vid_overlay_int_part = 0;
240dacca5f0SHans Verkuil unsigned vid_overlay_fract_part = 0;
241dacca5f0SHans Verkuil unsigned vid_overlay_y = 0;
242dacca5f0SHans Verkuil unsigned vid_overlay_error = 0;
243dacca5f0SHans Verkuil unsigned vid_cap_left = tpg_hdiv(tpg, p, dev->loop_vid_cap.left);
244dacca5f0SHans Verkuil unsigned vid_cap_right;
245dacca5f0SHans Verkuil bool quick;
246dacca5f0SHans Verkuil
247dacca5f0SHans Verkuil vid_out_int_part = dev->loop_vid_out.height / dev->loop_vid_cap.height;
248dacca5f0SHans Verkuil vid_out_fract_part = dev->loop_vid_out.height % dev->loop_vid_cap.height;
249dacca5f0SHans Verkuil
250dacca5f0SHans Verkuil if (!list_empty(&dev->vid_out_active))
251dacca5f0SHans Verkuil vid_out_buf = list_entry(dev->vid_out_active.next,
252dacca5f0SHans Verkuil struct vivid_buffer, list);
253dacca5f0SHans Verkuil if (vid_out_buf == NULL)
254dacca5f0SHans Verkuil return -ENODATA;
255dacca5f0SHans Verkuil
256dacca5f0SHans Verkuil vid_cap_buf->vb.field = vid_out_buf->vb.field;
257dacca5f0SHans Verkuil
258dacca5f0SHans Verkuil voutbuf = plane_vaddr(tpg, vid_out_buf, p,
259dacca5f0SHans Verkuil dev->bytesperline_out, dev->fmt_out_rect.height);
260dacca5f0SHans Verkuil if (p < dev->fmt_out->buffers)
261dacca5f0SHans Verkuil voutbuf += vid_out_buf->vb.vb2_buf.planes[p].data_offset;
262dacca5f0SHans Verkuil voutbuf += tpg_hdiv(tpg, p, dev->loop_vid_out.left) +
263dacca5f0SHans Verkuil (dev->loop_vid_out.top / vdiv) * stride_out;
264dacca5f0SHans Verkuil vcapbuf += tpg_hdiv(tpg, p, dev->compose_cap.left) +
265dacca5f0SHans Verkuil (dev->compose_cap.top / vdiv) * stride_cap;
266dacca5f0SHans Verkuil
267dacca5f0SHans Verkuil if (dev->loop_vid_copy.width == 0 || dev->loop_vid_copy.height == 0) {
268dacca5f0SHans Verkuil /*
269dacca5f0SHans Verkuil * If there is nothing to copy, then just fill the capture window
270dacca5f0SHans Verkuil * with black.
271dacca5f0SHans Verkuil */
272dacca5f0SHans Verkuil for (y = 0; y < hmax / vdiv; y++, vcapbuf += stride_cap)
273dacca5f0SHans Verkuil memcpy(vcapbuf, tpg->black_line[p], img_width);
274dacca5f0SHans Verkuil return 0;
275dacca5f0SHans Verkuil }
276dacca5f0SHans Verkuil
277dacca5f0SHans Verkuil if (dev->overlay_out_enabled &&
278dacca5f0SHans Verkuil dev->loop_vid_overlay.width && dev->loop_vid_overlay.height) {
279dacca5f0SHans Verkuil vosdbuf = dev->video_vbase;
280dacca5f0SHans Verkuil vosdbuf += (dev->loop_fb_copy.left * twopixsize) / 2 +
281dacca5f0SHans Verkuil dev->loop_fb_copy.top * stride_osd;
282dacca5f0SHans Verkuil vid_overlay_int_part = dev->loop_vid_overlay.height /
283dacca5f0SHans Verkuil dev->loop_vid_overlay_cap.height;
284dacca5f0SHans Verkuil vid_overlay_fract_part = dev->loop_vid_overlay.height %
285dacca5f0SHans Verkuil dev->loop_vid_overlay_cap.height;
286dacca5f0SHans Verkuil }
287dacca5f0SHans Verkuil
288dacca5f0SHans Verkuil vid_cap_right = tpg_hdiv(tpg, p, dev->loop_vid_cap.left + dev->loop_vid_cap.width);
289dacca5f0SHans Verkuil /* quick is true if no video scaling is needed */
290dacca5f0SHans Verkuil quick = dev->loop_vid_out.width == dev->loop_vid_cap.width;
291dacca5f0SHans Verkuil
292dacca5f0SHans Verkuil dev->cur_scaled_line = dev->loop_vid_out.height;
293dacca5f0SHans Verkuil for (y = 0; y < hmax; y += vdiv, vcapbuf += stride_cap) {
294dacca5f0SHans Verkuil /* osdline is true if this line requires overlay blending */
295dacca5f0SHans Verkuil bool osdline = vosdbuf && y >= dev->loop_vid_overlay_cap.top &&
296dacca5f0SHans Verkuil y < dev->loop_vid_overlay_cap.top + dev->loop_vid_overlay_cap.height;
297dacca5f0SHans Verkuil
298dacca5f0SHans Verkuil /*
299dacca5f0SHans Verkuil * If this line of the capture buffer doesn't get any video, then
300dacca5f0SHans Verkuil * just fill with black.
301dacca5f0SHans Verkuil */
302dacca5f0SHans Verkuil if (y < dev->loop_vid_cap.top ||
303dacca5f0SHans Verkuil y >= dev->loop_vid_cap.top + dev->loop_vid_cap.height) {
304dacca5f0SHans Verkuil memcpy(vcapbuf, tpg->black_line[p], img_width);
305dacca5f0SHans Verkuil continue;
306dacca5f0SHans Verkuil }
307dacca5f0SHans Verkuil
308dacca5f0SHans Verkuil /* fill the left border with black */
309dacca5f0SHans Verkuil if (dev->loop_vid_cap.left)
310dacca5f0SHans Verkuil memcpy(vcapbuf, tpg->black_line[p], vid_cap_left);
311dacca5f0SHans Verkuil
312dacca5f0SHans Verkuil /* fill the right border with black */
313dacca5f0SHans Verkuil if (vid_cap_right < img_width)
314dacca5f0SHans Verkuil memcpy(vcapbuf + vid_cap_right, tpg->black_line[p],
315dacca5f0SHans Verkuil img_width - vid_cap_right);
316dacca5f0SHans Verkuil
317dacca5f0SHans Verkuil if (quick && !osdline) {
318dacca5f0SHans Verkuil memcpy(vcapbuf + vid_cap_left,
319dacca5f0SHans Verkuil voutbuf + vid_out_y * stride_out,
320dacca5f0SHans Verkuil tpg_hdiv(tpg, p, dev->loop_vid_cap.width));
321dacca5f0SHans Verkuil goto update_vid_out_y;
322dacca5f0SHans Verkuil }
323dacca5f0SHans Verkuil if (dev->cur_scaled_line == vid_out_y) {
324dacca5f0SHans Verkuil memcpy(vcapbuf + vid_cap_left, dev->scaled_line,
325dacca5f0SHans Verkuil tpg_hdiv(tpg, p, dev->loop_vid_cap.width));
326dacca5f0SHans Verkuil goto update_vid_out_y;
327dacca5f0SHans Verkuil }
328dacca5f0SHans Verkuil if (!osdline) {
329dacca5f0SHans Verkuil scale_line(voutbuf + vid_out_y * stride_out, dev->scaled_line,
330dacca5f0SHans Verkuil tpg_hdiv(tpg, p, dev->loop_vid_out.width),
331dacca5f0SHans Verkuil tpg_hdiv(tpg, p, dev->loop_vid_cap.width),
332dacca5f0SHans Verkuil tpg_g_twopixelsize(tpg, p));
333dacca5f0SHans Verkuil } else {
334dacca5f0SHans Verkuil /*
335dacca5f0SHans Verkuil * Offset in bytes within loop_vid_copy to the start of the
336dacca5f0SHans Verkuil * loop_vid_overlay rectangle.
337dacca5f0SHans Verkuil */
338dacca5f0SHans Verkuil unsigned offset =
339dacca5f0SHans Verkuil ((dev->loop_vid_overlay.left - dev->loop_vid_copy.left) *
340dacca5f0SHans Verkuil twopixsize) / 2;
341dacca5f0SHans Verkuil u8 *osd = vosdbuf + vid_overlay_y * stride_osd;
342dacca5f0SHans Verkuil
343dacca5f0SHans Verkuil scale_line(voutbuf + vid_out_y * stride_out, dev->blended_line,
344dacca5f0SHans Verkuil dev->loop_vid_out.width, dev->loop_vid_copy.width,
345dacca5f0SHans Verkuil tpg_g_twopixelsize(tpg, p));
346dacca5f0SHans Verkuil if (blend)
347dacca5f0SHans Verkuil blend_line(dev, vid_overlay_y + dev->loop_vid_overlay.top,
348dacca5f0SHans Verkuil dev->loop_vid_overlay.left,
349dacca5f0SHans Verkuil dev->blended_line + offset, osd,
350dacca5f0SHans Verkuil dev->loop_vid_overlay.width, twopixsize / 2);
351dacca5f0SHans Verkuil else
352dacca5f0SHans Verkuil memcpy(dev->blended_line + offset,
353dacca5f0SHans Verkuil osd, (dev->loop_vid_overlay.width * twopixsize) / 2);
354dacca5f0SHans Verkuil scale_line(dev->blended_line, dev->scaled_line,
355dacca5f0SHans Verkuil dev->loop_vid_copy.width, dev->loop_vid_cap.width,
356dacca5f0SHans Verkuil tpg_g_twopixelsize(tpg, p));
357dacca5f0SHans Verkuil }
358dacca5f0SHans Verkuil dev->cur_scaled_line = vid_out_y;
359dacca5f0SHans Verkuil memcpy(vcapbuf + vid_cap_left, dev->scaled_line,
360dacca5f0SHans Verkuil tpg_hdiv(tpg, p, dev->loop_vid_cap.width));
361dacca5f0SHans Verkuil
362dacca5f0SHans Verkuil update_vid_out_y:
363dacca5f0SHans Verkuil if (osdline) {
364dacca5f0SHans Verkuil vid_overlay_y += vid_overlay_int_part;
365dacca5f0SHans Verkuil vid_overlay_error += vid_overlay_fract_part;
366dacca5f0SHans Verkuil if (vid_overlay_error >= dev->loop_vid_overlay_cap.height) {
367dacca5f0SHans Verkuil vid_overlay_error -= dev->loop_vid_overlay_cap.height;
368dacca5f0SHans Verkuil vid_overlay_y++;
369dacca5f0SHans Verkuil }
370dacca5f0SHans Verkuil }
371dacca5f0SHans Verkuil vid_out_y += vid_out_int_part;
372dacca5f0SHans Verkuil vid_out_error += vid_out_fract_part;
373dacca5f0SHans Verkuil if (vid_out_error >= dev->loop_vid_cap.height / vdiv) {
374dacca5f0SHans Verkuil vid_out_error -= dev->loop_vid_cap.height / vdiv;
375dacca5f0SHans Verkuil vid_out_y++;
376dacca5f0SHans Verkuil }
377dacca5f0SHans Verkuil }
378dacca5f0SHans Verkuil
379dacca5f0SHans Verkuil if (!blank)
380dacca5f0SHans Verkuil return 0;
381dacca5f0SHans Verkuil for (; y < img_height; y += vdiv, vcapbuf += stride_cap)
382dacca5f0SHans Verkuil memcpy(vcapbuf, tpg->contrast_line[p], img_width);
383dacca5f0SHans Verkuil return 0;
384dacca5f0SHans Verkuil }
385dacca5f0SHans Verkuil
vivid_fillbuff(struct vivid_dev * dev,struct vivid_buffer * buf)386dacca5f0SHans Verkuil static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
387dacca5f0SHans Verkuil {
388dacca5f0SHans Verkuil struct tpg_data *tpg = &dev->tpg;
389dacca5f0SHans Verkuil unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1;
390dacca5f0SHans Verkuil unsigned line_height = 16 / factor;
391dacca5f0SHans Verkuil bool is_tv = vivid_is_sdtv_cap(dev);
392dacca5f0SHans Verkuil bool is_60hz = is_tv && (dev->std_cap[dev->input] & V4L2_STD_525_60);
393dacca5f0SHans Verkuil unsigned p;
394dacca5f0SHans Verkuil int line = 1;
395dacca5f0SHans Verkuil u8 *basep[TPG_MAX_PLANES][2];
396dacca5f0SHans Verkuil unsigned ms;
397dacca5f0SHans Verkuil char str[100];
398dacca5f0SHans Verkuil s32 gain;
399dacca5f0SHans Verkuil bool is_loop = false;
400dacca5f0SHans Verkuil
401dacca5f0SHans Verkuil if (dev->loop_video && dev->can_loop_video &&
402dacca5f0SHans Verkuil ((vivid_is_svid_cap(dev) &&
403dacca5f0SHans Verkuil !VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) ||
404dacca5f0SHans Verkuil (vivid_is_hdmi_cap(dev) &&
405dacca5f0SHans Verkuil !VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode[dev->input]))))
406dacca5f0SHans Verkuil is_loop = true;
407dacca5f0SHans Verkuil
408dacca5f0SHans Verkuil buf->vb.sequence = dev->vid_cap_seq_count;
409bb65e3d9SHans Verkuil v4l2_ctrl_s_ctrl(dev->ro_int32, buf->vb.sequence & 0xff);
410dacca5f0SHans Verkuil if (dev->field_cap == V4L2_FIELD_ALTERNATE) {
411dacca5f0SHans Verkuil /*
412dacca5f0SHans Verkuil * 60 Hz standards start with the bottom field, 50 Hz standards
413dacca5f0SHans Verkuil * with the top field. So if the 0-based seq_count is even,
414dacca5f0SHans Verkuil * then the field is TOP for 50 Hz and BOTTOM for 60 Hz
415dacca5f0SHans Verkuil * standards.
416dacca5f0SHans Verkuil */
417dacca5f0SHans Verkuil buf->vb.field = ((dev->vid_cap_seq_count & 1) ^ is_60hz) ?
418dacca5f0SHans Verkuil V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP;
419dacca5f0SHans Verkuil /*
420dacca5f0SHans Verkuil * The sequence counter counts frames, not fields. So divide
421dacca5f0SHans Verkuil * by two.
422dacca5f0SHans Verkuil */
423dacca5f0SHans Verkuil buf->vb.sequence /= 2;
424dacca5f0SHans Verkuil } else {
425dacca5f0SHans Verkuil buf->vb.field = dev->field_cap;
426dacca5f0SHans Verkuil }
427dacca5f0SHans Verkuil tpg_s_field(tpg, buf->vb.field,
428dacca5f0SHans Verkuil dev->field_cap == V4L2_FIELD_ALTERNATE);
429dacca5f0SHans Verkuil tpg_s_perc_fill_blank(tpg, dev->must_blank[buf->vb.vb2_buf.index]);
430dacca5f0SHans Verkuil
431dacca5f0SHans Verkuil vivid_precalc_copy_rects(dev);
432dacca5f0SHans Verkuil
433dacca5f0SHans Verkuil for (p = 0; p < tpg_g_planes(tpg); p++) {
434dacca5f0SHans Verkuil void *vbuf = plane_vaddr(tpg, buf, p,
435dacca5f0SHans Verkuil tpg->bytesperline, tpg->buf_height);
436dacca5f0SHans Verkuil
437dacca5f0SHans Verkuil /*
438dacca5f0SHans Verkuil * The first plane of a multiplanar format has a non-zero
439dacca5f0SHans Verkuil * data_offset. This helps testing whether the application
440dacca5f0SHans Verkuil * correctly supports non-zero data offsets.
441dacca5f0SHans Verkuil */
442dacca5f0SHans Verkuil if (p < tpg_g_buffers(tpg) && dev->fmt_cap->data_offset[p]) {
443dacca5f0SHans Verkuil memset(vbuf, dev->fmt_cap->data_offset[p] & 0xff,
444dacca5f0SHans Verkuil dev->fmt_cap->data_offset[p]);
445dacca5f0SHans Verkuil vbuf += dev->fmt_cap->data_offset[p];
446dacca5f0SHans Verkuil }
447dacca5f0SHans Verkuil tpg_calc_text_basep(tpg, basep, p, vbuf);
448dacca5f0SHans Verkuil if (!is_loop || vivid_copy_buffer(dev, p, vbuf, buf))
449dacca5f0SHans Verkuil tpg_fill_plane_buffer(tpg, vivid_get_std_cap(dev),
450dacca5f0SHans Verkuil p, vbuf);
451dacca5f0SHans Verkuil }
452dacca5f0SHans Verkuil dev->must_blank[buf->vb.vb2_buf.index] = false;
453dacca5f0SHans Verkuil
454dacca5f0SHans Verkuil /* Updates stream time, only update at the start of a new frame. */
455dacca5f0SHans Verkuil if (dev->field_cap != V4L2_FIELD_ALTERNATE ||
456dacca5f0SHans Verkuil (dev->vid_cap_seq_count & 1) == 0)
457dacca5f0SHans Verkuil dev->ms_vid_cap =
458dacca5f0SHans Verkuil jiffies_to_msecs(jiffies - dev->jiffies_vid_cap);
459dacca5f0SHans Verkuil
460dacca5f0SHans Verkuil ms = dev->ms_vid_cap;
461dacca5f0SHans Verkuil if (dev->osd_mode <= 1) {
462dacca5f0SHans Verkuil snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d %u%s",
463dacca5f0SHans Verkuil (ms / (60 * 60 * 1000)) % 24,
464dacca5f0SHans Verkuil (ms / (60 * 1000)) % 60,
465dacca5f0SHans Verkuil (ms / 1000) % 60,
466dacca5f0SHans Verkuil ms % 1000,
467dacca5f0SHans Verkuil buf->vb.sequence,
468dacca5f0SHans Verkuil (dev->field_cap == V4L2_FIELD_ALTERNATE) ?
469dacca5f0SHans Verkuil (buf->vb.field == V4L2_FIELD_TOP ?
470dacca5f0SHans Verkuil " top" : " bottom") : "");
471dacca5f0SHans Verkuil tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
472dacca5f0SHans Verkuil }
473dacca5f0SHans Verkuil if (dev->osd_mode == 0) {
474dacca5f0SHans Verkuil snprintf(str, sizeof(str), " %dx%d, input %d ",
475dacca5f0SHans Verkuil dev->src_rect.width, dev->src_rect.height, dev->input);
476dacca5f0SHans Verkuil tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
477dacca5f0SHans Verkuil
478dacca5f0SHans Verkuil gain = v4l2_ctrl_g_ctrl(dev->gain);
479dacca5f0SHans Verkuil mutex_lock(dev->ctrl_hdl_user_vid.lock);
480dacca5f0SHans Verkuil snprintf(str, sizeof(str),
481dacca5f0SHans Verkuil " brightness %3d, contrast %3d, saturation %3d, hue %d ",
482dacca5f0SHans Verkuil dev->brightness->cur.val,
483dacca5f0SHans Verkuil dev->contrast->cur.val,
484dacca5f0SHans Verkuil dev->saturation->cur.val,
485dacca5f0SHans Verkuil dev->hue->cur.val);
486dacca5f0SHans Verkuil tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
487dacca5f0SHans Verkuil snprintf(str, sizeof(str),
488dacca5f0SHans Verkuil " autogain %d, gain %3d, alpha 0x%02x ",
489dacca5f0SHans Verkuil dev->autogain->cur.val, gain, dev->alpha->cur.val);
490dacca5f0SHans Verkuil mutex_unlock(dev->ctrl_hdl_user_vid.lock);
491dacca5f0SHans Verkuil tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
492dacca5f0SHans Verkuil mutex_lock(dev->ctrl_hdl_user_aud.lock);
493dacca5f0SHans Verkuil snprintf(str, sizeof(str),
494dacca5f0SHans Verkuil " volume %3d, mute %d ",
495dacca5f0SHans Verkuil dev->volume->cur.val, dev->mute->cur.val);
496dacca5f0SHans Verkuil mutex_unlock(dev->ctrl_hdl_user_aud.lock);
497dacca5f0SHans Verkuil tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
498dacca5f0SHans Verkuil mutex_lock(dev->ctrl_hdl_user_gen.lock);
499bb65e3d9SHans Verkuil snprintf(str, sizeof(str), " int32 %d, ro_int32 %d, int64 %lld, bitmask %08x ",
500dacca5f0SHans Verkuil dev->int32->cur.val,
501bb65e3d9SHans Verkuil dev->ro_int32->cur.val,
502dacca5f0SHans Verkuil *dev->int64->p_cur.p_s64,
503dacca5f0SHans Verkuil dev->bitmask->cur.val);
504dacca5f0SHans Verkuil tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
505dacca5f0SHans Verkuil snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
506dacca5f0SHans Verkuil dev->boolean->cur.val,
507dacca5f0SHans Verkuil dev->menu->qmenu[dev->menu->cur.val],
508dacca5f0SHans Verkuil dev->string->p_cur.p_char);
509dacca5f0SHans Verkuil tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
510dacca5f0SHans Verkuil snprintf(str, sizeof(str), " integer_menu %lld, value %d ",
511dacca5f0SHans Verkuil dev->int_menu->qmenu_int[dev->int_menu->cur.val],
512dacca5f0SHans Verkuil dev->int_menu->cur.val);
513dacca5f0SHans Verkuil mutex_unlock(dev->ctrl_hdl_user_gen.lock);
514dacca5f0SHans Verkuil tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
515dacca5f0SHans Verkuil if (dev->button_pressed) {
516dacca5f0SHans Verkuil dev->button_pressed--;
517dacca5f0SHans Verkuil snprintf(str, sizeof(str), " button pressed!");
518dacca5f0SHans Verkuil tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
519dacca5f0SHans Verkuil }
520dacca5f0SHans Verkuil if (dev->osd[0]) {
521dacca5f0SHans Verkuil if (vivid_is_hdmi_cap(dev)) {
522dacca5f0SHans Verkuil snprintf(str, sizeof(str),
523dacca5f0SHans Verkuil " OSD \"%s\"", dev->osd);
524dacca5f0SHans Verkuil tpg_gen_text(tpg, basep, line++ * line_height,
525dacca5f0SHans Verkuil 16, str);
526dacca5f0SHans Verkuil }
527dacca5f0SHans Verkuil if (dev->osd_jiffies &&
528dacca5f0SHans Verkuil time_is_before_jiffies(dev->osd_jiffies + 5 * HZ)) {
529dacca5f0SHans Verkuil dev->osd[0] = 0;
530dacca5f0SHans Verkuil dev->osd_jiffies = 0;
531dacca5f0SHans Verkuil }
532dacca5f0SHans Verkuil }
533dacca5f0SHans Verkuil }
534dacca5f0SHans Verkuil }
535dacca5f0SHans Verkuil
vivid_cap_update_frame_period(struct vivid_dev * dev)536dacca5f0SHans Verkuil static void vivid_cap_update_frame_period(struct vivid_dev *dev)
537dacca5f0SHans Verkuil {
538dacca5f0SHans Verkuil u64 f_period;
539dacca5f0SHans Verkuil
540dacca5f0SHans Verkuil f_period = (u64)dev->timeperframe_vid_cap.numerator * 1000000000;
541dacca5f0SHans Verkuil if (WARN_ON(dev->timeperframe_vid_cap.denominator == 0))
542dacca5f0SHans Verkuil dev->timeperframe_vid_cap.denominator = 1;
543dacca5f0SHans Verkuil do_div(f_period, dev->timeperframe_vid_cap.denominator);
544dacca5f0SHans Verkuil if (dev->field_cap == V4L2_FIELD_ALTERNATE)
545dacca5f0SHans Verkuil f_period >>= 1;
546dacca5f0SHans Verkuil /*
547dacca5f0SHans Verkuil * If "End of Frame", then offset the exposure time by 0.9
548dacca5f0SHans Verkuil * of the frame period.
549dacca5f0SHans Verkuil */
550dacca5f0SHans Verkuil dev->cap_frame_eof_offset = f_period * 9;
551dacca5f0SHans Verkuil do_div(dev->cap_frame_eof_offset, 10);
552dacca5f0SHans Verkuil dev->cap_frame_period = f_period;
553dacca5f0SHans Verkuil }
554dacca5f0SHans Verkuil
vivid_thread_vid_cap_tick(struct vivid_dev * dev,int dropped_bufs)555dacca5f0SHans Verkuil static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev,
556dacca5f0SHans Verkuil int dropped_bufs)
557dacca5f0SHans Verkuil {
558dacca5f0SHans Verkuil struct vivid_buffer *vid_cap_buf = NULL;
559dacca5f0SHans Verkuil struct vivid_buffer *vbi_cap_buf = NULL;
560dacca5f0SHans Verkuil struct vivid_buffer *meta_cap_buf = NULL;
561dacca5f0SHans Verkuil u64 f_time = 0;
562dacca5f0SHans Verkuil
563dacca5f0SHans Verkuil dprintk(dev, 1, "Video Capture Thread Tick\n");
564dacca5f0SHans Verkuil
565dacca5f0SHans Verkuil while (dropped_bufs-- > 1)
566dacca5f0SHans Verkuil tpg_update_mv_count(&dev->tpg,
567dacca5f0SHans Verkuil dev->field_cap == V4L2_FIELD_NONE ||
568dacca5f0SHans Verkuil dev->field_cap == V4L2_FIELD_ALTERNATE);
569dacca5f0SHans Verkuil
570dacca5f0SHans Verkuil /* Drop a certain percentage of buffers. */
571dacca5f0SHans Verkuil if (dev->perc_dropped_buffers &&
5728032bf12SJason A. Donenfeld get_random_u32_below(100) < dev->perc_dropped_buffers)
573dacca5f0SHans Verkuil goto update_mv;
574dacca5f0SHans Verkuil
575dacca5f0SHans Verkuil spin_lock(&dev->slock);
576dacca5f0SHans Verkuil if (!list_empty(&dev->vid_cap_active)) {
577dacca5f0SHans Verkuil vid_cap_buf = list_entry(dev->vid_cap_active.next, struct vivid_buffer, list);
578dacca5f0SHans Verkuil list_del(&vid_cap_buf->list);
579dacca5f0SHans Verkuil }
580dacca5f0SHans Verkuil if (!list_empty(&dev->vbi_cap_active)) {
581dacca5f0SHans Verkuil if (dev->field_cap != V4L2_FIELD_ALTERNATE ||
582dacca5f0SHans Verkuil (dev->vbi_cap_seq_count & 1)) {
583dacca5f0SHans Verkuil vbi_cap_buf = list_entry(dev->vbi_cap_active.next,
584dacca5f0SHans Verkuil struct vivid_buffer, list);
585dacca5f0SHans Verkuil list_del(&vbi_cap_buf->list);
586dacca5f0SHans Verkuil }
587dacca5f0SHans Verkuil }
588dacca5f0SHans Verkuil if (!list_empty(&dev->meta_cap_active)) {
589dacca5f0SHans Verkuil meta_cap_buf = list_entry(dev->meta_cap_active.next,
590dacca5f0SHans Verkuil struct vivid_buffer, list);
591dacca5f0SHans Verkuil list_del(&meta_cap_buf->list);
592dacca5f0SHans Verkuil }
593dacca5f0SHans Verkuil
594dacca5f0SHans Verkuil spin_unlock(&dev->slock);
595dacca5f0SHans Verkuil
596dacca5f0SHans Verkuil if (!vid_cap_buf && !vbi_cap_buf && !meta_cap_buf)
597dacca5f0SHans Verkuil goto update_mv;
598dacca5f0SHans Verkuil
59957c1d5deSDeborah Brouwer f_time = ktime_get_ns() + dev->time_wrap_offset;
600dacca5f0SHans Verkuil
601dacca5f0SHans Verkuil if (vid_cap_buf) {
602dacca5f0SHans Verkuil v4l2_ctrl_request_setup(vid_cap_buf->vb.vb2_buf.req_obj.req,
603dacca5f0SHans Verkuil &dev->ctrl_hdl_vid_cap);
604dacca5f0SHans Verkuil /* Fill buffer */
605dacca5f0SHans Verkuil vivid_fillbuff(dev, vid_cap_buf);
606dacca5f0SHans Verkuil dprintk(dev, 1, "filled buffer %d\n",
607dacca5f0SHans Verkuil vid_cap_buf->vb.vb2_buf.index);
608dacca5f0SHans Verkuil
609dacca5f0SHans Verkuil v4l2_ctrl_request_complete(vid_cap_buf->vb.vb2_buf.req_obj.req,
610dacca5f0SHans Verkuil &dev->ctrl_hdl_vid_cap);
611dacca5f0SHans Verkuil vb2_buffer_done(&vid_cap_buf->vb.vb2_buf, dev->dqbuf_error ?
612dacca5f0SHans Verkuil VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
613dacca5f0SHans Verkuil dprintk(dev, 2, "vid_cap buffer %d done\n",
614dacca5f0SHans Verkuil vid_cap_buf->vb.vb2_buf.index);
615dacca5f0SHans Verkuil
616dacca5f0SHans Verkuil vid_cap_buf->vb.vb2_buf.timestamp = f_time;
617dacca5f0SHans Verkuil if (!dev->tstamp_src_is_soe)
618dacca5f0SHans Verkuil vid_cap_buf->vb.vb2_buf.timestamp += dev->cap_frame_eof_offset;
619dacca5f0SHans Verkuil }
620dacca5f0SHans Verkuil
621dacca5f0SHans Verkuil if (vbi_cap_buf) {
622dacca5f0SHans Verkuil u64 vbi_period;
623dacca5f0SHans Verkuil
624dacca5f0SHans Verkuil v4l2_ctrl_request_setup(vbi_cap_buf->vb.vb2_buf.req_obj.req,
625dacca5f0SHans Verkuil &dev->ctrl_hdl_vbi_cap);
6262d8b2a64STomi Valkeinen if (vbi_cap_buf->vb.vb2_buf.type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
627dacca5f0SHans Verkuil vivid_sliced_vbi_cap_process(dev, vbi_cap_buf);
628dacca5f0SHans Verkuil else
629dacca5f0SHans Verkuil vivid_raw_vbi_cap_process(dev, vbi_cap_buf);
630dacca5f0SHans Verkuil v4l2_ctrl_request_complete(vbi_cap_buf->vb.vb2_buf.req_obj.req,
631dacca5f0SHans Verkuil &dev->ctrl_hdl_vbi_cap);
632dacca5f0SHans Verkuil vb2_buffer_done(&vbi_cap_buf->vb.vb2_buf, dev->dqbuf_error ?
633dacca5f0SHans Verkuil VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
634dacca5f0SHans Verkuil dprintk(dev, 2, "vbi_cap %d done\n",
635dacca5f0SHans Verkuil vbi_cap_buf->vb.vb2_buf.index);
636dacca5f0SHans Verkuil
637dacca5f0SHans Verkuil /* If capturing a VBI, offset by 0.05 */
638dacca5f0SHans Verkuil vbi_period = dev->cap_frame_period * 5;
639dacca5f0SHans Verkuil do_div(vbi_period, 100);
640dacca5f0SHans Verkuil vbi_cap_buf->vb.vb2_buf.timestamp = f_time + dev->cap_frame_eof_offset + vbi_period;
641dacca5f0SHans Verkuil }
642dacca5f0SHans Verkuil
643dacca5f0SHans Verkuil if (meta_cap_buf) {
644dacca5f0SHans Verkuil v4l2_ctrl_request_setup(meta_cap_buf->vb.vb2_buf.req_obj.req,
645dacca5f0SHans Verkuil &dev->ctrl_hdl_meta_cap);
646dacca5f0SHans Verkuil vivid_meta_cap_fillbuff(dev, meta_cap_buf, f_time);
647dacca5f0SHans Verkuil v4l2_ctrl_request_complete(meta_cap_buf->vb.vb2_buf.req_obj.req,
648dacca5f0SHans Verkuil &dev->ctrl_hdl_meta_cap);
649dacca5f0SHans Verkuil vb2_buffer_done(&meta_cap_buf->vb.vb2_buf, dev->dqbuf_error ?
650dacca5f0SHans Verkuil VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
651dacca5f0SHans Verkuil dprintk(dev, 2, "meta_cap %d done\n",
652dacca5f0SHans Verkuil meta_cap_buf->vb.vb2_buf.index);
653dacca5f0SHans Verkuil meta_cap_buf->vb.vb2_buf.timestamp = f_time + dev->cap_frame_eof_offset;
654dacca5f0SHans Verkuil }
655dacca5f0SHans Verkuil
656dacca5f0SHans Verkuil dev->dqbuf_error = false;
657dacca5f0SHans Verkuil
658dacca5f0SHans Verkuil update_mv:
659dacca5f0SHans Verkuil /* Update the test pattern movement counters */
660dacca5f0SHans Verkuil tpg_update_mv_count(&dev->tpg, dev->field_cap == V4L2_FIELD_NONE ||
661dacca5f0SHans Verkuil dev->field_cap == V4L2_FIELD_ALTERNATE);
662dacca5f0SHans Verkuil }
663dacca5f0SHans Verkuil
vivid_thread_vid_cap(void * data)664dacca5f0SHans Verkuil static int vivid_thread_vid_cap(void *data)
665dacca5f0SHans Verkuil {
666dacca5f0SHans Verkuil struct vivid_dev *dev = data;
667dacca5f0SHans Verkuil u64 numerators_since_start;
668dacca5f0SHans Verkuil u64 buffers_since_start;
669dacca5f0SHans Verkuil u64 next_jiffies_since_start;
670dacca5f0SHans Verkuil unsigned long jiffies_since_start;
671dacca5f0SHans Verkuil unsigned long cur_jiffies;
672dacca5f0SHans Verkuil unsigned wait_jiffies;
673dacca5f0SHans Verkuil unsigned numerator;
674dacca5f0SHans Verkuil unsigned denominator;
675dacca5f0SHans Verkuil int dropped_bufs;
676dacca5f0SHans Verkuil
677dacca5f0SHans Verkuil dprintk(dev, 1, "Video Capture Thread Start\n");
678dacca5f0SHans Verkuil
679dacca5f0SHans Verkuil set_freezable();
680dacca5f0SHans Verkuil
681dacca5f0SHans Verkuil /* Resets frame counters */
682dacca5f0SHans Verkuil dev->cap_seq_offset = 0;
683dacca5f0SHans Verkuil dev->cap_seq_count = 0;
684dacca5f0SHans Verkuil dev->cap_seq_resync = false;
685dacca5f0SHans Verkuil dev->jiffies_vid_cap = jiffies;
686dacca5f0SHans Verkuil dev->cap_stream_start = ktime_get_ns();
68757c1d5deSDeborah Brouwer if (dev->time_wrap)
68857c1d5deSDeborah Brouwer dev->time_wrap_offset = dev->time_wrap - dev->cap_stream_start;
68957c1d5deSDeborah Brouwer else
69057c1d5deSDeborah Brouwer dev->time_wrap_offset = 0;
691dacca5f0SHans Verkuil vivid_cap_update_frame_period(dev);
692dacca5f0SHans Verkuil
693dacca5f0SHans Verkuil for (;;) {
694dacca5f0SHans Verkuil try_to_freeze();
695dacca5f0SHans Verkuil if (kthread_should_stop())
696dacca5f0SHans Verkuil break;
697dacca5f0SHans Verkuil
698dacca5f0SHans Verkuil if (!mutex_trylock(&dev->mutex)) {
6996e8c09bbSHans Verkuil schedule();
700dacca5f0SHans Verkuil continue;
701dacca5f0SHans Verkuil }
702dacca5f0SHans Verkuil
703dacca5f0SHans Verkuil cur_jiffies = jiffies;
704dacca5f0SHans Verkuil if (dev->cap_seq_resync) {
705dacca5f0SHans Verkuil dev->jiffies_vid_cap = cur_jiffies;
706dacca5f0SHans Verkuil dev->cap_seq_offset = dev->cap_seq_count + 1;
707dacca5f0SHans Verkuil dev->cap_seq_count = 0;
708dacca5f0SHans Verkuil dev->cap_stream_start += dev->cap_frame_period *
709dacca5f0SHans Verkuil dev->cap_seq_offset;
710dacca5f0SHans Verkuil vivid_cap_update_frame_period(dev);
711dacca5f0SHans Verkuil dev->cap_seq_resync = false;
712dacca5f0SHans Verkuil }
713dacca5f0SHans Verkuil numerator = dev->timeperframe_vid_cap.numerator;
714dacca5f0SHans Verkuil denominator = dev->timeperframe_vid_cap.denominator;
715dacca5f0SHans Verkuil
716dacca5f0SHans Verkuil if (dev->field_cap == V4L2_FIELD_ALTERNATE)
717dacca5f0SHans Verkuil denominator *= 2;
718dacca5f0SHans Verkuil
719dacca5f0SHans Verkuil /* Calculate the number of jiffies since we started streaming */
720dacca5f0SHans Verkuil jiffies_since_start = cur_jiffies - dev->jiffies_vid_cap;
721dacca5f0SHans Verkuil /* Get the number of buffers streamed since the start */
722dacca5f0SHans Verkuil buffers_since_start = (u64)jiffies_since_start * denominator +
723dacca5f0SHans Verkuil (HZ * numerator) / 2;
724dacca5f0SHans Verkuil do_div(buffers_since_start, HZ * numerator);
725dacca5f0SHans Verkuil
726dacca5f0SHans Verkuil /*
727dacca5f0SHans Verkuil * After more than 0xf0000000 (rounded down to a multiple of
728dacca5f0SHans Verkuil * 'jiffies-per-day' to ease jiffies_to_msecs calculation)
729dacca5f0SHans Verkuil * jiffies have passed since we started streaming reset the
730dacca5f0SHans Verkuil * counters and keep track of the sequence offset.
731dacca5f0SHans Verkuil */
732dacca5f0SHans Verkuil if (jiffies_since_start > JIFFIES_RESYNC) {
733dacca5f0SHans Verkuil dev->jiffies_vid_cap = cur_jiffies;
734dacca5f0SHans Verkuil dev->cap_seq_offset = buffers_since_start;
735dacca5f0SHans Verkuil buffers_since_start = 0;
736dacca5f0SHans Verkuil }
737dacca5f0SHans Verkuil dropped_bufs = buffers_since_start + dev->cap_seq_offset - dev->cap_seq_count;
738dacca5f0SHans Verkuil dev->cap_seq_count = buffers_since_start + dev->cap_seq_offset;
739dacca5f0SHans Verkuil dev->vid_cap_seq_count = dev->cap_seq_count - dev->vid_cap_seq_start;
740dacca5f0SHans Verkuil dev->vbi_cap_seq_count = dev->cap_seq_count - dev->vbi_cap_seq_start;
741dacca5f0SHans Verkuil dev->meta_cap_seq_count = dev->cap_seq_count - dev->meta_cap_seq_start;
742dacca5f0SHans Verkuil
743dacca5f0SHans Verkuil vivid_thread_vid_cap_tick(dev, dropped_bufs);
744dacca5f0SHans Verkuil
745dacca5f0SHans Verkuil /*
746dacca5f0SHans Verkuil * Calculate the number of 'numerators' streamed since we started,
747dacca5f0SHans Verkuil * including the current buffer.
748dacca5f0SHans Verkuil */
749dacca5f0SHans Verkuil numerators_since_start = ++buffers_since_start * numerator;
750dacca5f0SHans Verkuil
751dacca5f0SHans Verkuil /* And the number of jiffies since we started */
752dacca5f0SHans Verkuil jiffies_since_start = jiffies - dev->jiffies_vid_cap;
753dacca5f0SHans Verkuil
754dacca5f0SHans Verkuil mutex_unlock(&dev->mutex);
755dacca5f0SHans Verkuil
756dacca5f0SHans Verkuil /*
757dacca5f0SHans Verkuil * Calculate when that next buffer is supposed to start
758dacca5f0SHans Verkuil * in jiffies since we started streaming.
759dacca5f0SHans Verkuil */
760dacca5f0SHans Verkuil next_jiffies_since_start = numerators_since_start * HZ +
761dacca5f0SHans Verkuil denominator / 2;
762dacca5f0SHans Verkuil do_div(next_jiffies_since_start, denominator);
763dacca5f0SHans Verkuil /* If it is in the past, then just schedule asap */
764dacca5f0SHans Verkuil if (next_jiffies_since_start < jiffies_since_start)
765dacca5f0SHans Verkuil next_jiffies_since_start = jiffies_since_start;
766dacca5f0SHans Verkuil
767dacca5f0SHans Verkuil wait_jiffies = next_jiffies_since_start - jiffies_since_start;
76884db51f5SWang Qing while (time_is_after_jiffies(cur_jiffies + wait_jiffies) &&
7696e8c09bbSHans Verkuil !kthread_should_stop())
7706e8c09bbSHans Verkuil schedule();
771dacca5f0SHans Verkuil }
772dacca5f0SHans Verkuil dprintk(dev, 1, "Video Capture Thread End\n");
773dacca5f0SHans Verkuil return 0;
774dacca5f0SHans Verkuil }
775dacca5f0SHans Verkuil
vivid_grab_controls(struct vivid_dev * dev,bool grab)776dacca5f0SHans Verkuil static void vivid_grab_controls(struct vivid_dev *dev, bool grab)
777dacca5f0SHans Verkuil {
778dacca5f0SHans Verkuil v4l2_ctrl_grab(dev->ctrl_has_crop_cap, grab);
779dacca5f0SHans Verkuil v4l2_ctrl_grab(dev->ctrl_has_compose_cap, grab);
780dacca5f0SHans Verkuil v4l2_ctrl_grab(dev->ctrl_has_scaler_cap, grab);
781dacca5f0SHans Verkuil }
782dacca5f0SHans Verkuil
vivid_start_generating_vid_cap(struct vivid_dev * dev,bool * pstreaming)783dacca5f0SHans Verkuil int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming)
784dacca5f0SHans Verkuil {
785dacca5f0SHans Verkuil dprintk(dev, 1, "%s\n", __func__);
786dacca5f0SHans Verkuil
787dacca5f0SHans Verkuil if (dev->kthread_vid_cap) {
788dacca5f0SHans Verkuil u32 seq_count = dev->cap_seq_count + dev->seq_wrap * 128;
789dacca5f0SHans Verkuil
790dacca5f0SHans Verkuil if (pstreaming == &dev->vid_cap_streaming)
791dacca5f0SHans Verkuil dev->vid_cap_seq_start = seq_count;
792dacca5f0SHans Verkuil else if (pstreaming == &dev->vbi_cap_streaming)
793dacca5f0SHans Verkuil dev->vbi_cap_seq_start = seq_count;
794dacca5f0SHans Verkuil else
795dacca5f0SHans Verkuil dev->meta_cap_seq_start = seq_count;
796dacca5f0SHans Verkuil *pstreaming = true;
797dacca5f0SHans Verkuil return 0;
798dacca5f0SHans Verkuil }
799dacca5f0SHans Verkuil
800dacca5f0SHans Verkuil /* Resets frame counters */
801dacca5f0SHans Verkuil tpg_init_mv_count(&dev->tpg);
802dacca5f0SHans Verkuil
803dacca5f0SHans Verkuil dev->vid_cap_seq_start = dev->seq_wrap * 128;
804dacca5f0SHans Verkuil dev->vbi_cap_seq_start = dev->seq_wrap * 128;
805dacca5f0SHans Verkuil dev->meta_cap_seq_start = dev->seq_wrap * 128;
806dacca5f0SHans Verkuil
807dacca5f0SHans Verkuil dev->kthread_vid_cap = kthread_run(vivid_thread_vid_cap, dev,
808dacca5f0SHans Verkuil "%s-vid-cap", dev->v4l2_dev.name);
809dacca5f0SHans Verkuil
810dacca5f0SHans Verkuil if (IS_ERR(dev->kthread_vid_cap)) {
811dacca5f0SHans Verkuil int err = PTR_ERR(dev->kthread_vid_cap);
812dacca5f0SHans Verkuil
813dacca5f0SHans Verkuil dev->kthread_vid_cap = NULL;
814dacca5f0SHans Verkuil v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
815dacca5f0SHans Verkuil return err;
816dacca5f0SHans Verkuil }
817dacca5f0SHans Verkuil *pstreaming = true;
818dacca5f0SHans Verkuil vivid_grab_controls(dev, true);
819dacca5f0SHans Verkuil
820dacca5f0SHans Verkuil dprintk(dev, 1, "returning from %s\n", __func__);
821dacca5f0SHans Verkuil return 0;
822dacca5f0SHans Verkuil }
823dacca5f0SHans Verkuil
vivid_stop_generating_vid_cap(struct vivid_dev * dev,bool * pstreaming)824dacca5f0SHans Verkuil void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming)
825dacca5f0SHans Verkuil {
826dacca5f0SHans Verkuil dprintk(dev, 1, "%s\n", __func__);
827dacca5f0SHans Verkuil
828dacca5f0SHans Verkuil if (dev->kthread_vid_cap == NULL)
829dacca5f0SHans Verkuil return;
830dacca5f0SHans Verkuil
831dacca5f0SHans Verkuil *pstreaming = false;
832dacca5f0SHans Verkuil if (pstreaming == &dev->vid_cap_streaming) {
833dacca5f0SHans Verkuil /* Release all active buffers */
834dacca5f0SHans Verkuil while (!list_empty(&dev->vid_cap_active)) {
835dacca5f0SHans Verkuil struct vivid_buffer *buf;
836dacca5f0SHans Verkuil
837dacca5f0SHans Verkuil buf = list_entry(dev->vid_cap_active.next,
838dacca5f0SHans Verkuil struct vivid_buffer, list);
839dacca5f0SHans Verkuil list_del(&buf->list);
840dacca5f0SHans Verkuil v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
841dacca5f0SHans Verkuil &dev->ctrl_hdl_vid_cap);
842dacca5f0SHans Verkuil vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
843dacca5f0SHans Verkuil dprintk(dev, 2, "vid_cap buffer %d done\n",
844dacca5f0SHans Verkuil buf->vb.vb2_buf.index);
845dacca5f0SHans Verkuil }
846dacca5f0SHans Verkuil }
847dacca5f0SHans Verkuil
848dacca5f0SHans Verkuil if (pstreaming == &dev->vbi_cap_streaming) {
849dacca5f0SHans Verkuil while (!list_empty(&dev->vbi_cap_active)) {
850dacca5f0SHans Verkuil struct vivid_buffer *buf;
851dacca5f0SHans Verkuil
852dacca5f0SHans Verkuil buf = list_entry(dev->vbi_cap_active.next,
853dacca5f0SHans Verkuil struct vivid_buffer, list);
854dacca5f0SHans Verkuil list_del(&buf->list);
855dacca5f0SHans Verkuil v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
856dacca5f0SHans Verkuil &dev->ctrl_hdl_vbi_cap);
857dacca5f0SHans Verkuil vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
858dacca5f0SHans Verkuil dprintk(dev, 2, "vbi_cap buffer %d done\n",
859dacca5f0SHans Verkuil buf->vb.vb2_buf.index);
860dacca5f0SHans Verkuil }
861dacca5f0SHans Verkuil }
862dacca5f0SHans Verkuil
863dacca5f0SHans Verkuil if (pstreaming == &dev->meta_cap_streaming) {
864dacca5f0SHans Verkuil while (!list_empty(&dev->meta_cap_active)) {
865dacca5f0SHans Verkuil struct vivid_buffer *buf;
866dacca5f0SHans Verkuil
867dacca5f0SHans Verkuil buf = list_entry(dev->meta_cap_active.next,
868dacca5f0SHans Verkuil struct vivid_buffer, list);
869dacca5f0SHans Verkuil list_del(&buf->list);
870dacca5f0SHans Verkuil v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
871dacca5f0SHans Verkuil &dev->ctrl_hdl_meta_cap);
872dacca5f0SHans Verkuil vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
873dacca5f0SHans Verkuil dprintk(dev, 2, "meta_cap buffer %d done\n",
874dacca5f0SHans Verkuil buf->vb.vb2_buf.index);
875dacca5f0SHans Verkuil }
876dacca5f0SHans Verkuil }
877dacca5f0SHans Verkuil
878dacca5f0SHans Verkuil if (dev->vid_cap_streaming || dev->vbi_cap_streaming ||
879dacca5f0SHans Verkuil dev->meta_cap_streaming)
880dacca5f0SHans Verkuil return;
881dacca5f0SHans Verkuil
882dacca5f0SHans Verkuil /* shutdown control thread */
883dacca5f0SHans Verkuil vivid_grab_controls(dev, false);
884dacca5f0SHans Verkuil kthread_stop(dev->kthread_vid_cap);
885dacca5f0SHans Verkuil dev->kthread_vid_cap = NULL;
886dacca5f0SHans Verkuil }
887