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