diff -urN video4linux-20040826-105939/doc/README.saa7134.oss video4linux-20040826-105939.monstertv.1/doc/README.saa7134.oss
--- video4linux-20040826-105939/doc/README.saa7134.oss	1970-01-01 09:00:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/doc/README.saa7134.oss	2004-08-29 15:04:11.000000000 +0900
@@ -0,0 +1,10 @@
+Synopsys:
+ Now,OSS driver for SAA7134 seems to be imcomplete.
+ When using OSS-SAA7134 (i.e. MythTv),you should do when update driver.
+ 1. Compile,install driver.
+ 2. run ./u script (module parameter: oss=1 oss_rate=32000 good).
+ 3. run ./test-oss script,and press ^C.
+ 4. run anything using OSS-SAA7134 (typically /dev/dsp1).
+ 
+Good Luck!
+ Artane.
diff -urN video4linux-20040826-105939/doc/insmod-options video4linux-20040826-105939.monstertv.1/doc/insmod-options
--- video4linux-20040826-105939/doc/insmod-options	2004-02-22 10:59:36.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/doc/insmod-options	2004-08-29 15:04:11.000000000 +0900
@@ -130,6 +130,14 @@
 	  card=65 (FlyVideo 2000S) - set AMSEL=1 or AMSEL=0
 	  card=72 (Prolink PV-BT878P rev.9B) - set AMSEL=0 only
 
+        insmod args for MSP3445G:
+                msp3445 = n   Select TV Standard for SKNet MONSTER TV[1|2].
+		              n = 1 : EIA-J Two Carrier FM (Japan Only)
+			          x : Not implement yet. Please Help!
+				  
+		
+		debug = 1	print debug messages
+
 msp3400.o
 	The driver for the msp34xx sound processor chips. If you have a
 	stereo card, you probably want to insmod this one.
diff -urN video4linux-20040826-105939/id.h video4linux-20040826-105939.monstertv.1/id.h
--- video4linux-20040826-105939/id.h	2004-07-30 23:07:01.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/id.h	2004-08-29 15:04:11.000000000 +0900
@@ -30,6 +30,9 @@
 #ifndef  I2C_DRIVERID_SAA6752HS
 # define I2C_DRIVERID_SAA6752HS I2C_DRIVERID_EXP0+8
 #endif
+#ifndef  I2C_DRIVERID_MSP3445
+# define I2C_DRIVERID_MSP3445 I2C_DRIVERID_EXP0+9
+#endif
 
 /* algorithms */
 #ifndef I2C_ALGO_SAA7134
diff -urN video4linux-20040826-105939/msp34x5.h video4linux-20040826-105939.monstertv.1/msp34x5.h
--- video4linux-20040826-105939/msp34x5.h	1970-01-01 09:00:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/msp34x5.h	2004-08-29 15:04:11.000000000 +0900
@@ -0,0 +1,37 @@
+/*
+ * Header for MICRONAS MSP34x5
+ * Modify FROM msp3400 driver @ v2.4.20pre6 
+ * 2002-09-15 K.Ohta
+ */
+#ifndef MSP34x5_H
+#define MSP34x5_H
+
+/* ---------------------------------------------------------------------- */
+
+struct msp_dfpreg {
+    int reg;
+    int value;
+};
+
+#define MSP_SET_DFPREG     _IOW('m',15,struct msp_dfpreg)
+#define MSP_GET_DFPREG     _IOW('m',16,struct msp_dfpreg)
+#define MSP_AUDC_SET_INPUT -1 /* Temporally value 20030325 K.O */
+#define MSP_AUDC_SET_RADIO -2 /* Temporally value 20030325 K.O */
+
+#define MSP_FLAG_NORM      0
+#define MSP_FLAG_EIAJ      1
+#define MSP_FLAG_KOREA     2
+/* After 0.2.7+2.4.21pre6 */
+static inline int MAX(int a,int b)
+{
+   if(a>b) return a;
+   return b;
+}
+
+static inline int MIN(int a,int b)
+{
+   if(a<b) return a;
+   return b;
+}
+
+#endif /* MSP34x5_H */
diff -urN video4linux-20040826-105939/saa7134-cards.c video4linux-20040826-105939.monstertv.1/saa7134-cards.c
--- video4linux-20040826-105939/saa7134-cards.c	2004-08-23 20:07:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/saa7134-cards.c	2004-08-29 15:04:11.000000000 +0900
@@ -204,11 +204,12 @@
                /* "K.Ohta" <alpha292@bremen.or.jp> */
                .name           = "SKNet Monster TV",
                .audio_clock    = 0x00187de7,
-               .tuner_type     = TUNER_PHILIPS_NTSC_M,
+               .tuner_type     = TUNER_PHILIPS_FM1236_MK3,
+	       .needs_tvaudio  = 1, /* 20040105 K.Ohta */
                .inputs         = {{
                        .name = name_tv,
                        .vmux = 1,
-                       .amux = TV,
+                       .amux = LINE2,
                        .tv   = 1,
                },{
                        .name = name_comp1,
@@ -950,6 +951,31 @@
 			.name = name_comp1,
 			.vmux = 3,
 		}},
+          },[SAA7134_BOARD_MONSTERTV2] = {
+                  /* K.Ohta : Thanx to http://pc.2ch.net/linux/1017186805/184 */
+                  .name           = "SKNet Monster TV2",
+                  .audio_clock    = 0x00187de7,
+                  .tuner_type     = TUNER_PHILIPS_FM1236_MK3,
+   	          .needs_tvaudio  = 1, /* 20040105 K.Ohta */
+                  .inputs         = {{
+                          .name = name_tv,
+                          .vmux = 1,
+                          .amux = LINE2,
+                          .tv   = 1,
+                  },{
+                          .name = name_comp1,
+                          .vmux = 0,
+                          .amux = LINE1,
+                  },{
+                          .name = name_svideo,
+                          .vmux = 8,
+                          .amux = LINE1,
+                  }},
+                  .radio = {
+                          .name = name_radio,
+                          .amux = LINE2,
+                  },
+	   
 	},
         [SAA7134_BOARD_NOVAC_PRIMETV7133] = {
                 /* toshii@netbsd.org */
@@ -1345,6 +1371,12 @@
                 .subdevice    = PCI_ANY_ID,
 		.driver_data  = SAA7134_BOARD_UNKNOWN,
 	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS, /* Add 20040101 */
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+                .subvendor    = 0x1131,
+                .subdevice    = 0x4f4d,
+		.driver_data  = SAA7134_BOARD_MONSTERTV2,
+        },{
 		/* --- end of list --- */
 	}
 };
diff -urN video4linux-20040826-105939/saa7134-cards.c.orig video4linux-20040826-105939.monstertv.1/saa7134-cards.c.orig
--- video4linux-20040826-105939/saa7134-cards.c.orig	1970-01-01 09:00:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/saa7134-cards.c.orig	2004-08-23 20:07:00.000000000 +0900
@@ -0,0 +1,1443 @@
+/*
+ * 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] = {
+		/* "Arnaud Quette" <aquette@free.fr> */
+		.name           = "LifeView FlyTV Platinum",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_SECAM,
+		.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_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,
+		},
+		.has_ts    = 1,
+		.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,
+		},
+		.has_ts		= 1,
+		.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,
+                .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,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 0,
+			.amux   = LINE2,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE2,
+		}},
+		.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,
+                },
+	},
+	[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,
+		}},
+		.has_ts    = 1,
+		.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_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 = LINE2,
+			.tv   = 1,
+		}},
+		.has_ts    = 1,
+		.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,
+                .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,
+		},
+	},
+	[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,
+		}},
+	},
+        [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_305] = {
+		.name           = "AverMedia 305",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.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,
+			.gpio = 0x0000,
+			.tv   = 1,
+		}},
+		.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,
+                        .tv   = 1,
+			.gpio = 0x00080
+                }},
+		.radio = {
+			 .name = name_radio,
+			 .amux = LINE2,
+			.gpio = 0x80000
+		 },
+		.mute = {
+			.name = name_mute,
+                        .amux = LINE2,
+			.gpio = 0x40000,
+		},
+        },
+};
+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    = 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,
+		.driver_data  = SAA7134_BOARD_FLYTVPLATINUM,
+        },{
+		.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_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_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_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,
+        },{
+		/* 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    = 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,
+		
+ 	},{
+		/* --- 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_init(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;
+		/* fall throuth */
+	case SAA7134_BOARD_FLYTVPLATINUM:
+		board_flyvideo(dev);
+		break;
+	case SAA7134_BOARD_CINERGY400:
+	case SAA7134_BOARD_CINERGY600:
+	case SAA7134_BOARD_ECS_TVP3XP:
+	case SAA7134_BOARD_ECS_TVP3XP_4CB5:
+		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;
+	}
+	return 0;
+}
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -urN video4linux-20040826-105939/saa7134-core.c video4linux-20040826-105939.monstertv.1/saa7134-core.c
--- video4linux-20040826-105939/saa7134-core.c	2004-08-26 01:07:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/saa7134-core.c	2004-08-29 15:04:24.000000000 +0900
@@ -926,6 +926,8 @@
 		request_module("tda9887");
   	if (card_has_ts(dev))
 		request_module("saa6752hs");
+	if (saa7134_boards[dev->board].needs_tvaudio) /* 20040105 K.Ohta */
+		request_module("tvaudio");
 
 #ifdef VIDIOC_G_PRIORITY
 	v4l2_prio_init(&dev->prio);
diff -urN video4linux-20040826-105939/saa7134-core.c.orig video4linux-20040826-105939.monstertv.1/saa7134-core.c.orig
--- video4linux-20040826-105939/saa7134-core.c.orig	1970-01-01 09:00:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/saa7134-core.c.orig	2004-08-29 15:04:24.000000000 +0900
@@ -0,0 +1,1120 @@
+/*
+ * 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/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/kmod.h>
+#include <linux/sound.h>
+#include <linux/interrupt.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");
+
+#define SAA7134_MAXBOARDS 8
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int irq_debug = 0;
+MODULE_PARM(irq_debug,"i");
+MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]");
+
+static unsigned int core_debug = 0;
+MODULE_PARM(core_debug,"i");
+MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
+
+static unsigned int gpio_tracking = 0;
+MODULE_PARM(gpio_tracking,"i");
+MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]");
+
+static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+MODULE_PARM(video_nr,"1-" __stringify(SAA7134_MAXBOARDS) "i");
+MODULE_PARM_DESC(video_nr,"video device number");
+
+static unsigned int ts_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+MODULE_PARM(ts_nr,"1-" __stringify(SAA7134_MAXBOARDS) "i");
+MODULE_PARM_DESC(ts_nr,"ts device number");
+
+static unsigned int vbi_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+MODULE_PARM(vbi_nr,"1-" __stringify(SAA7134_MAXBOARDS) "i");
+MODULE_PARM_DESC(vbi_nr,"vbi device number");
+
+static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+MODULE_PARM(radio_nr,"1-" __stringify(SAA7134_MAXBOARDS) "i");
+MODULE_PARM_DESC(radio_nr,"radio device number");
+
+static unsigned int oss = 0;
+MODULE_PARM(oss,"i");
+MODULE_PARM_DESC(oss,"register oss devices (default: no)");
+
+static unsigned int dsp_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+MODULE_PARM(dsp_nr,"1-" __stringify(SAA7134_MAXBOARDS) "i");
+MODULE_PARM_DESC(dsp_nr,"oss dsp device number");
+
+static unsigned int mixer_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+MODULE_PARM(mixer_nr,"1-" __stringify(SAA7134_MAXBOARDS) "i");
+MODULE_PARM_DESC(mixer_nr,"oss mixer device number");
+
+static unsigned int tuner[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+MODULE_PARM(tuner,"1-" __stringify(SAA7134_MAXBOARDS) "i");
+MODULE_PARM_DESC(tuner,"tuner type");
+
+static unsigned int card[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+MODULE_PARM(card,"1-" __stringify(SAA7134_MAXBOARDS) "i");
+MODULE_PARM_DESC(card,"card type");
+
+static unsigned int latency = UNSET;
+MODULE_PARM(latency,"i");
+MODULE_PARM_DESC(latency,"pci latency timer");
+
+struct list_head  saa7134_devlist;
+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
+
+/* ------------------------------------------------------------------ */
+
+/* nr of (saa7134-)pages for the given buffer size */
+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;
+#if DEBUG_SPINLOCKS
+	BUG_ON(!spin_is_locked(&dev->slock));
+#endif
+	
+	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)
+{
+#if DEBUG_SPINLOCKS
+	BUG_ON(!spin_is_locked(&dev->slock));
+#endif
+	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;
+
+#if DEBUG_SPINLOCKS
+	BUG_ON(!spin_is_locked(&dev->slock));
+#endif
+	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;
+
+#if DEBUG_SPINLOCKS
+	BUG_ON(!spin_is_locked(&dev->slock));
+#endif
+
+	/* 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_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_ts(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 {
+			/* 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);
+	dev->slock = SPIN_LOCK_UNLOCKED;
+
+	saa7134_track_gpio(dev,"pre-init");
+	saa7134_video_init1(dev);
+	saa7134_vbi_init1(dev);
+	if (card_has_ts(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,
+		   SAA7134_IRQ2_INTE_GPIO18  |
+		   SAA7134_IRQ2_INTE_GPIO18A |
+		   SAA7134_IRQ2_INTE_GPIO16  |
+		   SAA7134_IRQ2_INTE_SC2     |
+		   SAA7134_IRQ2_INTE_SC1     |
+		   SAA7134_IRQ2_INTE_SC0     |
+		   /* SAA7134_IRQ2_INTE_DEC5    |  FIXME: TRIG_ERR ??? */
+		   SAA7134_IRQ2_INTE_DEC3    |
+		   SAA7134_IRQ2_INTE_DEC2    |
+		   /* SAA7134_IRQ2_INTE_DEC1    | */
+		   SAA7134_IRQ2_INTE_DEC0    |
+		   SAA7134_IRQ2_INTE_PE      |
+		   SAA7134_IRQ2_INTE_AR);
+
+	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_ts(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;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	vfd->dev     = &dev->pci->dev;
+	vfd->release = video_device_release;
+#endif
+	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->ts_dev) {
+		if (-1 != dev->ts_dev->minor)
+			video_unregister_device(dev->ts_dev);
+		else
+			video_device_release(dev->ts_dev);
+		dev->ts_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 int __devinit saa7134_initdev(struct pci_dev *pci_dev,
+				     const struct pci_device_id *pci_id)
+{
+	struct saa7134_dev *dev;
+	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;
+	}
+	sprintf(dev->name,"saa%x[%d]",pci_dev->device,saa7134_devcount);
+
+	/* 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[saa7134_devcount] >= 0 &&
+	    card[saa7134_devcount] < saa7134_bcount)
+		dev->board = card[saa7134_devcount];
+	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[saa7134_devcount])
+		dev->tuner_type = tuner[saa7134_devcount];
+        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[saa7134_devcount] == 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*)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 */
+	saa7134_board_init(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 */
+	set_current_state(TASK_INTERRUPTIBLE);
+	schedule_timeout(HZ/10);
+	saa7134_i2c_register(dev);
+
+	/* initialize hardware #2 */
+	saa7134_hwinit2(dev);
+
+	/* load i2c helpers */
+	if (TUNER_ABSENT != dev->tuner_type)
+		request_module("tuner");
+	if (dev->tda9887_conf)
+		request_module("tda9887");
+  	if (card_has_ts(dev))
+		request_module("saa6752hs");
+
+#ifdef VIDIOC_G_PRIORITY
+	v4l2_prio_init(&dev->prio);
+#endif
+
+	/* 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[saa7134_devcount]);
+	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);
+
+	if (card_has_ts(dev)) {
+		dev->ts_dev = vdev_init(dev,&saa7134_ts_template,"ts");
+		err = video_register_device(dev->ts_dev,VFL_TYPE_GRABBER,
+					    ts_nr[saa7134_devcount]);
+		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 [ts]\n",
+		       dev->name,dev->ts_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[saa7134_devcount]);
+	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[saa7134_devcount]);
+		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[saa7134_devcount]);
+			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[saa7134_devcount]);
+			if (err < 0)
+				goto fail5;
+			printk(KERN_INFO "%s: registered device mixer%d\n",
+			       dev->name,dev->oss.minor_mixer >> 4);
+		}
+		break;
+	}
+
+	/* everything worked */
+	list_add_tail(&dev->devlist,&saa7134_devlist);
+	pci_set_drvdata(pci_dev,dev);
+	saa7134_devcount++;
+	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);
+
+	/* 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 */
+	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 */
+	list_del(&dev->devlist);
+	saa7134_devcount--;
+	kfree(dev);
+}
+
+static struct pci_driver saa7134_pci_driver = {
+        .name     = "saa7134",
+        .id_table = saa7134_pci_tbl,
+        .probe    = saa7134_initdev,
+        .remove   = 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)
+{
+	pci_unregister_driver(&saa7134_pci_driver);
+}
+
+module_init(saa7134_init);
+module_exit(saa7134_fini);
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -urN video4linux-20040826-105939/saa7134-input.c video4linux-20040826-105939.monstertv.1/saa7134-input.c
--- video4linux-20040826-105939/saa7134-input.c	2004-05-24 22:07:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/saa7134-input.c	2004-08-29 15:04:24.000000000 +0900
@@ -116,28 +116,29 @@
 static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = {
         [ 18 ] = KEY_POWER,
         [  1 ] = KEY_TV,             // DVR
+#if 0
         [ 21 ] = KEY_DVD,            // DVD
         [ 23 ] = KEY_AUDIO,          // music
-                                     // DVR mode / DVD mode / music mode
+#endif                               // DVR mode / DVD mode / music mode
 
         [ 27 ] = KEY_MUTE,           // mute
         [  2 ] = KEY_LANGUAGE,       // MTS/SAP / audio / autoseek
-        [ 30 ] = KEY_SUBTITLE,       // closed captioning / subtitle / seek
+//        [ 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
+//        [ 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
+//        [ 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
+//	[  4 ] = KEY_RIGHT,          // right
+//	[  3 ] = KEY_SELECT,         // select
 
 	[ 31 ] = KEY_REWIND,         // rewind
 	[ 32 ] = KEY_PLAYPAUSE,      // play/pause
@@ -146,7 +147,7 @@
 	[ 43 ] = KEY_RECORD,         // recording
 	[ 44 ] = KEY_STOP,           // stop
 	[ 45 ] = KEY_PLAY,           // play
-	[ 46 ] = KEY_SHUFFLE,        // snapshot / shuffle
+//	[ 46 ] = KEY_SHUFFLE,        // snapshot / shuffle
 
         [  0 ] = KEY_KP0,
         [  5 ] = KEY_KP1,
diff -urN video4linux-20040826-105939/saa7134-input.c.orig video4linux-20040826-105939.monstertv.1/saa7134-input.c.orig
--- video4linux-20040826-105939/saa7134-input.c.orig	1970-01-01 09:00:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/saa7134-input.c.orig	2004-08-29 15:04:24.000000000 +0900
@@ -0,0 +1,376 @@
+/*
+ * 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/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_PARM(disable_ir,"i");
+MODULE_PARM_DESC(disable_ir,"disable infrared remote support");
+
+static unsigned int ir_debug = 0;
+MODULE_PARM(ir_debug,"i");
+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
+};
+/* ---------------------------------------------------------------------- */
+
+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:
+		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;
+	}
+	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;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	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;
+	}
+#endif
+
+	/* 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 -urN video4linux-20040826-105939/saa7134-tvaudio.c video4linux-20040826-105939.monstertv.1/saa7134-tvaudio.c
--- video4linux-20040826-105939/saa7134-tvaudio.c	2004-07-14 21:27:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/saa7134-tvaudio.c	2004-08-29 15:04:24.000000000 +0900
@@ -154,7 +154,14 @@
 		.carr1         = 4500,
 		.carr2         = 4724,
 		.mode          = TVAUDIO_FM_K_STEREO,
+	},{
+		.name          = "NTSC-EIAJ FM-stereo",
+		.std           = V4L2_STD_NTSC,
+		.carr1         = 4500,
+		.carr2         = 4500,
+		.mode          = TVAUDIO_FM_EIAJ_STEREO,
 	}
+
 };
 #define TVAUDIO (sizeof(tvaudio)/sizeof(struct saa7134_tvaudio))
 
@@ -315,6 +322,13 @@
 	case TVAUDIO_FM_SAT_STEREO:
 		/* not implemented (yet) */
 		break;
+	case TVAUDIO_FM_EIAJ_STEREO: /* Temporally */
+		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;	   
 	}
 }
 
@@ -404,7 +418,9 @@
 {
 	__u32 idp,nicam;
 	int retval = -1;
-	
+        struct video_audio u;
+   
+        /* Normal */
 	switch (audio->mode) {
 	case TVAUDIO_FM_MONO:
 		return V4L2_TUNER_SUB_MONO;
@@ -438,6 +454,9 @@
 			break;
 		}
 		break;
+	 case TVAUDIO_FM_EIAJ_STEREO:
+	   /* Not Implemented Yet. */
+	   break;
 	}
 	if (retval != -1)
 		dprintk("found audio subchannels:%s%s%s%s\n",
@@ -481,6 +500,9 @@
 	case TVAUDIO_NICAM_FM:
 		/* FIXME */
 		break;
+	 case TVAUDIO_FM_EIAJ_STEREO: /* 20040105 K.Ohta */
+	   /* Not Implemented Yet. */
+	   break;
 	}
 	return 0;
 }
diff -urN video4linux-20040826-105939/saa7134-video.c video4linux-20040826-105939.monstertv.1/saa7134-video.c
--- video4linux-20040826-105939/saa7134-video.c	2004-08-26 01:07:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/saa7134-video.c	2004-08-29 15:04:24.000000000 +0900
@@ -1796,7 +1796,7 @@
 		dev->crop_current = crop->c;
 		return 0;
 	}
-
+	
 	/* --- tuner ioctls ------------------------------------------ */
 	case VIDIOC_G_TUNER:
 	{
@@ -1815,9 +1815,8 @@
 				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);
+			   t->rxsubchans = saa7134_tvaudio_getstereo(dev);
+			   t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans);	
 		}
 		if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03))
 			t->signal = 0xffff;
@@ -1826,12 +1825,14 @@
 	case VIDIOC_S_TUNER:
 	{
 		struct v4l2_tuner *t = arg;
+	        struct video_audio u;
 		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;
@@ -1877,17 +1878,50 @@
 	case VIDIOC_G_CTRL:
 	case VIDIOC_S_CTRL:
 		return saa7134_common_ioctl(dev, cmd, arg);
+	/* Add VIDIOC_S_MODULATOR  20040118 K.O */ 
+	case VIDIOC_S_MODULATOR:
+	{
+	        /* WRAPPER...SHOULD BE REPLACE VIDIOCSMODULATOR */
+	        struct v4l2_modulator *a=arg;
+	        struct video_audio t;
+	        memset(&t,0,sizeof(t));
+	        strcpy(t.name,"modulator");
+	        t.mode = (__u16)((a->txsubchans)%65536); /* right cast?*/
+	        saa7134_i2c_call_clients(dev,VIDIOCSAUDIO,&t);
+	        return 0;
+	}
+	/* Add VIDIOC_S_MODULATOR  20040118 K.O */ 
+	case VIDIOC_G_MODULATOR:
+	{
+	        /* WRAPPER */
+	        struct v4l2_modulator *a=arg;
+	        struct video_audio t;
+	        saa7134_i2c_call_clients(dev,VIDIOCGAUDIO,&t);
+		memset(a,0,sizeof(*a));
+		strcpy(a->name,"audio");
+	        a->txsubchans=(__u32)(t.mode);
+	        return 0;
 
+	}
+	   
 	case VIDIOC_G_AUDIO:
 	{
 		struct v4l2_audio *a = arg;
-
+	        struct video_audio t;
+	        saa7134_i2c_call_clients(dev,VIDIOCGAUDIO,&t);
 		memset(a,0,sizeof(*a));
 		strcpy(a->name,"audio");
+	        /* SET MPX MODE WAS MOVED TO MODULATOR */
 		return 0;
 	}
 	case VIDIOC_S_AUDIO:
-		return 0;
+	{
+	       struct video_audio t;
+	       memcpy(&t,arg,sizeof(t));
+               /* SET MPX MODE WAS MOVED TO MODULATOR */
+	       saa7134_i2c_call_clients(dev,VIDIOCSAUDIO,&t);
+	       return 0;
+	}
         case VIDIOC_G_PARM:
         {
                 struct v4l2_captureparm *parm = arg;
diff -urN video4linux-20040826-105939/saa7134-video.c.orig video4linux-20040826-105939.monstertv.1/saa7134-video.c.orig
--- video4linux-20040826-105939/saa7134-video.c.orig	1970-01-01 09:00:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/saa7134-video.c.orig	2004-08-29 15:04:24.000000000 +0900
@@ -0,0 +1,2379 @@
+/*
+ * 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/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_PARM(video_debug,"i");
+MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
+MODULE_PARM(gbuffers,"i");
+MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32");
+MODULE_PARM(noninterlaced,"i");
+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,
+
+	}
+};
+#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,nosignal;
+
+	dprintk("set tv norm = %s\n",norm->name);
+	dev->tvnorm = norm;
+        nosignal = (0 == (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03));
+
+	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 || 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 file *file, struct videobuf_buffer *vb,
+			  enum v4l2_field field)
+{
+	struct saa7134_fh *fh = file->private_data;
+	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_buf *buf = (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 file *file, unsigned int *count, unsigned int *size)
+{
+	struct saa7134_fh *fh = file->private_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 file *file, struct videobuf_buffer *vb)
+{
+	struct saa7134_fh *fh = file->private_data;
+	struct saa7134_buf *buf = (struct saa7134_buf *)vb;
+	
+	saa7134_buffer_queue(fh->dev,&fh->dev->video_q,buf);
+}
+
+static void buffer_release(struct file *file, struct videobuf_buffer *vb)
+{
+	struct saa7134_fh *fh = file->private_data;
+	struct saa7134_buf *buf = (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;
+#ifdef VIDIOC_G_PRIORITY
+	v4l2_prio_open(&dev->prio,&fh->prio);
+#endif
+
+	videobuf_queue_init(&fh->cap, &video_qops,
+			    dev->pci, &dev->slock,
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			    V4L2_FIELD_INTERLACED,
+			    sizeof(struct saa7134_buf));
+	init_MUTEX(&fh->cap.lock);
+	saa7134_pgtable_alloc(dev->pci,&fh->pt_cap);
+
+	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));
+        init_MUTEX(&fh->vbi.lock);
+	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 *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(file, saa7134_queue(fh),
+					 data, count, ppos);
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		if (!res_get(fh->dev,fh,RESOURCE_VBI))
+			return -EBUSY;
+		return videobuf_read_stream(file, saa7134_queue(fh),
+					    data, count, ppos, 1);
+		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(file,fh->cap.read_buf,fh->cap.field)) {
+                                up(&fh->cap.lock);
+                                return POLLERR;
+                        }
+                        fh->cap.ops->buf_queue(file,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(file,&fh->cap);
+		res_free(dev,fh,RESOURCE_VIDEO);
+	}
+	if (fh->cap.read_buf) {
+		buffer_release(file,fh->cap.read_buf);
+		kfree(fh->cap.read_buf);
+	}
+
+	/* stop vbi capture */
+	if (res_check(fh, RESOURCE_VBI)) {
+		if (fh->vbi.streaming)
+			videobuf_streamoff(file,&fh->vbi);
+		if (fh->vbi.reading)
+			videobuf_read_stop(file,&fh->vbi);
+		res_free(dev,fh,RESOURCE_VBI);
+	}
+
+	saa7134_pgtable_free(dev->pci,&fh->pt_cap);
+	saa7134_pgtable_free(dev->pci,&fh->pt_vbi);
+
+#ifdef VIDIOC_G_PRIORITY
+	v4l2_prio_close(&dev->prio,&fh->prio);
+#endif
+	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(vma,saa7134_queue(fh));
+}
+
+/* ------------------------------------------------------------------ */
+
+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
+}
+
+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;
+	}
+}
+
+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.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;
+	}
+}
+
+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;
+}
+
+/*
+ * 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);
+
+#ifdef VIDIOC_G_PRIORITY
+	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;
+	}
+#endif
+
+	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;
+        }
+
+#ifdef VIDIOC_G_PRIORITY
+        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);
+        }
+#endif
+
+	/* --- 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(file,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(file,saa7134_queue(fh),arg);
+
+	case VIDIOC_QUERYBUF:
+		return videobuf_querybuf(saa7134_queue(fh),arg);
+
+	case VIDIOC_QBUF:
+		return videobuf_qbuf(file,saa7134_queue(fh),arg);
+
+	case VIDIOC_DQBUF:
+		return videobuf_dqbuf(file,saa7134_queue(fh),arg);
+
+	case VIDIOC_STREAMON:
+	{
+		int res = saa7134_resource(fh);
+
+                if (!res_get(dev,fh,res))
+			return -EBUSY;
+		return videobuf_streamon(file,saa7134_queue(fh));
+	}
+	case VIDIOC_STREAMOFF:
+	{
+		int res = saa7134_resource(fh);
+
+		err = videobuf_streamoff(file,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       = 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", "found NTSC", "found PAL", "found SECAM" };
+	int norm;
+
+	norm = saa_readb(SAA7134_STATUS_VIDEO1) & 0x03;
+	dprintk("DCSDT: %s\n",st[norm]);
+	
+	if (0 != norm) {
+		/* wake up tvaudio audio carrier scan thread */
+		saa7134_tvaudio_do_scan(dev);
+		if (!noninterlaced)
+			saa_clearb(SAA7134_SYNC_CTRL, 0x20);
+	} else {
+		/* no video signal -> mute audio */
+		if (dev->ctl_automute)
+			dev->automute = 1;
+		saa7134_tvaudio_setmute(dev);
+		saa_setb(SAA7134_SYNC_CTRL, 0x20);
+	}
+}
+
+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 -urN video4linux-20040826-105939/saa7134.h video4linux-20040826-105939.monstertv.1/saa7134.h
--- video4linux-20040826-105939/saa7134.h	2004-08-23 20:07:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/saa7134.h	2004-08-29 15:05:40.000000000 +0900
@@ -74,6 +74,7 @@
 	TVAUDIO_FM_K_STEREO   = 4,
 	TVAUDIO_NICAM_AM      = 5,
 	TVAUDIO_NICAM_FM      = 6,
+        TVAUDIO_FM_EIAJ_STEREO= 7, /* Add 20040101 K.Ohta */
 };
 
 enum saa7134_audio_in {
@@ -178,6 +179,7 @@
 #define SAA7134_BOARD_CINERGY200       38
 #define SAA7134_BOARD_FLYTVPLATINUM    39
 #define SAA7134_BOARD_VIDEOMATE_TV_PVR 40
+#define SAA7134_BOARD_MONSTERTV2       41 /* Add: 2004.01.01 Pls.Test! */
 
 #define SAA7134_INPUT_MAX 8
 
@@ -202,7 +204,8 @@
 	/* peripheral I/O */
 	unsigned int            has_ts;
 	enum saa7134_video_out  video_out;
-
+        unsigned int            needs_tvaudio:1;
+   
 	/* i2c chip info */
 	unsigned int            tuner_type;
 	unsigned int            tda9887_conf;
diff -urN video4linux-20040826-105939/saa7134.h.orig video4linux-20040826-105939.monstertv.1/saa7134.h.orig
--- video4linux-20040826-105939/saa7134.h.orig	1970-01-01 09:00:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/saa7134.h.orig	2004-08-23 20:07:00.000000000 +0900
@@ -0,0 +1,582 @@
+/*
+ * 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>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,64)
+#include "video-buf.h"
+#include "tuner.h"
+#include "audiochip.h"
+#include "id.h"
+#include "i2c-compat.h"
+#include "ir-common.h"
+#else
+#include <media/video-buf.h>
+#include <media/tuner.h>
+#include <media/audiochip.h>
+#include <media/id.h>
+#include <media/ir-common.h>
+#endif
+#include "compat.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 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
+# define minor(x) MINOR(x)
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+# define need_resched() (current->need_resched)
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
+# define BUG_ON(condition) do { if ((condition)!=0) BUG(); } while(0)
+#endif
+
+/* ----------------------------------------------------------- */
+/* 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,
+};
+
+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_305    35
+#define SAA7133_BOARD_UPMOST_PURPLE_TV 36
+#define SAA7134_BOARD_ITEMS_MTV005     37
+#define SAA7134_BOARD_CINERGY200       38
+#define SAA7134_BOARD_FLYTVPLATINUM    39
+#define SAA7134_BOARD_VIDEOMATE_TV_PVR 40
+
+#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;
+};
+
+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;
+	
+	/* peripheral I/O */
+	unsigned int            has_ts;
+	enum saa7134_video_out  video_out;
+
+	/* i2c chip info */
+	unsigned int            tuner_type;
+	unsigned int            tda9887_conf;
+};
+
+#define card_has_radio(dev)   (NULL != saa7134_boards[dev->board].radio.name)
+#define card_has_ts(dev)      (saa7134_boards[dev->board].has_ts)
+#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;
+};
+
+/* TS status */
+struct saa7134_ts {
+	unsigned int               users;
+
+	/* TS capture */
+	struct videobuf_queue      ts;
+	struct saa7134_pgtable     pt_ts;
+	int			   started;
+};
+
+/* 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;
+};
+
+/* 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        *ts_dev;
+	struct video_device        *radio_dev;
+	struct video_device        *vbi_dev;
+	struct saa7134_oss         oss;
+	struct saa7134_ts          ts;
+
+	/* infrared remote */
+	int                        has_remote;
+	struct saa7134_ir          *remote;
+
+	/* pci i/o */
+	char                       name[32];
+	struct pci_dev             *pci;
+	unsigned char              pci_rev,pci_lat;
+	__u32                      *lmmio;
+	__u8                       *bmmio;
+
+	/* config info */
+	unsigned int               board;
+	unsigned int               tuner_type;
+	unsigned int               tda9887_conf;
+	unsigned int               gpio_value;
+
+	/* 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    ts_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;
+};
+
+/* ----------------------------------------------------------- */
+
+#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(d) { udelay(d); }
+
+/* ----------------------------------------------------------- */
+/* saa7134-core.c                                              */
+
+extern struct list_head  saa7134_devlist;
+extern unsigned int      saa7134_devcount;
+
+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_init(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                                                */
+
+extern struct video_device saa7134_ts_template;
+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);
+
+
+/* ----------------------------------------------------------- */
+/* 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:
+ */
diff -urN video4linux-20040826-105939/scripts/CVS/Entries.rej video4linux-20040826-105939.monstertv.1/scripts/CVS/Entries.rej
--- video4linux-20040826-105939/scripts/CVS/Entries.rej	1970-01-01 09:00:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/scripts/CVS/Entries.rej	2004-08-29 15:04:31.000000000 +0900
@@ -0,0 +1,12 @@
+***************
+*** 0 ****
+--- 1,9 ----
++ /cardlist/1.1.1.1/Sun Feb 22 01:59:36 2004//
++ /config.bttv/1.1.1.1/Sun Feb 22 01:59:36 2004//
++ /config.cx88/1.1.1.1/Sun Feb 22 01:59:36 2004//
++ /config.saa7134/1.1.1.1/Sun Feb 22 01:59:36 2004//
++ /modules.sh/1.1.1.1/Sun Feb 22 01:59:36 2004//
++ /release.sh/1.2/Tue Feb 24 11:03:00 2004//
++ /saa7134.pl/1.2/Fri Mar  5 14:04:57 2004//
++ /update/1.3/Tue Mar 16 10:05:35 2004//
++ D
diff -urN video4linux-20040826-105939/scripts/CVS/Repository.rej video4linux-20040826-105939.monstertv.1/scripts/CVS/Repository.rej
--- video4linux-20040826-105939/scripts/CVS/Repository.rej	1970-01-01 09:00:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/scripts/CVS/Repository.rej	2004-08-29 15:04:31.000000000 +0900
@@ -0,0 +1,4 @@
+***************
+*** 0 ****
+--- 1 ----
++ video4linux/scripts
diff -urN video4linux-20040826-105939/scripts/CVS/Root.rej video4linux-20040826-105939.monstertv.1/scripts/CVS/Root.rej
--- video4linux-20040826-105939/scripts/CVS/Root.rej	1970-01-01 09:00:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/scripts/CVS/Root.rej	2004-08-29 15:04:31.000000000 +0900
@@ -0,0 +1,4 @@
+***************
+*** 0 ****
+--- 1 ----
++ :ext:kraxel@cvs.bytesex.org/home/cvsroot
diff -urN video4linux-20040826-105939/scripts/modules.sh video4linux-20040826-105939.monstertv.1/scripts/modules.sh
--- video4linux-20040826-105939/scripts/modules.sh	2004-02-22 10:59:36.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/scripts/modules.sh	2004-08-29 15:04:31.000000000 +0900
@@ -41,7 +41,7 @@
 }
 
 function v4l2basic() {
-	for module in	i2c-core i2c-algo-bit			\
+	for module in				\
 			videodev v4l2-common v4l1-compat	\
 			video-buf				\
 			soundcore
diff -urN video4linux-20040826-105939/scripts/update video4linux-20040826-105939.monstertv.1/scripts/update
--- video4linux-20040826-105939/scripts/update	2004-08-26 00:07:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/scripts/update	2004-08-29 15:10:55.000000000 +0900
@@ -54,25 +54,25 @@
 # common
 v4l2basic
 xinsmod video-buf debug=2
-xinsmod btcx-risc debug=0
+#xinsmod btcx-risc debug=0
 xinsmod ir-common debug=0 repeat=0
-xinsmod tuner     debug=1
-xinsmod tda9887   debug=1
-xinsmod msp3400   debug=0
+xinsmod tuner     type=43 debug=1
+#xinsmod tda9887   debug=1
+#xinsmod msp3400   debug=0
 
 # bttv
-xinsmod bttv bttv_debug=0 vbi_debug=0 irq_debug=0 \
-	fdsr=0 chroma_agc=1 vbibufs=4 irq_iswitch=0 $btopt
+#xinsmod bttv bttv_debug=0 vbi_debug=0 irq_debug=0 \
+#	fdsr=0 chroma_agc=1 vbibufs=4 irq_iswitch=0 $btopt
 test -f ir-kbd-i2c.ko  && xinsmod ir-kbd-i2c  debug=0
-test -f ir-kbd-gpio.ko && xinsmod ir-kbd-gpio debug=0
+#test -f ir-kbd-gpio.ko && xinsmod ir-kbd-gpio debug=0
 
 # cx88
-xinsmod cx88xx core_debug=0 audio_debug=0
-xinsmod cx8800 video_debug=0
-xinsmod cx8801
-xinsmod cx8802
-xinsmod cx88-blackbird
-xinsmod cx88-dvb
+#xinsmod cx88xx core_debug=0 audio_debug=0
+#xinsmod cx8800 video_debug=0
+#xinsmod cx8801
+#xinsmod cx8802
+#xinsmod cx88-blackbird
+#xinsmod cx88-dvb
 
 # saa7134
-xinsmod saa7134 audio_debug=1 $saopt
+xinsmod saa7134  $saopt
diff -urN video4linux-20040826-105939/test-oss video4linux-20040826-105939.monstertv.1/test-oss
--- video4linux-20040826-105939/test-oss	1970-01-01 09:00:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/test-oss	2004-08-29 15:04:31.000000000 +0900
@@ -0,0 +1,13 @@
+#!/bin/sh
+args="$*"
+
+v4l="/dev/video0"
+dsp="/dev/dsp1"
+mix="/dev/mixer1"
+out="/dev/dsp"
+
+set -ex
+v4lctl -c $v4l volume mute off
+v4lctl -c $v4l setchannel 1
+#aumix -I -d $mix &
+exec sox $args -t ossdsp $dsp -t ossdsp $out
diff -urN video4linux-20040826-105939/tuner.c video4linux-20040826-105939.monstertv.1/tuner.c
--- video4linux-20040826-105939/tuner.c	2004-08-26 20:07:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/tuner.c	2004-08-29 15:04:31.000000000 +0900
@@ -133,7 +133,7 @@
   
 	unsigned short thresh1;  /*  band switch VHF_LO <=> VHF_HI  */
 	unsigned short thresh2;  /*  band switch VHF_HI <=> UHF     */
-	unsigned char VHF_L;
+        unsigned char VHF_L;
 	unsigned char VHF_H;
 	unsigned char UHF;
 	unsigned char config; 
@@ -992,6 +992,9 @@
 	case TUNER_LG_PAL_FM:
 		buffer[3] = 0xa5;
 		break;
+//	case TUNER_PHILIPS_FM1236_MK3:
+//		buffer[3] = 0xa5; /* If 0x19,Can't tune in Japan :-( */
+//		break;
 	default:
 		buffer[3] = 0xa4;
 		break;
diff -urN video4linux-20040826-105939/tuner.c.orig video4linux-20040826-105939.monstertv.1/tuner.c.orig
--- video4linux-20040826-105939/tuner.c.orig	1970-01-01 09:00:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/tuner.c.orig	2004-08-26 20:07:00.000000000 +0900
@@ -0,0 +1,1393 @@
+
+#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>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#include "tuner.h"
+#include "audiochip.h"
+#include "i2c-compat.h"
+#else
+#include <media/tuner.h>
+#include <media/audiochip.h>
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,71)
+# define strlcpy(dest,src,len) strncpy(dest,src,(len)-1)
+#endif
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {I2C_CLIENT_END};
+static unsigned short normal_i2c_range[] = {0x60,0x6f,I2C_CLIENT_END};
+I2C_CLIENT_INSMOD;
+
+#define UNSET (-1U)
+
+/* insmod options */
+static unsigned int debug =  0;
+static unsigned int type  =  UNSET;
+static unsigned int addr  =  0;
+static unsigned int tv_range[2]    = { 44, 958 };
+static unsigned int radio_range[2] = { 65, 108 };
+static unsigned int tv_antenna = 1;
+static unsigned int radio_antenna = 0;
+MODULE_PARM(debug,"i");
+MODULE_PARM(type,"i");
+MODULE_PARM(addr,"i");
+MODULE_PARM(tv_range,"2i");
+MODULE_PARM(radio_range,"2i");
+MODULE_PARM(tv_antenna,"i");
+MODULE_PARM(radio_antenna,"i");
+
+#define optimize_vco 1
+
+MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
+MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
+MODULE_LICENSE("GPL");
+
+static int this_adap;
+#define dprintk     if (debug) printk
+
+struct tuner {
+	unsigned int type;            /* chip type */
+	unsigned int freq;            /* keep track of the current settings */
+	v4l2_std_id  std;
+	int          using_v4l2;
+	
+	unsigned int radio;
+	unsigned int input;
+	
+	// only for MT2032
+	unsigned int xogc;
+	unsigned int radio_if2;
+
+	void (*tv_freq)(struct i2c_client *c, unsigned int freq);
+	void (*radio_freq)(struct i2c_client *c, unsigned int freq);
+};
+
+static struct i2c_driver driver;
+static struct i2c_client client_template;
+
+/* ---------------------------------------------------------------------- */
+
+/* tv standard selection for Temic 4046 FM5
+   this value takes the low bits of control byte 2
+   from datasheet Rev.01, Feb.00 
+     standard     BG      I       L       L2      D
+     picture IF   38.9    38.9    38.9    33.95   38.9
+     sound 1      33.4    32.9    32.4    40.45   32.4
+     sound 2      33.16   
+     NICAM        33.05   32.348  33.05           33.05
+ */
+#define TEMIC_SET_PAL_I         0x05
+#define TEMIC_SET_PAL_DK        0x09
+#define TEMIC_SET_PAL_L         0x0a // SECAM ?
+#define TEMIC_SET_PAL_L2        0x0b // change IF !
+#define TEMIC_SET_PAL_BG        0x0c
+
+/* tv tuner system standard selection for Philips FQ1216ME
+   this value takes the low bits of control byte 2
+   from datasheet "1999 Nov 16" (supersedes "1999 Mar 23")
+     standard 		BG	DK	I	L	L`
+     picture carrier	38.90	38.90	38.90	38.90	33.95
+     colour		34.47	34.47	34.47	34.47	38.38
+     sound 1		33.40	32.40	32.90	32.40	40.45
+     sound 2		33.16	-	-	-	-
+     NICAM		33.05	33.05	32.35	33.05	39.80
+ */
+#define PHILIPS_SET_PAL_I	0x01 /* Bit 2 always zero !*/
+#define PHILIPS_SET_PAL_BGDK	0x09
+#define PHILIPS_SET_PAL_L2	0x0a
+#define PHILIPS_SET_PAL_L	0x0b	
+
+/* system switching for Philips FI1216MF MK2
+   from datasheet "1996 Jul 09",
+    standard         BG     L      L'
+    picture carrier  38.90  38.90  33.95
+    colour	     34.47  34.37  38.38
+    sound 1          33.40  32.40  40.45
+    sound 2          33.16  -      -
+    NICAM            33.05  33.05  39.80
+ */
+#define PHILIPS_MF_SET_BG	0x01 /* Bit 2 must be zero, Bit 3 is system output */
+#define PHILIPS_MF_SET_PAL_L	0x03 // France
+#define PHILIPS_MF_SET_PAL_L2	0x02 // L'
+
+
+/* ---------------------------------------------------------------------- */
+
+struct tunertype 
+{
+	char *name;
+	unsigned char Vendor;
+	unsigned char Type;
+  
+	unsigned short thresh1;  /*  band switch VHF_LO <=> VHF_HI  */
+	unsigned short thresh2;  /*  band switch VHF_HI <=> UHF     */
+	unsigned char VHF_L;
+	unsigned char VHF_H;
+	unsigned char UHF;
+	unsigned char config; 
+	unsigned short IFPCoff; /* 622.4=16*38.90 MHz PAL, 
+				   732  =16*45.75 NTSCi, 
+				   940  =16*58.75 NTSC-Japan
+				   704  =16*44    ATSC */
+};
+
+/*
+ *	The floats in the tuner struct are computed at compile time
+ *	by gcc and cast back to integers. Thus we don't violate the
+ *	"no float in kernel" rule.
+ */
+static struct tunertype tuners[] = {
+        { "Temic PAL (4002 FH5)", TEMIC, PAL,
+	  16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623},
+	{ "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I,
+	  16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
+	{ "Philips NTSC (FI1236,FM1236 and compatibles)", Philips, NTSC,
+	  16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732},
+	{ "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", Philips, SECAM,
+	  16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623},
+
+	{ "NoTuner", NoTuner, NOTUNER,
+	  0,0,0x00,0x00,0x00,0x00,0x00},
+	{ "Philips PAL_BG (FI1216 and compatibles)", Philips, PAL,
+	  16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,623},
+	{ "Temic NTSC (4032 FY5)", TEMIC, NTSC,
+	  16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732},
+	{ "Temic PAL_I (4062 FY5)", TEMIC, PAL_I,
+	  16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623},
+
+ 	{ "Temic NTSC (4036 FY5)", TEMIC, NTSC,
+	  16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732},
+        { "Alps HSBH1", TEMIC, NTSC,
+	  16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
+        { "Alps TSBE1",TEMIC,PAL,
+	  16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
+        { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */
+	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632},
+
+        { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
+	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622},
+        { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
+	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608},
+	{ "Temic PAL_BG (4006FH5)", TEMIC, PAL,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, 
+  	{ "Alps TSCH6",Alps,NTSC,
+  	  16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732},
+
+  	{ "Temic PAL_DK (4016 FY5)",TEMIC,PAL,
+  	  16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623},
+  	{ "Philips NTSC_M (MK2)",Philips,NTSC,
+  	  16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
+        { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I,
+          16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+        { "Temic PAL* auto (4006 FN5)", TEMIC, PAL,
+          16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+
+        { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL,
+          16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
+        { "Temic NTSC (4039 FR5)", TEMIC, NTSC,
+          16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
+        { "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL,
+          16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+        { "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+
+	{ "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "LG PAL_I+FM (TAPC-I001D)", LGINNOTEK, PAL_I,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "LG PAL_I (TAPC-I701D)", LGINNOTEK, PAL_I,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "LG NTSC+FM (TPI8NSR01F)", LGINNOTEK, NTSC,
+	  16*210.00,16*497.00,0xa0,0x90,0x30,0x8e,732},
+
+	{ "LG PAL_BG+FM (TPI8PSB01D)", LGINNOTEK, PAL,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "LG PAL_BG (TPI8PSB11D)", LGINNOTEK, PAL,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL,
+	  16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
+	{ "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */
+	  16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940 },
+
+	{ "Samsung PAL TCPM9091PD27", Samsung, PAL,  /* from sourceforge v3tv */
+          16*169,16*464,0xA0,0x90,0x30,0x8e,623},
+	{ "MT20xx universal", Microtune,PAL|NTSC,
+               0,0,0,0,0,0,0},
+	{ "Temic PAL_BG (4106 FH5)", TEMIC, PAL,
+          16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
+	{ "Temic PAL_DK/SECAM_L (4012 FY5)", TEMIC, PAL,
+          16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623},
+
+	{ "Temic NTSC (4136 FY5)", TEMIC, NTSC,
+          16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
+        { "LG PAL (newer TAPC series)", LGINNOTEK, PAL,
+          16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623},
+	{ "Philips PAL/SECAM multi (FM1216ME MK3)", Philips, PAL,
+	  16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
+	{ "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC,
+          16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732},
+
+	{ "HITACHI V7-J180AT", HITACHI, NTSC,
+	  16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,940 },
+	{ "Philips PAL_MK (FI1216 MK)", Philips, PAL,
+	  16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623},
+	{ "Philips 1236D ATSC/NTSC daul in",Philips,ATSC,
+	  16*157.25,16*454.00,0xa0,0x90,0x30,0x8e,732},
+        { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC,
+          16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
+
+        { "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC,
+          16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
+	{ "Microtune 4049 FM5",Microtune,PAL,
+	  16*141.00,16*464.00,0xa0,0x90,0x30,0x8e,623},
+	{ "Panasonic VP27s/ENGE4324D", Panasonic, NTSC,
+	  16*160.00,16*454.00,0x01,0x02,0x08,0xce,940},
+        { "LG NTSC (TAPE series)", LGINNOTEK, NTSC,
+          16*170.00, 16*450.00, 0x01,0x02,0x04,0x8e,732 },
+
+        { "Tenna TNF 8831 BGFF)", Philips, PAL,
+          16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
+	{ "Microtune 4042 FI5 ATSC/NTSC dual in", Microtune, NTSC,
+	  16*162.00,16*457.00,0xa2,0x94,0x31,0x8e,732},
+
+};
+#define TUNERS ARRAY_SIZE(tuners)
+
+/* ---------------------------------------------------------------------- */
+
+static int tuner_getstatus(struct i2c_client *c)
+{
+	unsigned char byte;
+
+	struct tuner *t = i2c_get_clientdata(c);
+
+        if (t->type == TUNER_MT2032)
+		return 0;
+
+	if (1 != i2c_master_recv(c,&byte,1))
+		return 0;
+	return byte;
+}
+
+#define TUNER_POR       0x80
+#define TUNER_FL        0x40
+#define TUNER_MODE      0x38
+#define TUNER_AFC       0x07
+
+#define TUNER_STEREO    0x10 /* radio mode */
+#define TUNER_SIGNAL    0x07 /* radio mode */
+
+static int tuner_signal(struct i2c_client *c)
+{
+	return (tuner_getstatus(c) & TUNER_SIGNAL)<<13;
+}
+
+static int tuner_stereo(struct i2c_client *c)
+{
+	return (tuner_getstatus (c) & TUNER_STEREO);
+}
+
+#if 0 /* unused */
+static int tuner_islocked (struct i2c_client *c)
+{
+        return (tuner_getstatus (c) & TUNER_FL);
+}
+
+static int tuner_afcstatus (struct i2c_client *c)
+{
+        return (tuner_getstatus (c) & TUNER_AFC) - 2;
+}
+
+static int tuner_mode (struct i2c_client *c)
+{
+        return (tuner_getstatus (c) & TUNER_MODE) >> 3;
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+#define MT2032 0x04
+#define MT2030 0x06
+#define MT2040 0x07
+#define MT2050 0x42
+
+static char *microtune_part[] = {
+	[ MT2030 ] = "MT2030",
+	[ MT2032 ] = "MT2032",
+	[ MT2040 ] = "MT2040",
+	[ MT2050 ] = "MT2050",
+};
+
+// IsSpurInBand()?
+static int mt2032_spurcheck(int f1, int f2, int spectrum_from,int spectrum_to)
+{
+	int n1=1,n2,f;
+
+	f1=f1/1000; //scale to kHz to avoid 32bit overflows
+	f2=f2/1000;
+	spectrum_from/=1000;
+	spectrum_to/=1000;
+
+	dprintk("spurcheck f1=%d f2=%d  from=%d to=%d\n",f1,f2,spectrum_from,spectrum_to);
+
+	do {
+	    n2=-n1;
+	    f=n1*(f1-f2);
+	    do {
+		n2--;
+		f=f-f2;
+		dprintk(" spurtest n1=%d n2=%d ftest=%d\n",n1,n2,f);
+
+		if( (f>spectrum_from) && (f<spectrum_to))
+			printk("mt2032 spurcheck triggered: %d\n",n1);
+	    } while ( (f>(f2-spectrum_to)) || (n2>-5));
+	    n1++;
+	} while (n1<5);
+
+	return 1;
+}
+
+static int mt2032_compute_freq(unsigned int rfin,
+			       unsigned int if1, unsigned int if2,
+			       unsigned int spectrum_from,
+			       unsigned int spectrum_to,
+			       unsigned char *buf,
+			       int *ret_sel,
+			       unsigned int xogc) //all in Hz
+{
+        unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
+		desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq;
+
+        fref= 5250 *1000; //5.25MHz
+	desired_lo1=rfin+if1;
+
+	lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000);
+        lo1n=lo1/8;
+        lo1a=lo1-(lo1n*8);
+
+        s=rfin/1000/1000+1090;
+
+	if(optimize_vco) {
+		if(s>1890) sel=0;
+		else if(s>1720) sel=1;
+		else if(s>1530) sel=2;
+		else if(s>1370) sel=3;
+		else sel=4; // >1090
+	}
+	else {
+        	if(s>1790) sel=0; // <1958
+        	else if(s>1617) sel=1;
+        	else if(s>1449) sel=2;
+        	else if(s>1291) sel=3;
+        	else sel=4; // >1090
+	}
+	*ret_sel=sel;
+
+        lo1freq=(lo1a+8*lo1n)*fref;
+
+        dprintk("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n",
+		rfin,lo1,lo1n,lo1a,sel,lo1freq);
+
+        desired_lo2=lo1freq-rfin-if2;
+        lo2=(desired_lo2)/fref;
+        lo2n=lo2/8;
+        lo2a=lo2-(lo2n*8);
+        lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith
+        lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000;
+
+        dprintk("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n",
+		rfin,lo2,lo2n,lo2a,lo2num,lo2freq);
+
+        if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) {
+                printk("mt2032: frequency parameters out of range: %d %d %d %d\n",
+		       lo1a, lo1n, lo2a,lo2n);
+                return(-1);
+        }
+
+	mt2032_spurcheck(lo1freq, desired_lo2,  spectrum_from, spectrum_to);
+	// should recalculate lo1 (one step up/down)
+
+	// set up MT2032 register map for transfer over i2c
+	buf[0]=lo1n-1;
+	buf[1]=lo1a | (sel<<4);
+	buf[2]=0x86; // LOGC
+	buf[3]=0x0f; //reserved
+	buf[4]=0x1f;
+	buf[5]=(lo2n-1) | (lo2a<<5);
+ 	if(rfin >400*1000*1000)
+                buf[6]=0xe4;
+        else
+                buf[6]=0xf4; // set PKEN per rev 1.2 
+	buf[7]=8+xogc;
+	buf[8]=0xc3; //reserved
+	buf[9]=0x4e; //reserved
+	buf[10]=0xec; //reserved
+	buf[11]=(lo2num&0xff);
+	buf[12]=(lo2num>>8) |0x80; // Lo2RST
+
+	return 0;
+}
+
+static int mt2032_check_lo_lock(struct i2c_client *c)
+{
+	int try,lock=0;
+	unsigned char buf[2];
+	for(try=0;try<10;try++) {
+		buf[0]=0x0e;
+		i2c_master_send(c,buf,1);
+		i2c_master_recv(c,buf,1);
+		dprintk("mt2032 Reg.E=0x%02x\n",buf[0]);
+		lock=buf[0] &0x06;
+		
+		if (lock==6)
+			break;
+		
+		dprintk("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]);
+		udelay(1000);
+	}
+        return lock;
+}
+
+static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock)
+{
+	unsigned char buf[2];
+	int tad1;
+
+	buf[0]=0x0f;
+	i2c_master_send(c,buf,1);
+	i2c_master_recv(c,buf,1);
+	dprintk("mt2032 Reg.F=0x%02x\n",buf[0]);
+	tad1=buf[0]&0x07;
+
+	if(tad1 ==0) return lock;
+	if(tad1 ==1) return lock;
+
+	if(tad1==2) {
+		if(sel==0) 
+			return lock;
+		else sel--;
+	}
+	else {
+		if(sel<4)
+			sel++;
+		else
+			return lock;
+	}
+
+	dprintk("mt2032 optimize_vco: sel=%d\n",sel);
+
+	buf[0]=0x0f;
+	buf[1]=sel;
+        i2c_master_send(c,buf,2);
+	lock=mt2032_check_lo_lock(c);
+	return lock;
+}
+
+
+static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
+			       unsigned int if1, unsigned int if2,
+			       unsigned int from, unsigned int to)
+{
+	unsigned char buf[21];
+	int lint_try,ret,sel,lock=0;
+	struct tuner *t = i2c_get_clientdata(c);
+
+	dprintk("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",rfin,if1,if2,from,to);
+
+        buf[0]=0;
+        ret=i2c_master_send(c,buf,1);
+        i2c_master_recv(c,buf,21);
+
+	buf[0]=0;
+	ret=mt2032_compute_freq(rfin,if1,if2,from,to,&buf[1],&sel,t->xogc);
+	if (ret<0)
+		return;
+
+        // send only the relevant registers per Rev. 1.2
+        buf[0]=0;
+        ret=i2c_master_send(c,buf,4);
+        buf[5]=5;
+        ret=i2c_master_send(c,buf+5,4);
+        buf[11]=11;
+        ret=i2c_master_send(c,buf+11,3);
+        if(ret!=3)
+                printk("mt2032_set_if_freq failed with %d\n",ret);
+
+	// wait for PLLs to lock (per manual), retry LINT if not.
+	for(lint_try=0; lint_try<2; lint_try++) {
+		lock=mt2032_check_lo_lock(c);
+		
+		if(optimize_vco)
+			lock=mt2032_optimize_vco(c,sel,lock);
+		if(lock==6) break;
+		
+		printk("mt2032: re-init PLLs by LINT\n"); 
+		buf[0]=7; 
+		buf[1]=0x80 +8+t->xogc; // set LINT to re-init PLLs
+		i2c_master_send(c,buf,2);
+		mdelay(10);
+		buf[1]=8+t->xogc;
+		i2c_master_send(c,buf,2);
+        }
+
+	if (lock!=6)
+		printk("MT2032 Fatal Error: PLLs didn't lock.\n");
+
+	buf[0]=2;
+	buf[1]=0x20; // LOGC for optimal phase noise
+	ret=i2c_master_send(c,buf,2);
+	if (ret!=2)
+		printk("mt2032_set_if_freq2 failed with %d\n",ret);
+}
+
+
+static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	int if2,from,to;
+
+	// signal bandwidth and picture carrier
+	if (t->std & V4L2_STD_525_60) {
+		// NTSC
+		from = 40750*1000;
+		to   = 46750*1000;
+		if2  = 45750*1000; 
+	} else {
+		// PAL
+		from = 32900*1000;
+		to   = 39900*1000;
+		if2  = 38900*1000;
+	}
+
+        mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
+			   1090*1000*1000, if2, from, to);
+}
+
+static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	int if2 = t->radio_if2;
+
+	// per Manual for FM tuning: first if center freq. 1085 MHz
+        mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
+			   1085*1000*1000,if2,if2,if2);
+}
+
+// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
+static int mt2032_init(struct i2c_client *c)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+        unsigned char buf[21];
+        int ret,xogc,xok=0;
+
+	// Initialize Registers per spec.
+        buf[1]=2; // Index to register 2
+        buf[2]=0xff;
+        buf[3]=0x0f;
+        buf[4]=0x1f;
+        ret=i2c_master_send(c,buf+1,4);
+
+        buf[5]=6; // Index register 6
+        buf[6]=0xe4;
+        buf[7]=0x8f;
+        buf[8]=0xc3;
+        buf[9]=0x4e;
+        buf[10]=0xec;
+        ret=i2c_master_send(c,buf+5,6);
+
+        buf[12]=13;  // Index register 13
+        buf[13]=0x32;
+        ret=i2c_master_send(c,buf+12,2);
+
+        // Adjust XOGC (register 7), wait for XOK
+        xogc=7;
+        do {
+		dprintk("mt2032: xogc = 0x%02x\n",xogc&0x07);
+                mdelay(10);
+                buf[0]=0x0e;
+                i2c_master_send(c,buf,1);
+                i2c_master_recv(c,buf,1);
+                xok=buf[0]&0x01;
+                dprintk("mt2032: xok = 0x%02x\n",xok);
+                if (xok == 1) break;
+
+                xogc--;
+                dprintk("mt2032: xogc = 0x%02x\n",xogc&0x07);
+                if (xogc == 3) {
+                        xogc=4; // min. 4 per spec
+                        break;
+                }
+                buf[0]=0x07;
+                buf[1]=0x88 + xogc;
+                ret=i2c_master_send(c,buf,2);
+                if (ret!=2)
+                        printk("mt2032_init failed with %d\n",ret);
+        } while (xok != 1 );
+	t->xogc=xogc;
+
+	t->tv_freq    = mt2032_set_tv_freq;
+	t->radio_freq = mt2032_set_radio_freq;
+        return(1);
+}
+
+static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna)
+{
+       unsigned char buf[2];
+       int ret;
+
+       buf[0] = 6;
+       buf[1] = antenna ? 0x11 : 0x10;
+       ret=i2c_master_send(c,buf,2);
+       dprintk("mt2050: enabled antenna connector %d\n", antenna);
+}
+
+static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2)
+{
+	unsigned int if1=1218*1000*1000;
+	unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b;
+	int ret;
+	unsigned char buf[6];
+	
+	dprintk("mt2050_set_if_freq freq=%d\n",freq);
+	
+	f_lo1=freq+if1;
+	f_lo1=(f_lo1/1000000)*1000000;
+	
+	f_lo2=f_lo1-freq-if2;
+	f_lo2=(f_lo2/50000)*50000;
+	
+	lo1=f_lo1/4000000;
+	lo2=f_lo2/4000000;
+	
+	f_lo1_modulo= f_lo1-(lo1*4000000);
+	f_lo2_modulo= f_lo2-(lo2*4000000);
+	
+	num1=4*f_lo1_modulo/4000000;
+	num2=4096*(f_lo2_modulo/1000)/4000;
+	
+	// todo spurchecks
+	
+	div1a=(lo1/12)-1;
+	div1b=lo1-(div1a+1)*12;
+	
+	div2a=(lo2/8)-1;
+	div2b=lo2-(div2a+1)*8;
+	
+	dprintk("lo1 lo2 = %d %d\n", lo1, lo2);
+        dprintk("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n",num1,num2,div1a,div1b,div2a,div2b);
+	
+	
+	buf[0]=1;
+	buf[1]= 4*div1b + num1;
+	if(freq<275*1000*1000) buf[1] = buf[1]|0x80;
+	
+	buf[2]=div1a;
+	buf[3]=32*div2b + num2/256;
+	buf[4]=num2-(num2/256)*256;
+	buf[5]=div2a;
+	if(num2!=0) buf[5]=buf[5]|0x40;
+	
+	if(debug) {
+		int i;
+		printk("bufs is: ");
+		for(i=0;i<6;i++)
+			printk("%x ",buf[i]);
+		printk("\n");
+	}
+	
+	ret=i2c_master_send(c,buf,6);
+        if (ret!=6)
+                printk("mt2050_set_if_freq failed with %d\n",ret);
+}
+
+static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	unsigned int if2;
+	
+	if (t->std & V4L2_STD_525_60) {
+		// NTSC
+                if2 = 45750*1000;
+        } else {
+                // PAL
+                if2 = 38900*1000;
+        }
+	mt2050_set_if_freq(c, freq*62500, if2);
+	mt2050_set_antenna(c, tv_antenna);
+}
+
+static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	int if2 = t->radio_if2;
+	
+	mt2050_set_if_freq(c, freq*62500, if2);
+	mt2050_set_antenna(c, radio_antenna);
+}
+
+static int mt2050_init(struct i2c_client *c)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	unsigned char buf[2];
+	int ret;
+	
+	buf[0]=6;
+	buf[1]=0x10;
+	ret=i2c_master_send(c,buf,2); //  power
+	
+	buf[0]=0x0f;
+	buf[1]=0x0f;
+	ret=i2c_master_send(c,buf,2); // m1lo
+	
+	buf[0]=0x0d;
+	ret=i2c_master_send(c,buf,1);
+	i2c_master_recv(c,buf,1);
+	
+	dprintk("mt2050: sro is %x\n",buf[0]);
+	t->tv_freq    = mt2050_set_tv_freq;
+	t->radio_freq = mt2050_set_radio_freq;
+	return 0;
+}
+
+static int microtune_init(struct i2c_client *c)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	char *name;
+        unsigned char buf[21];
+	int company_code;
+	
+	memset(buf,0,sizeof(buf));
+	t->tv_freq    = NULL;
+	t->radio_freq = NULL;
+	name = "unknown";
+
+        i2c_master_send(c,buf,1);
+        i2c_master_recv(c,buf,21);
+        if(debug) {
+                int i;
+                printk(KERN_DEBUG "tuner: MT2032 hexdump:\n");
+                for(i=0;i<21;i++) {
+                        printk(" %02x",buf[i]);
+                        if(((i+1)%8)==0) printk(" ");
+                        if(((i+1)%16)==0) printk("\n ");
+                }
+                printk("\n ");
+        }
+	company_code = buf[0x11] << 8 | buf[0x12];
+        printk("tuner: microtune: companycode=%04x part=%02x rev=%02x\n",
+	       company_code,buf[0x13],buf[0x14]);
+
+#if 0
+	/* seems to cause more problems than it solves ... */
+	switch (company_code) {
+	case 0x30bf:
+	case 0x3cbf:
+	case 0x3dbf:
+	case 0x4d54:
+	case 0x8e81:
+	case 0x8e91:
+		/* ok (?) */
+		break;
+	default:
+		printk("tuner: microtune: unknown companycode\n");
+		return 0;
+	}
+#endif
+
+	if (buf[0x13] < ARRAY_SIZE(microtune_part) &&
+	    NULL != microtune_part[buf[0x13]])
+		name = microtune_part[buf[0x13]];
+	switch (buf[0x13]) {
+	case MT2032:
+		mt2032_init(c);
+		break;
+	case MT2050:
+		mt2050_init(c);
+		break;
+	default:
+		printk("tuner: microtune %s found, not (yet?) supported, sorry :-/\n",
+		       name);
+                return 0;
+        }
+	printk("tuner: microtune %s found, OK\n",name);
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	u8 config;
+	u16 div;
+	struct tunertype *tun;
+        unsigned char buffer[4];
+	int rc;
+
+	tun=&tuners[t->type];
+	if (freq < tun->thresh1) 
+		config = tun->VHF_L;
+	else if (freq < tun->thresh2) 
+		config = tun->VHF_H;
+	else
+		config = tun->UHF;
+
+
+	/* tv norm specific stuff for multi-norm tuners */
+	switch (t->type) {
+	case TUNER_PHILIPS_SECAM: // FI1216MF
+		/* 0x01 -> ??? no change ??? */
+		/* 0x02 -> PAL BDGHI / SECAM L */
+		/* 0x04 -> ??? PAL others / SECAM others ??? */
+		config &= ~0x02;
+		if (t->std & V4L2_STD_SECAM)
+			config |= 0x02;
+		break;
+
+	case TUNER_TEMIC_4046FM5:
+		config &= ~0x0f;
+
+		if (t->std & V4L2_STD_PAL_BG) {
+			config |= TEMIC_SET_PAL_BG;
+
+		} else if (t->std & V4L2_STD_PAL_I) {
+			config |= TEMIC_SET_PAL_I;
+
+		} else if (t->std & V4L2_STD_PAL_DK) {
+			config |= TEMIC_SET_PAL_DK;
+			
+		} else if (t->std & V4L2_STD_SECAM_L) {
+			config |= TEMIC_SET_PAL_L;
+
+		}
+		break;
+
+	case TUNER_PHILIPS_FQ1216ME:
+		config &= ~0x0f;
+
+		if (t->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
+			config |= PHILIPS_SET_PAL_BGDK;
+
+		} else if (t->std & V4L2_STD_PAL_I) {
+			config |= PHILIPS_SET_PAL_I;
+
+		} else if (t->std & V4L2_STD_SECAM_L) {
+			config |= PHILIPS_SET_PAL_L;
+
+		}
+		break;
+
+	case TUNER_PHILIPS_ATSC:
+		/* 0x00 -> ATSC antenna input 1 */
+		/* 0x01 -> ATSC antenna input 2 */
+		/* 0x02 -> NTSC antenna input 1 */
+		/* 0x03 -> NTSC antenna input 2 */
+		config &= ~0x03;
+		if (t->std & V4L2_STD_ATSC)
+			config |= 2;
+		/* FIXME: input */
+		break;
+
+	case TUNER_MICROTUNE_4042FI5:
+		/* Set the charge pump for fast tuning */
+		tun->config |= 0x40;
+		break;
+	}
+	
+	/*
+	 * Philips FI1216MK2 remark from specification :
+	 * for channel selection involving band switching, and to ensure
+	 * smooth tuning to the desired channel without causing
+	 * unnecessary charge pump action, it is recommended to consider
+	 * the difference between wanted channel frequency and the
+	 * current channel frequency.  Unnecessary charge pump action
+	 * will result in very low tuning voltage which may drive the
+	 * oscillator to extreme conditions.
+	 *
+	 * Progfou: specification says to send config data before
+	 * frequency in case (wanted frequency < current frequency).
+	 */
+
+	div=freq + tun->IFPCoff;
+	if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) {
+		buffer[0] = tun->config;
+		buffer[1] = config;
+		buffer[2] = (div>>8) & 0x7f;
+		buffer[3] = div      & 0xff;
+	} else {
+		buffer[0] = (div>>8) & 0x7f;
+		buffer[1] = div      & 0xff;
+		buffer[2] = tun->config;
+		buffer[3] = config;
+	}
+	dprintk("tuner: tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
+		buffer[0],buffer[1],buffer[2],buffer[3]);
+
+        if (4 != (rc = i2c_master_send(c,buffer,4)))
+                printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);
+
+	if (t->type == TUNER_MICROTUNE_4042FI5) {
+		// FIXME - this may also work for other tuners
+		unsigned long timeout = jiffies + msecs_to_jiffies(1);
+		u8 status_byte = 0;
+
+		/* Wait until the PLL locks */
+		for (;;) {
+			if (time_after(jiffies,timeout))
+				return;
+			if (1 != (rc = i2c_master_recv(c,&status_byte,1))) {
+				dprintk("tuner: i2c i/o read error: rc == %d (should be 1)\n",rc);
+				break;
+			}
+			/* bit 6 is PLL locked indicator */
+			if (status_byte & 0x40)
+				break;
+			udelay(10);
+		}
+		
+		/* Set the charge pump for optimized phase noise figure */
+		tun->config &= ~0x40;
+		buffer[0] = (div>>8) & 0x7f;
+		buffer[1] = div      & 0xff;
+		buffer[2] = tun->config;
+		buffer[3] = config;
+		dprintk("tuner: tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
+			buffer[0],buffer[1],buffer[2],buffer[3]);
+
+		if (4 != (rc = i2c_master_send(c,buffer,4)))
+			dprintk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);
+	}
+}
+
+static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
+{
+	struct tunertype *tun;
+	struct tuner *t = i2c_get_clientdata(c);
+        unsigned char buffer[4];
+	unsigned div;
+	int rc;
+
+	tun=&tuners[t->type];
+	div = freq + (int)(16*10.7);
+        buffer[0] = (div>>8) & 0x7f;
+        buffer[1] = div      & 0xff;
+	buffer[2] = tun->config;
+	switch (t->type) {
+	case TUNER_PHILIPS_FM1216ME_MK3:
+	case TUNER_PHILIPS_FM1236_MK3:
+		buffer[3] = 0x19;
+		break;
+	case TUNER_LG_PAL_FM:
+		buffer[3] = 0xa5;
+		break;
+	default:
+		buffer[3] = 0xa4;
+		break;
+	}
+
+	dprintk("tuner: radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
+		buffer[0],buffer[1],buffer[2],buffer[3]);
+
+        if (4 != (rc = i2c_master_send(c,buffer,4)))
+                printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);
+}
+
+/* ---------------------------------------------------------------------- */
+
+// Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHz
+static void set_tv_freq(struct i2c_client *c, unsigned int freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+
+	if (t->type == UNSET) {
+		printk("tuner: tuner type not set\n");
+		return;
+	}
+	if (NULL == t->tv_freq) {
+		printk("tuner: Huh? tv_set is NULL?\n");
+		return;
+	}
+	if (freq < tv_range[0]*16 || freq > tv_range[1]*16) {
+		/* FIXME: better do that chip-specific, but
+		   right now we don't have that in the config
+		   struct and this way is still better than no
+		   check at all */
+		printk("tuner: TV freq (%d.%02d) out of range (%d-%d)\n",
+		       freq/16,freq%16*100/16,tv_range[0],tv_range[1]);
+		return;
+	}
+	t->tv_freq(c,freq);
+}
+
+static void set_radio_freq(struct i2c_client *c, unsigned int freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+
+	if (t->type == UNSET) {
+		printk("tuner: tuner type not set\n");
+		return;
+	}
+	if (NULL == t->radio_freq) {
+		printk("tuner: no radio tuning for this one, sorry.\n");
+		return;
+	}
+	if (freq < radio_range[0]*16 || freq > radio_range[1]*16) {
+		printk("tuner: radio freq (%d.%02d) out of range (%d-%d)\n",
+		       freq/16,freq%16*100/16,
+		       radio_range[0],radio_range[1]);
+		return;
+	}
+	t->radio_freq(c,freq);
+}
+
+static void set_freq(struct i2c_client *c, unsigned long freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+
+	if (t->radio) {
+		dprintk("tuner: radio freq set to %lu.%02lu\n",
+			freq/16,freq%16*100/16);
+		set_radio_freq(c,freq);
+	} else {
+		dprintk("tuner: tv freq set to %lu.%02lu\n",
+			freq/16,freq%16*100/16);
+		set_tv_freq(c, freq);
+	}
+	t->freq = freq;
+}
+
+static void set_type(struct i2c_client *c, unsigned int type, char *source)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+
+	if (t->type != UNSET) {
+		if (t->type != type)
+			printk("tuner: type already set to %d, "
+			       "ignoring request for %d\n", t->type, type);
+		return;
+	}
+	if (type >= TUNERS)
+		return;
+
+	t->type = type;
+	printk("tuner: type set to %d (%s) by %s\n",
+	       t->type,tuners[t->type].name, source);
+	strlcpy(c->name, tuners[t->type].name, sizeof(c->name));
+
+	switch (t->type) {
+	case TUNER_MT2032:
+		microtune_init(c);
+		break;
+	default:
+		t->tv_freq    = default_set_tv_freq;
+		t->radio_freq = default_set_radio_freq;
+		break;
+	}
+}
+
+static char *pal = "-";
+MODULE_PARM(pal,"s");
+
+static int tuner_fixup_std(struct tuner *t)
+{
+	if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
+		/* get more precise norm info from insmod option */
+		switch (pal[0]) {
+		case 'b':
+		case 'B':
+		case 'g':
+		case 'G':
+			dprintk("insmod fixup: PAL => PAL-BG\n");
+			t->std = V4L2_STD_PAL_BG;
+			break;
+		case 'i':
+		case 'I':
+			dprintk("insmod fixup: PAL => PAL-I\n");
+			t->std = V4L2_STD_PAL_I;
+			break;
+		case 'd':
+		case 'D':
+		case 'k':
+		case 'K':
+			dprintk("insmod fixup: PAL => PAL-DK\n");
+			t->std = V4L2_STD_PAL_DK;
+			break;
+		}
+	}
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
+#else
+static int tuner_attach(struct i2c_adapter *adap, int addr,
+			unsigned short flags, int kind)
+#endif
+{
+	struct tuner *t;
+	struct i2c_client *client;
+
+	if (this_adap > 0)
+		return -1;
+	this_adap++;
+	
+        client_template.adapter = adap;
+        client_template.addr = addr;
+
+        printk("tuner: chip found at addr 0x%x i2c-bus %s\n",
+	       addr<<1, adap->name);
+
+        if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)))
+                return -ENOMEM;
+        memcpy(client,&client_template,sizeof(struct i2c_client));
+        t = kmalloc(sizeof(struct tuner),GFP_KERNEL);
+        if (NULL == t) {
+                kfree(client);
+                return -ENOMEM;
+        }
+        memset(t,0,sizeof(struct tuner));
+	i2c_set_clientdata(client, t);
+	t->type       = UNSET;
+	t->radio_if2  = 10700*1000; // 10.7MHz - FM radio
+
+        i2c_attach_client(client);
+	if (type < TUNERS) {
+		set_type(client, type, "insmod option");
+		printk("tuner: The type=<n> insmod option will go away soon.\n");
+		printk("tuner: Please use the tuner=<n> option provided by\n");
+		printk("tuner: tv aard core driver (bttv, saa7134, ...) instead.\n");
+	}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	MOD_INC_USE_COUNT;
+#endif
+	return 0;
+}
+
+static int tuner_probe(struct i2c_adapter *adap)
+{
+	if (0 != addr) {
+		normal_i2c_range[0] = addr;
+		normal_i2c_range[1] = addr;
+	}
+	this_adap = 0;
+
+#ifdef I2C_CLASS_TV_ANALOG
+	if (adap->class & I2C_CLASS_TV_ANALOG)
+		return i2c_probe(adap, &addr_data, tuner_attach);
+#else
+	switch (adap->id) {
+	case I2C_ALGO_BIT | I2C_HW_SMBUS_VOODOO3:
+	case I2C_ALGO_BIT | I2C_HW_B_BT848:
+	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
+	case I2C_ALGO_SAA7134:
+	case I2C_ALGO_SAA7146:
+		return i2c_probe(adap, &addr_data, tuner_attach);
+		break;
+	}
+#endif
+	return 0;
+}
+
+static int tuner_detach(struct i2c_client *client)
+{
+	struct tuner *t = i2c_get_clientdata(client);
+
+	i2c_detach_client(client);
+	kfree(t);
+	kfree(client);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	MOD_DEC_USE_COUNT;
+#endif
+	return 0;
+}
+
+#define SWITCH_V4L2	if (!t->using_v4l2 && debug) \
+		          printk("tuner: switching to v4l2\n"); \
+	                  t->using_v4l2 = 1;
+#define CHECK_V4L2	if (t->using_v4l2) { if (debug) \
+			  printk("tuner: ignore v4l1 call\n"); \
+		          return 0; }
+
+static int
+tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	struct tuner *t = i2c_get_clientdata(client);
+        unsigned int *iarg = (int*)arg;
+
+        switch (cmd) {
+
+	/* --- configuration --- */
+	case TUNER_SET_TYPE:
+		set_type(client,*iarg,client->adapter->name);
+		break;
+	case AUDC_SET_RADIO:
+		if (!t->radio) {
+			set_tv_freq(client,400 * 16);
+			t->radio = 1;
+		}
+		break;
+	case AUDC_CONFIG_PINNACLE:
+		switch (*iarg) {
+		case 2:
+			dprintk("tuner: pinnacle pal\n");
+			t->radio_if2 = 33300 * 1000;
+			break;
+		case 3:
+			dprintk("tuner: pinnacle ntsc\n");
+			t->radio_if2 = 41300 * 1000;
+			break;
+		}
+                break;
+		
+	/* --- v4l ioctls --- */
+	/* take care: bttv does userspace copying, we'll get a
+	   kernel pointer here... */
+	case VIDIOCSCHAN:
+	{
+		static const v4l2_std_id map[] = {
+			[ VIDEO_MODE_PAL   ] = V4L2_STD_PAL,
+			[ VIDEO_MODE_NTSC  ] = V4L2_STD_NTSC_M,
+			[ VIDEO_MODE_SECAM ] = V4L2_STD_SECAM,
+			[ 4 /* bttv */     ] = V4L2_STD_PAL_M,
+			[ 5 /* bttv */     ] = V4L2_STD_PAL_N,
+			[ 6 /* bttv */     ] = V4L2_STD_NTSC_M_JP,
+		};
+		struct video_channel *vc = arg;
+
+		CHECK_V4L2;
+		t->radio = 0;
+		if (vc->norm < ARRAY_SIZE(map))
+			t->std = map[vc->norm];
+		tuner_fixup_std(t);
+		if (t->freq)
+			set_tv_freq(client,t->freq);
+		return 0;
+	}
+	case VIDIOCSFREQ:
+	{
+		unsigned long *v = arg;
+
+		CHECK_V4L2;
+		set_freq(client,*v);
+		return 0;
+	}
+	case VIDIOCGTUNER:
+	{
+		struct video_tuner *vt = arg;
+
+		CHECK_V4L2;
+		if (t->radio)
+			vt->signal = tuner_signal(client);
+		return 0;
+	}
+	case VIDIOCGAUDIO:
+	{
+		struct video_audio *va = arg;
+
+		CHECK_V4L2;
+		if (t->radio)
+			va->mode = (tuner_stereo(client) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO);
+		return 0;
+	}
+
+	case VIDIOC_S_STD:
+	{
+		v4l2_std_id *id = arg;
+
+		SWITCH_V4L2;
+		t->radio = 0;
+		t->std = *id;
+		tuner_fixup_std(t);
+		if (t->freq)
+			set_freq(client,t->freq);
+		break;
+	}
+	case VIDIOC_S_FREQUENCY:
+	{
+		struct v4l2_frequency *f = arg;
+
+		SWITCH_V4L2;
+		if (V4L2_TUNER_ANALOG_TV == f->type) {
+			t->radio = 0;
+		}
+		if (V4L2_TUNER_RADIO == f->type) {
+			if (!t->radio) {
+				set_tv_freq(client,400*16);
+				t->radio = 1;
+			}
+		}
+		t->freq  = f->frequency;
+		set_freq(client,t->freq);
+		break;
+	}
+	case VIDIOC_G_TUNER:
+	{
+		struct v4l2_tuner *tuner = arg;
+
+		SWITCH_V4L2;
+		if (t->radio)
+			tuner->signal = tuner_signal(client);
+		break;
+	}
+	default:
+		/* nothing */
+		break;
+	}
+	
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver driver = {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,54)
+	.owner          = THIS_MODULE,
+#endif
+        .name           = "i2c TV tuner driver",
+        .id             = I2C_DRIVERID_TUNER,
+        .flags          = I2C_DF_NOTIFY,
+        .attach_adapter = tuner_probe,
+        .detach_client  = tuner_detach,
+        .command        = tuner_command,
+};
+static struct i2c_client client_template =
+{
+	I2C_DEVNAME("(tuner unset)"),
+	.flags      = I2C_CLIENT_ALLOW_USE,
+        .driver     = &driver,
+};
+
+static int __init tuner_init_module(void)
+{
+	return i2c_add_driver(&driver);
+}
+
+static void __exit tuner_cleanup_module(void)
+{
+	i2c_del_driver(&driver);
+}
+
+module_init(tuner_init_module);
+module_exit(tuner_cleanup_module);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -urN video4linux-20040826-105939/tvaudio.c video4linux-20040826-105939.monstertv.1/tvaudio.c
--- video4linux-20040826-105939/tvaudio.c	2004-07-01 00:07:01.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/tvaudio.c	2004-08-29 15:04:36.000000000 +0900
@@ -7,6 +7,8 @@
  *   Steve VanDeBogart (vandebo@uclink.berkeley.edu)
  *   Greg Alexander (galexand@acm.org)
  *
+ * Add: MSP34x5 20031025 K.Ohta (alpha292@bremen.or.jp)
+ * 
  * This code is placed under the terms of the GNU General Public License
  * 
  * OPTIONS:
@@ -39,15 +41,18 @@
 #endif
 
 #include "tvaudio.h"
+#include "msp34x5.h"
+#define I2C_MSP3445 0x80 
 
 /* ---------------------------------------------------------------------- */
 /* insmod args                                                            */
 
 MODULE_PARM(debug,"i");
+
 static int debug = 0;	/* insmod parameter */
 
 MODULE_DESCRIPTION("device driver for various i2c TV sound decoder / audiomux chips");
-MODULE_AUTHOR("Eric Sandeen, Steve VanDeBogart, Greg Alexander, Gerd Knorr");
+MODULE_AUTHOR("Eric Sandeen, Steve VanDeBogart, Greg Alexander, Gerd Knorr, Ohta Kyuma");
 MODULE_LICENSE("GPL");
 
 #define UNSET    (-1U)
@@ -152,6 +157,7 @@
 	I2C_TDA985x_H >> 1,
 	I2C_TDA9874   >> 1,
 	I2C_PIC16C54  >> 1,
+        I2C_MSP3445   >> 1, /* Okay? */
 	I2C_CLIENT_END };
 static unsigned short normal_i2c_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
 I2C_CLIENT_INSMOD;
@@ -168,8 +174,10 @@
 	unsigned char buffer[2];
 
 	if (-1 == subaddr) {
+#if 0
 		dprintk("%s: chip_write: 0x%x\n",
 			i2c_clientname(&chip->c), val);
+#endif
 		chip->shadow.bytes[1] = val;
 		buffer[0] = val;
 		if (1 != i2c_master_send(&chip->c,buffer,1)) {
@@ -178,8 +186,10 @@
 			return -1;
 		}
 	} else {
+#if 0
 		dprintk("%s: chip_write: reg%d=0x%x\n",
 			i2c_clientname(&chip->c), subaddr, val);
+#endif
 		chip->shadow.bytes[subaddr+1] = val;
 		buffer[0] = subaddr;
 		buffer[1] = val;
@@ -192,6 +202,7 @@
 	return 0;
 }
 
+
 static int chip_write_masked(struct CHIPSTATE *chip, int subaddr, int val, int mask)
 {
 	if (mask != 0) {
@@ -1217,6 +1228,323 @@
 	return ((rc & 0x1f) == 0x1f) ? 1 : 0;
 }
 
+/*-----------------------------------------------------------------------
+ * MSP3445G
+ * ----------------------------------------------------------------------*/
+/* MODULE OPTIONS */
+static int msp3445  = 1;
+MODULE_PARM(msp3445, "i");
+
+
+/* EIA-J ONLY Now :-( */
+#define MSP3445_DEM 0x10
+#define MSP3445_DFP 0x12
+
+/* MSP3445 MPX TYPE */
+#define MSP3445_EIAJ 1
+
+
+static int msp3445_reset(struct CHIPSTATE *chip)
+{
+   unsigned char reset[3];
+   unsigned char unreset[3];
+   struct i2c_msg msgs[2] = {
+	{ chip->c.addr,0x1000,3,reset},
+        { chip->c.addr,0x1000,3,unreset},
+   };
+
+   reset[0]=0x00;reset[1]=0x80;reset[2]=0x00;
+   unreset[0]=0x00;unreset[1]=0x00;unreset[2]=0x00;
+
+   if(i2c_transfer(chip->c.adapter,&msgs[0],1)!=1) {
+         printk("msp34xx: reset failed\n");
+         return -1;
+   }
+   if(i2c_transfer(chip->c.adapter,&msgs[1],1)!=1) {
+         dprintk("msp34xx: unreset failed\n");
+         return -1;
+   }
+
+   printk("msp34xx: reset okay\n");
+   return 0;
+}
+
+static int msp3445_read(struct CHIPSTATE *chip,int subaddr,int reg,unsigned char *read)
+{
+   unsigned char write[3];
+   struct i2c_msg msgs[2] = {
+	{ chip->c.addr,0,3,write},
+        { chip->c.addr,I2C_M_RD,2,read},
+   };
+   /* send CMD */
+   write[0]=(unsigned char)((subaddr%256)+1);
+   write[1]=(unsigned char)((reg/256)%256);
+   write[2]=(unsigned char)(reg%256);
+	if (2 != i2c_transfer(chip->c.adapter,msgs,2)) {
+		printk(KERN_WARNING "%s: I/O error (read2)\n",
+		       i2c_clientname(&chip->c));
+		return -1;
+	}
+	dprintk(KERN_DEBUG
+		"%s: read: subadr:reg %04x:%04x=0x%02x%02x\n",
+		i2c_clientname(&chip->c),subaddr+1,reg,read[0],read[1]); 
+
+   return 2;
+}
+
+static int msp3445_write(struct CHIPSTATE *chip,int subaddr,int reg,int cmd)
+{
+   unsigned char write[6];
+   int i;
+   /* send CMD */
+   write[0]=I2C_MSP3445>>1;
+   write[1]=(unsigned char)(subaddr%256);
+   write[2]=(unsigned char)((reg/256)%256);
+   write[3]=(unsigned char)(reg%256);
+   write[4]=(unsigned char)((cmd/256)%256);
+   write[5]=(unsigned char)(cmd%256);
+#if 0 /* No Good :-( */
+   if((i=chip_mwrite(chip,6,write))!=6) {
+      msp3445_reset(chip);
+      dprintk("msp34xx: writing : %02x-%02x-%02x%02x-%02x%02x Failed. bytes = %d\n",write[0],write[1],write[2],write[3],write[4],write[5],i);
+      return -1;
+   }
+#else /* Okay... :-( */
+   if((i=i2c_master_send(&chip->c,&(write[1]),5))!=5) {
+      msp3445_reset(chip);
+      dprintk("msp34xx: writing : %02x-%02x-%02x%02x-%02x%02x Failed. bytes = %d\n",write[0],write[1],write[2],write[3],write[4],write[5],i);
+      return -1;
+   }
+   i=i+1;
+#endif
+   dprintk(KERN_DEBUG
+	   "%s: write: subadr:reg %04x:%04x=%04x\n",
+		i2c_clientname(&chip->c),subaddr,reg,cmd); 
+  return i;
+}
+
+/* Set Volume : right,left <- 65536=0dB */
+static void msp3445_setvolume(struct CHIPSTATE *chip,int left,int right)
+{
+        int vol,val,balance;
+        balance = 0;
+        vol     = (left > right) ? left : right;
+	val     = ((vol * 0x73) / 65536) << 8;
+        if (vol > 0) {
+		balance = ((right-left) * 127) / vol;
+	}
+         
+   	msp3445_write(chip,MSP3445_DFP, 0x0000, val); /* loudspeaker */
+	msp3445_write(chip,MSP3445_DFP, 0x0006, val); /* headphones  */
+	/* scart - on/off only */
+	msp3445_write(chip,MSP3445_DFP, 0x0007, val ? 0x4000 : 0);
+	msp3445_write(chip,MSP3445_DFP, 0x0001, balance << 8);
+}
+static void msp3445_setmode(struct CHIPSTATE *chip,int mode)
+{
+	int src,matrix;
+        switch(msp3445) {
+        /* EIA-J Only :-( */
+	 case MSP3445_EIAJ:
+	   matrix=0x3002;
+	   break;
+	 default:
+	   matrix=0x3002;
+	   break;
+	}
+        /* End EIA-J */
+        msp3445_write(chip,MSP3445_DFP,0x000e,matrix);
+        switch(mode) {
+	 case VIDEO_SOUND_STEREO:
+	   src=0x0120;
+	   break;
+	 case VIDEO_SOUND_LANG1:
+	   src=0x0100;
+	   break;
+	 case VIDEO_SOUND_LANG2:
+	   src=0x0110;
+	   break;
+	 case VIDEO_SOUND_MONO:
+	   src=0x0030;
+	   break;
+	 default:
+	   src=0x0030;
+	   break;
+	}
+        printk(KERN_DEBUG
+	   "tvaudio: setmode : chip->mode = 0x%04x\n",chip->mode);
+        printk(KERN_DEBUG
+	   "tvaudio: setstereo final source/matrix = 0x%04x\n", src);
+        msp3445_write(chip,MSP3445_DFP, 0x0008,src);
+        msp3445_write(chip,MSP3445_DFP, 0x0009,src);
+        msp3445_write(chip,MSP3445_DFP, 0x000c,src);
+        msp3445_write(chip,MSP3445_DFP, 0x000a,src);
+        msp3445_write(chip,MSP3445_DFP, 0x000b,src);
+        chip->prevmode = mode;
+}
+#define MSP_CARRIER(freq) ((int)((float)(freq/18.432)*(1<<24)))
+
+	        
+static void msp3445_setcarrier(struct CHIPSTATE *chip, int cdo1, int cdo2)
+{
+	msp3445_write(chip,MSP3445_DEM, 0x0093, cdo1 & 0xfff);
+	msp3445_write(chip,MSP3445_DEM, 0x009b, cdo1 >> 12);
+	msp3445_write(chip,MSP3445_DEM, 0x00a3, cdo2 & 0xfff);
+	msp3445_write(chip,MSP3445_DEM, 0x00ab, cdo2 >> 12);
+	msp3445_write(chip,MSP3445_DEM, 0x0056, 0); /*LOAD_REG_1/2*/
+}
+
+
+#define SCART_MASK    0
+#define SCART_IN1     1
+#define SCART_IN2     2
+#define SCART_IN1_DA  3
+#define SCART_IN2_DA  4
+#define SCART_IN3     5
+#define SCART_IN4     6
+#define SCART_MONO    7
+#define SCART_MUTE    8
+
+static int msp3445_scarts[3][9] = {
+  /* MASK    IN1     IN2     IN1_DA  IN2_DA  IN3     IN4     MONO    MUTE   */
+  {  0x0320, 0x0000, 0x0200, -1,     -1,     0x0300, 0x0020, 0x0100, 0x0320 },
+  {  0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 },
+  {  0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 },
+};
+
+static void msp3445_setscart(struct CHIPSTATE *chip, int in, int out)
+{
+        int acb=0;
+	if (-1 == msp3445_scarts[out][in])
+		return;
+	acb |=  msp3445_scarts[out][in];
+	msp3445_write(chip,MSP3445_DFP, 0x0013, acb);
+}
+
+
+static void msp3445_setinput(struct CHIPSTATE *chip,int in)
+{
+   /* TUNER ONLY...Temporally :) */
+   switch(in){
+    case AUDIO_TUNER:
+      /* Monster TV */
+      msp3445_setscart(chip,SCART_IN1,0);
+      msp3445_write(chip,MSP3445_DFP,0x000d,0x1900);
+      /* End Monster TV */
+      break;
+    default:
+      msp3445_setscart(chip,SCART_IN1,0);
+      msp3445_write(chip,MSP3445_DFP,0x000d,0x1900);
+      break;
+   }
+}
+
+static int msp3445_getmode(struct CHIPSTATE *chip)
+{
+	unsigned int val;
+        int mode;
+        unsigned char read[2];
+   
+        mode=VIDEO_SOUND_MONO;
+   
+        if(msp3445_read(chip,MSP3445_DEM,0x0200,read)<=0) return -1;
+        val=(unsigned int)(read[0]<<8)+(unsigned int)read[1];
+        /* EIA-J */
+        if((val & 0x0040)!=0) {
+	     mode = VIDEO_SOUND_STEREO;
+	   /* Dirty? */
+	   } else if((val & 0x0100)!=0){
+	      if(chip->mode == VIDEO_SOUND_LANG2) {
+		 mode = VIDEO_SOUND_LANG2;
+	      } else if(chip->mode == VIDEO_SOUND_LANG1) {
+		 mode = VIDEO_SOUND_LANG1;
+	      } else {
+		 mode = VIDEO_SOUND_STEREO; /* NOT AUTO :FAKE? */
+	      }
+	   }
+	dprintk(KERN_DEBUG
+		"tvaudio: getstereo mode = 0x%04x val = 0x%04x\n", mode,val);
+        return mode;
+}
+
+
+static int msp3445_initialize(struct CHIPSTATE *chip)
+{
+   int std,demvar,matrix;
+   int cf1,cf2 ; /* CARRIER */
+   unsigned char read[2];
+   int right,left;
+   msp3445_reset(chip);
+   /* EIA-J */
+   switch(msp3445) {
+    case MSP3445_EIAJ:
+      std = 0x0030;
+      demvar = 0x4003;
+      matrix = 0x3002;
+      cf1 = MSP_CARRIER(4.5);
+      cf2 = MSP_CARRIER(4.5);
+      break;
+    default:
+      std = 0x0030;
+      demvar = 0x4003;
+      matrix = 0x3002;
+      cf1 = MSP_CARRIER(4.5);
+      cf2 = MSP_CARRIER(4.5);
+      break;
+   }
+      /* End EIA-J */
+   /* Genelic */
+   right=65536;
+   left=65536;
+   /* End Genelic */
+   msp3445_write(chip,MSP3445_DEM,0x0030,demvar); /* WRITE DEM */
+   msp3445_read(chip,MSP3445_DEM,0x200,read);     /* Read status */
+   msp3445_write(chip,MSP3445_DEM,0x0020,std);    /* WRITE STD */
+   msp3445_write(chip,MSP3445_DFP,0x000e,matrix); /* Write MATRIX */
+   msp3445_setcarrier(chip, cf1, cf2);
+   msp3445_setinput(chip,AUDIO_TUNER);
+   msp3445_setmode(chip,VIDEO_SOUND_STEREO);
+   msp3445_setvolume(chip,right,left);
+   chip->prevmode = msp3445_getmode(chip); /* Get First Mode */
+   chip->mode = 0; /* Get First Mode */
+   //chip->prevmode = 0;
+   return 0;
+}
+
+
+
+static int msp3445_checkit(struct CHIPSTATE *chip)
+{
+   unsigned char rev1[2],rev2[2];
+   char name[32];
+   if(msp3445_read(chip,MSP3445_DFP,0x1e,rev1)<0) return 0;
+   if(msp3445_read(chip,MSP3445_DFP,0x1f,rev2)<0) return 0;
+   sprintf(name,"MSP34%02d%c-%c%d",
+	   rev2[0], rev1[1]+'@', rev1[0]+'@', rev2[1]&0x1f);   
+   printk("msp34xx: detected as %s\n",name);
+   return 1;
+}
+
+static void msp3445_checkmode(struct CHIPSTATE *chip)
+{
+	int mode;
+        mode = msp3445_getmode(chip);
+        if(chip->prevmode == mode) return;
+   	chip->prevmode = mode;
+	printk(KERN_DEBUG
+	       "%s: thread checkmode\n", i2c_clientname(&chip->c));
+	if ((mode & VIDEO_SOUND_LANG2)!=0)
+		msp3445_setmode(chip,VIDEO_SOUND_LANG2);
+	else if ((mode & VIDEO_SOUND_LANG1)!=0)
+		msp3445_setmode(chip,VIDEO_SOUND_LANG1);
+	else if ((mode & VIDEO_SOUND_STEREO)!=0)
+		msp3445_setmode(chip,VIDEO_SOUND_STEREO);
+	else
+		msp3445_setmode(chip,VIDEO_SOUND_MONO);
+
+}
+
+
 /* ---------------------------------------------------------------------- */
 /* audio chip descriptions - struct CHIPDESC                              */
 
@@ -1232,6 +1560,7 @@
 int pic16c54 = 1;
 int ta8874z  = 0;  // address clash with tda9840
 
+   
 MODULE_PARM(tda8425,"i");
 MODULE_PARM(tda9840,"i");
 MODULE_PARM(tda9850,"i");
@@ -1422,6 +1751,23 @@
 
 	        .init       = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}},
 	},
+   	{
+		.name       = "msp3445",
+		//.id         = -1,
+	        .insmodopt  = &msp3445,
+		.id         = I2C_DRIVERID_MSP3445,
+		.checkit    = msp3445_checkit,
+		.addr_lo    = I2C_MSP3445 >>1,
+		.addr_hi    = I2C_MSP3445 >>1,
+		.registers  = 5,
+                .flags      = 0,
+		.getmode    = msp3445_getmode,
+		.setmode    = msp3445_setmode,
+	        .initialize = msp3445_initialize,
+                .checkmode  = msp3445_checkmode,
+	        //.checkmode  = generic_checkmode,
+	},
+   
 	{ .name = NULL } /* EOF */
 };
 
@@ -1465,7 +1811,7 @@
 		return -EIO;
 	}
 	printk("tvaudio: found %s @ 0x%x\n", desc->name, addr<<1);
-	dprintk("tvaudio: matches:%s%s%s.\n",
+	printk("tvaudio: matches:%s%s%s.\n",
 		(desc->flags & CHIP_HAS_VOLUME)     ? " volume"      : "",
 		(desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "",
 		(desc->flags & CHIP_HAS_INPUTSEL)   ? " audiomux"    : "");
@@ -1563,7 +1909,7 @@
 	struct CHIPSTATE *chip = i2c_get_clientdata(client);
 	struct CHIPDESC  *desc = chiplist + chip->type;
 
-	dprintk("%s: chip_command 0x%x\n",i2c_clientname(&chip->c),cmd);
+	printk("%s: chip_command 0x%x\n",i2c_clientname(&chip->c),cmd);
 
 	switch (cmd) {
 	case AUDC_SET_INPUT:
@@ -1627,12 +1973,17 @@
 			chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
 			chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
 		}
-		if (desc->setmode && va->mode) {
-			chip->watch_stereo = 0;
-			/* del_timer(&chip->wt); */
-			chip->mode = va->mode;
-			desc->setmode(chip,va->mode);
-		}
+		   if (desc->setmode) {
+		      chip->watch_stereo = 0;
+		      del_timer(&chip->wt);
+		      /* 
+		       * OOPS...V4L2 method "arg->mode" is not SOUND-MODE,
+		       * auto volume support flag only,MPX mode was moved
+		       * to VIDIOC_S_MODULATOR :-(
+		       */
+		      if(va->mode != 0) chip->mode = va->mode;/* wrapper spec*/
+		      desc->setmode(chip,chip->mode); 
+		   }
 		break;
 	}
 	case VIDIOCSCHAN:
@@ -1645,11 +1996,10 @@
 	}
 	case VIDIOCSFREQ:
 	{
-	    	chip->mode = 0; /* automatic */
 		if (desc->checkmode) {
-			desc->setmode(chip,VIDEO_SOUND_MONO);
+			desc->setmode(chip,chip->mode);
 		    	if (chip->prevmode != VIDEO_SOUND_MONO)
-		    		chip->prevmode = -1; /* reset previous mode */
+		    		chip->prevmode = VIDEO_SOUND_MONO; /* reset previous mode */
 			mod_timer(&chip->wt, jiffies+2*HZ);
 			/* the thread will call checkmode() later */
 		}
diff -urN video4linux-20040826-105939/tvaudio.h video4linux-20040826-105939.monstertv.1/tvaudio.h
--- video4linux-20040826-105939/tvaudio.h	2004-02-22 10:59:35.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/tvaudio.h	2004-08-29 15:04:36.000000000 +0900
@@ -12,3 +12,4 @@
 #define I2C_TEA6420	   0x98
 
 #define I2C_PIC16C54       0x96 /* PV951 */
+#define I2C_MSP3445G       0x80 /* Monster TV */       
diff -urN video4linux-20040826-105939/v4l1-compat.c video4linux-20040826-105939.monstertv.1/v4l1-compat.c
--- video4linux-20040826-105939/v4l1-compat.c	2004-08-26 01:07:00.000000000 +0900
+++ video4linux-20040826-105939.monstertv.1/v4l1-compat.c	2004-08-29 15:04:36.000000000 +0900
@@ -845,8 +845,9 @@
 			switch (aud->mode) {
 			default:
 			case VIDEO_SOUND_MONO:
+			        tun2.audmode = V4L2_TUNER_MODE_MONO;
 			case VIDEO_SOUND_LANG1:
-				tun2.audmode = V4L2_TUNER_MODE_MONO;
+				tun2.audmode = V4L2_TUNER_MODE_LANG1;
 				break;
 			case VIDEO_SOUND_STEREO:
 				tun2.audmode = V4L2_TUNER_MODE_STEREO;
