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