1/* 2 * vivid-vbi-out.c - vbi output support functions. 3 * 4 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. 5 * 6 * This program is free software; you may redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; version 2 of the License. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 11 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 12 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 13 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 14 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 15 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 16 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 17 * SOFTWARE. 18 */ 19 20#include <linux/errno.h> 21#include <linux/kernel.h> 22#include <linux/videodev2.h> 23#include <media/v4l2-common.h> 24 25#include "vivid-core.h" 26#include "vivid-kthread-out.h" 27#include "vivid-vbi-out.h" 28#include "vivid-vbi-cap.h" 29 30static int vbi_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, 31 unsigned *nbuffers, unsigned *nplanes, 32 unsigned sizes[], void *alloc_ctxs[]) 33{ 34 struct vivid_dev *dev = vb2_get_drv_priv(vq); 35 bool is_60hz = dev->std_out & V4L2_STD_525_60; 36 unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ? 37 36 * sizeof(struct v4l2_sliced_vbi_data) : 38 1440 * 2 * (is_60hz ? 12 : 18); 39 40 if (!vivid_is_svid_out(dev)) 41 return -EINVAL; 42 43 sizes[0] = size; 44 45 if (vq->num_buffers + *nbuffers < 2) 46 *nbuffers = 2 - vq->num_buffers; 47 48 *nplanes = 1; 49 return 0; 50} 51 52static int vbi_out_buf_prepare(struct vb2_buffer *vb) 53{ 54 struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); 55 bool is_60hz = dev->std_out & V4L2_STD_525_60; 56 unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ? 57 36 * sizeof(struct v4l2_sliced_vbi_data) : 58 1440 * 2 * (is_60hz ? 12 : 18); 59 60 dprintk(dev, 1, "%s\n", __func__); 61 62 if (dev->buf_prepare_error) { 63 /* 64 * Error injection: test what happens if buf_prepare() returns 65 * an error. 66 */ 67 dev->buf_prepare_error = false; 68 return -EINVAL; 69 } 70 if (vb2_plane_size(vb, 0) < size) { 71 dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", 72 __func__, vb2_plane_size(vb, 0), size); 73 return -EINVAL; 74 } 75 vb2_set_plane_payload(vb, 0, size); 76 77 return 0; 78} 79 80static void vbi_out_buf_queue(struct vb2_buffer *vb) 81{ 82 struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); 83 struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb); 84 85 dprintk(dev, 1, "%s\n", __func__); 86 87 spin_lock(&dev->slock); 88 list_add_tail(&buf->list, &dev->vbi_out_active); 89 spin_unlock(&dev->slock); 90} 91 92static int vbi_out_start_streaming(struct vb2_queue *vq, unsigned count) 93{ 94 struct vivid_dev *dev = vb2_get_drv_priv(vq); 95 int err; 96 97 dprintk(dev, 1, "%s\n", __func__); 98 dev->vbi_out_seq_count = 0; 99 if (dev->start_streaming_error) { 100 dev->start_streaming_error = false; 101 err = -EINVAL; 102 } else { 103 err = vivid_start_generating_vid_out(dev, &dev->vbi_out_streaming); 104 } 105 if (err) { 106 struct vivid_buffer *buf, *tmp; 107 108 list_for_each_entry_safe(buf, tmp, &dev->vbi_out_active, list) { 109 list_del(&buf->list); 110 vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); 111 } 112 } 113 return err; 114} 115 116/* abort streaming and wait for last buffer */ 117static void vbi_out_stop_streaming(struct vb2_queue *vq) 118{ 119 struct vivid_dev *dev = vb2_get_drv_priv(vq); 120 121 dprintk(dev, 1, "%s\n", __func__); 122 vivid_stop_generating_vid_out(dev, &dev->vbi_out_streaming); 123 dev->vbi_out_have_wss = false; 124 dev->vbi_out_have_cc[0] = false; 125 dev->vbi_out_have_cc[1] = false; 126} 127 128const struct vb2_ops vivid_vbi_out_qops = { 129 .queue_setup = vbi_out_queue_setup, 130 .buf_prepare = vbi_out_buf_prepare, 131 .buf_queue = vbi_out_buf_queue, 132 .start_streaming = vbi_out_start_streaming, 133 .stop_streaming = vbi_out_stop_streaming, 134 .wait_prepare = vb2_ops_wait_prepare, 135 .wait_finish = vb2_ops_wait_finish, 136}; 137 138int vidioc_g_fmt_vbi_out(struct file *file, void *priv, 139 struct v4l2_format *f) 140{ 141 struct vivid_dev *dev = video_drvdata(file); 142 struct v4l2_vbi_format *vbi = &f->fmt.vbi; 143 bool is_60hz = dev->std_out & V4L2_STD_525_60; 144 145 if (!vivid_is_svid_out(dev) || !dev->has_raw_vbi_out) 146 return -EINVAL; 147 148 vbi->sampling_rate = 25000000; 149 vbi->offset = 24; 150 vbi->samples_per_line = 1440; 151 vbi->sample_format = V4L2_PIX_FMT_GREY; 152 vbi->start[0] = is_60hz ? V4L2_VBI_ITU_525_F1_START + 9 : V4L2_VBI_ITU_625_F1_START + 5; 153 vbi->start[1] = is_60hz ? V4L2_VBI_ITU_525_F2_START + 9 : V4L2_VBI_ITU_625_F2_START + 5; 154 vbi->count[0] = vbi->count[1] = is_60hz ? 12 : 18; 155 vbi->flags = dev->vbi_cap_interlaced ? V4L2_VBI_INTERLACED : 0; 156 vbi->reserved[0] = 0; 157 vbi->reserved[1] = 0; 158 return 0; 159} 160 161int vidioc_s_fmt_vbi_out(struct file *file, void *priv, 162 struct v4l2_format *f) 163{ 164 struct vivid_dev *dev = video_drvdata(file); 165 int ret = vidioc_g_fmt_vbi_out(file, priv, f); 166 167 if (ret) 168 return ret; 169 if (vb2_is_busy(&dev->vb_vbi_out_q)) 170 return -EBUSY; 171 dev->stream_sliced_vbi_out = false; 172 dev->vbi_out_dev.queue->type = V4L2_BUF_TYPE_VBI_OUTPUT; 173 return 0; 174} 175 176int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) 177{ 178 struct vivid_dev *dev = video_drvdata(file); 179 struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; 180 181 if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out) 182 return -EINVAL; 183 184 vivid_fill_service_lines(vbi, dev->service_set_out); 185 return 0; 186} 187 188int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) 189{ 190 struct vivid_dev *dev = video_drvdata(file); 191 struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; 192 bool is_60hz = dev->std_out & V4L2_STD_525_60; 193 u32 service_set = vbi->service_set; 194 195 if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out) 196 return -EINVAL; 197 198 service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 : 199 V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; 200 vivid_fill_service_lines(vbi, service_set); 201 return 0; 202} 203 204int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) 205{ 206 struct vivid_dev *dev = video_drvdata(file); 207 struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; 208 int ret = vidioc_try_fmt_sliced_vbi_out(file, fh, fmt); 209 210 if (ret) 211 return ret; 212 if (vb2_is_busy(&dev->vb_vbi_out_q)) 213 return -EBUSY; 214 dev->service_set_out = vbi->service_set; 215 dev->stream_sliced_vbi_out = true; 216 dev->vbi_out_dev.queue->type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT; 217 return 0; 218} 219 220void vivid_sliced_vbi_out_process(struct vivid_dev *dev, struct vivid_buffer *buf) 221{ 222 struct v4l2_sliced_vbi_data *vbi = vb2_plane_vaddr(&buf->vb, 0); 223 unsigned elems = vb2_get_plane_payload(&buf->vb, 0) / sizeof(*vbi); 224 225 dev->vbi_out_have_cc[0] = false; 226 dev->vbi_out_have_cc[1] = false; 227 dev->vbi_out_have_wss = false; 228 while (elems--) { 229 switch (vbi->id) { 230 case V4L2_SLICED_CAPTION_525: 231 if ((dev->std_out & V4L2_STD_525_60) && vbi->line == 21) { 232 dev->vbi_out_have_cc[!!vbi->field] = true; 233 dev->vbi_out_cc[!!vbi->field][0] = vbi->data[0]; 234 dev->vbi_out_cc[!!vbi->field][1] = vbi->data[1]; 235 } 236 break; 237 case V4L2_SLICED_WSS_625: 238 if ((dev->std_out & V4L2_STD_625_50) && 239 vbi->field == 0 && vbi->line == 23) { 240 dev->vbi_out_have_wss = true; 241 dev->vbi_out_wss[0] = vbi->data[0]; 242 dev->vbi_out_wss[1] = vbi->data[1]; 243 } 244 break; 245 } 246 vbi++; 247 } 248} 249