362 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * vivid-vbi-cap.c - vbi capture support functions.4 *5 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.6 */7 8#include <linux/errno.h>9#include <linux/kernel.h>10#include <linux/videodev2.h>11#include <media/v4l2-common.h>12 13#include "vivid-core.h"14#include "vivid-kthread-cap.h"15#include "vivid-vbi-cap.h"16#include "vivid-vbi-gen.h"17#include "vivid-vid-common.h"18 19static void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr)20{21 struct vivid_vbi_gen_data *vbi_gen = &dev->vbi_gen;22 bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60;23 24 vivid_vbi_gen_sliced(vbi_gen, is_60hz, seqnr);25 26 if (!is_60hz) {27 if (vivid_vid_can_loop(dev)) {28 if (dev->vbi_out_have_wss) {29 vbi_gen->data[12].data[0] = dev->vbi_out_wss[0];30 vbi_gen->data[12].data[1] = dev->vbi_out_wss[1];31 } else {32 vbi_gen->data[12].id = 0;33 }34 } else {35 switch (tpg_g_video_aspect(&dev->tpg)) {36 case TPG_VIDEO_ASPECT_14X9_CENTRE:37 vbi_gen->data[12].data[0] = 0x01;38 break;39 case TPG_VIDEO_ASPECT_16X9_CENTRE:40 vbi_gen->data[12].data[0] = 0x0b;41 break;42 case TPG_VIDEO_ASPECT_16X9_ANAMORPHIC:43 vbi_gen->data[12].data[0] = 0x07;44 break;45 case TPG_VIDEO_ASPECT_4X3:46 default:47 vbi_gen->data[12].data[0] = 0x08;48 break;49 }50 }51 } else if (vivid_vid_can_loop(dev) && is_60hz) {52 if (dev->vbi_out_have_cc[0]) {53 vbi_gen->data[0].data[0] = dev->vbi_out_cc[0][0];54 vbi_gen->data[0].data[1] = dev->vbi_out_cc[0][1];55 } else {56 vbi_gen->data[0].id = 0;57 }58 if (dev->vbi_out_have_cc[1]) {59 vbi_gen->data[1].data[0] = dev->vbi_out_cc[1][0];60 vbi_gen->data[1].data[1] = dev->vbi_out_cc[1][1];61 } else {62 vbi_gen->data[1].id = 0;63 }64 }65}66 67static void vivid_g_fmt_vbi_cap(struct vivid_dev *dev, struct v4l2_vbi_format *vbi)68{69 bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60;70 71 vbi->sampling_rate = 27000000;72 vbi->offset = 24;73 vbi->samples_per_line = 1440;74 vbi->sample_format = V4L2_PIX_FMT_GREY;75 vbi->start[0] = is_60hz ? V4L2_VBI_ITU_525_F1_START + 9 : V4L2_VBI_ITU_625_F1_START + 5;76 vbi->start[1] = is_60hz ? V4L2_VBI_ITU_525_F2_START + 9 : V4L2_VBI_ITU_625_F2_START + 5;77 vbi->count[0] = vbi->count[1] = is_60hz ? 12 : 18;78 vbi->flags = dev->vbi_cap_interlaced ? V4L2_VBI_INTERLACED : 0;79 vbi->reserved[0] = 0;80 vbi->reserved[1] = 0;81}82 83void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)84{85 struct v4l2_vbi_format vbi;86 u8 *vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);87 88 vivid_g_fmt_vbi_cap(dev, &vbi);89 buf->vb.sequence = dev->vbi_cap_seq_count;90 if (dev->field_cap == V4L2_FIELD_ALTERNATE)91 buf->vb.sequence /= 2;92 93 vivid_sliced_vbi_cap_fill(dev, buf->vb.sequence);94 95 memset(vbuf, 0x10, vb2_plane_size(&buf->vb.vb2_buf, 0));96 97 if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input]))98 vivid_vbi_gen_raw(&dev->vbi_gen, &vbi, vbuf);99}100 101 102void vivid_sliced_vbi_cap_process(struct vivid_dev *dev,103 struct vivid_buffer *buf)104{105 struct v4l2_sliced_vbi_data *vbuf =106 vb2_plane_vaddr(&buf->vb.vb2_buf, 0);107 108 buf->vb.sequence = dev->vbi_cap_seq_count;109 if (dev->field_cap == V4L2_FIELD_ALTERNATE)110 buf->vb.sequence /= 2;111 112 vivid_sliced_vbi_cap_fill(dev, buf->vb.sequence);113 114 memset(vbuf, 0, vb2_plane_size(&buf->vb.vb2_buf, 0));115 if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) {116 unsigned i;117 118 for (i = 0; i < 25; i++)119 vbuf[i] = dev->vbi_gen.data[i];120 }121}122 123static int vbi_cap_queue_setup(struct vb2_queue *vq,124 unsigned *nbuffers, unsigned *nplanes,125 unsigned sizes[], struct device *alloc_devs[])126{127 struct vivid_dev *dev = vb2_get_drv_priv(vq);128 bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60;129 unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ?130 36 * sizeof(struct v4l2_sliced_vbi_data) :131 1440 * 2 * (is_60hz ? 12 : 18);132 133 if (!vivid_is_sdtv_cap(dev))134 return -EINVAL;135 136 if (*nplanes)137 return sizes[0] < size ? -EINVAL : 0;138 sizes[0] = size;139 140 *nplanes = 1;141 return 0;142}143 144static int vbi_cap_buf_prepare(struct vb2_buffer *vb)145{146 struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);147 bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60;148 unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ?149 36 * sizeof(struct v4l2_sliced_vbi_data) :150 1440 * 2 * (is_60hz ? 12 : 18);151 152 dprintk(dev, 1, "%s\n", __func__);153 154 if (dev->buf_prepare_error) {155 /*156 * Error injection: test what happens if buf_prepare() returns157 * an error.158 */159 dev->buf_prepare_error = false;160 return -EINVAL;161 }162 if (vb2_plane_size(vb, 0) < size) {163 dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n",164 __func__, vb2_plane_size(vb, 0), size);165 return -EINVAL;166 }167 vb2_set_plane_payload(vb, 0, size);168 169 return 0;170}171 172static void vbi_cap_buf_queue(struct vb2_buffer *vb)173{174 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);175 struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);176 struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb);177 178 dprintk(dev, 1, "%s\n", __func__);179 180 spin_lock(&dev->slock);181 list_add_tail(&buf->list, &dev->vbi_cap_active);182 spin_unlock(&dev->slock);183}184 185static int vbi_cap_start_streaming(struct vb2_queue *vq, unsigned count)186{187 struct vivid_dev *dev = vb2_get_drv_priv(vq);188 int err;189 190 dprintk(dev, 1, "%s\n", __func__);191 dev->vbi_cap_seq_count = 0;192 if (dev->start_streaming_error) {193 dev->start_streaming_error = false;194 err = -EINVAL;195 } else {196 err = vivid_start_generating_vid_cap(dev, &dev->vbi_cap_streaming);197 }198 if (err) {199 struct vivid_buffer *buf, *tmp;200 201 list_for_each_entry_safe(buf, tmp, &dev->vbi_cap_active, list) {202 list_del(&buf->list);203 vb2_buffer_done(&buf->vb.vb2_buf,204 VB2_BUF_STATE_QUEUED);205 }206 }207 return err;208}209 210/* abort streaming and wait for last buffer */211static void vbi_cap_stop_streaming(struct vb2_queue *vq)212{213 struct vivid_dev *dev = vb2_get_drv_priv(vq);214 215 dprintk(dev, 1, "%s\n", __func__);216 vivid_stop_generating_vid_cap(dev, &dev->vbi_cap_streaming);217}218 219static void vbi_cap_buf_request_complete(struct vb2_buffer *vb)220{221 struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);222 223 v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_vbi_cap);224}225 226const struct vb2_ops vivid_vbi_cap_qops = {227 .queue_setup = vbi_cap_queue_setup,228 .buf_prepare = vbi_cap_buf_prepare,229 .buf_queue = vbi_cap_buf_queue,230 .start_streaming = vbi_cap_start_streaming,231 .stop_streaming = vbi_cap_stop_streaming,232 .buf_request_complete = vbi_cap_buf_request_complete,233 .wait_prepare = vb2_ops_wait_prepare,234 .wait_finish = vb2_ops_wait_finish,235};236 237int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,238 struct v4l2_format *f)239{240 struct vivid_dev *dev = video_drvdata(file);241 struct v4l2_vbi_format *vbi = &f->fmt.vbi;242 243 if (!vivid_is_sdtv_cap(dev) || !dev->has_raw_vbi_cap)244 return -EINVAL;245 246 vivid_g_fmt_vbi_cap(dev, vbi);247 return 0;248}249 250int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,251 struct v4l2_format *f)252{253 struct vivid_dev *dev = video_drvdata(file);254 int ret = vidioc_g_fmt_vbi_cap(file, priv, f);255 256 if (ret)257 return ret;258 if (f->type != V4L2_BUF_TYPE_VBI_CAPTURE && vb2_is_busy(&dev->vb_vbi_cap_q))259 return -EBUSY;260 return 0;261}262 263void vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_set)264{265 vbi->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;266 vbi->service_set = service_set;267 memset(vbi->service_lines, 0, sizeof(vbi->service_lines));268 memset(vbi->reserved, 0, sizeof(vbi->reserved));269 270 if (vbi->service_set == 0)271 return;272 273 if (vbi->service_set & V4L2_SLICED_CAPTION_525) {274 vbi->service_lines[0][21] = V4L2_SLICED_CAPTION_525;275 vbi->service_lines[1][21] = V4L2_SLICED_CAPTION_525;276 }277 if (vbi->service_set & V4L2_SLICED_WSS_625) {278 unsigned i;279 280 for (i = 7; i <= 18; i++)281 vbi->service_lines[0][i] =282 vbi->service_lines[1][i] = V4L2_SLICED_TELETEXT_B;283 vbi->service_lines[0][23] = V4L2_SLICED_WSS_625;284 }285}286 287int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)288{289 struct vivid_dev *dev = video_drvdata(file);290 struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;291 292 if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap)293 return -EINVAL;294 295 vivid_fill_service_lines(vbi, dev->service_set_cap);296 return 0;297}298 299int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)300{301 struct vivid_dev *dev = video_drvdata(file);302 struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;303 bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60;304 u32 service_set = vbi->service_set;305 306 if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap)307 return -EINVAL;308 309 service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 :310 V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B;311 vivid_fill_service_lines(vbi, service_set);312 return 0;313}314 315int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)316{317 struct vivid_dev *dev = video_drvdata(file);318 struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;319 int ret = vidioc_try_fmt_sliced_vbi_cap(file, fh, fmt);320 321 if (ret)322 return ret;323 if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE && vb2_is_busy(&dev->vb_vbi_cap_q))324 return -EBUSY;325 dev->service_set_cap = vbi->service_set;326 return 0;327}328 329int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap)330{331 struct vivid_dev *dev = video_drvdata(file);332 struct video_device *vdev = video_devdata(file);333 bool is_60hz;334 335 if (vdev->vfl_dir == VFL_DIR_RX) {336 is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60;337 if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap ||338 cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)339 return -EINVAL;340 } else {341 is_60hz = dev->std_out & V4L2_STD_525_60;342 if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out ||343 cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)344 return -EINVAL;345 }346 347 cap->service_set = is_60hz ? V4L2_SLICED_CAPTION_525 :348 V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B;349 if (is_60hz) {350 cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525;351 cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525;352 } else {353 unsigned i;354 355 for (i = 7; i <= 18; i++)356 cap->service_lines[0][i] =357 cap->service_lines[1][i] = V4L2_SLICED_TELETEXT_B;358 cap->service_lines[0][23] = V4L2_SLICED_WSS_625;359 }360 return 0;361}362