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