162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * vivid-vbi-cap.c - vbi capture 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/errno.h> 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/videodev2.h> 1162306a36Sopenharmony_ci#include <media/v4l2-common.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "vivid-core.h" 1462306a36Sopenharmony_ci#include "vivid-kthread-cap.h" 1562306a36Sopenharmony_ci#include "vivid-vbi-cap.h" 1662306a36Sopenharmony_ci#include "vivid-vbi-gen.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci struct vivid_vbi_gen_data *vbi_gen = &dev->vbi_gen; 2162306a36Sopenharmony_ci bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci vivid_vbi_gen_sliced(vbi_gen, is_60hz, seqnr); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci if (!is_60hz) { 2662306a36Sopenharmony_ci if (dev->loop_video) { 2762306a36Sopenharmony_ci if (dev->vbi_out_have_wss) { 2862306a36Sopenharmony_ci vbi_gen->data[12].data[0] = dev->vbi_out_wss[0]; 2962306a36Sopenharmony_ci vbi_gen->data[12].data[1] = dev->vbi_out_wss[1]; 3062306a36Sopenharmony_ci } else { 3162306a36Sopenharmony_ci vbi_gen->data[12].id = 0; 3262306a36Sopenharmony_ci } 3362306a36Sopenharmony_ci } else { 3462306a36Sopenharmony_ci switch (tpg_g_video_aspect(&dev->tpg)) { 3562306a36Sopenharmony_ci case TPG_VIDEO_ASPECT_14X9_CENTRE: 3662306a36Sopenharmony_ci vbi_gen->data[12].data[0] = 0x01; 3762306a36Sopenharmony_ci break; 3862306a36Sopenharmony_ci case TPG_VIDEO_ASPECT_16X9_CENTRE: 3962306a36Sopenharmony_ci vbi_gen->data[12].data[0] = 0x0b; 4062306a36Sopenharmony_ci break; 4162306a36Sopenharmony_ci case TPG_VIDEO_ASPECT_16X9_ANAMORPHIC: 4262306a36Sopenharmony_ci vbi_gen->data[12].data[0] = 0x07; 4362306a36Sopenharmony_ci break; 4462306a36Sopenharmony_ci case TPG_VIDEO_ASPECT_4X3: 4562306a36Sopenharmony_ci default: 4662306a36Sopenharmony_ci vbi_gen->data[12].data[0] = 0x08; 4762306a36Sopenharmony_ci break; 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci } else if (dev->loop_video && is_60hz) { 5162306a36Sopenharmony_ci if (dev->vbi_out_have_cc[0]) { 5262306a36Sopenharmony_ci vbi_gen->data[0].data[0] = dev->vbi_out_cc[0][0]; 5362306a36Sopenharmony_ci vbi_gen->data[0].data[1] = dev->vbi_out_cc[0][1]; 5462306a36Sopenharmony_ci } else { 5562306a36Sopenharmony_ci vbi_gen->data[0].id = 0; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci if (dev->vbi_out_have_cc[1]) { 5862306a36Sopenharmony_ci vbi_gen->data[1].data[0] = dev->vbi_out_cc[1][0]; 5962306a36Sopenharmony_ci vbi_gen->data[1].data[1] = dev->vbi_out_cc[1][1]; 6062306a36Sopenharmony_ci } else { 6162306a36Sopenharmony_ci vbi_gen->data[1].id = 0; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic void vivid_g_fmt_vbi_cap(struct vivid_dev *dev, struct v4l2_vbi_format *vbi) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci vbi->sampling_rate = 27000000; 7162306a36Sopenharmony_ci vbi->offset = 24; 7262306a36Sopenharmony_ci vbi->samples_per_line = 1440; 7362306a36Sopenharmony_ci vbi->sample_format = V4L2_PIX_FMT_GREY; 7462306a36Sopenharmony_ci vbi->start[0] = is_60hz ? V4L2_VBI_ITU_525_F1_START + 9 : V4L2_VBI_ITU_625_F1_START + 5; 7562306a36Sopenharmony_ci vbi->start[1] = is_60hz ? V4L2_VBI_ITU_525_F2_START + 9 : V4L2_VBI_ITU_625_F2_START + 5; 7662306a36Sopenharmony_ci vbi->count[0] = vbi->count[1] = is_60hz ? 12 : 18; 7762306a36Sopenharmony_ci vbi->flags = dev->vbi_cap_interlaced ? V4L2_VBI_INTERLACED : 0; 7862306a36Sopenharmony_ci vbi->reserved[0] = 0; 7962306a36Sopenharmony_ci vbi->reserved[1] = 0; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_civoid vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct v4l2_vbi_format vbi; 8562306a36Sopenharmony_ci u8 *vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci vivid_g_fmt_vbi_cap(dev, &vbi); 8862306a36Sopenharmony_ci buf->vb.sequence = dev->vbi_cap_seq_count; 8962306a36Sopenharmony_ci if (dev->field_cap == V4L2_FIELD_ALTERNATE) 9062306a36Sopenharmony_ci buf->vb.sequence /= 2; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci vivid_sliced_vbi_cap_fill(dev, buf->vb.sequence); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci memset(vbuf, 0x10, vb2_plane_size(&buf->vb.vb2_buf, 0)); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) 9762306a36Sopenharmony_ci vivid_vbi_gen_raw(&dev->vbi_gen, &vbi, vbuf); 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_civoid vivid_sliced_vbi_cap_process(struct vivid_dev *dev, 10262306a36Sopenharmony_ci struct vivid_buffer *buf) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci struct v4l2_sliced_vbi_data *vbuf = 10562306a36Sopenharmony_ci vb2_plane_vaddr(&buf->vb.vb2_buf, 0); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci buf->vb.sequence = dev->vbi_cap_seq_count; 10862306a36Sopenharmony_ci if (dev->field_cap == V4L2_FIELD_ALTERNATE) 10962306a36Sopenharmony_ci buf->vb.sequence /= 2; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci vivid_sliced_vbi_cap_fill(dev, buf->vb.sequence); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci memset(vbuf, 0, vb2_plane_size(&buf->vb.vb2_buf, 0)); 11462306a36Sopenharmony_ci if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) { 11562306a36Sopenharmony_ci unsigned i; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci for (i = 0; i < 25; i++) 11862306a36Sopenharmony_ci vbuf[i] = dev->vbi_gen.data[i]; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic int vbi_cap_queue_setup(struct vb2_queue *vq, 12362306a36Sopenharmony_ci unsigned *nbuffers, unsigned *nplanes, 12462306a36Sopenharmony_ci unsigned sizes[], struct device *alloc_devs[]) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct vivid_dev *dev = vb2_get_drv_priv(vq); 12762306a36Sopenharmony_ci bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; 12862306a36Sopenharmony_ci unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ? 12962306a36Sopenharmony_ci 36 * sizeof(struct v4l2_sliced_vbi_data) : 13062306a36Sopenharmony_ci 1440 * 2 * (is_60hz ? 12 : 18); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (!vivid_is_sdtv_cap(dev)) 13362306a36Sopenharmony_ci return -EINVAL; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci sizes[0] = size; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (vq->num_buffers + *nbuffers < 2) 13862306a36Sopenharmony_ci *nbuffers = 2 - vq->num_buffers; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci *nplanes = 1; 14162306a36Sopenharmony_ci return 0; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic int vbi_cap_buf_prepare(struct vb2_buffer *vb) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); 14762306a36Sopenharmony_ci bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; 14862306a36Sopenharmony_ci unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ? 14962306a36Sopenharmony_ci 36 * sizeof(struct v4l2_sliced_vbi_data) : 15062306a36Sopenharmony_ci 1440 * 2 * (is_60hz ? 12 : 18); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci dprintk(dev, 1, "%s\n", __func__); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if (dev->buf_prepare_error) { 15562306a36Sopenharmony_ci /* 15662306a36Sopenharmony_ci * Error injection: test what happens if buf_prepare() returns 15762306a36Sopenharmony_ci * an error. 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_ci dev->buf_prepare_error = false; 16062306a36Sopenharmony_ci return -EINVAL; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci if (vb2_plane_size(vb, 0) < size) { 16362306a36Sopenharmony_ci dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", 16462306a36Sopenharmony_ci __func__, vb2_plane_size(vb, 0), size); 16562306a36Sopenharmony_ci return -EINVAL; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci vb2_set_plane_payload(vb, 0, size); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return 0; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic void vbi_cap_buf_queue(struct vb2_buffer *vb) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 17562306a36Sopenharmony_ci struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); 17662306a36Sopenharmony_ci struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci dprintk(dev, 1, "%s\n", __func__); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci spin_lock(&dev->slock); 18162306a36Sopenharmony_ci list_add_tail(&buf->list, &dev->vbi_cap_active); 18262306a36Sopenharmony_ci spin_unlock(&dev->slock); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic int vbi_cap_start_streaming(struct vb2_queue *vq, unsigned count) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct vivid_dev *dev = vb2_get_drv_priv(vq); 18862306a36Sopenharmony_ci int err; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci dprintk(dev, 1, "%s\n", __func__); 19162306a36Sopenharmony_ci dev->vbi_cap_seq_count = 0; 19262306a36Sopenharmony_ci if (dev->start_streaming_error) { 19362306a36Sopenharmony_ci dev->start_streaming_error = false; 19462306a36Sopenharmony_ci err = -EINVAL; 19562306a36Sopenharmony_ci } else { 19662306a36Sopenharmony_ci err = vivid_start_generating_vid_cap(dev, &dev->vbi_cap_streaming); 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci if (err) { 19962306a36Sopenharmony_ci struct vivid_buffer *buf, *tmp; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci list_for_each_entry_safe(buf, tmp, &dev->vbi_cap_active, list) { 20262306a36Sopenharmony_ci list_del(&buf->list); 20362306a36Sopenharmony_ci vb2_buffer_done(&buf->vb.vb2_buf, 20462306a36Sopenharmony_ci VB2_BUF_STATE_QUEUED); 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci return err; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci/* abort streaming and wait for last buffer */ 21162306a36Sopenharmony_cistatic void vbi_cap_stop_streaming(struct vb2_queue *vq) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci struct vivid_dev *dev = vb2_get_drv_priv(vq); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci dprintk(dev, 1, "%s\n", __func__); 21662306a36Sopenharmony_ci vivid_stop_generating_vid_cap(dev, &dev->vbi_cap_streaming); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic void vbi_cap_buf_request_complete(struct vb2_buffer *vb) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_vbi_cap); 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ciconst struct vb2_ops vivid_vbi_cap_qops = { 22762306a36Sopenharmony_ci .queue_setup = vbi_cap_queue_setup, 22862306a36Sopenharmony_ci .buf_prepare = vbi_cap_buf_prepare, 22962306a36Sopenharmony_ci .buf_queue = vbi_cap_buf_queue, 23062306a36Sopenharmony_ci .start_streaming = vbi_cap_start_streaming, 23162306a36Sopenharmony_ci .stop_streaming = vbi_cap_stop_streaming, 23262306a36Sopenharmony_ci .buf_request_complete = vbi_cap_buf_request_complete, 23362306a36Sopenharmony_ci .wait_prepare = vb2_ops_wait_prepare, 23462306a36Sopenharmony_ci .wait_finish = vb2_ops_wait_finish, 23562306a36Sopenharmony_ci}; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ciint vidioc_g_fmt_vbi_cap(struct file *file, void *priv, 23862306a36Sopenharmony_ci struct v4l2_format *f) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci struct vivid_dev *dev = video_drvdata(file); 24162306a36Sopenharmony_ci struct v4l2_vbi_format *vbi = &f->fmt.vbi; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (!vivid_is_sdtv_cap(dev) || !dev->has_raw_vbi_cap) 24462306a36Sopenharmony_ci return -EINVAL; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci vivid_g_fmt_vbi_cap(dev, vbi); 24762306a36Sopenharmony_ci return 0; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ciint vidioc_s_fmt_vbi_cap(struct file *file, void *priv, 25162306a36Sopenharmony_ci struct v4l2_format *f) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci struct vivid_dev *dev = video_drvdata(file); 25462306a36Sopenharmony_ci int ret = vidioc_g_fmt_vbi_cap(file, priv, f); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (ret) 25762306a36Sopenharmony_ci return ret; 25862306a36Sopenharmony_ci if (f->type != V4L2_BUF_TYPE_VBI_CAPTURE && vb2_is_busy(&dev->vb_vbi_cap_q)) 25962306a36Sopenharmony_ci return -EBUSY; 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_civoid vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_set) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci vbi->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; 26662306a36Sopenharmony_ci vbi->service_set = service_set; 26762306a36Sopenharmony_ci memset(vbi->service_lines, 0, sizeof(vbi->service_lines)); 26862306a36Sopenharmony_ci memset(vbi->reserved, 0, sizeof(vbi->reserved)); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (vbi->service_set == 0) 27162306a36Sopenharmony_ci return; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (vbi->service_set & V4L2_SLICED_CAPTION_525) { 27462306a36Sopenharmony_ci vbi->service_lines[0][21] = V4L2_SLICED_CAPTION_525; 27562306a36Sopenharmony_ci vbi->service_lines[1][21] = V4L2_SLICED_CAPTION_525; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci if (vbi->service_set & V4L2_SLICED_WSS_625) { 27862306a36Sopenharmony_ci unsigned i; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci for (i = 7; i <= 18; i++) 28162306a36Sopenharmony_ci vbi->service_lines[0][i] = 28262306a36Sopenharmony_ci vbi->service_lines[1][i] = V4L2_SLICED_TELETEXT_B; 28362306a36Sopenharmony_ci vbi->service_lines[0][23] = V4L2_SLICED_WSS_625; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ciint vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct vivid_dev *dev = video_drvdata(file); 29062306a36Sopenharmony_ci struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap) 29362306a36Sopenharmony_ci return -EINVAL; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci vivid_fill_service_lines(vbi, dev->service_set_cap); 29662306a36Sopenharmony_ci return 0; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ciint vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct vivid_dev *dev = video_drvdata(file); 30262306a36Sopenharmony_ci struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; 30362306a36Sopenharmony_ci bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; 30462306a36Sopenharmony_ci u32 service_set = vbi->service_set; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap) 30762306a36Sopenharmony_ci return -EINVAL; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 : 31062306a36Sopenharmony_ci V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; 31162306a36Sopenharmony_ci vivid_fill_service_lines(vbi, service_set); 31262306a36Sopenharmony_ci return 0; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ciint vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci struct vivid_dev *dev = video_drvdata(file); 31862306a36Sopenharmony_ci struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; 31962306a36Sopenharmony_ci int ret = vidioc_try_fmt_sliced_vbi_cap(file, fh, fmt); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (ret) 32262306a36Sopenharmony_ci return ret; 32362306a36Sopenharmony_ci if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE && vb2_is_busy(&dev->vb_vbi_cap_q)) 32462306a36Sopenharmony_ci return -EBUSY; 32562306a36Sopenharmony_ci dev->service_set_cap = vbi->service_set; 32662306a36Sopenharmony_ci return 0; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ciint vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct vivid_dev *dev = video_drvdata(file); 33262306a36Sopenharmony_ci struct video_device *vdev = video_devdata(file); 33362306a36Sopenharmony_ci bool is_60hz; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (vdev->vfl_dir == VFL_DIR_RX) { 33662306a36Sopenharmony_ci is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; 33762306a36Sopenharmony_ci if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap || 33862306a36Sopenharmony_ci cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) 33962306a36Sopenharmony_ci return -EINVAL; 34062306a36Sopenharmony_ci } else { 34162306a36Sopenharmony_ci is_60hz = dev->std_out & V4L2_STD_525_60; 34262306a36Sopenharmony_ci if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out || 34362306a36Sopenharmony_ci cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) 34462306a36Sopenharmony_ci return -EINVAL; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci cap->service_set = is_60hz ? V4L2_SLICED_CAPTION_525 : 34862306a36Sopenharmony_ci V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; 34962306a36Sopenharmony_ci if (is_60hz) { 35062306a36Sopenharmony_ci cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525; 35162306a36Sopenharmony_ci cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525; 35262306a36Sopenharmony_ci } else { 35362306a36Sopenharmony_ci unsigned i; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci for (i = 7; i <= 18; i++) 35662306a36Sopenharmony_ci cap->service_lines[0][i] = 35762306a36Sopenharmony_ci cap->service_lines[1][i] = V4L2_SLICED_TELETEXT_B; 35862306a36Sopenharmony_ci cap->service_lines[0][23] = V4L2_SLICED_WSS_625; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci return 0; 36162306a36Sopenharmony_ci} 362