diff -aurpN -X /home/fletch/.diff.exclude 670-tiocgdev/arch/ia64/lib/dec_and_lock.c 680-ia64_dec_and_lock/arch/ia64/lib/dec_and_lock.c
--- 670-tiocgdev/arch/ia64/lib/dec_and_lock.c	Fri Jan  9 17:40:00 2004
+++ 680-ia64_dec_and_lock/arch/ia64/lib/dec_and_lock.c	Wed Feb 11 10:17:11 2004
@@ -18,6 +18,7 @@
  * operations have to be done atomically, so that the count doesn't drop to zero without
  * acquiring the spinlock first.
  */
+#ifndef ATOMIC_DEC_AND_LOCK
 int
 atomic_dec_and_lock (atomic_t *refcount, spinlock_t *lock)
 {
@@ -38,5 +39,6 @@ atomic_dec_and_lock (atomic_t *refcount,
 	} while (cmpxchg(&refcount->counter, old, new) != old);
 	return 0;
 }
+#endif
 
 EXPORT_SYMBOL(atomic_dec_and_lock);
diff -aurpN -X /home/fletch/.diff.exclude 670-tiocgdev/drivers/media/video/Kconfig 680-ia64_dec_and_lock/drivers/media/video/Kconfig
--- 670-tiocgdev/drivers/media/video/Kconfig	Wed Feb  4 23:03:25 2004
+++ 680-ia64_dec_and_lock/drivers/media/video/Kconfig	Wed Feb 11 10:17:11 2004
@@ -19,17 +19,25 @@ config VIDEO_BT848
 	  If you say Y or M here, you need to say Y or M to "I2C support" and
 	  "I2C bit-banging interfaces" in the character device section.
 
-	  To compile this driver as a module, choose M here: the
-	  module will be called bttv.
+	  Saying M here will compile this driver as a module (bttv).
+
+config VIDEO_IVTV
+	tristate "IVTV Video For Linux"
+	depends on VIDEO_DEV && PCI && I2C_ALGOBIT && SOUND
+	---help---
+	  Support for Hauppauge WinTv PVR 250 and 350 boards.
+	  
+	  If you say Y or M here, you need to say Y or M to "I2C support" and
+	  "I2C bit-banging interfaces" in the character device section.
+
+	  Saying M here will compile this driver as a module (ivtv).
 
 config VIDEO_PMS
 	tristate "Mediavision Pro Movie Studio Video For Linux"
 	depends on VIDEO_DEV && ISA
 	help
-	  Say Y if you have such a thing.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called pms.
+	  Say Y if you have such a thing.  Saying M here will compile this
+	  driver as a module (pms).
 
 config VIDEO_PLANB
 	tristate "PlanB Video-In on PowerMac"
diff -aurpN -X /home/fletch/.diff.exclude 670-tiocgdev/drivers/media/video/Makefile 680-ia64_dec_and_lock/drivers/media/video/Makefile
--- 670-tiocgdev/drivers/media/video/Makefile	Wed Feb  4 23:03:25 2004
+++ 680-ia64_dec_and_lock/drivers/media/video/Makefile	Wed Feb 11 10:17:11 2004
@@ -8,11 +8,16 @@ zoran-objs      :=	zr36120.o zr36120_i2c
 zr36067-objs	:=	zoran_procfs.o zoran_device.o \
 			zoran_driver.o zoran_card.o
 
+ivtv-objs	:=	ivtv-driver.o ivtv-i2c.o ivtv-api.o
+
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o
 
 obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \
 	tda7432.o tda9875.o ir-kbd-i2c.o ir-kbd-gpio.o
 obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
+
+obj-$(CONFIG_VIDEO_IVTV) += msp3400.o saa7115.o tveeprom.o ivtv.o \
+	saa7127.o #ivtv-fb.o
 
 obj-$(CONFIG_VIDEO_ZR36120) += zoran.o
 obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
diff -aurpN -X /home/fletch/.diff.exclude 670-tiocgdev/drivers/media/video/ivtv-api.c 680-ia64_dec_and_lock/drivers/media/video/ivtv-api.c
--- 670-tiocgdev/drivers/media/video/ivtv-api.c	Wed Dec 31 16:00:00 1969
+++ 680-ia64_dec_and_lock/drivers/media/video/ivtv-api.c	Wed Feb 11 10:17:11 2004
@@ -0,0 +1,2715 @@
+/* License: GPL
+ * Author: Kevin Thayer <nufan_wfk at yahoo dot com>
+ *
+ * This file will hold API related functions, both internal (firmware api)
+ * and external (v4l2, etc)
+ *
+ */
+
+#include "ivtv.h"
+
+/* FIXME need to find a good value */
+#define V4L2_PIX_FMT_CMP_MPG2 77777
+#define IVTV_V4L2_MAX_MINOR 15
+
+static int ivtv_v4l2_init(struct video_device *v);
+static int ivtv_v4l2_close(struct inode *inode, struct file *filp);
+static int ivtv_v4l2_open(struct inode *inode, struct file *filp);
+static int ivtv_v4l2_read(struct file *filp, char *buf, size_t count,
+	loff_t *pos);
+static ssize_t ivtv_v4l2_write(struct file *filp, const char *buf, size_t count,
+	loff_t *pos);
+static int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+static int ivtv_v4l2_pre_init(struct ivtv *itv);
+
+struct file_operations ivtv_v4l2_fops = {
+	read:           ivtv_v4l2_read,
+	write:          ivtv_v4l2_write,
+	open:           ivtv_v4l2_open,
+	ioctl:          ivtv_v4l2_ioctl,
+	release:        ivtv_v4l2_close,
+	poll:		ivtv_poll,
+	owner:		THIS_MODULE,
+};
+
+/* FIXME  Static variables for the various card types go here */
+
+struct video_device tmk_v4l2dev = {  /*values that work with the author's card */
+.owner	= THIS_MODULE,
+.name	= "Vanilla iTVC15 card",
+.type	= VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY|
+	                 VID_TYPE_CLIPPING|VID_TYPE_SCALES,
+.fops	= &ivtv_v4l2_fops,
+.hardware      = 0,
+.minor         = -1,
+};
+
+
+/* some tuner table values can change, so allocate this dynamically when you use it*/
+struct v4l2_tuner tmk_tuners[2] = {
+	{
+	.index		= 0,
+	.name		= "ivtv TV Tuner",
+	.type		= V4L2_TUNER_ANALOG_TV,
+	.capability	= (V4L2_TUNER_CAP_NORM|V4L2_TUNER_CAP_STEREO),
+	.rxsubchans	= (V4L2_TUNER_SUB_STEREO),
+	.audmode	= V4L2_TUNER_MODE_STEREO,
+	.signal		= 0,
+	.afc		= 0,
+	.reserved	= {0,0,0,0}
+	},{
+	.index		= 1,
+	.name		= "ivtv Radio",
+	.type		= V4L2_TUNER_RADIO,
+	.capability	= (V4L2_TUNER_CAP_STEREO),
+	.rxsubchans	= 0,
+	.audmode	= V4L2_TUNER_MODE_STEREO,
+	.signal		= 0,
+	.afc		= 0,
+	.reserved	= {0,0,0,0}
+	}
+};
+
+struct v4l2_standard tmk_standards[3] = {
+	{
+	.index		= 0,
+	.id		= V4L2_STD_NTSC,
+	.name		= "NTSC",
+	.frameperiod	= { .numerator	= 1001,
+			    .denominator= 30000},
+	.framelines	= 525,
+	.reserved	= {0,0,0,0}
+	},{
+	.index		= 1,
+	.id		= V4L2_STD_PAL,
+	.name		= "PAL",
+	.frameperiod	= { .numerator	= 1,
+			    .denominator= 25},
+	.framelines	= 625,
+	.reserved	= {0,0,0,0}
+	},{
+	.index		= 2,
+	.id		= V4L2_STD_SECAM,
+	.name		= "SECAM",
+	.frameperiod	= { .numerator	= 1,
+			    .denominator= 25},
+	.framelines	= 625,
+	.reserved	= {0,0,0,0}
+	}
+};
+
+struct v4l2_input tmk_inputs[10] = { /*values that work with the author's card */
+	{
+	.index		= 0,
+	.name		= "Composite 0",
+	.type		= V4L2_INPUT_TYPE_CAMERA,
+	.audioset	= 1,
+	.tuner		= 0,
+	.status		= 0,
+	},{
+	.index		= 1,
+	.name		= "Composite 1",
+	.type		= V4L2_INPUT_TYPE_CAMERA,
+	.audioset	= 1,
+	.tuner		= 0,
+	.status		= 0,
+	},{
+	.index		= 2,
+	.name		= "Composite 2",
+	.type		= V4L2_INPUT_TYPE_CAMERA,
+	.audioset	= 1,
+	.tuner		= 0,
+	.status		= 0,
+	},{
+	.index		= 3,
+	.name		= "Composite 3",
+	.type		= V4L2_INPUT_TYPE_CAMERA,
+	.audioset	= 1,
+	.tuner		= 0,
+	.status		= 0,
+	},{
+	.index		= 4,
+	.name		= "Tuner 0",
+	.type		= V4L2_INPUT_TYPE_TUNER,
+	.audioset	= 0,
+	.tuner		= 0,
+	.status		= 0,
+	},{
+	.index		= 5,
+	.name		= "Composite 4",
+	.type		= V4L2_INPUT_TYPE_CAMERA,
+	.audioset	= 1,
+	.tuner		= 0,
+	.status		= 0,
+	},{
+	.index		= 6,
+	.name		= "S-Video 0",
+	.type		= V4L2_INPUT_TYPE_CAMERA,
+	.audioset	= 1,
+	.tuner		= 0,
+	.status		= 0,
+	},{
+	.index		= 7,
+	.name		= "S-Video 1",
+	.type		= V4L2_INPUT_TYPE_CAMERA,
+	.audioset	= 1,
+	.tuner		= 0,
+	.status		= 0,
+	},{
+	.index		= 8,
+	.name		= "S-Video 2",
+	.type		= V4L2_INPUT_TYPE_CAMERA,
+	.audioset	= 1,
+	.tuner		= 0,
+	.status		= 0,
+	},{
+	.index		= 9,
+	.name		= "S-Video 3",
+	.type		= V4L2_INPUT_TYPE_CAMERA,
+	.audioset	= 1,
+	.tuner		= 0,
+	.status		= 0,
+	}
+};
+
+//FIXME capability and mode might be wrong
+struct v4l2_audio tmk_audio_inputs[2] = {
+	{0,"Tuner Audio In",0,0,},
+	{1,"Audio Line In", 0,0,},
+};
+
+int tmk_audio_mapping[] = {
+	0,3, /* Input 0 is msp input 3 */
+	1,1, /* input 1 is msp input 1 */
+	0,0  /* you're at end of list! */
+};
+
+struct v4l2_queryctrl ivtv_ctrl_menu_freq = {
+		.id		= V4L2_CID_IVTV_FREQ,
+		.type		= V4L2_CTRL_TYPE_MENU, 
+		.name		= "Frequency",
+		.minimum	= 0,
+		.maximum	= 2,
+		.step		= 1,
+		.default_value	= 2,
+		.flags		= 0,
+		.reserved	= {0,0}
+};
+
+struct v4l2_querymenu	ivtv_ctrl_query_freq[] = {
+	/* ID, Index, Name, Reserved */
+	{V4L2_CID_IVTV_FREQ, 0, "32kHz",   0 },
+	{V4L2_CID_IVTV_FREQ, 1, "44.1kHz", 0 },
+	{V4L2_CID_IVTV_FREQ, 2, "48kHz",   0 }
+};
+
+u32 ivtv_audio_tbl_freq[] = {
+	/* setting */
+	0x2 /* 32kHz   binary 10 */,
+	0x0 /* 44.1kHz binary 00 */,
+	0x1 /* 48kHz   binary 01 */
+};
+
+u32 ivtv_audio_mask_freq = 0x3;
+
+struct v4l2_queryctrl ivtv_ctrl_menu_enc = {
+		.id		= V4L2_CID_IVTV_ENC,
+		.type		= V4L2_CTRL_TYPE_MENU, 
+		.name		= "Encoding",
+		.minimum	= 0,
+		.maximum	= 2,
+		.step		= 1,
+		.default_value	= 1,
+		.flags		= 0,
+		.reserved	= {0,0}
+};
+
+struct v4l2_querymenu	ivtv_ctrl_query_enc[] = {
+	/* ID, Index, Name, Reserved */
+	{V4L2_CID_IVTV_ENC, 0, "Layer 1",    0},
+	{V4L2_CID_IVTV_ENC, 1, "Layer 2",    0},
+	{V4L2_CID_IVTV_ENC, 2, "Layer 3(?)", 0}
+};
+
+u32 ivtv_audio_tbl_enc[] = {
+	/* setting */
+	0x1 << 2 /* Layer 1	binary 0100 */,
+	0x2 << 2 /* Layer 2	binary 1000 */,
+	0x3 << 2 /* Layer 3(?)	binary 1100 */
+};
+
+u32 ivtv_audio_mask_enc = 0xC;
+
+struct v4l2_queryctrl ivtv_ctrl_menu_bitrate = {
+		.id		= V4L2_CID_IVTV_BITRATE,
+		.type		= V4L2_CTRL_TYPE_MENU, 
+		.name		= "Audio Bitrate",
+		.minimum	= 0,
+		.maximum	= 14,
+		.step		= 1,
+		.default_value	= 14,
+		.flags		= 0,
+		.reserved	= {0,0}
+};
+
+struct v4l2_querymenu	ivtv_ctrl_query_bitrate[] = {
+	/* ID, Index, Name, Reserved */
+	{V4L2_CID_IVTV_BITRATE,  0, "[L1/L2] Free fmt",  0},
+	{V4L2_CID_IVTV_BITRATE,  1, "[L1/L2] 32k/32k",   0},
+	{V4L2_CID_IVTV_BITRATE,  2, "[L1/L2] 64k/48k",   0},
+	{V4L2_CID_IVTV_BITRATE,  3, "[L1/L2] 96k/56k",   0},
+	{V4L2_CID_IVTV_BITRATE,  4, "[L1/L2] 128k/64k",  0},
+	{V4L2_CID_IVTV_BITRATE,  5, "[L1/L2] 160k/80k",  0},
+	{V4L2_CID_IVTV_BITRATE,  6, "[L1/L2] 192k/96k",  0},
+	{V4L2_CID_IVTV_BITRATE,  7, "[L1/L2] 224k/112k", 0},
+	{V4L2_CID_IVTV_BITRATE,  8, "[L1/L2] 256k/128k", 0},
+	{V4L2_CID_IVTV_BITRATE,  9, "[L1/L2] 288k/160k", 0},
+	{V4L2_CID_IVTV_BITRATE, 10, "[L1/L2] 320k/192k", 0},
+	{V4L2_CID_IVTV_BITRATE, 11, "[L1/L2] 352k/224k", 0},
+	{V4L2_CID_IVTV_BITRATE, 12, "[L1/L2] 384k/256k", 0},
+	{V4L2_CID_IVTV_BITRATE, 13, "[L1/L2] 416k/320k", 0},
+	{V4L2_CID_IVTV_BITRATE, 14, "[L1/L2] 448k/384k", 0},
+};
+
+u32 ivtv_audio_tbl_bitrate[] = {
+	/* setting */
+	0x0 << 4 /* [L1/L2] Free fmt	binary 0000 */,
+	0x1 << 4 /* [L1/L2] 32k/32k,   binary 0001 */,
+	0x2 << 4 /* [L1/L2] 64k/48k,   binary 0010 */,
+	0x3 << 4 /* [L1/L2] 96k/56k,   binary 0011 */,
+	0x4 << 4 /* [L1/L2] 128k/64k,  binary 0100 */,
+	0x5 << 4 /* [L1/L2] 160k/80k,  binary 0101 */,
+	0x6 << 4 /* [L1/L2] 192k/96k,  binary 0110 */,
+	0x7 << 4 /* [L1/L2] 224k/112k, binary 0111 */,
+	0x8 << 4 /* [L1/L2] 256k/128k, binary 1000 */,
+	0x9 << 4 /* [L1/L2] 288k/160k, binary 1001 */,
+	0xA << 4 /* [L1/L2] 320k/192k, binary 1010 */,
+	0xB << 4 /* [L1/L2] 352k/224k, binary 1011 */,
+	0xC << 4 /* [L1/L2] 384k/256k, binary 1100 */,
+	0xD << 4 /* [L1/L2] 416k/320k, binary 1101 */,
+	0xE << 4 /* [L1/L2] 448k/384k, binary 1110 */
+};
+
+u32 ivtv_audio_mask_bitrate = 0xF0;
+
+
+struct v4l2_queryctrl ivtv_ctrl_menu_mono = {
+		.id		= V4L2_CID_IVTV_MONO,
+		.type		= V4L2_CTRL_TYPE_MENU, 
+		.name		= "Mono/Stereo",
+		.minimum	= 0,
+		.maximum	= 3,
+		.step		= 1,
+		.default_value	= 0,
+		.flags		= 0,
+		.reserved	= {0,0}
+};
+
+struct v4l2_querymenu	ivtv_ctrl_query_mono[] = {
+	/* ID, Index, Name, Reserved */
+	{V4L2_CID_IVTV_MONO, 0, "Stereo",      0},
+	{V4L2_CID_IVTV_MONO, 1, "JointStereo", 0},
+	{V4L2_CID_IVTV_MONO, 2, "Dual",        0},
+	{V4L2_CID_IVTV_MONO, 3, "Mono",        0}
+};
+
+u32 ivtv_audio_tbl_mono[] = {
+	/* setting */
+	0x0 << 8 /* Stereo,      binary 00 */,
+	0x1 << 8 /* JointStereo, binary 01 */,
+	0x2 << 8 /* Dual,        binary 10 */,
+	0x3 << 8 /* Mono,        binary 11 */
+};
+
+u32 ivtv_audio_mask_mono = 0x300;
+
+struct v4l2_queryctrl ivtv_ctrl_menu_joint = {
+		.id		= V4L2_CID_IVTV_JOINT,
+		.type		= V4L2_CTRL_TYPE_MENU, 
+		.name		= "Joint extension",
+		.minimum	= 0,
+		.maximum	= 3,
+		.step		= 1,
+		.default_value	= 0,
+		.flags		= 0,
+		.reserved	= {0,0}
+};
+
+struct v4l2_querymenu	ivtv_ctrl_query_joint[] = {
+	/* ID, Index, Name, Reserved */
+	{V4L2_CID_IVTV_JOINT, 0, "Subbands 4-31/bound=4",   0},
+	{V4L2_CID_IVTV_JOINT, 1, "Subbands 8-31/bound=8",   0},
+	{V4L2_CID_IVTV_JOINT, 2, "Subbands 12-31/bound=12", 0},
+	{V4L2_CID_IVTV_JOINT, 3, "Subbands 16-31/bound=16", 0}
+};
+
+u32 ivtv_audio_tbl_joint[] = {
+	/* setting */
+	0x0 << 10 /* Subbands 4-31/bound=4,   binary 00 */,
+	0x1 << 10 /* Subbands 8-31/bound=8,   binary 01 */,
+	0x2 << 10 /* Subbands 12-31/bound=12, binary 10 */,
+	0x3 << 10 /* Subbands 16-31/bound=16, binary 11 */
+};
+
+u32 ivtv_audio_mask_joint = 0xc00;
+
+struct v4l2_queryctrl ivtv_ctrl_menu_emphasis = {
+		.id		= V4L2_CID_IVTV_EMPHASIS,
+		.type		= V4L2_CTRL_TYPE_MENU, 
+		.name		= "Emphasis",
+		.minimum	= 0,
+		.maximum	= 2,
+		.step		= 1,
+		.default_value	= 0,
+		.flags		= 0,
+		.reserved	= {0,0}
+};
+
+struct v4l2_querymenu	ivtv_ctrl_query_emphasis[] = {
+	/* ID, Index, Name, Reserved */
+	{V4L2_CID_IVTV_EMPHASIS, 0, "None",       0},
+	{V4L2_CID_IVTV_EMPHASIS, 1, "50/15uS",    0},
+	{V4L2_CID_IVTV_EMPHASIS, 2, "CCITT J.17", 0}
+};
+
+u32 ivtv_audio_tbl_emphasis[] = {
+	/* setting */
+	0x0 << 12 /* None,       binary 00 */,
+	0x1 << 12 /* 50/15uS,    binary 01 */,
+	0x3 << 12 /* CCITT J.17, binary 11 */
+};
+
+u32 ivtv_audio_mask_emphasis = 0x3000;
+
+struct v4l2_queryctrl ivtv_ctrl_menu_crc = {
+		.id		= V4L2_CID_IVTV_CRC,
+		.type		= V4L2_CTRL_TYPE_MENU, 
+		.name		= "Audio CRC",
+		.minimum	= 0,
+		.maximum	= 1,
+		.step		= 1,
+		.default_value	= 0,
+		.flags		= 0,
+		.reserved	= {0,0}
+};
+
+struct v4l2_querymenu	ivtv_ctrl_query_crc[] = {
+	/* ID, Index, Name, Reserved */
+	{V4L2_CID_IVTV_CRC, 0, "off", 0},
+	{V4L2_CID_IVTV_CRC, 1, "on",  0}
+};
+
+u32 ivtv_audio_tbl_crc[] = {
+	/* setting */
+	0x0 << 14 /* off, binary 0 */,
+	0x1 << 14 /* on,  binary 1 */
+};
+
+u32 ivtv_audio_mask_crc = 0x4000;
+
+struct v4l2_queryctrl ivtv_ctrl_menu_copyright = {
+		.id		= V4L2_CID_IVTV_COPYRIGHT,
+		.type		= V4L2_CTRL_TYPE_MENU, 
+		.name		= "Copyright",
+		.minimum	= 0,
+		.maximum	= 1,
+		.step		= 1,
+		.default_value	= 0,
+		.flags		= 0,
+		.reserved	= {0,0}
+};
+
+struct v4l2_querymenu	ivtv_ctrl_query_copyright[] = {
+	/* ID, Index, Name, Reserved */
+	{V4L2_CID_IVTV_COPYRIGHT, 0, "off", 0},
+	{V4L2_CID_IVTV_COPYRIGHT, 1, "on",  0}
+};
+
+u32 ivtv_audio_tbl_copyright[] = {
+	/* setting */
+	0x0 << 15 /* off, binary 0 */,
+	0x1 << 15 /* on,  binary 1 */
+};
+
+u32 ivtv_audio_mask_copyright = 0x8000;
+
+struct v4l2_queryctrl ivtv_ctrl_menu_generation = {
+		.id		= V4L2_CID_IVTV_GEN,
+		.type		= V4L2_CTRL_TYPE_MENU, 
+		.name		= "Generation",
+		.minimum	= 0,
+		.maximum	= 1,
+		.step		= 1,
+		.default_value	= 0,
+		.flags		= 0,
+		.reserved	= {0,0}
+};
+
+struct v4l2_querymenu	ivtv_ctrl_query_generation[] = {
+	/* ID, Index, Name, Reserved */
+	{V4L2_CID_IVTV_GEN, 0, "copy",     0},
+	{V4L2_CID_IVTV_GEN, 1, "original", 0}
+};
+
+u32 ivtv_audio_tbl_generation[] = {
+	/* setting */
+	0x0 << 16 /* copy,     binary 0 */,
+	0x1 << 16 /* original, binary 1 */
+};
+
+u32 ivtv_audio_mask_generation = 0x10000;
+
+
+/* 3 stream types: mpeg, yuv, passthru */
+struct ivtv_v4l2_stream tmk_mpg_stream = {
+/*MPEG*/
+	.s_flags	= 0,
+	.id		= -1,
+	.v4l_reg_type	= VFL_TYPE_GRABBER,
+	.format		= {
+			  .type	= V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			  .fmt	= {
+				  .pix	= {
+					  .width 	= 720,
+					  .height 	= 480,
+					  .field	= V4L2_FIELD_INTERLACED,
+					  .sizeimage	= (128*1024),
+				  }
+			},
+	},
+	.controlcount	=  0,
+	.controls	=  NULL
+};
+
+struct ivtv_v4l2_stream tmk_yuv_stream = {
+/*YUV*/
+	.s_flags	= 0,
+	.id		= -1,
+	.v4l_reg_type	= VFL_TYPE_GRABBER,
+	.format		= {
+			  .type	= V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			  .fmt	= {
+				  .pix	= {
+					  .width 	= 720,
+					  .height 	= 480,
+					  .field	= V4L2_FIELD_INTERLACED,
+					  .sizeimage	= (720*720),
+				  }
+			  },
+	},
+	.controlcount	=  0,
+	.controls	=  NULL
+};
+
+//FIXME these settings are way wrong
+struct ivtv_v4l2_stream tmk_vbi_stream = {
+	.s_flags	= 0,
+	.id		= -1,
+	.v4l_reg_type	= VFL_TYPE_VBI,
+	.format		= {
+			  .type	= V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			  .fmt	= {
+				  .pix	= {
+					  .width 	= 720,
+					  .height 	= 480,
+					  .field	= V4L2_FIELD_INTERLACED,
+					  .sizeimage	= (128*1024),
+				  }
+			  },
+	},
+	.controlcount	=  0,
+	.controls	=  NULL
+};
+
+struct ivtv_v4l2_stream dec_mpg_stream = {
+/*Decoder MPG*/
+	.s_flags	= 0,
+	.id 	= -1,
+	.v4l_reg_type	= VFL_TYPE_GRABBER,
+	.format 	= {
+	 		  .type = V4L2_BUF_TYPE_VIDEO_OUTPUT,
+	 		  .fmt  = {
+	 			  .pix  = {
+	 				  .width	= 720,
+	 				  .height	= 480,
+	 				  .field	= V4L2_FIELD_INTERLACED,
+	 				  .sizeimage	= (128*1024),
+	 			  }
+	 		  },
+	},
+	.controlcount	=  0,
+	.controls	=  NULL
+};
+
+struct ivtv_v4l2_stream dec_yuv_stream = {
+/*Decoder YUV*/
+	.s_flags	= 0,
+	.id 	= -1,
+	.v4l_reg_type	= VFL_TYPE_GRABBER,
+	.format 	= {
+	 		  .type = V4L2_BUF_TYPE_VIDEO_OUTPUT,
+	 		  .fmt  = {
+	 			  .pix  = {
+	 				  .width	= 720,
+	 				  .height	= 480,
+	 				  .field	= V4L2_FIELD_INTERLACED,
+	 				  .sizeimage	= (720*720),
+	 			  }
+	 		  },
+	},
+	.controlcount	=  0,
+	.controls	=  NULL
+};
+
+/* Initialize v4l2 variables and register v4l2 device */
+int ivtv_v4l2_setup(struct ivtv *itv) {
+	int x, cont, retval;
+	
+	IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 setup\n");
+
+	/* Set owner for auto usage-incrementing and such */
+	//SET_MODULE_OWNER(&ivtv_v4l2_fops);
+
+	//switch based on card type
+	//  and fill in appropriate v4l2 device
+	switch (itv->card_type) {
+	case IVTV_350_V1:
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"Configuring 350rev1 card\n");
+		itv->v4l2.streamcount = IVTV_350_V1_STREAMS;
+		/* Disable dec yuv buffers if requested */
+		if (itv->options.dec_yuv_buffers == 0) itv->v4l2.streamcount--;
+		/* FIXME wrong values */
+		itv->v4l2.capabilities = (V4L2_CAP_VIDEO_CAPTURE|V4L2_CAP_TUNER|
+					  V4L2_CAP_AUDIO|V4L2_CAP_READWRITE|
+					  V4L2_CAP_VIDEO_OUTPUT);
+		break;
+	case IVTV_250_V2:
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"Configuring 250rev2 card\n");
+		itv->v4l2.streamcount = IVTV_250_V2_STREAMS;
+		/* FIXME wrong values */
+		itv->v4l2.capabilities = (V4L2_CAP_VIDEO_CAPTURE|V4L2_CAP_TUNER|
+					  V4L2_CAP_AUDIO|V4L2_CAP_READWRITE);
+		break;
+	case IVTV_250_V1:
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"Configuring 250rev1 card\n");
+	default: /* shouldn't happen, treat like V1 */
+		itv->v4l2.streamcount = IVTV_250_V1_STREAMS;
+		itv->v4l2.capabilities = (V4L2_CAP_VIDEO_CAPTURE|V4L2_CAP_TUNER|
+					  V4L2_CAP_AUDIO|V4L2_CAP_READWRITE);
+		
+		break;
+	}
+
+        /* Initial settings */
+        itv->v4l2.codec.bitrate_mode	= 0;
+        itv->v4l2.codec.bitrate		= 8000000;
+        itv->v4l2.codec.bitrate_peak	= 16000000;
+        itv->v4l2.codec.stream_type	= IVTV_STREAM_PS;
+        itv->v4l2.codec.bframes		= 3;
+        itv->v4l2.codec.gop_closure	= 0;
+        itv->v4l2.codec.dnr_mode	= 0;
+        itv->v4l2.codec.dnr_type	= 0;
+        itv->v4l2.codec.dnr_spatial 	= 0;
+        itv->v4l2.codec.dnr_temporal	= 0;
+	itv->v4l2.codec.aspect		= 2;
+
+	itv->dec_options.hide_last_frame= 1;
+	itv->dec_options.pts_low	= 0;
+	itv->dec_options.pts_hi		= 0;
+	itv->dec_options.gop_offset	= 0;
+	itv->dec_options.mute_frames	= 0;
+
+	/* Ctrls */
+	itv->dec_options.speed.mute	= 1;
+	itv->dec_options.speed.aud_mute	= 0;
+	itv->dec_options.speed.smooth	= 1;
+	itv->dec_options.speed.fr_mask	= 2;
+	itv->dec_options.speed.fr_field	= 1;
+	itv->dec_options.decbuffers	= 1;
+	itv->dec_options.prebuffer	= 1;
+
+	/* Allocate streams */
+        itv->v4l2.streams = (struct ivtv_v4l2_stream *)
+                        kmalloc((itv->v4l2.streamcount *
+                                sizeof(struct ivtv_v4l2_stream)),
+                                GFP_KERNEL);
+        if (NULL == itv->v4l2.streams) {
+                IVTV_DEBUG(IVTV_DEBUG_ERR, "Couldn't allocate v4l2 streams\n");
+                retval = -ENOMEM;
+                goto ivtv_stream_fail;
+        }
+
+	/* pre-init */
+	retval = ivtv_v4l2_pre_init(itv);
+	if (retval < 0) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Error in pre-init\n");
+		goto ivtv_pre_init_fail;
+	}
+
+        /* Fill in streams with some defaults */
+	/* FIXME assumes 3 streams, hardcoding */
+       	memcpy(&itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_MPG], &tmk_mpg_stream,
+               sizeof(struct ivtv_v4l2_stream));
+
+       	memcpy(&itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_YUV], &tmk_yuv_stream,
+               sizeof(struct ivtv_v4l2_stream));
+
+       	memcpy(&itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_VBI], &tmk_vbi_stream,
+               sizeof(struct ivtv_v4l2_stream));
+
+	/* Set some card-specific per-stream stuff here */	
+	switch (itv->card_type) { 
+	     case IVTV_350_V1:
+	       	memcpy(&itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG], &dec_mpg_stream,
+	     	       sizeof(struct ivtv_v4l2_stream));
+
+		if (itv->options.dec_yuv_buffers !=0) {
+		       	memcpy(&itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_YUV], &dec_yuv_stream,
+	     		       sizeof(struct ivtv_v4l2_stream));
+		}
+		break;
+	     case IVTV_250_V2:
+		break;
+	     case IVTV_250_V1:
+	     default: /* shouldn't happen, treat like V1 */
+		break;
+	}
+
+	for (x=0; x < itv->v4l2.streamcount ; x++) {
+		init_waitqueue_head(&itv->v4l2.streams[x].waitq);
+		itv->v4l2.streams[x].v4l2dev = video_device_alloc();
+		if (NULL == itv->v4l2.streams[x].v4l2dev) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR, "Couldn't allocate v4l2 video_device\n");
+			retval = -ENOMEM;
+			goto ivtv_videodev_fail;
+		}
+
+		memcpy(itv->v4l2.streams[x].v4l2dev,
+		       &tmk_v4l2dev, sizeof(struct video_device));
+		itv->v4l2.streams[x].v4l2dev->priv = itv;
+		itv->v4l2.streams[x].ubytes = 0;
+		itv->v4l2.streams[x].free_q.vdev = itv->v4l2.streams[x].v4l2dev;
+		itv->v4l2.streams[x].full_q.vdev = itv->v4l2.streams[x].v4l2dev;
+		itv->v4l2.streams[x].dma_q.vdev  = itv->v4l2.streams[x].v4l2dev;
+		INIT_LIST_HEAD(&itv->v4l2.streams[x].free_q.list);
+		INIT_LIST_HEAD(&itv->v4l2.streams[x].full_q.list);
+		INIT_LIST_HEAD(&itv->v4l2.streams[x].dma_q.list);
+
+		retval = ivtv_init_queue(itv, &itv->v4l2.streams[x].full_q, 0,
+				    itv->v4l2.streams[x].format.type);
+		if (retval < 0) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR,"Error on init_queue 1\n");
+			goto ivtv_initq_fail;
+		}
+		retval = ivtv_init_queue(itv, &itv->v4l2.streams[x].dma_q, 0,
+				    itv->v4l2.streams[x].format.type);
+		if (retval < 0) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR,"Error on init_queue 2\n");
+			goto ivtv_initq_fail;
+		}
+		
+		itv->v4l2.streams[x].v4l2dev->dev = &itv->dev->dev;
+		itv->v4l2.streams[x].v4l2dev->release = video_device_release;
+	}
+
+	/* Some streams have specific values */
+	x = ivtv_init_queue(itv,
+			    &itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_MPG].free_q,
+		       	    mpg_buffers,
+			    itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_MPG].format.type);
+	x = ivtv_init_queue(itv,
+			    &itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_YUV].free_q,
+			    yuv_buffers,
+			    itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_YUV].format.type);
+	x = ivtv_init_queue(itv,
+			    &itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_VBI].free_q,
+			    vbi_buffers,
+			    itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_VBI].format.type);
+
+	/* set default minors */
+	itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_MPG].v4l2dev->minor = itv->num;
+	itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_YUV].v4l2dev->minor = 
+		itv->num + IVTV_V4L2_YUV_OFFSET;
+	//vbi will get offset by v4l, so no offset needed by us
+	itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_VBI].v4l2dev->minor = itv->num;
+
+	/* Set any card-specific per-stream stuff here */	
+	switch (itv->card_type) { 
+        case IVTV_350_V1:
+		/* allocate buffers for decoder */
+		    x = ivtv_init_queue(itv,
+			&itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG]
+			.free_q, dec_mpg_buffers,
+			itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG].format.type);
+
+		itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG].v4l2dev->minor = 
+			itv->num + IVTV_V4L2_DEC_OFFSET;
+
+		if (itv->options.dec_yuv_buffers != 0) {
+		        x = ivtv_init_queue(itv,
+				&itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_YUV]
+				.free_q, dec_yuv_buffers,
+				itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_YUV].format.type);
+
+			itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_YUV].v4l2dev->minor = 
+				itv->num + IVTV_V4L2_YUV_OFFSET + IVTV_V4L2_DEC_OFFSET;
+		}
+
+		/* Set poll for decoder parts */
+		itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG].v4l2dev->fops->poll = ivtv_dec_poll;
+		if (itv->options.dec_yuv_buffers)
+			itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_YUV].v4l2dev->fops->poll = ivtv_dec_poll;
+		
+		break;
+        case IVTV_250_V2:
+		break;
+        case IVTV_250_V1:
+        default: /* shouldn't happen, treat like V1 */
+		break;
+	}
+	
+	/* allocate minor, register, loop until works or out of range */
+	for (x=0;x < itv->v4l2.streamcount; x++) {
+		cont = 0;
+		do {
+	 	    if(video_register_device(itv->v4l2.streams[x].v4l2dev,
+					 itv->v4l2.streams[x].v4l_reg_type,
+					 itv->v4l2.streams[x].v4l2dev->minor)) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR,
+					"Device or minor %d not accepted\n",
+					itv->v4l2.streams[x].v4l2dev->minor);
+		    	itv->v4l2.streams[x].v4l2dev->minor++;
+	 	    } else {
+			IVTV_DEBUG(IVTV_DEBUG_ERR,
+				   "Registered v4l2 device, minor %d\n",
+				   itv->v4l2.streams[x].v4l2dev->minor);
+			cont = 1;
+			ivtv_v4l2_init(itv->v4l2.streams[x].v4l2dev);
+		    }
+		} while ((0 == cont) && 
+			 (itv->v4l2.streams[x].v4l2dev->minor<=IVTV_V4L2_MAX_MINOR));
+		if (0 == cont) {
+		       IVTV_DEBUG(IVTV_DEBUG_ERR,"Couldn't register v4l2 device!\n");
+		       /* invalidate so we don't try to unload the device */
+		       itv->v4l2.streams[x].v4l2dev->minor = -1;
+		       return -ENODEV;
+		}
+	}
+
+	return 0;
+
+ivtv_pre_init_fail:
+	/* needs lots of queue cleanup here -axboe */
+ivtv_videodev_fail:
+	for (x = 0; x < itv->v4l2.streamcount; x++)
+		if (itv->v4l2.streams[x].v4l2dev != NULL)
+			video_device_release(itv->v4l2.streams[x].v4l2dev);
+ivtv_initq_fail:
+	kfree(itv->v4l2.streams);
+ivtv_stream_fail:
+	return retval;
+}
+
+/* After setting the audio.active param, call this to
+ *  get the right input.. think of it as a resolver */
+int ivtv_set_audio(struct ivtv *itv, int *map) {
+	int input,msp_input;
+	struct msp_matrix mspm;
+
+	do {
+		input = *(map++);
+		msp_input = *(map++);
+		if (input == itv->v4l2.audio.active) {
+			IVTV_DEBUG(IVTV_DEBUG_INFO,
+				   "Setting audio to input %d\n", msp_input);
+			mspm.input = msp_input;
+			mspm.output = itv->v4l2.audio_output;
+
+			ivtv_call_i2c_client(itv,
+					     IVTV_MSP3400_I2C_ADDR,
+					     MSP_SET_MATRIX,
+					     &mspm);
+			return 0;
+		}
+	} while ((msp_input !=0) || (input != 0));
+
+	IVTV_DEBUG(IVTV_DEBUG_ERR,"Invalid audio input, shouldn't happen!\n");
+
+	return -EINVAL;
+}
+
+u32 ivtv_pause_encoder(struct ivtv *itv, int cmd) {
+	u32 data[16], result=0;
+	int x;
+
+        data[0] = 0; /* 0 = pause, 1 = unpause */
+	if (cmd) data[0] = 1;
+
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_PAUSE_ENCODER,
+		     &result,1, &data[0]);
+	return result;
+}
+
+
+/* Called if v4l2 registration is successful. Set video mode here, at least
+ * that is required on PAL cards */
+int ivtv_v4l2_init(struct video_device *v) {
+	struct ivtv *ivtv = v->priv;
+	u32 data[IVTV_MBOX_MAX_DATA], result;
+	int x;
+
+	/*
+	 * only set it on minor 0
+	 */
+	if (v->minor != 0)
+		return 0;
+
+	memset(data, 0, sizeof(data));
+	/* set display standard */
+	if (ivtv_pal)
+		data[0] = 1;
+	else
+		data[0] = 0;
+
+	x = ivtv_api(ivtv->dec_mbox, &ivtv->dec_msem, IVTV_API_DEC_DISP_STANDARD,
+		     &result, 1, &data[0]);
+
+	return 0;
+}
+
+
+/* Called before v4l2 registration */
+int ivtv_v4l2_pre_init(struct ivtv *itv) {
+	int x, temp, retval = -1;
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 init\n");
+	//Allocate based on card type
+	//  allocate capabilities and such based on device type
+
+	/* FIXME too much hardcoding? */
+	//inputs
+	itv->v4l2.input.active	= 4; 
+	itv->v4l2.input.count	= 10;
+	itv->v4l2.input.table.input	= tmk_inputs;
+
+	itv->v4l2.audio_output	= 1;
+
+	//audio inputs
+	itv->v4l2.audio.active	= 0;
+	itv->v4l2.audio.count	= 2;
+	itv->v4l2.audio.table.audio	= tmk_audio_inputs;
+
+	//outputs .. none yet (no real 350 support anyways)
+	itv->v4l2.output.active = 0;
+	itv->v4l2.output.count	= 0;
+	itv->v4l2.output.table.output	= NULL;
+
+
+	//standards (NTSC, PAL, SECAM)
+	if (ivtv_pal)
+		itv->v4l2.standard.active	= 1;
+	else
+		itv->v4l2.standard.active	= 0;
+	itv->v4l2.standard.count	= 3;
+	itv->v4l2.standard.table.std	= tmk_standards;
+
+	if (itv->v4l2.standard.active == 0) {
+		itv->v4l2.codec.framespergop = 15;	// NTSC
+		itv->v4l2.codec.framerate	= 0;	// NTSC 30fps
+	} else {
+		itv->v4l2.codec.framespergop = 12;   // PAL
+		itv->v4l2.codec.framerate	= 1;	// PAL  25fps
+
+		/* set pal height in stream defaults */
+		tmk_mpg_stream.format.fmt.pix.height = 576;
+		tmk_yuv_stream.format.fmt.pix.height = 576;
+		tmk_vbi_stream.format.fmt.pix.height = 576;
+		dec_mpg_stream.format.fmt.pix.height = 576;
+		dec_yuv_stream.format.fmt.pix.height = 576;
+	}
+
+	//tuner
+	itv->v4l2.tuner.active	= 0;
+	if (itv->card_type == IVTV_350_V1) {
+		itv->v4l2.tuner.count	= 2;
+	} else {
+		itv->v4l2.tuner.count	= 1;
+	}
+	
+	itv->v4l2.tuner.table.tuner = (struct v4l2_tuner *)
+					kmalloc((itv->v4l2.tuner.count *
+					sizeof(struct v4l2_tuner)),
+					GFP_KERNEL);
+
+	if (itv->v4l2.tuner.table.tuner == NULL) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Couldn't allocate v4l2 tuner\n");
+		return -ENOMEM;
+	}
+
+	memcpy(itv->v4l2.tuner.table.tuner, &tmk_tuners[0],
+		(itv->v4l2.tuner.count * sizeof(struct v4l2_tuner)));
+
+	/* Setup audio */
+	/* V4L2_CID_IVTV_FREQ */
+	itv->v4l2.audio_meta[0].ctrl = &ivtv_ctrl_menu_freq;
+	itv->v4l2.audio_meta[0].menu = ivtv_ctrl_query_freq;
+	itv->v4l2.audio_meta[0].mask = ivtv_audio_mask_freq;
+	itv->v4l2.audio_meta[0].setting = ivtv_ctrl_menu_freq.default_value;
+	itv->v4l2.audio_meta[0].table = &ivtv_audio_tbl_freq[0];
+
+	/* V4L2_CID_IVTV_ENC*/
+	itv->v4l2.audio_meta[1].ctrl = &ivtv_ctrl_menu_enc;
+	itv->v4l2.audio_meta[1].menu = ivtv_ctrl_query_enc;
+	itv->v4l2.audio_meta[1].mask = ivtv_audio_mask_enc;
+	itv->v4l2.audio_meta[1].setting = ivtv_ctrl_menu_enc.default_value;
+	itv->v4l2.audio_meta[1].table = &ivtv_audio_tbl_enc[0];
+
+	/* V4L2_CID_IVTV_BITRATE*/
+	itv->v4l2.audio_meta[2].ctrl = &ivtv_ctrl_menu_bitrate;
+	itv->v4l2.audio_meta[2].menu = ivtv_ctrl_query_bitrate;
+	itv->v4l2.audio_meta[2].mask = ivtv_audio_mask_bitrate;
+	itv->v4l2.audio_meta[2].setting = ivtv_ctrl_menu_bitrate.default_value;
+	itv->v4l2.audio_meta[2].table = &ivtv_audio_tbl_bitrate[0];
+
+	/* V4L2_CID_IVTV_MONO*/
+	itv->v4l2.audio_meta[3].ctrl = &ivtv_ctrl_menu_mono;
+	itv->v4l2.audio_meta[3].menu = ivtv_ctrl_query_mono;
+	itv->v4l2.audio_meta[3].mask = ivtv_audio_mask_mono;
+	itv->v4l2.audio_meta[3].setting = ivtv_ctrl_menu_mono.default_value;
+	itv->v4l2.audio_meta[3].table = &ivtv_audio_tbl_mono[0];
+
+	/* V4L2_CID_IVTV_JOINT*/
+	itv->v4l2.audio_meta[4].ctrl = &ivtv_ctrl_menu_joint;
+	itv->v4l2.audio_meta[4].menu = ivtv_ctrl_query_joint;
+	itv->v4l2.audio_meta[4].mask = ivtv_audio_mask_joint;
+	itv->v4l2.audio_meta[4].setting = ivtv_ctrl_menu_joint.default_value;
+	itv->v4l2.audio_meta[4].table = &ivtv_audio_tbl_joint[0];
+
+	/* V4L2_CID_IVTV_EMPHASIS*/
+	itv->v4l2.audio_meta[5].ctrl = &ivtv_ctrl_menu_emphasis;
+	itv->v4l2.audio_meta[5].menu = ivtv_ctrl_query_emphasis;
+	itv->v4l2.audio_meta[5].mask = ivtv_audio_mask_emphasis;
+	itv->v4l2.audio_meta[5].setting = ivtv_ctrl_menu_emphasis.default_value;
+	itv->v4l2.audio_meta[5].table = &ivtv_audio_tbl_emphasis[0];
+
+	/* V4L2_CID_IVTV_CRC*/
+	itv->v4l2.audio_meta[6].ctrl = &ivtv_ctrl_menu_crc;
+	itv->v4l2.audio_meta[6].menu = ivtv_ctrl_query_crc;
+	itv->v4l2.audio_meta[6].mask = ivtv_audio_mask_crc;
+	itv->v4l2.audio_meta[6].setting = ivtv_ctrl_menu_crc.default_value;
+	itv->v4l2.audio_meta[6].table = &ivtv_audio_tbl_crc[0];
+
+	/* V4L2_CID_IVTV_COPYRIGHT*/
+	itv->v4l2.audio_meta[7].ctrl = &ivtv_ctrl_menu_copyright;
+	itv->v4l2.audio_meta[7].menu = ivtv_ctrl_query_copyright;
+	itv->v4l2.audio_meta[7].mask = ivtv_audio_mask_copyright;
+	itv->v4l2.audio_meta[7].setting = ivtv_ctrl_menu_copyright.default_value;
+	itv->v4l2.audio_meta[7].table = &ivtv_audio_tbl_copyright[0];
+
+	/* V4L2_CID_IVTV_GEN*/
+	itv->v4l2.audio_meta[8].ctrl = &ivtv_ctrl_menu_generation;
+	itv->v4l2.audio_meta[8].menu = ivtv_ctrl_query_generation;
+	itv->v4l2.audio_meta[8].mask = ivtv_audio_mask_generation;
+	itv->v4l2.audio_meta[8].setting = ivtv_ctrl_menu_generation.default_value;
+	itv->v4l2.audio_meta[8].table = &ivtv_audio_tbl_generation[0];
+
+	itv->v4l2.codec.audio_bitmap = 0; 
+	for (x = 0; x < IVTV_V4L2_AUDIO_MENUCOUNT; x++) {
+		temp = itv->v4l2.audio_meta[x].setting;
+		itv->v4l2.codec.audio_bitmap |= 
+			itv->v4l2.audio_meta[x].table[temp];
+	}
+
+	retval = ivtv_set_audio(itv,tmk_audio_mapping);
+	if (retval) {
+		kfree(itv->v4l2.tuner.table.tuner);
+		return retval;
+	}
+
+	//FIXME Setup components here? tuner channel etc
+	return 0;
+}
+
+int ivtv_start_v4l2_stream (struct ivtv_open_id *id) {
+	struct ivtv *itv = id->itv;
+	u32 data[IVTV_MBOX_MAX_DATA], result;
+	int x,vsize,vsync,hsize;
+	int type,subtype;
+	unsigned int dig;
+
+	/* sem_lock must be held */
+	IVTV_ASSERT(ivtv_sem_count(&itv->sem_lock) <= 0);
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO,"ivtv start v4l2 stream\n");
+	
+	/* NTSC/PAL switching */
+	vsize = itv->v4l2.streams[0].format.fmt.pix.height;
+	vsync = (int) itv->v4l2.streams[0].format.fmt.pix.height/2;
+	hsize =  itv->v4l2.streams[0].format.fmt.pix.width;
+
+	type = id->type;
+
+	switch (type) {
+	case 2: /* VBI, may be the wrong value */
+		subtype = 4;
+	case 4: /* Radio, probably not applicable */
+		subtype = 2;
+		break;
+	default:
+		subtype = 3;
+		break;
+	}
+
+	/* clear queues */
+	ivtv_move_queue(itv, &itv->v4l2.streams[id->type].full_q,
+			&itv->v4l2.streams[id->type].free_q);
+	ivtv_move_queue(itv, &itv->v4l2.streams[id->type].dma_q,
+			&itv->v4l2.streams[id->type].free_q);
+ 
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "fullq size %d\n",
+		   itv->v4l2.streams[id->type].full_q.elements);
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "freeq size %d\n",
+		   itv->v4l2.streams[id->type].free_q.elements);
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "dmaq size %d\n",
+		   itv->v4l2.streams[id->type].dma_q.elements);
+
+	/*assign dma block len*/
+	/* FIXME this needs a flag */
+	data[0] = 1; /* num bytes in block*/
+	data[1] = 1; /* use info from sg instead */
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem,
+			IVTV_API_ASSIGN_DMA_BLOCKLEN, &result, 2, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 1. Code %d\n",x);
+		
+	/*assign program index info */
+	/* FIXME need more info on this call */
+	data[0] = 0; /*Mask    0:Disable */
+	data[1] = 0; /*Num_req 0:??/ */
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem,
+			IVTV_API_ASSIGN_PGM_INDEX_INFO, &result, 2, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 2. Code %d\n",x);
+		
+	/*assign stream type */
+	data[0] = itv->v4l2.codec.stream_type;
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_STREAM_TYPE,
+		&result,1, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 3. Code %d\n",x);
+		
+	/*assign output port */
+	data[0] = 0; /*0:Memory */
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_OUTPUT_PORT,
+		&result, 1, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 4. Code %d\n",x);
+		
+	/*assign framerate */
+	data[0] = itv->v4l2.codec.framerate;
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_FRAMERATE,
+		&result, 1, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 5. Code %d\n",x);
+		
+	/*assign frame size */
+	data[0] = vsize; /* height*/
+	data[1] = hsize; /* width */
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_FRAME_SIZE,
+		&result, 2, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 6. Code %d\n",x);
+		
+	/*assign aspect ratio */
+	data[0] = itv->v4l2.codec.aspect; /*mpeg spec sez 2 */
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_ASPECT_RATIO,
+		&result, 1, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 7. Code %d\n",x);
+		
+	/*assign bitrates */
+	/*FIXME i think these settings are valid for compressed only */
+	data[0] = itv->v4l2.codec.bitrate_mode;		/*mode */
+	data[1] = itv->v4l2.codec.bitrate;		/* bps */
+	data[2] = itv->v4l2.codec.bitrate_peak / 400;	/* peak/400 */
+	data[3] = 0; 		/*??? */
+	data[4] = 0x70;		/*??? */
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_BITRATES,
+		&result, 5, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 8. Code %d\n",x);
+
+	/*assign gop properties */
+	data[0] = itv->v4l2.codec.framespergop;
+	data[1] = itv->v4l2.codec.bframes;
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_GOP_PROPERTIES,
+		&result, 2, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 9. Code %d\n",x);
+		
+	/*assign 3 2 pulldown */
+	data[0] = itv->v4l2.codec.pulldown;
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_3_2_PULLDOWN,
+		&result, 1, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 10. Code %d\n",x);
+		
+	/*assign gop closure */
+	data[0] = itv->v4l2.codec.gop_closure;
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_GOP_CLOSURE,
+		&result, 1, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 11. Code %d\n",x);
+		
+	/*assign audio properties */
+	data[0] = itv->v4l2.codec.audio_bitmap;
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_AUDIO_PROPERTIES,
+		&result, 1, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 12. Code %d\n",x);
+
+	/*assign dnr filter mode */
+	data[0] = itv->v4l2.codec.dnr_mode;
+	data[1] = itv->v4l2.codec.dnr_type;
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_DNR_FILTER_MODE,
+		&result, 2, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 13. Code %d\n",x);
+		
+	/*assign dnr filter props*/
+	data[0] = itv->v4l2.codec.dnr_spatial;
+	data[1] = itv->v4l2.codec.dnr_temporal;
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_DNR_FILTER_PROPS,
+		&result, 2, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 14. Code %d\n",x);
+		
+	/*assign coring levels */
+	data[0] = 0; /*luma_h */
+	data[1] = 255; /*luma_l */
+	data[2] = 0; /*chroma_h */
+	data[3] = 255; /*chroma_l */
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_CORING_LEVELS,
+		&result, 4, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 15. Code %d\n",x);
+		
+	/*assign spatial filter type */
+	data[0] = 1; /*luma_t: 1 = horiz_only */
+	data[1] = 1; /*chroma_t: 1 = horiz_only */
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_SPATIAL_FILTER_TYPE,
+		&result, 2, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 16. Code %d\n",x);
+		
+	/*assign frame drop rate */
+	data[0] = 0; 
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_FRAME_DROP_RATE,
+		&result, 1, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 17. Code %d\n",x);
+		
+	/*assign placeholder */
+	data[0] = 0; /* type: 0 = Extension/UserData */
+	data[1] = 0; /*period */
+	data[2] = 0; /*size_t*/
+	data[3] = 0; /*arg0 */
+	data[4] = 0; /*arg1 */
+	data[5] = 0; /*arg2 */
+	data[6] = 0; /*arg3 */
+	data[7] = 0; /*arg4 */
+	data[8] = 0; /*arg5 */
+	data[9] = 0; /*arg6 */
+	data[10] = 0; /*arg7 */
+	data[11] = 0; /*arg8 */
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_PLACEHOLDER,
+		&result, 12, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 18. Code %d\n\n",x);
+		
+	/* assign num vsync lines */
+	data[0] = vsync; /*??? */
+	data[1] = vsync; /* ??? */
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_NUM_VSYNC_LINES,
+		&result, 2, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 20. Code %d\n",x);
+		
+	if (atomic_read(&itv->capturing) == 0) {
+	
+		itv->trans_id = 0;
+		itv->first_read = 1;
+
+		/* Clear pending interrupts */
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "Clearing Interrupts\n");
+		writel((readl(itv->reg_mem + IVTV_REG_IRQSTATUS)&0xC8000000),
+			(IVTV_REG_IRQSTATUS+itv->reg_mem));
+#if 0
+		/* event notification (on) */
+		data[0] = 0; /*type: 0 = refresh */
+		data[1] = 1; /*on/off: 1 = on */
+		data[2] = 0x10000000; /*intr_bit: 0x10000000 = digitizer */
+		data[3] = -1; /*mbox_id: -1: none */
+	        x = ivtv_api(itv->enc_mbox, &itv->enc_msem,
+			     IVTV_API_EVENT_NOTIFICATION, &result, 4, &data[0]);
+		if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "startcap error 2. Code %d\n",x);
+#endif
+
+		/* Disable digitizer (saa7115) */
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "Disabling digitizer\n");
+		dig=0;
+		ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,
+				     DECODER_ENABLE_OUTPUT,&dig);
+	
+		/*initialize input (no args) */
+	        x = ivtv_api(itv->enc_mbox, &itv->enc_msem,
+			     IVTV_API_INITIALIZE_INPUT,	&result, 0, &data[0]);
+		if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 19. Code %d\n\n",x);
+		
+		/* enable digitizer (saa7115) */
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "Enabling digitizer\n");
+		dig=1;
+		ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,
+				     DECODER_ENABLE_OUTPUT,&dig);
+	
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 100ms\n");
+		ivtv_sleep_timeout(HZ/10);
+	}
+	
+	/* FIXME this is for mpg captures only i think */
+	clear_bit(IVTV_F_I_EOS, &itv->i_flags);
+
+    /* begin_capture */
+	data[0] = type; /*type: 0 = mpeg */
+	data[1] = subtype; /*subtype: 3 = video+audio */
+	x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_BEGIN_CAPTURE,
+	        &result, 2, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "startcap error 1. Code %d\n",x);
+
+	if (atomic_read(&itv->capturing) == 0) {
+	        /*Clear the following Interrupt mask bits: 0xd8000000 */
+		ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
+ 	        IVTV_DEBUG(IVTV_DEBUG_IRQ, "IRQ Mask is now: 0x%08x\n",itv->irqmask);
+	}
+
+    /*you're live! sit back and await interrupts :)*/
+	atomic_inc(&itv->capturing);
+	return 0;
+}
+
+int ivtv_api_dec_playback_speed(struct ivtv* itv, int fastspeed, int factor,
+			   int forward, int mpeg_frame_type_mask,
+			   int bframes_per_gop, int mute_audio,
+			   int display_fields) {
+
+   u32 data[IVTV_MBOX_MAX_DATA], result;
+
+   data[0] = (fastspeed << 31) | (factor & 0xff);
+   data[1] = forward;
+   data[2] = mpeg_frame_type_mask;
+   data[3] = bframes_per_gop;
+   data[4] = mute_audio;
+   data[5] = display_fields;
+
+   ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_PLAYBACK_SPEED, &result, 6, &data[0]);
+   return result;
+}
+
+int ivtv_start_v4l2_decode (struct ivtv_open_id *id)
+{
+   struct ivtv *itv = id->itv;
+   u32 data[IVTV_MBOX_MAX_DATA], result;
+   int x;
+   int type;
+   int standard=0;
+
+   /* sem_lock must be held */
+   IVTV_ASSERT(ivtv_sem_count(&itv->sem_lock) <= 0);
+   
+   type = id->type;
+
+   if (itv->v4l2.standard.active != 0) { /* if not NTSC */
+	   standard  = 1; /* PAL */
+   }
+
+/* this isn't needed until we use buffers for decoding */
+   /* clear queues */
+   ivtv_move_queue(itv, &itv->v4l2.streams[id->type].full_q,
+		   &itv->v4l2.streams[id->type].free_q);
+   ivtv_move_queue(itv, &itv->v4l2.streams[id->type].dma_q,
+		   &itv->v4l2.streams[id->type].free_q);
+
+   IVTV_DEBUG(IVTV_DEBUG_INFO, "Decoder fullq size %d\n",
+   itv->v4l2.streams[id->type].full_q.elements);
+   IVTV_DEBUG(IVTV_DEBUG_INFO, "Decoder freeq size %d\n",
+   itv->v4l2.streams[id->type].free_q.elements);
+   IVTV_DEBUG(IVTV_DEBUG_INFO, "Decoder dmaq size %d\n",
+   itv->v4l2.streams[id->type].dma_q.elements);
+   
+   if (atomic_read(&itv->decoding) == 0)
+   {
+	 /* Clear pending interrupts */
+	 IVTV_DEBUG(IVTV_DEBUG_INFO, "Clearing Interrupts\n");
+	 writel((readl(itv->reg_mem + IVTV_REG_IRQSTATUS)&0xC8000000),
+	 (IVTV_REG_IRQSTATUS+itv->reg_mem));
+   }
+
+   /* set display standard */
+   data[0] = standard; /* 0 = NTSC, 1 = PAL */
+   x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_DISP_STANDARD,
+	   &result, 1, &data[0]);
+   if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T SET DISPLAY STD %d\n",x);
+ 
+   /* set audio mode */
+   data[0] = 0; /* Dual mono-mode action: ??? */
+   data[1] = 0; /* stereo mode action: 0=stereo, 1=left, 2=right, 3=mono */
+   x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_SELECT_AUDIO,
+	   &result, 2, &data[0]);
+   if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T SET AUDIO MODE %d\n",x);
+ 
+   /* set decoder source settings */
+   data[0] = id->type; /* Data type: 0 = mpeg from host, 1 = yuv from encoder, 2 = yuv_from_host */
+   data[1] = 720; /* YUV source width*/
+   if (itv->v4l2.standard.active == 1)
+	   data[2] = 576; /* YUV source height*/
+   else
+	   data[2] = 480; /* YUV source height*/
+   data[3] = itv->v4l2.codec.audio_bitmap; /* Audio settings to use, bitmap. see docs.*/
+   x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_DECODE_SOURCE,
+				&result, 4, &data[0]);
+   if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN't INITIALIZE DECODER SOURCE %d\n",x);
+
+#if 0
+   /* select event notification */
+   data[0] = 0; /* Event: 0 = audio change between stereo and mono */
+   data[1] = 1; /* Enable/Disable: 0 = disabled, 1 = enabled */
+   data[2] = 0x00010000; /* Bit: interrupt bit to fire */
+   data[3] = -1; /* Mailbox to use: -1 = no mailbox needed */
+   x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_EVENT_NOTIFICATION,
+				&result, 4, &data[0]);
+   if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T INITIALIZE EVENT NOTIFICATION %d\n",x);
+#endif
+   /* set number of internal decoder buffers */
+   data[0] = itv->dec_options.decbuffers; /* 0 = 6 buffers, 1 = 9 buffers */
+   x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_DISPLAY_BUFFERS,
+   &result, 1, &data[0]);
+   if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T INITIALIZE # OF DISPLAY BUFFERS %d\n",x);
+
+   /* prebufferring*/
+   data[0] = itv->dec_options.prebuffer; /* 0 = no prebuffering, 1 = enabled, see docs */
+   x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_BUFFER, &result, 1,&data[0]);
+   if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN't INITIALIZE BUFFER %d\n",x);
+#if 0
+   /* set stream input port */
+   data[0] = 0; /* 0 = memory, 1 = streaming */
+   x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_STREAM_INPUT, &result, 1, &data[0]);
+   if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T INITIALIZE STREAM INPUT %d\n",x);
+   
+   /* A/V sync delay */
+   data[0] = 0; /* Delay in 90khz ticks. 0 = synced, negative = audio lags, positive = video lags */
+   x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_SET_AV_DELAY, &result, 1, &data[0]);
+   if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN't INITIALIZE Audio/Vid sync delay %d\n",x);
+#endif
+
+   /* start playback */
+   data[0] = itv->dec_options.gop_offset;  /* frame to start from (in GOP) */
+   data[1] = itv->dec_options.mute_frames; /* # of audio frames to mute */
+   x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_START_PLAYBACK, &result, 2, &data[0]);
+   if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T START PLAYBACK %d\n",x);
+
+   if (atomic_read(&itv->decoding) == 0) {
+	   /*Clear the following Interrupt mask bits: 0xd8000000 */
+	   ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_DECODE);
+	   IVTV_DEBUG(IVTV_DEBUG_IRQ, "IRQ Mask is now: 0x%08x\n",itv->irqmask);
+   }
+
+   /*you're live! sit back and await interrupts :)*/
+   atomic_inc(&itv->decoding);
+   return 0;
+}
+ 
+void ivtv_v4l2_cleanup(struct ivtv *itv) {
+	int x;
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 unregister\n");
+
+	if (atomic_read(&itv->capturing) >= 0) ivtv_stop_all_captures(itv);
+	if (itv->v4l2.tuner.table.tuner) kfree(itv->v4l2.tuner.table.tuner);
+	for (x=0; x < itv->v4l2.streamcount; x++) {
+		/* Catch a possible kernel panic */
+		if (itv->v4l2.streams[x].v4l2dev->minor != -1) {
+			video_unregister_device(itv->v4l2.streams[x].v4l2dev);
+		} else {
+			IVTV_DEBUG(IVTV_DEBUG_ERR,
+				   "invalid v4l2 registration on unload\n");
+		}
+	}
+	if (itv->v4l2.streams) kfree(itv->v4l2.streams);
+}
+
+int ivtv_v4l2_open(struct inode *inode, struct file *filp) {
+	int x,y=0,minor;
+	struct ivtv_open_id *item;
+	struct ivtv *itv=NULL;
+	
+	
+	minor = iminor(inode);
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 open on minor %d\n", minor);
+
+	/* Find which card this open was on */
+	spin_lock_irq(&ivtv_lock);
+	for (x=0;x<ivtv_cards_active;x++) {
+
+		/* find out which stream this open was on */
+		for (y=0; y < ivtv_cards[x].v4l2.streamcount;y++) {
+			IVTV_DEBUG(IVTV_DEBUG_INFO,"current minor %d\n",
+				       ivtv_cards[x].v4l2.streams[y].v4l2dev->minor);
+			if (ivtv_cards[x].v4l2.streams[y].v4l2dev->minor == minor) {
+				itv = ivtv_cards[x].v4l2.streams[y].v4l2dev->priv;
+				break;
+			}
+		}
+		/* FIXME ugly :( */
+		if (itv !=NULL) break;
+	}
+	spin_unlock_irq(&ivtv_lock);
+	
+	/* FIXME temporary 
+	if (y == 2) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "VBI not supported yet \n");
+		return -EINVAL;
+	}
+	*/
+	if (itv != NULL) {
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"opened card # %d, stream %d\n",x,y);
+		//allocate memory
+		item = kmalloc(sizeof(struct ivtv_open_id), GFP_KERNEL);
+		if (NULL == item) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR,"nomem on v4l2 open\n");
+			return -ENOMEM;
+		}
+		item->itv = itv;
+		item->type = y;
+		
+		INIT_LIST_HEAD(&item->list);
+
+		down(&itv->sem_lock);
+
+		item->open_id = item->itv->open_id++;
+
+		list_add_tail (&item->list, &item->itv->client_list);
+
+		up(&itv->sem_lock);
+		
+		filp->private_data = item;
+		
+		return 0;
+	}
+
+	/* Couldnt find a device registered on that minor, shouldn't happen! */
+	IVTV_DEBUG(IVTV_DEBUG_ERR,"Device on minor %d not found!\n",minor);
+
+	return -ENXIO;
+}
+
+
+int ivtv_v4l2_read(struct file *filp, char *buf, size_t count, loff_t *pos) {
+        struct ivtv_open_id *id = filp->private_data;
+		struct ivtv *itv = id->itv;
+		struct ivtv_v4l2_stream *stream;
+        int ret=0;
+	 
+	IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 read\n");
+
+	if (down_interruptible(&itv->sem_lock))
+		return -ERESTARTSYS;
+	stream = &itv->v4l2.streams[id->type];
+
+	if (!test_bit(IVTV_F_S_CAP, &stream->s_flags) && stream->id == -1) {
+		set_bit(IVTV_F_S_CAP, &stream->s_flags);
+		stream->id = id->open_id;
+
+		ret = ivtv_start_v4l2_stream(id);
+		if (ret) {
+			stream->id = -1;
+			IVTV_DEBUG(IVTV_DEBUG_INFO,
+				   "Error in v4l2 stream init\n");
+		}
+		stream->seq = 0;
+		stream->ubytes = 0;
+	} else {
+		if (id->open_id != stream->id)
+			ret = -EBUSY;
+	}
+
+	up(&itv->sem_lock);
+
+	if (ret)
+		return ret;
+
+	     ret = ivtv_read(id, buf, count, !(filp->f_flags & O_NONBLOCK));
+
+	if (ret > 0)
+		*pos += ret;
+
+	if (ret == 0) {
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 read returning 0\n");
+	}
+
+	return ret;
+}
+
+ssize_t ivtv_v4l2_write(struct file *filp, const char *buf, size_t count, loff_t *pos)
+{
+	struct ivtv_open_id *id = filp->private_data;
+	 	 struct ivtv *itv = id->itv;
+	struct ivtv_v4l2_stream *stream;
+	int ret=0;
+
+	if ( (id->type != IVTV_DEC_STREAM_TYPE_MPG) &&
+	 	 (id->type != IVTV_DEC_STREAM_TYPE_YUV)) {
+	 	IVTV_DEBUG(IVTV_DEBUG_ERR, "Write on read-only interface\n");
+	 	return -EINVAL;
+	}
+
+	if (down_interruptible(&itv->sem_lock))
+	 	return -ERESTARTSYS;
+
+	// Initialize Decoder
+	/* FIXME we'll need to make this its own stream type */
+	stream = &itv->v4l2.streams[id->type];
+	if ((stream->id == -1) && !test_bit(IVTV_F_S_CAP, &stream->s_flags)) {
+	 	set_bit(IVTV_F_S_CAP, &stream->s_flags);
+	 	stream->id = id->open_id;
+	 	ret = ivtv_start_v4l2_decode(id);
+	} else {
+	 	if (id->open_id != stream->id)
+	 		ret = -EBUSY;
+	}
+
+	up(&itv->sem_lock);
+
+	if (ret)
+	 	return ret;
+
+	/* do all the work */
+	return ivtv_write(id, buf, count, !(filp->f_flags & O_NONBLOCK));
+}
+
+int ivtv_v4l2_streamoff(struct ivtv_open_id *id) {
+	
+	 	 if (down_interruptible(&id->itv->sem_lock))
+	 			 return -ERESTARTSYS;
+
+	 	 if (id->open_id != id->itv->v4l2.streams[id->type].id) {
+	 	return -EINVAL;
+	} else {
+	 			 ivtv_stop_capture(id);
+	 	 }
+
+	up(&id->itv->sem_lock);
+
+	return 0;
+}
+
+int ivtv_v4l2_close(struct inode *inode, struct file *filp) {
+	struct ivtv_open_id *id = filp->private_data;
+	
+	IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 close\n");
+	
+	if (NULL == id) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR,"invalid id on v4l2 close\n");
+		return -ENODEV;
+	}
+
+	if (down_interruptible(&id->itv->sem_lock))
+		return -ERESTARTSYS;
+	
+	if (id->open_id == id->itv->v4l2.streams[id->type].id) {
+		ivtv_close(id);
+		clear_bit(IVTV_F_S_CAP, &id->itv->v4l2.streams[id->type].s_flags);
+		id->itv->v4l2.streams[id->type].id	  = -1;
+	}
+	up(&id->itv->sem_lock);
+	
+	list_del(&id->list);
+
+	kfree(id);
+
+	return 0;
+}
+
+int ivtv_change_speed(struct ivtv *itv, struct ivtv_speed speed) {
+	u32 data[IVTV_MBOX_MAX_DATA], result;
+
+	if ((speed.scale < 0) || (speed.scale > 50))
+	 	return -EINVAL;
+
+	if ((speed.speed < 0) || (speed.speed > 1))
+	 	return -EINVAL;
+	 	
+	data[0] = speed.scale;
+
+	if (speed.smooth) /* smooth ff */
+	 	data[0] |= 0x40000000;
+
+	if (speed.speed) /* fast forward */
+	 	data[0] |= 0x80000000;
+
+	if (speed.direction) {
+	 	IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: Reverse not supported\n");
+	 	return -EINVAL;
+	}
+
+	data[1] = speed.direction; /* Forward. Reverse not supported */
+
+	switch (speed.fr_mask) {
+	 	case 2:
+	 	default: 
+	 		data[2] |= 4; /* B */
+	 	case 1:
+	 		data[2] |= 2; /* P */
+	 	case 0:
+	 		data[2] |= 1; /* I */
+	 		break;
+	}
+
+	data[3] = itv->v4l2.codec.framespergop;
+	data[4] = speed.aud_mute; /* mute while fast/slow */
+	data[5] = speed.fr_field; /* frame or field at a time */
+	data[6] = speed.mute; /* # of frames to mute on normal speed resume */
+
+	if (ivtv_api(itv->dec_mbox, &itv->dec_msem,
+	 		 IVTV_API_DEC_PLAYBACK_SPEED, &result, 7, &data[0])) {
+	 	IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: error changing speed\n");
+	 	return (int)result;
+	}
+
+	/* Save speed options if call succeeded */
+	memcpy(&itv->dec_options.speed, &speed, sizeof(speed));
+
+	return 0;
+}
+
+int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+		                unsigned long arg) {
+
+        struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
+        struct ivtv *itv = id->itv;
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl 0x%08x\n", cmd);
+		
+	switch (cmd) {
+#ifdef SAA7115_REGTEST
+	/* ioctls to allow direct access to the saa7115 registers for testing */
+	case SAA7115_GET_REG: {
+		struct saa7115_reg_t *saa7115_reg = (struct saa7115_reg_t *)arg;
+
+		ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,SAA7115_GET_REG,saa7115_reg);
+		break;
+	}
+	case SAA7115_SET_REG: {
+		struct saa7115_reg_t *saa7115_reg = (struct saa7115_reg_t *)arg;
+
+                ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,SAA7115_SET_REG,saa7115_reg);
+		break;
+	}
+#endif
+	case IVTV_IOC_ZCOUNT: {
+		/* Zeroes out usage count so it can be unloaded in case of
+		 * drastic error */
+
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"ivtv ioctl: ZCOUNT\n");
+
+		/* disabled due to module code changes   ivtv_zero_usage_count(); */
+
+		break;
+	}
+	case IVTV_IOC_GET_FB: {
+		if (itv->fb_id < 0)
+			return -EINVAL;
+		if (copy_to_user((int*)arg, &itv->fb_id, sizeof(itv->fb_id)))
+			return -EFAULT;
+ 
+ 		break;
+ 	}
+	case IVTV_IOC_FWAPI: {
+		struct ivtv_ioctl_fwapi fwapi;
+		int x;
+
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"ivtv ioctl: FWAPI\n");
+
+		if (copy_from_user(&fwapi, (struct ivtv_ioctl_fwapi *) arg,
+				   sizeof(struct ivtv_ioctl_fwapi)))
+			return -EFAULT;
+		/* Encoder
+		x = ivtv_api(itv->enc_mbox, &itv->enc_msem, fwapi.cmd,
+	                      &fwapi.result, fwapi.args, &fwapi.data[0]);
+		*/
+		
+		/* Decoder */
+		x = ivtv_api(itv->dec_mbox, &itv->dec_msem, fwapi.cmd,
+		                  &fwapi.result, fwapi.args, &fwapi.data[0]);
+
+		if (copy_to_user((struct ivtv_ioctl_fwapi *) arg, &fwapi,
+				  sizeof(struct ivtv_ioctl_fwapi)))
+			return -EFAULT;
+
+		return x;
+	}
+	case IVTV_IOC_FRAMESYNC: {
+		interruptible_sleep_on(&itv->vsync_w);
+
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+
+		if (copy_to_user((void*)arg, &itv->dec_timestamp,
+				 sizeof(itv->dec_timestamp))) {
+			return -EFAULT;
+		}
+
+		break;
+	}
+	case IVTV_IOC_PLAY: {
+		u32 data[IVTV_MBOX_MAX_DATA], result;
+		data[0] = 0; /* 0-based frame # to start from (in GOP) */
+		data[1] = 0; /* # of audio frames to mute */
+		if (ivtv_api(itv->dec_mbox, &itv->dec_msem,
+			     IVTV_API_DEC_START_PLAYBACK, &result, 2, &data[0]))
+			IVTV_DEBUG(IVTV_DEBUG_ERR,
+				   "DEC: error starting playback\n");
+
+		break;
+
+	}
+	case IVTV_IOC_S_START_DECODE: {
+		struct ivtv_cfg_start_decode sd;
+
+		if (copy_from_user(&sd, (struct ivtv_cfg_start_decode *) arg,
+				   sizeof(sd)))
+			return -EFAULT;
+
+		if ((sd.gop_offset < 0) || (sd.gop_offset > 15))
+			return -EINVAL;
+		if  (sd.muted_audio_frames < 0)
+			return -EINVAL;
+		
+		itv->dec_options.gop_offset = sd.gop_offset;
+
+		itv->dec_options.mute_frames = sd.muted_audio_frames;
+		break;
+	     }
+	case IVTV_IOC_STOP_DECODE: 
+	case IVTV_IOC_S_STOP_DECODE: {
+		struct ivtv_cfg_stop_decode sd;
+
+		if (copy_from_user(&sd, (struct ivtv_cfg_stop_decode *)arg,
+				   sizeof(sd)))
+			return -EFAULT;
+
+		if ((sd.hide_last < 0) || (sd.hide_last > 1))
+			return -EINVAL;
+		itv->dec_options.hide_last_frame = sd.hide_last;
+
+		itv->dec_options.pts_low = (u32)(sd.pts_stop & 0xFFFFFFFF);
+		itv->dec_options.pts_hi  = (u32)(sd.pts_stop >> 32);
+		
+		if (cmd == IVTV_IOC_S_STOP_DECODE) break;
+
+		ivtv_stop_decode(id);
+		break;
+	}
+	case IVTV_IOC_G_SPEED: {
+		if (copy_to_user((void*)arg,
+				 &itv->dec_options.speed,
+				 sizeof(itv->dec_options.speed))) {
+			return -EFAULT;
+		}
+
+		break;
+	}
+	case IVTV_IOC_S_SPEED: {
+		struct ivtv_speed speed;
+		int ret=0;
+
+		if (copy_from_user(&speed, (struct ivtv_speed*)arg,
+				   sizeof(speed)))
+			return -EFAULT;
+
+		ret = ivtv_change_speed(itv, speed);
+		if (ret) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: error in slow/fast mode\n");
+			return ret;
+		}
+
+		break;
+	}
+	case IVTV_IOC_S_SLOW_FAST: {
+		struct ivtv_slow_fast	sf;
+		struct ivtv_speed 	speed;
+		int ret;
+
+		if (copy_from_user(&sf, (struct ivtv_slow_fast *)arg,
+				   sizeof(sf)))
+			return -EFAULT;
+		
+		if ((sf.scale < 0) || (sf.scale > 50))
+			return -EINVAL;
+		if ((sf.speed < 0) || (sf.speed > 1))
+			return -EINVAL;
+		
+		memcpy(&speed, &itv->dec_options.speed, sizeof(speed));
+		speed.scale = sf.scale;
+		speed.speed = sf.speed;
+
+		ret = ivtv_change_speed(itv, speed);
+		if (ret) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR,
+				   "DEC: error in set slow/fast mode\n");
+			return ret;
+		}
+
+		break;
+	}
+	case IVTV_IOC_PAUSE: {
+		u32 data[IVTV_MBOX_MAX_DATA], result;
+		data[0] = 0;
+		if (ivtv_api(itv->dec_mbox, &itv->dec_msem,
+			     IVTV_API_DEC_PAUSE_PLAYBACK, &result, 1, &data[0])) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR,
+				   "DEC: error pausing\n");
+		}
+
+		break;
+	}
+	case IVTV_IOC_GET_TIMING: {
+		struct ivtv_ioctl_framesync timing;
+		int ret;
+
+		if (atomic_read(&itv->decoding) == 0) {
+			memset(&timing, 0, sizeof(timing));
+		} else {
+			/* if the value pulled 'efficiently' was OK */
+			if (&itv->dec_timestamp.scr == 0) {
+				/* firmware glitch gave us a bad value.
+				   get a good one */
+
+				ret = ivtv_get_timing_info(itv, &timing);
+				if (ret) return -EINVAL;
+			} else {
+				memcpy(&timing, &itv->dec_timestamp, sizeof(timing));
+			}
+		}
+
+		if (copy_to_user((void*)arg, &timing, sizeof(timing))) {
+			return -EFAULT;
+		}
+
+		break;
+	}
+
+	case VIDIOC_QUERYMENU: {
+		struct v4l2_querymenu *qmenu = (struct v4l2_querymenu *)arg;
+		
+		if (qmenu->id >= V4L2_CID_PRIVATE_BASE) {
+			int off = qmenu->id - V4L2_CID_PRIVATE_BASE;
+			if (off < IVTV_V4L2_AUDIO_MENUCOUNT) {
+				u32 i = qmenu->index;
+				if ((i >= itv->v4l2.audio_meta[off].ctrl->minimum) &&
+				    (i <= itv->v4l2.audio_meta[off].ctrl->maximum)) {
+					memcpy(qmenu,
+						&itv->v4l2.audio_meta[off].menu[i], 
+						sizeof(struct v4l2_querymenu));
+				} else {
+					IVTV_DEBUG(IVTV_DEBUG_ERR,
+							"qmenu: invalid index\n");
+					return -EINVAL;
+				}
+			} else {
+				IVTV_DEBUG(IVTV_DEBUG_ERR,
+						"qmenu: id out of range\n");
+				return -EINVAL;
+			}
+
+		}
+
+		break;
+	}
+			       
+	case VIDIOC_QUERYCTRL: {
+		struct v4l2_queryctrl *qctrl = (struct v4l2_queryctrl *)arg;
+
+		if (qctrl->id >= V4L2_CID_PRIVATE_BASE) {
+			int off = qctrl->id - V4L2_CID_PRIVATE_BASE;
+			if (off < IVTV_V4L2_AUDIO_MENUCOUNT) {
+				memcpy(qctrl,itv->v4l2.audio_meta[off].ctrl, 
+						sizeof(struct v4l2_queryctrl));
+			} else {
+				switch (qctrl->id) {
+				case V4L2_CID_IVTV_DEC_SMOOTH_FF:
+					qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
+					strncpy(qctrl->name, "Smooth Slow/FF", 32);
+					qctrl->minimum = 0;
+					qctrl->maximum = 1;
+					qctrl->default_value = 1;
+					qctrl->flags = 0;
+					qctrl->reserved[0] = 0;
+					qctrl->reserved[1] = 0;
+					break;
+				case V4L2_CID_IVTV_DEC_FR_MASK:
+					qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+					strncpy(qctrl->name, "Frame Mask", 32);
+					qctrl->minimum = 0;
+					qctrl->maximum = 2;
+					qctrl->default_value = 2;
+					qctrl->flags = 0;
+					qctrl->reserved[0] = 0;
+					qctrl->reserved[1] = 0;
+					break;
+				case V4L2_CID_IVTV_DEC_SP_MUTE:
+					qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
+					strncpy(qctrl->name,
+						"Mute during slow/fast", 32);
+					qctrl->minimum = 0;
+					qctrl->maximum = 1;
+					qctrl->default_value = 1;
+					qctrl->flags = 0;
+					qctrl->reserved[0] = 0;
+					qctrl->reserved[1] = 0;
+					break;
+				case V4L2_CID_IVTV_DEC_FR_FIELD:
+					qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
+					strncpy(qctrl->name,
+						"Toggle frame/field", 32);
+					qctrl->minimum = 0;
+					qctrl->maximum = 1;
+					qctrl->default_value = 1;
+					qctrl->flags = 0;
+					qctrl->reserved[0] = 0;
+					qctrl->reserved[1] = 0;
+					break;
+				case V4L2_CID_IVTV_DEC_AUD_SKIP:
+					qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+					strncpy(qctrl->name, "Mute audio frames",32);
+					qctrl->minimum = 0;
+					qctrl->maximum = 15;
+					qctrl->default_value = 0;
+					qctrl->flags = 0;
+					qctrl->reserved[0] = 0;
+					qctrl->reserved[1] = 0;
+					break;
+				case V4L2_CID_IVTV_DEC_NUM_BUFFERS:
+					qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
+					strncpy(qctrl->name,
+						"Number of decoder buffers", 32);
+					qctrl->minimum = 0;
+					qctrl->maximum = 1;
+					qctrl->default_value = 1;
+					qctrl->flags = 0;
+					qctrl->reserved[0] = 0;
+					qctrl->reserved[1] = 1;
+					break;
+				case V4L2_CID_IVTV_DEC_PREBUFFER:
+					qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
+					strncpy(qctrl->name,
+						"Decoder prebuffer", 32);
+					qctrl->minimum = 0;
+					qctrl->maximum = 1;
+					qctrl->default_value = 1;
+					qctrl->flags = 0;
+					qctrl->reserved[0] = 0;
+					qctrl->reserved[1] = 1;
+					break;
+				default:
+					IVTV_DEBUG(IVTV_DEBUG_ERR,
+							"qctrl: invalid control\n");
+					return -EINVAL;
+					break;
+				}
+			}
+		
+			break;
+		}
+		
+		switch (qctrl->id) {
+		case V4L2_CID_BRIGHTNESS:
+			qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+			strncpy(qctrl->name, "Brightness", 32);
+			qctrl->minimum = 0;
+			qctrl->maximum = 255;
+			qctrl->step = 0;
+			qctrl->default_value = 128;
+			qctrl->flags = 0;
+			qctrl->reserved[0] = 0;
+			qctrl->reserved[1] = 0;
+			break;
+		case V4L2_CID_HUE:
+			qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+			strncpy(qctrl->name, "Hue", 32);
+			qctrl->minimum = -128;
+			qctrl->maximum = 127;
+			qctrl->step = 0;
+			qctrl->default_value = 0;
+			qctrl->flags = 0;
+			qctrl->reserved[0] = 0;
+			qctrl->reserved[1] = 0;
+			break;
+		case V4L2_CID_SATURATION:
+			qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+			strncpy(qctrl->name, "Saturation", 32);
+			qctrl->minimum = 0;
+			qctrl->maximum = 127;
+			qctrl->step = 0;
+			qctrl->default_value = 64;
+			qctrl->flags = 0;
+			qctrl->reserved[0] = 0;
+			qctrl->reserved[1] = 0;
+			break;
+		case V4L2_CID_CONTRAST:
+			qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+			strncpy(qctrl->name, "Contrast", 32);
+			qctrl->minimum = 0;
+			qctrl->maximum = 127;
+			qctrl->step = 0;
+			qctrl->default_value = 64;
+			qctrl->flags = 0;
+			qctrl->reserved[0] = 0;
+			qctrl->reserved[1] = 0;
+			break;
+		case V4L2_CID_AUDIO_VOLUME:
+			qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+			strncpy(qctrl->name, "Volume", 32);
+			qctrl->minimum = 0;
+			qctrl->maximum = 65535;
+			qctrl->step = 0;
+			qctrl->default_value = 65535;
+			qctrl->flags = 0;
+			qctrl->reserved[0] = 0;
+			qctrl->reserved[1] = 0;
+			break;
+		case V4L2_CID_AUDIO_MUTE:
+			qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+			strncpy(qctrl->name, "Mute", 32);
+			qctrl->minimum = 0;
+			qctrl->maximum = 1;
+			qctrl->step = 0;
+			qctrl->default_value = 1;
+			qctrl->flags = 0;
+			qctrl->reserved[0] = 0;
+			qctrl->reserved[1] = 0;
+			break;
+		default:
+			IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: invalid control\n");
+			return -EINVAL;
+		}
+		break;
+	}
+	case VIDIOC_S_CTRL: {
+		struct v4l2_control *vctrl = (struct v4l2_control *)arg;
+
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: set control\n");
+
+		if (vctrl->id >= V4L2_CID_PRIVATE_BASE) {
+			int off = vctrl->id - V4L2_CID_PRIVATE_BASE;
+			s32 v = vctrl->value;
+			if (off < IVTV_V4L2_AUDIO_MENUCOUNT) {
+				if ((v<=itv->v4l2.audio_meta[off].ctrl->maximum) &&
+				    (v>=itv->v4l2.audio_meta[off].ctrl->minimum)) {
+					itv->v4l2.audio_meta[off].setting = v;
+					/* presumably value has changed.
+					 * we should update the bitmap */
+					itv->v4l2.codec.audio_bitmap &= 
+						~itv->v4l2.audio_meta[off].mask;
+					itv->v4l2.codec.audio_bitmap |= 
+						itv->v4l2.audio_meta[off].table[v];
+
+					/* Also upade the digitizer setting */
+					if (0 == off) { /* audio input bitrate */
+						int vrate = (int)v;
+						/* FIXME not obvious how this works
+						 *  (see ivtv_ctrl_query_freq[]) */
+						ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_SET_AUDIO,&vrate);
+					}
+				} else {
+					IVTV_DEBUG(IVTV_DEBUG_ERR,
+						"ctrl: value out of range\n");
+				return -ERANGE;
+				}
+			} else {
+				switch (vctrl->id) {
+				case V4L2_CID_IVTV_DEC_SMOOTH_FF:
+					if ((v < 0) || (v > 1)) return -ERANGE;
+					itv->dec_options.speed.smooth = vctrl->value;
+					break;
+				case V4L2_CID_IVTV_DEC_FR_MASK:
+					if ((v < 0) || (v > 2)) return -ERANGE;
+					 itv->dec_options.speed.fr_mask=vctrl->value;
+					break;
+				case V4L2_CID_IVTV_DEC_SP_MUTE:
+					if ((v < 0) || (v > 1)) return -ERANGE;
+					itv->dec_options.speed.aud_mute=vctrl->value;
+					break;
+				case V4L2_CID_IVTV_DEC_FR_FIELD:
+					if ((v < 0) || (v > 1)) return -ERANGE;
+					itv->dec_options.speed.fr_field=vctrl->value;
+					break;
+				case V4L2_CID_IVTV_DEC_AUD_SKIP:
+					if ((v < 0) || (v > 15)) return -ERANGE;
+					itv->dec_options.mute_frames = vctrl->value;
+					break;
+				case V4L2_CID_IVTV_DEC_NUM_BUFFERS:
+					if ((v < 0) || (v > 1)) return -ERANGE;
+					itv->dec_options.decbuffers = vctrl->value;
+					break;
+				case V4L2_CID_IVTV_DEC_PREBUFFER:
+					if ((v < 0) || (v > 1)) return -ERANGE;
+					itv->dec_options.prebuffer = vctrl->value;
+					break;
+				default:
+					IVTV_DEBUG(IVTV_DEBUG_ERR,
+							"ctrl: invalid control\n");
+					return -EINVAL;
+				}
+			}
+		
+			break;
+		}
+		
+		switch (vctrl->id) {
+		case V4L2_CID_BRIGHTNESS: {
+			struct saa7114 pic;
+
+			if (vctrl->value < 0 || vctrl->value > 255) {
+				IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid brightness value: %d\n", vctrl->value);
+				return -EINVAL;
+			}
+			ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic);
+			pic.bright = vctrl->value;
+			ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_SET_PICTURE,&pic);
+			break;
+		}
+		case V4L2_CID_HUE: {
+			struct saa7114 pic;
+
+			if (vctrl->value < -128 || vctrl->value > 127) {
+				IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid hue value: %d\n", vctrl->value);
+				return -EINVAL;
+			}
+			ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic);
+			pic.hue = vctrl->value;
+			ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_SET_PICTURE,&pic);
+			break;
+		}
+		case V4L2_CID_SATURATION: {
+			struct saa7114 pic;
+
+			if (vctrl->value < 0 || vctrl->value > 127) {
+				IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid saturation value: %d\n", vctrl->value);
+				return -EINVAL;
+			}
+			ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic);
+			pic.sat = vctrl->value;
+			ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_SET_PICTURE,&pic);
+			break;
+		}
+		case V4L2_CID_CONTRAST: {
+			struct saa7114 pic;
+
+			if (vctrl->value < 0 || vctrl->value > 127) {
+				IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid contrast value: %d\n", vctrl->value);
+				return -EINVAL;
+			}
+			ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic);
+			pic.contrast = vctrl->value;
+			ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_SET_PICTURE,&pic);
+			break;
+		}
+		case V4L2_CID_AUDIO_VOLUME: {
+			struct video_audio va;
+
+			if (vctrl->value > 65535 || vctrl->value < 0) {
+				IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid value for volume: %d", vctrl->value);
+				return -EINVAL;
+			}
+			ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,VIDIOCGAUDIO,&va);
+			va.volume = vctrl->value;
+			ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,VIDIOCSAUDIO,&va);
+			break;
+		}
+		case V4L2_CID_AUDIO_MUTE: {
+			struct video_audio va;
+			ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,VIDIOCGAUDIO,&va);
+			if (vctrl->value)
+				va.flags |= VIDEO_AUDIO_MUTE;
+			else
+				va.flags = (va.flags & ~(VIDEO_AUDIO_MUTE));
+			ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,VIDIOCSAUDIO,&va);
+			break;
+		}
+		default:
+			IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid control\n");
+			return -EINVAL;
+		}
+
+		break;
+	}
+	case VIDIOC_G_CTRL: {
+		struct v4l2_control *vctrl = (struct v4l2_control *)arg;
+
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: get control\n");
+
+		if (vctrl->id >= V4L2_CID_PRIVATE_BASE) {
+			int off = vctrl->id - V4L2_CID_PRIVATE_BASE;
+			if (off < IVTV_V4L2_AUDIO_MENUCOUNT) {
+				vctrl->value =itv->v4l2.audio_meta[off].setting;
+			} else {
+				switch (vctrl->id) {
+				case V4L2_CID_IVTV_DEC_SMOOTH_FF:
+					vctrl->value = itv->dec_options.speed.smooth;
+					break;
+				case V4L2_CID_IVTV_DEC_FR_MASK:
+					vctrl->value= itv->dec_options.speed.fr_mask;
+					break;
+				case V4L2_CID_IVTV_DEC_SP_MUTE:
+					vctrl->value=itv->dec_options.speed.aud_mute;
+					break;
+				case V4L2_CID_IVTV_DEC_FR_FIELD:
+					vctrl->value=itv->dec_options.speed.fr_field;
+					break;
+				case V4L2_CID_IVTV_DEC_AUD_SKIP:
+					vctrl->value = itv->dec_options.mute_frames;
+					break;
+				case V4L2_CID_IVTV_DEC_NUM_BUFFERS:
+					vctrl->value = itv->dec_options.decbuffers;
+					break;
+				case V4L2_CID_IVTV_DEC_PREBUFFER:
+					vctrl->value = itv->dec_options.prebuffer;
+					break;
+				default:
+					IVTV_DEBUG(IVTV_DEBUG_ERR,
+							"ctrl: invalid control\n");
+					return -EINVAL;
+				}
+			}
+		
+			break;
+		}
+		
+		switch (vctrl->id) {
+		case V4L2_CID_BRIGHTNESS: {
+			struct saa7114 pic;
+			ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic);
+			vctrl->value = pic.bright;
+			break;
+		}
+		case V4L2_CID_HUE: {
+			struct saa7114 pic;
+			ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic);
+			vctrl->value = pic.hue;
+			break;
+		}
+		case V4L2_CID_SATURATION: {
+			struct saa7114 pic;
+			ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic);
+			vctrl->value = pic.sat;
+			break;
+		}
+		case V4L2_CID_CONTRAST: {
+			struct saa7114 pic;
+			ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic);
+			vctrl->value = pic.contrast;
+			break;
+		}
+		case V4L2_CID_AUDIO_VOLUME: {
+			struct video_audio va;
+			ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,VIDIOCGAUDIO,&va);
+			vctrl->value = va.volume;
+			break;
+		}
+		case V4L2_CID_AUDIO_MUTE: {
+			struct video_audio va;
+			ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,VIDIOCGAUDIO,&va);
+			vctrl->value = (va.flags & VIDEO_AUDIO_MUTE);
+			break;
+		}
+		default:
+			IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid control\n");
+			return -EINVAL;
+		}
+		break;
+	}
+	case VIDIOC_QUERYCAP: {
+		struct v4l2_capability *vcap = (struct v4l2_capability *)arg;
+		
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: querycap\n");
+
+		/* driver name */
+		strcpy(vcap->driver,IVTV_DRIVER_NAME);
+
+		/* card type */
+		strcpy(vcap->card,id->itv->v4l2.streams[id->type].v4l2dev->name);
+
+		/* bus info.. card # will do */
+		sprintf(vcap->bus_info, "%d", itv->num);
+
+		/* version */
+		vcap->version = IVTV_DRIVER_VERSION;
+
+		/* capabilities */
+		vcap->capabilities = itv->v4l2.capabilities;
+
+		/* reserved.. must set to 0! */
+		vcap->reserved[0] = vcap->reserved[1] = vcap->reserved[2] =
+			vcap->reserved[3] = 0;
+		break;
+	}
+	case VIDIOC_ENUMINPUT: {
+		struct v4l2_input *vin = (struct v4l2_input *)arg;
+		
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: enuminput\n");
+
+		if ((vin->index < 0) || (vin->index >= itv->v4l2.input.count))
+			return -EINVAL;
+
+		/* set it to defaults from our table */
+		memcpy(vin,
+		       &itv->v4l2.input.table.input[vin->index],
+		       sizeof(struct v4l2_input));
+
+		/* set the standard to whatever our overall standard is */
+		vin->std = tmk_standards[itv->v4l2.standard.active].id;
+		vin->status = 0; /*FIXME status isn't always ok... */
+
+		break;
+	} 
+					       
+	case VIDIOC_G_FMT: {
+		struct v4l2_format *vfmt = (struct v4l2_format *)arg;
+		
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: get format\n");
+
+		/* FIXME switch on stream type */
+		memcpy (vfmt, &itv->v4l2.streams[0].format, sizeof(struct v4l2_format));
+		break;
+	}
+	case VIDIOC_S_FMT: {
+		struct v4l2_format *vfmt = (struct v4l2_format *)arg;
+		struct video_window wind;
+
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: set format\n");
+
+		/* FIXME only sets resolution for now */
+		wind.width = vfmt->fmt.pix.width;
+		wind.height = vfmt->fmt.pix.height;
+		ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,
+				     DECODER_SET_SIZE,&wind);
+
+		/* FIXME switch on stream type, bounds checking */
+		memcpy (&itv->v4l2.streams[0].format, vfmt, sizeof(struct v4l2_format));
+		/* Adjust res in YUV also */
+		itv->v4l2.streams[1].format.fmt.pix.height = vfmt->fmt.pix.height;
+		itv->v4l2.streams[1].format.fmt.pix.width = vfmt->fmt.pix.width;
+
+		break;
+	}
+	case VIDIOC_G_INPUT: {
+		int *inp = (int *)arg;
+
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: get input\n");
+
+		*inp = itv->v4l2.input.active;
+		break;
+	}
+	case VIDIOC_S_INPUT: {
+		int a_in,inp = *(int *)arg;
+		struct msp_matrix mspm;
+		
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: set input\n");
+		
+                if ((inp < 0) || (inp >= itv->v4l2.input.count)) return -EINVAL;
+
+		if (inp == itv->v4l2.input.active) {
+			IVTV_DEBUG(IVTV_DEBUG_INFO, "Input unchanged\n");
+		} else {
+			IVTV_DEBUG(IVTV_DEBUG_INFO, "Changing input from %d to %d\n",
+				   itv->v4l2.input.active, inp);
+
+			itv->v4l2.input.active = inp;
+			itv->v4l2.audio.active	=
+				itv->v4l2.input.table.input[inp].audioset;
+
+			/* Mute sound to avoid pop */
+			mspm.input = 8;
+			mspm.output = itv->v4l2.audio_output;
+			ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR
+					     ,MSP_SET_MATRIX,&mspm);
+
+			if (0 != ivtv_pause_encoder(itv, 0)) 
+				IVTV_DEBUG(IVTV_DEBUG_ERR,
+					   "Input: Error pausing stream\n");
+
+			ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,
+					     DECODER_SET_INPUT,&inp);
+
+			/* Pause to let sound calm down */
+			ivtv_sleep_timeout(HZ/33);
+
+			if (0 != ivtv_pause_encoder(itv, 1)) 
+				IVTV_DEBUG(IVTV_DEBUG_ERR,
+					   "Input: Error unpausing stream\n");
+
+			/* FIXME Needs to be card-specific */
+			a_in = ivtv_set_audio(itv,tmk_audio_mapping);
+			if (a_in < 0) return a_in;
+		}
+		break;
+	}
+	case VIDIOC_G_FREQUENCY: {
+		struct v4l2_frequency *vf=(struct v4l2_frequency *)arg;
+
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: get frequency\n");
+
+		if ((vf->tuner < 0) || (vf->tuner >= itv->v4l2.tuner.count))
+			return -EINVAL;
+		vf->frequency = itv->v4l2.freq.frequency;
+		break;
+	}
+	case VIDIOC_S_FREQUENCY: {
+		struct v4l2_frequency *vf=(struct v4l2_frequency *)arg;
+		struct msp_matrix mspm;
+
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: set frequency\n");
+
+		if ((vf->tuner < 0) || (vf->tuner >= itv->v4l2.tuner.count))
+			return -EINVAL;
+		itv->v4l2.freq.frequency = vf->frequency;
+
+		/* Mute sound to avoid pop */
+		mspm.input = 8;
+		mspm.output = itv->v4l2.audio_output;
+		ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,MSP_SET_MATRIX,&mspm);
+
+		if (0 != ivtv_pause_encoder(itv, 0)) 
+			IVTV_DEBUG(IVTV_DEBUG_ERR, "Freq: Error pausing stream\n");
+
+		/* Set frequency */
+		ivtv_call_i2c_client(itv,IVTV_TUNER_I2C_ADDR,
+				     VIDIOCSFREQ,&itv->v4l2.freq.frequency);
+
+		/* Pause to let sound calm down */
+		ivtv_sleep_timeout(HZ/33);
+
+		if (0 != ivtv_pause_encoder(itv, 1)) 
+			IVTV_DEBUG(IVTV_DEBUG_ERR, "Freq: Error unpausing stream\n");
+
+		/* Unmute */
+		ivtv_set_audio(itv,tmk_audio_mapping);
+
+		break;
+	}
+	case VIDIOC_ENUMSTD: {
+		struct v4l2_standard *vs=(struct v4l2_standard *)arg;
+
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: enum standard\n");
+
+		if ((vs->index < 0) || (vs->index >= itv->v4l2.standard.count))
+			return -EINVAL;
+		
+		memcpy(vs, &itv->v4l2.standard.table.std[vs->index],
+		 	sizeof(struct v4l2_standard));
+
+		break;
+	}
+	case VIDIOC_G_STD: {
+		v4l2_std_id *vs=(v4l2_std_id *)arg;
+
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: get standard\n");
+
+		*vs = itv->v4l2.standard.table.std[itv->v4l2.standard.active].id;
+		break;
+	}
+	case VIDIOC_S_STD: {
+		v4l2_std_id *vs=(v4l2_std_id *)arg;
+                struct video_channel v;
+		int x;
+
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: set standard\n");
+
+		for (x = 0; x < itv->v4l2.standard.count; x++) {
+			if (itv->v4l2.standard.table.std[x].id & *vs) {
+				IVTV_DEBUG(IVTV_DEBUG_INFO,
+					   "Switching standard to %s.\n",
+					   itv->v4l2.standard.table.std[x].name);
+				itv->v4l2.standard.active = x;
+				/* fixme set standard here */
+				switch (itv->v4l2.standard.active) {
+				case 0: /* NTSC */
+					v.norm = VIDEO_MODE_NTSC;
+					break;
+				case 1: /* PAL */
+					v.norm = VIDEO_MODE_PAL;
+					break;
+				case 2: /* SECAM */
+					v.norm = VIDEO_MODE_SECAM;
+					break;
+				default:
+					break;
+				}
+
+				/* Tuner */
+				ivtv_call_i2c_client(itv,
+						     IVTV_TUNER_I2C_ADDR,
+						     VIDIOCSCHAN,&v);
+				/* Tuner Audio */
+                                ivtv_call_i2c_client(itv,
+                                                     IVTV_MSP3400_I2C_ADDR,
+                                                     VIDIOCSCHAN,&v);
+				/* Digitizer */
+		                ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,
+			                             DECODER_SET_NORM,&v.norm);
+
+                                if (itv->v4l2.standard.active == 0) { // NTSC
+                                        itv->v4l2.codec.framespergop = 15;
+                                        itv->v4l2.codec.framerate    = 0;
+                                } else { // PAL
+                                        itv->v4l2.codec.framespergop = 12;
+                                        itv->v4l2.codec.framerate    = 1;
+                                }
+
+				return 0;
+			}
+		}
+		return -EINVAL;
+	}
+	case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */
+		struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;
+
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: set tuner\n");
+
+		if ((vt->index < 0) || (vt->index >= itv->v4l2.tuner.count))
+			return -EINVAL;
+		/* looks like tuner.c doesn't support selection 
+		 * fallback to stereo... */
+		vt->audmode = V4L2_TUNER_MODE_STEREO;
+
+		break;
+	}
+	case VIDIOC_G_TUNER: {
+		struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;
+		int sig=0;
+
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: get tuner\n");
+
+		if ((vt->index < 0) || (vt->index >= itv->v4l2.tuner.count))
+			return -EINVAL;
+
+		memcpy(vt, &itv->v4l2.tuner.table.tuner[vt->index],
+		       sizeof(struct v4l2_tuner));
+		
+		
+	             ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,
+				     DECODER_GET_STATUS,&sig);
+
+		if (sig & DECODER_STATUS_GOOD) {
+			vt->signal = 65535; /* best possible signal */
+		} else {
+			vt->signal = 0;
+		}
+		break;
+	}
+	case MSP_SET_MATRIX: {
+		struct msp_matrix *mspm = (struct msp_matrix *)arg;
+
+		/* FIXME hardcoding! */
+		if ((mspm->input < 1) || (mspm->input > 8)) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR,"Invalid audio input!\n");
+			return -EINVAL;
+		}
+		if ((mspm->output < 0) || (mspm->output > 3)) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR,"Invalid audio output!\n");
+			return -EINVAL;
+		}
+
+		itv->v4l2.audio_output = mspm->output;
+
+		IVTV_DEBUG(IVTV_DEBUG_INFO,
+			   "v4l2 ioctl: set matrix in=%d,out=%d\n",
+			   mspm->input,
+			   mspm->output);
+
+		ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,MSP_SET_MATRIX, mspm);
+		break;
+	}
+	case IVTV_IOC_G_CODEC: {
+		struct ivtv_ioctl_codec *codec=(struct ivtv_ioctl_codec *)arg;
+
+		/* FIXME: bounds check? */
+		memcpy(codec, &(itv->v4l2.codec), sizeof(struct ivtv_ioctl_codec));
+		break;
+	}
+	case IVTV_IOC_S_CODEC: {
+		struct ivtv_ioctl_codec *codec=(struct ivtv_ioctl_codec *)arg;
+
+		/* FIXME: insert abundant parameter validation here */
+		if((codec->bitrate == 0) || (codec->bitrate_peak == 0) ||
+		   (codec->bitrate > codec->bitrate_peak) ) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR,"ivtv ioctl: set "
+				   "bitrate=%u < peak=%u: failed\n",
+				   codec->bitrate, codec->bitrate_peak);
+			return -EINVAL;
+		} else {
+	  		/* Passed the garbage check */
+	  		memcpy(&(itv->v4l2.codec), codec,
+				sizeof(struct ivtv_ioctl_codec));
+		}
+
+		/* VCD streamtype has some quirks. Handle them here */
+		if ((codec->stream_type == IVTV_STREAM_VCD) ||
+		    (codec->stream_type == IVTV_STREAM_MPEG1)) {
+		        struct v4l2_format *vfmt = (struct v4l2_format *)arg;
+			struct video_window wind;
+			int tmpsize = 480;
+
+			if (itv->v4l2.standard.active == 1) tmpsize = 576;
+			
+			IVTV_DEBUG(IVTV_DEBUG_INFO,"ivtv ioctl: mpeg1_stream "
+					           "size %d\n", tmpsize);
+
+			/* so far it looks like you can change width at will     *
+		 	 * but the compressor is unhappy when the height changes *
+			 * to anything other than 240 */
+		        wind.width = 352; 
+			wind.height = tmpsize;
+			vfmt->fmt.pix.width = 352;
+			vfmt->fmt.pix.height = tmpsize / 2;
+
+		        ivtv_call_i2c_client(itv,
+				IVTV_SAA7115_I2C_ADDR,DECODER_SET_SIZE,&wind);
+		        memcpy (&itv->v4l2.streams[0].format,
+				vfmt, sizeof(struct v4l2_format));
+		}
+
+		break;
+	}
+	case IVTV_IOCTL_GET_DEBUG_LEVEL: {
+		int *dbg_level = (int *)arg;
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "IVTV_IOCTL_GET_DEBUG_LEVEL ivtv_debug = "
+				"0x%08x\n", ivtv_debug);
+		if (dbg_level) {
+			put_user(ivtv_debug, dbg_level);
+		} else {
+			printk("ivtv: Error: IVTV_IOCTL_GET_DEBUG_LEVEL called with "
+					"NULL\n");
+		}
+		break;
+	}
+	case IVTV_IOCTL_SET_DEBUG_LEVEL: {
+		int *dbg_level = (int *)arg;
+		int old_debug_level = ivtv_debug;
+		get_user(ivtv_debug, dbg_level);
+		if (!(ivtv_debug & IVTV_DEBUG_ERR)) ivtv_debug |= IVTV_DEBUG_ERR;
+		IVTV_DEBUG(IVTV_DEBUG_INFO,
+			   "IVTV_IOCTL_SET_DEBUG_LEVEL ivtv_debug = "
+			   "0x%08x (new) 0x%08x (old)\n",
+			   ivtv_debug,
+			   old_debug_level);
+		put_user(ivtv_debug, dbg_level);
+		break;
+	}
+	case VIDIOC_STREAMOFF: { 
+		ivtv_v4l2_streamoff(id);
+		break;
+	}
+
+	case 0x00005401: /* Handle isatty() calls */
+		return -EINVAL;
+	default:
+		/* If it got here, it's probably not supported.. */
+		IVTV_DEBUG(IVTV_DEBUG_ERR,"ivtv-api.c: unknown ioctl 0x%08x\n", cmd);
+		return -ENOTTY;
+	}
+	return 0;
+}
diff -aurpN -X /home/fletch/.diff.exclude 670-tiocgdev/drivers/media/video/ivtv-driver.c 680-ia64_dec_and_lock/drivers/media/video/ivtv-driver.c
--- 670-tiocgdev/drivers/media/video/ivtv-driver.c	Wed Dec 31 16:00:00 1969
+++ 680-ia64_dec_and_lock/drivers/media/video/ivtv-driver.c	Wed Feb 11 10:17:11 2004
@@ -0,0 +1,2926 @@
+/* Main Driver file for the ivtv project:
+ * Driver for the iTVC15 chip.
+ * Author: Kevin Thayer (nufan_wfk at yahoo.com)
+ * License: GPL
+ * http://www.sourceforge.net/projects/ivtv/
+ */
+
+#define __KERNEL_SYSCALLS__
+#include "ivtv.h"
+
+// Version info
+#define IVTV_VERSION_NUMBER(name) name##_version_int
+#define IVTV_VERSION_STRING(name) name##_version_string
+#define IVTV_VERSION_COMMENT(name) name##_comment_string
+
+#define IVTV_DEFINE_VERSION_INTERNAL(name, major, minor, patchlevel, comment) \
+unsigned int IVTV_VERSION_NUMBER(name) = ((major << 16) | (minor << 8) | (patchlevel)); \
+const char * const IVTV_VERSION_STRING(name) = #major"."#minor"."#patchlevel;\
+const char * const IVTV_VERSION_COMMENT(name) = comment;
+
+#define IVTV_VERSION_MAJOR(name) (0xFF & (IVTV_VERSION_NUMBER(name) >> 16))
+#define IVTV_VERSION_MINOR(name) (0xFF & (IVTV_VERSION_NUMBER(name) >> 8))
+#define IVTV_VERSION_PATCHLEVEL(name) (0xFF & (IVTV_VERSION_NUMBER(name)))
+
+#define IVTV_DEFINE_VERSION(name, major, minor, patchlevel, comment) IVTV_DEFINE_VERSION_INTERNAL(name, major, minor, patchlevel, comment)
+
+IVTV_DEFINE_VERSION(ivtv_rev,
+		IVTV_DRIVER_VERSION_MAJOR,
+		IVTV_DRIVER_VERSION_MINOR,
+		IVTV_DRIVER_VERSION_PATCHLEVEL,
+		"pre");
+
+/* mini header */
+
+/* var to keep track of the number of array elements in use */
+int ivtv_cards_active = 0;
+
+/* Master variable for all ivtv info */
+struct ivtv ivtv_cards[IVTV_MAX_CARDS];
+
+/* for the global data */
+spinlock_t ivtv_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
+
+/* add your revision and whatnot here */
+static struct pci_device_id ivtv_pci_tbl[] __devinitdata = {
+		{PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV15,
+		 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+		{PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV16,
+		 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+		{0,}
+};
+
+static void ivtv_irq_dec_vsync(struct ivtv* itv);
+static irqreturn_t ivtv_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
+static void ivtv_DMA_done(struct ivtv *itv);
+static void ivtv_sched_DMA(struct ivtv *itv);
+static void ivtv_dec_DMA_done(struct ivtv *itv);
+static void ivtv_dec_sched_DMA(struct ivtv *itv);
+
+static u32 ivtv_firm_search_id[]= {0x12345678,0x34567812,0x56781234,0x78123456};
+
+/* Parameter declarations */
+static int num_devices = IVTV_DEFAULT_NUM_CARDS;
+int yuv_buffers = IVTV_DEFAULT_YUV_BUFFERS;
+int mpg_buffers = IVTV_DEFAULT_MPG_BUFFERS;
+int vbi_buffers = IVTV_DEFAULT_VBI_BUFFERS;
+int dec_mpg_buffers = IVTV_DEFAULT_DEC_MPG_BUFFERS;
+int dec_yuv_buffers = IVTV_DEFAULT_DEC_YUV_BUFFERS;
+static int dec_mpg_qlen = IVTV_DEFAULT_DEC_MPG_QLEN;
+static int dec_yuv_qlen = IVTV_DEFAULT_DEC_YUV_QLEN;
+#ifdef YUV_FIXUP
+static int yuv_fixup;
+#endif
+
+int ivtv_pal = 0;
+
+
+/* low debugging by default */
+#if 0
+int debug = ( 	IVTV_DEBUG_ERR | IVTV_DEBUG_INFO  | IVTV_DEBUG_API
+		| IVTV_DEBUG_DMA | IVTV_DEBUG_IOCTL | IVTV_DEBUG_I2C 
+		| IVTV_DEBUG_IRQ );
+#endif
+int ivtv_debug = IVTV_DEBUG_ERR;
+
+/* tuner.h tuner type for ivtv card */
+int tuner = -1;
+
+int errno;
+
+#define EXPAND_TO_STRING_INTERNAL(arg) #arg
+#define EXPAND_TO_STRING(arg) EXPAND_TO_STRING_INTERNAL(arg)
+
+#ifdef YUV_FIXUP
+MODULE_PARM(yuv_fixup, "i");
+MODULE_PARM_DESC(yuv_fixup,
+		 "\nToggles conversion of Hauppauge Macroblock NV12 to NV12\n");
+#endif
+
+MODULE_PARM(tuner, "i");
+MODULE_PARM_DESC(tuner, "\nTuner type selection, see tuner.h for values");
+
+MODULE_PARM(yuv_buffers, "i");
+MODULE_PARM_DESC(yuv_buffers,
+		 "\nNumber of 32K buffers for copying YUV.\n"
+		 "Default: " EXPAND_TO_STRING(IVTV_DEFAULT_YUV_BUFFERS) ", "
+		 "Min: " EXPAND_TO_STRING(IVTV_MIN_YUV_BUFFERS) " "
+		 "Max: " EXPAND_TO_STRING(IVTV_MAX_YUV_BUFFERS));
+
+MODULE_PARM(mpg_buffers, "i");
+MODULE_PARM_DESC(mpg_buffers,
+		 "\nNumber of 32K buffers for copying mpg.\n"
+		 "Default: " EXPAND_TO_STRING(IVTV_DEFAULT_MPG_BUFFERS) ", "
+		 "Min: " EXPAND_TO_STRING(IVTV_MIN_MPG_BUFFERS) " "
+		 "Max: " EXPAND_TO_STRING(IVTV_MAX_MPG_BUFFERS));
+
+MODULE_PARM(vbi_buffers, "i");
+MODULE_PARM_DESC(vbi_buffers,
+		 "\nNumber of 32K buffers for copying VBI.\n"
+		 "Default: " EXPAND_TO_STRING(IVTV_DEFAULT_VBI_BUFFERS) ", "
+		 "Min: " EXPAND_TO_STRING(IVTV_MIN_VBI_BUFFERS) " "
+		 "Max: " EXPAND_TO_STRING(IVTV_MAX_VBI_BUFFERS));
+
+MODULE_PARM(num_devices, "i");
+MODULE_PARM_DESC(num_devices, "\nNumber of supported devices (1-9).\n"
+		"Default: " EXPAND_TO_STRING(IVTV_DEFAULT_NUM_CARDS));
+
+MODULE_PARM(dec_mpg_buffers, "i");
+MODULE_PARM_DESC(dec_mpg_buffers,
+		 "\nNumber of 32K buffers for decoding MPG.\n"
+		 "Default: " EXPAND_TO_STRING(IVTV_DEFAULT_DEC_MPG_BUFFERS) ", "
+		 "Min: " EXPAND_TO_STRING(IVTV_MIN_DEC_MPG_BUFFERS) " "
+		 "Max: " EXPAND_TO_STRING(IVTV_MAX_DEC_MPG_BUFFERS));
+
+MODULE_PARM(dec_yuv_buffers, "i");
+MODULE_PARM_DESC(dec_yuv_buffers,
+		 "\nNumber of 32K buffers for decoding YUV.\n"
+		 "Default: " EXPAND_TO_STRING(IVTV_DEFAULT_DEC_YUV_BUFFERS) ", "
+		 "Min: " EXPAND_TO_STRING(IVTV_MIN_DEC_YUV_BUFFERS) " "
+		 "Max: " EXPAND_TO_STRING(IVTV_MAX_DEC_YUV_BUFFERS) ", "
+		 "0 to disable");
+
+MODULE_PARM(dec_mpg_qlen, "i");
+MODULE_PARM_DESC(dec_mpg_qlen, 
+		 "\nNumber of 32K buffers to queue before dispatching to decoder\n"
+		 "Default: " EXPAND_TO_STRING(IVTV_DEFAULT_DEC_MPG_QLEN) ", "
+		 "Min: " EXPAND_TO_STRING(IVTV_MIN_DEC_MPG_QLEN) " "
+		 "Max: <dec_mpg_buffers>");
+
+MODULE_PARM(dec_yuv_qlen, "i");
+MODULE_PARM_DESC(dec_yuv_qlen, 
+		 "\nNumber of 32K buffers to queue before dispatching to decoder\n"
+		 "Default: " EXPAND_TO_STRING(IVTV_DEFAULT_DEC_YUV_QLEN) ", "
+		 "Min: " EXPAND_TO_STRING(IVTV_MIN_DEC_YUV_QLEN) " "
+		 "Max: <dec_yuv_buffers>");
+
+MODULE_PARM(ivtv_debug, "i");
+MODULE_PARM_DESC(ivtv_debug, "\nDebug level (bitmask), default, errors only\n"
+		             "(debug=127 gives full debuging)");
+
+MODULE_PARM(ivtv_pal, "i");
+MODULE_PARM_DESC(ivtv_pal, "\nUse PAL as default video mode instead of NTSC");
+
+MODULE_AUTHOR("Kevin Thayer");
+MODULE_DESCRIPTION("Alpha iTVC15 driver");
+MODULE_SUPPORTED_DEVICE("iTVC15/16 mpg2 encoder (aka WinTV PVR 250/350)");
+MODULE_LICENSE("GPL");
+
+static int SGarray_size;
+static int DSGarray_size;
+
+void ivtv_sleep_timeout(int timeout)
+{
+	int sleep = timeout;
+
+	do {
+		set_current_state(TASK_INTERRUPTIBLE);
+		sleep = schedule_timeout(sleep);
+
+	} while (sleep && !signal_pending(current));
+}
+
+/* ceiling function for ints.. */
+int ivtv_ceil(int x, int y) {
+	int floor = (int)(x/y);
+
+	if ((floor * y) < x)
+		return floor+1;
+        return floor;
+}
+
+/* Release ioremapped memory */
+static void ivtv_iounmap(struct ivtv *itv) {
+	if (itv == NULL)
+		return ;
+
+	/* Release io memory */
+	if (itv->io_mem != NULL) {
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "releasing iomem\n");
+		iounmap(itv->io_mem);
+		itv->io_mem = NULL ;
+	}
+
+	/* Release registers memory */
+	if (itv->reg_mem != NULL) {
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "releasing regmem\n");
+		iounmap(itv->reg_mem);
+		itv->reg_mem = NULL ;
+	}
+
+	/* Release encoder mailboxes */
+	if (itv->enc_mbox != NULL) {
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "releasing encmbox\n");
+		iounmap(itv->enc_mbox);
+		itv->enc_mbox = NULL ;
+	}
+
+	/* Release decoder mailboxes */
+	if (itv->dec_mbox != NULL) {
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "releasing decmbox\n");
+		iounmap(itv->dec_mbox);
+		itv->dec_mbox = NULL ;
+	}
+}
+
+/* must only be used as hints, not as a definitive answer. the answer could
+ * be wrong as soon as we return */
+int ivtv_get_free_elements(struct ivtv *itv, struct ivtv_buffer_list *queue)
+{
+	unsigned long flags;
+	int elements;
+
+	spin_lock_irqsave(&itv->lock, flags);
+	elements = queue->elements;
+	spin_unlock_irqrestore(&itv->lock, flags);
+
+	return elements;
+}
+
+inline void __ivtv_enq_buf(struct ivtv_buffer_list *queue,
+			   struct ivtv_buffer *buf) {
+	WARN_ON(!list_empty(&buf->list));
+	list_add_tail(&buf->list, &queue->list);
+	queue->elements++;
+}
+
+
+/* Adds buffers to the tail, effectively making a queue */
+int ivtv_enq_buf(struct ivtv *itv, struct ivtv_buffer_list *queue,
+		 struct ivtv_buffer *buf) {
+	unsigned long flags;
+
+	spin_lock_irqsave(&itv->lock, flags);
+	__ivtv_enq_buf(queue, buf);
+	spin_unlock_irqrestore(&itv->lock, flags);
+
+	return 0;
+}
+
+inline void __ivtv_del_buf(struct ivtv_buffer_list *queue,
+			   struct ivtv_buffer *buffer) {
+	WARN_ON(list_empty(&buffer->list));
+	list_del_init(&buffer->list);
+	queue->elements--;
+}
+
+/* called to remove the buffer returned by _peek_ functions */
+void ivtv_del_buf(struct ivtv *itv, struct ivtv_buffer_list *queue,
+		  struct ivtv_buffer *buffer) {
+	unsigned long flags;
+
+	spin_lock_irqsave(&itv->lock, flags);
+	__ivtv_del_buf(queue, buffer);
+	spin_unlock_irqrestore(&itv->lock, flags);
+}
+
+void ivtv_move_buf(struct ivtv *itv, struct ivtv_buffer_list *from,
+		   struct ivtv_buffer_list *to, struct ivtv_buffer *buffer)
+{
+	unsigned long flags;
+
+	WARN_ON(list_empty(&buffer->list));
+
+	spin_lock_irqsave(&itv->lock, flags);
+	list_move_tail(&buffer->list, &to->list);
+	from->elements--;
+	to->elements++;
+	spin_unlock_irqrestore(&itv->lock, flags);
+}
+
+/* returns first item in queue, doesn't dequeue */
+struct ivtv_buffer *__ivtv_deq_peek_head(struct ivtv_buffer_list *queue) {
+
+	/* make sure list has something to DeQ */
+	if (!list_empty(&queue->list))
+		return list_entry(queue->list.next, struct ivtv_buffer, list);
+		
+	IVTV_DEBUG(IVTV_DEBUG_INFO,"DeQ from empty list\n");
+	queue->elements = 0;
+	return NULL;
+}
+
+struct ivtv_buffer *ivtv_deq_peek_head(struct ivtv *itv,
+				       struct ivtv_buffer_list *queue) {
+	unsigned long flags;
+	struct ivtv_buffer *buffer;
+
+	spin_lock_irqsave(&itv->lock, flags);
+	buffer = __ivtv_deq_peek_head(queue);
+	spin_unlock_irqrestore(&itv->lock, flags);
+
+	return buffer;
+}
+
+/* removes buffer from the head */
+struct ivtv_buffer *__ivtv_deq_buf(struct ivtv_buffer_list *queue) {
+	struct ivtv_buffer *buf;
+
+	/* make sure list has something to DeQ */
+	if (!list_empty(&queue->list)) {
+		buf = list_entry(queue->list.next, struct ivtv_buffer, list);
+		list_del_init(queue->list.next);
+		queue->elements--;
+		return buf;
+	}
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO,"DeQ from empty list!\n");
+	queue->elements = 0;
+	return NULL;
+}
+
+struct ivtv_buffer *ivtv_deq_buf(struct ivtv *itv,
+				 struct ivtv_buffer_list *queue) {
+	struct ivtv_buffer *buf;
+	unsigned long flags;
+
+	spin_lock_irqsave(&itv->lock, flags);
+	buf = __ivtv_deq_buf(queue);
+	spin_unlock_irqrestore(&itv->lock, flags);
+
+	return buf;
+}
+
+struct ivtv_buffer *ivtv_init_buffer(int gfp_mask) {
+	struct ivtv_buffer *ibuf;
+
+	ibuf = kmalloc(sizeof(struct ivtv_buffer), gfp_mask);
+	if (ibuf == NULL) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR,"No mem on ibuf alloc!\n");
+		return NULL;
+	}
+
+	(void *)ibuf->buffer.m.userptr = kmalloc(IVTV_DMA_BUF_SIZE, gfp_mask);
+	if ((void *)ibuf->buffer.m.userptr == NULL) {
+		kfree(ibuf);
+		IVTV_DEBUG(IVTV_DEBUG_ERR,"No mem on buf alloc!\n");
+		return NULL;
+	}
+
+	INIT_LIST_HEAD(&ibuf->list);
+	ibuf->buffer.length	= IVTV_DMA_BUF_SIZE;
+	ibuf->buffer.bytesused	= 0;
+	ibuf->readpos		= 0;
+
+	return ibuf;
+}
+
+#define IVTV_DMA_UNMAPPED	((u32) -1)
+
+void ivtv_free_buffer(struct ivtv *itv, struct ivtv_buffer *item) {
+	if (item->dma_handle != IVTV_DMA_UNMAPPED)
+		pci_unmap_single(itv->dev, item->dma_handle, IVTV_DMA_BUF_SIZE, PCI_DMA_TODEVICE);
+	if (item->buffer.m.userptr) {
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"Freeing buf %d!\n", item->buffer.index);
+		kfree((void *)item->buffer.m.userptr);
+	}
+	kfree(item);
+}
+
+int ivtv_free_queue(struct ivtv_buffer_list *queue) {
+        struct ivtv_buffer *item;
+	unsigned long flags;
+	struct ivtv *itv;
+	int x;
+
+	if (queue == NULL) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR,"Free on NULL list!\n");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&ivtv_lock, flags);
+
+	/* FIXME ugly */
+	/* verify ivtv before continuing */
+	itv = NULL;
+	for (x = 0; x < ivtv_cards_active; x++) {
+		if (queue->vdev->priv == &ivtv_cards[x]) {
+			itv = queue->vdev->priv;
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&ivtv_lock, flags);
+
+	if (itv == NULL)
+		return -ENODEV;
+
+	while ((item = ivtv_deq_buf(itv, queue)))
+		ivtv_free_buffer(itv, item);
+
+	return 0;
+}
+
+/* NOTE: This returns the # of buffers allocated */
+int ivtv_init_queue(struct ivtv *itv, struct ivtv_buffer_list *queue,
+		    int length, enum v4l2_buf_type type) {
+	int x;
+	struct ivtv_buffer *item;
+
+	/* Just in case */
+	INIT_LIST_HEAD(&queue->list);
+	
+	for (x=0;x < length; x++) {
+		/* allocate buffer */
+		item = ivtv_init_buffer(GFP_KERNEL);
+		if (item == NULL) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR,"Buffer alloc failed!\n");
+			return x;
+		}
+		
+		/* setup buffer */
+		item->buffer.index = x;
+		item->buffer.type = type;
+		item->buffer.field = V4L2_FIELD_INTERLACED;
+		item->buffer.memory = V4L2_MEMORY_MMAP;
+		
+		/* enqueue buffer */
+		ivtv_enq_buf(itv, queue, item);
+	}
+
+	return x;
+}
+
+int ivtv_move_queue(struct ivtv *itv, struct ivtv_buffer_list *src,
+		    struct ivtv_buffer_list *dst) {
+	struct ivtv_buffer *buf;
+	unsigned long flags;
+
+	spin_lock_irqsave(&itv->lock, flags);
+
+  	while ((buf = __ivtv_deq_buf(src)))
+		__ivtv_enq_buf(dst, buf);
+
+	spin_unlock_irqrestore(&itv->lock, flags);
+	return 0;
+}
+
+static int load_fw_direct(const char *fn, char *mem) {
+        int fd;
+        long l;
+	mm_segment_t fs = get_fs();
+
+	set_fs(get_ds());
+
+        if ( (fd = open(fn, 0, 0)) == -1) {
+                printk(KERN_INFO "Unable to open '%s'.\n", fn);
+		l = -EINVAL;
+		goto out;
+        }
+	/* the 2 means SEEK_END */
+        l = lseek(fd, 0L, 2);
+
+        if (l <= 0 || l > IVTV_FIRM_IMAGE_SIZE) {
+                printk(KERN_INFO "Firmware image too large '%s'\n", fn);
+		l = -ENOMEM;
+		goto out;
+        }
+
+	/* the 2 means SEEK_SET */
+        lseek(fd, 0L, 0);
+
+        if (read(fd, mem, l) != l){
+                printk(KERN_INFO "Failed to read '%s'.\n", fn);
+		l = -ENOMEM;
+        }
+
+out:
+	close(fd);
+	set_fs(fs);
+
+	return (int) l;
+}
+
+int ivtv_firmware_copy(struct ivtv *itv) {
+
+        IVTV_DEBUG(IVTV_DEBUG_INFO, "Loading encoder image\n");
+
+        if (load_fw_direct(IVTV_FIRM_ENC_FILENAME,
+			   (char *)(itv->io_mem + IVTV_ENC_MEM_START)) !=
+			   IVTV_FIRM_IMAGE_SIZE) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "failed loading encoder firmware\n");
+		return -3;
+	}
+
+
+	if (itv->card_type != IVTV_250_V2) {
+                IVTV_DEBUG(IVTV_DEBUG_INFO, "Loading decoder firmware\n");
+                if (load_fw_direct(IVTV_FIRM_DEC_FILENAME,
+				   (char *)(itv->io_mem + IVTV_DEC_MEM_START)) !=
+				   IVTV_FIRM_IMAGE_SIZE) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR,
+				   "failed loading decoder firmware\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+int ivtv_stop_firmware(struct ivtv *itv) {
+	u32 data[IVTV_MBOX_MAX_DATA], result;
+	int x = 0;
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping firmware\n");
+
+	if (atomic_read(&itv->capturing)) {
+		x = ivtv_stop_all_captures(itv);
+		if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stop_fw error 1. Code %d\n",x);
+	}
+		
+	/*Stop decoder_playback */
+	data[0] = 1; /* 0: render last frame, 1: stop NOW! :) */
+	data[1] = 0; /* "low 4 bytes of stop index" */
+	data[2] = 0; /* 0: stop immedeately */
+        x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_STOP_PLAYBACK,
+		&result, 3, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stop_fw error 2. Code %d\n",x);
+		
+	/*halt enc firmware */
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ENC_HALT_FW,
+		&result, 0, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stop_fw error 3. Code %d\n",x);
+		
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 10ms\n");
+	ivtv_sleep_timeout(HZ/100);
+	
+	/*halt dec firmware */
+	if (IVTV_250_V2 != itv->card_type) {
+        	x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_HALT_FW,
+			&result, 0, &data[0]);
+		if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stop_fw error 4. Code %d\n",x);
+		
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 10ms\n");
+		ivtv_sleep_timeout(HZ/100);
+	}
+	
+	return 0;
+}
+
+int ivtv_firmware_init(struct ivtv *itv) {
+	int x;
+
+	/* check that we're not RE-loading firmware */
+	/*  a sucessful load will have detected HW  */
+	/*  mailboxes. */
+
+	/* FIXME i dont think this will ever get called */
+	if (NULL != itv->enc_mbox) {
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "readying card for firmware upload\n");
+		x = ivtv_stop_firmware(itv);
+		if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "Error %d, stopping firmware\n", x);
+	}
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping VDM\n");
+	writel(IVTV_CMD_VDM_STOP, (IVTV_REG_VDM + itv->reg_mem));
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping AO\n");
+	writel(IVTV_CMD_AO_STOP, (IVTV_REG_AO + itv->reg_mem));
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "pinging (?) APU\n");
+	writel(IVTV_CMD_APU_PING, (IVTV_REG_APU + itv->reg_mem));
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping VPU\n");
+	if (IVTV_250_V2 == itv->card_type) {
+		writel(IVTV_CMD_VPU_STOP16, (IVTV_REG_VPU + itv->reg_mem));
+	}
+	else {
+		writel(IVTV_CMD_VPU_STOP15, (IVTV_REG_VPU + itv->reg_mem));
+	}
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Resetting Hw Blocks\n");
+	writel(IVTV_CMD_HW_BLOCKS_RST, (IVTV_REG_HW_BLOCKS + itv->reg_mem));
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping SPU\n");
+	writel(IVTV_CMD_SPU_STOP, (IVTV_REG_SPU + itv->reg_mem));
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 10ms\n");
+	ivtv_sleep_timeout(HZ/100);
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "init Encoder SDRAM pre-charge\n");
+	writel(IVTV_CMD_SDRAM_PRECHARGE_INIT,
+		       (IVTV_REG_ENC_SDRAM_PRECHARGE + itv->reg_mem));
+	
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "init Encoder SDRAM refresh to 1us\n");
+	writel(IVTV_CMD_SDRAM_REFRESH_INIT,
+		       (IVTV_REG_ENC_SDRAM_REFRESH + itv->reg_mem));
+	
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "init Decoder SDRAM pre-charge\n");
+	writel(IVTV_CMD_SDRAM_PRECHARGE_INIT,
+		       (IVTV_REG_DEC_SDRAM_PRECHARGE + itv->reg_mem));
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "init Decoder SDRAM refresh to 1us\n");
+	writel(IVTV_CMD_SDRAM_REFRESH_INIT,
+		       (IVTV_REG_DEC_SDRAM_REFRESH + itv->reg_mem));
+	
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for %dms (600 recommended)\n",(int)IVTV_SDRAM_SLEEPTIME);
+	ivtv_sleep_timeout(IVTV_SDRAM_SLEEPTIME);
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Card ready for firmware!\n");
+	x = ivtv_firmware_copy(itv);
+	if (x) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Error loading firmware!\n");
+		return x;
+	}
+
+	/*I guess this is read-modify-write :)*/
+	writel((readl(itv->reg_mem + IVTV_REG_SPU)&IVTV_MASK_SPU_ENABLE),
+			(IVTV_REG_SPU+itv->reg_mem));
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 1 sec\n");
+	ivtv_sleep_timeout(HZ);
+	
+	/*I guess this is read-modify-write :)*/
+	if (IVTV_250_V2 == itv->card_type) {
+		writel((readl(itv->reg_mem + IVTV_REG_VPU)&IVTV_MASK_VPU_ENABLE16),
+			(IVTV_REG_VPU+itv->reg_mem));
+	}
+	else {
+		writel((readl(itv->reg_mem + IVTV_REG_VPU)&IVTV_MASK_VPU_ENABLE15),
+			(IVTV_REG_VPU+itv->reg_mem));
+	}
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 1 sec\n");
+	ivtv_sleep_timeout(HZ);
+
+	/* FIXME Send Status API commands to encoder and decoder to verify!*/
+
+	return 0;
+}
+
+int ivtv_find_firmware_mailbox(struct ivtv *itv) {
+	u32 *searchptr, *result;
+	int match = 0;
+
+	searchptr = NULL;
+	result    = NULL;
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Searching for encoder mailbox\n");
+	searchptr =(u32 *)(IVTV_FIRM_SEARCH_ENCODER_START + itv->io_mem);
+
+	while (searchptr < (u32 *)(IVTV_FIRM_SEARCH_ENCODER_END + itv->io_mem)) {
+		if (ivtv_firm_search_id[match] == readl(searchptr)) {
+			(u32)result = (u32)searchptr+4; /* avoid pointer aritmetic */
+			match++;
+			while ((match > 0) && (match < 4)) {
+				IVTV_DEBUG(IVTV_DEBUG_INFO, "match: 0x%08x at "
+					   "0x%08x. match: %d\n", *result, 
+					   (u32)result, match);
+				if (ivtv_firm_search_id[match] == readl(result)) {
+					match++;
+					/* FIXME change to just "result++;" ? */
+					(u32)result =  (u32)result + 4;
+				}
+				else 
+					match = 0;
+			}
+		}
+		else {
+			IVTV_DEBUG(IVTV_DEBUG_INFO, ".");
+		}
+		if ( 4 == match ) {
+			IVTV_DEBUG(IVTV_DEBUG_INFO, "found encoder mailbox!\n");
+			itv->enc_mbox = (struct ivtv_mailbox *) result;
+			break;
+		}
+		(u32)searchptr += IVTV_FIRM_SEARCH_STEP;
+	}
+	if (itv->enc_mbox == NULL) IVTV_DEBUG(IVTV_DEBUG_ERR, "Encoder mailbox not found\n");
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Searching for decoder mailbox\n");
+	match = 0;
+	searchptr = (u32 *)(IVTV_FIRM_SEARCH_DECODER_START + itv->io_mem);
+
+	while (searchptr < (u32 *)(IVTV_FIRM_SEARCH_DECODER_END + itv->io_mem)) {
+		if (ivtv_firm_search_id[match] == readl(searchptr)) {
+			(u32)result = (u32)searchptr+4;  /* avoid pointer aritmetic */
+			match++;
+			while ((match > 0) && (match < 4)) {
+				IVTV_DEBUG(IVTV_DEBUG_INFO, "match: 0x%08x at 0x%08x. match: %d\n", 
+					*result, (u32)result, match);
+				if (ivtv_firm_search_id[match] == readl(result)) {
+					match++;
+					/* FIXME change to just "result++;" ? */
+					(u32)result =  (u32)result + 4;
+				}
+				else 
+					match = 0;
+			}
+		}
+		else {
+			IVTV_DEBUG(IVTV_DEBUG_INFO, ".");
+		}
+		if ( 4 == match ) {
+			IVTV_DEBUG(IVTV_DEBUG_INFO, "found decoder mailbox!\n");
+			itv->dec_mbox = (struct ivtv_mailbox *) result;
+			break;
+		}
+		(u32)searchptr += IVTV_FIRM_SEARCH_STEP;
+	}
+	if (itv->dec_mbox == 0) IVTV_DEBUG(IVTV_DEBUG_ERR, "Decoder mailbox not found\n");
+
+	return 0;
+}
+
+int ivtv_get_free_mailbox(struct ivtv_mailbox *mbox) {
+	int i = 0;
+	if (NULL == mbox) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Can't get mailbox from NULL\n");
+		return -ENODEV;
+	}
+
+	/* FIXME hardcoded cause i'm not sure what changing API_BOXES will do */
+	//for (i = 0; i < IVTV_MBOX_API_BOXES; i++) {
+	for (i = 0; i < 2; i++) {
+		if (mbox[i].flags & IVTV_MBOX_FIRMWARE_DONE) {
+			switch (mbox[i].cmd) {
+			case IVTV_API_SCHED_DMA_TO_HOST:
+			case IVTV_API_DEC_DMA_FROM_HOST:
+				IVTV_DEBUG(IVTV_DEBUG_API,
+					   "recycled mailbox: %d\n", i);
+				writel(IVTV_MBOX_IN_USE, &mbox[i].flags);
+				return i;
+				break;
+			default:
+				IVTV_DEBUG(IVTV_DEBUG_API,
+					   "Mailbox %d in use, skipping\n", i);
+				break;
+			}
+		/* FIXME using 'else' may leak mailboxes in some situations */
+		} else if (!test_and_set_bit(0, (void *) &mbox[i].flags)) { 
+			IVTV_DEBUG(IVTV_DEBUG_API, "got free mailbox: %d\n", i);
+			return i;
+		}
+	}
+
+	IVTV_DEBUG(IVTV_DEBUG_ERR, "no free mailboxes!\n");
+	IVTV_DEBUG(IVTV_DEBUG_ERR, "mbox 0: 0x%08x, mbox 1 0x%08x!\n",
+				   mbox[0].cmd, mbox[1].cmd);
+	return -ENODEV;
+}
+
+void ivtv_clear_irq_mask(struct ivtv *itv, unsigned long mask) {
+	itv->irqmask &= ~mask;
+	writel(itv->irqmask,(itv->reg_mem + IVTV_REG_IRQMASK));
+	/* pci posting */
+	readl(itv->reg_mem + IVTV_REG_IRQMASK);
+}
+
+void ivtv_set_irq_mask(struct ivtv *itv, unsigned long mask) {
+	itv->irqmask |= mask;
+	writel(itv->irqmask,(itv->reg_mem + IVTV_REG_IRQMASK));
+	/* pci posting */
+	readl(itv->reg_mem + IVTV_REG_IRQMASK);
+}
+
+/** 
+ * Call ivtv api function using given mailbox, without locking sem.
+ */
+int __ivtv_api_call(struct ivtv_mailbox *mbox, u32 cmd,	int elements,
+		    const u32* data) {
+	int x;
+	if (NULL == mbox) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "invalid api mailbox\n");
+		return -ENODEV;
+	}
+
+	/* "if mailbox is available" */
+	if ( (mbox->flags & IVTV_MBOX_FIRMWARE_DONE) ||
+	     (!test_and_set_bit(0, (void *) &mbox->flags))	 )     {
+		/* I'm too lazy to invert the condition ;) */
+	} else {
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "Mailbox busy (unexpected)\n");
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "cmd 0x%08x, m.cmd 0x%08x, fl 0x%08x\n",
+					    cmd, mbox->cmd, mbox->flags);
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "d0 0x%08x, d1 0x%08x, d2 0x%08x\n",
+					    mbox->data[0], mbox->data[1],
+					    mbox->data[2]);
+		return -EBUSY;
+	}
+
+	readl(&mbox->flags);
+	writel(cmd, &mbox->cmd);
+	writel(IVTV_API_STD_TIMEOUT, &mbox->timeout);
+
+	for (x = 0; x < IVTV_MBOX_MAX_DATA; x++) {
+		if (x < elements) {
+			writel(data[x], &mbox->data[x]);
+		} else {
+			writel(0, &mbox->data[x]);
+		}
+	}
+
+	writel((IVTV_MBOX_DRIVER_DONE | IVTV_MBOX_IN_USE), &mbox->flags);
+	readl(&mbox->flags);
+
+	return 0;
+}
+
+/* This one is for stuff that can't sleep.. irq handlers, etc.. */
+int ivtv_api_getresult_nosleep(struct ivtv_mailbox *mbox, u32 *result, u32 data[]) {
+	u32 readdata;
+	int count = 0;
+
+	if (NULL == mbox) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "invalid api mailbox\n");
+		return -ENODEV;
+	}
+
+	readdata = readl(&mbox->flags);
+
+	*result = readl(&mbox->retval);
+	for ( count=0; count < IVTV_MBOX_MAX_DATA; count++)
+		data[count] = readl(&mbox->data[count]);
+
+	return 0;
+}
+
+int __ivtv_api_getresult(struct ivtv_mailbox *mbox, u32 *result, u32 data[],
+			 int api_timeout) {
+	u32 readdata;
+	int count = 0;
+
+	readdata = readl(&mbox->flags);
+
+	while (!(readdata & IVTV_MBOX_FIRMWARE_DONE)) {
+		IVTV_DEBUG(IVTV_DEBUG_API,
+			   "[%d]result not ready, waiting 10 ms\n",
+			   count);
+		ivtv_sleep_timeout(HZ/100);
+		readdata = readl(&mbox->flags);
+
+		if (count++ > api_timeout) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR,
+				   "%d ms time out waiting for firmware\n",
+				   api_timeout);
+			return -EBUSY;
+		}
+	}
+
+	*result = readl(&mbox->retval);
+	for ( count=0; count < IVTV_MBOX_MAX_DATA; count++)
+		data[count] = readl(&mbox->data[count]);
+
+	return 0;
+}
+
+int ivtv_api(struct ivtv_mailbox *mbox, struct semaphore *sem, int cmd,
+		u32 *result, int args, u32 data[]) {
+	int x=0, gotsem=0, needsresult=1;
+	int die=0, api_timeout=100;
+	struct ivtv_mailbox *local_box;
+
+	IVTV_DEBUG(IVTV_DEBUG_API, "API Call: 0x%08x\n", cmd);
+
+	local_box = mbox;
+
+	/* check args */
+	if (args > IVTV_MBOX_MAX_DATA) return -EINVAL;
+	
+	switch (cmd) {
+		case IVTV_API_SCHED_DMA_TO_HOST:
+		case IVTV_API_DEC_DMA_FROM_HOST:
+			needsresult = 0;
+			if (down_trylock(sem)) { /* box 0 was busy */
+				gotsem	= 0;
+				local_box = &mbox[1];
+			} else {
+				gotsem = 1;
+			}
+			if ((x = __ivtv_api_call(local_box, cmd, args, data))) {
+				if (local_box == mbox) {
+					IVTV_DEBUG(IVTV_DEBUG_API,
+						   "Trying alternate mailbox\n");
+					x = __ivtv_api_call(&mbox[1],cmd,args,data);
+				}
+			}
+			goto ivtv_api_done;
+			break;
+		/* adjust api timeout for these 2 calls */
+		case IVTV_API_END_CAPTURE:
+		case IVTV_API_EVENT_NOTIFICATION:
+			api_timeout = 1000;
+		default:
+			if (down_interruptible(sem)) return -ERESTARTSYS;
+			gotsem	= 1;
+			break;		
+	}
+
+	/* wait 200ms for mailbox to become free */
+	x = __ivtv_api_call(local_box, cmd, args, data);
+	while ((x == -EBUSY) && (die < 20)) {
+		die++;
+		ivtv_sleep_timeout(HZ/100);
+		x = __ivtv_api_call(local_box, cmd, args, data);
+		IVTV_DEBUG(IVTV_DEBUG_API, "die: %d\n", die);
+	}
+
+        if (x == -EBUSY) {
+		/* dilemma here:
+		 if the command that currently has the mailbox
+		 is lost, then it'll never free up the box, and 
+		 we'll lose our only 'general purpose' box forever.
+		 But if it comes back, we run the risk of squishing
+		 something important!. */
+		switch (local_box->cmd) {
+		case IVTV_API_DEC_DMA_FROM_HOST:
+			/* if we got here, it's because the call to xfer the dma 
+			   was finished, and the command that wants to run has 
+			   already slept for 20ms. It's probably safe to take over
+			*/
+                	IVTV_DEBUG(IVTV_DEBUG_API, "Forcibly freeing mailbox\n");
+		        writel(0x00000000, &mbox->flags);
+	                x = __ivtv_api_call(local_box, cmd, args, data);
+			break;
+		default:
+			/* do nothing */
+			break;
+		}
+	}
+
+	if (x) {
+		IVTV_DEBUG(IVTV_DEBUG_API,"Error running command 0x%08x\n", cmd);
+		goto ivtv_api_done;
+        }
+
+	if (needsresult) {
+		x = __ivtv_api_getresult(local_box, result, &data[0], api_timeout);
+		IVTV_DEBUG(IVTV_DEBUG_API, "retval: 0x%08x\n", *result);
+		if(x == -EBUSY)
+			IVTV_DEBUG(IVTV_DEBUG_ERR, "api call 0x%08x\n", cmd);
+	}
+
+	IVTV_DEBUG(IVTV_DEBUG_API, "Releasing mailbox (before 0x%08x, ",
+				   readl(&mbox->flags));
+	writel(0x00000000, &mbox->flags);
+	IVTV_DEBUG(IVTV_DEBUG_API, "after 0x%08x )\n", readl(&mbox->flags));
+
+ivtv_api_done:
+	if (gotsem) {
+        	up(sem);
+	}
+
+	return x;
+}
+
+int ivtv_firmware_versions(struct ivtv *itv) {
+	u32 data[IVTV_MBOX_MAX_DATA], result;
+	int x;
+
+	/* Encoder */	
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Getting encoder firmware rev.\n");
+	x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ENC_GETVER,
+			&result, 0, &data[0]);
+	if (x) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR,
+			   "error getting Encoder firmware version\n");
+	}
+	else	{
+		IVTV_DEBUG(IVTV_DEBUG_ERR,
+			   "Encoder revision: 0x%08x\n", data[0]);
+	}
+
+	if (itv->card_type != IVTV_250_V2) {
+		/* Decoder */	
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "Getting decoder firmware rev.\n");
+		x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_GETVER,
+			&result, 0, &data[0]);
+		if (x) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR,
+				   "error getting Decoder firmware version\n");
+		}
+		else	{
+			IVTV_DEBUG(IVTV_DEBUG_ERR,
+				   "Decoder revision: 0x%08x\n", data[0]);
+		}
+	}
+	
+	return 0;
+}
+
+
+int ivtv_stop_all_captures(struct ivtv *itv) {
+	struct ivtv_open_id id;
+	int x;
+	id.itv = itv;
+
+	down(&itv->sem_lock);
+
+	for (x = 0; x < itv->v4l2.streamcount;x++) {
+		if (test_bit(IVTV_F_S_CAP, &itv->v4l2.streams[x].s_flags)) {
+			id.type=x;
+			ivtv_stop_capture(&id);
+		}
+	}
+	
+	up(&itv->sem_lock);
+	return 0;
+}
+
+int ivtv_stop_capture(struct ivtv_open_id *id) {
+	struct ivtv *itv=id->itv;
+	u32 data[IVTV_MBOX_MAX_DATA], result;
+	DECLARE_WAITQUEUE(wait, current);
+	int type, subtype, then;
+	int x;
+
+	/* This function assumes that you are allowed to stop the capture
+	   and that we are actually capturing */
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Stop Capture\n");
+
+	/* sem_lock must be held */
+	IVTV_ASSERT(ivtv_sem_count(&itv->sem_lock) <= 0);
+
+	type = id->type;
+	if (type == 1) {
+		subtype = 3; //FIXME temp
+	} else {
+		subtype = 3;
+	}
+
+#if 0
+	/* only run these if we're shutting down the last cap */
+	if (atomic_read(&itv->capturing) - 1 == 0) {
+		/* event notification (off)*/
+		data[0] = 0; /*type: 0 = refresh */
+		data[1] = 0; /*on/off: 0 = off */
+		data[2] = 0x10000000; /*intr_bit: 0x10000000 = digitizer */
+		data[3] = -1; /*mbox_id: -1: none */
+	        x = ivtv_api(itv->enc_mbox, &itv->enc_msem,
+			     IVTV_API_EVENT_NOTIFICATION, &result, 4, &data[0]);
+		if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stopcap error 1. Code %d\n",x);
+
+	}
+#endif
+
+	/* end_capture */
+	data[0] = 1; /*when: 0 =  end of GOP    1 = NOW! */
+	data[1] = type; /*type: 0 = mpeg */
+	data[2] = subtype; /*subtype: 3 = video+audio */
+        x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_END_CAPTURE,
+		&result, 3, &data[0]);
+	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stopcap error 2. Code %d\n",x);
+
+	then = jiffies;
+
+	add_wait_queue(&itv->v4l2.streams[type].waitq, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	do {
+		/* check if DMA is pending */
+		if (!test_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[type].s_flags)) {
+			break;
+		}
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "dma still pending!\n");
+		schedule_timeout(HZ/100);
+	} while ( ((then + HZ) < jiffies) && !signal_pending(current));
+
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&itv->v4l2.streams[type].waitq, &wait);
+
+	if (test_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[type].s_flags)) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR,
+				   "giving up waiting for DMA pending clear\n");
+	}
+/* only needed if we're searching for an EOS.. currently disabled */
+#if 0
+	/* only run these if we're shutting down the last cap */
+	if (atomic_read(&itv->capturing) - 1 == 0) {
+		add_wait_queue(&itv->cap_w, &wait);
+
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		/* wait 2s for EOS interrupt */
+		while((!test_bit(IVTV_F_I_EOS, &itv->i_flags)) && 
+		      (jiffies < then + 2 * HZ)) {
+			schedule_timeout(HZ);
+		}	
+		then = jiffies - then;
+
+		if (!test_bit(IVTV_F_I_EOS, &itv->i_flags)) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR,
+				   "EOS interrupt not received! stopping anyway.\n");
+			IVTV_DEBUG(IVTV_DEBUG_ERR,
+				   "waitied %d ms: %d\n", (1000/HZ)*then);
+		} else {
+			IVTV_DEBUG(IVTV_DEBUG_ERR,
+				   "EOS took %d ms to occur.\n",(1000/HZ)*then);
+		}
+		set_current_state(TASK_RUNNING);
+		remove_wait_queue(&itv->cap_w, &wait);
+	}
+#endif
+	clear_bit(IVTV_F_S_OVERFLOW, &itv->v4l2.streams[type].s_flags);
+	clear_bit(IVTV_F_S_CAP, &itv->v4l2.streams[type].s_flags);
+
+	atomic_dec(&itv->capturing);
+	if (atomic_read(&itv->capturing))
+		return 0;
+
+	/*Set the following Interrupt mask bits: 0xd8000000 */
+	ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
+	IVTV_DEBUG(IVTV_DEBUG_IRQ, "IRQ Mask is now: 0x%08x\n",itv->irqmask);
+
+	return 0;
+}
+
+int ivtv_stop_decode(struct ivtv_open_id *id) {
+	struct ivtv *itv=id->itv;
+	u32 data[IVTV_MBOX_MAX_DATA], result;
+	int x;
+
+	/* sem_lock must be held */
+	IVTV_ASSERT(ivtv_sem_count(&itv->sem_lock) <= 0);
+
+	/* FIXME set 'die' ?? */
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Decoder stop.\n");
+
+
+	/* only run these if we're shutting down the last cap */
+	if (atomic_read(&itv->decoding) - 1 == 0) {
+#if 0
+		/* event notification (off)*/
+	        data[0] = 0; /* Event: 0 = audio change between stereo and mono */
+	        data[1] = 0; /* Enable/Disable: 0 = disabled, 1 = enabled */
+	        data[2] = 0x00010000; /* Bit: interrupt bit to fire */
+	        data[3] = -1; /* Mailbox to use: -1 = no mailbox needed */
+	        x = ivtv_api(itv->dec_mbox, &itv->dec_msem,
+			     IVTV_API_DEC_EVENT_NOTIFICATION, &result, 4, &data[0]);
+		if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stopDEC error 1. Code %d\n",x);
+#endif
+
+		/* end_capture */
+		data[0] = itv->dec_options.hide_last_frame; /*  0 = last frame,
+								1 = black */
+		data[1] = itv->dec_options.pts_low; /* when: pts low */
+		data[2] = itv->dec_options.pts_hi;  /* when: pts hi */
+	        x = ivtv_api(itv->dec_mbox, &itv->dec_msem,
+			     IVTV_API_DEC_STOP_PLAYBACK, &result, 3, &data[0]);
+		if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stopDEC error 2. Code %d\n",x);
+	}
+		
+	/* FIXME turn off relevant irqmask here */
+	ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE);
+
+	/* stop decoder interrupt timeout */
+	del_timer_sync(&itv->dec_timeout);
+
+	if (test_and_clear_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[id->type].s_flags))
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: clearing dma_pending\n");
+
+	/* Clean up some possibly loose-ends */
+	clear_bit(IVTV_F_I_BUSY, &itv->i_flags);
+	atomic_dec(&itv->decoding);
+	wake_up(&itv->dec_master_w);
+
+	return 0;
+}
+
+void ivtv_dec_timeout(unsigned long arg) {
+	struct ivtv *itv = (struct ivtv *)arg;
+
+	/* FIXME mpg only :/ */
+	struct ivtv_v4l2_stream *stream = &itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG];
+	unsigned long flags;
+
+	if (!test_bit(IVTV_F_S_DMAP, &stream->s_flags))
+		return;
+
+	IVTV_DEBUG(IVTV_DEBUG_ERR, "ivtv_dec_timeout: lost IRQ; resetting...\n");
+	spin_lock_irqsave(&itv->lock, flags);
+	ivtv_dec_DMA_done(itv);
+	/* kick it off again! */
+	set_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags);
+	ivtv_dec_sched_DMA(itv);
+	spin_unlock_irqrestore(&itv->lock, flags);
+}
+
+#if 0
+static void ivtv_show_irq_status(struct ivtv* itv, u32 irqstat, u32 irqmask, u32 dmastat) {
+  struct ivtv_mailbox* mbox8 = &itv->dec_mbox[8];
+  struct ivtv_mailbox* mbox9 = &itv->dec_mbox[9];
+
+#if 0
+  // Make it less verbose...
+  if ((irqstat & ~4) == IVTV_IRQ_DEC_VSYNC)
+    return;
+#endif
+
+  printk("ivtv: irqstat [ "
+         "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s], "
+         "frame %d, pts %d, scr %d, type %d, offset %08x, max %d, full %d\n", 
+         (irqstat & IVTV_IRQ_ENC_START_CAP) ? "StartCap " : "",
+         (irqstat & IVTV_IRQ_ENC_EOS) ? "EndOfStream " : "",
+         (irqstat & IVTV_IRQ_ENC_VBI_CAP) ? "VBICap " : "",
+         (irqstat & IVTV_IRQ_ENC_VIM_RST) ? "VIMReset " : "",
+         (irqstat & IVTV_IRQ_ENC_DMA_COMPLETE) ? "EncDMAComplete " : "",
+         (irqstat & (1<<26)) ? "26 " : "",
+         (irqstat & IVTV_IRQ_DEC_COPY_PROTECT) ? "CopyProt " : "",
+         (irqstat & IVTV_IRQ_DEC_AUD_MODE_CHG) ? "AudioMode " : "",
+         (irqstat & (1<<23)) ? "23 " : "",
+         (irqstat & IVTV_IRQ_DEC_DATA_REQ) ? "DecDataReq " : "",
+         (irqstat & IVTV_IRQ_DEC_IFRAME_DONE) ? "IFrameDone " : "",
+         (irqstat & IVTV_IRQ_DEC_DMA_COMPLETE) ? "DecDMAComplete " : "",
+         (irqstat & IVTV_IRQ_DEC_VBI_RE_INSERT) ? "VBIReInsert " : "",
+         (irqstat & IVTV_IRQ_DEC_DMA_ERR) ? "DecDMAError " : "",
+         (irqstat & (1<<17)) ? "17 " : "",
+         (irqstat & (1<<16)) ? "16 " : "",
+         (irqstat & (1<<15)) ? "15 " : "",
+         (irqstat & (1<<14)) ? "14 " : "",
+         (irqstat & (1<<13)) ? "13 " : "",
+         (irqstat & (1<<12)) ? "12 " : "",
+         (irqstat & (1<<11)) ? "11 " : "",
+         (irqstat & IVTV_IRQ_DEC_VSYNC) ? "DecVSync " : "",
+         (irqstat & (1<<9)) ? "9 " : "",
+         (irqstat & (1<<8)) ? "8 " : "",
+         (irqstat & (1<<7)) ? "7 " : "",
+         (irqstat & (1<<6)) ? "6 " : "",
+         (irqstat & (1<<5)) ? "5 " : "",
+         (irqstat & (1<<4)) ? "4 " : "",
+         (irqstat & (1<<3)) ? "3 " : "",
+         (irqstat & (1<<2)) ? "2 " : "",
+         (irqstat & (1<<1)) ? "1 " : "",
+         (irqstat & (1<<0)) ? "0 " : "",
+         readl(&mbox8->data[0]), 
+         readl(&mbox8->data[1]), 
+         readl(&mbox8->data[3]), 
+         readl(&mbox9->data[0]),
+         readl(&mbox9->data[1]),
+         readl(&mbox9->data[2]), 
+         readl(&mbox9->data[3]));
+}
+#endif
+
+static irqreturn_t ivtv_irq_handler(int irq, void *dev_id, struct pt_regs *regs) {
+
+	u32 stat  = 0;
+	u32 combo = 0;
+	struct ivtv *itv=(struct ivtv *)dev_id;
+	
+	spin_lock(&itv->lock);
+	
+	/* get contents of irq status register*/
+	stat = readl(itv->reg_mem + IVTV_REG_IRQSTATUS);
+
+	combo=~itv->irqmask & stat;
+
+	if (0 == combo) {
+		/* wasn't for us*/
+		spin_unlock(&itv->lock);
+		return IRQ_NONE;
+	}
+	
+	/*
+	  ivtv_show_irq_status(itv, stat, itv->irqmask,
+				   readl(itv->reg_mem + IVTV_REG_DMASTATUS));
+	*/
+
+	IVTV_DEBUG(IVTV_DEBUG_IRQ, "======= valid IRQ bits: 0x%08x ======\n", combo);
+
+	writel(combo, (itv->reg_mem + IVTV_REG_IRQSTATUS));
+
+	if (combo & IVTV_IRQ_ENC_DMA_COMPLETE) {
+		ivtv_DMA_done(itv);
+		IVTV_DEBUG(IVTV_DEBUG_IRQ, "Processed DMA-complete\n");
+	}
+	if (combo & IVTV_IRQ_ENC_START_CAP) {
+		ivtv_sched_DMA(itv);
+		IVTV_DEBUG(IVTV_DEBUG_IRQ, "Processed enc-startcap\n");
+	}
+	if (combo & IVTV_IRQ_ENC_EOS) {
+		IVTV_DEBUG(IVTV_DEBUG_IRQ, "Encoder End Of Stream\n");
+		set_bit(IVTV_F_I_EOS, &itv->i_flags);
+		wake_up(&itv->cap_w);
+	}
+	if (combo & IVTV_IRQ_ENC_VBI_CAP) {
+		IVTV_DEBUG(IVTV_DEBUG_IRQ, "deb3\n");
+	}
+	if (combo & IVTV_IRQ_ENC_VIM_RST) {
+		IVTV_DEBUG(IVTV_DEBUG_IRQ, "VIM Restart\n");
+	}
+	if (combo & IVTV_IRQ_DEC_COPY_PROTECT) {
+		IVTV_DEBUG(IVTV_DEBUG_IRQ, "deb6\n");
+	}
+	if (combo & IVTV_IRQ_DEC_AUD_MODE_CHG) {
+		IVTV_DEBUG(IVTV_DEBUG_IRQ, "deb7\n");
+	}
+	if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) {
+		IVTV_DEBUG(IVTV_DEBUG_IRQ, "Decoder DMA Done\n");
+		ivtv_dec_DMA_done(itv);
+	}
+	if (combo & IVTV_IRQ_DEC_DATA_REQ) {
+		IVTV_DEBUG(IVTV_DEBUG_IRQ, "Decoder Data Request\n");
+		set_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags);
+		ivtv_dec_sched_DMA(itv);
+	}
+	if (combo & IVTV_IRQ_DEC_IFRAME_DONE) {
+		IVTV_DEBUG(IVTV_DEBUG_IRQ, "deb9\n");
+	}
+	if (combo & IVTV_IRQ_DEC_VBI_RE_INSERT) {
+		IVTV_DEBUG(IVTV_DEBUG_IRQ, "deb11\n");
+	}
+	if (combo & IVTV_IRQ_DEC_DMA_ERR) {
+		IVTV_DEBUG(IVTV_DEBUG_IRQ, "deb12\n");
+	}
+	if (combo & IVTV_IRQ_DEC_VSYNC) {
+		ivtv_irq_dec_vsync(itv);
+	}
+  /*
+	stat = readl(itv->reg_mem + IVTV_REG_IRQSTATUS);
+        IVTV_DEBUG(IVTV_DEBUG_IRQ, "IVTV IRQ STATUS REG AFTER INTERRUPT 0x%08x", stat);
+        if (combo & ~IVTV_IRQ_DEBUG_KLUGE) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR,
+			"unknown irq 0x%08x, mask:0x%08x, combo:0x%08x\n",
+					stat, itv->irqmask, combo);
+	}
+  */
+	spin_unlock(&itv->lock);
+	
+	return IRQ_HANDLED;
+}
+
+static void ivtv_irq_dec_vsync(struct ivtv* itv) {
+  u32* data = itv->dec_mbox[IVTV_MBOX_FIELD_DISPLAYED].data;
+
+  u32 newframe = readl(&data[0]);
+  u64 newpts = ((u64)readl(&data[2]) << 32) | (u64)(readl(&data[1]));
+  u64 newscr = ((u64)readl(&data[4]) << 32) | (u64)(readl(&data[3]));
+
+  itv->dec_timestamp.pts = newpts;
+  itv->dec_timestamp.scr = newscr;
+  if (newframe != itv->dec_timestamp.frame) {
+    itv->dec_timestamp.frame = newframe;
+    wake_up(&itv->vsync_w);
+  }
+
+  IVTV_DEBUG(IVTV_DEBUG_IRQ, "ivtv_irq_dec_vsync: frames %d, pts %ld, scr %ld\n", itv->dec_timestamp.frame, (long int)itv->dec_timestamp.pts, (long int)itv->dec_timestamp.scr);
+}
+
+static void ivtv_show_debug_flags(struct ivtv *itv)
+{
+	int y;
+
+	printk(KERN_DEBUG "ivtv: i_flags=%lx", itv->i_flags);
+	for (y=IVTV_DEC_STREAM_TYPE_MPG; y < itv->v4l2.streamcount; y++)
+		printk(", %d s_sflags=%lx", y, itv->v4l2.streams[y].s_flags);
+	printk("\n");
+}
+
+static void ivtv_DMA_done(struct ivtv *itv) {
+	u32 result;
+	int y,stmtype=-1;
+	struct ivtv_v4l2_stream *stream=NULL;
+	struct ivtv_buffer *buf;
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "DMA Done tasklet\n");
+
+	for (y=0; y < itv->v4l2.streamcount; y++) {
+		if (test_and_clear_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[y].s_flags)) {
+			stmtype = y;
+			break;
+		}
+	}
+
+	if (stmtype < 0) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Got DMA-done, but not expecting one\n");
+		ivtv_show_debug_flags(itv);
+		return;
+	}
+
+	stream = &itv->v4l2.streams[stmtype];
+
+	/* check DMA status register */
+	result = readl(itv->reg_mem + IVTV_REG_DMASTATUS);
+
+	if (!(result & IVTV_DMA_SUCCESS)) {
+		if (result & IVTV_DMA_WRITE_ERR)
+			IVTV_DEBUG(IVTV_DEBUG_ERR, "DMA write error. Result=0x%08x\n", result);
+		if (result & IVTV_DMA_READ_ERR)
+			IVTV_DEBUG(IVTV_DEBUG_ERR, "DMA read error. Result=0x%08x\n",result);
+		return;
+	}
+
+	/* DMA was fine if we made it this far */
+
+	/* remove from dma_pending queue */
+	while ((buf = __ivtv_deq_buf(&stream->dma_q))) {
+		IVTV_ASSERT(buf->dma_handle != IVTV_DMA_UNMAPPED);
+		pci_unmap_single(itv->dev, buf->dma_handle,
+					IVTV_DMA_BUF_SIZE, PCI_DMA_TODEVICE);
+		buf->dma_handle = IVTV_DMA_UNMAPPED;
+		/* byteswap ABCD -> DCBA for MPG data*/
+		if (stmtype == 0) {
+			for (y = 0; y < buf->buffer.bytesused; y += 4) {
+				swab32s( (u32 *)((u32)buf->buffer.m.userptr + y));
+			}
+		}
+		/* put in the 'done' queue */
+		__ivtv_enq_buf(&stream->full_q, buf);
+	}
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "DMA Done tasklet5\n");
+	/*wake up client*/
+	wake_up(&stream->waitq);
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "DMA Done tasklet6\n");
+}
+
+/* must hold itv->lock */
+static int ivtv_ignore_DMA_req(struct ivtv *itv, u32 type) {
+	u32 data[IVTV_MBOX_MAX_DATA], result;
+	int ret = 0;
+
+	data[0] = 0;
+	data[1] = 0; /* ACK the DMA and continue */
+	data[2] = type; // AEW - API docs say type goes here
+       	if (ivtv_api(itv->enc_mbox, &itv->enc_msem, 
+		     IVTV_API_SCHED_DMA_TO_HOST, &result, 3, &data[0])) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "error sending DMA info\n");
+		ret = -EIO;
+	}
+
+	if (!ret)
+		set_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[type].s_flags);
+
+	return ret;
+}
+
+
+/* FIXME this function is getting too long. split it up? */
+static void ivtv_sched_DMA(struct ivtv *itv) {
+	u32 data[IVTV_MBOX_MAX_DATA], result;
+	u32 type, size, offset;
+	u32 UVsize=0, UVoffset=0, pts_stamp=0;
+	struct ivtv_v4l2_stream *st;
+	int x, bufs_needed;
+	int uvflag=0;
+	struct ivtv_buffer *buf;
+	LIST_HEAD(free_list);
+	long sequence;
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Sched DMA tasklet\n");
+
+	/* Get DMA destination and size arguments from card*/
+	x = ivtv_api_getresult_nosleep(&itv->enc_mbox[9], &result, &data[0]);
+	if (x) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "error:%d getting DMA info\n", x);
+		return;
+	}
+	
+	type   = data[0];
+
+	/* FIXME should check for null on the stream element */
+	if (itv->v4l2.streamcount <= type) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR,"No stream handler for type %d\n", type);
+		ivtv_ignore_DMA_req(itv, type);
+		return;
+	}
+
+	switch (type) {
+		case 0:  /* MPEG */
+			offset = data[1];
+			size   = data[2];
+			IVTV_DEBUG(IVTV_DEBUG_INFO,
+				   "DMA/MPG type 0x%08x,size 0x%08x,offset 0x%08x\n",
+	 			   type, size, offset);
+			bufs_needed = ivtv_ceil(size, IVTV_DMA_BUF_SIZE);
+			break;
+		case 1: /* YUV */
+			offset		= data[1];
+			size		= data[2];
+			UVoffset	= data[3];
+			UVsize		= data[4];
+			pts_stamp	= data[6];
+			IVTV_DEBUG(IVTV_DEBUG_INFO,
+				   "DMA/YUV type 0x%08x,Ysize 0x%08x,Yoffset 0x%08x,"
+				   "UVsize 0x%08x,UVoffset 0x%08x,PTS 0x%08x\n",
+	 			   type, size, offset, UVsize, UVoffset, pts_stamp);
+			bufs_needed = ivtv_ceil(size, IVTV_DMA_BUF_SIZE);
+			bufs_needed += ivtv_ceil(UVsize, IVTV_DMA_BUF_SIZE);
+			break;
+
+		case 2:  /* PCM (audio) */
+			offset = data[1];
+			size   = data[2];
+			pts_stamp	= data[6];
+			IVTV_DEBUG(IVTV_DEBUG_INFO,
+				   "DMA/PCM type 0x%08x,size 0x%08x,offset 0x%08x "
+				   "PTS 0x%08x\n", type, size, offset, pts_stamp);
+			bufs_needed = ivtv_ceil(size, IVTV_DMA_BUF_SIZE);
+			ivtv_ignore_DMA_req(itv, type);
+			return;
+		case 3:  /* VBI */
+			offset = data[1];
+			size   = data[2];
+			bufs_needed = ivtv_ceil(size, IVTV_DMA_BUF_SIZE);
+			IVTV_DEBUG(IVTV_DEBUG_ERR,
+				   "DMA/VBI type 0x%08x, size 0x%08x, offset 0x%08x"
+				   "EXPERIMENTAL\n", type, size, offset);
+			break;
+		default:
+			IVTV_DEBUG(IVTV_DEBUG_ERR,
+				   "DMA/UNKNOWN type 0x%08x, NOT SUPPORTED\n", type);
+			ivtv_ignore_DMA_req(itv, type);
+			return;
+	}
+
+	if (bufs_needed > SGarray_size) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "INTERNAL ERROR: ivtv_sched_DMA_tasklet: "
+			   "bufs_needed = %d but SGarray_size = %d\n", 
+			   bufs_needed, SGarray_size);
+		return;
+	}
+
+	st = &itv->v4l2.streams[type];
+
+	/* gather the needed buffers first, so we don't have to bail
+	 * in mid-air. put them on a list on the stack */
+	for (x = 0; x < bufs_needed; x++) {
+		buf = __ivtv_deq_buf(&st->free_q);
+		if (!buf)
+			break;
+
+		list_add_tail(&buf->list, &free_list);
+	}
+
+	/* damn, failed */
+	if (x < bufs_needed) {
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "DMA buffer DeQueue failed! got %d, want %d\n", x + 1, bufs_needed + 1);
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "SCHED: free_q: %d elements\n", st->free_q.elements);
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "SCHED: dma_q: %d elements\n", st->dma_q.elements);
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "SCHED: full_q: %d elements\n", st->full_q.elements);
+		while (!list_empty(&free_list)) {
+			buf = list_entry(free_list.next, struct ivtv_buffer, list);
+			list_del_init(&buf->list);
+			__ivtv_enq_buf(&st->free_q, buf);
+		}
+		/* mark overflow condition, next free will restart dma req */
+		set_bit(IVTV_F_S_OVERFLOW, &st->s_flags);
+		return;
+	}
+
+	/* increment the sequence # */
+	sequence = ++st->seq;
+
+	for (x = 0; x < bufs_needed; x++) {
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "size: %d 0x%08x\n", size, size);
+
+		if ((size == 0) && (type == 1) && (uvflag == 0)) { /* YUV */
+			/* process the UV section */
+			offset	= UVoffset;
+			size	= UVsize;
+			uvflag	= 1;
+		}
+
+		/* extract the buffers we procured earlier */
+		buf = list_entry(free_list.next, struct ivtv_buffer, list);
+		list_del_init(&buf->list);
+
+		buf->readpos = 0;
+		buf->buffer.index = x;
+		buf->buffer.sequence = sequence;
+		buf->ts = jiffies;
+
+		if (size < (IVTV_DMA_BUF_SIZE & 0xffffff00)) {
+			buf->buffer.bytesused = size;
+			/* bytecount must be multiple of 0x100 (256) */
+			itv->SGarray[x].size = 
+				(0xffffff00 & (buf->buffer.bytesused + 0xFF));
+			size = 0;
+		}
+		else {
+			buf->buffer.bytesused	= IVTV_DMA_BUF_SIZE;
+			itv->SGarray[x].size	= IVTV_DMA_BUF_SIZE;
+			size		       -= IVTV_DMA_BUF_SIZE;
+		}
+
+		itv->SGarray[x].src = offset; 
+		offset += buf->buffer.bytesused;
+		
+		/* unfortunately the pci dma api wasn't properly defined
+		 * for handling mapping errors (running out of iommu space,
+		 * for instance). 0 can be a valid bus address. */
+		buf->dma_handle	= pci_map_single(itv->dev, 
+						 (void *)buf->buffer.m.userptr,
+						 buf->buffer.bytesused,
+						 PCI_DMA_FROMDEVICE);
+
+		itv->SGarray[x].dst = buf->dma_handle;
+		
+		/* FIXME need to add pts stuff, index, etc. */
+		__ivtv_enq_buf(&st->dma_q, buf);
+	}
+	
+	/* This should wrap gracefully */
+	/* FIXME obselete? */
+	itv->trans_id++;
+
+	itv->SGarray[bufs_needed-1].size |= 0x80000000;
+
+	/*FIXME unlock */
+
+	data[0] = itv->SG_handle;
+	/* 3 elements * 4 bytes per element * num_elements */
+	data[1] = (3 * 4 * bufs_needed);
+	data[2] = type;
+	data[3] = 0x0;
+
+	for  (x = 0; x < bufs_needed; x++)
+	 IVTV_DEBUG(IVTV_DEBUG_INFO, "SGarray[%d]: 0x%08x, 0x%08x 0x%08x\n",
+		x, itv->SGarray[x].src, itv->SGarray[x].dst, itv->SGarray[x].size);
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Sched dma: addr: 0x%08x, array_size 0x%08x,"
+		   " type 0x%08x\n", data[0], data[1], data[2]);
+
+	set_bit(IVTV_F_S_DMAP, &st->s_flags);
+	ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_SCHED_DMA_TO_HOST,
+		 &result, 4, &data[0]);
+}
+
+static void ivtv_sched_DMA_tasklet(unsigned long arg) {
+	struct ivtv *itv = (struct ivtv *) arg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&itv->lock, flags);
+	ivtv_sched_DMA(itv);
+	spin_unlock_irqrestore(&itv->lock, flags);
+}
+
+/* FIXME this function does way more than it should */
+static int __devinit ivtv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) {
+	int retval=0;
+	unsigned char pci_latency;
+	struct ivtv *itv;
+	struct video_channel v;
+	unsigned long freq;
+        u16 cmd;
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Found card #%d\n", ivtv_cards_active);
+
+	spin_lock_irq(&ivtv_lock);
+
+	/* Make sure we've got a place for this card */
+	if (ivtv_cards_active == IVTV_MAX_CARDS) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, ":Maximum # of cards already detected (%d).\n", ivtv_cards_active);
+		spin_unlock_irq(&ivtv_lock);
+		return -ENOMEM;
+	}
+
+	itv	 = &ivtv_cards[ivtv_cards_active];
+	itv->dev = dev;
+	itv->num = ivtv_cards_active;
+
+	ivtv_cards_active++;
+
+	spin_unlock_irq(&ivtv_lock);
+
+	/* always remember what you think the irq mask should be */
+	itv->irqmask = 0;
+
+#ifdef YUV_FIXUP
+	itv->options.yuv_fixup   = yuv_fixup;
+#endif
+	itv->options.dec_yuv_buffers = dec_yuv_buffers;
+	itv->options.dec_mpg_buffers = mpg_buffers;
+	itv->options.yuv_buffers = yuv_buffers;
+	itv->options.mpg_buffers = mpg_buffers;
+	itv->options.vbi_buffers = vbi_buffers;
+	itv->options.num_devices = num_devices;
+	itv->options.dec_mpg_qlen = dec_mpg_qlen;
+	itv->options.dec_yuv_qlen = dec_yuv_qlen;
+
+	/* Set FrameBuffer-ID to invalid */
+	itv->fb_id = -1;
+
+	switch (dev->subsystem_device) {
+	case IVTV_PCI_ID_250_V2:
+	case IVTV_PCI_ID_250_V4:
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Found an iTVC16 based chip\n");
+		itv->card_type = IVTV_250_V2;
+		break;
+	case IVTV_PCI_ID_350_V1:
+	case IVTV_PCI_ID_350_V2:
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Found an iTVC15 based chip\n");
+		itv->card_type = IVTV_350_V1;
+		break;
+	case IVTV_PCI_ID_250_V1:
+	case IVTV_PCI_ID_250_V3:
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Found an iTVC15 based chip\n");
+		itv->card_type = IVTV_250_V1;
+		break;
+	default: /* Default to 250 v1 style */
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Found an unknown chip, treating it like an iTVC15\n");
+		itv->card_type = IVTV_250_V1;
+		break;
+	}
+
+	init_MUTEX(&itv->enc_msem);
+	init_MUTEX(&itv->dec_msem);
+	init_MUTEX(&itv->sem_lock);
+	spin_lock_init(&itv->lock);
+	itv->base_addr=pci_resource_start(dev,0);
+	itv->enc_mbox = NULL;
+	itv->dec_mbox = NULL;
+	itv->io_mem = NULL;
+	itv->reg_mem = NULL;
+	itv->i_flags = 0;
+	atomic_set(&itv->capturing, 0);
+	atomic_set(&itv->decoding, 0);
+	itv->user_dma_to_device_state = NULL;
+
+	/* Prepare list for action! */
+	INIT_LIST_HEAD(&itv->client_list);
+
+	init_waitqueue_head(&itv->cap_w);
+	init_waitqueue_head(&itv->vsync_w);
+	init_waitqueue_head(&itv->dec_master_w);
+	init_timer(&itv->dec_timeout);
+	itv->dec_timeout.function = ivtv_dec_timeout;
+	itv->dec_timeout.data = (unsigned long)itv;
+
+	tasklet_init(&itv->dma_sched_tq, ivtv_sched_DMA_tasklet, (unsigned long) itv);
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "base addr: 0x%08x\n", itv->base_addr);
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Enabling pci device\n");
+	if (pci_enable_device(dev)) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Can't enable device %d!\n",itv->num);
+		retval = -EIO;
+		goto err;
+	}
+        if (pci_set_dma_mask(dev, 0xffffffff)) {
+                IVTV_DEBUG(IVTV_DEBUG_ERR, KERN_WARNING "No suitable DMA available on card %d.\n",
+                       itv->num);
+		retval = -EIO;
+		goto err;
+        }
+        if (!request_mem_region(pci_resource_start(dev,0), IVTV_IOREMAP_SIZE, IVTV_DEVNAME )) {
+		retval = -EIO;
+		goto err;
+	}
+
+        /* Check for bus mastering */
+        pci_read_config_word(dev, PCI_COMMAND, &cmd);
+        if (! (cmd & PCI_COMMAND_MASTER)) {
+                IVTV_DEBUG(IVTV_DEBUG_ERR, "Bus Mastering is not enabled\n");
+		retval = -ENXIO;
+		goto free_mem;
+        }
+        else {
+                IVTV_DEBUG(IVTV_DEBUG_INFO, "Bus Mastering Enabled.");
+        }
+	
+	pci_read_config_byte(dev, PCI_CLASS_REVISION, &itv->card_rev);
+	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "%d (rev %d) at %02x:%02x.%x, ",
+		itv->dev->device, itv->card_rev, dev->bus->number,
+		PCI_SLOT(dev->devfn),PCI_FUNC(dev->devfn));
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "     irq: %d, latency: %d, memory: 0x%lx\n",
+		itv->dev->irq, pci_latency, (unsigned long)itv->base_addr);
+
+	/*map io memory*/
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "attempting ioremap at 0x%08x len 0x%08x\n",
+		itv->base_addr, IVTV_ENCDEC_SIZE);
+	itv->io_mem = ioremap_nocache(itv->base_addr,IVTV_ENCDEC_SIZE);
+	if (!itv->io_mem) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, IVTV_IOREMAP_ERROR);
+		retval = -ENOMEM;
+		goto free_mem;
+	}
+
+	/*map registers memory*/
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "attempting ioremap at 0x%08x len 0x%08x\n",
+		itv->base_addr+IVTV_REG_OFFSET, IVTV_REG_SIZE);
+	itv->reg_mem = ioremap_nocache(itv->base_addr+IVTV_REG_OFFSET,IVTV_REG_SIZE);
+	if (!itv->reg_mem) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, IVTV_IOREMAP_ERROR);
+		retval = -ENOMEM;
+		goto free_io;
+	}	
+
+	IVTV_DEBUG(IVTV_DEBUG_IRQ, "Masking interrupts\n");
+	/* clear interrupt mask, effectively disabling interrupts */
+	ivtv_set_irq_mask(itv, 0xffffffff);
+
+	retval = request_irq(itv->dev->irq, ivtv_irq_handler,
+			SA_SHIRQ | SA_INTERRUPT,IVTV_DEVNAME,(void *)itv);
+	if (retval) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "failed to register irq %d\n", retval);
+		goto free_io;
+	}
+
+	/* save itv in the pci struct for later use*/
+	pci_set_drvdata(dev,itv);
+
+	/* active i2c  */
+	itv->i2c_command=(I2C_TIMING);
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "activating i2c..\n");
+	if (init_ivtv_i2c(itv)) {
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "i2c died! unloading\n");
+		goto free_irq;
+	}
+	
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Active card count: %d.\n", ivtv_cards_active);
+	
+	/*write firmware */
+	retval = ivtv_firmware_init(itv);
+	if (retval) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Error initializing.\n");
+		retval = -ENOMEM;
+		goto free_i2c;
+	}
+
+	/*search for encoder/decoder mailboxes*/
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "About to search for mailboxes\n");
+	ivtv_find_firmware_mailbox(itv);
+
+	if ((itv->enc_mbox == NULL) && (itv->dec_mbox ==NULL)) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Error locating firmware.\n");
+		retval = -ENOMEM;
+		goto free_i2c;
+	}
+
+	/*releasing unneeded iomapped memory (encoder+decoder)*/
+	//iounmap(itv->io_mem);
+
+	/*remapping only needed io memory (mailboxes) */
+	itv->enc_mbox = ioremap(itv->base_addr+((u8 *)itv->enc_mbox - (u8 *)itv->io_mem), 
+	    IVTV_MBOX_MAX_BOXES * IVTV_MBOX_SIZE);
+	itv->dec_mbox = ioremap(itv->base_addr+((u8 *)itv->dec_mbox - (u8 *)itv->io_mem), 
+	    IVTV_MBOX_MAX_BOXES * IVTV_MBOX_SIZE);
+	
+	/* clearing pointers */
+	//itv->io_mem = NULL ;
+
+	/*Try and get firmware versions */
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Getting firmware version..\n");
+	retval = ivtv_firmware_versions(itv);
+	if (retval) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "error %d getting version #!\n", retval);
+		goto free_i2c;
+	}
+
+	/* Allocate scatter-gather arrays*/
+
+  //++MTY NASTY little bug!!! If user changes dec_mpg_buffers, 
+  // memory corruption results with the old way!
+
+	/* encoder */
+	itv->SGarray = (struct ivtv_SG_element *)
+			kmalloc(sizeof(struct ivtv_SG_element) * 
+				SGarray_size,
+				GFP_KERNEL);
+	if (!(itv->SGarray)) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Error allocating SGarray[].\n");
+		retval = -ENOMEM;
+		goto free_i2c;
+	}
+
+	itv->SG_handle = pci_map_single(itv->dev,
+					(void *)&itv->SGarray[0],
+					(sizeof(struct ivtv_SG_element) * 
+           SGarray_size),
+					PCI_DMA_TODEVICE);
+
+	if (itv->card_type == IVTV_350_V1) {
+		/* decoder */
+		itv->DSGarray = (struct ivtv_SG_element *)
+				 kmalloc(sizeof(struct ivtv_SG_element) * 
+				 DSGarray_size, GFP_KERNEL);
+		if (!(itv->DSGarray)) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR, "Error allocating DSGarray[].\n");
+			retval = -ENOMEM;
+			goto free_sg;
+		}
+
+		itv->DSG_handle = pci_map_single(itv->dev,
+						(void *)&itv->DSGarray[0],
+						(sizeof(struct ivtv_SG_element) * 
+					        DSGarray_size),	PCI_DMA_TODEVICE);
+	}
+	
+	/* FIXME -temporary- setup tuner */
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Setting Tuner\n");
+
+	if( tuner > -1 ) {
+		ivtv_call_i2c_client(itv,
+				     IVTV_TUNER_I2C_ADDR,
+				     TUNER_SET_TYPE,
+				     &tuner );
+	}
+
+	/* set the standard */
+	if (!ivtv_pal)
+		v.norm = VIDEO_MODE_NTSC;
+	else
+		v.norm = VIDEO_MODE_PAL;
+
+	ivtv_call_i2c_client(itv,IVTV_TUNER_I2C_ADDR, VIDIOCSCHAN,&v);
+
+	if (!ivtv_pal) {
+		/* set the channel */
+		freq = 1076; /* ch. 4 67250*16/1000 */
+		ivtv_call_i2c_client(itv,IVTV_TUNER_I2C_ADDR,VIDIOCSFREQ,&freq);
+	}
+
+	retval = ivtv_v4l2_setup(itv);
+	if (retval) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Problem starting v4l2\n");
+		goto ivtv_v4l2_fail;
+	}
+
+	return 0;
+	
+ivtv_v4l2_fail:
+	pci_unmap_single(itv->dev,
+			 itv->DSG_handle,
+			 (sizeof(struct ivtv_SG_element) * 
+           DSGarray_size),
+			 PCI_DMA_TODEVICE);
+	kfree(itv->DSGarray);
+free_sg:
+	pci_unmap_single(itv->dev,
+			 itv->SG_handle,
+			 (sizeof(struct ivtv_SG_element) * 
+           SGarray_size),
+			 PCI_DMA_TODEVICE);
+	kfree(itv->SGarray);
+free_i2c:
+	exit_ivtv_i2c(itv);
+free_irq:
+	free_irq(itv->dev->irq, (void *)itv);
+free_io:
+	ivtv_iounmap(itv);
+free_mem:
+	release_mem_region(pci_resource_start(itv->dev,0), IVTV_IOREMAP_SIZE);
+err:
+	IVTV_DEBUG(IVTV_DEBUG_ERR, "Error %d on init\n", retval);
+
+	spin_lock_irq(&ivtv_lock);
+	ivtv_cards_active--;
+	spin_unlock_irq(&ivtv_lock);
+	return retval;
+}
+
+static void ivtv_remove(struct pci_dev *pci_dev) {
+	struct ivtv *itv=pci_get_drvdata(pci_dev);
+	int x = 0;
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Disabling interrupts!\n");
+	ivtv_set_irq_mask(itv, 0xffffffff);
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping thread\n");
+	atomic_set(&itv->decoding, 0);
+	
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping card parts\n");
+	x = ivtv_stop_firmware(itv);
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Freeing buffers\n");
+
+	for (x = 0; x < itv->v4l2.streamcount; x++) {
+		IVTV_DEBUG(IVTV_DEBUG_INFO,"Freeing stream %d!\n", x);
+		ivtv_free_queue(&itv->v4l2.streams[x].free_q);
+		ivtv_free_queue(&itv->v4l2.streams[x].full_q);
+		ivtv_free_queue(&itv->v4l2.streams[x].dma_q);
+	}
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Unregistering v4l devices!\n");
+	ivtv_v4l2_cleanup(itv);
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Freeing dma resources\n");
+
+	pci_unmap_single(itv->dev, itv->SG_handle,
+			 (sizeof(struct ivtv_SG_element) * SGarray_size),
+			 PCI_DMA_TODEVICE);
+	kfree(itv->SGarray);
+
+	pci_unmap_single(itv->dev, itv->DSG_handle,
+			 (sizeof(struct ivtv_SG_element) * DSGarray_size),
+			 PCI_DMA_TODEVICE);
+	kfree(itv->DSGarray);
+
+	exit_ivtv_i2c(itv);
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "releasing irq\n");
+	free_irq(itv->dev->irq, (void *)itv);
+
+	if (itv->dev) {
+	    ivtv_iounmap(itv);
+	}
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "releasing mem\n");
+	if (itv)
+	    release_mem_region(pci_resource_start(itv->dev,0), IVTV_IOREMAP_SIZE);
+
+	/* FIXME free v4l2 stuff! */
+	/* FIXME am i leaking kernel mem? */
+
+}
+
+/* define a pci_driver for card detection */
+static struct pci_driver ivtv_pci_driver = {
+	name:	  "ivtv: iTVC15/16 mpg2 encoder card",
+	id_table: ivtv_pci_tbl,
+	probe:	  ivtv_probe,
+	remove:	  ivtv_remove,
+};
+
+#ifdef YUV_FIXUP
+static int ivtv_YUV_fixup(struct ivtv_v4l2_stream *st, int count,
+			  char *ubuf, struct ivtv_buffer *buf) {
+/*  
+ * int count = # of bytes to transfer to client 
+ * st->ubytes = # of bytes written this frame
+ * ubuf = buffer to write to (user's buffer)
+ * buf = read buffer
+ *
+ */
+	int src_width=720; /* all known formats have src width of 720 */
+	int Hoff, Voff; /* collectors for offsets to read position */
+	int width, height; /* resolution of the capture stream */
+	int curline; /* vertical line currently being processed */
+	int maxline; /* height of combined frame */
+	int cur_m_block; /* current horizontal offset of working mblock in this row */
+	int maxblock; /* # of macroblocks in a row */
+	int Hbytes; /* # of bytes to write to user this time around */
+	int retval=0; /* accumulator for total bytes written */
+	int start; /* position in buf to read from */
+	int buf_start; /* byte offset of first byte in this *buf */
+
+	height = st->format.fmt.pix.height;
+	width  = st->format.fmt.pix.width;
+	maxblock = (width + 0xf) >> 4;
+	maxline = (int)(1.5 * height); /* 1 for Y, .5 for UV */
+	/* Offset is always bufsize * buffer index 
+	buf_start = (st->ubytes - buf->readpos);  tested/works */
+
+	buf_start = IVTV_DMA_BUF_SIZE * buf->buffer.index;
+
+	/* FIXME it may not be possible to get YUV width > 720 */
+	// if (width > src_width) src_width=width;
+
+	curline = (int) (st->ubytes / width);
+
+	while (curline < maxline) {
+// 	printk(" cl: %d, ml: %d\n", curline, maxline);
+	Voff =	16 * (curline & 0xf) +		   /* Voffset within MBlock */
+		  ((curline & 0xfff0) * src_width); /* Voffset of Mblock */
+
+	cur_m_block = (st->ubytes - (curline * width)) >> 4;
+
+/*	printk("voff %d, macroVoff %d, Voff %d, cmb %d\n", (16 * (curline & 0xf)), 
+			((curline & 0xff0) * src_width), Voff, cur_m_block);
+*/
+
+	while ((cur_m_block < maxblock) && (count > 0)) {
+		Hoff   = (cur_m_block * 256) +	/* mblock offset within line */
+			 /* Hoffset within mblock, usually 0 */
+			 ((st->ubytes - (curline * width)) & 0xf);
+		Hbytes = 16 - ((st->ubytes - (curline * width)) & 0xf);
+
+		if (Hbytes > count) Hbytes = count;
+
+		start = Hoff + Voff;
+
+		if (copy_to_user((char *)((u32)ubuf + retval),
+				 (u32 *)((u32)buf->buffer.m.userptr +
+				 (start - buf_start)),
+				 Hbytes)) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR, "copy to user failed\n");
+			return -EFAULT;
+		}
+		
+		count -= Hbytes;
+		retval += Hbytes;
+		st->ubytes += Hbytes;
+
+		cur_m_block++;
+	}
+
+	/* if user can't handle anymore data or buffer empty */
+	curline++;
+	if ((count == 0) ) /*|| ((curline * src_width) % IVTV_DMA_BUF_SIZE) == 0)*/
+		return retval;
+	}
+
+	/* FIXME i don't think you should ever get here */
+	IVTV_DEBUG(IVTV_DEBUG_ERR, "You've just sailed off the edge of this function\n");
+	return retval;
+}
+#endif
+
+long ivtv_read(struct ivtv_open_id *id, char *ubuf, size_t count, int block) {
+	int x, sleepctr, datalen, retval=0, freed=0;
+	struct ivtv *itv = id->itv;
+	size_t newcount;
+	unsigned long tid;
+	struct ivtv_buffer *buf;
+	struct ivtv_v4l2_stream *st=&itv->v4l2.streams[id->type];
+	DECLARE_WAITQUEUE(wait, current);
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, " Read stream.. \n");
+
+	if (atomic_read(&itv->capturing) == 0 && (st->id == -1)) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR,
+			   "Stream not initialized before read(shouldn't happen)\n");
+		return -EIO;
+	}
+
+	/* FIXME find a way to gracefully exit capture */
+
+	sleepctr = retval = 0;
+	buf = NULL;
+
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&st->waitq, &wait);
+	do {
+		if ((itv->trans_id == 0) && (sleepctr >= IVTV_MAX_DATA_SLEEP)) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR, "Timeout waiting for data!\n");
+			retval = -EIO;
+			break;
+		}
+
+		buf = ivtv_deq_peek_head(itv, &st->full_q);
+		if (buf) {
+			break;
+		} else {
+	                
+			/* Done capturing? */
+	                if (!test_bit(IVTV_F_S_CAP, &st->s_flags)) {
+				IVTV_DEBUG(IVTV_DEBUG_INFO,
+					   "No more data to send, returning 0\n");
+				set_current_state(TASK_RUNNING);
+				remove_wait_queue(&st->waitq, &wait);
+				return 0;
+			}
+		}
+
+		if (!block) {
+			retval = -EAGAIN;
+			break;
+		}
+
+		ivtv_sleep_timeout(IVTV_SLEEP_WAIT);
+
+		if (signal_pending(current))
+			retval = -ERESTARTSYS;
+
+		sleepctr++;
+	} while (!retval);
+
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&st->waitq, &wait);
+
+	/* an error (or signal) occured */
+	if (retval) {
+		return retval;
+	}
+
+	/* Skip the first 4 bytes of mpg streams to help out
+	 * finicky decoders.. but not for iTVC16 */
+	if ((id->type == 0) && (itv->first_read == 1) &&
+	    (itv->card_type != IVTV_250_V2)) {
+		for( x = 0; x < buf->buffer.bytesused-4; x++ ) {
+			unsigned char *p;
+			itv->first_read = 0;
+			p = (unsigned char *) buf->buffer.m.userptr +
+			    buf->readpos + x;
+			if( !p[0] && !p[1] && p[2] == 1 ) {
+				IVTV_DEBUG(IVTV_DEBUG_INFO,
+					   "Stripping first 4 bytes\n");
+				buf->buffer.bytesused -= x;
+				buf->readpos += x;
+				break;
+			}
+		}
+	}
+
+	/* data ready */
+	/* copy it to the client */
+	while ((count > 0) && (buf->buffer.bytesused > 0)) {
+		newcount = count;
+		datalen = buf->buffer.bytesused;
+
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "datalen 0x%08x\n", datalen);
+
+		if (newcount > datalen)
+		       	newcount = datalen;
+
+#ifdef YUV_FIXUP
+		if ((id->type == 1) && (itv->options.yuv_fixup)) {
+			newcount = ivtv_YUV_fixup(st,newcount,ubuf+retval,buf);
+			if (newcount < 0) {
+				IVTV_DEBUG(IVTV_DEBUG_ERR, "Error fixing up YUV!\n");
+				return newcount;
+			}
+		} else {
+#endif
+			if (copy_to_user((char *)((u32)ubuf+retval),
+			    (u32 *)((u32)buf->buffer.m.userptr +
+			    buf->readpos), newcount)) {
+				IVTV_DEBUG(IVTV_DEBUG_ERR, "copy to user failed\n");
+		 		return -EFAULT;
+			}
+#ifdef YUV_FIXUP
+		}
+#endif
+
+		buf->readpos += newcount;
+		retval += newcount;
+		count -= newcount;
+		buf->buffer.bytesused -= newcount;
+		IVTV_DEBUG(IVTV_DEBUG_INFO,
+			   "new datalen 0x%08x\n", buf->buffer.bytesused);
+
+		/* if buffer is empty or we've read the whole frame */
+		if ((buf->buffer.bytesused == 0)) {
+			ivtv_move_buf(itv, &st->full_q, &st->free_q, buf);
+			freed++;
+
+			buf = ivtv_deq_peek_head(itv, &st->full_q);
+			if (buf) {
+				tid = buf->buffer.sequence;
+				if (buf->buffer.sequence != tid) {
+					/* end of frame! */
+					st->ubytes = 0;
+					break;
+				}
+			} else {
+				/* user wanted more than we had. Since
+				 * queues are filled in irq time, 
+				 * that means end of frame */
+				st->ubytes = 0;
+				break;
+			}
+		}
+	} /* end of while */
+
+	/* if we put some buffers back in the free queue, kick off dma
+	 * scheduling if card was stopped due to overflow before */
+	if (freed && test_and_clear_bit(IVTV_F_S_OVERFLOW, &st->s_flags)) {
+		spin_lock_irq(&itv->lock);
+		ivtv_sched_DMA(itv);
+		spin_unlock_irq(&itv->lock);
+	}
+
+	/*FIXME unlock */
+	if (retval != 0) { 
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "Returning %d\n", retval);
+		return retval;
+	}
+
+	/* Shouldn't ever get here */
+	return -EIO;
+}
+
+static void ivtv_swap_copy(const char *buf, const char *ubuf, size_t count) {
+	u32 *src,*dst;
+
+	src=(u32 *)ubuf;
+	dst=(u32 *)buf;
+
+#ifdef CONFIG_X86
+	while ((u32)src <= (u32)ubuf + count) { /* byteswap while copying */
+		__asm__ __volatile__ ("bswap %0" :
+				      "=r" (*dst) :
+				      "0" (*src) );
+		src++;dst++;
+	}
+#else
+	{
+	int y;
+	/* Old slow memcpy then swab */
+	memcpy((void *)buf,(void *)ubuf,count);
+	for (y = 0; y < count; y += 4) {
+		swab32s( (u32 *)((u32)buf + y));
+	}
+	}
+#endif
+}
+
+static int ivtv_fill_dec_buffers(struct ivtv_open_id *id, const char *ubuf,
+				 size_t count, int block) {
+	struct ivtv *itv = id->itv;
+	struct ivtv_v4l2_stream *stream=&itv->v4l2.streams[id->type];
+	struct ivtv_buffer *buf;
+	int copybytes=0, bytesread=0, retval=0;
+	
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "ivtv_fill_dec_buffers, %d bytes\n", count);
+
+        /* Read what the user gives us. queue it for DMA after each buffer
+	 * also enqueue partly-full buffers. */
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO,
+		   "DEC: free_q: %d elements\n", stream->free_q.elements);
+	IVTV_DEBUG(IVTV_DEBUG_INFO,
+		   "DEC: dma_q: %d elements\n", stream->dma_q.elements);
+	IVTV_DEBUG(IVTV_DEBUG_INFO,
+		   "DEC: full_q: %d elements\n", stream->full_q.elements);
+
+	/* FIXME will only do one write. Has underlying code to handle more
+	 * 	than one, just need loop control logic for it, if it's 
+	 * 	deemed necessary. */
+	while (bytesread == 0) {
+		DECLARE_WAITQUEUE(wait, current);
+		unsigned long flags;
+
+		buf = NULL;
+		add_wait_queue(&stream->waitq, &wait);
+		do {
+			set_current_state(TASK_INTERRUPTIBLE);
+			buf = ivtv_deq_peek_head(itv, &stream->free_q);
+			if (buf)
+				break;
+
+                        if (!block) {
+                                retval = -EAGAIN;
+                                break;
+                        }
+
+			schedule();
+
+			if (signal_pending(current)) {
+				retval = -ERESTARTSYS;
+				break;
+			}
+
+			spin_lock_irqsave(&itv->lock, flags);
+			ivtv_dec_sched_DMA(id->itv);
+			spin_unlock_irqrestore(&itv->lock, flags);
+		} while (!buf);
+		set_current_state(TASK_RUNNING);
+		remove_wait_queue(&stream->waitq, &wait);
+
+		if (retval)
+			return retval;
+
+		/* bytes left to send > free bytes in current buffer */
+		if ((count - bytesread) >
+		    (IVTV_DMA_DEC_BUF_SIZE - buf->buffer.bytesused)) {
+			copybytes = IVTV_DMA_DEC_BUF_SIZE - buf->buffer.bytesused;
+		} else {
+			copybytes = count - bytesread;
+		}
+
+		/* copy data */
+		/* FIXME */
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "copying %d bytes to 0x%08x"
+					    " (buffer free = %d)\n",
+			   copybytes,(int)(buf->buffer.m.userptr + buf->buffer.bytesused),
+			   (int)(IVTV_DMA_DEC_BUF_SIZE - buf->buffer.bytesused));
+
+		ivtv_swap_copy((char *)(buf->buffer.m.userptr+buf->buffer.bytesused),
+				(char *)((u32)ubuf + bytesread),copybytes);
+
+		bytesread += copybytes;
+		buf->buffer.bytesused += copybytes;
+
+		/* enq buffer when full */
+		if (buf->buffer.bytesused == IVTV_DMA_DEC_BUF_SIZE)
+			ivtv_move_buf(itv,&stream->free_q,&stream->full_q,buf);
+	}
+
+	return bytesread;
+}
+
+/*
+ * Schedule host -> hardware DMA of one buffer from the stream (MPEG or YUV) 
+ * with the most recent request for more data, but only if dec->dec_needs_data
+ * is set.
+ *
+ * This code can be called from both interrupt context as well as userspace;
+ * it does the right things in either case. If called from userspace, it may
+ * block only when the same call is in progress in interupt context (since 
+ * interrupt context is not allowed to block.) 
+ *
+ * @returns 0 if the buffer was queued to dma_q and the DMA was initiated.
+ *
+ *          -EAGAIN if either the full_q queue is empty or the function is
+ *                  already in progress in interrupt context.
+ *
+ *          -ENOSPC if there is no space remaining in the hardware's buffer.
+ *                  This should never happen if proper flow control is used.
+ *
+ *          -EINVAL if the most recent "data needed" interrupt requested an
+ *                  unknown stream type (should really never happen!)
+ *
+ *          -EBUSY if a DMA on the same queue is already in progress (should
+ *                 never happen)
+ *
+ */
+static void ivtv_dec_sched_DMA(struct ivtv *itv) {
+	int ret=0, x=0, bytes_written=0, type=0, max=2;
+	struct ivtv_buffer *buf;
+        struct ivtv_v4l2_stream *stream=NULL;
+	u32 data[IVTV_MBOX_MAX_DATA], result;
+	u32 mem_offset, mem_size, hw_stream_type, buffer_bytes;
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "ivtv_dec_sched_DMA\n");
+
+	/* fancy way of saying "if (ivtv->dec_needs_data == 0)" */
+	if (!test_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags)) {
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: no data needed\n");
+		return;
+	}
+
+	/* Get Card Mem Dst address from mailbox 10 */
+	ret = ivtv_api_getresult_nosleep(&itv->dec_mbox[9], &result, &data[0]);
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: Mailbox 10: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+	           data[0],data[1],data[2],data[3]);
+	
+	hw_stream_type = data[0];
+
+	switch(hw_stream_type) {
+		case 0: /* MPG */
+			type = IVTV_DEC_STREAM_TYPE_MPG;
+			IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: mpg data\n");
+			break;
+		case 2: /* YUV */
+			type = IVTV_DEC_STREAM_TYPE_YUV;
+			IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: yuv data\n");
+			break;
+		default:
+			IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: unknown stream type %d\n",
+				   data[0]);
+			max = 0;
+			return;
+	}
+
+	stream = &itv->v4l2.streams[type];
+
+	if (test_bit(IVTV_F_I_BUSY, &itv->i_flags)) {
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: decoder busy, delaying\n");
+		set_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags);
+		return;
+	}
+
+	/* If we got this far, we have data to send and it wants it */
+	clear_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags);
+
+	/* Get card mem addr and size from data array */
+	mem_offset = data[1];
+	mem_size   = data[2];
+	buffer_bytes = data[3]; /* # bytes in card's buffer */
+
+	while ((max > x) && (mem_size > bytes_written)) { /* send a maximum of 
+							     'max' buffers */
+		buf = __ivtv_deq_peek_head(&stream->full_q);
+		if (buf == NULL) {
+			IVTV_DEBUG(IVTV_DEBUG_INFO,
+				   "DEC: No more buffers to send\n");
+			break;
+		}
+		
+#if 1
+		if (mem_size < buf->buffer.bytesused) {
+			itv->DSGarray[x].size = mem_size;
+		} else {
+			itv->DSGarray[x].size = buf->buffer.bytesused;
+		}
+#else
+		/* just send the whole buffer */
+		itv->DSGarray[x].size = buf->buffer.bytesused;
+#endif
+		buf->dma_handle = pci_map_single(itv->dev,
+						 (void *)(buf->buffer.m.userptr +
+							  buf->readpos),
+						 itv->DSGarray[x].size,
+						 PCI_DMA_TODEVICE);
+
+		itv->DSGarray[x].src	= buf->dma_handle;
+		itv->DSGarray[x].dst	= (mem_offset + bytes_written +
+					     IVTV_FIRM_SEARCH_DECODER_START);
+	
+		buf->readpos 		+= itv->DSGarray[x].size;
+		bytes_written		+= itv->DSGarray[x].size;
+		buf->buffer.bytesused	-= itv->DSGarray[x].size;
+
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "1st 32bits of buffer %d are 0x%08x\n", 
+			   buf->buffer.index, *(u32 *)buf->buffer.m.userptr);
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "DSGarray[%d]: 0x%08x, 0x%08x 0x%08x\n",
+	        	   x, itv->DSGarray[x].src,
+			   itv->DSGarray[x].dst,
+			   itv->DSGarray[x].size);
+
+		/* buffer is empty? */
+		if (buf->buffer.bytesused == 0) {
+			__ivtv_del_buf(&stream->full_q, buf);
+			__ivtv_enq_buf(&stream->dma_q, buf);
+		}
+		x++;
+	}
+
+	if (x == 0) { /* no full buffers */
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: Nothing to send\n");
+		set_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags);
+		return;
+	}
+
+	//Set Last Element Bit
+	itv->DSGarray[x-1].size |= 0x80000000;
+
+	//Schedule DMA XFER
+	data[0] = itv->DSG_handle;
+	data[1] = bytes_written;
+	data[2] = hw_stream_type;
+
+	/* note that we're DMA'ing */
+	mod_timer(&itv->dec_timeout, jiffies + DEC_DMA_TIMEOUT);
+	set_bit(IVTV_F_S_DMAP, &stream->s_flags);
+	set_bit(IVTV_F_I_BUSY, &itv->i_flags);
+
+	ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_DMA_FROM_HOST,
+		 &result, 3, &data[0]);
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO,
+	           "Sched DEC dma: addr: 0x%08x, array_size 0x%08x, type 0x%08x\n",
+		   data[0], data[1], data[2]);
+}
+
+static void ivtv_dec_DMA_done(struct ivtv *itv) {
+        struct ivtv_v4l2_stream *stream=NULL;
+	struct ivtv_buffer *buf;
+	int y, stmtype=-1, freed=0;
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: DMA Done tasklet\n");
+
+	if (!test_and_clear_bit(IVTV_F_I_BUSY, &itv->i_flags)) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "DMAP not set\n");
+		ivtv_show_debug_flags(itv);
+		return;
+	}
+
+#if 0
+	del_timer(&itv->dec_timeout);
+#else
+	mod_timer(&itv->dec_timeout, jiffies + DEC_DMA_TIMEOUT);
+#endif
+	
+	for (y=IVTV_DEC_STREAM_TYPE_MPG; y < itv->v4l2.streamcount; y++) {
+		if (test_and_clear_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[y].s_flags)) {
+			stmtype = y;
+			break;
+		}
+	}
+
+	/* Handle OSD DMA */
+	if (test_and_clear_bit(IVTV_F_I_OSD_DMA, &itv->i_flags)) {
+		IVTV_DEBUG(IVTV_DEBUG_INFO, "OSD: DMA Done\n");
+		
+		/* wake all the normal streams, in case they fell asleep */
+		for (y=IVTV_DEC_STREAM_TYPE_MPG; y < itv->v4l2.streamcount; y++) {
+			wake_up(&itv->v4l2.streams[y].waitq);
+		}
+
+		wake_up(&itv->dec_master_w);
+		return;
+	}
+
+	if (stmtype < 0) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: Got DMA-done, not expecting one\n");
+		ivtv_show_debug_flags(itv);
+		return;
+	}
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: Stream %d dma-done\n", y);
+	stream = &itv->v4l2.streams[y];
+
+	while ((buf = __ivtv_deq_buf(&stream->dma_q)) != NULL) {
+		IVTV_ASSERT(buf->dma_handle != IVTV_DMA_UNMAPPED);
+		pci_unmap_single(itv->dev, buf->dma_handle,
+				 IVTV_DMA_DEC_BUF_SIZE, PCI_DMA_TODEVICE);
+		buf->dma_handle = IVTV_DMA_UNMAPPED;
+		buf->buffer.bytesused	= 0;
+		buf->readpos = 0;
+
+		/* put in the 'done' queue */
+		__ivtv_enq_buf(&stream->free_q, buf);
+		freed++;
+	}
+
+	/* if we put some buffers back in the free queue, kick off dma
+	 * scheduling if card was stopped due to overflow before */
+	if (freed && test_and_clear_bit(IVTV_F_S_OVERFLOW, &stream->s_flags))
+		ivtv_sched_DMA(itv);
+
+	/* wake up queue filler */
+	wake_up(&stream->waitq);
+	wake_up(&itv->dec_master_w);
+}
+
+int ivtv_get_timing_info(struct ivtv *itv, struct ivtv_ioctl_framesync *info) {
+	u32 ret, result, data[IVTV_MBOX_MAX_DATA];
+
+	int suicidecounter = 0;
+	
+	memset(info, 0x00, sizeof(struct ivtv_ioctl_framesync));
+
+	/* Occasionally, we'll get a wierd, invalid number for 
+	 * frames played. fortunately, it sets the SCR timestamp to 0
+	 * in that case, which it never is otherwise. cool, huh */
+	while (info->scr == 0) { /* eliminate bogus values, FIXME ugly */
+		ret = ivtv_api(itv->dec_mbox, &itv->dec_msem,
+				IVTV_API_DEC_TIMING_INFO,&result,0,&data[0]);
+		if (ret) {
+			IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: err sending timing info\n");
+			return ret;
+		}
+
+		info->frame	= data[0];
+		info->pts	= ((u64)data[2] << 32) | (u64)data[1];
+		info->scr	= ((u64)data[4] << 32) | (u64)data[3];
+
+		if (suicidecounter++ > 10) { /* endless loops are bad! */
+			IVTV_DEBUG(IVTV_DEBUG_ERR,"Timeout getting frames played\n");
+			return -1;
+		}
+		if (info->scr == 0)
+			ivtv_sleep_timeout(HZ/50);
+	}
+
+	return 0;
+}
+
+ssize_t ivtv_write(struct ivtv_open_id *id, const char *ubuf, size_t count,
+                   int block) {
+	int bytes_written=0, ret=0;
+	unsigned long flags;
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "ivtv_write\n");
+
+	while (bytes_written < count) { /* completely use up user data 
+					 * before returning */
+		/* buffer the data - this may block waiting on free buffers */
+		ret = ivtv_fill_dec_buffers(id, ubuf + bytes_written, 
+					    (count - bytes_written), block);
+
+                /* FIXME temporary hack to make sure non-blocking works */
+		/* send it! it'll return right away if no data needed */
+		spin_lock_irqsave(&id->itv->lock, flags);
+		ivtv_dec_sched_DMA(id->itv);
+		spin_unlock_irqrestore(&id->itv->lock, flags);
+
+		if (ret < 0) {
+			break;
+		} else {
+			bytes_written += ret;
+		}
+	}
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: returning %d\n", bytes_written);
+	return bytes_written ? bytes_written : ret;
+}
+
+unsigned int ivtv_dec_poll(struct file *filp, poll_table *wait) {
+	struct ivtv_open_id *id = filp->private_data;
+	unsigned int mask = 0;
+	unsigned long flags;
+
+	/* add stream's waitq to the poll list */
+	poll_wait(filp, &id->itv->v4l2.streams[id->type].waitq, wait);
+
+        /* FIXME temporary hack to restart DMA in case the decoder's
+           been busy for a while and the application is using poll to
+           see if it can write */
+        spin_lock_irqsave(&id->itv->lock, flags);
+        ivtv_dec_sched_DMA(id->itv);
+        spin_unlock_irqrestore(&id->itv->lock, flags);
+
+	if (ivtv_deq_peek_head(id->itv, &id->itv->v4l2.streams[id->type].free_q))
+		mask |= POLLOUT | POLLWRNORM; /* Writable */
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: dec_poll returning 0x%x\n", mask);
+	return mask;
+}
+
+unsigned int ivtv_poll(struct file *filp, poll_table *wait) {
+	struct ivtv_open_id *id = filp->private_data;
+	unsigned int mask = 0;
+
+	/* add stream's waitq to the poll list */
+	poll_wait(filp, &id->itv->v4l2.streams[id->type].waitq, wait);
+
+#if 0
+	if (down_interruptible(&id->itv->sem_lock))
+		return -ERESTARTSYS;
+
+	if (ivtv_get_free_elements(id->itv, &id->itv->v4l2.streams[id->type].full_q))
+		mask |= POLLIN | POLLRDNORM; /* readable */
+
+	up(&id->itv->sem_lock);
+#else
+	mask |= POLLIN | POLLRDNORM;
+#endif
+	return mask;
+}
+
+#if 0
+static void ivtv_print_boxes(struct ivtv_mailbox *mbox) {
+
+	int x,y;
+
+	IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 10ms\n");
+	ivtv_sleep_timeout(HZ/100);
+
+	if (NULL == mbox) {
+		IVTV_DEBUG(IVTV_DEBUG_IOCTL, "Mailboxes not initialized!\n");
+		return;
+	}
+
+	for (x = 0; x <= IVTV_MBOX_MAX_BOXES; x++) {
+		IVTV_DEBUG(IVTV_DEBUG_IOCTL, "mbox: 0x%08x, # %d\n", (u32)mbox, x);
+		IVTV_DEBUG(IVTV_DEBUG_IOCTL, "flags:   0x%08x   ",(u32)readl(&mbox->flags));
+		IVTV_DEBUG(IVTV_DEBUG_IOCTL, "cmd:     0x%08x\n", readl(&mbox->cmd));
+		IVTV_DEBUG(IVTV_DEBUG_IOCTL, "result:  0x%08x   ", readl(&mbox->retval));
+		IVTV_DEBUG(IVTV_DEBUG_IOCTL, "timeout: 0x%08x\n", readl(&mbox->timeout));
+		IVTV_DEBUG(IVTV_DEBUG_IOCTL, "Data:\n");
+		for (y = 0; y < IVTV_MBOX_MAX_DATA; y++) {
+			IVTV_DEBUG(IVTV_DEBUG_IOCTL, "[%02d]0x%08x, ", y, readl(&mbox->data[y]));
+			if (2 == y%3) IVTV_DEBUG(IVTV_DEBUG_IOCTL, "\n");
+		}
+		/*Since mbox has type ptr, this should step it up*/
+		/* to the start of the next mbox */
+		mbox++; 
+		IVTV_DEBUG(IVTV_DEBUG_IOCTL, "\n");
+	}
+}
+#endif
+
+void ivtv_flush_queues(struct ivtv_open_id *id) {
+	struct ivtv *itv = id->itv;
+	struct ivtv_v4l2_stream *st = &itv->v4l2.streams[id->type];
+	struct ivtv_buffer *buf;
+
+	/* move free_q to full_q to clean up partially-filled buffers */
+	while ((buf = ivtv_deq_buf(itv, &st->free_q))) 
+		ivtv_enq_buf(itv, &st->full_q, buf);
+
+	while ((buf = ivtv_deq_buf(itv, &itv->v4l2.streams[id->type].full_q))) {
+		buf->buffer.bytesused=0;
+		buf->readpos=0;
+		ivtv_enq_buf(itv, &st->free_q, buf);
+	}
+
+	while ((buf = ivtv_deq_buf(itv, &itv->v4l2.streams[id->type].dma_q))) {
+		buf->buffer.bytesused=0;
+		buf->readpos=0;
+		ivtv_enq_buf(itv, &st->free_q, buf);
+	}
+
+	return;
+}
+
+int ivtv_close(struct ivtv_open_id *id) {
+	struct ivtv *itv=id->itv;
+	int ret = 0;
+
+	/* sem_lock must be held */
+	IVTV_ASSERT(ivtv_sem_count(&itv->sem_lock) <= 0);
+	
+	switch (id->type) {
+		case IVTV_DEC_STREAM_TYPE_MPG: /* decoder streams */
+		case IVTV_DEC_STREAM_TYPE_YUV:
+			if (atomic_read(&itv->decoding)) {
+				IVTV_DEBUG(IVTV_DEBUG_INFO,
+					   "close stopping decode\n");
+				ret = ivtv_stop_decode(id);
+			}
+			break;
+		default: /* encoder streams */
+			if (atomic_read(&itv->capturing)) {
+				IVTV_DEBUG(IVTV_DEBUG_INFO,
+					   "close stopping capture\n");
+				ret = ivtv_stop_capture(id);
+			}
+			break;
+	}
+
+	ivtv_flush_queues(id);
+	return ret;
+}
+
+static int module_start(void)  {
+	int loop_a;
+	
+	printk("ivtv: version %s (%s) loading\n", IVTV_VERSION_STRING(ivtv_rev),
+			IVTV_VERSION_COMMENT(ivtv_rev));
+
+	memset(&ivtv_cards[0], 0, IVTV_MAX_CARDS * sizeof(struct ivtv));
+
+	/* Validate parameters */
+	if (((yuv_buffers > IVTV_MAX_YUV_BUFFERS)
+		|| (yuv_buffers < IVTV_MIN_YUV_BUFFERS))
+		&& (yuv_buffers != 0)) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR,
+			   "Error! yuv_buffers must be between 40 and 500\n");
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n");
+		return -1;
+	}
+	
+#ifdef YUV_FIXUP
+	if ((yuv_fixup != 0) && (yuv_fixup != 1)) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR,
+			   "Error! yuv_fixup must be 0 or 1\n");
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n");
+		return -1;
+	}
+#endif
+	if ((dec_mpg_buffers > IVTV_MAX_DEC_MPG_BUFFERS)
+	    || (dec_mpg_buffers < IVTV_MIN_DEC_MPG_BUFFERS)) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR,
+			   "Error! dec_mpg_buffers must be between 5 and 100\n");
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n");
+		return -1;
+	}
+
+	if (((dec_yuv_buffers > IVTV_MAX_DEC_YUV_BUFFERS)
+	    || (dec_yuv_buffers < IVTV_MIN_DEC_YUV_BUFFERS))
+	    && (dec_yuv_buffers != 0)) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR,
+			   "Error! dec_yuv_buffers must be between 17 and 500\n");
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n");
+		return -1;
+	}
+
+	if ((mpg_buffers > IVTV_MAX_MPG_BUFFERS)
+	    || (mpg_buffers < IVTV_MIN_MPG_BUFFERS)) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR,
+			   "Error! mpg_buffers must be between 15 and 100\n");
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n");
+		return -1;
+	}
+
+	if ((dec_yuv_qlen > dec_yuv_buffers)
+			|| (dec_yuv_qlen < IVTV_MIN_DEC_YUV_QLEN)) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR,
+			   "Error! dec_yuv_qlen must be between %d and %d\n",
+			   IVTV_MIN_DEC_YUV_QLEN, dec_yuv_buffers);
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n");
+		return -1;
+	}
+
+	if ((dec_mpg_qlen > dec_mpg_buffers)
+			|| (dec_mpg_qlen < IVTV_MIN_DEC_MPG_QLEN)) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR,
+			   "Error! dec_mpg_qlen must be between %d and %d\n",
+			   IVTV_MIN_DEC_MPG_QLEN, dec_mpg_buffers);
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n");
+		return -1;
+	}
+
+	if ((vbi_buffers > IVTV_MAX_VBI_BUFFERS)
+	    || (vbi_buffers < IVTV_MIN_VBI_BUFFERS)) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR,
+			   "Error! vbi_buffers must be between 3 and 100\n");
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n");
+		return -1;
+	}
+
+	if ((num_devices > IVTV_MAX_CARDS) || (num_devices < 1)) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Error! num_devices must be between 1 and 9 (not working yet)\n");
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n");
+		return -1;
+	}
+
+	if (ivtv_debug < 0) IVTV_DEBUG(IVTV_DEBUG_ERR, "debug value must be >= 0!\n");
+
+       	IVTV_DEBUG(IVTV_DEBUG_INFO,
+		   "Loading, I'll try to detect %d devices!\n", num_devices);
+       	IVTV_DEBUG(IVTV_DEBUG_INFO,
+		   " .. running on kernel %s\n", UTS_RELEASE);
+	IVTV_DEBUG(IVTV_DEBUG_INFO,
+		   "Setting some variables to invalid for detection\n");
+
+	for (loop_a = 0; loop_a < IVTV_MAX_CARDS; loop_a++) {
+		ivtv_cards[loop_a].num = -1;
+		ivtv_cards[loop_a].dev = NULL;
+	}
+
+	SGarray_size = (mpg_buffers + yuv_buffers + vbi_buffers) * 2;
+	DSGarray_size = (dec_mpg_buffers + dec_yuv_buffers) * 2;
+
+	IVTV_DEBUG(IVTV_DEBUG_ERR, "SGarray_size = %d, DSGarray_size = %d\n",
+			SGarray_size, DSGarray_size);
+
+       	IVTV_DEBUG(IVTV_DEBUG_INFO, "Scanning PCI bus..\n");
+	if (pci_module_init(&ivtv_pci_driver)) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "Error detecting PCI card\n");	
+		return -ENODEV;
+	}
+
+	printk("ivtv: loaded\n");
+	return 0;
+}
+
+static void module_cleanup(void) {
+
+	pci_unregister_driver(&ivtv_pci_driver);
+	IVTV_DEBUG(IVTV_DEBUG_ERR, "You've not seen the last of willy!\n"); 
+#ifdef AEW_DEBUG
+	DUMP_BAD_ALLOC_TABLE;
+#endif // AEW_DEBUG
+}
+
+module_init(module_start);
+module_exit(module_cleanup);
diff -aurpN -X /home/fletch/.diff.exclude 670-tiocgdev/drivers/media/video/ivtv-fb.c 680-ia64_dec_and_lock/drivers/media/video/ivtv-fb.c
--- 670-tiocgdev/drivers/media/video/ivtv-fb.c	Wed Dec 31 16:00:00 1969
+++ 680-ia64_dec_and_lock/drivers/media/video/ivtv-fb.c	Wed Feb 11 10:17:11 2004
@@ -0,0 +1,1112 @@
+/*
+ * iTVC15 Framebuffer driver
+ *
+ * This module presents the iTVC15 OSD (onscreen display) framebuffer memory 
+ * as a standard Linux /dev/fb style framebuffer device. The framebuffer has
+ * a 32 bpp packed pixel format with full alpha channel support. Depending
+ * on the TV standard configured in the ivtv module at load time, resolution
+ * is fixed at either 720x480 (NTSC) or 720x576 (PAL).
+ *
+ * Copyright (c) 2003 Matt T. Yourst <yourst@yourst.com>
+ *
+ * Derived from drivers/video/vesafb.c
+ * Portions (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ * This file is licensed under the GNU General Public License, version 2.
+ *
+ */
+
+/*
+#
+# Instructions for making ivtv-fb work with XFree86:
+# Add the following sections and parts thereof to /etc/X11/XF86Config:
+#
+
+#
+# NOTE: The monitor section is obtainable by running:
+# fbset -fb /dev/fb1 -x
+# (or /dev/fbX for whatever framebuffer ivtv-fb is on)
+#
+Section "Monitor"
+    Identifier  "NTSC Monitor"
+    HorizSync  30-68
+    VertRefresh 50-120
+    Mode "720x480"
+      # D: 34.563 MHz, H: 37.244 kHz, V: 73.897 Hz
+      DotClock 34.564
+      HTimings 720 752 840 928
+      VTimings 480 484 488 504
+      Flags    "-HSync" "-VSync"
+    EndMode
+EndSection
+
+Section "Device"
+    Identifier  "Hauppauge PVR 350 iTVC15 Framebuffer"
+    Driver      "fbdev"
+    Option      "fbdev" "/dev/fb1"      # <-- modify if using another device
+    BusID "0:10:0"
+EndSection
+
+Section "Screen"
+  Identifier  "TV Screen"
+  Device      "Hauppauge PVR 350 iTVC15 Framebuffer"
+  Monitor     "NTSC Monitor"
+  DefaultDepth 24
+  DefaultFbbpp 32
+  Subsection "Display"
+    Depth 24
+    FbBpp 32
+    Modes "720x480"
+  EndSubsection
+EndSection
+
+Section "ServerLayout"
+  ...
+
+  Screen 0 "Screen 1"                      # << (your computer monitor)
+
+  # (add the following line)
+  Screen 1 "TV Screen" RightOf "Screen 1"  # << (TV screen)
+
+  ...
+EndSection
+
+#
+# Then start X as usual; both your normal (computer) monitor and the
+# NTSC or PAL TV monitor should display the default X background.
+#
+# Note the "RightOf" clause above: if you move the mouse off the right
+# side of the computer screen, the pointer should appear on your TV
+# screen. Keyboard events will go to windows in either screen.
+#
+# To start a program (e.g., xterm) on the TV only:
+#
+# export DISPLAY=:0.1         (i.e., X server #0, screen #1 = TV)
+# xterm&
+#
+# There is also a way to join both the computer monitor and TV into
+# one giant virtual screen using the Xinerama extension, but I haven't 
+# tried it. Doing so may not be such a good idea anyway, as you obviously
+# wouldn't want random X windows getting moved over the TV picture.
+
+
+A note on unloading the fb driver:
+
+If you want to be able to unload the framebuffer driver (and you aren't
+already using fbcon),  add this to your lilo config:
+
+video=vc:x-y
+
+where x is the first fb device to allocate and y is the second. If you 
+already have a fb driver loaded, fiddle with the numbers so all the consoles
+are already allocated. For me, i just set it to 0-0, ie:
+
+in lilo.conf:
+
+image=/vmlinuz
+        label=linux
+        read-only
+        append="root=/dev/hda1 video=vc:0-0"
+
+--OR--
+on bootup, do this
+LILO: linux video=vc:0-0
+
+according to how i read /usr/src/linux/drivers/video/fbmem.c and
+/usr/src/linux/drivers/char/console.c, that should disable the
+console hijacks, and allow you to unload the driver.
+
+-tmk
+#
+#
+#
+#
+#
+#
+#
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/bitops.h>
+#include <linux/pagemap.h>
+
+#include <asm/io.h>
+#include <asm/ioctl.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "ivtv.h"
+
+/*
+ * card parameters
+ */
+
+static int ivtv_fb_card_id;
+
+/* Card selected as framebuffer for this module instance: */
+static struct ivtv *ivtv_fb;
+
+/* card */
+static unsigned long video_base;	/* physical addr */
+static unsigned long video_rel_base;	/* address relative to base of decoder memory */
+static int video_size;
+static char *video_vbase;		/* mapped */
+
+/* mode */
+static int video_width;
+static int video_height;
+static int video_height_virtual;
+static int video_linelength;
+static unsigned long shadow_framebuf_offset;
+static unsigned long shadow_framebuf_size;
+
+/*
+ * ivtv API calls for framebuffer related support
+ */
+
+static inline int ivtv_api_fb_get_framebuffer(struct ivtv *itv,
+					      void **fbbase, int *fblength)
+{
+    u32 data[IVTV_MBOX_MAX_DATA], result;
+    int rc;
+
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_framebuffer\n");
+
+    rc = ivtv_api(itv->dec_mbox, &itv->dec_msem,
+		 IVTV_API_FB_GET_FRAMEBUFFER, &result, 0, &data[0]);
+    *fbbase = (void *) data[0];
+    *fblength = data[1];
+    return rc;
+}
+
+static inline int ivtv_api_fb_get_pixel_format(struct ivtv *itv)
+{
+    u32 data[IVTV_MBOX_MAX_DATA], result;
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_pixel_format\n");
+
+    ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_GET_PIXEL_FORMAT,
+	     &result, 0, &data[0]);
+    return data[0];
+}
+
+static inline int ivtv_api_fb_set_pixel_format(struct ivtv *itv,
+					       int format)
+{
+    u32 data[IVTV_MBOX_MAX_DATA], result;
+    data[0] = format;
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_pixel_format\n");
+
+    ivtv_api(itv->dec_mbox, &itv->dec_msem,
+	     IVTV_API_FB_SET_PIXEL_FORMAT, &result, 1, &data[0]);
+    return result;
+}
+
+static inline int ivtv_api_fb_get_state(struct ivtv *itv)
+{
+    u32 data[IVTV_MBOX_MAX_DATA], result;
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_state\n");
+
+    ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_GET_STATE,
+	     &result, 0, &data[0]);
+    return data[0];
+}
+
+static inline int ivtv_api_fb_set_state(struct ivtv *itv, int enabled)
+{
+    u32 params[IVTV_MBOX_MAX_DATA], result;
+    params[0] = enabled;
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_state\n");
+
+    ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_SET_STATE,
+	     &result, 1, &params[0]);
+    return result;
+}
+
+static inline int ivtv_api_fb_set_framebuffer_window(struct ivtv *itv,
+						     int left, int top,
+						     int width, int height)
+{
+    u32 data[IVTV_MBOX_MAX_DATA], result;
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_framebuffer_window\n");
+    data[0] = width;
+    data[1] = height;
+    data[2] = left;
+    data[3] = top;
+
+    ivtv_api(itv->dec_mbox, &itv->dec_msem,
+	     IVTV_API_FB_SET_FRAMEBUFFER_WINDOW, &result, 4, &data[0]);
+    return result;
+}
+
+static inline int ivtv_api_fb_get_osd_coords(struct ivtv *itv,
+					     struct ivtv_osd_coords *osd)
+{
+    u32 data[IVTV_MBOX_MAX_DATA], result;
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_osd_coords\n");
+
+    ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_GET_OSD_COORDS,
+	     &result, 0, &data[0]);
+
+    osd->offset = data[0] - video_rel_base;
+    osd->max_offset = video_size;
+    osd->pixel_stride = data[1];
+    osd->lines = data[2];
+    osd->x = data[3];
+    osd->y = data[4];
+
+    return result;
+}
+
+static inline int ivtv_api_fb_set_osd_coords(struct ivtv *itv,
+					     const struct ivtv_osd_coords
+					     *osd)
+{
+    u32 data[IVTV_MBOX_MAX_DATA], result;
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_osd_coords\n");
+    data[0] = osd->offset + video_rel_base;
+    data[1] = osd->pixel_stride;
+    data[2] = osd->lines;
+    data[3] = osd->x;
+    data[4] = osd->y;
+
+    // FIXME maybe wait on vsync?
+    ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_SET_OSD_COORDS,
+	     &result, 5, &data[0]);
+    return result;
+}
+
+static inline int ivtv_api_fb_get_screen_coords(struct ivtv *itv,
+						struct rectangle *r)
+{
+    u32 data[IVTV_MBOX_MAX_DATA], result;
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_screen_coords\n");
+
+    ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_GET_SCREEN_COORDS,
+	     &result, 0, &data[0]);
+
+    r->x0 = data[0];
+    r->y0 = data[1];
+    r->x1 = data[2];
+    r->y1 = data[3];
+
+    return result;
+}
+
+static inline int ivtv_api_fb_set_screen_coords(struct ivtv *itv,
+						const struct rectangle *r)
+{
+    u32 data[IVTV_MBOX_MAX_DATA], result;
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_screen_coords\n");
+    data[0] = r->x0;
+    data[1] = r->y0;
+    data[2] = r->x1;
+    data[3] = r->y1;
+
+    ivtv_api(itv->dec_mbox, &itv->dec_msem,
+	     IVTV_API_FB_SET_SCREEN_COORDS, &result, 4, &data[0]);
+    return result;
+}
+
+static inline int ivtv_api_fb_get_global_alpha(struct ivtv *itv)
+{
+    u32 data[IVTV_MBOX_MAX_DATA], result;
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_global_alpha\n");
+
+    ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_GET_GLOBAL_ALPHA,
+	     &result, 0, &data[0]);
+    return data[1];
+}
+
+static inline int ivtv_api_fb_set_global_alpha(struct ivtv *itv,
+					       int enable_global,
+					       int alpha, int enable_local)
+{
+    u32 data[IVTV_MBOX_MAX_DATA], result;
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_global_alpha\n");
+    data[0] = enable_global;
+    data[1] = alpha;
+    data[2] = !enable_local;
+    ivtv_api(itv->dec_mbox, &itv->dec_msem,
+	     IVTV_API_FB_SET_GLOBAL_ALPHA, &result, 3, &data[0]);
+    return result;
+}
+
+static inline int ivtv_api_fb_get_flicker_state(struct ivtv *itv)
+{
+    u32 data[IVTV_MBOX_MAX_DATA], result;
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_flicker_state\n");
+
+    ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_GET_FLICKER_STATE,
+	     &result, 0, &data[0]);
+    return data[0];
+}
+
+static inline int ivtv_api_fb_set_flicker_state(struct ivtv *itv,
+						int enabled)
+{
+    u32 params[IVTV_MBOX_MAX_DATA], result;
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_flicker_state\n");
+    params[0] = enabled;
+
+    ivtv_api(itv->dec_mbox, &itv->dec_msem,
+	     IVTV_API_FB_SET_FLICKER_STATE, &result, 1, &params[0]);
+    return result;
+}
+
+static inline int ivtv_api_fb_blt_fill(struct ivtv *itv, int rasterop,
+				       int alpha_mode, int alpha_mask_mode,
+				       int width, int height, int destmask,
+				       u32 destaddr, int deststride,
+				       u32 value)
+{
+    u32 data[IVTV_MBOX_MAX_DATA], result;
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_blt_fill\n");
+    data[0] = rasterop;
+    data[1] = alpha_mode;
+    data[2] = alpha_mask_mode;
+    data[3] = width;
+    data[4] = height;
+    data[5] = destmask;
+    data[6] = destaddr;
+    data[7] = deststride;
+    data[8] = value;
+
+    ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_BLT_FILL, &result,
+	     9, &data[0]);
+    return result;
+}
+
+static inline int ivtv_api_fb_blt_copy(struct ivtv *itv, int rasterop,
+				       int alpha_mode, int alpha_mask_mode,
+				       int width, int height, int destmask,
+				       u32 destaddr, int deststride,
+				       int sourcestride, int sourceaddr)
+{
+    u32 data[IVTV_MBOX_MAX_DATA], result;
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_blt_copy: width = %d, height = %d, destaddr = %d, deststride = %d, sourcestride = %d, sourceaddr = %d\n",
+	 width, height, destaddr, deststride, sourcestride, sourceaddr);
+
+    data[0] = rasterop;
+    data[1] = alpha_mode;
+    data[2] = alpha_mask_mode;
+    data[3] = width;
+    data[4] = height;
+    data[5] = destmask;
+    data[6] = destaddr;
+    data[7] = deststride;
+    data[8] = sourcestride;
+    data[9] = sourceaddr;
+
+    ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_FB_BLT_COPY, &result,
+	     10, &data[0]);
+    return result;
+}
+
+
+MODULE_PARM(ivtv_fb_card_id, "i");
+MODULE_PARM_DESC(ivtv_fb_card_id,
+		 "ID number of ivtv card to use as framebuffer device (0-2)");
+
+MODULE_LICENSE("GPL");
+
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo ivtvfb_defined = {
+    0, 0, 0, 0,			/* W,H, W, H (virtual) load xres,xres_virtual */
+    0, 0,			/* virtual -> visible no offset */
+    32,				/* depth -> load bits_per_pixel */
+    0,				/* greyscale ? */
+    {0, 0, 0},			/* R */
+    {0, 0, 0},			/* G */
+    {0, 0, 0},			/* B */
+    {0, 0, 0},			/* transparency */
+    0,				/* standard pixel format */
+    FB_ACTIVATE_NOW,
+    -1, -1,
+    0,
+    0L, 0L, 0L, 0L, 0L,
+    0L, 0L, 0,			/* No sync info */
+    FB_VMODE_NONINTERLACED,
+	0,
+    {0, 0, 0, 0, 0}
+};
+
+static struct display disp;
+static struct fb_info fb_info;
+static union {
+    u32 cfb32[16];
+} fbcon_cmap;
+
+#ifdef CONFIG_MTRR
+static int mtrr = 1;		//++MTY
+static unsigned long fb_start_aligned_physaddr;	/* video_base rounded down as required by hardware MTRRs */
+static unsigned long fb_end_aligned_physaddr;	/* video_base rounded up as required by hardware MTRRs */
+#endif
+
+static struct display_switch ivtvfb_sw;
+
+/* --------------------------------------------------------------------- */
+
+static int ivtvfb_update_var(int con, struct fb_info *info)
+{
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_update_var\n");
+    return 0;
+}
+
+static int ivtvfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			  struct fb_info *info)
+{
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_get_fix\n");
+    memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+    strcpy(fix->id, "iTVC15 TV out");
+
+    fix->smem_start = video_base;
+    fix->smem_len = video_size;
+    fix->type = FB_TYPE_PACKED_PIXELS;
+    fix->visual = FB_VISUAL_TRUECOLOR;
+    fix->xpanstep = 0;
+    fix->ypanstep = 0;
+    fix->ywrapstep = 0;
+    fix->line_length = video_linelength;
+    return 0;
+}
+
+static int ivtvfb_get_var(struct fb_var_screeninfo *var, int con,
+			  struct fb_info *info)
+{
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_get_var\n");
+    if (con == -1)
+	{
+		memcpy(var, &ivtvfb_defined, sizeof(struct fb_var_screeninfo));
+	}
+    else
+	{
+		*var = fb_display[con].var;
+	}
+    return 0;
+}
+
+static void ivtvfb_set_disp(int con)
+{
+    struct fb_fix_screeninfo fix;
+    struct display *display;
+    struct display_switch *sw;
+
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_set_disp\n");
+    if (con >= 0)
+	display = &fb_display[con];
+    else
+	display = &disp;	/* used during initialization */
+
+    ivtvfb_get_fix(&fix, con, 0);
+
+    memset(display, 0, sizeof(struct display));
+    display->screen_base = video_vbase;
+    display->visual = fix.visual;
+    display->type = fix.type;
+    display->type_aux = fix.type_aux;
+    display->ypanstep = fix.ypanstep;
+    display->ywrapstep = fix.ywrapstep;
+    display->line_length = fix.line_length;
+    display->next_line = fix.line_length;
+    display->can_soft_blank = 0;
+    display->inverse = 0;
+    ivtvfb_get_var(&display->var, -1, &fb_info);
+
+    sw = &fbcon_cfb32;
+    display->dispsw_data = fbcon_cmap.cfb32;
+    memcpy(&ivtvfb_sw, sw, sizeof(*sw));
+    display->dispsw = &ivtvfb_sw;
+    display->scrollmode = SCROLL_YREDRAW;
+    ivtvfb_sw.bmove = fbcon_redraw_bmove;
+}
+
+static int ivtvfb_set_var(struct fb_var_screeninfo *var, int con,
+			  struct fb_info *info)
+{
+    int first=0;
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_set_var\n");
+    if (con >= 0) first = 1;
+
+    if (var->xres != ivtvfb_defined.xres ||
+	var->yres != ivtvfb_defined.yres ||
+	var->xres_virtual != ivtvfb_defined.xres_virtual ||
+	var->yres_virtual > video_height_virtual ||
+	var->yres_virtual < video_height ||
+	var->xoffset ||
+	var->bits_per_pixel != ivtvfb_defined.bits_per_pixel ||
+	var->nonstd) {
+	if (first) {
+	    printk(KERN_ERR
+		   "ivtvfb does not support changing the video mode\n");
+	    first = 0;
+	}
+	return -EINVAL;
+    }
+
+    if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
+	return 0;
+
+    if (var->yoffset)
+	return -EINVAL;
+    return 0;
+}
+
+/*
+ * ivtv never uses a colormap: it is always straight RGBA 8:8:8:8...
+ */
+static int ivtvfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			   struct fb_info *info)
+{
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_get_cmap\n");
+    return 0;
+}
+
+static int ivtvfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			   struct fb_info *info)
+{
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_set_cmap\n");
+    return 0;
+}
+
+static int ivtv_fb_blt_copy(struct ivtv *itv, int x, int y, int width,
+			    int height, int source_offset,
+			    int source_stride)
+{
+    int rc;
+    unsigned long destaddr = ((y * video_width) + x) * 4;
+
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_fb_blt_copy\n");
+    source_offset += shadow_framebuf_offset;
+
+    rc = ivtv_api_fb_blt_copy(ivtv_fb, 0xa, 0x1, 0x0, width, height,
+			      0xffffffff, destaddr, video_width,
+			      source_stride, source_offset);
+    return rc;
+}
+
+/*
+ * Returns the physical location of the PTE associated with a given virtual address.
+ */
+static inline pte_t *virt_to_pte(struct mm_struct *mm, void *addr)
+{
+    return
+	pte_offset(pmd_offset
+		   (pgd_offset(mm, (unsigned long) addr),
+		    (unsigned long) addr), (unsigned long) addr);
+}
+
+struct ivtvfb_user_dma_to_device ivtvfb_current_fb_dma;
+
+// 4MB max buffer size (on IA32 at least: 1024 pages x 4KB/page = 4MB):
+#define IVTV_MAX_FB_DMA_PAGES 1024
+
+int ivtvfb_alloc_user_dma_to_device(struct ivtvfb_user_dma_to_device *dma)
+{
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_alloc_user_dma_to_device\n");
+    dma->page_count = 0;
+    dma->sglist = kmalloc(sizeof(struct ivtv_SG_element)*IVTV_MAX_FB_DMA_PAGES,
+			  GFP_KERNEL);
+    if (!dma->sglist) {
+	printk(KERN_ERR
+	       "ivtvfb: cannot allocate scatter/gather list for %d pages\n",
+	       IVTV_MAX_FB_DMA_PAGES);
+	return -ENOMEM;
+    }
+
+    dma->map = kmalloc(sizeof(struct page *) * IVTV_MAX_FB_DMA_PAGES, GFP_KERNEL);
+    if (!dma->map) {
+	IVTV_DEBUG_FB(IVTV_DEBUG_ERR, "can't alloc dma page array\n");
+	kfree(dma->sglist);
+	return -ENOMEM;
+    }
+
+    dma->sg_dma_handle =
+	pci_map_single(ivtv_fb->dev, (void *) dma->sglist,
+		       (sizeof(struct ivtv_SG_element) *
+			IVTV_MAX_FB_DMA_PAGES), PCI_DMA_TODEVICE);
+
+    return 0;
+}
+
+//++MTY This is pretty fast - fast enough to do around 30+ frames per second at NTSC 720x480x4 or 27 frames per second at PAL 720x576x4
+int ivtvfb_prep_user_dma_to_device(struct ivtvfb_user_dma_to_device *dma,
+				   unsigned long ivtv_dest_addr,
+				   char *userbuf, int size_in_bytes)
+{
+    int i, offset;
+    unsigned long uaddr;
+    int size_in_pages = (size_in_bytes + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+
+    IVTV_DEBUG_FB(IVTV_DEBUG_DMA, "ivtvfb_prep_user_dma_to_device, dst: 0x%08x\n",
+		    (unsigned int) ivtv_dest_addr);
+
+    uaddr = ((unsigned long) userbuf & PAGE_MASK);
+    offset = uaddr & ~PAGE_MASK;
+
+    down_read(&current->mm->mmap_sem);
+    size_in_pages = get_user_pages(current, current->mm, uaddr, size_in_pages, 0, 0, dma->map, NULL);
+    up_read(&current->mm->mmap_sem);
+
+    if (size_in_pages < 0) {
+	IVTV_DEBUG_FB(IVTV_DEBUG_ERR, "failed to map user pages\n");
+	return size_in_pages;
+    }
+
+    dma->page_count = size_in_pages;
+    for (i = 0; i < size_in_pages; i++) {
+	dma->sglist[i].size = PAGE_SIZE;
+	dma->sglist[i].src = pci_map_page(ivtv_fb->dev, dma->map[i], 0, offset, PCI_DMA_TODEVICE);
+	dma->sglist[i].dst = ivtv_dest_addr + i * PAGE_SIZE + offset;
+	offset = 0;
+    }
+
+    // Indicate the last element to the hardware, so we get an interrupt on completion...
+    dma->sglist[size_in_pages - 1].size |= 0x80000000;
+
+#ifdef IVTVFB_DEBUG_PER_FRAME
+    printk(KERN_INFO
+	   "ivtvfb: Allocated scatter/gather list of %d bytes (%d pages) at kva 0x%08x = physaddr 0x%08x:\n",
+	   size_in_bytes, size_in_pages, dma->sglist, dma->sg_dma_handle);
+    for (i = 0; i < size_in_pages; i++) {
+	printk(KERN_INFO
+	       "ivtvfb:   [%d] src 0x%08x -> dest 0x%08x, size 0x%08x bytes\n",
+	       i, dma->sglist[i].src, dma->sglist[i].dst,
+	       dma->sglist[i].size);
+    }
+#endif
+
+    return 0;
+}
+
+int ivtvfb_free_user_dma_to_device(struct ivtvfb_user_dma_to_device *dma)
+{
+    int i;
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_free_user_dma_to_device\n");
+
+    for (i = 0; i < dma->page_count; i++) {
+	pci_unmap_page(ivtv_fb->dev, dma->sglist[i].src, PAGE_SIZE, PCI_DMA_TODEVICE);
+	page_cache_release(dma->map[i]);
+    }
+    kfree(dma->sglist);
+    kfree(dma->map);
+    dma->page_count = 0;
+    return 0;
+}
+
+int ivtvfb_execute_user_dma_to_device(struct ivtvfb_user_dma_to_device
+				      *dma)
+{
+    u32 data[IVTV_MBOX_MAX_DATA], result;
+    int rc;
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_execute_user_dma_to_device\n");
+
+    data[0] = dma->sg_dma_handle;
+    data[1] = dma->page_count;
+    data[2] = 0x1;		// 0x1 = OSD data
+
+    IVTV_DEBUG_FB(IVTV_DEBUG_DMA, "Schedule FB DMA: physical address 0x%08x, "
+	   "arraysize 0x%08x, type 0x%08x\n", data[0], data[1], data[2]);
+
+    // Enable DMA complete interrupt:
+    ivtv_clear_irq_mask(ivtv_fb, IVTV_IRQ_DEC_DMA_COMPLETE);
+
+    set_bit(IVTV_F_I_OSD_DMA, &ivtv_fb->i_flags);
+
+    rc = ivtv_api(ivtv_fb->dec_mbox, &ivtv_fb->dec_msem, 
+		  IVTV_API_DEC_DMA_FROM_HOST, &result, 3, &data[0]);
+
+    if (rc) {
+	IVTV_DEBUG_FB(IVTV_DEBUG_ERR, "error sending DMA info\n");
+	clear_bit(IVTV_F_I_BUSY, &ivtv_fb->i_flags);
+    }
+
+    IVTV_DEBUG_FB(IVTV_DEBUG_DMA, "OK, scheduled FB DMA!");
+    return 0;
+}
+
+static inline int ivtv_fb_prep_frame(struct ivtv *itv,
+				     unsigned long destaddr, void *srcaddr,
+				     int count)
+{
+    DECLARE_WAITQUEUE(wait, current);
+    int rc;
+
+    //if (!srcaddr || verify_area(...)) ...
+    if ((destaddr + count) > video_size)
+	return -E2BIG;
+
+    rc = 0;
+    add_wait_queue(&ivtv_fb->dec_master_w, &wait);
+    do {
+	set_current_state(TASK_INTERRUPTIBLE);
+	/* FIXME mini-race still .. need to port to 'stream' format */
+	if (!test_and_set_bit(IVTV_F_I_BUSY, &ivtv_fb->i_flags))
+	    break;
+
+	schedule();
+
+	if (signal_pending(current))
+	    rc = -ERESTARTSYS;
+    } while (!rc);
+    set_current_state(TASK_RUNNING);
+    remove_wait_queue(&ivtv_fb->dec_master_w, &wait);
+
+    if (rc)
+	goto out_dma_lock;
+
+    destaddr = IVTV_DEC_MEM_START + video_rel_base + destaddr;
+
+    if (0 != (rc = ivtvfb_prep_user_dma_to_device(&ivtvfb_current_fb_dma, destaddr,
+					(char *) srcaddr, count)))
+    {
+	IVTV_DEBUG_FB(IVTV_DEBUG_DMA, "err prep user dma to device=%x\n",rc);
+	goto out_dma_lock;
+    }
+    if (0 != (rc = ivtvfb_execute_user_dma_to_device(&ivtvfb_current_fb_dma)))
+    {
+	IVTV_DEBUG_FB(IVTV_DEBUG_DMA, "err exec user dma to device=%x\n",rc);
+	goto out_dma_lock;
+    }
+
+    return 0;
+out_dma_lock:
+    clear_bit(IVTV_F_I_BUSY, &ivtv_fb->i_flags);
+    wake_up(&ivtv_fb->dec_master_w);
+    return rc;
+}
+
+int ivtv_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		  unsigned long arg, int con, struct fb_info *info)
+{
+
+    int rc;
+
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_fb_ioctl\n");
+    switch (cmd) {
+    case 0x7777:{
+	    while (MOD_IN_USE) MOD_DEC_USE_COUNT;
+	    MOD_INC_USE_COUNT;
+	    return 0;
+    }
+    case IVTVFB_IOCTL_GET_STATE:{
+	    struct ivtvfb_ioctl_state_info state;
+	    state.status = (ivtv_api_fb_get_state(ivtv_fb) & 0x7);
+	    state.status |= (ivtv_api_fb_get_flicker_state(ivtv_fb) << 3);
+	    state.alpha = ivtv_api_fb_get_global_alpha(ivtv_fb);
+	    IVTV_DEBUG_FB(IVTV_DEBUG_IOCTL, "IVTVFB_IOCTL_GET_STATE: status = %lu, alpha = %lu\n",
+		 state.status, state.alpha);
+	    if (copy_to_user((void *) arg, &state, sizeof(state)))
+		return -EFAULT;
+	    return 0;
+	}
+    case IVTVFB_IOCTL_SET_STATE:{
+	    struct ivtvfb_ioctl_state_info state;
+	    if (copy_from_user(&state, (void *) arg, sizeof(state)))
+		return -EFAULT;
+	    IVTV_DEBUG_FB(IVTV_DEBUG_IOCTL, "IVTVFB_IOCTL_SET_STATE: status = %lu, alpha = %lu\n",
+		 state.status, state.alpha);
+	    ivtv_api_fb_set_state(ivtv_fb,
+				  (state.status && IVTVFB_STATUS_ENABLED));
+	    ivtv_api_fb_set_global_alpha(ivtv_fb,
+					 (state.
+					  status &
+					  IVTVFB_STATUS_GLOBAL_ALPHA) ? 1 :
+					 0, state.alpha,
+					 (state.
+					  status &
+					  IVTVFB_STATUS_LOCAL_ALPHA) ? 1 :
+					 0);
+	    ivtv_api_fb_set_flicker_state(ivtv_fb,
+					  (state.
+					   status &
+					   IVTVFB_STATUS_FLICKER_REDUCTION)
+					  ? 1 : 0);
+	    IVTV_DEBUG_FB(IVTV_DEBUG_IOCTL, "new state = %d\n",
+		   ivtv_api_fb_get_state(ivtv_fb));
+	    IVTV_DEBUG_FB(IVTV_DEBUG_IOCTL, "global alpha now = %d\n",
+		   ivtv_api_fb_get_global_alpha(ivtv_fb));
+	    return 0;
+	}
+    case IVTVFB_IOCTL_PREP_FRAME:{
+	    struct ivtvfb_ioctl_dma_host_to_ivtv_args args;
+	    if (copy_from_user(&args, (void *) arg, sizeof(args)))
+		return -EFAULT;
+	    return ivtv_fb_prep_frame(ivtv_fb, args.dest_offset,
+				      args.source, args.count);
+	}
+    case IVTVFB_IOCTL_BLT_COPY:{
+	    struct ivtvfb_ioctl_blt_copy_args args;
+	    if (copy_from_user(&args, (void *) arg, sizeof(args)))
+		return -EFAULT;
+
+	    return ivtv_fb_blt_copy(ivtv_fb, args.x, args.y, args.width,
+				    args.height, args.source_stride,
+				    args.source_offset);
+	}
+    case IVTVFB_IOCTL_GET_ACTIVE_BUFFER:{
+	    struct ivtv_osd_coords bufinfo;
+	    rc = ivtv_api_fb_get_osd_coords(ivtv_fb, &bufinfo);
+	    return copy_to_user((void *) arg, &bufinfo, sizeof(bufinfo));
+	}
+    case IVTVFB_IOCTL_SET_ACTIVE_BUFFER:{
+	    struct ivtv_osd_coords bufinfo;
+	    if (copy_from_user(&bufinfo, (void *) arg, sizeof(bufinfo)))
+		return -EFAULT;
+	    return ivtv_api_fb_set_osd_coords(ivtv_fb, &bufinfo);
+	}
+    case IVTVFB_IOCTL_GET_FRAME_BUFFER:{
+	    struct ivtvfb_ioctl_get_frame_buffer getfb;
+	    getfb.mem  = (void *)video_vbase;
+	    getfb.bytes =  video_size;
+	    getfb.sizex =  video_width;
+	    getfb.sizey =  video_height;
+
+	    return copy_to_user((void *) arg, &getfb, sizeof(getfb));
+	}
+    default:
+	return -EINVAL;
+    }
+    return 0;
+}
+
+static struct fb_ops ivtvfb_ops = {
+    owner:THIS_MODULE,
+    fb_get_fix:ivtvfb_get_fix,
+    fb_get_var:ivtvfb_get_var,
+    fb_set_var:ivtvfb_set_var,
+    fb_get_cmap:ivtvfb_get_cmap,
+    fb_set_cmap:ivtvfb_set_cmap,
+    fb_ioctl:ivtv_fb_ioctl,
+    fb_pan_display:NULL,
+};
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static void ivtvfb_blank(int blank, struct fb_info *info)
+{
+    /* Not supported */
+}
+
+int __init ivtvfb_init(void)
+{
+    int rc;
+    u32 fbbase;
+    u32 fblength;
+    struct ivtv_osd_coords osd;
+    struct rectangle rect;
+
+    if ((ivtv_fb_card_id < 0) || (ivtv_fb_card_id >= ivtv_cards_active)) {
+	printk(KERN_ERR
+	       "Error! ivtv-fb: ivtv_fb_card_id parameter is out of range (valid range: 0-%d)\n",
+	       ivtv_cards_active - 1);
+	return -1;
+    }
+
+    ivtv_fb = &ivtv_cards[ivtv_fb_card_id];
+    if (!ivtv_fb || (ivtv_fb->card_type != IVTV_350_V1)) {
+	printk(KERN_ERR
+	       "Error! ivtv-fb: Specified card (id %d) is either not present or does not support TV out (PVR350 only)\n",
+	       ivtv_fb_card_id);
+	return -1;
+    }
+
+    printk(KERN_INFO
+	   "ivtv-fb: Framebuffer module loaded (attached to ivtv card id %d)\n",
+	   ivtv_fb_card_id);
+
+    rc = ivtv_api_fb_set_pixel_format(ivtv_fb, 4);	// 4 = AlphaRGB 8:8:8:8
+
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "Current pixel format = %d\n",
+	   ivtv_api_fb_get_pixel_format(ivtv_fb));
+
+    rc = ivtv_api_fb_get_framebuffer(ivtv_fb, (void **) &fbbase,
+				     &fblength);
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "Framebuffer is at decoder-relative address 0x%08x and has %d bytes.\n",
+	   fbbase, fblength);
+
+    rc = ivtv_api_fb_get_osd_coords(ivtv_fb, &osd);
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "OSD: offset = 0x%08x (max offset = 0x%08x), pixel_stride = %d, lines = %d, x = %d, y = %d\n",
+	   (u32)osd.offset, (u32)osd.max_offset, osd.pixel_stride, osd.lines, osd.x,
+	   osd.y);
+
+    /* setup OSD and screen for PAL */
+    if (ivtv_pal) {
+    	osd.lines = 576;
+    	rc = ivtv_api_fb_set_osd_coords(ivtv_fb, &osd);
+	if (rc)
+	    IVTV_DEBUG_FB(IVTV_DEBUG_ERR, "failed setting PAL osd\n");
+
+	rect.x0 = 0;
+	rect.x1 = 720;
+	rect.y0 = 0;
+	rect.y1 = 576;
+	rc = ivtv_api_fb_set_screen_coords(ivtv_fb, &rect);
+	if (rc)
+	    IVTV_DEBUG_FB(IVTV_DEBUG_ERR, "failed setting PAL screen\n");
+    }
+
+     rc = ivtv_api_fb_get_screen_coords(ivtv_fb, &rect);
+     printk(KERN_INFO "ivtv-fb: screen coords: [%d %d] -> [%d %d]\n",
+	   rect.x0, rect.y0, rect.x1, rect.y1);
+
+    printk(KERN_INFO "ivtv-fb: original global alpha = %d\n",
+	   ivtv_api_fb_get_global_alpha(ivtv_fb));
+
+    /*
+     * Normally a 32-bit RGBA framebuffer would be fine, however XFree86's fbdev 
+     * driver doesn't understand the concept of alpha channel and always sets
+     * bits 24-31 to zero when using a 24bpp-on-32bpp framebuffer device. We fix
+     * this behavior by enabling the iTVC15's global alpha feature, which causes 
+     * the chip to ignore the per-pixel alpha data and instead use one value (e.g.,
+     * full brightness = 255) for the entire framebuffer. The local alpha is also
+     * disabled in this step.
+     *
+     *++MTY Need to update http://ivtv.sourceforge.net/ivtv/firmware-api.html 
+     *      call 0x4b: param[2] says 1 = enable local alpha, when in reality
+     *      it means *disable* local alpha...
+     *      
+     */
+    ivtv_api_fb_set_global_alpha(ivtv_fb, 1, 255, 0);
+    printk(KERN_INFO "ivtv-fb: new global alpha = %d\n",
+	   ivtv_api_fb_get_global_alpha(ivtv_fb));
+
+    rc = ivtv_api_fb_set_state(ivtv_fb, 1);	// 1 = enabled
+    printk(KERN_INFO "ivtv-fb: current OSD state = %d\n",
+	   ivtv_api_fb_get_state(ivtv_fb));
+
+    video_rel_base = fbbase;
+    video_base = ivtv_fb->base_addr + IVTV_DEC_MEM_START + video_rel_base;
+    video_width = rect.x1 - rect.x0;
+    video_height = rect.y1 - rect.y0;
+    video_linelength = 4 * osd.pixel_stride;
+    video_size = fblength;
+
+    shadow_framebuf_size = (video_width * video_height * 4);
+    shadow_framebuf_offset = (video_size - shadow_framebuf_size) & ~3;
+
+    if (!request_mem_region(video_base, video_size, "ivtvfb")) {
+	printk(KERN_WARNING
+	       "ivtv-fb: warning: cannot reserve video memory at 0x%lx\n",
+	       video_base);
+	/* We cannot make this fatal. Sometimes this comes from magic spaces our resource handlers simply don't know about */
+    }
+
+    video_vbase = ioremap(video_base, video_size);
+    if (!video_vbase) {
+	release_mem_region(video_base, video_size);
+	printk(KERN_ERR
+	       "ivtv-fb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n",
+	       video_size, video_base);
+	return -EIO;
+    }
+
+    printk(KERN_INFO
+	   "ivtv-fb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
+	   video_base, video_vbase, video_size / 1024);
+    printk(KERN_INFO "ivtv-fb: mode is %dx%dx%d, linelength=%d\n",
+	   video_width, video_height, 32, video_linelength);
+
+    ivtvfb_defined.xres = video_width;
+    ivtvfb_defined.yres = video_height;
+    ivtvfb_defined.xres_virtual = video_width;
+    ivtvfb_defined.yres_virtual = video_height;
+    ivtvfb_defined.bits_per_pixel = 32;
+    video_height_virtual = ivtvfb_defined.yres_virtual;
+
+    /* some dummy values for timing to make fbset happy */
+    ivtvfb_defined.pixclock = 10000000 / video_width * 1000 / video_height;
+    ivtvfb_defined.left_margin = (video_width / 8) & 0xf8;
+    ivtvfb_defined.right_margin = 32;
+    ivtvfb_defined.upper_margin = 16;
+    ivtvfb_defined.lower_margin = 4;
+    ivtvfb_defined.hsync_len = (video_width / 8) & 0xf8;
+    ivtvfb_defined.vsync_len = 4;
+
+    ivtvfb_defined.red.offset = 0;
+    ivtvfb_defined.red.length = 8;
+    ivtvfb_defined.green.offset = 8;
+    ivtvfb_defined.green.length = 8;
+    ivtvfb_defined.blue.offset = 16;
+    ivtvfb_defined.blue.length = 8;
+    ivtvfb_defined.transp.offset = 24;
+    ivtvfb_defined.transp.length = 8;
+
+#ifdef CONFIG_MTRR
+    if (mtrr) {
+	/* Find the largest power of two that maps the whole buffer */
+	int size_shift = 31;
+	while (!(video_size & (1 << size_shift))) {
+	    size_shift--;
+	}
+	size_shift++;
+
+	fb_start_aligned_physaddr = video_base & ~((1 << size_shift) - 1);
+	fb_end_aligned_physaddr =
+	    (video_base + (1 << size_shift) - 1) & ~((1 << size_shift) -
+						     1);
+	if (mtrr_add
+	    (fb_start_aligned_physaddr,
+	     (fb_end_aligned_physaddr - fb_start_aligned_physaddr),
+	     MTRR_TYPE_WRCOMB, 1) < 0) {
+	    printk(KERN_WARNING
+		   "ivtv-fb: warning: mtrr_add() failed to add write combining region 0x%08x-0x%08x\n",
+		   (unsigned int) fb_start_aligned_physaddr,
+		   (unsigned int) fb_end_aligned_physaddr);
+	}
+    }
+#endif
+
+    strcpy(fb_info.modename, "iTVC15 TV out");
+    fb_info.fontname[0] = '\0';
+    fb_info.changevar = NULL;
+    fb_info.node = -1;
+    fb_info.fbops = &ivtvfb_ops;
+    fb_info.disp = &disp;
+    fb_info.switch_con = NULL;	//&ivtvfb_switch; (fbcon will ignore it then)
+    fb_info.updatevar = &ivtvfb_update_var;
+    fb_info.blank = &ivtvfb_blank;
+    fb_info.flags = FBINFO_FLAG_DEFAULT;
+    ivtvfb_set_disp(-1);
+
+    if (register_framebuffer(&fb_info) < 0)
+	return -EINVAL;
+
+    ivtv_fb->fb_id = GET_FB_IDX(fb_info.node);
+
+    printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	   ivtv_fb->fb_id, fb_info.modename);
+
+    /* Set up DMA and BLT copy structures */
+    ivtvfb_alloc_user_dma_to_device(&ivtvfb_current_fb_dma);
+    ivtv_fb->user_dma_to_device_state = &ivtvfb_current_fb_dma;
+    return 0;
+}
+
+
+static void ivtvfb_cleanup(void)
+{
+    IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "Unloading framebuffer module\n");
+    unregister_framebuffer(&fb_info);
+    iounmap(video_vbase);
+#ifdef CONFIG_MTRR
+    mtrr_del(-1, fb_start_aligned_physaddr,
+	     (fb_end_aligned_physaddr - fb_start_aligned_physaddr));
+#endif
+    ivtv_fb->user_dma_to_device_state = NULL;
+    ivtvfb_free_user_dma_to_device(&ivtvfb_current_fb_dma);
+    ivtv_fb->fb_id = -1;
+    //release_mem_region(video_base, video_size);
+}
+
+module_init(ivtvfb_init);
+module_exit(ivtvfb_cleanup);
diff -aurpN -X /home/fletch/.diff.exclude 670-tiocgdev/drivers/media/video/ivtv-i2c.c 680-ia64_dec_and_lock/drivers/media/video/ivtv-i2c.c
--- 670-tiocgdev/drivers/media/video/ivtv-i2c.c	Wed Dec 31 16:00:00 1969
+++ 680-ia64_dec_and_lock/drivers/media/video/ivtv-i2c.c	Wed Feb 11 10:17:11 2004
@@ -0,0 +1,211 @@
+#include "ivtv.h"
+
+/* i2c implementation for iTVC15 chip, ivtv project.
+ * Author: Kevin Thayer (nufan_wfk at yahoo.com)
+ * License: GPL
+ * http://www.sourceforge.net/projects/ivtv/
+ */
+
+
+/* moved here from ivtv.h */
+static int writeregs(struct i2c_client *client, const unsigned char *regs);
+static int attach_inform(struct i2c_client *client);
+static int detach_inform(struct i2c_client *client);
+
+int writereg(struct i2c_client *client,
+                    unsigned char reg, unsigned char data)
+{
+        int ret;
+        unsigned char msg[] = {0x1f, 0x00};
+
+        printk("<1>writing reg 0x%02x, data 0x%02x\n", reg,data);
+
+        msg[0]=reg; msg[1]=data;
+        ret=i2c_master_send(client, msg, 2);
+        if (ret!=2)
+                printk("writereg error\n");
+        return ret;
+}
+
+static int writeregs(struct i2c_client *client, const unsigned char *regs)
+{
+        unsigned char reg, data;
+
+        while (*regs!=0x00) {
+                reg =*(regs++);
+                data=*(regs++);
+                if (writereg(client, reg, data)<0)
+                        return -1;
+        }
+        return 0;
+}
+
+static struct i2c_adapter ivtv_i2c_adapter_template = {
+	.owner = THIS_MODULE,
+
+	.id= I2C_HW_B_BT848,		/*id?? (algo-bit is OR'd with this)*/
+        .class = I2C_ADAP_CLASS_TV_ANALOG,
+	.algo = NULL,		/*set by i2c-algo-bit*/
+	.algo_data = NULL, 	/*filled from template*/
+	.client_register =	attach_inform,
+	.client_unregister =	detach_inform,
+	I2C_DEVNAME("ivtv i2c driver"),
+};
+
+static struct i2c_algo_bit_data ivtv_i2c_algo_template = {
+	NULL,		/*??*/
+	ivtv_setsda,	/*setsda function*/
+	ivtv_setscl,	/*"*/
+	ivtv_getsda,	/*"*/
+	ivtv_getscl,	/*"*/
+	5,		/*udelay or mdelay*/
+       	5, 		/*whatever above isn't*/
+	200		/*timeout*/
+};
+
+void ivtv_setscl(void *data, int state) {
+	struct ivtv *itv = (struct ivtv *)data;
+
+	if (state) 
+		itv->i2c_state |= 0x01;
+	else
+		itv->i2c_state &= ~0x01;
+
+	/* write them out */
+	/* write bits are inverted */
+	writel(~itv->i2c_state,(itv->reg_mem + IVTV_REG_I2C_SETSCL_OFFSET));
+}
+
+void ivtv_setsda(void *data, int state) {
+	struct ivtv *itv = (struct ivtv *)data;
+
+	if (state) 
+		itv->i2c_state |= 0x01;
+	else
+		itv->i2c_state &= ~0x01;
+
+	/* write them out */
+	/* write bits are inverted */
+	writel(~itv->i2c_state,(itv->reg_mem + IVTV_REG_I2C_SETSDA_OFFSET));
+}
+
+int ivtv_getscl(void *data) {
+	struct ivtv *itv = (struct ivtv *)data;
+	return readb(itv->reg_mem + IVTV_REG_I2C_GETSCL_OFFSET);
+}
+
+int ivtv_getsda(void *data) {
+	struct ivtv *itv = (struct ivtv *)data;
+	return readb(itv->reg_mem + IVTV_REG_I2C_GETSDA_OFFSET);
+}
+
+static struct i2c_client ivtv_i2c_client_template = {
+	.id =   -1,
+	I2C_DEVNAME("ivtv internal use only")
+};
+
+static int attach_inform(struct i2c_client *client) {
+	struct ivtv *itv = (struct ivtv*) i2c_get_adapdata(client->adapter);
+        int i; 
+
+	IVTV_DEBUG(IVTV_DEBUG_I2C, "i2c client attach\n");
+        for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+		if (itv->i2c_clients[i] == NULL) {
+			itv->i2c_clients[i] = client;
+			break;
+		}
+	}
+	IVTV_DEBUG(IVTV_DEBUG_I2C, "i2c attach [client=%s,%s]\n",
+		client->name, (i < I2C_CLIENTS_MAX) ?  "ok" : "failed");
+
+	return 0;
+}
+
+static int detach_inform(struct i2c_client *client) {
+	struct ivtv *itv = (struct ivtv*) i2c_get_adapdata(client->adapter);
+        int i; 
+
+	IVTV_DEBUG(IVTV_DEBUG_I2C, "i2c client detach\n");
+        for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+		if (itv->i2c_clients[i] == client) {
+			itv->i2c_clients[i] = NULL;
+			break;
+		}
+	}
+	IVTV_DEBUG(IVTV_DEBUG_I2C, "i2c detach [client=%s,%s]\n",
+		client->name, (i < I2C_CLIENTS_MAX) ?  "ok" : "failed");
+
+	return 0;
+}
+
+
+void ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg) {
+        int i;
+
+	IVTV_DEBUG(IVTV_DEBUG_I2C, "call_i2c_client\n");
+        for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+                if (NULL == itv->i2c_clients[i])
+                        continue;
+                if (NULL == itv->i2c_clients[i]->driver->command)
+                        continue;
+                if (addr == itv->i2c_clients[i]->addr) {
+                	itv->i2c_clients[i]->driver->command(
+                        	itv->i2c_clients[i],cmd,arg);
+			return;
+		}
+        }
+	IVTV_DEBUG(IVTV_DEBUG_ERR, "i2c client addr: 0x%02x not found!\n",addr);
+}
+
+int ivtv_i2c_direct(struct ivtv *itv, int addr, const unsigned char *regs) {
+        int i, ret=0;
+
+	IVTV_DEBUG(IVTV_DEBUG_I2C, "i2c_direct\n");
+        for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+                if (NULL == itv->i2c_clients[i])
+                        continue;
+                if (addr == itv->i2c_clients[i]->addr) {
+			ret = writeregs(itv->i2c_clients[i], regs);
+			break;
+		}
+        }
+
+	if (ret) {
+		IVTV_DEBUG(IVTV_DEBUG_ERR, "error %d writing reg\n", ret);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/* init + register i2c algo-bit adapter */
+int __devinit init_ivtv_i2c(struct ivtv *itv) {
+	IVTV_DEBUG(IVTV_DEBUG_I2C, "i2c init\n");
+	memcpy(&itv->i2c_adap, &ivtv_i2c_adapter_template,
+               sizeof(struct i2c_adapter));
+        memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template,
+               sizeof(struct i2c_algo_bit_data));
+        memcpy(&itv->i2c_client, &ivtv_i2c_client_template,
+               sizeof(struct i2c_client));
+
+        sprintf(itv->i2c_adap.name+strlen(itv->i2c_adap.name),
+                " #%d", itv->num);
+        itv->i2c_algo.data = itv;
+        i2c_set_adapdata(&itv->i2c_adap, itv);
+        itv->i2c_adap.algo_data = &itv->i2c_algo;
+        itv->i2c_client.adapter = &itv->i2c_adap;
+
+	IVTV_DEBUG(IVTV_DEBUG_I2C, "setting scl and sda to 1\n");
+        ivtv_setscl(itv,1);
+        ivtv_setsda(itv,1);
+
+        itv->i2c_rc = i2c_bit_add_bus(&itv->i2c_adap);
+        return itv->i2c_rc;
+}
+
+void __devexit exit_ivtv_i2c(struct ivtv *itv) {
+	IVTV_DEBUG(IVTV_DEBUG_I2C, "i2c exit\n");
+
+	i2c_bit_del_bus(&itv->i2c_adap);
+}
+
diff -aurpN -X /home/fletch/.diff.exclude 670-tiocgdev/drivers/media/video/ivtv.h 680-ia64_dec_and_lock/drivers/media/video/ivtv.h
--- 670-tiocgdev/drivers/media/video/ivtv.h	Wed Dec 31 16:00:00 1969
+++ 680-ia64_dec_and_lock/drivers/media/video/ivtv.h	Wed Feb 11 10:17:11 2004
@@ -0,0 +1,847 @@
+#ifndef IVTV_H
+#define IVTV_H
+
+/* Header for ivtv project:
+ * Driver for the iTVC15 chip.
+ * Author: Kevin Thayer (nufan_wfk at yahoo.com)
+ * License: GPL
+ * http://www.sourceforge.net/projects/ivtv/
+ */
+
+#include <config/modversions.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/video_decoder.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/list.h>
+#include <linux/unistd.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <asm/system.h>
+#include "msp3400.h"
+/* If you don't want to patch to v4l2, grab a copy of
+ * videodev2.h and put it in the same dir as this file */ 
+#ifndef HAVE_V4L2
+ #define HAVE_V4L2 1 
+ #include "videodev2.h"
+#endif
+#include <linux/i2c-algo-bit.h>
+#include <linux/byteorder/swab.h>
+#include <media/tuner.h>
+
+#ifndef CONFIG_PCI
+#  error "This driver requires kernel PCI support."
+#endif
+
+#define IVTV_ENCODER_OFFSET	0x00000000
+#define IVTV_ENCODER_SIZE	0x01000000
+
+#define IVTV_DECODER_OFFSET	0x01000000
+#define IVTV_DECODER_SIZE	0x01000000
+
+#define IVTV_ENCDEC_SIZE	(IVTV_ENCODER_SIZE + IVTV_DECODER_SIZE)
+
+#define IVTV_REG_OFFSET 	0x02000000
+#define IVTV_REG_SIZE		0x00010000
+
+#define IVTV_IOREMAP_SIZE	(IVTV_ENCDEC_SIZE + IVTV_REG_SIZE)
+
+#define IVTV_IOREMAP_ERROR	"ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h " \
+				"or disabling CONFIG_HIMEM4G into the kernel would help"
+
+/* General */
+#define IVTV_DRIVER_NAME "ivtv"
+#define IVTV_DRIVER_VERSION_MAJOR 0
+#define IVTV_DRIVER_VERSION_MINOR 1
+#define IVTV_DRIVER_VERSION_PATCHLEVEL 8
+#define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL)
+#define IVTV_MAX_CARDS 9
+#define IVTV_DEFAULT_NUM_CARDS 1
+#define IVTV_MAX_YUV_BUFFERS 500
+#define IVTV_MIN_YUV_BUFFERS 40
+#define IVTV_DEFAULT_YUV_BUFFERS 60
+#define IVTV_MAX_MPG_BUFFERS 100
+#define IVTV_MIN_MPG_BUFFERS 15
+#define IVTV_DEFAULT_MPG_BUFFERS IVTV_MAX_MPG_BUFFERS
+#define IVTV_MAX_DEC_YUV_BUFFERS 500
+#define IVTV_MIN_DEC_YUV_BUFFERS 17
+#define IVTV_DEFAULT_DEC_YUV_BUFFERS 0
+#define IVTV_MAX_DEC_MPG_BUFFERS 100
+#define IVTV_MIN_DEC_MPG_BUFFERS 5
+#define IVTV_DEFAULT_DEC_MPG_BUFFERS 8
+#define IVTV_MAX_VBI_BUFFERS 100
+#define IVTV_MIN_VBI_BUFFERS 3
+#define IVTV_DEFAULT_VBI_BUFFERS 10
+#define IVTV_MIN_DEC_MPG_QLEN 0
+#define IVTV_DEFAULT_DEC_MPG_QLEN 2
+#define IVTV_MIN_DEC_YUV_QLEN 0
+#define IVTV_DEFAULT_DEC_YUV_QLEN 0
+#define IVTV_IOCTL_SET_DEBUG_LEVEL _IOWR('@', 98, int *)
+#define IVTV_IOCTL_GET_DEBUG_LEVEL _IOR('@', 99, int *)
+
+#define IVTV_PCI_ID_250_V1 0x4001 /* subsystem id */
+#define IVTV_PCI_ID_250_V2 0x4009
+#define IVTV_PCI_ID_250_V3 0x4801 /* treat like 250_V1 */
+#define IVTV_PCI_ID_250_V4 0x4803 /* treat like 250_V2 */
+#define IVTV_PCI_ID_350_V1 0x4000
+#define IVTV_PCI_ID_350_V2 0x4800 /* treat like 350_V1 */
+#define IVTV_250_V1 0 /* wintv pvr 250, encoder and decoder */
+#define IVTV_250_V2 1 /* pvr 250, encoder only */
+#define IVTV_350_V1 2 /* encoder, decoder, tv-out */
+#define IVTV_250_V1_STREAMS 3
+#define IVTV_250_V2_STREAMS 3
+#define IVTV_350_V1_STREAMS 5
+#define IVTV_V4L2_DEC_OFFSET 16 /* offset from 0 to register dec. v4l2 minors on */
+#define IVTV_V4L2_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */
+
+#define IVTV_ENC_STREAM_TYPE_MPG 0
+#define IVTV_ENC_STREAM_TYPE_YUV 1
+#define IVTV_ENC_STREAM_TYPE_VBI 2
+#define IVTV_DEC_STREAM_TYPE_MPG 3
+#define IVTV_DEC_STREAM_TYPE_YUV 4
+
+#define IVTV_ENC_MEM_START 0x00000000
+#define IVTV_DEC_MEM_START 0x01000000
+#define PCI_VENDOR_ID_ICOMP  0x4444
+#define PCI_DEVICE_ID_IVTV15 0x0803
+#define PCI_DEVICE_ID_IVTV16 0x0016
+#define IVTV_DEVNAME "ivtv: iTVC15/16 mpg2 encoder chip"
+#define IVTV_MBOX_MAX_BOXES 20
+#define IVTV_MBOX_API_BOXES 6
+#define IVTV_MBOX_DMA_START 6
+#define IVTV_MBOX_DMA_END 8
+#define IVTV_MBOX_MAX_DATA 16
+#define IVTV_MBOX_DMA 9
+#define IVTV_MBOX_FIELD_DISPLAYED 8
+#define IVTV_MBOX_SIZE 80
+#define IVTV_SAA7115_I2C_ADDR 0x21
+#define IVTV_TUNER_I2C_ADDR 0x61
+#define IVTV_MSP3400_I2C_ADDR 0x40
+#define IVTV_DMA_BUF_SIZE 34560 /* 0x8000 = 32kbytes, 0x20000 = 128kbytes */
+#define IVTV_DMA_DEC_BUF_SIZE 32768 /* 0x8000 = 32kbytes, 0x20000 = 128kbytes */
+//#define IVTV_DMA_BUF_SIZE 65536 /* 0x8000 = 32kbytes, 0x20000 = 128kbytes */
+//#define IVTV_DMA_DEC_BUF_SIZE 65536 /* 0x8000 = 32kbytes, 0x20000 = 128kbytes */
+
+#define IVTV_DMA_MAX_XFER 0x00080000 /* 0x8000 = 32kbytes, 0x20000 = 128kbytes */
+#define IVTV_DEC_MIN_BUF  0x00050000 /* want this many bytes+ in decoder buffer */
+#define IVTV_SLEEP_WAIT (HZ/10) /*100 ms*/
+#define IVTV_MAX_DATA_SLEEP 30
+#define DEC_DMA_TIMEOUT (15*HZ/100) /* used to be 100/15 */
+
+#define IVTV_DMA_ERR_LIST 0x00000008
+#define IVTV_DMA_ERR_WRITE 0x00000004
+#define IVTV_DMA_ERR_READ 0x00000002
+#define IVTV_DMA_SUCCESS 0x00000001
+#define IVTV_DMA_READ_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_READ)
+#define IVTV_DMA_WRITE_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE)
+#define IVTV_DMA_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE | IVTV_DMA_ERR_READ)
+
+/* video related */
+#define IVTV_MAX_INPUTS 9
+
+/*ioctl's*/
+#define IVTV_CTL_PRINTBOXES 0x00000001
+#define IVTV_CTL_CLEANUP 0x00000002
+#define IVTV_CTL_INIT_VIDCAP 0x00000003
+
+/* Registers */
+#define IVTV_REG_DMASTATUS (0x0004 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_IRQSTATUS (0x0040 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_IRQMASK (0x0048 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_DEC_SDRAM_REFRESH (0x08F8 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_DEC_SDRAM_PRECHARGE (0x08FC /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_VDM (0x2800 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_AO (0x2D00 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_BYTEFLUSH (0x2D24 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_SPU (0x9050 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_HW_BLOCKS (0x9054 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_VPU (0x9058 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_APU (0xA064 /*| IVTV_REG_OFFSET*/)
+
+/* IRQ Masks */
+#define IVTV_IRQ_MASK_DEFAULT 0x00000404 /*stuff to ignore*/
+#define IVTV_IRQ_MASK_CAPTURE 0xFC000400 /*inverse mask, we want the high bits!*/
+#define IVTV_IRQ_MASK_DECODE 0x00FC0400
+
+#define IVTV_IRQ_ENC_START_CAP		(0x1 << 31)
+#define IVTV_IRQ_ENC_EOS		(0x1 << 30)
+#define IVTV_IRQ_ENC_VBI_CAP		(0x1 << 29)
+#define IVTV_IRQ_ENC_VIM_RST		(0x1 << 28)
+#define IVTV_IRQ_ENC_DMA_COMPLETE	(0x1 << 27)
+
+#define IVTV_IRQ_DEC_COPY_PROTECT	(0x1 << 25)
+#define IVTV_IRQ_DEC_AUD_MODE_CHG	(0x1 << 24)
+#define IVTV_IRQ_DEC_DATA_REQ		(0x1 << 22)
+#define IVTV_IRQ_DEC_IFRAME_DONE	(0x1 << 21)
+#define IVTV_IRQ_DEC_DMA_COMPLETE	(0x1 << 20)
+#define IVTV_IRQ_DEC_VBI_RE_INSERT	(0x1 << 19)
+#define IVTV_IRQ_DEC_DMA_ERR		(0x1 << 18)
+#define IVTV_IRQ_DEC_VSYNC		(0x1 << 10)
+
+#define IVTV_IRQ_DEBUG_KLUGE ( IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_ENC_VIM_RST | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DEC_COPY_PROTECT | IVTV_IRQ_DEC_AUD_MODE_CHG | IVTV_IRQ_DEC_DATA_REQ | IVTV_IRQ_DEC_IFRAME_DONE | IVTV_IRQ_DEC_DMA_COMPLETE | IVTV_IRQ_DEC_VBI_RE_INSERT | IVTV_IRQ_DEC_DMA_ERR )
+
+/* commands */
+#define IVTV_MASK_SPU_ENABLE 0xFFFFFFFE
+#define IVTV_MASK_VPU_ENABLE15 0xFFFFFFF6
+#define IVTV_MASK_VPU_ENABLE16 0xFFFFFFFB
+#define IVTV_CMD_VDM_STOP 0x00000000
+#define IVTV_CMD_AO_STOP 0x00000005
+#define IVTV_CMD_APU_PING 0x00000000
+#define IVTV_CMD_VPU_STOP15 0xFFFFFFFE
+#define IVTV_CMD_VPU_STOP16 0xFFFFFFEE
+#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
+#define IVTV_CMD_SPU_STOP 0x00000001
+#define IVTV_CMD_SDRAM_PRECHARGE_INIT 0x0000001A
+#define IVTV_CMD_SDRAM_REFRESH_INIT 0x80000640
+#define IVTV_SDRAM_SLEEPTIME (60 * HZ / 100)	/* 600ms */
+
+/*Used for locating the firmware mailboxes*/
+#define IVTV_FIRM_ENC_FILENAME "/lib/modules/ivtv-fw-enc.bin" 
+#define IVTV_FIRM_DEC_FILENAME "/lib/modules/ivtv-fw-dec.bin"
+#define IVTV_FIRM_IMAGE_SIZE 256*1024
+#define IVTV_FIRM_SEARCH_ENCODER_START IVTV_ENCODER_OFFSET
+#define IVTV_FIRM_SEARCH_DECODER_START IVTV_DECODER_OFFSET
+#define IVTV_FIRM_SEARCH_ENCODER_END (IVTV_ENCODER_OFFSET + IVTV_ENCODER_SIZE - 1)
+#define IVTV_FIRM_SEARCH_DECODER_END (IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE - 1)
+#define IVTV_FIRM_SEARCH_STEP 0x00000100
+ 
+/* Firmware mailbox flags*/
+#define IVTV_MBOX_FIRMWARE_DONE 0x00000004
+#define IVTV_MBOX_DRIVER_DONE 0x00000002
+#define IVTV_MBOX_IN_USE 0x00000001
+#define IVTV_MBOX_FREE 0x00000000
+
+/*Firmware API commands*/
+#define IVTV_API_ENC_GETVER 0x000000C4
+#define IVTV_API_DEC_GETVER 0x00000011
+#define IVTV_API_ENC_HALT_FW 0x000000C3
+#define IVTV_API_DEC_HALT_FW 0x0000000E
+#define IVTV_API_DEC_START_PLAYBACK 0x00000001
+#define IVTV_API_DEC_STOP_PLAYBACK 0x00000002
+#define IVTV_API_DEC_PLAYBACK_SPEED 0x00000003
+#define IVTV_API_DEC_PAUSE_PLAYBACK 0x0000000d
+#define IVTV_API_DEC_DMA_BLOCKSIZE 0x00000008
+#define IVTV_API_DEC_DMA_FROM_HOST 0x00000000b
+#define IVTV_API_DEC_DISP_STANDARD 0x00000010
+#define IVTV_API_DEC_STREAM_INPUT 0x00000014
+#define IVTV_API_DEC_TIMING_INFO 0x00000015
+#define IVTV_API_DEC_SELECT_AUDIO 0x00000016
+#define IVTV_API_DEC_EVENT_NOTIFICATION 0x00000017
+#define IVTV_API_DEC_DISPLAY_BUFFERS 0x00000018
+#define IVTV_API_DEC_DECODE_SOURCE 0x0000001a
+#define IVTV_API_DEC_AUDIO_OUTPUT 0x0000001b
+#define IVTV_API_DEC_SET_AV_DELAY 0x0000001c
+#define IVTV_API_DEC_BUFFER 0x0000001e
+#define IVTV_API_DEC_DMA_STATUS 0x0000000a
+#define IVTV_API_DEC_XFER_INFO 0x00000009
+#define IVTV_API_STD_TIMEOUT 0x00010000 /*units??*/
+#define IVTV_API_ASSIGN_DMA_BLOCKLEN 0x000000c9
+#define IVTV_API_ASSIGN_PGM_INDEX_INFO 0x000000c7
+#define IVTV_API_ASSIGN_STREAM_TYPE 0x000000b9
+#define IVTV_API_ASSIGN_OUTPUT_PORT 0x000000bb
+#define IVTV_API_ASSIGN_FRAMERATE 0x0000008f
+#define IVTV_API_ASSIGN_FRAME_SIZE 0x00000091
+#define IVTV_API_ASSIGN_ASPECT_RATIO 0x00000099
+#define IVTV_API_ASSIGN_BITRATES 0x00000095
+#define IVTV_API_ASSIGN_GOP_PROPERTIES 0x00000097
+#define IVTV_API_ASSIGN_3_2_PULLDOWN 0x000000b1
+#define IVTV_API_ASSIGN_GOP_CLOSURE 0x000000c5
+#define IVTV_API_ASSIGN_AUDIO_PROPERTIES 0x000000bd
+#define IVTV_API_ASSIGN_DNR_FILTER_MODE 0x0000009b
+#define IVTV_API_ASSIGN_DNR_FILTER_PROPS 0x0000009d
+#define IVTV_API_ASSIGN_CORING_LEVELS 0x0000009f
+#define IVTV_API_ASSIGN_SPATIAL_FILTER_TYPE 0x000000a1
+#define IVTV_API_ASSIGN_FRAME_DROP_RATE 0x000000d0
+#define IVTV_API_ASSIGN_PLACEHOLDER 0x000000d8
+#define IVTV_API_INITIALIZE_INPUT 0x000000cd
+#define IVTV_API_ASSIGN_NUM_VSYNC_LINES 0x000000d6
+#define IVTV_API_BEGIN_CAPTURE 0x00000081
+#define IVTV_API_PAUSE_ENCODER 0x000000d2
+#define IVTV_API_EVENT_NOTIFICATION 0x000000d5
+#define IVTV_API_END_CAPTURE 0x00000082
+#define IVTV_API_SCHED_DMA_TO_HOST 0x000000cc
+#define IVTV_API_FB_GET_FRAMEBUFFER 0x00000041
+#define IVTV_API_FB_GET_PIXEL_FORMAT 0x00000042
+#define IVTV_API_FB_SET_PIXEL_FORMAT 0x00000043
+#define IVTV_API_FB_GET_STATE 0x00000044
+#define IVTV_API_FB_SET_STATE 0x00000045
+#define IVTV_API_FB_GET_OSD_COORDS 0x00000046
+#define IVTV_API_FB_SET_OSD_COORDS 0x00000047
+#define IVTV_API_FB_GET_SCREEN_COORDS 0x00000048
+#define IVTV_API_FB_SET_SCREEN_COORDS 0x00000049
+#define IVTV_API_FB_GET_GLOBAL_ALPHA 0x0000004a
+#define IVTV_API_FB_SET_GLOBAL_ALPHA 0x0000004b
+#define IVTV_API_FB_SET_BLEND_COORDS 0x0000004c
+// 0x4d unknown
+// 0x4e unknown
+#define IVTV_API_FB_GET_FLICKER_STATE 0x0000004f
+#define IVTV_API_FB_SET_FLICKER_STATE 0x00000050
+// 0x51 unknown
+#define IVTV_API_FB_BLT_COPY 0x00000052
+#define IVTV_API_FB_BLT_FILL 0x00000053
+#define IVTV_API_FB_BLT_TEXT 0x00000054
+// 0x55 unknown
+#define IVTV_API_FB_SET_FRAMEBUFFER_WINDOW 0x00000056
+// 0x57 - 0x5f unknown
+#define IVTV_API_FB_SET_CHROMA_KEY 0x00000060
+#define IVTV_API_FB_GET_ALPHA_CONTENT_INDEX 0x00000061
+#define IVTV_API_FB_SET_ALPHA_CONTENT_INDEX 0x00000062
+
+/* i2c stuff */
+#define I2C_CLIENTS_MAX 16
+#define I2C_TIMING (0x7<<4)
+#define IVTV_REG_I2C_SETSCL_OFFSET (0x7000 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_I2C_SETSDA_OFFSET (0x7004 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_I2C_GETSCL_OFFSET (0x7008 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_I2C_GETSDA_OFFSET (0x700c /*| IVTV_REG_OFFSET*/)
+
+/* debugging */
+#define IVTV_DEBUG_ERR   (1 << 0)
+#define IVTV_DEBUG_INFO  (1 << 1)
+#define IVTV_DEBUG_API   (1 << 2)
+#define IVTV_DEBUG_DMA   (1 << 3)
+#define IVTV_DEBUG_IOCTL (1 << 4)
+#define IVTV_DEBUG_I2C   (1 << 5)
+#define IVTV_DEBUG_IRQ   (1 << 6)
+#define IVTV_DEBUG(x,args...) if((x)&ivtv_debug) printk("ivtv: " args);
+#define IVTV_DEBUG_FB(x,args...) if((x)&ivtv_debug) printk("ivtv-fb: " args);
+
+/* Temp saa7115 hack FIXME */
+#define DECODER_SET_SIZE    76598
+#define	DECODER_GET_PICTURE 76599
+
+/* Values for IVTV_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */
+#define MPEG_FRAME_TYPE_IFRAME 1
+#define MPEG_FRAME_TYPE_IFRAME_PFRAME 3
+#define MPEG_FRAME_TYPE_ALL 7
+
+/* External API stuff */
+#define IVTV_IOC_FWAPI		0xFFEE7701 /*just some values i picked for now*/
+#define IVTV_IOC_ZCOUNT		0xFFEE7702
+#define IVTV_IOC_G_CODEC	0xFFEE7703
+#define IVTV_IOC_S_CODEC	0xFFEE7704
+
+/* allow direct access to the saa7115 registers for testing */
+#define SAA7115_GET_REG         0xFFEE7705
+#define SAA7115_SET_REG         0xFFEE7706
+
+
+#define DECODER_SET_AUDIO       0xFFEE7707
+#define DECODER_AUDIO_32_KHZ	0
+#define DECODER_AUDIO_441_KHZ	1
+#define DECODER_AUDIO_48_KHZ	2
+
+#define IVTV_IOC_PLAY     	0xFFEE7781
+#define IVTV_IOC_PAUSE     	0xFFEE7782
+#define IVTV_IOC_FRAMESYNC	0xFFEE7783
+#define IVTV_IOC_GET_TIMING	0xFFEE7784
+#define IVTV_IOC_S_SLOW_FAST	0xFFEE7785
+#define IVTV_IOC_S_START_DECODE 0xFFEE7786
+#define IVTV_IOC_S_STOP_DECODE  0xFFEE7787
+#define IVTV_IOC_S_OSD          0xFFEE7788
+#define IVTV_IOC_GET_FB		0xFFEE7789
+
+#define IVTV_IOC_STOP_DECODE	_IOW('@', 30, struct ivtv_cfg_stop_decode)
+#define IVTV_IOC_G_SPEED	_IOR('@', 31, struct ivtv_speed)
+#define IVTV_IOC_S_SPEED	_IOW('@', 32, struct ivtv_speed)
+
+/* Framebuffer external API */
+/* NOTE: These must *exactly* match the structures and constants in driver/ivtv.h */
+
+struct ivtvfb_ioctl_state_info {
+  unsigned long status;
+  unsigned long alpha;
+};
+
+struct ivtvfb_ioctl_blt_copy_args {
+  int x, y, width, height, source_offset, source_stride;
+};
+
+struct ivtvfb_ioctl_dma_host_to_ivtv_args {
+	void* source;
+	unsigned long dest_offset;
+	int count;
+};
+
+struct ivtvfb_ioctl_get_frame_buffer {
+	void* mem;
+	int   bytes;
+	int   sizex;
+	int   sizey;
+};
+
+struct ivtv_osd_coords {
+  unsigned long offset;
+  unsigned long max_offset;
+  int pixel_stride;
+  int lines;
+  int x;
+  int y;
+};
+
+struct rectangle {
+  int x0;
+  int y0;
+  int x1;
+  int y1;
+};
+
+#define IVTVFB_IOCTL_GET_STATE          _IOR('@', 1, struct ivtvfb_ioctl_state_info)
+#define IVTVFB_IOCTL_SET_STATE          _IOW('@', 2, struct ivtvfb_ioctl_state_info)
+#define IVTVFB_IOCTL_PREP_FRAME         _IOW('@', 3, struct ivtvfb_ioctl_dma_host_to_ivtv_args)
+#define IVTVFB_IOCTL_BLT_COPY           _IOW('@', 4, struct ivtvfb_ioctl_blt_copy_args)
+#define IVTVFB_IOCTL_GET_ACTIVE_BUFFER  _IOR('@', 5, struct ivtv_osd_coords)
+#define IVTVFB_IOCTL_SET_ACTIVE_BUFFER  _IOW('@', 6, struct ivtv_osd_coords)
+#define IVTVFB_IOCTL_GET_FRAME_BUFFER   _IOR('@', 7, struct ivtvfb_ioctl_get_frame_buffer)
+
+#define IVTVFB_STATUS_ENABLED           (1 << 0)
+#define IVTVFB_STATUS_GLOBAL_ALPHA      (1 << 1)
+#define IVTVFB_STATUS_LOCAL_ALPHA       (1 << 2)
+#define IVTVFB_STATUS_FLICKER_REDUCTION (1 << 3)
+
+/* Stream types */
+#define IVTV_STREAM_PS		0
+#define IVTV_STREAM_TS		1
+#define IVTV_STREAM_MPEG1	2
+#define IVTV_STREAM_PES_AV	3
+#define IVTV_STREAM_PES_V	5
+#define IVTV_STREAM_PES_A	7
+#define IVTV_STREAM_DVD		10
+#define IVTV_STREAM_VCD		11
+#define IVTV_STREAM_SVCD	12
+#define IVTV_STREAM_DVD_S1	13
+#define IVTV_STREAM_DVD_S2	14
+
+/* Custom v4l controls */
+#ifndef V4L2_CID_PRIVATE_BASE
+#define V4L2_CID_PRIVATE_BASE			0x08000000
+#endif
+
+#define V4L2_CID_IVTV_FREQ	(V4L2_CID_PRIVATE_BASE)
+#define V4L2_CID_IVTV_ENC	(V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_IVTV_BITRATE	(V4L2_CID_PRIVATE_BASE + 2)
+#define V4L2_CID_IVTV_MONO	(V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_IVTV_JOINT	(V4L2_CID_PRIVATE_BASE + 4)
+#define V4L2_CID_IVTV_EMPHASIS	(V4L2_CID_PRIVATE_BASE + 5)
+#define V4L2_CID_IVTV_CRC	(V4L2_CID_PRIVATE_BASE + 6)
+#define V4L2_CID_IVTV_COPYRIGHT	(V4L2_CID_PRIVATE_BASE + 7)
+#define V4L2_CID_IVTV_GEN	(V4L2_CID_PRIVATE_BASE + 8)
+
+#define IVTV_V4L2_AUDIO_MENUCOUNT 9 /* # of v4l controls */
+
+#define IVTV_DEC_PRIVATE_BASE	(V4L2_CID_PRIVATE_BASE + IVTV_V4L2_AUDIO_MENUCOUNT)
+
+#define V4L2_CID_IVTV_DEC_SMOOTH_FF	(IVTV_DEC_PRIVATE_BASE + 0)
+#define V4L2_CID_IVTV_DEC_FR_MASK	(IVTV_DEC_PRIVATE_BASE + 1)
+#define V4L2_CID_IVTV_DEC_SP_MUTE	(IVTV_DEC_PRIVATE_BASE + 2)
+#define V4L2_CID_IVTV_DEC_FR_FIELD	(IVTV_DEC_PRIVATE_BASE + 3)
+#define V4L2_CID_IVTV_DEC_AUD_SKIP	(IVTV_DEC_PRIVATE_BASE + 4)
+#define V4L2_CID_IVTV_DEC_NUM_BUFFERS   (IVTV_DEC_PRIVATE_BASE + 5)
+#define V4L2_CID_IVTV_DEC_PREBUFFER     (IVTV_DEC_PRIVATE_BASE + 6)
+
+#define IVTV_V4L2_DEC_MENUCOUNT 7
+
+#ifdef SAA7115_REGTEST
+/* allow direct access to the saa7115 registers for testing */
+#define SAA7115_GET_REG         0xFFEE7705
+#define SAA7115_SET_REG         0xFFEE7706
+
+struct saa7115_reg_t {
+	u8 reg;
+	u8 val;
+};
+#endif
+struct saa7114 {
+	int norm;
+	int input;
+	int enable;
+	int bright;
+	int contrast;
+	int hue;
+	int sat;
+	int playback;
+};
+
+
+struct ivtv_cfg_start_decode {
+	u32	gop_offset;		/*Frames in GOP to skip before starting */
+	u32	muted_audio_frames;	/* #of audio frames to mute */
+};
+
+struct ivtv_cfg_stop_decode {
+	int	hide_last; /* 1 = show black after stop, 0 = show last frame */
+	u64	pts_stop; /* PTS to stop at */
+};
+
+struct ivtv_speed {
+	int scale; 		/* 1-?? (50 for now) */
+	int smooth;		/* Smooth mode when in slow/fast mode */
+	int speed; 		/* 0 = slow, 1 = fast */
+	int direction; 		/* 0 = forward, 1 = reverse (not supportd */
+	int fr_mask;		/* 0 = I, 1 = I,P, 2 = I,P,B */
+	int b_per_gop;		/* frames per GOP (reverse only) */
+	int aud_mute;		/* Mute audio while in slow/fast mode */
+	int fr_field;		/* 1 = show every field, 0 = show every frame */
+	int mute;		/* # of audio frames to mute on playback resume */
+};
+
+struct ivtv_slow_fast {
+	int speed; /* 0 = slow, 1 = fast */
+	int scale; /* 1-?? (50 for now) */
+};
+
+struct ivtv_ioctl_fwapi {
+        u32 cmd;
+        u32 result;
+        int args;
+        u32 data[IVTV_MBOX_MAX_DATA];
+};
+
+struct ivtv_ioctl_framesync {
+  u32 frame;
+  u64 pts;
+  u64 scr;
+};
+
+struct ivtv_audio_meta {
+	        struct v4l2_queryctrl   *ctrl;
+	        struct v4l2_querymenu   *menu;
+	        u32                     *table;
+	        u32                     mask;
+	        s32                     setting;
+};
+
+/* For use with IVTV_IOC_G_CODEC and IVTV_IOC_S_CODEC */
+struct ivtv_ioctl_codec {
+	u32 aspect;
+	u32 audio_bitmap;
+	u32 bframes;
+	u32 bitrate_mode;
+	u32 bitrate;
+	u32 bitrate_peak;
+	u32 dnr_mode;
+	u32 dnr_spatial;
+	u32 dnr_temporal;
+	u32 dnr_type;
+	u32 framerate;
+	u32 framespergop;
+	u32 gop_closure;
+	u32 pulldown;
+	u32 stream_type;
+};
+
+extern int ivtv_debug;
+extern int ivtv_pal;
+           
+/* Scatter-Gather array element, used in DMA transfers */
+struct ivtv_SG_element {
+	u32 src;
+	u32 dst;
+	u32 size;
+};
+
+/* ivtv-specific mailbox template */
+struct ivtv_mailbox {
+	u32 flags;
+	u32 cmd;
+	u32 retval;
+	u32 timeout;
+	u32 data[IVTV_MBOX_MAX_DATA];
+};
+
+struct ivtv_state {
+	unsigned long freq; /* Current tuned frequency */
+	int input; /* Current digitizer input */
+	u32 flags;/* tuner, audio */
+	u16 type; /* tv or camera */
+	u16 norm; /* Current video standard */
+	/* more to come! */
+};
+
+struct ivtv_buffer {
+	size_t			readpos;
+	dma_addr_t		dma_handle;
+	struct v4l2_buffer	buffer;
+        struct list_head        list;
+	unsigned long		ts;
+};
+
+struct ivtv_buffer_list {
+	struct video_device	*vdev; /* to get itv from */
+	int			elements;
+        struct list_head        list;
+};
+
+struct ivtv_options {
+	int yuv_fixup;		/* Should we re-work YUV to a standard format? */
+	int yuv_buffers;	/* How many yuv buffers to allocate? */
+	int mpg_buffers;	/* how many mpg buffers to allocate? */
+	int vbi_buffers;	/* how many vbi buffers to allocate? */
+	int dec_mpg_buffers;	/* how many decoder mpg buffers to allocate? */
+	int dec_yuv_buffers;	/* How many decoder yuv buffers to allocate? */
+	int dec_mpg_qlen;	/* how many decoder mpg buffers to queue? */
+	int dec_yuv_qlen;	/* how many decoder yuv buffers to queue? */
+	int num_devices;	/* how many cards to detect? */
+};
+
+struct ivtv_dec_options {
+	int hide_last_frame;	/* 0 = display last frame on stop_decode
+				 * 1 = display black */
+	u32 pts_low;		/* low bits PTS to stop playback at */
+	u32 pts_hi;		/* hi bits  PTS to stop playback at */
+	int gop_offset;		/* on start-playback, skip this
+				 *  # of frames in the GOP */
+	int mute_frames;	/* # of audio frames to mute on playback start */
+	int decbuffers;		/* 0 = 6 buffers, 1 = 9 buffers */
+	int prebuffer;		/* 0 = no prebuffer, 1 = enabled, see docs */
+	struct ivtv_speed	speed;
+};
+
+/* per-stream, s_flags */
+#define IVTV_F_S_DMAP		0
+#define IVTV_F_S_OVERFLOW	1
+#define IVTV_F_S_CAP		2
+
+/* per-ivtv, i_flags */
+#define IVTV_F_I_BUSY		0
+#define IVTV_F_I_NEEDS_DATA	1
+#define IVTV_F_I_EOS		2
+#define IVTV_F_I_OSD_DMA	3
+
+struct ivtv_v4l2_stream {
+	int			buf_size; /* size of buffers this stream */
+	long			id;
+	long			seq;
+	int			ubytes; /* bytes written back to user this frame */
+	unsigned long		s_flags;
+	int			v4l_reg_type;
+	wait_queue_head_t	waitq;
+	struct video_device	*v4l2dev;
+	struct v4l2_format	format;
+
+	// FIXME need to make sure no read() if streaming
+	struct ivtv_buffer_list free_q; /* unused buffers */
+	struct ivtv_buffer_list full_q; /* filled buffers */
+	struct ivtv_buffer_list dma_q;  /* awaiting dma to fill them */
+					/* only updated in interrupt time! */
+
+	int			controlcount; /* Number of elements in controls */
+	struct v4l2_control	*controls;
+};
+
+struct ivtv_v4l2_table {
+	int	count;
+	int	active;
+	union {
+		struct v4l2_input	*input;
+		struct v4l2_output	*output;
+		struct v4l2_audio	*audio;
+		struct v4l2_tuner	*tuner;
+		struct v4l2_control	*control;
+		struct v4l2_standard	*std;
+	} table;
+};
+		
+struct ivtv_v4l2 {
+	u32			capabilities;
+	struct ivtv_v4l2_table	input;
+	int			audio_output;
+	struct ivtv_v4l2_table	output;
+	struct ivtv_v4l2_table	audio;
+	struct ivtv_v4l2_table	tuner;
+	struct ivtv_v4l2_table	standard;
+	struct v4l2_capability	capability;
+	struct v4l2_frequency   freq;
+	int			streamcount; /* Number of elements in streams */
+	struct ivtv_v4l2_stream	*streams;
+
+        /* codec settings */
+        struct ivtv_ioctl_codec codec;
+	struct ivtv_audio_meta audio_meta[IVTV_V4L2_AUDIO_MENUCOUNT];
+
+	/* FIXME probably should get rid of this */
+	wait_queue_head_t	waitq;
+};
+
+struct ivtv_open_id {
+        int                     open_id;
+        int                     type;
+        struct ivtv             *itv;
+        struct list_head        list;
+};
+
+struct ivtvfb_user_dma_to_device {
+	    int page_count;
+	struct ivtv_SG_element* sglist;
+	struct page **map;
+	dma_addr_t sg_dma_handle;
+};
+
+
+
+/* Stuct to hold info about ivtv cards */
+struct ivtv {
+	int card_type; /* pvr 250 rev1, 250 rev2, 350 are options so far */
+	struct pci_dev *dev;
+	struct ivtv_options	options;
+	struct ivtv_dec_options	dec_options;
+	int num;                /* invalidate during init! */
+	int first_read;		/* used to clean up stream */
+	unsigned long i_flags;
+	atomic_t capturing;
+	atomic_t decoding;
+	struct semaphore sem_lock __cacheline_aligned_in_smp;
+	spinlock_t lock __cacheline_aligned_in_smp;
+
+	long	open_id; /* incremented each time an open occurs
+			    used as unique ID */
+
+	/* FIXME should use part of v4l2_performace instead */
+	unsigned long trans_id;
+	
+	struct tasklet_struct dma_sched_tq;
+
+	u32 enc_fw_ver, dec_fw_ver, base_addr; /*is base_addr needed? */
+	u32			irqmask;
+
+       	struct ivtv_mailbox *enc_mbox, *dec_mbox;
+	struct semaphore enc_msem __cacheline_aligned_in_smp;
+	struct semaphore dec_msem __cacheline_aligned_in_smp;
+	
+	unsigned char card_rev, *io_mem, *reg_mem;
+	
+	wait_queue_head_t cap_w, vsync_w;
+	
+	/*FIXME perhaps move these to the v4l2_stream struct */
+	struct ivtv_SG_element *SGarray, *DSGarray;
+	dma_addr_t SG_handle, DSG_handle;
+
+	/* Decoder */
+	struct ivtv_ioctl_framesync dec_timestamp;
+	wait_queue_head_t dec_master_w;
+	struct timer_list dec_timeout;
+
+	/* Framebuffer DMA support */
+	struct ivtvfb_user_dma_to_device* user_dma_to_device_state;
+	int	fb_id;
+
+	/* i2c */
+	struct i2c_adapter         i2c_adap;
+	struct i2c_algo_bit_data   i2c_algo;
+	struct i2c_client          i2c_client;
+	int                        i2c_state, i2c_rc, i2c_command;
+	struct i2c_client         *i2c_clients[I2C_CLIENTS_MAX];
+
+	/* v4l2 and User settings*/
+	struct ivtv_state	state;
+	struct ivtv_v4l2	v4l2;
+	struct list_head	client_list;
+};
+
+/* Globals */
+extern struct ivtv ivtv_cards[];
+extern int ivtv_cards_active;
+extern int dec_yuv_buffers;
+extern int dec_mpg_buffers;
+extern int yuv_buffers;
+extern int mpg_buffers;
+extern int vbi_buffers;
+extern spinlock_t ivtv_lock;
+
+/*==============Prototypes==================*/
+/* FIXME some of these proably need fine-tuning 
+ *  to avoid warnings
+ */
+
+void ivtv_setscl(void *data, int state);
+void ivtv_setsda(void *data, int state);
+int ivtv_getscl(void *data);
+int ivtv_getsda(void *data);
+
+void ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg);
+int ivtv_i2c_direct(struct ivtv *itv, int addr, const unsigned char *regs);
+
+void ivtv_inc(struct i2c_adapter *adapter);
+void ivtv_dec(struct i2c_adapter *adapter);
+
+/* init + register i2c algo-bit adapter */
+int __devinit init_ivtv_i2c(struct ivtv *itv);
+void __devexit exit_ivtv_i2c(struct ivtv *itv);
+
+/* end i2c stuff */
+
+/* Initialization stuff */
+int  ivtv_firmware_copy(struct ivtv *itv);
+
+/* Unload stuff */
+void ivtv_v4l2_cleanup(struct ivtv *itv);
+int  ivtv_stop_firmware(struct ivtv *itv);
+void ivtv_zero_usage_count(void);
+
+/* API Related */
+int ivtv_find_firmware_mailbox(struct ivtv *itv);
+int ivtv_get_free_mailbox(struct ivtv_mailbox *mbox);
+int ivtv_api_call(struct ivtv_mailbox *mbox, u32 cmd,  struct semaphore *sem,
+	       	int elements, u32 data[]);
+int ivtv_api_getresult_nosleep(struct ivtv_mailbox *mbox, u32 *result, u32 data[]);
+int ivtv_api_getresult(struct ivtv_mailbox *mbox, struct semaphore *sem,
+		u32 *result, u32 data[]);
+int ivtv_api(struct ivtv_mailbox *mbox, struct semaphore *sem, int cmd,
+		u32 *result, int args, u32 data[]);
+extern int __ivtv_api(struct ivtv_mailbox *mbox, int cmd,
+		u32 *result, int args, u32 data[]);
+int ivtv_v4l2_setup(struct ivtv *itv);
+
+/* Capture related */
+int ivtv_stop_all_captures(struct ivtv *itv);
+int ivtv_stop_capture(struct ivtv_open_id *id);
+long ivtv_read(struct ivtv_open_id *id, char *ubuf, size_t count, int block);
+int ivtv_get_timing_info(struct ivtv *itv, struct ivtv_ioctl_framesync *info);
+ssize_t ivtv_write(struct ivtv_open_id *id, const char *buf, size_t count,
+                   int block);
+unsigned int ivtv_poll(struct file *filp, poll_table *wait);
+unsigned int ivtv_dec_poll(struct file *filp, poll_table *wait);
+	/* makes a queue complete with 'length' items */
+	/* NOTE: This returns the # of buffers allocated */
+extern int ivtv_init_queue(struct ivtv *itv,struct ivtv_buffer_list *queue,
+			   int length, enum v4l2_buf_type type);
+	/* moves all items in queue 'src' to queue 'dst' */
+extern int ivtv_move_queue(struct ivtv *itv, struct ivtv_buffer_list *src,
+			   struct ivtv_buffer_list *dst);
+extern int ivtv_stop_decode(struct ivtv_open_id *id);
+
+/* Hardware/IRQ */
+extern void ivtv_set_irq_mask(struct ivtv *itv, unsigned long mask);
+extern void ivtv_clear_irq_mask(struct ivtv *itv, unsigned long mask);
+extern void ivtv_sleep_timeout(int timeout);
+
+/* Testing/Debugging */
+extern int ivtv_close(struct ivtv_open_id *id);
+
+/* debug stuff, to get the locking right */
+#ifndef WARN_ON
+#define WARN_ON(condition) do { \
+	if (unlikely((condition)!=0)) { \
+		printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \
+		dump_stack(); \
+	} \
+} while (0)
+#endif
+
+#define IVTV_ASSERT(x)	WARN_ON(!(x))
+
+static inline int ivtv_sem_count(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
+#endif
diff -aurpN -X /home/fletch/.diff.exclude 670-tiocgdev/drivers/media/video/msp3400.c 680-ia64_dec_and_lock/drivers/media/video/msp3400.c
--- 670-tiocgdev/drivers/media/video/msp3400.c	Wed Feb  4 23:03:25 2004
+++ 680-ia64_dec_and_lock/drivers/media/video/msp3400.c	Wed Feb 11 10:17:11 2004
@@ -58,6 +58,7 @@ static int debug    = 0;    /* debug out
 static int once     = 0;    /* no continous stereo monitoring */
 static int amsound  = 0;    /* hard-wire AM sound at 6.5 Hz (france),
 			      the autoscan seems work well only with FM... */
+static int standard = 1;   /* Override auto detect of audio standard, if needed. */
 static int simple   = -1;   /* use short programming (>= msp3410 only) */
 static int dolby    = 0;
 
@@ -113,6 +114,7 @@ static struct i2c_client *msps[MSP3400_M
 MODULE_PARM(once,"i");
 MODULE_PARM(debug,"i");
 MODULE_PARM(simple,"i");
+MODULE_PARM(standard,"i");
 MODULE_PARM(amsound,"i");
 MODULE_PARM(dolby,"i");
 
@@ -330,16 +332,6 @@ static struct CARRIER_DETECT carrier_det
 
 /* ----------------------------------------------------------------------- */
 
-#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 scarts[3][9] = {
   /* MASK    IN1     IN2     IN1_DA  IN2_DA  IN3     IN4     MONO    MUTE   */
   {  0x0320, 0x0000, 0x0200, -1,     -1,     0x0300, 0x0020, 0x0100, 0x0320 },
@@ -384,7 +376,7 @@ static void msp3400c_setvolume(struct i2
 
 	if (!muted) {
 		vol     = (left > right) ? left : right;
-		val     = (vol * 0x73 / 65535) << 8;
+		val     = (vol * 0x7F / 65535) << 8;
 	}
 	if (vol > 0) {
 		balance = ((right-left) * 127) / vol;
@@ -395,8 +387,10 @@ static void msp3400c_setvolume(struct i2
 		muted ? "on" : "off", left, right, val>>8, balance);
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones  */
-	/* scart - on/off only */
-	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0007, val ? 0x4000 : 0);
+	// scart - on/off only - AEW why? undone NOTE values below
+	// 40000 are mostly useless, 59343 is a good default (0x73)
+	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0007,
+			muted ? 0x1 : (val | 0x1));
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0001, balance << 8);
 }
 
@@ -473,6 +467,19 @@ static void msp3400c_setmode(struct i2c_
 	}
 }
 
+// given a bitmask of VIDEO_SOUND_XXX returns the "best" in the bitmask
+static int best_video_sound(int mode) {
+	int ret_cap = VIDEO_SOUND_MONO;
+	if (mode & VIDEO_SOUND_STEREO) {
+		ret_cap = VIDEO_SOUND_STEREO;
+	} else if (mode & VIDEO_SOUND_LANG1) {
+		ret_cap = VIDEO_SOUND_LANG1;
+	} else if (mode & VIDEO_SOUND_LANG2) {
+		ret_cap = VIDEO_SOUND_LANG2;
+	}
+	return ret_cap;
+}
+
 /* turn on/off nicam + stereo */
 static void msp3400c_setstereo(struct i2c_client *client, int mode)
 {
@@ -547,7 +554,7 @@ static void msp3400c_setstereo(struct i2
 	}
 
 	/* switch audio */
-	switch (mode) {
+	switch (best_video_sound(mode)) {
 	case VIDEO_SOUND_STEREO:
 		src = 0x0020 | nicam;
 #if 0 
@@ -771,10 +778,9 @@ static int msp3400c_thread(void *data)
 	struct CARRIER_DETECT *cd;
 	int count, max1,max2,val1,val2, val,this;
 	
-	lock_kernel();
 	daemonize("msp3400");
+
 	msp->thread = current;
-	unlock_kernel();
 
 	printk("msp3400: daemon started\n");
 	if(msp->notify != NULL)
@@ -1019,10 +1025,9 @@ static int msp3410d_thread(void *data)
 	struct msp3400c *msp = i2c_get_clientdata(client);
 	int mode,val,i,std;
     
-	lock_kernel();
 	daemonize("msp3410 [auto]");
+
 	msp->thread = current;
-	unlock_kernel();
 
 	printk("msp3410: daemon started\n");
 	if(msp->notify != NULL)
@@ -1072,7 +1077,7 @@ static int msp3410d_thread(void *data)
 		switch (msp->norm) {
 		case VIDEO_MODE_PAL:
 			mode = 0x1003;
-			std  = 1;
+			std  = standard;
 			break;
 		case VIDEO_MODE_NTSC:  /* BTSC */
 			mode = 0x2003;
@@ -1080,15 +1085,19 @@ static int msp3410d_thread(void *data)
 			break;
 		case VIDEO_MODE_SECAM: 
 			mode = 0x0003;
-			std  = 1;
+			std  = standard;
 			break;
 		case VIDEO_MODE_RADIO:
 			mode = 0x0003;
 			std  = 0x0040;
 			break;
+		case VIDEO_MODE_AUTO:
+			mode = 0x2003;
+			std  = standard;
+			break;
 		default:
 			mode = 0x0003;
-			std  = 1;
+			std  = standard;
 			break;
 		}
 		msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode);
@@ -1208,7 +1217,11 @@ static int msp3410d_thread(void *data)
 			msp->watch_stereo = 1;
 			break;
 		}
-		
+
+		// AEW a true reset has probably messed with our ACB register
+		// we need to restore this.
+		msp3400c_write(client, I2C_MSP3400C_DFP, 0x0013, msp->acb);
+
 		/* unmute + restore dfp registers */
 		msp3400c_setbass(client, msp->bass);
 		msp3400c_settreble(client, msp->treble);
@@ -1239,7 +1252,7 @@ static int msp_probe(struct i2c_adapter 
 static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg);
 
 static struct i2c_driver driver = {
-	.owner          = THIS_MODULE,
+		.owner			= THIS_MODULE,
         .name           = "i2c msp3400 driver",
         .id             = I2C_DRIVERID_MSP3400,
         .flags          = I2C_DF_NOTIFY,
@@ -1250,7 +1263,7 @@ static struct i2c_driver driver = {
 
 static struct i2c_client client_template = 
 {
-	I2C_DEVNAME("(unset)"),
+	I2C_DEVNAME("(msp3400 internal)"),
 	.flags     = I2C_CLIENT_ALLOW_USE,
         .driver    = &driver,
 };
@@ -1279,12 +1292,13 @@ static int msp_attach(struct i2c_adapter
 	}
 	
 	memset(msp,0,sizeof(struct msp3400c));
-	msp->left   = 65535;
-	msp->right  = 65535;
+	msp->norm   = VIDEO_MODE_NTSC;
+	msp->left   = 59343;
+	msp->right  = 59343;
 	msp->bass   = 32768;
 	msp->treble = 32768;
 	msp->input  = -1;
-	msp->muted  = 1;
+//	msp->muted  = 1;
 	for (i = 0; i < DFP_COUNT; i++)
 		msp->dfp_regs[i] = -1;
 
@@ -1521,7 +1535,7 @@ static int msp_command(struct i2c_client
 		struct video_audio *va = arg;
 
 		dprintk(KERN_DEBUG "msp34xx: VIDIOCGAUDIO\n");
-		va->flags |= VIDEO_AUDIO_VOLUME |
+		va->flags = VIDEO_AUDIO_VOLUME |
 			VIDEO_AUDIO_BASS |
 			VIDEO_AUDIO_TREBLE |
 			VIDEO_AUDIO_MUTABLE;
@@ -1573,6 +1587,7 @@ static int msp_command(struct i2c_client
 		
 		dprintk(KERN_DEBUG "msp34xx: VIDIOCSCHAN\n");
 		msp->norm = vc->norm;
+		msp_wake_thread(client);
 		break;
 	}
 	case VIDIOCSFREQ:
@@ -1582,7 +1597,14 @@ static int msp_command(struct i2c_client
 		msp_wake_thread(client);
 		break;
 	}
+	case MSP_SET_MATRIX:
+	{
+		struct msp_matrix *mspm = arg;
 
+		dprintk(KERN_DEBUG "msp34xx: MSP_SET_MATRIX\n");
+		msp3400c_set_scart(client, mspm->input, mspm->output);
+		break;
+	}
 	default:
 		/* nothing */
 		break;
diff -aurpN -X /home/fletch/.diff.exclude 670-tiocgdev/drivers/media/video/msp3400.h 680-ia64_dec_and_lock/drivers/media/video/msp3400.h
--- 670-tiocgdev/drivers/media/video/msp3400.h	Sun Nov 17 20:29:54 2002
+++ 680-ia64_dec_and_lock/drivers/media/video/msp3400.h	Wed Feb 11 10:17:11 2004
@@ -8,7 +8,29 @@ struct msp_dfpreg {
     int value;
 };
 
+struct msp_matrix {
+    int input;
+    int output;
+};
+
 #define MSP_SET_DFPREG     _IOW('m',15,struct msp_dfpreg)
 #define MSP_GET_DFPREG     _IOW('m',16,struct msp_dfpreg)
+
+/* ioctl for MSP_SET_MATRIX will have to be registered */
+#define MSP_SET_MATRIX     _IOW('m',17,struct msp_matrix)
+
+#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
+
+#define SCART_DSP_IN  0
+#define SCART1_OUT    1
+#define SCART2_OUT    2
 
 #endif /* MSP3400_H */
diff -aurpN -X /home/fletch/.diff.exclude 670-tiocgdev/drivers/media/video/saa7115.c 680-ia64_dec_and_lock/drivers/media/video/saa7115.c
--- 670-tiocgdev/drivers/media/video/saa7115.c	Wed Dec 31 16:00:00 1969
+++ 680-ia64_dec_and_lock/drivers/media/video/saa7115.c	Wed Feb 11 10:17:11 2004
@@ -0,0 +1,1106 @@
+/* 
+ * saa7114 - Philips SAA7114H video decoder driver version 0.0.1
+ *
+ * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com>
+ *
+ * Based on saa7111 driver by Dave Perks
+ *
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ *
+ * Slight changes for video timing and attachment output by
+ * Wolfgang Scherr <scherr@net4you.net>
+ *
+ * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *    - moved over to linux>=2.4.x i2c protocol (1/1/2003)
+ *
+ * Changes by Kevin Thayer <nufan_wfk at yahoo.com>
+ *    - changed to saa7115. (2/17/2003)
+ *
+ * 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>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+
+#include <linux/slab.h>
+
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+
+#include <linux/videodev.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+MODULE_DESCRIPTION("Philips SAA7115 video decoder driver");
+MODULE_AUTHOR("Kevin Thayer");
+MODULE_LICENSE("GPL");
+
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#ifndef I2C_DRIVERID_SAA7114
+#warning Using temporary hack for missing I2C driver-ID for saa7114
+#define I2C_DRIVERID_SAA7114 I2C_DRIVERID_EXP1
+#endif
+
+#include <linux/video_decoder.h>
+
+static int debug = 1;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+/* FIXME need to get this properly allocated 
+ *   also defined in ivtv.h, so change it there too */
+#define DECODER_SET_SIZE    76598
+#define	DECODER_GET_PICTURE 76599
+
+/* Need to be able to set the audio bitrates */
+#define DECODER_SET_AUDIO	0xFFEE7707
+#define DECODER_AUDIO_32_KHZ	0
+#define DECODER_AUDIO_441_KHZ	1
+#define DECODER_AUDIO_48_KHZ	2
+ 
+#ifdef SAA7115_REGTEST
+/* allow direct access to the saa7115 registers for testing */
+#define SAA7115_GET_REG		0xFFEE7705
+#define SAA7115_SET_REG		0xFFEE7706
+
+
+struct saa7115_reg_t {
+	u8 reg;
+	u8 val;
+};
+#endif
+
+#define dprintk(num, format, args...) \
+	do { \
+		if (debug >= num) \
+			printk(format, ##args); \
+	} while (0)
+
+/* ----------------------------------------------------------------------- */
+
+static u8 readreg(struct i2c_client *client, unsigned char reg) {
+        struct i2c_adapter *adap=client->adapter;
+        unsigned char mm1[] = {0x1e};
+        unsigned char mm2[] = {0x00};
+        struct i2c_msg msgs[2];
+        
+        msgs[0].flags=0;
+        msgs[1].flags=I2C_M_RD;
+        msgs[0].addr=msgs[1].addr=client->addr;
+        mm1[0]=reg;
+        msgs[0].len=1; msgs[1].len=1;
+        msgs[0].buf=mm1; msgs[1].buf=mm2;
+        i2c_transfer(adap, msgs, 2);
+        
+        return mm2[0];
+}
+
+struct saa7114 {
+	int norm;
+	int input;
+	int enable;
+	int bright;
+	int contrast;
+	int hue;
+	int sat;
+	int playback;
+	int audio;
+};
+
+#define   I2C_SAA7114        0x42
+#define   I2C_SAA7114A       0x40
+
+#define   I2C_DELAY   10
+
+
+//#define SAA_7114_NTSC_HSYNC_START       (-3)
+//#define SAA_7114_NTSC_HSYNC_STOP        (-18)
+
+#define SAA_7114_NTSC_HSYNC_START  (-17)
+#define SAA_7114_NTSC_HSYNC_STOP   (-32)
+
+//#define SAA_7114_NTSC_HOFFSET           (5)
+#define SAA_7114_NTSC_HOFFSET		(6)
+#define SAA_7114_NTSC_VOFFSET           (10)
+#define SAA_7114_NTSC_WIDTH             (720)
+#define SAA_7114_NTSC_HEIGHT            (480) /* was 250*/
+
+#define SAA_7114_SECAM_HSYNC_START      (-17)
+#define SAA_7114_SECAM_HSYNC_STOP       (-32)
+
+#define SAA_7114_SECAM_HOFFSET          (2)
+#define SAA_7114_SECAM_VOFFSET          (10)
+#define SAA_7114_SECAM_WIDTH            (720)
+#define SAA_7114_SECAM_HEIGHT           (300)
+
+#define SAA_7114_PAL_HSYNC_START        (-17)
+#define SAA_7114_PAL_HSYNC_STOP         (-32)
+
+#define SAA_7114_PAL_HOFFSET            (2)
+#define SAA_7114_PAL_VOFFSET            (10)
+#define SAA_7114_PAL_WIDTH              (720)
+#define SAA_7114_PAL_HEIGHT             (300)
+
+#define SAA_7114_VERTICAL_CHROMA_OFFSET         0	//0x50504040
+#define SAA_7114_VERTICAL_LUMA_OFFSET           0
+
+#define REG_ADDR(x) (((x) << 1) + 1)
+#define LOBYTE(x) ((unsigned char)((x) & 0xff))
+#define HIBYTE(x) ((unsigned char)(((x) >> 8) & 0xff))
+#define LOWORD(x) ((unsigned short int)((x) & 0xffff))
+#define HIWORD(x) ((unsigned short int)(((x) >> 16) & 0xffff))
+
+
+/* ----------------------------------------------------------------------- */
+
+static inline int
+saa7114_write (struct i2c_client *client,
+	       u8                 reg,
+	       u8                 value)
+{
+//	struct saa7114 *decoder = i2c_get_clientdata(client);
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+
+static int writeregs(struct i2c_client *client, const unsigned char *regs)
+{
+        unsigned char reg, data;
+
+        while (*regs!=0x00) {
+                reg =*(regs++);
+                data=*(regs++);
+                if (saa7114_write(client, reg, data) < 0)
+                        return -1;
+        }
+        return 0;
+}
+
+static inline int
+saa7114_read (struct i2c_client *client,
+	      u8                 reg)
+{
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+
+static const unsigned char init_saa7115_auto_input[] = {
+	0x01, 0x08, //(was 0x48)   // 0x08: white peak control enabled, 0x48: white peak control disabled
+	0x03, 0x2C, //was 0x20     // 0x20: automatic gain control, 0x2c: user programmable gain
+	0x04, 0x90, // analog gain set to 0
+	0x05, 0x90, // analog gain set to 0
+	0x06, 0xEB, // horiz sync begin = -21
+	0x07, 0xE0, // horiz sync stop = -17
+
+	// done in misc
+//	0x09, 0x40, //80 for svideo  // 0x40: use luminance comb filter, 0x80: don't use ...
+
+	0x0A, 0x80, //i2c dump ends up at 96 (was 80) // decoder brightness, 0x80 is itu standard
+	0x0B, 0x44, // decoder contrast, 0x44 is itu standard
+	0x0C, 0x40, // decoder saturation, 0x40 is itu standard
+	0x0D, 0x00, //i2c dump ends up at 04 (was 00) // chrominance hue control
+	0x0F, 0x24, //i2c dump says 0x30 (was 0x2A) // chrominance gain control , should be 0x00 for agc, otherwise 0x80+0x24: 0xA4
+	0x10, 0x06,
+	0x11, 0x00,
+	0x12, 0x9D, //i2c dump says 0x9D (was 0x00)
+	0x13, 0x80, //" 0x80 (was 0x00)
+	0x14, 0x01, //" 0x01 (was 0x01)
+	0x15, 0x04, //" 0x00 (was 0x11) //should also be moved to NTSC/PAL VGATE start
+	/* moved to NTSC/PAL sections
+	0x16, 0x11, //" 0x11 (was 0xFE) // VGATE stop
+	*/
+	0x17, 0x98, //" 0x98 (was 0xD8) //may set to 98 // VGATE MSB and other values
+	0x18, 0x40, // raw data gain 0x00 = nominal
+	0x19, 0x80, // raw data offset 0x80 = 0 LSB
+	0x1A, 0x77, // color killer level control 0x77 = recommended
+	0x1B, 0x42, // misc chroma control 0x42 = recommended
+	0x1C, 0xA9, // combfilter control 0xA9 = recommended
+	0x1D, 0x01, // combfilter control 0x01 = recommended
+	0x88, 0xD0, //reset device // set programmed, reset
+	0x88, 0xF0, //Set device programmed, all in operational mode // set programmed, active ?programmed should be 0?
+	0x00, 0x00 // ? not necessary, version readback register
+};
+
+/* ============== SAA7715 VIDEO templates =============  */
+
+static const unsigned char cfg_saa7115_reset_scaler[] = {
+	0x87, 0x00, //Disable I-port output
+	0x88, 0x0B, //reset scaler (was 0xD0) // ?should be 0xD0
+	0x88, 0xF0, //activate scaler
+	0x87, 0x01, //Enable I-port output  // what about high bits? how is ICLK used?
+	0x00, 0x00
+};
+static const unsigned char cfg_saa7115_NTSC_fullres_x[] = {
+	0xCC, 0xD0, //hsize low (output) //hor output window size = 0x2d0 = 720
+	0xCD, 0x02, //hsize hi (output)
+
+	0xD0, 0x01, // down scale = 1
+	0xD1, 0x00, // prescale accumulation length = 1
+	0xD2, 0x00, // dc gain and fir prefilter control
+	0xD4, 0x80, //Lum Brightness // nominal value = 0x80
+	0xD5, 0x40, //Lum contrast // nominal value = 0x40
+	0xD6, 0x40, //Chroma satur. // nominal value = 0x80
+	0xD8, 0x00, // hor lum scaling 0x0400 = 1
+	0xD9, 0x04,
+	0xDA, 0x00, //H-phase offset Luma = 0
+	0xDC, 0x00, // hor chrom scaling 0x0200. must be hor lum scaling /2
+	0xDD, 0x02, //H-scaling incr chroma 
+	0xDE, 0x00, //H-phase offset chroma // must be offset luma /2
+	
+	0x00, 0x00
+};
+static const unsigned char cfg_saa7115_NTSC_fullres_y[] = {
+	0xCE, 0xFD, //vsize low (output) was FD // ver output window size = 253 ??240
+	0xCF, 0x00, //vsize hi (output)
+
+	0xE0, 0x00, //V-scaling incr luma low 0x0400 = 1
+	0xE1, 0x04, //" hi
+	0xE2, 0x00, //V-scaling incr chroma low // must be same as luma
+	0xE3, 0x04, //" hi
+	0xE4, 0x01, //V-scaling mode control // no mirroring, higher order accumulation
+	0xE8, 0x00, //V-phase offset chroma 00 //?only regs E8 and EC necessary?
+	0xE9, 0x00, //V-phase offset chroma 01
+	0xEA, 0x00, //V-phase offset chroma 10
+	0xEB, 0x00, //V-phase offset chroma 11
+	0xEC, 0x00, //V-phase offset luma 00
+	0xED, 0x00, //V-phase offset luma 01
+	0xEE, 0x00, //V-phase offset luma 10
+
+	0x00, 0x00
+};
+
+static const unsigned char cfg_saa7115_NTSC_video[] = {
+	0x80, 0x00, //reset tasks
+	0x88, 0x0B, //reset scaler (was 0xD0)
+	
+	0x16, 0x11, //" 0x11 (was 0xFE) //VGATE pulse stop
+
+	0x08, 0x68, //i2c dump says 0x68 (was 0xB0) NTSC ONLY  // 0xBO: auto detection, 0x68 = NTSC
+	0x0E, 0x07, //i2c dump says 0x0d (was 0x07) // lots of different stuff... video autodetection is on
+
+	0xC0, 0x00, //Task Handling Control (was 0x00)
+	0xC1, 0x08, //X-port formats/config
+	0xC2, 0x00, //Input Ref. signal Def.
+	0xC3, 0x80, //I-port config (was 0x80)
+	0xC4, 0x02, //hoffset low (input) // 0x0002 is minimum
+	0xC5, 0x00, //hoffset hi (input)
+	0xC6, 0xD0, //hsize low (input) // 0x02d0 = 720
+	0xC7, 0x02, //hsize hi (input)
+	0xC8, 0x14, //voff low was 0x14, changing to 0x0E (14) // 0x0014 = 20
+	0xC9, 0x00, //voff hi
+	0xCA, 0xFD, //vsize low (input) was FD // 0x00fd = 253
+	0xCB, 0x00, //vsize hi (input)
+
+	0xF0, 0xAD, //Set PLL Register. NTSC 525 lines per frame, 27 MHz
+	0xF1, 0x05, //low bit with 0xF0, (was 0x05)
+	0xF5, 0xAD, //Set pulse generator register
+	0xF6, 0x01,
+
+	0x87, 0x00, //Disable I-port output
+	0x88, 0x0B, //reset scaler (was 0xD0)
+	0x80, 0x20, //Activate only task "B", continuous mode (was 0xA0)
+	0x88, 0xF0, //activate scaler
+	0x87, 0x01, //Enable I-port output
+	0x00, 0x00
+};
+ 
+static const unsigned char cfg_saa7115_PAL_fullres_x[] = {
+ 	0xCC, 0xD0, //hsize low (output) //720 same as NTSC
+ 	0xCD, 0x02, //hsize hi (output)
+
+ 	0xD0, 0x01,
+ 	0xD1, 0x00,
+ 	0xD2, 0x00,
+ 	0xD4, 0x80, //Lum Brightness
+ 	0xD5, 0x40, //Lum contrast
+ 	0xD6, 0x40, //Chroma satur.
+ 	0xD8, 0x00,
+ 	0xD9, 0x04,
+ 	0xDA, 0x00, //H-phase offset Luma
+ 	0xDC, 0x00,
+ 	0xDD, 0x02, //H-scaling incr chroma
+ 	0xDE, 0x00, //H-phase offset chroma
+
+	0x00, 0x00
+};
+static const unsigned char cfg_saa7115_PAL_fullres_y[] = {
+ 	0xCE, 0x20, //vsize low (output) // 0x0120 = 288
+ 	0xCF, 0x01, //vsize hi (output)
+ 
+ 	0xE0, 0x00, //V-scaling incr luma low
+ 	0xE1, 0x04, //" hi
+ 	0xE2, 0x00, //V-scaling incr chroma low
+ 	0xE3, 0x04, //" hi
+ 	0xE4, 0x01, //V-scaling mode control
+ 	0xE8, 0x00, //V-phase offset chroma 00
+ 	0xE9, 0x00, //V-phase offset chroma 01
+ 	0xEA, 0x00, //V-phase offset chroma 10
+ 	0xEB, 0x00, //V-phase offset chroma 11
+ 	0xEC, 0x00, //V-phase offset luma 00
+ 	0xED, 0x00, //V-phase offset luma 01
+ 	0xEE, 0x00, //V-phase offset luma 10
+ 	0xEF, 0x00, //V-phase offset luma 11
+
+	0x00, 0x00
+};
+
+/* FIXME need to input proper height/width */
+static const unsigned char cfg_saa7115_PAL_video[] = {
+ 	0x80, 0x00, //reset tasks
+ 	0x88, 0x0B, //reset scaler (was 0xD0)
+
+	0x16, 0x15, //" 0x11 (was 0xFE)
+
+	0x08, 0x28, //i2c dump says 0x28 (was 0xB0) PAL ONLY // 0x28 = PAL
+	0x0E, 0x07, //i2c dump says 0x0d (was 0x07)
+
+ 	0xC0, 0x00, //Task Handling Control (was 0x00)
+ 	0xC1, 0x08, //X-port formats/config
+ 	0xC2, 0x00, //Input Ref. signal Def.
+ 	0xC3, 0x80, //I-port config (was 0x80)
+ 	0xC4, 0x00, //hoffset low (input)
+ 	0xC5, 0x00, //hoffset hi (input)
+ 	0xC6, 0xD0, //hsize low (input) // 0x02D0 = 720
+ 	0xC7, 0x02, //hsize hi (input)
+ 	0xC8, 0x14, //voffset low (input) low was 0x14, changing to 0x0E (14)
+ 	0xC9, 0x00, //voffset hi (input)
+ 	0xCA, 0x20, //vsize low (input) // 288
+ 	0xCB, 0x01, //vsize hi (input)
+
+	0xF0, 0xB0, //Set PLL Register. PAL 625 lines per frame, 27 MHz
+	0xF1, 0x05, //low bit with 0xF0, (was 0x05)
+	0xF5, 0xB0, //Set pulse generator register
+	0xF6, 0x01,
+
+	0x87, 0x00, //Disable I-port output
+ 	0x88, 0x0B, //reset scaler (was 0xD0)
+ 	0x80, 0xA0, //Activate only task "B", continuous mode (was 0xA0)
+ 	0x88, 0xF0, //activate scaler
+ 	0x87, 0x01, //Enable I-port output
+ 	0x00, 0x00
+};
+/* ============== SAA7715 VIDEO templates (end) =======  */
+
+
+static const unsigned char init_saa7115_misc[] = {
+	0x38, 0x03, // audio stuff
+	0x39, 0x10,
+	0x3A, 0x00,
+
+//	0x80, 0x00, // set below
+	0x81, 0x01, //reg 0x15,0x16 define blanking window
+	0x82, 0x00,
+	0x83, 0x01, //was 0x01 // I port settings
+	0x84, 0x20,
+	0x85, 0x21,
+	0x86, 0xC5,
+	0x87, 0x01,
+//	0x88, 0xD0, // unnecessary
+
+//	0xF0, 0xAD, //this goes in PAL/NTSC video
+//	0xF1, 0x05,
+	0xF2, 0x50, // crystal clock = 24.576 MHz, target = 27MHz
+	0xF3, 0x46,
+	0xF4, 0x00,
+//	0xF5, 0xAD, //this goes in PAL/NTSC video
+//	0xF6, 0x01,
+	0xF7, 0x4B, // not the recommended settings!
+	0xF8, 0x00,
+	0xF9, 0x4B,
+	0xFA, 0x00,
+	0xFB, 0x4B,
+//	0xFC, 0x00, // unused
+//	0xFD, 0x00,
+//	0xFE, 0x00,
+	0xFF, 0x88, // PLL2 lock detection settings: 71 lines 50% phase error
+
+//	0x88, 0xF0, // unnecessary
+
+//	0x0D, 0x04, // already set in auto_input
+//	0x0C, 0x40,
+//	0x0A, 0x96,
+//	0x0B, 0x41,
+//	0x98, 0x05, // belongs to task A; unnecessary
+/* Turn off VBI */
+	0x40, 0x00,
+	0x41, 0xFF,
+	0x42, 0xFF,
+	0x43, 0xFF,
+	0x44, 0xFF,
+	0x45, 0xFF,
+	0x46, 0xFF,
+	0x47, 0xFF,
+	0x48, 0xFF,
+	0x49, 0xFF,
+	0x4A, 0xFF,
+	0x4B, 0xFF,
+	0x4C, 0xFF,
+	0x4D, 0xFF,
+	0x4E, 0xFF,
+	0x4F, 0xFF,
+	0x50, 0xFF,
+	0x51, 0xFF,
+	0x52, 0xFF,
+	0x53, 0xFF,
+	0x54, 0xFF,
+	0x55, 0xFF,
+	0x56, 0xFF,
+	0x57, 0xFF,
+	0x58, 0x00,
+	0x59, 0x47,
+	0x5A, 0x06,
+	0x5B, 0x88,
+	0x5D, 0xBF,
+	0x5E, 0x35,
+
+	0x02, 0x84, //input tuner -> input 4, amplifier active
+	0x09, 0x53, //chrom trap for tuner // special tuner stuff?
+
+	0x80, 0x20, //was 0x30 // 0x20 clock from PLL2, 0x30 clock from ICLK
+	0x88, 0xD0,
+	0x88, 0xF0,
+	0x00, 0x00 
+};
+
+/* ============== SAA7715 AUDIO settings =============  */
+static const unsigned char cfg_saa7115_48_audio[] = {
+	0x34, 0xCE, // 48khz
+	0x35, 0xFB, // "
+	0x36, 0x30, // "
+	0x00, 0x00
+};
+
+static const unsigned char cfg_saa7115_441_audio[] = {
+	0x34, 0xF2, // 44.1khz
+	0x35, 0x00, // "
+	0x36, 0x2D, // "
+	0x00, 0x00
+};
+
+static const unsigned char cfg_saa7115_32_audio[] = {
+	0x34, 0xDF, // 32.0khz
+	0x35, 0xA7, // "
+	0x36, 0x20, // "
+	0x00, 0x00
+};
+
+static const unsigned char cfg_saa7115_NTSC_48_audio[] = {
+	0x30, 0xCD, // 48.0khz NTSC
+	0x31, 0x20, // "
+	0x32, 0x03, // "
+	0x00, 0x00
+};
+
+static const unsigned char cfg_saa7115_PAL_48_audio[] = {
+	0x30, 0x00, // 48.0khz PAL
+	0x31, 0xC0, // "
+	0x32, 0x03, // "
+	0x00, 0x00
+};
+
+static const unsigned char cfg_saa7115_NTSC_441_audio[] = {
+	0x30, 0xBC, // 44.1khz NTSC
+	0x31, 0xDF, // "
+	0x32, 0x02, // "
+	0x00, 0x00
+};
+
+static const unsigned char cfg_saa7115_PAL_441_audio[] = {
+	0x30, 0x00, // 44.1khz PAL
+	0x31, 0x72, // "
+	0x32, 0x03, // "
+	0x00, 0x00
+};
+
+static const unsigned char cfg_saa7115_NTSC_32_audio[] = {
+	0x30, 0xDE, // 32.0khz NTSC
+	0x31, 0x15, // "
+	0x32, 0x02, // "
+	0x00, 0x00
+};
+
+static const unsigned char cfg_saa7115_PAL_32_audio[] = {
+	0x30, 0x00, // 32.0khz PAL
+	0x31, 0x80, // "
+	0x32, 0x02, // "
+	0x00, 0x00
+};
+
+/* ============ SAA7715 AUDIO settings (end) ============= */
+
+static int
+saa7114_command (struct i2c_client *client,
+		 unsigned int       cmd,
+		 void              *arg)
+{
+	struct saa7114 *decoder = i2c_get_clientdata(client);
+
+	switch (cmd) {
+
+	case 0:
+		//dprintk(1, KERN_INFO "%s: writing init\n", client->dev.name);
+		//saa7114_write_block(client, init, sizeof(init));
+		break;
+#ifdef SAA7115_REGTEST
+	/* ioctls to allow direct access to the saa7115 registers for testing */
+	case SAA7115_GET_REG:
+	{
+		struct saa7115_reg_t *saa7115_reg = (struct saa7115_reg_t *)arg;
+
+		saa7115_reg->val = saa7114_read(client, saa7115_reg->reg);
+		break;
+	}
+	case SAA7115_SET_REG:
+	{
+		struct saa7115_reg_t *saa7115_reg = (struct saa7115_reg_t *)arg;
+
+		saa7114_write(client, saa7115_reg->reg, saa7115_reg->val);
+		break;
+	}
+#endif
+	case DECODER_SET_SIZE:
+	{
+		/* Used video_window because it has height/width and is
+		 * already defined */
+		struct video_window *wind = arg;
+		int HPSC, HFSC;
+		int VSCY, Vsrc;
+
+		dprintk(1, KERN_INFO "%s: decoder set size\n", client->name);
+
+		/* FIXME need better bounds checking here */
+		if ( (wind->width < 1) || (wind->width > 1440))
+			return -EINVAL;
+		if ( (wind->height < 1) || (wind->height > 960))
+			return -EINVAL;
+			
+		/* probably have a valid size, let's set it */
+/* Set output width/height */
+		/* width */
+		saa7114_write (client, 0xCC, (u8)(wind->width & 0xFF));
+		saa7114_write (client, 0xCD, (u8)((wind->width >> 8)&0xFF));
+		/* height */
+		saa7114_write (client, 0xCE, (u8)(wind->height & 0xFF));
+		saa7114_write (client, 0xCF, (u8)((wind->height >> 8)&0xFF));
+
+/* Scaling settings */
+		/* Hprescaler is floor(inres/outres) */
+		/* FIXME hardcoding input res */
+		if (wind->width != 720) {
+			HPSC = (int) (720/wind->width);
+			HFSC = (int) ((1024*720)/(HPSC*wind->width));
+
+			printk("Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
+			/* FIXME hardcodes to "Task B" 
+			 * write H prescaler integer */
+			saa7114_write (client, 0xD0, (u8)(HPSC & 0x3F));
+
+			/* write H fine-scaling (luminance)*/
+			saa7114_write (client, 0xD8, (u8)(HFSC & 0xFF));
+			saa7114_write (client, 0xD9, (u8)((HFSC >> 8) & 0xFF) );
+			/* write H fine-scaling (chrominance)
+			 * must be lum/2, so i'll just bitshift :) */
+			saa7114_write (client, 0xDC, (u8)((HFSC >> 1) & 0xFF) );
+			saa7114_write (client, 0xDD, (u8)((HFSC >> 9) & 0xFF) );
+		} else {
+			if (decoder->norm != VIDEO_MODE_NTSC) {
+				printk("Setting full PAL width\n");
+				writeregs(client, cfg_saa7115_PAL_fullres_x);
+			} else {
+				printk("Setting full NTSC width\n");
+				writeregs(client, cfg_saa7115_NTSC_fullres_x);
+			}
+		}
+		
+		Vsrc = 480;
+		if (decoder->norm != VIDEO_MODE_NTSC) Vsrc = 576;
+
+		if (wind->height != Vsrc) {
+			VSCY = (int) ((1024*Vsrc)/wind->height);
+			printk("Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
+			/* write V fine-scaling (luminance)*/
+			saa7114_write (client, 0xE0, (u8)(VSCY & 0xFF));
+			saa7114_write (client, 0xE1, (u8)((VSCY >> 8) & 0xFF) );
+			/* write V fine-scaling (chrominance)*/
+			saa7114_write (client, 0xE2, (u8)(VSCY & 0xFF));
+			saa7114_write (client, 0xE3, (u8)((VSCY >> 8) & 0xFF) );
+		} else {
+			if (decoder->norm != VIDEO_MODE_NTSC) {
+				printk("Setting full PAL height\n");
+				writeregs(client, cfg_saa7115_PAL_fullres_y);
+			} else {
+				printk("Setting full NTSC height\n");
+				writeregs(client, cfg_saa7115_NTSC_fullres_y);
+			}
+		}
+
+		writeregs(client, cfg_saa7115_reset_scaler);
+		break;
+	}
+	case DECODER_DUMP:
+	{
+		int i;
+
+		dprintk(1, KERN_INFO "%s: decoder dump\n", client->name);
+
+		for (i = 0; i < 32; i += 16) {
+			int j;
+
+			printk(KERN_DEBUG "%s: %03x", client->name, i);
+			for (j = 0; j < 16; ++j) {
+				printk(" %02x",
+				       saa7114_read(client, i + j));
+			}
+			printk("\n");
+		}
+	}
+		break;
+
+	case DECODER_GET_CAPABILITIES:
+	{
+		struct video_decoder_capability *cap = arg;
+
+		dprintk(1, KERN_DEBUG "%s: decoder get capabilities\n",
+			client->name);
+
+		cap->flags = VIDEO_DECODER_PAL |
+			     VIDEO_DECODER_NTSC |
+			     VIDEO_DECODER_SECAM |
+			     VIDEO_DECODER_AUTO |
+			     VIDEO_DECODER_CCIR;
+		cap->inputs = 8;
+		cap->outputs = 1;
+	}
+		break;
+
+	case DECODER_SET_AUDIO:
+	{
+		int *iarg = arg;
+		dprintk(1, KERN_DEBUG "%s set audio: 0x%02x\n", client->name, *iarg);
+		switch (*iarg) {
+			case DECODER_AUDIO_32_KHZ:
+				writeregs(client, cfg_saa7115_32_audio);
+				if (decoder->norm == VIDEO_MODE_NTSC) {
+					writeregs(client, cfg_saa7115_NTSC_32_audio);
+				} else {
+					writeregs(client, cfg_saa7115_PAL_32_audio);
+				}
+				break;
+			case DECODER_AUDIO_441_KHZ:
+				writeregs(client, cfg_saa7115_441_audio);
+				if (decoder->norm == VIDEO_MODE_NTSC) {
+					writeregs(client, cfg_saa7115_NTSC_441_audio);
+				} else {
+					writeregs(client, cfg_saa7115_PAL_441_audio);
+				}
+				break;
+			case DECODER_AUDIO_48_KHZ:
+				writeregs(client, cfg_saa7115_48_audio);
+				if (decoder->norm == VIDEO_MODE_NTSC) {
+					writeregs(client, cfg_saa7115_NTSC_48_audio);
+				} else {
+					writeregs(client, cfg_saa7115_PAL_48_audio);
+				}
+				break;
+			default:
+				printk(KERN_DEBUG "%s invalid audio setting 0x%02x\n", client->name, *iarg);
+		}
+
+		/*FIXME digitizer reset needed? 
+		 *   if so, uncomment this line */
+		//writeregs(client, cfg_saa7115_reset_scaler);
+
+		decoder->audio = *iarg;
+		
+	}
+		break;
+	case DECODER_GET_STATUS:
+	{
+		int *iarg = arg;
+		int status;
+		int res;
+
+		status = saa7114_read(client, 0x1f);
+
+		dprintk(1, KERN_DEBUG "%s status: 0x%02x\n", client->name,
+			status);
+		res = 0;
+		if ((status & (1 << 6)) == 0) {
+			res |= DECODER_STATUS_GOOD;
+		}
+		switch (decoder->norm) {
+		case VIDEO_MODE_NTSC:
+			res |= DECODER_STATUS_NTSC;
+			break;
+		case VIDEO_MODE_PAL:
+			res |= DECODER_STATUS_PAL;
+			break;
+		case VIDEO_MODE_SECAM:
+			res |= DECODER_STATUS_SECAM;
+			break;
+		default:
+		case VIDEO_MODE_AUTO:
+			if ((status & (1 << 5)) != 0) {
+				res |= DECODER_STATUS_NTSC;
+			} else {
+				res |= DECODER_STATUS_PAL;
+			}
+			break;
+		}
+		if ((status & (1 << 0)) != 0) {
+			res |= DECODER_STATUS_COLOR;
+		}
+		*iarg = res;
+	}
+		break;
+
+	case DECODER_SET_NORM:
+	{
+		u16 *iarg = arg;
+
+		dprintk(1, KERN_DEBUG "%s: decoder set norm ",
+			client->name);
+
+		switch (*iarg) {
+
+		case VIDEO_MODE_NTSC:
+			dprintk(1, "NTSC\n");
+			writeregs(client, cfg_saa7115_NTSC_video);
+			break;
+
+		case VIDEO_MODE_PAL:
+			dprintk(1, "PAL\n");
+			writeregs(client, cfg_saa7115_PAL_video);
+			break;
+
+		case VIDEO_MODE_SECAM:
+			dprintk(1, "SECAM\n");
+			writeregs(client, cfg_saa7115_PAL_video);
+			break;
+
+		default:
+			dprintk(1, " Unknown video mode!!!\n");
+			return -EINVAL;
+
+		}
+
+		decoder->norm = *iarg;
+
+		/* switch audio mode too! */
+		saa7114_command(client, DECODER_SET_AUDIO, &decoder->audio);
+
+	}
+		break;
+
+	case DECODER_SET_INPUT:
+	{
+		int *iarg = arg;
+
+		dprintk(1, KERN_DEBUG "%s: decoder set input (%d)\n",
+			client->name, *iarg);
+		/* inputs from 0-9 are available*/
+		if (*iarg < 0 || *iarg > 9) { 
+			return -EINVAL;
+		}
+
+		if (decoder->input != *iarg) {
+			dprintk(1, KERN_DEBUG "%s: now setting %s input\n",
+				client->name,
+				*iarg >= 6 ? "S-Video" : "Composite");
+			decoder->input = *iarg;
+
+			/* select mode */
+			saa7114_write(
+				client,
+				0x02,
+				(saa7114_read(client, 0x02) & 0xf0)|decoder->input);
+
+			/* bypass chrominance trap for modes 6..9 */
+			saa7114_write(client, 0x09,
+				(saa7114_read(client,0x09) & 0x7f)|
+				(decoder->input < 6 ? 0x0 : 0x80));
+		}
+	}
+		break;
+
+	case DECODER_SET_OUTPUT:
+	{
+		int *iarg = arg;
+
+		dprintk(1, KERN_DEBUG "%s: decoder set output\n",
+			client->name);
+
+		/* not much choice of outputs */
+		if (*iarg != 0) {
+			return -EINVAL;
+		}
+	}
+		break;
+
+	case DECODER_ENABLE_OUTPUT:
+	{
+		int *iarg = arg;
+		int enable = (*iarg != 0);
+
+		dprintk(1, KERN_DEBUG "%s: decoder %s output\n",
+			client->name, enable ? "enable" : "disable");
+
+		decoder->playback = !enable;
+
+		if (decoder->enable != enable) {
+			decoder->enable = enable;
+
+			if (decoder->enable) {
+				saa7114_write(client,0x87,0x01);
+			} else {
+				saa7114_write(client,0x87,0x00);
+			}
+		}
+	}
+		break;
+		
+	case DECODER_GET_PICTURE:
+	{
+		struct saa7114 *pic = arg;
+
+		pic->bright = decoder->bright;
+		pic->contrast = decoder->contrast;
+		pic->sat = decoder->sat;
+		pic->hue = decoder->hue;
+	}
+		break;
+
+	case DECODER_SET_PICTURE:
+	{
+		struct saa7114 *pic = arg;
+
+		dprintk(1,
+			KERN_DEBUG
+			"%s: decoder set picture bright=%d contrast=%d saturation=%d hue=%d\n",
+			client->name, pic->bright, pic->contrast,
+			pic->sat, pic->hue);
+
+		if (decoder->bright != pic->bright) {
+			/* We want 0 to 255 */
+			if (pic->bright < 0 || pic->bright > 255) {
+				dprintk(0, KERN_ERR "%s: invalid brightness setting %d", client->name, pic->bright);
+				return -EINVAL;
+			}
+			decoder->bright = pic->bright;
+			saa7114_write(client, 0x0a, decoder->bright);
+	  	}
+		if (decoder->contrast != pic->contrast) {
+			/* We want 0 to 127 */
+			if (pic->contrast < 0 || pic->contrast > 127) {
+				dprintk(0, KERN_ERR "%s: invalid contrast setting %d", client->name, pic->contrast);
+				return -EINVAL;
+			}
+			decoder->contrast = pic->contrast;
+			saa7114_write(client, 0x0b, decoder->contrast);
+  		}
+		if (decoder->sat != pic->sat) {
+			/* We want 0 to 127 */
+			if (pic->sat < 0 || pic->sat > 127) {
+				dprintk(0, KERN_ERR "%s: invalid saturation setting %d", client->name, pic->sat);
+				return -EINVAL;
+			}
+			decoder->sat = pic->sat;
+			saa7114_write(client, 0x0c, decoder->sat);
+  		}
+  		if (decoder->hue != pic->hue) {
+			/* We want -128 to 127 */
+			if (pic->hue < -128 || pic->hue > 127) {
+				dprintk(0, KERN_ERR "%s: invalid hue setting %d", client->name, pic->hue);
+				return -EINVAL;
+			}
+  			decoder->hue = pic->hue;
+			saa7114_write(client, 0x0d, decoder->hue);
+  		}
+	}
+		break;
+		
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+static unsigned short normal_i2c[] =
+    { I2C_SAA7114 >> 1, I2C_SAA7114A >> 1, I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+
+static int saa7114_i2c_id = 0;
+struct i2c_driver i2c_driver_saa7114;
+
+static int
+saa7114_detect_client (struct i2c_adapter *adapter,
+		       int                 address,
+		       int                 kind)
+{
+//	int i, err[30];
+//	short int hoff = SAA_7114_NTSC_HOFFSET;
+//	short int voff = SAA_7114_NTSC_VOFFSET;
+//	short int w = SAA_7114_NTSC_WIDTH;
+//	short int h = SAA_7114_NTSC_HEIGHT;
+	struct i2c_client *client;
+	struct saa7114 *decoder;
+
+	dprintk(1,
+		KERN_INFO
+		"saa7114.c: detecting saa7114 client on address 0x%x\n",
+		address << 1);
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return 0;
+
+	client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	if (client == 0)
+		return -ENOMEM;
+	memset(client, 0, sizeof(struct i2c_client));
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &i2c_driver_saa7114;
+	client->flags = I2C_CLIENT_ALLOW_USE;
+	client->id = saa7114_i2c_id++;
+	snprintf(client->name, sizeof(client->name) - 1, "saa7115[%d]",
+		 client->id);
+
+	i2c_set_clientdata(client, decoder =
+	    kmalloc(sizeof(struct saa7114), GFP_KERNEL));
+	if (decoder == NULL) {
+		kfree(client);
+		return -ENOMEM;
+	}
+	memset(decoder, 0, sizeof(struct saa7114));
+	decoder->norm = VIDEO_MODE_NTSC;
+	decoder->input = -1;
+	decoder->enable = 1;
+	decoder->bright = 128;
+	decoder->contrast = 64;
+	decoder->hue = 0;
+	decoder->sat = 64;
+	decoder->playback = 0;	// initially capture mode used
+	decoder->audio = DECODER_AUDIO_48_KHZ;
+
+	dprintk(1,
+		KERN_INFO
+		"saa7115.c: writing init values\n");
+
+	/* init to NTSC/48khz */
+	writeregs(client, init_saa7115_auto_input);
+	writeregs(client, init_saa7115_misc);
+	writeregs(client, cfg_saa7115_NTSC_fullres_x);
+	writeregs(client, cfg_saa7115_NTSC_fullres_y);
+	writeregs(client, cfg_saa7115_NTSC_video);
+	writeregs(client, cfg_saa7115_48_audio);
+	writeregs(client, cfg_saa7115_NTSC_48_audio);
+	writeregs(client, cfg_saa7115_reset_scaler);
+
+	set_current_state(TASK_INTERRUPTIBLE);
+	schedule_timeout(2*HZ);
+	
+	printk("status: (1E) 0x%02x, (1F) 0x%02x\n",
+		readreg(client, 0x1e),
+		readreg(client, 0x1f));
+
+	i2c_attach_client(client);
+
+	return 0;
+}
+
+static int
+saa7114_attach_adapter (struct i2c_adapter *adapter)
+{
+	dprintk(1,
+		KERN_INFO
+		"saa7114.c: starting probe for adapter %s (0x%x)\n",
+		adapter->name, adapter->id);
+	return i2c_probe(adapter, &addr_data, &saa7114_detect_client);
+}
+
+static int
+saa7114_detach_client (struct i2c_client *client)
+{
+	struct saa7114 *decoder = i2c_get_clientdata(client);
+	int err;
+
+	err = i2c_detach_client(client);
+	if (err) {
+		return err;
+	}
+
+	kfree(decoder);
+	kfree(client);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+struct i2c_driver i2c_driver_saa7114 = {
+	.owner = THIS_MODULE,
+	.name = "saa7115",
+
+	.id = I2C_DRIVERID_SAA7114,
+	.flags = I2C_DF_NOTIFY,
+
+	.attach_adapter = saa7114_attach_adapter,
+	.detach_client = saa7114_detach_client,
+	.command = saa7114_command,
+};
+
+static int saa7114_init_module (void)
+{
+	i2c_add_driver(&i2c_driver_saa7114);
+	
+	return 0;
+}
+
+static void saa7114_exit_module (void)
+{
+	i2c_del_driver(&i2c_driver_saa7114);
+}
+
+module_init(saa7114_init_module);
+module_exit(saa7114_exit_module);
diff -aurpN -X /home/fletch/.diff.exclude 670-tiocgdev/drivers/media/video/saa7127.c 680-ia64_dec_and_lock/drivers/media/video/saa7127.c
--- 670-tiocgdev/drivers/media/video/saa7127.c	Wed Dec 31 16:00:00 1969
+++ 680-ia64_dec_and_lock/drivers/media/video/saa7127.c	Wed Feb 11 10:17:11 2004
@@ -0,0 +1,912 @@
+/*
+ * saa7127 - Philips SAA7127 video encoder driver version 0.2
+ *
+ * Copyright (C) 2003 Roy Bulter <rbulter@hetnet.nl>
+ *
+ * Based on SAA7126 video encoder driver by Gillem & Andreas Oberritter
+ *
+ * Copyright (C) 2000-2001 Gillem <htoa@gmx.net>
+ * Copyright (C) 2002 Andreas Oberritter <obi@saftware.de>
+ *
+ * Based on Stadis 4:2:2 MPEG-2 Decoder Driver by Nathan Laredo
+ *
+ * Copyright (C) 1999 Nathan Laredo <laredo@gnu.org>
+ *
+ * This driver is designed for the Hauppauge 250/350 Linux driver
+ * designed by the Ivytv Project (ivtv.sf.net) 
+ *  
+ * Copyright (C) 2003 Kevin Thayer <nufan_wfk@yahoo.com>
+ *
+ * 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.
+ */
+
+/*
+ * Revision History
+ *
+ *
+ * Revision : 0.1 (09-05-2003)
+ * Change   : First Version
+ *
+ * Revision : 0.2 (21-05-2003)
+ * Change   : solved compiler error on line 785(800) 
+ *            reg61h variable was not set in saa7127_set_norm function
+ *
+ * Revision : 0.3 (21-07-2003) Matt T. Yourst <yourst@yourst.com>
+ * Change   : Update configuration tables to make NTSC appear correctly;
+ *            Enable alternative outputs (s-video, composite, RGB, etc.) 
+ */
+
+
+#include <linux/version.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/init.h>
+
+#include <linux/slab.h>
+
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/videodev.h>
+#include <linux/video_encoder.h>
+
+#include "saa7127.h"
+
+/*
+ **********************************************************************
+ *  Debug Macro's
+ *
+ *
+ **********************************************************************
+ */
+
+#define CURRENT_MASK   3
+#define NO_MASK        0
+#define INFO_MASK      1      /*  0b0000000000001 */
+#define ERROR_MASK     2      /*  0b0000000000010 */
+#define ENTER_MASK     4      /*  0b0000000000100 */
+#define RETURN_MASK    8      /*  0b0000000001000 */
+#define TRACE1_MASK    16     /*  0b0000000010000 */
+#define TRACE2_MASK    32     /*  0b0000000100000 */
+#define TRACE3_MASK    64     /*  0b0000001000000 */
+#define TRACE4_MASK    128    /*  0b0000010000000 */
+#define TRACE5_MASK    256    /*  0b0000100000000 */
+#define TRACE6_MASK    512    /*  0b0001000000000 */
+#define TRACE7_MASK    1024   /*  0b0010000000000 */
+#define TRACE8_MASK    2048   /*  0b0100000000000 */
+#define TRACE9_MASK    4096   /*  0b1000000000000 */
+
+
+static int debug_mask = CURRENT_MASK;
+static int test_image = 0;
+static int pal = 0;
+static int enable_output = 0;
+static int output_select = SAA7127_OUTPUT_TYPE_SVIDEO;
+
+#define INFO(format, args...)\
+      if ((debug_mask&INFO_MASK) == INFO_MASK)\
+      {\
+        printk("[%s: INFO]: ", __FILE__);\
+        printk(format, ##args);\
+        printk("\n");\
+      }\
+
+#define ERROR(format, args...)\
+      if ((debug_mask&ERROR_MASK) == ERROR_MASK)\
+      {\
+        printk("[%s: %d: ERROR]: ", __FILE__,__LINE__);\
+        printk(format, ##args);\
+        printk("\n");\
+      }\
+
+
+#ifdef DEBUG
+
+#define ENTER\
+  if ((debug_mask&ENTER_MASK) == ENTER_MASK)\
+  {\
+    printk("[%s : %s: %d: ENTER]: ",__FILE__,__FUNCTION__,__LINE__);\
+    printk("\n");\
+  }\
+
+#define RETURN(value)\
+      if ((debug_mask&RETURN_MASK) == RETURN_MASK)\
+      {\
+        printk("[%s : %s : %d: RETURN]: ", __FILE__,__FUNCTION__,__LINE__);\
+        printk("value: %x",value);\
+        printk("\n");\
+      }\
+      return(value);\
+
+static int get_trace_mask(int num)
+{
+  switch (num)
+  {
+    case 1:
+      return TRACE1_MASK;
+      break;
+    case 2:
+      return TRACE2_MASK;
+      break;
+    case 3:
+      return TRACE3_MASK;
+      break;
+    case 4:
+      return TRACE4_MASK;
+      break;
+    case 5:
+      return TRACE5_MASK;
+      break;
+    case 6:
+      return TRACE6_MASK;
+      break;
+    case 7:
+      return TRACE7_MASK;
+      break;
+    case 8:
+      return TRACE8_MASK;
+      break;
+    case 9:
+      return TRACE9_MASK;
+      break;
+    default:
+      return NO_MASK;
+  }
+}
+
+#define TRACE(num, format, args...) \
+      if ((debug_mask&get_trace_mask(num)) == get_trace_mask(num)) \
+      {\
+        printk("[%s: %d: TRACE%d] ", __FILE__, __LINE__,num);\
+        printk(format, ##args);\
+        printk("\n");\
+      }\
+      
+#else
+
+#define ENTER 
+#define RETURN(value) return(value);
+#define TRACE(num, format, args...) 
+
+#endif /* DEBUG */
+
+/*
+ **********************************************************************
+ *  
+ *  Array's with configuration parameters for the SAA7127
+ *
+ **********************************************************************
+ */
+
+struct i2c_reg_value 
+{
+  unsigned char reg;
+  unsigned char value;
+};
+
+struct i2c_reg_value saa7127_init_config_common[] = 
+{
+  {SAA7127_REG_WIDESCREEN_CONFIG,               0x0d},
+  {SAA7127_REG_WIDESCREEN_ENABLE,               0x00},
+  {SAA7127_REG_COPYGEN_0,                       0x77},
+  {SAA7127_REG_COPYGEN_1,                       0x41},
+  {SAA7127_REG_COPYGEN_2,                       0x00}, // (Macrovision enable/disable)
+  {SAA7127_REG_OUTPUT_PORT_CONTROL,             0x9e},
+  {SAA7127_REG_GAIN_LUMINANCE_RGB,              0x00},
+  {SAA7127_REG_GAIN_COLORDIFF_RGB,              0x00},
+  {SAA7127_REG_INPUT_PORT_CONTROL_1,            0x80}, // (for color bars)
+  {SAA7127_REG_LINE_21_ODD_0,                   0x77},
+  {SAA7127_REG_LINE_21_ODD_1,                   0x41},
+  {SAA7127_REG_LINE_21_EVEN_0,                  0x88},
+  {SAA7127_REG_LINE_21_EVEN_1,                  0x41},
+  {SAA7127_REG_RCV_PORT_CONTROL,                0x12},
+  {SAA7127_REG_VTRIG,                           0xf9},
+  {SAA7127_REG_HTRIG_HI,                        0x00},
+  {SAA7127_REG_RCV2_OUTPUT_START,               0x41},
+  {SAA7127_REG_RCV2_OUTPUT_END,                 0xc3},
+  {SAA7127_REG_RCV2_OUTPUT_MSBS,                0x00},
+  {SAA7127_REG_TTX_REQUEST_H_START,             0x3e},
+  {SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH,      0xb8},
+  {SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT,       0x03},
+  {SAA7127_REG_TTX_ODD_REQ_VERT_START,          0x15},
+  {SAA7127_REG_TTX_ODD_REQ_VERT_END,            0x16},
+  {SAA7127_REG_TTX_EVEN_REQ_VERT_START,         0x15},
+  {SAA7127_REG_TTX_EVEN_REQ_VERT_END,           0x16},
+  {SAA7127_REG_FIRST_ACTIVE,                    0x1a},
+  {SAA7127_REG_LAST_ACTIVE,                     0x01},
+  {SAA7127_REG_MSB_VERTICAL,                    0xc0},
+  {SAA7127_REG_DISABLE_TTX_LINE_LO_0,           0x00},
+  {SAA7127_REG_DISABLE_TTX_LINE_LO_1,           0x00},
+  {0, 0}
+};
+
+#define SAA7127_NTSC_DAC_CONTROL 0x05
+struct i2c_reg_value saa7127_init_config_ntsc[] = 
+{
+  {SAA7127_REG_BURST_START,                     0x19},
+  {SAA7127_REG_BURST_END,                       0x1d},
+  {SAA7127_REG_CHROMA_PHASE,                    0x27},
+  {SAA7127_REG_GAINU,                           0x88},
+  {SAA7127_REG_GAINV,                           0xc0},
+  {SAA7127_REG_BLACK_LEVEL,                     0x3f},
+  {SAA7127_REG_BLANKING_LEVEL,                  0x36},
+  {SAA7127_REG_VBI_BLANKING,                    0x36},
+  {SAA7127_REG_DAC_CONTROL,                     0x05},
+  {SAA7127_REG_BURST_AMP,                       0x4a},
+  {SAA7127_REG_SUBC3,                           0x1f},
+  {SAA7127_REG_SUBC2,                           0x7c},
+  {SAA7127_REG_SUBC1,                           0xf0},
+  {SAA7127_REG_SUBC0,                           0x21},
+  {SAA7127_REG_MULTI,                           0x90},
+  {SAA7127_REG_CLOSED_CAPTION,                  0x14},
+  {0, 0}
+};
+
+#define SAA7127_PAL_DAC_CONTROL 0x02
+struct i2c_reg_value saa7127_init_config_pal[] = 
+{
+  {SAA7127_REG_BURST_START,                     0x21},
+  {SAA7127_REG_BURST_END,                       0x1d},
+  {SAA7127_REG_CHROMA_PHASE,                    0x3f},
+  {SAA7127_REG_GAINU,                           0x7d},
+  {SAA7127_REG_GAINV,                           0xaf},
+  {SAA7127_REG_BLACK_LEVEL,                     0x23},
+  {SAA7127_REG_BLANKING_LEVEL,                  0x35},
+  {SAA7127_REG_VBI_BLANKING,                    0x35},
+  {SAA7127_REG_DAC_CONTROL,                     0x02},
+  {SAA7127_REG_BURST_AMP,                       0x2f},
+  {SAA7127_REG_SUBC3,                           0xcb}, 
+  {SAA7127_REG_SUBC2,                           0x8a},
+  {SAA7127_REG_SUBC1,                           0x09},
+  {SAA7127_REG_SUBC0,                           0x2a},
+  {SAA7127_REG_MULTI,                           0xa0},
+  {SAA7127_REG_CLOSED_CAPTION,                  0x00},
+  {0, 0}
+};
+
+/*
+ **********************************************************************
+ *  
+ *  Encoder Struct, holds the configuration state of the encoder
+ *
+ **********************************************************************
+ */
+
+struct saa7127
+{
+  enum SAA7127_video_norm       norm;
+  enum SAA7127_input_type       input_type;
+  enum SAA7127_output_type      output_type;
+  enum SAA7127_enable_type      enable;
+  enum SAA7127_wss_enable_type  wss_enable;
+  enum SAA7127_wss_mode_type    wss_mode;
+  u8 reg_2d;
+  u8 reg_3a;
+  u8 reg_61;
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_read (struct i2c_client *client,
+                         u8                 reg)
+{
+  ENTER;
+  RETURN (i2c_smbus_read_byte_data(client, reg));
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+
+static int saa7127_writereg(struct i2c_client *client, u8 reg, u8 val)
+{
+  ENTER;
+  if (i2c_smbus_write_byte_data(client, reg, val)  < 0)
+  {
+      ERROR ("I2C Write Problem");
+      return (-1);
+  }
+  TRACE(4,"I2C Write to reg: %x, data: %x",reg,val); 
+  RETURN (0);
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_write_inittab(struct i2c_client *client, const struct i2c_reg_value *regs)
+{
+  ENTER;
+
+  while (regs->reg != 0) 
+  {
+    if (i2c_smbus_write_byte_data(client, regs->reg, regs->value) < 0)
+    {
+      ERROR ("I2C Write Problem");
+      RETURN (-1);
+    }
+    TRACE(4,"I2C Write to reg: %x, data: %x",regs->reg,regs->value);
+    regs++;
+  }
+  RETURN (0);
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+
+static int saa7127_set_wss(struct i2c_client *client)
+{
+  struct saa7127 *encoder = (struct saa7127 *) i2c_get_clientdata(client);
+
+  ENTER;
+  switch (encoder->wss_enable)
+  {
+    case SAA7127_WSS_DISABLE:
+      TRACE(3,"Disable Wide Screen Signal");
+      saa7127_writereg(client, 0x27, 0x00);
+      break;
+    case SAA7127_WSS_ENABLE:
+      TRACE(3,"Enable Wide Screen Signal");    
+      saa7127_writereg(client, 0x27, 0x80);
+      break;
+    default:
+      return (-EINVAL);
+  }
+  return (0);
+}
+
+
+
+/* ----------------------------------------------------------------------- */
+
+
+static int saa7127_set_wss_mode(struct i2c_client *client)
+{
+  struct saa7127 *encoder = (struct saa7127 *) i2c_get_clientdata(client);
+
+  ENTER;
+
+  switch (encoder->wss_mode)
+  {
+    case SAA7127_WSS_MODE_4_3_FULL_FORMAT:
+      TRACE(3,"Widescreen Mode 4:3 Full Format");    
+      saa7127_writereg(client, 0x26, 0x08);
+      break;
+    case SAA7127_WSS_MODE_BOX_14_9_C:
+      TRACE(3,"Widescreen Mode Box 14:9 Center");        
+      saa7127_writereg(client, 0x26, 0x01);
+      break;
+    case SAA7127_WSS_MODE_BOX_14_9_TOP:
+      TRACE(3,"Widescreen Mode Box 14:9 Top");     
+      saa7127_writereg(client, 0x26, 0x02);
+      break;
+    case SAA7127_WSS_MODE_BOX_16_9_C:
+      TRACE(3,"Widescreen Mode Box 16:9 Center");         
+      saa7127_writereg(client, 0x26, 0x0b);
+      break;
+    case SAA7127_WSS_MODE_BOX_16_9_TOP:
+      TRACE(3,"Widescreen Mode Box 16:9 Top");        
+      saa7127_writereg(client, 0x26, 0x04);
+      break;
+    case SAA7127_WSS_MODE_SMALL_BOX_16_9_C:
+      TRACE(3,"Widescreen Mode Small Box 16:9 Center");            
+      saa7127_writereg(client, 0x26, 0x0d);
+      break;
+    case SAA7127_WSS_MODE_4_3_14_9_FULL_FORMAT:
+      TRACE(3,"Widescreen Mode 14:9 Full Format");                
+      saa7127_writereg(client, 0x26, 0x0e);
+      break;
+    case SAA7127_WSS_MODE_16_9_ANAMORPHIC:
+      TRACE(3,"Widescreen Mode 16:9 Full Format");                    
+      saa7127_writereg(client, 0x26, 0x07);
+      break;
+    default:
+      RETURN (-EINVAL);
+  }
+  RETURN (0);
+}
+
+
+
+/* ----------------------------------------------------------------------- */
+
+
+static int saa7127_set_enable (struct i2c_client *client)
+{
+  struct saa7127 *encoder = (struct saa7127 *) i2c_get_clientdata(client);
+
+  ENTER;
+
+  switch (encoder->enable)
+  {
+    case SAA7127_DISABLE:
+      TRACE(3,"Disable Video Output");       
+      saa7127_writereg(client, 0x2d, (encoder->reg_2d & 0xf0));
+      saa7127_writereg(client, 0x61, (encoder->reg_61 | 0xc0));
+      break;
+    case SAA7127_ENABLE:
+      TRACE(3,"Enable Video Output");          
+      saa7127_writereg(client, 0x2d, encoder->reg_2d);
+      saa7127_writereg(client, 0x61, encoder->reg_61);
+      break;
+    default:
+      RETURN (-EINVAL);
+  }
+
+#if 0
+	int j;
+	for (j = 0; j < 128/16; j++) 
+	{
+	  TRACE(3, "saa7127 registers 0x%02x-0x%02x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+	    	 j*16, j*16 + 15,
+	    	 saa7127_read(client, j*16 + 0),
+	    	 saa7127_read(client, j*16 + 1),
+	    	 saa7127_read(client, j*16 + 2),
+	    	 saa7127_read(client, j*16 + 3),
+	    	 saa7127_read(client, j*16 + 4),
+	    	 saa7127_read(client, j*16 + 5),
+	    	 saa7127_read(client, j*16 + 6),
+	    	 saa7127_read(client, j*16 + 7),
+	    	 saa7127_read(client, j*16 + 8),
+	    	 saa7127_read(client, j*16 + 9),
+	    	 saa7127_read(client, j*16 + 10),
+	    	 saa7127_read(client, j*16 + 11),
+	    	 saa7127_read(client, j*16 + 12),
+	    	 saa7127_read(client, j*16 + 13),
+	    	 saa7127_read(client, j*16 + 14),
+	    	 saa7127_read(client, j*16 + 15));
+	}
+#endif
+
+  RETURN (0);
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_norm(struct i2c_client *client)
+{
+  struct saa7127 *encoder = (struct saa7127 *) i2c_get_clientdata(client);
+  const struct i2c_reg_value *inittab;
+  
+  ENTER;
+  
+  switch (encoder->norm)
+  {
+    case SAA7127_VIDEO_NORM_NTSC:
+      TRACE(3,"Selecting NTSC video Standard");
+	  inittab = saa7127_init_config_ntsc;    
+      encoder->reg_61 = SAA7127_NTSC_DAC_CONTROL;
+      break;
+    case SAA7127_VIDEO_NORM_PAL:
+      TRACE(3,"Selecting PAL video Standard");
+	  inittab = saa7127_init_config_pal;
+	  encoder->reg_61 = SAA7127_PAL_DAC_CONTROL;            
+      break;
+    default:
+      RETURN (-EINVAL);
+  }
+  
+  /* Write Table */
+  saa7127_write_inittab(client, inittab);
+  RETURN (0);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_output_type(struct i2c_client *client)
+{
+  struct saa7127 *encoder = (struct saa7127 *) i2c_get_clientdata(client);
+
+  ENTER;
+
+  encoder->reg_3a = 0x13;   // by default swithch YUV to RGB-matrix on
+
+  switch (encoder->output_type)
+  {
+  case SAA7127_OUTPUT_TYPE_RGB:
+    TRACE(3,"Selecting RGB Output Type");
+    encoder->reg_2d = 0x0f; // RGB + CVBS (for sync)
+    break;
+  case SAA7127_OUTPUT_TYPE_COMPOSITE:
+    TRACE(3,"Selecting Composite Output Type");
+    encoder->reg_2d = 0x08; // 00001000 CVBS only, RGB DAC's off (high impedance mode) !!!
+    break;
+  case SAA7127_OUTPUT_TYPE_SVIDEO:
+    TRACE(3,"Selecting S-Video Output Type");      
+    encoder->reg_2d = 0xff; // 11111111  croma -> R, luma -> CVBS + G + B
+    break;
+  case SAA7127_OUTPUT_TYPE_YUV_V:
+    TRACE(3,"Selecting YUV V Output Type");        
+    encoder->reg_2d = 0x4f; // reg 2D = 01001111, all DAC's on, RGB + VBS
+    encoder->reg_3a = 0x0b; // reg 3A = 00001011, bypass RGB-matrix
+    break;
+  case SAA7127_OUTPUT_TYPE_YUV_C:
+    TRACE(3,"Selecting YUV C Output Type");
+    encoder->reg_2d = 0x0f; // reg 2D = 00001111, all DAC's on, RGB + CVBS
+    encoder->reg_3a = 0x0b; // reg 3A = 00001011, bypass RGB-matrix
+    break;
+  default:
+    RETURN (-EINVAL);
+  }
+
+  /* Configure Encoder */
+
+  saa7127_writereg(client, 0x2d, encoder->reg_2d);
+  saa7127_writereg(client, 0x3a, (encoder->input_type == SAA7127_INPUT_TYPE_TEST_IMAGE) ? 0x80 : encoder->reg_3a);
+
+  RETURN (0);
+}
+
+
+static int saa7127_set_input_type(struct i2c_client *client)
+{
+  struct saa7127 *encoder = (struct saa7127 *) i2c_get_clientdata(client);
+
+  ENTER;
+  
+  switch (encoder->input_type)
+  {
+  case SAA7127_INPUT_TYPE_NORMAL:         /* avia */
+    TRACE(3,"Selecting Normal Encoder Input");          
+    saa7127_writereg(client, 0x3a, encoder->reg_3a);
+    break;
+  case SAA7127_INPUT_TYPE_TEST_IMAGE:     /* color bar */
+    TRACE(3,"Selecting Colour Bar generator");
+    saa7127_writereg(client, 0x3a, 0x80);
+    break;
+  default:
+    RETURN (-EINVAL);
+  }
+
+  RETURN (0);
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+
+static int saa7127_command (struct i2c_client *client,
+                            unsigned int       cmd,
+                            void              *parg)
+{
+  struct saa7127 *encoder = i2c_get_clientdata(client);
+  unsigned long arg = (unsigned long) parg;
+  struct video_encoder_capability *cap = parg;
+  ENTER;
+  printk("saa7127_command: entered with cmd = %d\n", cmd);
+
+  switch (cmd) 
+  {
+    case ENCODER_GET_CAPABILITIES:
+      TRACE(3,"Asking Encoder Capabilities");
+      cap->flags = VIDEO_ENCODER_PAL | VIDEO_ENCODER_NTSC;
+      cap->inputs  = 1;
+      cap->outputs = 1;
+      break;
+
+    case ENCODER_SET_NORM:
+      TRACE(3,"Setting Encoder Video Standard");        
+      switch (arg)
+      {
+        case VIDEO_MODE_NTSC:
+          TRACE(3,"Set NTSC Video Mode");    
+          encoder->norm  = SAA7127_VIDEO_NORM_NTSC;
+          break;
+        case VIDEO_MODE_PAL:
+          TRACE(3,"Set PAL Video Mode");        
+          encoder->norm  = SAA7127_VIDEO_NORM_PAL;
+          break;
+        default:
+          return (-EINVAL);
+      }
+        saa7127_set_norm(client);
+      break;
+
+    case ENCODER_SET_INPUT:
+      TRACE(3,"Setting Encoder Input");
+      switch (arg)
+      {
+        case SAA7127_INPUT_NORMAL:    /* encoder input selected */
+          TRACE(3,"Select Normal input");        
+          encoder->input_type = SAA7127_INPUT_TYPE_NORMAL;
+          break;
+        case SAA7127_INPUT_TESTIMAGE: /* Internal colourbars selected */
+          TRACE(3,"Select ColourBar Generator");              
+          encoder->input_type = SAA7127_INPUT_TYPE_TEST_IMAGE;
+          break;
+        default:
+          RETURN (-EINVAL);
+      }
+      saa7127_set_input_type (client);
+      break;
+
+    case ENCODER_SET_OUTPUT:
+      TRACE(3,"Setting Encoder Output");
+      encoder->output_type = arg;
+      saa7127_set_output_type(client);
+      break;
+
+    case ENCODER_ENABLE_OUTPUT:
+      TRACE(3,"Turn on/off Output");    
+      switch (arg)
+      {     
+        case SAA7127_VIDEO_ENABLE:
+          TRACE (3,"Turn on Video Output");
+          encoder->enable=SAA7127_ENABLE;
+          break;
+        case SAA7127_VIDEO_DISABLE:
+          TRACE (3,"Turn off Video Output");      
+          encoder->enable=SAA7127_DISABLE;
+          break;
+        default:
+          RETURN (-EINVAL);
+      }
+      saa7127_set_enable(client);
+      break;
+
+    default:
+      RETURN (-EINVAL);
+  }
+  RETURN (0);
+}
+
+
+
+/* ----------------------------------------------------------------------- */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static unsigned short normal_i2c[]        = { I2C_SAA7127_ADRESS >> 1,I2C_CLIENT_END };
+static unsigned short normal_i2c_range[]  = { I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+
+static int saa7127_i2c_id = 0;
+struct i2c_driver i2c_driver_saa7127;
+
+
+/* ----------------------------------------------------------------------- */
+
+
+
+static int saa7127_detect_client (struct i2c_adapter *adapter,
+                                  int                 address,
+                                  int                 kind)
+{
+  struct i2c_client *client;
+  struct saa7127 *encoder;
+  int read_result = 0;
+  
+  ENTER;
+  
+  TRACE(1,"detecting saa7127 client on address 0x%x", address << 1);
+
+  /* Check if the adapter supports the needed features */
+  if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+    return (0);
+
+  client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+  if (client == 0)
+    return (-ENOMEM);
+
+  memset(client, 0, sizeof(struct i2c_client));
+  client->addr = address;
+  client->adapter = adapter;
+  client->driver = &i2c_driver_saa7127;
+  client->flags = I2C_CLIENT_ALLOW_USE;
+  client->id = saa7127_i2c_id++;
+  snprintf(client->name, sizeof(client->name) - 1, "saa7127[%d]", client->id);
+
+  i2c_set_clientdata(client, encoder = kmalloc(sizeof(struct saa7127), GFP_KERNEL));
+
+  if (encoder == NULL)
+  {
+    kfree(client);
+    return (-ENOMEM);
+  }
+
+  memset(encoder, 0, sizeof(struct saa7127));
+
+
+  /* Initialize default values */
+
+  encoder->output_type  = output_select;
+  encoder->wss_enable   = SAA7127_WSS_DISABLE;
+  encoder->wss_mode     = SAA7127_WSS_MODE_4_3_FULL_FORMAT;
+
+
+  /* Look if the pal module parameter is set */
+
+  if (pal == 1)
+  {
+    /* Select PAL Video Standard */
+    encoder->norm         = SAA7127_VIDEO_NORM_PAL;
+  }
+  else
+  {
+    /* Select NTSC Video Standard, default */  
+    encoder->norm         = SAA7127_VIDEO_NORM_NTSC;
+  }
+
+  /* Look if the Encoder needs to be enabled */
+  
+  if (enable_output == 1)
+  {
+    encoder->enable       = SAA7127_ENABLE;
+  }
+  else
+  {
+    /* for default disable output */
+    /* Because the MPEG DECODER is not initialised */
+    encoder->enable       = SAA7127_DISABLE;
+  }
+
+  /* The Encoder is does have internal Colourbar generator */
+  /* This can be used for debugging, configuration values for the encoder */
+  
+  if (test_image == 1)
+  {
+     /* Select ColourBar Generator */
+     encoder->input_type = SAA7127_INPUT_TYPE_TEST_IMAGE;
+  }
+  else
+  {
+     /* Select normal input */
+     encoder->input_type = SAA7127_INPUT_TYPE_NORMAL;
+  }
+
+
+  TRACE(2,"writing init values");
+
+  /* Configure Encoder */
+
+  printk("saa7127: Configuring encoder...");
+  saa7127_write_inittab(client, saa7127_init_config_common);
+  saa7127_set_norm(client);
+  saa7127_set_output_type (client);
+  saa7127_set_wss (client);
+  saa7127_set_wss_mode (client);
+  saa7127_set_input_type (client);
+  saa7127_set_enable (client);
+
+
+  set_current_state(TASK_INTERRUPTIBLE);
+  schedule_timeout(2*HZ);
+
+  read_result = saa7127_read(client, 0x00);
+
+  TRACE(4,"Read status register (00h) : 0x%02x ", read_result);
+
+  i2c_attach_client(client);
+
+  RETURN (0);
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+
+static int saa7127_attach_adapter (struct i2c_adapter *adapter)
+{
+
+  TRACE(2,"starting probe for adapter %s (0x%x)", adapter->dev.name, adapter->id);
+  return (i2c_probe(adapter, &addr_data, &saa7127_detect_client));
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+
+static int saa7127_detach_client (struct i2c_client *client)
+{
+  struct saa7127 *encoder = i2c_get_clientdata(client);
+  int err;
+  
+  /* Turn off TV output */
+
+  encoder->enable       = SAA7127_DISABLE;
+  saa7127_set_enable (client);
+
+  err = i2c_detach_client(client);
+
+  if (err)
+  {
+    return (err);
+  }
+
+  kfree(encoder);
+  kfree(client);
+  return (0);
+}
+
+/* ----------------------------------------------------------------------- */
+
+
+struct i2c_driver i2c_driver_saa7127 =
+{
+  .owner		  = THIS_MODULE,
+  .name           = "saa7127",
+  .id             = I2C_DRIVERID_SAA7127,
+  .flags          = I2C_DF_NOTIFY,
+  .attach_adapter = saa7127_attach_adapter,
+  .detach_client  = saa7127_detach_client,
+  .command        = saa7127_command,
+};
+
+
+/* ----------------------------------------------------------------------- */
+
+
+static int saa7127_init (void)
+{
+  INFO ("SAA7127 video encoder driver loaded");
+  TRACE (1,"Driver version: V %s",SAA7127_DRIVER_VERSION);
+  return (i2c_add_driver(&i2c_driver_saa7127));
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+
+static void saa7127_exit (void)
+{
+ 
+  INFO ("SAA7127 video encoder driver unloaded");
+  i2c_del_driver(&i2c_driver_saa7127);
+}
+
+
+
+/* ----------------------------------------------------------------------- */
+
+
+module_init(saa7127_init);
+module_exit(saa7127_exit);
+
+
+MODULE_DESCRIPTION("Philips SAA7127 video encoder driver");
+MODULE_AUTHOR("Roy Bulter");
+MODULE_LICENSE("GPL");
+MODULE_PARM(debug_mask, "i");
+MODULE_PARM(test_image, "i");
+MODULE_PARM(pal, "i");
+MODULE_PARM(enable_output, "i");
+MODULE_PARM(output_select, "i");
+MODULE_PARM_DESC(debug_mask, "debug_mask (0-8192) ");
+MODULE_PARM_DESC(test_image, "test_image (0-1) ");
+MODULE_PARM_DESC(pal, "pal (0-1) ");
+MODULE_PARM_DESC(enable_output, "enable_output (0-1) ");
+MODULE_PARM_DESC(output_select, "output_select (0 = composite, 1 = s-video, 2 = rgb, 3 = YUVc, 4 = YUVv)");
diff -aurpN -X /home/fletch/.diff.exclude 670-tiocgdev/drivers/media/video/saa7127.h 680-ia64_dec_and_lock/drivers/media/video/saa7127.h
--- 670-tiocgdev/drivers/media/video/saa7127.h	Wed Dec 31 16:00:00 1969
+++ 680-ia64_dec_and_lock/drivers/media/video/saa7127.h	Wed Feb 11 10:17:11 2004
@@ -0,0 +1,154 @@
+#ifndef _SAA7127_H
+#define _SAA7127_H
+
+/*
+ **********************************************************************
+ *
+ * Define's
+ *
+ *
+ **********************************************************************
+ */
+
+
+#define SAA7127_DRIVER_VERSION "0.3"
+
+
+#ifndef I2C_DRIVERID_SAA7127
+  #warning Using temporary hack for missing I2C driver-ID for saa7127
+  #define I2C_DRIVERID_SAA7127 I2C_DRIVERID_EXP2
+#endif
+
+
+#define I2C_SAA7127_ADRESS  0x88
+
+#define SAA7127_VIDEO_ENABLE        0x01
+#define SAA7127_VIDEO_DISABLE       0x00
+
+#define SAA7127_INPUT_TESTIMAGE     0x01
+#define SAA7127_INPUT_NORMAL        0x00
+
+/*
+ * SAA7127 registers
+ */
+
+#define SAA7127_REG_STATUS                           0x00
+/* (registers 0x01-0x25 unused.) */
+#define SAA7127_REG_WIDESCREEN_CONFIG                0x26
+#define SAA7127_REG_WIDESCREEN_ENABLE                0x27
+#define SAA7127_REG_BURST_START                      0x28
+#define SAA7127_REG_BURST_END                        0x29
+#define SAA7127_REG_COPYGEN_0                        0x2a
+#define SAA7127_REG_COPYGEN_1                        0x2b
+#define SAA7127_REG_COPYGEN_2                        0x2c
+#define SAA7127_REG_OUTPUT_PORT_CONTROL              0x2d
+/* (registers 0x2e-0x37 unused.) */
+#define SAA7127_REG_GAIN_LUMINANCE_RGB               0x38
+#define SAA7127_REG_GAIN_COLORDIFF_RGB               0x39
+#define SAA7127_REG_INPUT_PORT_CONTROL_1             0x3A
+/* (registers 0x3b-0x53 undefined) */
+#define SAA7127_REG_CHROMA_PHASE                     0x5A
+#define SAA7127_REG_GAINU                            0x5B
+#define SAA7127_REG_GAINV                            0x5C
+#define SAA7127_REG_BLACK_LEVEL                      0x5D
+#define SAA7127_REG_BLANKING_LEVEL                   0x5E
+#define SAA7127_REG_VBI_BLANKING                     0x5F
+/* (register 0x60 unused) */
+#define SAA7127_REG_DAC_CONTROL                      0x61
+#define SAA7127_REG_BURST_AMP                        0x62
+#define SAA7127_REG_SUBC3                            0x63
+#define SAA7127_REG_SUBC2                            0x64
+#define SAA7127_REG_SUBC1                            0x65
+#define SAA7127_REG_SUBC0                            0x66
+#define SAA7127_REG_LINE_21_ODD_0                    0x67
+#define SAA7127_REG_LINE_21_ODD_1                    0x68
+#define SAA7127_REG_LINE_21_EVEN_0                   0x69
+#define SAA7127_REG_LINE_21_EVEN_1                   0x6A
+#define SAA7127_REG_RCV_PORT_CONTROL                 0x6B
+#define SAA7127_REG_VTRIG                            0x6C
+#define SAA7127_REG_HTRIG_HI                         0x6D
+#define SAA7127_REG_MULTI                            0x6E
+#define SAA7127_REG_CLOSED_CAPTION                   0x6F
+#define SAA7127_REG_RCV2_OUTPUT_START                0x70
+#define SAA7127_REG_RCV2_OUTPUT_END                  0x71
+#define SAA7127_REG_RCV2_OUTPUT_MSBS                 0x72
+#define SAA7127_REG_TTX_REQUEST_H_START              0x73
+#define SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH       0x74
+#define SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT        0x75
+#define SAA7127_REG_TTX_ODD_REQ_VERT_START           0x76
+#define SAA7127_REG_TTX_ODD_REQ_VERT_END             0x77
+#define SAA7127_REG_TTX_EVEN_REQ_VERT_START          0x78
+#define SAA7127_REG_TTX_EVEN_REQ_VERT_END            0x79
+#define SAA7127_REG_FIRST_ACTIVE                     0x7A
+#define SAA7127_REG_LAST_ACTIVE                      0x7B
+#define SAA7127_REG_MSB_VERTICAL                     0x7C
+/* (register 0x7d unused) */
+#define SAA7127_REG_DISABLE_TTX_LINE_LO_0            0x7E
+#define SAA7127_REG_DISABLE_TTX_LINE_LO_1            0x7F
+
+
+
+/*
+ **********************************************************************
+ *  
+ *  Enumurations
+ *
+ **********************************************************************
+ */
+
+
+/* Enumeration for the Video Standard */
+
+
+enum SAA7127_video_norm       {
+                                SAA7127_VIDEO_NORM_NTSC,
+                                SAA7127_VIDEO_NORM_PAL
+                              };
+
+
+/* Enumeration for the Supported input types */
+
+enum SAA7127_input_type      {
+                                SAA7127_INPUT_TYPE_NORMAL,
+                                SAA7127_INPUT_TYPE_TEST_IMAGE
+                             };
+
+
+/* Enumeration for the Supported Output signal types */
+
+enum SAA7127_output_type      {
+                                SAA7127_OUTPUT_TYPE_COMPOSITE,
+                                SAA7127_OUTPUT_TYPE_SVIDEO,
+                                SAA7127_OUTPUT_TYPE_RGB,
+                                SAA7127_OUTPUT_TYPE_YUV_C,
+                                SAA7127_OUTPUT_TYPE_YUV_V
+                              };
+
+/* Enumeration for the enable/disabeling the output signal */
+
+enum SAA7127_enable_type      {
+                                SAA7127_DISABLE,
+                                SAA7127_ENABLE
+                              };
+/* Enumeration for the turning on/off the Wide screen signal for Wide screen TV */
+
+enum SAA7127_wss_enable_type  {
+                                SAA7127_WSS_DISABLE,
+                                SAA7127_WSS_ENABLE
+                              };
+
+/* Enumeration for the selecting the different Wide screen mode */
+
+enum SAA7127_wss_mode_type    {
+                                SAA7127_WSS_MODE_4_3_FULL_FORMAT,           /* full format 4:3 */
+                                SAA7127_WSS_MODE_BOX_14_9_C,           /* box 14:9 c */
+                                SAA7127_WSS_MODE_BOX_14_9_TOP,              /* box 14:9 top */
+                                SAA7127_WSS_MODE_BOX_16_9_C,           /* box 16:9 c */
+                                SAA7127_WSS_MODE_BOX_16_9_TOP,              /* box 16:9 top */
+                                SAA7127_WSS_MODE_SMALL_BOX_16_9_C,     /* box > 16:9 c */
+                                SAA7127_WSS_MODE_4_3_14_9_FULL_FORMAT,      /* full format 4:3 with 14:9 c letterbox content */
+                                SAA7127_WSS_MODE_16_9_ANAMORPHIC            /* full format 16:9 (anamorphic) */
+                              };
+
+
+#endif // _SAA7127_H
diff -aurpN -X /home/fletch/.diff.exclude 670-tiocgdev/drivers/media/video/tveeprom.c 680-ia64_dec_and_lock/drivers/media/video/tveeprom.c
--- 670-tiocgdev/drivers/media/video/tveeprom.c	Wed Dec 31 16:00:00 1969
+++ 680-ia64_dec_and_lock/drivers/media/video/tveeprom.c	Wed Feb 11 10:17:11 2004
@@ -0,0 +1,565 @@
+/* 
+ * tveeprom - eeprom decoder for tvcard configuration eeproms
+ *
+ * Data and decoding routines shamelessly borrowed from bttv-cards.c
+ * eeprom access routine shamelessly borrowed from bttv-if.c
+ * which are:
+
+    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+                           & Marcus Metzler (mocm@thp.uni-koeln.de)
+    (c) 1999-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+
+ * Adjustments to fit a more general model and all bugs:
+ 
+ 	Copyright (C) 2003 John Klar <linpvr at projectplasma.com>
+
+ * 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>
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/init.h>
+
+#include <linux/slab.h>
+
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+
+#include <linux/kmod.h>
+#include <linux/init.h>
+
+#include <linux/videodev.h>
+
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+MODULE_DESCRIPTION("i2c eeprom decoder driver");
+MODULE_AUTHOR("John Klar");
+MODULE_LICENSE("GPL");
+
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#include <media/tuner.h>
+
+#ifndef I2C_DRIVERID_TVEEPROM
+#warning Using temporary hack for missing I2C driver-ID for tveeprom
+#define I2C_DRIVERID_TVEEPROM I2C_DRIVERID_EXP2
+#endif
+
+static int debug = 1;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
+
+#define STRM(array,i) (i < sizeof(array)/sizeof(char*) ? array[i] : "unknown")
+
+#define dprintk(num, format, args...) \
+	do { \
+		if (debug >= num) \
+			printk(format, ##args); \
+	} while (0)
+
+/* ----------------------------------------------------------------------- */
+
+static unsigned char eeprom_buf[256];
+
+struct tveeprom {
+	u32 has_radio;
+
+	u32 tuner_type;
+	u32 tuner_formats;
+
+	u32 digitizer;
+	u32 digitizer_formats;
+
+	u32 audio_processor;
+	/* a_p_fmts? */
+
+	u32 model;
+	u32 revision;
+	u32 serial_number;
+	char rev_str[5];
+};
+
+#define   I2C_TVEEPROM        0xA0
+#define   I2C_TVEEPROMA       0xA0
+
+#define   I2C_DELAY   10
+
+
+#define REG_ADDR(x) (((x) << 1) + 1)
+#define LOBYTE(x) ((unsigned char)((x) & 0xff))
+#define HIBYTE(x) ((unsigned char)(((x) >> 8) & 0xff))
+#define LOWORD(x) ((unsigned short int)((x) & 0xffff))
+#define HIWORD(x) ((unsigned short int)(((x) >> 16) & 0xffff))
+
+/* ----------------------------------------------------------------------- */
+/* some hauppauge specific stuff                                           */
+
+static struct HAUPPAUGE_TUNER_FMT
+{
+	int	id;
+	char *name;
+}
+hauppauge_tuner_fmt[] __devinitdata =
+{
+	{ 0x00000000, "unknown1" },
+	{ 0x00000000, "unknown2" },
+	{ 0x00000007, "PAL(B/G)" },
+	{ 0x00001000, "NTSC(M)" },
+	{ 0x00000010, "PAL(I)" },
+	{ 0x00400000, "SECAM(L/L�)" },
+	{ 0x00000e00, "PAL(D/K)" },
+	{ 0x03000000, "ATSC Digital" },
+};
+
+static struct HAUPPAUGE_TUNER 
+{
+	int  id;
+	char *name;
+} 
+hauppauge_tuner[] __devinitdata = 
+{
+	{ TUNER_ABSENT,        "" },
+	{ TUNER_ABSENT,        "External" },
+	{ TUNER_ABSENT,        "Unspecified" },
+	{ TUNER_PHILIPS_PAL,   "Philips FI1216" },
+	{ TUNER_PHILIPS_SECAM, "Philips FI1216MF" },
+	{ TUNER_PHILIPS_NTSC,  "Philips FI1236" },
+	{ TUNER_PHILIPS_PAL_I, "Philips FI1246" },
+	{ TUNER_PHILIPS_PAL_DK,"Philips FI1256" },
+	{ TUNER_PHILIPS_PAL,   "Philips FI1216 MK2" },
+	{ TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" },
+	{ TUNER_PHILIPS_NTSC,  "Philips FI1236 MK2" },
+	{ TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" },
+	{ TUNER_PHILIPS_PAL_DK,"Philips FI1256 MK2" },
+	{ TUNER_TEMIC_NTSC,    "Temic 4032FY5" },
+	{ TUNER_TEMIC_PAL,     "Temic 4002FH5" },
+	{ TUNER_TEMIC_PAL_I,   "Temic 4062FY5" },
+	{ TUNER_PHILIPS_PAL,   "Philips FR1216 MK2" },
+	{ TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" },
+	{ TUNER_PHILIPS_NTSC,  "Philips FR1236 MK2" },
+	{ TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" },
+	{ TUNER_PHILIPS_PAL_DK,"Philips FR1256 MK2" },
+	{ TUNER_PHILIPS_PAL,   "Philips FM1216" },
+	{ TUNER_PHILIPS_SECAM, "Philips FM1216MF" },
+	{ TUNER_PHILIPS_NTSC,  "Philips FM1236" },
+	{ TUNER_PHILIPS_PAL_I, "Philips FM1246" },
+	{ TUNER_PHILIPS_PAL_DK,"Philips FM1256" },
+	{ TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" },
+	{ TUNER_ABSENT,        "Samsung TCPN9082D" },
+	{ TUNER_ABSENT,        "Samsung TCPM9092P" },
+	{ TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" },
+	{ TUNER_ABSENT,        "Samsung TCPN9085D" },
+	{ TUNER_ABSENT,        "Samsung TCPB9085P" },
+	{ TUNER_ABSENT,        "Samsung TCPL9091P" },
+	{ TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" },
+	{ TUNER_PHILIPS_FQ1216ME,   "Philips FQ1216 ME" },
+	{ TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
+	{ TUNER_ABSENT,        "Philips TD1536" },
+	{ TUNER_ABSENT,        "Philips TD1536D" },
+	{ TUNER_PHILIPS_NTSC,  "Philips FMR1236" }, /* mono radio */
+	{ TUNER_ABSENT,        "Philips FI1256MP" },
+	{ TUNER_ABSENT,        "Samsung TCPQ9091P" },
+	{ TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" },
+	{ TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" },
+	{ TUNER_TEMIC_4046FM5,     "Temic 4046FM5" },
+	{ TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" },
+	{ TUNER_ABSENT,        "Philips TD1536D_FH_44"},
+	{ TUNER_LG_NTSC_FM,    "LG TP18NSR01F"},
+	{ TUNER_LG_PAL_FM,     "LG TP18PSB01D"},
+	{ TUNER_LG_PAL,        "LG TP18PSB11D"},	
+	{ TUNER_LG_PAL_I_FM,   "LG TAPC-I001D"},
+	{ TUNER_LG_PAL_I,      "LG TAPC-I701D"}
+};
+
+static char *sndtype[] = {
+	"None", "TEA6300", "TEA6320", "TDA9850", "MSP3400C", "MSP3410D",
+	"MSP3415", "MSP3430", "MSP3438", "CS5331", "MSP3435", "MSP3440",
+	"MSP3445", "MSP3411", "MSP3416", "MSP3425",
+
+	"Type 0x10","Type 0x11","Type 0x12","Type 0x13",
+	"Type 0x14","Type 0x15","Type 0x16","Type 0x17",
+	"Type 0x18","MSP4418","Type 0x1a","MSP4448",
+	"Type 0x1c","Type 0x1d","Type 0x1e","Type 0x1f",
+};
+
+static void __devinit hauppauge_eeprom(struct tveeprom *tvee, 
+									   unsigned char *eeprom_data)
+{
+
+	/* ----------------------------------------------
+	** The hauppauge eeprom format is tagged
+	**
+	** if packet[0] == 0x84, then packet[0..1] == length
+	** else length = packet[0] & 3f;
+	** if packet[0] & f8 == f8, then EOD and packet[1] == checksum
+	**
+	** In our (ivtv) case we're interested in the following:
+	** tuner type: tag [00].05 or [0a].01 (index into hauppauge_tuners)
+	** tuner fmts: tag [00].04 or [0a].00 (bitmask index into hauppauge_fmts)
+	** radio:      tag [00].{last} or [0e].00  (bitmask.  bit2=FM)
+	** audio proc: tag [02].01 or [05].00 (lower nibble indexes lut?)
+
+	** Fun info:
+	** model:      tag [00].07-08 or [06].00-01
+	** revision:   tag [00].09-0b or [06].04-06
+	** serial#:    tag [01].05-07 or [04].04-06
+
+	** # of inputs/outputs ???
+	*/
+
+	int i,j,len,done,tag,tuner=0,t_format=0;
+	char *t_name = NULL, *t_fmt_name = NULL;
+	
+	tvee->revision = done = len = 0;
+	for(i=0; !done && i<256; i+=len) {
+
+		dprintk(2,
+				KERN_INFO 
+				"tvee: processing pos=%02x (%02x,%02x)\n",
+				i,eeprom_data[i],eeprom_data[i+1]);
+
+		if(eeprom_data[i] == 0x84) {
+			len = eeprom_data[i+1] + (eeprom_data[i+2] << 8);
+			i+=3;
+		} else
+		if((eeprom_data[i] & 0xf0) == 0x70) {
+			if((eeprom_data[i] & 0x08)) {
+				/* verify checksum! */
+				done = 1;
+				break;
+			}
+			len = eeprom_data[i] & 0x07;
+			++i;
+		} else {
+			printk(KERN_WARNING "Encountered bad packet header [%02x].  "
+				   "Corrupt or not a Hauppauge eeprom.\n",eeprom_data[i]);
+			return;
+		}
+
+		dprintk(1,
+				KERN_INFO 
+				"%3d [%02x] ",
+				len,eeprom_data[i]);
+		for(j=1; j<len; j++) {
+			dprintk(1,
+					"%02x ",eeprom_data[i+j]);
+		}
+		dprintk(1,"\n");
+
+		/* process by tag */
+		tag = eeprom_data[i];
+		switch( tag ) {
+		case 0x00:
+			tuner = eeprom_data[i+6];
+			t_format = eeprom_data[i+5];
+			tvee->has_radio = eeprom_data[i+len-1];
+			tvee->model = 
+				eeprom_data[i+8] + 
+				(eeprom_data[i+9] << 8);
+			tvee->revision = eeprom_data[i+10] +
+				(eeprom_data[i+11] << 8) +
+				(eeprom_data[i+12] << 16);
+			break;
+		case 0x01:
+			tvee->serial_number = 
+				eeprom_data[i+6] + 
+				(eeprom_data[i+7] << 8) + 
+				(eeprom_data[i+8] << 16);
+			break;
+		case 0x02:
+			tvee->audio_processor = eeprom_data[i+2] & 0x0f;
+			break;
+		case 0x04:
+			tvee->serial_number = 
+				eeprom_data[i+5] + 
+				(eeprom_data[i+6] << 8) + 
+				(eeprom_data[i+7] << 16);
+			break;
+		case 0x05:
+			tvee->audio_processor = eeprom_data[i+1] & 0x0f;
+			break;
+		case 0x06:
+			tvee->model = 
+				eeprom_data[i+1] + 
+				(eeprom_data[i+2] << 8);
+			tvee->revision = eeprom_data[i+5] +
+				(eeprom_data[i+6] << 8) +
+				(eeprom_data[i+7] << 16);
+			break;
+		case 0x0a:
+			tuner = eeprom_data[i+2];
+			t_format = eeprom_data[i+1];
+			break;
+		case 0x0e:
+			tvee->has_radio = eeprom_data[i+1];
+			break;
+		default:
+			printk(KERN_WARNING "Not sure what to do with tag [%02x]\n",tag);
+			/* dump the rest of the packet? */
+		}
+
+	}
+
+	if(!done) {
+		printk(KERN_WARNING "Ran out of data!\n");
+		return;
+	}
+
+	if(tvee->revision != 0) {
+		tvee->rev_str[0] = 32 + ((tvee->revision >> 18) & 0x3f);
+		tvee->rev_str[1] = 32 + ((tvee->revision >> 12) & 0x3f);
+		tvee->rev_str[2] = 32 + ((tvee->revision >>  6) & 0x3f);
+		tvee->rev_str[3] = 32 + ( tvee->revision        & 0x3f);
+		tvee->rev_str[4] = 0;
+	}
+
+	if (tuner < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) {
+		tvee->tuner_type = hauppauge_tuner[tuner].id;
+		t_name = hauppauge_tuner[tuner].name;
+	} else {
+		t_name = "<unknown>";
+	}
+
+	tvee->tuner_formats = 0;
+	t_fmt_name = "<none>";
+	for(i=0; i<8; i++) {
+		if( (t_format & (1<<i)) ) {
+			tvee->tuner_formats |= hauppauge_tuner_fmt[i].id;
+			/* yuck */
+			t_fmt_name = hauppauge_tuner_fmt[i].name;
+		}
+	}
+
+#if 0
+	if (t_format < sizeof(hauppauge_tuner_fmt)/sizeof(struct HAUPPAUGE_TUNER_FMT)) {
+		tvee->tuner_formats = hauppauge_tuner_fmt[t_format].id;
+		t_fmt_name = hauppauge_tuner_fmt[t_format].name;
+	} else {
+		t_fmt_name = "<unknown>";
+	}
+#endif
+
+	printk(KERN_INFO "tvee: Hauppauge: model=%d, rev=%s, serial#=%d\n",
+		   tvee->model,
+		   tvee->rev_str,
+		   tvee->serial_number);
+	printk(KERN_INFO "tvee: tuner=%s (idx=%d, type=%d)\n",
+		   t_name,
+		   tuner,
+		   tvee->tuner_type);
+	printk(KERN_INFO "tvee: tuner fmt=%s (eeprom=0x%02x, v4l2=0x%08x)\n",
+		   t_fmt_name,
+		   t_format,
+		   tvee->tuner_formats);
+
+	printk(KERN_INFO "tvee: audio_processor=%s (type=%d)\n",
+		   STRM(sndtype,tvee->audio_processor),
+		   tvee->audio_processor);
+
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* write I2C */
+int tvee_I2CWrite(struct i2c_client *client, 
+				  unsigned char b1,
+                  unsigned char b2, int both)
+{
+	unsigned char buffer[2];
+	int bytes = both ? 2 : 1;
+
+	buffer[0] = b1;
+	buffer[1] = b2;
+	if (bytes != i2c_master_send(client, buffer, bytes))
+		return -1;
+	return 0;
+}
+
+void __devinit tvee_readee(struct i2c_client *client, 
+						   unsigned char *eedata)
+{
+	int i;
+        
+	if (tvee_I2CWrite(client, 0, -1, 0)<0) {
+		printk(KERN_WARNING "tvee: readee error\n");
+		return;
+	}
+
+	for (i=0; i<256; i+=16) {
+		if (16 != i2c_master_recv(client,eedata+i,16)) {
+			printk(KERN_WARNING "tvee: readee error\n");
+			break;
+		}
+	}
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int
+tveeprom_command (struct i2c_client *client,
+		 unsigned int       cmd,
+		 void              *arg)
+{
+
+	struct tveeprom *eeprom = i2c_get_clientdata(client);
+	u32 *eeprom_props = arg;
+
+	switch (cmd) {
+
+	case 0:
+		eeprom_props[0] = eeprom->tuner_type;
+		eeprom_props[1] = eeprom->tuner_formats;
+		eeprom_props[2] = eeprom->model;
+		eeprom_props[3] = eeprom->revision;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+static unsigned short normal_i2c[] =
+    { I2C_TVEEPROM >> 1, I2C_TVEEPROMA >> 1, I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+
+static int tveeprom_i2c_id = 0;
+struct i2c_driver i2c_driver_tveeprom;
+
+static int
+tveeprom_detect_client (struct i2c_adapter *adapter,
+		       int                 address,
+		       int                 kind)
+{
+	struct i2c_client *client;
+	struct tveeprom *eeprom;
+
+	dprintk(1,
+		KERN_INFO
+		"tveeprom.c: detecting tveeprom client on address 0x%x\n",
+		address << 1);
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return 0;
+
+	client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	if (client == 0)
+		return -ENOMEM;
+	memset(client, 0, sizeof(struct i2c_client));
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &i2c_driver_tveeprom;
+	client->flags = I2C_CLIENT_ALLOW_USE;
+	client->id = tveeprom_i2c_id++;
+	snprintf(client->name, sizeof(client->name) - 1, "tveeprom[%d]",
+		 client->id);
+
+	i2c_set_clientdata(client, eeprom =
+	    kmalloc(sizeof(struct tveeprom), GFP_KERNEL));
+	if (eeprom == NULL) {
+		kfree(client);
+		return -ENOMEM;
+	}
+	memset(eeprom, 0, sizeof(struct tveeprom));
+	eeprom->tuner_type = -1;
+	eeprom->has_radio = 0;
+	eeprom->model = 0;
+
+	tvee_readee(client,eeprom_buf);
+	hauppauge_eeprom(eeprom,eeprom_buf);
+
+	return 0;
+}
+
+static int
+tveeprom_attach_adapter (struct i2c_adapter *adapter)
+{
+	if(adapter->id != (I2C_ALGO_BIT | I2C_HW_B_BT848))
+		return 0;
+	dprintk(1,
+		KERN_INFO
+		"tveeprom.c: starting probe for adapter %s (0x%x)\n",
+		adapter->name, adapter->id);
+	return i2c_probe(adapter, &addr_data, tveeprom_detect_client);
+}
+
+static int
+tveeprom_detach_client (struct i2c_client *client)
+{
+	struct tveeprom *eeprom = i2c_get_clientdata(client);
+	int err;
+
+	err = i2c_detach_client(client);
+	if (err) {
+		return err;
+	}
+
+	kfree(eeprom);
+	kfree(client);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+struct i2c_driver i2c_driver_tveeprom = {
+	.owner = THIS_MODULE,
+	.name = "tveeprom",
+
+	.id = I2C_DRIVERID_TVEEPROM,
+	.flags = I2C_DF_NOTIFY,
+
+	.attach_adapter = tveeprom_attach_adapter,
+	.detach_client = tveeprom_detach_client,
+	.command = tveeprom_command,
+};
+
+static int tveeprom_init (void)
+{
+	return i2c_add_driver(&i2c_driver_tveeprom);
+}
+
+static void tveeprom_exit (void)
+{
+	i2c_del_driver(&i2c_driver_tveeprom);
+}
+
+module_init(tveeprom_init);
+module_exit(tveeprom_exit);