18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * vivid-vbi-cap.c - vbi capture support functions. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/errno.h> 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 118c2ecf20Sopenharmony_ci#include <media/v4l2-common.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "vivid-core.h" 148c2ecf20Sopenharmony_ci#include "vivid-kthread-cap.h" 158c2ecf20Sopenharmony_ci#include "vivid-vbi-cap.h" 168c2ecf20Sopenharmony_ci#include "vivid-vbi-gen.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci struct vivid_vbi_gen_data *vbi_gen = &dev->vbi_gen; 218c2ecf20Sopenharmony_ci bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci vivid_vbi_gen_sliced(vbi_gen, is_60hz, seqnr); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci if (!is_60hz) { 268c2ecf20Sopenharmony_ci if (dev->loop_video) { 278c2ecf20Sopenharmony_ci if (dev->vbi_out_have_wss) { 288c2ecf20Sopenharmony_ci vbi_gen->data[12].data[0] = dev->vbi_out_wss[0]; 298c2ecf20Sopenharmony_ci vbi_gen->data[12].data[1] = dev->vbi_out_wss[1]; 308c2ecf20Sopenharmony_ci } else { 318c2ecf20Sopenharmony_ci vbi_gen->data[12].id = 0; 328c2ecf20Sopenharmony_ci } 338c2ecf20Sopenharmony_ci } else { 348c2ecf20Sopenharmony_ci switch (tpg_g_video_aspect(&dev->tpg)) { 358c2ecf20Sopenharmony_ci case TPG_VIDEO_ASPECT_14X9_CENTRE: 368c2ecf20Sopenharmony_ci vbi_gen->data[12].data[0] = 0x01; 378c2ecf20Sopenharmony_ci break; 388c2ecf20Sopenharmony_ci case TPG_VIDEO_ASPECT_16X9_CENTRE: 398c2ecf20Sopenharmony_ci vbi_gen->data[12].data[0] = 0x0b; 408c2ecf20Sopenharmony_ci break; 418c2ecf20Sopenharmony_ci case TPG_VIDEO_ASPECT_16X9_ANAMORPHIC: 428c2ecf20Sopenharmony_ci vbi_gen->data[12].data[0] = 0x07; 438c2ecf20Sopenharmony_ci break; 448c2ecf20Sopenharmony_ci case TPG_VIDEO_ASPECT_4X3: 458c2ecf20Sopenharmony_ci default: 468c2ecf20Sopenharmony_ci vbi_gen->data[12].data[0] = 0x08; 478c2ecf20Sopenharmony_ci break; 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci } else if (dev->loop_video && is_60hz) { 518c2ecf20Sopenharmony_ci if (dev->vbi_out_have_cc[0]) { 528c2ecf20Sopenharmony_ci vbi_gen->data[0].data[0] = dev->vbi_out_cc[0][0]; 538c2ecf20Sopenharmony_ci vbi_gen->data[0].data[1] = dev->vbi_out_cc[0][1]; 548c2ecf20Sopenharmony_ci } else { 558c2ecf20Sopenharmony_ci vbi_gen->data[0].id = 0; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci if (dev->vbi_out_have_cc[1]) { 588c2ecf20Sopenharmony_ci vbi_gen->data[1].data[0] = dev->vbi_out_cc[1][0]; 598c2ecf20Sopenharmony_ci vbi_gen->data[1].data[1] = dev->vbi_out_cc[1][1]; 608c2ecf20Sopenharmony_ci } else { 618c2ecf20Sopenharmony_ci vbi_gen->data[1].id = 0; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic void vivid_g_fmt_vbi_cap(struct vivid_dev *dev, struct v4l2_vbi_format *vbi) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci vbi->sampling_rate = 27000000; 718c2ecf20Sopenharmony_ci vbi->offset = 24; 728c2ecf20Sopenharmony_ci vbi->samples_per_line = 1440; 738c2ecf20Sopenharmony_ci vbi->sample_format = V4L2_PIX_FMT_GREY; 748c2ecf20Sopenharmony_ci vbi->start[0] = is_60hz ? V4L2_VBI_ITU_525_F1_START + 9 : V4L2_VBI_ITU_625_F1_START + 5; 758c2ecf20Sopenharmony_ci vbi->start[1] = is_60hz ? V4L2_VBI_ITU_525_F2_START + 9 : V4L2_VBI_ITU_625_F2_START + 5; 768c2ecf20Sopenharmony_ci vbi->count[0] = vbi->count[1] = is_60hz ? 12 : 18; 778c2ecf20Sopenharmony_ci vbi->flags = dev->vbi_cap_interlaced ? V4L2_VBI_INTERLACED : 0; 788c2ecf20Sopenharmony_ci vbi->reserved[0] = 0; 798c2ecf20Sopenharmony_ci vbi->reserved[1] = 0; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_civoid vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct v4l2_vbi_format vbi; 858c2ecf20Sopenharmony_ci u8 *vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci vivid_g_fmt_vbi_cap(dev, &vbi); 888c2ecf20Sopenharmony_ci buf->vb.sequence = dev->vbi_cap_seq_count; 898c2ecf20Sopenharmony_ci if (dev->field_cap == V4L2_FIELD_ALTERNATE) 908c2ecf20Sopenharmony_ci buf->vb.sequence /= 2; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci vivid_sliced_vbi_cap_fill(dev, buf->vb.sequence); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci memset(vbuf, 0x10, vb2_plane_size(&buf->vb.vb2_buf, 0)); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) 978c2ecf20Sopenharmony_ci vivid_vbi_gen_raw(&dev->vbi_gen, &vbi, vbuf); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_civoid vivid_sliced_vbi_cap_process(struct vivid_dev *dev, 1028c2ecf20Sopenharmony_ci struct vivid_buffer *buf) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci struct v4l2_sliced_vbi_data *vbuf = 1058c2ecf20Sopenharmony_ci vb2_plane_vaddr(&buf->vb.vb2_buf, 0); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci buf->vb.sequence = dev->vbi_cap_seq_count; 1088c2ecf20Sopenharmony_ci if (dev->field_cap == V4L2_FIELD_ALTERNATE) 1098c2ecf20Sopenharmony_ci buf->vb.sequence /= 2; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci vivid_sliced_vbi_cap_fill(dev, buf->vb.sequence); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci memset(vbuf, 0, vb2_plane_size(&buf->vb.vb2_buf, 0)); 1148c2ecf20Sopenharmony_ci if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) { 1158c2ecf20Sopenharmony_ci unsigned i; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci for (i = 0; i < 25; i++) 1188c2ecf20Sopenharmony_ci vbuf[i] = dev->vbi_gen.data[i]; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic int vbi_cap_queue_setup(struct vb2_queue *vq, 1238c2ecf20Sopenharmony_ci unsigned *nbuffers, unsigned *nplanes, 1248c2ecf20Sopenharmony_ci unsigned sizes[], struct device *alloc_devs[]) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct vivid_dev *dev = vb2_get_drv_priv(vq); 1278c2ecf20Sopenharmony_ci bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; 1288c2ecf20Sopenharmony_ci unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ? 1298c2ecf20Sopenharmony_ci 36 * sizeof(struct v4l2_sliced_vbi_data) : 1308c2ecf20Sopenharmony_ci 1440 * 2 * (is_60hz ? 12 : 18); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (!vivid_is_sdtv_cap(dev)) 1338c2ecf20Sopenharmony_ci return -EINVAL; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci sizes[0] = size; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (vq->num_buffers + *nbuffers < 2) 1388c2ecf20Sopenharmony_ci *nbuffers = 2 - vq->num_buffers; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci *nplanes = 1; 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic int vbi_cap_buf_prepare(struct vb2_buffer *vb) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); 1478c2ecf20Sopenharmony_ci bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; 1488c2ecf20Sopenharmony_ci unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ? 1498c2ecf20Sopenharmony_ci 36 * sizeof(struct v4l2_sliced_vbi_data) : 1508c2ecf20Sopenharmony_ci 1440 * 2 * (is_60hz ? 12 : 18); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci dprintk(dev, 1, "%s\n", __func__); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (dev->buf_prepare_error) { 1558c2ecf20Sopenharmony_ci /* 1568c2ecf20Sopenharmony_ci * Error injection: test what happens if buf_prepare() returns 1578c2ecf20Sopenharmony_ci * an error. 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_ci dev->buf_prepare_error = false; 1608c2ecf20Sopenharmony_ci return -EINVAL; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci if (vb2_plane_size(vb, 0) < size) { 1638c2ecf20Sopenharmony_ci dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", 1648c2ecf20Sopenharmony_ci __func__, vb2_plane_size(vb, 0), size); 1658c2ecf20Sopenharmony_ci return -EINVAL; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci vb2_set_plane_payload(vb, 0, size); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci return 0; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic void vbi_cap_buf_queue(struct vb2_buffer *vb) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 1758c2ecf20Sopenharmony_ci struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); 1768c2ecf20Sopenharmony_ci struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci dprintk(dev, 1, "%s\n", __func__); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci spin_lock(&dev->slock); 1818c2ecf20Sopenharmony_ci list_add_tail(&buf->list, &dev->vbi_cap_active); 1828c2ecf20Sopenharmony_ci spin_unlock(&dev->slock); 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic int vbi_cap_start_streaming(struct vb2_queue *vq, unsigned count) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct vivid_dev *dev = vb2_get_drv_priv(vq); 1888c2ecf20Sopenharmony_ci int err; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci dprintk(dev, 1, "%s\n", __func__); 1918c2ecf20Sopenharmony_ci dev->vbi_cap_seq_count = 0; 1928c2ecf20Sopenharmony_ci if (dev->start_streaming_error) { 1938c2ecf20Sopenharmony_ci dev->start_streaming_error = false; 1948c2ecf20Sopenharmony_ci err = -EINVAL; 1958c2ecf20Sopenharmony_ci } else { 1968c2ecf20Sopenharmony_ci err = vivid_start_generating_vid_cap(dev, &dev->vbi_cap_streaming); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci if (err) { 1998c2ecf20Sopenharmony_ci struct vivid_buffer *buf, *tmp; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci list_for_each_entry_safe(buf, tmp, &dev->vbi_cap_active, list) { 2028c2ecf20Sopenharmony_ci list_del(&buf->list); 2038c2ecf20Sopenharmony_ci vb2_buffer_done(&buf->vb.vb2_buf, 2048c2ecf20Sopenharmony_ci VB2_BUF_STATE_QUEUED); 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci return err; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci/* abort streaming and wait for last buffer */ 2118c2ecf20Sopenharmony_cistatic void vbi_cap_stop_streaming(struct vb2_queue *vq) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct vivid_dev *dev = vb2_get_drv_priv(vq); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci dprintk(dev, 1, "%s\n", __func__); 2168c2ecf20Sopenharmony_ci vivid_stop_generating_vid_cap(dev, &dev->vbi_cap_streaming); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic void vbi_cap_buf_request_complete(struct vb2_buffer *vb) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_vbi_cap); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ciconst struct vb2_ops vivid_vbi_cap_qops = { 2278c2ecf20Sopenharmony_ci .queue_setup = vbi_cap_queue_setup, 2288c2ecf20Sopenharmony_ci .buf_prepare = vbi_cap_buf_prepare, 2298c2ecf20Sopenharmony_ci .buf_queue = vbi_cap_buf_queue, 2308c2ecf20Sopenharmony_ci .start_streaming = vbi_cap_start_streaming, 2318c2ecf20Sopenharmony_ci .stop_streaming = vbi_cap_stop_streaming, 2328c2ecf20Sopenharmony_ci .buf_request_complete = vbi_cap_buf_request_complete, 2338c2ecf20Sopenharmony_ci .wait_prepare = vb2_ops_wait_prepare, 2348c2ecf20Sopenharmony_ci .wait_finish = vb2_ops_wait_finish, 2358c2ecf20Sopenharmony_ci}; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ciint vidioc_g_fmt_vbi_cap(struct file *file, void *priv, 2388c2ecf20Sopenharmony_ci struct v4l2_format *f) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct vivid_dev *dev = video_drvdata(file); 2418c2ecf20Sopenharmony_ci struct v4l2_vbi_format *vbi = &f->fmt.vbi; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (!vivid_is_sdtv_cap(dev) || !dev->has_raw_vbi_cap) 2448c2ecf20Sopenharmony_ci return -EINVAL; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci vivid_g_fmt_vbi_cap(dev, vbi); 2478c2ecf20Sopenharmony_ci return 0; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ciint vidioc_s_fmt_vbi_cap(struct file *file, void *priv, 2518c2ecf20Sopenharmony_ci struct v4l2_format *f) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci struct vivid_dev *dev = video_drvdata(file); 2548c2ecf20Sopenharmony_ci int ret = vidioc_g_fmt_vbi_cap(file, priv, f); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (ret) 2578c2ecf20Sopenharmony_ci return ret; 2588c2ecf20Sopenharmony_ci if (dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q)) 2598c2ecf20Sopenharmony_ci return -EBUSY; 2608c2ecf20Sopenharmony_ci dev->stream_sliced_vbi_cap = false; 2618c2ecf20Sopenharmony_ci dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_VBI_CAPTURE; 2628c2ecf20Sopenharmony_ci return 0; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_civoid vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_set) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci vbi->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; 2688c2ecf20Sopenharmony_ci vbi->service_set = service_set; 2698c2ecf20Sopenharmony_ci memset(vbi->service_lines, 0, sizeof(vbi->service_lines)); 2708c2ecf20Sopenharmony_ci memset(vbi->reserved, 0, sizeof(vbi->reserved)); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (vbi->service_set == 0) 2738c2ecf20Sopenharmony_ci return; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (vbi->service_set & V4L2_SLICED_CAPTION_525) { 2768c2ecf20Sopenharmony_ci vbi->service_lines[0][21] = V4L2_SLICED_CAPTION_525; 2778c2ecf20Sopenharmony_ci vbi->service_lines[1][21] = V4L2_SLICED_CAPTION_525; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci if (vbi->service_set & V4L2_SLICED_WSS_625) { 2808c2ecf20Sopenharmony_ci unsigned i; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci for (i = 7; i <= 18; i++) 2838c2ecf20Sopenharmony_ci vbi->service_lines[0][i] = 2848c2ecf20Sopenharmony_ci vbi->service_lines[1][i] = V4L2_SLICED_TELETEXT_B; 2858c2ecf20Sopenharmony_ci vbi->service_lines[0][23] = V4L2_SLICED_WSS_625; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ciint vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct vivid_dev *dev = video_drvdata(file); 2928c2ecf20Sopenharmony_ci struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap) 2958c2ecf20Sopenharmony_ci return -EINVAL; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci vivid_fill_service_lines(vbi, dev->service_set_cap); 2988c2ecf20Sopenharmony_ci return 0; 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ciint vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci struct vivid_dev *dev = video_drvdata(file); 3048c2ecf20Sopenharmony_ci struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; 3058c2ecf20Sopenharmony_ci bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; 3068c2ecf20Sopenharmony_ci u32 service_set = vbi->service_set; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap) 3098c2ecf20Sopenharmony_ci return -EINVAL; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 : 3128c2ecf20Sopenharmony_ci V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; 3138c2ecf20Sopenharmony_ci vivid_fill_service_lines(vbi, service_set); 3148c2ecf20Sopenharmony_ci return 0; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ciint vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct vivid_dev *dev = video_drvdata(file); 3208c2ecf20Sopenharmony_ci struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; 3218c2ecf20Sopenharmony_ci int ret = vidioc_try_fmt_sliced_vbi_cap(file, fh, fmt); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (ret) 3248c2ecf20Sopenharmony_ci return ret; 3258c2ecf20Sopenharmony_ci if (!dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q)) 3268c2ecf20Sopenharmony_ci return -EBUSY; 3278c2ecf20Sopenharmony_ci dev->service_set_cap = vbi->service_set; 3288c2ecf20Sopenharmony_ci dev->stream_sliced_vbi_cap = true; 3298c2ecf20Sopenharmony_ci dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; 3308c2ecf20Sopenharmony_ci return 0; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ciint vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct vivid_dev *dev = video_drvdata(file); 3368c2ecf20Sopenharmony_ci struct video_device *vdev = video_devdata(file); 3378c2ecf20Sopenharmony_ci bool is_60hz; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (vdev->vfl_dir == VFL_DIR_RX) { 3408c2ecf20Sopenharmony_ci is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; 3418c2ecf20Sopenharmony_ci if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap || 3428c2ecf20Sopenharmony_ci cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) 3438c2ecf20Sopenharmony_ci return -EINVAL; 3448c2ecf20Sopenharmony_ci } else { 3458c2ecf20Sopenharmony_ci is_60hz = dev->std_out & V4L2_STD_525_60; 3468c2ecf20Sopenharmony_ci if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out || 3478c2ecf20Sopenharmony_ci cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) 3488c2ecf20Sopenharmony_ci return -EINVAL; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci cap->service_set = is_60hz ? V4L2_SLICED_CAPTION_525 : 3528c2ecf20Sopenharmony_ci V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; 3538c2ecf20Sopenharmony_ci if (is_60hz) { 3548c2ecf20Sopenharmony_ci cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525; 3558c2ecf20Sopenharmony_ci cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525; 3568c2ecf20Sopenharmony_ci } else { 3578c2ecf20Sopenharmony_ci unsigned i; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci for (i = 7; i <= 18; i++) 3608c2ecf20Sopenharmony_ci cap->service_lines[0][i] = 3618c2ecf20Sopenharmony_ci cap->service_lines[1][i] = V4L2_SLICED_TELETEXT_B; 3628c2ecf20Sopenharmony_ci cap->service_lines[0][23] = V4L2_SLICED_WSS_625; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci return 0; 3658c2ecf20Sopenharmony_ci} 366