19b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth/*
29b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth *  Driver for the NXP SAA7164 PCIe bridge
39b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth *
49b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
59b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth *
69b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth *  This program is free software; you can redistribute it and/or modify
79b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth *  it under the terms of the GNU General Public License as published by
89b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth *  the Free Software Foundation; either version 2 of the License, or
99b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth *  (at your option) any later version.
109b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth *
119b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth *  This program is distributed in the hope that it will be useful,
129b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth *  but WITHOUT ANY WARRANTY; without even the implied warranty of
139b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
149b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth *
159b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth *  GNU General Public License for more details.
169b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth *
179b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth *  You should have received a copy of the GNU General Public License
189b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth *  along with this program; if not, write to the Free Software
199b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
209b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth */
219b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth
229b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth#include "saa7164.h"
239b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth
247615e434aefd95181eae099c4f019e021b024eb6Steven Toth#define ENCODER_MAX_BITRATE 6500000
257615e434aefd95181eae099c4f019e021b024eb6Steven Toth#define ENCODER_MIN_BITRATE 1000000
267615e434aefd95181eae099c4f019e021b024eb6Steven Toth#define ENCODER_DEF_BITRATE 5000000
277615e434aefd95181eae099c4f019e021b024eb6Steven Toth
287615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic struct saa7164_tvnorm saa7164_tvnorms[] = {
297615e434aefd95181eae099c4f019e021b024eb6Steven Toth	{
307615e434aefd95181eae099c4f019e021b024eb6Steven Toth		.name      = "NTSC-M",
317615e434aefd95181eae099c4f019e021b024eb6Steven Toth		.id        = V4L2_STD_NTSC_M,
327615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}, {
337615e434aefd95181eae099c4f019e021b024eb6Steven Toth		.name      = "NTSC-JP",
347615e434aefd95181eae099c4f019e021b024eb6Steven Toth		.id        = V4L2_STD_NTSC_M_JP,
357615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
367615e434aefd95181eae099c4f019e021b024eb6Steven Toth};
377615e434aefd95181eae099c4f019e021b024eb6Steven Toth
387615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic const u32 saa7164_v4l2_ctrls[] = {
397615e434aefd95181eae099c4f019e021b024eb6Steven Toth	V4L2_CID_BRIGHTNESS,
407615e434aefd95181eae099c4f019e021b024eb6Steven Toth	V4L2_CID_CONTRAST,
417615e434aefd95181eae099c4f019e021b024eb6Steven Toth	V4L2_CID_SATURATION,
427615e434aefd95181eae099c4f019e021b024eb6Steven Toth	V4L2_CID_HUE,
437615e434aefd95181eae099c4f019e021b024eb6Steven Toth	V4L2_CID_AUDIO_VOLUME,
447615e434aefd95181eae099c4f019e021b024eb6Steven Toth	V4L2_CID_SHARPNESS,
455fa56ccdacc54f5f694141c1a74f781cf77874bbSteven Toth	V4L2_CID_MPEG_STREAM_TYPE,
467615e434aefd95181eae099c4f019e021b024eb6Steven Toth	V4L2_CID_MPEG_VIDEO_ASPECT,
475fa56ccdacc54f5f694141c1a74f781cf77874bbSteven Toth	V4L2_CID_MPEG_VIDEO_B_FRAMES,
48f91d095c92e8fdcb6bd8cb35e8fa9c87d9c10768Steven Toth	V4L2_CID_MPEG_VIDEO_GOP_SIZE,
497615e434aefd95181eae099c4f019e021b024eb6Steven Toth	V4L2_CID_MPEG_AUDIO_MUTE,
502600d71cc535907e5d95cd31751c587afc370065Steven Toth	V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
517615e434aefd95181eae099c4f019e021b024eb6Steven Toth	V4L2_CID_MPEG_VIDEO_BITRATE,
52968b11b20143036098a7013817a15615a54383d3Steven Toth	V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
537615e434aefd95181eae099c4f019e021b024eb6Steven Toth	0
547615e434aefd95181eae099c4f019e021b024eb6Steven Toth};
557615e434aefd95181eae099c4f019e021b024eb6Steven Toth
567615e434aefd95181eae099c4f019e021b024eb6Steven Toth/* Take the encoder configuration form the port struct and
577615e434aefd95181eae099c4f019e021b024eb6Steven Toth * flush it to the hardware.
587615e434aefd95181eae099c4f019e021b024eb6Steven Toth */
597615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic void saa7164_encoder_configure(struct saa7164_port *port)
607615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
617615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
627615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s()\n", __func__);
637615e434aefd95181eae099c4f019e021b024eb6Steven Toth
647615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->encoder_params.width = port->width;
657615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->encoder_params.height = port->height;
667615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->encoder_params.is_50hz =
677615e434aefd95181eae099c4f019e021b024eb6Steven Toth		(port->encodernorm.id & V4L2_STD_625_50) != 0;
687615e434aefd95181eae099c4f019e021b024eb6Steven Toth
697615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Set up the DIF (enable it) for analog mode by default */
707615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_initialize_dif(port);
717615e434aefd95181eae099c4f019e021b024eb6Steven Toth
727615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Configure the correct video standard */
737615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_configure_dif(port, port->encodernorm.id);
747615e434aefd95181eae099c4f019e021b024eb6Steven Toth
757615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Ensure the audio decoder is correct configured */
767615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_audio_std(port);
777615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
787615e434aefd95181eae099c4f019e021b024eb6Steven Toth
791b0e8e46297a214336d85c8e278a8a004f97889eSteven Tothstatic int saa7164_encoder_buffers_dealloc(struct saa7164_port *port)
801b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth{
811b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	struct list_head *c, *n, *p, *q, *l, *v;
821b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	struct saa7164_dev *dev = port->dev;
831b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	struct saa7164_buffer *buf;
841b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	struct saa7164_user_buffer *ubuf;
851b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
861b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	/* Remove any allocated buffers */
871b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	mutex_lock(&port->dmaqueue_lock);
881b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
891b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	dprintk(DBGLVL_ENC, "%s(port=%d) dmaqueue\n", __func__, port->nr);
901b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	list_for_each_safe(c, n, &port->dmaqueue.list) {
911b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		buf = list_entry(c, struct saa7164_buffer, list);
921b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		list_del(c);
931b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		saa7164_buffer_dealloc(buf);
941b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	}
951b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
961b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	dprintk(DBGLVL_ENC, "%s(port=%d) used\n", __func__, port->nr);
971b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	list_for_each_safe(p, q, &port->list_buf_used.list) {
981b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		ubuf = list_entry(p, struct saa7164_user_buffer, list);
991b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		list_del(p);
1001b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		saa7164_buffer_dealloc_user(ubuf);
1011b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	}
1021b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
1031b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	dprintk(DBGLVL_ENC, "%s(port=%d) free\n", __func__, port->nr);
1041b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	list_for_each_safe(l, v, &port->list_buf_free.list) {
1051b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		ubuf = list_entry(l, struct saa7164_user_buffer, list);
1061b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		list_del(l);
1071b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		saa7164_buffer_dealloc_user(ubuf);
1081b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	}
1091b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
1101b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	mutex_unlock(&port->dmaqueue_lock);
1111b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	dprintk(DBGLVL_ENC, "%s(port=%d) done\n", __func__, port->nr);
1121b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
1131b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	return 0;
1141b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth}
1151b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
1161b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth/* Dynamic buffer switch at encoder start time */
1171b0e8e46297a214336d85c8e278a8a004f97889eSteven Tothstatic int saa7164_encoder_buffers_alloc(struct saa7164_port *port)
1187615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
1197615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
1201b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	struct saa7164_buffer *buf;
1211b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	struct saa7164_user_buffer *ubuf;
1224d270cfb36683f623f2c23f96b695deb1812476eMauro Carvalho Chehab	struct tmHWStreamParameters *params = &port->hw_streamingparams;
1231b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	int result = -ENODEV, i;
1241b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	int len = 0;
1257615e434aefd95181eae099c4f019e021b024eb6Steven Toth
1267615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s()\n", __func__);
1277615e434aefd95181eae099c4f019e021b024eb6Steven Toth
128bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth	if (port->encoder_params.stream_type ==
129bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth		V4L2_MPEG_STREAM_TYPE_MPEG2_PS) {
130bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth		dprintk(DBGLVL_ENC,
131bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth			"%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_PS\n",
132bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth			__func__);
1331b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		params->samplesperline = 128;
1341b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		params->numberoflines = 256;
1351b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		params->pitch = 128;
1361b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		params->numpagetables = 2 +
1371b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			((SAA7164_PS_NUMBER_OF_LINES * 128) / PAGE_SIZE);
1381b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	} else
139bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth	if (port->encoder_params.stream_type ==
140bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth		V4L2_MPEG_STREAM_TYPE_MPEG2_TS) {
141bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth		dprintk(DBGLVL_ENC,
142bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth			"%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_TS\n",
143bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth			__func__);
1441b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		params->samplesperline = 188;
1451b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		params->numberoflines = 312;
1461b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		params->pitch = 188;
1471b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		params->numpagetables = 2 +
1481b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			((SAA7164_TS_NUMBER_OF_LINES * 188) / PAGE_SIZE);
1491b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	} else
1501b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		BUG();
1511b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
1521b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	/* Init and establish defaults */
1531b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	params->bitspersample = 8;
1541b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	params->linethreshold = 0;
15561ca1500c5ee04f2be34a4f58bb9baed0214b7a9Peter Huewe	params->pagetablelistvirt = NULL;
15661ca1500c5ee04f2be34a4f58bb9baed0214b7a9Peter Huewe	params->pagetablelistphys = NULL;
1571b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	params->numpagetableentries = port->hwcfg.buffercount;
1581b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
1591b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	/* Allocate the PCI resources, buffers (hard) */
1601b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	for (i = 0; i < port->hwcfg.buffercount; i++) {
1611b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		buf = saa7164_buffer_alloc(port,
1621b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			params->numberoflines *
1631b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			params->pitch);
1641b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
1651b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		if (!buf) {
1661b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			printk(KERN_ERR "%s() failed "
1671b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			       "(errno = %d), unable to allocate buffer\n",
1681b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth				__func__, result);
1691b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			result = -ENOMEM;
1701b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			goto failed;
1711b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		} else {
1721b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
1731b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			mutex_lock(&port->dmaqueue_lock);
1741b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			list_add_tail(&buf->list, &port->dmaqueue.list);
1751b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			mutex_unlock(&port->dmaqueue_lock);
1761b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
1771b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		}
1781b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	}
1791b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
18070f23fd66bc821a0e99647f70a809e277cc93c4cJustin P. Mattock	/* Allocate some kernel buffers for copying
1811b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	 * to userpsace.
1821b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	 */
1831b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	len = params->numberoflines * params->pitch;
1841b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
1851b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	if (encoder_buffers < 16)
1861b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		encoder_buffers = 16;
1871b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	if (encoder_buffers > 512)
1881b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		encoder_buffers = 512;
1891b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
1901b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	for (i = 0; i < encoder_buffers; i++) {
1911b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
1921b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		ubuf = saa7164_buffer_alloc_user(dev, len);
1931b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		if (ubuf) {
1941b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			mutex_lock(&port->dmaqueue_lock);
1951b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			list_add_tail(&ubuf->list, &port->list_buf_free.list);
1961b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			mutex_unlock(&port->dmaqueue_lock);
1971b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		}
1981b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
1991b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	}
2001b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
2011b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	result = 0;
2027615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2031b0e8e46297a214336d85c8e278a8a004f97889eSteven Tothfailed:
2041b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	return result;
2051b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth}
2061b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
2071b0e8e46297a214336d85c8e278a8a004f97889eSteven Tothstatic int saa7164_encoder_initialize(struct saa7164_port *port)
2081b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth{
2091b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	saa7164_encoder_configure(port);
2107615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
2117615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
2127615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2137615e434aefd95181eae099c4f019e021b024eb6Steven Toth/* -- V4L2 --------------------------------------------------------- */
214314527acbbb3f33f72c2ef19d8cfabcada9912a5Hans Verkuilstatic int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
2157615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
21696d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
2177615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
2187615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
2197615e434aefd95181eae099c4f019e021b024eb6Steven Toth	unsigned int i;
2207615e434aefd95181eae099c4f019e021b024eb6Steven Toth
221314527acbbb3f33f72c2ef19d8cfabcada9912a5Hans Verkuil	dprintk(DBGLVL_ENC, "%s(id=0x%x)\n", __func__, (u32)id);
2227615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2237615e434aefd95181eae099c4f019e021b024eb6Steven Toth	for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) {
224314527acbbb3f33f72c2ef19d8cfabcada9912a5Hans Verkuil		if (id & saa7164_tvnorms[i].id)
2257615e434aefd95181eae099c4f019e021b024eb6Steven Toth			break;
2267615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
2277615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (i == ARRAY_SIZE(saa7164_tvnorms))
2287615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
2297615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2307615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->encodernorm = saa7164_tvnorms[i];
2318d2d41e92d99e25f7d42fc83fc39096d89caa35eHans Verkuil	port->std = id;
2327615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2337615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Update the audio decoder while is not running in
2347615e434aefd95181eae099c4f019e021b024eb6Steven Toth	 * auto detect mode.
2357615e434aefd95181eae099c4f019e021b024eb6Steven Toth	 */
2367615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_audio_std(port);
2377615e434aefd95181eae099c4f019e021b024eb6Steven Toth
238314527acbbb3f33f72c2ef19d8cfabcada9912a5Hans Verkuil	dprintk(DBGLVL_ENC, "%s(id=0x%x) OK\n", __func__, (u32)id);
2397615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2407615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
2417615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
2427615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2438d2d41e92d99e25f7d42fc83fc39096d89caa35eHans Verkuilstatic int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
2448d2d41e92d99e25f7d42fc83fc39096d89caa35eHans Verkuil{
2458d2d41e92d99e25f7d42fc83fc39096d89caa35eHans Verkuil	struct saa7164_encoder_fh *fh = file->private_data;
2468d2d41e92d99e25f7d42fc83fc39096d89caa35eHans Verkuil	struct saa7164_port *port = fh->port;
2478d2d41e92d99e25f7d42fc83fc39096d89caa35eHans Verkuil
2488d2d41e92d99e25f7d42fc83fc39096d89caa35eHans Verkuil	*id = port->std;
2498d2d41e92d99e25f7d42fc83fc39096d89caa35eHans Verkuil	return 0;
2508d2d41e92d99e25f7d42fc83fc39096d89caa35eHans Verkuil}
2518d2d41e92d99e25f7d42fc83fc39096d89caa35eHans Verkuil
2527615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_enum_input(struct file *file, void *priv,
2537615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_input *i)
2547615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
2557615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int n;
2567615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2577615e434aefd95181eae099c4f019e021b024eb6Steven Toth	char *inputs[] = { "tuner", "composite", "svideo", "aux",
258f89076c5f13dc2fafd6c4a411111f1be7aab0098Gavin Hurlbut		"composite 2", "svideo 2", "aux 2" };
2597615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2607615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (i->index >= 7)
2617615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
2627615e434aefd95181eae099c4f019e021b024eb6Steven Toth
263c7e242baf73a284eff92444fb58af11439e3a22cMauro Carvalho Chehab	strcpy(i->name, inputs[i->index]);
2647615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2657615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (i->index == 0)
2667615e434aefd95181eae099c4f019e021b024eb6Steven Toth		i->type = V4L2_INPUT_TYPE_TUNER;
2677615e434aefd95181eae099c4f019e021b024eb6Steven Toth	else
2687615e434aefd95181eae099c4f019e021b024eb6Steven Toth		i->type  = V4L2_INPUT_TYPE_CAMERA;
2697615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2707615e434aefd95181eae099c4f019e021b024eb6Steven Toth	for (n = 0; n < ARRAY_SIZE(saa7164_tvnorms); n++)
2717615e434aefd95181eae099c4f019e021b024eb6Steven Toth		i->std |= saa7164_tvnorms[n].id;
2727615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2737615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
2747615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
2757615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2767615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
2777615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
27896d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
2797615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
2807615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
2817615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2827615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (saa7164_api_get_videomux(port) != SAA_OK)
2837615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EIO;
2847615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2857615e434aefd95181eae099c4f019e021b024eb6Steven Toth	*i = (port->mux_input - 1);
2867615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2877615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s() input=%d\n", __func__, *i);
2887615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2897615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
2907615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
2917615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2927615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_s_input(struct file *file, void *priv, unsigned int i)
2937615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
29496d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
2957615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
2967615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
2977615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2987615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s() input=%d\n", __func__, i);
2997615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3007615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (i >= 7)
3017615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
3027615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3037615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->mux_input = i + 1;
3047615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3057615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (saa7164_api_set_videomux(port) != SAA_OK)
3067615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EIO;
3077615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3087615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
3097615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
3107615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3117615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_g_tuner(struct file *file, void *priv,
3127615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_tuner *t)
3137615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
31496d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
3157615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
3167615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
3177615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3187615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (0 != t->index)
3197615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
3207615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3217615e434aefd95181eae099c4f019e021b024eb6Steven Toth	strcpy(t->name, "tuner");
3227615e434aefd95181eae099c4f019e021b024eb6Steven Toth	t->type = V4L2_TUNER_ANALOG_TV;
3237615e434aefd95181eae099c4f019e021b024eb6Steven Toth	t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO;
3247615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3257615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
3267615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3277615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
3287615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
3297615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3307615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_s_tuner(struct file *file, void *priv,
3312f73c7c582a685b3198b974cd6d964d0338f8ab5Hans Verkuil	const struct v4l2_tuner *t)
3327615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
3337615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Update the A/V core */
3347615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
3357615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
3367615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3377615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_g_frequency(struct file *file, void *priv,
3387615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_frequency *f)
3397615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
34096d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
3417615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
3427615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3437615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->type = V4L2_TUNER_ANALOG_TV;
3447615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->frequency = port->freq;
3457615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3467615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
3477615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
3487615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3497615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_s_frequency(struct file *file, void *priv,
350b530a447bb588fdf43fdf4eb909e4ee1921d47acHans Verkuil	const struct v4l2_frequency *f)
3517615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
35296d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
3537615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
3547615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
3557615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *tsport;
3567615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct dvb_frontend *fe;
3577615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3587615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* TODO: Pull this for the std */
3597615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct analog_parameters params = {
3607615e434aefd95181eae099c4f019e021b024eb6Steven Toth		.mode      = V4L2_TUNER_ANALOG_TV,
3617615e434aefd95181eae099c4f019e021b024eb6Steven Toth		.audmode   = V4L2_TUNER_MODE_STEREO,
3627615e434aefd95181eae099c4f019e021b024eb6Steven Toth		.std       = port->encodernorm.id,
3637615e434aefd95181eae099c4f019e021b024eb6Steven Toth		.frequency = f->frequency
3647615e434aefd95181eae099c4f019e021b024eb6Steven Toth	};
3657615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3667615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Stop the encoder */
3677615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s() frequency=%d tuner=%d\n", __func__,
3687615e434aefd95181eae099c4f019e021b024eb6Steven Toth		f->frequency, f->tuner);
3697615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3707615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (f->tuner != 0)
3717615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
3727615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3737615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (f->type != V4L2_TUNER_ANALOG_TV)
3747615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
3757615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3767615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->freq = f->frequency;
3777615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3787615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Update the hardware */
3797615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (port->nr == SAA7164_PORT_ENC1)
380c7e242baf73a284eff92444fb58af11439e3a22cMauro Carvalho Chehab		tsport = &dev->ports[SAA7164_PORT_TS1];
3817615e434aefd95181eae099c4f019e021b024eb6Steven Toth	else
3827615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (port->nr == SAA7164_PORT_ENC2)
383c7e242baf73a284eff92444fb58af11439e3a22cMauro Carvalho Chehab		tsport = &dev->ports[SAA7164_PORT_TS2];
3847615e434aefd95181eae099c4f019e021b024eb6Steven Toth	else
3857615e434aefd95181eae099c4f019e021b024eb6Steven Toth		BUG();
3867615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3877615e434aefd95181eae099c4f019e021b024eb6Steven Toth	fe = tsport->dvb.frontend;
3887615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3897615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (fe && fe->ops.tuner_ops.set_analog_params)
3907615e434aefd95181eae099c4f019e021b024eb6Steven Toth		fe->ops.tuner_ops.set_analog_params(fe, &params);
3917615e434aefd95181eae099c4f019e021b024eb6Steven Toth	else
3927615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__);
3937615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3947615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_encoder_initialize(port);
3957615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3967615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
3977615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
3987615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3997615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_g_ctrl(struct file *file, void *priv,
4007615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_control *ctl)
4017615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
40296d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
4037615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
4047615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
4057615e434aefd95181eae099c4f019e021b024eb6Steven Toth
4067615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s(id=%d, value=%d)\n", __func__,
4077615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctl->id, ctl->value);
4087615e434aefd95181eae099c4f019e021b024eb6Steven Toth
4097615e434aefd95181eae099c4f019e021b024eb6Steven Toth	switch (ctl->id) {
4107615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_BRIGHTNESS:
4117615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctl->value = port->ctl_brightness;
4127615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4137615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_CONTRAST:
4147615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctl->value = port->ctl_contrast;
4157615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4167615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_SATURATION:
4177615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctl->value = port->ctl_saturation;
4187615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4197615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_HUE:
4207615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctl->value = port->ctl_hue;
4217615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4227615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_SHARPNESS:
4237615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctl->value = port->ctl_sharpness;
4247615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4257615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_AUDIO_VOLUME:
4267615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctl->value = port->ctl_volume;
4277615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4287615e434aefd95181eae099c4f019e021b024eb6Steven Toth	default:
4297615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
4307615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
4317615e434aefd95181eae099c4f019e021b024eb6Steven Toth
4327615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
4337615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
4347615e434aefd95181eae099c4f019e021b024eb6Steven Toth
4357615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_s_ctrl(struct file *file, void *priv,
4367615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_control *ctl)
4377615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
43896d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
4397615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
4407615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
4417615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int ret = 0;
4427615e434aefd95181eae099c4f019e021b024eb6Steven Toth
4437615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s(id=%d, value=%d)\n", __func__,
4447615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctl->id, ctl->value);
4457615e434aefd95181eae099c4f019e021b024eb6Steven Toth
4467615e434aefd95181eae099c4f019e021b024eb6Steven Toth	switch (ctl->id) {
4477615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_BRIGHTNESS:
4487615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctl->value >= 0) && (ctl->value <= 255)) {
4497615e434aefd95181eae099c4f019e021b024eb6Steven Toth			port->ctl_brightness = ctl->value;
4507615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_api_set_usercontrol(port,
4517615e434aefd95181eae099c4f019e021b024eb6Steven Toth				PU_BRIGHTNESS_CONTROL);
4527615e434aefd95181eae099c4f019e021b024eb6Steven Toth		} else
4537615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = -EINVAL;
4547615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4557615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_CONTRAST:
4567615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctl->value >= 0) && (ctl->value <= 255)) {
4577615e434aefd95181eae099c4f019e021b024eb6Steven Toth			port->ctl_contrast = ctl->value;
4587615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL);
4597615e434aefd95181eae099c4f019e021b024eb6Steven Toth		} else
4607615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = -EINVAL;
4617615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4627615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_SATURATION:
4637615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctl->value >= 0) && (ctl->value <= 255)) {
4647615e434aefd95181eae099c4f019e021b024eb6Steven Toth			port->ctl_saturation = ctl->value;
4657615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_api_set_usercontrol(port,
4667615e434aefd95181eae099c4f019e021b024eb6Steven Toth				PU_SATURATION_CONTROL);
4677615e434aefd95181eae099c4f019e021b024eb6Steven Toth		} else
4687615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = -EINVAL;
4697615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4707615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_HUE:
4717615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctl->value >= 0) && (ctl->value <= 255)) {
4727615e434aefd95181eae099c4f019e021b024eb6Steven Toth			port->ctl_hue = ctl->value;
4737615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_api_set_usercontrol(port, PU_HUE_CONTROL);
4747615e434aefd95181eae099c4f019e021b024eb6Steven Toth		} else
4757615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = -EINVAL;
4767615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4777615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_SHARPNESS:
4787615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctl->value >= 0) && (ctl->value <= 255)) {
4797615e434aefd95181eae099c4f019e021b024eb6Steven Toth			port->ctl_sharpness = ctl->value;
4807615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL);
4817615e434aefd95181eae099c4f019e021b024eb6Steven Toth		} else
4827615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = -EINVAL;
4837615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4847615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_AUDIO_VOLUME:
4857615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctl->value >= -83) && (ctl->value <= 24)) {
4867615e434aefd95181eae099c4f019e021b024eb6Steven Toth			port->ctl_volume = ctl->value;
4877615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_api_set_audio_volume(port, port->ctl_volume);
4887615e434aefd95181eae099c4f019e021b024eb6Steven Toth		} else
4897615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = -EINVAL;
4907615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4917615e434aefd95181eae099c4f019e021b024eb6Steven Toth	default:
4927615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = -EINVAL;
4937615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
4947615e434aefd95181eae099c4f019e021b024eb6Steven Toth
4957615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return ret;
4967615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
4977615e434aefd95181eae099c4f019e021b024eb6Steven Toth
4987615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int saa7164_get_ctrl(struct saa7164_port *port,
4997615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_ext_control *ctrl)
5007615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
5017615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_encoder_params *params = &port->encoder_params;
5027615e434aefd95181eae099c4f019e021b024eb6Steven Toth
5037615e434aefd95181eae099c4f019e021b024eb6Steven Toth	switch (ctrl->id) {
5047615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE:
5057615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctrl->value = params->bitrate;
5067615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
5077615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_STREAM_TYPE:
5087615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctrl->value = params->stream_type;
5097615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
5107615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_AUDIO_MUTE:
5117615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctrl->value = params->ctl_mute;
5127615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
5137615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_ASPECT:
5147615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctrl->value = params->ctl_aspect;
5157615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
5162600d71cc535907e5d95cd31751c587afc370065Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
5172600d71cc535907e5d95cd31751c587afc370065Steven Toth		ctrl->value = params->bitrate_mode;
5182600d71cc535907e5d95cd31751c587afc370065Steven Toth		break;
5193ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
5203ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth		ctrl->value = params->refdist;
5213ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth		break;
522968b11b20143036098a7013817a15615a54383d3Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
523968b11b20143036098a7013817a15615a54383d3Steven Toth		ctrl->value = params->bitrate_peak;
524968b11b20143036098a7013817a15615a54383d3Steven Toth		break;
5255fa56ccdacc54f5f694141c1a74f781cf77874bbSteven Toth	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
5265fa56ccdacc54f5f694141c1a74f781cf77874bbSteven Toth		ctrl->value = params->gop_size;
5275fa56ccdacc54f5f694141c1a74f781cf77874bbSteven Toth		break;
5287615e434aefd95181eae099c4f019e021b024eb6Steven Toth	default:
5297615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
5307615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
5317615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
5327615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
5337615e434aefd95181eae099c4f019e021b024eb6Steven Toth
5347615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_g_ext_ctrls(struct file *file, void *priv,
5357615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_ext_controls *ctrls)
5367615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
53796d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
5387615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
5397615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int i, err = 0;
5407615e434aefd95181eae099c4f019e021b024eb6Steven Toth
5417615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
5427615e434aefd95181eae099c4f019e021b024eb6Steven Toth		for (i = 0; i < ctrls->count; i++) {
5437615e434aefd95181eae099c4f019e021b024eb6Steven Toth			struct v4l2_ext_control *ctrl = ctrls->controls + i;
5447615e434aefd95181eae099c4f019e021b024eb6Steven Toth
5457615e434aefd95181eae099c4f019e021b024eb6Steven Toth			err = saa7164_get_ctrl(port, ctrl);
5467615e434aefd95181eae099c4f019e021b024eb6Steven Toth			if (err) {
5477615e434aefd95181eae099c4f019e021b024eb6Steven Toth				ctrls->error_idx = i;
5487615e434aefd95181eae099c4f019e021b024eb6Steven Toth				break;
5497615e434aefd95181eae099c4f019e021b024eb6Steven Toth			}
5507615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
5517615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return err;
5527615e434aefd95181eae099c4f019e021b024eb6Steven Toth
5537615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
5547615e434aefd95181eae099c4f019e021b024eb6Steven Toth
5557615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return -EINVAL;
5567615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
5577615e434aefd95181eae099c4f019e021b024eb6Steven Toth
5587615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int saa7164_try_ctrl(struct v4l2_ext_control *ctrl, int ac3)
5597615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
5607615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int ret = -EINVAL;
5617615e434aefd95181eae099c4f019e021b024eb6Steven Toth
5627615e434aefd95181eae099c4f019e021b024eb6Steven Toth	switch (ctrl->id) {
5637615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE:
5647615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctrl->value >= ENCODER_MIN_BITRATE) &&
5657615e434aefd95181eae099c4f019e021b024eb6Steven Toth			(ctrl->value <= ENCODER_MAX_BITRATE))
5667615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = 0;
5677615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
5687615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_STREAM_TYPE:
569f91d095c92e8fdcb6bd8cb35e8fa9c87d9c10768Steven Toth		if ((ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) ||
570f91d095c92e8fdcb6bd8cb35e8fa9c87d9c10768Steven Toth			(ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS))
5717615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = 0;
5727615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
5737615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_AUDIO_MUTE:
5747615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctrl->value >= 0) &&
5757615e434aefd95181eae099c4f019e021b024eb6Steven Toth			(ctrl->value <= 1))
5767615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = 0;
5777615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
5787615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_ASPECT:
5797615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctrl->value >= V4L2_MPEG_VIDEO_ASPECT_1x1) &&
5807615e434aefd95181eae099c4f019e021b024eb6Steven Toth			(ctrl->value <= V4L2_MPEG_VIDEO_ASPECT_221x100))
5817615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = 0;
5827615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
5837615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
5847615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctrl->value >= 0) &&
5857615e434aefd95181eae099c4f019e021b024eb6Steven Toth			(ctrl->value <= 255))
5867615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = 0;
5877615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
5882600d71cc535907e5d95cd31751c587afc370065Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
5892600d71cc535907e5d95cd31751c587afc370065Steven Toth		if ((ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) ||
5902600d71cc535907e5d95cd31751c587afc370065Steven Toth			(ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR))
5912600d71cc535907e5d95cd31751c587afc370065Steven Toth			ret = 0;
5922600d71cc535907e5d95cd31751c587afc370065Steven Toth		break;
5933ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
5943ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth		if ((ctrl->value >= 1) &&
5953ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth			(ctrl->value <= 3))
5963ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth			ret = 0;
5973ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth		break;
598968b11b20143036098a7013817a15615a54383d3Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
599968b11b20143036098a7013817a15615a54383d3Steven Toth		if ((ctrl->value >= ENCODER_MIN_BITRATE) &&
600968b11b20143036098a7013817a15615a54383d3Steven Toth			(ctrl->value <= ENCODER_MAX_BITRATE))
601968b11b20143036098a7013817a15615a54383d3Steven Toth			ret = 0;
602968b11b20143036098a7013817a15615a54383d3Steven Toth		break;
6037615e434aefd95181eae099c4f019e021b024eb6Steven Toth	default:
6047615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = -EINVAL;
6057615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
6067615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6077615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return ret;
6087615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
6097615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6107615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_try_ext_ctrls(struct file *file, void *priv,
6117615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_ext_controls *ctrls)
6127615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
6137615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int i, err = 0;
6147615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6157615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
6167615e434aefd95181eae099c4f019e021b024eb6Steven Toth		for (i = 0; i < ctrls->count; i++) {
6177615e434aefd95181eae099c4f019e021b024eb6Steven Toth			struct v4l2_ext_control *ctrl = ctrls->controls + i;
6187615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6197615e434aefd95181eae099c4f019e021b024eb6Steven Toth			err = saa7164_try_ctrl(ctrl, 0);
6207615e434aefd95181eae099c4f019e021b024eb6Steven Toth			if (err) {
6217615e434aefd95181eae099c4f019e021b024eb6Steven Toth				ctrls->error_idx = i;
6227615e434aefd95181eae099c4f019e021b024eb6Steven Toth				break;
6237615e434aefd95181eae099c4f019e021b024eb6Steven Toth			}
6247615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
6257615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return err;
6267615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
6277615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6287615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return -EINVAL;
6297615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
6307615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6317615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int saa7164_set_ctrl(struct saa7164_port *port,
6327615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_ext_control *ctrl)
6337615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
6347615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_encoder_params *params = &port->encoder_params;
6357615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int ret = 0;
6367615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6377615e434aefd95181eae099c4f019e021b024eb6Steven Toth	switch (ctrl->id) {
6387615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE:
6397615e434aefd95181eae099c4f019e021b024eb6Steven Toth		params->bitrate = ctrl->value;
6407615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
6417615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_STREAM_TYPE:
6427615e434aefd95181eae099c4f019e021b024eb6Steven Toth		params->stream_type = ctrl->value;
6437615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
6447615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_AUDIO_MUTE:
6457615e434aefd95181eae099c4f019e021b024eb6Steven Toth		params->ctl_mute = ctrl->value;
6467615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = saa7164_api_audio_mute(port, params->ctl_mute);
6477615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (ret != SAA_OK) {
6487615e434aefd95181eae099c4f019e021b024eb6Steven Toth			printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
6497615e434aefd95181eae099c4f019e021b024eb6Steven Toth				ret);
6507615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = -EIO;
6517615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
6527615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
6537615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_ASPECT:
6547615e434aefd95181eae099c4f019e021b024eb6Steven Toth		params->ctl_aspect = ctrl->value;
6557615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = saa7164_api_set_aspect_ratio(port);
6567615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (ret != SAA_OK) {
6577615e434aefd95181eae099c4f019e021b024eb6Steven Toth			printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
6587615e434aefd95181eae099c4f019e021b024eb6Steven Toth				ret);
6597615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = -EIO;
6607615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
6617615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
6622600d71cc535907e5d95cd31751c587afc370065Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
6632600d71cc535907e5d95cd31751c587afc370065Steven Toth		params->bitrate_mode = ctrl->value;
6642600d71cc535907e5d95cd31751c587afc370065Steven Toth		break;
6653ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
6663ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth		params->refdist = ctrl->value;
6673ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth		break;
668968b11b20143036098a7013817a15615a54383d3Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
669968b11b20143036098a7013817a15615a54383d3Steven Toth		params->bitrate_peak = ctrl->value;
670968b11b20143036098a7013817a15615a54383d3Steven Toth		break;
6715fa56ccdacc54f5f694141c1a74f781cf77874bbSteven Toth	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
6725fa56ccdacc54f5f694141c1a74f781cf77874bbSteven Toth		params->gop_size = ctrl->value;
6735fa56ccdacc54f5f694141c1a74f781cf77874bbSteven Toth		break;
6747615e434aefd95181eae099c4f019e021b024eb6Steven Toth	default:
6757615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
6767615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
6777615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6787615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* TODO: Update the hardware */
6797615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6807615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return ret;
6817615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
6827615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6837615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_s_ext_ctrls(struct file *file, void *priv,
6847615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_ext_controls *ctrls)
6857615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
68696d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
6877615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
6887615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int i, err = 0;
6897615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6907615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
6917615e434aefd95181eae099c4f019e021b024eb6Steven Toth		for (i = 0; i < ctrls->count; i++) {
6927615e434aefd95181eae099c4f019e021b024eb6Steven Toth			struct v4l2_ext_control *ctrl = ctrls->controls + i;
6937615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6947615e434aefd95181eae099c4f019e021b024eb6Steven Toth			err = saa7164_try_ctrl(ctrl, 0);
6957615e434aefd95181eae099c4f019e021b024eb6Steven Toth			if (err) {
6967615e434aefd95181eae099c4f019e021b024eb6Steven Toth				ctrls->error_idx = i;
6977615e434aefd95181eae099c4f019e021b024eb6Steven Toth				break;
6987615e434aefd95181eae099c4f019e021b024eb6Steven Toth			}
6997615e434aefd95181eae099c4f019e021b024eb6Steven Toth			err = saa7164_set_ctrl(port, ctrl);
7007615e434aefd95181eae099c4f019e021b024eb6Steven Toth			if (err) {
7017615e434aefd95181eae099c4f019e021b024eb6Steven Toth				ctrls->error_idx = i;
7027615e434aefd95181eae099c4f019e021b024eb6Steven Toth				break;
7037615e434aefd95181eae099c4f019e021b024eb6Steven Toth			}
7047615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
7057615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return err;
7067615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7077615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
7087615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7097615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return -EINVAL;
7107615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
7117615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7127615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_querycap(struct file *file, void  *priv,
7137615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_capability *cap)
7147615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
71596d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
7167615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
7177615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
7187615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7197615e434aefd95181eae099c4f019e021b024eb6Steven Toth	strcpy(cap->driver, dev->name);
7207615e434aefd95181eae099c4f019e021b024eb6Steven Toth	strlcpy(cap->card, saa7164_boards[dev->board].name,
7217615e434aefd95181eae099c4f019e021b024eb6Steven Toth		sizeof(cap->card));
7227615e434aefd95181eae099c4f019e021b024eb6Steven Toth	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
7237615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7247615e434aefd95181eae099c4f019e021b024eb6Steven Toth	cap->capabilities =
7257615e434aefd95181eae099c4f019e021b024eb6Steven Toth		V4L2_CAP_VIDEO_CAPTURE |
7267615e434aefd95181eae099c4f019e021b024eb6Steven Toth		V4L2_CAP_READWRITE     |
7277615e434aefd95181eae099c4f019e021b024eb6Steven Toth		0;
7287615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7297615e434aefd95181eae099c4f019e021b024eb6Steven Toth	cap->capabilities |= V4L2_CAP_TUNER;
7307615e434aefd95181eae099c4f019e021b024eb6Steven Toth	cap->version = 0;
7317615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7327615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
7337615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
7347615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7357615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
7367615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_fmtdesc *f)
7377615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
7387615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (f->index != 0)
7397615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
7407615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7417615e434aefd95181eae099c4f019e021b024eb6Steven Toth	strlcpy(f->description, "MPEG", sizeof(f->description));
7427615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->pixelformat = V4L2_PIX_FMT_MPEG;
7437615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7447615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
7457615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
7467615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7477615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
7487615e434aefd95181eae099c4f019e021b024eb6Steven Toth				struct v4l2_format *f)
7497615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
75096d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
7517615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
7527615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
7537615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7547615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
7557615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.bytesperline = 0;
7567615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.sizeimage    =
7577615e434aefd95181eae099c4f019e021b024eb6Steven Toth		port->ts_packet_size * port->ts_packet_count;
7587615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.colorspace   = 0;
7597615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.width        = port->width;
7607615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.height       = port->height;
7617615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7627615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "VIDIOC_G_FMT: w: %d, h: %d\n",
7637615e434aefd95181eae099c4f019e021b024eb6Steven Toth		port->width, port->height);
7647615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7657615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
7667615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
7677615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7687615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
7697615e434aefd95181eae099c4f019e021b024eb6Steven Toth				struct v4l2_format *f)
7707615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
77196d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
7727615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
7737615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
7747615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7757615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
7767615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.bytesperline = 0;
7777615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.sizeimage    =
7787615e434aefd95181eae099c4f019e021b024eb6Steven Toth		port->ts_packet_size * port->ts_packet_count;
7797615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.colorspace   = 0;
7807615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
7817615e434aefd95181eae099c4f019e021b024eb6Steven Toth		port->width, port->height);
7827615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
7837615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
7847615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7857615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
7867615e434aefd95181eae099c4f019e021b024eb6Steven Toth				struct v4l2_format *f)
7877615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
78896d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
7897615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
7907615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
7917615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7927615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
7937615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.bytesperline = 0;
7947615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.sizeimage    =
7957615e434aefd95181eae099c4f019e021b024eb6Steven Toth		port->ts_packet_size * port->ts_packet_count;
7967615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.colorspace   = 0;
7977615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7987615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
7997615e434aefd95181eae099c4f019e021b024eb6Steven Toth		f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
8007615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8017615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
8027615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
8037615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8047615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int fill_queryctrl(struct saa7164_encoder_params *params,
8057615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_queryctrl *c)
8067615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
8077615e434aefd95181eae099c4f019e021b024eb6Steven Toth	switch (c->id) {
8087615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_BRIGHTNESS:
8097615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 127);
8107615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_CONTRAST:
8117615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 66);
8127615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_SATURATION:
8137615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 62);
8147615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_HUE:
8157615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 128);
8167615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_SHARPNESS:
8177615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c, 0x0, 0x0f, 1, 8);
8187615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_AUDIO_MUTE:
8197615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c, 0x0, 0x01, 1, 0);
8207615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_AUDIO_VOLUME:
8217615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c, -83, 24, 1, 20);
8227615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE:
8237615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c,
8247615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ENCODER_MIN_BITRATE, ENCODER_MAX_BITRATE,
8257615e434aefd95181eae099c4f019e021b024eb6Steven Toth			100000, ENCODER_DEF_BITRATE);
8267615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_STREAM_TYPE:
8277615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c,
8287615e434aefd95181eae099c4f019e021b024eb6Steven Toth			V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
829f91d095c92e8fdcb6bd8cb35e8fa9c87d9c10768Steven Toth			V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
830f91d095c92e8fdcb6bd8cb35e8fa9c87d9c10768Steven Toth			1, V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
8317615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_ASPECT:
8327615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c,
8337615e434aefd95181eae099c4f019e021b024eb6Steven Toth			V4L2_MPEG_VIDEO_ASPECT_1x1,
8347615e434aefd95181eae099c4f019e021b024eb6Steven Toth			V4L2_MPEG_VIDEO_ASPECT_221x100,
8357615e434aefd95181eae099c4f019e021b024eb6Steven Toth			1, V4L2_MPEG_VIDEO_ASPECT_4x3);
8367615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
8377615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c, 1, 255, 1, 15);
8382600d71cc535907e5d95cd31751c587afc370065Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
8392600d71cc535907e5d95cd31751c587afc370065Steven Toth		return v4l2_ctrl_query_fill(c,
840bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth			V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
841bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth			V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
8422600d71cc535907e5d95cd31751c587afc370065Steven Toth			1, V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
8433ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
8443ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth		return v4l2_ctrl_query_fill(c,
8453ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth			1, 3, 1, 1);
846968b11b20143036098a7013817a15615a54383d3Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
847968b11b20143036098a7013817a15615a54383d3Steven Toth		return v4l2_ctrl_query_fill(c,
848968b11b20143036098a7013817a15615a54383d3Steven Toth			ENCODER_MIN_BITRATE, ENCODER_MAX_BITRATE,
849968b11b20143036098a7013817a15615a54383d3Steven Toth			100000, ENCODER_DEF_BITRATE);
8507615e434aefd95181eae099c4f019e021b024eb6Steven Toth	default:
8517615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
8527615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
8537615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
8547615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8557615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_queryctrl(struct file *file, void *priv,
8567615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_queryctrl *c)
8577615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
85896d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = priv;
8597615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
8607615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int i, next;
8617615e434aefd95181eae099c4f019e021b024eb6Steven Toth	u32 id = c->id;
8627615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8637615e434aefd95181eae099c4f019e021b024eb6Steven Toth	memset(c, 0, sizeof(*c));
8647615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8657615e434aefd95181eae099c4f019e021b024eb6Steven Toth	next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL);
8667615e434aefd95181eae099c4f019e021b024eb6Steven Toth	c->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
8677615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8687615e434aefd95181eae099c4f019e021b024eb6Steven Toth	for (i = 0; i < ARRAY_SIZE(saa7164_v4l2_ctrls); i++) {
8697615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (next) {
8707615e434aefd95181eae099c4f019e021b024eb6Steven Toth			if (c->id < saa7164_v4l2_ctrls[i])
8717615e434aefd95181eae099c4f019e021b024eb6Steven Toth				c->id = saa7164_v4l2_ctrls[i];
8727615e434aefd95181eae099c4f019e021b024eb6Steven Toth			else
8737615e434aefd95181eae099c4f019e021b024eb6Steven Toth				continue;
8747615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
8757615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8767615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (c->id == saa7164_v4l2_ctrls[i])
8777615e434aefd95181eae099c4f019e021b024eb6Steven Toth			return fill_queryctrl(&port->encoder_params, c);
8787615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8797615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (c->id < saa7164_v4l2_ctrls[i])
8807615e434aefd95181eae099c4f019e021b024eb6Steven Toth			break;
8817615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
8827615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8837615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return -EINVAL;
8847615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
8857615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8867615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int saa7164_encoder_stop_port(struct saa7164_port *port)
8877615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
8887615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
8897615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int ret;
8907615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8917615e434aefd95181eae099c4f019e021b024eb6Steven Toth	ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
8927615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
8937615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n",
8947615e434aefd95181eae099c4f019e021b024eb6Steven Toth			__func__, ret);
8957615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = -EIO;
8967615e434aefd95181eae099c4f019e021b024eb6Steven Toth	} else {
8977615e434aefd95181eae099c4f019e021b024eb6Steven Toth		dprintk(DBGLVL_ENC, "%s()    Stopped\n", __func__);
8987615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = 0;
8997615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
9007615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9017615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return ret;
9027615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
9037615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9047615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int saa7164_encoder_acquire_port(struct saa7164_port *port)
9057615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
9067615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
9077615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int ret;
9087615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9097615e434aefd95181eae099c4f019e021b024eb6Steven Toth	ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
9107615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
9117615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n",
9127615e434aefd95181eae099c4f019e021b024eb6Steven Toth			__func__, ret);
9137615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = -EIO;
9147615e434aefd95181eae099c4f019e021b024eb6Steven Toth	} else {
9157615e434aefd95181eae099c4f019e021b024eb6Steven Toth		dprintk(DBGLVL_ENC, "%s() Acquired\n", __func__);
9167615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = 0;
9177615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
9187615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9197615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return ret;
9207615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
9217615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9227615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int saa7164_encoder_pause_port(struct saa7164_port *port)
9237615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
9247615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
9257615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int ret;
9267615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9277615e434aefd95181eae099c4f019e021b024eb6Steven Toth	ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
9287615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
9297615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n",
9307615e434aefd95181eae099c4f019e021b024eb6Steven Toth			__func__, ret);
9317615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = -EIO;
9327615e434aefd95181eae099c4f019e021b024eb6Steven Toth	} else {
9337615e434aefd95181eae099c4f019e021b024eb6Steven Toth		dprintk(DBGLVL_ENC, "%s()   Paused\n", __func__);
9347615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = 0;
9357615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
9367615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9377615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return ret;
9387615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
9397615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9407615e434aefd95181eae099c4f019e021b024eb6Steven Toth/* Firmware is very windows centric, meaning you have to transition
9417615e434aefd95181eae099c4f019e021b024eb6Steven Toth * the part through AVStream / KS Windows stages, forwards or backwards.
9427615e434aefd95181eae099c4f019e021b024eb6Steven Toth * States are: stopped, acquired (h/w), paused, started.
9437615e434aefd95181eae099c4f019e021b024eb6Steven Toth * We have to leave here will all of the soft buffers on the free list,
9447615e434aefd95181eae099c4f019e021b024eb6Steven Toth * else the cfg_post() func won't have soft buffers to correctly configure.
9457615e434aefd95181eae099c4f019e021b024eb6Steven Toth */
9467615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int saa7164_encoder_stop_streaming(struct saa7164_port *port)
9477615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
9487615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
9497615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_buffer *buf;
9507615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_user_buffer *ubuf;
9517615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct list_head *c, *n;
9527615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int ret;
9537615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9547615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
9557615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9567615e434aefd95181eae099c4f019e021b024eb6Steven Toth	ret = saa7164_encoder_pause_port(port);
9577615e434aefd95181eae099c4f019e021b024eb6Steven Toth	ret = saa7164_encoder_acquire_port(port);
9587615e434aefd95181eae099c4f019e021b024eb6Steven Toth	ret = saa7164_encoder_stop_port(port);
9597615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9607615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s(port=%d) Hardware stopped\n", __func__,
9617615e434aefd95181eae099c4f019e021b024eb6Steven Toth		port->nr);
9627615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9631b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	/* Reset the state of any allocated buffer resources */
9647615e434aefd95181eae099c4f019e021b024eb6Steven Toth	mutex_lock(&port->dmaqueue_lock);
9657615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9667615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Reset the hard and soft buffer state */
9677615e434aefd95181eae099c4f019e021b024eb6Steven Toth	list_for_each_safe(c, n, &port->dmaqueue.list) {
9687615e434aefd95181eae099c4f019e021b024eb6Steven Toth		buf = list_entry(c, struct saa7164_buffer, list);
9697615e434aefd95181eae099c4f019e021b024eb6Steven Toth		buf->flags = SAA7164_BUFFER_FREE;
9707615e434aefd95181eae099c4f019e021b024eb6Steven Toth		buf->pos = 0;
9717615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
9727615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9737615e434aefd95181eae099c4f019e021b024eb6Steven Toth	list_for_each_safe(c, n, &port->list_buf_used.list) {
9747615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ubuf = list_entry(c, struct saa7164_user_buffer, list);
9757615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ubuf->pos = 0;
9767615e434aefd95181eae099c4f019e021b024eb6Steven Toth		list_move_tail(&ubuf->list, &port->list_buf_free.list);
9777615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
9787615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9797615e434aefd95181eae099c4f019e021b024eb6Steven Toth	mutex_unlock(&port->dmaqueue_lock);
9801b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
9811b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	/* Free any allocated resources */
9821b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	saa7164_encoder_buffers_dealloc(port);
9831b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
9847615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s(port=%d) Released\n", __func__, port->nr);
9857615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9867615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return ret;
9877615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
9887615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9897615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int saa7164_encoder_start_streaming(struct saa7164_port *port)
9907615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
9917615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
9927615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int result, ret = 0;
9937615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9947615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
9957615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9961b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	port->done_first_interrupt = 0;
9971b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
9981b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	/* allocate all of the PCIe DMA buffer resources on the fly,
9991b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	 * allowing switching between TS and PS payloads without
10001b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	 * requiring a complete driver reload.
10011b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	 */
10021b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	saa7164_encoder_buffers_alloc(port);
10031b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
10047615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Configure the encoder with any cache values */
10057615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_encoder(port);
100612d3203e39db306f56611b3f47ba425ca6a409f9Steven Toth	saa7164_api_get_encoder(port);
10077615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10081b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	/* Place the empty buffers on the hardware */
10097615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_buffer_cfg_port(port);
10107615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10117615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Acquire the hardware */
10127615e434aefd95181eae099c4f019e021b024eb6Steven Toth	result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
10137615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
10147615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n",
10157615e434aefd95181eae099c4f019e021b024eb6Steven Toth			__func__, result);
10167615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10177615e434aefd95181eae099c4f019e021b024eb6Steven Toth		/* Stop the hardware, regardless */
10187615e434aefd95181eae099c4f019e021b024eb6Steven Toth		result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
10197615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
10207615e434aefd95181eae099c4f019e021b024eb6Steven Toth			printk(KERN_ERR "%s() acquire/forced stop transition "
10217615e434aefd95181eae099c4f019e021b024eb6Steven Toth				"failed, res = 0x%x\n", __func__, result);
10227615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
10237615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = -EIO;
10247615e434aefd95181eae099c4f019e021b024eb6Steven Toth		goto out;
10257615e434aefd95181eae099c4f019e021b024eb6Steven Toth	} else
10267615e434aefd95181eae099c4f019e021b024eb6Steven Toth		dprintk(DBGLVL_ENC, "%s()   Acquired\n", __func__);
10277615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10287615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Pause the hardware */
10297615e434aefd95181eae099c4f019e021b024eb6Steven Toth	result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
10307615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
10317615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n",
10327615e434aefd95181eae099c4f019e021b024eb6Steven Toth				__func__, result);
10337615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10347615e434aefd95181eae099c4f019e021b024eb6Steven Toth		/* Stop the hardware, regardless */
10357615e434aefd95181eae099c4f019e021b024eb6Steven Toth		result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
10367615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
10377615e434aefd95181eae099c4f019e021b024eb6Steven Toth			printk(KERN_ERR "%s() pause/forced stop transition "
10387615e434aefd95181eae099c4f019e021b024eb6Steven Toth				"failed, res = 0x%x\n", __func__, result);
10397615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
10407615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10417615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = -EIO;
10427615e434aefd95181eae099c4f019e021b024eb6Steven Toth		goto out;
10437615e434aefd95181eae099c4f019e021b024eb6Steven Toth	} else
10447615e434aefd95181eae099c4f019e021b024eb6Steven Toth		dprintk(DBGLVL_ENC, "%s()   Paused\n", __func__);
10457615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10467615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Start the hardware */
10477615e434aefd95181eae099c4f019e021b024eb6Steven Toth	result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN);
10487615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
10497615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_ERR "%s() run transition failed, result = 0x%x\n",
10507615e434aefd95181eae099c4f019e021b024eb6Steven Toth				__func__, result);
10517615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10527615e434aefd95181eae099c4f019e021b024eb6Steven Toth		/* Stop the hardware, regardless */
10537615e434aefd95181eae099c4f019e021b024eb6Steven Toth		result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
10547615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
10557615e434aefd95181eae099c4f019e021b024eb6Steven Toth			printk(KERN_ERR "%s() run/forced stop transition "
10567615e434aefd95181eae099c4f019e021b024eb6Steven Toth				"failed, res = 0x%x\n", __func__, result);
10577615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
10587615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10597615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = -EIO;
10607615e434aefd95181eae099c4f019e021b024eb6Steven Toth	} else
10617615e434aefd95181eae099c4f019e021b024eb6Steven Toth		dprintk(DBGLVL_ENC, "%s()   Running\n", __func__);
10627615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10637615e434aefd95181eae099c4f019e021b024eb6Steven Tothout:
10647615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return ret;
10657615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
10667615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10677615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int fops_open(struct file *file)
10687615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
1069214ce3faacafa3cca2fdd340d18ff35cfe463c2bSteven Toth	struct saa7164_dev *dev;
1070214ce3faacafa3cca2fdd340d18ff35cfe463c2bSteven Toth	struct saa7164_port *port;
107196d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh;
10727615e434aefd95181eae099c4f019e021b024eb6Steven Toth
1073214ce3faacafa3cca2fdd340d18ff35cfe463c2bSteven Toth	port = (struct saa7164_port *)video_get_drvdata(video_devdata(file));
1074214ce3faacafa3cca2fdd340d18ff35cfe463c2bSteven Toth	if (!port)
1075214ce3faacafa3cca2fdd340d18ff35cfe463c2bSteven Toth		return -ENODEV;
10767615e434aefd95181eae099c4f019e021b024eb6Steven Toth
1077214ce3faacafa3cca2fdd340d18ff35cfe463c2bSteven Toth	dev = port->dev;
10787615e434aefd95181eae099c4f019e021b024eb6Steven Toth
1079214ce3faacafa3cca2fdd340d18ff35cfe463c2bSteven Toth	dprintk(DBGLVL_ENC, "%s()\n", __func__);
10807615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10817615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* allocate + initialize per filehandle data */
10827615e434aefd95181eae099c4f019e021b024eb6Steven Toth	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
1083214ce3faacafa3cca2fdd340d18ff35cfe463c2bSteven Toth	if (NULL == fh)
10847615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -ENOMEM;
10857615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10867615e434aefd95181eae099c4f019e021b024eb6Steven Toth	file->private_data = fh;
10877615e434aefd95181eae099c4f019e021b024eb6Steven Toth	fh->port = port;
10887615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10897615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
10907615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
10917615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10927615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int fops_release(struct file *file)
10937615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
109496d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
10957615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
10967615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
10977615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10987615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s()\n", __func__);
10997615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11007615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Shut device down on last close */
11017615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
11027615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (atomic_dec_return(&port->v4l_reader_count) == 0) {
11037615e434aefd95181eae099c4f019e021b024eb6Steven Toth			/* stop mpeg capture then cancel buffers */
11047615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_encoder_stop_streaming(port);
11057615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
11067615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
11077615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11087615e434aefd95181eae099c4f019e021b024eb6Steven Toth	file->private_data = NULL;
11097615e434aefd95181eae099c4f019e021b024eb6Steven Toth	kfree(fh);
11107615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11117615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
11127615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
11137615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11145faf7db804e1e67ab8f78edb305d1858779a6279Mauro Carvalho Chehabstatic struct
11155faf7db804e1e67ab8f78edb305d1858779a6279Mauro Carvalho Chehabsaa7164_user_buffer *saa7164_enc_next_buf(struct saa7164_port *port)
11167615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
111761ca1500c5ee04f2be34a4f58bb9baed0214b7a9Peter Huewe	struct saa7164_user_buffer *ubuf = NULL;
11187615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
111912d3203e39db306f56611b3f47ba425ca6a409f9Steven Toth	u32 crc;
11207615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11217615e434aefd95181eae099c4f019e021b024eb6Steven Toth	mutex_lock(&port->dmaqueue_lock);
11227615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (!list_empty(&port->list_buf_used.list)) {
11231b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		ubuf = list_first_entry(&port->list_buf_used.list,
11247615e434aefd95181eae099c4f019e021b024eb6Steven Toth			struct saa7164_user_buffer, list);
112512d3203e39db306f56611b3f47ba425ca6a409f9Steven Toth
11261b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		if (crc_checking) {
11271b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			crc = crc32(0, ubuf->data, ubuf->actual_size);
11281b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			if (crc != ubuf->crc) {
1129bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth				printk(KERN_ERR
1130bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth		"%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n",
1131bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth					__func__,
11321b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth					ubuf, ubuf->crc, crc);
11331b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			}
113412d3203e39db306f56611b3f47ba425ca6a409f9Steven Toth		}
113512d3203e39db306f56611b3f47ba425ca6a409f9Steven Toth
11367615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
11377615e434aefd95181eae099c4f019e021b024eb6Steven Toth	mutex_unlock(&port->dmaqueue_lock);
11387615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11391b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	dprintk(DBGLVL_ENC, "%s() returns %p\n", __func__, ubuf);
11407615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11411b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	return ubuf;
11427615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
11437615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11447615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic ssize_t fops_read(struct file *file, char __user *buffer,
11457615e434aefd95181eae099c4f019e021b024eb6Steven Toth	size_t count, loff_t *pos)
11467615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
114796d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
11487615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
11497615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_user_buffer *ubuf = NULL;
11507615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
1151f20a07d431c3c516c37beff9638f70c8e059a3fcGavin Hurlbut	int ret = 0;
11527615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int rem, cnt;
11537615e434aefd95181eae099c4f019e021b024eb6Steven Toth	u8 *p;
11547615e434aefd95181eae099c4f019e021b024eb6Steven Toth
115558acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth	port->last_read_msecs_diff = port->last_read_msecs;
115658acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth	port->last_read_msecs = jiffies_to_msecs(jiffies);
115758acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth	port->last_read_msecs_diff = port->last_read_msecs -
115858acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth		port->last_read_msecs_diff;
115958acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth
116058acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth	saa7164_histogram_update(&port->read_interval,
116158acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth		port->last_read_msecs_diff);
116258acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth
116346eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth	if (*pos) {
116446eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth		printk(KERN_ERR "%s() ESPIPE\n", __func__);
11657615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -ESPIPE;
116646eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth	}
11677615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11687615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
11697615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (atomic_inc_return(&port->v4l_reader_count) == 1) {
11707615e434aefd95181eae099c4f019e021b024eb6Steven Toth
117146eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth			if (saa7164_encoder_initialize(port) < 0) {
117246eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth				printk(KERN_ERR "%s() EINVAL\n", __func__);
11737615e434aefd95181eae099c4f019e021b024eb6Steven Toth				return -EINVAL;
117446eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth			}
11757615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11767615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_encoder_start_streaming(port);
11777615e434aefd95181eae099c4f019e021b024eb6Steven Toth			msleep(200);
11787615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
11797615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
11807615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11817615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* blocking wait for buffer */
11827615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if ((file->f_flags & O_NONBLOCK) == 0) {
11837615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (wait_event_interruptible(port->wait_read,
11847615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_enc_next_buf(port))) {
118546eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth				printk(KERN_ERR "%s() ERESTARTSYS\n", __func__);
11867615e434aefd95181eae099c4f019e021b024eb6Steven Toth				return -ERESTARTSYS;
11877615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
11887615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
11897615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11907615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Pull the first buffer from the used list */
11917615e434aefd95181eae099c4f019e021b024eb6Steven Toth	ubuf = saa7164_enc_next_buf(port);
11927615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11937615e434aefd95181eae099c4f019e021b024eb6Steven Toth	while ((count > 0) && ubuf) {
11947615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11957615e434aefd95181eae099c4f019e021b024eb6Steven Toth		/* set remaining bytes to copy */
11967615e434aefd95181eae099c4f019e021b024eb6Steven Toth		rem = ubuf->actual_size - ubuf->pos;
11977615e434aefd95181eae099c4f019e021b024eb6Steven Toth		cnt = rem > count ? count : rem;
11987615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11997615e434aefd95181eae099c4f019e021b024eb6Steven Toth		p = ubuf->data + ubuf->pos;
12007615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12017615e434aefd95181eae099c4f019e021b024eb6Steven Toth		dprintk(DBGLVL_ENC,
12027615e434aefd95181eae099c4f019e021b024eb6Steven Toth			"%s() count=%d cnt=%d rem=%d buf=%p buf->pos=%d\n",
12037615e434aefd95181eae099c4f019e021b024eb6Steven Toth			__func__, (int)count, cnt, rem, ubuf, ubuf->pos);
12047615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12057615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (copy_to_user(buffer, p, cnt)) {
12067615e434aefd95181eae099c4f019e021b024eb6Steven Toth			printk(KERN_ERR "%s() copy_to_user failed\n", __func__);
120746eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth			if (!ret) {
120846eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth				printk(KERN_ERR "%s() EFAULT\n", __func__);
12097615e434aefd95181eae099c4f019e021b024eb6Steven Toth				ret = -EFAULT;
121046eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth			}
12117615e434aefd95181eae099c4f019e021b024eb6Steven Toth			goto err;
12127615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
12137615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12147615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ubuf->pos += cnt;
12157615e434aefd95181eae099c4f019e021b024eb6Steven Toth		count -= cnt;
12167615e434aefd95181eae099c4f019e021b024eb6Steven Toth		buffer += cnt;
12177615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret += cnt;
12187615e434aefd95181eae099c4f019e021b024eb6Steven Toth
1219bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth		if (ubuf->pos > ubuf->actual_size)
122046eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth			printk(KERN_ERR "read() pos > actual, huh?\n");
122146eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth
12227615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (ubuf->pos == ubuf->actual_size) {
12237615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12247615e434aefd95181eae099c4f019e021b024eb6Steven Toth			/* finished with current buffer, take next buffer */
12257615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12267615e434aefd95181eae099c4f019e021b024eb6Steven Toth			/* Requeue the buffer on the free list */
12277615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ubuf->pos = 0;
12287615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12297615e434aefd95181eae099c4f019e021b024eb6Steven Toth			mutex_lock(&port->dmaqueue_lock);
12307615e434aefd95181eae099c4f019e021b024eb6Steven Toth			list_move_tail(&ubuf->list, &port->list_buf_free.list);
12317615e434aefd95181eae099c4f019e021b024eb6Steven Toth			mutex_unlock(&port->dmaqueue_lock);
12327615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12337615e434aefd95181eae099c4f019e021b024eb6Steven Toth			/* Dequeue next */
12347615e434aefd95181eae099c4f019e021b024eb6Steven Toth			if ((file->f_flags & O_NONBLOCK) == 0) {
12357615e434aefd95181eae099c4f019e021b024eb6Steven Toth				if (wait_event_interruptible(port->wait_read,
12367615e434aefd95181eae099c4f019e021b024eb6Steven Toth					saa7164_enc_next_buf(port))) {
12377615e434aefd95181eae099c4f019e021b024eb6Steven Toth						break;
12387615e434aefd95181eae099c4f019e021b024eb6Steven Toth				}
12397615e434aefd95181eae099c4f019e021b024eb6Steven Toth			}
12407615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ubuf = saa7164_enc_next_buf(port);
12417615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
12427615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
12437615e434aefd95181eae099c4f019e021b024eb6Steven Totherr:
1244bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth	if (!ret && !ubuf)
12457615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = -EAGAIN;
12467615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12477615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return ret;
12487615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
12497615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12507615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic unsigned int fops_poll(struct file *file, poll_table *wait)
12517615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
1252bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth	struct saa7164_encoder_fh *fh =
1253bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth		(struct saa7164_encoder_fh *)file->private_data;
12547615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
12557615e434aefd95181eae099c4f019e021b024eb6Steven Toth	unsigned int mask = 0;
12567615e434aefd95181eae099c4f019e021b024eb6Steven Toth
125758acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth	port->last_poll_msecs_diff = port->last_poll_msecs;
125858acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth	port->last_poll_msecs = jiffies_to_msecs(jiffies);
125958acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth	port->last_poll_msecs_diff = port->last_poll_msecs -
126058acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth		port->last_poll_msecs_diff;
126158acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth
126258acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth	saa7164_histogram_update(&port->poll_interval,
126358acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth		port->last_poll_msecs_diff);
126458acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth
1265bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth	if (!video_is_registered(port->v4l_device))
12667615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EIO;
12677615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12687615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
12697615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (atomic_inc_return(&port->v4l_reader_count) == 1) {
12707615e434aefd95181eae099c4f019e021b024eb6Steven Toth			if (saa7164_encoder_initialize(port) < 0)
12717615e434aefd95181eae099c4f019e021b024eb6Steven Toth				return -EINVAL;
12727615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_encoder_start_streaming(port);
12737615e434aefd95181eae099c4f019e021b024eb6Steven Toth			msleep(200);
12747615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
12757615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
12767615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12777615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* blocking wait for buffer */
12787615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if ((file->f_flags & O_NONBLOCK) == 0) {
12797615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (wait_event_interruptible(port->wait_read,
12807615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_enc_next_buf(port))) {
12817615e434aefd95181eae099c4f019e021b024eb6Steven Toth				return -ERESTARTSYS;
12827615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
12837615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
12847615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12857615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Pull the first buffer from the used list */
1286061d55eb450102408289599ae79b92322d6126e1Dan Carpenter	if (!list_empty(&port->list_buf_used.list))
12877615e434aefd95181eae099c4f019e021b024eb6Steven Toth		mask |= POLLIN | POLLRDNORM;
12887615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12897615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return mask;
12907615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
12917615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12927615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic const struct v4l2_file_operations mpeg_fops = {
12937615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.owner		= THIS_MODULE,
12947615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.open		= fops_open,
12957615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.release	= fops_release,
12967615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.read		= fops_read,
12977615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.poll		= fops_poll,
12987615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.unlocked_ioctl	= video_ioctl2,
12997615e434aefd95181eae099c4f019e021b024eb6Steven Toth};
13007615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13017615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
13027615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_s_std		 = vidioc_s_std,
13038d2d41e92d99e25f7d42fc83fc39096d89caa35eHans Verkuil	.vidioc_g_std		 = vidioc_g_std,
13047615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_enum_input	 = vidioc_enum_input,
13057615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_g_input		 = vidioc_g_input,
13067615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_s_input		 = vidioc_s_input,
13077615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_g_tuner		 = vidioc_g_tuner,
13087615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_s_tuner		 = vidioc_s_tuner,
13097615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_g_frequency	 = vidioc_g_frequency,
13107615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_s_frequency	 = vidioc_s_frequency,
13117615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_s_ctrl		 = vidioc_s_ctrl,
13127615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_g_ctrl		 = vidioc_g_ctrl,
13137615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_querycap	 = vidioc_querycap,
13147615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
13157615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_g_fmt_vid_cap	 = vidioc_g_fmt_vid_cap,
13167615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_try_fmt_vid_cap	 = vidioc_try_fmt_vid_cap,
13177615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_s_fmt_vid_cap	 = vidioc_s_fmt_vid_cap,
13187615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_g_ext_ctrls	 = vidioc_g_ext_ctrls,
13197615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_s_ext_ctrls	 = vidioc_s_ext_ctrls,
13207615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_try_ext_ctrls	 = vidioc_try_ext_ctrls,
13217615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_queryctrl	 = vidioc_queryctrl,
13227615e434aefd95181eae099c4f019e021b024eb6Steven Toth};
13237615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13247615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic struct video_device saa7164_mpeg_template = {
13257615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.name          = "saa7164",
13267615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.fops          = &mpeg_fops,
13277615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.ioctl_ops     = &mpeg_ioctl_ops,
13287615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.minor         = -1,
13297615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.tvnorms       = SAA7164_NORMS,
13307615e434aefd95181eae099c4f019e021b024eb6Steven Toth};
13317615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13327615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic struct video_device *saa7164_encoder_alloc(
13337615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port,
13347615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct pci_dev *pci,
13357615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct video_device *template,
13367615e434aefd95181eae099c4f019e021b024eb6Steven Toth	char *type)
13377615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
13387615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct video_device *vfd;
13397615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
13407615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13417615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s()\n", __func__);
13427615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13437615e434aefd95181eae099c4f019e021b024eb6Steven Toth	vfd = video_device_alloc();
13447615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (NULL == vfd)
13457615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return NULL;
13467615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13477615e434aefd95181eae099c4f019e021b024eb6Steven Toth	*vfd = *template;
13487615e434aefd95181eae099c4f019e021b024eb6Steven Toth	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
13497615e434aefd95181eae099c4f019e021b024eb6Steven Toth		type, saa7164_boards[dev->board].name);
13507615e434aefd95181eae099c4f019e021b024eb6Steven Toth
1351d66de790c77b98589b93cb327bde2cddd2a4c2ccHans Verkuil	vfd->v4l2_dev  = &dev->v4l2_dev;
13527615e434aefd95181eae099c4f019e021b024eb6Steven Toth	vfd->release = video_device_release;
13537615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return vfd;
13547615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
13557615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13567615e434aefd95181eae099c4f019e021b024eb6Steven Tothint saa7164_encoder_register(struct saa7164_port *port)
13577615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
13587615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
13591b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	int result = -ENODEV;
13607615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13617615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s()\n", __func__);
13627615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13637615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (port->type != SAA7164_MPEG_ENCODER)
13647615e434aefd95181eae099c4f019e021b024eb6Steven Toth		BUG();
13657615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13667615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Sanity check that the PCI configuration space is active */
13677615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (port->hwcfg.BARLocation == 0) {
13687615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_ERR "%s() failed "
13697615e434aefd95181eae099c4f019e021b024eb6Steven Toth		       "(errno = %d), NO PCI configuration\n",
13707615e434aefd95181eae099c4f019e021b024eb6Steven Toth			__func__, result);
13717615e434aefd95181eae099c4f019e021b024eb6Steven Toth		result = -ENOMEM;
13727615e434aefd95181eae099c4f019e021b024eb6Steven Toth		goto failed;
13737615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
13747615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13757615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Establish encoder defaults here */
13767615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Set default TV standard */
13777615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->encodernorm = saa7164_tvnorms[0];
13787615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->width = 720;
13797615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->mux_input = 1; /* Composite */
13807615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->video_format = EU_VIDEO_FORMAT_MPEG_2;
13817615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->audio_format = 0;
13827615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->video_resolution = 0;
13837615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->ctl_brightness = 127;
13847615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->ctl_contrast = 66;
13857615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->ctl_hue = 128;
13867615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->ctl_saturation = 62;
13877615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->ctl_sharpness = 8;
13887615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->encoder_params.bitrate = ENCODER_DEF_BITRATE;
1389968b11b20143036098a7013817a15615a54383d3Steven Toth	port->encoder_params.bitrate_peak = ENCODER_DEF_BITRATE;
13905fa56ccdacc54f5f694141c1a74f781cf77874bbSteven Toth	port->encoder_params.bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
13917615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->encoder_params.stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS;
13927615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->encoder_params.ctl_mute = 0;
13937615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->encoder_params.ctl_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3;
13943ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth	port->encoder_params.refdist = 1;
13955fa56ccdacc54f5f694141c1a74f781cf77874bbSteven Toth	port->encoder_params.gop_size = SAA7164_ENCODER_DEFAULT_GOP_SIZE;
13968d2d41e92d99e25f7d42fc83fc39096d89caa35eHans Verkuil	port->std = V4L2_STD_NTSC_M;
13977615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13987615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (port->encodernorm.id & V4L2_STD_525_60)
13997615e434aefd95181eae099c4f019e021b024eb6Steven Toth		port->height = 480;
14007615e434aefd95181eae099c4f019e021b024eb6Steven Toth	else
14017615e434aefd95181eae099c4f019e021b024eb6Steven Toth		port->height = 576;
14027615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14037615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Allocate and register the video device node */
14047615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->v4l_device = saa7164_encoder_alloc(port,
14057615e434aefd95181eae099c4f019e021b024eb6Steven Toth		dev->pci, &saa7164_mpeg_template, "mpeg");
14067615e434aefd95181eae099c4f019e021b024eb6Steven Toth
140761ca1500c5ee04f2be34a4f58bb9baed0214b7a9Peter Huewe	if (!port->v4l_device) {
14087615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_INFO "%s: can't allocate mpeg device\n",
14097615e434aefd95181eae099c4f019e021b024eb6Steven Toth			dev->name);
14107615e434aefd95181eae099c4f019e021b024eb6Steven Toth		result = -ENOMEM;
14117615e434aefd95181eae099c4f019e021b024eb6Steven Toth		goto failed;
14127615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
14137615e434aefd95181eae099c4f019e021b024eb6Steven Toth
1414214ce3faacafa3cca2fdd340d18ff35cfe463c2bSteven Toth	video_set_drvdata(port->v4l_device, port);
14157615e434aefd95181eae099c4f019e021b024eb6Steven Toth	result = video_register_device(port->v4l_device,
14167615e434aefd95181eae099c4f019e021b024eb6Steven Toth		VFL_TYPE_GRABBER, -1);
14177615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (result < 0) {
14187615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_INFO "%s: can't register mpeg device\n",
14197615e434aefd95181eae099c4f019e021b024eb6Steven Toth			dev->name);
14207615e434aefd95181eae099c4f019e021b024eb6Steven Toth		/* TODO: We're going to leak here if we don't dealloc
14217615e434aefd95181eae099c4f019e021b024eb6Steven Toth		 The buffers above. The unreg function can't deal wit it.
14227615e434aefd95181eae099c4f019e021b024eb6Steven Toth		*/
14237615e434aefd95181eae099c4f019e021b024eb6Steven Toth		goto failed;
14247615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
14257615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14267615e434aefd95181eae099c4f019e021b024eb6Steven Toth	printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
14277615e434aefd95181eae099c4f019e021b024eb6Steven Toth		dev->name, port->v4l_device->num);
14287615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14297615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Configure the hardware defaults */
14307615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_videomux(port);
14317615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_usercontrol(port, PU_BRIGHTNESS_CONTROL);
14327615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL);
14337615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_usercontrol(port, PU_HUE_CONTROL);
14347615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_usercontrol(port, PU_SATURATION_CONTROL);
14357615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL);
14367615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_audio_mute(port, 0);
14377615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_audio_volume(port, 20);
14387615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_aspect_ratio(port);
14397615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14407615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Disable audio standard detection, it's buggy */
14417615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_audio_detection(port, 0);
14427615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14437615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_encoder(port);
14447615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_get_encoder(port);
14457615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14467615e434aefd95181eae099c4f019e021b024eb6Steven Toth	result = 0;
14477615e434aefd95181eae099c4f019e021b024eb6Steven Tothfailed:
14487615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return result;
14497615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
14507615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14517615e434aefd95181eae099c4f019e021b024eb6Steven Tothvoid saa7164_encoder_unregister(struct saa7164_port *port)
14527615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
14537615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
14547615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14557615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
14567615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14577615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (port->type != SAA7164_MPEG_ENCODER)
14587615e434aefd95181eae099c4f019e021b024eb6Steven Toth		BUG();
14597615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14607615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (port->v4l_device) {
14617615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (port->v4l_device->minor != -1)
14627615e434aefd95181eae099c4f019e021b024eb6Steven Toth			video_unregister_device(port->v4l_device);
14637615e434aefd95181eae099c4f019e021b024eb6Steven Toth		else
14647615e434aefd95181eae099c4f019e021b024eb6Steven Toth			video_device_release(port->v4l_device);
14657615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14667615e434aefd95181eae099c4f019e021b024eb6Steven Toth		port->v4l_device = NULL;
14677615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
14687615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14697615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s(port=%d) done\n", __func__, port->nr);
14707615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
14717615e434aefd95181eae099c4f019e021b024eb6Steven Toth
1472