saa7164-encoder.c revision bc25068495b110fcdf35a22f43d32637e99fd018
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;
1551b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	params->pagetablelistvirt = 0;
1561b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	params->pagetablelistphys = 0;
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
1801b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	/* Allocate some kenrel 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 --------------------------------------------------------- */
2147615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic 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
2217615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s(id=0x%x)\n", __func__, (u32)*id);
2227615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2237615e434aefd95181eae099c4f019e021b024eb6Steven Toth	for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) {
2247615e434aefd95181eae099c4f019e021b024eb6Steven Toth		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];
2317615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2327615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Update the audio decoder while is not running in
2337615e434aefd95181eae099c4f019e021b024eb6Steven Toth	 * auto detect mode.
2347615e434aefd95181eae099c4f019e021b024eb6Steven Toth	 */
2357615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_audio_std(port);
2367615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2377615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s(id=0x%x) OK\n", __func__, (u32)*id);
2387615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2397615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
2407615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
2417615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2427615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_enum_input(struct file *file, void *priv,
2437615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_input *i)
2447615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
2457615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int n;
2467615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2477615e434aefd95181eae099c4f019e021b024eb6Steven Toth	char *inputs[] = { "tuner", "composite", "svideo", "aux",
248f89076c5f13dc2fafd6c4a411111f1be7aab0098Gavin Hurlbut		"composite 2", "svideo 2", "aux 2" };
2497615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2507615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (i->index >= 7)
2517615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
2527615e434aefd95181eae099c4f019e021b024eb6Steven Toth
253c7e242baf73a284eff92444fb58af11439e3a22cMauro Carvalho Chehab	strcpy(i->name, inputs[i->index]);
2547615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2557615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (i->index == 0)
2567615e434aefd95181eae099c4f019e021b024eb6Steven Toth		i->type = V4L2_INPUT_TYPE_TUNER;
2577615e434aefd95181eae099c4f019e021b024eb6Steven Toth	else
2587615e434aefd95181eae099c4f019e021b024eb6Steven Toth		i->type  = V4L2_INPUT_TYPE_CAMERA;
2597615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2607615e434aefd95181eae099c4f019e021b024eb6Steven Toth	for (n = 0; n < ARRAY_SIZE(saa7164_tvnorms); n++)
2617615e434aefd95181eae099c4f019e021b024eb6Steven Toth		i->std |= saa7164_tvnorms[n].id;
2627615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2637615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
2647615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
2657615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2667615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
2677615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
26896d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
2697615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
2707615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
2717615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2727615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (saa7164_api_get_videomux(port) != SAA_OK)
2737615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EIO;
2747615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2757615e434aefd95181eae099c4f019e021b024eb6Steven Toth	*i = (port->mux_input - 1);
2767615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2777615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s() input=%d\n", __func__, *i);
2787615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2797615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
2807615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
2817615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2827615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_s_input(struct file *file, void *priv, unsigned int i)
2837615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
28496d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
2857615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
2867615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
2877615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2887615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s() input=%d\n", __func__, i);
2897615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2907615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (i >= 7)
2917615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
2927615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2937615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->mux_input = i + 1;
2947615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2957615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (saa7164_api_set_videomux(port) != SAA_OK)
2967615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EIO;
2977615e434aefd95181eae099c4f019e021b024eb6Steven Toth
2987615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
2997615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
3007615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3017615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_g_tuner(struct file *file, void *priv,
3027615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_tuner *t)
3037615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
30496d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
3057615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
3067615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
3077615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3087615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (0 != t->index)
3097615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
3107615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3117615e434aefd95181eae099c4f019e021b024eb6Steven Toth	strcpy(t->name, "tuner");
3127615e434aefd95181eae099c4f019e021b024eb6Steven Toth	t->type = V4L2_TUNER_ANALOG_TV;
3137615e434aefd95181eae099c4f019e021b024eb6Steven Toth	t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO;
3147615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3157615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
3167615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3177615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
3187615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
3197615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3207615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_s_tuner(struct file *file, void *priv,
3217615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_tuner *t)
3227615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
3237615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Update the A/V core */
3247615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
3257615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
3267615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3277615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_g_frequency(struct file *file, void *priv,
3287615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_frequency *f)
3297615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
33096d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
3317615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
3327615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3337615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->type = V4L2_TUNER_ANALOG_TV;
3347615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->frequency = port->freq;
3357615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3367615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
3377615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
3387615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3397615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_s_frequency(struct file *file, void *priv,
3407615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_frequency *f)
3417615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
34296d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
3437615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
3447615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
3457615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *tsport;
3467615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct dvb_frontend *fe;
3477615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3487615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* TODO: Pull this for the std */
3497615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct analog_parameters params = {
3507615e434aefd95181eae099c4f019e021b024eb6Steven Toth		.mode      = V4L2_TUNER_ANALOG_TV,
3517615e434aefd95181eae099c4f019e021b024eb6Steven Toth		.audmode   = V4L2_TUNER_MODE_STEREO,
3527615e434aefd95181eae099c4f019e021b024eb6Steven Toth		.std       = port->encodernorm.id,
3537615e434aefd95181eae099c4f019e021b024eb6Steven Toth		.frequency = f->frequency
3547615e434aefd95181eae099c4f019e021b024eb6Steven Toth	};
3557615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3567615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Stop the encoder */
3577615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s() frequency=%d tuner=%d\n", __func__,
3587615e434aefd95181eae099c4f019e021b024eb6Steven Toth		f->frequency, f->tuner);
3597615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3607615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (f->tuner != 0)
3617615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
3627615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3637615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (f->type != V4L2_TUNER_ANALOG_TV)
3647615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
3657615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3667615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->freq = f->frequency;
3677615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3687615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Update the hardware */
3697615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (port->nr == SAA7164_PORT_ENC1)
370c7e242baf73a284eff92444fb58af11439e3a22cMauro Carvalho Chehab		tsport = &dev->ports[SAA7164_PORT_TS1];
3717615e434aefd95181eae099c4f019e021b024eb6Steven Toth	else
3727615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (port->nr == SAA7164_PORT_ENC2)
373c7e242baf73a284eff92444fb58af11439e3a22cMauro Carvalho Chehab		tsport = &dev->ports[SAA7164_PORT_TS2];
3747615e434aefd95181eae099c4f019e021b024eb6Steven Toth	else
3757615e434aefd95181eae099c4f019e021b024eb6Steven Toth		BUG();
3767615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3777615e434aefd95181eae099c4f019e021b024eb6Steven Toth	fe = tsport->dvb.frontend;
3787615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3797615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (fe && fe->ops.tuner_ops.set_analog_params)
3807615e434aefd95181eae099c4f019e021b024eb6Steven Toth		fe->ops.tuner_ops.set_analog_params(fe, &params);
3817615e434aefd95181eae099c4f019e021b024eb6Steven Toth	else
3827615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__);
3837615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3847615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_encoder_initialize(port);
3857615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3867615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
3877615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
3887615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3897615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_g_ctrl(struct file *file, void *priv,
3907615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_control *ctl)
3917615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
39296d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
3937615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
3947615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
3957615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3967615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s(id=%d, value=%d)\n", __func__,
3977615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctl->id, ctl->value);
3987615e434aefd95181eae099c4f019e021b024eb6Steven Toth
3997615e434aefd95181eae099c4f019e021b024eb6Steven Toth	switch (ctl->id) {
4007615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_BRIGHTNESS:
4017615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctl->value = port->ctl_brightness;
4027615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4037615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_CONTRAST:
4047615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctl->value = port->ctl_contrast;
4057615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4067615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_SATURATION:
4077615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctl->value = port->ctl_saturation;
4087615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4097615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_HUE:
4107615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctl->value = port->ctl_hue;
4117615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4127615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_SHARPNESS:
4137615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctl->value = port->ctl_sharpness;
4147615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4157615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_AUDIO_VOLUME:
4167615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctl->value = port->ctl_volume;
4177615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4187615e434aefd95181eae099c4f019e021b024eb6Steven Toth	default:
4197615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
4207615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
4217615e434aefd95181eae099c4f019e021b024eb6Steven Toth
4227615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
4237615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
4247615e434aefd95181eae099c4f019e021b024eb6Steven Toth
4257615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_s_ctrl(struct file *file, void *priv,
4267615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_control *ctl)
4277615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
42896d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
4297615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
4307615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
4317615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int ret = 0;
4327615e434aefd95181eae099c4f019e021b024eb6Steven Toth
4337615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s(id=%d, value=%d)\n", __func__,
4347615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctl->id, ctl->value);
4357615e434aefd95181eae099c4f019e021b024eb6Steven Toth
4367615e434aefd95181eae099c4f019e021b024eb6Steven Toth	switch (ctl->id) {
4377615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_BRIGHTNESS:
4387615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctl->value >= 0) && (ctl->value <= 255)) {
4397615e434aefd95181eae099c4f019e021b024eb6Steven Toth			port->ctl_brightness = ctl->value;
4407615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_api_set_usercontrol(port,
4417615e434aefd95181eae099c4f019e021b024eb6Steven Toth				PU_BRIGHTNESS_CONTROL);
4427615e434aefd95181eae099c4f019e021b024eb6Steven Toth		} else
4437615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = -EINVAL;
4447615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4457615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_CONTRAST:
4467615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctl->value >= 0) && (ctl->value <= 255)) {
4477615e434aefd95181eae099c4f019e021b024eb6Steven Toth			port->ctl_contrast = ctl->value;
4487615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL);
4497615e434aefd95181eae099c4f019e021b024eb6Steven Toth		} else
4507615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = -EINVAL;
4517615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4527615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_SATURATION:
4537615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctl->value >= 0) && (ctl->value <= 255)) {
4547615e434aefd95181eae099c4f019e021b024eb6Steven Toth			port->ctl_saturation = ctl->value;
4557615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_api_set_usercontrol(port,
4567615e434aefd95181eae099c4f019e021b024eb6Steven Toth				PU_SATURATION_CONTROL);
4577615e434aefd95181eae099c4f019e021b024eb6Steven Toth		} else
4587615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = -EINVAL;
4597615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4607615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_HUE:
4617615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctl->value >= 0) && (ctl->value <= 255)) {
4627615e434aefd95181eae099c4f019e021b024eb6Steven Toth			port->ctl_hue = ctl->value;
4637615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_api_set_usercontrol(port, PU_HUE_CONTROL);
4647615e434aefd95181eae099c4f019e021b024eb6Steven Toth		} else
4657615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = -EINVAL;
4667615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4677615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_SHARPNESS:
4687615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctl->value >= 0) && (ctl->value <= 255)) {
4697615e434aefd95181eae099c4f019e021b024eb6Steven Toth			port->ctl_sharpness = ctl->value;
4707615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL);
4717615e434aefd95181eae099c4f019e021b024eb6Steven Toth		} else
4727615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = -EINVAL;
4737615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4747615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_AUDIO_VOLUME:
4757615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctl->value >= -83) && (ctl->value <= 24)) {
4767615e434aefd95181eae099c4f019e021b024eb6Steven Toth			port->ctl_volume = ctl->value;
4777615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_api_set_audio_volume(port, port->ctl_volume);
4787615e434aefd95181eae099c4f019e021b024eb6Steven Toth		} else
4797615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = -EINVAL;
4807615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4817615e434aefd95181eae099c4f019e021b024eb6Steven Toth	default:
4827615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = -EINVAL;
4837615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
4847615e434aefd95181eae099c4f019e021b024eb6Steven Toth
4857615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return ret;
4867615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
4877615e434aefd95181eae099c4f019e021b024eb6Steven Toth
4887615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int saa7164_get_ctrl(struct saa7164_port *port,
4897615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_ext_control *ctrl)
4907615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
4917615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_encoder_params *params = &port->encoder_params;
4927615e434aefd95181eae099c4f019e021b024eb6Steven Toth
4937615e434aefd95181eae099c4f019e021b024eb6Steven Toth	switch (ctrl->id) {
4947615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE:
4957615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctrl->value = params->bitrate;
4967615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
4977615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_STREAM_TYPE:
4987615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctrl->value = params->stream_type;
4997615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
5007615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_AUDIO_MUTE:
5017615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctrl->value = params->ctl_mute;
5027615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
5037615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_ASPECT:
5047615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ctrl->value = params->ctl_aspect;
5057615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
5062600d71cc535907e5d95cd31751c587afc370065Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
5072600d71cc535907e5d95cd31751c587afc370065Steven Toth		ctrl->value = params->bitrate_mode;
5082600d71cc535907e5d95cd31751c587afc370065Steven Toth		break;
5093ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
5103ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth		ctrl->value = params->refdist;
5113ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth		break;
512968b11b20143036098a7013817a15615a54383d3Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
513968b11b20143036098a7013817a15615a54383d3Steven Toth		ctrl->value = params->bitrate_peak;
514968b11b20143036098a7013817a15615a54383d3Steven Toth		break;
5155fa56ccdacc54f5f694141c1a74f781cf77874bbSteven Toth	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
5165fa56ccdacc54f5f694141c1a74f781cf77874bbSteven Toth		ctrl->value = params->gop_size;
5175fa56ccdacc54f5f694141c1a74f781cf77874bbSteven Toth		break;
5187615e434aefd95181eae099c4f019e021b024eb6Steven Toth	default:
5197615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
5207615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
5217615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
5227615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
5237615e434aefd95181eae099c4f019e021b024eb6Steven Toth
5247615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_g_ext_ctrls(struct file *file, void *priv,
5257615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_ext_controls *ctrls)
5267615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
52796d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
5287615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
5297615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int i, err = 0;
5307615e434aefd95181eae099c4f019e021b024eb6Steven Toth
5317615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
5327615e434aefd95181eae099c4f019e021b024eb6Steven Toth		for (i = 0; i < ctrls->count; i++) {
5337615e434aefd95181eae099c4f019e021b024eb6Steven Toth			struct v4l2_ext_control *ctrl = ctrls->controls + i;
5347615e434aefd95181eae099c4f019e021b024eb6Steven Toth
5357615e434aefd95181eae099c4f019e021b024eb6Steven Toth			err = saa7164_get_ctrl(port, ctrl);
5367615e434aefd95181eae099c4f019e021b024eb6Steven Toth			if (err) {
5377615e434aefd95181eae099c4f019e021b024eb6Steven Toth				ctrls->error_idx = i;
5387615e434aefd95181eae099c4f019e021b024eb6Steven Toth				break;
5397615e434aefd95181eae099c4f019e021b024eb6Steven Toth			}
5407615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
5417615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return err;
5427615e434aefd95181eae099c4f019e021b024eb6Steven Toth
5437615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
5447615e434aefd95181eae099c4f019e021b024eb6Steven Toth
5457615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return -EINVAL;
5467615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
5477615e434aefd95181eae099c4f019e021b024eb6Steven Toth
5487615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int saa7164_try_ctrl(struct v4l2_ext_control *ctrl, int ac3)
5497615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
5507615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int ret = -EINVAL;
5517615e434aefd95181eae099c4f019e021b024eb6Steven Toth
5527615e434aefd95181eae099c4f019e021b024eb6Steven Toth	switch (ctrl->id) {
5537615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE:
5547615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctrl->value >= ENCODER_MIN_BITRATE) &&
5557615e434aefd95181eae099c4f019e021b024eb6Steven Toth			(ctrl->value <= ENCODER_MAX_BITRATE))
5567615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = 0;
5577615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
5587615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_STREAM_TYPE:
559f91d095c92e8fdcb6bd8cb35e8fa9c87d9c10768Steven Toth		if ((ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) ||
560f91d095c92e8fdcb6bd8cb35e8fa9c87d9c10768Steven Toth			(ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS))
5617615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = 0;
5627615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
5637615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_AUDIO_MUTE:
5647615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctrl->value >= 0) &&
5657615e434aefd95181eae099c4f019e021b024eb6Steven Toth			(ctrl->value <= 1))
5667615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = 0;
5677615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
5687615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_ASPECT:
5697615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctrl->value >= V4L2_MPEG_VIDEO_ASPECT_1x1) &&
5707615e434aefd95181eae099c4f019e021b024eb6Steven Toth			(ctrl->value <= V4L2_MPEG_VIDEO_ASPECT_221x100))
5717615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = 0;
5727615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
5737615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
5747615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((ctrl->value >= 0) &&
5757615e434aefd95181eae099c4f019e021b024eb6Steven Toth			(ctrl->value <= 255))
5767615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = 0;
5777615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
5782600d71cc535907e5d95cd31751c587afc370065Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
5792600d71cc535907e5d95cd31751c587afc370065Steven Toth		if ((ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) ||
5802600d71cc535907e5d95cd31751c587afc370065Steven Toth			(ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR))
5812600d71cc535907e5d95cd31751c587afc370065Steven Toth			ret = 0;
5822600d71cc535907e5d95cd31751c587afc370065Steven Toth		break;
5833ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
5843ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth		if ((ctrl->value >= 1) &&
5853ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth			(ctrl->value <= 3))
5863ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth			ret = 0;
5873ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth		break;
588968b11b20143036098a7013817a15615a54383d3Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
589968b11b20143036098a7013817a15615a54383d3Steven Toth		if ((ctrl->value >= ENCODER_MIN_BITRATE) &&
590968b11b20143036098a7013817a15615a54383d3Steven Toth			(ctrl->value <= ENCODER_MAX_BITRATE))
591968b11b20143036098a7013817a15615a54383d3Steven Toth			ret = 0;
592968b11b20143036098a7013817a15615a54383d3Steven Toth		break;
5937615e434aefd95181eae099c4f019e021b024eb6Steven Toth	default:
5947615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = -EINVAL;
5957615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
5967615e434aefd95181eae099c4f019e021b024eb6Steven Toth
5977615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return ret;
5987615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
5997615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6007615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_try_ext_ctrls(struct file *file, void *priv,
6017615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_ext_controls *ctrls)
6027615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
6037615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int i, err = 0;
6047615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6057615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
6067615e434aefd95181eae099c4f019e021b024eb6Steven Toth		for (i = 0; i < ctrls->count; i++) {
6077615e434aefd95181eae099c4f019e021b024eb6Steven Toth			struct v4l2_ext_control *ctrl = ctrls->controls + i;
6087615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6097615e434aefd95181eae099c4f019e021b024eb6Steven Toth			err = saa7164_try_ctrl(ctrl, 0);
6107615e434aefd95181eae099c4f019e021b024eb6Steven Toth			if (err) {
6117615e434aefd95181eae099c4f019e021b024eb6Steven Toth				ctrls->error_idx = i;
6127615e434aefd95181eae099c4f019e021b024eb6Steven Toth				break;
6137615e434aefd95181eae099c4f019e021b024eb6Steven Toth			}
6147615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
6157615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return err;
6167615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
6177615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6187615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return -EINVAL;
6197615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
6207615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6217615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int saa7164_set_ctrl(struct saa7164_port *port,
6227615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_ext_control *ctrl)
6237615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
6247615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_encoder_params *params = &port->encoder_params;
6257615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int ret = 0;
6267615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6277615e434aefd95181eae099c4f019e021b024eb6Steven Toth	switch (ctrl->id) {
6287615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE:
6297615e434aefd95181eae099c4f019e021b024eb6Steven Toth		params->bitrate = ctrl->value;
6307615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
6317615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_STREAM_TYPE:
6327615e434aefd95181eae099c4f019e021b024eb6Steven Toth		params->stream_type = ctrl->value;
6337615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
6347615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_AUDIO_MUTE:
6357615e434aefd95181eae099c4f019e021b024eb6Steven Toth		params->ctl_mute = ctrl->value;
6367615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = saa7164_api_audio_mute(port, params->ctl_mute);
6377615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (ret != SAA_OK) {
6387615e434aefd95181eae099c4f019e021b024eb6Steven Toth			printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
6397615e434aefd95181eae099c4f019e021b024eb6Steven Toth				ret);
6407615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = -EIO;
6417615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
6427615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
6437615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_ASPECT:
6447615e434aefd95181eae099c4f019e021b024eb6Steven Toth		params->ctl_aspect = ctrl->value;
6457615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = saa7164_api_set_aspect_ratio(port);
6467615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (ret != SAA_OK) {
6477615e434aefd95181eae099c4f019e021b024eb6Steven Toth			printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
6487615e434aefd95181eae099c4f019e021b024eb6Steven Toth				ret);
6497615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ret = -EIO;
6507615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
6517615e434aefd95181eae099c4f019e021b024eb6Steven Toth		break;
6522600d71cc535907e5d95cd31751c587afc370065Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
6532600d71cc535907e5d95cd31751c587afc370065Steven Toth		params->bitrate_mode = ctrl->value;
6542600d71cc535907e5d95cd31751c587afc370065Steven Toth		break;
6553ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
6563ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth		params->refdist = ctrl->value;
6573ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth		break;
658968b11b20143036098a7013817a15615a54383d3Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
659968b11b20143036098a7013817a15615a54383d3Steven Toth		params->bitrate_peak = ctrl->value;
660968b11b20143036098a7013817a15615a54383d3Steven Toth		break;
6615fa56ccdacc54f5f694141c1a74f781cf77874bbSteven Toth	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
6625fa56ccdacc54f5f694141c1a74f781cf77874bbSteven Toth		params->gop_size = ctrl->value;
6635fa56ccdacc54f5f694141c1a74f781cf77874bbSteven Toth		break;
6647615e434aefd95181eae099c4f019e021b024eb6Steven Toth	default:
6657615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
6667615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
6677615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6687615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* TODO: Update the hardware */
6697615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6707615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return ret;
6717615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
6727615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6737615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_s_ext_ctrls(struct file *file, void *priv,
6747615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_ext_controls *ctrls)
6757615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
67696d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
6777615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
6787615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int i, err = 0;
6797615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6807615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
6817615e434aefd95181eae099c4f019e021b024eb6Steven Toth		for (i = 0; i < ctrls->count; i++) {
6827615e434aefd95181eae099c4f019e021b024eb6Steven Toth			struct v4l2_ext_control *ctrl = ctrls->controls + i;
6837615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6847615e434aefd95181eae099c4f019e021b024eb6Steven Toth			err = saa7164_try_ctrl(ctrl, 0);
6857615e434aefd95181eae099c4f019e021b024eb6Steven Toth			if (err) {
6867615e434aefd95181eae099c4f019e021b024eb6Steven Toth				ctrls->error_idx = i;
6877615e434aefd95181eae099c4f019e021b024eb6Steven Toth				break;
6887615e434aefd95181eae099c4f019e021b024eb6Steven Toth			}
6897615e434aefd95181eae099c4f019e021b024eb6Steven Toth			err = saa7164_set_ctrl(port, ctrl);
6907615e434aefd95181eae099c4f019e021b024eb6Steven Toth			if (err) {
6917615e434aefd95181eae099c4f019e021b024eb6Steven Toth				ctrls->error_idx = i;
6927615e434aefd95181eae099c4f019e021b024eb6Steven Toth				break;
6937615e434aefd95181eae099c4f019e021b024eb6Steven Toth			}
6947615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
6957615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return err;
6967615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6977615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
6987615e434aefd95181eae099c4f019e021b024eb6Steven Toth
6997615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return -EINVAL;
7007615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
7017615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7027615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_querycap(struct file *file, void  *priv,
7037615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_capability *cap)
7047615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
70596d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
7067615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
7077615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
7087615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7097615e434aefd95181eae099c4f019e021b024eb6Steven Toth	strcpy(cap->driver, dev->name);
7107615e434aefd95181eae099c4f019e021b024eb6Steven Toth	strlcpy(cap->card, saa7164_boards[dev->board].name,
7117615e434aefd95181eae099c4f019e021b024eb6Steven Toth		sizeof(cap->card));
7127615e434aefd95181eae099c4f019e021b024eb6Steven Toth	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
7137615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7147615e434aefd95181eae099c4f019e021b024eb6Steven Toth	cap->capabilities =
7157615e434aefd95181eae099c4f019e021b024eb6Steven Toth		V4L2_CAP_VIDEO_CAPTURE |
7167615e434aefd95181eae099c4f019e021b024eb6Steven Toth		V4L2_CAP_READWRITE     |
7177615e434aefd95181eae099c4f019e021b024eb6Steven Toth		0;
7187615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7197615e434aefd95181eae099c4f019e021b024eb6Steven Toth	cap->capabilities |= V4L2_CAP_TUNER;
7207615e434aefd95181eae099c4f019e021b024eb6Steven Toth	cap->version = 0;
7217615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7227615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
7237615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
7247615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7257615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
7267615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_fmtdesc *f)
7277615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
7287615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (f->index != 0)
7297615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
7307615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7317615e434aefd95181eae099c4f019e021b024eb6Steven Toth	strlcpy(f->description, "MPEG", sizeof(f->description));
7327615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->pixelformat = V4L2_PIX_FMT_MPEG;
7337615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7347615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
7357615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
7367615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7377615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
7387615e434aefd95181eae099c4f019e021b024eb6Steven Toth				struct v4l2_format *f)
7397615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
74096d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
7417615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
7427615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
7437615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7447615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
7457615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.bytesperline = 0;
7467615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.sizeimage    =
7477615e434aefd95181eae099c4f019e021b024eb6Steven Toth		port->ts_packet_size * port->ts_packet_count;
7487615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.colorspace   = 0;
7497615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.width        = port->width;
7507615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.height       = port->height;
7517615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7527615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "VIDIOC_G_FMT: w: %d, h: %d\n",
7537615e434aefd95181eae099c4f019e021b024eb6Steven Toth		port->width, port->height);
7547615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7557615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
7567615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
7577615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7587615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
7597615e434aefd95181eae099c4f019e021b024eb6Steven Toth				struct v4l2_format *f)
7607615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
76196d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
7627615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
7637615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
7647615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7657615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
7667615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.bytesperline = 0;
7677615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.sizeimage    =
7687615e434aefd95181eae099c4f019e021b024eb6Steven Toth		port->ts_packet_size * port->ts_packet_count;
7697615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.colorspace   = 0;
7707615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
7717615e434aefd95181eae099c4f019e021b024eb6Steven Toth		port->width, port->height);
7727615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
7737615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
7747615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7757615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
7767615e434aefd95181eae099c4f019e021b024eb6Steven Toth				struct v4l2_format *f)
7777615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
77896d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
7797615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
7807615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
7817615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7827615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
7837615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.bytesperline = 0;
7847615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.sizeimage    =
7857615e434aefd95181eae099c4f019e021b024eb6Steven Toth		port->ts_packet_size * port->ts_packet_count;
7867615e434aefd95181eae099c4f019e021b024eb6Steven Toth	f->fmt.pix.colorspace   = 0;
7877615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7887615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
7897615e434aefd95181eae099c4f019e021b024eb6Steven Toth		f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
7907615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7917615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
7927615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
7937615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7947615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_log_status(struct file *file, void *priv)
7957615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
7967615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
7977615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
7987615e434aefd95181eae099c4f019e021b024eb6Steven Toth
7997615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int fill_queryctrl(struct saa7164_encoder_params *params,
8007615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_queryctrl *c)
8017615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
8027615e434aefd95181eae099c4f019e021b024eb6Steven Toth	switch (c->id) {
8037615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_BRIGHTNESS:
8047615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 127);
8057615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_CONTRAST:
8067615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 66);
8077615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_SATURATION:
8087615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 62);
8097615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_HUE:
8107615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 128);
8117615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_SHARPNESS:
8127615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c, 0x0, 0x0f, 1, 8);
8137615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_AUDIO_MUTE:
8147615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c, 0x0, 0x01, 1, 0);
8157615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_AUDIO_VOLUME:
8167615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c, -83, 24, 1, 20);
8177615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE:
8187615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c,
8197615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ENCODER_MIN_BITRATE, ENCODER_MAX_BITRATE,
8207615e434aefd95181eae099c4f019e021b024eb6Steven Toth			100000, ENCODER_DEF_BITRATE);
8217615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_STREAM_TYPE:
8227615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c,
8237615e434aefd95181eae099c4f019e021b024eb6Steven Toth			V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
824f91d095c92e8fdcb6bd8cb35e8fa9c87d9c10768Steven Toth			V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
825f91d095c92e8fdcb6bd8cb35e8fa9c87d9c10768Steven Toth			1, V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
8267615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_ASPECT:
8277615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c,
8287615e434aefd95181eae099c4f019e021b024eb6Steven Toth			V4L2_MPEG_VIDEO_ASPECT_1x1,
8297615e434aefd95181eae099c4f019e021b024eb6Steven Toth			V4L2_MPEG_VIDEO_ASPECT_221x100,
8307615e434aefd95181eae099c4f019e021b024eb6Steven Toth			1, V4L2_MPEG_VIDEO_ASPECT_4x3);
8317615e434aefd95181eae099c4f019e021b024eb6Steven Toth	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
8327615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return v4l2_ctrl_query_fill(c, 1, 255, 1, 15);
8332600d71cc535907e5d95cd31751c587afc370065Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
8342600d71cc535907e5d95cd31751c587afc370065Steven Toth		return v4l2_ctrl_query_fill(c,
835bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth			V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
836bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth			V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
8372600d71cc535907e5d95cd31751c587afc370065Steven Toth			1, V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
8383ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
8393ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth		return v4l2_ctrl_query_fill(c,
8403ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth			1, 3, 1, 1);
841968b11b20143036098a7013817a15615a54383d3Steven Toth	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
842968b11b20143036098a7013817a15615a54383d3Steven Toth		return v4l2_ctrl_query_fill(c,
843968b11b20143036098a7013817a15615a54383d3Steven Toth			ENCODER_MIN_BITRATE, ENCODER_MAX_BITRATE,
844968b11b20143036098a7013817a15615a54383d3Steven Toth			100000, ENCODER_DEF_BITRATE);
8457615e434aefd95181eae099c4f019e021b024eb6Steven Toth	default:
8467615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EINVAL;
8477615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
8487615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
8497615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8507615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int vidioc_queryctrl(struct file *file, void *priv,
8517615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_queryctrl *c)
8527615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
85396d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = priv;
8547615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
8557615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int i, next;
8567615e434aefd95181eae099c4f019e021b024eb6Steven Toth	u32 id = c->id;
8577615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8587615e434aefd95181eae099c4f019e021b024eb6Steven Toth	memset(c, 0, sizeof(*c));
8597615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8607615e434aefd95181eae099c4f019e021b024eb6Steven Toth	next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL);
8617615e434aefd95181eae099c4f019e021b024eb6Steven Toth	c->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
8627615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8637615e434aefd95181eae099c4f019e021b024eb6Steven Toth	for (i = 0; i < ARRAY_SIZE(saa7164_v4l2_ctrls); i++) {
8647615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (next) {
8657615e434aefd95181eae099c4f019e021b024eb6Steven Toth			if (c->id < saa7164_v4l2_ctrls[i])
8667615e434aefd95181eae099c4f019e021b024eb6Steven Toth				c->id = saa7164_v4l2_ctrls[i];
8677615e434aefd95181eae099c4f019e021b024eb6Steven Toth			else
8687615e434aefd95181eae099c4f019e021b024eb6Steven Toth				continue;
8697615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
8707615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8717615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (c->id == saa7164_v4l2_ctrls[i])
8727615e434aefd95181eae099c4f019e021b024eb6Steven Toth			return fill_queryctrl(&port->encoder_params, c);
8737615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8747615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (c->id < saa7164_v4l2_ctrls[i])
8757615e434aefd95181eae099c4f019e021b024eb6Steven Toth			break;
8767615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
8777615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8787615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return -EINVAL;
8797615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
8807615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8817615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int saa7164_encoder_stop_port(struct saa7164_port *port)
8827615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
8837615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
8847615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int ret;
8857615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8867615e434aefd95181eae099c4f019e021b024eb6Steven Toth	ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
8877615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
8887615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n",
8897615e434aefd95181eae099c4f019e021b024eb6Steven Toth			__func__, ret);
8907615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = -EIO;
8917615e434aefd95181eae099c4f019e021b024eb6Steven Toth	} else {
8927615e434aefd95181eae099c4f019e021b024eb6Steven Toth		dprintk(DBGLVL_ENC, "%s()    Stopped\n", __func__);
8937615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = 0;
8947615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
8957615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8967615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return ret;
8977615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
8987615e434aefd95181eae099c4f019e021b024eb6Steven Toth
8997615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int saa7164_encoder_acquire_port(struct saa7164_port *port)
9007615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
9017615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
9027615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int ret;
9037615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9047615e434aefd95181eae099c4f019e021b024eb6Steven Toth	ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
9057615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
9067615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n",
9077615e434aefd95181eae099c4f019e021b024eb6Steven Toth			__func__, ret);
9087615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = -EIO;
9097615e434aefd95181eae099c4f019e021b024eb6Steven Toth	} else {
9107615e434aefd95181eae099c4f019e021b024eb6Steven Toth		dprintk(DBGLVL_ENC, "%s() Acquired\n", __func__);
9117615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = 0;
9127615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
9137615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9147615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return ret;
9157615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
9167615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9177615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int saa7164_encoder_pause_port(struct saa7164_port *port)
9187615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
9197615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
9207615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int ret;
9217615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9227615e434aefd95181eae099c4f019e021b024eb6Steven Toth	ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
9237615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
9247615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n",
9257615e434aefd95181eae099c4f019e021b024eb6Steven Toth			__func__, ret);
9267615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = -EIO;
9277615e434aefd95181eae099c4f019e021b024eb6Steven Toth	} else {
9287615e434aefd95181eae099c4f019e021b024eb6Steven Toth		dprintk(DBGLVL_ENC, "%s()   Paused\n", __func__);
9297615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = 0;
9307615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
9317615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9327615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return ret;
9337615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
9347615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9357615e434aefd95181eae099c4f019e021b024eb6Steven Toth/* Firmware is very windows centric, meaning you have to transition
9367615e434aefd95181eae099c4f019e021b024eb6Steven Toth * the part through AVStream / KS Windows stages, forwards or backwards.
9377615e434aefd95181eae099c4f019e021b024eb6Steven Toth * States are: stopped, acquired (h/w), paused, started.
9387615e434aefd95181eae099c4f019e021b024eb6Steven Toth * We have to leave here will all of the soft buffers on the free list,
9397615e434aefd95181eae099c4f019e021b024eb6Steven Toth * else the cfg_post() func won't have soft buffers to correctly configure.
9407615e434aefd95181eae099c4f019e021b024eb6Steven Toth */
9417615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int saa7164_encoder_stop_streaming(struct saa7164_port *port)
9427615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
9437615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
9447615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_buffer *buf;
9457615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_user_buffer *ubuf;
9467615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct list_head *c, *n;
9477615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int ret;
9487615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9497615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
9507615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9517615e434aefd95181eae099c4f019e021b024eb6Steven Toth	ret = saa7164_encoder_pause_port(port);
9527615e434aefd95181eae099c4f019e021b024eb6Steven Toth	ret = saa7164_encoder_acquire_port(port);
9537615e434aefd95181eae099c4f019e021b024eb6Steven Toth	ret = saa7164_encoder_stop_port(port);
9547615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9557615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s(port=%d) Hardware stopped\n", __func__,
9567615e434aefd95181eae099c4f019e021b024eb6Steven Toth		port->nr);
9577615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9581b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	/* Reset the state of any allocated buffer resources */
9597615e434aefd95181eae099c4f019e021b024eb6Steven Toth	mutex_lock(&port->dmaqueue_lock);
9607615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9617615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Reset the hard and soft buffer state */
9627615e434aefd95181eae099c4f019e021b024eb6Steven Toth	list_for_each_safe(c, n, &port->dmaqueue.list) {
9637615e434aefd95181eae099c4f019e021b024eb6Steven Toth		buf = list_entry(c, struct saa7164_buffer, list);
9647615e434aefd95181eae099c4f019e021b024eb6Steven Toth		buf->flags = SAA7164_BUFFER_FREE;
9657615e434aefd95181eae099c4f019e021b024eb6Steven Toth		buf->pos = 0;
9667615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
9677615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9687615e434aefd95181eae099c4f019e021b024eb6Steven Toth	list_for_each_safe(c, n, &port->list_buf_used.list) {
9697615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ubuf = list_entry(c, struct saa7164_user_buffer, list);
9707615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ubuf->pos = 0;
9717615e434aefd95181eae099c4f019e021b024eb6Steven Toth		list_move_tail(&ubuf->list, &port->list_buf_free.list);
9727615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
9737615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9747615e434aefd95181eae099c4f019e021b024eb6Steven Toth	mutex_unlock(&port->dmaqueue_lock);
9751b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
9761b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	/* Free any allocated resources */
9771b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	saa7164_encoder_buffers_dealloc(port);
9781b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
9797615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s(port=%d) Released\n", __func__, port->nr);
9807615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9817615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return ret;
9827615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
9837615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9847615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int saa7164_encoder_start_streaming(struct saa7164_port *port)
9857615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
9867615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
9877615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int result, ret = 0;
9887615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9897615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
9907615e434aefd95181eae099c4f019e021b024eb6Steven Toth
9911b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	port->done_first_interrupt = 0;
9921b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
9931b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	/* allocate all of the PCIe DMA buffer resources on the fly,
9941b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	 * allowing switching between TS and PS payloads without
9951b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	 * requiring a complete driver reload.
9961b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	 */
9971b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	saa7164_encoder_buffers_alloc(port);
9981b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth
9997615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Configure the encoder with any cache values */
10007615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_encoder(port);
100112d3203e39db306f56611b3f47ba425ca6a409f9Steven Toth	saa7164_api_get_encoder(port);
10027615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10031b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	/* Place the empty buffers on the hardware */
10047615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_buffer_cfg_port(port);
10057615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10067615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Acquire the hardware */
10077615e434aefd95181eae099c4f019e021b024eb6Steven Toth	result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
10087615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
10097615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n",
10107615e434aefd95181eae099c4f019e021b024eb6Steven Toth			__func__, result);
10117615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10127615e434aefd95181eae099c4f019e021b024eb6Steven Toth		/* Stop the hardware, regardless */
10137615e434aefd95181eae099c4f019e021b024eb6Steven Toth		result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
10147615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
10157615e434aefd95181eae099c4f019e021b024eb6Steven Toth			printk(KERN_ERR "%s() acquire/forced stop transition "
10167615e434aefd95181eae099c4f019e021b024eb6Steven Toth				"failed, res = 0x%x\n", __func__, result);
10177615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
10187615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = -EIO;
10197615e434aefd95181eae099c4f019e021b024eb6Steven Toth		goto out;
10207615e434aefd95181eae099c4f019e021b024eb6Steven Toth	} else
10217615e434aefd95181eae099c4f019e021b024eb6Steven Toth		dprintk(DBGLVL_ENC, "%s()   Acquired\n", __func__);
10227615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10237615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Pause the hardware */
10247615e434aefd95181eae099c4f019e021b024eb6Steven Toth	result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
10257615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
10267615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n",
10277615e434aefd95181eae099c4f019e021b024eb6Steven Toth				__func__, result);
10287615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10297615e434aefd95181eae099c4f019e021b024eb6Steven Toth		/* Stop the hardware, regardless */
10307615e434aefd95181eae099c4f019e021b024eb6Steven Toth		result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
10317615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
10327615e434aefd95181eae099c4f019e021b024eb6Steven Toth			printk(KERN_ERR "%s() pause/forced stop transition "
10337615e434aefd95181eae099c4f019e021b024eb6Steven Toth				"failed, res = 0x%x\n", __func__, result);
10347615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
10357615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10367615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = -EIO;
10377615e434aefd95181eae099c4f019e021b024eb6Steven Toth		goto out;
10387615e434aefd95181eae099c4f019e021b024eb6Steven Toth	} else
10397615e434aefd95181eae099c4f019e021b024eb6Steven Toth		dprintk(DBGLVL_ENC, "%s()   Paused\n", __func__);
10407615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10417615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Start the hardware */
10427615e434aefd95181eae099c4f019e021b024eb6Steven Toth	result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN);
10437615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
10447615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_ERR "%s() run transition failed, result = 0x%x\n",
10457615e434aefd95181eae099c4f019e021b024eb6Steven Toth				__func__, result);
10467615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10477615e434aefd95181eae099c4f019e021b024eb6Steven Toth		/* Stop the hardware, regardless */
10487615e434aefd95181eae099c4f019e021b024eb6Steven Toth		result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
10497615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
10507615e434aefd95181eae099c4f019e021b024eb6Steven Toth			printk(KERN_ERR "%s() run/forced stop transition "
10517615e434aefd95181eae099c4f019e021b024eb6Steven Toth				"failed, res = 0x%x\n", __func__, result);
10527615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
10537615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10547615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = -EIO;
10557615e434aefd95181eae099c4f019e021b024eb6Steven Toth	} else
10567615e434aefd95181eae099c4f019e021b024eb6Steven Toth		dprintk(DBGLVL_ENC, "%s()   Running\n", __func__);
10577615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10587615e434aefd95181eae099c4f019e021b024eb6Steven Tothout:
10597615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return ret;
10607615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
10617615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10627615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int fops_open(struct file *file)
10637615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
1064214ce3faacafa3cca2fdd340d18ff35cfe463c2bSteven Toth	struct saa7164_dev *dev;
1065214ce3faacafa3cca2fdd340d18ff35cfe463c2bSteven Toth	struct saa7164_port *port;
106696d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh;
10677615e434aefd95181eae099c4f019e021b024eb6Steven Toth
1068214ce3faacafa3cca2fdd340d18ff35cfe463c2bSteven Toth	port = (struct saa7164_port *)video_get_drvdata(video_devdata(file));
1069214ce3faacafa3cca2fdd340d18ff35cfe463c2bSteven Toth	if (!port)
1070214ce3faacafa3cca2fdd340d18ff35cfe463c2bSteven Toth		return -ENODEV;
10717615e434aefd95181eae099c4f019e021b024eb6Steven Toth
1072214ce3faacafa3cca2fdd340d18ff35cfe463c2bSteven Toth	dev = port->dev;
10737615e434aefd95181eae099c4f019e021b024eb6Steven Toth
1074214ce3faacafa3cca2fdd340d18ff35cfe463c2bSteven Toth	dprintk(DBGLVL_ENC, "%s()\n", __func__);
10757615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10767615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* allocate + initialize per filehandle data */
10777615e434aefd95181eae099c4f019e021b024eb6Steven Toth	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
1078214ce3faacafa3cca2fdd340d18ff35cfe463c2bSteven Toth	if (NULL == fh)
10797615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -ENOMEM;
10807615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10817615e434aefd95181eae099c4f019e021b024eb6Steven Toth	file->private_data = fh;
10827615e434aefd95181eae099c4f019e021b024eb6Steven Toth	fh->port = port;
10837615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10847615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
10857615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
10867615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10877615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic int fops_release(struct file *file)
10887615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
108996d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
10907615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
10917615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
10927615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10937615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s()\n", __func__);
10947615e434aefd95181eae099c4f019e021b024eb6Steven Toth
10957615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Shut device down on last close */
10967615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
10977615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (atomic_dec_return(&port->v4l_reader_count) == 0) {
10987615e434aefd95181eae099c4f019e021b024eb6Steven Toth			/* stop mpeg capture then cancel buffers */
10997615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_encoder_stop_streaming(port);
11007615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
11017615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
11027615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11037615e434aefd95181eae099c4f019e021b024eb6Steven Toth	file->private_data = NULL;
11047615e434aefd95181eae099c4f019e021b024eb6Steven Toth	kfree(fh);
11057615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11067615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
11077615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
11087615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11097615e434aefd95181eae099c4f019e021b024eb6Steven Tothstruct saa7164_user_buffer *saa7164_enc_next_buf(struct saa7164_port *port)
11107615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
11111b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	struct saa7164_user_buffer *ubuf = 0;
11127615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
111312d3203e39db306f56611b3f47ba425ca6a409f9Steven Toth	u32 crc;
11147615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11157615e434aefd95181eae099c4f019e021b024eb6Steven Toth	mutex_lock(&port->dmaqueue_lock);
11167615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (!list_empty(&port->list_buf_used.list)) {
11171b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		ubuf = list_first_entry(&port->list_buf_used.list,
11187615e434aefd95181eae099c4f019e021b024eb6Steven Toth			struct saa7164_user_buffer, list);
111912d3203e39db306f56611b3f47ba425ca6a409f9Steven Toth
11201b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth		if (crc_checking) {
11211b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			crc = crc32(0, ubuf->data, ubuf->actual_size);
11221b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			if (crc != ubuf->crc) {
1123bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth				printk(KERN_ERR
1124bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth		"%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n",
1125bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth					__func__,
11261b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth					ubuf, ubuf->crc, crc);
11271b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth			}
112812d3203e39db306f56611b3f47ba425ca6a409f9Steven Toth		}
112912d3203e39db306f56611b3f47ba425ca6a409f9Steven Toth
11307615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
11317615e434aefd95181eae099c4f019e021b024eb6Steven Toth	mutex_unlock(&port->dmaqueue_lock);
11327615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11331b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	dprintk(DBGLVL_ENC, "%s() returns %p\n", __func__, ubuf);
11347615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11351b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	return ubuf;
11367615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
11377615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11387615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic ssize_t fops_read(struct file *file, char __user *buffer,
11397615e434aefd95181eae099c4f019e021b024eb6Steven Toth	size_t count, loff_t *pos)
11407615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
114196d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_encoder_fh *fh = file->private_data;
11427615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
11437615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_user_buffer *ubuf = NULL;
11447615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
1145f20a07d431c3c516c37beff9638f70c8e059a3fcGavin Hurlbut	int ret = 0;
11467615e434aefd95181eae099c4f019e021b024eb6Steven Toth	int rem, cnt;
11477615e434aefd95181eae099c4f019e021b024eb6Steven Toth	u8 *p;
11487615e434aefd95181eae099c4f019e021b024eb6Steven Toth
114958acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth	port->last_read_msecs_diff = port->last_read_msecs;
115058acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth	port->last_read_msecs = jiffies_to_msecs(jiffies);
115158acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth	port->last_read_msecs_diff = port->last_read_msecs -
115258acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth		port->last_read_msecs_diff;
115358acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth
115458acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth	saa7164_histogram_update(&port->read_interval,
115558acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth		port->last_read_msecs_diff);
115658acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth
115746eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth	if (*pos) {
115846eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth		printk(KERN_ERR "%s() ESPIPE\n", __func__);
11597615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -ESPIPE;
116046eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth	}
11617615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11627615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
11637615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (atomic_inc_return(&port->v4l_reader_count) == 1) {
11647615e434aefd95181eae099c4f019e021b024eb6Steven Toth
116546eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth			if (saa7164_encoder_initialize(port) < 0) {
116646eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth				printk(KERN_ERR "%s() EINVAL\n", __func__);
11677615e434aefd95181eae099c4f019e021b024eb6Steven Toth				return -EINVAL;
116846eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth			}
11697615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11707615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_encoder_start_streaming(port);
11717615e434aefd95181eae099c4f019e021b024eb6Steven Toth			msleep(200);
11727615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
11737615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
11747615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11757615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* blocking wait for buffer */
11767615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if ((file->f_flags & O_NONBLOCK) == 0) {
11777615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (wait_event_interruptible(port->wait_read,
11787615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_enc_next_buf(port))) {
117946eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth				printk(KERN_ERR "%s() ERESTARTSYS\n", __func__);
11807615e434aefd95181eae099c4f019e021b024eb6Steven Toth				return -ERESTARTSYS;
11817615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
11827615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
11837615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11847615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Pull the first buffer from the used list */
11857615e434aefd95181eae099c4f019e021b024eb6Steven Toth	ubuf = saa7164_enc_next_buf(port);
11867615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11877615e434aefd95181eae099c4f019e021b024eb6Steven Toth	while ((count > 0) && ubuf) {
11887615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11897615e434aefd95181eae099c4f019e021b024eb6Steven Toth		/* set remaining bytes to copy */
11907615e434aefd95181eae099c4f019e021b024eb6Steven Toth		rem = ubuf->actual_size - ubuf->pos;
11917615e434aefd95181eae099c4f019e021b024eb6Steven Toth		cnt = rem > count ? count : rem;
11927615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11937615e434aefd95181eae099c4f019e021b024eb6Steven Toth		p = ubuf->data + ubuf->pos;
11947615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11957615e434aefd95181eae099c4f019e021b024eb6Steven Toth		dprintk(DBGLVL_ENC,
11967615e434aefd95181eae099c4f019e021b024eb6Steven Toth			"%s() count=%d cnt=%d rem=%d buf=%p buf->pos=%d\n",
11977615e434aefd95181eae099c4f019e021b024eb6Steven Toth			__func__, (int)count, cnt, rem, ubuf, ubuf->pos);
11987615e434aefd95181eae099c4f019e021b024eb6Steven Toth
11997615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (copy_to_user(buffer, p, cnt)) {
12007615e434aefd95181eae099c4f019e021b024eb6Steven Toth			printk(KERN_ERR "%s() copy_to_user failed\n", __func__);
120146eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth			if (!ret) {
120246eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth				printk(KERN_ERR "%s() EFAULT\n", __func__);
12037615e434aefd95181eae099c4f019e021b024eb6Steven Toth				ret = -EFAULT;
120446eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth			}
12057615e434aefd95181eae099c4f019e021b024eb6Steven Toth			goto err;
12067615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
12077615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12087615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ubuf->pos += cnt;
12097615e434aefd95181eae099c4f019e021b024eb6Steven Toth		count -= cnt;
12107615e434aefd95181eae099c4f019e021b024eb6Steven Toth		buffer += cnt;
12117615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret += cnt;
12127615e434aefd95181eae099c4f019e021b024eb6Steven Toth
1213bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth		if (ubuf->pos > ubuf->actual_size)
121446eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth			printk(KERN_ERR "read() pos > actual, huh?\n");
121546eeb8dd30d3651e6ea55c2e60594206cd591d79Steven Toth
12167615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (ubuf->pos == ubuf->actual_size) {
12177615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12187615e434aefd95181eae099c4f019e021b024eb6Steven Toth			/* finished with current buffer, take next buffer */
12197615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12207615e434aefd95181eae099c4f019e021b024eb6Steven Toth			/* Requeue the buffer on the free list */
12217615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ubuf->pos = 0;
12227615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12237615e434aefd95181eae099c4f019e021b024eb6Steven Toth			mutex_lock(&port->dmaqueue_lock);
12247615e434aefd95181eae099c4f019e021b024eb6Steven Toth			list_move_tail(&ubuf->list, &port->list_buf_free.list);
12257615e434aefd95181eae099c4f019e021b024eb6Steven Toth			mutex_unlock(&port->dmaqueue_lock);
12267615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12277615e434aefd95181eae099c4f019e021b024eb6Steven Toth			/* Dequeue next */
12287615e434aefd95181eae099c4f019e021b024eb6Steven Toth			if ((file->f_flags & O_NONBLOCK) == 0) {
12297615e434aefd95181eae099c4f019e021b024eb6Steven Toth				if (wait_event_interruptible(port->wait_read,
12307615e434aefd95181eae099c4f019e021b024eb6Steven Toth					saa7164_enc_next_buf(port))) {
12317615e434aefd95181eae099c4f019e021b024eb6Steven Toth						break;
12327615e434aefd95181eae099c4f019e021b024eb6Steven Toth				}
12337615e434aefd95181eae099c4f019e021b024eb6Steven Toth			}
12347615e434aefd95181eae099c4f019e021b024eb6Steven Toth			ubuf = saa7164_enc_next_buf(port);
12357615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
12367615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
12377615e434aefd95181eae099c4f019e021b024eb6Steven Totherr:
1238bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth	if (!ret && !ubuf)
12397615e434aefd95181eae099c4f019e021b024eb6Steven Toth		ret = -EAGAIN;
12407615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12417615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return ret;
12427615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
12437615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12447615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic unsigned int fops_poll(struct file *file, poll_table *wait)
12457615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
1246bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth	struct saa7164_encoder_fh *fh =
1247bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth		(struct saa7164_encoder_fh *)file->private_data;
12487615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port = fh->port;
12497615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_user_buffer *ubuf;
12507615e434aefd95181eae099c4f019e021b024eb6Steven Toth	unsigned int mask = 0;
12517615e434aefd95181eae099c4f019e021b024eb6Steven Toth
125258acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth	port->last_poll_msecs_diff = port->last_poll_msecs;
125358acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth	port->last_poll_msecs = jiffies_to_msecs(jiffies);
125458acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth	port->last_poll_msecs_diff = port->last_poll_msecs -
125558acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth		port->last_poll_msecs_diff;
125658acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth
125758acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth	saa7164_histogram_update(&port->poll_interval,
125858acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth		port->last_poll_msecs_diff);
125958acca1056434dbbbcb3f1aacd759f1039a3169dSteven Toth
1260bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth	if (!video_is_registered(port->v4l_device))
12617615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EIO;
12627615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12637615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
12647615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (atomic_inc_return(&port->v4l_reader_count) == 1) {
12657615e434aefd95181eae099c4f019e021b024eb6Steven Toth			if (saa7164_encoder_initialize(port) < 0)
12667615e434aefd95181eae099c4f019e021b024eb6Steven Toth				return -EINVAL;
12677615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_encoder_start_streaming(port);
12687615e434aefd95181eae099c4f019e021b024eb6Steven Toth			msleep(200);
12697615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
12707615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
12717615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12727615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* blocking wait for buffer */
12737615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if ((file->f_flags & O_NONBLOCK) == 0) {
12747615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (wait_event_interruptible(port->wait_read,
12757615e434aefd95181eae099c4f019e021b024eb6Steven Toth			saa7164_enc_next_buf(port))) {
12767615e434aefd95181eae099c4f019e021b024eb6Steven Toth				return -ERESTARTSYS;
12777615e434aefd95181eae099c4f019e021b024eb6Steven Toth		}
12787615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
12797615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12807615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Pull the first buffer from the used list */
12817615e434aefd95181eae099c4f019e021b024eb6Steven Toth	ubuf = list_first_entry(&port->list_buf_used.list,
12827615e434aefd95181eae099c4f019e021b024eb6Steven Toth		struct saa7164_user_buffer, list);
12837615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12847615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (ubuf)
12857615e434aefd95181eae099c4f019e021b024eb6Steven Toth		mask |= POLLIN | POLLRDNORM;
12867615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12877615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return mask;
12887615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
12897615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12907615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic const struct v4l2_file_operations mpeg_fops = {
12917615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.owner		= THIS_MODULE,
12927615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.open		= fops_open,
12937615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.release	= fops_release,
12947615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.read		= fops_read,
12957615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.poll		= fops_poll,
12967615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.unlocked_ioctl	= video_ioctl2,
12977615e434aefd95181eae099c4f019e021b024eb6Steven Toth};
12987615e434aefd95181eae099c4f019e021b024eb6Steven Toth
12997615e434aefd95181eae099c4f019e021b024eb6Steven Tothint saa7164_g_chip_ident(struct file *file, void *fh,
13007615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_dbg_chip_ident *chip)
13017615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
130296d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port;
13037615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
13047615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s()\n", __func__);
13057615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13067615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
13077615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
13087615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13097615e434aefd95181eae099c4f019e021b024eb6Steven Tothint saa7164_g_register(struct file *file, void *fh,
13107615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_dbg_register *reg)
13117615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
131296d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port;
13137615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
13147615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s()\n", __func__);
13157615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13167615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (!capable(CAP_SYS_ADMIN))
13177615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EPERM;
13187615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13197615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
13207615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
13217615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13227615e434aefd95181eae099c4f019e021b024eb6Steven Tothint saa7164_s_register(struct file *file, void *fh,
13237615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct v4l2_dbg_register *reg)
13247615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
132596d8420d17809f0b090da3dddb26a3625b1b6e7aSteven Toth	struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port;
13267615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
13277615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s()\n", __func__);
13287615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13297615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (!capable(CAP_SYS_ADMIN))
13307615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return -EPERM;
13317615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13327615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return 0;
13337615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
13347615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13357615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
13367615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_s_std		 = vidioc_s_std,
13377615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_enum_input	 = vidioc_enum_input,
13387615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_g_input		 = vidioc_g_input,
13397615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_s_input		 = vidioc_s_input,
13407615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_g_tuner		 = vidioc_g_tuner,
13417615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_s_tuner		 = vidioc_s_tuner,
13427615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_g_frequency	 = vidioc_g_frequency,
13437615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_s_frequency	 = vidioc_s_frequency,
13447615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_s_ctrl		 = vidioc_s_ctrl,
13457615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_g_ctrl		 = vidioc_g_ctrl,
13467615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_querycap	 = vidioc_querycap,
13477615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
13487615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_g_fmt_vid_cap	 = vidioc_g_fmt_vid_cap,
13497615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_try_fmt_vid_cap	 = vidioc_try_fmt_vid_cap,
13507615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_s_fmt_vid_cap	 = vidioc_s_fmt_vid_cap,
13517615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_g_ext_ctrls	 = vidioc_g_ext_ctrls,
13527615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_s_ext_ctrls	 = vidioc_s_ext_ctrls,
13537615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_try_ext_ctrls	 = vidioc_try_ext_ctrls,
13547615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_log_status	 = vidioc_log_status,
13557615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_queryctrl	 = vidioc_queryctrl,
13567615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_g_chip_ident	 = saa7164_g_chip_ident,
13577615e434aefd95181eae099c4f019e021b024eb6Steven Toth#ifdef CONFIG_VIDEO_ADV_DEBUG
13587615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_g_register	 = saa7164_g_register,
13597615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.vidioc_s_register	 = saa7164_s_register,
13607615e434aefd95181eae099c4f019e021b024eb6Steven Toth#endif
13617615e434aefd95181eae099c4f019e021b024eb6Steven Toth};
13627615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13637615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic struct video_device saa7164_mpeg_template = {
13647615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.name          = "saa7164",
13657615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.fops          = &mpeg_fops,
13667615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.ioctl_ops     = &mpeg_ioctl_ops,
13677615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.minor         = -1,
13687615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.tvnorms       = SAA7164_NORMS,
13697615e434aefd95181eae099c4f019e021b024eb6Steven Toth	.current_norm  = V4L2_STD_NTSC_M,
13707615e434aefd95181eae099c4f019e021b024eb6Steven Toth};
13717615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13727615e434aefd95181eae099c4f019e021b024eb6Steven Tothstatic struct video_device *saa7164_encoder_alloc(
13737615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_port *port,
13747615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct pci_dev *pci,
13757615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct video_device *template,
13767615e434aefd95181eae099c4f019e021b024eb6Steven Toth	char *type)
13777615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
13787615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct video_device *vfd;
13797615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
13807615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13817615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s()\n", __func__);
13827615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13837615e434aefd95181eae099c4f019e021b024eb6Steven Toth	vfd = video_device_alloc();
13847615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (NULL == vfd)
13857615e434aefd95181eae099c4f019e021b024eb6Steven Toth		return NULL;
13867615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13877615e434aefd95181eae099c4f019e021b024eb6Steven Toth	*vfd = *template;
13887615e434aefd95181eae099c4f019e021b024eb6Steven Toth	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
13897615e434aefd95181eae099c4f019e021b024eb6Steven Toth		type, saa7164_boards[dev->board].name);
13907615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13917615e434aefd95181eae099c4f019e021b024eb6Steven Toth	vfd->parent  = &pci->dev;
13927615e434aefd95181eae099c4f019e021b024eb6Steven Toth	vfd->release = video_device_release;
13937615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return vfd;
13947615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
13957615e434aefd95181eae099c4f019e021b024eb6Steven Toth
13967615e434aefd95181eae099c4f019e021b024eb6Steven Tothint saa7164_encoder_register(struct saa7164_port *port)
13977615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
13987615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
13991b0e8e46297a214336d85c8e278a8a004f97889eSteven Toth	int result = -ENODEV;
14007615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14017615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s()\n", __func__);
14027615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14037615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (port->type != SAA7164_MPEG_ENCODER)
14047615e434aefd95181eae099c4f019e021b024eb6Steven Toth		BUG();
14057615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14067615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Sanity check that the PCI configuration space is active */
14077615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (port->hwcfg.BARLocation == 0) {
14087615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_ERR "%s() failed "
14097615e434aefd95181eae099c4f019e021b024eb6Steven Toth		       "(errno = %d), NO PCI configuration\n",
14107615e434aefd95181eae099c4f019e021b024eb6Steven Toth			__func__, result);
14117615e434aefd95181eae099c4f019e021b024eb6Steven Toth		result = -ENOMEM;
14127615e434aefd95181eae099c4f019e021b024eb6Steven Toth		goto failed;
14137615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
14147615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14157615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Establish encoder defaults here */
14167615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Set default TV standard */
14177615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->encodernorm = saa7164_tvnorms[0];
14187615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->width = 720;
14197615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->mux_input = 1; /* Composite */
14207615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->video_format = EU_VIDEO_FORMAT_MPEG_2;
14217615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->audio_format = 0;
14227615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->video_resolution = 0;
14237615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->ctl_brightness = 127;
14247615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->ctl_contrast = 66;
14257615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->ctl_hue = 128;
14267615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->ctl_saturation = 62;
14277615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->ctl_sharpness = 8;
14287615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->encoder_params.bitrate = ENCODER_DEF_BITRATE;
1429968b11b20143036098a7013817a15615a54383d3Steven Toth	port->encoder_params.bitrate_peak = ENCODER_DEF_BITRATE;
14305fa56ccdacc54f5f694141c1a74f781cf77874bbSteven Toth	port->encoder_params.bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
14317615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->encoder_params.stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS;
14327615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->encoder_params.ctl_mute = 0;
14337615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->encoder_params.ctl_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3;
14343ed43cf96aa9fc565d74855649d8cee0def67f38Steven Toth	port->encoder_params.refdist = 1;
14355fa56ccdacc54f5f694141c1a74f781cf77874bbSteven Toth	port->encoder_params.gop_size = SAA7164_ENCODER_DEFAULT_GOP_SIZE;
14367615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14377615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (port->encodernorm.id & V4L2_STD_525_60)
14387615e434aefd95181eae099c4f019e021b024eb6Steven Toth		port->height = 480;
14397615e434aefd95181eae099c4f019e021b024eb6Steven Toth	else
14407615e434aefd95181eae099c4f019e021b024eb6Steven Toth		port->height = 576;
14417615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14427615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Allocate and register the video device node */
14437615e434aefd95181eae099c4f019e021b024eb6Steven Toth	port->v4l_device = saa7164_encoder_alloc(port,
14447615e434aefd95181eae099c4f019e021b024eb6Steven Toth		dev->pci, &saa7164_mpeg_template, "mpeg");
14457615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14467615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (port->v4l_device == NULL) {
14477615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_INFO "%s: can't allocate mpeg device\n",
14487615e434aefd95181eae099c4f019e021b024eb6Steven Toth			dev->name);
14497615e434aefd95181eae099c4f019e021b024eb6Steven Toth		result = -ENOMEM;
14507615e434aefd95181eae099c4f019e021b024eb6Steven Toth		goto failed;
14517615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
14527615e434aefd95181eae099c4f019e021b024eb6Steven Toth
1453214ce3faacafa3cca2fdd340d18ff35cfe463c2bSteven Toth	video_set_drvdata(port->v4l_device, port);
14547615e434aefd95181eae099c4f019e021b024eb6Steven Toth	result = video_register_device(port->v4l_device,
14557615e434aefd95181eae099c4f019e021b024eb6Steven Toth		VFL_TYPE_GRABBER, -1);
14567615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (result < 0) {
14577615e434aefd95181eae099c4f019e021b024eb6Steven Toth		printk(KERN_INFO "%s: can't register mpeg device\n",
14587615e434aefd95181eae099c4f019e021b024eb6Steven Toth			dev->name);
14597615e434aefd95181eae099c4f019e021b024eb6Steven Toth		/* TODO: We're going to leak here if we don't dealloc
14607615e434aefd95181eae099c4f019e021b024eb6Steven Toth		 The buffers above. The unreg function can't deal wit it.
14617615e434aefd95181eae099c4f019e021b024eb6Steven Toth		*/
14627615e434aefd95181eae099c4f019e021b024eb6Steven Toth		goto failed;
14637615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
14647615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14657615e434aefd95181eae099c4f019e021b024eb6Steven Toth	printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
14667615e434aefd95181eae099c4f019e021b024eb6Steven Toth		dev->name, port->v4l_device->num);
14677615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14687615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Configure the hardware defaults */
14697615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_videomux(port);
14707615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_usercontrol(port, PU_BRIGHTNESS_CONTROL);
14717615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL);
14727615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_usercontrol(port, PU_HUE_CONTROL);
14737615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_usercontrol(port, PU_SATURATION_CONTROL);
14747615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL);
14757615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_audio_mute(port, 0);
14767615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_audio_volume(port, 20);
14777615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_aspect_ratio(port);
14787615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14797615e434aefd95181eae099c4f019e021b024eb6Steven Toth	/* Disable audio standard detection, it's buggy */
14807615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_audio_detection(port, 0);
14817615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14827615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_set_encoder(port);
14837615e434aefd95181eae099c4f019e021b024eb6Steven Toth	saa7164_api_get_encoder(port);
14847615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14857615e434aefd95181eae099c4f019e021b024eb6Steven Toth	result = 0;
14867615e434aefd95181eae099c4f019e021b024eb6Steven Tothfailed:
14877615e434aefd95181eae099c4f019e021b024eb6Steven Toth	return result;
14887615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
14897615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14907615e434aefd95181eae099c4f019e021b024eb6Steven Tothvoid saa7164_encoder_unregister(struct saa7164_port *port)
14917615e434aefd95181eae099c4f019e021b024eb6Steven Toth{
14927615e434aefd95181eae099c4f019e021b024eb6Steven Toth	struct saa7164_dev *dev = port->dev;
14937615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14947615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
14957615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14967615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (port->type != SAA7164_MPEG_ENCODER)
14977615e434aefd95181eae099c4f019e021b024eb6Steven Toth		BUG();
14987615e434aefd95181eae099c4f019e021b024eb6Steven Toth
14997615e434aefd95181eae099c4f019e021b024eb6Steven Toth	if (port->v4l_device) {
15007615e434aefd95181eae099c4f019e021b024eb6Steven Toth		if (port->v4l_device->minor != -1)
15017615e434aefd95181eae099c4f019e021b024eb6Steven Toth			video_unregister_device(port->v4l_device);
15027615e434aefd95181eae099c4f019e021b024eb6Steven Toth		else
15037615e434aefd95181eae099c4f019e021b024eb6Steven Toth			video_device_release(port->v4l_device);
15047615e434aefd95181eae099c4f019e021b024eb6Steven Toth
15057615e434aefd95181eae099c4f019e021b024eb6Steven Toth		port->v4l_device = NULL;
15067615e434aefd95181eae099c4f019e021b024eb6Steven Toth	}
15077615e434aefd95181eae099c4f019e021b024eb6Steven Toth
15087615e434aefd95181eae099c4f019e021b024eb6Steven Toth	dprintk(DBGLVL_ENC, "%s(port=%d) done\n", __func__, port->nr);
15097615e434aefd95181eae099c4f019e021b024eb6Steven Toth}
15107615e434aefd95181eae099c4f019e021b024eb6Steven Toth
1511