1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2b285192aSMauro Carvalho Chehab /*
3b285192aSMauro Carvalho Chehab * Driver for the NXP SAA7164 PCIe bridge
4b285192aSMauro Carvalho Chehab *
563a412ecSSteven Toth * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com>
6b285192aSMauro Carvalho Chehab */
7b285192aSMauro Carvalho Chehab
8b285192aSMauro Carvalho Chehab #include "saa7164.h"
9b285192aSMauro Carvalho Chehab
10b285192aSMauro Carvalho Chehab #define ENCODER_MAX_BITRATE 6500000
11b285192aSMauro Carvalho Chehab #define ENCODER_MIN_BITRATE 1000000
12b285192aSMauro Carvalho Chehab #define ENCODER_DEF_BITRATE 5000000
13b285192aSMauro Carvalho Chehab
14031d2297SHans Verkuil /*
15031d2297SHans Verkuil * This is a dummy non-zero value for the sizeimage field of v4l2_pix_format.
16031d2297SHans Verkuil * It is not actually used for anything since this driver does not support
17031d2297SHans Verkuil * stream I/O, only read(), and because this driver produces an MPEG stream
18031d2297SHans Verkuil * and not discrete frames. But the V4L2 spec doesn't allow for this value
19031d2297SHans Verkuil * to be 0, so set it to 0x10000 instead.
20031d2297SHans Verkuil *
21031d2297SHans Verkuil * If we ever change this driver to support stream I/O, then this field
22031d2297SHans Verkuil * will be the size of the streaming buffers.
23031d2297SHans Verkuil */
24031d2297SHans Verkuil #define SAA7164_SIZEIMAGE (0x10000)
25031d2297SHans Verkuil
26b285192aSMauro Carvalho Chehab static struct saa7164_tvnorm saa7164_tvnorms[] = {
27b285192aSMauro Carvalho Chehab {
28b285192aSMauro Carvalho Chehab .name = "NTSC-M",
29b285192aSMauro Carvalho Chehab .id = V4L2_STD_NTSC_M,
30b285192aSMauro Carvalho Chehab }, {
31b285192aSMauro Carvalho Chehab .name = "NTSC-JP",
32b285192aSMauro Carvalho Chehab .id = V4L2_STD_NTSC_M_JP,
33b285192aSMauro Carvalho Chehab }
34b285192aSMauro Carvalho Chehab };
35b285192aSMauro Carvalho Chehab
36b285192aSMauro Carvalho Chehab /* Take the encoder configuration form the port struct and
37b285192aSMauro Carvalho Chehab * flush it to the hardware.
38b285192aSMauro Carvalho Chehab */
saa7164_encoder_configure(struct saa7164_port * port)39b285192aSMauro Carvalho Chehab static void saa7164_encoder_configure(struct saa7164_port *port)
40b285192aSMauro Carvalho Chehab {
41b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
42b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s()\n", __func__);
43b285192aSMauro Carvalho Chehab
44b285192aSMauro Carvalho Chehab port->encoder_params.width = port->width;
45b285192aSMauro Carvalho Chehab port->encoder_params.height = port->height;
46b285192aSMauro Carvalho Chehab port->encoder_params.is_50hz =
47b285192aSMauro Carvalho Chehab (port->encodernorm.id & V4L2_STD_625_50) != 0;
48b285192aSMauro Carvalho Chehab
49b285192aSMauro Carvalho Chehab /* Set up the DIF (enable it) for analog mode by default */
50b285192aSMauro Carvalho Chehab saa7164_api_initialize_dif(port);
51b285192aSMauro Carvalho Chehab
52b285192aSMauro Carvalho Chehab /* Configure the correct video standard */
53b285192aSMauro Carvalho Chehab saa7164_api_configure_dif(port, port->encodernorm.id);
54b285192aSMauro Carvalho Chehab
55b285192aSMauro Carvalho Chehab /* Ensure the audio decoder is correct configured */
56b285192aSMauro Carvalho Chehab saa7164_api_set_audio_std(port);
57b285192aSMauro Carvalho Chehab }
58b285192aSMauro Carvalho Chehab
saa7164_encoder_buffers_dealloc(struct saa7164_port * port)59b285192aSMauro Carvalho Chehab static int saa7164_encoder_buffers_dealloc(struct saa7164_port *port)
60b285192aSMauro Carvalho Chehab {
61b285192aSMauro Carvalho Chehab struct list_head *c, *n, *p, *q, *l, *v;
62b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
63b285192aSMauro Carvalho Chehab struct saa7164_buffer *buf;
64b285192aSMauro Carvalho Chehab struct saa7164_user_buffer *ubuf;
65b285192aSMauro Carvalho Chehab
66b285192aSMauro Carvalho Chehab /* Remove any allocated buffers */
67b285192aSMauro Carvalho Chehab mutex_lock(&port->dmaqueue_lock);
68b285192aSMauro Carvalho Chehab
69b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s(port=%d) dmaqueue\n", __func__, port->nr);
70b285192aSMauro Carvalho Chehab list_for_each_safe(c, n, &port->dmaqueue.list) {
71b285192aSMauro Carvalho Chehab buf = list_entry(c, struct saa7164_buffer, list);
72b285192aSMauro Carvalho Chehab list_del(c);
73b285192aSMauro Carvalho Chehab saa7164_buffer_dealloc(buf);
74b285192aSMauro Carvalho Chehab }
75b285192aSMauro Carvalho Chehab
76b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s(port=%d) used\n", __func__, port->nr);
77b285192aSMauro Carvalho Chehab list_for_each_safe(p, q, &port->list_buf_used.list) {
78b285192aSMauro Carvalho Chehab ubuf = list_entry(p, struct saa7164_user_buffer, list);
79b285192aSMauro Carvalho Chehab list_del(p);
80b285192aSMauro Carvalho Chehab saa7164_buffer_dealloc_user(ubuf);
81b285192aSMauro Carvalho Chehab }
82b285192aSMauro Carvalho Chehab
83b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s(port=%d) free\n", __func__, port->nr);
84b285192aSMauro Carvalho Chehab list_for_each_safe(l, v, &port->list_buf_free.list) {
85b285192aSMauro Carvalho Chehab ubuf = list_entry(l, struct saa7164_user_buffer, list);
86b285192aSMauro Carvalho Chehab list_del(l);
87b285192aSMauro Carvalho Chehab saa7164_buffer_dealloc_user(ubuf);
88b285192aSMauro Carvalho Chehab }
89b285192aSMauro Carvalho Chehab
90b285192aSMauro Carvalho Chehab mutex_unlock(&port->dmaqueue_lock);
91b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s(port=%d) done\n", __func__, port->nr);
92b285192aSMauro Carvalho Chehab
93b285192aSMauro Carvalho Chehab return 0;
94b285192aSMauro Carvalho Chehab }
95b285192aSMauro Carvalho Chehab
96b285192aSMauro Carvalho Chehab /* Dynamic buffer switch at encoder start time */
saa7164_encoder_buffers_alloc(struct saa7164_port * port)97b285192aSMauro Carvalho Chehab static int saa7164_encoder_buffers_alloc(struct saa7164_port *port)
98b285192aSMauro Carvalho Chehab {
99b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
100b285192aSMauro Carvalho Chehab struct saa7164_buffer *buf;
101b285192aSMauro Carvalho Chehab struct saa7164_user_buffer *ubuf;
102b285192aSMauro Carvalho Chehab struct tmHWStreamParameters *params = &port->hw_streamingparams;
103b285192aSMauro Carvalho Chehab int result = -ENODEV, i;
104b285192aSMauro Carvalho Chehab int len = 0;
105b285192aSMauro Carvalho Chehab
106b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s()\n", __func__);
107b285192aSMauro Carvalho Chehab
108b285192aSMauro Carvalho Chehab if (port->encoder_params.stream_type ==
109b285192aSMauro Carvalho Chehab V4L2_MPEG_STREAM_TYPE_MPEG2_PS) {
110b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC,
111b285192aSMauro Carvalho Chehab "%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_PS\n",
112b285192aSMauro Carvalho Chehab __func__);
113b285192aSMauro Carvalho Chehab params->samplesperline = 128;
114b285192aSMauro Carvalho Chehab params->numberoflines = 256;
115b285192aSMauro Carvalho Chehab params->pitch = 128;
116b285192aSMauro Carvalho Chehab params->numpagetables = 2 +
117b285192aSMauro Carvalho Chehab ((SAA7164_PS_NUMBER_OF_LINES * 128) / PAGE_SIZE);
118b285192aSMauro Carvalho Chehab } else
119b285192aSMauro Carvalho Chehab if (port->encoder_params.stream_type ==
120b285192aSMauro Carvalho Chehab V4L2_MPEG_STREAM_TYPE_MPEG2_TS) {
121b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC,
122b285192aSMauro Carvalho Chehab "%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_TS\n",
123b285192aSMauro Carvalho Chehab __func__);
124b285192aSMauro Carvalho Chehab params->samplesperline = 188;
125b285192aSMauro Carvalho Chehab params->numberoflines = 312;
126b285192aSMauro Carvalho Chehab params->pitch = 188;
127b285192aSMauro Carvalho Chehab params->numpagetables = 2 +
128b285192aSMauro Carvalho Chehab ((SAA7164_TS_NUMBER_OF_LINES * 188) / PAGE_SIZE);
129b285192aSMauro Carvalho Chehab } else
130b285192aSMauro Carvalho Chehab BUG();
131b285192aSMauro Carvalho Chehab
132b285192aSMauro Carvalho Chehab /* Init and establish defaults */
133b285192aSMauro Carvalho Chehab params->bitspersample = 8;
134b285192aSMauro Carvalho Chehab params->linethreshold = 0;
135b285192aSMauro Carvalho Chehab params->pagetablelistvirt = NULL;
136b285192aSMauro Carvalho Chehab params->pagetablelistphys = NULL;
137b285192aSMauro Carvalho Chehab params->numpagetableentries = port->hwcfg.buffercount;
138b285192aSMauro Carvalho Chehab
139b285192aSMauro Carvalho Chehab /* Allocate the PCI resources, buffers (hard) */
140b285192aSMauro Carvalho Chehab for (i = 0; i < port->hwcfg.buffercount; i++) {
141b285192aSMauro Carvalho Chehab buf = saa7164_buffer_alloc(port,
142b285192aSMauro Carvalho Chehab params->numberoflines *
143b285192aSMauro Carvalho Chehab params->pitch);
144b285192aSMauro Carvalho Chehab
145b285192aSMauro Carvalho Chehab if (!buf) {
14624f711c1SMauro Carvalho Chehab printk(KERN_ERR "%s() failed (errno = %d), unable to allocate buffer\n",
147b285192aSMauro Carvalho Chehab __func__, result);
148b285192aSMauro Carvalho Chehab result = -ENOMEM;
149b285192aSMauro Carvalho Chehab goto failed;
150b285192aSMauro Carvalho Chehab } else {
151b285192aSMauro Carvalho Chehab
152b285192aSMauro Carvalho Chehab mutex_lock(&port->dmaqueue_lock);
153b285192aSMauro Carvalho Chehab list_add_tail(&buf->list, &port->dmaqueue.list);
154b285192aSMauro Carvalho Chehab mutex_unlock(&port->dmaqueue_lock);
155b285192aSMauro Carvalho Chehab
156b285192aSMauro Carvalho Chehab }
157b285192aSMauro Carvalho Chehab }
158b285192aSMauro Carvalho Chehab
159b285192aSMauro Carvalho Chehab /* Allocate some kernel buffers for copying
160b285192aSMauro Carvalho Chehab * to userpsace.
161b285192aSMauro Carvalho Chehab */
162b285192aSMauro Carvalho Chehab len = params->numberoflines * params->pitch;
163b285192aSMauro Carvalho Chehab
164b285192aSMauro Carvalho Chehab if (encoder_buffers < 16)
165b285192aSMauro Carvalho Chehab encoder_buffers = 16;
166b285192aSMauro Carvalho Chehab if (encoder_buffers > 512)
167b285192aSMauro Carvalho Chehab encoder_buffers = 512;
168b285192aSMauro Carvalho Chehab
169b285192aSMauro Carvalho Chehab for (i = 0; i < encoder_buffers; i++) {
170b285192aSMauro Carvalho Chehab
171b285192aSMauro Carvalho Chehab ubuf = saa7164_buffer_alloc_user(dev, len);
172b285192aSMauro Carvalho Chehab if (ubuf) {
173b285192aSMauro Carvalho Chehab mutex_lock(&port->dmaqueue_lock);
174b285192aSMauro Carvalho Chehab list_add_tail(&ubuf->list, &port->list_buf_free.list);
175b285192aSMauro Carvalho Chehab mutex_unlock(&port->dmaqueue_lock);
176b285192aSMauro Carvalho Chehab }
177b285192aSMauro Carvalho Chehab
178b285192aSMauro Carvalho Chehab }
179b285192aSMauro Carvalho Chehab
180b285192aSMauro Carvalho Chehab result = 0;
181b285192aSMauro Carvalho Chehab
182b285192aSMauro Carvalho Chehab failed:
183b285192aSMauro Carvalho Chehab return result;
184b285192aSMauro Carvalho Chehab }
185b285192aSMauro Carvalho Chehab
saa7164_encoder_initialize(struct saa7164_port * port)186b285192aSMauro Carvalho Chehab static int saa7164_encoder_initialize(struct saa7164_port *port)
187b285192aSMauro Carvalho Chehab {
188b285192aSMauro Carvalho Chehab saa7164_encoder_configure(port);
189b285192aSMauro Carvalho Chehab return 0;
190b285192aSMauro Carvalho Chehab }
191b285192aSMauro Carvalho Chehab
192b285192aSMauro Carvalho Chehab /* -- V4L2 --------------------------------------------------------- */
saa7164_s_std(struct saa7164_port * port,v4l2_std_id id)193225b783bSHans Verkuil int saa7164_s_std(struct saa7164_port *port, v4l2_std_id id)
194b285192aSMauro Carvalho Chehab {
195b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
196b285192aSMauro Carvalho Chehab unsigned int i;
197b285192aSMauro Carvalho Chehab
198314527acSHans Verkuil dprintk(DBGLVL_ENC, "%s(id=0x%x)\n", __func__, (u32)id);
199b285192aSMauro Carvalho Chehab
200b285192aSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) {
201314527acSHans Verkuil if (id & saa7164_tvnorms[i].id)
202b285192aSMauro Carvalho Chehab break;
203b285192aSMauro Carvalho Chehab }
204b285192aSMauro Carvalho Chehab if (i == ARRAY_SIZE(saa7164_tvnorms))
205b285192aSMauro Carvalho Chehab return -EINVAL;
206b285192aSMauro Carvalho Chehab
207b285192aSMauro Carvalho Chehab port->encodernorm = saa7164_tvnorms[i];
2088d2d41e9SHans Verkuil port->std = id;
209b285192aSMauro Carvalho Chehab
210b285192aSMauro Carvalho Chehab /* Update the audio decoder while is not running in
211b285192aSMauro Carvalho Chehab * auto detect mode.
212b285192aSMauro Carvalho Chehab */
213b285192aSMauro Carvalho Chehab saa7164_api_set_audio_std(port);
214b285192aSMauro Carvalho Chehab
215314527acSHans Verkuil dprintk(DBGLVL_ENC, "%s(id=0x%x) OK\n", __func__, (u32)id);
216b285192aSMauro Carvalho Chehab
217b285192aSMauro Carvalho Chehab return 0;
218b285192aSMauro Carvalho Chehab }
219b285192aSMauro Carvalho Chehab
vidioc_s_std(struct file * file,void * priv,v4l2_std_id id)220225b783bSHans Verkuil static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
2218d2d41e9SHans Verkuil {
2228d2d41e9SHans Verkuil struct saa7164_encoder_fh *fh = file->private_data;
2238d2d41e9SHans Verkuil
224225b783bSHans Verkuil return saa7164_s_std(fh->port, id);
225225b783bSHans Verkuil }
226225b783bSHans Verkuil
saa7164_g_std(struct saa7164_port * port,v4l2_std_id * id)227225b783bSHans Verkuil int saa7164_g_std(struct saa7164_port *port, v4l2_std_id *id)
228225b783bSHans Verkuil {
2298d2d41e9SHans Verkuil *id = port->std;
2308d2d41e9SHans Verkuil return 0;
2318d2d41e9SHans Verkuil }
2328d2d41e9SHans Verkuil
vidioc_g_std(struct file * file,void * priv,v4l2_std_id * id)233225b783bSHans Verkuil static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
234225b783bSHans Verkuil {
235225b783bSHans Verkuil struct saa7164_encoder_fh *fh = file->private_data;
236225b783bSHans Verkuil
237225b783bSHans Verkuil return saa7164_g_std(fh->port, id);
238225b783bSHans Verkuil }
239225b783bSHans Verkuil
saa7164_enum_input(struct file * file,void * priv,struct v4l2_input * i)240225b783bSHans Verkuil int saa7164_enum_input(struct file *file, void *priv, struct v4l2_input *i)
241b285192aSMauro Carvalho Chehab {
2426b996126SHans Verkuil static const char * const inputs[] = {
2436b996126SHans Verkuil "tuner", "composite", "svideo", "aux",
2446b996126SHans Verkuil "composite 2", "svideo 2", "aux 2"
2456b996126SHans Verkuil };
246b285192aSMauro Carvalho Chehab int n;
247b285192aSMauro Carvalho Chehab
248b285192aSMauro Carvalho Chehab if (i->index >= 7)
249b285192aSMauro Carvalho Chehab return -EINVAL;
250b285192aSMauro Carvalho Chehab
251cc1e6315SMauro Carvalho Chehab strscpy(i->name, inputs[i->index], sizeof(i->name));
252b285192aSMauro Carvalho Chehab
253b285192aSMauro Carvalho Chehab if (i->index == 0)
254b285192aSMauro Carvalho Chehab i->type = V4L2_INPUT_TYPE_TUNER;
255b285192aSMauro Carvalho Chehab else
256b285192aSMauro Carvalho Chehab i->type = V4L2_INPUT_TYPE_CAMERA;
257b285192aSMauro Carvalho Chehab
258b285192aSMauro Carvalho Chehab for (n = 0; n < ARRAY_SIZE(saa7164_tvnorms); n++)
259b285192aSMauro Carvalho Chehab i->std |= saa7164_tvnorms[n].id;
260b285192aSMauro Carvalho Chehab
261b285192aSMauro Carvalho Chehab return 0;
262b285192aSMauro Carvalho Chehab }
263b285192aSMauro Carvalho Chehab
saa7164_g_input(struct saa7164_port * port,unsigned int * i)264225b783bSHans Verkuil int saa7164_g_input(struct saa7164_port *port, unsigned int *i)
265b285192aSMauro Carvalho Chehab {
266b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
267b285192aSMauro Carvalho Chehab
268b285192aSMauro Carvalho Chehab if (saa7164_api_get_videomux(port) != SAA_OK)
269b285192aSMauro Carvalho Chehab return -EIO;
270b285192aSMauro Carvalho Chehab
271b285192aSMauro Carvalho Chehab *i = (port->mux_input - 1);
272b285192aSMauro Carvalho Chehab
273b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s() input=%d\n", __func__, *i);
274b285192aSMauro Carvalho Chehab
275b285192aSMauro Carvalho Chehab return 0;
276b285192aSMauro Carvalho Chehab }
277b285192aSMauro Carvalho Chehab
vidioc_g_input(struct file * file,void * priv,unsigned int * i)278225b783bSHans Verkuil static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
279b285192aSMauro Carvalho Chehab {
280b285192aSMauro Carvalho Chehab struct saa7164_encoder_fh *fh = file->private_data;
281225b783bSHans Verkuil
282225b783bSHans Verkuil return saa7164_g_input(fh->port, i);
283225b783bSHans Verkuil }
284225b783bSHans Verkuil
saa7164_s_input(struct saa7164_port * port,unsigned int i)285225b783bSHans Verkuil int saa7164_s_input(struct saa7164_port *port, unsigned int i)
286225b783bSHans Verkuil {
287b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
288b285192aSMauro Carvalho Chehab
289b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s() input=%d\n", __func__, i);
290b285192aSMauro Carvalho Chehab
291b285192aSMauro Carvalho Chehab if (i >= 7)
292b285192aSMauro Carvalho Chehab return -EINVAL;
293b285192aSMauro Carvalho Chehab
294b285192aSMauro Carvalho Chehab port->mux_input = i + 1;
295b285192aSMauro Carvalho Chehab
296b285192aSMauro Carvalho Chehab if (saa7164_api_set_videomux(port) != SAA_OK)
297b285192aSMauro Carvalho Chehab return -EIO;
298b285192aSMauro Carvalho Chehab
299b285192aSMauro Carvalho Chehab return 0;
300b285192aSMauro Carvalho Chehab }
301b285192aSMauro Carvalho Chehab
vidioc_s_input(struct file * file,void * priv,unsigned int i)302225b783bSHans Verkuil static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
303225b783bSHans Verkuil {
304225b783bSHans Verkuil struct saa7164_encoder_fh *fh = file->private_data;
305225b783bSHans Verkuil
306225b783bSHans Verkuil return saa7164_s_input(fh->port, i);
307225b783bSHans Verkuil }
308225b783bSHans Verkuil
saa7164_g_tuner(struct file * file,void * priv,struct v4l2_tuner * t)309225b783bSHans Verkuil int saa7164_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
310b285192aSMauro Carvalho Chehab {
311b285192aSMauro Carvalho Chehab struct saa7164_encoder_fh *fh = file->private_data;
312b285192aSMauro Carvalho Chehab struct saa7164_port *port = fh->port;
313b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
314b285192aSMauro Carvalho Chehab
315b285192aSMauro Carvalho Chehab if (0 != t->index)
316b285192aSMauro Carvalho Chehab return -EINVAL;
317b285192aSMauro Carvalho Chehab
318cc1e6315SMauro Carvalho Chehab strscpy(t->name, "tuner", sizeof(t->name));
319b285192aSMauro Carvalho Chehab t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO;
3206b996126SHans Verkuil t->rangelow = SAA7164_TV_MIN_FREQ;
3216b996126SHans Verkuil t->rangehigh = SAA7164_TV_MAX_FREQ;
322b285192aSMauro Carvalho Chehab
323b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
324b285192aSMauro Carvalho Chehab
325b285192aSMauro Carvalho Chehab return 0;
326b285192aSMauro Carvalho Chehab }
327b285192aSMauro Carvalho Chehab
saa7164_s_tuner(struct file * file,void * priv,const struct v4l2_tuner * t)328225b783bSHans Verkuil int saa7164_s_tuner(struct file *file, void *priv,
3292f73c7c5SHans Verkuil const struct v4l2_tuner *t)
330b285192aSMauro Carvalho Chehab {
3316b996126SHans Verkuil if (0 != t->index)
3326b996126SHans Verkuil return -EINVAL;
3336b996126SHans Verkuil
334b285192aSMauro Carvalho Chehab /* Update the A/V core */
335b285192aSMauro Carvalho Chehab return 0;
336b285192aSMauro Carvalho Chehab }
337b285192aSMauro Carvalho Chehab
saa7164_g_frequency(struct saa7164_port * port,struct v4l2_frequency * f)338225b783bSHans Verkuil int saa7164_g_frequency(struct saa7164_port *port, struct v4l2_frequency *f)
339b285192aSMauro Carvalho Chehab {
3406b996126SHans Verkuil if (f->tuner)
3416b996126SHans Verkuil return -EINVAL;
3426b996126SHans Verkuil
343b285192aSMauro Carvalho Chehab f->frequency = port->freq;
344b285192aSMauro Carvalho Chehab return 0;
345b285192aSMauro Carvalho Chehab }
346b285192aSMauro Carvalho Chehab
vidioc_g_frequency(struct file * file,void * priv,struct v4l2_frequency * f)347225b783bSHans Verkuil static int vidioc_g_frequency(struct file *file, void *priv,
348225b783bSHans Verkuil struct v4l2_frequency *f)
349b285192aSMauro Carvalho Chehab {
350b285192aSMauro Carvalho Chehab struct saa7164_encoder_fh *fh = file->private_data;
351225b783bSHans Verkuil
352225b783bSHans Verkuil return saa7164_g_frequency(fh->port, f);
353225b783bSHans Verkuil }
354225b783bSHans Verkuil
saa7164_s_frequency(struct saa7164_port * port,const struct v4l2_frequency * f)355225b783bSHans Verkuil int saa7164_s_frequency(struct saa7164_port *port,
356225b783bSHans Verkuil const struct v4l2_frequency *f)
357225b783bSHans Verkuil {
358b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
359b285192aSMauro Carvalho Chehab struct saa7164_port *tsport;
360b285192aSMauro Carvalho Chehab struct dvb_frontend *fe;
361b285192aSMauro Carvalho Chehab
362b285192aSMauro Carvalho Chehab /* TODO: Pull this for the std */
363b285192aSMauro Carvalho Chehab struct analog_parameters params = {
364b285192aSMauro Carvalho Chehab .mode = V4L2_TUNER_ANALOG_TV,
365b285192aSMauro Carvalho Chehab .audmode = V4L2_TUNER_MODE_STEREO,
366b285192aSMauro Carvalho Chehab .std = port->encodernorm.id,
367b285192aSMauro Carvalho Chehab .frequency = f->frequency
368b285192aSMauro Carvalho Chehab };
369b285192aSMauro Carvalho Chehab
370b285192aSMauro Carvalho Chehab /* Stop the encoder */
371b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s() frequency=%d tuner=%d\n", __func__,
372b285192aSMauro Carvalho Chehab f->frequency, f->tuner);
373b285192aSMauro Carvalho Chehab
374b285192aSMauro Carvalho Chehab if (f->tuner != 0)
375b285192aSMauro Carvalho Chehab return -EINVAL;
376b285192aSMauro Carvalho Chehab
3776b996126SHans Verkuil port->freq = clamp(f->frequency,
3786b996126SHans Verkuil SAA7164_TV_MIN_FREQ, SAA7164_TV_MAX_FREQ);
379b285192aSMauro Carvalho Chehab
380b285192aSMauro Carvalho Chehab /* Update the hardware */
381b285192aSMauro Carvalho Chehab if (port->nr == SAA7164_PORT_ENC1)
382b285192aSMauro Carvalho Chehab tsport = &dev->ports[SAA7164_PORT_TS1];
383225b783bSHans Verkuil else if (port->nr == SAA7164_PORT_ENC2)
384b285192aSMauro Carvalho Chehab tsport = &dev->ports[SAA7164_PORT_TS2];
385b285192aSMauro Carvalho Chehab else
386*c62b0891SHans Verkuil return -EINVAL; /* should not happen */
387b285192aSMauro Carvalho Chehab
388b285192aSMauro Carvalho Chehab fe = tsport->dvb.frontend;
389b285192aSMauro Carvalho Chehab
390b285192aSMauro Carvalho Chehab if (fe && fe->ops.tuner_ops.set_analog_params)
391b285192aSMauro Carvalho Chehab fe->ops.tuner_ops.set_analog_params(fe, ¶ms);
392b285192aSMauro Carvalho Chehab else
393b285192aSMauro Carvalho Chehab printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__);
394b285192aSMauro Carvalho Chehab
395b285192aSMauro Carvalho Chehab saa7164_encoder_initialize(port);
396b285192aSMauro Carvalho Chehab
397b285192aSMauro Carvalho Chehab return 0;
398b285192aSMauro Carvalho Chehab }
399b285192aSMauro Carvalho Chehab
vidioc_s_frequency(struct file * file,void * priv,const struct v4l2_frequency * f)400225b783bSHans Verkuil static int vidioc_s_frequency(struct file *file, void *priv,
401225b783bSHans Verkuil const struct v4l2_frequency *f)
402225b783bSHans Verkuil {
403225b783bSHans Verkuil struct saa7164_encoder_fh *fh = file->private_data;
404225b783bSHans Verkuil
405225b783bSHans Verkuil return saa7164_s_frequency(fh->port, f);
406225b783bSHans Verkuil }
407225b783bSHans Verkuil
saa7164_s_ctrl(struct v4l2_ctrl * ctrl)4081a708ea0SHans Verkuil static int saa7164_s_ctrl(struct v4l2_ctrl *ctrl)
409b285192aSMauro Carvalho Chehab {
4101a708ea0SHans Verkuil struct saa7164_port *port =
4111a708ea0SHans Verkuil container_of(ctrl->handler, struct saa7164_port, ctrl_handler);
4121a708ea0SHans Verkuil struct saa7164_encoder_params *params = &port->encoder_params;
413b285192aSMauro Carvalho Chehab int ret = 0;
414b285192aSMauro Carvalho Chehab
4151a708ea0SHans Verkuil switch (ctrl->id) {
416b285192aSMauro Carvalho Chehab case V4L2_CID_BRIGHTNESS:
4171a708ea0SHans Verkuil port->ctl_brightness = ctrl->val;
4181a708ea0SHans Verkuil saa7164_api_set_usercontrol(port, PU_BRIGHTNESS_CONTROL);
419b285192aSMauro Carvalho Chehab break;
420b285192aSMauro Carvalho Chehab case V4L2_CID_CONTRAST:
4211a708ea0SHans Verkuil port->ctl_contrast = ctrl->val;
422b285192aSMauro Carvalho Chehab saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL);
423b285192aSMauro Carvalho Chehab break;
424b285192aSMauro Carvalho Chehab case V4L2_CID_SATURATION:
4251a708ea0SHans Verkuil port->ctl_saturation = ctrl->val;
4261a708ea0SHans Verkuil saa7164_api_set_usercontrol(port, PU_SATURATION_CONTROL);
427b285192aSMauro Carvalho Chehab break;
428b285192aSMauro Carvalho Chehab case V4L2_CID_HUE:
4291a708ea0SHans Verkuil port->ctl_hue = ctrl->val;
430b285192aSMauro Carvalho Chehab saa7164_api_set_usercontrol(port, PU_HUE_CONTROL);
431b285192aSMauro Carvalho Chehab break;
432b285192aSMauro Carvalho Chehab case V4L2_CID_SHARPNESS:
4331a708ea0SHans Verkuil port->ctl_sharpness = ctrl->val;
434b285192aSMauro Carvalho Chehab saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL);
435b285192aSMauro Carvalho Chehab break;
436b285192aSMauro Carvalho Chehab case V4L2_CID_AUDIO_VOLUME:
4371a708ea0SHans Verkuil port->ctl_volume = ctrl->val;
438b285192aSMauro Carvalho Chehab saa7164_api_set_audio_volume(port, port->ctl_volume);
439b285192aSMauro Carvalho Chehab break;
440b285192aSMauro Carvalho Chehab case V4L2_CID_MPEG_VIDEO_BITRATE:
4411a708ea0SHans Verkuil params->bitrate = ctrl->val;
442b285192aSMauro Carvalho Chehab break;
443b285192aSMauro Carvalho Chehab case V4L2_CID_MPEG_STREAM_TYPE:
4441a708ea0SHans Verkuil params->stream_type = ctrl->val;
445b285192aSMauro Carvalho Chehab break;
446b285192aSMauro Carvalho Chehab case V4L2_CID_MPEG_AUDIO_MUTE:
4471a708ea0SHans Verkuil params->ctl_mute = ctrl->val;
448b285192aSMauro Carvalho Chehab ret = saa7164_api_audio_mute(port, params->ctl_mute);
449b285192aSMauro Carvalho Chehab if (ret != SAA_OK) {
450b285192aSMauro Carvalho Chehab printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
451b285192aSMauro Carvalho Chehab ret);
452b285192aSMauro Carvalho Chehab ret = -EIO;
453b285192aSMauro Carvalho Chehab }
454b285192aSMauro Carvalho Chehab break;
455b285192aSMauro Carvalho Chehab case V4L2_CID_MPEG_VIDEO_ASPECT:
4561a708ea0SHans Verkuil params->ctl_aspect = ctrl->val;
457b285192aSMauro Carvalho Chehab ret = saa7164_api_set_aspect_ratio(port);
458b285192aSMauro Carvalho Chehab if (ret != SAA_OK) {
459b285192aSMauro Carvalho Chehab printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
460b285192aSMauro Carvalho Chehab ret);
461b285192aSMauro Carvalho Chehab ret = -EIO;
462b285192aSMauro Carvalho Chehab }
463b285192aSMauro Carvalho Chehab break;
464b285192aSMauro Carvalho Chehab case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
4651a708ea0SHans Verkuil params->bitrate_mode = ctrl->val;
466b285192aSMauro Carvalho Chehab break;
467b285192aSMauro Carvalho Chehab case V4L2_CID_MPEG_VIDEO_B_FRAMES:
4681a708ea0SHans Verkuil params->refdist = ctrl->val;
469b285192aSMauro Carvalho Chehab break;
470b285192aSMauro Carvalho Chehab case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
4711a708ea0SHans Verkuil params->bitrate_peak = ctrl->val;
472b285192aSMauro Carvalho Chehab break;
473b285192aSMauro Carvalho Chehab case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
4741a708ea0SHans Verkuil params->gop_size = ctrl->val;
475b285192aSMauro Carvalho Chehab break;
476b285192aSMauro Carvalho Chehab default:
4771a708ea0SHans Verkuil ret = -EINVAL;
478b285192aSMauro Carvalho Chehab }
479b285192aSMauro Carvalho Chehab
480b285192aSMauro Carvalho Chehab return ret;
481b285192aSMauro Carvalho Chehab }
482b285192aSMauro Carvalho Chehab
vidioc_querycap(struct file * file,void * priv,struct v4l2_capability * cap)483b285192aSMauro Carvalho Chehab static int vidioc_querycap(struct file *file, void *priv,
484b285192aSMauro Carvalho Chehab struct v4l2_capability *cap)
485b285192aSMauro Carvalho Chehab {
486b285192aSMauro Carvalho Chehab struct saa7164_encoder_fh *fh = file->private_data;
487b285192aSMauro Carvalho Chehab struct saa7164_port *port = fh->port;
488b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
489b285192aSMauro Carvalho Chehab
490cc1e6315SMauro Carvalho Chehab strscpy(cap->driver, dev->name, sizeof(cap->driver));
491c0decac1SMauro Carvalho Chehab strscpy(cap->card, saa7164_boards[dev->board].name,
492b285192aSMauro Carvalho Chehab sizeof(cap->card));
49321615365SHans Verkuil cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
49421615365SHans Verkuil V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE |
495534bc3e2SHans Verkuil V4L2_CAP_DEVICE_CAPS;
496b285192aSMauro Carvalho Chehab return 0;
497b285192aSMauro Carvalho Chehab }
498b285192aSMauro Carvalho Chehab
vidioc_enum_fmt_vid_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)499b285192aSMauro Carvalho Chehab static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
500b285192aSMauro Carvalho Chehab struct v4l2_fmtdesc *f)
501b285192aSMauro Carvalho Chehab {
502b285192aSMauro Carvalho Chehab if (f->index != 0)
503b285192aSMauro Carvalho Chehab return -EINVAL;
504b285192aSMauro Carvalho Chehab
505b285192aSMauro Carvalho Chehab f->pixelformat = V4L2_PIX_FMT_MPEG;
506b285192aSMauro Carvalho Chehab
507b285192aSMauro Carvalho Chehab return 0;
508b285192aSMauro Carvalho Chehab }
509b285192aSMauro Carvalho Chehab
vidioc_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)510031d2297SHans Verkuil static int vidioc_fmt_vid_cap(struct file *file, void *priv,
511b285192aSMauro Carvalho Chehab struct v4l2_format *f)
512b285192aSMauro Carvalho Chehab {
513b285192aSMauro Carvalho Chehab struct saa7164_encoder_fh *fh = file->private_data;
514b285192aSMauro Carvalho Chehab struct saa7164_port *port = fh->port;
515b285192aSMauro Carvalho Chehab
516b285192aSMauro Carvalho Chehab f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
517b285192aSMauro Carvalho Chehab f->fmt.pix.bytesperline = 0;
518031d2297SHans Verkuil f->fmt.pix.sizeimage = SAA7164_SIZEIMAGE;
519031d2297SHans Verkuil f->fmt.pix.field = V4L2_FIELD_INTERLACED;
520031d2297SHans Verkuil f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
521b285192aSMauro Carvalho Chehab f->fmt.pix.width = port->width;
522b285192aSMauro Carvalho Chehab f->fmt.pix.height = port->height;
523b285192aSMauro Carvalho Chehab return 0;
524b285192aSMauro Carvalho Chehab }
525b285192aSMauro Carvalho Chehab
saa7164_encoder_stop_port(struct saa7164_port * port)526b285192aSMauro Carvalho Chehab static int saa7164_encoder_stop_port(struct saa7164_port *port)
527b285192aSMauro Carvalho Chehab {
528b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
529b285192aSMauro Carvalho Chehab int ret;
530b285192aSMauro Carvalho Chehab
531b285192aSMauro Carvalho Chehab ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
532b285192aSMauro Carvalho Chehab if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
533b285192aSMauro Carvalho Chehab printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n",
534b285192aSMauro Carvalho Chehab __func__, ret);
535b285192aSMauro Carvalho Chehab ret = -EIO;
536b285192aSMauro Carvalho Chehab } else {
537b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s() Stopped\n", __func__);
538b285192aSMauro Carvalho Chehab ret = 0;
539b285192aSMauro Carvalho Chehab }
540b285192aSMauro Carvalho Chehab
541b285192aSMauro Carvalho Chehab return ret;
542b285192aSMauro Carvalho Chehab }
543b285192aSMauro Carvalho Chehab
saa7164_encoder_acquire_port(struct saa7164_port * port)544b285192aSMauro Carvalho Chehab static int saa7164_encoder_acquire_port(struct saa7164_port *port)
545b285192aSMauro Carvalho Chehab {
546b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
547b285192aSMauro Carvalho Chehab int ret;
548b285192aSMauro Carvalho Chehab
549b285192aSMauro Carvalho Chehab ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
550b285192aSMauro Carvalho Chehab if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
551b285192aSMauro Carvalho Chehab printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n",
552b285192aSMauro Carvalho Chehab __func__, ret);
553b285192aSMauro Carvalho Chehab ret = -EIO;
554b285192aSMauro Carvalho Chehab } else {
555b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s() Acquired\n", __func__);
556b285192aSMauro Carvalho Chehab ret = 0;
557b285192aSMauro Carvalho Chehab }
558b285192aSMauro Carvalho Chehab
559b285192aSMauro Carvalho Chehab return ret;
560b285192aSMauro Carvalho Chehab }
561b285192aSMauro Carvalho Chehab
saa7164_encoder_pause_port(struct saa7164_port * port)562b285192aSMauro Carvalho Chehab static int saa7164_encoder_pause_port(struct saa7164_port *port)
563b285192aSMauro Carvalho Chehab {
564b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
565b285192aSMauro Carvalho Chehab int ret;
566b285192aSMauro Carvalho Chehab
567b285192aSMauro Carvalho Chehab ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
568b285192aSMauro Carvalho Chehab if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
569b285192aSMauro Carvalho Chehab printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n",
570b285192aSMauro Carvalho Chehab __func__, ret);
571b285192aSMauro Carvalho Chehab ret = -EIO;
572b285192aSMauro Carvalho Chehab } else {
573b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s() Paused\n", __func__);
574b285192aSMauro Carvalho Chehab ret = 0;
575b285192aSMauro Carvalho Chehab }
576b285192aSMauro Carvalho Chehab
577b285192aSMauro Carvalho Chehab return ret;
578b285192aSMauro Carvalho Chehab }
579b285192aSMauro Carvalho Chehab
580b285192aSMauro Carvalho Chehab /* Firmware is very windows centric, meaning you have to transition
581b285192aSMauro Carvalho Chehab * the part through AVStream / KS Windows stages, forwards or backwards.
582b285192aSMauro Carvalho Chehab * States are: stopped, acquired (h/w), paused, started.
583b285192aSMauro Carvalho Chehab * We have to leave here will all of the soft buffers on the free list,
584b285192aSMauro Carvalho Chehab * else the cfg_post() func won't have soft buffers to correctly configure.
585b285192aSMauro Carvalho Chehab */
saa7164_encoder_stop_streaming(struct saa7164_port * port)586b285192aSMauro Carvalho Chehab static int saa7164_encoder_stop_streaming(struct saa7164_port *port)
587b285192aSMauro Carvalho Chehab {
588b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
589b285192aSMauro Carvalho Chehab struct saa7164_buffer *buf;
590b285192aSMauro Carvalho Chehab struct saa7164_user_buffer *ubuf;
591b285192aSMauro Carvalho Chehab struct list_head *c, *n;
592b285192aSMauro Carvalho Chehab int ret;
593b285192aSMauro Carvalho Chehab
594b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
595b285192aSMauro Carvalho Chehab
596b285192aSMauro Carvalho Chehab ret = saa7164_encoder_pause_port(port);
597b285192aSMauro Carvalho Chehab ret = saa7164_encoder_acquire_port(port);
598b285192aSMauro Carvalho Chehab ret = saa7164_encoder_stop_port(port);
599b285192aSMauro Carvalho Chehab
600b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s(port=%d) Hardware stopped\n", __func__,
601b285192aSMauro Carvalho Chehab port->nr);
602b285192aSMauro Carvalho Chehab
603b285192aSMauro Carvalho Chehab /* Reset the state of any allocated buffer resources */
604b285192aSMauro Carvalho Chehab mutex_lock(&port->dmaqueue_lock);
605b285192aSMauro Carvalho Chehab
606b285192aSMauro Carvalho Chehab /* Reset the hard and soft buffer state */
607b285192aSMauro Carvalho Chehab list_for_each_safe(c, n, &port->dmaqueue.list) {
608b285192aSMauro Carvalho Chehab buf = list_entry(c, struct saa7164_buffer, list);
609b285192aSMauro Carvalho Chehab buf->flags = SAA7164_BUFFER_FREE;
610b285192aSMauro Carvalho Chehab buf->pos = 0;
611b285192aSMauro Carvalho Chehab }
612b285192aSMauro Carvalho Chehab
613b285192aSMauro Carvalho Chehab list_for_each_safe(c, n, &port->list_buf_used.list) {
614b285192aSMauro Carvalho Chehab ubuf = list_entry(c, struct saa7164_user_buffer, list);
615b285192aSMauro Carvalho Chehab ubuf->pos = 0;
616b285192aSMauro Carvalho Chehab list_move_tail(&ubuf->list, &port->list_buf_free.list);
617b285192aSMauro Carvalho Chehab }
618b285192aSMauro Carvalho Chehab
619b285192aSMauro Carvalho Chehab mutex_unlock(&port->dmaqueue_lock);
620b285192aSMauro Carvalho Chehab
621b285192aSMauro Carvalho Chehab /* Free any allocated resources */
622b285192aSMauro Carvalho Chehab saa7164_encoder_buffers_dealloc(port);
623b285192aSMauro Carvalho Chehab
624b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s(port=%d) Released\n", __func__, port->nr);
625b285192aSMauro Carvalho Chehab
626b285192aSMauro Carvalho Chehab return ret;
627b285192aSMauro Carvalho Chehab }
628b285192aSMauro Carvalho Chehab
saa7164_encoder_start_streaming(struct saa7164_port * port)629b285192aSMauro Carvalho Chehab static int saa7164_encoder_start_streaming(struct saa7164_port *port)
630b285192aSMauro Carvalho Chehab {
631b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
632b285192aSMauro Carvalho Chehab int result, ret = 0;
633b285192aSMauro Carvalho Chehab
634b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
635b285192aSMauro Carvalho Chehab
636b285192aSMauro Carvalho Chehab port->done_first_interrupt = 0;
637b285192aSMauro Carvalho Chehab
638b285192aSMauro Carvalho Chehab /* allocate all of the PCIe DMA buffer resources on the fly,
639b285192aSMauro Carvalho Chehab * allowing switching between TS and PS payloads without
640b285192aSMauro Carvalho Chehab * requiring a complete driver reload.
641b285192aSMauro Carvalho Chehab */
642b285192aSMauro Carvalho Chehab saa7164_encoder_buffers_alloc(port);
643b285192aSMauro Carvalho Chehab
644b285192aSMauro Carvalho Chehab /* Configure the encoder with any cache values */
645b285192aSMauro Carvalho Chehab saa7164_api_set_encoder(port);
646b285192aSMauro Carvalho Chehab saa7164_api_get_encoder(port);
647b285192aSMauro Carvalho Chehab
648b285192aSMauro Carvalho Chehab /* Place the empty buffers on the hardware */
649b285192aSMauro Carvalho Chehab saa7164_buffer_cfg_port(port);
650b285192aSMauro Carvalho Chehab
651b285192aSMauro Carvalho Chehab /* Acquire the hardware */
652b285192aSMauro Carvalho Chehab result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
653b285192aSMauro Carvalho Chehab if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
654b285192aSMauro Carvalho Chehab printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n",
655b285192aSMauro Carvalho Chehab __func__, result);
656b285192aSMauro Carvalho Chehab
657b285192aSMauro Carvalho Chehab /* Stop the hardware, regardless */
658b285192aSMauro Carvalho Chehab result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
659b285192aSMauro Carvalho Chehab if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
66024f711c1SMauro Carvalho Chehab printk(KERN_ERR "%s() acquire/forced stop transition failed, res = 0x%x\n",
66124f711c1SMauro Carvalho Chehab __func__, result);
662b285192aSMauro Carvalho Chehab }
663b285192aSMauro Carvalho Chehab ret = -EIO;
664b285192aSMauro Carvalho Chehab goto out;
665b285192aSMauro Carvalho Chehab } else
666b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s() Acquired\n", __func__);
667b285192aSMauro Carvalho Chehab
668b285192aSMauro Carvalho Chehab /* Pause the hardware */
669b285192aSMauro Carvalho Chehab result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
670b285192aSMauro Carvalho Chehab if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
671b285192aSMauro Carvalho Chehab printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n",
672b285192aSMauro Carvalho Chehab __func__, result);
673b285192aSMauro Carvalho Chehab
674b285192aSMauro Carvalho Chehab /* Stop the hardware, regardless */
675b285192aSMauro Carvalho Chehab result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
676b285192aSMauro Carvalho Chehab if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
67724f711c1SMauro Carvalho Chehab printk(KERN_ERR "%s() pause/forced stop transition failed, res = 0x%x\n",
67824f711c1SMauro Carvalho Chehab __func__, result);
679b285192aSMauro Carvalho Chehab }
680b285192aSMauro Carvalho Chehab
681b285192aSMauro Carvalho Chehab ret = -EIO;
682b285192aSMauro Carvalho Chehab goto out;
683b285192aSMauro Carvalho Chehab } else
684b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s() Paused\n", __func__);
685b285192aSMauro Carvalho Chehab
686b285192aSMauro Carvalho Chehab /* Start the hardware */
687b285192aSMauro Carvalho Chehab result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN);
688b285192aSMauro Carvalho Chehab if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
689b285192aSMauro Carvalho Chehab printk(KERN_ERR "%s() run transition failed, result = 0x%x\n",
690b285192aSMauro Carvalho Chehab __func__, result);
691b285192aSMauro Carvalho Chehab
692b285192aSMauro Carvalho Chehab /* Stop the hardware, regardless */
693b285192aSMauro Carvalho Chehab result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
694b285192aSMauro Carvalho Chehab if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
69524f711c1SMauro Carvalho Chehab printk(KERN_ERR "%s() run/forced stop transition failed, res = 0x%x\n",
69624f711c1SMauro Carvalho Chehab __func__, result);
697b285192aSMauro Carvalho Chehab }
698b285192aSMauro Carvalho Chehab
699b285192aSMauro Carvalho Chehab ret = -EIO;
700b285192aSMauro Carvalho Chehab } else
701b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s() Running\n", __func__);
702b285192aSMauro Carvalho Chehab
703b285192aSMauro Carvalho Chehab out:
704b285192aSMauro Carvalho Chehab return ret;
705b285192aSMauro Carvalho Chehab }
706b285192aSMauro Carvalho Chehab
fops_open(struct file * file)707b285192aSMauro Carvalho Chehab static int fops_open(struct file *file)
708b285192aSMauro Carvalho Chehab {
709b285192aSMauro Carvalho Chehab struct saa7164_dev *dev;
710b285192aSMauro Carvalho Chehab struct saa7164_port *port;
711b285192aSMauro Carvalho Chehab struct saa7164_encoder_fh *fh;
712b285192aSMauro Carvalho Chehab
713b285192aSMauro Carvalho Chehab port = (struct saa7164_port *)video_get_drvdata(video_devdata(file));
714b285192aSMauro Carvalho Chehab if (!port)
715b285192aSMauro Carvalho Chehab return -ENODEV;
716b285192aSMauro Carvalho Chehab
717b285192aSMauro Carvalho Chehab dev = port->dev;
718b285192aSMauro Carvalho Chehab
719b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s()\n", __func__);
720b285192aSMauro Carvalho Chehab
721b285192aSMauro Carvalho Chehab /* allocate + initialize per filehandle data */
722b285192aSMauro Carvalho Chehab fh = kzalloc(sizeof(*fh), GFP_KERNEL);
723b285192aSMauro Carvalho Chehab if (NULL == fh)
724b285192aSMauro Carvalho Chehab return -ENOMEM;
725b285192aSMauro Carvalho Chehab
726b285192aSMauro Carvalho Chehab fh->port = port;
727d6d3fe2fSHans Verkuil v4l2_fh_init(&fh->fh, video_devdata(file));
728d6d3fe2fSHans Verkuil v4l2_fh_add(&fh->fh);
729d6d3fe2fSHans Verkuil file->private_data = fh;
730b285192aSMauro Carvalho Chehab
731b285192aSMauro Carvalho Chehab return 0;
732b285192aSMauro Carvalho Chehab }
733b285192aSMauro Carvalho Chehab
fops_release(struct file * file)734b285192aSMauro Carvalho Chehab static int fops_release(struct file *file)
735b285192aSMauro Carvalho Chehab {
736b285192aSMauro Carvalho Chehab struct saa7164_encoder_fh *fh = file->private_data;
737b285192aSMauro Carvalho Chehab struct saa7164_port *port = fh->port;
738b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
739b285192aSMauro Carvalho Chehab
740b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s()\n", __func__);
741b285192aSMauro Carvalho Chehab
742b285192aSMauro Carvalho Chehab /* Shut device down on last close */
743b285192aSMauro Carvalho Chehab if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
744b285192aSMauro Carvalho Chehab if (atomic_dec_return(&port->v4l_reader_count) == 0) {
745b285192aSMauro Carvalho Chehab /* stop mpeg capture then cancel buffers */
746b285192aSMauro Carvalho Chehab saa7164_encoder_stop_streaming(port);
747b285192aSMauro Carvalho Chehab }
748b285192aSMauro Carvalho Chehab }
749b285192aSMauro Carvalho Chehab
750d6d3fe2fSHans Verkuil v4l2_fh_del(&fh->fh);
751d6d3fe2fSHans Verkuil v4l2_fh_exit(&fh->fh);
752b285192aSMauro Carvalho Chehab kfree(fh);
753b285192aSMauro Carvalho Chehab
754b285192aSMauro Carvalho Chehab return 0;
755b285192aSMauro Carvalho Chehab }
756b285192aSMauro Carvalho Chehab
7575faf7db8SMauro Carvalho Chehab static struct
saa7164_enc_next_buf(struct saa7164_port * port)7585faf7db8SMauro Carvalho Chehab saa7164_user_buffer *saa7164_enc_next_buf(struct saa7164_port *port)
759b285192aSMauro Carvalho Chehab {
760b285192aSMauro Carvalho Chehab struct saa7164_user_buffer *ubuf = NULL;
761b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
762b285192aSMauro Carvalho Chehab u32 crc;
763b285192aSMauro Carvalho Chehab
764b285192aSMauro Carvalho Chehab mutex_lock(&port->dmaqueue_lock);
765b285192aSMauro Carvalho Chehab if (!list_empty(&port->list_buf_used.list)) {
766b285192aSMauro Carvalho Chehab ubuf = list_first_entry(&port->list_buf_used.list,
767b285192aSMauro Carvalho Chehab struct saa7164_user_buffer, list);
768b285192aSMauro Carvalho Chehab
769b285192aSMauro Carvalho Chehab if (crc_checking) {
770b285192aSMauro Carvalho Chehab crc = crc32(0, ubuf->data, ubuf->actual_size);
771b285192aSMauro Carvalho Chehab if (crc != ubuf->crc) {
772b285192aSMauro Carvalho Chehab printk(KERN_ERR
773b285192aSMauro Carvalho Chehab "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n",
774b285192aSMauro Carvalho Chehab __func__,
775b285192aSMauro Carvalho Chehab ubuf, ubuf->crc, crc);
776b285192aSMauro Carvalho Chehab }
777b285192aSMauro Carvalho Chehab }
778b285192aSMauro Carvalho Chehab
779b285192aSMauro Carvalho Chehab }
780b285192aSMauro Carvalho Chehab mutex_unlock(&port->dmaqueue_lock);
781b285192aSMauro Carvalho Chehab
782b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s() returns %p\n", __func__, ubuf);
783b285192aSMauro Carvalho Chehab
784b285192aSMauro Carvalho Chehab return ubuf;
785b285192aSMauro Carvalho Chehab }
786b285192aSMauro Carvalho Chehab
fops_read(struct file * file,char __user * buffer,size_t count,loff_t * pos)787b285192aSMauro Carvalho Chehab static ssize_t fops_read(struct file *file, char __user *buffer,
788b285192aSMauro Carvalho Chehab size_t count, loff_t *pos)
789b285192aSMauro Carvalho Chehab {
790b285192aSMauro Carvalho Chehab struct saa7164_encoder_fh *fh = file->private_data;
791b285192aSMauro Carvalho Chehab struct saa7164_port *port = fh->port;
792b285192aSMauro Carvalho Chehab struct saa7164_user_buffer *ubuf = NULL;
793b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
794b285192aSMauro Carvalho Chehab int ret = 0;
795b285192aSMauro Carvalho Chehab int rem, cnt;
796b285192aSMauro Carvalho Chehab u8 *p;
797b285192aSMauro Carvalho Chehab
798b285192aSMauro Carvalho Chehab port->last_read_msecs_diff = port->last_read_msecs;
799b285192aSMauro Carvalho Chehab port->last_read_msecs = jiffies_to_msecs(jiffies);
800b285192aSMauro Carvalho Chehab port->last_read_msecs_diff = port->last_read_msecs -
801b285192aSMauro Carvalho Chehab port->last_read_msecs_diff;
802b285192aSMauro Carvalho Chehab
803b285192aSMauro Carvalho Chehab saa7164_histogram_update(&port->read_interval,
804b285192aSMauro Carvalho Chehab port->last_read_msecs_diff);
805b285192aSMauro Carvalho Chehab
806b285192aSMauro Carvalho Chehab if (*pos) {
807b285192aSMauro Carvalho Chehab printk(KERN_ERR "%s() ESPIPE\n", __func__);
808b285192aSMauro Carvalho Chehab return -ESPIPE;
809b285192aSMauro Carvalho Chehab }
810b285192aSMauro Carvalho Chehab
811b285192aSMauro Carvalho Chehab if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
812b285192aSMauro Carvalho Chehab if (atomic_inc_return(&port->v4l_reader_count) == 1) {
813b285192aSMauro Carvalho Chehab
814b285192aSMauro Carvalho Chehab if (saa7164_encoder_initialize(port) < 0) {
815b285192aSMauro Carvalho Chehab printk(KERN_ERR "%s() EINVAL\n", __func__);
816b285192aSMauro Carvalho Chehab return -EINVAL;
817b285192aSMauro Carvalho Chehab }
818b285192aSMauro Carvalho Chehab
819b285192aSMauro Carvalho Chehab saa7164_encoder_start_streaming(port);
820b285192aSMauro Carvalho Chehab msleep(200);
821b285192aSMauro Carvalho Chehab }
822b285192aSMauro Carvalho Chehab }
823b285192aSMauro Carvalho Chehab
824b285192aSMauro Carvalho Chehab /* blocking wait for buffer */
825b285192aSMauro Carvalho Chehab if ((file->f_flags & O_NONBLOCK) == 0) {
826b285192aSMauro Carvalho Chehab if (wait_event_interruptible(port->wait_read,
827b285192aSMauro Carvalho Chehab saa7164_enc_next_buf(port))) {
828b285192aSMauro Carvalho Chehab printk(KERN_ERR "%s() ERESTARTSYS\n", __func__);
829b285192aSMauro Carvalho Chehab return -ERESTARTSYS;
830b285192aSMauro Carvalho Chehab }
831b285192aSMauro Carvalho Chehab }
832b285192aSMauro Carvalho Chehab
833b285192aSMauro Carvalho Chehab /* Pull the first buffer from the used list */
834b285192aSMauro Carvalho Chehab ubuf = saa7164_enc_next_buf(port);
835b285192aSMauro Carvalho Chehab
836b285192aSMauro Carvalho Chehab while ((count > 0) && ubuf) {
837b285192aSMauro Carvalho Chehab
838b285192aSMauro Carvalho Chehab /* set remaining bytes to copy */
839b285192aSMauro Carvalho Chehab rem = ubuf->actual_size - ubuf->pos;
840b285192aSMauro Carvalho Chehab cnt = rem > count ? count : rem;
841b285192aSMauro Carvalho Chehab
842b285192aSMauro Carvalho Chehab p = ubuf->data + ubuf->pos;
843b285192aSMauro Carvalho Chehab
844b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC,
845b285192aSMauro Carvalho Chehab "%s() count=%d cnt=%d rem=%d buf=%p buf->pos=%d\n",
846b285192aSMauro Carvalho Chehab __func__, (int)count, cnt, rem, ubuf, ubuf->pos);
847b285192aSMauro Carvalho Chehab
848b285192aSMauro Carvalho Chehab if (copy_to_user(buffer, p, cnt)) {
849b285192aSMauro Carvalho Chehab printk(KERN_ERR "%s() copy_to_user failed\n", __func__);
850b285192aSMauro Carvalho Chehab if (!ret) {
851b285192aSMauro Carvalho Chehab printk(KERN_ERR "%s() EFAULT\n", __func__);
852b285192aSMauro Carvalho Chehab ret = -EFAULT;
853b285192aSMauro Carvalho Chehab }
854b285192aSMauro Carvalho Chehab goto err;
855b285192aSMauro Carvalho Chehab }
856b285192aSMauro Carvalho Chehab
857b285192aSMauro Carvalho Chehab ubuf->pos += cnt;
858b285192aSMauro Carvalho Chehab count -= cnt;
859b285192aSMauro Carvalho Chehab buffer += cnt;
860b285192aSMauro Carvalho Chehab ret += cnt;
861b285192aSMauro Carvalho Chehab
862b285192aSMauro Carvalho Chehab if (ubuf->pos > ubuf->actual_size)
863b285192aSMauro Carvalho Chehab printk(KERN_ERR "read() pos > actual, huh?\n");
864b285192aSMauro Carvalho Chehab
865b285192aSMauro Carvalho Chehab if (ubuf->pos == ubuf->actual_size) {
866b285192aSMauro Carvalho Chehab
867b285192aSMauro Carvalho Chehab /* finished with current buffer, take next buffer */
868b285192aSMauro Carvalho Chehab
869b285192aSMauro Carvalho Chehab /* Requeue the buffer on the free list */
870b285192aSMauro Carvalho Chehab ubuf->pos = 0;
871b285192aSMauro Carvalho Chehab
872b285192aSMauro Carvalho Chehab mutex_lock(&port->dmaqueue_lock);
873b285192aSMauro Carvalho Chehab list_move_tail(&ubuf->list, &port->list_buf_free.list);
874b285192aSMauro Carvalho Chehab mutex_unlock(&port->dmaqueue_lock);
875b285192aSMauro Carvalho Chehab
876b285192aSMauro Carvalho Chehab /* Dequeue next */
877b285192aSMauro Carvalho Chehab if ((file->f_flags & O_NONBLOCK) == 0) {
878b285192aSMauro Carvalho Chehab if (wait_event_interruptible(port->wait_read,
879b285192aSMauro Carvalho Chehab saa7164_enc_next_buf(port))) {
880b285192aSMauro Carvalho Chehab break;
881b285192aSMauro Carvalho Chehab }
882b285192aSMauro Carvalho Chehab }
883b285192aSMauro Carvalho Chehab ubuf = saa7164_enc_next_buf(port);
884b285192aSMauro Carvalho Chehab }
885b285192aSMauro Carvalho Chehab }
886b285192aSMauro Carvalho Chehab err:
887b285192aSMauro Carvalho Chehab if (!ret && !ubuf)
888b285192aSMauro Carvalho Chehab ret = -EAGAIN;
889b285192aSMauro Carvalho Chehab
890b285192aSMauro Carvalho Chehab return ret;
891b285192aSMauro Carvalho Chehab }
892b285192aSMauro Carvalho Chehab
fops_poll(struct file * file,poll_table * wait)893c23e0cb8SAl Viro static __poll_t fops_poll(struct file *file, poll_table *wait)
894b285192aSMauro Carvalho Chehab {
89501699437SAl Viro __poll_t req_events = poll_requested_events(wait);
896b285192aSMauro Carvalho Chehab struct saa7164_encoder_fh *fh =
897b285192aSMauro Carvalho Chehab (struct saa7164_encoder_fh *)file->private_data;
898b285192aSMauro Carvalho Chehab struct saa7164_port *port = fh->port;
899c23e0cb8SAl Viro __poll_t mask = v4l2_ctrl_poll(file, wait);
900b285192aSMauro Carvalho Chehab
901b285192aSMauro Carvalho Chehab port->last_poll_msecs_diff = port->last_poll_msecs;
902b285192aSMauro Carvalho Chehab port->last_poll_msecs = jiffies_to_msecs(jiffies);
903b285192aSMauro Carvalho Chehab port->last_poll_msecs_diff = port->last_poll_msecs -
904b285192aSMauro Carvalho Chehab port->last_poll_msecs_diff;
905b285192aSMauro Carvalho Chehab
906b285192aSMauro Carvalho Chehab saa7164_histogram_update(&port->poll_interval,
907b285192aSMauro Carvalho Chehab port->last_poll_msecs_diff);
908b285192aSMauro Carvalho Chehab
909a9a08845SLinus Torvalds if (!(req_events & (EPOLLIN | EPOLLRDNORM)))
91045053edcSHans Verkuil return mask;
911b285192aSMauro Carvalho Chehab
912b285192aSMauro Carvalho Chehab if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
913b285192aSMauro Carvalho Chehab if (atomic_inc_return(&port->v4l_reader_count) == 1) {
914b285192aSMauro Carvalho Chehab if (saa7164_encoder_initialize(port) < 0)
915a9a08845SLinus Torvalds return mask | EPOLLERR;
916b285192aSMauro Carvalho Chehab saa7164_encoder_start_streaming(port);
917b285192aSMauro Carvalho Chehab msleep(200);
918b285192aSMauro Carvalho Chehab }
919b285192aSMauro Carvalho Chehab }
920b285192aSMauro Carvalho Chehab
921b285192aSMauro Carvalho Chehab /* Pull the first buffer from the used list */
922b285192aSMauro Carvalho Chehab if (!list_empty(&port->list_buf_used.list))
923a9a08845SLinus Torvalds mask |= EPOLLIN | EPOLLRDNORM;
924b285192aSMauro Carvalho Chehab
925b285192aSMauro Carvalho Chehab return mask;
926b285192aSMauro Carvalho Chehab }
927b285192aSMauro Carvalho Chehab
9281a708ea0SHans Verkuil static const struct v4l2_ctrl_ops saa7164_ctrl_ops = {
9291a708ea0SHans Verkuil .s_ctrl = saa7164_s_ctrl,
9301a708ea0SHans Verkuil };
9311a708ea0SHans Verkuil
932b285192aSMauro Carvalho Chehab static const struct v4l2_file_operations mpeg_fops = {
933b285192aSMauro Carvalho Chehab .owner = THIS_MODULE,
934b285192aSMauro Carvalho Chehab .open = fops_open,
935b285192aSMauro Carvalho Chehab .release = fops_release,
936b285192aSMauro Carvalho Chehab .read = fops_read,
937b285192aSMauro Carvalho Chehab .poll = fops_poll,
938b285192aSMauro Carvalho Chehab .unlocked_ioctl = video_ioctl2,
939b285192aSMauro Carvalho Chehab };
940b285192aSMauro Carvalho Chehab
941b285192aSMauro Carvalho Chehab static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
942b285192aSMauro Carvalho Chehab .vidioc_s_std = vidioc_s_std,
9438d2d41e9SHans Verkuil .vidioc_g_std = vidioc_g_std,
944225b783bSHans Verkuil .vidioc_enum_input = saa7164_enum_input,
945b285192aSMauro Carvalho Chehab .vidioc_g_input = vidioc_g_input,
946b285192aSMauro Carvalho Chehab .vidioc_s_input = vidioc_s_input,
947225b783bSHans Verkuil .vidioc_g_tuner = saa7164_g_tuner,
948225b783bSHans Verkuil .vidioc_s_tuner = saa7164_s_tuner,
949b285192aSMauro Carvalho Chehab .vidioc_g_frequency = vidioc_g_frequency,
950b285192aSMauro Carvalho Chehab .vidioc_s_frequency = vidioc_s_frequency,
951b285192aSMauro Carvalho Chehab .vidioc_querycap = vidioc_querycap,
952b285192aSMauro Carvalho Chehab .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
953031d2297SHans Verkuil .vidioc_g_fmt_vid_cap = vidioc_fmt_vid_cap,
954031d2297SHans Verkuil .vidioc_try_fmt_vid_cap = vidioc_fmt_vid_cap,
955031d2297SHans Verkuil .vidioc_s_fmt_vid_cap = vidioc_fmt_vid_cap,
956245b5ae9SHans Verkuil .vidioc_log_status = v4l2_ctrl_log_status,
957245b5ae9SHans Verkuil .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
958245b5ae9SHans Verkuil .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
959b285192aSMauro Carvalho Chehab };
960b285192aSMauro Carvalho Chehab
961b285192aSMauro Carvalho Chehab static struct video_device saa7164_mpeg_template = {
962b285192aSMauro Carvalho Chehab .name = "saa7164",
963b285192aSMauro Carvalho Chehab .fops = &mpeg_fops,
964b285192aSMauro Carvalho Chehab .ioctl_ops = &mpeg_ioctl_ops,
965b285192aSMauro Carvalho Chehab .minor = -1,
966b285192aSMauro Carvalho Chehab .tvnorms = SAA7164_NORMS,
96721615365SHans Verkuil .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
96821615365SHans Verkuil V4L2_CAP_TUNER,
969b285192aSMauro Carvalho Chehab };
970b285192aSMauro Carvalho Chehab
saa7164_encoder_alloc(struct saa7164_port * port,struct pci_dev * pci,struct video_device * template,char * type)971b285192aSMauro Carvalho Chehab static struct video_device *saa7164_encoder_alloc(
972b285192aSMauro Carvalho Chehab struct saa7164_port *port,
973b285192aSMauro Carvalho Chehab struct pci_dev *pci,
974b285192aSMauro Carvalho Chehab struct video_device *template,
975b285192aSMauro Carvalho Chehab char *type)
976b285192aSMauro Carvalho Chehab {
977b285192aSMauro Carvalho Chehab struct video_device *vfd;
978b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
979b285192aSMauro Carvalho Chehab
980b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s()\n", __func__);
981b285192aSMauro Carvalho Chehab
982b285192aSMauro Carvalho Chehab vfd = video_device_alloc();
983b285192aSMauro Carvalho Chehab if (NULL == vfd)
984b285192aSMauro Carvalho Chehab return NULL;
985b285192aSMauro Carvalho Chehab
986b285192aSMauro Carvalho Chehab *vfd = *template;
987b285192aSMauro Carvalho Chehab snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
988b285192aSMauro Carvalho Chehab type, saa7164_boards[dev->board].name);
989b285192aSMauro Carvalho Chehab
990d66de790SHans Verkuil vfd->v4l2_dev = &dev->v4l2_dev;
991b285192aSMauro Carvalho Chehab vfd->release = video_device_release;
992b285192aSMauro Carvalho Chehab return vfd;
993b285192aSMauro Carvalho Chehab }
994b285192aSMauro Carvalho Chehab
saa7164_encoder_register(struct saa7164_port * port)995b285192aSMauro Carvalho Chehab int saa7164_encoder_register(struct saa7164_port *port)
996b285192aSMauro Carvalho Chehab {
997b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
9981a708ea0SHans Verkuil struct v4l2_ctrl_handler *hdl = &port->ctrl_handler;
999b285192aSMauro Carvalho Chehab int result = -ENODEV;
1000b285192aSMauro Carvalho Chehab
1001b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s()\n", __func__);
1002b285192aSMauro Carvalho Chehab
10032aefee05SAmitoj Kaur Chawla BUG_ON(port->type != SAA7164_MPEG_ENCODER);
1004b285192aSMauro Carvalho Chehab
1005b285192aSMauro Carvalho Chehab /* Sanity check that the PCI configuration space is active */
1006b285192aSMauro Carvalho Chehab if (port->hwcfg.BARLocation == 0) {
100724f711c1SMauro Carvalho Chehab printk(KERN_ERR "%s() failed (errno = %d), NO PCI configuration\n",
1008b285192aSMauro Carvalho Chehab __func__, result);
1009b285192aSMauro Carvalho Chehab result = -ENOMEM;
1010c759b297SDaniel Niv goto fail_pci;
1011b285192aSMauro Carvalho Chehab }
1012b285192aSMauro Carvalho Chehab
1013b285192aSMauro Carvalho Chehab /* Establish encoder defaults here */
1014b285192aSMauro Carvalho Chehab /* Set default TV standard */
1015b285192aSMauro Carvalho Chehab port->encodernorm = saa7164_tvnorms[0];
1016b285192aSMauro Carvalho Chehab port->width = 720;
1017b285192aSMauro Carvalho Chehab port->mux_input = 1; /* Composite */
1018b285192aSMauro Carvalho Chehab port->video_format = EU_VIDEO_FORMAT_MPEG_2;
1019b285192aSMauro Carvalho Chehab port->audio_format = 0;
1020b285192aSMauro Carvalho Chehab port->video_resolution = 0;
10216b996126SHans Verkuil port->freq = SAA7164_TV_MIN_FREQ;
10221a708ea0SHans Verkuil
10231a708ea0SHans Verkuil v4l2_ctrl_handler_init(hdl, 14);
10241a708ea0SHans Verkuil v4l2_ctrl_new_std(hdl, &saa7164_ctrl_ops,
10251a708ea0SHans Verkuil V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
10261a708ea0SHans Verkuil v4l2_ctrl_new_std(hdl, &saa7164_ctrl_ops,
10271a708ea0SHans Verkuil V4L2_CID_CONTRAST, 0, 255, 1, 66);
10281a708ea0SHans Verkuil v4l2_ctrl_new_std(hdl, &saa7164_ctrl_ops,
10291a708ea0SHans Verkuil V4L2_CID_SATURATION, 0, 255, 1, 62);
10301a708ea0SHans Verkuil v4l2_ctrl_new_std(hdl, &saa7164_ctrl_ops,
10311a708ea0SHans Verkuil V4L2_CID_HUE, 0, 255, 1, 128);
10321a708ea0SHans Verkuil v4l2_ctrl_new_std(hdl, &saa7164_ctrl_ops,
10331a708ea0SHans Verkuil V4L2_CID_SHARPNESS, 0x0, 0x0f, 1, 8);
10341a708ea0SHans Verkuil v4l2_ctrl_new_std(hdl, &saa7164_ctrl_ops,
10351a708ea0SHans Verkuil V4L2_CID_MPEG_AUDIO_MUTE, 0x0, 0x01, 1, 0);
10361a708ea0SHans Verkuil v4l2_ctrl_new_std(hdl, &saa7164_ctrl_ops,
10371a708ea0SHans Verkuil V4L2_CID_AUDIO_VOLUME, -83, 24, 1, 20);
10381a708ea0SHans Verkuil v4l2_ctrl_new_std(hdl, &saa7164_ctrl_ops,
10391a708ea0SHans Verkuil V4L2_CID_MPEG_VIDEO_BITRATE,
10401a708ea0SHans Verkuil ENCODER_MIN_BITRATE, ENCODER_MAX_BITRATE,
10411a708ea0SHans Verkuil 100000, ENCODER_DEF_BITRATE);
10421a708ea0SHans Verkuil v4l2_ctrl_new_std_menu(hdl, &saa7164_ctrl_ops,
10431a708ea0SHans Verkuil V4L2_CID_MPEG_STREAM_TYPE,
10441a708ea0SHans Verkuil V4L2_MPEG_STREAM_TYPE_MPEG2_TS, 0,
10451a708ea0SHans Verkuil V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
10461a708ea0SHans Verkuil v4l2_ctrl_new_std_menu(hdl, &saa7164_ctrl_ops,
10471a708ea0SHans Verkuil V4L2_CID_MPEG_VIDEO_ASPECT,
10481a708ea0SHans Verkuil V4L2_MPEG_VIDEO_ASPECT_221x100, 0,
10491a708ea0SHans Verkuil V4L2_MPEG_VIDEO_ASPECT_4x3);
10501a708ea0SHans Verkuil v4l2_ctrl_new_std(hdl, &saa7164_ctrl_ops,
10511a708ea0SHans Verkuil V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 255, 1, 15);
10521a708ea0SHans Verkuil v4l2_ctrl_new_std_menu(hdl, &saa7164_ctrl_ops,
10531a708ea0SHans Verkuil V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
10541a708ea0SHans Verkuil V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
10551a708ea0SHans Verkuil V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
10561a708ea0SHans Verkuil v4l2_ctrl_new_std(hdl, &saa7164_ctrl_ops,
10571a708ea0SHans Verkuil V4L2_CID_MPEG_VIDEO_B_FRAMES, 1, 3, 1, 1);
10581a708ea0SHans Verkuil v4l2_ctrl_new_std(hdl, &saa7164_ctrl_ops,
10591a708ea0SHans Verkuil V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
10601a708ea0SHans Verkuil ENCODER_MIN_BITRATE, ENCODER_MAX_BITRATE,
10611a708ea0SHans Verkuil 100000, ENCODER_DEF_BITRATE);
10621a708ea0SHans Verkuil if (hdl->error) {
10631a708ea0SHans Verkuil result = hdl->error;
1064c759b297SDaniel Niv goto fail_hdl;
10651a708ea0SHans Verkuil }
10661a708ea0SHans Verkuil
10678d2d41e9SHans Verkuil port->std = V4L2_STD_NTSC_M;
1068b285192aSMauro Carvalho Chehab
1069b285192aSMauro Carvalho Chehab if (port->encodernorm.id & V4L2_STD_525_60)
1070b285192aSMauro Carvalho Chehab port->height = 480;
1071b285192aSMauro Carvalho Chehab else
1072b285192aSMauro Carvalho Chehab port->height = 576;
1073b285192aSMauro Carvalho Chehab
1074b285192aSMauro Carvalho Chehab /* Allocate and register the video device node */
1075b285192aSMauro Carvalho Chehab port->v4l_device = saa7164_encoder_alloc(port,
1076b285192aSMauro Carvalho Chehab dev->pci, &saa7164_mpeg_template, "mpeg");
1077b285192aSMauro Carvalho Chehab
1078b285192aSMauro Carvalho Chehab if (!port->v4l_device) {
1079b285192aSMauro Carvalho Chehab printk(KERN_INFO "%s: can't allocate mpeg device\n",
1080b285192aSMauro Carvalho Chehab dev->name);
1081b285192aSMauro Carvalho Chehab result = -ENOMEM;
1082c759b297SDaniel Niv goto fail_hdl;
1083b285192aSMauro Carvalho Chehab }
1084b285192aSMauro Carvalho Chehab
10851a708ea0SHans Verkuil port->v4l_device->ctrl_handler = hdl;
10861a708ea0SHans Verkuil v4l2_ctrl_handler_setup(hdl);
1087b285192aSMauro Carvalho Chehab video_set_drvdata(port->v4l_device, port);
1088b285192aSMauro Carvalho Chehab result = video_register_device(port->v4l_device,
10893e30a927SHans Verkuil VFL_TYPE_VIDEO, -1);
1090b285192aSMauro Carvalho Chehab if (result < 0) {
1091b285192aSMauro Carvalho Chehab printk(KERN_INFO "%s: can't register mpeg device\n",
1092b285192aSMauro Carvalho Chehab dev->name);
1093c759b297SDaniel Niv goto fail_reg;
1094b285192aSMauro Carvalho Chehab }
1095b285192aSMauro Carvalho Chehab
1096b285192aSMauro Carvalho Chehab printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
1097b285192aSMauro Carvalho Chehab dev->name, port->v4l_device->num);
1098b285192aSMauro Carvalho Chehab
1099b285192aSMauro Carvalho Chehab /* Configure the hardware defaults */
1100b285192aSMauro Carvalho Chehab saa7164_api_set_videomux(port);
1101b285192aSMauro Carvalho Chehab saa7164_api_set_usercontrol(port, PU_BRIGHTNESS_CONTROL);
1102b285192aSMauro Carvalho Chehab saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL);
1103b285192aSMauro Carvalho Chehab saa7164_api_set_usercontrol(port, PU_HUE_CONTROL);
1104b285192aSMauro Carvalho Chehab saa7164_api_set_usercontrol(port, PU_SATURATION_CONTROL);
1105b285192aSMauro Carvalho Chehab saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL);
1106b285192aSMauro Carvalho Chehab saa7164_api_audio_mute(port, 0);
1107b285192aSMauro Carvalho Chehab saa7164_api_set_audio_volume(port, 20);
1108b285192aSMauro Carvalho Chehab saa7164_api_set_aspect_ratio(port);
1109b285192aSMauro Carvalho Chehab
1110b285192aSMauro Carvalho Chehab /* Disable audio standard detection, it's buggy */
1111b285192aSMauro Carvalho Chehab saa7164_api_set_audio_detection(port, 0);
1112b285192aSMauro Carvalho Chehab
1113b285192aSMauro Carvalho Chehab saa7164_api_set_encoder(port);
1114b285192aSMauro Carvalho Chehab saa7164_api_get_encoder(port);
1115c759b297SDaniel Niv return 0;
1116b285192aSMauro Carvalho Chehab
1117c759b297SDaniel Niv fail_reg:
1118c759b297SDaniel Niv video_device_release(port->v4l_device);
1119c759b297SDaniel Niv port->v4l_device = NULL;
1120c759b297SDaniel Niv fail_hdl:
1121c759b297SDaniel Niv v4l2_ctrl_handler_free(hdl);
1122c759b297SDaniel Niv fail_pci:
1123b285192aSMauro Carvalho Chehab return result;
1124b285192aSMauro Carvalho Chehab }
1125b285192aSMauro Carvalho Chehab
saa7164_encoder_unregister(struct saa7164_port * port)1126b285192aSMauro Carvalho Chehab void saa7164_encoder_unregister(struct saa7164_port *port)
1127b285192aSMauro Carvalho Chehab {
1128b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = port->dev;
1129b285192aSMauro Carvalho Chehab
1130b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
1131b285192aSMauro Carvalho Chehab
11322aefee05SAmitoj Kaur Chawla BUG_ON(port->type != SAA7164_MPEG_ENCODER);
1133b285192aSMauro Carvalho Chehab
1134b285192aSMauro Carvalho Chehab if (port->v4l_device) {
1135b285192aSMauro Carvalho Chehab if (port->v4l_device->minor != -1)
1136b285192aSMauro Carvalho Chehab video_unregister_device(port->v4l_device);
1137b285192aSMauro Carvalho Chehab else
1138b285192aSMauro Carvalho Chehab video_device_release(port->v4l_device);
1139b285192aSMauro Carvalho Chehab
1140b285192aSMauro Carvalho Chehab port->v4l_device = NULL;
1141b285192aSMauro Carvalho Chehab }
11421a708ea0SHans Verkuil v4l2_ctrl_handler_free(&port->ctrl_handler);
1143b285192aSMauro Carvalho Chehab
1144b285192aSMauro Carvalho Chehab dprintk(DBGLVL_ENC, "%s(port=%d) done\n", __func__, port->nr);
1145b285192aSMauro Carvalho Chehab }
1146b285192aSMauro Carvalho Chehab
1147