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