Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
new file mode 100644
index 0000000..e577a06
--- /dev/null
+++ b/drivers/media/video/saa7134/Makefile
@@ -0,0 +1,11 @@
+
+saa7134-objs :=	saa7134-cards.o saa7134-core.o saa7134-i2c.o	\
+		saa7134-oss.o saa7134-ts.o saa7134-tvaudio.o	\
+		saa7134-vbi.o saa7134-video.o saa7134-input.o
+
+obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o saa6752hs.o
+obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
+
+EXTRA_CFLAGS += -I$(src)/..
+EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/frontends
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
new file mode 100644
index 0000000..cee1358
--- /dev/null
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -0,0 +1,543 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/i2c.h>
+#include <linux/types.h>
+#include <linux/videodev.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+
+#include <media/id.h>
+
+#define MPEG_VIDEO_TARGET_BITRATE_MAX  27000
+#define MPEG_VIDEO_MAX_BITRATE_MAX     27000
+#define MPEG_TOTAL_TARGET_BITRATE_MAX  27000
+#define MPEG_PID_MAX ((1 << 14) - 1)
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END};
+static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
+I2C_CLIENT_INSMOD;
+
+MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder");
+MODULE_AUTHOR("Andrew de Quincey");
+MODULE_LICENSE("GPL");
+
+static struct i2c_driver driver;
+static struct i2c_client client_template;
+
+struct saa6752hs_state {
+	struct i2c_client             client;
+	struct v4l2_mpeg_compression  params;
+};
+
+enum saa6752hs_command {
+	SAA6752HS_COMMAND_RESET = 0,
+    	SAA6752HS_COMMAND_STOP = 1,
+    	SAA6752HS_COMMAND_START = 2,
+    	SAA6752HS_COMMAND_PAUSE = 3,
+    	SAA6752HS_COMMAND_RECONFIGURE = 4,
+    	SAA6752HS_COMMAND_SLEEP = 5,
+	SAA6752HS_COMMAND_RECONFIGURE_FORCE = 6,
+
+	SAA6752HS_COMMAND_MAX
+};
+
+/* ---------------------------------------------------------------------- */
+
+static u8 PAT[] = {
+	0xc2, // i2c register
+	0x00, // table number for encoder
+
+	0x47, // sync
+	0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0)
+	0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0)
+
+	0x00, // PSI pointer to start of table
+
+	0x00, // tid(0)
+	0xb0, 0x0d, // section_syntax_indicator(1), section_length(13)
+
+	0x00, 0x01, // transport_stream_id(1)
+
+	0xc1, // version_number(0), current_next_indicator(1)
+
+	0x00, 0x00, // section_number(0), last_section_number(0)
+
+	0x00, 0x01, // program_number(1)
+
+	0xe0, 0x00, // PMT PID
+
+	0x00, 0x00, 0x00, 0x00 // CRC32
+};
+
+static u8 PMT[] = {
+	0xc2, // i2c register
+	0x01, // table number for encoder
+
+	0x47, // sync
+	0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid
+	0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0)
+
+	0x00, // PSI pointer to start of table
+
+	0x02, // tid(2)
+	0xb0, 0x17, // section_syntax_indicator(1), section_length(23)
+
+	0x00, 0x01, // program_number(1)
+
+	0xc1, // version_number(0), current_next_indicator(1)
+
+	0x00, 0x00, // section_number(0), last_section_number(0)
+
+	0xe0, 0x00, // PCR_PID
+
+	0xf0, 0x00, // program_info_length(0)
+
+	0x02, 0xe0, 0x00, 0xf0, 0x00, // video stream type(2), pid
+	0x04, 0xe0, 0x00, 0xf0, 0x00, // audio stream type(4), pid
+
+	0x00, 0x00, 0x00, 0x00 // CRC32
+};
+
+static struct v4l2_mpeg_compression param_defaults =
+{
+	.st_type         = V4L2_MPEG_TS_2,
+	.st_bitrate      = {
+		.mode    = V4L2_BITRATE_CBR,
+		.target  = 7000,
+	},
+
+	.ts_pid_pmt      = 16,
+	.ts_pid_video    = 260,
+	.ts_pid_audio    = 256,
+	.ts_pid_pcr      = 259,
+
+	.vi_type         = V4L2_MPEG_VI_2,
+	.vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3,
+	.vi_bitrate      = {
+		.mode    = V4L2_BITRATE_VBR,
+		.target  = 4000,
+		.max     = 6000,
+	},
+
+	.au_type         = V4L2_MPEG_AU_2_II,
+	.au_bitrate      = {
+		.mode    = V4L2_BITRATE_CBR,
+		.target  = 256,
+	},
+
+#if 0
+	/* FIXME: size? via S_FMT? */
+	.video_format = MPEG_VIDEO_FORMAT_D1,
+#endif
+};
+
+/* ---------------------------------------------------------------------- */
+
+static int saa6752hs_chip_command(struct i2c_client* client,
+				  enum saa6752hs_command command)
+{
+	unsigned char buf[3];
+	unsigned long timeout;
+	int status = 0;
+
+	// execute the command
+	switch(command) {
+  	case SAA6752HS_COMMAND_RESET:
+  		buf[0] = 0x00;
+		break;
+
+	case SAA6752HS_COMMAND_STOP:
+	  	buf[0] = 0x03;
+		break;
+
+	case SAA6752HS_COMMAND_START:
+  		buf[0] = 0x02;
+		break;
+
+	case SAA6752HS_COMMAND_PAUSE:
+  		buf[0] = 0x04;
+		break;
+
+	case SAA6752HS_COMMAND_RECONFIGURE:
+		buf[0] = 0x05;
+		break;
+
+  	case SAA6752HS_COMMAND_SLEEP:
+  		buf[0] = 0x06;
+		break;
+
+  	case SAA6752HS_COMMAND_RECONFIGURE_FORCE:
+		buf[0] = 0x07;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+  	// set it and wait for it to be so
+	i2c_master_send(client, buf, 1);
+	timeout = jiffies + HZ * 3;
+	for (;;) {
+		// get the current status
+		buf[0] = 0x10;
+	  	i2c_master_send(client, buf, 1);
+		i2c_master_recv(client, buf, 1);
+
+		if (!(buf[0] & 0x20))
+			break;
+		if (time_after(jiffies,timeout)) {
+			status = -ETIMEDOUT;
+			break;
+		}
+
+		// wait a bit
+		msleep(10);
+	}
+
+	// delay a bit to let encoder settle
+	msleep(50);
+
+	// done
+  	return status;
+}
+
+
+static int saa6752hs_set_bitrate(struct i2c_client* client,
+				 struct v4l2_mpeg_compression* params)
+{
+  	u8 buf[3];
+
+	// set the bitrate mode
+	buf[0] = 0x71;
+	buf[1] = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ? 0 : 1;
+	i2c_master_send(client, buf, 2);
+
+	// set the video bitrate
+	if (params->vi_bitrate.mode == V4L2_BITRATE_VBR) {
+		// set the target bitrate
+		buf[0] = 0x80;
+	    	buf[1] = params->vi_bitrate.target >> 8;
+	  	buf[2] = params->vi_bitrate.target & 0xff;
+		i2c_master_send(client, buf, 3);
+
+		// set the max bitrate
+		buf[0] = 0x81;
+	    	buf[1] = params->vi_bitrate.max >> 8;
+	  	buf[2] = params->vi_bitrate.max & 0xff;
+		i2c_master_send(client, buf, 3);
+	} else {
+		// set the target bitrate (no max bitrate for CBR)
+  		buf[0] = 0x81;
+	    	buf[1] = params->vi_bitrate.target >> 8;
+	  	buf[2] = params->vi_bitrate.target & 0xff;
+		i2c_master_send(client, buf, 3);
+	}
+
+	// set the audio bitrate
+ 	buf[0] = 0x94;
+	buf[1] = (256 == params->au_bitrate.target) ? 0 : 1;
+	i2c_master_send(client, buf, 2);
+
+	// set the total bitrate
+	buf[0] = 0xb1;
+  	buf[1] = params->st_bitrate.target >> 8;
+  	buf[2] = params->st_bitrate.target & 0xff;
+	i2c_master_send(client, buf, 3);
+
+	// return success
+	return 0;
+}
+
+
+static void saa6752hs_set_params(struct i2c_client* client,
+				 struct v4l2_mpeg_compression* params)
+{
+	struct saa6752hs_state *h = i2c_get_clientdata(client);
+
+	/* check PIDs */
+	if (params->ts_pid_pmt <= MPEG_PID_MAX)
+		h->params.ts_pid_pmt = params->ts_pid_pmt;
+	if (params->ts_pid_pcr <= MPEG_PID_MAX)
+		h->params.ts_pid_pcr = params->ts_pid_pcr;
+	if (params->ts_pid_video <= MPEG_PID_MAX)
+		h->params.ts_pid_video = params->ts_pid_video;
+	if (params->ts_pid_audio <= MPEG_PID_MAX)
+		h->params.ts_pid_audio = params->ts_pid_audio;
+
+	/* check bitrate parameters */
+	if ((params->vi_bitrate.mode == V4L2_BITRATE_CBR) ||
+	    (params->vi_bitrate.mode == V4L2_BITRATE_VBR))
+		h->params.vi_bitrate.mode = params->vi_bitrate.mode;
+	if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
+		h->params.st_bitrate.target = params->st_bitrate.target;
+	if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
+		h->params.vi_bitrate.target = params->vi_bitrate.target;
+	if (params->vi_bitrate.mode == V4L2_BITRATE_VBR)
+		h->params.vi_bitrate.max = params->vi_bitrate.max;
+	if (params->au_bitrate.mode != V4L2_BITRATE_NONE)
+		h->params.au_bitrate.target = params->au_bitrate.target;
+
+	/* aspect ratio */
+	if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3 ||
+	    params->vi_aspect_ratio == V4L2_MPEG_ASPECT_16_9)
+		h->params.vi_aspect_ratio = params->vi_aspect_ratio;
+
+	/* range checks */
+	if (h->params.st_bitrate.target > MPEG_TOTAL_TARGET_BITRATE_MAX)
+		h->params.st_bitrate.target = MPEG_TOTAL_TARGET_BITRATE_MAX;
+	if (h->params.vi_bitrate.target > MPEG_VIDEO_TARGET_BITRATE_MAX)
+		h->params.vi_bitrate.target = MPEG_VIDEO_TARGET_BITRATE_MAX;
+	if (h->params.vi_bitrate.max > MPEG_VIDEO_MAX_BITRATE_MAX)
+		h->params.vi_bitrate.max = MPEG_VIDEO_MAX_BITRATE_MAX;
+	if (h->params.au_bitrate.target <= 256)
+		h->params.au_bitrate.target = 256;
+	else
+		h->params.au_bitrate.target = 384;
+}
+
+static int saa6752hs_init(struct i2c_client* client)
+{
+	unsigned char buf[9], buf2[4];
+	struct saa6752hs_state *h;
+	u32 crc;
+	unsigned char localPAT[256];
+	unsigned char localPMT[256];
+
+	h = i2c_get_clientdata(client);
+
+	// Set video format - must be done first as it resets other settings
+	buf[0] = 0x41;
+	buf[1] = 0 /* MPEG_VIDEO_FORMAT_D1 */;
+	i2c_master_send(client, buf, 2);
+
+        // set bitrate
+        saa6752hs_set_bitrate(client, &h->params);
+
+	// Set GOP structure {3, 13}
+	buf[0] = 0x72;
+	buf[1] = 0x03;
+	buf[2] = 0x0D;
+	i2c_master_send(client,buf,3);
+
+    	// Set minimum Q-scale {4}
+	buf[0] = 0x82;
+	buf[1] = 0x04;
+	i2c_master_send(client,buf,2);
+
+    	// Set maximum Q-scale {12}
+	buf[0] = 0x83;
+	buf[1] = 0x0C;
+	i2c_master_send(client,buf,2);
+
+    	// Set Output Protocol
+	buf[0] = 0xD0;
+	buf[1] = 0x81;
+	i2c_master_send(client,buf,2);
+
+    	// Set video output stream format {TS}
+	buf[0] = 0xB0;
+	buf[1] = 0x05;
+	i2c_master_send(client,buf,2);
+
+	/* compute PAT */
+	memcpy(localPAT, PAT, sizeof(PAT));
+	localPAT[17] = 0xe0 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
+	localPAT[18] = h->params.ts_pid_pmt & 0xff;
+	crc = crc32_be(~0, &localPAT[7], sizeof(PAT) - 7 - 4);
+	localPAT[sizeof(PAT) - 4] = (crc >> 24) & 0xFF;
+	localPAT[sizeof(PAT) - 3] = (crc >> 16) & 0xFF;
+	localPAT[sizeof(PAT) - 2] = (crc >> 8) & 0xFF;
+	localPAT[sizeof(PAT) - 1] = crc & 0xFF;
+
+	/* compute PMT */
+      	memcpy(localPMT, PMT, sizeof(PMT));
+   	localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
+   	localPMT[4] = h->params.ts_pid_pmt & 0xff;
+	localPMT[15] = 0xE0 | ((h->params.ts_pid_pcr >> 8) & 0x0F);
+	localPMT[16] = h->params.ts_pid_pcr & 0xFF;
+	localPMT[20] = 0xE0 | ((h->params.ts_pid_video >> 8) & 0x0F);
+	localPMT[21] = h->params.ts_pid_video & 0xFF;
+	localPMT[25] = 0xE0 | ((h->params.ts_pid_audio >> 8) & 0x0F);
+	localPMT[26] = h->params.ts_pid_audio & 0xFF;
+	crc = crc32_be(~0, &localPMT[7], sizeof(PMT) - 7 - 4);
+	localPMT[sizeof(PMT) - 4] = (crc >> 24) & 0xFF;
+	localPMT[sizeof(PMT) - 3] = (crc >> 16) & 0xFF;
+	localPMT[sizeof(PMT) - 2] = (crc >> 8) & 0xFF;
+	localPMT[sizeof(PMT) - 1] = crc & 0xFF;
+
+    	// Set Audio PID
+	buf[0] = 0xC1;
+	buf[1] = (h->params.ts_pid_audio >> 8) & 0xFF;
+	buf[2] = h->params.ts_pid_audio & 0xFF;
+	i2c_master_send(client,buf,3);
+
+	// Set Video PID
+	buf[0] = 0xC0;
+	buf[1] = (h->params.ts_pid_video >> 8) & 0xFF;
+	buf[2] = h->params.ts_pid_video & 0xFF;
+	i2c_master_send(client,buf,3);
+
+ 	// Set PCR PID
+	buf[0] = 0xC4;
+	buf[1] = (h->params.ts_pid_pcr >> 8) & 0xFF;
+	buf[2] = h->params.ts_pid_pcr & 0xFF;
+	i2c_master_send(client,buf,3);
+
+	// Send SI tables
+	i2c_master_send(client,localPAT,sizeof(PAT));
+	i2c_master_send(client,localPMT,sizeof(PMT));
+
+	// mute then unmute audio. This removes buzzing artefacts
+	buf[0] = 0xa4;
+	buf[1] = 1;
+	i2c_master_send(client, buf, 2);
+  	buf[1] = 0;
+	i2c_master_send(client, buf, 2);
+
+	// start it going
+	saa6752hs_chip_command(client, SAA6752HS_COMMAND_START);
+
+	// readout current state
+	buf[0] = 0xE1;
+	buf[1] = 0xA7;
+	buf[2] = 0xFE;
+	buf[3] = 0x82;
+	buf[4] = 0xB0;
+	i2c_master_send(client, buf, 5);
+	i2c_master_recv(client, buf2, 4);
+
+	// change aspect ratio
+	buf[0] = 0xE0;
+	buf[1] = 0xA7;
+	buf[2] = 0xFE;
+	buf[3] = 0x82;
+	buf[4] = 0xB0;
+	buf[5] = buf2[0];
+	switch(h->params.vi_aspect_ratio) {
+	case V4L2_MPEG_ASPECT_16_9:
+		buf[6] = buf2[1] | 0x40;
+		break;
+	case V4L2_MPEG_ASPECT_4_3:
+	default:
+		buf[6] = buf2[1] & 0xBF;
+		break;
+		break;
+	}
+	buf[7] = buf2[2];
+	buf[8] = buf2[3];
+	i2c_master_send(client, buf, 9);
+
+   	// return success
+	return 0;
+}
+
+static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
+{
+	struct saa6752hs_state *h;
+
+        printk("saa6752hs: chip found @ 0x%x\n", addr<<1);
+
+        if (NULL == (h = kmalloc(sizeof(*h), GFP_KERNEL)))
+                return -ENOMEM;
+	memset(h,0,sizeof(*h));
+	h->client = client_template;
+	h->params = param_defaults;
+	h->client.adapter = adap;
+	h->client.addr = addr;
+
+	i2c_set_clientdata(&h->client, h);
+        i2c_attach_client(&h->client);
+	return 0;
+}
+
+static int saa6752hs_probe(struct i2c_adapter *adap)
+{
+	if (adap->class & I2C_CLASS_TV_ANALOG)
+		return i2c_probe(adap, &addr_data, saa6752hs_attach);
+	return 0;
+}
+
+static int saa6752hs_detach(struct i2c_client *client)
+{
+	struct saa6752hs_state *h;
+
+	h = i2c_get_clientdata(client);
+	i2c_detach_client(client);
+	kfree(h);
+	return 0;
+}
+
+static int
+saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	struct saa6752hs_state *h = i2c_get_clientdata(client);
+	struct v4l2_mpeg_compression *params = arg;
+	int err = 0;
+
+        switch (cmd) {
+	case VIDIOC_S_MPEGCOMP:
+		if (NULL == params) {
+			/* apply settings and start encoder */
+			saa6752hs_init(client);
+			break;
+		}
+		saa6752hs_set_params(client, params);
+		/* fall through */
+	case VIDIOC_G_MPEGCOMP:
+		*params = h->params;
+		break;
+	default:
+		/* nothing */
+		break;
+	}
+
+	return err;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver driver = {
+	.owner          = THIS_MODULE,
+        .name           = "i2c saa6752hs MPEG encoder",
+        .id             = I2C_DRIVERID_SAA6752HS,
+        .flags          = I2C_DF_NOTIFY,
+        .attach_adapter = saa6752hs_probe,
+        .detach_client  = saa6752hs_detach,
+        .command        = saa6752hs_command,
+};
+
+static struct i2c_client client_template =
+{
+	I2C_DEVNAME("saa6752hs"),
+	.flags      = I2C_CLIENT_ALLOW_USE,
+        .driver     = &driver,
+};
+
+static int __init saa6752hs_init_module(void)
+{
+	return i2c_add_driver(&driver);
+}
+
+static void __exit saa6752hs_cleanup_module(void)
+{
+	i2c_del_driver(&driver);
+}
+
+module_init(saa6752hs_init_module);
+module_exit(saa6752hs_cleanup_module);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
new file mode 100644
index 0000000..180d317
--- /dev/null
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -0,0 +1,2018 @@
+
+/*
+ * $Id: saa7134-cards.c,v 1.54 2005/03/07 12:01:51 kraxel Exp $
+ *
+ * device driver for philips saa7134 based TV cards
+ * card-specific stuff.
+ *
+ * (c) 2001-04 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+/* commly used strings */
+static char name_mute[]    = "mute";
+static char name_radio[]   = "Radio";
+static char name_tv[]      = "Television";
+static char name_tv_mono[] = "TV (mono only)";
+static char name_comp1[]   = "Composite1";
+static char name_comp2[]   = "Composite2";
+static char name_comp3[]   = "Composite3";
+static char name_comp4[]   = "Composite4";
+static char name_svideo[]  = "S-Video";
+
+/* ------------------------------------------------------------------ */
+/* board config info                                                  */
+
+struct saa7134_board saa7134_boards[] = {
+	[SAA7134_BOARD_UNKNOWN] = {
+		.name		= "UNKNOWN/GENERIC",
+		.audio_clock	= 0x00187de7,
+		.tuner_type	= TUNER_ABSENT,
+		.inputs         = {{
+			.name = "default",
+			.vmux = 0,
+			.amux = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_PROTEUS_PRO] = {
+		/* /me */
+		.name		= "Proteus Pro [philips reference design]",
+		.audio_clock	= 0x00187de7,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.inputs         = {{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_FLYVIDEO3000] = {
+		/* "Marco d'Itri" <md@Linux.IT> */
+		.name		= "LifeView FlyVIDEO3000",
+		.audio_clock	= 0x00200000,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.gpiomask       = 0xe000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.gpio = 0x8000,
+			.tv   = 1,
+                },{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x0000,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x2000,
+		},
+	},
+	[SAA7134_BOARD_FLYVIDEO2000] = {
+		/* "TC Wan" <tcwan@cs.usm.my> */
+		.name           = "LifeView FlyVIDEO2000",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_LG_PAL_NEW_TAPC,
+		.gpiomask       = 0xe000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x0000,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		}},
+                .radio = {
+                        .name = name_radio,
+                        .amux = LINE2,
+			.gpio = 0x2000,
+                },
+		.mute = {
+			.name = name_mute,
+                        .amux = LINE2,
+			.gpio = 0x8000,
+		},
+	},
+	[SAA7134_BOARD_FLYTVPLATINUM_MINI] = {
+		/* "Arnaud Quette" <aquette@free.fr> */
+		.name           = "LifeView FlyTV Platinum Mini",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_FLYTVPLATINUM_FM] = {
+		/* LifeView FlyTV Platinum FM (LR214WF) */
+		/* "Peter Missel <peter.missel@onlinehome.de> */
+		.name           = "LifeView FlyTV Platinum FM",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+//		.gpiomask       = 0xe000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+//			.gpio = 0x0000,
+			.tv   = 1,
+                },{
+/*			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x0000,
+			.tv   = 1,
+		},{
+*/			.name = name_comp1,	/* Composite signal on S-Video input */
+			.vmux = 0,
+			.amux = LINE2,
+//			.gpio = 0x4000,
+		},{
+			.name = name_comp2,	/* Composite input */
+			.vmux = 3,
+			.amux = LINE2,
+//			.gpio = 0x4000,
+		},{
+			.name = name_svideo,	/* S-Video signal on S-Video input */
+			.vmux = 8,
+			.amux = LINE2,
+//			.gpio = 0x4000,
+		}},
+/*		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x2000,
+		},
+*/	},
+	[SAA7134_BOARD_EMPRESS] = {
+		/* "Gert Vervoort" <gert.vervoort@philips.com> */
+		.name		= "EMPRESS",
+		.audio_clock	= 0x00187de7,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.inputs         = {{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+		.mpeg      = SAA7134_MPEG_EMPRESS,
+		.video_out = CCIR656,
+	},
+	[SAA7134_BOARD_MONSTERTV] = {
+               /* "K.Ohta" <alpha292@bremen.or.jp> */
+               .name           = "SKNet Monster TV",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_NTSC_M,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 0,
+                       .amux = LINE1,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               }},
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+	},
+	[SAA7134_BOARD_MD9717] = {
+		.name		= "Tevion MD 9717",
+		.audio_clock	= 0x00200000,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			/* workaround for problems with normal TV sound */
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 2,
+			.amux = LINE1,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_TVSTATION_RDS] = {
+                /* Typhoon TV Tuner RDS: Art.Nr. 50694 */
+		.name		= "KNC One TV-Station RDS / Typhoon TV Tuner RDS",
+		.audio_clock	= 0x00200000,
+		.tuner_type	= TUNER_PHILIPS_FM1216ME_MK3,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_tv_mono,
+                        .vmux = 1,
+                        .amux   = LINE2,
+                        .tv   = 1,
+                },{
+
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+
+                        .name = "CVid over SVid",
+                        .vmux = 0,
+                        .amux = LINE1,
+                }},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_TVSTATION_DVR] = {
+		.name		= "KNC One TV-Station DVR",
+		.audio_clock	= 0x00200000,
+		.tuner_type	= TUNER_PHILIPS_FM1216ME_MK3,
+		.tda9887_conf	= TDA9887_PRESENT,
+		.gpiomask	= 0x820000,
+		.inputs		= {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+			.gpio = 0x20000,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+			.gpio = 0x20000,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+			.gpio = 0x20000,
+		}},
+		.radio		= {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x20000,
+		},
+		.mpeg           = SAA7134_MPEG_EMPRESS,
+		.video_out	= CCIR656,
+	},
+	[SAA7134_BOARD_CINERGY400] = {
+                .name           = "Terratec Cinergy 400 TV",
+                .audio_clock    = 0x00200000,
+                .tuner_type     = TUNER_PHILIPS_PAL,
+                .inputs         = {{
+                        .name = name_tv,
+                        .vmux = 1,
+                        .amux = TV,
+                        .tv   = 1,
+                },{
+                        .name = name_comp1,
+                        .vmux = 4,
+                        .amux = LINE1,
+                },{
+                        .name = name_svideo,
+                        .vmux = 8,
+                        .amux = LINE1,
+                },{
+                        .name = name_comp2, // CVideo over SVideo Connector
+                        .vmux = 0,
+                        .amux = LINE1,
+                }}
+        },
+	[SAA7134_BOARD_MD5044] = {
+		.name           = "Medion 5044",
+		.audio_clock    = 0x00187de7, // was: 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			/* workaround for problems with normal TV sound */
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_KWORLD] = {
+                .name           = "Kworld/KuroutoShikou SAA7130-TVPCI",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_NTSC_M,
+                .inputs         = {{
+                        .name = name_svideo,
+                        .vmux = 8,
+                        .amux = LINE1,
+                },{
+                        .name = name_comp1,
+                        .vmux = 3,
+                        .amux = LINE1,
+                },{
+                        .name = name_tv,
+                        .vmux = 1,
+                        .amux = LINE2,
+                        .tv   = 1,
+                }},
+        },
+	[SAA7134_BOARD_CINERGY600] = {
+                .name           = "Terratec Cinergy 600 TV",
+                .audio_clock    = 0x00200000,
+                .tuner_type     = TUNER_PHILIPS_PAL,
+		.tda9887_conf   = TDA9887_PRESENT,
+                .inputs         = {{
+                        .name = name_tv,
+                        .vmux = 1,
+                        .amux = TV,
+                        .tv   = 1,
+                },{
+                        .name = name_comp1,
+                        .vmux = 4,
+                        .amux = LINE1,
+                },{
+                        .name = name_svideo,
+                        .vmux = 8,
+                        .amux = LINE1,
+                },{
+                        .name = name_comp2, // CVideo over SVideo Connector
+                        .vmux = 0,
+                        .amux = LINE1,
+                }},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+               },
+        },
+	[SAA7134_BOARD_MD7134] = {
+		.name           = "Medion 7134",
+		//.audio_clock    = 0x00200000,
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 0,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = LINE2,
+		},
+	},
+	[SAA7134_BOARD_TYPHOON_90031] = {
+		/* aka Typhoon "TV+Radio", Art.Nr 90031 */
+		/* Tom Zoerner <tomzo at users sourceforge net> */
+		.name           = "Typhoon TV+Radio 90031",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = LINE2,
+		},
+        },
+	[SAA7134_BOARD_ELSA] = {
+		.name           = "ELSA EX-VISION 300TV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_HITACHI_NTSC,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 0,
+			.amux   = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 4,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+        },
+	[SAA7134_BOARD_ELSA_500TV] = {
+		.name           = "ELSA EX-VISION 500TV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_HITACHI_NTSC,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 7,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 8,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_tv_mono,
+			.vmux = 8,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+        },
+	[SAA7134_BOARD_ASUSTeK_TVFM7134] = {
+                .name           = "ASUS TV-FM 7134",
+                .audio_clock    = 0x00187de7,
+                .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+                .tda9887_conf   = TDA9887_PRESENT,
+                .inputs         = {{
+                        .name = name_tv,
+                        .vmux = 1,
+                        .amux = TV,
+                        .tv   = 1,
+                },{
+                        .name = name_comp1,
+                        .vmux = 4,
+                        .amux = LINE2,
+                },{
+                        .name = name_svideo,
+                        .vmux = 6,
+                        .amux = LINE2,
+                }},
+                .radio = {
+                        .name = name_radio,
+                        .amux = LINE1,
+                },
+	},
+	[SAA7135_BOARD_ASUSTeK_TVFM7135] = {
+                .name           = "ASUS TV-FM 7135",
+                .audio_clock    = 0x00187de7,
+                .tuner_type     = TUNER_PHILIPS_TDA8290,
+		.gpiomask       = 0x200000,
+                .inputs         = {{
+                        .name = name_tv,
+                        .vmux = 1,
+                        .amux = TV,
+			.gpio = 0x0000,
+                        .tv   = 1,
+                },{
+                        .name = name_comp1,
+                        .vmux = 4,
+                        .amux = LINE2,
+			.gpio = 0x0000,
+                },{
+                        .name = name_svideo,
+                        .vmux = 6,
+                        .amux = LINE2,
+			.gpio = 0x0000,
+                }},
+                .radio = {
+                        .name = name_radio,
+                        .amux = TV,
+			.gpio = 0x200000,
+                },
+	},
+	[SAA7134_BOARD_VA1000POWER] = {
+                .name           = "AOPEN VA1000 POWER",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_NTSC,
+                .inputs         = {{
+                        .name = name_svideo,
+                        .vmux = 8,
+                        .amux = LINE1,
+                },{
+                        .name = name_comp1,
+                        .vmux = 3,
+                        .amux = LINE1,
+                },{
+                        .name = name_tv,
+                        .vmux = 1,
+                        .amux = LINE2,
+                        .tv   = 1,
+                }},
+	},
+	[SAA7134_BOARD_10MOONSTVMASTER] = {
+		/* "lilicheng" <llc@linuxfans.org> */
+		.name           = "10MOONS PCI TV CAPTURE CARD",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_LG_PAL_NEW_TAPC,
+		.gpiomask       = 0xe000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x0000,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		}},
+                .radio = {
+                        .name = name_radio,
+                        .amux = LINE2,
+			.gpio = 0x2000,
+                },
+		.mute = {
+			.name = name_mute,
+                        .amux = LINE2,
+			.gpio = 0x8000,
+		},
+	},
+	[SAA7134_BOARD_BMK_MPEX_NOTUNER] = {
+		/* "Andrew de Quincey" <adq@lidskialf.net> */
+		.name		= "BMK MPEX No Tuner",
+		.audio_clock	= 0x200000,
+		.tuner_type	= TUNER_ABSENT,
+		.inputs         = {{
+			.name = name_comp1,
+			.vmux = 4,
+			.amux = LINE1,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+			.name = name_comp3,
+			.vmux = 0,
+			.amux = LINE1,
+		},{
+			.name = name_comp4,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+		.mpeg      = SAA7134_MPEG_EMPRESS,
+		.video_out = CCIR656,
+	},
+	[SAA7134_BOARD_VIDEOMATE_TV] = {
+		.name           = "Compro VideoMate TV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_NTSC_M,
+                .inputs         = {{
+                        .name = name_svideo,
+                        .vmux = 8,
+                        .amux = LINE1,
+                },{
+                        .name = name_comp1,
+                        .vmux = 3,
+                        .amux = LINE1,
+                },{
+                        .name = name_tv,
+                        .vmux = 1,
+                        .amux = LINE2,
+                        .tv   = 1,
+                }},
+        },
+    [SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS] = {
+		.name           = "Compro VideoMate TV Gold+",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_NTSC_M,
+		.gpiomask       = 0x800c0000,
+                .inputs         = {{
+                        .name = name_svideo,
+                        .vmux = 8,
+                        .amux = LINE1,
+                        .gpio = 0x06c00012,
+                },{
+                        .name = name_comp1,
+                        .vmux = 3,
+                        .amux = LINE1,
+                        .gpio = 0x0ac20012,
+                },{
+                        .name = name_tv,
+                        .vmux = 1,
+                        .amux = LINE2,
+                        .gpio = 0x08c20012,
+                        .tv   = 1,
+                }},
+        },
+	[SAA7134_BOARD_CRONOS_PLUS] = {
+		/* gpio pins:
+		   0  .. 3   BASE_ID
+		   4  .. 7   PROTECT_ID
+		   8  .. 11  USER_OUT
+		   12 .. 13  USER_IN
+		   14 .. 15  VIDIN_SEL */
+		.name           = "Matrox CronosPlus",
+		.tuner_type     = TUNER_ABSENT,
+		.gpiomask       = 0xcf00,
+                .inputs         = {{
+                        .name = name_comp1,
+                        .vmux = 0,
+			.gpio = 2 << 14,
+		},{
+                        .name = name_comp2,
+                        .vmux = 0,
+			.gpio = 1 << 14,
+		},{
+                        .name = name_comp3,
+                        .vmux = 0,
+			.gpio = 0 << 14,
+		},{
+                        .name = name_comp4,
+                        .vmux = 0,
+			.gpio = 3 << 14,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.gpio = 2 << 14,
+                }},
+        },
+	[SAA7134_BOARD_MD2819] = {
+		.name           = "AverMedia M156 / Medion 2819",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BMK_MPEX_TUNER] = {
+		/* "Greg Wickham <greg.wickham@grangenet.net> */
+		.name           = "BMK MPEX Tuner",
+		.audio_clock    = 0x200000,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.inputs         = {{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		}},
+		.mpeg      = SAA7134_MPEG_EMPRESS,
+		.video_out = CCIR656,
+        },
+        [SAA7134_BOARD_ASUSTEK_TVFM7133] = {
+                .name           = "ASUS TV-FM 7133",
+                .audio_clock    = 0x00187de7,
+		// probably wrong, the 7133 one is the NTSC version ...
+		// .tuner_type     = TUNER_PHILIPS_FM1236_MK3
+                .tuner_type     = TUNER_LG_NTSC_NEW_TAPC,
+                .tda9887_conf   = TDA9887_PRESENT,
+                .inputs         = {{
+                        .name = name_tv,
+                        .vmux = 1,
+                        .amux = TV,
+                        .tv   = 1,
+		},{
+                        .name = name_comp1,
+                        .vmux = 4,
+                        .amux = LINE2,
+                },{
+                        .name = name_svideo,
+                        .vmux = 6,
+                        .amux = LINE2,
+                }},
+                .radio = {
+                        .name = name_radio,
+                        .amux = LINE1,
+                },
+        },
+	[SAA7134_BOARD_PINNACLE_PCTV_STEREO] = {
+                .name           = "Pinnacle PCTV Stereo (saa7134)",
+                .audio_clock    = 0x00187de7,
+                .tuner_type     = TUNER_MT2032,
+                .tda9887_conf   = TDA9887_PRESENT | TDA9887_INTERCARRIER,
+                .inputs         = {{
+                        .name = name_tv,
+                        .vmux = 3,
+                        .amux = TV,
+                        .tv   = 1,
+                },{
+                        .name = name_comp1,
+                        .vmux = 0,
+                        .amux = LINE2,
+                },{
+                        .name = name_comp2,
+                        .vmux = 1,
+                        .amux = LINE2,
+                },{
+                        .name = name_svideo,
+                        .vmux = 8,
+                        .amux = LINE2,
+                }},
+        },
+	[SAA7134_BOARD_MANLI_MTV002] = {
+		/* Ognjen Nastic <ognjen@logosoft.ba> */
+		.name           = "Manli MuchTV M-TV002",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 1,
+			.amux   = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+		.mute = {
+			.name = name_mute,
+                        .amux = LINE1,
+		},
+	},
+	[SAA7134_BOARD_MANLI_MTV001] = {
+		/* Ognjen Nastic <ognjen@logosoft.ba> UNTESTED */
+		.name           = "Manli MuchTV M-TV001",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+        },
+	[SAA7134_BOARD_TG3000TV] = {
+		/* TransGear 3000TV */
+		.name           = "Nagase Sangyo TransGear 3000TV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_NTSC_M,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+	},
+        [SAA7134_BOARD_ECS_TVP3XP] = {
+                .name           = "Elitegroup ECS TVP3XP FM1216 Tuner Card(PAL-BG,FM) ",
+                .audio_clock    = 0x187de7,  // xtal 32.1 MHz
+                .tuner_type     = TUNER_PHILIPS_PAL,
+                .inputs         = {{
+                        .name   = name_tv,
+                        .vmux   = 1,
+                        .amux   = TV,
+                        .tv     = 1,
+                },{
+                        .name   = name_tv_mono,
+                        .vmux   = 1,
+                        .amux   = LINE2,
+                        .tv     = 1,
+                },{
+                        .name   = name_comp1,
+                        .vmux   = 3,
+                        .amux   = LINE1,
+                },{
+                        .name   = name_svideo,
+                        .vmux   = 8,
+                        .amux   = LINE1,
+		},{
+			.name   = "CVid over SVid",
+			.vmux   = 0,
+			.amux   = LINE1,
+		}},
+                .radio = {
+                        .name   = name_radio,
+                        .amux   = LINE2,
+                },
+        },
+        [SAA7134_BOARD_ECS_TVP3XP_4CB5] = {
+                .name           = "Elitegroup ECS TVP3XP FM1236 Tuner Card (NTSC,FM)",
+                .audio_clock    = 0x187de7,
+                .tuner_type     = TUNER_PHILIPS_NTSC,
+                .inputs         = {{
+                        .name   = name_tv,
+                        .vmux   = 1,
+                        .amux   = TV,
+                        .tv     = 1,
+                },{
+                        .name   = name_tv_mono,
+                        .vmux   = 1,
+                        .amux   = LINE2,
+                        .tv     = 1,
+                },{
+                        .name   = name_comp1,
+                        .vmux   = 3,
+                        .amux   = LINE1,
+                },{
+                        .name   = name_svideo,
+                        .vmux   = 8,
+                        .amux   = LINE1,
+                },{
+                        .name   = "CVid over SVid",
+                        .vmux   = 0,
+                        .amux   = LINE1,
+                }},
+                .radio = {
+                        .name   = name_radio,
+                        .amux   = LINE2,
+                },
+        },
+	[SAA7134_BOARD_AVACSSMARTTV] = {
+		/* Roman Pszonczenko <romka@kolos.math.uni.lodz.pl> */
+		.name           = "AVACS SmartTV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+                },{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x200000,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER] = {
+		/* Michael Smith <msmith@cbnco.com> */
+		.name           = "AVerMedia DVD EZMaker",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_ABSENT,
+		.inputs         = {{
+			.name = name_comp1,
+			.vmux = 3,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+		}},
+	},
+        [SAA7134_BOARD_NOVAC_PRIMETV7133] = {
+                /* toshii@netbsd.org */
+                .name           = "Noval Prime TV 7133",
+                .audio_clock    = 0x00200000,
+                .tuner_type     = TUNER_ALPS_TSBH1_NTSC,
+                .inputs         = {{
+                        .name = name_comp1,
+                        .vmux = 3,
+                },{
+                        .name = name_tv,
+                        .vmux = 1,
+                        .amux = TV,
+                        .tv   = 1,
+                },{
+                        .name = name_svideo,
+                        .vmux = 8,
+                }},
+        },
+	[SAA7134_BOARD_AVERMEDIA_STUDIO_305] = {
+		.name           = "AverMedia AverTV Studio 305",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1256_IH3,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask = 0x3,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+		.radio = {
+			 .name = name_radio,
+			 .amux = LINE2,
+		 },
+		.mute = {
+			 .name = name_mute,
+			 .amux = LINE1,
+		},
+	},
+  	[SAA7133_BOARD_UPMOST_PURPLE_TV] = {
+  		.name           = "UPMOST PURPLE TV",
+  		.audio_clock    = 0x00187de7,
+  		.tuner_type     = TUNER_PHILIPS_FM1236_MK3,
+  		.tda9887_conf   = TDA9887_PRESENT,
+  		.inputs         = {{
+  			.name = name_tv,
+  			.vmux = 7,
+  			.amux = TV,
+  			.tv   = 1,
+  		},{
+  			.name = name_svideo,
+  			.vmux = 7,
+  			.amux = LINE1,
+  		}},
+	},
+	[SAA7134_BOARD_ITEMS_MTV005] = {
+		/* Norman Jonas <normanjonas@arcor.de> */
+		.name           = "Items MuchTV Plus / IT-005",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 1,
+			.amux   = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_CINERGY200] = {
+		.name           = "Terratec Cinergy 200 TV",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.inputs         = {{
+       			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+                },{
+                        .name = name_comp1,
+                        .vmux = 4,
+                        .amux = LINE1,
+                },{
+                        .name = name_svideo,
+                        .vmux = 8,
+                        .amux = LINE1,
+                },{
+                        .name = name_comp2, // CVideo over SVideo Connector
+                        .vmux = 0,
+                        .amux = LINE1,
+		}},
+		.mute = {
+			 .name = name_mute,
+			 .amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_VIDEOMATE_TV_PVR] = {
+		/* Alain St-Denis <alain@topaze.homeip.net> */
+		.name           = "Compro VideoMate TV PVR/FM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_NTSC_M,
+		.gpiomask	= 0x808c0080,
+                .inputs         = {{
+                        .name = name_svideo,
+                        .vmux = 8,
+                        .amux = LINE1,
+			.gpio = 0x00080,
+                },{
+                        .name = name_comp1,
+                        .vmux = 3,
+                        .amux = LINE1,
+			.gpio = 0x00080,
+                },{
+                        .name = name_tv,
+                        .vmux = 1,
+                        .amux = LINE2_LEFT,
+                        .tv   = 1,
+			.gpio = 0x00080,
+                }},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x80000,
+		 },
+		.mute = {
+			.name = name_mute,
+                        .amux = LINE2,
+			.gpio = 0x40000,
+		},
+        },
+        [SAA7134_BOARD_SABRENT_SBTTVFM] = {
+		/* Michael Rodriguez-Torrent <mrtorrent@asu.edu> */
+                .name           = "Sabrent SBT-TVFM (saa7130)",
+                .audio_clock    = 0x00187de7,
+                .tuner_type     = TUNER_PHILIPS_NTSC_M,
+                .inputs         = {{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE2,
+		},{
+                        .name = name_tv,
+                        .vmux = 3,
+                        .amux = LINE2,
+                        .tv   = 1,
+                },{
+                        .name = name_svideo,
+                        .vmux = 8,
+                        .amux = LINE2,
+                }},
+                .radio = {
+                        .name   = name_radio,
+                        .amux   = LINE2,
+                },
+        },
+	[SAA7134_BOARD_ZOLID_XPERT_TV7134] = {
+		/* Helge Jensen <helge.jensen@slog.dk> */
+                .name           = ":Zolid Xpert TV7134",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_NTSC,
+                .inputs         = {{
+			.name = name_svideo,
+                        .vmux = 8,
+                        .amux = LINE1,
+                },{
+                        .name = name_comp1,
+                        .vmux = 3,
+                        .amux = LINE1,
+                },{
+                        .name = name_tv,
+                        .vmux = 1,
+                        .amux = LINE2,
+                        .tv   = 1,
+                }},
+	},
+	[SAA7134_BOARD_EMPIRE_PCI_TV_RADIO_LE] = {
+		/* "Matteo Az" <matte.az@nospam.libero.it> ;-) */
+		.name           = "Empire PCI TV-Radio LE",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.gpiomask       = 0x4000,
+		.inputs         = {{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x8000,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+			.gpio = 0x8000,
+		},{
+			.name = name_svideo,
+			.vmux = 6,
+			.amux = LINE1,
+			.gpio = 0x8000,
+		}},
+                .radio = {
+			 .name = name_radio,
+			 .amux = LINE1,
+			 .gpio = 0x8000,
+		 },
+		.mute = {
+			 .name = name_mute,
+			 .amux = TV,
+			 .gpio =0x8000,
+		 }
+	},
+        [SAA7134_BOARD_AVERMEDIA_307] = {
+		/*
+		Nickolay V. Shmyrev <nshmyrev@yandex.ru>
+		Lots of thanks to Andrey Zolotarev <zolotarev_andrey@mail.ru>
+		*/
+		.name           = "Avermedia AVerTV Studio 307",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1256_IH3,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x03,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x00,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+			.gpio = 0x00,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+			.gpio = 0x00,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+			.gpio = 0x00,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE1,
+			.gpio = 0x01,
+		},
+        },
+	[SAA7134_BOARD_AVERMEDIA_CARDBUS] = {
+		/* Jon Westgate <oryn@oryn.fsck.tv> */
+		.name           = "AVerMedia Cardbus TV/Radio",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+		.radio = {
+                	.name = name_radio,
+			.amux = LINE1,
+		},
+	},
+	[SAA7134_BOARD_CINERGY400_CARDBUS] = {
+		.name           = "Terratec Cinergy 400 mobile",
+		.audio_clock    = 0x187de7,
+		.tuner_type     = TUNER_ALPS_TSBE5_PAL,
+  		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+       			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+               },{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+                },{
+                        .name = name_comp1,
+                        .vmux = 3,
+                        .amux = LINE1,
+                },{
+                        .name = name_svideo,
+                        .vmux = 8,
+                        .amux = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_CINERGY600_MK3] = {
+                .name           = "Terratec Cinergy 600 TV MK3",
+                .audio_clock    = 0x00200000,
+		.tuner_type	= TUNER_PHILIPS_FM1216ME_MK3,
+  		.tda9887_conf   = TDA9887_PRESENT,
+                .inputs         = {{
+                        .name = name_tv,
+                        .vmux = 1,
+                        .amux = TV,
+                        .tv   = 1,
+                },{
+                        .name = name_comp1,
+                        .vmux = 4,
+                        .amux = LINE1,
+                },{
+                        .name = name_svideo,
+                        .vmux = 8,
+                        .amux = LINE1,
+                },{
+                        .name = name_comp2, // CVideo over SVideo Connector
+                        .vmux = 0,
+                        .amux = LINE1,
+                }},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+               },
+        },
+ 	[SAA7134_BOARD_VIDEOMATE_GOLD_PLUS] = {
+ 		/* Dylan Walkden <dylan_walkden@hotmail.com> */
+ 		.name		= "Compro VideoMate Gold+ Pal",
+ 		.audio_clock	= 0x00187de7,
+ 		.tuner_type	= TUNER_PHILIPS_PAL,
+ 		.gpiomask	= 0x1ce780,
+ 		.inputs		= {{
+ 			.name = name_svideo,
+ 			.vmux = 0,		// CVideo over SVideo Connector - ok?
+ 			.amux = LINE1,
+ 			.gpio = 0x008080,
+ 		},{
+ 			.name = name_comp1,
+ 			.vmux = 3,
+ 			.amux = LINE1,
+ 			.gpio = 0x008080,
+ 		},{
+ 			.name = name_tv,
+ 			.vmux = 1,
+ 			.amux = TV,
+ 			.tv   = 1,
+ 			.gpio = 0x008080,
+ 		}},
+ 		.radio = {
+ 			.name = name_radio,
+ 			.amux = LINE2,
+ 			.gpio = 0x80000,
+ 		},
+ 		.mute = {
+ 			.name = name_mute,
+ 			.amux = LINE2,
+ 			.gpio = 0x0c8000,
+ 		},
+ 	},
+	[SAA7134_BOARD_PINNACLE_300I_DVBT_PAL] = {
+                .name           = "Pinnacle PCTV 300i DVB-T + PAL",
+                .audio_clock    = 0x00187de7,
+                .tuner_type     = TUNER_MT2032,
+                .tda9887_conf   = TDA9887_PRESENT | TDA9887_INTERCARRIER,
+		.mpeg           = SAA7134_MPEG_DVB,
+                .inputs         = {{
+                        .name = name_tv,
+                        .vmux = 3,
+                        .amux = TV,
+                        .tv   = 1,
+                },{
+                        .name = name_comp1,
+                        .vmux = 0,
+                        .amux = LINE2,
+                },{
+                        .name = name_comp2,
+                        .vmux = 1,
+                        .amux = LINE2,
+                },{
+                        .name = name_svideo,
+                        .vmux = 8,
+                        .amux = LINE2,
+                }},
+        },
+	[SAA7134_BOARD_PROVIDEO_PV952] = {
+		/* andreas.kretschmer@web.de */
+		.name		= "ProVideo PV952",
+		.audio_clock	= 0x00187de7,
+		.tuner_type	= TUNER_PHILIPS_FM1216ME_MK3,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_305] = {
+		/* much like the "studio" version but without radio
+		 * and another tuner (sirspiritus@yandex.ru) */
+		.name           = "AverMedia AverTV/305",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask = 0x3,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+		.mute = {
+			 .name = name_mute,
+			 .amux = LINE1,
+		},
+	},
+	[SAA7134_BOARD_FLYDVBTDUO] = {
+		/* LifeView FlyDVB-T DUO */
+		/* "Nico Sabbi <nsabbi@tiscali.it> */
+		.name           = "LifeView FlyDVB-T DUO",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+//		.gpiomask       = 0xe000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+//			.gpio = 0x0000,
+			.tv   = 1,
+                },{
+			.name = name_comp1,	/* Composite signal on S-Video input */
+			.vmux = 0,
+			.amux = LINE2,
+//			.gpio = 0x4000,
+		},{
+			.name = name_comp2,	/* Composite input */
+			.vmux = 3,
+			.amux = LINE2,
+//			.gpio = 0x4000,
+		},{
+			.name = name_svideo,	/* S-Video signal on S-Video input */
+			.vmux = 8,
+			.amux = LINE2,
+//			.gpio = 0x4000,
+		}},
+	},
+};
+const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
+
+/* ------------------------------------------------------------------ */
+/* PCI ids + subsystem IDs                                            */
+
+struct pci_device_id saa7134_pci_tbl[] = {
+	{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0x2001,
+		.driver_data  = SAA7134_BOARD_PROTEUS_PRO,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0x2001,
+		.driver_data  = SAA7134_BOARD_PROTEUS_PRO,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0x6752,
+		.driver_data  = SAA7134_BOARD_EMPRESS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+                .subvendor    = 0x1131,
+                .subdevice    = 0x4e85,
+		.driver_data  = SAA7134_BOARD_MONSTERTV,
+        },{
+                .vendor       = PCI_VENDOR_ID_PHILIPS,
+                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+                .subvendor    = 0x153B,
+                .subdevice    = 0x1142,
+                .driver_data  = SAA7134_BOARD_CINERGY400,
+        },{
+                .vendor       = PCI_VENDOR_ID_PHILIPS,
+                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+                .subvendor    = 0x153B,
+                .subdevice    = 0x1143,
+                .driver_data  = SAA7134_BOARD_CINERGY600,
+        },{
+                .vendor       = PCI_VENDOR_ID_PHILIPS,
+                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+                .subvendor    = 0x153B,
+                .subdevice    = 0x1158,
+                .driver_data  = SAA7134_BOARD_CINERGY600_MK3,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x153b,
+		.subdevice    = 0x1162,
+		.driver_data  = SAA7134_BOARD_CINERGY400_CARDBUS,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x5168,
+		.subdevice    = 0x0138,
+		.driver_data  = SAA7134_BOARD_FLYVIDEO3000,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+                .subvendor    = 0x4e42,				//"Typhoon PCI Capture TV Card" Art.No. 50673
+                .subdevice    = 0x0138,
+                .driver_data  = SAA7134_BOARD_FLYVIDEO3000,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x5168,
+		.subdevice    = 0x0138,
+		.driver_data  = SAA7134_BOARD_FLYVIDEO2000,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7135,
+		.subvendor    = 0x5168,
+		.subdevice    = 0x0212, /* minipci, LR212 */
+		.driver_data  = SAA7134_BOARD_FLYTVPLATINUM_MINI,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5168,
+		.subdevice    = 0x0214, /* Standard PCI, LR214WF */
+		.driver_data  = SAA7134_BOARD_FLYTVPLATINUM_FM,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x16be,
+		.subdevice    = 0x0003,
+		.driver_data  = SAA7134_BOARD_MD7134,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x1048,
+		.subdevice    = 0x226b,
+		.driver_data  = SAA7134_BOARD_ELSA,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x1048,
+		.subdevice    = 0x226b,
+		.driver_data  = SAA7134_BOARD_ELSA_500TV,
+	},{
+                .vendor       = PCI_VENDOR_ID_PHILIPS,
+                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+                .subvendor    = PCI_VENDOR_ID_ASUSTEK,
+                .subdevice    = 0x4842,
+                .driver_data  = SAA7134_BOARD_ASUSTeK_TVFM7134,
+	},{
+                .vendor       = PCI_VENDOR_ID_PHILIPS,
+                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+                .subvendor    = PCI_VENDOR_ID_ASUSTEK,
+                .subdevice    = 0x4845,
+                .driver_data  = SAA7135_BOARD_ASUSTeK_TVFM7135,
+	},{
+                .vendor       = PCI_VENDOR_ID_PHILIPS,
+                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+                .subvendor    = PCI_VENDOR_ID_ASUSTEK,
+                .subdevice    = 0x4830,
+                .driver_data  = SAA7134_BOARD_ASUSTeK_TVFM7134,
+        },{
+                .vendor       = PCI_VENDOR_ID_PHILIPS,
+                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+                .subvendor    = PCI_VENDOR_ID_ASUSTEK,
+                .subdevice    = 0x4843,
+                .driver_data  = SAA7134_BOARD_ASUSTEK_TVFM7133,
+	},{
+                .vendor       = PCI_VENDOR_ID_PHILIPS,
+                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+                .subvendor    = PCI_VENDOR_ID_ASUSTEK,
+                .subdevice    = 0x4840,
+                .driver_data  = SAA7134_BOARD_ASUSTeK_TVFM7134,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0xfe01,
+		.driver_data  = SAA7134_BOARD_TVSTATION_RDS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1894,
+		.subdevice    = 0xfe01,
+		.driver_data  = SAA7134_BOARD_TVSTATION_RDS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1894,
+		.subdevice    = 0xa006,
+		.driver_data  = SAA7134_BOARD_TVSTATION_DVR,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+                .subvendor    = 0x1131,
+                .subdevice    = 0x7133,
+		.driver_data  = SAA7134_BOARD_VA1000POWER,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+                .subvendor    = PCI_VENDOR_ID_PHILIPS,
+                .subdevice    = 0x2001,
+		.driver_data  = SAA7134_BOARD_10MOONSTVMASTER,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+                .subvendor    = 0x185b,
+                .subdevice    = 0xc100,
+		.driver_data  = SAA7134_BOARD_VIDEOMATE_TV,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+                .subvendor    = 0x185b,
+                .subdevice    = 0xc100,
+		.driver_data  = SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+                .subvendor    = PCI_VENDOR_ID_MATROX,
+                .subdevice    = 0x48d0,
+		.driver_data  = SAA7134_BOARD_CRONOS_PLUS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+                .subvendor    = 0x1461, /* Avermedia Technologies Inc */
+                .subdevice    = 0xa70b,
+		.driver_data  = SAA7134_BOARD_MD2819,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+                .subvendor    = 0x1461, /* Avermedia Technologies Inc */
+                .subdevice    = 0x2115,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_STUDIO_305,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+                .subvendor    = 0x1461, /* Avermedia Technologies Inc */
+                .subdevice    = 0x2108,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_305,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+                .subvendor    = 0x1461, /* Avermedia Technologies Inc */
+                .subdevice    = 0x10ff,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER,
+        },{
+		/* AVerMedia CardBus */
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+                .subvendor    = 0x1461, /* Avermedia Technologies Inc */
+                .subdevice    = 0xd6ee,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_CARDBUS,
+	},{
+		/* TransGear 3000TV */
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+                .subvendor    = 0x1461, /* Avermedia Technologies Inc */
+                .subdevice    = 0x050c,
+		.driver_data  = SAA7134_BOARD_TG3000TV,
+	},{
+                .vendor       = PCI_VENDOR_ID_PHILIPS,
+                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+                .subvendor    = 0x11bd,
+                .subdevice    = 0x002b,
+                .driver_data  = SAA7134_BOARD_PINNACLE_PCTV_STEREO,
+        },{
+                .vendor       = PCI_VENDOR_ID_PHILIPS,
+                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+                .subvendor    = 0x11bd,
+                .subdevice    = 0x002d,
+                .driver_data  = SAA7134_BOARD_PINNACLE_300I_DVBT_PAL,
+        },{
+                .vendor       = PCI_VENDOR_ID_PHILIPS,
+                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+                .subvendor    = 0x1019,
+                .subdevice    = 0x4cb4,
+                .driver_data  = SAA7134_BOARD_ECS_TVP3XP,
+        },{
+                .vendor       = PCI_VENDOR_ID_PHILIPS,
+                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+                .subvendor    = 0x1019,
+                .subdevice    = 0x4cb5,
+                .driver_data  = SAA7134_BOARD_ECS_TVP3XP_4CB5,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+ 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+                .subvendor    = 0x12ab,
+                .subdevice    = 0x0800,
+ 		.driver_data  = SAA7133_BOARD_UPMOST_PURPLE_TV,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x153B,
+		.subdevice    = 0x1152,
+		.driver_data  = SAA7134_BOARD_CINERGY200,
+ 	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+                .subvendor    = 0x185b,
+                .subdevice    = 0xc100,
+		.driver_data  = SAA7134_BOARD_VIDEOMATE_TV_PVR,
+ 	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+                .subvendor    = 0x1131,
+                .subdevice    = 0,
+		.driver_data  = SAA7134_BOARD_SABRENT_SBTTVFM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0x9715,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_307,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x185b,
+		.subdevice    = 0xc200,
+		.driver_data  = SAA7134_BOARD_VIDEOMATE_GOLD_PLUS,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1540,
+		.subdevice    = 0x9524,
+		.driver_data  = SAA7134_BOARD_PROVIDEO_PV952,
+
+ 	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5168,
+		.subdevice    = 0x0306,
+		.driver_data  = SAA7134_BOARD_FLYDVBTDUO,
+
+ 	},{
+		/* --- boards without eeprom + subsystem ID --- */
+                .vendor       = PCI_VENDOR_ID_PHILIPS,
+                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+                .subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0,
+		.driver_data  = SAA7134_BOARD_NOAUTO,
+        },{
+                .vendor       = PCI_VENDOR_ID_PHILIPS,
+                .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+                .subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0,
+		.driver_data  = SAA7134_BOARD_NOAUTO,
+	},{
+
+		/* --- default catch --- */
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+                .subvendor    = PCI_ANY_ID,
+                .subdevice    = PCI_ANY_ID,
+		.driver_data  = SAA7134_BOARD_UNKNOWN,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+                .subvendor    = PCI_ANY_ID,
+                .subdevice    = PCI_ANY_ID,
+		.driver_data  = SAA7134_BOARD_UNKNOWN,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+                .subvendor    = PCI_ANY_ID,
+                .subdevice    = PCI_ANY_ID,
+		.driver_data  = SAA7134_BOARD_UNKNOWN,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7135,
+                .subvendor    = PCI_ANY_ID,
+                .subdevice    = PCI_ANY_ID,
+		.driver_data  = SAA7134_BOARD_UNKNOWN,
+	},{
+		/* --- end of list --- */
+	}
+};
+MODULE_DEVICE_TABLE(pci, saa7134_pci_tbl);
+
+/* ----------------------------------------------------------- */
+/* flyvideo tweaks                                             */
+
+#if 0
+static struct {
+	char  *model;
+	int   tuner_type;
+} fly_list[0x20] = {
+	/* default catch ... */
+	[ 0 ... 0x1f ] = {
+		.model      = "UNKNOWN",
+		.tuner_type = TUNER_ABSENT,
+	},
+	/* ... the ones known so far */
+	[ 0x05 ] = {
+		.model      = "PAL-BG",
+		.tuner_type = TUNER_LG_PAL_NEW_TAPC,
+	},
+	[ 0x10 ] = {
+		.model      = "PAL-BG / PAL-DK",
+		.tuner_type = TUNER_PHILIPS_PAL,
+	},
+	[ 0x15 ] = {
+		.model      = "NTSC",
+		.tuner_type = TUNER_ABSENT /* FIXME */,
+	},
+};
+#endif
+
+static void board_flyvideo(struct saa7134_dev *dev)
+{
+#if 0
+	/* non-working attempt to detect the correct tuner type ... */
+	u32 value;
+	int index;
+
+	value = dev->gpio_value;
+	index = (value & 0x1f00) >> 8;
+	printk(KERN_INFO "%s: flyvideo: gpio is 0x%x [model=%s,tuner=%d]\n",
+	       dev->name, value, fly_list[index].model,
+	       fly_list[index].tuner_type);
+	dev->tuner_type = fly_list[index].tuner_type;
+#endif
+	printk("%s: there are different flyvideo cards with different tuners\n"
+	       "%s: out there, you might have to use the tuner=<nr> insmod\n"
+	       "%s: option to override the default value.\n",
+	       dev->name, dev->name, dev->name);
+}
+
+/* ----------------------------------------------------------- */
+
+int saa7134_board_init1(struct saa7134_dev *dev)
+{
+	// Always print gpio, often manufacturers encode tuner type and other info.
+	saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0);
+	dev->gpio_value = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+	printk(KERN_INFO "%s: board init: gpio is %x\n", dev->name, dev->gpio_value);
+
+	switch (dev->board) {
+	case SAA7134_BOARD_FLYVIDEO2000:
+	case SAA7134_BOARD_FLYVIDEO3000:
+		dev->has_remote = 1;
+		board_flyvideo(dev);
+		break;
+	case SAA7134_BOARD_CINERGY400:
+	case SAA7134_BOARD_CINERGY600:
+	case SAA7134_BOARD_CINERGY600_MK3:
+	case SAA7134_BOARD_ECS_TVP3XP:
+	case SAA7134_BOARD_ECS_TVP3XP_4CB5:
+	case SAA7134_BOARD_MD2819:
+	case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+	case SAA7134_BOARD_AVERMEDIA_305:
+	case SAA7134_BOARD_AVERMEDIA_307:
+//	case SAA7134_BOARD_SABRENT_SBTTVFM:  /* not finished yet */
+	case SAA7134_BOARD_VIDEOMATE_TV_PVR:
+		dev->has_remote = 1;
+		break;
+	case SAA7134_BOARD_AVACSSMARTTV:
+		dev->has_remote = 1;
+		break;
+	case SAA7134_BOARD_MD5044:
+		printk("%s: seems there are two different versions of the MD5044\n"
+		       "%s: (with the same ID) out there.  If sound doesn't work for\n"
+		       "%s: you try the audio_clock_override=0x200000 insmod option.\n",
+		       dev->name,dev->name,dev->name);
+		break;
+	case SAA7134_BOARD_CINERGY400_CARDBUS:
+		/* power-up tuner chip */
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x00040000, 0x00040000);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000000);
+		msleep(1);
+		break;
+	}
+	if (dev->has_remote)
+		dev->irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18  |
+				   SAA7134_IRQ2_INTE_GPIO18A |
+				   SAA7134_IRQ2_INTE_GPIO16  );
+	return 0;
+}
+
+/* stuff which needs working i2c */
+int saa7134_board_init2(struct saa7134_dev *dev)
+{
+	unsigned char buf;
+	int board;
+
+	switch (dev->board) {
+	case SAA7134_BOARD_BMK_MPEX_NOTUNER:
+	case SAA7134_BOARD_BMK_MPEX_TUNER:
+		dev->i2c_client.addr = 0x60;
+		board = (i2c_master_recv(&dev->i2c_client,&buf,0) < 0)
+			? SAA7134_BOARD_BMK_MPEX_NOTUNER
+			: SAA7134_BOARD_BMK_MPEX_TUNER;
+		if (board == dev->board)
+			break;
+		dev->board = board;
+		printk("%s: board type fixup: %s\n", dev->name,
+		       saa7134_boards[dev->board].name);
+		dev->tuner_type = saa7134_boards[dev->board].tuner_type;
+		if (TUNER_ABSENT != dev->tuner_type)
+			saa7134_i2c_call_clients(dev,TUNER_SET_TYPE,&dev->tuner_type);
+		break;
+	}
+	return 0;
+}
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
new file mode 100644
index 0000000..d506caf
--- /dev/null
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -0,0 +1,1237 @@
+/*
+ * $Id: saa7134-core.c,v 1.28 2005/02/22 09:56:29 kraxel Exp $
+ *
+ * device driver for philips saa7134 based TV cards
+ * driver core
+ *
+ * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/kmod.h>
+#include <linux/sound.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+MODULE_DESCRIPTION("v4l2 driver module for saa7130/34 based TV cards");
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int irq_debug = 0;
+module_param(irq_debug, int, 0644);
+MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]");
+
+static unsigned int core_debug = 0;
+module_param(core_debug, int, 0644);
+MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
+
+static unsigned int gpio_tracking = 0;
+module_param(gpio_tracking, int, 0644);
+MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]");
+
+static unsigned int oss = 0;
+module_param(oss, int, 0444);
+MODULE_PARM_DESC(oss,"register oss devices (default: no)");
+
+static unsigned int latency = UNSET;
+module_param(latency, int, 0444);
+MODULE_PARM_DESC(latency,"pci latency timer");
+
+static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+static unsigned int vbi_nr[]   = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+static unsigned int dsp_nr[]   = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+static unsigned int mixer_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+static unsigned int tuner[]    = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+static unsigned int card[]     = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(video_nr, int, NULL, 0444);
+module_param_array(vbi_nr,   int, NULL, 0444);
+module_param_array(radio_nr, int, NULL, 0444);
+module_param_array(dsp_nr,   int, NULL, 0444);
+module_param_array(mixer_nr, int, NULL, 0444);
+module_param_array(tuner,    int, NULL, 0444);
+module_param_array(card,     int, NULL, 0444);
+
+MODULE_PARM_DESC(video_nr, "video device number");
+MODULE_PARM_DESC(vbi_nr,   "vbi device number");
+MODULE_PARM_DESC(radio_nr, "radio device number");
+MODULE_PARM_DESC(dsp_nr,   "oss dsp device number");
+MODULE_PARM_DESC(mixer_nr, "oss mixer device number");
+MODULE_PARM_DESC(tuner,    "tuner type");
+MODULE_PARM_DESC(card,     "card type");
+
+static DECLARE_MUTEX(devlist_lock);
+LIST_HEAD(saa7134_devlist);
+static LIST_HEAD(mops_list);
+static unsigned int saa7134_devcount;
+
+#define dprintk(fmt, arg...)	if (core_debug) \
+	printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg)
+
+/* ------------------------------------------------------------------ */
+/* debug help functions                                               */
+
+static const char *v4l1_ioctls[] = {
+	"0", "GCAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
+	"CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
+	"SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
+	"GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
+	"SMICROCODE", "GVBIFMT", "SVBIFMT" };
+#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
+
+static const char *v4l2_ioctls[] = {
+	"QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT",
+	"G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF",
+	"G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON",
+	"STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD",
+	"ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER",
+	"G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL",
+	"QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43",
+	"44", "45",  "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT",
+	"S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR",
+	"S_MODULATOR"
+};
+#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
+
+static const char *osspcm_ioctls[] = {
+	"RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT",
+	"CHANNELS", "?", "POST", "SUBDIVIDE", "SETFRAGMENT", "GETFMTS",
+	"GETOSPACE", "GETISPACE", "NONBLOCK", "GETCAPS", "GET/SETTRIGGER",
+	"GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO",
+	"SETDUPLEX", "GETODELAY"
+};
+#define OSSPCM_IOCTLS ARRAY_SIZE(v4l2_ioctls)
+
+void saa7134_print_ioctl(char *name, unsigned int cmd)
+{
+	char *dir;
+
+	switch (_IOC_DIR(cmd)) {
+	case _IOC_NONE:              dir = "--"; break;
+	case _IOC_READ:              dir = "r-"; break;
+	case _IOC_WRITE:             dir = "-w"; break;
+	case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
+	default:                     dir = "??"; break;
+	}
+	switch (_IOC_TYPE(cmd)) {
+	case 'v':
+		printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n",
+		       name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
+		       v4l1_ioctls[_IOC_NR(cmd)] : "???");
+		break;
+	case 'V':
+		printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n",
+		       name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ?
+		       v4l2_ioctls[_IOC_NR(cmd)] : "???");
+		break;
+	case 'P':
+		printk(KERN_DEBUG "%s: ioctl 0x%08x (oss dsp, %s, SNDCTL_DSP_%s)\n",
+		       name, cmd, dir, (_IOC_NR(cmd) < OSSPCM_IOCTLS) ?
+		       osspcm_ioctls[_IOC_NR(cmd)] : "???");
+		break;
+	case 'M':
+		printk(KERN_DEBUG "%s: ioctl 0x%08x (oss mixer, %s, #%d)\n",
+		       name, cmd, dir, _IOC_NR(cmd));
+		break;
+	default:
+		printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
+		       name, cmd, dir, _IOC_NR(cmd));
+	}
+}
+
+void saa7134_track_gpio(struct saa7134_dev *dev, char *msg)
+{
+	unsigned long mode,status;
+
+	if (!gpio_tracking)
+		return;
+	/* rising SAA7134_GPIO_GPRESCAN reads the status */
+	saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,0);
+	saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,SAA7134_GPIO_GPRESCAN);
+	mode   = saa_readl(SAA7134_GPIO_GPMODE0   >> 2) & 0xfffffff;
+	status = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & 0xfffffff;
+	printk(KERN_DEBUG
+	       "%s: gpio: mode=0x%07lx in=0x%07lx out=0x%07lx [%s]\n",
+	       dev->name, mode, (~mode) & status, mode & status, msg);
+}
+
+/* ------------------------------------------------------------------ */
+
+#if 0
+static char *dec1_bits[8] = {
+	"DCSTD0", "DCSCT1", "WIPA", "GLIMB",
+	"GLIMT", "SLTCA", "HLCK"
+};
+static char *dec2_bits[8] = {
+	"RDCAP", "COPRO", "COLSTR", "TYPE3",
+	NULL, "FIDT", "HLVLN", "INTL"
+};
+static char *scale1_bits[8] = {
+	"VID_A", "VBI_A", NULL, NULL, "VID_B", "VBI_B"
+};
+static char *scale2_bits[8] = {
+	"TRERR", "CFERR", "LDERR", "WASRST",
+	"FIDSCI", "FIDSCO", "D6^D5", "TASK"
+};
+
+static void dump_statusreg(struct saa7134_dev *dev, int reg,
+			   char *regname, char **bits)
+{
+	int value,i;
+
+	value = saa_readb(reg);
+	printk(KERN_DEBUG "%s: %s:", dev->name, regname);
+	for (i = 7; i >= 0; i--) {
+		if (NULL == bits[i])
+			continue;
+		printk(" %s=%d", bits[i], (value & (1 << i)) ? 1 : 0);
+	}
+	printk("\n");
+}
+
+static void dump_statusregs(struct saa7134_dev *dev)
+{
+	dump_statusreg(dev,SAA7134_STATUS_VIDEO1,"dec1",dec1_bits);
+	dump_statusreg(dev,SAA7134_STATUS_VIDEO2,"dec2",dec2_bits);
+	dump_statusreg(dev,SAA7134_SCALER_STATUS0,"scale0",scale1_bits);
+	dump_statusreg(dev,SAA7134_SCALER_STATUS1,"scale1",scale2_bits);
+}
+#endif
+
+/* ----------------------------------------------------------- */
+/* delayed request_module                                      */
+
+#ifdef CONFIG_MODULES
+
+static int need_empress;
+static int need_dvb;
+
+static int pending_call(struct notifier_block *self, unsigned long state,
+			void *module)
+{
+	if (module != THIS_MODULE || state != MODULE_STATE_LIVE)
+		return NOTIFY_DONE;
+
+        if (need_empress)
+                request_module("saa7134-empress");
+        if (need_dvb)
+                request_module("saa7134-dvb");
+	return NOTIFY_DONE;
+}
+
+static int pending_registered;
+static struct notifier_block pending_notifier = {
+	.notifier_call = pending_call,
+};
+
+static void request_module_depend(char *name, int *flag)
+{
+	switch (THIS_MODULE->state) {
+	case MODULE_STATE_COMING:
+		if (!pending_registered) {
+			register_module_notifier(&pending_notifier);
+			pending_registered = 1;
+		}
+		*flag = 1;
+		break;
+	case MODULE_STATE_LIVE:
+		request_module(name);
+		break;
+	default:
+		/* nothing */;
+		break;
+	}
+}
+
+#else
+
+#define request_module_depend(name,flag)
+
+#endif /* CONFIG_MODULES */
+
+/* ------------------------------------------------------------------ */
+
+/* nr of (saa7134-)pages for the given buffer size */
+static int saa7134_buffer_pages(int size)
+{
+	size  = PAGE_ALIGN(size);
+	size += PAGE_SIZE; /* for non-page-aligned buffers */
+	size /= 4096;
+	return size;
+}
+
+/* calc max # of buffers from size (must not exceed the 4MB virtual
+ * address space per DMA channel) */
+int saa7134_buffer_count(unsigned int size, unsigned int count)
+{
+	unsigned int maxcount;
+
+	maxcount = 1024 / saa7134_buffer_pages(size);
+	if (count > maxcount)
+		count = maxcount;
+	return count;
+}
+
+int saa7134_buffer_startpage(struct saa7134_buf *buf)
+{
+	return saa7134_buffer_pages(buf->vb.bsize) * buf->vb.i;
+}
+
+unsigned long saa7134_buffer_base(struct saa7134_buf *buf)
+{
+	unsigned long base;
+
+	base  = saa7134_buffer_startpage(buf) * 4096;
+	base += buf->vb.dma.sglist[0].offset;
+	return base;
+}
+
+/* ------------------------------------------------------------------ */
+
+int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt)
+{
+        u32          *cpu;
+        dma_addr_t   dma_addr;
+
+	cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr);
+	if (NULL == cpu)
+		return -ENOMEM;
+	pt->size = SAA7134_PGTABLE_SIZE;
+	pt->cpu  = cpu;
+	pt->dma  = dma_addr;
+	return 0;
+}
+
+int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt,
+			  struct scatterlist *list, unsigned int length,
+			  unsigned int startpage)
+{
+	u32           *ptr;
+	unsigned int  i,p;
+
+	BUG_ON(NULL == pt || NULL == pt->cpu);
+
+	ptr = pt->cpu + startpage;
+	for (i = 0; i < length; i++, list++)
+		for (p = 0; p * 4096 < list->length; p++, ptr++)
+			*ptr = sg_dma_address(list) - list->offset;
+	return 0;
+}
+
+void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt)
+{
+	if (NULL == pt->cpu)
+		return;
+	pci_free_consistent(pci, pt->size, pt->cpu, pt->dma);
+	pt->cpu = NULL;
+}
+
+/* ------------------------------------------------------------------ */
+
+void saa7134_dma_free(struct saa7134_dev *dev,struct saa7134_buf *buf)
+{
+	if (in_interrupt())
+		BUG();
+
+	videobuf_waiton(&buf->vb,0,0);
+	videobuf_dma_pci_unmap(dev->pci, &buf->vb.dma);
+	videobuf_dma_free(&buf->vb.dma);
+	buf->vb.state = STATE_NEEDS_INIT;
+}
+
+/* ------------------------------------------------------------------ */
+
+int saa7134_buffer_queue(struct saa7134_dev *dev,
+			 struct saa7134_dmaqueue *q,
+			 struct saa7134_buf *buf)
+{
+	struct saa7134_buf *next = NULL;
+
+	assert_spin_locked(&dev->slock);
+	dprintk("buffer_queue %p\n",buf);
+	if (NULL == q->curr) {
+		if (!q->need_two) {
+			q->curr = buf;
+			buf->activate(dev,buf,NULL);
+		} else if (list_empty(&q->queue)) {
+			list_add_tail(&buf->vb.queue,&q->queue);
+			buf->vb.state = STATE_QUEUED;
+		} else {
+			next = list_entry(q->queue.next,struct saa7134_buf,
+					  vb.queue);
+			q->curr = buf;
+			buf->activate(dev,buf,next);
+		}
+	} else {
+		list_add_tail(&buf->vb.queue,&q->queue);
+		buf->vb.state = STATE_QUEUED;
+	}
+	return 0;
+}
+
+void saa7134_buffer_finish(struct saa7134_dev *dev,
+			   struct saa7134_dmaqueue *q,
+			   unsigned int state)
+{
+	assert_spin_locked(&dev->slock);
+	dprintk("buffer_finish %p\n",q->curr);
+
+	/* finish current buffer */
+	q->curr->vb.state = state;
+	do_gettimeofday(&q->curr->vb.ts);
+	wake_up(&q->curr->vb.done);
+	q->curr = NULL;
+}
+
+void saa7134_buffer_next(struct saa7134_dev *dev,
+			 struct saa7134_dmaqueue *q)
+{
+	struct saa7134_buf *buf,*next = NULL;
+
+	assert_spin_locked(&dev->slock);
+	BUG_ON(NULL != q->curr);
+
+	if (!list_empty(&q->queue)) {
+		/* activate next one from queue */
+		buf = list_entry(q->queue.next,struct saa7134_buf,vb.queue);
+		dprintk("buffer_next %p [prev=%p/next=%p]\n",
+			buf,q->queue.prev,q->queue.next);
+		list_del(&buf->vb.queue);
+		if (!list_empty(&q->queue))
+			next = list_entry(q->queue.next,struct saa7134_buf,
+					  vb.queue);
+		q->curr = buf;
+		buf->activate(dev,buf,next);
+		dprintk("buffer_next #2 prev=%p/next=%p\n",
+			q->queue.prev,q->queue.next);
+	} else {
+		/* nothing to do -- just stop DMA */
+		dprintk("buffer_next %p\n",NULL);
+		saa7134_set_dmabits(dev);
+		del_timer(&q->timeout);
+	}
+}
+
+void saa7134_buffer_timeout(unsigned long data)
+{
+	struct saa7134_dmaqueue *q = (struct saa7134_dmaqueue*)data;
+	struct saa7134_dev *dev = q->dev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->slock,flags);
+
+	/* try to reset the hardware (SWRST) */
+	saa_writeb(SAA7134_REGION_ENABLE, 0x00);
+	saa_writeb(SAA7134_REGION_ENABLE, 0x80);
+	saa_writeb(SAA7134_REGION_ENABLE, 0x00);
+
+	/* flag current buffer as failed,
+	   try to start over with the next one. */
+	if (q->curr) {
+		dprintk("timeout on %p\n",q->curr);
+		saa7134_buffer_finish(dev,q,STATE_ERROR);
+	}
+	saa7134_buffer_next(dev,q);
+	spin_unlock_irqrestore(&dev->slock,flags);
+}
+
+/* ------------------------------------------------------------------ */
+
+int saa7134_set_dmabits(struct saa7134_dev *dev)
+{
+	u32 split, task=0, ctrl=0, irq=0;
+	enum v4l2_field cap = V4L2_FIELD_ANY;
+	enum v4l2_field ov  = V4L2_FIELD_ANY;
+
+	assert_spin_locked(&dev->slock);
+
+	/* video capture -- dma 0 + video task A */
+	if (dev->video_q.curr) {
+		task |= 0x01;
+		ctrl |= SAA7134_MAIN_CTRL_TE0;
+		irq  |= SAA7134_IRQ1_INTE_RA0_1 |
+			SAA7134_IRQ1_INTE_RA0_0;
+	        cap = dev->video_q.curr->vb.field;
+	}
+
+	/* video capture -- dma 1+2 (planar modes) */
+	if (dev->video_q.curr &&
+	    dev->video_q.curr->fmt->planar) {
+		ctrl |= SAA7134_MAIN_CTRL_TE4 |
+			SAA7134_MAIN_CTRL_TE5;
+	}
+
+	/* screen overlay -- dma 0 + video task B */
+	if (dev->ovenable) {
+		task |= 0x10;
+		ctrl |= SAA7134_MAIN_CTRL_TE1;
+		ov = dev->ovfield;
+	}
+
+	/* vbi capture -- dma 0 + vbi task A+B */
+	if (dev->vbi_q.curr) {
+		task |= 0x22;
+		ctrl |= SAA7134_MAIN_CTRL_TE2 |
+			SAA7134_MAIN_CTRL_TE3;
+		irq  |= SAA7134_IRQ1_INTE_RA0_7 |
+			SAA7134_IRQ1_INTE_RA0_6 |
+			SAA7134_IRQ1_INTE_RA0_5 |
+			SAA7134_IRQ1_INTE_RA0_4;
+	}
+
+	/* audio capture -- dma 3 */
+	if (dev->oss.dma_running) {
+		ctrl |= SAA7134_MAIN_CTRL_TE6;
+		irq  |= SAA7134_IRQ1_INTE_RA3_1 |
+			SAA7134_IRQ1_INTE_RA3_0;
+	}
+
+	/* TS capture -- dma 5 */
+	if (dev->ts_q.curr) {
+		ctrl |= SAA7134_MAIN_CTRL_TE5;
+		irq  |= SAA7134_IRQ1_INTE_RA2_3 |
+			SAA7134_IRQ1_INTE_RA2_2 |
+			SAA7134_IRQ1_INTE_RA2_1 |
+			SAA7134_IRQ1_INTE_RA2_0;
+	}
+
+	/* set task conditions + field handling */
+	if (V4L2_FIELD_HAS_BOTH(cap) || V4L2_FIELD_HAS_BOTH(ov) || cap == ov) {
+		/* default config -- use full frames */
+		saa_writeb(SAA7134_TASK_CONDITIONS(TASK_A), 0x0d);
+		saa_writeb(SAA7134_TASK_CONDITIONS(TASK_B), 0x0d);
+		saa_writeb(SAA7134_FIELD_HANDLING(TASK_A),  0x02);
+		saa_writeb(SAA7134_FIELD_HANDLING(TASK_B),  0x02);
+		split = 0;
+	} else {
+		/* split fields between tasks */
+		if (V4L2_FIELD_TOP == cap) {
+			/* odd A, even B, repeat */
+			saa_writeb(SAA7134_TASK_CONDITIONS(TASK_A), 0x0d);
+			saa_writeb(SAA7134_TASK_CONDITIONS(TASK_B), 0x0e);
+		} else {
+			/* odd B, even A, repeat */
+			saa_writeb(SAA7134_TASK_CONDITIONS(TASK_A), 0x0e);
+			saa_writeb(SAA7134_TASK_CONDITIONS(TASK_B), 0x0d);
+		}
+		saa_writeb(SAA7134_FIELD_HANDLING(TASK_A),  0x01);
+		saa_writeb(SAA7134_FIELD_HANDLING(TASK_B),  0x01);
+		split = 1;
+	}
+
+	/* irqs */
+	saa_writeb(SAA7134_REGION_ENABLE, task);
+	saa_writel(SAA7134_IRQ1,          irq);
+	saa_andorl(SAA7134_MAIN_CTRL,
+		   SAA7134_MAIN_CTRL_TE0 |
+		   SAA7134_MAIN_CTRL_TE1 |
+		   SAA7134_MAIN_CTRL_TE2 |
+		   SAA7134_MAIN_CTRL_TE3 |
+		   SAA7134_MAIN_CTRL_TE4 |
+		   SAA7134_MAIN_CTRL_TE5 |
+		   SAA7134_MAIN_CTRL_TE6,
+		   ctrl);
+	dprintk("dmabits: task=0x%02x ctrl=0x%02x irq=0x%x split=%s\n",
+		task, ctrl, irq, split ? "no" : "yes");
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* IRQ handler + helpers                                              */
+
+static char *irqbits[] = {
+	"DONE_RA0", "DONE_RA1", "DONE_RA2", "DONE_RA3",
+	"AR", "PE", "PWR_ON", "RDCAP", "INTL", "FIDT", "MMC",
+	"TRIG_ERR", "CONF_ERR", "LOAD_ERR",
+	"GPIO16?", "GPIO18", "GPIO22", "GPIO23"
+};
+#define IRQBITS ARRAY_SIZE(irqbits)
+
+static void print_irqstatus(struct saa7134_dev *dev, int loop,
+			    unsigned long report, unsigned long status)
+{
+	unsigned int i;
+
+	printk(KERN_DEBUG "%s/irq[%d,%ld]: r=0x%lx s=0x%02lx",
+	       dev->name,loop,jiffies,report,status);
+	for (i = 0; i < IRQBITS; i++) {
+		if (!(report & (1 << i)))
+			continue;
+		printk(" %s",irqbits[i]);
+	}
+	if (report & SAA7134_IRQ_REPORT_DONE_RA0) {
+		printk(" | RA0=%s,%s,%s,%ld",
+		       (status & 0x40) ? "vbi"  : "video",
+		       (status & 0x20) ? "b"    : "a",
+		       (status & 0x10) ? "odd"  : "even",
+		       (status & 0x0f));
+	}
+	printk("\n");
+}
+
+static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct saa7134_dev *dev = (struct saa7134_dev*) dev_id;
+	unsigned long report,status;
+	int loop, handled = 0;
+
+	for (loop = 0; loop < 10; loop++) {
+		report = saa_readl(SAA7134_IRQ_REPORT);
+		status = saa_readl(SAA7134_IRQ_STATUS);
+		if (0 == report) {
+			if (irq_debug > 1)
+				printk(KERN_DEBUG "%s/irq: no (more) work\n",
+				       dev->name);
+			goto out;
+		}
+		handled = 1;
+		saa_writel(SAA7134_IRQ_REPORT,report);
+		if (irq_debug)
+			print_irqstatus(dev,loop,report,status);
+
+#if 0
+		if (report & SAA7134_IRQ_REPORT_CONF_ERR)
+			dump_statusregs(dev);
+#endif
+
+		if (report & SAA7134_IRQ_REPORT_RDCAP /* _INTL */)
+			saa7134_irq_video_intl(dev);
+
+		if ((report & SAA7134_IRQ_REPORT_DONE_RA0) &&
+		    (status & 0x60) == 0)
+			saa7134_irq_video_done(dev,status);
+
+		if ((report & SAA7134_IRQ_REPORT_DONE_RA0) &&
+		    (status & 0x40) == 0x40)
+			saa7134_irq_vbi_done(dev,status);
+
+		if ((report & SAA7134_IRQ_REPORT_DONE_RA2) &&
+		    card_has_mpeg(dev))
+			saa7134_irq_ts_done(dev,status);
+
+		if ((report & SAA7134_IRQ_REPORT_DONE_RA3))
+			saa7134_irq_oss_done(dev,status);
+
+		if ((report & (SAA7134_IRQ_REPORT_GPIO16 |
+			       SAA7134_IRQ_REPORT_GPIO18)) &&
+		    dev->remote)
+			saa7134_input_irq(dev);
+	}
+
+	if (10 == loop) {
+		print_irqstatus(dev,loop,report,status);
+		if (report & SAA7134_IRQ_REPORT_PE) {
+			/* disable all parity error */
+			printk(KERN_WARNING "%s/irq: looping -- "
+			       "clearing PE (parity error!) enable bit\n",dev->name);
+			saa_clearl(SAA7134_IRQ2,SAA7134_IRQ2_INTE_PE);
+		} else if (report & (SAA7134_IRQ_REPORT_GPIO16 |
+				     SAA7134_IRQ_REPORT_GPIO18)) {
+			/* disable gpio IRQs */
+			printk(KERN_WARNING "%s/irq: looping -- "
+			       "clearing GPIO enable bits\n",dev->name);
+			saa_clearl(SAA7134_IRQ2, (SAA7134_IRQ2_INTE_GPIO16 |
+						  SAA7134_IRQ2_INTE_GPIO18));
+		} else {
+			/* disable all irqs */
+			printk(KERN_WARNING "%s/irq: looping -- "
+			       "clearing all enable bits\n",dev->name);
+			saa_writel(SAA7134_IRQ1,0);
+			saa_writel(SAA7134_IRQ2,0);
+		}
+	}
+
+ out:
+	return IRQ_RETVAL(handled);
+}
+
+/* ------------------------------------------------------------------ */
+
+/* early init (no i2c, no irq) */
+static int saa7134_hwinit1(struct saa7134_dev *dev)
+{
+	dprintk("hwinit1\n");
+
+	saa_writel(SAA7134_IRQ1, 0);
+	saa_writel(SAA7134_IRQ2, 0);
+        init_MUTEX(&dev->lock);
+	spin_lock_init(&dev->slock);
+
+	saa7134_track_gpio(dev,"pre-init");
+	saa7134_video_init1(dev);
+	saa7134_vbi_init1(dev);
+	if (card_has_mpeg(dev))
+		saa7134_ts_init1(dev);
+	saa7134_input_init1(dev);
+
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		saa7134_oss_init1(dev);
+		break;
+	}
+
+	/* RAM FIFO config */
+	saa_writel(SAA7134_FIFO_SIZE, 0x08070503);
+	saa_writel(SAA7134_THRESHOULD,0x02020202);
+
+	/* enable audio + video processing */
+	saa_writel(SAA7134_MAIN_CTRL,
+		   SAA7134_MAIN_CTRL_VPLLE |
+		   SAA7134_MAIN_CTRL_APLLE |
+		   SAA7134_MAIN_CTRL_EXOSC |
+		   SAA7134_MAIN_CTRL_EVFE1 |
+		   SAA7134_MAIN_CTRL_EVFE2 |
+		   SAA7134_MAIN_CTRL_ESFE  |
+		   SAA7134_MAIN_CTRL_EBADC |
+		   SAA7134_MAIN_CTRL_EBDAC);
+
+	/* enable peripheral devices */
+	saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+
+	/* set vertical line numbering start (vbi needs this) */
+	saa_writeb(SAA7134_SOURCE_TIMING2, 0x20);
+
+	return 0;
+}
+
+/* late init (with i2c + irq) */
+static int saa7134_hwinit2(struct saa7134_dev *dev)
+{
+	dprintk("hwinit2\n");
+
+	saa7134_video_init2(dev);
+	saa7134_tvaudio_init2(dev);
+
+	/* enable IRQ's */
+	saa_writel(SAA7134_IRQ1, 0);
+	saa_writel(SAA7134_IRQ2, dev->irq2_mask);
+
+	return 0;
+}
+
+/* shutdown */
+static int saa7134_hwfini(struct saa7134_dev *dev)
+{
+	dprintk("hwfini\n");
+
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		saa7134_oss_fini(dev);
+		break;
+	}
+	if (card_has_mpeg(dev))
+		saa7134_ts_fini(dev);
+	saa7134_input_fini(dev);
+	saa7134_vbi_fini(dev);
+	saa7134_video_fini(dev);
+	saa7134_tvaudio_fini(dev);
+	return 0;
+}
+
+static void __devinit must_configure_manually(void)
+{
+	unsigned int i,p;
+
+	printk(KERN_WARNING
+	       "saa7134: <rant>\n"
+	       "saa7134:  Congratulations!  Your TV card vendor saved a few\n"
+	       "saa7134:  cents for a eeprom, thus your pci board has no\n"
+	       "saa7134:  subsystem ID and I can't identify it automatically\n"
+	       "saa7134: </rant>\n"
+	       "saa7134: I feel better now.  Ok, here are the good news:\n"
+	       "saa7134: You can use the card=<nr> insmod option to specify\n"
+	       "saa7134: which board do you have.  The list:\n");
+	for (i = 0; i < saa7134_bcount; i++) {
+		printk(KERN_WARNING "saa7134:   card=%d -> %-40.40s",
+		       i,saa7134_boards[i].name);
+		for (p = 0; saa7134_pci_tbl[p].driver_data; p++) {
+			if (saa7134_pci_tbl[p].driver_data != i)
+				continue;
+			printk(" %04x:%04x",
+			       saa7134_pci_tbl[p].subvendor,
+			       saa7134_pci_tbl[p].subdevice);
+		}
+		printk("\n");
+	}
+}
+
+static struct video_device *vdev_init(struct saa7134_dev *dev,
+				      struct video_device *template,
+				      char *type)
+{
+	struct video_device *vfd;
+
+	vfd = video_device_alloc();
+	if (NULL == vfd)
+		return NULL;
+	*vfd = *template;
+	vfd->minor   = -1;
+	vfd->dev     = &dev->pci->dev;
+	vfd->release = video_device_release;
+	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
+		 dev->name, type, saa7134_boards[dev->board].name);
+	return vfd;
+}
+
+static void saa7134_unregister_video(struct saa7134_dev *dev)
+{
+	if (dev->video_dev) {
+		if (-1 != dev->video_dev->minor)
+			video_unregister_device(dev->video_dev);
+		else
+			video_device_release(dev->video_dev);
+		dev->video_dev = NULL;
+	}
+	if (dev->vbi_dev) {
+		if (-1 != dev->vbi_dev->minor)
+			video_unregister_device(dev->vbi_dev);
+		else
+			video_device_release(dev->vbi_dev);
+		dev->vbi_dev = NULL;
+	}
+	if (dev->radio_dev) {
+		if (-1 != dev->radio_dev->minor)
+			video_unregister_device(dev->radio_dev);
+		else
+			video_device_release(dev->radio_dev);
+		dev->radio_dev = NULL;
+	}
+}
+
+static void mpeg_ops_attach(struct saa7134_mpeg_ops *ops,
+			    struct saa7134_dev *dev)
+{
+	int err;
+
+	if (NULL != dev->mops)
+		return;
+	if (saa7134_boards[dev->board].mpeg != ops->type)
+		return;
+	err = ops->init(dev);
+	if (0 != err)
+		return;
+	dev->mops = ops;
+}
+
+static void mpeg_ops_detach(struct saa7134_mpeg_ops *ops,
+			    struct saa7134_dev *dev)
+{
+	if (NULL == dev->mops)
+		return;
+	if (dev->mops != ops)
+		return;
+	dev->mops->fini(dev);
+	dev->mops = NULL;
+}
+
+static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
+				     const struct pci_device_id *pci_id)
+{
+	struct saa7134_dev *dev;
+	struct list_head *item;
+	struct saa7134_mpeg_ops *mops;
+	int err;
+
+	dev = kmalloc(sizeof(*dev),GFP_KERNEL);
+	if (NULL == dev)
+		return -ENOMEM;
+	memset(dev,0,sizeof(*dev));
+
+	/* pci init */
+	dev->pci = pci_dev;
+	if (pci_enable_device(pci_dev)) {
+		err = -EIO;
+		goto fail1;
+	}
+
+	dev->nr = saa7134_devcount;
+	sprintf(dev->name,"saa%x[%d]",pci_dev->device,dev->nr);
+
+	/* pci quirks */
+	if (pci_pci_problems) {
+		if (pci_pci_problems & PCIPCI_TRITON)
+			printk(KERN_INFO "%s: quirk: PCIPCI_TRITON\n", dev->name);
+		if (pci_pci_problems & PCIPCI_NATOMA)
+			printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA\n", dev->name);
+		if (pci_pci_problems & PCIPCI_VIAETBF)
+			printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF\n", dev->name);
+		if (pci_pci_problems & PCIPCI_VSFX)
+			printk(KERN_INFO "%s: quirk: PCIPCI_VSFX\n",dev->name);
+#ifdef PCIPCI_ALIMAGIK
+		if (pci_pci_problems & PCIPCI_ALIMAGIK) {
+			printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
+			       dev->name);
+			latency = 0x0A;
+		}
+#endif
+	}
+	if (UNSET != latency) {
+		printk(KERN_INFO "%s: setting pci latency timer to %d\n",
+		       dev->name,latency);
+		pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);
+	}
+
+	/* print pci info */
+	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
+        printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, "
+	       "latency: %d, mmio: 0x%lx\n", dev->name,
+	       pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
+	       dev->pci_lat,pci_resource_start(pci_dev,0));
+	pci_set_master(pci_dev);
+	if (!pci_dma_supported(pci_dev,0xffffffff)) {
+		printk("%s: Oops: no 32bit PCI DMA ???\n",dev->name);
+		err = -EIO;
+		goto fail1;
+	}
+
+	/* board config */
+	dev->board = pci_id->driver_data;
+	if (card[dev->nr] >= 0 &&
+	    card[dev->nr] < saa7134_bcount)
+		dev->board = card[dev->nr];
+	if (SAA7134_BOARD_NOAUTO == dev->board) {
+		must_configure_manually();
+		dev->board = SAA7134_BOARD_UNKNOWN;
+	}
+	dev->tuner_type   = saa7134_boards[dev->board].tuner_type;
+	dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf;
+	if (UNSET != tuner[dev->nr])
+		dev->tuner_type = tuner[dev->nr];
+        printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+	       dev->name,pci_dev->subsystem_vendor,
+	       pci_dev->subsystem_device,saa7134_boards[dev->board].name,
+	       dev->board, card[dev->nr] == dev->board ?
+	       "insmod option" : "autodetected");
+
+	/* get mmio */
+	if (!request_mem_region(pci_resource_start(pci_dev,0),
+				pci_resource_len(pci_dev,0),
+				dev->name)) {
+		err = -EBUSY;
+		printk(KERN_ERR "%s: can't get MMIO memory @ 0x%lx\n",
+		       dev->name,pci_resource_start(pci_dev,0));
+		goto fail1;
+	}
+	dev->lmmio = ioremap(pci_resource_start(pci_dev,0), 0x1000);
+	dev->bmmio = (__u8 __iomem *)dev->lmmio;
+	if (NULL == dev->lmmio) {
+		err = -EIO;
+		printk(KERN_ERR "%s: can't ioremap() MMIO memory\n",
+		       dev->name);
+		goto fail2;
+	}
+
+	/* initialize hardware #1 */
+   	dev->irq2_mask =
+		SAA7134_IRQ2_INTE_DEC3    |
+		SAA7134_IRQ2_INTE_DEC2    |
+		SAA7134_IRQ2_INTE_DEC1    |
+		SAA7134_IRQ2_INTE_DEC0    |
+		SAA7134_IRQ2_INTE_PE      |
+		SAA7134_IRQ2_INTE_AR;
+	saa7134_board_init1(dev);
+	saa7134_hwinit1(dev);
+
+	/* get irq */
+	err = request_irq(pci_dev->irq, saa7134_irq,
+			  SA_SHIRQ | SA_INTERRUPT, dev->name, dev);
+	if (err < 0) {
+		printk(KERN_ERR "%s: can't get IRQ %d\n",
+		       dev->name,pci_dev->irq);
+		goto fail3;
+	}
+
+	/* wait a bit, register i2c bus */
+	msleep(100);
+	saa7134_i2c_register(dev);
+
+	/* initialize hardware #2 */
+	saa7134_board_init2(dev);
+	saa7134_hwinit2(dev);
+
+	/* load i2c helpers */
+	if (TUNER_ABSENT != dev->tuner_type)
+		request_module("tuner");
+	if (dev->tda9887_conf)
+		request_module("tda9887");
+  	if (card_is_empress(dev)) {
+		request_module("saa6752hs");
+		request_module_depend("saa7134-empress",&need_empress);
+	}
+  	if (card_is_dvb(dev))
+		request_module_depend("saa7134-dvb",&need_dvb);
+
+	v4l2_prio_init(&dev->prio);
+
+	/* register v4l devices */
+	dev->video_dev = vdev_init(dev,&saa7134_video_template,"video");
+	err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
+				    video_nr[dev->nr]);
+	if (err < 0) {
+		printk(KERN_INFO "%s: can't register video device\n",
+		       dev->name);
+		goto fail4;
+	}
+	printk(KERN_INFO "%s: registered device video%d [v4l2]\n",
+	       dev->name,dev->video_dev->minor & 0x1f);
+
+	dev->vbi_dev = vdev_init(dev,&saa7134_vbi_template,"vbi");
+	err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
+				    vbi_nr[dev->nr]);
+	if (err < 0)
+		goto fail4;
+	printk(KERN_INFO "%s: registered device vbi%d\n",
+	       dev->name,dev->vbi_dev->minor & 0x1f);
+
+	if (card_has_radio(dev)) {
+		dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio");
+		err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
+					    radio_nr[dev->nr]);
+		if (err < 0)
+			goto fail4;
+		printk(KERN_INFO "%s: registered device radio%d\n",
+		       dev->name,dev->radio_dev->minor & 0x1f);
+	}
+
+	/* register oss devices */
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		if (oss) {
+			err = dev->oss.minor_dsp =
+				register_sound_dsp(&saa7134_dsp_fops,
+						   dsp_nr[dev->nr]);
+			if (err < 0) {
+				goto fail4;
+			}
+			printk(KERN_INFO "%s: registered device dsp%d\n",
+			       dev->name,dev->oss.minor_dsp >> 4);
+
+			err = dev->oss.minor_mixer =
+				register_sound_mixer(&saa7134_mixer_fops,
+						     mixer_nr[dev->nr]);
+			if (err < 0)
+				goto fail5;
+			printk(KERN_INFO "%s: registered device mixer%d\n",
+			       dev->name,dev->oss.minor_mixer >> 4);
+		}
+		break;
+	}
+
+	/* everything worked */
+	pci_set_drvdata(pci_dev,dev);
+	saa7134_devcount++;
+
+	down(&devlist_lock);
+	list_for_each(item,&mops_list) {
+		mops = list_entry(item, struct saa7134_mpeg_ops, next);
+		mpeg_ops_attach(mops, dev);
+	}
+	list_add_tail(&dev->devlist,&saa7134_devlist);
+	up(&devlist_lock);
+
+	/* check for signal */
+	saa7134_irq_video_intl(dev);
+	return 0;
+
+ fail5:
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		if (oss)
+			unregister_sound_dsp(dev->oss.minor_dsp);
+		break;
+	}
+ fail4:
+	saa7134_unregister_video(dev);
+	saa7134_i2c_unregister(dev);
+	free_irq(pci_dev->irq, dev);
+ fail3:
+	saa7134_hwfini(dev);
+	iounmap(dev->lmmio);
+ fail2:
+	release_mem_region(pci_resource_start(pci_dev,0),
+			   pci_resource_len(pci_dev,0));
+ fail1:
+	kfree(dev);
+	return err;
+}
+
+static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
+{
+        struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
+	struct list_head *item;
+	struct saa7134_mpeg_ops *mops;
+
+	/* debugging ... */
+	if (irq_debug) {
+		u32 report = saa_readl(SAA7134_IRQ_REPORT);
+		u32 status = saa_readl(SAA7134_IRQ_STATUS);
+		print_irqstatus(dev,42,report,status);
+	}
+
+	/* disable peripheral devices */
+	saa_writeb(SAA7134_SPECIAL_MODE,0);
+
+	/* shutdown hardware */
+	saa_writel(SAA7134_IRQ1,0);
+	saa_writel(SAA7134_IRQ2,0);
+	saa_writel(SAA7134_MAIN_CTRL,0);
+
+	/* shutdown subsystems */
+	saa7134_hwfini(dev);
+
+	/* unregister */
+	down(&devlist_lock);
+	list_del(&dev->devlist);
+	list_for_each(item,&mops_list) {
+		mops = list_entry(item, struct saa7134_mpeg_ops, next);
+		mpeg_ops_detach(mops, dev);
+	}
+	up(&devlist_lock);
+	saa7134_devcount--;
+
+	saa7134_i2c_unregister(dev);
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		if (oss) {
+			unregister_sound_mixer(dev->oss.minor_mixer);
+			unregister_sound_dsp(dev->oss.minor_dsp);
+		}
+		break;
+	}
+	saa7134_unregister_video(dev);
+
+	/* release ressources */
+	free_irq(pci_dev->irq, dev);
+	iounmap(dev->lmmio);
+	release_mem_region(pci_resource_start(pci_dev,0),
+			   pci_resource_len(pci_dev,0));
+
+#if 0  /* causes some trouble when reinserting the driver ... */
+	pci_disable_device(pci_dev);
+#endif
+	pci_set_drvdata(pci_dev, NULL);
+
+	/* free memory */
+	kfree(dev);
+}
+
+/* ----------------------------------------------------------- */
+
+int saa7134_ts_register(struct saa7134_mpeg_ops *ops)
+{
+	struct list_head *item;
+	struct saa7134_dev *dev;
+
+	down(&devlist_lock);
+	list_for_each(item,&saa7134_devlist) {
+		dev = list_entry(item, struct saa7134_dev, devlist);
+		mpeg_ops_attach(ops, dev);
+	}
+	list_add_tail(&ops->next,&mops_list);
+	up(&devlist_lock);
+	return 0;
+}
+
+void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops)
+{
+	struct list_head *item;
+	struct saa7134_dev *dev;
+
+	down(&devlist_lock);
+	list_del(&ops->next);
+	list_for_each(item,&saa7134_devlist) {
+		dev = list_entry(item, struct saa7134_dev, devlist);
+		mpeg_ops_detach(ops, dev);
+	}
+	up(&devlist_lock);
+}
+
+EXPORT_SYMBOL(saa7134_ts_register);
+EXPORT_SYMBOL(saa7134_ts_unregister);
+
+/* ----------------------------------------------------------- */
+
+static struct pci_driver saa7134_pci_driver = {
+        .name     = "saa7134",
+        .id_table = saa7134_pci_tbl,
+        .probe    = saa7134_initdev,
+        .remove   = __devexit_p(saa7134_finidev),
+};
+
+static int saa7134_init(void)
+{
+	INIT_LIST_HEAD(&saa7134_devlist);
+	printk(KERN_INFO "saa7130/34: v4l2 driver version %d.%d.%d loaded\n",
+	       (SAA7134_VERSION_CODE >> 16) & 0xff,
+	       (SAA7134_VERSION_CODE >>  8) & 0xff,
+	       SAA7134_VERSION_CODE & 0xff);
+#ifdef SNAPSHOT
+	printk(KERN_INFO "saa7130/34: snapshot date %04d-%02d-%02d\n",
+	       SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
+#endif
+	return pci_module_init(&saa7134_pci_driver);
+}
+
+static void saa7134_fini(void)
+{
+#ifdef CONFIG_MODULES
+	if (pending_registered)
+		unregister_module_notifier(&pending_notifier);
+#endif
+	pci_unregister_driver(&saa7134_pci_driver);
+}
+
+module_init(saa7134_init);
+module_exit(saa7134_fini);
+
+/* ----------------------------------------------------------- */
+
+EXPORT_SYMBOL(saa7134_print_ioctl);
+EXPORT_SYMBOL(saa7134_i2c_call_clients);
+EXPORT_SYMBOL(saa7134_devlist);
+EXPORT_SYMBOL(saa7134_boards);
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
new file mode 100644
index 0000000..dd4a6c8
--- /dev/null
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -0,0 +1,266 @@
+/*
+ * $Id: saa7134-dvb.c,v 1.12 2005/02/18 12:28:29 kraxel Exp $
+ *
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/suspend.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+#include "dvb-pll.h"
+#include "mt352.h"
+#include "mt352_priv.h" /* FIXME */
+#include "tda1004x.h"
+
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+static unsigned int antenna_pwr = 0;
+module_param(antenna_pwr, int, 0444);
+MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)");
+
+/* ------------------------------------------------------------------ */
+
+static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on)
+{
+	u32 ok;
+
+	if (!on) {
+		saa_setl(SAA7134_GPIO_GPMODE0 >> 2,     (1 << 26));
+		saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26));
+		return 0;
+	}
+
+	saa_setl(SAA7134_GPIO_GPMODE0 >> 2,     (1 << 26));
+	saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2,   (1 << 26));
+	udelay(10);
+
+	saa_setl(SAA7134_GPIO_GPMODE0 >> 2,     (1 << 28));
+	saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28));
+	udelay(10);
+	saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2,   (1 << 28));
+	udelay(10);
+	ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27);
+	printk("%s: %s %s\n", dev->name, __FUNCTION__,
+	       ok ? "on" : "off");
+
+	if (!ok)
+		saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2,   (1 << 26));
+	return ok;
+}
+
+static int mt352_pinnacle_init(struct dvb_frontend* fe)
+{
+	static u8 clock_config []  = { CLOCK_CTL,  0x3d, 0x28 };
+	static u8 reset []         = { RESET,      0x80 };
+	static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+	static u8 agc_cfg []       = { AGC_TARGET, 0x28, 0xa0 };
+	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x31 };
+	static u8 fsm_ctl_cfg[]    = { 0x7b,       0x04 };
+	static u8 gpp_ctl_cfg []   = { GPP_CTL,    0x0f };
+	static u8 scan_ctl_cfg []  = { SCAN_CTL,   0x0d };
+	static u8 irq_cfg []       = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 };
+	struct saa7134_dev *dev= fe->dvb->priv;
+
+	printk("%s: %s called\n",dev->name,__FUNCTION__);
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(200);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+	mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
+
+	mt352_write(fe, fsm_ctl_cfg,    sizeof(fsm_ctl_cfg));
+	mt352_write(fe, scan_ctl_cfg,   sizeof(scan_ctl_cfg));
+	mt352_write(fe, irq_cfg,        sizeof(irq_cfg));
+	return 0;
+}
+
+static int mt352_pinnacle_pll_set(struct dvb_frontend* fe,
+				  struct dvb_frontend_parameters* params,
+				  u8* pllbuf)
+{
+	static int on  = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE;
+	static int off = TDA9887_PRESENT | TDA9887_PORT2_ACTIVE;
+	struct saa7134_dev *dev = fe->dvb->priv;
+	struct v4l2_frequency f;
+
+	/* set frequency (mt2050) */
+	f.tuner     = 0;
+	f.type      = V4L2_TUNER_DIGITAL_TV;
+	f.frequency = params->frequency / 1000 * 16 / 1000;
+	saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&on);
+	saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f);
+	saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&off);
+
+	pinnacle_antenna_pwr(dev, antenna_pwr);
+
+	/* mt352 setup */
+	mt352_pinnacle_init(fe);
+	pllbuf[0] = 0xc2;
+	pllbuf[1] = 0x00;
+	pllbuf[2] = 0x00;
+	pllbuf[3] = 0x80;
+	pllbuf[4] = 0x00;
+	return 0;
+}
+
+static struct mt352_config pinnacle_300i = {
+	.demod_address = 0x3c >> 1,
+	.adc_clock     = 20333,
+	.if2           = 36150,
+	.no_tuner      = 1,
+	.demod_init    = mt352_pinnacle_init,
+	.pll_set       = mt352_pinnacle_pll_set,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int medion_cardbus_init(struct dvb_frontend* fe)
+{
+	/* anything to do here ??? */
+	return 0;
+}
+
+static int medion_cardbus_pll_set(struct dvb_frontend* fe,
+				  struct dvb_frontend_parameters* params)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	struct v4l2_frequency f;
+
+	/*
+	 * this instructs tuner.o to set the frequency, the call will
+	 * end up in tuner_command(), VIDIOC_S_FREQUENCY switch.
+	 * tda9887.o will see that as well.
+	 */
+	f.tuner     = 0;
+	f.type      = V4L2_TUNER_DIGITAL_TV;
+	f.frequency = params->frequency / 1000 * 16 / 1000;
+	saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f);
+	return 0;
+}
+
+static int fe_request_firmware(struct dvb_frontend* fe,
+			       const struct firmware **fw, char* name)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	return request_firmware(fw, name, &dev->pci->dev);
+}
+
+struct tda1004x_config medion_cardbus = {
+	.demod_address = 0x08,  /* not sure this is correct */
+	.invert        = 0,
+        .invert_oclk   = 0,
+        .pll_init      = medion_cardbus_init,
+        .pll_set       = medion_cardbus_pll_set,
+        .request_firmware = fe_request_firmware,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int dvb_init(struct saa7134_dev *dev)
+{
+	/* init struct videobuf_dvb */
+	dev->ts.nr_bufs    = 32;
+	dev->ts.nr_packets = 32*4;
+	dev->dvb.name = dev->name;
+	videobuf_queue_init(&dev->dvb.dvbq, &saa7134_ts_qops,
+			    dev->pci, &dev->slock,
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			    V4L2_FIELD_ALTERNATE,
+			    sizeof(struct saa7134_buf),
+			    dev);
+
+	switch (dev->board) {
+	case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
+		printk("%s: pinnacle 300i dvb setup\n",dev->name);
+		dev->dvb.frontend = mt352_attach(&pinnacle_300i,
+						 &dev->i2c_adap);
+		break;
+	case SAA7134_BOARD_MD7134:
+		dev->dvb.frontend = tda10046_attach(&medion_cardbus,
+						    &dev->i2c_adap);
+		if (NULL == dev->dvb.frontend)
+			printk("%s: Hmm, looks like this is the old MD7134 "
+			       "version without DVB-T support\n",dev->name);
+		break;
+	default:
+		printk("%s: Huh? unknown DVB card?\n",dev->name);
+		break;
+	}
+
+	if (NULL == dev->dvb.frontend) {
+		printk("%s: frontend initialization failed\n",dev->name);
+		return -1;
+	}
+
+	/* register everything else */
+	return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev);
+}
+
+static int dvb_fini(struct saa7134_dev *dev)
+{
+	static int on  = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE;
+
+	printk("%s: %s\n",dev->name,__FUNCTION__);
+
+	switch (dev->board) {
+	case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
+		/* otherwise we don't detect the tuner on next insmod */
+		saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&on);
+		break;
+	};
+	videobuf_dvb_unregister(&dev->dvb);
+	return 0;
+}
+
+static struct saa7134_mpeg_ops dvb_ops = {
+	.type          = SAA7134_MPEG_DVB,
+	.init          = dvb_init,
+	.fini          = dvb_fini,
+};
+
+static int __init dvb_register(void)
+{
+	return saa7134_ts_register(&dvb_ops);
+}
+
+static void __exit dvb_unregister(void)
+{
+	saa7134_ts_unregister(&dvb_ops);
+}
+
+module_init(dvb_register);
+module_exit(dvb_unregister);
+
+/* ------------------------------------------------------------------ */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
new file mode 100644
index 0000000..2021e09
--- /dev/null
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -0,0 +1,436 @@
+/*
+ * $Id: saa7134-empress.c,v 1.10 2005/02/03 10:24:33 kraxel Exp $
+ *
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+#include <media/saa6752hs.h>
+
+/* ------------------------------------------------------------------ */
+
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+static unsigned int empress_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+module_param_array(empress_nr, int, NULL, 0444);
+MODULE_PARM_DESC(empress_nr,"ts device number");
+
+static unsigned int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages");
+
+#define dprintk(fmt, arg...)	if (debug)			\
+	printk(KERN_DEBUG "%s/empress: " fmt, dev->name , ## arg)
+
+/* ------------------------------------------------------------------ */
+
+static void ts_reset_encoder(struct saa7134_dev* dev)
+{
+	if (!dev->empress_started)
+		return;
+
+	saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
+	msleep(10);
+   	saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+	msleep(100);
+	dev->empress_started = 0;
+}
+
+static int ts_init_encoder(struct saa7134_dev* dev)
+{
+	ts_reset_encoder(dev);
+	saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, NULL);
+	dev->empress_started = 1;
+ 	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int ts_open(struct inode *inode, struct file *file)
+{
+	int minor = iminor(inode);
+	struct saa7134_dev *h,*dev = NULL;
+	struct list_head *list;
+	int err;
+
+	list_for_each(list,&saa7134_devlist) {
+		h = list_entry(list, struct saa7134_dev, devlist);
+		if (h->empress_dev && h->empress_dev->minor == minor)
+			dev = h;
+	}
+	if (NULL == dev)
+		return -ENODEV;
+
+	dprintk("open minor=%d\n",minor);
+	err = -EBUSY;
+	if (down_trylock(&dev->empress_tsq.lock))
+		goto done;
+	if (dev->empress_users)
+		goto done_up;
+
+	dev->empress_users++;
+	file->private_data = dev;
+	err = 0;
+
+done_up:
+	up(&dev->empress_tsq.lock);
+done:
+	return err;
+}
+
+static int ts_release(struct inode *inode, struct file *file)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	if (dev->empress_tsq.streaming)
+		videobuf_streamoff(&dev->empress_tsq);
+	down(&dev->empress_tsq.lock);
+	if (dev->empress_tsq.reading)
+		videobuf_read_stop(&dev->empress_tsq);
+	videobuf_mmap_free(&dev->empress_tsq);
+	dev->empress_users--;
+
+	/* stop the encoder */
+	ts_reset_encoder(dev);
+
+	up(&dev->empress_tsq.lock);
+	return 0;
+}
+
+static ssize_t
+ts_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	if (!dev->empress_started)
+		ts_init_encoder(dev);
+
+	return videobuf_read_stream(&dev->empress_tsq,
+				    data, count, ppos, 0,
+				    file->f_flags & O_NONBLOCK);
+}
+
+static unsigned int
+ts_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	return videobuf_poll_stream(file, &dev->empress_tsq, wait);
+}
+
+
+static int
+ts_mmap(struct file *file, struct vm_area_struct * vma)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	return videobuf_mmap_mapper(&dev->empress_tsq, vma);
+}
+
+/*
+ * This function is _not_ called directly, but from
+ * video_generic_ioctl (and maybe others).  userspace
+ * copying is done already, arg is a kernel pointer.
+ */
+static int ts_do_ioctl(struct inode *inode, struct file *file,
+		       unsigned int cmd, void *arg)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	if (debug > 1)
+		saa7134_print_ioctl(dev->name,cmd);
+	switch (cmd) {
+	case VIDIOC_QUERYCAP:
+	{
+		struct v4l2_capability *cap = arg;
+
+		memset(cap,0,sizeof(*cap));
+                strcpy(cap->driver, "saa7134");
+		strlcpy(cap->card, saa7134_boards[dev->board].name,
+			sizeof(cap->card));
+		sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
+		cap->version = SAA7134_VERSION_CODE;
+		cap->capabilities =
+			V4L2_CAP_VIDEO_CAPTURE |
+			V4L2_CAP_READWRITE |
+			V4L2_CAP_STREAMING;
+		return 0;
+	}
+
+	/* --- input switching --------------------------------------- */
+	case VIDIOC_ENUMINPUT:
+	{
+		struct v4l2_input *i = arg;
+
+		if (i->index != 0)
+			return -EINVAL;
+		i->type = V4L2_INPUT_TYPE_CAMERA;
+		strcpy(i->name,"CCIR656");
+		return 0;
+	}
+	case VIDIOC_G_INPUT:
+	{
+		int *i = arg;
+		*i = 0;
+		return 0;
+	}
+	case VIDIOC_S_INPUT:
+	{
+		int *i = arg;
+
+		if (*i != 0)
+			return -EINVAL;
+		return 0;
+	}
+	/* --- capture ioctls ---------------------------------------- */
+
+	case VIDIOC_ENUM_FMT:
+	{
+		struct v4l2_fmtdesc *f = arg;
+		int index;
+
+		index = f->index;
+		if (index != 0)
+			return -EINVAL;
+
+		memset(f,0,sizeof(*f));
+		f->index = index;
+		strlcpy(f->description, "MPEG TS", sizeof(f->description));
+		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		f->pixelformat = V4L2_PIX_FMT_MPEG;
+		return 0;
+	}
+
+	case VIDIOC_G_FMT:
+	{
+		struct v4l2_format *f = arg;
+
+		memset(f,0,sizeof(*f));
+		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+		/* FIXME: translate subsampling type EMPRESS into
+		 *        width/height: */
+		f->fmt.pix.width        = 720; /* D1 */
+		f->fmt.pix.height       = 576;
+		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+		f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
+		return 0;
+	}
+
+	case VIDIOC_S_FMT:
+	{
+		struct v4l2_format *f = arg;
+
+		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		    return -EINVAL;
+
+		/*
+		  FIXME: translate and round width/height into EMPRESS
+		  subsample type:
+
+		          type  |   PAL   |  NTSC
+			---------------------------
+			  SIF   | 352x288 | 352x240
+			 1/2 D1 | 352x576 | 352x480
+			 2/3 D1 | 480x576 | 480x480
+			  D1    | 720x576 | 720x480
+		*/
+
+		f->fmt.pix.width        = 720; /* D1 */
+		f->fmt.pix.height       = 576;
+		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+		f->fmt.pix.sizeimage    = TS_PACKET_SIZE* dev->ts.nr_packets;
+		return 0;
+	}
+
+	case VIDIOC_REQBUFS:
+		return videobuf_reqbufs(&dev->empress_tsq,arg);
+
+	case VIDIOC_QUERYBUF:
+		return videobuf_querybuf(&dev->empress_tsq,arg);
+
+	case VIDIOC_QBUF:
+		return videobuf_qbuf(&dev->empress_tsq,arg);
+
+	case VIDIOC_DQBUF:
+		return videobuf_dqbuf(&dev->empress_tsq,arg,
+				      file->f_flags & O_NONBLOCK);
+
+	case VIDIOC_STREAMON:
+		return videobuf_streamon(&dev->empress_tsq);
+
+	case VIDIOC_STREAMOFF:
+		return videobuf_streamoff(&dev->empress_tsq);
+
+	case VIDIOC_QUERYCTRL:
+	case VIDIOC_G_CTRL:
+	case VIDIOC_S_CTRL:
+		return saa7134_common_ioctl(dev, cmd, arg);
+
+	case VIDIOC_S_MPEGCOMP:
+		saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, arg);
+		ts_init_encoder(dev);
+		return 0;
+	case VIDIOC_G_MPEGCOMP:
+		saa7134_i2c_call_clients(dev, VIDIOC_G_MPEGCOMP, arg);
+		return 0;
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static int ts_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	return video_usercopy(inode, file, cmd, arg, ts_do_ioctl);
+}
+
+static struct file_operations ts_fops =
+{
+	.owner	  = THIS_MODULE,
+	.open	  = ts_open,
+	.release  = ts_release,
+	.read	  = ts_read,
+	.poll	  = ts_poll,
+	.mmap	  = ts_mmap,
+	.ioctl	  = ts_ioctl,
+	.llseek   = no_llseek,
+};
+
+/* ----------------------------------------------------------- */
+
+static struct video_device saa7134_empress_template =
+{
+	.name          = "saa7134-empress",
+	.type          = 0 /* FIXME */,
+	.type2         = 0 /* FIXME */,
+	.hardware      = 0,
+	.fops          = &ts_fops,
+	.minor	       = -1,
+};
+
+static void empress_signal_update(void* data)
+{
+	struct saa7134_dev* dev = (struct saa7134_dev*) data;
+
+	if (dev->nosignal) {
+		dprintk("no video signal\n");
+		ts_reset_encoder(dev);
+	} else {
+		dprintk("video signal acquired\n");
+		if (dev->empress_users)
+			ts_init_encoder(dev);
+	}
+}
+
+static void empress_signal_change(struct saa7134_dev *dev)
+{
+	schedule_work(&dev->empress_workqueue);
+}
+
+
+static int empress_init(struct saa7134_dev *dev)
+{
+	int err;
+
+	dprintk("%s: %s\n",dev->name,__FUNCTION__);
+	dev->empress_dev = video_device_alloc();
+	if (NULL == dev->empress_dev)
+		return -ENOMEM;
+	*(dev->empress_dev) = saa7134_empress_template;
+	dev->empress_dev->dev     = &dev->pci->dev;
+	dev->empress_dev->release = video_device_release;
+	snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name),
+		 "%s empress (%s)", dev->name,
+		 saa7134_boards[dev->board].name);
+
+	INIT_WORK(&dev->empress_workqueue, empress_signal_update, (void*) dev);
+
+	err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER,
+				    empress_nr[dev->nr]);
+	if (err < 0) {
+		printk(KERN_INFO "%s: can't register video device\n",
+		       dev->name);
+		video_device_release(dev->empress_dev);
+		dev->empress_dev = NULL;
+		return err;
+	}
+	printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
+	       dev->name,dev->empress_dev->minor & 0x1f);
+
+	videobuf_queue_init(&dev->empress_tsq, &saa7134_ts_qops,
+			    dev->pci, &dev->slock,
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			    V4L2_FIELD_ALTERNATE,
+			    sizeof(struct saa7134_buf),
+			    dev);
+
+	empress_signal_update(dev);
+	return 0;
+}
+
+static int empress_fini(struct saa7134_dev *dev)
+{
+	dprintk("%s: %s\n",dev->name,__FUNCTION__);
+
+	if (NULL == dev->empress_dev)
+		return 0;
+	flush_scheduled_work();
+	video_unregister_device(dev->empress_dev);
+	dev->empress_dev = NULL;
+	return 0;
+}
+
+static struct saa7134_mpeg_ops empress_ops = {
+	.type          = SAA7134_MPEG_EMPRESS,
+	.init          = empress_init,
+	.fini          = empress_fini,
+	.signal_change = empress_signal_change,
+};
+
+static int __init empress_register(void)
+{
+	return saa7134_ts_register(&empress_ops);
+}
+
+static void __exit empress_unregister(void)
+{
+	saa7134_ts_unregister(&empress_ops);
+}
+
+module_init(empress_register);
+module_exit(empress_unregister);
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
new file mode 100644
index 0000000..702bb63
--- /dev/null
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -0,0 +1,453 @@
+/*
+ * $Id: saa7134-i2c.c,v 1.10 2005/01/24 17:37:23 kraxel Exp $
+ *
+ * device driver for philips saa7134 based TV cards
+ * i2c interface support
+ *
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+/* ----------------------------------------------------------- */
+
+static unsigned int i2c_debug = 0;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]");
+
+static unsigned int i2c_scan = 0;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
+
+#define d1printk if (1 == i2c_debug) printk
+#define d2printk if (2 == i2c_debug) printk
+
+#define I2C_WAIT_DELAY  32
+#define I2C_WAIT_RETRY  16
+
+/* ----------------------------------------------------------- */
+
+static char *str_i2c_status[] = {
+	"IDLE", "DONE_STOP", "BUSY", "TO_SCL", "TO_ARB", "DONE_WRITE",
+	"DONE_READ", "DONE_WRITE_TO", "DONE_READ_TO", "NO_DEVICE",
+	"NO_ACKN", "BUS_ERR", "ARB_LOST", "SEQ_ERR", "ST_ERR", "SW_ERR"
+};
+
+enum i2c_status {
+	IDLE          = 0,  // no I2C command pending
+	DONE_STOP     = 1,  // I2C command done and STOP executed
+	BUSY          = 2,  // executing I2C command
+	TO_SCL        = 3,  // executing I2C command, time out on clock stretching
+	TO_ARB        = 4,  // time out on arbitration trial, still trying
+	DONE_WRITE    = 5,  // I2C command done and awaiting next write command
+	DONE_READ     = 6,  // I2C command done and awaiting next read command
+	DONE_WRITE_TO = 7,  // see 5, and time out on status echo
+	DONE_READ_TO  = 8,  // see 6, and time out on status echo
+	NO_DEVICE     = 9,  // no acknowledge on device slave address
+	NO_ACKN       = 10, // no acknowledge after data byte transfer
+	BUS_ERR       = 11, // bus error
+	ARB_LOST      = 12, // arbitration lost during transfer
+	SEQ_ERR       = 13, // erroneous programming sequence
+	ST_ERR        = 14, // wrong status echoing
+	SW_ERR        = 15  // software error
+};
+
+static char *str_i2c_attr[] = {
+	"NOP", "STOP", "CONTINUE", "START"
+};
+
+enum i2c_attr {
+	NOP           = 0,  // no operation on I2C bus
+	STOP          = 1,  // stop condition, no associated byte transfer
+	CONTINUE      = 2,  // continue with byte transfer
+	START         = 3   // start condition with byte transfer
+};
+
+static inline enum i2c_status i2c_get_status(struct saa7134_dev *dev)
+{
+	enum i2c_status status;
+
+	status = saa_readb(SAA7134_I2C_ATTR_STATUS) & 0x0f;
+	d2printk(KERN_DEBUG "%s: i2c stat <= %s\n",dev->name,
+		 str_i2c_status[status]);
+	return status;
+}
+
+static inline void i2c_set_status(struct saa7134_dev *dev,
+				  enum i2c_status status)
+{
+	d2printk(KERN_DEBUG "%s: i2c stat => %s\n",dev->name,
+		 str_i2c_status[status]);
+	saa_andorb(SAA7134_I2C_ATTR_STATUS,0x0f,status);
+}
+
+static inline void i2c_set_attr(struct saa7134_dev *dev, enum i2c_attr attr)
+{
+	d2printk(KERN_DEBUG "%s: i2c attr => %s\n",dev->name,
+		 str_i2c_attr[attr]);
+	saa_andorb(SAA7134_I2C_ATTR_STATUS,0xc0,attr << 6);
+}
+
+static inline int i2c_is_error(enum i2c_status status)
+{
+	switch (status) {
+	case NO_DEVICE:
+	case NO_ACKN:
+	case BUS_ERR:
+	case ARB_LOST:
+	case SEQ_ERR:
+	case ST_ERR:
+		return TRUE;
+	default:
+		return FALSE;
+	}
+}
+
+static inline int i2c_is_idle(enum i2c_status status)
+{
+	switch (status) {
+	case IDLE:
+	case DONE_STOP:
+		return TRUE;
+	default:
+		return FALSE;
+	}
+}
+
+static inline int i2c_is_busy(enum i2c_status status)
+{
+	switch (status) {
+	case BUSY:
+		return TRUE;
+	default:
+		return FALSE;
+	}
+}
+
+static int i2c_is_busy_wait(struct saa7134_dev *dev)
+{
+	enum i2c_status status;
+	int count;
+
+	for (count = 0; count < I2C_WAIT_RETRY; count++) {
+		status = i2c_get_status(dev);
+		if (!i2c_is_busy(status))
+			break;
+		saa_wait(I2C_WAIT_DELAY);
+	}
+	if (I2C_WAIT_RETRY == count)
+		return FALSE;
+	return TRUE;
+}
+
+static int i2c_reset(struct saa7134_dev *dev)
+{
+	enum i2c_status status;
+	int count;
+
+	d2printk(KERN_DEBUG "%s: i2c reset\n",dev->name);
+	status = i2c_get_status(dev);
+	if (!i2c_is_error(status))
+		return TRUE;
+	i2c_set_status(dev,status);
+
+	for (count = 0; count < I2C_WAIT_RETRY; count++) {
+		status = i2c_get_status(dev);
+		if (!i2c_is_error(status))
+			break;
+		udelay(I2C_WAIT_DELAY);
+	}
+	if (I2C_WAIT_RETRY == count)
+		return FALSE;
+
+	if (!i2c_is_idle(status))
+		return FALSE;
+
+	i2c_set_attr(dev,NOP);
+	return TRUE;
+}
+
+static inline int i2c_send_byte(struct saa7134_dev *dev,
+				enum i2c_attr attr,
+				unsigned char data)
+{
+	enum i2c_status status;
+	__u32 dword;
+
+#if 0
+	i2c_set_attr(dev,attr);
+	saa_writeb(SAA7134_I2C_DATA, data);
+#else
+	/* have to write both attr + data in one 32bit word */
+	dword  = saa_readl(SAA7134_I2C_ATTR_STATUS >> 2);
+	dword &= 0x0f;
+	dword |= (attr << 6);
+	dword |= ((__u32)data << 8);
+	dword |= 0x00 << 16;  /* 100 kHz */
+//	dword |= 0x40 << 16;  /* 400 kHz */
+	dword |= 0xf0 << 24;
+	saa_writel(SAA7134_I2C_ATTR_STATUS >> 2, dword);
+#endif
+	d2printk(KERN_DEBUG "%s: i2c data => 0x%x\n",dev->name,data);
+
+	if (!i2c_is_busy_wait(dev))
+		return -EIO;
+	status = i2c_get_status(dev);
+	if (i2c_is_error(status))
+		return -EIO;
+	return 0;
+}
+
+static inline int i2c_recv_byte(struct saa7134_dev *dev)
+{
+	enum i2c_status status;
+	unsigned char data;
+
+	i2c_set_attr(dev,CONTINUE);
+	if (!i2c_is_busy_wait(dev))
+		return -EIO;
+	status = i2c_get_status(dev);
+	if (i2c_is_error(status))
+		return -EIO;
+	data = saa_readb(SAA7134_I2C_DATA);
+	d2printk(KERN_DEBUG "%s: i2c data <= 0x%x\n",dev->name,data);
+	return data;
+}
+
+static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
+			    struct i2c_msg *msgs, int num)
+{
+	struct saa7134_dev *dev = i2c_adap->algo_data;
+	enum i2c_status status;
+	unsigned char data;
+	int addr,rc,i,byte;
+
+  	status = i2c_get_status(dev);
+	if (!i2c_is_idle(status))
+		if (!i2c_reset(dev))
+			return -EIO;
+
+	d2printk("start xfer\n");
+	d1printk(KERN_DEBUG "%s: i2c xfer:",dev->name);
+	for (i = 0; i < num; i++) {
+		if (!(msgs[i].flags & I2C_M_NOSTART) || 0 == i) {
+			/* send address */
+			d2printk("send address\n");
+			addr  = msgs[i].addr << 1;
+			if (msgs[i].flags & I2C_M_RD)
+				addr |= 1;
+			if (i > 0 && msgs[i].flags & I2C_M_RD) {
+				/* workaround for a saa7134 i2c bug
+				 * needed to talk to the mt352 demux
+				 * thanks to pinnacle for the hint */
+				int quirk = 0xfd;
+				d1printk(" [%02x quirk]",quirk);
+				i2c_send_byte(dev,START,quirk);
+				i2c_recv_byte(dev);
+			}
+			d1printk(" < %02x", addr);
+			rc = i2c_send_byte(dev,START,addr);
+			if (rc < 0)
+				 goto err;
+		}
+		if (msgs[i].flags & I2C_M_RD) {
+			/* read bytes */
+			d2printk("read bytes\n");
+			for (byte = 0; byte < msgs[i].len; byte++) {
+				d1printk(" =");
+				rc = i2c_recv_byte(dev);
+				if (rc < 0)
+					goto err;
+				d1printk("%02x", rc);
+				msgs[i].buf[byte] = rc;
+			}
+		} else {
+			/* write bytes */
+			d2printk("write bytes\n");
+			for (byte = 0; byte < msgs[i].len; byte++) {
+				data = msgs[i].buf[byte];
+				d1printk(" %02x", data);
+				rc = i2c_send_byte(dev,CONTINUE,data);
+				if (rc < 0)
+					goto err;
+			}
+		}
+	}
+	d2printk("xfer done\n");
+	d1printk(" >");
+	i2c_set_attr(dev,STOP);
+	rc = -EIO;
+	if (!i2c_is_busy_wait(dev))
+		goto err;
+  	status = i2c_get_status(dev);
+	if (i2c_is_error(status))
+		goto err;
+
+	d1printk("\n");
+	return num;
+ err:
+	if (1 == i2c_debug) {
+		status = i2c_get_status(dev);
+		printk(" ERROR: %s\n",str_i2c_status[status]);
+	}
+	return rc;
+}
+
+/* ----------------------------------------------------------- */
+
+static int algo_control(struct i2c_adapter *adapter,
+			unsigned int cmd, unsigned long arg)
+{
+	return 0;
+}
+
+static u32 functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL;
+}
+
+static int attach_inform(struct i2c_client *client)
+{
+        struct saa7134_dev *dev = client->adapter->algo_data;
+	int tuner = dev->tuner_type;
+	int conf  = dev->tda9887_conf;
+
+	saa7134_i2c_call_clients(dev,TUNER_SET_TYPE,&tuner);
+	saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&conf);
+        return 0;
+}
+
+static struct i2c_algorithm saa7134_algo = {
+	.name          = "saa7134",
+	.id            = I2C_ALGO_SAA7134,
+	.master_xfer   = saa7134_i2c_xfer,
+	.algo_control  = algo_control,
+	.functionality = functionality,
+};
+
+static struct i2c_adapter saa7134_adap_template = {
+	.owner         = THIS_MODULE,
+#ifdef I2C_CLASS_TV_ANALOG
+	.class         = I2C_CLASS_TV_ANALOG,
+#endif
+	I2C_DEVNAME("saa7134"),
+	.id            = I2C_ALGO_SAA7134,
+	.algo          = &saa7134_algo,
+	.client_register = attach_inform,
+};
+
+static struct i2c_client saa7134_client_template = {
+	I2C_DEVNAME("saa7134 internal"),
+};
+
+/* ----------------------------------------------------------- */
+
+static int
+saa7134_i2c_eeprom(struct saa7134_dev *dev, unsigned char *eedata, int len)
+{
+	unsigned char buf;
+	int i,err;
+
+	dev->i2c_client.addr = 0xa0 >> 1;
+	buf = 0;
+	if (1 != (err = i2c_master_send(&dev->i2c_client,&buf,1))) {
+		printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
+		       dev->name,err);
+		return -1;
+	}
+	if (len != (err = i2c_master_recv(&dev->i2c_client,eedata,len))) {
+		printk(KERN_WARNING "%s: i2c eeprom read error (err=%d)\n",
+		       dev->name,err);
+		return -1;
+	}
+	for (i = 0; i < len; i++) {
+		if (0 == (i % 16))
+			printk(KERN_INFO "%s: i2c eeprom %02x:",dev->name,i);
+		printk(" %02x",eedata[i]);
+		if (15 == (i % 16))
+			printk("\n");
+	}
+	return 0;
+}
+
+static char *i2c_devs[128] = {
+	[ 0x20      ] = "mpeg encoder (saa6752hs)",
+	[ 0xa0 >> 1 ] = "eeprom",
+	[ 0xc0 >> 1 ] = "tuner (analog)",
+	[ 0x86 >> 1 ] = "tda9887",
+};
+
+static void do_i2c_scan(char *name, struct i2c_client *c)
+{
+	unsigned char buf;
+	int i,rc;
+
+	for (i = 0; i < 128; i++) {
+		c->addr = i;
+		rc = i2c_master_recv(c,&buf,0);
+		if (rc < 0)
+			continue;
+		printk("%s: i2c scan: found device @ 0x%x  [%s]\n",
+		       name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+	}
+}
+
+void saa7134_i2c_call_clients(struct saa7134_dev *dev,
+			      unsigned int cmd, void *arg)
+{
+	BUG_ON(NULL == dev->i2c_adap.algo_data);
+	i2c_clients_command(&dev->i2c_adap, cmd, arg);
+}
+
+int saa7134_i2c_register(struct saa7134_dev *dev)
+{
+	dev->i2c_adap = saa7134_adap_template;
+	dev->i2c_adap.dev.parent = &dev->pci->dev;
+	strcpy(dev->i2c_adap.name,dev->name);
+	dev->i2c_adap.algo_data = dev;
+	i2c_add_adapter(&dev->i2c_adap);
+
+	dev->i2c_client = saa7134_client_template;
+	dev->i2c_client.adapter = &dev->i2c_adap;
+
+	saa7134_i2c_eeprom(dev,dev->eedata,sizeof(dev->eedata));
+	if (i2c_scan)
+		do_i2c_scan(dev->name,&dev->i2c_client);
+	return 0;
+}
+
+int saa7134_i2c_unregister(struct saa7134_dev *dev)
+{
+	i2c_del_adapter(&dev->i2c_adap);
+	return 0;
+}
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
new file mode 100644
index 0000000..727d437
--- /dev/null
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -0,0 +1,491 @@
+/*
+ * $Id: saa7134-input.c,v 1.16 2004/12/10 12:33:39 kraxel Exp $
+ *
+ * handle saa7134 IR remotes via linux kernel input layer.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+static unsigned int disable_ir = 0;
+module_param(disable_ir, int, 0444);
+MODULE_PARM_DESC(disable_ir,"disable infrared remote support");
+
+static unsigned int ir_debug = 0;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+
+#define dprintk(fmt, arg...)	if (ir_debug) \
+	printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
+
+/* ---------------------------------------------------------------------- */
+
+static IR_KEYTAB_TYPE flyvideo_codes[IR_KEYTAB_SIZE] = {
+	[   15 ] = KEY_KP0,
+	[    3 ] = KEY_KP1,
+	[    4 ] = KEY_KP2,
+	[    5 ] = KEY_KP3,
+	[    7 ] = KEY_KP4,
+	[    8 ] = KEY_KP5,
+	[    9 ] = KEY_KP6,
+	[   11 ] = KEY_KP7,
+	[   12 ] = KEY_KP8,
+	[   13 ] = KEY_KP9,
+
+	[   14 ] = KEY_TUNER,        // Air/Cable
+	[   17 ] = KEY_VIDEO,        // Video
+	[   21 ] = KEY_AUDIO,        // Audio
+	[    0 ] = KEY_POWER,        // Pover
+	[    2 ] = KEY_ZOOM,         // Fullscreen
+	[   27 ] = KEY_MUTE,         // Mute
+	[   20 ] = KEY_VOLUMEUP,
+	[   23 ] = KEY_VOLUMEDOWN,
+	[   18 ] = KEY_CHANNELUP,    // Channel +
+	[   19 ] = KEY_CHANNELDOWN,  // Channel -
+	[    6 ] = KEY_AGAIN,        // Recal
+	[   16 ] = KEY_KPENTER,      // Enter
+
+#if 1 /* FIXME */
+	[   26 ] = KEY_F22,          // Stereo
+	[   24 ] = KEY_EDIT,         // AV Source
+#endif
+};
+
+static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = {
+	[    0 ] = KEY_KP0,
+	[    1 ] = KEY_KP1,
+	[    2 ] = KEY_KP2,
+	[    3 ] = KEY_KP3,
+	[    4 ] = KEY_KP4,
+	[    5 ] = KEY_KP5,
+	[    6 ] = KEY_KP6,
+	[    7 ] = KEY_KP7,
+	[    8 ] = KEY_KP8,
+	[    9 ] = KEY_KP9,
+
+	[ 0x0a ] = KEY_POWER,
+	[ 0x0b ] = KEY_PROG1,           // app
+	[ 0x0c ] = KEY_ZOOM,            // zoom/fullscreen
+	[ 0x0d ] = KEY_CHANNELUP,       // channel
+	[ 0x0e ] = KEY_CHANNELDOWN,     // channel-
+	[ 0x0f ] = KEY_VOLUMEUP,
+	[ 0x10 ] = KEY_VOLUMEDOWN,
+	[ 0x11 ] = KEY_TUNER,           // AV
+	[ 0x12 ] = KEY_NUMLOCK,         // -/--
+	[ 0x13 ] = KEY_AUDIO,           // audio
+	[ 0x14 ] = KEY_MUTE,
+	[ 0x15 ] = KEY_UP,
+	[ 0x16 ] = KEY_DOWN,
+	[ 0x17 ] = KEY_LEFT,
+	[ 0x18 ] = KEY_RIGHT,
+	[ 0x19 ] = BTN_LEFT,
+	[ 0x1a ] = BTN_RIGHT,
+	[ 0x1b ] = KEY_WWW,             // text
+	[ 0x1c ] = KEY_REWIND,
+	[ 0x1d ] = KEY_FORWARD,
+	[ 0x1e ] = KEY_RECORD,
+	[ 0x1f ] = KEY_PLAY,
+	[ 0x20 ] = KEY_PREVIOUSSONG,
+	[ 0x21 ] = KEY_NEXTSONG,
+	[ 0x22 ] = KEY_PAUSE,
+	[ 0x23 ] = KEY_STOP,
+};
+
+/* Alfons Geser <a.geser@cox.net>
+ * updates from Job D. R. Borges <jobdrb@ig.com.br> */
+static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = {
+        [ 18 ] = KEY_POWER,
+        [  1 ] = KEY_TV,             // DVR
+        [ 21 ] = KEY_DVD,            // DVD
+        [ 23 ] = KEY_AUDIO,          // music
+                                     // DVR mode / DVD mode / music mode
+
+        [ 27 ] = KEY_MUTE,           // mute
+        [  2 ] = KEY_LANGUAGE,       // MTS/SAP / audio / autoseek
+        [ 30 ] = KEY_SUBTITLE,       // closed captioning / subtitle / seek
+        [ 22 ] = KEY_ZOOM,           // full screen
+        [ 28 ] = KEY_VIDEO,          // video source / eject / delall
+        [ 29 ] = KEY_RESTART,        // playback / angle / del
+        [ 47 ] = KEY_SEARCH,         // scan / menu / playlist
+        [ 48 ] = KEY_CHANNEL,        // CH surfing / bookmark / memo
+
+        [ 49 ] = KEY_HELP,           // help
+        [ 50 ] = KEY_MODE,           // num/memo
+        [ 51 ] = KEY_ESC,            // cancel
+
+	[ 12 ] = KEY_UP,             // up
+	[ 16 ] = KEY_DOWN,           // down
+	[  8 ] = KEY_LEFT,           // left
+	[  4 ] = KEY_RIGHT,          // right
+	[  3 ] = KEY_SELECT,         // select
+
+	[ 31 ] = KEY_REWIND,         // rewind
+	[ 32 ] = KEY_PLAYPAUSE,      // play/pause
+	[ 41 ] = KEY_FORWARD,        // forward
+	[ 20 ] = KEY_AGAIN,          // repeat
+	[ 43 ] = KEY_RECORD,         // recording
+	[ 44 ] = KEY_STOP,           // stop
+	[ 45 ] = KEY_PLAY,           // play
+	[ 46 ] = KEY_SHUFFLE,        // snapshot / shuffle
+
+        [  0 ] = KEY_KP0,
+        [  5 ] = KEY_KP1,
+        [  6 ] = KEY_KP2,
+        [  7 ] = KEY_KP3,
+        [  9 ] = KEY_KP4,
+        [ 10 ] = KEY_KP5,
+        [ 11 ] = KEY_KP6,
+        [ 13 ] = KEY_KP7,
+        [ 14 ] = KEY_KP8,
+        [ 15 ] = KEY_KP9,
+
+        [ 42 ] = KEY_VOLUMEUP,
+        [ 17 ] = KEY_VOLUMEDOWN,
+        [ 24 ] = KEY_CHANNELUP,      // CH.tracking up
+        [ 25 ] = KEY_CHANNELDOWN,    // CH.tracking down
+
+        [ 19 ] = KEY_KPENTER,        // enter
+        [ 33 ] = KEY_KPDOT,          // . (decimal dot)
+};
+
+static IR_KEYTAB_TYPE avacssmart_codes[IR_KEYTAB_SIZE] = {
+        [ 30 ] = KEY_POWER,		// power
+	[ 28 ] = KEY_SEARCH,		// scan
+        [  7 ] = KEY_SELECT,		// source
+
+	[ 22 ] = KEY_VOLUMEUP,
+	[ 20 ] = KEY_VOLUMEDOWN,
+        [ 31 ] = KEY_CHANNELUP,
+	[ 23 ] = KEY_CHANNELDOWN,
+	[ 24 ] = KEY_MUTE,
+
+	[  2 ] = KEY_KP0,
+        [  1 ] = KEY_KP1,
+        [ 11 ] = KEY_KP2,
+        [ 27 ] = KEY_KP3,
+        [  5 ] = KEY_KP4,
+        [  9 ] = KEY_KP5,
+        [ 21 ] = KEY_KP6,
+	[  6 ] = KEY_KP7,
+        [ 10 ] = KEY_KP8,
+	[ 18 ] = KEY_KP9,
+	[ 16 ] = KEY_KPDOT,
+
+	[  3 ] = KEY_TUNER,		// tv/fm
+        [  4 ] = KEY_REWIND,		// fm tuning left or function left
+        [ 12 ] = KEY_FORWARD,		// fm tuning right or function right
+
+	[  0 ] = KEY_RECORD,
+        [  8 ] = KEY_STOP,
+        [ 17 ] = KEY_PLAY,
+
+	[ 25 ] = KEY_ZOOM,
+	[ 14 ] = KEY_MENU,		// function
+	[ 19 ] = KEY_AGAIN,		// recall
+	[ 29 ] = KEY_RESTART,		// reset
+
+// FIXME
+	[ 13 ] = KEY_F21,		// mts
+        [ 15 ] = KEY_F22,		// min
+	[ 26 ] = KEY_F23,		// freeze
+};
+
+/* Alex Hermann <gaaf@gmx.net> */
+static IR_KEYTAB_TYPE md2819_codes[IR_KEYTAB_SIZE] = {
+	[ 40 ] = KEY_KP1,
+	[ 24 ] = KEY_KP2,
+	[ 56 ] = KEY_KP3,
+	[ 36 ] = KEY_KP4,
+	[ 20 ] = KEY_KP5,
+	[ 52 ] = KEY_KP6,
+	[ 44 ] = KEY_KP7,
+	[ 28 ] = KEY_KP8,
+	[ 60 ] = KEY_KP9,
+	[ 34 ] = KEY_KP0,
+
+	[ 32 ] = KEY_TV,		// TV/FM
+	[ 16 ] = KEY_CD,		// CD
+	[ 48 ] = KEY_TEXT,		// TELETEXT
+	[  0 ] = KEY_POWER,		// POWER
+
+	[  8 ] = KEY_VIDEO,		// VIDEO
+	[  4 ] = KEY_AUDIO,		// AUDIO
+	[ 12 ] = KEY_ZOOM,		// FULL SCREEN
+
+	[ 18 ] = KEY_SUBTITLE,		// DISPLAY	- ???
+	[ 50 ] = KEY_REWIND,		// LOOP		- ???
+	[  2 ] = KEY_PRINT,		// PREVIEW	- ???
+
+	[ 42 ] = KEY_SEARCH,		// AUTOSCAN
+	[ 26 ] = KEY_SLEEP,		// FREEZE	- ???
+	[ 58 ] = KEY_SHUFFLE,		// SNAPSHOT	- ???
+	[ 10 ] = KEY_MUTE,		// MUTE
+
+	[ 38 ] = KEY_RECORD,		// RECORD
+	[ 22 ] = KEY_PAUSE,		// PAUSE
+	[ 54 ] = KEY_STOP,		// STOP
+	[  6 ] = KEY_PLAY,		// PLAY
+
+	[ 46 ] = KEY_RED,		// <RED>
+	[ 33 ] = KEY_GREEN,		// <GREEN>
+	[ 14 ] = KEY_YELLOW,		// <YELLOW>
+	[  1 ] = KEY_BLUE,		// <BLUE>
+
+	[ 30 ] = KEY_VOLUMEDOWN,	// VOLUME-
+	[ 62 ] = KEY_VOLUMEUP,		// VOLUME+
+	[ 17 ] = KEY_CHANNELDOWN,	// CHANNEL/PAGE-
+	[ 49 ] = KEY_CHANNELUP		// CHANNEL/PAGE+
+};
+
+static IR_KEYTAB_TYPE videomate_tv_pvr_codes[IR_KEYTAB_SIZE] = {
+	[ 20 ] = KEY_MUTE,
+	[ 36 ] = KEY_ZOOM,
+
+	[  1 ] = KEY_DVD,
+	[ 35 ] = KEY_RADIO,
+	[  0 ] = KEY_TV,
+
+	[ 10 ] = KEY_REWIND,
+	[  8 ] = KEY_PLAYPAUSE,
+	[ 15 ] = KEY_FORWARD,
+
+	[  2 ] = KEY_PREVIOUS,
+	[  7 ] = KEY_STOP,
+	[  6 ] = KEY_NEXT,
+
+	[ 12 ] = KEY_UP,
+	[ 14 ] = KEY_DOWN,
+	[ 11 ] = KEY_LEFT,
+	[ 13 ] = KEY_RIGHT,
+	[ 17 ] = KEY_OK,
+
+	[  3 ] = KEY_MENU,
+	[  9 ] = KEY_SETUP,
+	[  5 ] = KEY_VIDEO,
+	[ 34 ] = KEY_CHANNEL,
+
+	[ 18 ] = KEY_VOLUMEUP,
+	[ 21 ] = KEY_VOLUMEDOWN,
+	[ 16 ] = KEY_CHANNELUP,
+	[ 19 ] = KEY_CHANNELDOWN,
+
+	[  4 ] = KEY_RECORD,
+
+	[ 22 ] = KEY_KP1,
+	[ 23 ] = KEY_KP2,
+	[ 24 ] = KEY_KP3,
+	[ 25 ] = KEY_KP4,
+	[ 26 ] = KEY_KP5,
+	[ 27 ] = KEY_KP6,
+	[ 28 ] = KEY_KP7,
+	[ 29 ] = KEY_KP8,
+	[ 30 ] = KEY_KP9,
+	[ 31 ] = KEY_KP0,
+
+	[ 32 ] = KEY_LANGUAGE,
+	[ 33 ] = KEY_SLEEP,
+};
+/* ---------------------------------------------------------------------- */
+
+static int build_key(struct saa7134_dev *dev)
+{
+	struct saa7134_ir *ir = dev->remote;
+	u32 gpio, data;
+
+	/* rising SAA7134_GPIO_GPRESCAN reads the status */
+	saa_clearb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
+	saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
+
+	gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+        if (ir->polling) {
+                if (ir->last_gpio == gpio)
+                        return 0;
+                ir->last_gpio = gpio;
+        }
+
+ 	data = ir_extract_bits(gpio, ir->mask_keycode);
+	dprintk("build_key gpio=0x%x mask=0x%x data=%d\n",
+		gpio, ir->mask_keycode, data);
+
+	if ((ir->mask_keydown  &&  (0 != (gpio & ir->mask_keydown))) ||
+	    (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
+		ir_input_keydown(&ir->dev,&ir->ir,data,data);
+	} else {
+		ir_input_nokey(&ir->dev,&ir->ir);
+	}
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void saa7134_input_irq(struct saa7134_dev *dev)
+{
+        struct saa7134_ir *ir = dev->remote;
+
+        if (!ir->polling)
+		build_key(dev);
+}
+
+static void saa7134_input_timer(unsigned long data)
+{
+	struct saa7134_dev *dev = (struct saa7134_dev*)data;
+	struct saa7134_ir *ir = dev->remote;
+	unsigned long timeout;
+
+	build_key(dev);
+	timeout = jiffies + (ir->polling * HZ / 1000);
+	mod_timer(&ir->timer, timeout);
+}
+
+int saa7134_input_init1(struct saa7134_dev *dev)
+{
+	struct saa7134_ir *ir;
+	IR_KEYTAB_TYPE *ir_codes = NULL;
+	u32 mask_keycode = 0;
+	u32 mask_keydown = 0;
+	u32 mask_keyup   = 0;
+	int polling      = 0;
+	int ir_type      = IR_TYPE_OTHER;
+
+	if (!dev->has_remote)
+		return -ENODEV;
+	if (disable_ir)
+		return -ENODEV;
+
+	/* detect & configure */
+	switch (dev->board) {
+	case SAA7134_BOARD_FLYVIDEO2000:
+	case SAA7134_BOARD_FLYVIDEO3000:
+		ir_codes     = flyvideo_codes;
+		mask_keycode = 0xEC00000;
+		mask_keydown = 0x0040000;
+		break;
+	case SAA7134_BOARD_CINERGY400:
+	case SAA7134_BOARD_CINERGY600:
+	case SAA7134_BOARD_CINERGY600_MK3:
+		ir_codes     = cinergy_codes;
+		mask_keycode = 0x00003f;
+		mask_keyup   = 0x040000;
+		break;
+	case SAA7134_BOARD_ECS_TVP3XP:
+	case SAA7134_BOARD_ECS_TVP3XP_4CB5:
+                ir_codes     = eztv_codes;
+                mask_keycode = 0x00017c;
+                mask_keyup   = 0x000002;
+		polling      = 50; // ms
+                break;
+	case SAA7134_BOARD_AVACSSMARTTV:
+	        ir_codes     = avacssmart_codes;
+		mask_keycode = 0x00001F;
+		mask_keyup   = 0x000020;
+		polling      = 50; // ms
+		break;
+	case SAA7134_BOARD_MD2819:
+	case SAA7134_BOARD_AVERMEDIA_305:
+	case SAA7134_BOARD_AVERMEDIA_307:
+		ir_codes     = md2819_codes;
+		mask_keycode = 0x0007C8;
+		mask_keydown = 0x000010;
+		polling      = 50; // ms
+		/* Set GPIO pin2 to high to enable the IR controller */
+		saa_setb(SAA7134_GPIO_GPMODE0, 0x4);
+		saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
+		break;
+	case SAA7134_BOARD_VIDEOMATE_TV_PVR:
+		ir_codes     = videomate_tv_pvr_codes;
+		mask_keycode = 0x00003F;
+		mask_keyup   = 0x400000;
+		polling      = 50; // ms
+		break;
+	}
+	if (NULL == ir_codes) {
+		printk("%s: Oops: IR config error [card=%d]\n",
+		       dev->name, dev->board);
+		return -ENODEV;
+	}
+
+	ir = kmalloc(sizeof(*ir),GFP_KERNEL);
+	if (NULL == ir)
+		return -ENOMEM;
+	memset(ir,0,sizeof(*ir));
+
+	/* init hardware-specific stuff */
+	ir->mask_keycode = mask_keycode;
+	ir->mask_keydown = mask_keydown;
+	ir->mask_keyup   = mask_keyup;
+        ir->polling      = polling;
+
+	/* init input device */
+	snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
+		 saa7134_boards[dev->board].name);
+	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
+		 pci_name(dev->pci));
+
+	ir_input_init(&ir->dev, &ir->ir, ir_type, ir_codes);
+	ir->dev.name = ir->name;
+	ir->dev.phys = ir->phys;
+	ir->dev.id.bustype = BUS_PCI;
+	ir->dev.id.version = 1;
+	if (dev->pci->subsystem_vendor) {
+		ir->dev.id.vendor  = dev->pci->subsystem_vendor;
+		ir->dev.id.product = dev->pci->subsystem_device;
+	} else {
+		ir->dev.id.vendor  = dev->pci->vendor;
+		ir->dev.id.product = dev->pci->device;
+	}
+
+	/* all done */
+	dev->remote = ir;
+	if (ir->polling) {
+		init_timer(&ir->timer);
+		ir->timer.function = saa7134_input_timer;
+		ir->timer.data     = (unsigned long)dev;
+		ir->timer.expires  = jiffies + HZ;
+		add_timer(&ir->timer);
+	}
+
+	input_register_device(&dev->remote->dev);
+	printk("%s: registered input device for IR\n",dev->name);
+	return 0;
+}
+
+void saa7134_input_fini(struct saa7134_dev *dev)
+{
+	if (NULL == dev->remote)
+		return;
+
+	input_unregister_device(&dev->remote->dev);
+	if (dev->remote->polling)
+		del_timer_sync(&dev->remote->timer);
+	kfree(dev->remote);
+	dev->remote = NULL;
+}
+
+/* ----------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
new file mode 100644
index 0000000..6b6a643
--- /dev/null
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -0,0 +1,857 @@
+/*
+ * $Id: saa7134-oss.c,v 1.13 2004/12/10 12:33:39 kraxel Exp $
+ *
+ * device driver for philips saa7134 based TV cards
+ * oss dsp interface
+ *
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/soundcard.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int oss_debug  = 0;
+module_param(oss_debug, int, 0644);
+MODULE_PARM_DESC(oss_debug,"enable debug messages [oss]");
+
+static unsigned int oss_rate  = 0;
+module_param(oss_rate, int, 0444);
+MODULE_PARM_DESC(oss_rate,"sample rate (valid are: 32000,48000)");
+
+#define dprintk(fmt, arg...)	if (oss_debug) \
+	printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg)
+
+/* ------------------------------------------------------------------ */
+
+static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
+{
+	blksize &= ~0xff;
+	if (blksize < 0x100)
+		blksize = 0x100;
+	if (blksize > 0x10000)
+		blksize = 0x10000;
+
+	if (blocks < 2)
+		blocks = 2;
+        while ((blksize * blocks) & ~PAGE_MASK)
+		blocks++;
+	if ((blksize * blocks) > 1024*1024)
+		blocks = 1024*1024 / blksize;
+
+	dev->oss.blocks  = blocks;
+	dev->oss.blksize = blksize;
+	dev->oss.bufsize = blksize * blocks;
+
+	dprintk("buffer config: %d blocks / %d bytes, %d kB total\n",
+ 		blocks,blksize,blksize * blocks / 1024);
+	return 0;
+}
+
+static int dsp_buffer_init(struct saa7134_dev *dev)
+{
+	int err;
+
+	if (!dev->oss.bufsize)
+		BUG();
+	videobuf_dma_init(&dev->oss.dma);
+	err = videobuf_dma_init_kernel(&dev->oss.dma, PCI_DMA_FROMDEVICE,
+				       dev->oss.bufsize >> PAGE_SHIFT);
+	if (0 != err)
+		return err;
+	return 0;
+}
+
+static int dsp_buffer_free(struct saa7134_dev *dev)
+{
+	if (!dev->oss.blksize)
+		BUG();
+	videobuf_dma_free(&dev->oss.dma);
+	dev->oss.blocks  = 0;
+	dev->oss.blksize = 0;
+	dev->oss.bufsize = 0;
+	return 0;
+}
+
+static void dsp_dma_start(struct saa7134_dev *dev)
+{
+	dev->oss.dma_blk     = 0;
+	dev->oss.dma_running = 1;
+	saa7134_set_dmabits(dev);
+}
+
+static void dsp_dma_stop(struct saa7134_dev *dev)
+{
+	dev->oss.dma_blk     = -1;
+	dev->oss.dma_running = 0;
+	saa7134_set_dmabits(dev);
+}
+
+static int dsp_rec_start(struct saa7134_dev *dev)
+{
+	int err, bswap, sign;
+	u32 fmt, control;
+	unsigned long flags;
+
+	/* prepare buffer */
+	if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->oss.dma)))
+		return err;
+	if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->oss.pt)))
+		goto fail1;
+	if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->oss.pt,
+					      dev->oss.dma.sglist,
+					      dev->oss.dma.sglen,
+					      0)))
+		goto fail2;
+
+	/* sample format */
+	switch (dev->oss.afmt) {
+	case AFMT_U8:
+	case AFMT_S8:     fmt = 0x00;  break;
+	case AFMT_U16_LE:
+	case AFMT_U16_BE:
+	case AFMT_S16_LE:
+	case AFMT_S16_BE: fmt = 0x01;  break;
+	default:
+		err = -EINVAL;
+		goto fail2;
+	}
+
+	switch (dev->oss.afmt) {
+	case AFMT_S8:
+	case AFMT_S16_LE:
+	case AFMT_S16_BE: sign = 1; break;
+	default:          sign = 0; break;
+	}
+
+	switch (dev->oss.afmt) {
+	case AFMT_U16_BE:
+	case AFMT_S16_BE: bswap = 1; break;
+	default:          bswap = 0; break;
+	}
+
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		if (1 == dev->oss.channels)
+			fmt |= (1 << 3);
+		if (2 == dev->oss.channels)
+			fmt |= (3 << 3);
+		if (sign)
+			fmt |= 0x04;
+		fmt |= (TV == dev->oss.input) ? 0xc0 : 0x80;
+
+		saa_writeb(SAA7134_NUM_SAMPLES0, (dev->oss.blksize & 0x0000ff));
+		saa_writeb(SAA7134_NUM_SAMPLES1, (dev->oss.blksize & 0x00ff00) >>  8);
+		saa_writeb(SAA7134_NUM_SAMPLES2, (dev->oss.blksize & 0xff0000) >> 16);
+		saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		if (1 == dev->oss.channels)
+			fmt |= (1 << 4);
+		if (2 == dev->oss.channels)
+			fmt |= (2 << 4);
+		if (!sign)
+			fmt |= 0x04;
+		saa_writel(0x588 >> 2, dev->oss.blksize -4);
+		saa_writel(0x58c >> 2, 0x543210 | (fmt << 24));
+		break;
+	}
+	dprintk("rec_start: afmt=%d ch=%d  =>  fmt=0x%x swap=%c\n",
+		dev->oss.afmt, dev->oss.channels, fmt,
+		bswap ? 'b' : '-');
+
+	/* dma: setup channel 6 (= AUDIO) */
+	control = SAA7134_RS_CONTROL_BURST_16 |
+		SAA7134_RS_CONTROL_ME |
+		(dev->oss.pt.dma >> 12);
+	if (bswap)
+		control |= SAA7134_RS_CONTROL_BSWAP;
+	saa_writel(SAA7134_RS_BA1(6),0);
+	saa_writel(SAA7134_RS_BA2(6),dev->oss.blksize);
+	saa_writel(SAA7134_RS_PITCH(6),0);
+	saa_writel(SAA7134_RS_CONTROL(6),control);
+
+	/* start dma */
+	dev->oss.recording_on = 1;
+	spin_lock_irqsave(&dev->slock,flags);
+	dsp_dma_start(dev);
+	spin_unlock_irqrestore(&dev->slock,flags);
+	return 0;
+
+ fail2:
+	saa7134_pgtable_free(dev->pci,&dev->oss.pt);
+ fail1:
+	videobuf_dma_pci_unmap(dev->pci,&dev->oss.dma);
+	return err;
+}
+
+static int dsp_rec_stop(struct saa7134_dev *dev)
+{
+	unsigned long flags;
+
+	dprintk("rec_stop dma_blk=%d\n",dev->oss.dma_blk);
+
+	/* stop dma */
+	dev->oss.recording_on = 0;
+	spin_lock_irqsave(&dev->slock,flags);
+	dsp_dma_stop(dev);
+	spin_unlock_irqrestore(&dev->slock,flags);
+
+	/* unlock buffer */
+	saa7134_pgtable_free(dev->pci,&dev->oss.pt);
+	videobuf_dma_pci_unmap(dev->pci,&dev->oss.dma);
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int dsp_open(struct inode *inode, struct file *file)
+{
+	int minor = iminor(inode);
+	struct saa7134_dev *h,*dev = NULL;
+	struct list_head *list;
+	int err;
+
+	list_for_each(list,&saa7134_devlist) {
+		h = list_entry(list, struct saa7134_dev, devlist);
+		if (h->oss.minor_dsp == minor)
+			dev = h;
+	}
+	if (NULL == dev)
+		return -ENODEV;
+
+	down(&dev->oss.lock);
+	err = -EBUSY;
+	if (dev->oss.users_dsp)
+		goto fail1;
+	dev->oss.users_dsp++;
+	file->private_data = dev;
+
+	dev->oss.afmt        = AFMT_U8;
+	dev->oss.channels    = 1;
+	dev->oss.read_count  = 0;
+	dev->oss.read_offset = 0;
+	dsp_buffer_conf(dev,PAGE_SIZE,64);
+	err = dsp_buffer_init(dev);
+	if (0 != err)
+		goto fail2;
+
+	up(&dev->oss.lock);
+	return 0;
+
+ fail2:
+	dev->oss.users_dsp--;
+ fail1:
+	up(&dev->oss.lock);
+	return err;
+}
+
+static int dsp_release(struct inode *inode, struct file *file)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	down(&dev->oss.lock);
+	if (dev->oss.recording_on)
+		dsp_rec_stop(dev);
+	dsp_buffer_free(dev);
+	dev->oss.users_dsp--;
+	file->private_data = NULL;
+	up(&dev->oss.lock);
+	return 0;
+}
+
+static ssize_t dsp_read(struct file *file, char __user *buffer,
+			size_t count, loff_t *ppos)
+{
+	struct saa7134_dev *dev = file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned int bytes;
+	unsigned long flags;
+	int err,ret = 0;
+
+	add_wait_queue(&dev->oss.wq, &wait);
+	down(&dev->oss.lock);
+	while (count > 0) {
+		/* wait for data if needed */
+		if (0 == dev->oss.read_count) {
+			if (!dev->oss.recording_on) {
+				err = dsp_rec_start(dev);
+				if (err < 0) {
+					if (0 == ret)
+						ret = err;
+					break;
+				}
+			}
+			if (dev->oss.recording_on &&
+			    !dev->oss.dma_running) {
+				/* recover from overruns */
+				spin_lock_irqsave(&dev->slock,flags);
+				dsp_dma_start(dev);
+				spin_unlock_irqrestore(&dev->slock,flags);
+			}
+			if (file->f_flags & O_NONBLOCK) {
+				if (0 == ret)
+					ret = -EAGAIN;
+				break;
+			}
+			up(&dev->oss.lock);
+			set_current_state(TASK_INTERRUPTIBLE);
+			if (0 == dev->oss.read_count)
+				schedule();
+			set_current_state(TASK_RUNNING);
+			down(&dev->oss.lock);
+			if (signal_pending(current)) {
+				if (0 == ret)
+					ret = -EINTR;
+				break;
+			}
+		}
+
+		/* copy data to userspace */
+		bytes = count;
+		if (bytes > dev->oss.read_count)
+			bytes = dev->oss.read_count;
+		if (bytes > dev->oss.bufsize - dev->oss.read_offset)
+			bytes = dev->oss.bufsize - dev->oss.read_offset;
+		if (copy_to_user(buffer + ret,
+				 dev->oss.dma.vmalloc + dev->oss.read_offset,
+				 bytes)) {
+			if (0 == ret)
+				ret = -EFAULT;
+			break;
+		}
+
+		ret   += bytes;
+		count -= bytes;
+		dev->oss.read_count  -= bytes;
+		dev->oss.read_offset += bytes;
+		if (dev->oss.read_offset == dev->oss.bufsize)
+			dev->oss.read_offset = 0;
+	}
+	up(&dev->oss.lock);
+	remove_wait_queue(&dev->oss.wq, &wait);
+	return ret;
+}
+
+static ssize_t dsp_write(struct file *file, const char __user *buffer,
+			 size_t count, loff_t *ppos)
+{
+	return -EINVAL;
+}
+
+static int dsp_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	struct saa7134_dev *dev = file->private_data;
+	void __user *argp = (void __user *) arg;
+	int __user *p = argp;
+	int val = 0;
+
+	if (oss_debug > 1)
+		saa7134_print_ioctl(dev->name,cmd);
+        switch (cmd) {
+        case OSS_GETVERSION:
+                return put_user(SOUND_VERSION, p);
+        case SNDCTL_DSP_GETCAPS:
+		return 0;
+
+        case SNDCTL_DSP_SPEED:
+		if (get_user(val, p))
+			return -EFAULT;
+		/* fall through */
+        case SOUND_PCM_READ_RATE:
+		return put_user(dev->oss.rate, p);
+
+        case SNDCTL_DSP_STEREO:
+		if (get_user(val, p))
+			return -EFAULT;
+		down(&dev->oss.lock);
+		dev->oss.channels = val ? 2 : 1;
+		if (dev->oss.recording_on) {
+			dsp_rec_stop(dev);
+			dsp_rec_start(dev);
+		}
+		up(&dev->oss.lock);
+		return put_user(dev->oss.channels-1, p);
+
+        case SNDCTL_DSP_CHANNELS:
+		if (get_user(val, p))
+			return -EFAULT;
+		if (val != 1 && val != 2)
+			return -EINVAL;
+		down(&dev->oss.lock);
+		dev->oss.channels = val;
+		if (dev->oss.recording_on) {
+			dsp_rec_stop(dev);
+			dsp_rec_start(dev);
+		}
+		up(&dev->oss.lock);
+		/* fall through */
+        case SOUND_PCM_READ_CHANNELS:
+		return put_user(dev->oss.channels, p);
+
+        case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+		return put_user(AFMT_U8     | AFMT_S8     |
+				AFMT_U16_LE | AFMT_U16_BE |
+				AFMT_S16_LE | AFMT_S16_BE, p);
+
+        case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */
+		if (get_user(val, p))
+			return -EFAULT;
+		switch (val) {
+		case AFMT_QUERY:
+			/* nothing to do */
+			break;
+		case AFMT_U8:
+		case AFMT_S8:
+		case AFMT_U16_LE:
+		case AFMT_U16_BE:
+		case AFMT_S16_LE:
+		case AFMT_S16_BE:
+			down(&dev->oss.lock);
+			dev->oss.afmt = val;
+			if (dev->oss.recording_on) {
+				dsp_rec_stop(dev);
+				dsp_rec_start(dev);
+			}
+			up(&dev->oss.lock);
+			return put_user(dev->oss.afmt, p);
+		default:
+			return -EINVAL;
+		}
+
+        case SOUND_PCM_READ_BITS:
+		switch (dev->oss.afmt) {
+		case AFMT_U8:
+		case AFMT_S8:
+			return put_user(8, p);
+		case AFMT_U16_LE:
+		case AFMT_U16_BE:
+		case AFMT_S16_LE:
+		case AFMT_S16_BE:
+			return put_user(16, p);
+		default:
+			return -EINVAL;
+		}
+
+        case SNDCTL_DSP_NONBLOCK:
+                file->f_flags |= O_NONBLOCK;
+                return 0;
+
+        case SNDCTL_DSP_RESET:
+		down(&dev->oss.lock);
+		if (dev->oss.recording_on)
+			dsp_rec_stop(dev);
+		up(&dev->oss.lock);
+		return 0;
+        case SNDCTL_DSP_GETBLKSIZE:
+		return put_user(dev->oss.blksize, p);
+
+        case SNDCTL_DSP_SETFRAGMENT:
+		if (get_user(val, p))
+			return -EFAULT;
+		if (dev->oss.recording_on)
+			return -EBUSY;
+		dsp_buffer_free(dev);
+		/* used to be arg >> 16 instead of val >> 16; fixed */
+		dsp_buffer_conf(dev,1 << (val & 0xffff), (val >> 16) & 0xffff);
+		dsp_buffer_init(dev);
+		return 0;
+
+        case SNDCTL_DSP_SYNC:
+		/* NOP */
+		return 0;
+
+	case SNDCTL_DSP_GETISPACE:
+	{
+		audio_buf_info info;
+		info.fragsize   = dev->oss.blksize;
+		info.fragstotal = dev->oss.blocks;
+		info.bytes      = dev->oss.read_count;
+		info.fragments  = info.bytes / info.fragsize;
+		if (copy_to_user(argp, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	default:
+		return -EINVAL;
+	}
+}
+
+static unsigned int dsp_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct saa7134_dev *dev = file->private_data;
+	unsigned int mask = 0;
+
+	poll_wait(file, &dev->oss.wq, wait);
+
+	if (0 == dev->oss.read_count) {
+		down(&dev->oss.lock);
+		if (!dev->oss.recording_on)
+			dsp_rec_start(dev);
+		up(&dev->oss.lock);
+	} else
+		mask |= (POLLIN | POLLRDNORM);
+	return mask;
+}
+
+struct file_operations saa7134_dsp_fops = {
+	.owner   = THIS_MODULE,
+	.open    = dsp_open,
+	.release = dsp_release,
+	.read    = dsp_read,
+	.write   = dsp_write,
+	.ioctl   = dsp_ioctl,
+	.poll    = dsp_poll,
+	.llseek  = no_llseek,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int
+mixer_recsrc_7134(struct saa7134_dev *dev)
+{
+	int analog_io,rate;
+
+	switch (dev->oss.input) {
+	case TV:
+		saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0);
+		saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, 0x00);
+		break;
+	case LINE1:
+	case LINE2:
+	case LINE2_LEFT:
+		analog_io = (LINE1 == dev->oss.input) ? 0x00 : 0x08;
+		rate = (32000 == dev->oss.rate) ? 0x01 : 0x03;
+		saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x08, analog_io);
+		saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80);
+		saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, rate);
+		break;
+	}
+	return 0;
+}
+
+static int
+mixer_recsrc_7133(struct saa7134_dev *dev)
+{
+	u32 value = 0xbbbbbb;
+
+	switch (dev->oss.input) {
+	case TV:
+		value = 0xbbbb10;  /* MAIN */
+		break;
+	case LINE1:
+		value = 0xbbbb32;  /* AUX1 */
+		break;
+	case LINE2:
+	case LINE2_LEFT:
+		value = 0xbbbb54;  /* AUX2 */
+		break;
+	}
+	saa_dsp_writel(dev, 0x46c >> 2, value);
+	return 0;
+}
+
+static int
+mixer_recsrc(struct saa7134_dev *dev, enum saa7134_audio_in src)
+{
+	static const char *iname[] = { "Oops", "TV", "LINE1", "LINE2" };
+
+	dev->oss.count++;
+	dev->oss.input = src;
+	dprintk("mixer input = %s\n",iname[dev->oss.input]);
+
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		mixer_recsrc_7134(dev);
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		mixer_recsrc_7133(dev);
+		break;
+	}
+	return 0;
+}
+
+static int
+mixer_level(struct saa7134_dev *dev, enum saa7134_audio_in src, int level)
+{
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		switch (src) {
+		case TV:
+			/* nothing */
+			break;
+		case LINE1:
+			saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x10,
+				   (100 == level) ? 0x00 : 0x10);
+			break;
+		case LINE2:
+		case LINE2_LEFT:
+			saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x20,
+				   (100 == level) ? 0x00 : 0x20);
+			break;
+		}
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		/* nothing */
+		break;
+	}
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int mixer_open(struct inode *inode, struct file *file)
+{
+	int minor = iminor(inode);
+	struct saa7134_dev *h,*dev = NULL;
+	struct list_head *list;
+
+	list_for_each(list,&saa7134_devlist) {
+		h = list_entry(list, struct saa7134_dev, devlist);
+		if (h->oss.minor_mixer == minor)
+			dev = h;
+	}
+	if (NULL == dev)
+		return -ENODEV;
+
+	file->private_data = dev;
+	return 0;
+}
+
+static int mixer_release(struct inode *inode, struct file *file)
+{
+	file->private_data = NULL;
+	return 0;
+}
+
+static int mixer_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	struct saa7134_dev *dev = file->private_data;
+	enum saa7134_audio_in input;
+	int val,ret;
+	void __user *argp = (void __user *) arg;
+	int __user *p = argp;
+
+	if (oss_debug > 1)
+		saa7134_print_ioctl(dev->name,cmd);
+        switch (cmd) {
+        case OSS_GETVERSION:
+                return put_user(SOUND_VERSION, p);
+	case SOUND_MIXER_INFO:
+	{
+		mixer_info info;
+		memset(&info,0,sizeof(info));
+                strlcpy(info.id,   "TV audio", sizeof(info.id));
+                strlcpy(info.name, dev->name,  sizeof(info.name));
+                info.modify_counter = dev->oss.count;
+                if (copy_to_user(argp, &info, sizeof(info)))
+                        return -EFAULT;
+		return 0;
+	}
+	case SOUND_OLD_MIXER_INFO:
+	{
+		_old_mixer_info info;
+		memset(&info,0,sizeof(info));
+                strlcpy(info.id,   "TV audio", sizeof(info.id));
+                strlcpy(info.name, dev->name,  sizeof(info.name));
+                if (copy_to_user(argp, &info, sizeof(info)))
+                        return -EFAULT;
+		return 0;
+	}
+	case MIXER_READ(SOUND_MIXER_CAPS):
+		return put_user(SOUND_CAP_EXCL_INPUT, p);
+	case MIXER_READ(SOUND_MIXER_STEREODEVS):
+		return put_user(0, p);
+	case MIXER_READ(SOUND_MIXER_RECMASK):
+	case MIXER_READ(SOUND_MIXER_DEVMASK):
+		val = SOUND_MASK_LINE1 | SOUND_MASK_LINE2;
+		if (32000 == dev->oss.rate)
+			val |= SOUND_MASK_VIDEO;
+		return put_user(val, p);
+
+	case MIXER_WRITE(SOUND_MIXER_RECSRC):
+		if (get_user(val, p))
+			return -EFAULT;
+		input = dev->oss.input;
+		if (32000 == dev->oss.rate  &&
+		    val & SOUND_MASK_VIDEO  &&  dev->oss.input != TV)
+			input = TV;
+		if (val & SOUND_MASK_LINE1  &&  dev->oss.input != LINE1)
+			input = LINE1;
+		if (val & SOUND_MASK_LINE2  &&  dev->oss.input != LINE2)
+			input = LINE2;
+		if (input != dev->oss.input)
+			mixer_recsrc(dev,input);
+		/* fall throuth */
+	case MIXER_READ(SOUND_MIXER_RECSRC):
+		switch (dev->oss.input) {
+		case TV:    ret = SOUND_MASK_VIDEO; break;
+		case LINE1: ret = SOUND_MASK_LINE1; break;
+		case LINE2: ret = SOUND_MASK_LINE2; break;
+		default:    ret = 0;
+		}
+		return put_user(ret, p);
+
+	case MIXER_WRITE(SOUND_MIXER_VIDEO):
+	case MIXER_READ(SOUND_MIXER_VIDEO):
+		if (32000 != dev->oss.rate)
+			return -EINVAL;
+		return put_user(100 | 100 << 8, p);
+
+	case MIXER_WRITE(SOUND_MIXER_LINE1):
+		if (get_user(val, p))
+			return -EFAULT;
+		val &= 0xff;
+		val = (val <= 50) ? 50 : 100;
+		dev->oss.line1 = val;
+		mixer_level(dev,LINE1,dev->oss.line1);
+		/* fall throuth */
+	case MIXER_READ(SOUND_MIXER_LINE1):
+		return put_user(dev->oss.line1 | dev->oss.line1 << 8, p);
+
+	case MIXER_WRITE(SOUND_MIXER_LINE2):
+		if (get_user(val, p))
+			return -EFAULT;
+		val &= 0xff;
+		val = (val <= 50) ? 50 : 100;
+		dev->oss.line2 = val;
+		mixer_level(dev,LINE2,dev->oss.line2);
+		/* fall throuth */
+	case MIXER_READ(SOUND_MIXER_LINE2):
+		return put_user(dev->oss.line2 | dev->oss.line2 << 8, p);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+struct file_operations saa7134_mixer_fops = {
+	.owner   = THIS_MODULE,
+	.open    = mixer_open,
+	.release = mixer_release,
+	.ioctl   = mixer_ioctl,
+	.llseek  = no_llseek,
+};
+
+/* ------------------------------------------------------------------ */
+
+int saa7134_oss_init1(struct saa7134_dev *dev)
+{
+	/* general */
+        init_MUTEX(&dev->oss.lock);
+	init_waitqueue_head(&dev->oss.wq);
+
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		saa_writel(0x588 >> 2, 0x00000fff);
+		saa_writel(0x58c >> 2, 0x00543210);
+		saa_dsp_writel(dev, 0x46c >> 2, 0xbbbbbb);
+		break;
+	}
+
+	/* dsp */
+	dev->oss.rate = 32000;
+	if (oss_rate)
+		dev->oss.rate = oss_rate;
+	dev->oss.rate = (dev->oss.rate > 40000) ? 48000 : 32000;
+
+	/* mixer */
+	dev->oss.line1 = 50;
+	dev->oss.line2 = 50;
+	mixer_level(dev,LINE1,dev->oss.line1);
+	mixer_level(dev,LINE2,dev->oss.line2);
+	mixer_recsrc(dev, (dev->oss.rate == 32000) ? TV : LINE2);
+
+	return 0;
+}
+
+int saa7134_oss_fini(struct saa7134_dev *dev)
+{
+	/* nothing */
+	return 0;
+}
+
+void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status)
+{
+	int next_blk, reg = 0;
+
+	spin_lock(&dev->slock);
+	if (UNSET == dev->oss.dma_blk) {
+		dprintk("irq: recording stopped\n");
+		goto done;
+	}
+	if (0 != (status & 0x0f000000))
+		dprintk("irq: lost %ld\n", (status >> 24) & 0x0f);
+	if (0 == (status & 0x10000000)) {
+		/* odd */
+		if (0 == (dev->oss.dma_blk & 0x01))
+			reg = SAA7134_RS_BA1(6);
+	} else {
+		/* even */
+		if (0 == (dev->oss.dma_blk & 0x00))
+			reg = SAA7134_RS_BA2(6);
+	}
+	if (0 == reg) {
+		dprintk("irq: field oops [%s]\n",
+			(status & 0x10000000) ? "even" : "odd");
+		goto done;
+	}
+	if (dev->oss.read_count >= dev->oss.blksize * (dev->oss.blocks-2)) {
+		dprintk("irq: overrun [full=%d/%d]\n",dev->oss.read_count,
+			dev->oss.bufsize);
+		dsp_dma_stop(dev);
+		goto done;
+	}
+
+	/* next block addr */
+	next_blk = (dev->oss.dma_blk + 2) % dev->oss.blocks;
+	saa_writel(reg,next_blk * dev->oss.blksize);
+	if (oss_debug > 2)
+		dprintk("irq: ok, %s, next_blk=%d, addr=%x\n",
+			(status & 0x10000000) ? "even" : "odd ", next_blk,
+			next_blk * dev->oss.blksize);
+
+	/* update status & wake waiting readers */
+	dev->oss.dma_blk = (dev->oss.dma_blk + 1) % dev->oss.blocks;
+	dev->oss.read_count += dev->oss.blksize;
+	wake_up(&dev->oss.wq);
+
+ done:
+	spin_unlock(&dev->slock);
+}
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/saa7134/saa7134-reg.h b/drivers/media/video/saa7134/saa7134-reg.h
new file mode 100644
index 0000000..87734f2
--- /dev/null
+++ b/drivers/media/video/saa7134/saa7134-reg.h
@@ -0,0 +1,366 @@
+/*
+ * $Id: saa7134-reg.h,v 1.2 2004/09/15 16:15:24 kraxel Exp $
+ *
+ * philips saa7134 registers
+ */
+
+/* ------------------------------------------------------------------ */
+/*
+ * PCI ID's
+ */
+#ifndef PCI_DEVICE_ID_PHILIPS_SAA7130
+# define PCI_DEVICE_ID_PHILIPS_SAA7130 0x7130
+#endif
+#ifndef PCI_DEVICE_ID_PHILIPS_SAA7133
+# define PCI_DEVICE_ID_PHILIPS_SAA7133 0x7133
+#endif
+#ifndef PCI_DEVICE_ID_PHILIPS_SAA7134
+# define PCI_DEVICE_ID_PHILIPS_SAA7134 0x7134
+#endif
+#ifndef PCI_DEVICE_ID_PHILIPS_SAA7135
+# define PCI_DEVICE_ID_PHILIPS_SAA7135 0x7135
+#endif
+
+/* ------------------------------------------------------------------ */
+/*
+ *  registers -- 32 bit
+ */
+
+/* DMA channels, n = 0 ... 6 */
+#define SAA7134_RS_BA1(n)			((0x200 >> 2) + 4*n)
+#define SAA7134_RS_BA2(n)	       		((0x204 >> 2) + 4*n)
+#define SAA7134_RS_PITCH(n)			((0x208 >> 2) + 4*n)
+#define SAA7134_RS_CONTROL(n)			((0x20c >> 2) + 4*n)
+#define   SAA7134_RS_CONTROL_WSWAP		(0x01 << 25)
+#define   SAA7134_RS_CONTROL_BSWAP		(0x01 << 24)
+#define   SAA7134_RS_CONTROL_BURST_2		(0x01 << 21)
+#define   SAA7134_RS_CONTROL_BURST_4		(0x02 << 21)
+#define   SAA7134_RS_CONTROL_BURST_8		(0x03 << 21)
+#define   SAA7134_RS_CONTROL_BURST_16		(0x04 << 21)
+#define   SAA7134_RS_CONTROL_BURST_32		(0x05 << 21)
+#define   SAA7134_RS_CONTROL_BURST_64		(0x06 << 21)
+#define   SAA7134_RS_CONTROL_BURST_MAX		(0x07 << 21)
+#define   SAA7134_RS_CONTROL_ME			(0x01 << 20)
+#define SAA7134_FIFO_SIZE                       (0x2a0 >> 2)
+#define SAA7134_THRESHOULD                      (0x2a4 >> 2)
+
+/* main control */
+#define SAA7134_MAIN_CTRL                       (0x2a8 >> 2)
+#define   SAA7134_MAIN_CTRL_VPLLE	       	(1 << 15)
+#define   SAA7134_MAIN_CTRL_APLLE	       	(1 << 14)
+#define   SAA7134_MAIN_CTRL_EXOSC	       	(1 << 13)
+#define   SAA7134_MAIN_CTRL_EVFE1	       	(1 << 12)
+#define   SAA7134_MAIN_CTRL_EVFE2	       	(1 << 11)
+#define   SAA7134_MAIN_CTRL_ESFE	       	(1 << 10)
+#define   SAA7134_MAIN_CTRL_EBADC	       	(1 << 9)
+#define   SAA7134_MAIN_CTRL_EBDAC	       	(1 << 8)
+#define   SAA7134_MAIN_CTRL_TE6			(1 << 6)
+#define   SAA7134_MAIN_CTRL_TE5			(1 << 5)
+#define   SAA7134_MAIN_CTRL_TE4			(1 << 4)
+#define   SAA7134_MAIN_CTRL_TE3			(1 << 3)
+#define   SAA7134_MAIN_CTRL_TE2			(1 << 2)
+#define   SAA7134_MAIN_CTRL_TE1			(1 << 1)
+#define   SAA7134_MAIN_CTRL_TE0			(1 << 0)
+
+/* DMA status */
+#define SAA7134_DMA_STATUS                      (0x2ac >> 2)
+
+/* audio / video status */
+#define SAA7134_AV_STATUS			(0x2c0 >> 2)
+#define   SAA7134_AV_STATUS_STEREO		(1 << 17)
+#define   SAA7134_AV_STATUS_DUAL                (1 << 16)
+#define   SAA7134_AV_STATUS_PILOT               (1 << 15)
+#define   SAA7134_AV_STATUS_SMB                 (1 << 14)
+#define   SAA7134_AV_STATUS_DMB                 (1 << 13)
+#define   SAA7134_AV_STATUS_VDSP                (1 << 12)
+#define   SAA7134_AV_STATUS_IIC_STATUS          (3 << 10)
+#define   SAA7134_AV_STATUS_MVM                 (7 << 7)
+#define   SAA7134_AV_STATUS_FIDT                (1 << 6)
+#define   SAA7134_AV_STATUS_INTL                (1 << 5)
+#define   SAA7134_AV_STATUS_RDCAP               (1 << 4)
+#define   SAA7134_AV_STATUS_PWR_ON              (1 << 3)
+#define   SAA7134_AV_STATUS_LOAD_ERR            (1 << 2)
+#define   SAA7134_AV_STATUS_TRIG_ERR            (1 << 1)
+#define   SAA7134_AV_STATUS_CONF_ERR            (1 << 0)
+
+/* interrupt */
+#define SAA7134_IRQ1                            (0x2c4 >> 2)
+#define   SAA7134_IRQ1_INTE_RA3_1               (1 << 25)
+#define   SAA7134_IRQ1_INTE_RA3_0               (1 << 24)
+#define   SAA7134_IRQ1_INTE_RA2_3               (1 << 19)
+#define   SAA7134_IRQ1_INTE_RA2_2               (1 << 18)
+#define   SAA7134_IRQ1_INTE_RA2_1               (1 << 17)
+#define   SAA7134_IRQ1_INTE_RA2_0               (1 << 16)
+#define   SAA7134_IRQ1_INTE_RA1_3               (1 << 11)
+#define   SAA7134_IRQ1_INTE_RA1_2               (1 << 10)
+#define   SAA7134_IRQ1_INTE_RA1_1               (1 <<  9)
+#define   SAA7134_IRQ1_INTE_RA1_0               (1 <<  8)
+#define   SAA7134_IRQ1_INTE_RA0_7               (1 <<  7)
+#define   SAA7134_IRQ1_INTE_RA0_6               (1 <<  6)
+#define   SAA7134_IRQ1_INTE_RA0_5               (1 <<  5)
+#define   SAA7134_IRQ1_INTE_RA0_4               (1 <<  4)
+#define   SAA7134_IRQ1_INTE_RA0_3               (1 <<  3)
+#define   SAA7134_IRQ1_INTE_RA0_2               (1 <<  2)
+#define   SAA7134_IRQ1_INTE_RA0_1               (1 <<  1)
+#define   SAA7134_IRQ1_INTE_RA0_0               (1 <<  0)
+
+#define SAA7134_IRQ2                            (0x2c8 >> 2)
+#define   SAA7134_IRQ2_INTE_GPIO23A             (1 << 17)
+#define   SAA7134_IRQ2_INTE_GPIO23              (1 << 16)
+#define   SAA7134_IRQ2_INTE_GPIO22A             (1 << 15)
+#define   SAA7134_IRQ2_INTE_GPIO22              (1 << 14)
+#define   SAA7134_IRQ2_INTE_GPIO18A             (1 << 13)
+#define   SAA7134_IRQ2_INTE_GPIO18              (1 << 12)
+#define   SAA7134_IRQ2_INTE_GPIO16              (1 << 11) /* not certain */
+#define   SAA7134_IRQ2_INTE_SC2                 (1 << 10)
+#define   SAA7134_IRQ2_INTE_SC1                 (1 <<  9)
+#define   SAA7134_IRQ2_INTE_SC0                 (1 <<  8)
+#define   SAA7134_IRQ2_INTE_DEC5                (1 <<  7)
+#define   SAA7134_IRQ2_INTE_DEC4                (1 <<  6)
+#define   SAA7134_IRQ2_INTE_DEC3                (1 <<  5)
+#define   SAA7134_IRQ2_INTE_DEC2                (1 <<  4)
+#define   SAA7134_IRQ2_INTE_DEC1                (1 <<  3)
+#define   SAA7134_IRQ2_INTE_DEC0                (1 <<  2)
+#define   SAA7134_IRQ2_INTE_PE                  (1 <<  1)
+#define   SAA7134_IRQ2_INTE_AR                  (1 <<  0)
+
+#define SAA7134_IRQ_REPORT                      (0x2cc >> 2)
+#define   SAA7134_IRQ_REPORT_GPIO23             (1 << 17)
+#define   SAA7134_IRQ_REPORT_GPIO22             (1 << 16)
+#define   SAA7134_IRQ_REPORT_GPIO18             (1 << 15)
+#define   SAA7134_IRQ_REPORT_GPIO16             (1 << 14) /* not certain */
+#define   SAA7134_IRQ_REPORT_LOAD_ERR           (1 << 13)
+#define   SAA7134_IRQ_REPORT_CONF_ERR           (1 << 12)
+#define   SAA7134_IRQ_REPORT_TRIG_ERR           (1 << 11)
+#define   SAA7134_IRQ_REPORT_MMC                (1 << 10)
+#define   SAA7134_IRQ_REPORT_FIDT               (1 <<  9)
+#define   SAA7134_IRQ_REPORT_INTL               (1 <<  8)
+#define   SAA7134_IRQ_REPORT_RDCAP              (1 <<  7)
+#define   SAA7134_IRQ_REPORT_PWR_ON             (1 <<  6)
+#define   SAA7134_IRQ_REPORT_PE                 (1 <<  5)
+#define   SAA7134_IRQ_REPORT_AR                 (1 <<  4)
+#define   SAA7134_IRQ_REPORT_DONE_RA3           (1 <<  3)
+#define   SAA7134_IRQ_REPORT_DONE_RA2           (1 <<  2)
+#define   SAA7134_IRQ_REPORT_DONE_RA1           (1 <<  1)
+#define   SAA7134_IRQ_REPORT_DONE_RA0           (1 <<  0)
+#define SAA7134_IRQ_STATUS                      (0x2d0 >> 2)
+
+
+/* ------------------------------------------------------------------ */
+/*
+ *  registers -- 8 bit
+ */
+
+/* video decoder */
+#define SAA7134_INCR_DELAY                      0x101
+#define SAA7134_ANALOG_IN_CTRL1                 0x102
+#define SAA7134_ANALOG_IN_CTRL2                 0x103
+#define SAA7134_ANALOG_IN_CTRL3                 0x104
+#define SAA7134_ANALOG_IN_CTRL4                 0x105
+#define SAA7134_HSYNC_START                     0x106
+#define SAA7134_HSYNC_STOP                      0x107
+#define SAA7134_SYNC_CTRL                       0x108
+#define SAA7134_LUMA_CTRL                       0x109
+#define SAA7134_DEC_LUMA_BRIGHT                 0x10a
+#define SAA7134_DEC_LUMA_CONTRAST               0x10b
+#define SAA7134_DEC_CHROMA_SATURATION           0x10c
+#define SAA7134_DEC_CHROMA_HUE                  0x10d
+#define SAA7134_CHROMA_CTRL1                    0x10e
+#define SAA7134_CHROMA_GAIN                     0x10f
+#define SAA7134_CHROMA_CTRL2                    0x110
+#define SAA7134_MODE_DELAY_CTRL                 0x111
+
+#define SAA7134_ANALOG_ADC                      0x114
+#define SAA7134_VGATE_START                     0x115
+#define SAA7134_VGATE_STOP                      0x116
+#define SAA7134_MISC_VGATE_MSB                  0x117
+#define SAA7134_RAW_DATA_GAIN                   0x118
+#define SAA7134_RAW_DATA_OFFSET                 0x119
+#define SAA7134_STATUS_VIDEO1                   0x11e
+#define SAA7134_STATUS_VIDEO2                   0x11f
+
+/* video scaler */
+#define SAA7134_SOURCE_TIMING1                  0x000
+#define SAA7134_SOURCE_TIMING2                  0x001
+#define SAA7134_REGION_ENABLE                   0x004
+#define SAA7134_SCALER_STATUS0                  0x006
+#define SAA7134_SCALER_STATUS1                  0x007
+#define SAA7134_START_GREEN                     0x00c
+#define SAA7134_START_BLUE                      0x00d
+#define SAA7134_START_RED                       0x00e
+#define SAA7134_GREEN_PATH(x)                   (0x010 +x)
+#define SAA7134_BLUE_PATH(x)                    (0x020 +x)
+#define SAA7134_RED_PATH(x)                     (0x030 +x)
+
+#define TASK_A                                  0x040
+#define TASK_B                                  0x080
+#define SAA7134_TASK_CONDITIONS(t)              (0x000 +t)
+#define SAA7134_FIELD_HANDLING(t)               (0x001 +t)
+#define SAA7134_DATA_PATH(t)                    (0x002 +t)
+#define SAA7134_VBI_H_START1(t)                 (0x004 +t)
+#define SAA7134_VBI_H_START2(t)                 (0x005 +t)
+#define SAA7134_VBI_H_STOP1(t)                  (0x006 +t)
+#define SAA7134_VBI_H_STOP2(t)                  (0x007 +t)
+#define SAA7134_VBI_V_START1(t)                 (0x008 +t)
+#define SAA7134_VBI_V_START2(t)                 (0x009 +t)
+#define SAA7134_VBI_V_STOP1(t)                  (0x00a +t)
+#define SAA7134_VBI_V_STOP2(t)                  (0x00b +t)
+#define SAA7134_VBI_H_LEN1(t)                   (0x00c +t)
+#define SAA7134_VBI_H_LEN2(t)                   (0x00d +t)
+#define SAA7134_VBI_V_LEN1(t)                   (0x00e +t)
+#define SAA7134_VBI_V_LEN2(t)                   (0x00f +t)
+
+#define SAA7134_VIDEO_H_START1(t)               (0x014 +t)
+#define SAA7134_VIDEO_H_START2(t)               (0x015 +t)
+#define SAA7134_VIDEO_H_STOP1(t)                (0x016 +t)
+#define SAA7134_VIDEO_H_STOP2(t)                (0x017 +t)
+#define SAA7134_VIDEO_V_START1(t)               (0x018 +t)
+#define SAA7134_VIDEO_V_START2(t)               (0x019 +t)
+#define SAA7134_VIDEO_V_STOP1(t)                (0x01a +t)
+#define SAA7134_VIDEO_V_STOP2(t)                (0x01b +t)
+#define SAA7134_VIDEO_PIXELS1(t)                (0x01c +t)
+#define SAA7134_VIDEO_PIXELS2(t)                (0x01d +t)
+#define SAA7134_VIDEO_LINES1(t)                 (0x01e +t)
+#define SAA7134_VIDEO_LINES2(t)                 (0x01f +t)
+
+#define SAA7134_H_PRESCALE(t)                   (0x020 +t)
+#define SAA7134_ACC_LENGTH(t)                   (0x021 +t)
+#define SAA7134_LEVEL_CTRL(t)                   (0x022 +t)
+#define SAA7134_FIR_PREFILTER_CTRL(t)           (0x023 +t)
+#define SAA7134_LUMA_BRIGHT(t)                  (0x024 +t)
+#define SAA7134_LUMA_CONTRAST(t)                (0x025 +t)
+#define SAA7134_CHROMA_SATURATION(t)            (0x026 +t)
+#define SAA7134_VBI_H_SCALE_INC1(t)             (0x028 +t)
+#define SAA7134_VBI_H_SCALE_INC2(t)             (0x029 +t)
+#define SAA7134_VBI_PHASE_OFFSET_LUMA(t)        (0x02a +t)
+#define SAA7134_VBI_PHASE_OFFSET_CHROMA(t)      (0x02b +t)
+#define SAA7134_H_SCALE_INC1(t)                 (0x02c +t)
+#define SAA7134_H_SCALE_INC2(t)                 (0x02d +t)
+#define SAA7134_H_PHASE_OFF_LUMA(t)             (0x02e +t)
+#define SAA7134_H_PHASE_OFF_CHROMA(t)           (0x02f +t)
+#define SAA7134_V_SCALE_RATIO1(t)               (0x030 +t)
+#define SAA7134_V_SCALE_RATIO2(t)               (0x031 +t)
+#define SAA7134_V_FILTER(t)                     (0x032 +t)
+#define SAA7134_V_PHASE_OFFSET0(t)              (0x034 +t)
+#define SAA7134_V_PHASE_OFFSET1(t)              (0x035 +t)
+#define SAA7134_V_PHASE_OFFSET2(t)              (0x036 +t)
+#define SAA7134_V_PHASE_OFFSET3(t)              (0x037 +t)
+
+/* clipping & dma */
+#define SAA7134_OFMT_VIDEO_A                    0x300
+#define SAA7134_OFMT_DATA_A                     0x301
+#define SAA7134_OFMT_VIDEO_B                    0x302
+#define SAA7134_OFMT_DATA_B                     0x303
+#define SAA7134_ALPHA_NOCLIP                    0x304
+#define SAA7134_ALPHA_CLIP                      0x305
+#define SAA7134_UV_PIXEL                        0x308
+#define SAA7134_CLIP_RED                        0x309
+#define SAA7134_CLIP_GREEN                      0x30a
+#define SAA7134_CLIP_BLUE                       0x30b
+
+/* i2c bus */
+#define SAA7134_I2C_ATTR_STATUS                 0x180
+#define SAA7134_I2C_DATA                        0x181
+#define SAA7134_I2C_CLOCK_SELECT                0x182
+#define SAA7134_I2C_TIMER                       0x183
+
+/* audio */
+#define SAA7134_NICAM_ADD_DATA1                 0x140
+#define SAA7134_NICAM_ADD_DATA2                 0x141
+#define SAA7134_NICAM_STATUS                    0x142
+#define SAA7134_AUDIO_STATUS                    0x143
+#define SAA7134_NICAM_ERROR_COUNT               0x144
+#define SAA7134_IDENT_SIF                       0x145
+#define SAA7134_LEVEL_READOUT1                  0x146
+#define SAA7134_LEVEL_READOUT2                  0x147
+#define SAA7134_NICAM_ERROR_LOW                 0x148
+#define SAA7134_NICAM_ERROR_HIGH                0x149
+#define SAA7134_DCXO_IDENT_CTRL                 0x14a
+#define SAA7134_DEMODULATOR                     0x14b
+#define SAA7134_AGC_GAIN_SELECT                 0x14c
+#define SAA7134_CARRIER1_FREQ0                  0x150
+#define SAA7134_CARRIER1_FREQ1                  0x151
+#define SAA7134_CARRIER1_FREQ2                  0x152
+#define SAA7134_CARRIER2_FREQ0                  0x154
+#define SAA7134_CARRIER2_FREQ1                  0x155
+#define SAA7134_CARRIER2_FREQ2                  0x156
+#define SAA7134_NUM_SAMPLES0                    0x158
+#define SAA7134_NUM_SAMPLES1                    0x159
+#define SAA7134_NUM_SAMPLES2                    0x15a
+#define SAA7134_AUDIO_FORMAT_CTRL               0x15b
+#define SAA7134_MONITOR_SELECT                  0x160
+#define SAA7134_FM_DEEMPHASIS                   0x161
+#define SAA7134_FM_DEMATRIX                     0x162
+#define SAA7134_CHANNEL1_LEVEL                  0x163
+#define SAA7134_CHANNEL2_LEVEL                  0x164
+#define SAA7134_NICAM_CONFIG                    0x165
+#define SAA7134_NICAM_LEVEL_ADJUST              0x166
+#define SAA7134_STEREO_DAC_OUTPUT_SELECT        0x167
+#define SAA7134_I2S_OUTPUT_FORMAT               0x168
+#define SAA7134_I2S_OUTPUT_SELECT               0x169
+#define SAA7134_I2S_OUTPUT_LEVEL                0x16a
+#define SAA7134_DSP_OUTPUT_SELECT               0x16b
+#define SAA7134_AUDIO_MUTE_CTRL                 0x16c
+#define SAA7134_SIF_SAMPLE_FREQ                 0x16d
+#define SAA7134_ANALOG_IO_SELECT                0x16e
+#define SAA7134_AUDIO_CLOCK0                    0x170
+#define SAA7134_AUDIO_CLOCK1                    0x171
+#define SAA7134_AUDIO_CLOCK2                    0x172
+#define SAA7134_AUDIO_PLL_CTRL                  0x173
+#define SAA7134_AUDIO_CLOCKS_PER_FIELD0         0x174
+#define SAA7134_AUDIO_CLOCKS_PER_FIELD1         0x175
+#define SAA7134_AUDIO_CLOCKS_PER_FIELD2         0x176
+
+/* video port output */
+#define SAA7134_VIDEO_PORT_CTRL0                0x190
+#define SAA7134_VIDEO_PORT_CTRL1                0x191
+#define SAA7134_VIDEO_PORT_CTRL2                0x192
+#define SAA7134_VIDEO_PORT_CTRL3                0x193
+#define SAA7134_VIDEO_PORT_CTRL4                0x194
+#define SAA7134_VIDEO_PORT_CTRL5                0x195
+#define SAA7134_VIDEO_PORT_CTRL6                0x196
+#define SAA7134_VIDEO_PORT_CTRL7                0x197
+#define SAA7134_VIDEO_PORT_CTRL8                0x198
+
+/* transport stream interface */
+#define SAA7134_TS_PARALLEL                     0x1a0
+#define SAA7134_TS_PARALLEL_SERIAL              0x1a1
+#define SAA7134_TS_SERIAL0                      0x1a2
+#define SAA7134_TS_SERIAL1                      0x1a3
+#define SAA7134_TS_DMA0                         0x1a4
+#define SAA7134_TS_DMA1                         0x1a5
+#define SAA7134_TS_DMA2                         0x1a6
+
+/* GPIO Controls */
+#define SAA7134_GPIO_GPRESCAN                   0x80
+#define SAA7134_GPIO_27_25                      0x0E
+
+#define SAA7134_GPIO_GPMODE0                    0x1B0
+#define SAA7134_GPIO_GPMODE1                    0x1B1
+#define SAA7134_GPIO_GPMODE2                    0x1B2
+#define SAA7134_GPIO_GPMODE3                    0x1B3
+#define SAA7134_GPIO_GPSTATUS0                  0x1B4
+#define SAA7134_GPIO_GPSTATUS1                  0x1B5
+#define SAA7134_GPIO_GPSTATUS2                  0x1B6
+#define SAA7134_GPIO_GPSTATUS3                  0x1B7
+
+/* I2S output */
+#define SAA7134_I2S_AUDIO_OUTPUT                0x1c0
+
+/* test modes */
+#define SAA7134_SPECIAL_MODE                    0x1d0
+
+/* audio -- saa7133 + saa7135 only */
+#define SAA7135_DSP_RWSTATE                     0x580
+#define SAA7135_DSP_RWSTATE_ERR                 (1 << 3)
+#define SAA7135_DSP_RWSTATE_IDA                 (1 << 2)
+#define SAA7135_DSP_RWSTATE_RDB                 (1 << 1)
+#define SAA7135_DSP_RWSTATE_WRR                 (1 << 0)
+
+/* ------------------------------------------------------------------ */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c
new file mode 100644
index 0000000..345eb2a
--- /dev/null
+++ b/drivers/media/video/saa7134/saa7134-ts.c
@@ -0,0 +1,243 @@
+/*
+ * $Id: saa7134-ts.c,v 1.14 2005/02/03 10:24:33 kraxel Exp $
+ *
+ * device driver for philips saa7134 based TV cards
+ * video4linux video interface
+ *
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int ts_debug  = 0;
+module_param(ts_debug, int, 0644);
+MODULE_PARM_DESC(ts_debug,"enable debug messages [ts]");
+
+#define dprintk(fmt, arg...)	if (ts_debug) \
+	printk(KERN_DEBUG "%s/ts: " fmt, dev->name , ## arg)
+
+/* ------------------------------------------------------------------ */
+
+static int buffer_activate(struct saa7134_dev *dev,
+			   struct saa7134_buf *buf,
+			   struct saa7134_buf *next)
+{
+	u32 control;
+
+	dprintk("buffer_activate [%p]",buf);
+	buf->vb.state = STATE_ACTIVE;
+	buf->top_seen = 0;
+
+        /* dma: setup channel 5 (= TS) */
+        control = SAA7134_RS_CONTROL_BURST_16 |
+                SAA7134_RS_CONTROL_ME |
+                (buf->pt->dma >> 12);
+
+	if (NULL == next)
+		next = buf;
+	if (V4L2_FIELD_TOP == buf->vb.field) {
+		dprintk("- [top]     buf=%p next=%p\n",buf,next);
+		saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(buf));
+		saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(next));
+	} else {
+		dprintk("- [bottom]  buf=%p next=%p\n",buf,next);
+		saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(next));
+		saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(buf));
+	}
+	saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE);
+	saa_writel(SAA7134_RS_CONTROL(5),control);
+
+	/* start DMA */
+	saa7134_set_dmabits(dev);
+
+	mod_timer(&dev->ts_q.timeout, jiffies+BUFFER_TIMEOUT);
+	return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+			  enum v4l2_field field)
+{
+	struct saa7134_dev *dev = q->priv_data;
+	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+	unsigned int lines, llength, size;
+	int err;
+
+	dprintk("buffer_prepare [%p,%s]\n",buf,v4l2_field_names[field]);
+
+	llength = TS_PACKET_SIZE;
+	lines = dev->ts.nr_packets;
+
+	size = lines * llength;
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+		return -EINVAL;
+
+	if (buf->vb.size != size) {
+		saa7134_dma_free(dev,buf);
+	}
+
+	if (STATE_NEEDS_INIT == buf->vb.state) {
+		buf->vb.width  = llength;
+		buf->vb.height = lines;
+		buf->vb.size   = size;
+		buf->pt        = &dev->ts.pt_ts;
+
+		err = videobuf_iolock(dev->pci,&buf->vb,NULL);
+		if (err)
+			goto oops;
+		err = saa7134_pgtable_build(dev->pci,buf->pt,
+					    buf->vb.dma.sglist,
+					    buf->vb.dma.sglen,
+					    saa7134_buffer_startpage(buf));
+		if (err)
+			goto oops;
+	}
+	buf->vb.state = STATE_PREPARED;
+	buf->activate = buffer_activate;
+	buf->vb.field = field;
+	return 0;
+
+ oops:
+	saa7134_dma_free(dev,buf);
+	return err;
+}
+
+static int
+buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+	struct saa7134_dev *dev = q->priv_data;
+
+	*size = TS_PACKET_SIZE * dev->ts.nr_packets;
+	if (0 == *count)
+		*count = dev->ts.nr_bufs;
+	*count = saa7134_buffer_count(*size,*count);
+	return 0;
+}
+
+static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct saa7134_dev *dev = q->priv_data;
+	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+
+	saa7134_buffer_queue(dev,&dev->ts_q,buf);
+}
+
+static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct saa7134_dev *dev = q->priv_data;
+	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+
+	saa7134_dma_free(dev,buf);
+}
+
+struct videobuf_queue_ops saa7134_ts_qops = {
+	.buf_setup    = buffer_setup,
+	.buf_prepare  = buffer_prepare,
+	.buf_queue    = buffer_queue,
+	.buf_release  = buffer_release,
+};
+EXPORT_SYMBOL_GPL(saa7134_ts_qops);
+
+/* ----------------------------------------------------------- */
+/* exported stuff                                              */
+
+static unsigned int tsbufs = 4;
+module_param(tsbufs, int, 0444);
+MODULE_PARM_DESC(tsbufs,"number of ts buffers, range 2-32");
+
+static unsigned int ts_nr_packets = 30;
+module_param(ts_nr_packets, int, 0444);
+MODULE_PARM_DESC(ts_nr_packets,"size of a ts buffers (in ts packets)");
+
+int saa7134_ts_init1(struct saa7134_dev *dev)
+{
+	/* sanitycheck insmod options */
+	if (tsbufs < 2)
+		tsbufs = 2;
+	if (tsbufs > VIDEO_MAX_FRAME)
+		tsbufs = VIDEO_MAX_FRAME;
+	if (ts_nr_packets < 4)
+		ts_nr_packets = 4;
+	if (ts_nr_packets > 312)
+		ts_nr_packets = 312;
+	dev->ts.nr_bufs    = tsbufs;
+	dev->ts.nr_packets = ts_nr_packets;
+
+	INIT_LIST_HEAD(&dev->ts_q.queue);
+	init_timer(&dev->ts_q.timeout);
+	dev->ts_q.timeout.function = saa7134_buffer_timeout;
+	dev->ts_q.timeout.data     = (unsigned long)(&dev->ts_q);
+	dev->ts_q.dev              = dev;
+	dev->ts_q.need_two         = 1;
+	saa7134_pgtable_alloc(dev->pci,&dev->ts.pt_ts);
+
+	/* init TS hw */
+	saa_writeb(SAA7134_TS_SERIAL1, 0x00);  /* deactivate TS softreset */
+	saa_writeb(SAA7134_TS_PARALLEL, 0xec); /* TSSOP high active, TSVAL high active, TSLOCK ignored */
+	saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1));
+	saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff));
+	saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff));
+	saa_writeb(SAA7134_TS_DMA2, ((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00)); /* TSNOPIT=0, TSCOLAP=0 */
+
+	return 0;
+}
+
+int saa7134_ts_fini(struct saa7134_dev *dev)
+{
+	saa7134_pgtable_free(dev->pci,&dev->ts.pt_ts);
+	return 0;
+}
+
+
+void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status)
+{
+	enum v4l2_field field;
+
+	spin_lock(&dev->slock);
+	if (dev->ts_q.curr) {
+		field = dev->ts_q.curr->vb.field;
+		if (field == V4L2_FIELD_TOP) {
+			if ((status & 0x100000) != 0x000000)
+				goto done;
+		} else {
+			if ((status & 0x100000) != 0x100000)
+				goto done;
+		}
+		saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE);
+	}
+	saa7134_buffer_next(dev,&dev->ts_q);
+
+ done:
+	spin_unlock(&dev->slock);
+}
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
new file mode 100644
index 0000000..ecac13c
--- /dev/null
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -0,0 +1,1031 @@
+/*
+ * $Id: saa7134-tvaudio.c,v 1.22 2005/01/07 13:11:19 kraxel Exp $
+ *
+ * device driver for philips saa7134 based TV cards
+ * tv audio decoder (fm stereo, nicam, ...)
+ *
+ * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/smp_lock.h>
+#include <asm/div64.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int audio_debug = 0;
+module_param(audio_debug, int, 0644);
+MODULE_PARM_DESC(audio_debug,"enable debug messages [tv audio]");
+
+static unsigned int audio_ddep = 0;
+module_param(audio_ddep, int, 0644);
+MODULE_PARM_DESC(audio_ddep,"audio ddep overwrite");
+
+static int audio_clock_override = UNSET;
+module_param(audio_clock_override, int, 0644);
+
+static int audio_clock_tweak = 0;
+module_param(audio_clock_tweak, int, 0644);
+MODULE_PARM_DESC(audio_clock_tweak, "Audio clock tick fine tuning for cards with audio crystal that's slightly off (range [-1024 .. 1024])");
+
+#define dprintk(fmt, arg...)	if (audio_debug) \
+	printk(KERN_DEBUG "%s/audio: " fmt, dev->name , ## arg)
+#define d2printk(fmt, arg...)	if (audio_debug > 1) \
+	printk(KERN_DEBUG "%s/audio: " fmt, dev->name, ## arg)
+
+#define print_regb(reg) printk("%s:   reg 0x%03x [%-16s]: 0x%02x\n", \
+		dev->name,(SAA7134_##reg),(#reg),saa_readb((SAA7134_##reg)))
+
+/* msecs */
+#define SCAN_INITIAL_DELAY     1000
+#define SCAN_SAMPLE_DELAY       200
+#define SCAN_SUBCARRIER_DELAY  2000
+
+/* ------------------------------------------------------------------ */
+/* saa7134 code                                                       */
+
+static struct mainscan {
+	char         *name;
+	v4l2_std_id  std;
+	int          carr;
+} mainscan[] = {
+	{
+		.name = "M",
+		.std  = V4L2_STD_NTSC | V4L2_STD_PAL_M,
+		.carr = 4500,
+	},{
+		.name = "BG",
+		.std  = V4L2_STD_PAL_BG,
+		.carr = 5500,
+	},{
+		.name = "I",
+		.std  = V4L2_STD_PAL_I,
+		.carr = 6000,
+	},{
+		.name = "DKL",
+		.std  = V4L2_STD_PAL_DK | V4L2_STD_SECAM,
+		.carr = 6500,
+	}
+};
+
+static struct saa7134_tvaudio tvaudio[] = {
+	{
+		.name          = "PAL-B/G FM-stereo",
+		.std           = V4L2_STD_PAL,
+		.mode          = TVAUDIO_FM_BG_STEREO,
+		.carr1         = 5500,
+		.carr2         = 5742,
+	},{
+		.name          = "PAL-D/K1 FM-stereo",
+		.std           = V4L2_STD_PAL,
+		.carr1         = 6500,
+		.carr2         = 6258,
+		.mode          = TVAUDIO_FM_BG_STEREO,
+	},{
+		.name          = "PAL-D/K2 FM-stereo",
+		.std           = V4L2_STD_PAL,
+		.carr1         = 6500,
+		.carr2         = 6742,
+		.mode          = TVAUDIO_FM_BG_STEREO,
+	},{
+		.name          = "PAL-D/K3 FM-stereo",
+		.std           = V4L2_STD_PAL,
+		.carr1         = 6500,
+		.carr2         = 5742,
+		.mode          = TVAUDIO_FM_BG_STEREO,
+	},{
+		.name          = "PAL-B/G NICAM",
+		.std           = V4L2_STD_PAL,
+		.carr1         = 5500,
+		.carr2         = 5850,
+		.mode          = TVAUDIO_NICAM_FM,
+	},{
+		.name          = "PAL-I NICAM",
+		.std           = V4L2_STD_PAL,
+		.carr1         = 6000,
+		.carr2         = 6552,
+		.mode          = TVAUDIO_NICAM_FM,
+	},{
+		.name          = "PAL-D/K NICAM",
+		.std           = V4L2_STD_PAL,
+		.carr1         = 6500,
+		.carr2         = 5850,
+		.mode          = TVAUDIO_NICAM_FM,
+	},{
+		.name          = "SECAM-L NICAM",
+		.std           = V4L2_STD_SECAM,
+		.carr1         = 6500,
+		.carr2         = 5850,
+		.mode          = TVAUDIO_NICAM_AM,
+	},{
+		.name          = "SECAM-D/K",
+		.std           = V4L2_STD_SECAM,
+		.carr1         = 6500,
+		.carr2         = -1,
+		.mode          = TVAUDIO_FM_MONO,
+	},{
+		.name          = "NTSC-M",
+		.std           = V4L2_STD_NTSC,
+		.carr1         = 4500,
+		.carr2         = -1,
+		.mode          = TVAUDIO_FM_MONO,
+	},{
+		.name          = "NTSC-A2 FM-stereo",
+		.std           = V4L2_STD_NTSC,
+		.carr1         = 4500,
+		.carr2         = 4724,
+		.mode          = TVAUDIO_FM_K_STEREO,
+	}
+};
+#define TVAUDIO (sizeof(tvaudio)/sizeof(struct saa7134_tvaudio))
+
+/* ------------------------------------------------------------------ */
+
+static void tvaudio_init(struct saa7134_dev *dev)
+{
+	int clock = saa7134_boards[dev->board].audio_clock;
+
+	if (UNSET != audio_clock_override)
+	        clock = audio_clock_override;
+
+	/* init all audio registers */
+	saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x00);
+	if (need_resched())
+		schedule();
+	else
+		udelay(10);
+
+	saa_writeb(SAA7134_AUDIO_CLOCK0,      clock        & 0xff);
+	saa_writeb(SAA7134_AUDIO_CLOCK1,     (clock >>  8) & 0xff);
+	saa_writeb(SAA7134_AUDIO_CLOCK2,     (clock >> 16) & 0xff);
+	saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x01);
+
+	saa_writeb(SAA7134_NICAM_ERROR_LOW,  0x14);
+	saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50);
+	saa_writeb(SAA7134_MONITOR_SELECT,   0xa0);
+	saa_writeb(SAA7134_FM_DEMATRIX,      0x80);
+}
+
+static u32 tvaudio_carr2reg(u32 carrier)
+{
+	u64 a = carrier;
+
+	a <<= 24;
+	do_div(a,12288);
+	return a;
+}
+
+static void tvaudio_setcarrier(struct saa7134_dev *dev,
+			       int primary, int secondary)
+{
+	if (-1 == secondary)
+		secondary = primary;
+	saa_writel(SAA7134_CARRIER1_FREQ0 >> 2, tvaudio_carr2reg(primary));
+	saa_writel(SAA7134_CARRIER2_FREQ0 >> 2, tvaudio_carr2reg(secondary));
+}
+
+static void mute_input_7134(struct saa7134_dev *dev)
+{
+	unsigned int mute;
+	struct saa7134_input *in;
+	int ausel=0, ics=0, ocs=0;
+	int mask;
+
+	/* look what is to do ... */
+	in   = dev->input;
+	mute = (dev->ctl_mute ||
+		(dev->automute  &&  (&card(dev).radio) != in));
+	if (PCI_DEVICE_ID_PHILIPS_SAA7130 == dev->pci->device &&
+	    card(dev).mute.name) {
+		/* 7130 - we'll mute using some unconnected audio input */
+		if (mute)
+			in = &card(dev).mute;
+	}
+	if (dev->hw_mute  == mute &&
+	    dev->hw_input == in) {
+		dprintk("mute/input: nothing to do [mute=%d,input=%s]\n",
+			mute,in->name);
+		return;
+	}
+
+	dprintk("ctl_mute=%d automute=%d input=%s  =>  mute=%d input=%s\n",
+		dev->ctl_mute,dev->automute,dev->input->name,mute,in->name);
+	dev->hw_mute  = mute;
+	dev->hw_input = in;
+
+	if (PCI_DEVICE_ID_PHILIPS_SAA7134 == dev->pci->device)
+		/* 7134 mute */
+		saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ? 0xbf : 0xbb);
+
+	/* switch internal audio mux */
+	switch (in->amux) {
+	case TV:         ausel=0xc0; ics=0x00; ocs=0x02; break;
+	case LINE1:      ausel=0x80; ics=0x00; ocs=0x00; break;
+	case LINE2:      ausel=0x80; ics=0x08; ocs=0x01; break;
+	case LINE2_LEFT: ausel=0x80; ics=0x08; ocs=0x05; break;
+	}
+	saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, ausel);
+	saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, ics);
+	saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, ocs);
+
+	/* switch gpio-connected external audio mux */
+	if (0 == card(dev).gpiomask)
+		return;
+	mask = card(dev).gpiomask;
+	saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   mask, mask);
+	saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio);
+	saa7134_track_gpio(dev,in->name);
+}
+
+static void tvaudio_setmode(struct saa7134_dev *dev,
+			    struct saa7134_tvaudio *audio,
+			    char *note)
+{
+	int acpf, tweak = 0;
+
+	if (dev->tvnorm->id == V4L2_STD_NTSC) {
+		acpf = 0x19066;
+	} else {
+		acpf = 0x1e000;
+	}
+	if (audio_clock_tweak > -1024 && audio_clock_tweak < 1024)
+		tweak = audio_clock_tweak;
+
+	if (note)
+		dprintk("tvaudio_setmode: %s %s [%d.%03d/%d.%03d MHz] acpf=%d%+d\n",
+			note,audio->name,
+			audio->carr1 / 1000, audio->carr1 % 1000,
+			audio->carr2 / 1000, audio->carr2 % 1000,
+			acpf, tweak);
+
+	acpf += tweak;
+	saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD0, (acpf & 0x0000ff) >> 0);
+	saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD1, (acpf & 0x00ff00) >> 8);
+	saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD2, (acpf & 0x030000) >> 16);
+	tvaudio_setcarrier(dev,audio->carr1,audio->carr2);
+
+	switch (audio->mode) {
+	case TVAUDIO_FM_MONO:
+	case TVAUDIO_FM_BG_STEREO:
+		saa_writeb(SAA7134_DEMODULATOR,               0x00);
+		saa_writeb(SAA7134_DCXO_IDENT_CTRL,           0x00);
+		saa_writeb(SAA7134_FM_DEEMPHASIS,             0x22);
+		saa_writeb(SAA7134_FM_DEMATRIX,               0x80);
+		saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT,  0xa0);
+		break;
+	case TVAUDIO_FM_K_STEREO:
+		saa_writeb(SAA7134_DEMODULATOR,               0x00);
+		saa_writeb(SAA7134_DCXO_IDENT_CTRL,           0x01);
+		saa_writeb(SAA7134_FM_DEEMPHASIS,             0x22);
+		saa_writeb(SAA7134_FM_DEMATRIX,               0x80);
+		saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT,  0xa0);
+		break;
+	case TVAUDIO_NICAM_FM:
+		saa_writeb(SAA7134_DEMODULATOR,               0x10);
+		saa_writeb(SAA7134_DCXO_IDENT_CTRL,           0x00);
+		saa_writeb(SAA7134_FM_DEEMPHASIS,             0x44);
+		saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT,  0xa1);
+		saa_writeb(SAA7134_NICAM_CONFIG,              0x00);
+		break;
+	case TVAUDIO_NICAM_AM:
+		saa_writeb(SAA7134_DEMODULATOR,               0x12);
+		saa_writeb(SAA7134_DCXO_IDENT_CTRL,           0x00);
+		saa_writeb(SAA7134_FM_DEEMPHASIS,             0x44);
+		saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT,  0xa1);
+		saa_writeb(SAA7134_NICAM_CONFIG,              0x00);
+		break;
+	case TVAUDIO_FM_SAT_STEREO:
+		/* not implemented (yet) */
+		break;
+	}
+}
+
+static int tvaudio_sleep(struct saa7134_dev *dev, int timeout)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	add_wait_queue(&dev->thread.wq, &wait);
+	if (dev->thread.scan1 == dev->thread.scan2 && !dev->thread.shutdown) {
+		if (timeout < 0) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+		} else {
+#if 0
+			/* hmm, that one doesn't return on wakeup ... */
+			msleep_interruptible(timeout);
+#else
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(msecs_to_jiffies(timeout));
+#endif
+		}
+	}
+	remove_wait_queue(&dev->thread.wq, &wait);
+	return dev->thread.scan1 != dev->thread.scan2;
+}
+
+static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan)
+{
+	__s32 left,right,value;
+
+	if (audio_debug > 1) {
+		int i;
+		dprintk("debug %d:",scan->carr);
+		for (i = -150; i <= 150; i += 30) {
+			tvaudio_setcarrier(dev,scan->carr+i,scan->carr+i);
+			saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+			if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
+				return -1;
+			value = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+			if (0 == i)
+				printk("  #  %6d  # ",value >> 16);
+			else
+				printk(" %6d",value >> 16);
+		}
+		printk("\n");
+	}
+
+	if (dev->tvnorm->id & scan->std) {
+		tvaudio_setcarrier(dev,scan->carr-90,scan->carr-90);
+		saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+		if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
+			return -1;
+		left = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+
+		tvaudio_setcarrier(dev,scan->carr+90,scan->carr+90);
+		saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+		if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
+			return -1;
+		right = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+
+		left >>= 16;
+		right >>= 16;
+		value = left > right ? left - right : right - left;
+		dprintk("scanning %d.%03d MHz [%4s] =>  dc is %5d [%d/%d]\n",
+			scan->carr / 1000, scan->carr % 1000,
+			scan->name, value, left, right);
+	} else {
+		value = 0;
+		dprintk("skipping %d.%03d MHz [%4s]\n",
+			scan->carr / 1000, scan->carr % 1000, scan->name);
+	}
+	return value;
+}
+
+#if 0
+static void sifdebug_dump_regs(struct saa7134_dev *dev)
+{
+	print_regb(AUDIO_STATUS);
+	print_regb(IDENT_SIF);
+	print_regb(LEVEL_READOUT1);
+	print_regb(LEVEL_READOUT2);
+	print_regb(DCXO_IDENT_CTRL);
+	print_regb(DEMODULATOR);
+	print_regb(AGC_GAIN_SELECT);
+	print_regb(MONITOR_SELECT);
+	print_regb(FM_DEEMPHASIS);
+	print_regb(FM_DEMATRIX);
+	print_regb(SIF_SAMPLE_FREQ);
+	print_regb(ANALOG_IO_SELECT);
+}
+#endif
+
+static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *audio)
+{
+	__u32 idp,nicam;
+	int retval = -1;
+
+	switch (audio->mode) {
+	case TVAUDIO_FM_MONO:
+		return V4L2_TUNER_SUB_MONO;
+	case TVAUDIO_FM_K_STEREO:
+	case TVAUDIO_FM_BG_STEREO:
+		idp = (saa_readb(SAA7134_IDENT_SIF) & 0xe0) >> 5;
+		dprintk("getstereo: fm/stereo: idp=0x%x\n",idp);
+		if (0x03 == (idp & 0x03))
+			retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+		else if (0x05 == (idp & 0x05))
+			retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+		else if (0x01 == (idp & 0x01))
+			retval = V4L2_TUNER_SUB_MONO;
+		break;
+	case TVAUDIO_FM_SAT_STEREO:
+		/* not implemented (yet) */
+		break;
+	case TVAUDIO_NICAM_FM:
+	case TVAUDIO_NICAM_AM:
+		nicam = saa_readb(SAA7134_NICAM_STATUS);
+		dprintk("getstereo: nicam=0x%x\n",nicam);
+		switch (nicam & 0x0b) {
+		case 0x09:
+			retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+			break;
+		case 0x0a:
+			retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+			break;
+		case 0x08:
+		default:
+			retval = V4L2_TUNER_SUB_MONO;
+			break;
+		}
+		break;
+	}
+	if (retval != -1)
+		dprintk("found audio subchannels:%s%s%s%s\n",
+			(retval & V4L2_TUNER_SUB_MONO)   ? " mono"   : "",
+			(retval & V4L2_TUNER_SUB_STEREO) ? " stereo" : "",
+			(retval & V4L2_TUNER_SUB_LANG1)  ? " lang1"  : "",
+			(retval & V4L2_TUNER_SUB_LANG2)  ? " lang2"  : "");
+	return retval;
+}
+
+static int tvaudio_setstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *audio,
+			     u32 mode)
+{
+	static char *name[] = {
+		[ V4L2_TUNER_MODE_MONO   ] = "mono",
+		[ V4L2_TUNER_MODE_STEREO ] = "stereo",
+		[ V4L2_TUNER_MODE_LANG1  ] = "lang1",
+		[ V4L2_TUNER_MODE_LANG2  ] = "lang2",
+	};
+	static u32 fm[] = {
+		[ V4L2_TUNER_MODE_MONO   ] = 0x00,  /* ch1  */
+		[ V4L2_TUNER_MODE_STEREO ] = 0x80,  /* auto */
+		[ V4L2_TUNER_MODE_LANG1  ] = 0x00,  /* ch1  */
+		[ V4L2_TUNER_MODE_LANG2  ] = 0x01,  /* ch2  */
+	};
+	u32 reg;
+
+	switch (audio->mode) {
+	case TVAUDIO_FM_MONO:
+		/* nothing to do ... */
+		break;
+	case TVAUDIO_FM_K_STEREO:
+	case TVAUDIO_FM_BG_STEREO:
+		dprintk("setstereo [fm] => %s\n",
+			name[ mode % ARRAY_SIZE(name) ]);
+		reg = fm[ mode % ARRAY_SIZE(fm) ];
+		saa_writeb(SAA7134_FM_DEMATRIX, reg);
+		break;
+	case TVAUDIO_FM_SAT_STEREO:
+	case TVAUDIO_NICAM_AM:
+	case TVAUDIO_NICAM_FM:
+		/* FIXME */
+		break;
+	}
+	return 0;
+}
+
+static int tvaudio_thread(void *data)
+{
+	struct saa7134_dev *dev = data;
+	int carr_vals[ARRAY_SIZE(mainscan)];
+	unsigned int i, audio, nscan;
+	int max1,max2,carrier,rx,mode,lastmode,default_carrier;
+
+	daemonize("%s", dev->name);
+	allow_signal(SIGTERM);
+	for (;;) {
+		tvaudio_sleep(dev,-1);
+		if (dev->thread.shutdown || signal_pending(current))
+			goto done;
+
+	restart:
+		dev->thread.scan1 = dev->thread.scan2;
+		dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1);
+		dev->tvaudio  = NULL;
+		tvaudio_init(dev);
+		if (dev->ctl_automute)
+			dev->automute = 1;
+		mute_input_7134(dev);
+
+		/* give the tuner some time */
+		if (tvaudio_sleep(dev,SCAN_INITIAL_DELAY))
+			goto restart;
+
+		max1 = 0;
+		max2 = 0;
+		nscan = 0;
+		carrier = 0;
+		default_carrier = 0;
+		for (i = 0; i < ARRAY_SIZE(mainscan); i++) {
+			if (!(dev->tvnorm->id & mainscan[i].std))
+				continue;
+			if (!default_carrier)
+				default_carrier = mainscan[i].carr;
+			nscan++;
+		}
+
+		if (1 == nscan) {
+			/* only one candidate -- skip scan ;) */
+			max1 = 12345;
+			carrier = default_carrier;
+		} else {
+			/* scan for the main carrier */
+			saa_writeb(SAA7134_MONITOR_SELECT,0x00);
+			tvaudio_setmode(dev,&tvaudio[0],NULL);
+			for (i = 0; i < ARRAY_SIZE(mainscan); i++) {
+				carr_vals[i] = tvaudio_checkcarrier(dev, mainscan+i);
+				if (dev->thread.scan1 != dev->thread.scan2)
+					goto restart;
+			}
+			for (max1 = 0, max2 = 0, i = 0; i < ARRAY_SIZE(mainscan); i++) {
+				if (max1 < carr_vals[i]) {
+					max2 = max1;
+					max1 = carr_vals[i];
+					carrier = mainscan[i].carr;
+				} else if (max2 < carr_vals[i]) {
+					max2 = carr_vals[i];
+				}
+			}
+		}
+
+		if (0 != carrier && max1 > 2000 && max1 > max2*3) {
+			/* found good carrier */
+			dprintk("found %s main sound carrier @ %d.%03d MHz [%d/%d]\n",
+				dev->tvnorm->name, carrier/1000, carrier%1000,
+				max1, max2);
+			dev->last_carrier = carrier;
+
+		} else if (0 != dev->last_carrier) {
+			/* no carrier -- try last detected one as fallback */
+			carrier = dev->last_carrier;
+			printk(KERN_WARNING "%s/audio: audio carrier scan failed, "
+			       "using %d.%03d MHz [last detected]\n",
+			       dev->name, carrier/1000, carrier%1000);
+
+		} else {
+			/* no carrier + no fallback -- use default */
+			carrier = default_carrier;
+			printk(KERN_WARNING "%s/audio: audio carrier scan failed, "
+			       "using %d.%03d MHz [default]\n",
+			       dev->name, carrier/1000, carrier%1000);
+		}
+		tvaudio_setcarrier(dev,carrier,carrier);
+		dev->automute = 0;
+		saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x00);
+		saa7134_tvaudio_setmute(dev);
+
+		/* find the exact tv audio norm */
+		for (audio = UNSET, i = 0; i < TVAUDIO; i++) {
+			if (dev->tvnorm->id != UNSET &&
+			    !(dev->tvnorm->id & tvaudio[i].std))
+				continue;
+			if (tvaudio[i].carr1 != carrier)
+				continue;
+
+			if (UNSET == audio)
+				audio = i;
+			tvaudio_setmode(dev,&tvaudio[i],"trying");
+			if (tvaudio_sleep(dev,SCAN_SUBCARRIER_DELAY))
+				goto restart;
+			if (-1 != tvaudio_getstereo(dev,&tvaudio[i])) {
+				audio = i;
+				break;
+			}
+		}
+		saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x30);
+		if (UNSET == audio)
+			continue;
+		tvaudio_setmode(dev,&tvaudio[audio],"using");
+		tvaudio_setstereo(dev,&tvaudio[audio],V4L2_TUNER_MODE_MONO);
+		dev->tvaudio = &tvaudio[audio];
+
+		lastmode = 42;
+		for (;;) {
+			if (tvaudio_sleep(dev,5000))
+				goto restart;
+			if (dev->thread.shutdown || signal_pending(current))
+				break;
+			if (UNSET == dev->thread.mode) {
+				rx = tvaudio_getstereo(dev,&tvaudio[i]);
+				mode = saa7134_tvaudio_rx2mode(rx);
+			} else {
+				mode = dev->thread.mode;
+			}
+			if (lastmode != mode) {
+				tvaudio_setstereo(dev,&tvaudio[audio],mode);
+				lastmode = mode;
+			}
+		}
+	}
+
+ done:
+	complete_and_exit(&dev->thread.exit, 0);
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* saa7133 / saa7135 code                                             */
+
+static char *stdres[0x20] = {
+	[0x00] = "no standard detected",
+	[0x01] = "B/G (in progress)",
+	[0x02] = "D/K (in progress)",
+	[0x03] = "M (in progress)",
+
+	[0x04] = "B/G A2",
+	[0x05] = "B/G NICAM",
+	[0x06] = "D/K A2 (1)",
+	[0x07] = "D/K A2 (2)",
+	[0x08] = "D/K A2 (3)",
+	[0x09] = "D/K NICAM",
+	[0x0a] = "L NICAM",
+	[0x0b] = "I NICAM",
+
+	[0x0c] = "M Korea",
+	[0x0d] = "M BTSC ",
+	[0x0e] = "M EIAJ",
+
+	[0x0f] = "FM radio / IF 10.7 / 50 deemp",
+	[0x10] = "FM radio / IF 10.7 / 75 deemp",
+	[0x11] = "FM radio / IF sel / 50 deemp",
+	[0x12] = "FM radio / IF sel / 75 deemp",
+
+	[0x13 ... 0x1e ] = "unknown",
+	[0x1f] = "??? [in progress]",
+};
+
+#define DSP_RETRY 32
+#define DSP_DELAY 16
+
+static inline int saa_dsp_wait_bit(struct saa7134_dev *dev, int bit)
+{
+	int state, count = DSP_RETRY;
+
+	state = saa_readb(SAA7135_DSP_RWSTATE);
+	if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) {
+		printk("%s: dsp access error\n",dev->name);
+		/* FIXME: send ack ... */
+		return -EIO;
+	}
+	while (0 == (state & bit)) {
+		if (unlikely(0 == count)) {
+			printk("%s: dsp access wait timeout [bit=%s]\n",
+			       dev->name,
+			       (bit & SAA7135_DSP_RWSTATE_WRR) ? "WRR" :
+			       (bit & SAA7135_DSP_RWSTATE_RDB) ? "RDB" :
+			       (bit & SAA7135_DSP_RWSTATE_IDA) ? "IDA" :
+			       "???");
+			return -EIO;
+		}
+		saa_wait(DSP_DELAY);
+		state = saa_readb(SAA7135_DSP_RWSTATE);
+		count--;
+	}
+	return 0;
+}
+
+#if 0
+static int saa_dsp_readl(struct saa7134_dev *dev, int reg, u32 *value)
+{
+	int err;
+
+	d2printk("dsp read reg 0x%x\n", reg<<2);
+	saa_readl(reg);
+	err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_RDB);
+	if (err < 0)
+		return err;
+	*value = saa_readl(reg);
+	d2printk("dsp read   => 0x%06x\n", *value & 0xffffff);
+	err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_IDA);
+	if (err < 0)
+		return err;
+	return 0;
+}
+#endif
+
+int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value)
+{
+	int err;
+
+	d2printk("dsp write reg 0x%x = 0x%06x\n",reg<<2,value);
+	err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR);
+	if (err < 0)
+		return err;
+	saa_writel(reg,value);
+	err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+static int getstereo_7133(struct saa7134_dev *dev)
+{
+	int retval = V4L2_TUNER_SUB_MONO;
+	u32 value;
+
+	value = saa_readl(0x528 >> 2);
+	if (value & 0x20)
+		retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+	if (value & 0x40)
+		retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+	return retval;
+}
+
+static int mute_input_7133(struct saa7134_dev *dev)
+{
+	u32 reg = 0;
+	int mask;
+
+	switch (dev->input->amux) {
+	case TV:
+		reg = 0x02;
+		break;
+	case LINE1:
+		reg = 0x00;
+		break;
+	case LINE2:
+	case LINE2_LEFT:
+		reg = 0x01;
+		break;
+	}
+	if (dev->ctl_mute)
+		reg = 0x07;
+	saa_writel(0x594 >> 2, reg);
+
+	/* switch gpio-connected external audio mux */
+        if (0 != card(dev).gpiomask) {
+        	mask = card(dev).gpiomask;
+        	saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   mask, mask);
+        	saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, dev->input->gpio);
+        	saa7134_track_gpio(dev,dev->input->name);
+	}
+	return 0;
+}
+
+static int tvaudio_thread_ddep(void *data)
+{
+	struct saa7134_dev *dev = data;
+	u32 value, norms, clock;
+
+	daemonize("%s", dev->name);
+	allow_signal(SIGTERM);
+
+	clock = saa7134_boards[dev->board].audio_clock;
+	if (UNSET != audio_clock_override)
+		clock = audio_clock_override;
+	saa_writel(0x598 >> 2, clock);
+
+	/* unmute */
+	saa_dsp_writel(dev, 0x474 >> 2, 0x00);
+	saa_dsp_writel(dev, 0x450 >> 2, 0x00);
+
+	for (;;) {
+		tvaudio_sleep(dev,-1);
+		if (dev->thread.shutdown || signal_pending(current))
+			goto done;
+
+	restart:
+		dev->thread.scan1 = dev->thread.scan2;
+		dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1);
+
+		if (audio_ddep >= 0x04 && audio_ddep <= 0x0e) {
+			/* insmod option override */
+			norms = (audio_ddep << 2) | 0x01;
+			dprintk("ddep override: %s\n",stdres[audio_ddep]);
+		} else if (&card(dev).radio == dev->input) {
+			dprintk("FM Radio\n");
+			norms = (0x0f << 2) | 0x01;
+		} else {
+			/* (let chip) scan for sound carrier */
+			norms = 0;
+			if (dev->tvnorm->id & V4L2_STD_PAL) {
+				dprintk("PAL scan\n");
+				norms |= 0x2c; /* B/G + D/K + I */
+			}
+			if (dev->tvnorm->id & V4L2_STD_NTSC) {
+				dprintk("NTSC scan\n");
+				norms |= 0x40; /* M */
+			}
+			if (dev->tvnorm->id & V4L2_STD_SECAM) {
+				dprintk("SECAM scan\n");
+				norms |= 0x18; /* L + D/K */
+			}
+			if (0 == norms)
+				norms = 0x7c; /* all */
+			dprintk("scanning:%s%s%s%s%s\n",
+				(norms & 0x04) ? " B/G"  : "",
+				(norms & 0x08) ? " D/K"  : "",
+				(norms & 0x10) ? " L/L'" : "",
+				(norms & 0x20) ? " I"    : "",
+				(norms & 0x40) ? " M"    : "");
+		}
+
+		/* kick automatic standard detection */
+		saa_dsp_writel(dev, 0x454 >> 2, 0);
+		saa_dsp_writel(dev, 0x454 >> 2, norms | 0x80);
+
+		/* setup crossbars */
+		saa_dsp_writel(dev, 0x464 >> 2, 0x000000);
+		saa_dsp_writel(dev, 0x470 >> 2, 0x101010);
+
+		if (tvaudio_sleep(dev,3000))
+			goto restart;
+		value = saa_readl(0x528 >> 2) & 0xffffff;
+
+		dprintk("tvaudio thread status: 0x%x [%s%s%s]\n",
+			value, stdres[value & 0x1f],
+			(value & 0x000020) ? ",stereo" : "",
+			(value & 0x000040) ? ",dual"   : "");
+		dprintk("detailed status: "
+			"%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n",
+			(value & 0x000080) ? " A2/EIAJ pilot tone "     : "",
+			(value & 0x000100) ? " A2/EIAJ dual "           : "",
+			(value & 0x000200) ? " A2/EIAJ stereo "         : "",
+			(value & 0x000400) ? " A2/EIAJ noise mute "     : "",
+
+			(value & 0x000800) ? " BTSC/FM radio pilot "    : "",
+			(value & 0x001000) ? " SAP carrier "            : "",
+			(value & 0x002000) ? " BTSC stereo noise mute " : "",
+			(value & 0x004000) ? " SAP noise mute "         : "",
+			(value & 0x008000) ? " VDSP "                   : "",
+
+			(value & 0x010000) ? " NICST "                  : "",
+			(value & 0x020000) ? " NICDU "                  : "",
+			(value & 0x040000) ? " NICAM muted "            : "",
+			(value & 0x080000) ? " NICAM reserve sound "    : "",
+
+			(value & 0x100000) ? " init done "              : "");
+	}
+
+ done:
+	complete_and_exit(&dev->thread.exit, 0);
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* common stuff + external entry points                               */
+
+static void saa7134_enable_i2s(struct saa7134_dev *dev)
+{
+	int i2s_format;
+
+	if (!card_is_empress(dev))
+		return;
+	i2s_format = (dev->input->amux == TV) ? 0x00 : 0x01;
+
+	/* enable I2S audio output for the mpeg encoder */
+	saa_writeb(SAA7134_I2S_OUTPUT_SELECT,  0x80);
+	saa_writeb(SAA7134_I2S_OUTPUT_FORMAT,  i2s_format);
+	saa_writeb(SAA7134_I2S_OUTPUT_LEVEL,   0x0F);
+	saa_writeb(SAA7134_I2S_AUDIO_OUTPUT,   0x01);
+}
+
+int saa7134_tvaudio_rx2mode(u32 rx)
+{
+	u32 mode;
+
+	mode = V4L2_TUNER_MODE_MONO;
+	if (rx & V4L2_TUNER_SUB_STEREO)
+		mode = V4L2_TUNER_MODE_STEREO;
+	else if (rx & V4L2_TUNER_SUB_LANG1)
+		mode = V4L2_TUNER_MODE_LANG1;
+	else if (rx & V4L2_TUNER_SUB_LANG2)
+		mode = V4L2_TUNER_MODE_LANG2;
+	return mode;
+}
+
+void saa7134_tvaudio_setmute(struct saa7134_dev *dev)
+{
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7130:
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		mute_input_7134(dev);
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		mute_input_7133(dev);
+		break;
+	}
+}
+
+void saa7134_tvaudio_setinput(struct saa7134_dev *dev,
+			      struct saa7134_input *in)
+{
+	dev->input = in;
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7130:
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		mute_input_7134(dev);
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		mute_input_7133(dev);
+		break;
+	}
+	saa7134_enable_i2s(dev);
+}
+
+void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level)
+{
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		saa_writeb(SAA7134_CHANNEL1_LEVEL,     level & 0x1f);
+		saa_writeb(SAA7134_CHANNEL2_LEVEL,     level & 0x1f);
+		saa_writeb(SAA7134_NICAM_LEVEL_ADJUST, level & 0x1f);
+		break;
+	}
+}
+
+int saa7134_tvaudio_getstereo(struct saa7134_dev *dev)
+{
+	int retval = V4L2_TUNER_SUB_MONO;
+
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		if (dev->tvaudio)
+			retval = tvaudio_getstereo(dev,dev->tvaudio);
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		retval = getstereo_7133(dev);
+		break;
+	}
+	return retval;
+}
+
+int saa7134_tvaudio_init2(struct saa7134_dev *dev)
+{
+	DECLARE_MUTEX_LOCKED(sem);
+	int (*my_thread)(void *data) = NULL;
+
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		my_thread = tvaudio_thread;
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		my_thread = tvaudio_thread_ddep;
+		break;
+	}
+
+	dev->thread.pid = -1;
+	if (my_thread) {
+		/* start tvaudio thread */
+		init_waitqueue_head(&dev->thread.wq);
+		init_completion(&dev->thread.exit);
+		dev->thread.pid = kernel_thread(my_thread,dev,0);
+		if (dev->thread.pid < 0)
+			printk(KERN_WARNING "%s: kernel_thread() failed\n",
+			       dev->name);
+		saa7134_tvaudio_do_scan(dev);
+	}
+
+	saa7134_enable_i2s(dev);
+	return 0;
+}
+
+int saa7134_tvaudio_fini(struct saa7134_dev *dev)
+{
+	/* shutdown tvaudio thread */
+	if (dev->thread.pid >= 0) {
+		dev->thread.shutdown = 1;
+		wake_up_interruptible(&dev->thread.wq);
+		wait_for_completion(&dev->thread.exit);
+	}
+	saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, 0x00); /* LINE1 */
+	return 0;
+}
+
+int saa7134_tvaudio_do_scan(struct saa7134_dev *dev)
+{
+	if (dev->thread.pid >= 0) {
+		dev->thread.mode = UNSET;
+		dev->thread.scan2++;
+		wake_up_interruptible(&dev->thread.wq);
+	} else {
+		dev->automute = 0;
+		saa7134_tvaudio_setmute(dev);
+	}
+	return 0;
+}
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c
new file mode 100644
index 0000000..86954cc
--- /dev/null
+++ b/drivers/media/video/saa7134/saa7134-vbi.c
@@ -0,0 +1,270 @@
+/*
+ * $Id: saa7134-vbi.c,v 1.6 2004/12/10 12:33:39 kraxel Exp $
+ *
+ * device driver for philips saa7134 based TV cards
+ * video4linux video interface
+ *
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int vbi_debug  = 0;
+module_param(vbi_debug, int, 0644);
+MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]");
+
+static unsigned int vbibufs = 4;
+module_param(vbibufs, int, 0444);
+MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32");
+
+#define dprintk(fmt, arg...)	if (vbi_debug) \
+	printk(KERN_DEBUG "%s/vbi: " fmt, dev->name , ## arg)
+
+/* ------------------------------------------------------------------ */
+
+#define VBI_LINE_COUNT     16
+#define VBI_LINE_LENGTH  2048
+#define VBI_SCALE       0x200
+
+static void task_init(struct saa7134_dev *dev, struct saa7134_buf *buf,
+		      int task)
+{
+	struct saa7134_tvnorm *norm = dev->tvnorm;
+
+	/* setup video scaler */
+	saa_writeb(SAA7134_VBI_H_START1(task), norm->h_start     &  0xff);
+	saa_writeb(SAA7134_VBI_H_START2(task), norm->h_start     >> 8);
+	saa_writeb(SAA7134_VBI_H_STOP1(task),  norm->h_stop      &  0xff);
+	saa_writeb(SAA7134_VBI_H_STOP2(task),  norm->h_stop      >> 8);
+	saa_writeb(SAA7134_VBI_V_START1(task), norm->vbi_v_start &  0xff);
+	saa_writeb(SAA7134_VBI_V_START2(task), norm->vbi_v_start >> 8);
+	saa_writeb(SAA7134_VBI_V_STOP1(task),  norm->vbi_v_stop  &  0xff);
+	saa_writeb(SAA7134_VBI_V_STOP2(task),  norm->vbi_v_stop  >> 8);
+
+	saa_writeb(SAA7134_VBI_H_SCALE_INC1(task),        VBI_SCALE & 0xff);
+	saa_writeb(SAA7134_VBI_H_SCALE_INC2(task),        VBI_SCALE >> 8);
+	saa_writeb(SAA7134_VBI_PHASE_OFFSET_LUMA(task),   0x00);
+	saa_writeb(SAA7134_VBI_PHASE_OFFSET_CHROMA(task), 0x00);
+
+	saa_writeb(SAA7134_VBI_H_LEN1(task), buf->vb.width   & 0xff);
+	saa_writeb(SAA7134_VBI_H_LEN2(task), buf->vb.width   >> 8);
+	saa_writeb(SAA7134_VBI_V_LEN1(task), buf->vb.height  & 0xff);
+	saa_writeb(SAA7134_VBI_V_LEN2(task), buf->vb.height  >> 8);
+
+	saa_andorb(SAA7134_DATA_PATH(task), 0xc0, 0x00);
+}
+
+/* ------------------------------------------------------------------ */
+
+static int buffer_activate(struct saa7134_dev *dev,
+			   struct saa7134_buf *buf,
+			   struct saa7134_buf *next)
+{
+	unsigned long control,base;
+
+	dprintk("buffer_activate [%p]\n",buf);
+	buf->vb.state = STATE_ACTIVE;
+	buf->top_seen = 0;
+
+	task_init(dev,buf,TASK_A);
+	task_init(dev,buf,TASK_B);
+	saa_writeb(SAA7134_OFMT_DATA_A, 0x06);
+	saa_writeb(SAA7134_OFMT_DATA_B, 0x06);
+
+	/* DMA: setup channel 2+3 (= VBI Task A+B) */
+	base    = saa7134_buffer_base(buf);
+	control = SAA7134_RS_CONTROL_BURST_16 |
+		SAA7134_RS_CONTROL_ME |
+		(buf->pt->dma >> 12);
+	saa_writel(SAA7134_RS_BA1(2),base);
+	saa_writel(SAA7134_RS_BA2(2),base + buf->vb.size/2);
+	saa_writel(SAA7134_RS_PITCH(2),buf->vb.width);
+	saa_writel(SAA7134_RS_CONTROL(2),control);
+	saa_writel(SAA7134_RS_BA1(3),base);
+	saa_writel(SAA7134_RS_BA2(3),base + buf->vb.size/2);
+	saa_writel(SAA7134_RS_PITCH(3),buf->vb.width);
+	saa_writel(SAA7134_RS_CONTROL(3),control);
+
+	/* start DMA */
+	saa7134_set_dmabits(dev);
+	mod_timer(&dev->vbi_q.timeout, jiffies+BUFFER_TIMEOUT);
+
+	return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *q,
+			  struct videobuf_buffer *vb,
+			  enum v4l2_field field)
+{
+	struct saa7134_fh *fh   = q->priv_data;
+	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+	struct saa7134_tvnorm *norm = dev->tvnorm;
+	unsigned int lines, llength, size;
+	int err;
+
+	lines   = norm->vbi_v_stop - norm->vbi_v_start +1;
+	if (lines > VBI_LINE_COUNT)
+		lines = VBI_LINE_COUNT;
+#if 1
+	llength = VBI_LINE_LENGTH;
+#else
+	llength = (norm->h_stop - norm->h_start +1) * 2;
+	if (llength > VBI_LINE_LENGTH)
+		llength = VBI_LINE_LENGTH;
+#endif
+	size = lines * llength * 2;
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+		return -EINVAL;
+
+	if (buf->vb.size != size)
+		saa7134_dma_free(dev,buf);
+
+	if (STATE_NEEDS_INIT == buf->vb.state) {
+		buf->vb.width  = llength;
+		buf->vb.height = lines;
+		buf->vb.size   = size;
+		buf->pt        = &fh->pt_vbi;
+
+		err = videobuf_iolock(dev->pci,&buf->vb,NULL);
+		if (err)
+			goto oops;
+		err = saa7134_pgtable_build(dev->pci,buf->pt,
+					    buf->vb.dma.sglist,
+					    buf->vb.dma.sglen,
+					    saa7134_buffer_startpage(buf));
+		if (err)
+			goto oops;
+	}
+	buf->vb.state = STATE_PREPARED;
+	buf->activate = buffer_activate;
+	buf->vb.field = field;
+	return 0;
+
+ oops:
+	saa7134_dma_free(dev,buf);
+	return err;
+}
+
+static int
+buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+	struct saa7134_fh *fh   = q->priv_data;
+	struct saa7134_dev *dev = fh->dev;
+	int llength,lines;
+
+	lines   = dev->tvnorm->vbi_v_stop - dev->tvnorm->vbi_v_start +1;
+#if 1
+	llength = VBI_LINE_LENGTH;
+#else
+	llength = (norm->h_stop - norm->h_start +1) * 2;
+	if (llength > VBI_LINE_LENGTH)
+		llength = VBI_LINE_LENGTH;
+#endif
+	*size = lines * llength * 2;
+	if (0 == *count)
+		*count = vbibufs;
+	*count = saa7134_buffer_count(*size,*count);
+	return 0;
+}
+
+static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct saa7134_fh *fh = q->priv_data;
+	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+
+	saa7134_buffer_queue(dev,&dev->vbi_q,buf);
+}
+
+static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct saa7134_fh *fh   = q->priv_data;
+	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+
+	saa7134_dma_free(dev,buf);
+}
+
+struct videobuf_queue_ops saa7134_vbi_qops = {
+	.buf_setup    = buffer_setup,
+	.buf_prepare  = buffer_prepare,
+	.buf_queue    = buffer_queue,
+	.buf_release  = buffer_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+int saa7134_vbi_init1(struct saa7134_dev *dev)
+{
+	INIT_LIST_HEAD(&dev->vbi_q.queue);
+	init_timer(&dev->vbi_q.timeout);
+	dev->vbi_q.timeout.function = saa7134_buffer_timeout;
+	dev->vbi_q.timeout.data     = (unsigned long)(&dev->vbi_q);
+	dev->vbi_q.dev              = dev;
+
+	if (vbibufs < 2)
+		vbibufs = 2;
+	if (vbibufs > VIDEO_MAX_FRAME)
+		vbibufs = VIDEO_MAX_FRAME;
+	return 0;
+}
+
+int saa7134_vbi_fini(struct saa7134_dev *dev)
+{
+	/* nothing */
+	return 0;
+}
+
+void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status)
+{
+	spin_lock(&dev->slock);
+	if (dev->vbi_q.curr) {
+		dev->vbi_fieldcount++;
+		/* make sure we have seen both fields */
+		if ((status & 0x10) == 0x00) {
+			dev->vbi_q.curr->top_seen = 1;
+			goto done;
+		}
+		if (!dev->vbi_q.curr->top_seen)
+			goto done;
+
+		dev->vbi_q.curr->vb.field_count = dev->vbi_fieldcount;
+		saa7134_buffer_finish(dev,&dev->vbi_q,STATE_DONE);
+	}
+	saa7134_buffer_next(dev,&dev->vbi_q);
+
+ done:
+	spin_unlock(&dev->slock);
+}
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
new file mode 100644
index 0000000..5d66060
--- /dev/null
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -0,0 +1,2406 @@
+/*
+ * $Id: saa7134-video.c,v 1.28 2005/02/15 15:59:35 kraxel Exp $
+ *
+ * device driver for philips saa7134 based TV cards
+ * video4linux video interface
+ *
+ * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+#define V4L2_I2C_CLIENTS 1
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int video_debug   = 0;
+static unsigned int gbuffers      = 8;
+static unsigned int noninterlaced = 0;
+static unsigned int gbufsize      = 720*576*4;
+static unsigned int gbufsize_max  = 720*576*4;
+module_param(video_debug, int, 0644);
+MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
+module_param(gbuffers, int, 0444);
+MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32");
+module_param(noninterlaced, int, 0644);
+MODULE_PARM_DESC(noninterlaced,"video input is noninterlaced");
+
+#define dprintk(fmt, arg...)	if (video_debug) \
+	printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg)
+
+/* ------------------------------------------------------------------ */
+/* data structs for video                                             */
+
+static int video_out[][9] = {
+	[CCIR656] = { 0x00, 0xb1, 0x00, 0xa1, 0x00, 0x04, 0x06, 0x00, 0x00 },
+};
+
+static struct saa7134_format formats[] = {
+	{
+		.name     = "8 bpp gray",
+		.fourcc   = V4L2_PIX_FMT_GREY,
+		.depth    = 8,
+		.pm       = 0x06,
+	},{
+		.name     = "15 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_RGB555,
+		.depth    = 16,
+		.pm       = 0x13 | 0x80,
+	},{
+		.name     = "15 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB555X,
+		.depth    = 16,
+		.pm       = 0x13 | 0x80,
+		.bswap    = 1,
+	},{
+		.name     = "16 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_RGB565,
+		.depth    = 16,
+		.pm       = 0x10 | 0x80,
+	},{
+		.name     = "16 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB565X,
+		.depth    = 16,
+		.pm       = 0x10 | 0x80,
+		.bswap    = 1,
+	},{
+		.name     = "24 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_BGR24,
+		.depth    = 24,
+		.pm       = 0x11,
+	},{
+		.name     = "24 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB24,
+		.depth    = 24,
+		.pm       = 0x11,
+		.bswap    = 1,
+	},{
+		.name     = "32 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_BGR32,
+		.depth    = 32,
+		.pm       = 0x12,
+	},{
+		.name     = "32 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB32,
+		.depth    = 32,
+		.pm       = 0x12,
+		.bswap    = 1,
+		.wswap    = 1,
+	},{
+		.name     = "4:2:2 packed, YUYV",
+		.fourcc   = V4L2_PIX_FMT_YUYV,
+		.depth    = 16,
+		.pm       = 0x00,
+		.bswap    = 1,
+		.yuv      = 1,
+	},{
+		.name     = "4:2:2 packed, UYVY",
+		.fourcc   = V4L2_PIX_FMT_UYVY,
+		.depth    = 16,
+		.pm       = 0x00,
+		.yuv      = 1,
+	},{
+		.name     = "4:2:2 planar, Y-Cb-Cr",
+		.fourcc   = V4L2_PIX_FMT_YUV422P,
+		.depth    = 16,
+		.pm       = 0x09,
+		.yuv      = 1,
+		.planar   = 1,
+		.hshift   = 1,
+		.vshift   = 0,
+	},{
+		.name     = "4:2:0 planar, Y-Cb-Cr",
+		.fourcc   = V4L2_PIX_FMT_YUV420,
+		.depth    = 12,
+		.pm       = 0x0a,
+		.yuv      = 1,
+		.planar   = 1,
+		.hshift   = 1,
+		.vshift   = 1,
+	},{
+		.name     = "4:2:0 planar, Y-Cb-Cr",
+		.fourcc   = V4L2_PIX_FMT_YVU420,
+		.depth    = 12,
+		.pm       = 0x0a,
+		.yuv      = 1,
+		.planar   = 1,
+		.uvswap   = 1,
+		.hshift   = 1,
+		.vshift   = 1,
+	}
+};
+#define FORMATS ARRAY_SIZE(formats)
+
+#define NORM_625_50			\
+		.h_start       = 0,	\
+		.h_stop        = 719,	\
+		.video_v_start = 24,	\
+		.video_v_stop  = 311,	\
+		.vbi_v_start   = 7,	\
+		.vbi_v_stop    = 22,	\
+		.src_timing    = 4
+
+#define NORM_525_60			\
+		.h_start       = 0,	\
+		.h_stop        = 703,	\
+		.video_v_start = 22,	\
+		.video_v_stop  = 22+239, \
+		.vbi_v_start   = 10, /* FIXME */ \
+		.vbi_v_stop    = 21, /* FIXME */ \
+		.src_timing    = 1
+
+static struct saa7134_tvnorm tvnorms[] = {
+	{
+		.name          = "PAL", /* autodetect */
+		.id            = V4L2_STD_PAL,
+		NORM_625_50,
+
+		.sync_control  = 0x18,
+		.luma_control  = 0x40,
+		.chroma_ctrl1  = 0x81,
+		.chroma_gain   = 0x2a,
+		.chroma_ctrl2  = 0x06,
+		.vgate_misc    = 0x1c,
+
+	},{
+		.name          = "PAL-BG",
+		.id            = V4L2_STD_PAL_BG,
+		NORM_625_50,
+
+		.sync_control  = 0x18,
+		.luma_control  = 0x40,
+		.chroma_ctrl1  = 0x81,
+		.chroma_gain   = 0x2a,
+		.chroma_ctrl2  = 0x06,
+		.vgate_misc    = 0x1c,
+
+	},{
+		.name          = "PAL-I",
+		.id            = V4L2_STD_PAL_I,
+		NORM_625_50,
+
+		.sync_control  = 0x18,
+		.luma_control  = 0x40,
+		.chroma_ctrl1  = 0x81,
+		.chroma_gain   = 0x2a,
+		.chroma_ctrl2  = 0x06,
+		.vgate_misc    = 0x1c,
+
+	},{
+		.name          = "PAL-DK",
+		.id            = V4L2_STD_PAL_DK,
+		NORM_625_50,
+
+		.sync_control  = 0x18,
+		.luma_control  = 0x40,
+		.chroma_ctrl1  = 0x81,
+		.chroma_gain   = 0x2a,
+		.chroma_ctrl2  = 0x06,
+		.vgate_misc    = 0x1c,
+
+	},{
+		.name          = "NTSC",
+		.id            = V4L2_STD_NTSC,
+		NORM_525_60,
+
+		.sync_control  = 0x59,
+		.luma_control  = 0x40,
+		.chroma_ctrl1  = 0x89,
+		.chroma_gain   = 0x2a,
+		.chroma_ctrl2  = 0x0e,
+		.vgate_misc    = 0x18,
+
+	},{
+		.name          = "SECAM",
+		.id            = V4L2_STD_SECAM,
+		NORM_625_50,
+
+		.sync_control  = 0x18, /* old: 0x58, */
+		.luma_control  = 0x1b,
+		.chroma_ctrl1  = 0xd1,
+		.chroma_gain   = 0x80,
+		.chroma_ctrl2  = 0x00,
+		.vgate_misc    = 0x1c,
+
+	},{
+		.name          = "PAL-M",
+		.id            = V4L2_STD_PAL_M,
+		NORM_525_60,
+
+		.sync_control  = 0x59,
+		.luma_control  = 0x40,
+		.chroma_ctrl1  = 0xb9,
+		.chroma_gain   = 0x2a,
+		.chroma_ctrl2  = 0x0e,
+		.vgate_misc    = 0x18,
+
+	},{
+		.name          = "PAL-Nc",
+		.id            = V4L2_STD_PAL_Nc,
+		NORM_625_50,
+
+		.sync_control  = 0x18,
+		.luma_control  = 0x40,
+		.chroma_ctrl1  = 0xa1,
+		.chroma_gain   = 0x2a,
+		.chroma_ctrl2  = 0x06,
+		.vgate_misc    = 0x1c,
+
+	},{
+		.name          = "PAL-60",
+		.id            = V4L2_STD_PAL_60,
+
+		.h_start       = 0,
+		.h_stop        = 719,
+		.video_v_start = 22,
+		.video_v_stop  = 22+239,
+		.vbi_v_start   = 10, /* FIXME */
+		.vbi_v_stop    = 21, /* FIXME */
+		.src_timing    = 1,
+
+		.sync_control  = 0x18,
+		.luma_control  = 0x40,
+		.chroma_ctrl1  = 0x81,
+		.chroma_gain   = 0x2a,
+		.chroma_ctrl2  = 0x06,
+		.vgate_misc    = 0x1c,
+	}
+};
+#define TVNORMS ARRAY_SIZE(tvnorms)
+
+#define V4L2_CID_PRIVATE_INVERT      (V4L2_CID_PRIVATE_BASE + 0)
+#define V4L2_CID_PRIVATE_Y_ODD       (V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_PRIVATE_Y_EVEN      (V4L2_CID_PRIVATE_BASE + 2)
+#define V4L2_CID_PRIVATE_AUTOMUTE    (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_PRIVATE_LASTP1      (V4L2_CID_PRIVATE_BASE + 4)
+
+static const struct v4l2_queryctrl no_ctrl = {
+	.name  = "42",
+	.flags = V4L2_CTRL_FLAG_DISABLED,
+};
+static const struct v4l2_queryctrl video_ctrls[] = {
+	/* --- video --- */
+	{
+		.id            = V4L2_CID_BRIGHTNESS,
+		.name          = "Brightness",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = 128,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_CONTRAST,
+		.name          = "Contrast",
+		.minimum       = 0,
+		.maximum       = 127,
+		.step          = 1,
+		.default_value = 68,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_SATURATION,
+		.name          = "Saturation",
+		.minimum       = 0,
+		.maximum       = 127,
+		.step          = 1,
+		.default_value = 64,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_HUE,
+		.name          = "Hue",
+		.minimum       = -128,
+		.maximum       = 127,
+		.step          = 1,
+		.default_value = 0,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_VFLIP,
+		.name          = "vertical flip",
+		.minimum       = 0,
+		.maximum       = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},
+	/* --- audio --- */
+	{
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_AUDIO_VOLUME,
+		.name          = "Volume",
+		.minimum       = -15,
+		.maximum       = 15,
+		.step          = 1,
+		.default_value = 0,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},
+	/* --- private --- */
+	{
+		.id            = V4L2_CID_PRIVATE_INVERT,
+		.name          = "Invert",
+		.minimum       = 0,
+		.maximum       = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_PRIVATE_Y_ODD,
+		.name          = "y offset odd field",
+		.minimum       = 0,
+		.maximum       = 128,
+		.default_value = 0,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_PRIVATE_Y_EVEN,
+		.name          = "y offset even field",
+		.minimum       = 0,
+		.maximum       = 128,
+		.default_value = 0,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_PRIVATE_AUTOMUTE,
+		.name          = "automute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	}
+};
+static const unsigned int CTRLS = ARRAY_SIZE(video_ctrls);
+
+static const struct v4l2_queryctrl* ctrl_by_id(unsigned int id)
+{
+	unsigned int i;
+
+	for (i = 0; i < CTRLS; i++)
+		if (video_ctrls[i].id == id)
+			return video_ctrls+i;
+	return NULL;
+}
+
+static struct saa7134_format* format_by_fourcc(unsigned int fourcc)
+{
+	unsigned int i;
+
+	for (i = 0; i < FORMATS; i++)
+		if (formats[i].fourcc == fourcc)
+			return formats+i;
+	return NULL;
+}
+
+/* ----------------------------------------------------------------------- */
+/* resource management                                                     */
+
+static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bit)
+{
+	if (fh->resources & bit)
+		/* have it already allocated */
+		return 1;
+
+	/* is it free? */
+	down(&dev->lock);
+	if (dev->resources & bit) {
+		/* no, someone else uses it */
+		up(&dev->lock);
+		return 0;
+	}
+	/* it's free, grab it */
+	fh->resources  |= bit;
+	dev->resources |= bit;
+	dprintk("res: get %d\n",bit);
+	up(&dev->lock);
+	return 1;
+}
+
+static
+int res_check(struct saa7134_fh *fh, unsigned int bit)
+{
+	return (fh->resources & bit);
+}
+
+static
+int res_locked(struct saa7134_dev *dev, unsigned int bit)
+{
+	return (dev->resources & bit);
+}
+
+static
+void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits)
+{
+	if ((fh->resources & bits) != bits)
+		BUG();
+
+	down(&dev->lock);
+	fh->resources  &= ~bits;
+	dev->resources &= ~bits;
+	dprintk("res: put %d\n",bits);
+	up(&dev->lock);
+}
+
+/* ------------------------------------------------------------------ */
+
+static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
+{
+	int luma_control,sync_control,mux;
+
+	dprintk("set tv norm = %s\n",norm->name);
+	dev->tvnorm = norm;
+
+	mux = card_in(dev,dev->ctl_input).vmux;
+	luma_control = norm->luma_control;
+	sync_control = norm->sync_control;
+
+	if (mux > 5)
+		luma_control |= 0x80; /* svideo */
+	if (noninterlaced || dev->nosignal)
+		sync_control |= 0x20;
+
+	/* setup cropping */
+	dev->crop_bounds.left    = norm->h_start;
+	dev->crop_defrect.left   = norm->h_start;
+	dev->crop_bounds.width   = norm->h_stop - norm->h_start +1;
+	dev->crop_defrect.width  = norm->h_stop - norm->h_start +1;
+
+	dev->crop_bounds.top     = (norm->vbi_v_stop+1)*2;
+	dev->crop_defrect.top    = norm->video_v_start*2;
+	dev->crop_bounds.height  = ((norm->id & V4L2_STD_525_60) ? 524 : 624)
+		- dev->crop_bounds.top;
+	dev->crop_defrect.height = (norm->video_v_stop - norm->video_v_start +1)*2;
+
+	dev->crop_current = dev->crop_defrect;
+
+	/* setup video decoder */
+	saa_writeb(SAA7134_INCR_DELAY,            0x08);
+	saa_writeb(SAA7134_ANALOG_IN_CTRL1,       0xc0 | mux);
+	saa_writeb(SAA7134_ANALOG_IN_CTRL2,       0x00);
+
+	saa_writeb(SAA7134_ANALOG_IN_CTRL3,       0x90);
+	saa_writeb(SAA7134_ANALOG_IN_CTRL4,       0x90);
+	saa_writeb(SAA7134_HSYNC_START,           0xeb);
+	saa_writeb(SAA7134_HSYNC_STOP,            0xe0);
+	saa_writeb(SAA7134_SOURCE_TIMING1,        norm->src_timing);
+
+	saa_writeb(SAA7134_SYNC_CTRL,             sync_control);
+	saa_writeb(SAA7134_LUMA_CTRL,             luma_control);
+	saa_writeb(SAA7134_DEC_LUMA_BRIGHT,       dev->ctl_bright);
+	saa_writeb(SAA7134_DEC_LUMA_CONTRAST,     dev->ctl_contrast);
+
+	saa_writeb(SAA7134_DEC_CHROMA_SATURATION, dev->ctl_saturation);
+	saa_writeb(SAA7134_DEC_CHROMA_HUE,        dev->ctl_hue);
+	saa_writeb(SAA7134_CHROMA_CTRL1,          norm->chroma_ctrl1);
+	saa_writeb(SAA7134_CHROMA_GAIN,           norm->chroma_gain);
+
+	saa_writeb(SAA7134_CHROMA_CTRL2,          norm->chroma_ctrl2);
+	saa_writeb(SAA7134_MODE_DELAY_CTRL,       0x00);
+
+	saa_writeb(SAA7134_ANALOG_ADC,            0x01);
+	saa_writeb(SAA7134_VGATE_START,           0x11);
+	saa_writeb(SAA7134_VGATE_STOP,            0xfe);
+	saa_writeb(SAA7134_MISC_VGATE_MSB,        norm->vgate_misc);
+	saa_writeb(SAA7134_RAW_DATA_GAIN,         0x40);
+	saa_writeb(SAA7134_RAW_DATA_OFFSET,       0x80);
+
+#ifdef V4L2_I2C_CLIENTS
+	saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id);
+#else
+	{
+		/* pass down info to the i2c chips (v4l1) */
+		struct video_channel c;
+		memset(&c,0,sizeof(c));
+		c.channel = dev->ctl_input;
+		c.norm = VIDEO_MODE_PAL;
+		if (norm->id & V4L2_STD_NTSC)
+			c.norm = VIDEO_MODE_NTSC;
+		if (norm->id & V4L2_STD_SECAM)
+			c.norm = VIDEO_MODE_SECAM;
+		saa7134_i2c_call_clients(dev,VIDIOCSCHAN,&c);
+	}
+#endif
+}
+
+static void video_mux(struct saa7134_dev *dev, int input)
+{
+	dprintk("video input = %d [%s]\n",input,card_in(dev,input).name);
+	dev->ctl_input = input;
+	set_tvnorm(dev,dev->tvnorm);
+	saa7134_tvaudio_setinput(dev,&card_in(dev,input));
+}
+
+static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale)
+{
+	static const struct {
+		int xpsc;
+		int xacl;
+		int xc2_1;
+		int xdcg;
+		int vpfy;
+	} vals[] = {
+		/* XPSC XACL XC2_1 XDCG VPFY */
+		{    1,   0,    0,    0,   0 },
+		{    2,   2,    1,    2,   2 },
+		{    3,   4,    1,    3,   2 },
+		{    4,   8,    1,    4,   2 },
+		{    5,   8,    1,    4,   2 },
+		{    6,   8,    1,    4,   3 },
+		{    7,   8,    1,    4,   3 },
+		{    8,  15,    0,    4,   3 },
+		{    9,  15,    0,    4,   3 },
+		{   10,  16,    1,    5,   3 },
+	};
+	static const int count = ARRAY_SIZE(vals);
+	int i;
+
+	for (i = 0; i < count; i++)
+		if (vals[i].xpsc == prescale)
+			break;
+	if (i == count)
+		return;
+
+	saa_writeb(SAA7134_H_PRESCALE(task), vals[i].xpsc);
+	saa_writeb(SAA7134_ACC_LENGTH(task), vals[i].xacl);
+	saa_writeb(SAA7134_LEVEL_CTRL(task),
+		   (vals[i].xc2_1 << 3) | (vals[i].xdcg));
+	saa_andorb(SAA7134_FIR_PREFILTER_CTRL(task), 0x0f,
+		   (vals[i].vpfy << 2) | vals[i].vpfy);
+}
+
+static void set_v_scale(struct saa7134_dev *dev, int task, int yscale)
+{
+	int val,mirror;
+
+	saa_writeb(SAA7134_V_SCALE_RATIO1(task), yscale &  0xff);
+	saa_writeb(SAA7134_V_SCALE_RATIO2(task), yscale >> 8);
+
+	mirror = (dev->ctl_mirror) ? 0x02 : 0x00;
+	if (yscale < 2048) {
+		/* LPI */
+		dprintk("yscale LPI yscale=%d\n",yscale);
+		saa_writeb(SAA7134_V_FILTER(task), 0x00 | mirror);
+		saa_writeb(SAA7134_LUMA_CONTRAST(task), 0x40);
+		saa_writeb(SAA7134_CHROMA_SATURATION(task), 0x40);
+	} else {
+		/* ACM */
+		val = 0x40 * 1024 / yscale;
+		dprintk("yscale ACM yscale=%d val=0x%x\n",yscale,val);
+		saa_writeb(SAA7134_V_FILTER(task), 0x01 | mirror);
+		saa_writeb(SAA7134_LUMA_CONTRAST(task), val);
+		saa_writeb(SAA7134_CHROMA_SATURATION(task), val);
+	}
+	saa_writeb(SAA7134_LUMA_BRIGHT(task),       0x80);
+}
+
+static void set_size(struct saa7134_dev *dev, int task,
+		     int width, int height, int interlace)
+{
+	int prescale,xscale,yscale,y_even,y_odd;
+	int h_start, h_stop, v_start, v_stop;
+	int div = interlace ? 2 : 1;
+
+	/* setup video scaler */
+	h_start = dev->crop_current.left;
+	v_start = dev->crop_current.top/2;
+	h_stop  = (dev->crop_current.left + dev->crop_current.width -1);
+	v_stop  = (dev->crop_current.top + dev->crop_current.height -1)/2;
+
+	saa_writeb(SAA7134_VIDEO_H_START1(task), h_start &  0xff);
+	saa_writeb(SAA7134_VIDEO_H_START2(task), h_start >> 8);
+	saa_writeb(SAA7134_VIDEO_H_STOP1(task),  h_stop  &  0xff);
+	saa_writeb(SAA7134_VIDEO_H_STOP2(task),  h_stop  >> 8);
+	saa_writeb(SAA7134_VIDEO_V_START1(task), v_start &  0xff);
+	saa_writeb(SAA7134_VIDEO_V_START2(task), v_start >> 8);
+	saa_writeb(SAA7134_VIDEO_V_STOP1(task),  v_stop  &  0xff);
+	saa_writeb(SAA7134_VIDEO_V_STOP2(task),  v_stop  >> 8);
+
+	prescale = dev->crop_current.width / width;
+	if (0 == prescale)
+		prescale = 1;
+	xscale = 1024 * dev->crop_current.width / prescale / width;
+	yscale = 512 * div * dev->crop_current.height / height;
+       	dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale);
+	set_h_prescale(dev,task,prescale);
+	saa_writeb(SAA7134_H_SCALE_INC1(task),      xscale &  0xff);
+	saa_writeb(SAA7134_H_SCALE_INC2(task),      xscale >> 8);
+	set_v_scale(dev,task,yscale);
+
+	saa_writeb(SAA7134_VIDEO_PIXELS1(task),     width  & 0xff);
+	saa_writeb(SAA7134_VIDEO_PIXELS2(task),     width  >> 8);
+	saa_writeb(SAA7134_VIDEO_LINES1(task),      height/div & 0xff);
+	saa_writeb(SAA7134_VIDEO_LINES2(task),      height/div >> 8);
+
+	/* deinterlace y offsets */
+	y_odd  = dev->ctl_y_odd;
+	y_even = dev->ctl_y_even;
+	saa_writeb(SAA7134_V_PHASE_OFFSET0(task), y_odd);
+	saa_writeb(SAA7134_V_PHASE_OFFSET1(task), y_even);
+	saa_writeb(SAA7134_V_PHASE_OFFSET2(task), y_odd);
+	saa_writeb(SAA7134_V_PHASE_OFFSET3(task), y_even);
+}
+
+/* ------------------------------------------------------------------ */
+
+struct cliplist {
+	__u16 position;
+	__u8  enable;
+	__u8  disable;
+};
+
+static void sort_cliplist(struct cliplist *cl, int entries)
+{
+	struct cliplist swap;
+	int i,j,n;
+
+	for (i = entries-2; i >= 0; i--) {
+		for (n = 0, j = 0; j <= i; j++) {
+			if (cl[j].position > cl[j+1].position) {
+				swap = cl[j];
+				cl[j] = cl[j+1];
+				cl[j+1] = swap;
+				n++;
+			}
+		}
+		if (0 == n)
+			break;
+	}
+}
+
+static void set_cliplist(struct saa7134_dev *dev, int reg,
+			struct cliplist *cl, int entries, char *name)
+{
+	__u8 winbits = 0;
+	int i;
+
+	for (i = 0; i < entries; i++) {
+		winbits |= cl[i].enable;
+		winbits &= ~cl[i].disable;
+		if (i < 15 && cl[i].position == cl[i+1].position)
+			continue;
+		saa_writeb(reg + 0, winbits);
+		saa_writeb(reg + 2, cl[i].position & 0xff);
+		saa_writeb(reg + 3, cl[i].position >> 8);
+		dprintk("clip: %s winbits=%02x pos=%d\n",
+			name,winbits,cl[i].position);
+		reg += 8;
+	}
+	for (; reg < 0x400; reg += 8) {
+		saa_writeb(reg+ 0, 0);
+		saa_writeb(reg + 1, 0);
+		saa_writeb(reg + 2, 0);
+		saa_writeb(reg + 3, 0);
+	}
+}
+
+static int clip_range(int val)
+{
+	if (val < 0)
+		val = 0;
+	return val;
+}
+
+static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips,
+			  int nclips, int interlace)
+{
+	struct cliplist col[16], row[16];
+	int cols, rows, i;
+	int div = interlace ? 2 : 1;
+
+	memset(col,0,sizeof(col)); cols = 0;
+	memset(row,0,sizeof(row)); rows = 0;
+	for (i = 0; i < nclips && i < 8; i++) {
+		col[cols].position = clip_range(clips[i].c.left);
+		col[cols].enable   = (1 << i);
+		cols++;
+		col[cols].position = clip_range(clips[i].c.left+clips[i].c.width);
+		col[cols].disable  = (1 << i);
+		cols++;
+		row[rows].position = clip_range(clips[i].c.top / div);
+		row[rows].enable   = (1 << i);
+		rows++;
+		row[rows].position = clip_range((clips[i].c.top + clips[i].c.height)
+						/ div);
+		row[rows].disable  = (1 << i);
+		rows++;
+	}
+	sort_cliplist(col,cols);
+	sort_cliplist(row,rows);
+	set_cliplist(dev,0x380,col,cols,"cols");
+	set_cliplist(dev,0x384,row,rows,"rows");
+	return 0;
+}
+
+static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win)
+{
+	enum v4l2_field field;
+	int maxw, maxh;
+
+	if (NULL == dev->ovbuf.base)
+		return -EINVAL;
+	if (NULL == dev->ovfmt)
+		return -EINVAL;
+	if (win->w.width < 48 || win->w.height <  32)
+		return -EINVAL;
+	if (win->clipcount > 2048)
+		return -EINVAL;
+
+	field = win->field;
+	maxw  = dev->crop_current.width;
+	maxh  = dev->crop_current.height;
+
+	if (V4L2_FIELD_ANY == field) {
+                field = (win->w.height > maxh/2)
+                        ? V4L2_FIELD_INTERLACED
+                        : V4L2_FIELD_TOP;
+        }
+        switch (field) {
+        case V4L2_FIELD_TOP:
+        case V4L2_FIELD_BOTTOM:
+                maxh = maxh / 2;
+                break;
+        case V4L2_FIELD_INTERLACED:
+                break;
+        default:
+                return -EINVAL;
+        }
+
+	win->field = field;
+	if (win->w.width > maxw)
+		win->w.width = maxw;
+	if (win->w.height > maxh)
+		win->w.height = maxh;
+	return 0;
+}
+
+static int start_preview(struct saa7134_dev *dev, struct saa7134_fh *fh)
+{
+	unsigned long base,control,bpl;
+	int err;
+
+	err = verify_preview(dev,&fh->win);
+	if (0 != err)
+		return err;
+
+	dev->ovfield = fh->win.field;
+	dprintk("start_preview %dx%d+%d+%d %s field=%s\n",
+		fh->win.w.width,fh->win.w.height,
+		fh->win.w.left,fh->win.w.top,
+		dev->ovfmt->name,v4l2_field_names[dev->ovfield]);
+
+	/* setup window + clipping */
+	set_size(dev,TASK_B,fh->win.w.width,fh->win.w.height,
+		 V4L2_FIELD_HAS_BOTH(dev->ovfield));
+	setup_clipping(dev,fh->clips,fh->nclips,
+		       V4L2_FIELD_HAS_BOTH(dev->ovfield));
+	if (dev->ovfmt->yuv)
+		saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x03);
+	else
+		saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x01);
+	saa_writeb(SAA7134_OFMT_VIDEO_B, dev->ovfmt->pm | 0x20);
+
+	/* dma: setup channel 1 (= Video Task B) */
+	base  = (unsigned long)dev->ovbuf.base;
+	base += dev->ovbuf.fmt.bytesperline * fh->win.w.top;
+	base += dev->ovfmt->depth/8         * fh->win.w.left;
+	bpl   = dev->ovbuf.fmt.bytesperline;
+	control = SAA7134_RS_CONTROL_BURST_16;
+	if (dev->ovfmt->bswap)
+		control |= SAA7134_RS_CONTROL_BSWAP;
+	if (dev->ovfmt->wswap)
+		control |= SAA7134_RS_CONTROL_WSWAP;
+	if (V4L2_FIELD_HAS_BOTH(dev->ovfield)) {
+		saa_writel(SAA7134_RS_BA1(1),base);
+		saa_writel(SAA7134_RS_BA2(1),base+bpl);
+		saa_writel(SAA7134_RS_PITCH(1),bpl*2);
+		saa_writel(SAA7134_RS_CONTROL(1),control);
+	} else {
+		saa_writel(SAA7134_RS_BA1(1),base);
+		saa_writel(SAA7134_RS_BA2(1),base);
+		saa_writel(SAA7134_RS_PITCH(1),bpl);
+		saa_writel(SAA7134_RS_CONTROL(1),control);
+	}
+
+	/* start dma */
+	dev->ovenable = 1;
+	saa7134_set_dmabits(dev);
+
+	return 0;
+}
+
+static int stop_preview(struct saa7134_dev *dev, struct saa7134_fh *fh)
+{
+	dev->ovenable = 0;
+	saa7134_set_dmabits(dev);
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int buffer_activate(struct saa7134_dev *dev,
+			   struct saa7134_buf *buf,
+			   struct saa7134_buf *next)
+{
+	unsigned long base,control,bpl;
+	unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */
+
+	dprintk("buffer_activate buf=%p\n",buf);
+	buf->vb.state = STATE_ACTIVE;
+	buf->top_seen = 0;
+
+	set_size(dev,TASK_A,buf->vb.width,buf->vb.height,
+		 V4L2_FIELD_HAS_BOTH(buf->vb.field));
+	if (buf->fmt->yuv)
+		saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x03);
+	else
+		saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x01);
+	saa_writeb(SAA7134_OFMT_VIDEO_A, buf->fmt->pm);
+
+	/* DMA: setup channel 0 (= Video Task A0) */
+	base  = saa7134_buffer_base(buf);
+	if (buf->fmt->planar)
+		bpl = buf->vb.width;
+	else
+		bpl = (buf->vb.width * buf->fmt->depth) / 8;
+	control = SAA7134_RS_CONTROL_BURST_16 |
+		SAA7134_RS_CONTROL_ME |
+		(buf->pt->dma >> 12);
+	if (buf->fmt->bswap)
+		control |= SAA7134_RS_CONTROL_BSWAP;
+	if (buf->fmt->wswap)
+		control |= SAA7134_RS_CONTROL_WSWAP;
+	if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) {
+		/* interlaced */
+		saa_writel(SAA7134_RS_BA1(0),base);
+		saa_writel(SAA7134_RS_BA2(0),base+bpl);
+		saa_writel(SAA7134_RS_PITCH(0),bpl*2);
+	} else {
+		/* non-interlaced */
+		saa_writel(SAA7134_RS_BA1(0),base);
+		saa_writel(SAA7134_RS_BA2(0),base);
+		saa_writel(SAA7134_RS_PITCH(0),bpl);
+	}
+	saa_writel(SAA7134_RS_CONTROL(0),control);
+
+	if (buf->fmt->planar) {
+		/* DMA: setup channel 4+5 (= planar task A) */
+		bpl_uv   = bpl >> buf->fmt->hshift;
+		lines_uv = buf->vb.height >> buf->fmt->vshift;
+		base2    = base + bpl * buf->vb.height;
+		base3    = base2 + bpl_uv * lines_uv;
+		if (buf->fmt->uvswap)
+			tmp = base2, base2 = base3, base3 = tmp;
+		dprintk("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n",
+			bpl_uv,lines_uv,base2,base3);
+		if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) {
+			/* interlaced */
+			saa_writel(SAA7134_RS_BA1(4),base2);
+			saa_writel(SAA7134_RS_BA2(4),base2+bpl_uv);
+			saa_writel(SAA7134_RS_PITCH(4),bpl_uv*2);
+			saa_writel(SAA7134_RS_BA1(5),base3);
+			saa_writel(SAA7134_RS_BA2(5),base3+bpl_uv);
+			saa_writel(SAA7134_RS_PITCH(5),bpl_uv*2);
+		} else {
+			/* non-interlaced */
+			saa_writel(SAA7134_RS_BA1(4),base2);
+			saa_writel(SAA7134_RS_BA2(4),base2);
+			saa_writel(SAA7134_RS_PITCH(4),bpl_uv);
+			saa_writel(SAA7134_RS_BA1(5),base3);
+			saa_writel(SAA7134_RS_BA2(5),base3);
+			saa_writel(SAA7134_RS_PITCH(5),bpl_uv);
+		}
+		saa_writel(SAA7134_RS_CONTROL(4),control);
+		saa_writel(SAA7134_RS_CONTROL(5),control);
+	}
+
+	/* start DMA */
+	saa7134_set_dmabits(dev);
+	mod_timer(&dev->video_q.timeout, jiffies+BUFFER_TIMEOUT);
+	return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *q,
+			  struct videobuf_buffer *vb,
+			  enum v4l2_field field)
+{
+	struct saa7134_fh *fh = q->priv_data;
+	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+	unsigned int size;
+	int err;
+
+	/* sanity checks */
+	if (NULL == fh->fmt)
+		return -EINVAL;
+	if (fh->width    < 48 ||
+	    fh->height   < 32 ||
+	    fh->width/4  > dev->crop_current.width  ||
+	    fh->height/4 > dev->crop_current.height ||
+	    fh->width    > dev->crop_bounds.width  ||
+	    fh->height   > dev->crop_bounds.height)
+		return -EINVAL;
+	size = (fh->width * fh->height * fh->fmt->depth) >> 3;
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+		return -EINVAL;
+
+	dprintk("buffer_prepare [%d,size=%dx%d,bytes=%d,fields=%s,%s]\n",
+		vb->i,fh->width,fh->height,size,v4l2_field_names[field],
+		fh->fmt->name);
+	if (buf->vb.width  != fh->width  ||
+	    buf->vb.height != fh->height ||
+	    buf->vb.size   != size       ||
+	    buf->vb.field  != field      ||
+	    buf->fmt       != fh->fmt) {
+		saa7134_dma_free(dev,buf);
+	}
+
+	if (STATE_NEEDS_INIT == buf->vb.state) {
+		buf->vb.width  = fh->width;
+		buf->vb.height = fh->height;
+		buf->vb.size   = size;
+		buf->vb.field  = field;
+		buf->fmt       = fh->fmt;
+		buf->pt        = &fh->pt_cap;
+
+		err = videobuf_iolock(dev->pci,&buf->vb,&dev->ovbuf);
+		if (err)
+			goto oops;
+		err = saa7134_pgtable_build(dev->pci,buf->pt,
+					    buf->vb.dma.sglist,
+					    buf->vb.dma.sglen,
+					    saa7134_buffer_startpage(buf));
+		if (err)
+			goto oops;
+	}
+	buf->vb.state = STATE_PREPARED;
+	buf->activate = buffer_activate;
+	return 0;
+
+ oops:
+	saa7134_dma_free(dev,buf);
+	return err;
+}
+
+static int
+buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+	struct saa7134_fh *fh = q->priv_data;
+
+	*size = fh->fmt->depth * fh->width * fh->height >> 3;
+	if (0 == *count)
+		*count = gbuffers;
+	*count = saa7134_buffer_count(*size,*count);
+	return 0;
+}
+
+static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct saa7134_fh *fh = q->priv_data;
+	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+
+	saa7134_buffer_queue(fh->dev,&fh->dev->video_q,buf);
+}
+
+static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct saa7134_fh *fh = q->priv_data;
+	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+
+	saa7134_dma_free(fh->dev,buf);
+}
+
+static struct videobuf_queue_ops video_qops = {
+	.buf_setup    = buffer_setup,
+	.buf_prepare  = buffer_prepare,
+	.buf_queue    = buffer_queue,
+	.buf_release  = buffer_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int get_control(struct saa7134_dev *dev, struct v4l2_control *c)
+{
+	const struct v4l2_queryctrl* ctrl;
+
+	ctrl = ctrl_by_id(c->id);
+	if (NULL == ctrl)
+		return -EINVAL;
+	switch (c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		c->value = dev->ctl_bright;
+		break;
+	case V4L2_CID_HUE:
+		c->value = dev->ctl_hue;
+		break;
+	case V4L2_CID_CONTRAST:
+		c->value = dev->ctl_contrast;
+		break;
+	case V4L2_CID_SATURATION:
+		c->value = dev->ctl_saturation;
+		break;
+	case V4L2_CID_AUDIO_MUTE:
+		c->value = dev->ctl_mute;
+		break;
+	case V4L2_CID_AUDIO_VOLUME:
+		c->value = dev->ctl_volume;
+		break;
+	case V4L2_CID_PRIVATE_INVERT:
+		c->value = dev->ctl_invert;
+		break;
+	case V4L2_CID_VFLIP:
+		c->value = dev->ctl_mirror;
+		break;
+	case V4L2_CID_PRIVATE_Y_EVEN:
+		c->value = dev->ctl_y_even;
+		break;
+	case V4L2_CID_PRIVATE_Y_ODD:
+		c->value = dev->ctl_y_odd;
+		break;
+	case V4L2_CID_PRIVATE_AUTOMUTE:
+		c->value = dev->ctl_automute;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
+		       struct v4l2_control *c)
+{
+	const struct v4l2_queryctrl* ctrl;
+	unsigned long flags;
+	int restart_overlay = 0;
+
+	ctrl = ctrl_by_id(c->id);
+	if (NULL == ctrl)
+		return -EINVAL;
+	dprintk("set_control name=%s val=%d\n",ctrl->name,c->value);
+	switch (ctrl->type) {
+	case V4L2_CTRL_TYPE_BOOLEAN:
+	case V4L2_CTRL_TYPE_MENU:
+	case V4L2_CTRL_TYPE_INTEGER:
+		if (c->value < ctrl->minimum)
+			c->value = ctrl->minimum;
+		if (c->value > ctrl->maximum)
+			c->value = ctrl->maximum;
+		break;
+	default:
+		/* nothing */;
+	};
+	switch (c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		dev->ctl_bright = c->value;
+		saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright);
+		break;
+	case V4L2_CID_HUE:
+		dev->ctl_hue = c->value;
+		saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue);
+		break;
+	case V4L2_CID_CONTRAST:
+		dev->ctl_contrast = c->value;
+		saa_writeb(SAA7134_DEC_LUMA_CONTRAST,
+			   dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast);
+		break;
+	case V4L2_CID_SATURATION:
+		dev->ctl_saturation = c->value;
+		saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
+			   dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
+		break;
+	case V4L2_CID_AUDIO_MUTE:
+		dev->ctl_mute = c->value;
+		saa7134_tvaudio_setmute(dev);
+		break;
+	case V4L2_CID_AUDIO_VOLUME:
+		dev->ctl_volume = c->value;
+		saa7134_tvaudio_setvolume(dev,dev->ctl_volume);
+		break;
+	case V4L2_CID_PRIVATE_INVERT:
+		dev->ctl_invert = c->value;
+		saa_writeb(SAA7134_DEC_LUMA_CONTRAST,
+			   dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast);
+		saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
+			   dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
+		break;
+	case V4L2_CID_VFLIP:
+		dev->ctl_mirror = c->value;
+		restart_overlay = 1;
+		break;
+	case V4L2_CID_PRIVATE_Y_EVEN:
+		dev->ctl_y_even = c->value;
+		restart_overlay = 1;
+		break;
+	case V4L2_CID_PRIVATE_Y_ODD:
+		dev->ctl_y_odd = c->value;
+		restart_overlay = 1;
+		break;
+	case V4L2_CID_PRIVATE_AUTOMUTE:
+		dev->ctl_automute = c->value;
+		if (dev->tda9887_conf) {
+			if (dev->ctl_automute)
+				dev->tda9887_conf |= TDA9887_AUTOMUTE;
+			else
+				dev->tda9887_conf &= ~TDA9887_AUTOMUTE;
+			saa7134_i2c_call_clients(dev, TDA9887_SET_CONFIG,
+						 &dev->tda9887_conf);
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) {
+		spin_lock_irqsave(&dev->slock,flags);
+		stop_preview(dev,fh);
+		start_preview(dev,fh);
+		spin_unlock_irqrestore(&dev->slock,flags);
+	}
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh)
+{
+	struct videobuf_queue* q = NULL;
+
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		q = &fh->cap;
+		break;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		q = &fh->vbi;
+		break;
+	default:
+		BUG();
+	}
+	return q;
+}
+
+static int saa7134_resource(struct saa7134_fh *fh)
+{
+	int res = 0;
+
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		res = RESOURCE_VIDEO;
+		break;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		res = RESOURCE_VBI;
+		break;
+	default:
+		BUG();
+	}
+	return res;
+}
+
+static int video_open(struct inode *inode, struct file *file)
+{
+	int minor = iminor(inode);
+	struct saa7134_dev *h,*dev = NULL;
+	struct saa7134_fh *fh;
+	struct list_head *list;
+	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	int radio = 0;
+
+	list_for_each(list,&saa7134_devlist) {
+		h = list_entry(list, struct saa7134_dev, devlist);
+		if (h->video_dev && (h->video_dev->minor == minor))
+			dev = h;
+		if (h->radio_dev && (h->radio_dev->minor == minor)) {
+			radio = 1;
+			dev = h;
+		}
+		if (h->vbi_dev && (h->vbi_dev->minor == minor)) {
+			type = V4L2_BUF_TYPE_VBI_CAPTURE;
+			dev = h;
+		}
+	}
+	if (NULL == dev)
+		return -ENODEV;
+
+	dprintk("open minor=%d radio=%d type=%s\n",minor,radio,
+		v4l2_type_names[type]);
+
+	/* allocate + initialize per filehandle data */
+	fh = kmalloc(sizeof(*fh),GFP_KERNEL);
+	if (NULL == fh)
+		return -ENOMEM;
+	memset(fh,0,sizeof(*fh));
+	file->private_data = fh;
+	fh->dev      = dev;
+	fh->radio    = radio;
+	fh->type     = type;
+	fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
+	fh->width    = 720;
+	fh->height   = 576;
+	v4l2_prio_open(&dev->prio,&fh->prio);
+
+	videobuf_queue_init(&fh->cap, &video_qops,
+			    dev->pci, &dev->slock,
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			    V4L2_FIELD_INTERLACED,
+			    sizeof(struct saa7134_buf),
+			    fh);
+	videobuf_queue_init(&fh->vbi, &saa7134_vbi_qops,
+			    dev->pci, &dev->slock,
+			    V4L2_BUF_TYPE_VBI_CAPTURE,
+			    V4L2_FIELD_SEQ_TB,
+			    sizeof(struct saa7134_buf),
+			    fh);
+	saa7134_pgtable_alloc(dev->pci,&fh->pt_cap);
+	saa7134_pgtable_alloc(dev->pci,&fh->pt_vbi);
+
+	if (fh->radio) {
+		/* switch to radio mode */
+		saa7134_tvaudio_setinput(dev,&card(dev).radio);
+		saa7134_i2c_call_clients(dev,AUDC_SET_RADIO,NULL);
+	} else {
+		/* switch to video/vbi mode */
+		video_mux(dev,dev->ctl_input);
+	}
+        return 0;
+}
+
+static ssize_t
+video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+{
+	struct saa7134_fh *fh = file->private_data;
+
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		if (res_locked(fh->dev,RESOURCE_VIDEO))
+			return -EBUSY;
+		return videobuf_read_one(saa7134_queue(fh),
+					 data, count, ppos,
+					 file->f_flags & O_NONBLOCK);
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		if (!res_get(fh->dev,fh,RESOURCE_VBI))
+			return -EBUSY;
+		return videobuf_read_stream(saa7134_queue(fh),
+					    data, count, ppos, 1,
+					    file->f_flags & O_NONBLOCK);
+		break;
+	default:
+		BUG();
+		return 0;
+	}
+}
+
+static unsigned int
+video_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct saa7134_fh *fh = file->private_data;
+	struct videobuf_buffer *buf = NULL;
+
+	if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
+		return videobuf_poll_stream(file, &fh->vbi, wait);
+
+	if (res_check(fh,RESOURCE_VIDEO)) {
+		if (!list_empty(&fh->cap.stream))
+			buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream);
+	} else {
+		down(&fh->cap.lock);
+		if (UNSET == fh->cap.read_off) {
+                        /* need to capture a new frame */
+			if (res_locked(fh->dev,RESOURCE_VIDEO)) {
+                                up(&fh->cap.lock);
+                                return POLLERR;
+                        }
+                        if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) {
+                                up(&fh->cap.lock);
+                                return POLLERR;
+                        }
+                        fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
+                        fh->cap.read_off = 0;
+		}
+		up(&fh->cap.lock);
+		buf = fh->cap.read_buf;
+	}
+
+	if (!buf)
+		return POLLERR;
+
+	poll_wait(file, &buf->done, wait);
+	if (buf->state == STATE_DONE ||
+	    buf->state == STATE_ERROR)
+		return POLLIN|POLLRDNORM;
+	return 0;
+}
+
+static int video_release(struct inode *inode, struct file *file)
+{
+	struct saa7134_fh  *fh  = file->private_data;
+	struct saa7134_dev *dev = fh->dev;
+	unsigned long flags;
+
+	/* turn off overlay */
+	if (res_check(fh, RESOURCE_OVERLAY)) {
+		spin_lock_irqsave(&dev->slock,flags);
+		stop_preview(dev,fh);
+		spin_unlock_irqrestore(&dev->slock,flags);
+		res_free(dev,fh,RESOURCE_OVERLAY);
+	}
+
+	/* stop video capture */
+	if (res_check(fh, RESOURCE_VIDEO)) {
+		videobuf_streamoff(&fh->cap);
+		res_free(dev,fh,RESOURCE_VIDEO);
+	}
+	if (fh->cap.read_buf) {
+		buffer_release(&fh->cap,fh->cap.read_buf);
+		kfree(fh->cap.read_buf);
+	}
+
+	/* stop vbi capture */
+	if (res_check(fh, RESOURCE_VBI)) {
+		if (fh->vbi.streaming)
+			videobuf_streamoff(&fh->vbi);
+		if (fh->vbi.reading)
+			videobuf_read_stop(&fh->vbi);
+		res_free(dev,fh,RESOURCE_VBI);
+	}
+
+	/* free stuff */
+	videobuf_mmap_free(&fh->cap);
+	videobuf_mmap_free(&fh->vbi);
+	saa7134_pgtable_free(dev->pci,&fh->pt_cap);
+	saa7134_pgtable_free(dev->pci,&fh->pt_vbi);
+
+	v4l2_prio_close(&dev->prio,&fh->prio);
+	file->private_data = NULL;
+	kfree(fh);
+	return 0;
+}
+
+static int
+video_mmap(struct file *file, struct vm_area_struct * vma)
+{
+	struct saa7134_fh *fh = file->private_data;
+
+	return videobuf_mmap_mapper(saa7134_queue(fh), vma);
+}
+
+/* ------------------------------------------------------------------ */
+
+static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f)
+{
+	struct saa7134_tvnorm *norm = dev->tvnorm;
+
+	f->fmt.vbi.sampling_rate = 6750000 * 4;
+	f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */;
+	f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+	f->fmt.vbi.offset = 64 * 4;
+	f->fmt.vbi.start[0] = norm->vbi_v_start;
+	f->fmt.vbi.count[0] = norm->vbi_v_stop - norm->vbi_v_start +1;
+	f->fmt.vbi.start[1] = norm->video_v_stop + norm->vbi_v_start +1;
+	f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
+	f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */
+
+#if 0
+	if (V4L2_STD_PAL == norm->id) {
+		/* FIXME */
+		f->fmt.vbi.start[0] += 3;
+		f->fmt.vbi.start[1] += 3*2;
+	}
+#endif
+}
+
+static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
+			 struct v4l2_format *f)
+{
+	switch (f->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
+		f->fmt.pix.width        = fh->width;
+		f->fmt.pix.height       = fh->height;
+		f->fmt.pix.field        = fh->cap.field;
+		f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+		f->fmt.pix.bytesperline =
+			(f->fmt.pix.width * fh->fmt->depth) >> 3;
+		f->fmt.pix.sizeimage =
+			f->fmt.pix.height * f->fmt.pix.bytesperline;
+		return 0;
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+		f->fmt.win = fh->win;
+		return 0;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		saa7134_vbi_fmt(dev,f);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
+			   struct v4l2_format *f)
+{
+	int err;
+
+	switch (f->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+	{
+		struct saa7134_format *fmt;
+		enum v4l2_field field;
+		unsigned int maxw, maxh;
+
+		fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+		if (NULL == fmt)
+			return -EINVAL;
+
+		field = f->fmt.pix.field;
+		maxw  = min(dev->crop_current.width*4,  dev->crop_bounds.width);
+		maxh  = min(dev->crop_current.height*4, dev->crop_bounds.height);
+
+		if (V4L2_FIELD_ANY == field) {
+			field = (f->fmt.pix.height > maxh/2)
+				? V4L2_FIELD_INTERLACED
+				: V4L2_FIELD_BOTTOM;
+		}
+		switch (field) {
+		case V4L2_FIELD_TOP:
+		case V4L2_FIELD_BOTTOM:
+			maxh = maxh / 2;
+			break;
+		case V4L2_FIELD_INTERLACED:
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		f->fmt.pix.field = field;
+		if (f->fmt.pix.width  < 48)
+			f->fmt.pix.width  = 48;
+		if (f->fmt.pix.height < 32)
+			f->fmt.pix.height = 32;
+		if (f->fmt.pix.width > maxw)
+			f->fmt.pix.width = maxw;
+		if (f->fmt.pix.height > maxh)
+			f->fmt.pix.height = maxh;
+		f->fmt.pix.width &= ~0x03;
+		f->fmt.pix.bytesperline =
+			(f->fmt.pix.width * fmt->depth) >> 3;
+		f->fmt.pix.sizeimage =
+			f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+		return 0;
+	}
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+		err = verify_preview(dev,&f->fmt.win);
+		if (0 != err)
+			return err;
+		return 0;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		saa7134_vbi_fmt(dev,f);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
+			 struct v4l2_format *f)
+{
+	unsigned long flags;
+	int err;
+
+	switch (f->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		err = saa7134_try_fmt(dev,fh,f);
+		if (0 != err)
+			return err;
+
+		fh->fmt       = format_by_fourcc(f->fmt.pix.pixelformat);
+		fh->width     = f->fmt.pix.width;
+		fh->height    = f->fmt.pix.height;
+		fh->cap.field = f->fmt.pix.field;
+		return 0;
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+		err = verify_preview(dev,&f->fmt.win);
+		if (0 != err)
+			return err;
+
+		down(&dev->lock);
+		fh->win    = f->fmt.win;
+		fh->nclips = f->fmt.win.clipcount;
+		if (fh->nclips > 8)
+			fh->nclips = 8;
+		if (copy_from_user(fh->clips,f->fmt.win.clips,
+				   sizeof(struct v4l2_clip)*fh->nclips)) {
+			up(&dev->lock);
+			return -EFAULT;
+		}
+
+		if (res_check(fh, RESOURCE_OVERLAY)) {
+			spin_lock_irqsave(&dev->slock,flags);
+			stop_preview(dev,fh);
+			start_preview(dev,fh);
+			spin_unlock_irqrestore(&dev->slock,flags);
+		}
+		up(&dev->lock);
+		return 0;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		saa7134_vbi_fmt(dev,f);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+int saa7134_common_ioctl(struct saa7134_dev *dev,
+			 unsigned int cmd, void *arg)
+{
+	int err;
+
+	switch (cmd) {
+	case VIDIOC_QUERYCTRL:
+	{
+		const struct v4l2_queryctrl *ctrl;
+		struct v4l2_queryctrl *c = arg;
+
+		if ((c->id <  V4L2_CID_BASE ||
+		     c->id >= V4L2_CID_LASTP1) &&
+		    (c->id <  V4L2_CID_PRIVATE_BASE ||
+		     c->id >= V4L2_CID_PRIVATE_LASTP1))
+			return -EINVAL;
+		ctrl = ctrl_by_id(c->id);
+		*c = (NULL != ctrl) ? *ctrl : no_ctrl;
+		return 0;
+	}
+	case VIDIOC_G_CTRL:
+		return get_control(dev,arg);
+	case VIDIOC_S_CTRL:
+	{
+		down(&dev->lock);
+		err = set_control(dev,NULL,arg);
+		up(&dev->lock);
+		return err;
+	}
+	/* --- input switching --------------------------------------- */
+	case VIDIOC_ENUMINPUT:
+	{
+		struct v4l2_input *i = arg;
+		unsigned int n;
+
+		n = i->index;
+		if (n >= SAA7134_INPUT_MAX)
+			return -EINVAL;
+		if (NULL == card_in(dev,i->index).name)
+			return -EINVAL;
+		memset(i,0,sizeof(*i));
+		i->index = n;
+		i->type  = V4L2_INPUT_TYPE_CAMERA;
+		strcpy(i->name,card_in(dev,n).name);
+		if (card_in(dev,n).tv)
+			i->type = V4L2_INPUT_TYPE_TUNER;
+		i->audioset = 1;
+		if (n == dev->ctl_input) {
+			int v1 = saa_readb(SAA7134_STATUS_VIDEO1);
+			int v2 = saa_readb(SAA7134_STATUS_VIDEO2);
+
+			if (0 != (v1 & 0x40))
+				i->status |= V4L2_IN_ST_NO_H_LOCK;
+			if (0 != (v2 & 0x40))
+				i->status |= V4L2_IN_ST_NO_SYNC;
+			if (0 != (v2 & 0x0e))
+				i->status |= V4L2_IN_ST_MACROVISION;
+		}
+		for (n = 0; n < TVNORMS; n++)
+			i->std |= tvnorms[n].id;
+		return 0;
+	}
+	case VIDIOC_G_INPUT:
+	{
+		int *i = arg;
+		*i = dev->ctl_input;
+		return 0;
+	}
+	case VIDIOC_S_INPUT:
+	{
+		int *i = arg;
+
+		if (*i < 0  ||  *i >= SAA7134_INPUT_MAX)
+			return -EINVAL;
+		if (NULL == card_in(dev,*i).name)
+			return -EINVAL;
+		down(&dev->lock);
+		video_mux(dev,*i);
+		up(&dev->lock);
+		return 0;
+	}
+
+	}
+	return 0;
+}
+EXPORT_SYMBOL(saa7134_common_ioctl);
+
+/*
+ * This function is _not_ called directly, but from
+ * video_generic_ioctl (and maybe others).  userspace
+ * copying is done already, arg is a kernel pointer.
+ */
+static int video_do_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, void *arg)
+{
+	struct saa7134_fh *fh = file->private_data;
+	struct saa7134_dev *dev = fh->dev;
+	unsigned long flags;
+	int err;
+
+	if (video_debug > 1)
+		saa7134_print_ioctl(dev->name,cmd);
+
+	switch (cmd) {
+	case VIDIOC_S_CTRL:
+	case VIDIOC_S_STD:
+	case VIDIOC_S_INPUT:
+	case VIDIOC_S_TUNER:
+	case VIDIOC_S_FREQUENCY:
+		err = v4l2_prio_check(&dev->prio,&fh->prio);
+		if (0 != err)
+			return err;
+	}
+
+	switch (cmd) {
+	case VIDIOC_QUERYCAP:
+	{
+		struct v4l2_capability *cap = arg;
+
+		memset(cap,0,sizeof(*cap));
+                strcpy(cap->driver, "saa7134");
+		strlcpy(cap->card, saa7134_boards[dev->board].name,
+			sizeof(cap->card));
+		sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
+		cap->version = SAA7134_VERSION_CODE;
+		cap->capabilities =
+			V4L2_CAP_VIDEO_CAPTURE |
+			V4L2_CAP_VIDEO_OVERLAY |
+			V4L2_CAP_VBI_CAPTURE |
+			V4L2_CAP_TUNER |
+			V4L2_CAP_READWRITE |
+			V4L2_CAP_STREAMING;
+		return 0;
+	}
+
+	/* --- tv standards ------------------------------------------ */
+	case VIDIOC_ENUMSTD:
+	{
+		struct v4l2_standard *e = arg;
+		unsigned int i;
+
+		i = e->index;
+		if (i >= TVNORMS)
+			return -EINVAL;
+		err = v4l2_video_std_construct(e, tvnorms[e->index].id,
+					       tvnorms[e->index].name);
+		e->index = i;
+		if (err < 0)
+			return err;
+		return 0;
+	}
+	case VIDIOC_G_STD:
+	{
+		v4l2_std_id *id = arg;
+
+		*id = dev->tvnorm->id;
+		return 0;
+	}
+	case VIDIOC_S_STD:
+	{
+		v4l2_std_id *id = arg;
+		unsigned int i;
+
+		for (i = 0; i < TVNORMS; i++)
+			if (*id == tvnorms[i].id)
+				break;
+		if (i == TVNORMS)
+			for (i = 0; i < TVNORMS; i++)
+				if (*id & tvnorms[i].id)
+					break;
+		if (i == TVNORMS)
+			return -EINVAL;
+
+		down(&dev->lock);
+		if (res_check(fh, RESOURCE_OVERLAY)) {
+			spin_lock_irqsave(&dev->slock,flags);
+			stop_preview(dev,fh);
+			set_tvnorm(dev,&tvnorms[i]);
+			start_preview(dev,fh);
+			spin_unlock_irqrestore(&dev->slock,flags);
+		} else
+			set_tvnorm(dev,&tvnorms[i]);
+		saa7134_tvaudio_do_scan(dev);
+		up(&dev->lock);
+		return 0;
+	}
+
+	case VIDIOC_CROPCAP:
+	{
+		struct v4l2_cropcap *cap = arg;
+
+		if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+		    cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+			return -EINVAL;
+		cap->bounds  = dev->crop_bounds;
+		cap->defrect = dev->crop_defrect;
+		cap->pixelaspect.numerator   = 1;
+		cap->pixelaspect.denominator = 1;
+		if (dev->tvnorm->id & V4L2_STD_525_60) {
+			cap->pixelaspect.numerator   = 11;
+			cap->pixelaspect.denominator = 10;
+		}
+		if (dev->tvnorm->id & V4L2_STD_625_50) {
+			cap->pixelaspect.numerator   = 54;
+			cap->pixelaspect.denominator = 59;
+		}
+		return 0;
+	}
+
+	case VIDIOC_G_CROP:
+	{
+		struct v4l2_crop * crop = arg;
+
+		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+			return -EINVAL;
+		crop->c = dev->crop_current;
+		return 0;
+	}
+	case VIDIOC_S_CROP:
+	{
+		struct v4l2_crop *crop = arg;
+		struct v4l2_rect *b = &dev->crop_bounds;
+
+		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+			return -EINVAL;
+		if (crop->c.height < 0)
+			return -EINVAL;
+		if (crop->c.width < 0)
+			return -EINVAL;
+
+		if (res_locked(fh->dev,RESOURCE_OVERLAY))
+			return -EBUSY;
+		if (res_locked(fh->dev,RESOURCE_VIDEO))
+			return -EBUSY;
+
+		if (crop->c.top < b->top)
+			crop->c.top = b->top;
+		if (crop->c.top > b->top + b->height)
+			crop->c.top = b->top + b->height;
+		if (crop->c.height > b->top - crop->c.top + b->height)
+			crop->c.height = b->top - crop->c.top + b->height;
+
+		if (crop->c.left < b->left)
+			crop->c.top = b->left;
+		if (crop->c.left > b->left + b->width)
+			crop->c.top = b->left + b->width;
+		if (crop->c.width > b->left - crop->c.left + b->width)
+			crop->c.width = b->left - crop->c.left + b->width;
+
+		dev->crop_current = crop->c;
+		return 0;
+	}
+
+	/* --- tuner ioctls ------------------------------------------ */
+	case VIDIOC_G_TUNER:
+	{
+		struct v4l2_tuner *t = arg;
+		int n;
+
+		if (0 != t->index)
+			return -EINVAL;
+		memset(t,0,sizeof(*t));
+		for (n = 0; n < SAA7134_INPUT_MAX; n++)
+			if (card_in(dev,n).tv)
+				break;
+		if (NULL != card_in(dev,n).name) {
+			strcpy(t->name, "Television");
+			t->capability = V4L2_TUNER_CAP_NORM |
+				V4L2_TUNER_CAP_STEREO |
+				V4L2_TUNER_CAP_LANG1 |
+				V4L2_TUNER_CAP_LANG2;
+			t->rangehigh = 0xffffffffUL;
+			t->rxsubchans = saa7134_tvaudio_getstereo(dev);
+			t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans);
+		}
+		if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03))
+			t->signal = 0xffff;
+		return 0;
+	}
+	case VIDIOC_S_TUNER:
+	{
+		struct v4l2_tuner *t = arg;
+		int rx,mode;
+
+		mode = dev->thread.mode;
+		if (UNSET == mode) {
+			rx   = saa7134_tvaudio_getstereo(dev);
+			mode = saa7134_tvaudio_rx2mode(t->rxsubchans);
+		}
+		if (mode != t->audmode) {
+			dev->thread.mode = t->audmode;
+		}
+		return 0;
+	}
+	case VIDIOC_G_FREQUENCY:
+	{
+		struct v4l2_frequency *f = arg;
+
+		memset(f,0,sizeof(*f));
+		f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+		f->frequency = dev->ctl_freq;
+		return 0;
+	}
+	case VIDIOC_S_FREQUENCY:
+	{
+		struct v4l2_frequency *f = arg;
+
+		if (0 != f->tuner)
+			return -EINVAL;
+		if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
+			return -EINVAL;
+		if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
+			return -EINVAL;
+		down(&dev->lock);
+		dev->ctl_freq = f->frequency;
+#ifdef V4L2_I2C_CLIENTS
+		saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f);
+#else
+		saa7134_i2c_call_clients(dev,VIDIOCSFREQ,&dev->ctl_freq);
+#endif
+		saa7134_tvaudio_do_scan(dev);
+		up(&dev->lock);
+		return 0;
+	}
+
+	/* --- control ioctls ---------------------------------------- */
+	case VIDIOC_ENUMINPUT:
+	case VIDIOC_G_INPUT:
+	case VIDIOC_S_INPUT:
+	case VIDIOC_QUERYCTRL:
+	case VIDIOC_G_CTRL:
+	case VIDIOC_S_CTRL:
+		return saa7134_common_ioctl(dev, cmd, arg);
+
+	case VIDIOC_G_AUDIO:
+	{
+		struct v4l2_audio *a = arg;
+
+		memset(a,0,sizeof(*a));
+		strcpy(a->name,"audio");
+		return 0;
+	}
+	case VIDIOC_S_AUDIO:
+		return 0;
+        case VIDIOC_G_PARM:
+        {
+                struct v4l2_captureparm *parm = arg;
+                memset(parm,0,sizeof(*parm));
+                return 0;
+        }
+
+        case VIDIOC_G_PRIORITY:
+        {
+                enum v4l2_priority *p = arg;
+
+                *p = v4l2_prio_max(&dev->prio);
+                return 0;
+        }
+        case VIDIOC_S_PRIORITY:
+        {
+                enum v4l2_priority *prio = arg;
+
+                return v4l2_prio_change(&dev->prio, &fh->prio, *prio);
+        }
+
+	/* --- preview ioctls ---------------------------------------- */
+	case VIDIOC_ENUM_FMT:
+	{
+		struct v4l2_fmtdesc *f = arg;
+		enum v4l2_buf_type type;
+		unsigned int index;
+
+		index = f->index;
+		type  = f->type;
+		switch (type) {
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+			if (index >= FORMATS)
+				return -EINVAL;
+			if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY &&
+			    formats[index].planar)
+				return -EINVAL;
+			memset(f,0,sizeof(*f));
+			f->index = index;
+			f->type  = type;
+			strlcpy(f->description,formats[index].name,sizeof(f->description));
+			f->pixelformat = formats[index].fourcc;
+			break;
+		case V4L2_BUF_TYPE_VBI_CAPTURE:
+			if (0 != index)
+				return -EINVAL;
+			memset(f,0,sizeof(*f));
+			f->index = index;
+			f->type  = type;
+			f->pixelformat = V4L2_PIX_FMT_GREY;
+			strcpy(f->description,"vbi data");
+			break;
+		default:
+			return -EINVAL;
+		}
+		return 0;
+	}
+	case VIDIOC_G_FBUF:
+	{
+		struct v4l2_framebuffer *fb = arg;
+
+		*fb = dev->ovbuf;
+		fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+		return 0;
+	}
+	case VIDIOC_S_FBUF:
+	{
+		struct v4l2_framebuffer *fb = arg;
+		struct saa7134_format *fmt;
+
+		if(!capable(CAP_SYS_ADMIN) &&
+		   !capable(CAP_SYS_RAWIO))
+			return -EPERM;
+
+		/* check args */
+		fmt = format_by_fourcc(fb->fmt.pixelformat);
+		if (NULL == fmt)
+			return -EINVAL;
+
+		/* ok, accept it */
+		dev->ovbuf = *fb;
+		dev->ovfmt = fmt;
+		if (0 == dev->ovbuf.fmt.bytesperline)
+			dev->ovbuf.fmt.bytesperline =
+				dev->ovbuf.fmt.width*fmt->depth/8;
+		return 0;
+	}
+	case VIDIOC_OVERLAY:
+	{
+		int *on = arg;
+
+		if (*on) {
+			if (!res_get(dev,fh,RESOURCE_OVERLAY))
+				return -EBUSY;
+			spin_lock_irqsave(&dev->slock,flags);
+			start_preview(dev,fh);
+			spin_unlock_irqrestore(&dev->slock,flags);
+		}
+		if (!*on) {
+			if (!res_check(fh, RESOURCE_OVERLAY))
+				return -EINVAL;
+			spin_lock_irqsave(&dev->slock,flags);
+			stop_preview(dev,fh);
+			spin_unlock_irqrestore(&dev->slock,flags);
+			res_free(dev,fh,RESOURCE_OVERLAY);
+		}
+		return 0;
+	}
+
+	/* --- capture ioctls ---------------------------------------- */
+	case VIDIOC_G_FMT:
+	{
+		struct v4l2_format *f = arg;
+		return saa7134_g_fmt(dev,fh,f);
+	}
+	case VIDIOC_S_FMT:
+	{
+		struct v4l2_format *f = arg;
+		return saa7134_s_fmt(dev,fh,f);
+	}
+	case VIDIOC_TRY_FMT:
+	{
+		struct v4l2_format *f = arg;
+		return saa7134_try_fmt(dev,fh,f);
+	}
+
+	case VIDIOCGMBUF:
+	{
+		struct video_mbuf *mbuf = arg;
+		struct videobuf_queue *q;
+		struct v4l2_requestbuffers req;
+		unsigned int i;
+
+		q = saa7134_queue(fh);
+		memset(&req,0,sizeof(req));
+		req.type   = q->type;
+		req.count  = gbuffers;
+		req.memory = V4L2_MEMORY_MMAP;
+		err = videobuf_reqbufs(q,&req);
+		if (err < 0)
+			return err;
+		memset(mbuf,0,sizeof(*mbuf));
+		mbuf->frames = req.count;
+		mbuf->size   = 0;
+		for (i = 0; i < mbuf->frames; i++) {
+			mbuf->offsets[i]  = q->bufs[i]->boff;
+			mbuf->size       += q->bufs[i]->bsize;
+		}
+		return 0;
+	}
+	case VIDIOC_REQBUFS:
+		return videobuf_reqbufs(saa7134_queue(fh),arg);
+
+	case VIDIOC_QUERYBUF:
+		return videobuf_querybuf(saa7134_queue(fh),arg);
+
+	case VIDIOC_QBUF:
+		return videobuf_qbuf(saa7134_queue(fh),arg);
+
+	case VIDIOC_DQBUF:
+		return videobuf_dqbuf(saa7134_queue(fh),arg,
+				      file->f_flags & O_NONBLOCK);
+
+	case VIDIOC_STREAMON:
+	{
+		int res = saa7134_resource(fh);
+
+                if (!res_get(dev,fh,res))
+			return -EBUSY;
+		return videobuf_streamon(saa7134_queue(fh));
+	}
+	case VIDIOC_STREAMOFF:
+	{
+		int res = saa7134_resource(fh);
+
+		err = videobuf_streamoff(saa7134_queue(fh));
+		if (err < 0)
+			return err;
+		res_free(dev,fh,res);
+		return 0;
+	}
+
+	default:
+		return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+						  video_do_ioctl);
+	}
+	return 0;
+}
+
+static int video_ioctl(struct inode *inode, struct file *file,
+		       unsigned int cmd, unsigned long arg)
+{
+	return video_usercopy(inode, file, cmd, arg, video_do_ioctl);
+}
+
+static int radio_do_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, void *arg)
+{
+	struct saa7134_fh *fh = file->private_data;
+	struct saa7134_dev *dev = fh->dev;
+
+	if (video_debug > 1)
+		saa7134_print_ioctl(dev->name,cmd);
+	switch (cmd) {
+	case VIDIOC_QUERYCAP:
+	{
+		struct v4l2_capability *cap = arg;
+
+		memset(cap,0,sizeof(*cap));
+                strcpy(cap->driver, "saa7134");
+		strlcpy(cap->card, saa7134_boards[dev->board].name,
+			sizeof(cap->card));
+		sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
+		cap->version = SAA7134_VERSION_CODE;
+		cap->capabilities = V4L2_CAP_TUNER;
+		return 0;
+	}
+	case VIDIOC_G_TUNER:
+	{
+		struct v4l2_tuner *t = arg;
+
+		if (0 != t->index)
+			return -EINVAL;
+
+		memset(t,0,sizeof(*t));
+		strcpy(t->name, "Radio");
+                t->rangelow  = (int)(65*16);
+                t->rangehigh = (int)(108*16);
+
+#ifdef V4L2_I2C_CLIENTS
+		saa7134_i2c_call_clients(dev,VIDIOC_G_TUNER,t);
+#else
+		{
+			struct video_tuner vt;
+			memset(&vt,0,sizeof(vt));
+			saa7134_i2c_call_clients(dev,VIDIOCGTUNER,&vt);
+			t->signal = vt.signal;
+		}
+#endif
+		return 0;
+	}
+	case VIDIOC_ENUMINPUT:
+	{
+		struct v4l2_input *i = arg;
+
+		if (i->index != 0)
+			return -EINVAL;
+		strcpy(i->name,"Radio");
+		i->type = V4L2_INPUT_TYPE_TUNER;
+		return 0;
+	}
+	case VIDIOC_G_INPUT:
+	{
+		int *i = arg;
+		*i = 0;
+		return 0;
+	}
+	case VIDIOC_G_AUDIO:
+	{
+		struct v4l2_audio *a = arg;
+
+		memset(a,0,sizeof(*a));
+		strcpy(a->name,"Radio");
+		return 0;
+	}
+	case VIDIOC_G_STD:
+	{
+		v4l2_std_id *id = arg;
+		*id = 0;
+		return 0;
+	}
+	case VIDIOC_S_AUDIO:
+	case VIDIOC_S_TUNER:
+	case VIDIOC_S_INPUT:
+	case VIDIOC_S_STD:
+		return 0;
+
+	case VIDIOC_QUERYCTRL:
+	{
+		const struct v4l2_queryctrl *ctrl;
+		struct v4l2_queryctrl *c = arg;
+
+		if (c->id <  V4L2_CID_BASE ||
+		    c->id >= V4L2_CID_LASTP1)
+			return -EINVAL;
+		if (c->id == V4L2_CID_AUDIO_MUTE) {
+			ctrl = ctrl_by_id(c->id);
+			*c = *ctrl;
+		} else
+			*c = no_ctrl;
+		return 0;
+	}
+
+	case VIDIOC_G_CTRL:
+	case VIDIOC_S_CTRL:
+	case VIDIOC_G_FREQUENCY:
+	case VIDIOC_S_FREQUENCY:
+		return video_do_ioctl(inode,file,cmd,arg);
+
+	default:
+		return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+						  radio_do_ioctl);
+	}
+	return 0;
+}
+
+static int radio_ioctl(struct inode *inode, struct file *file,
+		       unsigned int cmd, unsigned long arg)
+{
+	return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
+}
+
+static struct file_operations video_fops =
+{
+	.owner	  = THIS_MODULE,
+	.open	  = video_open,
+	.release  = video_release,
+	.read	  = video_read,
+	.poll     = video_poll,
+	.mmap	  = video_mmap,
+	.ioctl	  = video_ioctl,
+	.llseek   = no_llseek,
+};
+
+static struct file_operations radio_fops =
+{
+	.owner	  = THIS_MODULE,
+	.open	  = video_open,
+	.release  = video_release,
+	.ioctl	  = radio_ioctl,
+	.llseek   = no_llseek,
+};
+
+/* ----------------------------------------------------------- */
+/* exported stuff                                              */
+
+struct video_device saa7134_video_template =
+{
+	.name          = "saa7134-video",
+	.type          = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY|
+	                 VID_TYPE_CLIPPING|VID_TYPE_SCALES,
+	.hardware      = 0,
+	.fops          = &video_fops,
+	.minor         = -1,
+};
+
+struct video_device saa7134_vbi_template =
+{
+	.name          = "saa7134-vbi",
+	.type          = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
+	.hardware      = 0,
+	.fops          = &video_fops,
+	.minor         = -1,
+};
+
+struct video_device saa7134_radio_template =
+{
+	.name          = "saa7134-radio",
+	.type          = VID_TYPE_TUNER,
+	.hardware      = 0,
+	.fops          = &radio_fops,
+	.minor         = -1,
+};
+
+int saa7134_video_init1(struct saa7134_dev *dev)
+{
+	/* sanitycheck insmod options */
+	if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
+		gbuffers = 2;
+	if (gbufsize < 0 || gbufsize > gbufsize_max)
+		gbufsize = gbufsize_max;
+	gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
+
+	/* put some sensible defaults into the data structures ... */
+	dev->ctl_bright     = ctrl_by_id(V4L2_CID_BRIGHTNESS)->default_value;
+	dev->ctl_contrast   = ctrl_by_id(V4L2_CID_CONTRAST)->default_value;
+	dev->ctl_hue        = ctrl_by_id(V4L2_CID_HUE)->default_value;
+	dev->ctl_saturation = ctrl_by_id(V4L2_CID_SATURATION)->default_value;
+	dev->ctl_volume     = ctrl_by_id(V4L2_CID_AUDIO_VOLUME)->default_value;
+	dev->ctl_mute       = 1; // ctrl_by_id(V4L2_CID_AUDIO_MUTE)->default_value;
+	dev->ctl_invert     = ctrl_by_id(V4L2_CID_PRIVATE_INVERT)->default_value;
+	dev->ctl_automute   = ctrl_by_id(V4L2_CID_PRIVATE_AUTOMUTE)->default_value;
+
+	if (dev->tda9887_conf && dev->ctl_automute)
+		dev->tda9887_conf |= TDA9887_AUTOMUTE;
+	dev->automute       = 0;
+
+        INIT_LIST_HEAD(&dev->video_q.queue);
+	init_timer(&dev->video_q.timeout);
+	dev->video_q.timeout.function = saa7134_buffer_timeout;
+	dev->video_q.timeout.data     = (unsigned long)(&dev->video_q);
+	dev->video_q.dev              = dev;
+
+	if (saa7134_boards[dev->board].video_out) {
+		/* enable video output */
+		int vo = saa7134_boards[dev->board].video_out;
+		saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
+		saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_out[vo][1]);
+		saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
+		saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
+		saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
+		saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_out[vo][5]);
+		saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_out[vo][6]);
+		saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
+		saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
+	}
+
+	return 0;
+}
+
+int saa7134_video_init2(struct saa7134_dev *dev)
+{
+	/* init video hw */
+	set_tvnorm(dev,&tvnorms[0]);
+	video_mux(dev,0);
+	saa7134_tvaudio_setmute(dev);
+	saa7134_tvaudio_setvolume(dev,dev->ctl_volume);
+	return 0;
+}
+
+int saa7134_video_fini(struct saa7134_dev *dev)
+{
+	/* nothing */
+	return 0;
+}
+
+void saa7134_irq_video_intl(struct saa7134_dev *dev)
+{
+	static const char *st[] = {
+		"(no signal)", "NTSC", "PAL", "SECAM" };
+	u32 st1,st2;
+
+	st1 = saa_readb(SAA7134_STATUS_VIDEO1);
+	st2 = saa_readb(SAA7134_STATUS_VIDEO2);
+	dprintk("DCSDT: pll: %s, sync: %s, norm: %s\n",
+		(st1 & 0x40) ? "not locked" : "locked",
+		(st2 & 0x40) ? "no"         : "yes",
+		st[st1 & 0x03]);
+	dev->nosignal = (st1 & 0x40) || (st2 & 0x40);
+
+	if (dev->nosignal) {
+		/* no video signal -> mute audio */
+		if (dev->ctl_automute)
+			dev->automute = 1;
+		saa7134_tvaudio_setmute(dev);
+		saa_setb(SAA7134_SYNC_CTRL, 0x20);
+	} else {
+		/* wake up tvaudio audio carrier scan thread */
+		saa7134_tvaudio_do_scan(dev);
+		if (!noninterlaced)
+			saa_clearb(SAA7134_SYNC_CTRL, 0x20);
+	}
+	if (dev->mops && dev->mops->signal_change)
+		dev->mops->signal_change(dev);
+}
+
+void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
+{
+	enum v4l2_field field;
+
+	spin_lock(&dev->slock);
+	if (dev->video_q.curr) {
+		dev->video_fieldcount++;
+		field = dev->video_q.curr->vb.field;
+		if (V4L2_FIELD_HAS_BOTH(field)) {
+			/* make sure we have seen both fields */
+			if ((status & 0x10) == 0x00) {
+				dev->video_q.curr->top_seen = 1;
+				goto done;
+			}
+			if (!dev->video_q.curr->top_seen)
+				goto done;
+		} else if (field == V4L2_FIELD_TOP) {
+			if ((status & 0x10) != 0x10)
+				goto done;
+		} else if (field == V4L2_FIELD_BOTTOM) {
+			if ((status & 0x10) != 0x00)
+				goto done;
+		}
+		dev->video_q.curr->vb.field_count = dev->video_fieldcount;
+		saa7134_buffer_finish(dev,&dev->video_q,STATE_DONE);
+	}
+	saa7134_buffer_next(dev,&dev->video_q);
+
+ done:
+	spin_unlock(&dev->slock);
+}
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
new file mode 100644
index 0000000..ac90a98
--- /dev/null
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -0,0 +1,618 @@
+/*
+ * $Id: saa7134.h,v 1.38 2005/03/07 12:01:51 kraxel Exp $
+ *
+ * v4l2 device driver for philips saa7134 based TV cards
+ *
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/version.h>
+#define SAA7134_VERSION_CODE KERNEL_VERSION(0,2,12)
+
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/kdev_t.h>
+#include <linux/input.h>
+
+#include <asm/io.h>
+
+#include <media/tuner.h>
+#include <media/audiochip.h>
+#include <media/id.h>
+#include <media/ir-common.h>
+#include <media/video-buf.h>
+#include <media/video-buf-dvb.h>
+
+#ifndef TRUE
+# define TRUE (1==1)
+#endif
+#ifndef FALSE
+# define FALSE (1==0)
+#endif
+#define UNSET (-1U)
+
+/* 2.4 / 2.5 driver compatibility stuff */
+
+/* ----------------------------------------------------------- */
+/* enums                                                       */
+
+enum saa7134_tvaudio_mode {
+	TVAUDIO_FM_MONO       = 1,
+	TVAUDIO_FM_BG_STEREO  = 2,
+	TVAUDIO_FM_SAT_STEREO = 3,
+	TVAUDIO_FM_K_STEREO   = 4,
+	TVAUDIO_NICAM_AM      = 5,
+	TVAUDIO_NICAM_FM      = 6,
+};
+
+enum saa7134_audio_in {
+	TV    = 1,
+	LINE1 = 2,
+	LINE2 = 3,
+	LINE2_LEFT,
+};
+
+enum saa7134_video_out {
+	CCIR656 = 1,
+};
+
+/* ----------------------------------------------------------- */
+/* static data                                                 */
+
+struct saa7134_tvnorm {
+	char          *name;
+	v4l2_std_id   id;
+
+	/* video decoder */
+	unsigned int  sync_control;
+	unsigned int  luma_control;
+	unsigned int  chroma_ctrl1;
+	unsigned int  chroma_gain;
+	unsigned int  chroma_ctrl2;
+	unsigned int  vgate_misc;
+
+	/* video scaler */
+	unsigned int  h_start;
+	unsigned int  h_stop;
+	unsigned int  video_v_start;
+	unsigned int  video_v_stop;
+	unsigned int  vbi_v_start;
+	unsigned int  vbi_v_stop;
+	unsigned int  src_timing;
+};
+
+struct saa7134_tvaudio {
+	char         *name;
+	v4l2_std_id  std;
+	enum         saa7134_tvaudio_mode mode;
+	int          carr1;
+	int          carr2;
+};
+
+struct saa7134_format {
+	char           *name;
+	unsigned int   fourcc;
+	unsigned int   depth;
+	unsigned int   pm;
+	unsigned int   vshift;   /* vertical downsampling (for planar yuv) */
+	unsigned int   hshift;   /* horizontal downsampling (for planar yuv) */
+	unsigned int   bswap:1;
+	unsigned int   wswap:1;
+	unsigned int   yuv:1;
+	unsigned int   planar:1;
+	unsigned int   uvswap:1;
+};
+
+/* ----------------------------------------------------------- */
+/* card configuration                                          */
+
+#define SAA7134_BOARD_NOAUTO        UNSET
+#define SAA7134_BOARD_UNKNOWN           0
+#define SAA7134_BOARD_PROTEUS_PRO       1
+#define SAA7134_BOARD_FLYVIDEO3000      2
+#define SAA7134_BOARD_FLYVIDEO2000      3
+#define SAA7134_BOARD_EMPRESS           4
+#define SAA7134_BOARD_MONSTERTV         5
+#define SAA7134_BOARD_MD9717            6
+#define SAA7134_BOARD_TVSTATION_RDS     7
+#define SAA7134_BOARD_CINERGY400	8
+#define SAA7134_BOARD_MD5044		9
+#define SAA7134_BOARD_KWORLD           10
+#define SAA7134_BOARD_CINERGY600       11
+#define SAA7134_BOARD_MD7134           12
+#define SAA7134_BOARD_TYPHOON_90031    13
+#define SAA7134_BOARD_ELSA             14
+#define SAA7134_BOARD_ELSA_500TV       15
+#define SAA7134_BOARD_ASUSTeK_TVFM7134 16
+#define SAA7134_BOARD_VA1000POWER      17
+#define SAA7134_BOARD_BMK_MPEX_NOTUNER 18
+#define SAA7134_BOARD_VIDEOMATE_TV     19
+#define SAA7134_BOARD_CRONOS_PLUS      20
+#define SAA7134_BOARD_10MOONSTVMASTER  21
+#define SAA7134_BOARD_MD2819           22
+#define SAA7134_BOARD_BMK_MPEX_TUNER   23
+#define SAA7134_BOARD_TVSTATION_DVR    24
+#define SAA7134_BOARD_ASUSTEK_TVFM7133	25
+#define SAA7134_BOARD_PINNACLE_PCTV_STEREO 26
+#define SAA7134_BOARD_MANLI_MTV002     27
+#define SAA7134_BOARD_MANLI_MTV001     28
+#define SAA7134_BOARD_TG3000TV         29
+#define SAA7134_BOARD_ECS_TVP3XP       30
+#define SAA7134_BOARD_ECS_TVP3XP_4CB5  31
+#define SAA7134_BOARD_AVACSSMARTTV     32
+#define SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER 33
+#define SAA7134_BOARD_NOVAC_PRIMETV7133 34
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_305 35
+#define SAA7133_BOARD_UPMOST_PURPLE_TV 36
+#define SAA7134_BOARD_ITEMS_MTV005     37
+#define SAA7134_BOARD_CINERGY200       38
+#define SAA7134_BOARD_FLYTVPLATINUM_MINI 39
+#define SAA7134_BOARD_VIDEOMATE_TV_PVR 40
+#define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS 41
+#define SAA7134_BOARD_SABRENT_SBTTVFM  42
+#define SAA7134_BOARD_ZOLID_XPERT_TV7134 43
+#define SAA7134_BOARD_EMPIRE_PCI_TV_RADIO_LE 44
+#define SAA7134_BOARD_AVERMEDIA_307    45
+#define SAA7134_BOARD_AVERMEDIA_CARDBUS 46
+#define SAA7134_BOARD_CINERGY400_CARDBUS 47
+#define SAA7134_BOARD_CINERGY600_MK3   48
+#define SAA7134_BOARD_VIDEOMATE_GOLD_PLUS 49
+#define SAA7134_BOARD_PINNACLE_300I_DVBT_PAL 50
+#define SAA7134_BOARD_PROVIDEO_PV952   51
+#define SAA7134_BOARD_AVERMEDIA_305    52
+#define SAA7135_BOARD_ASUSTeK_TVFM7135 53
+#define SAA7134_BOARD_FLYTVPLATINUM_FM 54
+#define SAA7134_BOARD_FLYDVBTDUO 55
+
+#define SAA7134_MAXBOARDS 8
+#define SAA7134_INPUT_MAX 8
+
+struct saa7134_input {
+	char                    *name;
+	unsigned int            vmux;
+	enum saa7134_audio_in   amux;
+	unsigned int            gpio;
+	unsigned int            tv:1;
+};
+
+enum saa7134_mpeg_type {
+	SAA7134_MPEG_UNUSED,
+	SAA7134_MPEG_EMPRESS,
+	SAA7134_MPEG_DVB,
+};
+
+struct saa7134_board {
+	char                    *name;
+	unsigned int            audio_clock;
+
+	/* input switching */
+	unsigned int            gpiomask;
+	struct saa7134_input    inputs[SAA7134_INPUT_MAX];
+	struct saa7134_input    radio;
+	struct saa7134_input    mute;
+
+	/* i2c chip info */
+	unsigned int            tuner_type;
+	unsigned int            tda9887_conf;
+
+	/* peripheral I/O */
+	enum saa7134_video_out  video_out;
+	enum saa7134_mpeg_type  mpeg;
+};
+
+#define card_has_radio(dev)   (NULL != saa7134_boards[dev->board].radio.name)
+#define card_is_empress(dev)  (SAA7134_MPEG_EMPRESS == saa7134_boards[dev->board].mpeg)
+#define card_is_dvb(dev)      (SAA7134_MPEG_DVB     == saa7134_boards[dev->board].mpeg)
+#define card_has_mpeg(dev)    (SAA7134_MPEG_UNUSED  != saa7134_boards[dev->board].mpeg)
+#define card(dev)             (saa7134_boards[dev->board])
+#define card_in(dev,n)        (saa7134_boards[dev->board].inputs[n])
+
+/* ----------------------------------------------------------- */
+/* device / file handle status                                 */
+
+#define RESOURCE_OVERLAY       1
+#define RESOURCE_VIDEO         2
+#define RESOURCE_VBI           4
+
+#define INTERLACE_AUTO         0
+#define INTERLACE_ON           1
+#define INTERLACE_OFF          2
+
+#define BUFFER_TIMEOUT     (HZ/2)  /* 0.5 seconds */
+
+struct saa7134_dev;
+struct saa7134_dma;
+
+/* saa7134 page table */
+struct saa7134_pgtable {
+	unsigned int               size;
+	u32                        *cpu;
+	dma_addr_t                 dma;
+};
+
+/* tvaudio thread status */
+struct saa7134_thread {
+	pid_t                      pid;
+	struct completion          exit;
+	wait_queue_head_t          wq;
+	unsigned int               shutdown;
+	unsigned int               scan1;
+	unsigned int               scan2;
+	unsigned int               mode;
+};
+
+/* buffer for one video/vbi/ts frame */
+struct saa7134_buf {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer vb;
+
+	/* saa7134 specific */
+	struct saa7134_format   *fmt;
+	unsigned int            top_seen;
+	int (*activate)(struct saa7134_dev *dev,
+			struct saa7134_buf *buf,
+			struct saa7134_buf *next);
+
+	/* page tables */
+	struct saa7134_pgtable  *pt;
+};
+
+struct saa7134_dmaqueue {
+	struct saa7134_dev         *dev;
+	struct saa7134_buf         *curr;
+	struct list_head           queue;
+	struct timer_list          timeout;
+	unsigned int               need_two;
+};
+
+/* video filehandle status */
+struct saa7134_fh {
+	struct saa7134_dev         *dev;
+	unsigned int               radio;
+	enum v4l2_buf_type         type;
+	unsigned int               resources;
+#ifdef VIDIOC_G_PRIORITY
+	enum v4l2_priority	   prio;
+#endif
+
+	/* video overlay */
+	struct v4l2_window         win;
+	struct v4l2_clip           clips[8];
+	unsigned int               nclips;
+
+	/* video capture */
+	struct saa7134_format      *fmt;
+	unsigned int               width,height;
+	struct videobuf_queue      cap;
+	struct saa7134_pgtable     pt_cap;
+
+	/* vbi capture */
+	struct videobuf_queue      vbi;
+	struct saa7134_pgtable     pt_vbi;
+};
+
+/* oss dsp status */
+struct saa7134_oss {
+        struct semaphore           lock;
+	int                        minor_mixer;
+	int                        minor_dsp;
+	unsigned int               users_dsp;
+
+	/* mixer */
+	enum saa7134_audio_in      input;
+	unsigned int               count;
+	unsigned int               line1;
+	unsigned int               line2;
+
+	/* dsp */
+	unsigned int               afmt;
+	unsigned int               rate;
+	unsigned int               channels;
+	unsigned int               recording_on;
+	unsigned int               dma_running;
+	unsigned int               blocks;
+	unsigned int               blksize;
+	unsigned int               bufsize;
+	struct saa7134_pgtable     pt;
+	struct videobuf_dmabuf     dma;
+	wait_queue_head_t          wq;
+	unsigned int               dma_blk;
+	unsigned int               read_offset;
+	unsigned int               read_count;
+};
+
+/* IR input */
+struct saa7134_ir {
+	struct input_dev           dev;
+	struct ir_input_state      ir;
+	char                       name[32];
+	char                       phys[32];
+	u32                        mask_keycode;
+	u32                        mask_keydown;
+	u32                        mask_keyup;
+        int                        polling;
+        u32                        last_gpio;
+        struct timer_list          timer;
+};
+
+/* ts/mpeg status */
+struct saa7134_ts {
+	/* TS capture */
+	struct saa7134_pgtable     pt_ts;
+	int                        nr_packets;
+	int                        nr_bufs;
+};
+
+/* ts/mpeg ops */
+struct saa7134_mpeg_ops {
+	enum saa7134_mpeg_type     type;
+	struct list_head           next;
+	int                        (*init)(struct saa7134_dev *dev);
+	int                        (*fini)(struct saa7134_dev *dev);
+	void                       (*signal_change)(struct saa7134_dev *dev);
+};
+
+/* global device status */
+struct saa7134_dev {
+	struct list_head           devlist;
+        struct semaphore           lock;
+       	spinlock_t                 slock;
+#ifdef VIDIOC_G_PRIORITY
+	struct v4l2_prio_state     prio;
+#endif
+
+	/* various device info */
+	unsigned int               resources;
+	struct video_device        *video_dev;
+	struct video_device        *radio_dev;
+	struct video_device        *vbi_dev;
+	struct saa7134_oss         oss;
+
+	/* infrared remote */
+	int                        has_remote;
+	struct saa7134_ir          *remote;
+
+	/* pci i/o */
+	char                       name[32];
+	int                        nr;
+	struct pci_dev             *pci;
+	unsigned char              pci_rev,pci_lat;
+	__u32                      __iomem *lmmio;
+	__u8                       __iomem *bmmio;
+
+	/* config info */
+	unsigned int               board;
+	unsigned int               tuner_type;
+	unsigned int               tda9887_conf;
+	unsigned int               gpio_value;
+	unsigned int               irq2_mask;
+
+	/* i2c i/o */
+	struct i2c_adapter         i2c_adap;
+	struct i2c_client          i2c_client;
+	unsigned char              eedata[64];
+
+	/* video overlay */
+	struct v4l2_framebuffer    ovbuf;
+	struct saa7134_format      *ovfmt;
+	unsigned int               ovenable;
+	enum v4l2_field            ovfield;
+
+	/* video+ts+vbi capture */
+	struct saa7134_dmaqueue    video_q;
+	struct saa7134_dmaqueue    vbi_q;
+	unsigned int               video_fieldcount;
+	unsigned int               vbi_fieldcount;
+
+	/* various v4l controls */
+	struct saa7134_tvnorm      *tvnorm;              /* video */
+	struct saa7134_tvaudio     *tvaudio;
+	unsigned int               ctl_input;
+	int                        ctl_bright;
+	int                        ctl_contrast;
+	int                        ctl_hue;
+	int                        ctl_saturation;
+	int                        ctl_freq;
+	int                        ctl_mute;             /* audio */
+	int                        ctl_volume;
+	int                        ctl_invert;           /* private */
+	int                        ctl_mirror;
+	int                        ctl_y_odd;
+	int                        ctl_y_even;
+	int                        ctl_automute;
+
+	/* crop */
+	struct v4l2_rect           crop_bounds;
+	struct v4l2_rect           crop_defrect;
+	struct v4l2_rect           crop_current;
+
+	/* other global state info */
+	unsigned int               automute;
+	struct saa7134_thread      thread;
+	struct saa7134_input       *input;
+	struct saa7134_input       *hw_input;
+	unsigned int               hw_mute;
+	int                        last_carrier;
+	int                        nosignal;
+
+	/* SAA7134_MPEG_* */
+	struct saa7134_ts          ts;
+	struct saa7134_dmaqueue    ts_q;
+	struct saa7134_mpeg_ops    *mops;
+
+	/* SAA7134_MPEG_EMPRESS only */
+	struct video_device        *empress_dev;
+	struct videobuf_queue      empress_tsq;
+	unsigned int               empress_users;
+	struct work_struct         empress_workqueue;
+	int                        empress_started;
+
+	/* SAA7134_MPEG_DVB only */
+	struct videobuf_dvb        dvb;
+};
+
+/* ----------------------------------------------------------- */
+
+#define saa_readl(reg)             readl(dev->lmmio + (reg))
+#define saa_writel(reg,value)      writel((value), dev->lmmio + (reg));
+#define saa_andorl(reg,mask,value) \
+  writel((readl(dev->lmmio+(reg)) & ~(mask)) |\
+  ((value) & (mask)), dev->lmmio+(reg))
+#define saa_setl(reg,bit)          saa_andorl((reg),(bit),(bit))
+#define saa_clearl(reg,bit)        saa_andorl((reg),(bit),0)
+
+#define saa_readb(reg)             readb(dev->bmmio + (reg))
+#define saa_writeb(reg,value)      writeb((value), dev->bmmio + (reg));
+#define saa_andorb(reg,mask,value) \
+  writeb((readb(dev->bmmio+(reg)) & ~(mask)) |\
+  ((value) & (mask)), dev->bmmio+(reg))
+#define saa_setb(reg,bit)          saa_andorb((reg),(bit),(bit))
+#define saa_clearb(reg,bit)        saa_andorb((reg),(bit),0)
+
+#define saa_wait(us) { udelay(us); }
+
+/* ----------------------------------------------------------- */
+/* saa7134-core.c                                              */
+
+extern struct list_head  saa7134_devlist;
+
+void saa7134_print_ioctl(char *name, unsigned int cmd);
+void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
+
+#define SAA7134_PGTABLE_SIZE 4096
+
+int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt);
+int  saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt,
+			   struct scatterlist *list, unsigned int length,
+			   unsigned int startpage);
+void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt);
+
+int saa7134_buffer_count(unsigned int size, unsigned int count);
+int saa7134_buffer_startpage(struct saa7134_buf *buf);
+unsigned long saa7134_buffer_base(struct saa7134_buf *buf);
+
+int saa7134_buffer_queue(struct saa7134_dev *dev, struct saa7134_dmaqueue *q,
+			 struct saa7134_buf *buf);
+void saa7134_buffer_finish(struct saa7134_dev *dev, struct saa7134_dmaqueue *q,
+			   unsigned int state);
+void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q);
+void saa7134_buffer_timeout(unsigned long data);
+void saa7134_dma_free(struct saa7134_dev *dev,struct saa7134_buf *buf);
+
+int saa7134_set_dmabits(struct saa7134_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* saa7134-cards.c                                             */
+
+extern struct saa7134_board saa7134_boards[];
+extern const unsigned int saa7134_bcount;
+extern struct pci_device_id __devinitdata saa7134_pci_tbl[];
+
+extern int saa7134_board_init1(struct saa7134_dev *dev);
+extern int saa7134_board_init2(struct saa7134_dev *dev);
+
+
+/* ----------------------------------------------------------- */
+/* saa7134-i2c.c                                               */
+
+int saa7134_i2c_register(struct saa7134_dev *dev);
+int saa7134_i2c_unregister(struct saa7134_dev *dev);
+void saa7134_i2c_call_clients(struct saa7134_dev *dev,
+			      unsigned int cmd, void *arg);
+
+
+/* ----------------------------------------------------------- */
+/* saa7134-video.c                                             */
+
+extern struct video_device saa7134_video_template;
+extern struct video_device saa7134_radio_template;
+
+int saa7134_common_ioctl(struct saa7134_dev *dev,
+			 unsigned int cmd, void *arg);
+
+int saa7134_video_init1(struct saa7134_dev *dev);
+int saa7134_video_init2(struct saa7134_dev *dev);
+int saa7134_video_fini(struct saa7134_dev *dev);
+void saa7134_irq_video_intl(struct saa7134_dev *dev);
+void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status);
+
+
+/* ----------------------------------------------------------- */
+/* saa7134-ts.c                                                */
+
+#define TS_PACKET_SIZE 188 /* TS packets 188 bytes */
+
+extern struct videobuf_queue_ops saa7134_ts_qops;
+
+int saa7134_ts_init1(struct saa7134_dev *dev);
+int saa7134_ts_fini(struct saa7134_dev *dev);
+void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status);
+
+int saa7134_ts_register(struct saa7134_mpeg_ops *ops);
+void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops);
+
+/* ----------------------------------------------------------- */
+/* saa7134-vbi.c                                               */
+
+extern struct videobuf_queue_ops saa7134_vbi_qops;
+extern struct video_device saa7134_vbi_template;
+
+int saa7134_vbi_init1(struct saa7134_dev *dev);
+int saa7134_vbi_fini(struct saa7134_dev *dev);
+void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status);
+
+
+/* ----------------------------------------------------------- */
+/* saa7134-tvaudio.c                                           */
+
+int saa7134_tvaudio_rx2mode(u32 rx);
+
+void saa7134_tvaudio_setmute(struct saa7134_dev *dev);
+void saa7134_tvaudio_setinput(struct saa7134_dev *dev,
+			      struct saa7134_input *in);
+void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level);
+int saa7134_tvaudio_getstereo(struct saa7134_dev *dev);
+
+int saa7134_tvaudio_init2(struct saa7134_dev *dev);
+int saa7134_tvaudio_fini(struct saa7134_dev *dev);
+int saa7134_tvaudio_do_scan(struct saa7134_dev *dev);
+
+int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value);
+
+/* ----------------------------------------------------------- */
+/* saa7134-oss.c                                               */
+
+extern struct file_operations saa7134_dsp_fops;
+extern struct file_operations saa7134_mixer_fops;
+
+int saa7134_oss_init1(struct saa7134_dev *dev);
+int saa7134_oss_fini(struct saa7134_dev *dev);
+void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status);
+
+/* ----------------------------------------------------------- */
+/* saa7134-input.c                                             */
+
+int  saa7134_input_init1(struct saa7134_dev *dev);
+void saa7134_input_fini(struct saa7134_dev *dev);
+void saa7134_input_irq(struct saa7134_dev *dev);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */