162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * vivid-kthread-cap.h - video/vbi capture thread support functions. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/errno.h> 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/sched.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci#include <linux/font.h> 1562306a36Sopenharmony_ci#include <linux/mutex.h> 1662306a36Sopenharmony_ci#include <linux/videodev2.h> 1762306a36Sopenharmony_ci#include <linux/kthread.h> 1862306a36Sopenharmony_ci#include <linux/freezer.h> 1962306a36Sopenharmony_ci#include <linux/random.h> 2062306a36Sopenharmony_ci#include <linux/v4l2-dv-timings.h> 2162306a36Sopenharmony_ci#include <linux/jiffies.h> 2262306a36Sopenharmony_ci#include <asm/div64.h> 2362306a36Sopenharmony_ci#include <media/videobuf2-vmalloc.h> 2462306a36Sopenharmony_ci#include <media/v4l2-dv-timings.h> 2562306a36Sopenharmony_ci#include <media/v4l2-ioctl.h> 2662306a36Sopenharmony_ci#include <media/v4l2-fh.h> 2762306a36Sopenharmony_ci#include <media/v4l2-event.h> 2862306a36Sopenharmony_ci#include <media/v4l2-rect.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include "vivid-core.h" 3162306a36Sopenharmony_ci#include "vivid-vid-common.h" 3262306a36Sopenharmony_ci#include "vivid-vid-cap.h" 3362306a36Sopenharmony_ci#include "vivid-vid-out.h" 3462306a36Sopenharmony_ci#include "vivid-radio-common.h" 3562306a36Sopenharmony_ci#include "vivid-radio-rx.h" 3662306a36Sopenharmony_ci#include "vivid-radio-tx.h" 3762306a36Sopenharmony_ci#include "vivid-sdr-cap.h" 3862306a36Sopenharmony_ci#include "vivid-vbi-cap.h" 3962306a36Sopenharmony_ci#include "vivid-vbi-out.h" 4062306a36Sopenharmony_ci#include "vivid-osd.h" 4162306a36Sopenharmony_ci#include "vivid-ctrls.h" 4262306a36Sopenharmony_ci#include "vivid-kthread-cap.h" 4362306a36Sopenharmony_ci#include "vivid-meta-cap.h" 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic inline v4l2_std_id vivid_get_std_cap(const struct vivid_dev *dev) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci if (vivid_is_sdtv_cap(dev)) 4862306a36Sopenharmony_ci return dev->std_cap[dev->input]; 4962306a36Sopenharmony_ci return 0; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic void copy_pix(struct vivid_dev *dev, int win_y, int win_x, 5362306a36Sopenharmony_ci u16 *cap, const u16 *osd) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci u16 out; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci out = *cap; 5862306a36Sopenharmony_ci *cap = *osd; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_CHROMAKEY) && 6162306a36Sopenharmony_ci *osd != dev->chromakey_out) 6262306a36Sopenharmony_ci return; 6362306a36Sopenharmony_ci if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) && 6462306a36Sopenharmony_ci out == dev->chromakey_out) 6562306a36Sopenharmony_ci return; 6662306a36Sopenharmony_ci if (dev->fmt_cap->alpha_mask) { 6762306a36Sopenharmony_ci if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) && 6862306a36Sopenharmony_ci dev->global_alpha_out) 6962306a36Sopenharmony_ci return; 7062306a36Sopenharmony_ci if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) && 7162306a36Sopenharmony_ci *cap & dev->fmt_cap->alpha_mask) 7262306a36Sopenharmony_ci return; 7362306a36Sopenharmony_ci if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_LOCAL_INV_ALPHA) && 7462306a36Sopenharmony_ci !(*cap & dev->fmt_cap->alpha_mask)) 7562306a36Sopenharmony_ci return; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci *cap = out; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic void blend_line(struct vivid_dev *dev, unsigned y_offset, unsigned x_offset, 8162306a36Sopenharmony_ci u8 *vcapbuf, const u8 *vosdbuf, 8262306a36Sopenharmony_ci unsigned width, unsigned pixsize) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci unsigned x; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci for (x = 0; x < width; x++, vcapbuf += pixsize, vosdbuf += pixsize) { 8762306a36Sopenharmony_ci copy_pix(dev, y_offset, x_offset + x, 8862306a36Sopenharmony_ci (u16 *)vcapbuf, (const u16 *)vosdbuf); 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic void scale_line(const u8 *src, u8 *dst, unsigned srcw, unsigned dstw, unsigned twopixsize) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci /* Coarse scaling with Bresenham */ 9562306a36Sopenharmony_ci unsigned int_part; 9662306a36Sopenharmony_ci unsigned fract_part; 9762306a36Sopenharmony_ci unsigned src_x = 0; 9862306a36Sopenharmony_ci unsigned error = 0; 9962306a36Sopenharmony_ci unsigned x; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* 10262306a36Sopenharmony_ci * We always combine two pixels to prevent color bleed in the packed 10362306a36Sopenharmony_ci * yuv case. 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_ci srcw /= 2; 10662306a36Sopenharmony_ci dstw /= 2; 10762306a36Sopenharmony_ci int_part = srcw / dstw; 10862306a36Sopenharmony_ci fract_part = srcw % dstw; 10962306a36Sopenharmony_ci for (x = 0; x < dstw; x++, dst += twopixsize) { 11062306a36Sopenharmony_ci memcpy(dst, src + src_x * twopixsize, twopixsize); 11162306a36Sopenharmony_ci src_x += int_part; 11262306a36Sopenharmony_ci error += fract_part; 11362306a36Sopenharmony_ci if (error >= dstw) { 11462306a36Sopenharmony_ci error -= dstw; 11562306a36Sopenharmony_ci src_x++; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/* 12162306a36Sopenharmony_ci * Precalculate the rectangles needed to perform video looping: 12262306a36Sopenharmony_ci * 12362306a36Sopenharmony_ci * The nominal pipeline is that the video output buffer is cropped by 12462306a36Sopenharmony_ci * crop_out, scaled to compose_out, overlaid with the output overlay, 12562306a36Sopenharmony_ci * cropped on the capture side by crop_cap and scaled again to the video 12662306a36Sopenharmony_ci * capture buffer using compose_cap. 12762306a36Sopenharmony_ci * 12862306a36Sopenharmony_ci * To keep things efficient we calculate the intersection of compose_out 12962306a36Sopenharmony_ci * and crop_cap (since that's the only part of the video that will 13062306a36Sopenharmony_ci * actually end up in the capture buffer), determine which part of the 13162306a36Sopenharmony_ci * video output buffer that is and which part of the video capture buffer 13262306a36Sopenharmony_ci * so we can scale the video straight from the output buffer to the capture 13362306a36Sopenharmony_ci * buffer without any intermediate steps. 13462306a36Sopenharmony_ci * 13562306a36Sopenharmony_ci * If we need to deal with an output overlay, then there is no choice and 13662306a36Sopenharmony_ci * that intermediate step still has to be taken. For the output overlay 13762306a36Sopenharmony_ci * support we calculate the intersection of the framebuffer and the overlay 13862306a36Sopenharmony_ci * window (which may be partially or wholly outside of the framebuffer 13962306a36Sopenharmony_ci * itself) and the intersection of that with loop_vid_copy (i.e. the part of 14062306a36Sopenharmony_ci * the actual looped video that will be overlaid). The result is calculated 14162306a36Sopenharmony_ci * both in framebuffer coordinates (loop_fb_copy) and compose_out coordinates 14262306a36Sopenharmony_ci * (loop_vid_overlay). Finally calculate the part of the capture buffer that 14362306a36Sopenharmony_ci * will receive that overlaid video. 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_cistatic void vivid_precalc_copy_rects(struct vivid_dev *dev) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci /* Framebuffer rectangle */ 14862306a36Sopenharmony_ci struct v4l2_rect r_fb = { 14962306a36Sopenharmony_ci 0, 0, dev->display_width, dev->display_height 15062306a36Sopenharmony_ci }; 15162306a36Sopenharmony_ci /* Overlay window rectangle in framebuffer coordinates */ 15262306a36Sopenharmony_ci struct v4l2_rect r_overlay = { 15362306a36Sopenharmony_ci dev->overlay_out_left, dev->overlay_out_top, 15462306a36Sopenharmony_ci dev->compose_out.width, dev->compose_out.height 15562306a36Sopenharmony_ci }; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci v4l2_rect_intersect(&dev->loop_vid_copy, &dev->crop_cap, &dev->compose_out); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci dev->loop_vid_out = dev->loop_vid_copy; 16062306a36Sopenharmony_ci v4l2_rect_scale(&dev->loop_vid_out, &dev->compose_out, &dev->crop_out); 16162306a36Sopenharmony_ci dev->loop_vid_out.left += dev->crop_out.left; 16262306a36Sopenharmony_ci dev->loop_vid_out.top += dev->crop_out.top; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci dev->loop_vid_cap = dev->loop_vid_copy; 16562306a36Sopenharmony_ci v4l2_rect_scale(&dev->loop_vid_cap, &dev->crop_cap, &dev->compose_cap); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci dprintk(dev, 1, 16862306a36Sopenharmony_ci "loop_vid_copy: %dx%d@%dx%d loop_vid_out: %dx%d@%dx%d loop_vid_cap: %dx%d@%dx%d\n", 16962306a36Sopenharmony_ci dev->loop_vid_copy.width, dev->loop_vid_copy.height, 17062306a36Sopenharmony_ci dev->loop_vid_copy.left, dev->loop_vid_copy.top, 17162306a36Sopenharmony_ci dev->loop_vid_out.width, dev->loop_vid_out.height, 17262306a36Sopenharmony_ci dev->loop_vid_out.left, dev->loop_vid_out.top, 17362306a36Sopenharmony_ci dev->loop_vid_cap.width, dev->loop_vid_cap.height, 17462306a36Sopenharmony_ci dev->loop_vid_cap.left, dev->loop_vid_cap.top); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci v4l2_rect_intersect(&r_overlay, &r_fb, &r_overlay); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* shift r_overlay to the same origin as compose_out */ 17962306a36Sopenharmony_ci r_overlay.left += dev->compose_out.left - dev->overlay_out_left; 18062306a36Sopenharmony_ci r_overlay.top += dev->compose_out.top - dev->overlay_out_top; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci v4l2_rect_intersect(&dev->loop_vid_overlay, &r_overlay, &dev->loop_vid_copy); 18362306a36Sopenharmony_ci dev->loop_fb_copy = dev->loop_vid_overlay; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* shift dev->loop_fb_copy back again to the fb origin */ 18662306a36Sopenharmony_ci dev->loop_fb_copy.left -= dev->compose_out.left - dev->overlay_out_left; 18762306a36Sopenharmony_ci dev->loop_fb_copy.top -= dev->compose_out.top - dev->overlay_out_top; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci dev->loop_vid_overlay_cap = dev->loop_vid_overlay; 19062306a36Sopenharmony_ci v4l2_rect_scale(&dev->loop_vid_overlay_cap, &dev->crop_cap, &dev->compose_cap); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci dprintk(dev, 1, 19362306a36Sopenharmony_ci "loop_fb_copy: %dx%d@%dx%d loop_vid_overlay: %dx%d@%dx%d loop_vid_overlay_cap: %dx%d@%dx%d\n", 19462306a36Sopenharmony_ci dev->loop_fb_copy.width, dev->loop_fb_copy.height, 19562306a36Sopenharmony_ci dev->loop_fb_copy.left, dev->loop_fb_copy.top, 19662306a36Sopenharmony_ci dev->loop_vid_overlay.width, dev->loop_vid_overlay.height, 19762306a36Sopenharmony_ci dev->loop_vid_overlay.left, dev->loop_vid_overlay.top, 19862306a36Sopenharmony_ci dev->loop_vid_overlay_cap.width, dev->loop_vid_overlay_cap.height, 19962306a36Sopenharmony_ci dev->loop_vid_overlay_cap.left, dev->loop_vid_overlay_cap.top); 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic void *plane_vaddr(struct tpg_data *tpg, struct vivid_buffer *buf, 20362306a36Sopenharmony_ci unsigned p, unsigned bpl[TPG_MAX_PLANES], unsigned h) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci unsigned i; 20662306a36Sopenharmony_ci void *vbuf; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (p == 0 || tpg_g_buffers(tpg) > 1) 20962306a36Sopenharmony_ci return vb2_plane_vaddr(&buf->vb.vb2_buf, p); 21062306a36Sopenharmony_ci vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); 21162306a36Sopenharmony_ci for (i = 0; i < p; i++) 21262306a36Sopenharmony_ci vbuf += bpl[i] * h / tpg->vdownsampling[i]; 21362306a36Sopenharmony_ci return vbuf; 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic noinline_for_stack int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, 21762306a36Sopenharmony_ci u8 *vcapbuf, struct vivid_buffer *vid_cap_buf) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci bool blank = dev->must_blank[vid_cap_buf->vb.vb2_buf.index]; 22062306a36Sopenharmony_ci struct tpg_data *tpg = &dev->tpg; 22162306a36Sopenharmony_ci struct vivid_buffer *vid_out_buf = NULL; 22262306a36Sopenharmony_ci unsigned vdiv = dev->fmt_out->vdownsampling[p]; 22362306a36Sopenharmony_ci unsigned twopixsize = tpg_g_twopixelsize(tpg, p); 22462306a36Sopenharmony_ci unsigned img_width = tpg_hdiv(tpg, p, dev->compose_cap.width); 22562306a36Sopenharmony_ci unsigned img_height = dev->compose_cap.height; 22662306a36Sopenharmony_ci unsigned stride_cap = tpg->bytesperline[p]; 22762306a36Sopenharmony_ci unsigned stride_out = dev->bytesperline_out[p]; 22862306a36Sopenharmony_ci unsigned stride_osd = dev->display_byte_stride; 22962306a36Sopenharmony_ci unsigned hmax = (img_height * tpg->perc_fill) / 100; 23062306a36Sopenharmony_ci u8 *voutbuf; 23162306a36Sopenharmony_ci u8 *vosdbuf = NULL; 23262306a36Sopenharmony_ci unsigned y; 23362306a36Sopenharmony_ci bool blend = dev->fbuf_out_flags; 23462306a36Sopenharmony_ci /* Coarse scaling with Bresenham */ 23562306a36Sopenharmony_ci unsigned vid_out_int_part; 23662306a36Sopenharmony_ci unsigned vid_out_fract_part; 23762306a36Sopenharmony_ci unsigned vid_out_y = 0; 23862306a36Sopenharmony_ci unsigned vid_out_error = 0; 23962306a36Sopenharmony_ci unsigned vid_overlay_int_part = 0; 24062306a36Sopenharmony_ci unsigned vid_overlay_fract_part = 0; 24162306a36Sopenharmony_ci unsigned vid_overlay_y = 0; 24262306a36Sopenharmony_ci unsigned vid_overlay_error = 0; 24362306a36Sopenharmony_ci unsigned vid_cap_left = tpg_hdiv(tpg, p, dev->loop_vid_cap.left); 24462306a36Sopenharmony_ci unsigned vid_cap_right; 24562306a36Sopenharmony_ci bool quick; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci vid_out_int_part = dev->loop_vid_out.height / dev->loop_vid_cap.height; 24862306a36Sopenharmony_ci vid_out_fract_part = dev->loop_vid_out.height % dev->loop_vid_cap.height; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (!list_empty(&dev->vid_out_active)) 25162306a36Sopenharmony_ci vid_out_buf = list_entry(dev->vid_out_active.next, 25262306a36Sopenharmony_ci struct vivid_buffer, list); 25362306a36Sopenharmony_ci if (vid_out_buf == NULL) 25462306a36Sopenharmony_ci return -ENODATA; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci vid_cap_buf->vb.field = vid_out_buf->vb.field; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci voutbuf = plane_vaddr(tpg, vid_out_buf, p, 25962306a36Sopenharmony_ci dev->bytesperline_out, dev->fmt_out_rect.height); 26062306a36Sopenharmony_ci if (p < dev->fmt_out->buffers) 26162306a36Sopenharmony_ci voutbuf += vid_out_buf->vb.vb2_buf.planes[p].data_offset; 26262306a36Sopenharmony_ci voutbuf += tpg_hdiv(tpg, p, dev->loop_vid_out.left) + 26362306a36Sopenharmony_ci (dev->loop_vid_out.top / vdiv) * stride_out; 26462306a36Sopenharmony_ci vcapbuf += tpg_hdiv(tpg, p, dev->compose_cap.left) + 26562306a36Sopenharmony_ci (dev->compose_cap.top / vdiv) * stride_cap; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (dev->loop_vid_copy.width == 0 || dev->loop_vid_copy.height == 0) { 26862306a36Sopenharmony_ci /* 26962306a36Sopenharmony_ci * If there is nothing to copy, then just fill the capture window 27062306a36Sopenharmony_ci * with black. 27162306a36Sopenharmony_ci */ 27262306a36Sopenharmony_ci for (y = 0; y < hmax / vdiv; y++, vcapbuf += stride_cap) 27362306a36Sopenharmony_ci memcpy(vcapbuf, tpg->black_line[p], img_width); 27462306a36Sopenharmony_ci return 0; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (dev->overlay_out_enabled && 27862306a36Sopenharmony_ci dev->loop_vid_overlay.width && dev->loop_vid_overlay.height) { 27962306a36Sopenharmony_ci vosdbuf = dev->video_vbase; 28062306a36Sopenharmony_ci vosdbuf += (dev->loop_fb_copy.left * twopixsize) / 2 + 28162306a36Sopenharmony_ci dev->loop_fb_copy.top * stride_osd; 28262306a36Sopenharmony_ci vid_overlay_int_part = dev->loop_vid_overlay.height / 28362306a36Sopenharmony_ci dev->loop_vid_overlay_cap.height; 28462306a36Sopenharmony_ci vid_overlay_fract_part = dev->loop_vid_overlay.height % 28562306a36Sopenharmony_ci dev->loop_vid_overlay_cap.height; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci vid_cap_right = tpg_hdiv(tpg, p, dev->loop_vid_cap.left + dev->loop_vid_cap.width); 28962306a36Sopenharmony_ci /* quick is true if no video scaling is needed */ 29062306a36Sopenharmony_ci quick = dev->loop_vid_out.width == dev->loop_vid_cap.width; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci dev->cur_scaled_line = dev->loop_vid_out.height; 29362306a36Sopenharmony_ci for (y = 0; y < hmax; y += vdiv, vcapbuf += stride_cap) { 29462306a36Sopenharmony_ci /* osdline is true if this line requires overlay blending */ 29562306a36Sopenharmony_ci bool osdline = vosdbuf && y >= dev->loop_vid_overlay_cap.top && 29662306a36Sopenharmony_ci y < dev->loop_vid_overlay_cap.top + dev->loop_vid_overlay_cap.height; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci /* 29962306a36Sopenharmony_ci * If this line of the capture buffer doesn't get any video, then 30062306a36Sopenharmony_ci * just fill with black. 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_ci if (y < dev->loop_vid_cap.top || 30362306a36Sopenharmony_ci y >= dev->loop_vid_cap.top + dev->loop_vid_cap.height) { 30462306a36Sopenharmony_ci memcpy(vcapbuf, tpg->black_line[p], img_width); 30562306a36Sopenharmony_ci continue; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* fill the left border with black */ 30962306a36Sopenharmony_ci if (dev->loop_vid_cap.left) 31062306a36Sopenharmony_ci memcpy(vcapbuf, tpg->black_line[p], vid_cap_left); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* fill the right border with black */ 31362306a36Sopenharmony_ci if (vid_cap_right < img_width) 31462306a36Sopenharmony_ci memcpy(vcapbuf + vid_cap_right, tpg->black_line[p], 31562306a36Sopenharmony_ci img_width - vid_cap_right); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (quick && !osdline) { 31862306a36Sopenharmony_ci memcpy(vcapbuf + vid_cap_left, 31962306a36Sopenharmony_ci voutbuf + vid_out_y * stride_out, 32062306a36Sopenharmony_ci tpg_hdiv(tpg, p, dev->loop_vid_cap.width)); 32162306a36Sopenharmony_ci goto update_vid_out_y; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci if (dev->cur_scaled_line == vid_out_y) { 32462306a36Sopenharmony_ci memcpy(vcapbuf + vid_cap_left, dev->scaled_line, 32562306a36Sopenharmony_ci tpg_hdiv(tpg, p, dev->loop_vid_cap.width)); 32662306a36Sopenharmony_ci goto update_vid_out_y; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci if (!osdline) { 32962306a36Sopenharmony_ci scale_line(voutbuf + vid_out_y * stride_out, dev->scaled_line, 33062306a36Sopenharmony_ci tpg_hdiv(tpg, p, dev->loop_vid_out.width), 33162306a36Sopenharmony_ci tpg_hdiv(tpg, p, dev->loop_vid_cap.width), 33262306a36Sopenharmony_ci tpg_g_twopixelsize(tpg, p)); 33362306a36Sopenharmony_ci } else { 33462306a36Sopenharmony_ci /* 33562306a36Sopenharmony_ci * Offset in bytes within loop_vid_copy to the start of the 33662306a36Sopenharmony_ci * loop_vid_overlay rectangle. 33762306a36Sopenharmony_ci */ 33862306a36Sopenharmony_ci unsigned offset = 33962306a36Sopenharmony_ci ((dev->loop_vid_overlay.left - dev->loop_vid_copy.left) * 34062306a36Sopenharmony_ci twopixsize) / 2; 34162306a36Sopenharmony_ci u8 *osd = vosdbuf + vid_overlay_y * stride_osd; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci scale_line(voutbuf + vid_out_y * stride_out, dev->blended_line, 34462306a36Sopenharmony_ci dev->loop_vid_out.width, dev->loop_vid_copy.width, 34562306a36Sopenharmony_ci tpg_g_twopixelsize(tpg, p)); 34662306a36Sopenharmony_ci if (blend) 34762306a36Sopenharmony_ci blend_line(dev, vid_overlay_y + dev->loop_vid_overlay.top, 34862306a36Sopenharmony_ci dev->loop_vid_overlay.left, 34962306a36Sopenharmony_ci dev->blended_line + offset, osd, 35062306a36Sopenharmony_ci dev->loop_vid_overlay.width, twopixsize / 2); 35162306a36Sopenharmony_ci else 35262306a36Sopenharmony_ci memcpy(dev->blended_line + offset, 35362306a36Sopenharmony_ci osd, (dev->loop_vid_overlay.width * twopixsize) / 2); 35462306a36Sopenharmony_ci scale_line(dev->blended_line, dev->scaled_line, 35562306a36Sopenharmony_ci dev->loop_vid_copy.width, dev->loop_vid_cap.width, 35662306a36Sopenharmony_ci tpg_g_twopixelsize(tpg, p)); 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci dev->cur_scaled_line = vid_out_y; 35962306a36Sopenharmony_ci memcpy(vcapbuf + vid_cap_left, dev->scaled_line, 36062306a36Sopenharmony_ci tpg_hdiv(tpg, p, dev->loop_vid_cap.width)); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ciupdate_vid_out_y: 36362306a36Sopenharmony_ci if (osdline) { 36462306a36Sopenharmony_ci vid_overlay_y += vid_overlay_int_part; 36562306a36Sopenharmony_ci vid_overlay_error += vid_overlay_fract_part; 36662306a36Sopenharmony_ci if (vid_overlay_error >= dev->loop_vid_overlay_cap.height) { 36762306a36Sopenharmony_ci vid_overlay_error -= dev->loop_vid_overlay_cap.height; 36862306a36Sopenharmony_ci vid_overlay_y++; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci vid_out_y += vid_out_int_part; 37262306a36Sopenharmony_ci vid_out_error += vid_out_fract_part; 37362306a36Sopenharmony_ci if (vid_out_error >= dev->loop_vid_cap.height / vdiv) { 37462306a36Sopenharmony_ci vid_out_error -= dev->loop_vid_cap.height / vdiv; 37562306a36Sopenharmony_ci vid_out_y++; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (!blank) 38062306a36Sopenharmony_ci return 0; 38162306a36Sopenharmony_ci for (; y < img_height; y += vdiv, vcapbuf += stride_cap) 38262306a36Sopenharmony_ci memcpy(vcapbuf, tpg->contrast_line[p], img_width); 38362306a36Sopenharmony_ci return 0; 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci struct tpg_data *tpg = &dev->tpg; 38962306a36Sopenharmony_ci unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1; 39062306a36Sopenharmony_ci unsigned line_height = 16 / factor; 39162306a36Sopenharmony_ci bool is_tv = vivid_is_sdtv_cap(dev); 39262306a36Sopenharmony_ci bool is_60hz = is_tv && (dev->std_cap[dev->input] & V4L2_STD_525_60); 39362306a36Sopenharmony_ci unsigned p; 39462306a36Sopenharmony_ci int line = 1; 39562306a36Sopenharmony_ci u8 *basep[TPG_MAX_PLANES][2]; 39662306a36Sopenharmony_ci unsigned ms; 39762306a36Sopenharmony_ci char str[100]; 39862306a36Sopenharmony_ci s32 gain; 39962306a36Sopenharmony_ci bool is_loop = false; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if (dev->loop_video && dev->can_loop_video && 40262306a36Sopenharmony_ci ((vivid_is_svid_cap(dev) && 40362306a36Sopenharmony_ci !VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) || 40462306a36Sopenharmony_ci (vivid_is_hdmi_cap(dev) && 40562306a36Sopenharmony_ci !VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode[dev->input])))) 40662306a36Sopenharmony_ci is_loop = true; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci buf->vb.sequence = dev->vid_cap_seq_count; 40962306a36Sopenharmony_ci v4l2_ctrl_s_ctrl(dev->ro_int32, buf->vb.sequence & 0xff); 41062306a36Sopenharmony_ci if (dev->field_cap == V4L2_FIELD_ALTERNATE) { 41162306a36Sopenharmony_ci /* 41262306a36Sopenharmony_ci * 60 Hz standards start with the bottom field, 50 Hz standards 41362306a36Sopenharmony_ci * with the top field. So if the 0-based seq_count is even, 41462306a36Sopenharmony_ci * then the field is TOP for 50 Hz and BOTTOM for 60 Hz 41562306a36Sopenharmony_ci * standards. 41662306a36Sopenharmony_ci */ 41762306a36Sopenharmony_ci buf->vb.field = ((dev->vid_cap_seq_count & 1) ^ is_60hz) ? 41862306a36Sopenharmony_ci V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP; 41962306a36Sopenharmony_ci /* 42062306a36Sopenharmony_ci * The sequence counter counts frames, not fields. So divide 42162306a36Sopenharmony_ci * by two. 42262306a36Sopenharmony_ci */ 42362306a36Sopenharmony_ci buf->vb.sequence /= 2; 42462306a36Sopenharmony_ci } else { 42562306a36Sopenharmony_ci buf->vb.field = dev->field_cap; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci tpg_s_field(tpg, buf->vb.field, 42862306a36Sopenharmony_ci dev->field_cap == V4L2_FIELD_ALTERNATE); 42962306a36Sopenharmony_ci tpg_s_perc_fill_blank(tpg, dev->must_blank[buf->vb.vb2_buf.index]); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci vivid_precalc_copy_rects(dev); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci for (p = 0; p < tpg_g_planes(tpg); p++) { 43462306a36Sopenharmony_ci void *vbuf = plane_vaddr(tpg, buf, p, 43562306a36Sopenharmony_ci tpg->bytesperline, tpg->buf_height); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* 43862306a36Sopenharmony_ci * The first plane of a multiplanar format has a non-zero 43962306a36Sopenharmony_ci * data_offset. This helps testing whether the application 44062306a36Sopenharmony_ci * correctly supports non-zero data offsets. 44162306a36Sopenharmony_ci */ 44262306a36Sopenharmony_ci if (p < tpg_g_buffers(tpg) && dev->fmt_cap->data_offset[p]) { 44362306a36Sopenharmony_ci memset(vbuf, dev->fmt_cap->data_offset[p] & 0xff, 44462306a36Sopenharmony_ci dev->fmt_cap->data_offset[p]); 44562306a36Sopenharmony_ci vbuf += dev->fmt_cap->data_offset[p]; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci tpg_calc_text_basep(tpg, basep, p, vbuf); 44862306a36Sopenharmony_ci if (!is_loop || vivid_copy_buffer(dev, p, vbuf, buf)) 44962306a36Sopenharmony_ci tpg_fill_plane_buffer(tpg, vivid_get_std_cap(dev), 45062306a36Sopenharmony_ci p, vbuf); 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci dev->must_blank[buf->vb.vb2_buf.index] = false; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci /* Updates stream time, only update at the start of a new frame. */ 45562306a36Sopenharmony_ci if (dev->field_cap != V4L2_FIELD_ALTERNATE || 45662306a36Sopenharmony_ci (dev->vid_cap_seq_count & 1) == 0) 45762306a36Sopenharmony_ci dev->ms_vid_cap = 45862306a36Sopenharmony_ci jiffies_to_msecs(jiffies - dev->jiffies_vid_cap); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci ms = dev->ms_vid_cap; 46162306a36Sopenharmony_ci if (dev->osd_mode <= 1) { 46262306a36Sopenharmony_ci snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d %u%s", 46362306a36Sopenharmony_ci (ms / (60 * 60 * 1000)) % 24, 46462306a36Sopenharmony_ci (ms / (60 * 1000)) % 60, 46562306a36Sopenharmony_ci (ms / 1000) % 60, 46662306a36Sopenharmony_ci ms % 1000, 46762306a36Sopenharmony_ci buf->vb.sequence, 46862306a36Sopenharmony_ci (dev->field_cap == V4L2_FIELD_ALTERNATE) ? 46962306a36Sopenharmony_ci (buf->vb.field == V4L2_FIELD_TOP ? 47062306a36Sopenharmony_ci " top" : " bottom") : ""); 47162306a36Sopenharmony_ci tpg_gen_text(tpg, basep, line++ * line_height, 16, str); 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci if (dev->osd_mode == 0) { 47462306a36Sopenharmony_ci snprintf(str, sizeof(str), " %dx%d, input %d ", 47562306a36Sopenharmony_ci dev->src_rect.width, dev->src_rect.height, dev->input); 47662306a36Sopenharmony_ci tpg_gen_text(tpg, basep, line++ * line_height, 16, str); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci gain = v4l2_ctrl_g_ctrl(dev->gain); 47962306a36Sopenharmony_ci mutex_lock(dev->ctrl_hdl_user_vid.lock); 48062306a36Sopenharmony_ci snprintf(str, sizeof(str), 48162306a36Sopenharmony_ci " brightness %3d, contrast %3d, saturation %3d, hue %d ", 48262306a36Sopenharmony_ci dev->brightness->cur.val, 48362306a36Sopenharmony_ci dev->contrast->cur.val, 48462306a36Sopenharmony_ci dev->saturation->cur.val, 48562306a36Sopenharmony_ci dev->hue->cur.val); 48662306a36Sopenharmony_ci tpg_gen_text(tpg, basep, line++ * line_height, 16, str); 48762306a36Sopenharmony_ci snprintf(str, sizeof(str), 48862306a36Sopenharmony_ci " autogain %d, gain %3d, alpha 0x%02x ", 48962306a36Sopenharmony_ci dev->autogain->cur.val, gain, dev->alpha->cur.val); 49062306a36Sopenharmony_ci mutex_unlock(dev->ctrl_hdl_user_vid.lock); 49162306a36Sopenharmony_ci tpg_gen_text(tpg, basep, line++ * line_height, 16, str); 49262306a36Sopenharmony_ci mutex_lock(dev->ctrl_hdl_user_aud.lock); 49362306a36Sopenharmony_ci snprintf(str, sizeof(str), 49462306a36Sopenharmony_ci " volume %3d, mute %d ", 49562306a36Sopenharmony_ci dev->volume->cur.val, dev->mute->cur.val); 49662306a36Sopenharmony_ci mutex_unlock(dev->ctrl_hdl_user_aud.lock); 49762306a36Sopenharmony_ci tpg_gen_text(tpg, basep, line++ * line_height, 16, str); 49862306a36Sopenharmony_ci mutex_lock(dev->ctrl_hdl_user_gen.lock); 49962306a36Sopenharmony_ci snprintf(str, sizeof(str), " int32 %d, ro_int32 %d, int64 %lld, bitmask %08x ", 50062306a36Sopenharmony_ci dev->int32->cur.val, 50162306a36Sopenharmony_ci dev->ro_int32->cur.val, 50262306a36Sopenharmony_ci *dev->int64->p_cur.p_s64, 50362306a36Sopenharmony_ci dev->bitmask->cur.val); 50462306a36Sopenharmony_ci tpg_gen_text(tpg, basep, line++ * line_height, 16, str); 50562306a36Sopenharmony_ci snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ", 50662306a36Sopenharmony_ci dev->boolean->cur.val, 50762306a36Sopenharmony_ci dev->menu->qmenu[dev->menu->cur.val], 50862306a36Sopenharmony_ci dev->string->p_cur.p_char); 50962306a36Sopenharmony_ci tpg_gen_text(tpg, basep, line++ * line_height, 16, str); 51062306a36Sopenharmony_ci snprintf(str, sizeof(str), " integer_menu %lld, value %d ", 51162306a36Sopenharmony_ci dev->int_menu->qmenu_int[dev->int_menu->cur.val], 51262306a36Sopenharmony_ci dev->int_menu->cur.val); 51362306a36Sopenharmony_ci mutex_unlock(dev->ctrl_hdl_user_gen.lock); 51462306a36Sopenharmony_ci tpg_gen_text(tpg, basep, line++ * line_height, 16, str); 51562306a36Sopenharmony_ci if (dev->button_pressed) { 51662306a36Sopenharmony_ci dev->button_pressed--; 51762306a36Sopenharmony_ci snprintf(str, sizeof(str), " button pressed!"); 51862306a36Sopenharmony_ci tpg_gen_text(tpg, basep, line++ * line_height, 16, str); 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci if (dev->osd[0]) { 52162306a36Sopenharmony_ci if (vivid_is_hdmi_cap(dev)) { 52262306a36Sopenharmony_ci snprintf(str, sizeof(str), 52362306a36Sopenharmony_ci " OSD \"%s\"", dev->osd); 52462306a36Sopenharmony_ci tpg_gen_text(tpg, basep, line++ * line_height, 52562306a36Sopenharmony_ci 16, str); 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci if (dev->osd_jiffies && 52862306a36Sopenharmony_ci time_is_before_jiffies(dev->osd_jiffies + 5 * HZ)) { 52962306a36Sopenharmony_ci dev->osd[0] = 0; 53062306a36Sopenharmony_ci dev->osd_jiffies = 0; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic void vivid_cap_update_frame_period(struct vivid_dev *dev) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci u64 f_period; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci f_period = (u64)dev->timeperframe_vid_cap.numerator * 1000000000; 54162306a36Sopenharmony_ci if (WARN_ON(dev->timeperframe_vid_cap.denominator == 0)) 54262306a36Sopenharmony_ci dev->timeperframe_vid_cap.denominator = 1; 54362306a36Sopenharmony_ci do_div(f_period, dev->timeperframe_vid_cap.denominator); 54462306a36Sopenharmony_ci if (dev->field_cap == V4L2_FIELD_ALTERNATE) 54562306a36Sopenharmony_ci f_period >>= 1; 54662306a36Sopenharmony_ci /* 54762306a36Sopenharmony_ci * If "End of Frame", then offset the exposure time by 0.9 54862306a36Sopenharmony_ci * of the frame period. 54962306a36Sopenharmony_ci */ 55062306a36Sopenharmony_ci dev->cap_frame_eof_offset = f_period * 9; 55162306a36Sopenharmony_ci do_div(dev->cap_frame_eof_offset, 10); 55262306a36Sopenharmony_ci dev->cap_frame_period = f_period; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev, 55662306a36Sopenharmony_ci int dropped_bufs) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci struct vivid_buffer *vid_cap_buf = NULL; 55962306a36Sopenharmony_ci struct vivid_buffer *vbi_cap_buf = NULL; 56062306a36Sopenharmony_ci struct vivid_buffer *meta_cap_buf = NULL; 56162306a36Sopenharmony_ci u64 f_time = 0; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci dprintk(dev, 1, "Video Capture Thread Tick\n"); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci while (dropped_bufs-- > 1) 56662306a36Sopenharmony_ci tpg_update_mv_count(&dev->tpg, 56762306a36Sopenharmony_ci dev->field_cap == V4L2_FIELD_NONE || 56862306a36Sopenharmony_ci dev->field_cap == V4L2_FIELD_ALTERNATE); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci /* Drop a certain percentage of buffers. */ 57162306a36Sopenharmony_ci if (dev->perc_dropped_buffers && 57262306a36Sopenharmony_ci get_random_u32_below(100) < dev->perc_dropped_buffers) 57362306a36Sopenharmony_ci goto update_mv; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci spin_lock(&dev->slock); 57662306a36Sopenharmony_ci if (!list_empty(&dev->vid_cap_active)) { 57762306a36Sopenharmony_ci vid_cap_buf = list_entry(dev->vid_cap_active.next, struct vivid_buffer, list); 57862306a36Sopenharmony_ci list_del(&vid_cap_buf->list); 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci if (!list_empty(&dev->vbi_cap_active)) { 58162306a36Sopenharmony_ci if (dev->field_cap != V4L2_FIELD_ALTERNATE || 58262306a36Sopenharmony_ci (dev->vbi_cap_seq_count & 1)) { 58362306a36Sopenharmony_ci vbi_cap_buf = list_entry(dev->vbi_cap_active.next, 58462306a36Sopenharmony_ci struct vivid_buffer, list); 58562306a36Sopenharmony_ci list_del(&vbi_cap_buf->list); 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci if (!list_empty(&dev->meta_cap_active)) { 58962306a36Sopenharmony_ci meta_cap_buf = list_entry(dev->meta_cap_active.next, 59062306a36Sopenharmony_ci struct vivid_buffer, list); 59162306a36Sopenharmony_ci list_del(&meta_cap_buf->list); 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci spin_unlock(&dev->slock); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (!vid_cap_buf && !vbi_cap_buf && !meta_cap_buf) 59762306a36Sopenharmony_ci goto update_mv; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci f_time = ktime_get_ns() + dev->time_wrap_offset; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (vid_cap_buf) { 60262306a36Sopenharmony_ci v4l2_ctrl_request_setup(vid_cap_buf->vb.vb2_buf.req_obj.req, 60362306a36Sopenharmony_ci &dev->ctrl_hdl_vid_cap); 60462306a36Sopenharmony_ci /* Fill buffer */ 60562306a36Sopenharmony_ci vivid_fillbuff(dev, vid_cap_buf); 60662306a36Sopenharmony_ci dprintk(dev, 1, "filled buffer %d\n", 60762306a36Sopenharmony_ci vid_cap_buf->vb.vb2_buf.index); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci v4l2_ctrl_request_complete(vid_cap_buf->vb.vb2_buf.req_obj.req, 61062306a36Sopenharmony_ci &dev->ctrl_hdl_vid_cap); 61162306a36Sopenharmony_ci vb2_buffer_done(&vid_cap_buf->vb.vb2_buf, dev->dqbuf_error ? 61262306a36Sopenharmony_ci VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); 61362306a36Sopenharmony_ci dprintk(dev, 2, "vid_cap buffer %d done\n", 61462306a36Sopenharmony_ci vid_cap_buf->vb.vb2_buf.index); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci vid_cap_buf->vb.vb2_buf.timestamp = f_time; 61762306a36Sopenharmony_ci if (!dev->tstamp_src_is_soe) 61862306a36Sopenharmony_ci vid_cap_buf->vb.vb2_buf.timestamp += dev->cap_frame_eof_offset; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci if (vbi_cap_buf) { 62262306a36Sopenharmony_ci u64 vbi_period; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci v4l2_ctrl_request_setup(vbi_cap_buf->vb.vb2_buf.req_obj.req, 62562306a36Sopenharmony_ci &dev->ctrl_hdl_vbi_cap); 62662306a36Sopenharmony_ci if (vbi_cap_buf->vb.vb2_buf.type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) 62762306a36Sopenharmony_ci vivid_sliced_vbi_cap_process(dev, vbi_cap_buf); 62862306a36Sopenharmony_ci else 62962306a36Sopenharmony_ci vivid_raw_vbi_cap_process(dev, vbi_cap_buf); 63062306a36Sopenharmony_ci v4l2_ctrl_request_complete(vbi_cap_buf->vb.vb2_buf.req_obj.req, 63162306a36Sopenharmony_ci &dev->ctrl_hdl_vbi_cap); 63262306a36Sopenharmony_ci vb2_buffer_done(&vbi_cap_buf->vb.vb2_buf, dev->dqbuf_error ? 63362306a36Sopenharmony_ci VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); 63462306a36Sopenharmony_ci dprintk(dev, 2, "vbi_cap %d done\n", 63562306a36Sopenharmony_ci vbi_cap_buf->vb.vb2_buf.index); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* If capturing a VBI, offset by 0.05 */ 63862306a36Sopenharmony_ci vbi_period = dev->cap_frame_period * 5; 63962306a36Sopenharmony_ci do_div(vbi_period, 100); 64062306a36Sopenharmony_ci vbi_cap_buf->vb.vb2_buf.timestamp = f_time + dev->cap_frame_eof_offset + vbi_period; 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (meta_cap_buf) { 64462306a36Sopenharmony_ci v4l2_ctrl_request_setup(meta_cap_buf->vb.vb2_buf.req_obj.req, 64562306a36Sopenharmony_ci &dev->ctrl_hdl_meta_cap); 64662306a36Sopenharmony_ci vivid_meta_cap_fillbuff(dev, meta_cap_buf, f_time); 64762306a36Sopenharmony_ci v4l2_ctrl_request_complete(meta_cap_buf->vb.vb2_buf.req_obj.req, 64862306a36Sopenharmony_ci &dev->ctrl_hdl_meta_cap); 64962306a36Sopenharmony_ci vb2_buffer_done(&meta_cap_buf->vb.vb2_buf, dev->dqbuf_error ? 65062306a36Sopenharmony_ci VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); 65162306a36Sopenharmony_ci dprintk(dev, 2, "meta_cap %d done\n", 65262306a36Sopenharmony_ci meta_cap_buf->vb.vb2_buf.index); 65362306a36Sopenharmony_ci meta_cap_buf->vb.vb2_buf.timestamp = f_time + dev->cap_frame_eof_offset; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci dev->dqbuf_error = false; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ciupdate_mv: 65962306a36Sopenharmony_ci /* Update the test pattern movement counters */ 66062306a36Sopenharmony_ci tpg_update_mv_count(&dev->tpg, dev->field_cap == V4L2_FIELD_NONE || 66162306a36Sopenharmony_ci dev->field_cap == V4L2_FIELD_ALTERNATE); 66262306a36Sopenharmony_ci} 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_cistatic int vivid_thread_vid_cap(void *data) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci struct vivid_dev *dev = data; 66762306a36Sopenharmony_ci u64 numerators_since_start; 66862306a36Sopenharmony_ci u64 buffers_since_start; 66962306a36Sopenharmony_ci u64 next_jiffies_since_start; 67062306a36Sopenharmony_ci unsigned long jiffies_since_start; 67162306a36Sopenharmony_ci unsigned long cur_jiffies; 67262306a36Sopenharmony_ci unsigned wait_jiffies; 67362306a36Sopenharmony_ci unsigned numerator; 67462306a36Sopenharmony_ci unsigned denominator; 67562306a36Sopenharmony_ci int dropped_bufs; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci dprintk(dev, 1, "Video Capture Thread Start\n"); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci set_freezable(); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci /* Resets frame counters */ 68262306a36Sopenharmony_ci dev->cap_seq_offset = 0; 68362306a36Sopenharmony_ci dev->cap_seq_count = 0; 68462306a36Sopenharmony_ci dev->cap_seq_resync = false; 68562306a36Sopenharmony_ci dev->jiffies_vid_cap = jiffies; 68662306a36Sopenharmony_ci dev->cap_stream_start = ktime_get_ns(); 68762306a36Sopenharmony_ci if (dev->time_wrap) 68862306a36Sopenharmony_ci dev->time_wrap_offset = dev->time_wrap - dev->cap_stream_start; 68962306a36Sopenharmony_ci else 69062306a36Sopenharmony_ci dev->time_wrap_offset = 0; 69162306a36Sopenharmony_ci vivid_cap_update_frame_period(dev); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci for (;;) { 69462306a36Sopenharmony_ci try_to_freeze(); 69562306a36Sopenharmony_ci if (kthread_should_stop()) 69662306a36Sopenharmony_ci break; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci if (!mutex_trylock(&dev->mutex)) { 69962306a36Sopenharmony_ci schedule(); 70062306a36Sopenharmony_ci continue; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci cur_jiffies = jiffies; 70462306a36Sopenharmony_ci if (dev->cap_seq_resync) { 70562306a36Sopenharmony_ci dev->jiffies_vid_cap = cur_jiffies; 70662306a36Sopenharmony_ci dev->cap_seq_offset = dev->cap_seq_count + 1; 70762306a36Sopenharmony_ci dev->cap_seq_count = 0; 70862306a36Sopenharmony_ci dev->cap_stream_start += dev->cap_frame_period * 70962306a36Sopenharmony_ci dev->cap_seq_offset; 71062306a36Sopenharmony_ci vivid_cap_update_frame_period(dev); 71162306a36Sopenharmony_ci dev->cap_seq_resync = false; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci numerator = dev->timeperframe_vid_cap.numerator; 71462306a36Sopenharmony_ci denominator = dev->timeperframe_vid_cap.denominator; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci if (dev->field_cap == V4L2_FIELD_ALTERNATE) 71762306a36Sopenharmony_ci denominator *= 2; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci /* Calculate the number of jiffies since we started streaming */ 72062306a36Sopenharmony_ci jiffies_since_start = cur_jiffies - dev->jiffies_vid_cap; 72162306a36Sopenharmony_ci /* Get the number of buffers streamed since the start */ 72262306a36Sopenharmony_ci buffers_since_start = (u64)jiffies_since_start * denominator + 72362306a36Sopenharmony_ci (HZ * numerator) / 2; 72462306a36Sopenharmony_ci do_div(buffers_since_start, HZ * numerator); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci /* 72762306a36Sopenharmony_ci * After more than 0xf0000000 (rounded down to a multiple of 72862306a36Sopenharmony_ci * 'jiffies-per-day' to ease jiffies_to_msecs calculation) 72962306a36Sopenharmony_ci * jiffies have passed since we started streaming reset the 73062306a36Sopenharmony_ci * counters and keep track of the sequence offset. 73162306a36Sopenharmony_ci */ 73262306a36Sopenharmony_ci if (jiffies_since_start > JIFFIES_RESYNC) { 73362306a36Sopenharmony_ci dev->jiffies_vid_cap = cur_jiffies; 73462306a36Sopenharmony_ci dev->cap_seq_offset = buffers_since_start; 73562306a36Sopenharmony_ci buffers_since_start = 0; 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci dropped_bufs = buffers_since_start + dev->cap_seq_offset - dev->cap_seq_count; 73862306a36Sopenharmony_ci dev->cap_seq_count = buffers_since_start + dev->cap_seq_offset; 73962306a36Sopenharmony_ci dev->vid_cap_seq_count = dev->cap_seq_count - dev->vid_cap_seq_start; 74062306a36Sopenharmony_ci dev->vbi_cap_seq_count = dev->cap_seq_count - dev->vbi_cap_seq_start; 74162306a36Sopenharmony_ci dev->meta_cap_seq_count = dev->cap_seq_count - dev->meta_cap_seq_start; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci vivid_thread_vid_cap_tick(dev, dropped_bufs); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci /* 74662306a36Sopenharmony_ci * Calculate the number of 'numerators' streamed since we started, 74762306a36Sopenharmony_ci * including the current buffer. 74862306a36Sopenharmony_ci */ 74962306a36Sopenharmony_ci numerators_since_start = ++buffers_since_start * numerator; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* And the number of jiffies since we started */ 75262306a36Sopenharmony_ci jiffies_since_start = jiffies - dev->jiffies_vid_cap; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci mutex_unlock(&dev->mutex); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci /* 75762306a36Sopenharmony_ci * Calculate when that next buffer is supposed to start 75862306a36Sopenharmony_ci * in jiffies since we started streaming. 75962306a36Sopenharmony_ci */ 76062306a36Sopenharmony_ci next_jiffies_since_start = numerators_since_start * HZ + 76162306a36Sopenharmony_ci denominator / 2; 76262306a36Sopenharmony_ci do_div(next_jiffies_since_start, denominator); 76362306a36Sopenharmony_ci /* If it is in the past, then just schedule asap */ 76462306a36Sopenharmony_ci if (next_jiffies_since_start < jiffies_since_start) 76562306a36Sopenharmony_ci next_jiffies_since_start = jiffies_since_start; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci wait_jiffies = next_jiffies_since_start - jiffies_since_start; 76862306a36Sopenharmony_ci while (time_is_after_jiffies(cur_jiffies + wait_jiffies) && 76962306a36Sopenharmony_ci !kthread_should_stop()) 77062306a36Sopenharmony_ci schedule(); 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci dprintk(dev, 1, "Video Capture Thread End\n"); 77362306a36Sopenharmony_ci return 0; 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic void vivid_grab_controls(struct vivid_dev *dev, bool grab) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci v4l2_ctrl_grab(dev->ctrl_has_crop_cap, grab); 77962306a36Sopenharmony_ci v4l2_ctrl_grab(dev->ctrl_has_compose_cap, grab); 78062306a36Sopenharmony_ci v4l2_ctrl_grab(dev->ctrl_has_scaler_cap, grab); 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ciint vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci dprintk(dev, 1, "%s\n", __func__); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if (dev->kthread_vid_cap) { 78862306a36Sopenharmony_ci u32 seq_count = dev->cap_seq_count + dev->seq_wrap * 128; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci if (pstreaming == &dev->vid_cap_streaming) 79162306a36Sopenharmony_ci dev->vid_cap_seq_start = seq_count; 79262306a36Sopenharmony_ci else if (pstreaming == &dev->vbi_cap_streaming) 79362306a36Sopenharmony_ci dev->vbi_cap_seq_start = seq_count; 79462306a36Sopenharmony_ci else 79562306a36Sopenharmony_ci dev->meta_cap_seq_start = seq_count; 79662306a36Sopenharmony_ci *pstreaming = true; 79762306a36Sopenharmony_ci return 0; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci /* Resets frame counters */ 80162306a36Sopenharmony_ci tpg_init_mv_count(&dev->tpg); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci dev->vid_cap_seq_start = dev->seq_wrap * 128; 80462306a36Sopenharmony_ci dev->vbi_cap_seq_start = dev->seq_wrap * 128; 80562306a36Sopenharmony_ci dev->meta_cap_seq_start = dev->seq_wrap * 128; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci dev->kthread_vid_cap = kthread_run(vivid_thread_vid_cap, dev, 80862306a36Sopenharmony_ci "%s-vid-cap", dev->v4l2_dev.name); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci if (IS_ERR(dev->kthread_vid_cap)) { 81162306a36Sopenharmony_ci int err = PTR_ERR(dev->kthread_vid_cap); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci dev->kthread_vid_cap = NULL; 81462306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); 81562306a36Sopenharmony_ci return err; 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci *pstreaming = true; 81862306a36Sopenharmony_ci vivid_grab_controls(dev, true); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci dprintk(dev, 1, "returning from %s\n", __func__); 82162306a36Sopenharmony_ci return 0; 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_civoid vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) 82562306a36Sopenharmony_ci{ 82662306a36Sopenharmony_ci dprintk(dev, 1, "%s\n", __func__); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci if (dev->kthread_vid_cap == NULL) 82962306a36Sopenharmony_ci return; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci *pstreaming = false; 83262306a36Sopenharmony_ci if (pstreaming == &dev->vid_cap_streaming) { 83362306a36Sopenharmony_ci /* Release all active buffers */ 83462306a36Sopenharmony_ci while (!list_empty(&dev->vid_cap_active)) { 83562306a36Sopenharmony_ci struct vivid_buffer *buf; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci buf = list_entry(dev->vid_cap_active.next, 83862306a36Sopenharmony_ci struct vivid_buffer, list); 83962306a36Sopenharmony_ci list_del(&buf->list); 84062306a36Sopenharmony_ci v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, 84162306a36Sopenharmony_ci &dev->ctrl_hdl_vid_cap); 84262306a36Sopenharmony_ci vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); 84362306a36Sopenharmony_ci dprintk(dev, 2, "vid_cap buffer %d done\n", 84462306a36Sopenharmony_ci buf->vb.vb2_buf.index); 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci if (pstreaming == &dev->vbi_cap_streaming) { 84962306a36Sopenharmony_ci while (!list_empty(&dev->vbi_cap_active)) { 85062306a36Sopenharmony_ci struct vivid_buffer *buf; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci buf = list_entry(dev->vbi_cap_active.next, 85362306a36Sopenharmony_ci struct vivid_buffer, list); 85462306a36Sopenharmony_ci list_del(&buf->list); 85562306a36Sopenharmony_ci v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, 85662306a36Sopenharmony_ci &dev->ctrl_hdl_vbi_cap); 85762306a36Sopenharmony_ci vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); 85862306a36Sopenharmony_ci dprintk(dev, 2, "vbi_cap buffer %d done\n", 85962306a36Sopenharmony_ci buf->vb.vb2_buf.index); 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci if (pstreaming == &dev->meta_cap_streaming) { 86462306a36Sopenharmony_ci while (!list_empty(&dev->meta_cap_active)) { 86562306a36Sopenharmony_ci struct vivid_buffer *buf; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci buf = list_entry(dev->meta_cap_active.next, 86862306a36Sopenharmony_ci struct vivid_buffer, list); 86962306a36Sopenharmony_ci list_del(&buf->list); 87062306a36Sopenharmony_ci v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, 87162306a36Sopenharmony_ci &dev->ctrl_hdl_meta_cap); 87262306a36Sopenharmony_ci vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); 87362306a36Sopenharmony_ci dprintk(dev, 2, "meta_cap buffer %d done\n", 87462306a36Sopenharmony_ci buf->vb.vb2_buf.index); 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci if (dev->vid_cap_streaming || dev->vbi_cap_streaming || 87962306a36Sopenharmony_ci dev->meta_cap_streaming) 88062306a36Sopenharmony_ci return; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci /* shutdown control thread */ 88362306a36Sopenharmony_ci vivid_grab_controls(dev, false); 88462306a36Sopenharmony_ci kthread_stop(dev->kthread_vid_cap); 88562306a36Sopenharmony_ci dev->kthread_vid_cap = NULL; 88662306a36Sopenharmony_ci} 887