| 
									
										
										
										
											2014-08-25 07:56:49 -03:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * vivid-vbi-cap.c - vbi capture support functions. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you may redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |  * the Free Software Foundation; version 2 of the License. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | 
					
						
							|  |  |  |  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | 
					
						
							|  |  |  |  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | 
					
						
							|  |  |  |  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | 
					
						
							|  |  |  |  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | 
					
						
							|  |  |  |  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | 
					
						
							|  |  |  |  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | 
					
						
							|  |  |  |  * SOFTWARE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/errno.h>
 | 
					
						
							|  |  |  | #include <linux/kernel.h>
 | 
					
						
							|  |  |  | #include <linux/videodev2.h>
 | 
					
						
							|  |  |  | #include <media/v4l2-common.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "vivid-core.h"
 | 
					
						
							|  |  |  | #include "vivid-kthread-cap.h"
 | 
					
						
							|  |  |  | #include "vivid-vbi-cap.h"
 | 
					
						
							|  |  |  | #include "vivid-vbi-gen.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct vivid_vbi_gen_data *vbi_gen = &dev->vbi_gen; | 
					
						
							|  |  |  | 	bool is_60hz = dev->std_cap & V4L2_STD_525_60; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vivid_vbi_gen_sliced(vbi_gen, is_60hz, seqnr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!is_60hz) { | 
					
						
							|  |  |  | 		if (dev->loop_video) { | 
					
						
							|  |  |  | 			if (dev->vbi_out_have_wss) { | 
					
						
							| 
									
										
										
										
											2014-09-20 06:11:44 -03:00
										 |  |  | 				vbi_gen->data[12].data[0] = dev->vbi_out_wss[0]; | 
					
						
							|  |  |  | 				vbi_gen->data[12].data[1] = dev->vbi_out_wss[1]; | 
					
						
							| 
									
										
										
										
											2014-08-25 07:56:49 -03:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2014-09-20 06:11:44 -03:00
										 |  |  | 				vbi_gen->data[12].id = 0; | 
					
						
							| 
									
										
										
										
											2014-08-25 07:56:49 -03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			switch (tpg_g_video_aspect(&dev->tpg)) { | 
					
						
							|  |  |  | 			case TPG_VIDEO_ASPECT_14X9_CENTRE: | 
					
						
							| 
									
										
										
										
											2014-09-20 06:11:44 -03:00
										 |  |  | 				vbi_gen->data[12].data[0] = 0x01; | 
					
						
							| 
									
										
										
										
											2014-08-25 07:56:49 -03:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			case TPG_VIDEO_ASPECT_16X9_CENTRE: | 
					
						
							| 
									
										
										
										
											2014-09-20 06:11:44 -03:00
										 |  |  | 				vbi_gen->data[12].data[0] = 0x0b; | 
					
						
							| 
									
										
										
										
											2014-08-25 07:56:49 -03:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			case TPG_VIDEO_ASPECT_16X9_ANAMORPHIC: | 
					
						
							| 
									
										
										
										
											2014-09-20 06:11:44 -03:00
										 |  |  | 				vbi_gen->data[12].data[0] = 0x07; | 
					
						
							| 
									
										
										
										
											2014-08-25 07:56:49 -03:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			case TPG_VIDEO_ASPECT_4X3: | 
					
						
							|  |  |  | 			default: | 
					
						
							| 
									
										
										
										
											2014-09-20 06:11:44 -03:00
										 |  |  | 				vbi_gen->data[12].data[0] = 0x08; | 
					
						
							| 
									
										
										
										
											2014-08-25 07:56:49 -03:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else if (dev->loop_video && is_60hz) { | 
					
						
							|  |  |  | 		if (dev->vbi_out_have_cc[0]) { | 
					
						
							|  |  |  | 			vbi_gen->data[0].data[0] = dev->vbi_out_cc[0][0]; | 
					
						
							|  |  |  | 			vbi_gen->data[0].data[1] = dev->vbi_out_cc[0][1]; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			vbi_gen->data[0].id = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (dev->vbi_out_have_cc[1]) { | 
					
						
							|  |  |  | 			vbi_gen->data[1].data[0] = dev->vbi_out_cc[1][0]; | 
					
						
							|  |  |  | 			vbi_gen->data[1].data[1] = dev->vbi_out_cc[1][1]; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			vbi_gen->data[1].id = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vivid_g_fmt_vbi_cap(struct vivid_dev *dev, struct v4l2_vbi_format *vbi) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	bool is_60hz = dev->std_cap & V4L2_STD_525_60; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vbi->sampling_rate = 27000000; | 
					
						
							|  |  |  | 	vbi->offset = 24; | 
					
						
							|  |  |  | 	vbi->samples_per_line = 1440; | 
					
						
							|  |  |  | 	vbi->sample_format = V4L2_PIX_FMT_GREY; | 
					
						
							| 
									
										
										
										
											2014-09-20 06:11:44 -03:00
										 |  |  | 	vbi->start[0] = is_60hz ? V4L2_VBI_ITU_525_F1_START + 9 : V4L2_VBI_ITU_625_F1_START + 5; | 
					
						
							|  |  |  | 	vbi->start[1] = is_60hz ? V4L2_VBI_ITU_525_F2_START + 9 : V4L2_VBI_ITU_625_F2_START + 5; | 
					
						
							| 
									
										
										
										
											2014-08-25 07:56:49 -03:00
										 |  |  | 	vbi->count[0] = vbi->count[1] = is_60hz ? 12 : 18; | 
					
						
							|  |  |  | 	vbi->flags = dev->vbi_cap_interlaced ? V4L2_VBI_INTERLACED : 0; | 
					
						
							|  |  |  | 	vbi->reserved[0] = 0; | 
					
						
							|  |  |  | 	vbi->reserved[1] = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct v4l2_vbi_format vbi; | 
					
						
							|  |  |  | 	u8 *vbuf = vb2_plane_vaddr(&buf->vb, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vivid_g_fmt_vbi_cap(dev, &vbi); | 
					
						
							|  |  |  | 	buf->vb.v4l2_buf.sequence = dev->vbi_cap_seq_count; | 
					
						
							|  |  |  | 	if (dev->field_cap == V4L2_FIELD_ALTERNATE) | 
					
						
							|  |  |  | 		buf->vb.v4l2_buf.sequence /= 2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vivid_sliced_vbi_cap_fill(dev, buf->vb.v4l2_buf.sequence); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memset(vbuf, 0x10, vb2_plane_size(&buf->vb, 0)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode)) | 
					
						
							|  |  |  | 		vivid_vbi_gen_raw(&dev->vbi_gen, &vbi, vbuf); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); | 
					
						
							|  |  |  | 	buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void vivid_sliced_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct v4l2_sliced_vbi_data *vbuf = vb2_plane_vaddr(&buf->vb, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	buf->vb.v4l2_buf.sequence = dev->vbi_cap_seq_count; | 
					
						
							|  |  |  | 	if (dev->field_cap == V4L2_FIELD_ALTERNATE) | 
					
						
							|  |  |  | 		buf->vb.v4l2_buf.sequence /= 2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vivid_sliced_vbi_cap_fill(dev, buf->vb.v4l2_buf.sequence); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memset(vbuf, 0, vb2_plane_size(&buf->vb, 0)); | 
					
						
							|  |  |  | 	if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode)) { | 
					
						
							| 
									
										
										
										
											2014-09-20 06:11:44 -03:00
										 |  |  | 		unsigned i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (i = 0; i < 25; i++) | 
					
						
							|  |  |  | 			vbuf[i] = dev->vbi_gen.data[i]; | 
					
						
							| 
									
										
										
										
											2014-08-25 07:56:49 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); | 
					
						
							|  |  |  | 	buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int vbi_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, | 
					
						
							|  |  |  | 		       unsigned *nbuffers, unsigned *nplanes, | 
					
						
							|  |  |  | 		       unsigned sizes[], void *alloc_ctxs[]) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct vivid_dev *dev = vb2_get_drv_priv(vq); | 
					
						
							|  |  |  | 	bool is_60hz = dev->std_cap & V4L2_STD_525_60; | 
					
						
							|  |  |  | 	unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ? | 
					
						
							|  |  |  | 		36 * sizeof(struct v4l2_sliced_vbi_data) : | 
					
						
							|  |  |  | 		1440 * 2 * (is_60hz ? 12 : 18); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!vivid_is_sdtv_cap(dev)) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sizes[0] = size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (vq->num_buffers + *nbuffers < 2) | 
					
						
							|  |  |  | 		*nbuffers = 2 - vq->num_buffers; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*nplanes = 1; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int vbi_cap_buf_prepare(struct vb2_buffer *vb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); | 
					
						
							|  |  |  | 	bool is_60hz = dev->std_cap & V4L2_STD_525_60; | 
					
						
							|  |  |  | 	unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ? | 
					
						
							|  |  |  | 		36 * sizeof(struct v4l2_sliced_vbi_data) : | 
					
						
							|  |  |  | 		1440 * 2 * (is_60hz ? 12 : 18); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dprintk(dev, 1, "%s\n", __func__); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (dev->buf_prepare_error) { | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Error injection: test what happens if buf_prepare() returns | 
					
						
							|  |  |  | 		 * an error. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		dev->buf_prepare_error = false; | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (vb2_plane_size(vb, 0) < size) { | 
					
						
							|  |  |  | 		dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", | 
					
						
							|  |  |  | 				__func__, vb2_plane_size(vb, 0), size); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	vb2_set_plane_payload(vb, 0, size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vbi_cap_buf_queue(struct vb2_buffer *vb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); | 
					
						
							|  |  |  | 	struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dprintk(dev, 1, "%s\n", __func__); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock(&dev->slock); | 
					
						
							|  |  |  | 	list_add_tail(&buf->list, &dev->vbi_cap_active); | 
					
						
							|  |  |  | 	spin_unlock(&dev->slock); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int vbi_cap_start_streaming(struct vb2_queue *vq, unsigned count) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct vivid_dev *dev = vb2_get_drv_priv(vq); | 
					
						
							|  |  |  | 	int err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dprintk(dev, 1, "%s\n", __func__); | 
					
						
							|  |  |  | 	dev->vbi_cap_seq_count = 0; | 
					
						
							|  |  |  | 	if (dev->start_streaming_error) { | 
					
						
							|  |  |  | 		dev->start_streaming_error = false; | 
					
						
							|  |  |  | 		err = -EINVAL; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		err = vivid_start_generating_vid_cap(dev, &dev->vbi_cap_streaming); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (err) { | 
					
						
							|  |  |  | 		struct vivid_buffer *buf, *tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		list_for_each_entry_safe(buf, tmp, &dev->vbi_cap_active, list) { | 
					
						
							|  |  |  | 			list_del(&buf->list); | 
					
						
							|  |  |  | 			vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* abort streaming and wait for last buffer */ | 
					
						
							|  |  |  | static void vbi_cap_stop_streaming(struct vb2_queue *vq) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct vivid_dev *dev = vb2_get_drv_priv(vq); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dprintk(dev, 1, "%s\n", __func__); | 
					
						
							|  |  |  | 	vivid_stop_generating_vid_cap(dev, &dev->vbi_cap_streaming); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const struct vb2_ops vivid_vbi_cap_qops = { | 
					
						
							|  |  |  | 	.queue_setup		= vbi_cap_queue_setup, | 
					
						
							|  |  |  | 	.buf_prepare		= vbi_cap_buf_prepare, | 
					
						
							|  |  |  | 	.buf_queue		= vbi_cap_buf_queue, | 
					
						
							|  |  |  | 	.start_streaming	= vbi_cap_start_streaming, | 
					
						
							|  |  |  | 	.stop_streaming		= vbi_cap_stop_streaming, | 
					
						
							| 
									
										
										
										
											2014-11-18 08:23:39 -03:00
										 |  |  | 	.wait_prepare		= vb2_ops_wait_prepare, | 
					
						
							|  |  |  | 	.wait_finish		= vb2_ops_wait_finish, | 
					
						
							| 
									
										
										
										
											2014-08-25 07:56:49 -03:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, | 
					
						
							|  |  |  | 					struct v4l2_format *f) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct vivid_dev *dev = video_drvdata(file); | 
					
						
							|  |  |  | 	struct v4l2_vbi_format *vbi = &f->fmt.vbi; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!vivid_is_sdtv_cap(dev) || !dev->has_raw_vbi_cap) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vivid_g_fmt_vbi_cap(dev, vbi); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int vidioc_s_fmt_vbi_cap(struct file *file, void *priv, | 
					
						
							|  |  |  | 					struct v4l2_format *f) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct vivid_dev *dev = video_drvdata(file); | 
					
						
							|  |  |  | 	int ret = vidioc_g_fmt_vbi_cap(file, priv, f); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 	if (dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q)) | 
					
						
							|  |  |  | 		return -EBUSY; | 
					
						
							|  |  |  | 	dev->stream_sliced_vbi_cap = false; | 
					
						
							|  |  |  | 	dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_VBI_CAPTURE; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_set) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	vbi->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; | 
					
						
							|  |  |  | 	vbi->service_set = service_set; | 
					
						
							|  |  |  | 	memset(vbi->service_lines, 0, sizeof(vbi->service_lines)); | 
					
						
							|  |  |  | 	memset(vbi->reserved, 0, sizeof(vbi->reserved)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (vbi->service_set == 0) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (vbi->service_set & V4L2_SLICED_CAPTION_525) { | 
					
						
							|  |  |  | 		vbi->service_lines[0][21] = V4L2_SLICED_CAPTION_525; | 
					
						
							|  |  |  | 		vbi->service_lines[1][21] = V4L2_SLICED_CAPTION_525; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-09-20 06:11:44 -03:00
										 |  |  | 	if (vbi->service_set & V4L2_SLICED_WSS_625) { | 
					
						
							|  |  |  | 		unsigned i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (i = 7; i <= 18; i++) | 
					
						
							|  |  |  | 			vbi->service_lines[0][i] = | 
					
						
							|  |  |  | 			vbi->service_lines[1][i] = V4L2_SLICED_TELETEXT_B; | 
					
						
							| 
									
										
										
										
											2014-08-25 07:56:49 -03:00
										 |  |  | 		vbi->service_lines[0][23] = V4L2_SLICED_WSS_625; | 
					
						
							| 
									
										
										
										
											2014-09-20 06:11:44 -03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-08-25 07:56:49 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct vivid_dev *dev = video_drvdata(file); | 
					
						
							|  |  |  | 	struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vivid_fill_service_lines(vbi, dev->service_set_cap); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct vivid_dev *dev = video_drvdata(file); | 
					
						
							|  |  |  | 	struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; | 
					
						
							|  |  |  | 	bool is_60hz = dev->std_cap & V4L2_STD_525_60; | 
					
						
							|  |  |  | 	u32 service_set = vbi->service_set; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-20 06:11:44 -03:00
										 |  |  | 	service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 : | 
					
						
							|  |  |  | 				 V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; | 
					
						
							| 
									
										
										
										
											2014-08-25 07:56:49 -03:00
										 |  |  | 	vivid_fill_service_lines(vbi, service_set); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct vivid_dev *dev = video_drvdata(file); | 
					
						
							|  |  |  | 	struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; | 
					
						
							|  |  |  | 	int ret = vidioc_try_fmt_sliced_vbi_cap(file, fh, fmt); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 	if (!dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q)) | 
					
						
							|  |  |  | 		return -EBUSY; | 
					
						
							|  |  |  | 	dev->service_set_cap = vbi->service_set; | 
					
						
							|  |  |  | 	dev->stream_sliced_vbi_cap = true; | 
					
						
							|  |  |  | 	dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct vivid_dev *dev = video_drvdata(file); | 
					
						
							|  |  |  | 	struct video_device *vdev = video_devdata(file); | 
					
						
							|  |  |  | 	bool is_60hz; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (vdev->vfl_dir == VFL_DIR_RX) { | 
					
						
							|  |  |  | 		is_60hz = dev->std_cap & V4L2_STD_525_60; | 
					
						
							|  |  |  | 		if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap || | 
					
						
							|  |  |  | 		    cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) | 
					
						
							|  |  |  | 			return -EINVAL; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		is_60hz = dev->std_out & V4L2_STD_525_60; | 
					
						
							|  |  |  | 		if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out || | 
					
						
							|  |  |  | 		    cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) | 
					
						
							|  |  |  | 			return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-20 06:11:44 -03:00
										 |  |  | 	cap->service_set = is_60hz ? V4L2_SLICED_CAPTION_525 : | 
					
						
							|  |  |  | 				     V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; | 
					
						
							| 
									
										
										
										
											2014-08-25 07:56:49 -03:00
										 |  |  | 	if (is_60hz) { | 
					
						
							|  |  |  | 		cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525; | 
					
						
							|  |  |  | 		cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525; | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2014-09-20 06:11:44 -03:00
										 |  |  | 		unsigned i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (i = 7; i <= 18; i++) | 
					
						
							|  |  |  | 			cap->service_lines[0][i] = | 
					
						
							|  |  |  | 			cap->service_lines[1][i] = V4L2_SLICED_TELETEXT_B; | 
					
						
							| 
									
										
										
										
											2014-08-25 07:56:49 -03:00
										 |  |  | 		cap->service_lines[0][23] = V4L2_SLICED_WSS_625; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } |