diff -urN linux-2.6.16-rc3.orig/drivers/media/video/Makefile linux-2.6.16-rc3/drivers/media/video/Makefile
--- linux-2.6.16-rc3.orig/drivers/media/video/Makefile	2006-02-13 21:25:28.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/Makefile	2006-02-13 21:34:31.000000000 +0900
@@ -9,7 +9,8 @@
 zr36067-objs	:=	zoran_procfs.o zoran_device.o \
 			zoran_driver.o zoran_card.o
 tuner-objs	:=	tuner-core.o tuner-types.o tuner-simple.o \
-			mt20xx.o tda8290.o tea5767.o
+			mt20xx.o tda8290.o tea5767.o \
+			xc3028_meta.o xc3028_motv.o
 
 msp3400-objs	:=	msp3400-driver.o msp3400-kthreads.o
 
diff -urN linux-2.6.16-rc3.orig/drivers/media/video/compat.h linux-2.6.16-rc3/drivers/media/video/compat.h
--- linux-2.6.16-rc3.orig/drivers/media/video/compat.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/compat.h	2006-02-13 21:34:31.000000000 +0900
@@ -0,0 +1,286 @@
+/*
+ * $Id: compat.h,v 1.44 2006/01/15 09:35:16 mchehab Exp $
+ */
+
+#ifndef _COMPAT_H
+#define _COMPAT_H
+
+#include <linux/i2c-id.h>
+#include <linux/pm.h>
+#include <linux/version.h>
+#include <linux/utsname.h>
+#include <linux/sched.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
+# define minor(x) MINOR(x)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#include <linux/delay.h>
+# define need_resched() (current->need_resched)
+
+#define work_struct tq_struct
+#else
+#include <linux/device.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
+# define BUG_ON(condition) do { if ((condition)!=0) BUG(); } while(0)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23)
+# define irqreturn_t void
+# define IRQ_RETVAL(foobar)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,71)
+# define strlcpy(dest,src,len) strncpy(dest,src,(len)-1)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+# define iminor(inode) minor(inode->i_rdev)
+#endif
+
+#if defined(I2C_ADAP_CLASS_TV_ANALOG) && !defined(I2C_CLASS_TV_ANALOG)
+# define  I2C_CLASS_TV_ANALOG  I2C_ADAP_CLASS_TV_ANALOG
+# define  I2C_CLASS_TV_DIGITAL I2C_ADAP_CLASS_TV_DIGITAL
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
+# define __user
+# define __kernel
+# define __iomem
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
+# define pm_message_t                      u32
+# define pci_choose_state(pci_dev, state)  (state)
+# define PCI_D0                            (0)
+# define assert_spin_locked(foobar)
+#endif
+#if !defined(I2C_ALGO_SAA7134)
+#define I2C_ALGO_SAA7134 I2C_HW_B_BT848
+#endif
+#if !defined(I2C_HW_B_CX2388x)
+# define I2C_HW_B_CX2388x I2C_HW_B_BT848
+#endif
+#if !defined(I2C_HW_SAA7134)
+# define I2C_HW_SAA7134 I2C_ALGO_SAA7134
+#endif
+#if !defined(I2C_HW_SAA7146)
+# define I2C_HW_SAA7146 I2C_ALGO_SAA7146
+#endif
+
+#if !defined(I2C_HW_B_EM2820)
+#define I2C_HW_B_EM2820 0x99
+#endif
+
+#ifndef I2C_M_IGNORE_NAK
+# define I2C_M_IGNORE_NAK 0x1000
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
+#define __le32 __u32
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7))
+static inline unsigned long msecs_to_jiffies(const unsigned int m)
+{
+#if HZ <= 1000 && !(1000 % HZ)
+        return (m + (1000 / HZ) - 1) / (1000 / HZ);
+#else
+#if HZ > 1000 && !(HZ % 1000)
+        return m * (HZ / 1000);
+#else
+        return (m * HZ + 999) / 1000;
+#endif
+#endif
+}
+static inline unsigned int jiffies_to_msecs(const unsigned long j)
+{
+#if HZ <= 1000 && !(1000 % HZ)
+        return (1000 / HZ) * j;
+#else
+#if HZ > 1000 && !(HZ % 1000)
+        return (j + (HZ / 1000) - 1)/(HZ / 1000);
+#else
+        return (j * 1000) / HZ;
+#endif
+#endif
+}
+static inline void msleep(unsigned int msecs)
+{
+	unsigned long timeout = msecs_to_jiffies(msecs);
+	while (timeout) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		timeout = schedule_timeout(timeout);
+	}
+}
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
+static inline unsigned long msleep_interruptible(unsigned int msecs)
+{
+	unsigned long timeout = msecs_to_jiffies(msecs);
+
+	while (timeout) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		timeout = schedule_timeout(timeout);
+	}
+	return jiffies_to_msecs(timeout);
+}
+#endif
+
+#ifndef DVB_CVS
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
+#undef HAVE_LGDT330X
+#undef HAVE_TDA1004X
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+#undef HAVE_NXT200X
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
+#undef HAVE_CX24123
+#endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+/* some keys from 2.6.x which are not (yet?) in 2.4.x */
+# define KEY_PLAY                207
+# define KEY_PRINT	     	 210
+# define KEY_EMAIL         215
+# define KEY_SEARCH              217
+# define KEY_SELECT 	         0x161
+# define KEY_GOTO                0x162
+# define KEY_INFO                0x166
+# define KEY_CHANNEL             0x16b
+# define KEY_LANGUAGE            0x170
+# define KEY_SUBTITLE	         0x172
+# define KEY_ZOOM                0x174
+# define KEY_MODE		 0x175
+# define KEY_TV                  0x179
+# define KEY_CD                  0x17f
+# define KEY_TUNER               0x182
+# define KEY_TEXT                0x184
+# define KEY_DVD		 0x185
+# define KEY_AUDIO               0x188
+# define KEY_VIDEO               0x189
+# define KEY_RED                 0x18e
+# define KEY_GREEN               0x18f
+# define KEY_YELLOW              0x190
+# define KEY_BLUE                0x191
+# define KEY_CHANNELUP           0x192
+# define KEY_CHANNELDOWN         0x193
+# define KEY_RESTART	         0x198
+# define KEY_SHUFFLE     	 0x19a
+# define KEY_NEXT                0x197
+# define KEY_RADIO               0x181
+# define KEY_PREVIOUS            0x19c
+# define KEY_MHP                 0x16f
+# define KEY_EPG                 0x16d
+# define KEY_FASTFORWARD         208
+# define KEY_LIST                0x18b
+# define KEY_LAST                0x195
+# define KEY_CLEAR               0x163
+# define KEY_AUX                 0x186
+# define KEY_SCREEN              0x177
+# define KEY_PC                  0x178
+# define KEY_MEDIA               226
+# define KEY_SLOW                0x199
+# define KEY_OK                  0x160
+# define KEY_DIGITS              0x19d
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#define container_of(ptr, type, member) ({                      \
+        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+        (type *)( (char *)__mptr - offsetof(type,member) );})
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+#include <linux/mm.h>
+static inline unsigned long vmalloc_to_pfn(void * vmalloc_addr)
+{
+    return page_to_pfn(vmalloc_to_page(vmalloc_addr));
+}
+
+#ifndef wait_event_timeout
+#define wait_event_timeout(wq, condition, timeout)                   	     \
+({                                                                           \
+     long __ret = timeout;                                                   \
+     if (!(condition))                                                       \
+     do {                                                                    \
+	     DEFINE_WAIT(__wait);                                            \
+	     for (;;) {                                                      \
+    		     prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);    \
+	             if (condition)                                          \
+    	                 break;                                              \
+	             __ret = schedule_timeout(__ret);                        \
+    		     if (!__ret)                                             \
+            	         break;                                              \
+	     }                                                               \
+	     finish_wait(&wq, &__wait);                                      \
+     } while (0);							     \
+     __ret;                                                                  \
+})
+#endif
+
+#define remap_pfn_range remap_page_range
+
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
+#ifndef kcalloc
+#define kcalloc(n,size,flags)			\
+({						\
+  void * __ret = NULL;				\
+  __ret = kmalloc(n * size, flags);		\
+  if (__ret)					\
+         memset(__ret, 0, n * size);		\
+  __ret;					\
+}) 
+#endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+#ifndef kzalloc
+#define kzalloc(size, flags)				\
+({							\
+        void *__ret = kmalloc(size, flags);		\
+        if (__ret)			      		\
+                memset(__ret, 0, size);	      		\
+        __ret;				      		\
+})
+#endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
+# define class_device_create(a, b, c, d, e, f, g, h) class_simple_device_add(a, c, d, e, f, g, h)
+# define class_device_destroy(a, b) class_simple_device_remove(b)
+# define class_create(a, b) class_simple_create(a, b)
+# define class_destroy(a) class_simple_destroy(a)
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+# define class_device_create(a, b, c, d, e, f, g, h) class_device_create(a, c, d, e, f, g, h)
+#endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+# define input_allocate_device() kzalloc(sizeof(struct input_dev),GFP_KERNEL);
+# define input_free_device(input_dev) kfree(input_dev)
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
+#define DEFINE_MUTEX(a) DECLARE_MUTEX(a)
+#define mutex_lock_interruptible(a) down_interruptible(a)
+#define mutex_unlock(a) up(a)
+#define mutex_lock(a) down(a)
+#define mutex_init(a) init_MUTEX(a)
+#endif
+
+#endif
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -urN linux-2.6.16-rc3.orig/drivers/media/video/msp34x5.h linux-2.6.16-rc3/drivers/media/video/msp34x5.h
--- linux-2.6.16-rc3.orig/drivers/media/video/msp34x5.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/msp34x5.h	2006-02-13 21:34:31.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 linux-2.6.16-rc3.orig/drivers/media/video/saa7134/Makefile linux-2.6.16-rc3/drivers/media/video/saa7134/Makefile
--- linux-2.6.16-rc3.orig/drivers/media/video/saa7134/Makefile	2006-01-03 12:21:10.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/saa7134/Makefile	2006-02-13 21:34:31.000000000 +0900
@@ -2,6 +2,7 @@
 saa7134-objs :=	saa7134-cards.o saa7134-core.o saa7134-i2c.o	\
 		saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o    \
 		saa7134-video.o saa7134-input.o
+#		xc3028_motv.o
 
 obj-$(CONFIG_VIDEO_SAA7134) +=  saa7134.o saa7134-empress.o \
 				saa6752hs.o
diff -urN linux-2.6.16-rc3.orig/drivers/media/video/saa7134/doc/README.monstertv linux-2.6.16-rc3/drivers/media/video/saa7134/doc/README.monstertv
--- linux-2.6.16-rc3.orig/drivers/media/video/saa7134/doc/README.monstertv	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/saa7134/doc/README.monstertv	2006-02-13 21:34:32.000000000 +0900
@@ -0,0 +1,39 @@
+*Usage for Japan-NTSC user.
+
+ build kernel,saa7134 as module.
+ make all;make install;make install_modules
+ insmod saa7134
+
+ 
+*Why tvaudio?( Obsolete Article)
+
+ Monster TV 1,2 (Vender is SKNet Corp. http://www.sknet-web.co.jp/ )
+ contains MSP3445 as Japanese Multi voice decoder,but msp3400 driver of
+ upstream not support decoding Japanese-NTSC with MSP3445.
+ I tried apply Japan-NTSC to msp3400 driver,but it is unstable,driver locks up
+ kernel sometimes.
+ As of,I added MSP3445 with Japan-NTSC driver to tvaudio module.
+
+*Support status (2005/11/22)
+
+ Monster TV : Complete.
+ Monster TV2: May be OKay,but not be checked,please notify.
+ Monster TV3/3 Lite : Testing. (ID Reserved),
+                      I don't have card yet,please tell me 
+                      result of card. (lspci -n).
+ Monster TV PH-R    : Not Support Yet.
+                      Please tell me information of PCI ID and TUNER.
+ Monster TV PH-GTR  : Not support Yet (I will wish to support). 
+                      I need Datasheet of Panasonic MN82832 (Y/C Sep.) and
+		      Oren 433006MOC (Ghost Reducer),please send me these sheets.
+ Monster TV Pocket etc.... : I will not support, please help!
+ 
+ Monster TV V Series: Testing "Pure V" only.
+                      "VF" "VFM" "VM" is not tested yet. Pls,Help!
+                      Using silicon chip as tuner,I'm hacking it:-)
+ *Author
+ 
+  Ohta Kyuma <whatisthis@jcom.home.ne.jp>
+  
+
+ 
diff -urN linux-2.6.16-rc3.orig/drivers/media/video/saa7134/doc/README.saa7134.oss linux-2.6.16-rc3/drivers/media/video/saa7134/doc/README.saa7134.oss
--- linux-2.6.16-rc3.orig/drivers/media/video/saa7134/doc/README.saa7134.oss	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/saa7134/doc/README.saa7134.oss	2006-02-13 21:34:32.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 linux-2.6.16-rc3.orig/drivers/media/video/saa7134/doc/README.xc3028 linux-2.6.16-rc3/drivers/media/video/saa7134/doc/README.xc3028
--- linux-2.6.16-rc3.orig/drivers/media/video/saa7134/doc/README.xc3028	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/saa7134/doc/README.xc3028	2006-02-13 21:34:32.000000000 +0900
@@ -0,0 +1,37 @@
+== Hauppauge HVR 900 ==
+
+==== Installation ====
+
+1. get the v4l-dvb repository from linuxtv and type make for generating all symlinks in v4l-dvb/v4l
+2. copy tuner.h into v4l-dvb/linux/include/media/ in your v4l directory
+3. simply replace following files in the repository  
+ * Makefile
+ * em28xx-cards.c  
+ * em28xx.h  
+ * tuner-core.c  
+ * tuner-types.c  
+ * xc3028.c 
+with the files in this directory and simply recompile (copy these files to v4l-dvb/v4l)
+
+==== Firmware ====
+
+this device needs a firmware, which is stored in emBDA.sys
+build the firmwareextractor with
+$ gcc convert.c -o convert
+and extract the firmware
+$ ./convert emBDA.sys > /lib/firmware/xceive_xc_3028.fw
+(I only tested that tool with Hauppauge HVR 900, Terratec might work too but without any guarantee - please send me BDA files of other xc3028 devices)
+
+==== General ====
+
+ * the xc3028 works very reliable and the frequencies are correct for europe
+ * Please add your email, product name, vendor/product id to the discussion in the v4l wiki at www.linuxtv.org
+ * I'll not be responsible for any damage caused by this driver, use it with your own risk
+ 
+==== TODO ====
+
+ * some cleanup
+ * figuring out channel locks
+
+
+Markus Rechberger <mrechberger@gmail.com>
diff -urN linux-2.6.16-rc3.orig/drivers/media/video/saa7134/doc/convert.c linux-2.6.16-rc3/drivers/media/video/saa7134/doc/convert.c
--- linux-2.6.16-rc3.orig/drivers/media/video/saa7134/doc/convert.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/saa7134/doc/convert.c	2006-02-13 21:34:32.000000000 +0900
@@ -0,0 +1,84 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define ARRAY_SIZE(fw) sizeof(fw)/sizeof(fw[0])
+struct{
+	char *fwname;
+	char *fwstart;
+	char *fwstart2;
+	int length1;
+	int length2;
+} xc_firmware[]={{"Terratec","\x2a\x03\xe5\xe0\x00\x07\xf4\xd0\x01\xc0\x70\xe0\x00\x07","\x2a\x00\xc3\xe0\x00\x07\xb9\xf1\x05\x01\x6e\x82\x02\x82",2480,3876},
+              {"Hauppauge","\x2a\x03\xcc\xe0\x00\x07\xf4\xd0\x01\xc0\x70\xe0\x00\x07","\x2a\x00\xbe\xe0\x00\x07\xb9\xf1\x05\x01\x69\x82\x02\x82",2532,3886}};
+
+int main(int argc, char **argv){
+	FILE *file;
+	char buffer[1024];
+	char *fwmem=0;
+	int len;
+	long fleng=0;
+	int i;
+	int n=0;
+	int x;
+	int done=0;
+	int d=0;
+	int e=0;
+	if(argc!=2){
+		printf("./convert <filename>\n");
+		exit(1);
+	}
+	file=fopen(argv[1],"r");
+	fprintf(stderr,"Firmware extractor 0.1\n");
+	while((len=fread(buffer,1,1024,file))){
+		fleng+=len;
+		fwmem=realloc(fwmem,fleng);
+		memcpy(&fwmem[fleng-len],buffer,len);
+	}
+	fprintf(stderr,"Stored in memory: %ld\n",fleng);
+	for(n=0;n<ARRAY_SIZE(xc_firmware);n++){
+		for(i=0;i<fleng&&done!=2;i++){
+			if(xc_firmware[n].fwstart[d]==fwmem[i]&&done!=1){
+				if(d==13){
+					fprintf(stderr,"==== %s ====\n",xc_firmware[n].fwname);
+					printf("%d\n",xc_firmware[n].length1);
+					fprintf(stderr,"FW part 1 found!\n");
+					fprintf(stderr,"Length: %d bytes\n",xc_firmware[n].length1);
+					for(x=1;x<=xc_firmware[n].length1;x++){
+						fprintf(stderr,"%02x ",((unsigned char*)fwmem)[i-13+x]);
+						printf("%c",((unsigned char*)fwmem)[i-13+x]);
+						if(x%63==0){
+							fprintf(stderr,"\n");
+						}
+					}
+					fprintf(stderr,"\n");
+					done++;
+				}
+				d++;
+			} else {
+				d=0;
+			}
+			if(xc_firmware[n].fwstart2[e]==fwmem[i]){
+				if(e==13){
+					fprintf(stderr,"-------------------------------------------\n");
+					fprintf(stderr,"FW part 2 found!\n");
+					fprintf(stderr,"Length: %d bytes\n",xc_firmware[n].length2);
+					for(x=1;x<=xc_firmware[n].length2;x++){
+						printf("%c",((unsigned char*)fwmem)[i-13+x]);
+						fprintf(stderr,"%02x ",((unsigned char*)fwmem)[i-13+x]);
+						if(x%63==0){
+							fprintf(stderr,"\n");
+						}
+					}
+					done++;
+				}
+				e++;
+			} else {
+				e=0;
+			}
+		}
+	}
+	free(fwmem);
+	fclose(file);
+	exit(0);
+}
diff -urN linux-2.6.16-rc3.orig/drivers/media/video/saa7134/doc/test-oss linux-2.6.16-rc3/drivers/media/video/saa7134/doc/test-oss
--- linux-2.6.16-rc3.orig/drivers/media/video/saa7134/doc/test-oss	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/saa7134/doc/test-oss	2006-02-13 21:34:32.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 linux-2.6.16-rc3.orig/drivers/media/video/saa7134/doc/xc3028.c linux-2.6.16-rc3/drivers/media/video/saa7134/doc/xc3028.c
--- linux-2.6.16-rc3.orig/drivers/media/video/saa7134/doc/xc3028.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/saa7134/doc/xc3028.c	2006-02-13 21:34:32.000000000 +0900
@@ -0,0 +1,218 @@
+/*
+
+   Xceive -  xc3028 tuner interface
+
+   Copyright (c) 2006 Markus Rechberger <mrechberger@gmail.com>
+
+
+TODO: - remove em28xx dependency
+      - add channel locking (requires some more reverse engineering)
+      - try to get the datasheet from Xceive :)
+
+   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/i2c.h>
+#include <linux/usb.h>
+#include "compat.h"
+#include <linux/videodev.h>
+#include "em28xx.h"
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <media/tuner.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#include "i2c-compat.h"
+#endif
+
+#define XC3028_DEFAULT_FIRMWARE "xceive_xc_3028.fw"
+
+int xceive_set_color(struct i2c_client *c);
+
+/* ---------------------------------------------------------------------- */
+
+int xc3028_probe(struct i2c_client *c)
+{
+	printk("xc3028: probe function unknown\n");
+	return -1;
+}
+
+static void xc3028_set_tv_freq(struct i2c_client *c, unsigned int freq){
+	// the frequency is just shifted and there's a 1:1 relation for all frequencies
+	// E11 is Das Erste in Germany/Ulm all other channels match their frequency too
+	
+	unsigned char chanbuf[4];
+	freq<<=2;
+	chanbuf[0]=0;
+	chanbuf[1]=0;
+	chanbuf[2]=(freq&0xff00)>>8;
+	chanbuf[3]=freq&0x00ff;
+	i2c_master_send(c,"\xa0\x00\x00\x00",4);
+	i2c_master_send(c,"\x1e\x1f\x13\x87\x18\x02\x93\x91\x44\x86\x96\x8c",12);
+	i2c_master_send(c,"\x00\x8c",2);
+	i2c_master_send(c,"\x80\x02\x00\x00",4);
+	i2c_master_send(c,chanbuf,4);
+}
+
+int xc3028_init(struct i2c_client *c)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	int ret;
+	const struct firmware *fw = NULL;
+	u8 *firmware;
+	char *fwoffset;
+	u8 initoffset[8];
+	u8 linebuffer[100];
+	int splitrange;
+	struct em28xx *dev;
+	int i=0;
+	int d=0;
+	int txtlen;
+	long fwoff;
+	size_t firmware_size = 5000;
+
+	// request firmware from /lib/firmware, note that the file got extracted by the convert application I wrote and which is available
+	// on linuxtv.org / xc3028
+	
+	ret = request_firmware(&fw, XC3028_DEFAULT_FIRMWARE, &t->i2c.dev);
+	if (ret) {
+		printk("xc3028: no firmware uploaded please check %s\n",XC3028_DEFAULT_FIRMWARE);
+		return ret;
+	}
+	firmware = fw->data;
+	firmware_size = fw->size;
+
+	// small firmware check, both firmwares I have are between 6 and 7k bytes
+	
+	if(fw->size>7000||fw->size<6000){
+		printk("xc3028: wrong firmware provided!\n");
+		release_firmware(fw);
+		return(ret);
+	}
+	for(i=0;i<8&&firmware[i]!='\n';i++);
+	txtlen=i;
+	firmware[i++]=0;
+	fwoff=simple_strtol(firmware,&fwoffset,10);
+	if(fwoff>fw->size){
+		printk("xc3028: firmware offset doesn't match!\n");
+		release_firmware(fw);
+		return(-1);
+	}
+
+	linebuffer[d++]=0x2a;
+        dev=c->adapter->algo_data;
+
+	// 0x08 is a GPIO address of the em28xx has to get replaced with something generic here
+
+	dev->em28xx_write_regs(dev, 0x08, "\x6d", 1);
+	mdelay(100);
+	dev->em28xx_write_regs(dev, 0x08, "\x7d", 1);
+	mdelay(100);
+
+	// the firmware always starts with 0x2a + 0x40 bytes payload I use to add the offset of the first part
+	// as the first line into the firmware binary
+	
+	while(i!=fw->size){
+		linebuffer[d++]=firmware[i];
+		if((d%64==0&&d!=0)||i==fwoff+txtlen){
+			i2c_master_send(c,linebuffer,d);
+			if(i==(fwoff+txtlen)){
+                                i2c_master_send(c,"\x02\x02",2);
+                                i2c_master_send(c,"\x02\x03",2);
+                                i2c_master_send(c,"\x00\x8c",2);
+                                i2c_master_send(c,"\x00\x00\x00\x00",4);
+				// another reset here
+				dev->em28xx_write_regs(dev, 0x08, "\x6d", 1);
+				mdelay(100);
+				dev->em28xx_write_regs(dev, 0x08, "\x7d", 1);
+				mdelay(100);
+                                
+			}       
+			linebuffer[0]=0x2a;
+			d=1;
+		}
+		i++;
+	}
+	printk("xc3024: Firmware uploaded\n");
+
+	firmware[firmware_size-1]=0;
+
+	release_firmware(fw);
+	
+	/* MAGIC VALUES */
+        i2c_master_send(c,"\x13\x39",2);
+        i2c_master_send(c,"\x0c\x80\xf0\xf7\x3e\x75\xc1\x8a\xe4\x02\x00",11);
+        i2c_master_send(c,"\x05\x0f\xee\xaa\x5f\xea\x90",7);
+        i2c_master_send(c,"\x06\x00\x0a\x4d\x8c\xf2\xd8\xcf\x30\x79\x9f",11);
+        i2c_master_send(c,"\x0b\x0d\xa4\x6c",4);
+        i2c_master_send(c,"\x0a\x01\x67\x24\x40\x08\xc3\x20\x10\x64\x3c\xfa\xf7\xe1\x0c\x2c",0x10);
+        i2c_master_send(c,"\x09\x0b",0x2);
+        i2c_master_send(c,"\x10\x13",0x2);
+        i2c_master_send(c,"\x16\x12",0x2);
+        i2c_master_send(c,"\x1f\x02",0x2);
+        i2c_master_send(c,"\x21\x02",0x2);
+        i2c_master_send(c,"\x01\x02",0x2);
+        i2c_master_send(c,"\x2b\x10",0x2);
+        i2c_master_send(c,"\x02\x02",0x2);
+        i2c_master_send(c,"\x02\x03",0x2);
+        i2c_master_send(c,"\x00\x8c",0x2);
+
+#if 0
+	// if set video will mostly be black/white  - if set_color is called instead the video will have color
+        i2c_master_send(c,"\x80\x01\x00\x00",0x4);
+        i2c_master_send(c,"\x00\x5e\x00\x29",0x4);
+        i2c_master_send(c,"\x2b\x1a",0x2);
+#endif
+	xceive_set_color(c);
+	t->set_tv_freq    = xc3028_set_tv_freq;
+	return(0);
+}
+
+int xceive_set_color(struct i2c_client *c){
+	// I found this codeblock within the sniffed logfile it got called as it is a several times after 0x00 0x04 tuner settings are made
+	i2c_master_send(c,"\x80\x01\x00\x00",4);
+	i2c_master_send(c,"\x00\x5e\x00\x29",4);
+	i2c_master_send(c,"\x2b\x1a",2);
+	i2c_master_send(c,"\x2b\x1b",2);
+	i2c_master_send(c,"\x14\x01\x6c\x25\x82\x38\xa4\x49\xa9\x24\x96\x69",0x0c);
+	i2c_master_send(c,"\x13\x14\x08\x30\x10\x6c\x18\x12\x0d\x19\x32\xad",0x0c);
+	i2c_master_send(c,"\x0d\x01\x4b\x03\x97\x55\xc7\xd7\x00\xa1\xeb\x8f\x5c",0x0d);
+	i2c_master_send(c,"\x1a\x00\x00\x16\x8a\x40\x00\x00\x00\x20",0x0a);
+	i2c_master_send(c,"\x2d\x01",2);
+	i2c_master_send(c,"\x18\x01",2);
+	i2c_master_send(c,"\x1b\x01\xb6\x15\x16\xb1\xa6\xd2\xa9\x12\x41\x66",0x0c);
+	i2c_master_send(c,"\x1d\x00",2);
+	i2c_master_send(c,"\x0f\x00\x29\x56\xb0\x00\xb6",0x07);
+	i2c_master_send(c,"\x20\x00",0x02);
+	i2c_master_send(c,"\x1e\x10\x32\x00\x00\x02\xe4\x81\x00\x06\xa9\x04",0x0c);
+	i2c_master_send(c,"\x22\x29",0x02);
+	i2c_master_send(c,"\x23\x06",0x02);
+	i2c_master_send(c,"\x25\x00\x09\x90\x09\x06\x64\x02\x41",0x09);
+	i2c_master_send(c,"\x26\xcc",0x02);
+	i2c_master_send(c,"\x29\x40",0x02);
+	i2c_master_send(c,"\x21\x03",0x02);
+	i2c_master_send(c,"\x00\x8c",0x02);
+	i2c_master_send(c,"\x00\x00\x00\x00",0x04);
+	i2c_master_send(c,"\x00\x04",0x02);
+	return(0);
+}
+
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -urN linux-2.6.16-rc3.orig/drivers/media/video/saa7134/msp34x5.h linux-2.6.16-rc3/drivers/media/video/saa7134/msp34x5.h
--- linux-2.6.16-rc3.orig/drivers/media/video/saa7134/msp34x5.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/saa7134/msp34x5.h	2006-02-13 21:34:32.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 linux-2.6.16-rc3.orig/drivers/media/video/saa7134/saa7134-cards.c linux-2.6.16-rc3/drivers/media/video/saa7134/saa7134-cards.c
--- linux-2.6.16-rc3.orig/drivers/media/video/saa7134/saa7134-cards.c	2006-02-13 21:25:28.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/saa7134/saa7134-cards.c	2006-02-14 00:40:06.000000000 +0900
@@ -289,15 +289,16 @@
 		/* "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,*/ /* 20041005 K.Ohta */
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-
+	        .needs_tvaudio = 1, /* 20060203 K.Ohta */
 		.inputs         = {{
 			.name = name_tv,
 			.vmux = 1,
-			.amux = TV,
+			.amux = LINE2,
 			.tv   = 1,
 		},{
 			.name = name_comp1,
@@ -996,6 +997,31 @@
 			.vmux = 8,
 			.amux = LINE2,
 		}},
+          },[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_MANLI_MTV002] = {
 		/* Ognjen Nastic <ognjen@logosoft.ba> */
@@ -2619,6 +2645,88 @@
 			.gpio = 0x000000,	/* GPIO21=Low for FM radio antenna */
 		},
 	},
+        [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 */
+	           .radio_type     = UNSET,
+	           .tuner_addr	   = ADDR_UNSET,
+		   .radio_addr	   = ADDR_UNSET,
+
+                   .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_MONSTERTV3] = {
+                /* "K.Ohta" <alpha292@bremen.or.jp> Skelton...Pls.Test! 20050317*/
+                .name           = "SKNet Monster TV3/Lite",
+                .audio_clock    = 0x00187de7,
+                .tuner_type     = TUNER_PHILIPS_FQ1286, /* Philips FQ1286 (Testing) */
+     		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+                .inputs         = {{
+                        .name = name_tv,
+                        .vmux = 1,
+                        .amux = TV,
+                        .tv   = 1,
+                },{
+                        .name = name_comp1,
+                        .vmux = 0,
+                        .amux = LINE1,
+                },{
+                        .name = name_svideo,
+                        .vmux = 8,
+                        .amux = LINE1,
+                }},
+ 	},
+       	[SAA7134_BOARD_MONSTERTV_V] = {
+                /* "K.Ohta" <whatisthis@jcom.home.ne.jp> Skelton...Pls.Test! 20050730*/
+                .name           = "SKNet Monster TV V/VF",
+                .audio_clock    = 0x00187de7,
+                .tuner_type     = TUNER_XCEIVE_XC_x028_MOTV, /* XCEIVE's Silicon tuner (Testing) */
+     		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET, // Testing
+		.radio_addr	= ADDR_UNSET,
+                .inputs         = {{
+                        .name = name_tv,
+                        .vmux = 1,
+                        .amux = TV,
+                        .tv   = 1,
+                },{
+                        .name = name_comp1,
+                        .vmux = 2,
+                        .amux = LINE1,
+                },{
+                        .name = name_svideo,
+                        .vmux = 0,
+                        .amux = LINE1,
+                }},
+                   .radio = {
+                           .name = name_radio,
+                           .amux = TV,
+		},
+
+ 	},
+   
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -3090,6 +3198,24 @@
 		.subdevice    = 0x0319,
 		.driver_data  = SAA7134_BOARD_FLYDVB_TRIO,
 	},{
+  		.vendor       = PCI_VENDOR_ID_PHILIPS, /* Add 20040101 */
+  		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+                .subvendor    = 0x1131,
+                .subdevice    = 0x4f4d,
+ 		.driver_data  = SAA7134_BOARD_MONSTERTV2,
+        },{
+ 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+  		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133, /* OKay? 20050716 K.Ohta*/
+                .subvendor    = 0x1131,
+                .subdevice    = 0x4ee9,
+  		.driver_data  = SAA7134_BOARD_MONSTERTV3,
+	},{
+ 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+  		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133, /* OKay? 20050730 K.Ohta*/
+                .subvendor    = 0x1131,
+                .subdevice    = 0x4ef3,
+  		.driver_data  = SAA7134_BOARD_MONSTERTV_V,
+	},{
 		/* --- boards without eeprom + subsystem ID --- */
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -3128,7 +3254,7 @@
 		.subvendor    = PCI_ANY_ID,
 		.subdevice    = PCI_ANY_ID,
 		.driver_data  = SAA7134_BOARD_UNKNOWN,
-	},{
+        },{
 		/* --- end of list --- */
 	}
 };
@@ -3237,6 +3363,7 @@
 	return 0;
 }
 
+
 /* stuff which needs working i2c */
 int saa7134_board_init2(struct saa7134_dev *dev)
 {
@@ -3361,6 +3488,19 @@
 		i2c_transfer(&dev->i2c_adap, &msg, 1);
 		}
 		break;
+	case SAA7134_BOARD_MONSTERTV: // 20060127 K.Ohta
+	case SAA7134_BOARD_MONSTERTV2: // 20060127 K.Ohta
+	case SAA7134_BOARD_MONSTERTV3: // 20060127 K.Ohta
+	       break; //20060129
+	case SAA7134_BOARD_MONSTERTV_V: // 20060127 K.Ohta
+               {
+		  struct tuner_setup tun_setup;
+		  tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
+		  tun_setup.type = dev->tuner_type;
+		  tun_setup.addr = dev->tuner_addr;		  
+		  saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
+	       }
+	       break;
 	}
 	return 0;
 }
diff -urN linux-2.6.16-rc3.orig/drivers/media/video/saa7134/saa7134-core.c linux-2.6.16-rc3/drivers/media/video/saa7134/saa7134-core.c
--- linux-2.6.16-rc3.orig/drivers/media/video/saa7134/saa7134-core.c	2006-02-13 21:25:28.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/saa7134/saa7134-core.c	2006-02-13 21:34:32.000000000 +0900
@@ -913,7 +913,7 @@
 	/* initialize hardware #2 */
 	saa7134_board_init2(dev);
 	saa7134_hwinit2(dev);
-
+        /* printk("TUNER=%d\n",dev->tuner_type); // For DEBUG */
 	/* load i2c helpers */
 	if (TUNER_ABSENT != dev->tuner_type)
 		request_module("tuner");
@@ -923,10 +923,11 @@
 		request_module("saa6752hs");
 		request_module_depend("saa7134-empress",&need_empress);
 	}
-
+  	if (saa7134_boards[dev->board].needs_tvaudio) /* 20040105 K.Ohta */
+ 		request_module("tvaudio");
 	if (card_is_dvb(dev))
 		request_module_depend("saa7134-dvb",&need_dvb);
-
+ 
 
 	if (alsa)
 		request_module_depend("saa7134-alsa",&need_alsa);
diff -urN linux-2.6.16-rc3.orig/drivers/media/video/saa7134/saa7134-i2c.c linux-2.6.16-rc3/drivers/media/video/saa7134/saa7134-i2c.c
--- linux-2.6.16-rc3.orig/drivers/media/video/saa7134/saa7134-i2c.c	2006-02-13 21:25:28.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/saa7134/saa7134-i2c.c	2006-02-14 01:11:29.000000000 +0900
@@ -333,7 +333,7 @@
 	int conf  = dev->tda9887_conf;
 	struct tuner_setup tun_setup;
 
-	d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
+	printk( "%s i2c attach [addr=0x%x,client=%s]\n",
 		client->driver->driver.name, client->addr, client->name);
 
 	/* Am I an i2c remote control? */
@@ -349,7 +349,7 @@
 			break;
 		}
 	}
-
+        /* printk("TUNER=%d\n",tuner); // Debug */
 	if (!client->driver->command)
 		return 0;
 
@@ -369,7 +369,7 @@
 
 		tun_setup.type = tuner;
 		tun_setup.addr = saa7134_boards[dev->board].tuner_addr;
-
+	        printk("TUNER=%d ADDR=%02x\n",tun_setup.type,tun_setup.addr); // Debug */
 		if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) {
 
 			tun_setup.mode_mask = T_ANALOG_TV;
@@ -444,7 +444,7 @@
 	unsigned char buf;
 	int i,rc;
 
-	for (i = 0; i < 128; i++) {
+	for (i = 0; i < 255; i++) {
 		c->addr = i;
 		rc = i2c_master_recv(c,&buf,0);
 		if (rc < 0)
diff -urN linux-2.6.16-rc3.orig/drivers/media/video/saa7134/saa7134-input.c linux-2.6.16-rc3/drivers/media/video/saa7134/saa7134-input.c
--- linux-2.6.16-rc3.orig/drivers/media/video/saa7134/saa7134-input.c	2006-02-13 21:25:28.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/saa7134/saa7134-input.c	2006-02-13 21:34:32.000000000 +0900
@@ -148,7 +148,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 linux-2.6.16-rc3.orig/drivers/media/video/saa7134/saa7134-tvaudio.c linux-2.6.16-rc3/drivers/media/video/saa7134/saa7134-tvaudio.c
--- linux-2.6.16-rc3.orig/drivers/media/video/saa7134/saa7134-tvaudio.c	2006-02-13 21:25:28.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/saa7134/saa7134-tvaudio.c	2006-02-13 21:34:32.000000000 +0900
@@ -157,7 +157,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))
 
@@ -337,6 +344,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;	   
 	}
 }
 
@@ -451,6 +465,9 @@
 			/* No nicam detected */
 		}
 		break;
+	 case TVAUDIO_FM_EIAJ_STEREO:
+	   /* Not Implemented Yet. */
+	   break;
 	}
 	if (retval != -1)
 		dprintk("found audio subchannels:%s%s%s%s\n",
@@ -494,6 +511,9 @@
 	case TVAUDIO_FM_SAT_STEREO:
 		/* Not implemented */
 		break;
+	 case TVAUDIO_FM_EIAJ_STEREO: /* 20040105 K.Ohta */
+	   /* Not Implemented Yet. */
+	   break;
 	}
 	return 0;
 }
diff -urN linux-2.6.16-rc3.orig/drivers/media/video/saa7134/saa7134-video.c linux-2.6.16-rc3/drivers/media/video/saa7134/saa7134-video.c
--- linux-2.6.16-rc3.orig/drivers/media/video/saa7134/saa7134-video.c	2006-02-13 21:25:28.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/saa7134/saa7134-video.c	2006-02-13 21:34:32.000000000 +0900
@@ -1847,7 +1847,7 @@
 		dev->crop_current = crop->c;
 		return 0;
 	}
-
+	
 	/* --- tuner ioctls ------------------------------------------ */
 	case VIDIOC_G_TUNER:
 	{
@@ -1927,17 +1927,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 linux-2.6.16-rc3.orig/drivers/media/video/saa7134/saa7134.h linux-2.6.16-rc3/drivers/media/video/saa7134/saa7134.h
--- linux-2.6.16-rc3.orig/drivers/media/video/saa7134/saa7134.h	2006-02-13 21:25:28.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/saa7134/saa7134.h	2006-02-13 21:34:32.000000000 +0900
@@ -60,6 +60,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 {
@@ -210,6 +211,10 @@
 #define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS  82
 #define SAA7134_BOARD_CINERGY250PCI 83
 #define SAA7134_BOARD_FLYDVB_TRIO 84
+/* MONSTER TV Series: Patched by K.Ohta <whatisthis@jcom.home.ne.jp */
+#define SAA7134_BOARD_MONSTERTV2  85 /* Add: 2004.01.01 Pls.Test! */
+#define SAA7134_BOARD_MONSTERTV3  86 /* Add: 2004.11.10 Pls.Test! */
+#define SAA7134_BOARD_MONSTERTV_V 87 /* Add: 2005.07.30 Pls.Test! */
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -257,9 +262,9 @@
 	unsigned int		radio_type;
 	unsigned char		tuner_addr;
 	unsigned char		radio_addr;
-
+        unsigned int            needs_tvaudio;
 	unsigned int            tda9887_conf;
-
+   
 	/* peripheral I/O */
 	enum saa7134_video_out  video_out;
 	enum saa7134_mpeg_type  mpeg;
diff -urN linux-2.6.16-rc3.orig/drivers/media/video/tuner-core.c linux-2.6.16-rc3/drivers/media/video/tuner-core.c
--- linux-2.6.16-rc3.orig/drivers/media/video/tuner-core.c	2006-02-13 21:25:28.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/tuner-core.c	2006-02-13 21:36:31.000000000 +0900
@@ -18,6 +18,7 @@
 #include <linux/types.h>
 #include <linux/videodev.h>
 #include <linux/init.h>
+#include "saa7134/saa7134.h"
 
 #include <media/tuner.h>
 #include <media/v4l2-common.h>
@@ -73,6 +74,9 @@
 
 /* ---------------------------------------------------------------------- */
 
+extern void xc3028_set_tv_freq(struct i2c_client *c,unsigned int freq);
+extern int xc3028_motv_init(struct i2c_client *c,struct  saa7134_dev *dev);
+
 /* Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHz */
 static void set_tv_freq(struct i2c_client *c, unsigned int freq)
 {
@@ -97,7 +101,11 @@
 		else
 			freq = tv_range[1] * 16;
 	}
-	t->set_tv_freq(c, freq);
+	if(t->type==TUNER_XCEIVE_XC_x028_MOTV) { // 20060127 K.Ohta
+		xc3028_set_tv_freq(c,freq); 
+	} else {
+		t->set_tv_freq(c, freq);
+	}
 }
 
 static void set_radio_freq(struct i2c_client *c, unsigned int freq)
@@ -123,8 +131,11 @@
 		else
 			freq = radio_range[1] * 16000;
 	}
-
-	t->set_radio_freq(c, freq);
+	if(t->type==TUNER_XCEIVE_XC_x028_MOTV) { // 20060127 K.Ohta
+		xc3028_set_tv_freq(c,freq); 
+	} else {
+		t->set_radio_freq(c, freq);
+	}
 }
 
 static void set_freq(struct i2c_client *c, unsigned long freq)
@@ -148,6 +159,7 @@
 	}
 }
 
+
 static void set_type(struct i2c_client *c, unsigned int type,
 		     unsigned int new_mode_mask)
 {
@@ -217,6 +229,11 @@
 		i2c_master_send(c,buffer,4);
 		default_tuner_init(c);
 		break;
+ 	case TUNER_XCEIVE_XC_x028_MOTV: /* 20060127 K.Ohta */
+ 		/* WIP! NEED GPIO in SAA7133 TO RESET Tuner?*/
+ 	        xc3028_motv_init(c, &(t->i2c.dev));
+ 	        printk("WARNING: XCEIVE's TUNER DRIVER for MonstetTV V is non imcomplete\n");
+ 		break;
 	default:
 		default_tuner_init(c);
 		break;
@@ -248,6 +265,9 @@
 		tun_setup->addr == c->addr)) {
 			set_type(c, tun_setup->type, tun_setup->mode_mask);
 	}
+   
+	   
+	
 }
 
 static inline int check_mode(struct tuner *t, char *cmd)
@@ -641,9 +661,8 @@
 				return 0;
 			if (check_v4l2(t) == EINVAL)
 				return 0;
-
-			set_freq(client, *v);
-			return 0;
+		       set_freq(client, *v);
+		       return 0;
 		}
 	case VIDIOCGTUNER:
 		{
diff -urN linux-2.6.16-rc3.orig/drivers/media/video/tuner-types.c linux-2.6.16-rc3/drivers/media/video/tuner-types.c
--- linux-2.6.16-rc3.orig/drivers/media/video/tuner-types.c	2006-02-13 21:25:28.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/tuner-types.c	2006-02-13 22:30:53.000000000 +0900
@@ -1101,6 +1101,25 @@
 	},
 };
 
+/* ------------ TUNER_SAMSUNG_TCPN_2121P30A - Samsung NTSC ------------ */
+/*
+ * ADD for MonsterTV V 20060203
+ */
+static struct tuner_range tuner_xceive_xcx028_motv_ntsc_ranges[] = {
+	{ 16 * 175.75 /*MHz*/, 0x01, },
+	{ 16 * 410.25 /*MHz*/, 0x02, },
+	{ 16 * 999.99        , 0x08, },
+};
+
+static struct tuner_params tuner_xceive_xcx028_motv_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_xceive_xcx028_motv_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_xceive_xcx028_motv_ntsc_ranges),
+		.config = 0xce, /* TEMPORALLY */
+	},
+};
+
 /* --------------------------------------------------------------------- */
 
 struct tunertype tuners[] = {
@@ -1401,6 +1420,10 @@
 		.name   = "Samsung TCPN 2121P30A",
 		.params = tuner_samsung_tcpn_2121p30a_params,
 	},
+        [TUNER_XCEIVE_XC_x028_MOTV] = { /* XCWEIVE XC?028 for MonsterTV V (OOPS!) */
+	        .name   = "Xeive XC?028 Silicon tuner for SKNet Monster TV VSeries",
+	        .params = tuner_xceive_xcx028_motv_params,
+	},
 };
 
 unsigned const int tuner_count = ARRAY_SIZE(tuners);
diff -urN linux-2.6.16-rc3.orig/drivers/media/video/tvaudio.c linux-2.6.16-rc3/drivers/media/video/tvaudio.c
--- linux-2.6.16-rc3.orig/drivers/media/video/tvaudio.c	2006-02-13 21:25:28.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/tvaudio.c	2006-02-13 21:34:33.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:
@@ -34,6 +36,8 @@
 #include <media/v4l2-common.h>
 
 #include "tvaudio.h"
+#include "msp34x5.h"
+#define I2C_MSP3445 0x80 
 
 /* ---------------------------------------------------------------------- */
 /* insmod args                                                            */
@@ -42,7 +46,7 @@
 module_param(debug, int, 0644);
 
 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)
@@ -144,6 +148,7 @@
 	I2C_TDA985x_H >> 1,
 	I2C_TDA9874   >> 1,
 	I2C_PIC16C54  >> 1,
+        I2C_MSP3445   >> 1, /* Okay? */
 	I2C_CLIENT_END };
 I2C_CLIENT_INSMOD;
 
@@ -183,6 +188,7 @@
 	return 0;
 }
 
+
 static int chip_write_masked(struct CHIPSTATE *chip, int subaddr, int val, int mask)
 {
 	if (mask != 0) {
@@ -1235,6 +1241,321 @@
 	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) {
+         printk("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)) {
+		tvaudio_info("%s: I/O error (read2)\n",
+		       chip->c.name);
+		return -1;
+	}
+	tvaudio_dbg("%s: read: subadr:reg %04x:%04x=0x%02x%02x\n",
+		    chip->c.name,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);
+      tvaudio_dbg("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);
+      tvaudio_dbg("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
+   tvaudio_dbg("%s: write: subadr:reg %04x:%04x=%04x\n",
+	       chip->c.name,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;
+	}
+        tvaudio_info(
+	   "tvaudio: setmode : chip->mode = 0x%04x\n",chip->mode);
+        tvaudio_info(
+	   "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? */
+	      }
+	   }
+	tvaudio_info(
+		"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;
+	tvaudio_dbg(
+	       "%s: thread checkmode\n", chip->c.name);
+	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                              */
 
@@ -1465,6 +1786,23 @@
 
 		.init       = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}},
 	},
+   	{
+		.name       = "msp3445",
+		//.id         = -1,
+	        .insmodopt  = &msp3445,
+		.id         = I2C_DRIVERID_MSP3400, /* FIXME */
+		.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 */
 };
 
@@ -1657,12 +1995,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;
 	}
 
diff -urN linux-2.6.16-rc3.orig/drivers/media/video/tvaudio.h linux-2.6.16-rc3/drivers/media/video/tvaudio.h
--- linux-2.6.16-rc3.orig/drivers/media/video/tvaudio.h	2006-01-03 12:21:10.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/tvaudio.h	2006-02-13 21:34:33.000000000 +0900
@@ -12,3 +12,4 @@
 #define I2C_TEA6420	   0x98
 
 #define I2C_PIC16C54       0x96 /* PV951 */
+#define I2C_MSP3445G       0x80 /* Monster TV */       
diff -urN linux-2.6.16-rc3.orig/drivers/media/video/tveeprom.c linux-2.6.16-rc3/drivers/media/video/tveeprom.c
--- linux-2.6.16-rc3.orig/drivers/media/video/tveeprom.c	2006-02-13 21:25:28.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/tveeprom.c	2006-02-13 21:34:33.000000000 +0900
@@ -229,6 +229,7 @@
 	/* 120-129 */
 	{ TUNER_ABSENT,        "Xceive XC3028"},
 	{ TUNER_ABSENT,        "Philips FQ1216LME MK5"},
+	{ TUNER_XCEIVE_XC_x028_MOTV,        "Xceive XC3028 for MonsterTV"}, /* XCEIVE TUNER for MonsterTV */
 };
 
 static struct HAUPPAUGE_AUDIOIC
diff -urN linux-2.6.16-rc3.orig/drivers/media/video/v4l1-compat.c linux-2.6.16-rc3/drivers/media/video/v4l1-compat.c
--- linux-2.6.16-rc3.orig/drivers/media/video/v4l1-compat.c	2006-02-13 21:25:28.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/v4l1-compat.c	2006-02-13 21:34:33.000000000 +0900
@@ -820,8 +820,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;
diff -urN linux-2.6.16-rc3.orig/drivers/media/video/xc3028_meta.c linux-2.6.16-rc3/drivers/media/video/xc3028_meta.c
--- linux-2.6.16-rc3.orig/drivers/media/video/xc3028_meta.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/xc3028_meta.c	2006-02-13 21:34:33.000000000 +0900
@@ -0,0 +1,112 @@
+/*
+
+   Xceive -  xc3028 tuner interface
+
+   Copyright (c) 2006 Markus Rechberger <mrechberger@gmail.com>
+
+
+TODO: - remove em28xx dependency
+      - add channel locking (requires some more reverse engineering)
+      - try to get the datasheet from Xceive :)
+
+   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.
+
+ Modified Information: 20060127 K.Ohta
+ * Depends for SKNet Monster TV V (WIP!) 
+*/
+
+#include <linux/i2c.h>
+#include <linux/usb.h>
+#include "compat.h"
+#include <linux/videodev.h>
+/* #include "em28xx.h" */
+
+//#include "saa7134.h" /* APPLY TO SAA713x (MonsterTV V) */
+//#include "saa7134-reg.h" /* APPLY TO SAA713x (MonsterTV V) */
+
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <media/tuner.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#include "i2c-compat.h"
+#endif
+
+#define XC3028_DEFAULT_FIRMWARE "xceive_xc_3028.fw"
+
+//int xceive_set_color(struct i2c_client *c);
+
+/* ---------------------------------------------------------------------- */
+
+int xc3028_probe(struct i2c_client *c)
+{
+	printk("xc3028: probe function unknown\n");
+	return -1;
+}
+
+void xc3028_set_tv_freq(struct i2c_client *c, unsigned int freq){
+	// the frequency is just shifted and there's a 1:1 relation for all frequencies
+	// E11 is Das Erste in Germany/Ulm all other channels match their frequency too
+	
+	unsigned char chanbuf[4];
+	freq<<=2;
+	chanbuf[0]=0;
+	chanbuf[1]=0;
+	chanbuf[2]=(freq&0xff00)>>8;
+	chanbuf[3]=freq&0x00ff;
+	i2c_master_send(c,"\xa0\x00\x00\x00",4);
+	i2c_master_send(c,"\x1e\x1f\x13\x87\x18\x02\x93\x91\x44\x86\x96\x8c",12);
+	i2c_master_send(c,"\x00\x8c",2);
+	i2c_master_send(c,"\x80\x02\x00\x00",4);
+	i2c_master_send(c,chanbuf,4);
+}
+
+
+int xceive_set_color(struct i2c_client *c){
+	// I found this codeblock within the sniffed logfile it got called as it is a several times after 0x00 0x04 tuner settings are made
+	i2c_master_send(c,"\x80\x01\x00\x00",4);
+	i2c_master_send(c,"\x00\x5e\x00\x29",4);
+	i2c_master_send(c,"\x2b\x1a",2);
+	i2c_master_send(c,"\x2b\x1b",2);
+	i2c_master_send(c,"\x14\x01\x6c\x25\x82\x38\xa4\x49\xa9\x24\x96\x69",0x0c);
+	i2c_master_send(c,"\x13\x14\x08\x30\x10\x6c\x18\x12\x0d\x19\x32\xad",0x0c);
+	i2c_master_send(c,"\x0d\x01\x4b\x03\x97\x55\xc7\xd7\x00\xa1\xeb\x8f\x5c",0x0d);
+	i2c_master_send(c,"\x1a\x00\x00\x16\x8a\x40\x00\x00\x00\x20",0x0a);
+	i2c_master_send(c,"\x2d\x01",2);
+	i2c_master_send(c,"\x18\x01",2);
+	i2c_master_send(c,"\x1b\x01\xb6\x15\x16\xb1\xa6\xd2\xa9\x12\x41\x66",0x0c);
+	i2c_master_send(c,"\x1d\x00",2);
+	i2c_master_send(c,"\x0f\x00\x29\x56\xb0\x00\xb6",0x07);
+	i2c_master_send(c,"\x20\x00",0x02);
+	i2c_master_send(c,"\x1e\x10\x32\x00\x00\x02\xe4\x81\x00\x06\xa9\x04",0x0c);
+	i2c_master_send(c,"\x22\x29",0x02);
+	i2c_master_send(c,"\x23\x06",0x02);
+	i2c_master_send(c,"\x25\x00\x09\x90\x09\x06\x64\x02\x41",0x09);
+	i2c_master_send(c,"\x26\xcc",0x02);
+	i2c_master_send(c,"\x29\x40",0x02);
+	i2c_master_send(c,"\x21\x03",0x02);
+	i2c_master_send(c,"\x00\x8c",0x02);
+	i2c_master_send(c,"\x00\x00\x00\x00",0x04);
+	i2c_master_send(c,"\x00\x04",0x02);
+	return(0);
+}
+
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -urN linux-2.6.16-rc3.orig/drivers/media/video/xc3028_motv.c linux-2.6.16-rc3/drivers/media/video/xc3028_motv.c
--- linux-2.6.16-rc3.orig/drivers/media/video/xc3028_motv.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.16-rc3/drivers/media/video/xc3028_motv.c	2006-02-14 18:48:35.000000000 +0900
@@ -0,0 +1,170 @@
+/*
+
+   Xceive -  xc3028 tuner interface
+
+   Copyright (c) 2006 Markus Rechberger <mrechberger@gmail.com>
+
+
+TODO: - remove em28xx dependency
+      - add channel locking (requires some more reverse engineering)
+      - try to get the datasheet from Xceive :)
+
+   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/i2c.h>
+#include <linux/usb.h>
+#include "compat.h"
+#include <linux/videodev.h>
+#include "saa7134/saa7134.h"
+#include "saa7134/saa7134-reg.h"
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <media/tuner.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#include "i2c-compat.h"
+#endif
+
+#define XC3028_DEFAULT_FIRMWARE "xceive_xc_3028.fw"
+
+
+extern void xc3028_set_tv_freq(struct i2c_client *c, unsigned int freq);
+extern int xceive_set_color(struct i2c_client *c);
+
+
+/* ---------------------------------------------------------------------- */
+
+int xc3028_motv_init(struct i2c_client *c,struct saa7134_dev *dev)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	int ret;
+	const struct firmware *fw = NULL;
+	u8 *firmware;
+	char *fwoffset;
+	u8 initoffset[8];
+	u8 linebuffer[100];
+	int splitrange;
+	int i=0;
+	int d=0;
+	int txtlen;
+	long fwoff;
+	size_t firmware_size = 5000;
+
+	// request firmware from /lib/firmware, note that the file got extracted by the convert application I wrote and which is available
+	// on linuxtv.org / xc3028
+	
+	ret = request_firmware(&fw, XC3028_DEFAULT_FIRMWARE, &t->i2c.dev);
+	if (ret) {
+		printk("xc3028: no firmware uploaded please check %s\n",XC3028_DEFAULT_FIRMWARE);
+		return ret;
+	}
+	firmware = fw->data;
+	firmware_size = fw->size;
+
+	// small firmware check, both firmwares I have are between 6 and 7k bytes
+	
+	if(fw->size>7000||fw->size<6000){
+		printk("xc3028: wrong firmware provided!\n");
+		release_firmware(fw);
+		return(ret);
+	}
+	for(i=0;i<8&&firmware[i]!='\n';i++);
+	txtlen=i;
+	firmware[i++]=0;
+	fwoff=simple_strtol(firmware,&fwoffset,10);
+	if(fwoff>fw->size){
+		printk("xc3028: firmware offset doesn't match!\n");
+		release_firmware(fw);
+		return(-1);
+	}
+
+	linebuffer[d++]=0x2a;
+        //dev=c->adapter->algo_data;
+
+        // Apply to monstertv V Series
+	// 20060203 K.Ohta
+	saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_27_25);
+	mdelay(100);
+	saa_clearb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_27_25);
+	mdelay(100);
+        printk("xc3028: reset!\n");
+	// the firmware always starts with 0x2a + 0x40 bytes payload I use to add the offset of the first part
+	// as the first line into the firmware binary
+	
+	while(i!=fw->size){
+		linebuffer[d++]=firmware[i];
+		if((d%64==0&&d!=0)||i==fwoff+txtlen){
+			i2c_master_send(c,linebuffer,d);
+			if(i==(fwoff+txtlen)){
+                                i2c_master_send(c,"\x02\x02",2);
+                                i2c_master_send(c,"\x02\x03",2);
+                                i2c_master_send(c,"\x00\x8c",2);
+                                i2c_master_send(c,"\x00\x00\x00\x00",4);
+				// another reset here
+  			        // Apply to monstertv V Series
+			        // 20060203 K.Ohta
+			        saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_27_25);
+			        mdelay(100);
+			        saa_clearb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_27_25);
+			        mdelay(100);
+			}       
+			linebuffer[0]=0x2a;
+			d=1;
+		}
+		i++;
+	}
+	printk("xc3024: Firmware uploaded\n");
+
+	firmware[firmware_size-1]=0;
+
+	release_firmware(fw);
+	
+	/* MAGIC VALUES */
+        i2c_master_send(c,"\x13\x39",2);
+        i2c_master_send(c,"\x0c\x80\xf0\xf7\x3e\x75\xc1\x8a\xe4\x02\x00",11);
+        i2c_master_send(c,"\x05\x0f\xee\xaa\x5f\xea\x90",7);
+        i2c_master_send(c,"\x06\x00\x0a\x4d\x8c\xf2\xd8\xcf\x30\x79\x9f",11);
+        i2c_master_send(c,"\x0b\x0d\xa4\x6c",4);
+        i2c_master_send(c,"\x0a\x01\x67\x24\x40\x08\xc3\x20\x10\x64\x3c\xfa\xf7\xe1\x0c\x2c",0x10);
+        i2c_master_send(c,"\x09\x0b",0x2);
+        i2c_master_send(c,"\x10\x13",0x2);
+        i2c_master_send(c,"\x16\x12",0x2);
+        i2c_master_send(c,"\x1f\x02",0x2);
+        i2c_master_send(c,"\x21\x02",0x2);
+        i2c_master_send(c,"\x01\x02",0x2);
+        i2c_master_send(c,"\x2b\x10",0x2);
+        i2c_master_send(c,"\x02\x02",0x2);
+        i2c_master_send(c,"\x02\x03",0x2);
+        i2c_master_send(c,"\x00\x8c",0x2);
+
+#if 0
+	// if set video will mostly be black/white  - if set_color is called instead the video will have color
+        i2c_master_send(c,"\x80\x01\x00\x00",0x4);
+        i2c_master_send(c,"\x00\x5e\x00\x29",0x4);
+        i2c_master_send(c,"\x2b\x1a",0x2);
+#endif
+	xceive_set_color(c);
+	//t->set_tv_freq    = xc3028_set_tv_freq;
+	return(0);
+}
+
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -urN linux-2.6.16-rc3.orig/include/media/tuner.h linux-2.6.16-rc3/include/media/tuner.h
--- linux-2.6.16-rc3.orig/include/media/tuner.h	2006-02-13 21:25:35.000000000 +0900
+++ linux-2.6.16-rc3/include/media/tuner.h	2006-02-13 21:34:33.000000000 +0900
@@ -116,6 +116,7 @@
 #define TUNER_PHILIPS_TUV1236D		68	/* ATI HDTV Wonder */
 #define TUNER_TNF_5335MF                69	/* Sabrent Bt848   */
 #define TUNER_SAMSUNG_TCPN_2121P30A     70 	/* Hauppauge PVR-500MCE NTSC */
+#define TUNER_XCEIVE_XC_x028_MOTV       71	/* XCEIVE Sil.tuner for MONSTERTV_V SERIES : RESERVED by K.Ohta 20060127 */
 
 /* tv card specific */
 #define TDA9887_PRESENT 		(1<<0)
