xref: /linux/drivers/media/pci/ivtv/ivtv-streams.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
1b285192aSMauro Carvalho Chehab /*
2b285192aSMauro Carvalho Chehab     init/start/stop/exit stream functions
3b285192aSMauro Carvalho Chehab     Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
4b285192aSMauro Carvalho Chehab     Copyright (C) 2004  Chris Kennedy <c@groovy.org>
5b285192aSMauro Carvalho Chehab     Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
6b285192aSMauro Carvalho Chehab 
7b285192aSMauro Carvalho Chehab     This program is free software; you can redistribute it and/or modify
8b285192aSMauro Carvalho Chehab     it under the terms of the GNU General Public License as published by
9b285192aSMauro Carvalho Chehab     the Free Software Foundation; either version 2 of the License, or
10b285192aSMauro Carvalho Chehab     (at your option) any later version.
11b285192aSMauro Carvalho Chehab 
12b285192aSMauro Carvalho Chehab     This program is distributed in the hope that it will be useful,
13b285192aSMauro Carvalho Chehab     but WITHOUT ANY WARRANTY; without even the implied warranty of
14b285192aSMauro Carvalho Chehab     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15b285192aSMauro Carvalho Chehab     GNU General Public License for more details.
16b285192aSMauro Carvalho Chehab 
17b285192aSMauro Carvalho Chehab     You should have received a copy of the GNU General Public License
18b285192aSMauro Carvalho Chehab     along with this program; if not, write to the Free Software
19b285192aSMauro Carvalho Chehab     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20b285192aSMauro Carvalho Chehab  */
21b285192aSMauro Carvalho Chehab 
22b285192aSMauro Carvalho Chehab /* License: GPL
23b285192aSMauro Carvalho Chehab  * Author: Kevin Thayer <nufan_wfk at yahoo dot com>
24b285192aSMauro Carvalho Chehab  *
25b285192aSMauro Carvalho Chehab  * This file will hold API related functions, both internal (firmware api)
26b285192aSMauro Carvalho Chehab  * and external (v4l2, etc)
27b285192aSMauro Carvalho Chehab  *
28b285192aSMauro Carvalho Chehab  * -----
29b285192aSMauro Carvalho Chehab  * MPG600/MPG160 support by  T.Adachi <tadachi@tadachi-net.com>
30b285192aSMauro Carvalho Chehab  *                      and Takeru KOMORIYA<komoriya@paken.org>
31b285192aSMauro Carvalho Chehab  *
32b285192aSMauro Carvalho Chehab  * AVerMedia M179 GPIO info by Chris Pinkham <cpinkham@bc2va.org>
33b285192aSMauro Carvalho Chehab  *                using information provided by Jiun-Kuei Jung @ AVerMedia.
34b285192aSMauro Carvalho Chehab  */
35b285192aSMauro Carvalho Chehab 
36b285192aSMauro Carvalho Chehab #include "ivtv-driver.h"
37b285192aSMauro Carvalho Chehab #include "ivtv-fileops.h"
38b285192aSMauro Carvalho Chehab #include "ivtv-queue.h"
39b285192aSMauro Carvalho Chehab #include "ivtv-mailbox.h"
40b285192aSMauro Carvalho Chehab #include "ivtv-ioctl.h"
41b285192aSMauro Carvalho Chehab #include "ivtv-irq.h"
42b285192aSMauro Carvalho Chehab #include "ivtv-yuv.h"
43b285192aSMauro Carvalho Chehab #include "ivtv-cards.h"
44b285192aSMauro Carvalho Chehab #include "ivtv-streams.h"
45b285192aSMauro Carvalho Chehab #include "ivtv-firmware.h"
46b285192aSMauro Carvalho Chehab #include <media/v4l2-event.h>
47b285192aSMauro Carvalho Chehab 
48b285192aSMauro Carvalho Chehab static const struct v4l2_file_operations ivtv_v4l2_enc_fops = {
49b285192aSMauro Carvalho Chehab 	.owner = THIS_MODULE,
50b285192aSMauro Carvalho Chehab 	.read = ivtv_v4l2_read,
51b285192aSMauro Carvalho Chehab 	.write = ivtv_v4l2_write,
52b285192aSMauro Carvalho Chehab 	.open = ivtv_v4l2_open,
53b285192aSMauro Carvalho Chehab 	.unlocked_ioctl = video_ioctl2,
548a24280bSArnd Bergmann #ifdef CONFIG_COMPAT
558a24280bSArnd Bergmann 	.compat_ioctl32 = video_ioctl2, /* for ivtv_default() */
568a24280bSArnd Bergmann #endif
57b285192aSMauro Carvalho Chehab 	.release = ivtv_v4l2_close,
58b285192aSMauro Carvalho Chehab 	.poll = ivtv_v4l2_enc_poll,
59b285192aSMauro Carvalho Chehab };
60b285192aSMauro Carvalho Chehab 
61b285192aSMauro Carvalho Chehab static const struct v4l2_file_operations ivtv_v4l2_dec_fops = {
62b285192aSMauro Carvalho Chehab 	.owner = THIS_MODULE,
63b285192aSMauro Carvalho Chehab 	.read = ivtv_v4l2_read,
64b285192aSMauro Carvalho Chehab 	.write = ivtv_v4l2_write,
65b285192aSMauro Carvalho Chehab 	.open = ivtv_v4l2_open,
66b285192aSMauro Carvalho Chehab 	.unlocked_ioctl = video_ioctl2,
678a24280bSArnd Bergmann #ifdef CONFIG_COMPAT
688a24280bSArnd Bergmann 	.compat_ioctl32 = video_ioctl2, /* for ivtv_default() */
698a24280bSArnd Bergmann #endif
70b285192aSMauro Carvalho Chehab 	.release = ivtv_v4l2_close,
71b285192aSMauro Carvalho Chehab 	.poll = ivtv_v4l2_dec_poll,
72b285192aSMauro Carvalho Chehab };
73b285192aSMauro Carvalho Chehab 
747eaf4966SHans Verkuil static const struct v4l2_file_operations ivtv_v4l2_radio_fops = {
757eaf4966SHans Verkuil 	.owner = THIS_MODULE,
767eaf4966SHans Verkuil 	.open = ivtv_v4l2_open,
777eaf4966SHans Verkuil 	.unlocked_ioctl = video_ioctl2,
788a24280bSArnd Bergmann #ifdef CONFIG_COMPAT
798a24280bSArnd Bergmann 	.compat_ioctl32 = video_ioctl2, /* for ivtv_default() */
808a24280bSArnd Bergmann #endif
817eaf4966SHans Verkuil 	.release = ivtv_v4l2_close,
827eaf4966SHans Verkuil 	.poll = ivtv_v4l2_enc_poll,
837eaf4966SHans Verkuil };
847eaf4966SHans Verkuil 
85b285192aSMauro Carvalho Chehab #define IVTV_V4L2_DEC_MPG_OFFSET  16	/* offset from 0 to register decoder mpg v4l2 minors on */
86b285192aSMauro Carvalho Chehab #define IVTV_V4L2_ENC_PCM_OFFSET  24	/* offset from 0 to register pcm v4l2 minors on */
87b285192aSMauro Carvalho Chehab #define IVTV_V4L2_ENC_YUV_OFFSET  32	/* offset from 0 to register yuv v4l2 minors on */
88b285192aSMauro Carvalho Chehab #define IVTV_V4L2_DEC_YUV_OFFSET  48	/* offset from 0 to register decoder yuv v4l2 minors on */
89b285192aSMauro Carvalho Chehab #define IVTV_V4L2_DEC_VBI_OFFSET   8	/* offset from 0 to register decoder vbi input v4l2 minors on */
90b285192aSMauro Carvalho Chehab #define IVTV_V4L2_DEC_VOUT_OFFSET 16	/* offset from 0 to register vbi output v4l2 minors on */
91b285192aSMauro Carvalho Chehab 
92b285192aSMauro Carvalho Chehab static struct {
93b285192aSMauro Carvalho Chehab 	const char *name;
94b285192aSMauro Carvalho Chehab 	int vfl_type;
95b285192aSMauro Carvalho Chehab 	int num_offset;
96b285192aSMauro Carvalho Chehab 	int dma, pio;
97b285192aSMauro Carvalho Chehab 	u32 v4l2_caps;
98b285192aSMauro Carvalho Chehab 	const struct v4l2_file_operations *fops;
99b285192aSMauro Carvalho Chehab } ivtv_stream_info[] = {
100b285192aSMauro Carvalho Chehab 	{	/* IVTV_ENC_STREAM_TYPE_MPG */
101b285192aSMauro Carvalho Chehab 		"encoder MPG",
1023e30a927SHans Verkuil 		VFL_TYPE_VIDEO, 0,
1031932dc2fSChristophe JAILLET 		DMA_FROM_DEVICE, 0,
104b285192aSMauro Carvalho Chehab 		V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
105b285192aSMauro Carvalho Chehab 			V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
106b285192aSMauro Carvalho Chehab 		&ivtv_v4l2_enc_fops
107b285192aSMauro Carvalho Chehab 	},
108b285192aSMauro Carvalho Chehab 	{	/* IVTV_ENC_STREAM_TYPE_YUV */
109b285192aSMauro Carvalho Chehab 		"encoder YUV",
1103e30a927SHans Verkuil 		VFL_TYPE_VIDEO, IVTV_V4L2_ENC_YUV_OFFSET,
1111932dc2fSChristophe JAILLET 		DMA_FROM_DEVICE, 0,
112b285192aSMauro Carvalho Chehab 		V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
113b285192aSMauro Carvalho Chehab 			V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
114b285192aSMauro Carvalho Chehab 		&ivtv_v4l2_enc_fops
115b285192aSMauro Carvalho Chehab 	},
116b285192aSMauro Carvalho Chehab 	{	/* IVTV_ENC_STREAM_TYPE_VBI */
117b285192aSMauro Carvalho Chehab 		"encoder VBI",
118b285192aSMauro Carvalho Chehab 		VFL_TYPE_VBI, 0,
1191932dc2fSChristophe JAILLET 		DMA_FROM_DEVICE, 0,
120b285192aSMauro Carvalho Chehab 		V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_TUNER |
121b285192aSMauro Carvalho Chehab 			V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
122b285192aSMauro Carvalho Chehab 		&ivtv_v4l2_enc_fops
123b285192aSMauro Carvalho Chehab 	},
124b285192aSMauro Carvalho Chehab 	{	/* IVTV_ENC_STREAM_TYPE_PCM */
125b285192aSMauro Carvalho Chehab 		"encoder PCM",
1263e30a927SHans Verkuil 		VFL_TYPE_VIDEO, IVTV_V4L2_ENC_PCM_OFFSET,
1271932dc2fSChristophe JAILLET 		DMA_FROM_DEVICE, 0,
128b285192aSMauro Carvalho Chehab 		V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
129b285192aSMauro Carvalho Chehab 		&ivtv_v4l2_enc_fops
130b285192aSMauro Carvalho Chehab 	},
131b285192aSMauro Carvalho Chehab 	{	/* IVTV_ENC_STREAM_TYPE_RAD */
132b285192aSMauro Carvalho Chehab 		"encoder radio",
133b285192aSMauro Carvalho Chehab 		VFL_TYPE_RADIO, 0,
1341932dc2fSChristophe JAILLET 		DMA_NONE, 1,
135b285192aSMauro Carvalho Chehab 		V4L2_CAP_RADIO | V4L2_CAP_TUNER,
1367eaf4966SHans Verkuil 		&ivtv_v4l2_radio_fops
137b285192aSMauro Carvalho Chehab 	},
138b285192aSMauro Carvalho Chehab 	{	/* IVTV_DEC_STREAM_TYPE_MPG */
139b285192aSMauro Carvalho Chehab 		"decoder MPG",
1403e30a927SHans Verkuil 		VFL_TYPE_VIDEO, IVTV_V4L2_DEC_MPG_OFFSET,
1411932dc2fSChristophe JAILLET 		DMA_TO_DEVICE, 0,
14221615365SHans Verkuil 		V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
143b285192aSMauro Carvalho Chehab 		&ivtv_v4l2_dec_fops
144b285192aSMauro Carvalho Chehab 	},
145b285192aSMauro Carvalho Chehab 	{	/* IVTV_DEC_STREAM_TYPE_VBI */
146b285192aSMauro Carvalho Chehab 		"decoder VBI",
147b285192aSMauro Carvalho Chehab 		VFL_TYPE_VBI, IVTV_V4L2_DEC_VBI_OFFSET,
1481932dc2fSChristophe JAILLET 		DMA_NONE, 1,
149b285192aSMauro Carvalho Chehab 		V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_READWRITE,
150b285192aSMauro Carvalho Chehab 		&ivtv_v4l2_enc_fops
151b285192aSMauro Carvalho Chehab 	},
152b285192aSMauro Carvalho Chehab 	{	/* IVTV_DEC_STREAM_TYPE_VOUT */
153b285192aSMauro Carvalho Chehab 		"decoder VOUT",
154b285192aSMauro Carvalho Chehab 		VFL_TYPE_VBI, IVTV_V4L2_DEC_VOUT_OFFSET,
1551932dc2fSChristophe JAILLET 		DMA_NONE, 1,
156b285192aSMauro Carvalho Chehab 		V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
157b285192aSMauro Carvalho Chehab 		&ivtv_v4l2_dec_fops
158b285192aSMauro Carvalho Chehab 	},
159b285192aSMauro Carvalho Chehab 	{	/* IVTV_DEC_STREAM_TYPE_YUV */
160b285192aSMauro Carvalho Chehab 		"decoder YUV",
1613e30a927SHans Verkuil 		VFL_TYPE_VIDEO, IVTV_V4L2_DEC_YUV_OFFSET,
1621932dc2fSChristophe JAILLET 		DMA_TO_DEVICE, 0,
16321615365SHans Verkuil 		V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
164b285192aSMauro Carvalho Chehab 		&ivtv_v4l2_dec_fops
165b285192aSMauro Carvalho Chehab 	}
166b285192aSMauro Carvalho Chehab };
167b285192aSMauro Carvalho Chehab 
ivtv_stream_init(struct ivtv * itv,int type)168b285192aSMauro Carvalho Chehab static void ivtv_stream_init(struct ivtv *itv, int type)
169b285192aSMauro Carvalho Chehab {
170b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s = &itv->streams[type];
171b285192aSMauro Carvalho Chehab 
172b285192aSMauro Carvalho Chehab 	/* we need to keep vdev, so restore it afterwards */
173b285192aSMauro Carvalho Chehab 	memset(s, 0, sizeof(*s));
174b285192aSMauro Carvalho Chehab 
175b285192aSMauro Carvalho Chehab 	/* initialize ivtv_stream fields */
176b285192aSMauro Carvalho Chehab 	s->itv = itv;
177b285192aSMauro Carvalho Chehab 	s->type = type;
178b285192aSMauro Carvalho Chehab 	s->name = ivtv_stream_info[type].name;
17925e94139SHans Verkuil 	s->vdev.device_caps = ivtv_stream_info[type].v4l2_caps;
180b285192aSMauro Carvalho Chehab 
181b285192aSMauro Carvalho Chehab 	if (ivtv_stream_info[type].pio)
1821932dc2fSChristophe JAILLET 		s->dma = DMA_NONE;
183b285192aSMauro Carvalho Chehab 	else
184b285192aSMauro Carvalho Chehab 		s->dma = ivtv_stream_info[type].dma;
185b285192aSMauro Carvalho Chehab 	s->buf_size = itv->stream_buf_size[type];
186b285192aSMauro Carvalho Chehab 	if (s->buf_size)
187b285192aSMauro Carvalho Chehab 		s->buffers = (itv->options.kilobytes[type] * 1024 + s->buf_size - 1) / s->buf_size;
188b285192aSMauro Carvalho Chehab 	spin_lock_init(&s->qlock);
189b285192aSMauro Carvalho Chehab 	init_waitqueue_head(&s->waitq);
190b285192aSMauro Carvalho Chehab 	s->sg_handle = IVTV_DMA_UNMAPPED;
191b285192aSMauro Carvalho Chehab 	ivtv_queue_init(&s->q_free);
192b285192aSMauro Carvalho Chehab 	ivtv_queue_init(&s->q_full);
193b285192aSMauro Carvalho Chehab 	ivtv_queue_init(&s->q_dma);
194b285192aSMauro Carvalho Chehab 	ivtv_queue_init(&s->q_predma);
195b285192aSMauro Carvalho Chehab 	ivtv_queue_init(&s->q_io);
196b285192aSMauro Carvalho Chehab }
197b285192aSMauro Carvalho Chehab 
ivtv_prep_dev(struct ivtv * itv,int type)198b285192aSMauro Carvalho Chehab static int ivtv_prep_dev(struct ivtv *itv, int type)
199b285192aSMauro Carvalho Chehab {
200b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s = &itv->streams[type];
201b285192aSMauro Carvalho Chehab 	int num_offset = ivtv_stream_info[type].num_offset;
202b285192aSMauro Carvalho Chehab 	int num = itv->instance + ivtv_first_minor + num_offset;
203b285192aSMauro Carvalho Chehab 
204635d62f0SHans Verkuil 	/* These four fields are always initialized. If vdev.v4l2_dev == NULL, then
205b285192aSMauro Carvalho Chehab 	   this stream is not in use. In that case no other fields but these
206b285192aSMauro Carvalho Chehab 	   four can be used. */
207635d62f0SHans Verkuil 	s->vdev.v4l2_dev = NULL;
208b285192aSMauro Carvalho Chehab 	s->itv = itv;
209b285192aSMauro Carvalho Chehab 	s->type = type;
210b285192aSMauro Carvalho Chehab 	s->name = ivtv_stream_info[type].name;
211b285192aSMauro Carvalho Chehab 
212b285192aSMauro Carvalho Chehab 	/* Check whether the radio is supported */
213b285192aSMauro Carvalho Chehab 	if (type == IVTV_ENC_STREAM_TYPE_RAD && !(itv->v4l2_cap & V4L2_CAP_RADIO))
214b285192aSMauro Carvalho Chehab 		return 0;
215b285192aSMauro Carvalho Chehab 	if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
216b285192aSMauro Carvalho Chehab 		return 0;
217b285192aSMauro Carvalho Chehab 
218b285192aSMauro Carvalho Chehab 	/* User explicitly selected 0 buffers for these streams, so don't
219b285192aSMauro Carvalho Chehab 	   create them. */
2201932dc2fSChristophe JAILLET 	if (ivtv_stream_info[type].dma != DMA_NONE &&
221b285192aSMauro Carvalho Chehab 	    itv->options.kilobytes[type] == 0) {
222b285192aSMauro Carvalho Chehab 		IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name);
223b285192aSMauro Carvalho Chehab 		return 0;
224b285192aSMauro Carvalho Chehab 	}
225b285192aSMauro Carvalho Chehab 
226b285192aSMauro Carvalho Chehab 	ivtv_stream_init(itv, type);
227b285192aSMauro Carvalho Chehab 
228635d62f0SHans Verkuil 	snprintf(s->vdev.name, sizeof(s->vdev.name), "%s %s",
229b285192aSMauro Carvalho Chehab 			itv->v4l2_dev.name, s->name);
230b285192aSMauro Carvalho Chehab 
231635d62f0SHans Verkuil 	s->vdev.num = num;
232635d62f0SHans Verkuil 	s->vdev.v4l2_dev = &itv->v4l2_dev;
233954f340fSHans Verkuil 	if (ivtv_stream_info[type].v4l2_caps &
234954f340fSHans Verkuil 			(V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_SLICED_VBI_OUTPUT))
235635d62f0SHans Verkuil 		s->vdev.vfl_dir = VFL_DIR_TX;
236635d62f0SHans Verkuil 	s->vdev.fops = ivtv_stream_info[type].fops;
237635d62f0SHans Verkuil 	s->vdev.ctrl_handler = itv->v4l2_dev.ctrl_handler;
238635d62f0SHans Verkuil 	s->vdev.release = video_device_release_empty;
239635d62f0SHans Verkuil 	s->vdev.tvnorms = V4L2_STD_ALL;
240635d62f0SHans Verkuil 	s->vdev.lock = &itv->serialize_lock;
2415f9c82c0SHans Verkuil 	if (s->type == IVTV_DEC_STREAM_TYPE_VBI) {
242635d62f0SHans Verkuil 		v4l2_disable_ioctl(&s->vdev, VIDIOC_S_AUDIO);
243635d62f0SHans Verkuil 		v4l2_disable_ioctl(&s->vdev, VIDIOC_G_AUDIO);
244635d62f0SHans Verkuil 		v4l2_disable_ioctl(&s->vdev, VIDIOC_ENUMAUDIO);
245635d62f0SHans Verkuil 		v4l2_disable_ioctl(&s->vdev, VIDIOC_ENUMINPUT);
246635d62f0SHans Verkuil 		v4l2_disable_ioctl(&s->vdev, VIDIOC_S_INPUT);
247635d62f0SHans Verkuil 		v4l2_disable_ioctl(&s->vdev, VIDIOC_G_INPUT);
248635d62f0SHans Verkuil 		v4l2_disable_ioctl(&s->vdev, VIDIOC_S_FREQUENCY);
249635d62f0SHans Verkuil 		v4l2_disable_ioctl(&s->vdev, VIDIOC_G_FREQUENCY);
250635d62f0SHans Verkuil 		v4l2_disable_ioctl(&s->vdev, VIDIOC_S_TUNER);
251635d62f0SHans Verkuil 		v4l2_disable_ioctl(&s->vdev, VIDIOC_G_TUNER);
252635d62f0SHans Verkuil 		v4l2_disable_ioctl(&s->vdev, VIDIOC_S_STD);
2535f9c82c0SHans Verkuil 	}
254635d62f0SHans Verkuil 	ivtv_set_funcs(&s->vdev);
255b285192aSMauro Carvalho Chehab 	return 0;
256b285192aSMauro Carvalho Chehab }
257b285192aSMauro Carvalho Chehab 
258b285192aSMauro Carvalho Chehab /* Initialize v4l2 variables and prepare v4l2 devices */
ivtv_streams_setup(struct ivtv * itv)259b285192aSMauro Carvalho Chehab int ivtv_streams_setup(struct ivtv *itv)
260b285192aSMauro Carvalho Chehab {
261b285192aSMauro Carvalho Chehab 	int type;
262b285192aSMauro Carvalho Chehab 
263b285192aSMauro Carvalho Chehab 	/* Setup V4L2 Devices */
264b285192aSMauro Carvalho Chehab 	for (type = 0; type < IVTV_MAX_STREAMS; type++) {
265b285192aSMauro Carvalho Chehab 		/* Prepare device */
266b285192aSMauro Carvalho Chehab 		if (ivtv_prep_dev(itv, type))
267b285192aSMauro Carvalho Chehab 			break;
268b285192aSMauro Carvalho Chehab 
269635d62f0SHans Verkuil 		if (itv->streams[type].vdev.v4l2_dev == NULL)
270b285192aSMauro Carvalho Chehab 			continue;
271b285192aSMauro Carvalho Chehab 
272b285192aSMauro Carvalho Chehab 		/* Allocate Stream */
273b285192aSMauro Carvalho Chehab 		if (ivtv_stream_alloc(&itv->streams[type]))
274b285192aSMauro Carvalho Chehab 			break;
275b285192aSMauro Carvalho Chehab 	}
276b285192aSMauro Carvalho Chehab 	if (type == IVTV_MAX_STREAMS)
277b285192aSMauro Carvalho Chehab 		return 0;
278b285192aSMauro Carvalho Chehab 
279b285192aSMauro Carvalho Chehab 	/* One or more streams could not be initialized. Clean 'em all up. */
280635d62f0SHans Verkuil 	ivtv_streams_cleanup(itv);
281b285192aSMauro Carvalho Chehab 	return -ENOMEM;
282b285192aSMauro Carvalho Chehab }
283b285192aSMauro Carvalho Chehab 
ivtv_reg_dev(struct ivtv * itv,int type)284b285192aSMauro Carvalho Chehab static int ivtv_reg_dev(struct ivtv *itv, int type)
285b285192aSMauro Carvalho Chehab {
286b285192aSMauro Carvalho Chehab 	struct ivtv_stream *s = &itv->streams[type];
287b285192aSMauro Carvalho Chehab 	int vfl_type = ivtv_stream_info[type].vfl_type;
288b285192aSMauro Carvalho Chehab 	const char *name;
289b285192aSMauro Carvalho Chehab 	int num;
290b285192aSMauro Carvalho Chehab 
291635d62f0SHans Verkuil 	if (s->vdev.v4l2_dev == NULL)
292b285192aSMauro Carvalho Chehab 		return 0;
293b285192aSMauro Carvalho Chehab 
294635d62f0SHans Verkuil 	num = s->vdev.num;
295b285192aSMauro Carvalho Chehab 	/* card number + user defined offset + device offset */
296b285192aSMauro Carvalho Chehab 	if (type != IVTV_ENC_STREAM_TYPE_MPG) {
297b285192aSMauro Carvalho Chehab 		struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG];
298b285192aSMauro Carvalho Chehab 
299635d62f0SHans Verkuil 		if (s_mpg->vdev.v4l2_dev)
300635d62f0SHans Verkuil 			num = s_mpg->vdev.num + ivtv_stream_info[type].num_offset;
301b285192aSMauro Carvalho Chehab 	}
30225e94139SHans Verkuil 	if (itv->osd_video_pbase && (type == IVTV_DEC_STREAM_TYPE_YUV ||
30325e94139SHans Verkuil 				     type == IVTV_DEC_STREAM_TYPE_MPG)) {
30425e94139SHans Verkuil 		s->vdev.device_caps |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
30521615365SHans Verkuil 		itv->v4l2_cap |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
30621615365SHans Verkuil 	}
307635d62f0SHans Verkuil 	video_set_drvdata(&s->vdev, s);
308b285192aSMauro Carvalho Chehab 
309b285192aSMauro Carvalho Chehab 	/* Register device. First try the desired minor, then any free one. */
310635d62f0SHans Verkuil 	if (video_register_device_no_warn(&s->vdev, vfl_type, num)) {
311b285192aSMauro Carvalho Chehab 		IVTV_ERR("Couldn't register v4l2 device for %s (device node number %d)\n",
312b285192aSMauro Carvalho Chehab 				s->name, num);
313b285192aSMauro Carvalho Chehab 		return -ENOMEM;
314b285192aSMauro Carvalho Chehab 	}
315635d62f0SHans Verkuil 	name = video_device_node_name(&s->vdev);
316b285192aSMauro Carvalho Chehab 
317b285192aSMauro Carvalho Chehab 	switch (vfl_type) {
3183e30a927SHans Verkuil 	case VFL_TYPE_VIDEO:
319b285192aSMauro Carvalho Chehab 		IVTV_INFO("Registered device %s for %s (%d kB)\n",
320b285192aSMauro Carvalho Chehab 			name, s->name, itv->options.kilobytes[type]);
321b285192aSMauro Carvalho Chehab 		break;
322b285192aSMauro Carvalho Chehab 	case VFL_TYPE_RADIO:
323b285192aSMauro Carvalho Chehab 		IVTV_INFO("Registered device %s for %s\n",
324b285192aSMauro Carvalho Chehab 			name, s->name);
325b285192aSMauro Carvalho Chehab 		break;
326b285192aSMauro Carvalho Chehab 	case VFL_TYPE_VBI:
327b285192aSMauro Carvalho Chehab 		if (itv->options.kilobytes[type])
328b285192aSMauro Carvalho Chehab 			IVTV_INFO("Registered device %s for %s (%d kB)\n",
329b285192aSMauro Carvalho Chehab 				name, s->name, itv->options.kilobytes[type]);
330b285192aSMauro Carvalho Chehab 		else
331b285192aSMauro Carvalho Chehab 			IVTV_INFO("Registered device %s for %s\n",
332b285192aSMauro Carvalho Chehab 				name, s->name);
333b285192aSMauro Carvalho Chehab 		break;
334b285192aSMauro Carvalho Chehab 	}
335b285192aSMauro Carvalho Chehab 	return 0;
336b285192aSMauro Carvalho Chehab }
337b285192aSMauro Carvalho Chehab 
338b285192aSMauro Carvalho Chehab /* Register v4l2 devices */
ivtv_streams_register(struct ivtv * itv)339b285192aSMauro Carvalho Chehab int ivtv_streams_register(struct ivtv *itv)
340b285192aSMauro Carvalho Chehab {
341b285192aSMauro Carvalho Chehab 	int type;
342b285192aSMauro Carvalho Chehab 	int err = 0;
343b285192aSMauro Carvalho Chehab 
344b285192aSMauro Carvalho Chehab 	/* Register V4L2 devices */
345b285192aSMauro Carvalho Chehab 	for (type = 0; type < IVTV_MAX_STREAMS; type++)
346b285192aSMauro Carvalho Chehab 		err |= ivtv_reg_dev(itv, type);
347b285192aSMauro Carvalho Chehab 
348b285192aSMauro Carvalho Chehab 	if (err == 0)
349b285192aSMauro Carvalho Chehab 		return 0;
350b285192aSMauro Carvalho Chehab 
351b285192aSMauro Carvalho Chehab 	/* One or more streams could not be initialized. Clean 'em all up. */
352635d62f0SHans Verkuil 	ivtv_streams_cleanup(itv);
353b285192aSMauro Carvalho Chehab 	return -ENOMEM;
354b285192aSMauro Carvalho Chehab }
355b285192aSMauro Carvalho Chehab 
356b285192aSMauro Carvalho Chehab /* Unregister v4l2 devices */
ivtv_streams_cleanup(struct ivtv * itv)357635d62f0SHans Verkuil void ivtv_streams_cleanup(struct ivtv *itv)
358b285192aSMauro Carvalho Chehab {
359b285192aSMauro Carvalho Chehab 	int type;
360b285192aSMauro Carvalho Chehab 
361b285192aSMauro Carvalho Chehab 	/* Teardown all streams */
362b285192aSMauro Carvalho Chehab 	for (type = 0; type < IVTV_MAX_STREAMS; type++) {
363635d62f0SHans Verkuil 		struct video_device *vdev = &itv->streams[type].vdev;
364b285192aSMauro Carvalho Chehab 
365635d62f0SHans Verkuil 		if (vdev->v4l2_dev == NULL)
366b285192aSMauro Carvalho Chehab 			continue;
367b285192aSMauro Carvalho Chehab 
368b285192aSMauro Carvalho Chehab 		video_unregister_device(vdev);
369635d62f0SHans Verkuil 		ivtv_stream_free(&itv->streams[type]);
370635d62f0SHans Verkuil 		itv->streams[type].vdev.v4l2_dev = NULL;
371b285192aSMauro Carvalho Chehab 	}
372b285192aSMauro Carvalho Chehab }
373b285192aSMauro Carvalho Chehab 
ivtv_vbi_setup(struct ivtv * itv)374b285192aSMauro Carvalho Chehab static void ivtv_vbi_setup(struct ivtv *itv)
375b285192aSMauro Carvalho Chehab {
376b285192aSMauro Carvalho Chehab 	int raw = ivtv_raw_vbi(itv);
377b285192aSMauro Carvalho Chehab 	u32 data[CX2341X_MBOX_MAX_DATA];
378b285192aSMauro Carvalho Chehab 	int lines;
379b285192aSMauro Carvalho Chehab 	int i;
380b285192aSMauro Carvalho Chehab 
381b285192aSMauro Carvalho Chehab 	/* Reset VBI */
382b285192aSMauro Carvalho Chehab 	ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0);
383b285192aSMauro Carvalho Chehab 
384b285192aSMauro Carvalho Chehab 	/* setup VBI registers */
385b285192aSMauro Carvalho Chehab 	if (raw)
386b285192aSMauro Carvalho Chehab 		v4l2_subdev_call(itv->sd_video, vbi, s_raw_fmt, &itv->vbi.in.fmt.vbi);
387b285192aSMauro Carvalho Chehab 	else
388b285192aSMauro Carvalho Chehab 		v4l2_subdev_call(itv->sd_video, vbi, s_sliced_fmt, &itv->vbi.in.fmt.sliced);
389b285192aSMauro Carvalho Chehab 
390b285192aSMauro Carvalho Chehab 	/* determine number of lines and total number of VBI bytes.
391b285192aSMauro Carvalho Chehab 	   A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1
392b285192aSMauro Carvalho Chehab 	   The '- 1' byte is probably an unused U or V byte. Or something...
393b285192aSMauro Carvalho Chehab 	   A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal
394b285192aSMauro Carvalho Chehab 	   header, 42 data bytes + checksum (to be confirmed) */
395b285192aSMauro Carvalho Chehab 	if (raw) {
396b285192aSMauro Carvalho Chehab 		lines = itv->vbi.count * 2;
397b285192aSMauro Carvalho Chehab 	} else {
398b285192aSMauro Carvalho Chehab 		lines = itv->is_60hz ? 24 : 38;
399b285192aSMauro Carvalho Chehab 		if (itv->is_60hz && (itv->hw_flags & IVTV_HW_CX25840))
400b285192aSMauro Carvalho Chehab 			lines += 2;
401b285192aSMauro Carvalho Chehab 	}
402b285192aSMauro Carvalho Chehab 
403b285192aSMauro Carvalho Chehab 	itv->vbi.enc_size = lines * (raw ? itv->vbi.raw_size : itv->vbi.sliced_size);
404b285192aSMauro Carvalho Chehab 
405b285192aSMauro Carvalho Chehab 	/* Note: sliced vs raw flag doesn't seem to have any effect
406b285192aSMauro Carvalho Chehab 	   TODO: check mode (0x02) value with older ivtv versions. */
407b285192aSMauro Carvalho Chehab 	data[0] = raw | 0x02 | (0xbd << 8);
408b285192aSMauro Carvalho Chehab 
409b285192aSMauro Carvalho Chehab 	/* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */
410b285192aSMauro Carvalho Chehab 	data[1] = 1;
411b285192aSMauro Carvalho Chehab 	/* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */
412b285192aSMauro Carvalho Chehab 	data[2] = raw ? 4 : 4 * (itv->vbi.raw_size / itv->vbi.enc_size);
413b285192aSMauro Carvalho Chehab 	/* The start/stop codes determine which VBI lines end up in the raw VBI data area.
414b285192aSMauro Carvalho Chehab 	   The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line
415b285192aSMauro Carvalho Chehab 	   is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video)
416b285192aSMauro Carvalho Chehab 	   code. These values for raw VBI are obtained from a driver disassembly. The sliced
417b285192aSMauro Carvalho Chehab 	   start/stop codes was deduced from this, but they do not appear in the driver.
418b285192aSMauro Carvalho Chehab 	   Other code pairs that I found are: 0x250E6249/0x13545454 and 0x25256262/0x38137F54.
419b285192aSMauro Carvalho Chehab 	   However, I have no idea what these values are for. */
420b285192aSMauro Carvalho Chehab 	if (itv->hw_flags & IVTV_HW_CX25840) {
421b285192aSMauro Carvalho Chehab 		/* Setup VBI for the cx25840 digitizer */
422b285192aSMauro Carvalho Chehab 		if (raw) {
423b285192aSMauro Carvalho Chehab 			data[3] = 0x20602060;
424b285192aSMauro Carvalho Chehab 			data[4] = 0x30703070;
425b285192aSMauro Carvalho Chehab 		} else {
426b285192aSMauro Carvalho Chehab 			data[3] = 0xB0F0B0F0;
427b285192aSMauro Carvalho Chehab 			data[4] = 0xA0E0A0E0;
428b285192aSMauro Carvalho Chehab 		}
429b285192aSMauro Carvalho Chehab 		/* Lines per frame */
430b285192aSMauro Carvalho Chehab 		data[5] = lines;
431b285192aSMauro Carvalho Chehab 		/* bytes per line */
432b285192aSMauro Carvalho Chehab 		data[6] = (raw ? itv->vbi.raw_size : itv->vbi.sliced_size);
433b285192aSMauro Carvalho Chehab 	} else {
434b285192aSMauro Carvalho Chehab 		/* Setup VBI for the saa7115 digitizer */
435b285192aSMauro Carvalho Chehab 		if (raw) {
436b285192aSMauro Carvalho Chehab 			data[3] = 0x25256262;
437b285192aSMauro Carvalho Chehab 			data[4] = 0x387F7F7F;
438b285192aSMauro Carvalho Chehab 		} else {
439b285192aSMauro Carvalho Chehab 			data[3] = 0xABABECEC;
440b285192aSMauro Carvalho Chehab 			data[4] = 0xB6F1F1F1;
441b285192aSMauro Carvalho Chehab 		}
442b285192aSMauro Carvalho Chehab 		/* Lines per frame */
443b285192aSMauro Carvalho Chehab 		data[5] = lines;
444b285192aSMauro Carvalho Chehab 		/* bytes per line */
445b285192aSMauro Carvalho Chehab 		data[6] = itv->vbi.enc_size / lines;
446b285192aSMauro Carvalho Chehab 	}
447b285192aSMauro Carvalho Chehab 
448b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_INFO(
449b285192aSMauro Carvalho Chehab 		"Setup VBI API header 0x%08x pkts %d buffs %d ln %d sz %d\n",
450b285192aSMauro Carvalho Chehab 			data[0], data[1], data[2], data[5], data[6]);
451b285192aSMauro Carvalho Chehab 
452b285192aSMauro Carvalho Chehab 	ivtv_api(itv, CX2341X_ENC_SET_VBI_CONFIG, 7, data);
453b285192aSMauro Carvalho Chehab 
454b285192aSMauro Carvalho Chehab 	/* returns the VBI encoder memory area. */
455b285192aSMauro Carvalho Chehab 	itv->vbi.enc_start = data[2];
456b285192aSMauro Carvalho Chehab 	itv->vbi.fpi = data[0];
457b285192aSMauro Carvalho Chehab 	if (!itv->vbi.fpi)
458b285192aSMauro Carvalho Chehab 		itv->vbi.fpi = 1;
459b285192aSMauro Carvalho Chehab 
460b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d\n",
461b285192aSMauro Carvalho Chehab 		itv->vbi.enc_start, data[1], itv->vbi.fpi);
462b285192aSMauro Carvalho Chehab 
463b285192aSMauro Carvalho Chehab 	/* select VBI lines.
464b285192aSMauro Carvalho Chehab 	   Note that the sliced argument seems to have no effect. */
465b285192aSMauro Carvalho Chehab 	for (i = 2; i <= 24; i++) {
466b285192aSMauro Carvalho Chehab 		int valid;
467b285192aSMauro Carvalho Chehab 
468b285192aSMauro Carvalho Chehab 		if (itv->is_60hz) {
469b285192aSMauro Carvalho Chehab 			valid = i >= 10 && i < 22;
470b285192aSMauro Carvalho Chehab 		} else {
471b285192aSMauro Carvalho Chehab 			valid = i >= 6 && i < 24;
472b285192aSMauro Carvalho Chehab 		}
473b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, i - 1,
474b285192aSMauro Carvalho Chehab 				valid, 0 , 0, 0);
475b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, (i - 1) | 0x80000000,
476b285192aSMauro Carvalho Chehab 				valid, 0, 0, 0);
477b285192aSMauro Carvalho Chehab 	}
478b285192aSMauro Carvalho Chehab 
479b285192aSMauro Carvalho Chehab 	/* Remaining VBI questions:
480b285192aSMauro Carvalho Chehab 	   - Is it possible to select particular VBI lines only for inclusion in the MPEG
481b285192aSMauro Carvalho Chehab 	   stream? Currently you can only get the first X lines.
482b285192aSMauro Carvalho Chehab 	   - Is mixed raw and sliced VBI possible?
483b285192aSMauro Carvalho Chehab 	   - What's the meaning of the raw/sliced flag?
484b285192aSMauro Carvalho Chehab 	   - What's the meaning of params 2, 3 & 4 of the Select VBI command? */
485b285192aSMauro Carvalho Chehab }
486b285192aSMauro Carvalho Chehab 
ivtv_start_v4l2_encode_stream(struct ivtv_stream * s)487b285192aSMauro Carvalho Chehab int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
488b285192aSMauro Carvalho Chehab {
489b285192aSMauro Carvalho Chehab 	u32 data[CX2341X_MBOX_MAX_DATA];
490b285192aSMauro Carvalho Chehab 	struct ivtv *itv = s->itv;
491b285192aSMauro Carvalho Chehab 	int captype = 0, subtype = 0;
492b285192aSMauro Carvalho Chehab 	int enable_passthrough = 0;
493b285192aSMauro Carvalho Chehab 
494635d62f0SHans Verkuil 	if (s->vdev.v4l2_dev == NULL)
495b285192aSMauro Carvalho Chehab 		return -EINVAL;
496b285192aSMauro Carvalho Chehab 
497b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name);
498b285192aSMauro Carvalho Chehab 
499b285192aSMauro Carvalho Chehab 	switch (s->type) {
500b285192aSMauro Carvalho Chehab 	case IVTV_ENC_STREAM_TYPE_MPG:
501b285192aSMauro Carvalho Chehab 		captype = 0;
502b285192aSMauro Carvalho Chehab 		subtype = 3;
503b285192aSMauro Carvalho Chehab 
504b285192aSMauro Carvalho Chehab 		/* Stop Passthrough */
505b285192aSMauro Carvalho Chehab 		if (itv->output_mode == OUT_PASSTHROUGH) {
506b285192aSMauro Carvalho Chehab 			ivtv_passthrough_mode(itv, 0);
507b285192aSMauro Carvalho Chehab 			enable_passthrough = 1;
508b285192aSMauro Carvalho Chehab 		}
509b285192aSMauro Carvalho Chehab 		itv->mpg_data_received = itv->vbi_data_inserted = 0;
510b285192aSMauro Carvalho Chehab 		itv->dualwatch_jiffies = jiffies;
511b285192aSMauro Carvalho Chehab 		itv->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(itv->cxhdl.audio_mode);
512b285192aSMauro Carvalho Chehab 		itv->search_pack_header = 0;
513b285192aSMauro Carvalho Chehab 		break;
514b285192aSMauro Carvalho Chehab 
515b285192aSMauro Carvalho Chehab 	case IVTV_ENC_STREAM_TYPE_YUV:
516b285192aSMauro Carvalho Chehab 		if (itv->output_mode == OUT_PASSTHROUGH) {
517b285192aSMauro Carvalho Chehab 			captype = 2;
518b285192aSMauro Carvalho Chehab 			subtype = 11;	/* video+audio+decoder */
519b285192aSMauro Carvalho Chehab 			break;
520b285192aSMauro Carvalho Chehab 		}
521b285192aSMauro Carvalho Chehab 		captype = 1;
522b285192aSMauro Carvalho Chehab 		subtype = 1;
523b285192aSMauro Carvalho Chehab 		break;
524b285192aSMauro Carvalho Chehab 	case IVTV_ENC_STREAM_TYPE_PCM:
525b285192aSMauro Carvalho Chehab 		captype = 1;
526b285192aSMauro Carvalho Chehab 		subtype = 2;
527b285192aSMauro Carvalho Chehab 		break;
528b285192aSMauro Carvalho Chehab 	case IVTV_ENC_STREAM_TYPE_VBI:
529b285192aSMauro Carvalho Chehab 		captype = 1;
530b285192aSMauro Carvalho Chehab 		subtype = 4;
531b285192aSMauro Carvalho Chehab 
532b285192aSMauro Carvalho Chehab 		itv->vbi.frame = 0;
533b285192aSMauro Carvalho Chehab 		itv->vbi.inserted_frame = 0;
534b285192aSMauro Carvalho Chehab 		memset(itv->vbi.sliced_mpeg_size,
535b285192aSMauro Carvalho Chehab 			0, sizeof(itv->vbi.sliced_mpeg_size));
536b285192aSMauro Carvalho Chehab 		break;
537b285192aSMauro Carvalho Chehab 	default:
538b285192aSMauro Carvalho Chehab 		return -EINVAL;
539b285192aSMauro Carvalho Chehab 	}
540b285192aSMauro Carvalho Chehab 	s->subtype = subtype;
541b285192aSMauro Carvalho Chehab 	s->buffers_stolen = 0;
542b285192aSMauro Carvalho Chehab 
543b285192aSMauro Carvalho Chehab 	/* Clear Streamoff flags in case left from last capture */
544b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
545b285192aSMauro Carvalho Chehab 
546b285192aSMauro Carvalho Chehab 	if (atomic_read(&itv->capturing) == 0) {
547b285192aSMauro Carvalho Chehab 		int digitizer;
548b285192aSMauro Carvalho Chehab 
549b285192aSMauro Carvalho Chehab 		/* Always use frame based mode. Experiments have demonstrated that byte
550b285192aSMauro Carvalho Chehab 		   stream based mode results in dropped frames and corruption. Not often,
551b285192aSMauro Carvalho Chehab 		   but occasionally. Many thanks go to Leonard Orb who spent a lot of
552b285192aSMauro Carvalho Chehab 		   effort and time trying to trace the cause of the drop outs. */
553b285192aSMauro Carvalho Chehab 		/* 1 frame per DMA */
554b285192aSMauro Carvalho Chehab 		/*ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 128, 0); */
555b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 1, 1);
556b285192aSMauro Carvalho Chehab 
557b285192aSMauro Carvalho Chehab 		/* Stuff from Windows, we don't know what it is */
558b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1, 0);
559b285192aSMauro Carvalho Chehab 		/* According to the docs, this should be correct. However, this is
560b285192aSMauro Carvalho Chehab 		   untested. I don't dare enable this without having tested it.
561b285192aSMauro Carvalho Chehab 		   Only very few old cards actually have this hardware combination.
562b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1,
563b285192aSMauro Carvalho Chehab 			((itv->hw_flags & IVTV_HW_SAA7114) && itv->is_60hz) ? 10001 : 0);
564b285192aSMauro Carvalho Chehab 		*/
565b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 3, !itv->has_cx23415);
566b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 8, 0);
567b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 4, 1);
568b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
569b285192aSMauro Carvalho Chehab 
570b285192aSMauro Carvalho Chehab 		/* assign placeholder */
571b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_SET_PLACEHOLDER, 12,
572b285192aSMauro Carvalho Chehab 			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
573b285192aSMauro Carvalho Chehab 
574b285192aSMauro Carvalho Chehab 		if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X))
575b285192aSMauro Carvalho Chehab 		    digitizer = 0xF1;
576b285192aSMauro Carvalho Chehab 		else if (itv->card->hw_all & IVTV_HW_SAA7114)
577b285192aSMauro Carvalho Chehab 		    digitizer = 0xEF;
578b285192aSMauro Carvalho Chehab 		else /* cx25840 */
579b285192aSMauro Carvalho Chehab 		    digitizer = 0x140;
580b285192aSMauro Carvalho Chehab 
581b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, digitizer, digitizer);
582b285192aSMauro Carvalho Chehab 
583b285192aSMauro Carvalho Chehab 		/* Setup VBI */
584b285192aSMauro Carvalho Chehab 		if (itv->v4l2_cap & V4L2_CAP_VBI_CAPTURE) {
585b285192aSMauro Carvalho Chehab 			ivtv_vbi_setup(itv);
586b285192aSMauro Carvalho Chehab 		}
587b285192aSMauro Carvalho Chehab 
588b285192aSMauro Carvalho Chehab 		/* assign program index info. Mask 7: select I/P/B, Num_req: 400 max */
589b285192aSMauro Carvalho Chehab 		ivtv_vapi_result(itv, data, CX2341X_ENC_SET_PGM_INDEX_INFO, 2, 7, 400);
590b285192aSMauro Carvalho Chehab 		itv->pgm_info_offset = data[0];
591b285192aSMauro Carvalho Chehab 		itv->pgm_info_num = data[1];
592b285192aSMauro Carvalho Chehab 		itv->pgm_info_write_idx = 0;
593b285192aSMauro Carvalho Chehab 		itv->pgm_info_read_idx = 0;
594b285192aSMauro Carvalho Chehab 
595b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_INFO("PGM Index at 0x%08x with %d elements\n",
596b285192aSMauro Carvalho Chehab 				itv->pgm_info_offset, itv->pgm_info_num);
597b285192aSMauro Carvalho Chehab 
598b285192aSMauro Carvalho Chehab 		/* Setup API for Stream */
599b285192aSMauro Carvalho Chehab 		cx2341x_handler_setup(&itv->cxhdl);
600b285192aSMauro Carvalho Chehab 
601b285192aSMauro Carvalho Chehab 		/* mute if capturing radio */
602b285192aSMauro Carvalho Chehab 		if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags))
603b285192aSMauro Carvalho Chehab 			ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1,
604b285192aSMauro Carvalho Chehab 				1 | (v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8));
605b285192aSMauro Carvalho Chehab 	}
606b285192aSMauro Carvalho Chehab 
607b285192aSMauro Carvalho Chehab 	/* Vsync Setup */
608b285192aSMauro Carvalho Chehab 	if (itv->has_cx23415 && !test_and_set_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
609b285192aSMauro Carvalho Chehab 		/* event notification (on) */
610b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_ENC_VIM_RST, -1);
611b285192aSMauro Carvalho Chehab 		ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
612b285192aSMauro Carvalho Chehab 	}
613b285192aSMauro Carvalho Chehab 
614b285192aSMauro Carvalho Chehab 	if (atomic_read(&itv->capturing) == 0) {
615b285192aSMauro Carvalho Chehab 		/* Clear all Pending Interrupts */
616b285192aSMauro Carvalho Chehab 		ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
617b285192aSMauro Carvalho Chehab 
618b285192aSMauro Carvalho Chehab 		clear_bit(IVTV_F_I_EOS, &itv->i_flags);
619b285192aSMauro Carvalho Chehab 
620b285192aSMauro Carvalho Chehab 		cx2341x_handler_set_busy(&itv->cxhdl, 1);
621b285192aSMauro Carvalho Chehab 
622b285192aSMauro Carvalho Chehab 		/* Initialize Digitizer for Capture */
623b285192aSMauro Carvalho Chehab 		/* Avoid tinny audio problem - ensure audio clocks are going */
624b285192aSMauro Carvalho Chehab 		v4l2_subdev_call(itv->sd_audio, audio, s_stream, 1);
625b285192aSMauro Carvalho Chehab 		/* Avoid unpredictable PCI bus hang - disable video clocks */
626*c411b39dSHans Verkuil 		if (itv->sd_video_is_streaming)
627b285192aSMauro Carvalho Chehab 			v4l2_subdev_call(itv->sd_video, video, s_stream, 0);
628b285192aSMauro Carvalho Chehab 		ivtv_msleep_timeout(300, 0);
629b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
630b285192aSMauro Carvalho Chehab 		v4l2_subdev_call(itv->sd_video, video, s_stream, 1);
631*c411b39dSHans Verkuil 		itv->sd_video_is_streaming = true;
632b285192aSMauro Carvalho Chehab 	}
633b285192aSMauro Carvalho Chehab 
634b285192aSMauro Carvalho Chehab 	/* begin_capture */
635b285192aSMauro Carvalho Chehab 	if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype))
636b285192aSMauro Carvalho Chehab 	{
637b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_WARN( "Error starting capture!\n");
638b285192aSMauro Carvalho Chehab 		return -EINVAL;
639b285192aSMauro Carvalho Chehab 	}
640b285192aSMauro Carvalho Chehab 
641b285192aSMauro Carvalho Chehab 	/* Start Passthrough */
642b285192aSMauro Carvalho Chehab 	if (enable_passthrough) {
643b285192aSMauro Carvalho Chehab 		ivtv_passthrough_mode(itv, 1);
644b285192aSMauro Carvalho Chehab 	}
645b285192aSMauro Carvalho Chehab 
646b285192aSMauro Carvalho Chehab 	if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
647b285192aSMauro Carvalho Chehab 		ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);
648b285192aSMauro Carvalho Chehab 	else
649b285192aSMauro Carvalho Chehab 		ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
650b285192aSMauro Carvalho Chehab 
651b285192aSMauro Carvalho Chehab 	/* you're live! sit back and await interrupts :) */
652b285192aSMauro Carvalho Chehab 	atomic_inc(&itv->capturing);
653b285192aSMauro Carvalho Chehab 	return 0;
654b285192aSMauro Carvalho Chehab }
655269c11fbSAndy Walls EXPORT_SYMBOL(ivtv_start_v4l2_encode_stream);
656b285192aSMauro Carvalho Chehab 
ivtv_setup_v4l2_decode_stream(struct ivtv_stream * s)657b285192aSMauro Carvalho Chehab static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
658b285192aSMauro Carvalho Chehab {
659b285192aSMauro Carvalho Chehab 	u32 data[CX2341X_MBOX_MAX_DATA];
660b285192aSMauro Carvalho Chehab 	struct ivtv *itv = s->itv;
661b285192aSMauro Carvalho Chehab 	int datatype;
662b285192aSMauro Carvalho Chehab 	u16 width;
663b285192aSMauro Carvalho Chehab 	u16 height;
664b285192aSMauro Carvalho Chehab 
665635d62f0SHans Verkuil 	if (s->vdev.v4l2_dev == NULL)
666b285192aSMauro Carvalho Chehab 		return -EINVAL;
667b285192aSMauro Carvalho Chehab 
668b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_INFO("Setting some initial decoder settings\n");
669b285192aSMauro Carvalho Chehab 
670b285192aSMauro Carvalho Chehab 	width = itv->cxhdl.width;
671b285192aSMauro Carvalho Chehab 	height = itv->cxhdl.height;
672b285192aSMauro Carvalho Chehab 
673b285192aSMauro Carvalho Chehab 	/* set audio mode to left/stereo  for dual/stereo mode. */
674b285192aSMauro Carvalho Chehab 	ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
675b285192aSMauro Carvalho Chehab 
676b285192aSMauro Carvalho Chehab 	/* set number of internal decoder buffers */
677b285192aSMauro Carvalho Chehab 	ivtv_vapi(itv, CX2341X_DEC_SET_DISPLAY_BUFFERS, 1, 0);
678b285192aSMauro Carvalho Chehab 
679b285192aSMauro Carvalho Chehab 	/* prebuffering */
680b285192aSMauro Carvalho Chehab 	ivtv_vapi(itv, CX2341X_DEC_SET_PREBUFFERING, 1, 1);
681b285192aSMauro Carvalho Chehab 
682b285192aSMauro Carvalho Chehab 	/* extract from user packets */
683b285192aSMauro Carvalho Chehab 	ivtv_vapi_result(itv, data, CX2341X_DEC_EXTRACT_VBI, 1, 1);
684b285192aSMauro Carvalho Chehab 	itv->vbi.dec_start = data[0];
685b285192aSMauro Carvalho Chehab 
686b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_INFO("Decoder VBI RE-Insert start 0x%08x size 0x%08x\n",
687b285192aSMauro Carvalho Chehab 		itv->vbi.dec_start, data[1]);
688b285192aSMauro Carvalho Chehab 
689b285192aSMauro Carvalho Chehab 	/* set decoder source settings */
690b285192aSMauro Carvalho Chehab 	/* Data type: 0 = mpeg from host,
691b285192aSMauro Carvalho Chehab 	   1 = yuv from encoder,
692b285192aSMauro Carvalho Chehab 	   2 = yuv_from_host */
693b285192aSMauro Carvalho Chehab 	switch (s->type) {
694b285192aSMauro Carvalho Chehab 	case IVTV_DEC_STREAM_TYPE_YUV:
695b285192aSMauro Carvalho Chehab 		if (itv->output_mode == OUT_PASSTHROUGH) {
696b285192aSMauro Carvalho Chehab 			datatype = 1;
697b285192aSMauro Carvalho Chehab 		} else {
698b285192aSMauro Carvalho Chehab 			/* Fake size to avoid switching video standard */
699b285192aSMauro Carvalho Chehab 			datatype = 2;
700b285192aSMauro Carvalho Chehab 			width = 720;
701b285192aSMauro Carvalho Chehab 			height = itv->is_out_50hz ? 576 : 480;
702b285192aSMauro Carvalho Chehab 		}
703b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_INFO("Setup DEC YUV Stream data[0] = %d\n", datatype);
704b285192aSMauro Carvalho Chehab 		break;
705b285192aSMauro Carvalho Chehab 	case IVTV_DEC_STREAM_TYPE_MPG:
706b285192aSMauro Carvalho Chehab 	default:
707b285192aSMauro Carvalho Chehab 		datatype = 0;
708b285192aSMauro Carvalho Chehab 		break;
709b285192aSMauro Carvalho Chehab 	}
710b285192aSMauro Carvalho Chehab 	if (ivtv_vapi(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, datatype,
711b285192aSMauro Carvalho Chehab 			width, height, itv->cxhdl.audio_properties)) {
712b285192aSMauro Carvalho Chehab 		IVTV_DEBUG_WARN("Couldn't initialize decoder source\n");
713b285192aSMauro Carvalho Chehab 	}
714b285192aSMauro Carvalho Chehab 
715b285192aSMauro Carvalho Chehab 	/* Decoder sometimes dies here, so wait a moment */
716b285192aSMauro Carvalho Chehab 	ivtv_msleep_timeout(10, 0);
717b285192aSMauro Carvalho Chehab 
718b285192aSMauro Carvalho Chehab 	/* Known failure point for firmware, so check */
719b285192aSMauro Carvalho Chehab 	return ivtv_firmware_check(itv, "ivtv_setup_v4l2_decode_stream");
720b285192aSMauro Carvalho Chehab }
721b285192aSMauro Carvalho Chehab 
ivtv_start_v4l2_decode_stream(struct ivtv_stream * s,int gop_offset)722b285192aSMauro Carvalho Chehab int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
723b285192aSMauro Carvalho Chehab {
724b285192aSMauro Carvalho Chehab 	struct ivtv *itv = s->itv;
725b285192aSMauro Carvalho Chehab 	int rc;
726b285192aSMauro Carvalho Chehab 
727635d62f0SHans Verkuil 	if (s->vdev.v4l2_dev == NULL)
728b285192aSMauro Carvalho Chehab 		return -EINVAL;
729b285192aSMauro Carvalho Chehab 
730b285192aSMauro Carvalho Chehab 	if (test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags))
731b285192aSMauro Carvalho Chehab 		return 0;	/* already started */
732b285192aSMauro Carvalho Chehab 
733b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset);
734b285192aSMauro Carvalho Chehab 
735b285192aSMauro Carvalho Chehab 	rc = ivtv_setup_v4l2_decode_stream(s);
736b285192aSMauro Carvalho Chehab 	if (rc < 0) {
737b285192aSMauro Carvalho Chehab 		clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
738b285192aSMauro Carvalho Chehab 		return rc;
739b285192aSMauro Carvalho Chehab 	}
740b285192aSMauro Carvalho Chehab 
741b285192aSMauro Carvalho Chehab 	/* set dma size to 65536 bytes */
742b285192aSMauro Carvalho Chehab 	ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536);
743b285192aSMauro Carvalho Chehab 
744b285192aSMauro Carvalho Chehab 	/* Clear Streamoff */
745b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
746b285192aSMauro Carvalho Chehab 
747b285192aSMauro Carvalho Chehab 	/* Zero out decoder counters */
748b285192aSMauro Carvalho Chehab 	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[0]);
749b285192aSMauro Carvalho Chehab 	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[1]);
750b285192aSMauro Carvalho Chehab 	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[2]);
751b285192aSMauro Carvalho Chehab 	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[3]);
752b285192aSMauro Carvalho Chehab 	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[0]);
753b285192aSMauro Carvalho Chehab 	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[1]);
754b285192aSMauro Carvalho Chehab 	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[2]);
755b285192aSMauro Carvalho Chehab 	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[3]);
756b285192aSMauro Carvalho Chehab 
757b285192aSMauro Carvalho Chehab 	/* turn on notification of dual/stereo mode change */
758b285192aSMauro Carvalho Chehab 	ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_DEC_AUD_MODE_CHG, -1);
759b285192aSMauro Carvalho Chehab 
760b285192aSMauro Carvalho Chehab 	/* start playback */
761b285192aSMauro Carvalho Chehab 	ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, gop_offset, 0);
762b285192aSMauro Carvalho Chehab 
763b285192aSMauro Carvalho Chehab 	/* Let things settle before we actually start */
764b285192aSMauro Carvalho Chehab 	ivtv_msleep_timeout(10, 0);
765b285192aSMauro Carvalho Chehab 
766b285192aSMauro Carvalho Chehab 	/* Clear the following Interrupt mask bits for decoding */
767b285192aSMauro Carvalho Chehab 	ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_DECODE);
768b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_IRQ("IRQ Mask is now: 0x%08x\n", itv->irqmask);
769b285192aSMauro Carvalho Chehab 
770b285192aSMauro Carvalho Chehab 	/* you're live! sit back and await interrupts :) */
771b285192aSMauro Carvalho Chehab 	atomic_inc(&itv->decoding);
772b285192aSMauro Carvalho Chehab 	return 0;
773b285192aSMauro Carvalho Chehab }
774b285192aSMauro Carvalho Chehab 
ivtv_stop_all_captures(struct ivtv * itv)775b285192aSMauro Carvalho Chehab void ivtv_stop_all_captures(struct ivtv *itv)
776b285192aSMauro Carvalho Chehab {
777b285192aSMauro Carvalho Chehab 	int i;
778b285192aSMauro Carvalho Chehab 
779b285192aSMauro Carvalho Chehab 	for (i = IVTV_MAX_STREAMS - 1; i >= 0; i--) {
780b285192aSMauro Carvalho Chehab 		struct ivtv_stream *s = &itv->streams[i];
781b285192aSMauro Carvalho Chehab 
782635d62f0SHans Verkuil 		if (s->vdev.v4l2_dev == NULL)
783b285192aSMauro Carvalho Chehab 			continue;
784b285192aSMauro Carvalho Chehab 		if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
785b285192aSMauro Carvalho Chehab 			ivtv_stop_v4l2_encode_stream(s, 0);
786b285192aSMauro Carvalho Chehab 		}
787b285192aSMauro Carvalho Chehab 	}
788b285192aSMauro Carvalho Chehab }
789b285192aSMauro Carvalho Chehab 
ivtv_stop_v4l2_encode_stream(struct ivtv_stream * s,int gop_end)790b285192aSMauro Carvalho Chehab int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
791b285192aSMauro Carvalho Chehab {
792b285192aSMauro Carvalho Chehab 	struct ivtv *itv = s->itv;
793b285192aSMauro Carvalho Chehab 	DECLARE_WAITQUEUE(wait, current);
794b285192aSMauro Carvalho Chehab 	int cap_type;
795b285192aSMauro Carvalho Chehab 	int stopmode;
796b285192aSMauro Carvalho Chehab 
797635d62f0SHans Verkuil 	if (s->vdev.v4l2_dev == NULL)
798b285192aSMauro Carvalho Chehab 		return -EINVAL;
799b285192aSMauro Carvalho Chehab 
800b285192aSMauro Carvalho Chehab 	/* This function assumes that you are allowed to stop the capture
801b285192aSMauro Carvalho Chehab 	   and that we are actually capturing */
802b285192aSMauro Carvalho Chehab 
803b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_INFO("Stop Capture\n");
804b285192aSMauro Carvalho Chehab 
805b285192aSMauro Carvalho Chehab 	if (s->type == IVTV_DEC_STREAM_TYPE_VOUT)
806b285192aSMauro Carvalho Chehab 		return 0;
807b285192aSMauro Carvalho Chehab 	if (atomic_read(&itv->capturing) == 0)
808b285192aSMauro Carvalho Chehab 		return 0;
809b285192aSMauro Carvalho Chehab 
810b285192aSMauro Carvalho Chehab 	switch (s->type) {
811b285192aSMauro Carvalho Chehab 	case IVTV_ENC_STREAM_TYPE_YUV:
812b285192aSMauro Carvalho Chehab 		cap_type = 1;
813b285192aSMauro Carvalho Chehab 		break;
814b285192aSMauro Carvalho Chehab 	case IVTV_ENC_STREAM_TYPE_PCM:
815b285192aSMauro Carvalho Chehab 		cap_type = 1;
816b285192aSMauro Carvalho Chehab 		break;
817b285192aSMauro Carvalho Chehab 	case IVTV_ENC_STREAM_TYPE_VBI:
818b285192aSMauro Carvalho Chehab 		cap_type = 1;
819b285192aSMauro Carvalho Chehab 		break;
820b285192aSMauro Carvalho Chehab 	case IVTV_ENC_STREAM_TYPE_MPG:
821b285192aSMauro Carvalho Chehab 	default:
822b285192aSMauro Carvalho Chehab 		cap_type = 0;
823b285192aSMauro Carvalho Chehab 		break;
824b285192aSMauro Carvalho Chehab 	}
825b285192aSMauro Carvalho Chehab 
826b285192aSMauro Carvalho Chehab 	/* Stop Capture Mode */
827b285192aSMauro Carvalho Chehab 	if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) {
828b285192aSMauro Carvalho Chehab 		stopmode = 0;
829b285192aSMauro Carvalho Chehab 	} else {
830b285192aSMauro Carvalho Chehab 		stopmode = 1;
831b285192aSMauro Carvalho Chehab 	}
832b285192aSMauro Carvalho Chehab 
833b285192aSMauro Carvalho Chehab 	/* end_capture */
834b285192aSMauro Carvalho Chehab 	/* when: 0 =  end of GOP  1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */
835b285192aSMauro Carvalho Chehab 	ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype);
836b285192aSMauro Carvalho Chehab 
837b285192aSMauro Carvalho Chehab 	if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) {
838b285192aSMauro Carvalho Chehab 		if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) {
839b285192aSMauro Carvalho Chehab 			/* only run these if we're shutting down the last cap */
840b285192aSMauro Carvalho Chehab 			unsigned long duration;
841b285192aSMauro Carvalho Chehab 			unsigned long then = jiffies;
842b285192aSMauro Carvalho Chehab 
843b285192aSMauro Carvalho Chehab 			add_wait_queue(&itv->eos_waitq, &wait);
844b285192aSMauro Carvalho Chehab 
845b285192aSMauro Carvalho Chehab 			set_current_state(TASK_INTERRUPTIBLE);
846b285192aSMauro Carvalho Chehab 
847b285192aSMauro Carvalho Chehab 			/* wait 2s for EOS interrupt */
848b285192aSMauro Carvalho Chehab 			while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) &&
849b285192aSMauro Carvalho Chehab 				time_before(jiffies,
850b285192aSMauro Carvalho Chehab 					    then + msecs_to_jiffies(2000))) {
851b285192aSMauro Carvalho Chehab 				schedule_timeout(msecs_to_jiffies(10));
852b285192aSMauro Carvalho Chehab 			}
853b285192aSMauro Carvalho Chehab 
854b285192aSMauro Carvalho Chehab 			/* To convert jiffies to ms, we must multiply by 1000
855b285192aSMauro Carvalho Chehab 			 * and divide by HZ.  To avoid runtime division, we
856b285192aSMauro Carvalho Chehab 			 * convert this to multiplication by 1000/HZ.
857b285192aSMauro Carvalho Chehab 			 * Since integer division truncates, we get the best
858b285192aSMauro Carvalho Chehab 			 * accuracy if we do a rounding calculation of the constant.
859b285192aSMauro Carvalho Chehab 			 * Think of the case where HZ is 1024.
860b285192aSMauro Carvalho Chehab 			 */
861b285192aSMauro Carvalho Chehab 			duration = ((1000 + HZ / 2) / HZ) * (jiffies - then);
862b285192aSMauro Carvalho Chehab 
863b285192aSMauro Carvalho Chehab 			if (!test_bit(IVTV_F_I_EOS, &itv->i_flags)) {
864b285192aSMauro Carvalho Chehab 				IVTV_DEBUG_WARN("%s: EOS interrupt not received! stopping anyway.\n", s->name);
865b285192aSMauro Carvalho Chehab 				IVTV_DEBUG_WARN("%s: waited %lu ms.\n", s->name, duration);
866b285192aSMauro Carvalho Chehab 			} else {
867b285192aSMauro Carvalho Chehab 				IVTV_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration);
868b285192aSMauro Carvalho Chehab 			}
869b285192aSMauro Carvalho Chehab 			set_current_state(TASK_RUNNING);
870b285192aSMauro Carvalho Chehab 			remove_wait_queue(&itv->eos_waitq, &wait);
871b285192aSMauro Carvalho Chehab 			set_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
872b285192aSMauro Carvalho Chehab 		}
873b285192aSMauro Carvalho Chehab 
874b285192aSMauro Carvalho Chehab 		/* Handle any pending interrupts */
875b285192aSMauro Carvalho Chehab 		ivtv_msleep_timeout(100, 0);
876b285192aSMauro Carvalho Chehab 	}
877b285192aSMauro Carvalho Chehab 
878b285192aSMauro Carvalho Chehab 	atomic_dec(&itv->capturing);
879b285192aSMauro Carvalho Chehab 
880b285192aSMauro Carvalho Chehab 	/* Clear capture and no-read bits */
881b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
882b285192aSMauro Carvalho Chehab 
883b285192aSMauro Carvalho Chehab 	if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
884b285192aSMauro Carvalho Chehab 		ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);
885b285192aSMauro Carvalho Chehab 
886b285192aSMauro Carvalho Chehab 	if (atomic_read(&itv->capturing) > 0) {
887b285192aSMauro Carvalho Chehab 		return 0;
888b285192aSMauro Carvalho Chehab 	}
889b285192aSMauro Carvalho Chehab 
890b285192aSMauro Carvalho Chehab 	cx2341x_handler_set_busy(&itv->cxhdl, 0);
891b285192aSMauro Carvalho Chehab 
892b285192aSMauro Carvalho Chehab 	/* Set the following Interrupt mask bits for capture */
893b285192aSMauro Carvalho Chehab 	ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
894b285192aSMauro Carvalho Chehab 	del_timer(&itv->dma_timer);
895b285192aSMauro Carvalho Chehab 
896b285192aSMauro Carvalho Chehab 	/* event notification (off) */
897b285192aSMauro Carvalho Chehab 	if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
898b285192aSMauro Carvalho Chehab 		/* type: 0 = refresh */
899b285192aSMauro Carvalho Chehab 		/* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */
900b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1);
901b285192aSMauro Carvalho Chehab 		ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
902b285192aSMauro Carvalho Chehab 	}
903b285192aSMauro Carvalho Chehab 
904b285192aSMauro Carvalho Chehab 	/* Raw-passthrough is implied on start. Make sure it's stopped so
905b285192aSMauro Carvalho Chehab 	   the encoder will re-initialize when next started */
906b285192aSMauro Carvalho Chehab 	ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, 1, 2, 7);
907b285192aSMauro Carvalho Chehab 
908b285192aSMauro Carvalho Chehab 	wake_up(&s->waitq);
909b285192aSMauro Carvalho Chehab 
910b285192aSMauro Carvalho Chehab 	return 0;
911b285192aSMauro Carvalho Chehab }
912269c11fbSAndy Walls EXPORT_SYMBOL(ivtv_stop_v4l2_encode_stream);
913b285192aSMauro Carvalho Chehab 
ivtv_stop_v4l2_decode_stream(struct ivtv_stream * s,int flags,u64 pts)914b285192aSMauro Carvalho Chehab int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
915b285192aSMauro Carvalho Chehab {
916b285192aSMauro Carvalho Chehab 	static const struct v4l2_event ev = {
917b285192aSMauro Carvalho Chehab 		.type = V4L2_EVENT_EOS,
918b285192aSMauro Carvalho Chehab 	};
919b285192aSMauro Carvalho Chehab 	struct ivtv *itv = s->itv;
920b285192aSMauro Carvalho Chehab 
921635d62f0SHans Verkuil 	if (s->vdev.v4l2_dev == NULL)
922b285192aSMauro Carvalho Chehab 		return -EINVAL;
923b285192aSMauro Carvalho Chehab 
924b285192aSMauro Carvalho Chehab 	if (s->type != IVTV_DEC_STREAM_TYPE_YUV && s->type != IVTV_DEC_STREAM_TYPE_MPG)
925b285192aSMauro Carvalho Chehab 		return -EINVAL;
926b285192aSMauro Carvalho Chehab 
927b285192aSMauro Carvalho Chehab 	if (!test_bit(IVTV_F_S_STREAMING, &s->s_flags))
928b285192aSMauro Carvalho Chehab 		return 0;
929b285192aSMauro Carvalho Chehab 
930b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_INFO("Stop Decode at %llu, flags: %x\n", (unsigned long long)pts, flags);
931b285192aSMauro Carvalho Chehab 
932b285192aSMauro Carvalho Chehab 	/* Stop Decoder */
933b285192aSMauro Carvalho Chehab 	if (!(flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) || pts) {
934b285192aSMauro Carvalho Chehab 		u32 tmp = 0;
935b285192aSMauro Carvalho Chehab 
936b285192aSMauro Carvalho Chehab 		/* Wait until the decoder is no longer running */
937b285192aSMauro Carvalho Chehab 		if (pts) {
938b285192aSMauro Carvalho Chehab 			ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3,
939b285192aSMauro Carvalho Chehab 				0, (u32)(pts & 0xffffffff), (u32)(pts >> 32));
940b285192aSMauro Carvalho Chehab 		}
941b285192aSMauro Carvalho Chehab 		while (1) {
942b285192aSMauro Carvalho Chehab 			u32 data[CX2341X_MBOX_MAX_DATA];
943b285192aSMauro Carvalho Chehab 			ivtv_vapi_result(itv, data, CX2341X_DEC_GET_XFER_INFO, 0);
944b285192aSMauro Carvalho Chehab 			if (s->q_full.buffers + s->q_dma.buffers == 0) {
945b285192aSMauro Carvalho Chehab 				if (tmp == data[3])
946b285192aSMauro Carvalho Chehab 					break;
947b285192aSMauro Carvalho Chehab 				tmp = data[3];
948b285192aSMauro Carvalho Chehab 			}
949b285192aSMauro Carvalho Chehab 			if (ivtv_msleep_timeout(100, 1))
950b285192aSMauro Carvalho Chehab 				break;
951b285192aSMauro Carvalho Chehab 		}
952b285192aSMauro Carvalho Chehab 	}
953b285192aSMauro Carvalho Chehab 	ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & V4L2_DEC_CMD_STOP_TO_BLACK, 0, 0);
954b285192aSMauro Carvalho Chehab 
955b285192aSMauro Carvalho Chehab 	/* turn off notification of dual/stereo mode change */
956b285192aSMauro Carvalho Chehab 	ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1);
957b285192aSMauro Carvalho Chehab 
958b285192aSMauro Carvalho Chehab 	ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE);
959b285192aSMauro Carvalho Chehab 	del_timer(&itv->dma_timer);
960b285192aSMauro Carvalho Chehab 
961b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
962b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
963b285192aSMauro Carvalho Chehab 	ivtv_flush_queues(s);
964b285192aSMauro Carvalho Chehab 
965b285192aSMauro Carvalho Chehab 	/* decoder needs time to settle */
966b285192aSMauro Carvalho Chehab 	ivtv_msleep_timeout(40, 0);
967b285192aSMauro Carvalho Chehab 
968b285192aSMauro Carvalho Chehab 	/* decrement decoding */
969b285192aSMauro Carvalho Chehab 	atomic_dec(&itv->decoding);
970b285192aSMauro Carvalho Chehab 
971b285192aSMauro Carvalho Chehab 	set_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags);
972b285192aSMauro Carvalho Chehab 	wake_up(&itv->event_waitq);
973635d62f0SHans Verkuil 	v4l2_event_queue(&s->vdev, &ev);
974b285192aSMauro Carvalho Chehab 
975b285192aSMauro Carvalho Chehab 	/* wake up wait queues */
976b285192aSMauro Carvalho Chehab 	wake_up(&s->waitq);
977b285192aSMauro Carvalho Chehab 
978b285192aSMauro Carvalho Chehab 	return 0;
979b285192aSMauro Carvalho Chehab }
980b285192aSMauro Carvalho Chehab 
ivtv_passthrough_mode(struct ivtv * itv,int enable)981b285192aSMauro Carvalho Chehab int ivtv_passthrough_mode(struct ivtv *itv, int enable)
982b285192aSMauro Carvalho Chehab {
983b285192aSMauro Carvalho Chehab 	struct ivtv_stream *yuv_stream = &itv->streams[IVTV_ENC_STREAM_TYPE_YUV];
984b285192aSMauro Carvalho Chehab 	struct ivtv_stream *dec_stream = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
985b285192aSMauro Carvalho Chehab 
986635d62f0SHans Verkuil 	if (yuv_stream->vdev.v4l2_dev == NULL || dec_stream->vdev.v4l2_dev == NULL)
987b285192aSMauro Carvalho Chehab 		return -EINVAL;
988b285192aSMauro Carvalho Chehab 
989b285192aSMauro Carvalho Chehab 	IVTV_DEBUG_INFO("ivtv ioctl: Select passthrough mode\n");
990b285192aSMauro Carvalho Chehab 
991b285192aSMauro Carvalho Chehab 	/* Prevent others from starting/stopping streams while we
992b285192aSMauro Carvalho Chehab 	   initiate/terminate passthrough mode */
993b285192aSMauro Carvalho Chehab 	if (enable) {
994b285192aSMauro Carvalho Chehab 		if (itv->output_mode == OUT_PASSTHROUGH) {
995b285192aSMauro Carvalho Chehab 			return 0;
996b285192aSMauro Carvalho Chehab 		}
997b285192aSMauro Carvalho Chehab 		if (ivtv_set_output_mode(itv, OUT_PASSTHROUGH) != OUT_PASSTHROUGH)
998b285192aSMauro Carvalho Chehab 			return -EBUSY;
999b285192aSMauro Carvalho Chehab 
1000b285192aSMauro Carvalho Chehab 		/* Fully initialize stream, and then unflag init */
1001b285192aSMauro Carvalho Chehab 		set_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags);
1002b285192aSMauro Carvalho Chehab 		set_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags);
1003b285192aSMauro Carvalho Chehab 
1004b285192aSMauro Carvalho Chehab 		/* Setup YUV Decoder */
1005b285192aSMauro Carvalho Chehab 		ivtv_setup_v4l2_decode_stream(dec_stream);
1006b285192aSMauro Carvalho Chehab 
1007b285192aSMauro Carvalho Chehab 		/* Start Decoder */
1008b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1);
1009b285192aSMauro Carvalho Chehab 		atomic_inc(&itv->decoding);
1010b285192aSMauro Carvalho Chehab 
1011b285192aSMauro Carvalho Chehab 		/* Setup capture if not already done */
1012b285192aSMauro Carvalho Chehab 		if (atomic_read(&itv->capturing) == 0) {
1013b285192aSMauro Carvalho Chehab 			cx2341x_handler_setup(&itv->cxhdl);
1014b285192aSMauro Carvalho Chehab 			cx2341x_handler_set_busy(&itv->cxhdl, 1);
1015b285192aSMauro Carvalho Chehab 		}
1016b285192aSMauro Carvalho Chehab 
1017b285192aSMauro Carvalho Chehab 		/* Start Passthrough Mode */
1018b285192aSMauro Carvalho Chehab 		ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, 2, 11);
1019b285192aSMauro Carvalho Chehab 		atomic_inc(&itv->capturing);
1020b285192aSMauro Carvalho Chehab 		return 0;
1021b285192aSMauro Carvalho Chehab 	}
1022b285192aSMauro Carvalho Chehab 
1023b285192aSMauro Carvalho Chehab 	if (itv->output_mode != OUT_PASSTHROUGH)
1024b285192aSMauro Carvalho Chehab 		return 0;
1025b285192aSMauro Carvalho Chehab 
1026b285192aSMauro Carvalho Chehab 	/* Stop Passthrough Mode */
1027b285192aSMauro Carvalho Chehab 	ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, 1, 2, 11);
1028b285192aSMauro Carvalho Chehab 	ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, 1, 0, 0);
1029b285192aSMauro Carvalho Chehab 
1030b285192aSMauro Carvalho Chehab 	atomic_dec(&itv->capturing);
1031b285192aSMauro Carvalho Chehab 	atomic_dec(&itv->decoding);
1032b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags);
1033b285192aSMauro Carvalho Chehab 	clear_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags);
1034b285192aSMauro Carvalho Chehab 	itv->output_mode = OUT_NONE;
1035b285192aSMauro Carvalho Chehab 	if (atomic_read(&itv->capturing) == 0)
1036b285192aSMauro Carvalho Chehab 		cx2341x_handler_set_busy(&itv->cxhdl, 0);
1037b285192aSMauro Carvalho Chehab 
1038b285192aSMauro Carvalho Chehab 	return 0;
1039b285192aSMauro Carvalho Chehab }
1040