patch-2.3.34 linux/drivers/char/bttv.c

Next file: linux/drivers/char/bttv.h
Previous file: linux/drivers/char/audiochip.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.33/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
@@ -1,9 +1,9 @@
-
-/* 
+/*
     bttv - Bt848 frame grabber driver
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
                            & Marcus Metzler (mocm@thp.uni-koeln.de)
+    (c) 1999 Gerd Knorr <kraxel@goldbach.in-berlin.de>
 
     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
@@ -21,7 +21,6 @@
 */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -41,43 +40,53 @@
 #include <linux/types.h>
 #include <linux/wrapper.h>
 #include <linux/interrupt.h>
-
-#include <asm/uaccess.h>
+#include <linux/version.h>
+#include <linux/kmod.h>
 #include <linux/vmalloc.h>
 
-#include <linux/videodev.h>
 #include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/videodev.h>
+
+
 #include "bttv.h"
 #include "tuner.h"
 
-#define DEBUG(x)		/* Debug driver */	
-#define IDEBUG(x)		/* Debug interrupt handler */
+#define DEBUG(x) 		/* Debug driver */
+#define IDEBUG(x) 		/* Debug interrupt handler */
+#define MIN(a,b) (((a)>(b))?(b):(a))
+#define MAX(a,b) (((a)>(b))?(a):(b))
 
 
 /* Anybody who uses more than four? */
 #define BTTV_MAX 4
-
 static void bt848_set_risc_jmps(struct bttv *btv);
 
-static unsigned int vidmem=0;   /* manually set video mem address */
-static int triton1=0;
-#ifndef USE_PLL
-/* 0=no pll, 1=28MHz, 2=34MHz */
-#define USE_PLL 0
-#endif
-#ifndef CARD_DEFAULT
-/* card type (see bttv.h) 0=autodetect */
-#define CARD_DEFAULT 0
-#endif
+static int bttv_num;			/* number of Bt848s in use */
+static struct bttv bttvs[BTTV_MAX];
+
 
-static unsigned long remap[BTTV_MAX];    /* remap Bt848 */
+/* insmod args */
+MODULE_PARM(triton1,"i");
+MODULE_PARM(remap,"1-4i");
+MODULE_PARM(radio,"1-4i");
+MODULE_PARM(card,"1-4i");
+MODULE_PARM(pll,"1-4i");
+MODULE_PARM(bigendian,"i");
+MODULE_PARM(fieldnr,"i");
+
+#if defined(__sparc__) || defined(__powerpc__)
+static unsigned int bigendian=1;
+#else
+static unsigned int bigendian=0;
+#endif
+static int triton1=0;
+static unsigned long remap[BTTV_MAX];
 static unsigned int radio[BTTV_MAX];
-static unsigned int card[BTTV_MAX] = { CARD_DEFAULT, CARD_DEFAULT, 
-                                       CARD_DEFAULT, CARD_DEFAULT };
-static unsigned int pll[BTTV_MAX] = { USE_PLL, USE_PLL, USE_PLL, USE_PLL };
+static unsigned int card[BTTV_MAX] = { 0, 0, 0, 0 };
+static unsigned int pll[BTTV_MAX] = { 0, 0, 0, 0};
+static unsigned int fieldnr = 0;
 
-static int bttv_num;			/* number of Bt848s in use */
-static struct bttv bttvs[BTTV_MAX];
 
 #define I2C_TIMING (0x7<<4)
 #define I2C_DELAY   10
@@ -86,9 +95,9 @@
     { btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); }
 #define I2C_GET()   (btread(BT848_I2C)&1)
 
-#define EEPROM_WRITE_DELAY    20000
 #define BURSTOFFSET 76
 
+
 /*******************************/
 /* Memory management functions */
 /*******************************/
@@ -121,9 +130,8 @@
                 if (!pmd_none(*pmd)) {
                         ptep = pte_offset(pmd, adr);
                         pte = *ptep;
-                        /* Note; page_address will panic for us if the page is high */
                         if(pte_present(pte))
-                                ret = page_address(pte_page(pte))|(adr&(PAGE_SIZE-1));
+                                ret = (page_address(pte_page(pte))|(adr&(PAGE_SIZE-1)));
                 }
         }
         MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
@@ -205,12 +213,6 @@
 	}
 }
 
-MODULE_PARM(vidmem,"i");
-MODULE_PARM(triton1,"i");
-MODULE_PARM(remap,"1-4i");
-MODULE_PARM(radio,"1-4i");
-MODULE_PARM(card,"1-4i");
-MODULE_PARM(pll,"1-4i");
 
 
 /*
@@ -223,7 +225,7 @@
 static int fbuffer_alloc(struct bttv *btv)
 {
 	if(!btv->fbuffer)
-		btv->fbuffer=(unsigned char *) rvmalloc(2*BTTV_MAX_FBUF);
+		btv->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS*BTTV_MAX_FBUF);
 	else
 		printk(KERN_ERR "bttv%d: Double alloc of fbuffer!\n",
 			btv->nr);
@@ -236,194 +238,204 @@
 /* ----------------------------------------------------------------------- */
 /* I2C functions                                                           */
 
-/* software I2C functions */
-
-static void i2c_setlines(struct i2c_bus *bus,int ctrl,int data)
+static void bttv_bit_setscl(void *data, int state)
 {
-        struct bttv *btv = (struct bttv*)bus->data;
-	btwrite((ctrl<<1)|data, BT848_I2C);
-	btread(BT848_I2C); /* flush buffers */
-	udelay(I2C_DELAY);
+	struct bttv *btv = (struct bttv*)data;
+
+	if (state)
+		btv->i2c_state |= 0x02;
+	else
+		btv->i2c_state &= ~0x02;
+	btwrite(btv->i2c_state, BT848_I2C);
+	btread(BT848_I2C);
 }
 
-static int i2c_getdataline(struct i2c_bus *bus)
+static void bttv_bit_setsda(void *data, int state)
 {
-        struct bttv *btv = (struct bttv*)bus->data;
-	return btread(BT848_I2C)&1;
+	struct bttv *btv = (struct bttv*)data;
+
+	if (state)
+		btv->i2c_state |= 0x01;
+	else
+		btv->i2c_state &= ~0x01;
+	btwrite(btv->i2c_state, BT848_I2C);
+	btread(BT848_I2C);
 }
 
-/* hardware I2C functions */
+static int bttv_bit_getscl(void *data)
+{
+	struct bttv *btv = (struct bttv*)data;
+	int state;
+	
+	state = btread(BT848_I2C) & 0x02 ? 1 : 0;
+	return state;
+}
 
-/* read I2C */
-static int I2CRead(struct i2c_bus *bus, unsigned char addr) 
+static int bttv_bit_getsda(void *data)
 {
-	u32 i;
-	u32 stat;
-	struct bttv *btv = (struct bttv*)bus->data;
-  
-	/* clear status bit ; BT848_INT_RACK is ro */
-	btwrite(BT848_INT_I2CDONE, BT848_INT_STAT);
-  
-	btwrite(((addr & 0xff) << 24) | btv->i2c_command, BT848_I2C);
-  
-	/*
-	 * Timeout for I2CRead is 1 second (this should be enough, really!)
-	 */
-	for (i=1000; i; i--)
-	{
-		stat=btread(BT848_INT_STAT);
-		if (stat & BT848_INT_I2CDONE)
-                        break;
-                mdelay(1);
-	}
-  
-	if (!i) 
-	{
-		printk(KERN_DEBUG "bttv%d: I2CRead timeout\n",
-			btv->nr);
-		return -1;
-	}
-	if (!(stat & BT848_INT_RACK))
-		return -2;
-  
-	i=(btread(BT848_I2C)>>8)&0xff;
-	return i;
+	struct bttv *btv = (struct bttv*)data;
+	int state;
+
+	state = btread(BT848_I2C) & 0x01;
+	return state;
 }
 
-/* set both to write both bytes, reset it to write only b1 */
+static void bttv_inc_use(struct i2c_adapter *adap)
+{
+	MOD_INC_USE_COUNT;
+}
 
-static int I2CWrite(struct i2c_bus *bus, unsigned char addr, unsigned char b1,
-		    unsigned char b2, int both)
+static void bttv_dec_use(struct i2c_adapter *adap)
 {
-	u32 i;
-	u32 data;
-	u32 stat;
-	struct bttv *btv = (struct bttv*)bus->data;
-  
-	/* clear status bit; BT848_INT_RACK is ro */
-	btwrite(BT848_INT_I2CDONE, BT848_INT_STAT);
-  
-	data=((addr & 0xff) << 24) | ((b1 & 0xff) << 16) | btv->i2c_command;
-	if (both)
-	{
-		data|=((b2 & 0xff) << 8);
-		data|=BT848_I2C_W3B;
-	}
-  
-	btwrite(data, BT848_I2C);
+	MOD_DEC_USE_COUNT;
+}
 
-	for (i=0x1000; i; i--)
-	{
-		stat=btread(BT848_INT_STAT);
-		if (stat & BT848_INT_I2CDONE)
-			break;
-                mdelay(1);
-	}
-  
-	if (!i) 
-	{
-		printk(KERN_DEBUG "bttv%d: I2CWrite timeout\n",
-			btv->nr);
-		return -1;
+static void call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
+{
+	int i;
+	
+	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+		if (NULL == btv->i2c_clients[i])
+			continue;
+		if (NULL == btv->i2c_clients[i]->driver->command)
+			continue;
+		btv->i2c_clients[i]->driver->command(
+			btv->i2c_clients[i],cmd,arg);
 	}
-	if (!(stat & BT848_INT_RACK))
-		return -2;
-  
-	return 0;
 }
 
-/* read EEPROM */
-static void readee(struct i2c_bus *bus, unsigned char *eedata)
+static int attach_inform(struct i2c_client *client)
 {
-	int i, k;
-        
-	if (I2CWrite(bus, 0xa0, 0, -1, 0)<0)
-	{
-		printk(KERN_WARNING "bttv: readee error\n");
-		return;
-	}
-        
-	for (i=0; i<256; i++)
-	{
-		k=I2CRead(bus, 0xa1);
-		if (k<0)
-		{
-			printk(KERN_WARNING "bttv: readee error\n");
+        struct bttv *btv = (struct bttv*)client->adapter->data;
+	int i;
+
+	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+		if (btv->i2c_clients[i] == NULL ||
+		    btv->i2c_clients[i]->driver->id == client->driver->id) {
+			btv->i2c_clients[i] = client;
 			break;
 		}
-		eedata[i]=k;
 	}
+	if (btv->tuner_type != -1)
+		call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
+        printk("bttv%d: i2c attach [%s]\n",btv->nr,client->name);
+        return 0;
 }
 
-/* write EEPROM */
-static void writeee(struct i2c_bus *bus, unsigned char *eedata)
+static int detach_inform(struct i2c_client *client)
 {
+        struct bttv *btv = (struct bttv*)client->adapter->data;
 	int i;
-  
-	for (i=0; i<256; i++)
-	{
-		if (I2CWrite(bus, 0xa0, i, eedata[i], 1)<0)
-		{
-			printk(KERN_WARNING "bttv: writeee error (%d)\n", i);
+        
+        printk("bttv%d: i2c detach [%s]\n",btv->nr,client->name);
+	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+		if (NULL != btv->i2c_clients[i] &&
+		    btv->i2c_clients[i]->driver->id == client->driver->id) {
+			btv->i2c_clients[i] = NULL;
 			break;
 		}
-		udelay(EEPROM_WRITE_DELAY);
 	}
+        return 0;
 }
 
-static void attach_inform(struct i2c_bus *bus, int id)
+static struct i2c_algo_bit_data i2c_algo_template = {
+	NULL,
+	bttv_bit_setsda,
+	bttv_bit_setscl,
+	bttv_bit_getsda,
+	bttv_bit_getscl,
+	10, 10, 100,
+};
+
+static struct i2c_adapter i2c_adap_template = {
+	"bt848",
+	I2C_HW_B_BT848,
+	NULL,
+	NULL,
+	bttv_inc_use,
+	bttv_dec_use,
+	attach_inform,
+	detach_inform,
+	NULL,
+};
+
+static struct i2c_client i2c_client_template = {
+        "bttv internal",
+        -1,
+        0,
+        0,
+        NULL,
+        NULL
+};
+
+static int init_bttv_i2c(struct bttv *btv)
 {
-        struct bttv *btv = (struct bttv*)bus->data;
-        
-	switch (id) 
-        {
-        	case I2C_DRIVERID_MSP3400:
-                	btv->have_msp3400 = 1;
-			break;
-        	case I2C_DRIVERID_TUNER:
-			btv->have_tuner = 1;
-			if (btv->tuner_type != -1) 
- 				i2c_control_device(&(btv->i2c), 
-                                                   I2C_DRIVERID_TUNER,
-                                                   TUNER_SET_TYPE,&btv->tuner_type);
-			break;
-	}
+	/* i2c bit_adapter */
+	memcpy(&btv->i2c_adap, &i2c_adap_template, sizeof(struct i2c_adapter));
+	memcpy(&btv->i2c_algo, &i2c_algo_template, sizeof(struct i2c_algo_bit_data));
+	memcpy(&btv->i2c_client, &i2c_client_template, sizeof(struct i2c_client));
+
+	sprintf(btv->i2c_adap.name+strlen(btv->i2c_adap.name),
+		" #%d", btv->nr);
+        btv->i2c_algo.data = btv;
+        btv->i2c_adap.data = btv;
+        btv->i2c_adap.algo_data = &btv->i2c_algo;
+        btv->i2c_client.adapter = &btv->i2c_adap;
+
+	bttv_bit_setscl(btv,1);
+	bttv_bit_setsda(btv,1);
+	
+	return i2c_bit_add_bus(&btv->i2c_adap);
 }
 
-static void detach_inform(struct i2c_bus *bus, int id)
+/* read I2C */
+static int I2CRead(struct bttv *btv, unsigned char addr) 
 {
-        struct bttv *btv = (struct bttv*)bus->data;
+        unsigned char buffer = 0;
 
-	switch (id) 
-	{
-		case I2C_DRIVERID_MSP3400:
-		        btv->have_msp3400 = 0;
-			break;
-		case I2C_DRIVERID_TUNER:
-			btv->have_tuner = 0;
-			break;
+        btv->i2c_client.addr = addr >> 1;
+        if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) {
+		printk("bttv%d: i2c read 0x%x: error\n",btv->nr,addr);
+                return -1;
 	}
+	printk("bttv%d: i2c read 0x%x: %d\n",btv->nr,addr,buffer);
+        return buffer;
 }
 
-static struct i2c_bus bttv_i2c_bus_template = 
+/* write I2C */
+static int I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
+                    unsigned char b2, int both)
 {
-        "bt848",
-        I2C_BUSID_BT848,
-	NULL,
+        unsigned char buffer[2];
+        int bytes = both ? 2 : 1;
+
+        btv->i2c_client.addr = addr >> 1;
+        buffer[0] = b1;
+        buffer[1] = b2;
+        if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes))
+                return -1;
+        return 0;
+}
+
+/* read EEPROM */
+static void readee(struct bttv *btv, unsigned char *eedata)
+{
+	int i;
+        
+	if (I2CWrite(btv, 0xa0, 0, -1, 0)<0) {
+		printk(KERN_WARNING "bttv: readee error\n");
+		return;
+	}
+	btv->i2c_client.addr = 0xa0 >> 1;
+	for (i=0; i<256; i+=16) {
+		if (16 != i2c_master_recv(&btv->i2c_client,eedata+i,16)) {
+			printk(KERN_WARNING "bttv: readee error\n");
+			break;
+		}
+	}
+}
 
-#if LINUX_VERSION_CODE >= 0x020100
-	SPIN_LOCK_UNLOCKED,
-#endif
 
-	attach_inform,
-	detach_inform,
-	
-	i2c_setlines,
-	i2c_getdataline,
-	I2CRead,
-	I2CWrite,
-};
- 
 /* ----------------------------------------------------------------------- */
 /* some hauppauge specific stuff                                           */
 
@@ -439,7 +451,7 @@
         { TUNER_ABSENT,        "External" },
         { TUNER_ABSENT,        "Unspecified" },
         { TUNER_ABSENT,        "Philips FI1216" },
-        { TUNER_ABSENT,        "Philips FI1216MF" },
+        { TUNER_PHILIPS_SECAM, "Philips FI1216MF" },
         { TUNER_PHILIPS_NTSC,  "Philips FI1236" },
         { TUNER_ABSENT,        "Philips FI1246" },
         { TUNER_ABSENT,        "Philips FI1256" },
@@ -462,11 +474,9 @@
 };
 
 static void
-hauppauge_eeprom(struct i2c_bus *bus)
+hauppauge_eeprom(struct bttv *btv)
 {
-        struct bttv *btv = (struct bttv*)bus->data;
-        
-        readee(bus, eeprom_data);
+        readee(btv, eeprom_data);
         if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) 
         {
                 btv->tuner_type = hauppauge_tuner[eeprom_data[9]].id;
@@ -488,76 +498,214 @@
         /* btaor(0, ~32, BT848_GPIO_OUT_EN); */
 }
 
-/* ----------------------------------------------------------------------- */
 
+/*	Imagenation L-Model PXC200 Framegrabber */
+/*  This is basically the same procedure as 
+ *  used by Alessandro Rubini in his pxc200 
+ *  driver, but using BTTV functions */
+static void init_PXC200(struct bttv *btv)
+{
+	int tmp;
+
+	/*	Initialise GPIO-connevted stuff */
+	btwrite(1<<13,BT848_GPIO_OUT_EN); /* Reset pin only */
+	btwrite(0,BT848_GPIO_DATA);
+	udelay(3);
+	btwrite(1<<13,BT848_GPIO_DATA);
+	/* GPIO inputs are pulled up, so no need to drive 
+	 * reset pin any longer */
+	btwrite(0,BT848_GPIO_OUT_EN);
+	
+	
+	/*	Initialise MAX517 DAC */
+	printk(KERN_INFO "Setting DAC reference voltage level ...\n");
+	I2CWrite(btv,0x5E,0,0x80,1);
+	
+	/*	Initialise 12C508 PIC */
+	/*	The I2CWrite and I2CRead commmands are actually to the 
+	 *	same chips - but the R/W bit is included in the address
+	 *	argument so the numbers are different */
+	
+	printk(KERN_INFO "Initialising 12C508 PIC chip ...\n");
+	
+	tmp=I2CWrite(btv,0x1E,0x08,0,1);
+	printk(KERN_INFO "I2C Write(0x08) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+	tmp=I2CWrite(btv,0x1E,0x09,0,1);
+	printk(KERN_INFO "I2C Write(0x09) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+	tmp=I2CWrite(btv,0x1E,0x0a,0,1);
+	printk(KERN_INFO "I2C Write(0x0a) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+	tmp=I2CWrite(btv,0x1E,0x0b,0,1);
+	printk(KERN_INFO "I2C Write(0x0b) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+	tmp=I2CWrite(btv,0x1E,0x0c,0,1);
+	printk(KERN_INFO "I2C Write(0x0c) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+	tmp=I2CWrite(btv,0x1E,0x0d,0,1);
+	printk(KERN_INFO "I2C Write(0x0d) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+	tmp=I2CWrite(btv,0x1E,0x01,0,1);
+	printk(KERN_INFO "I2C Write(0x01) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+	tmp=I2CWrite(btv,0x1E,0x02,0,1);
+	printk(KERN_INFO "I2C Write(0x02) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+	tmp=I2CWrite(btv,0x1E,0x03,0,1);
+	printk(KERN_INFO "I2C Write(0x03) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+	tmp=I2CWrite(btv,0x1E,0x04,0,1);
+	printk(KERN_INFO "I2C Write(0x04) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+	tmp=I2CWrite(btv,0x1E,0x05,0,1);
+	printk(KERN_INFO "I2C Write(0x05) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+	tmp=I2CWrite(btv,0x1E,0x06,0,1);
+	printk(KERN_INFO "I2C Write(0x06) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+	tmp=I2CWrite(btv,0x1E,0x00,0,1);
+	printk(KERN_INFO "I2C Write(0x00) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+	
+	printk(KERN_INFO "PXC200 Initialised.\n");
+}
+
+/* ----------------------------------------------------------------------- */
 
 struct tvcard
 {
+        char *name;
         int video_inputs;
         int audio_inputs;
         int tuner;
         int svhs;
         u32 gpiomask;
         u32 muxsel[8];
-        u32 audiomux[6]; /* Tuner, Radio, internal, external, mute, stereo */
-        u32 gpiomask2; /* GPIO MUX mask */
+        u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */
+        u32 gpiomask2;   /* GPIO MUX mask */
+
+	/* look for these i2c audio chips */
+	int msp34xx:1;
+	int tda8425:1;
+	int tda9840:1;
+	int tda985x:1;
+	int tea63xx:1;
 };
 
 static struct tvcard tvcards[] = 
 {
-        /* default */
-        { 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}},
-        /* MIRO */
-        { 4, 1, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10}},
-        /* Hauppauge */
-        { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}},
-	/* STB */
-        { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1}},
-	/* Intel??? */
-        { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}},
-	/* Diamond DTV2000 */
-        { 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3}},
-	/* AVerMedia TVPhone */
-        { 3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 0,11,11, 0}},
-        /* Matrix Vision MV-Delta */
-        { 5, 1, -1, 3, 0, { 2, 3, 1, 0, 0}},
-        /* Fly Video II */
-        { 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1}, 
-        {0, 0xc00, 0x800, 0x400, 0xc00, 0}},
-        /* TurboTV */
-        { 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0}},
-        /* Newer Hauppauge (bt878) */
-	{ 3, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4}},
-        /* MIRO PCTV pro */
-        { 3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10}},
-	/* ADS Technologies Channel Surfer TV (and maybe TV+FM) */
-	{ 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0}, 0},
-        /* AVerMedia TVCapture 98 */
-	{ 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0}, 0},
-        /* Aimslab VHX */
-        { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}},
-        /* Zoltrix TV-Max */
-        { 3, 1, 0, 2, 0x00000f, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0x8}},
-        /* Pixelview PlayTV (bt878) */
-        { 3, 4, 0, 2, 0x01e000, { 2, 0, 1, 1}, {0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 }},
-        /* "Leadtek WinView 601", */
-        { 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, {0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007}},
-        /* AVEC Intercapture */
-        { 3, 2, 0, 2, 0, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0}},
-         /* LifeView FlyKit w/o Tuner */
-        { 3, 1, -1, -1, 0x8dff00, { 2, 3, 1, 1}},
-        /* CEI Raffles Card */
-        { 3, 3, 0, 2, 0, {2, 3, 1, 1}, {0, 0, 0, 0 ,0}},
-         /* Lucky Star Image World ConferenceTV */
-        {3, 1, 0, 2, 16777215, { 2, 3, 1, 1}, { 131072, 1, 1638400, 3, 4}},
-         /* Phoebe Tv Master + FM */
-        { 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1},{0, 1, 0x800, 0x400, 0xc00, 0}},
-	/* Modular Technology MM205 PCTV, bt878 */
-	{ 2, 1, 0, -1, 7, { 2, 3 }, { 0, 0, 0, 0, 0 }},
-        /* Magic TView CPH061 (bt878) */
-	{ 3, 1, 0, 2, 0xe00, { 2, 0, 1, 1}, {0x400, 0, 0, 0, 0}},
+	/* 0x00 */
+        { "unknown",
+          3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0,
+	  1,1,1,1,0 },
+        { "MIRO PCTV",
+          4, 1, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10},0,
+	  1,1,1,1,0 },
+        { "Hauppauge old",
+          3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0,
+	  1,1,0,1,0 },
+        { "STB",
+          3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0,
+	  0,1,1,1,1 },
+
+        { "Intel",
+          3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0,
+	  1,1,1,1,0 },
+	{ "Diamond DTV2000",
+          3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3},0,
+	  1,1,1,1,0 },
+	{ "AVerMedia TVPhone",
+          3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 0,11,11, 0},0,
+	  1,1,1,1,0 },
+        { "MATRIX-Vision MV-Delta",
+          5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0,
+	  1,1,1,1,0 },
+
+	/* 0x08 */
+        { "Fly Video II",
+          3, 1, 0, 2, 0xc00, { 2, 3, 1, 1},
+	  { 0, 0xc00, 0x800, 0x400, 0xc00, 0},0,
+	  1,1,1,1,0 },
+        { "TurboTV",
+          3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0},0,
+	  1,1,1,1,0 },
+        { "Hauppauge new (bt878)",
+	  3, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0,
+	  1,1,0,1,0 },
+        { "MIRO PCTV pro",
+          3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10},0,
+	  1,1,1,1,0 },
+
+	{ "ADS Technologies Channel Surfer TV",
+	  3, 1, 2, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0,
+	  1,1,1,1,0 },
+        { "AVerMedia TVCapture 98",
+	  3, 1, 4, 0, 15, { 2, 3, 1, 0, 0}, { 13, 14, 11, 7, 0, 0},0,
+	  1,1,1,1,0 },
+        { "Aimslab VHX",
+          3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0,
+	  1,1,1,1,0 },
+        { "Zoltrix TV-Max",
+          3, 1, 0, 2,15, { 2, 3, 1, 1}, {0 , 0, 1 , 0, 10},0,
+	  1,1,1,1,0 },
+
+	/* 0x10 */
+        { "Pixelview PlayTV (bt878)",
+          3, 1, 0, 2, 0x01e000, { 2, 0, 1, 1},
+	  { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },0,
+	  1,1,1,1,0 },
+        { "Leadtek WinView 601",
+          3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0},
+	  { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},0,
+	  1,1,1,1,0 },
+        { "AVEC Intercapture",
+	  3, 2, 0, 2, 0, {2, 3, 1, 1}, {1, 0, 0, 0, 0},0,
+	  1,1,1,1,0 },
+	{ "LifeView FlyKit w/o Tuner",
+	  3, 1, -1, -1, 0x8dff00, { 2, 3, 1, 1}, { 0 },0,
+	  0,0,0,0,0 },
+
+        { "CEI Raffles Card",
+	  3, 3, 0, 2, 0, {2, 3, 1, 1}, {0, 0, 0, 0 ,0},0,
+	  1,1,1,1,0 },
+	{ "Lucky Star Image World ConferenceTV",
+	  3, 1, 0, 2, 16777215, { 2, 3, 1, 1}, { 131072, 1, 1638400, 3, 4},0,
+	  1,1,1,1,0 },
+	{ "Phoebe Tv Master + FM",
+	  3, 1, 0, 2, 0xc00, { 2, 3, 1, 1},{0, 1, 0x800, 0x400, 0xc00, 0},0,
+	  1,1,1,1,0 },
+        { "Modular Technology MM205 PCTV, bt878",
+	  2, 1, 0, -1, 7, { 2, 3 }, { 0, 0, 0, 0, 0 },0,
+	  1,1,1,1,0 },
+
+	/* 0x18 */
+	{ "Magic TView CPH061 (bt878)",
+	  3, 1, 0, 2, 0xe00, { 2, 0, 1, 1}, {0x400, 0, 0, 0, 0},0,
+	  1,1,1,1,0 },
+        { "Terratec/Vobis TV-Boostar",
+          3, 1, 0, 2, 16777215 , { 2, 3, 1, 1}, { 131072, 1, 1638400, 3,4},0,
+	  1,1,1,1,0 },
+        { "Newer Hauppauge WinCam (bt878)",
+ 	  4, 1, 0, 3, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0,
+	  1,1,1,1,0 },
+        { "MAXI TV Video PCI2",
+          3, 1, 0, 2, 0xffff, { 2, 3, 1, 1}, { 0, 1, 2, 3, 0xc00},0,
+	  1,1,1,1,0 },
+
+        { "Terratec TerraTV+",
+          3, 1, 0, 2, 0x70000, { 2, 3, 1, 1}, 
+          { 0x20000, 0x30000, 0x00000, 0x10000, 0x40000},0,
+	  1,1,1,1,0 },
+        { "Imagenation PXC200",
+          5, 1, -1, 4, 0, { 2, 3, 1, 0, 0}, { 0 }, 0,
+	  1,1,1,1,0 },
+        { "FlyVideo 98",
+          3, 1, 0, 2, 0x8dff00, {2, 3, 1, 1}, 
+          { 0, 0x8dff00, 0x800, 0x400, 0x8dff00, 0 },0,
+	  1,1,1,1,0 },
+        { "iProTV",
+	  3, 1, 0, 2, 1, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0 },0,
+	  1,1,1,1,0 },
+
+	/* 0x20 */
+	{ "Intel Create and Share PCI",
+	  4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 4, 4, 4, 4},0,
+	  1,1,1,1,0 },
+        { "Askey/Typhoon/Anubis Magic TView",
+	  3, 1, 0, 2, 0xe00, { 2, 0, 1, 1}, {0x400, 0x400, 0x400, 0x400, 0},0,
+	  1,1,1,1,0 },
 };
-#define TVCARDS (sizeof(tvcards)/sizeof(tvcard))
+#define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard))
+
+/* ----------------------------------------------------------------------- */
 
 static void audio(struct bttv *btv, int mode)
 {
@@ -585,17 +733,13 @@
 			break;
 	}
         /* if audio mute or not in H-lock, turn audio off */
-	if ((btv->audio&AUDIO_MUTE)
-#if 0	
-	 || 
-	    (!btv->radio && !(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC))
-#endif	    
-		)
+	if ((btv->audio&AUDIO_MUTE))
 	        mode=AUDIO_OFF;
-        if ((mode == 0) && (btv->radio))
-		mode = 1;
+        if ((mode == AUDIO_TUNER) && (btv->radio))
+		mode = AUDIO_RADIO;
 	btaor(tvcards[btv->type].audiomux[mode],
               ~tvcards[btv->type].gpiomask, BT848_GPIO_DATA);
+	call_i2c_clients(btv,AUDC_SET_INPUT,&(mode));
 }
 
 
@@ -697,7 +841,7 @@
 	}
 	while(time_before(jiffies,tv));
 
-        for (i=0; i<10; i++) 
+        for (i=0; i<100; i++) 
         {
                 if ((btread(BT848_DSTATUS)&BT848_DSTATUS_PLOCK))
                         btwrite(0,BT848_DSTATUS);
@@ -743,15 +887,7 @@
 		~tvcards[btv->type].gpiomask2, BT848_GPIO_DATA);
 }
 
-/*
- *	Set the registers for the size we have specified. Don't bother
- *	trying to understand this without the BT848 manual in front of
- *	you [AC]. 
- *
- *	PS: The manual is free for download in .pdf format from 
- *	www.brooktree.com - nicely done those folks.
- */
- 
+
 struct tvnorm 
 {
         u32 Fsc;
@@ -768,29 +904,14 @@
 	/* PAL-BDGHI */
         /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
  	/* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
-#ifdef VIDEODAT
         { 35468950,
           924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
           1135, 186, 924, 0x20, 255},
-#else
-        { 35468950,
-          924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
-          1135, 186, 924, 0x20, 255},
-#endif
-/*
-        { 35468950, 
-          768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
-	  944, 186, 922, 0x20, 255},
-*/
+
 	/* NTSC */
 	{ 28636363,
           768, 480,  910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
           910, 128, 910, 0x1a, 144},
-/*
-	{ 28636363,
-          640, 480,  910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
-          780, 122, 754, 0x1a, 144},
-*/
 #if 0
 	/* SECAM EAST */
 	{ 35468950, 
@@ -889,8 +1010,10 @@
 	unsigned long bpl=1024;		/* bytes per line */
 	unsigned long vadr=(unsigned long) vbuf;
 
-	*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0;
-	*(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0;
+	*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); 
+        *(ro++)=cpu_to_le32(0);
+	*(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
+        *(re++)=cpu_to_le32(0);
   
         /* In PAL 650 blocks of 256 DWORDs are sampled, but only if VDELAY
            is 2 and without separate VBI grabbing.
@@ -913,7 +1036,6 @@
 	return 0;
 }
 
-
 static int  make_prisctab(struct bttv *btv, unsigned int *ro,
                           unsigned int *re, 
                           unsigned int *vbuf, unsigned short width,
@@ -962,8 +1084,10 @@
 	cradr=cbadr+csize;
 	inter = (height>btv->win.cropheight/2) ? 1 : 0;
 	
-	*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); *(ro++)=0;
-	*(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); *(re++)=0;
+	*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3);
+        *(ro++)=0;
+	*(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3);
+        *(re++)=0;
   
 	for (line=0; line < (height<<(1^inter)); line++)
 	{
@@ -1005,7 +1129,7 @@
 		 vadr+=bl;
 		 if((rcmd&(15<<28))==BT848_RISC_WRITE123)
 		 {
-		 	*((*rp)++)=cpu_to_le32(kvirt_to_bus(cbadr));
+		 	*((*rp)++)=(kvirt_to_bus(cbadr));
 		 	cbadr+=blcb;
 		 	*((*rp)++)=cpu_to_le32(kvirt_to_bus(cradr));
 		 	cradr+=blcr;
@@ -1045,8 +1169,10 @@
 	inter = (height>btv->win.cropheight/2) ? 1 : 0;
 	bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2;
 	
-	*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0;
-	*(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0;
+	*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); 
+        *(ro++)=cpu_to_le32(0);
+	*(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
+        *(re++)=cpu_to_le32(0);
   
 	for (line=0; line < (height<<(1^inter)); line++)
 	{
@@ -1059,7 +1185,7 @@
 		if (bpl<=bl)
                 {
 		        *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
-                                               BT848_RISC_EOL|bpl);
+			        BT848_RISC_EOL|bpl); 
 			*((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr));
 			vadr+=bpl;
 		}
@@ -1156,18 +1282,28 @@
 	unsigned long adr;
 	unsigned char *clipmap, cbit, lastbit, outofmem;
 
+	if (btv->win.use_yuv) {
+		/* yuv-to-offscreen (BT848_COLOR_FMT_YUY2) */
+		bpp    = 2;
+		bpl    = btv->win.win2.pitch;
+		adr    = btv->win.vidadr + btv->win.win2.start;
+	} else {
+		bpp=btv->win.bpp;
+		if (bpp==15)	/* handle 15bpp as 16bpp in calculations */
+			bpp++;
+		bpl=btv->win.bpl;
+		adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl;
+	}
 	inter=(btv->win.interlace&1)^1;
-	bpp=btv->win.bpp;
-	if (bpp==15)	/* handle 15bpp as 16bpp in calculations */
-		bpp++;
-	bpl=btv->win.bpl;
-	ro=btv->risc_odd;
-	re=btv->risc_even;
-	if((width=btv->win.width)>1023)
+	width=btv->win.width;
+	height=btv->win.height;
+	if(width > 1023)
 		width = 1023;		/* sanity check */
-	if((height=btv->win.height)>625)
+	if(height > 625)
 		height = 625;		/* sanity check */
-	adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl;
+	ro=btv->risc_odd;
+	re=btv->risc_even;
+
 	if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) {
 		/* can't clip, don't generate any risc code */
 		*(ro++)=cpu_to_le32(BT848_RISC_JUMP);
@@ -1186,17 +1322,21 @@
 	/* clip against viewing window AND screen 
 	   so we do not have to rely on the user program
 	 */
-	clip_draw_rectangle(clipmap,(btv->win.x+width>btv->win.swidth) ?
-		(btv->win.swidth-btv->win.x) : width, 0, 1024, 768);
-	clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ?
-		(btv->win.sheight-btv->win.y) : height,1024,768);
-	if (btv->win.x<0)
-		clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768);
-	if (btv->win.y<0)
-		clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y));
+	if (!btv->win.use_yuv) {
+		clip_draw_rectangle(clipmap,(btv->win.x+width>btv->win.swidth) ?
+				    (btv->win.swidth-btv->win.x) : width, 0, 1024, 768);
+		clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ?
+				    (btv->win.sheight-btv->win.y) : height,1024,768);
+		if (btv->win.x<0)
+			clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768);
+		if (btv->win.y<0)
+			clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y));
+	}
 	
-	*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0;
-	*(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0;
+	*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
+        *(ro++)=cpu_to_le32(0);
+	*(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
+        *(re++)=cpu_to_le32(0);
 	
 	/* translate bitmap to risc code */
         for (line=outofmem=0; line < (height<<inter) && !outofmem; line++)
@@ -1216,8 +1356,9 @@
 				if (!lastbit) {
 					*((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|flags|len);
 					*((*rp)++)=cpu_to_le32(adr + bpp * sx);
-				} else
+				} else {
 					*((*rp)++)=cpu_to_le32(BT848_RISC_SKIP|flags|len);
+				}
 				lastbit=cbit;
 				sx += dx;
 				dx = 1;
@@ -1230,6 +1371,7 @@
 		if ((!inter)||(line&1))
                         adr+=bpl;
 	}
+
 	vfree(clipmap);
 	/* outofmem flag relies on the following code to discard extra data */
 	*(ro++)=cpu_to_le32(BT848_RISC_JUMP);
@@ -1238,6 +1380,15 @@
 	*(re++)=cpu_to_le32(btv->bus_vbi_odd);
 }
 
+/*
+ *	Set the registers for the size we have specified. Don't bother
+ *	trying to understand this without the BT848 manual in front of
+ *	you [AC]. 
+ *
+ *	PS: The manual is free for download in .pdf format from 
+ *	www.brooktree.com - nicely done those folks.
+ */
+ 
 /* set geometry for even/odd frames 
    just if you are wondering:
    handling of even and odd frames will be separated, e.g. for grabbing
@@ -1266,7 +1417,8 @@
 }
 
 
-static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt, int pllset)
+static void bt848_set_geo(struct bttv *btv, u16 width, u16 height,
+			  u16 fmt, int pllset)
 {
         u16 vscale, hscale;
 	u32 xsf, sr;
@@ -1279,7 +1431,7 @@
  	
 	if (!width || !height)
 	        return;
-	        
+
 	save_flags(flags);
 	cli();
 
@@ -1288,17 +1440,6 @@
         btv->win.cropheight=tvn->sheight;
         btv->win.cropwidth=tvn->swidth;
 
-/*
-	if (btv->win.cropwidth>tvn->cropwidth)
-                btv->win.cropwidth=tvn->cropwidth;
-	if (btv->win.cropheight>tvn->cropheight)
-	        btv->win.cropheight=tvn->cropheight;
-
-	if (width>btv->win.cropwidth)
-                width=btv->win.cropwidth;
-	if (height>btv->win.cropheight)
-	        height=btv->win.cropheight;
-*/
 	btwrite(tvn->adelay, BT848_ADELAY);
 	btwrite(tvn->bdelay, BT848_BDELAY);
 	btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM);
@@ -1306,27 +1447,28 @@
 	btwrite(1, BT848_VBI_PACK_DEL);
 
         btv->pll.pll_ofreq = tvn->Fsc;
-        if(pllset)
-        	set_pll(btv);
+	if (pllset)
+		set_pll(btv);
 
 	btwrite(fmt, BT848_COLOR_FMT);
-#ifdef __sparc__
-        if(fmt == BT848_COLOR_FMT_RGB32 ||
-           fmt == BT848_COLOR_FMT_RGB24) {
+	if (bigendian &&
+	    fmt == BT848_COLOR_FMT_RGB32) {
                 btwrite((BT848_COLOR_CTL_GAMMA		|
-                         BT848_COLOR_CTL_WSWAP_ODD	|
-                         BT848_COLOR_CTL_WSWAP_EVEN	|
-                         BT848_COLOR_CTL_BSWAP_ODD	|
-                         BT848_COLOR_CTL_BSWAP_EVEN),
-                        BT848_COLOR_CTL);
-        } else if(fmt == BT848_COLOR_FMT_RGB16 ||
-           fmt == BT848_COLOR_FMT_RGB15) {
-                btwrite((BT848_COLOR_CTL_GAMMA		|
-                         BT848_COLOR_CTL_BSWAP_ODD	|
-                         BT848_COLOR_CTL_BSWAP_EVEN),
-                        BT848_COLOR_CTL);
-        }
-#endif
+			 BT848_COLOR_CTL_WSWAP_ODD	|
+			 BT848_COLOR_CTL_WSWAP_EVEN	|
+			 BT848_COLOR_CTL_BSWAP_ODD	|
+			 BT848_COLOR_CTL_BSWAP_EVEN),
+			 BT848_COLOR_CTL);
+        } else if (bigendian &&
+		   (fmt == BT848_COLOR_FMT_RGB16 ||
+                    fmt == BT848_COLOR_FMT_RGB15)) {
+		btwrite((BT848_COLOR_CTL_GAMMA		|
+			 BT848_COLOR_CTL_BSWAP_ODD	|
+			 BT848_COLOR_CTL_BSWAP_EVEN),
+			 BT848_COLOR_CTL);
+        } else {
+		btwrite(0x10, BT848_COLOR_CTL);
+	}
 	hactive=width;
 
         vtc=0;
@@ -1350,18 +1492,18 @@
 	crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)|
 	        ((vactive>>4)&0x30)|((vdelay>>2)&0xc0);
 	vscale|= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0;
-	
+
 	bt848_set_eogeo(btv, 0, vtc, hscale, vscale, hactive, vactive,
 			hdelay, vdelay, crop);
 	bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, vactive,
 			hdelay, vdelay, crop);
-			
+
 	restore_flags(flags);
 }
 
 
 int bpp2fmt[4] = {
-        BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16, 
+        BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16,
         BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32 
 };
 
@@ -1369,9 +1511,14 @@
 {
         unsigned short format;
 
-        btv->win.color_fmt = format = 
-                (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 :
-                        bpp2fmt[(btv->win.bpp-1)&3];
+	if (btv->win.use_yuv) {
+		/* yuv-to-offscreen */
+		format = BT848_COLOR_FMT_YUY2;
+	} else {
+		format = (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 :
+			bpp2fmt[(btv->win.bpp-1)&3];
+	}
+	btv->win.color_fmt = format;
 
 	/*	RGB8 seems to be a 9x5x5 GRB color cube starting at
 	 *	color 16. Why the h... can't they even mention this in the
@@ -1385,45 +1532,39 @@
 	else
 	        btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL);
 
-        bt848_set_geo(btv, btv->win.width, btv->win.height, format, 1);
+        bt848_set_geo(btv, btv->win.width, btv->win.height, format,1);
 }
 
 /*
  *	Set TSA5522 synthesizer frequency in 1/16 Mhz steps
  */
 
+#if 0
 static void set_freq(struct bttv *btv, unsigned short freq)
 {
+	int naudio;
 	int fixme = freq; /* XXX */
-	
+	/* int oldAudio = btv->audio; */
+
         /* mute */
-        if (btv->have_msp3400)
-                i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400,
-                                   MSP_SWITCH_MUTE,0);
-
-        /* switch channel */
-        if (btv->have_tuner) {
-                if (btv->radio) {
-			i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER,
-					   TUNER_SET_RADIOFREQ,&fixme);
-                } else {
-			i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER,
-					   TUNER_SET_TVFREQ,&fixme);
-                }
-        }
+        AUDIO(AUDC_SWITCH_MUTE,0);
 
-        if (btv->have_msp3400) {
-                if (btv->radio) {
-			i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400,
-					   MSP_SET_RADIO,0);
-                } else {
-			i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400,
-					   MSP_SET_TVNORM,&(btv->win.norm));
-			i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400,
-					   MSP_NEWCHANNEL,0);
-                }
+	/* tune */
+	if (btv->radio) {
+		TUNER(TUNER_SET_RADIOFREQ,&fixme);
+	} else {
+		TUNER(TUNER_SET_TVFREQ,&fixme);
+        }
+	
+	if (btv->radio) {
+		AUDIO(AUDC_SET_RADIO,0);
+	} else {
+		AUDIO(AUDC_SET_TVNORM,&(btv->win.norm));
+		AUDIO(AUDC_NEWCHANNEL,0);
         }
 }
+#endif
+
 
 /*
  *	Grab into virtual memory.
@@ -1447,7 +1588,7 @@
 	 *	No grabbing past the end of the buffer!
 	 */
 	 
-	if(mp->frame>1 || mp->frame <0)
+	if(mp->frame>(MAX_GBUFFERS-1) || mp->frame <0)
 		return -EINVAL;
 		
 	if(mp->height <0 || mp->width <0)
@@ -1485,6 +1626,7 @@
 	re=ro+2048;
         make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format);
 	/* bt848_set_risc_jmps(btv); */
+        cli();
         btv->frame_stat[mp->frame] = GBUFFER_GRABBING;
         if (btv->grabbing) {
 		btv->gfmt_next=palette2fmt[mp->format];
@@ -1508,12 +1650,14 @@
 		}
 		btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ);
         }
+        sti();
 	btor(3, BT848_CAP_CTL);
 	btor(3, BT848_GPIO_DMA_CTL);
 	/* interruptible_sleep_on(&btv->capq); */
 	return 0;
 }
 
+
 static long bttv_write(struct video_device *v, const char *buf, unsigned long count, int nonblock)
 {
 	return -EINVAL;
@@ -1523,6 +1667,7 @@
 {
 	struct bttv *btv= (struct bttv *)v;
 	int q,todo;
+
 	/* BROKEN: RETURNS VBI WHEN IT SHOULD RETURN GRABBED VIDEO FRAME */
 	todo=count;
 	while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) 
@@ -1569,18 +1714,17 @@
 static int bttv_open(struct video_device *dev, int flags)
 {
 	struct bttv *btv = (struct bttv *)dev;
-	int i, ret;
-	
+        int i,ret;
+
 	ret = -EBUSY;
-	down(&btv->lock);
-        if (btv->user)
+	if (btv->user)
 		goto out_unlock;
-
-	btv->fbuffer= (unsigned char *) rvmalloc(2*BTTV_MAX_FBUF);
+	
+	btv->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS*BTTV_MAX_FBUF);
 	ret = -ENOMEM;
-        if (!btv->fbuffer)
+	if (!btv->fbuffer)
 		goto out_unlock;
-	audio(btv, AUDIO_UNMUTE);
+
         btv->grabbing = 0;
         btv->grab = 0;
         btv->lastgrab = 0;
@@ -1588,9 +1732,9 @@
                 btv->frame_stat[i] = GBUFFER_UNUSED;
 
         btv->user++;
-        up(&btv->lock);
+	up(&btv->lock);
         MOD_INC_USE_COUNT;
-        return 0;   
+        return 0;
 
  out_unlock:
 	up(&btv->lock);
@@ -1601,9 +1745,8 @@
 {
 	struct bttv *btv=(struct bttv *)dev;
 
-	down(&btv->lock);	
+	down(&btv->lock);
 	btv->user--;
-	audio(btv, AUDIO_INTERN);
 	btv->cap&=~3;
 	bt848_set_risc_jmps(btv);
 
@@ -1621,15 +1764,16 @@
 	 *	be sure its safe to free the buffer. We wait 5-6 fields
 	 *	which is more than sufficient to be sure.
 	 */
-	 
+
 	current->state = TASK_UNINTERRUPTIBLE;
 	schedule_timeout(HZ/10);	/* Wait 1/10th of a second */
 	
 	/*
 	 *	We have allowed it to drain.
 	 */
+
 	if(btv->fbuffer)
-		rvfree((void *) btv->fbuffer, 2*BTTV_MAX_FBUF);
+		rvfree((void *) btv->fbuffer, MAX_GBUFFERS*BTTV_MAX_FBUF);
 	btv->fbuffer=0;
 	up(&btv->lock);
 	MOD_DEC_USE_COUNT;  
@@ -1680,6 +1824,7 @@
 	btaor(datahi, ~1, BT848_O_CONTROL);
 }
 
+
 /*
  *	ioctl routine
  */
@@ -1687,619 +1832,597 @@
 
 static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
 {
-	unsigned char eedata[256];
 	struct bttv *btv=(struct bttv *)dev;
  	int i;
   	
-	switch (cmd)
-	{	
-		case VIDIOCGCAP:
-		{
-			struct video_capability b;
-			strcpy(b.name,btv->video_dev.name);
-			b.type = VID_TYPE_CAPTURE|
-			 	VID_TYPE_TUNER|
-				VID_TYPE_TELETEXT|
-				VID_TYPE_OVERLAY|
-				VID_TYPE_CLIPPING|
-				VID_TYPE_FRAMERAM|
-				VID_TYPE_SCALES;
-			b.channels = tvcards[btv->type].video_inputs;
-			b.audios = tvcards[btv->type].audio_inputs;
-			b.maxwidth = tvnorms[btv->win.norm].swidth;
-			b.maxheight = tvnorms[btv->win.norm].sheight;
-			b.minwidth = 32;
-			b.minheight = 32;
-			if(copy_to_user(arg,&b,sizeof(b)))
-				return -EFAULT;
-			return 0;
-		}
-		case VIDIOCGCHAN:
+	switch (cmd) {
+	case VIDIOCGCAP:
+	{
+		struct video_capability b;
+		strcpy(b.name,btv->video_dev.name);
+		b.type = VID_TYPE_CAPTURE|
+			((tvcards[btv->type].tuner != -1) ? VID_TYPE_TUNER : 0) |
+			VID_TYPE_OVERLAY|
+			VID_TYPE_CLIPPING|
+			VID_TYPE_FRAMERAM|
+			VID_TYPE_SCALES;
+		b.channels = tvcards[btv->type].video_inputs;
+		b.audios = tvcards[btv->type].audio_inputs;
+		b.maxwidth = tvnorms[btv->win.norm].swidth;
+		b.maxheight = tvnorms[btv->win.norm].sheight;
+		b.minwidth = 32;
+		b.minheight = 32;
+		if(copy_to_user(arg,&b,sizeof(b)))
+			return -EFAULT;
+		return 0;
+	}
+	case VIDIOCGCHAN:
+	{
+		struct video_channel v;
+		if(copy_from_user(&v, arg,sizeof(v)))
+			return -EFAULT;
+		v.flags=VIDEO_VC_AUDIO;
+		v.tuners=0;
+		v.type=VIDEO_TYPE_CAMERA;
+		v.norm = btv->win.norm;
+		if (v.channel>=tvcards[btv->type].video_inputs)
+			return -EINVAL;
+		if(v.channel==tvcards[btv->type].tuner) 
 		{
-			struct video_channel v;
-			if(copy_from_user(&v, arg,sizeof(v)))
-				return -EFAULT;
-			v.flags=VIDEO_VC_AUDIO;
-			v.tuners=0;
-			v.type=VIDEO_TYPE_CAMERA;
-			v.norm = btv->win.norm;
-                        if (v.channel>=tvcards[btv->type].video_inputs)
-                                return -EINVAL;
-                        if(v.channel==tvcards[btv->type].tuner) 
-                        {
-                                strcpy(v.name,"Television");
-                                v.flags|=VIDEO_VC_TUNER;
-                                v.type=VIDEO_TYPE_TV;
-                                v.tuners=1;
-                        } 
-                        else if(v.channel==tvcards[btv->type].svhs) 
-                                strcpy(v.name,"S-Video");
-                        else
-                                sprintf(v.name,"Composite%d",v.channel);
-
-			if(copy_to_user(arg,&v,sizeof(v)))
-				return -EFAULT;
-			return 0;
-		}
-		/*
-		 *	Each channel has 1 tuner
-		 */
-		case VIDIOCSCHAN:
-		{
-			struct video_channel v;
-			if(copy_from_user(&v, arg,sizeof(v)))
-				return -EFAULT;
-                        
-                        if (v.channel>tvcards[btv->type].video_inputs)
-                                return -EINVAL;
-			if(v.norm!=VIDEO_MODE_PAL&&v.norm!=VIDEO_MODE_NTSC
-			   &&v.norm!=VIDEO_MODE_SECAM)
-				return -EOPNOTSUPP;
-			down(&btv->lock);
-			bt848_muxsel(btv, v.channel);
+			strcpy(v.name,"Television");
+			v.flags|=VIDEO_VC_TUNER;
+			v.type=VIDEO_TYPE_TV;
+			v.tuners=1;
+		} 
+		else if(v.channel==tvcards[btv->type].svhs) 
+			strcpy(v.name,"S-Video");
+		else
+			sprintf(v.name,"Composite%d",v.channel);
+		
+		if(copy_to_user(arg,&v,sizeof(v)))
+			return -EFAULT;
+		return 0;
+	}
+	/*
+	 *	Each channel has 1 tuner
+	 */
+	case VIDIOCSCHAN:
+	{
+		struct video_channel v;
+		if(copy_from_user(&v, arg,sizeof(v)))
+			return -EFAULT;
+		
+		if (v.channel>tvcards[btv->type].video_inputs)
+			return -EINVAL;
+		if (v.norm > (sizeof(tvnorms)/sizeof(*tvnorms)))
+			return -EOPNOTSUPP;
+
+		call_i2c_clients(btv,cmd,&v);
+		down(&btv->lock);
+		bt848_muxsel(btv, v.channel);
+		btv->channel=v.channel;
+		if (btv->win.norm != v.norm) {
 			btv->win.norm = v.norm;
-                        make_vbitab(btv);
+			make_vbitab(btv);
 			bt848_set_winsize(btv);
-			btv->channel=v.channel;
-			up(&btv->lock);
-			return 0;
-		}
-		case VIDIOCGTUNER:
-		{
-			struct video_tuner v;
-			if(copy_from_user(&v,arg,sizeof(v))!=0)
-				return -EFAULT;
-			if(v.tuner||btv->channel)	/* Only tuner 0 */
-				return -EINVAL;
-			strcpy(v.name, "Television");
-			v.rangelow=0;
-			v.rangehigh=0xFFFFFFFF;
-			v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
-			if (btv->audio_chip == TDA9840) {
-				v.flags |= VIDEO_AUDIO_VOLUME;
-				v.mode = VIDEO_SOUND_MONO|VIDEO_SOUND_STEREO;
-				v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2;
-			}
-			if (btv->audio_chip == TDA9850) {
-				unsigned char ALR1;
-				ALR1 = I2CRead(&(btv->i2c), I2C_TDA9850|1);
-				if (ALR1 & 32)
-					v.flags |= VIDEO_TUNER_STEREO_ON;
-			}
-			v.mode = btv->win.norm;
-			v.signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
-			if(copy_to_user(arg,&v,sizeof(v)))
-				return -EFAULT;
-			return 0;
 		}
-		/* We have but one tuner */
-		case VIDIOCSTUNER:
-		{
-			struct video_tuner v;
-			if(copy_from_user(&v, arg, sizeof(v)))
-				return -EFAULT;
-			/* Only one channel has a tuner */
-                        if(v.tuner!=tvcards[btv->type].tuner)
- 				return -EINVAL;
+		up(&btv->lock);
+		return 0;
+	}
+	case VIDIOCGTUNER:
+	{
+		struct video_tuner v;
+		if(copy_from_user(&v,arg,sizeof(v))!=0)
+			return -EFAULT;
+		if(v.tuner||btv->channel)	/* Only tuner 0 */
+			return -EINVAL;
+		strcpy(v.name, "Television");
+		v.rangelow=0;
+		v.rangehigh=0xFFFFFFFF;
+		v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
+		v.mode = btv->win.norm;
+		v.signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
+		call_i2c_clients(btv,cmd,&v);
+		if(copy_to_user(arg,&v,sizeof(v)))
+			return -EFAULT;
+		return 0;
+	}
+	/* We have but one tuner */
+	case VIDIOCSTUNER:
+	{
+		struct video_tuner v;
+		if(copy_from_user(&v, arg, sizeof(v)))
+			return -EFAULT;
+		/* Only one channel has a tuner */
+		if(v.tuner!=tvcards[btv->type].tuner)
+			return -EINVAL;
  				
-			if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC
-			   &&v.mode!=VIDEO_MODE_SECAM)
-				return -EOPNOTSUPP;
- 			btv->win.norm = v.mode;
- 			down(&btv->lock);
- 			bt848_set_winsize(btv);
- 			up(&btv->lock);
-			return 0;
-		}
-		case VIDIOCGPICT:
-		{
-			struct video_picture p=btv->picture;
-			if(btv->win.depth==8)
-				p.palette=VIDEO_PALETTE_HI240;
-			if(btv->win.depth==15)
-				p.palette=VIDEO_PALETTE_RGB555;
-			if(btv->win.depth==16)
-				p.palette=VIDEO_PALETTE_RGB565;
-			if(btv->win.depth==24)
-				p.palette=VIDEO_PALETTE_RGB24;
-			if(btv->win.depth==32)
-				p.palette=VIDEO_PALETTE_RGB32;
-			
-			if(copy_to_user(arg, &p, sizeof(p)))
-				return -EFAULT;
-			return 0;
-		}
-		case VIDIOCSPICT:
-		{
-			struct video_picture p;
-			int format;
-			if(copy_from_user(&p, arg,sizeof(p)))
-				return -EFAULT;
-			down(&btv->lock);
-			/* We want -128 to 127 we get 0-65535 */
-			bt848_bright(btv, (p.brightness>>8)-128);
-			/* 0-511 for the colour */
-			bt848_sat_u(btv, p.colour>>7);
-			bt848_sat_v(btv, ((p.colour>>7)*201L)/237);
-			/* -128 to 127 */
-			bt848_hue(btv, (p.hue>>8)-128);
-			/* 0-511 */
-			bt848_contrast(btv, p.contrast>>7);
-			btv->picture = p;
-
-                        /* set palette if bpp matches */
-                        if (p.palette < sizeof(palette2fmt)/sizeof(int)) {
-                                format = palette2fmt[p.palette];
-                                if (fmtbppx2[format&0x0f]/2 == btv->win.bpp)
-                                        btv->win.color_fmt = format;
-                        }
+		if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC
+		   &&v.mode!=VIDEO_MODE_SECAM)
+			return -EOPNOTSUPP;
+		call_i2c_clients(btv,cmd,&v);
+		if (btv->win.norm != v.mode) {
+			btv->win.norm = v.mode;
+                        down(&btv->lock);
+			make_vbitab(btv);
+			bt848_set_winsize(btv);
 			up(&btv->lock);
-                	return 0;
 		}
-		case VIDIOCSWIN:
-		{
-			struct video_window vw;
-			struct video_clip *vcp = NULL;
-			int on;
-			
-			if(copy_from_user(&vw,arg,sizeof(vw)))
-				return -EFAULT;
-				
- 			if(vw.flags || vw.width < 16 || vw.height < 16) 
-                        {
-                        	down(&btv->lock);
- 			        bt848_cap(btv,0);
- 			        up(&btv->lock);
-				return -EINVAL;
-                        }		
-			if (btv->win.bpp < 4) 
-                        {	/* 32-bit align start and adjust width */
-				int i = vw.x;
-				vw.x = (vw.x + 3) & ~3;
-				i = vw.x - i;
-				vw.width -= i;
-			}
+		return 0;
+	}
+	case VIDIOCGPICT:
+	{
+		struct video_picture p=btv->picture;
+		if(btv->win.depth==8)
+			p.palette=VIDEO_PALETTE_HI240;
+		if(btv->win.depth==15)
+			p.palette=VIDEO_PALETTE_RGB555;
+		if(btv->win.depth==16)
+			p.palette=VIDEO_PALETTE_RGB565;
+		if(btv->win.depth==24)
+			p.palette=VIDEO_PALETTE_RGB24;
+		if(btv->win.depth==32)
+			p.palette=VIDEO_PALETTE_RGB32;
 			
-			down(&btv->lock);
-			btv->win.x=vw.x;
-			btv->win.y=vw.y;
-			btv->win.width=vw.width;
-			btv->win.height=vw.height;
-
-			if(btv->win.height>btv->win.cropheight/2)
-				btv->win.interlace=1;
-			else
-				btv->win.interlace=0;
-
-			on=(btv->cap&3);
+		if(copy_to_user(arg, &p, sizeof(p)))
+			return -EFAULT;
+		return 0;
+	}
+	case VIDIOCSPICT:
+	{
+		struct video_picture p;
+		if(copy_from_user(&p, arg,sizeof(p)))
+			return -EFAULT;
+		down(&btv->lock);
+		/* We want -128 to 127 we get 0-65535 */
+		bt848_bright(btv, (p.brightness>>8)-128);
+		/* 0-511 for the colour */
+		bt848_sat_u(btv, p.colour>>7);
+		bt848_sat_v(btv, ((p.colour>>7)*201L)/237);
+		/* -128 to 127 */
+		bt848_hue(btv, (p.hue>>8)-128);
+		/* 0-511 */
+		bt848_contrast(btv, p.contrast>>7);
+		btv->picture = p;
+		up(&btv->lock);
+		return 0;
+	}
+	case VIDIOCSWIN:
+	{
+		struct video_window vw;
+		struct video_clip *vcp = NULL;
+		int on;
 			
+		if(copy_from_user(&vw,arg,sizeof(vw)))
+			return -EFAULT;
+				
+		if(vw.flags || vw.width < 16 || vw.height < 16) 
+		{
+                        down(&btv->lock);
 			bt848_cap(btv,0);
-			bt848_set_winsize(btv);
-			
 			up(&btv->lock);
+			return -EINVAL;
+		}		
+		if (btv->win.bpp < 4) 
+		{	/* adjust and align writes */
+			vw.x = (vw.x + 3) & ~3;
+			vw.width &= ~3;
+		}
+		down(&btv->lock);
+		btv->win.use_yuv=0;
+		btv->win.x=vw.x;
+		btv->win.y=vw.y;
+		btv->win.width=vw.width;
+		btv->win.height=vw.height;
 
-			/*
-			 *	Do any clips.
-			 */
-			if(vw.clipcount<0) {
-				if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL)
-					return -ENOMEM;
-				if(copy_from_user(vcp, vw.clips,
-					VIDEO_CLIPMAP_SIZE)) {
-					vfree(vcp);
-					return -EFAULT;
-				}
-			} else if (vw.clipcount) {
-				if((vcp=vmalloc(sizeof(struct video_clip)*
-					(vw.clipcount))) == NULL)
-					return -ENOMEM;
-				if(copy_from_user(vcp,vw.clips,
-					sizeof(struct video_clip)*
-					vw.clipcount)) {
-					vfree(vcp);
-					return -EFAULT;
-				}
+		on=(btv->cap&3);
+			
+		bt848_cap(btv,0);
+		bt848_set_winsize(btv);
+		up(&btv->lock);
+
+		/*
+		 *	Do any clips.
+		 */
+		if(vw.clipcount<0) {
+			if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL)
+				return -ENOMEM;
+			if(copy_from_user(vcp, vw.clips,
+					  VIDEO_CLIPMAP_SIZE)) {
+				vfree(vcp);
+				return -EFAULT;
 			}
-			down(&btv->lock);
-			make_clip_tab(btv, vcp, vw.clipcount);
-			if (vw.clipcount != 0)
+		} else if (vw.clipcount) {
+			if((vcp=vmalloc(sizeof(struct video_clip)*
+					(vw.clipcount))) == NULL)
+				return -ENOMEM;
+			if(copy_from_user(vcp,vw.clips,
+					  sizeof(struct video_clip)*
+					  vw.clipcount)) {
 				vfree(vcp);
-			if(on && btv->win.vidadr!=0)
-				bt848_cap(btv,1);
-			up(&btv->lock);
-			return 0;
-		}
-		case VIDIOCGWIN:
-		{
-			struct video_window vw;
-			/* Oh for a COBOL move corresponding .. */
-			vw.x=btv->win.x;
-			vw.y=btv->win.y;
-			vw.width=btv->win.width;
-			vw.height=btv->win.height;
-			vw.chromakey=0;
-			vw.flags=0;
-			if(btv->win.interlace)
-				vw.flags|=VIDEO_WINDOW_INTERLACE;
-			if(copy_to_user(arg,&vw,sizeof(vw)))
 				return -EFAULT;
-			return 0;
+			}
 		}
-		case VIDIOCCAPTURE:
-		{
-			int v;
-			if(copy_from_user(&v, arg,sizeof(v)))
-				return -EFAULT;
-		        if(v!=0 && (btv->win.vidadr==0 || btv->win.width==0
-				   || btv->win.height==0))
-				   return -EINVAL;
-
-			down(&btv->lock);				   
-			if(v==0)
-				bt848_cap(btv,0);
-			else
-				bt848_cap(btv,1);
-			up(&btv->lock);
+		down(&btv->lock);
+		make_clip_tab(btv, vcp, vw.clipcount);
+		if (vw.clipcount != 0)
+			vfree(vcp);
+		if(on && btv->win.vidadr!=0)
+			bt848_cap(btv,1);
+		up(&btv->lock);
+		return 0;
+	}
+	case VIDIOCSWIN2:
+	{
+		/* experimental -- right now it handles unclipped yuv data only */
+		struct video_window2 vo;
+		__u32 fbsize;
+		int on;
+			
+		if(copy_from_user(&vo,arg,sizeof(vo)))
+			return -EFAULT;
 
-			return 0;
-		}
-		case VIDIOCGFBUF:
-		{
-			struct video_buffer v;
-			v.base=(void *)btv->win.vidadr;
-			v.height=btv->win.sheight;
-			v.width=btv->win.swidth;
-			v.depth=btv->win.depth;
-			v.bytesperline=btv->win.bpl;
-			if(copy_to_user(arg, &v,sizeof(v)))
-				return -EFAULT;
-			return 0;
+		fbsize = btv->win.sheight * btv->win.bpl;
+		if (vo.start + vo.pitch*vo.height > fbsize)
+			return -EINVAL;
+                if (vo.palette != VIDEO_PALETTE_YUV422)
+			return -EINVAL;
+		
+		down(&btv->lock);
+		btv->win.use_yuv=1;
+		memcpy(&btv->win.win2,&vo,sizeof(vo));
+		btv->win.width=vo.width;
+		btv->win.height=vo.height;
+
+		on=(btv->cap&3);
+		bt848_cap(btv,0);
+		bt848_set_winsize(btv);
+		make_clip_tab(btv, NULL, 0);
+		if(on && btv->win.vidadr!=0)
+			bt848_cap(btv,1);
+		up(&btv->lock);
+		return 0;
+	}
+	case VIDIOCGWIN:
+	{
+		struct video_window vw;
+		/* Oh for a COBOL move corresponding .. */
+		vw.x=btv->win.x;
+		vw.y=btv->win.y;
+		vw.width=btv->win.width;
+		vw.height=btv->win.height;
+		vw.chromakey=0;
+		vw.flags=0;
+		if(btv->win.interlace)
+			vw.flags|=VIDEO_WINDOW_INTERLACE;
+		if(copy_to_user(arg,&vw,sizeof(vw)))
+			return -EFAULT;
+		return 0;
+	}
+	case VIDIOCCAPTURE:
+	{
+		int v;
+		if(copy_from_user(&v, arg,sizeof(v)))
+			return -EFAULT;
+		if(btv->win.vidadr == 0)
+			return -EINVAL;
+		if (0 == btv->win.use_yuv && (btv->win.width==0 || btv->win.height==0))
+			return -EINVAL;
+		down(&btv->lock);
+		if(v==0)
+			bt848_cap(btv,0);
+		else
+			bt848_cap(btv,1);
+		up(&btv->lock);
+		return 0;
+	}
+	case VIDIOCGFBUF:
+	{
+		struct video_buffer v;
+		v.base=(void *)btv->win.vidadr;
+		v.height=btv->win.sheight;
+		v.width=btv->win.swidth;
+		v.depth=btv->win.depth;
+		v.bytesperline=btv->win.bpl;
+		if(copy_to_user(arg, &v,sizeof(v)))
+			return -EFAULT;
+		return 0;
 			
-		}
-		case VIDIOCSFBUF:
-		{
-			struct video_buffer v;
-#if LINUX_VERSION_CODE >= 0x020100
-			if(!capable(CAP_SYS_ADMIN)
-			&& !capable(CAP_SYS_RAWIO))
-#else
-			if(!suser())
-#endif
-				return -EPERM;
-			if(copy_from_user(&v, arg,sizeof(v)))
-				return -EFAULT;
-			if(v.depth!=8 && v.depth!=15 && v.depth!=16 && 
-				v.depth!=24 && v.depth!=32 && v.width > 16 &&
-				v.height > 16 && v.bytesperline > 16)
-				return -EINVAL;
-			down(&btv->lock);
-                        if (v.base)
-                        	btv->win.vidadr=(unsigned long)v.base;
-			btv->win.sheight=v.height;
-			btv->win.swidth=v.width;
-			btv->win.bpp=((v.depth+7)&0x38)/8;
-			btv->win.depth=v.depth;
-			btv->win.bpl=v.bytesperline;
+	}
+	case VIDIOCSFBUF:
+	{
+		struct video_buffer v;
+		if(!capable(CAP_SYS_ADMIN) &&
+		   !capable(CAP_SYS_RAWIO))
+			return -EPERM;
+		if(copy_from_user(&v, arg,sizeof(v)))
+			return -EFAULT;
+		if(v.depth!=8 && v.depth!=15 && v.depth!=16 && 
+		   v.depth!=24 && v.depth!=32 && v.width > 16 &&
+		   v.height > 16 && v.bytesperline > 16)
+			return -EINVAL;
+		down(&btv->lock);
+		if (v.base)
+			btv->win.vidadr=(unsigned long)v.base;
+		btv->win.sheight=v.height;
+		btv->win.swidth=v.width;
+		btv->win.bpp=((v.depth+7)&0x38)/8;
+		btv->win.depth=v.depth;
+		btv->win.bpl=v.bytesperline;
 			
-			DEBUG(printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n",
-				v.base, v.width,v.height, btv->win.bpp, btv->win.bpl));
-			bt848_set_winsize(btv);
-			up(&btv->lock);
-			return 0;		
-		}
-		case VIDIOCKEY:
-		{
-			/* Will be handled higher up .. */
-			return 0;
-		}
-		case VIDIOCGFREQ:
-		{
-			unsigned long v=btv->win.freq;
-			if(copy_to_user(arg,&v,sizeof(v)))
-				return -EFAULT;
-			return 0;
+		DEBUG(printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n",
+			     v.base, v.width,v.height, btv->win.bpp, btv->win.bpl));
+		bt848_set_winsize(btv);
+		up(&btv->lock);
+		return 0;		
+	}
+	case VIDIOCKEY:
+	{
+		/* Will be handled higher up .. */
+		return 0;
+	}
+	case VIDIOCGFREQ:
+	{
+		unsigned long v=btv->win.freq;
+		if(copy_to_user(arg,&v,sizeof(v)))
+			return -EFAULT;
+		return 0;
+	}
+	case VIDIOCSFREQ:
+	{
+		unsigned long v;
+		if(copy_from_user(&v, arg, sizeof(v)))
+			return -EFAULT;
+		btv->win.freq=v;
+		call_i2c_clients(btv,cmd,&v);
+		return 0;
+	}
+	
+	case VIDIOCGAUDIO:
+	{
+		struct video_audio v;
+
+		v=btv->audio_dev;
+		v.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE);
+		v.flags|=VIDEO_AUDIO_MUTABLE;
+		strcpy(v.name,"TV");
+
+		v.mode = VIDEO_SOUND_MONO;
+		call_i2c_clients(btv,cmd,&v);
+
+		if (btv->type == BTTV_TERRATV) {
+			v.mode  = VIDEO_SOUND_MONO;
+			v.mode |= VIDEO_SOUND_STEREO;
+			v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2;
+
+		} else if (btv->audio_chip == TDA9840) {
+			/* begin of Horrible Hack <grin@tolna.net> */
+			v.flags|=VIDEO_AUDIO_VOLUME;
+			v.mode  = VIDEO_SOUND_MONO;
+			v.mode |= VIDEO_SOUND_STEREO;
+			v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2;
+			v.volume = 32768;       /* fixme */
+			v.step = 4096;
 		}
-		case VIDIOCSFREQ:
-		{
-			unsigned long v;
-			if(copy_from_user(&v, arg, sizeof(v)))
-				return -EFAULT;
-			btv->win.freq=v;
-			set_freq(btv, btv->win.freq);
-			return 0;
-		}
-	
-		case VIDIOCGAUDIO:
-		{
-			struct video_audio v;
-			v=btv->audio_dev;
-			v.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE);
-			v.flags|=VIDEO_AUDIO_MUTABLE;
-			strcpy(v.name,"TV");
-			if (btv->audio_chip == TDA9850) {
-				unsigned char ALR1;
-				ALR1 = I2CRead(&(btv->i2c), I2C_TDA9850|1);
-				v.mode = VIDEO_SOUND_MONO;
-				v.mode |= (ALR1 & 32) ? VIDEO_SOUND_STEREO:0;
-				v.mode |= (ALR1 & 64) ? VIDEO_SOUND_LANG1:0;
-			}
-			if (btv->have_msp3400) 
-			{
-                                v.flags|=VIDEO_AUDIO_VOLUME |
-                                	VIDEO_AUDIO_BASS |
-                                	VIDEO_AUDIO_TREBLE;
-                                i2c_control_device(&(btv->i2c),
-                                                I2C_DRIVERID_MSP3400,
-                                                MSP_GET_VOLUME,&(v.volume));
-                                i2c_control_device(&(btv->i2c),
-                                                I2C_DRIVERID_MSP3400,
-                                                MSP_GET_BASS,&(v.bass));
-                                i2c_control_device(&(btv->i2c),
-                                                I2C_DRIVERID_MSP3400,
-                                                MSP_GET_TREBLE,&(v.treble));
-                        	i2c_control_device(&(btv->i2c),
-                                		I2C_DRIVERID_MSP3400,
-                                                MSP_GET_STEREO,&(v.mode));
-			}
-			else v.mode = VIDEO_SOUND_MONO;
-			if(copy_to_user(arg,&v,sizeof(v)))
-				return -EFAULT;
-			return 0;
+
+#if 0
+#warning this should be handled by tda9855.c
+		else if (btv->audio_chip == TDA9850) {
+			unsigned char ALR1;
+			v.flags|=VIDEO_AUDIO_VOLUME;
+			ALR1 = I2CRead(btv, I2C_TDA9850|1);
+			v.mode = VIDEO_SOUND_MONO;
+			v.mode |= (ALR1 & 32) ? VIDEO_SOUND_STEREO:0;
+			v.mode |= (ALR1 & 32) ? VIDEO_SOUND_LANG1:0;
+			v.volume = 32768;       /* fixme */
+			v.step = 4096;
 		}
-		case VIDIOCSAUDIO:
-		{
-			struct video_audio v;
-			if(copy_from_user(&v,arg, sizeof(v)))
-				return -EFAULT;
-			down(&btv->lock);
-			if(v.flags&VIDEO_AUDIO_MUTE)
-				audio(btv, AUDIO_MUTE);
- 			/* One audio source per tuner */
- 			/* if(v.audio!=0) */
-			/* ADSTech TV card has more than one */
-			if(v.audio<0 || v.audio >= tvcards[btv->type].audio_inputs)
-			{
-				up(&btv->lock);
-				return -EINVAL;
-			}
-			bt848_muxsel(btv,v.audio);
-			if(!(v.flags&VIDEO_AUDIO_MUTE))
-				audio(btv, AUDIO_UNMUTE);
-			if (btv->audio_chip == TDA9850) {
-				unsigned char con3 = 0;
-				if (v.mode & VIDEO_SOUND_LANG1)
-					con3 = 0x80;	/* sap */
-				if (v.mode & VIDEO_SOUND_STEREO)
-					con3 = 0x40;	/* stereo */
-				I2CWrite(&(btv->i2c), I2C_TDA9850,
-					TDA9850_CON3, con3, 1);
-			}
-		   
-		       /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */
-		        if (btv->type == BTTV_WINVIEW_601) { 
-			   int bits_out, loops, vol, data;
-
-			   /* 32 levels logarithmic */
-			   vol = 32 - ((v.volume>>11));
-			   /* units */
-                           bits_out = (PT2254_DBS_IN_2>>(vol%5));
-			   /* tens */
-                           bits_out |= (PT2254_DBS_IN_10>>(vol/5));
-			   bits_out |= PT2254_L_CHANEL | PT2254_R_CHANEL;
-			   data = btread(BT848_GPIO_DATA);
-			   data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
-				      WINVIEW_PT2254_STROBE);
-			   for (loops = 17; loops >= 0 ; loops--) {
-				if (bits_out & (1<<loops))
-				   data |=  WINVIEW_PT2254_DATA;
-				else
-				   data &= ~WINVIEW_PT2254_DATA;
-			       btwrite(data, BT848_GPIO_DATA);
-			       udelay(5);
-			       data |= WINVIEW_PT2254_CLK;
-			       btwrite(data, BT848_GPIO_DATA);
-			       udelay(5);
-			       data &= ~WINVIEW_PT2254_CLK;
-			       btwrite(data, BT848_GPIO_DATA);
-			   }
-			   data |=  WINVIEW_PT2254_STROBE;
-			   data &= ~WINVIEW_PT2254_DATA;
-			   btwrite(data, BT848_GPIO_DATA);
-			   udelay(10);			   
-			   data &= ~WINVIEW_PT2254_STROBE;
-			   btwrite(data, BT848_GPIO_DATA);
-			}
-                        /* TEA 6320 Audio Support by Michael Wrighton
-                           mgw1@cec.wustl.edu */
-                        if (btv->audio_chip == TEA6320)
-                        {
-                          int vol;
-                          vol = v.volume >> 11;
-                          if (!(v.flags&VIDEO_AUDIO_MUTE))
-                            I2CWrite(&(btv->i2c), I2C_TEA6320,
-                                     TEA6320_S, TEA6320_S_SB,1); /* at least Raffles card uses input B */
-                          else
-                            I2CWrite(&(btv->i2c), I2C_TEA6320,
-                                     TEA6320_S, TEA6320_S_GMU,1);
-                          I2CWrite(&(btv->i2c), I2C_TEA6320,
-                                   TEA6320_V, vol, 1);
-                        }
-			if (btv->have_msp3400) 
-			{
-                                i2c_control_device(&(btv->i2c),
-                                                I2C_DRIVERID_MSP3400,
-                                                MSP_SET_VOLUME,&(v.volume));
-                                i2c_control_device(&(btv->i2c),
-                                                I2C_DRIVERID_MSP3400,
-                                                MSP_SET_BASS,&(v.bass));
-                                i2c_control_device(&(btv->i2c),
-                                                I2C_DRIVERID_MSP3400,
-                                                MSP_SET_TREBLE,&(v.treble));
-                        	i2c_control_device(&(btv->i2c),
-                                		I2C_DRIVERID_MSP3400,
-                                		MSP_SET_STEREO,&(v.mode));
-			}
-			btv->audio_dev=v;
+#endif
+		if(copy_to_user(arg,&v,sizeof(v)))
+			return -EFAULT;
+		return 0;
+	}
+	case VIDIOCSAUDIO:
+	{
+		struct video_audio v;
+
+		if(copy_from_user(&v,arg, sizeof(v)))
+			return -EFAULT;
+		down(&btv->lock);
+		if(v.flags&VIDEO_AUDIO_MUTE)
+			audio(btv, AUDIO_MUTE);
+		/* One audio source per tuner -- huh? <GA> */
+		if(v.audio<0 || v.audio >= tvcards[btv->type].audio_inputs) {
 			up(&btv->lock);
-			return 0;
+			return -EINVAL;
 		}
+		/* bt848_muxsel(btv,v.audio); */
+		if(!(v.flags&VIDEO_AUDIO_MUTE))
+			audio(btv, AUDIO_UNMUTE);
 
-	        case VIDIOCSYNC:
-			if(copy_from_user((void *)&i,arg,sizeof(int)))
-				return -EFAULT;
-/*                        if(i>1 || i<0)
-                                return -EINVAL;
-*/
-                        switch (btv->frame_stat[i]) {
-                        case GBUFFER_UNUSED:
-                                return -EINVAL;
-                        case GBUFFER_GRABBING:
-                        	while(btv->frame_stat[i]==GBUFFER_GRABBING) {
- 			        	interruptible_sleep_on(&btv->capq);
- 			        	if(signal_pending(current))
- 			        		return -EINTR;
- 			        }
-                                /* fall */
-                        case GBUFFER_DONE:
-                                btv->frame_stat[i] = GBUFFER_UNUSED;
-                                break;
-                        }
-                        return 0;
+		call_i2c_clients(btv,cmd,&v);
+		
+		if (btv->type == BTTV_TERRATV) {
+			unsigned int con = 0;
+			btor(0x180000, BT848_GPIO_OUT_EN);
+			if (v.mode & VIDEO_SOUND_LANG2)
+				con = 0x080000;
+			if (v.mode & VIDEO_SOUND_STEREO)
+				con = 0x180000;
+			btaor(con, ~0x180000, BT848_GPIO_DATA);
+
+		} else if (btv->type == BTTV_WINVIEW_601) { 
+			/* PT2254A programming Jon Tombs, jon@gte.esi.us.es */
+			int bits_out, loops, vol, data;
+			
+			/* 32 levels logarithmic */
+			vol = 32 - ((v.volume>>11));
+			/* units */
+			bits_out = (PT2254_DBS_IN_2>>(vol%5));
+			/* tens */
+			bits_out |= (PT2254_DBS_IN_10>>(vol/5));
+			bits_out |= PT2254_L_CHANEL | PT2254_R_CHANEL;
+			data = btread(BT848_GPIO_DATA);
+			data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
+				  WINVIEW_PT2254_STROBE);
+			for (loops = 17; loops >= 0 ; loops--) {
+                                if (bits_out & (1<<loops))
+					data |=  WINVIEW_PT2254_DATA;
+                                else
+					data &= ~WINVIEW_PT2254_DATA;
+				btwrite(data, BT848_GPIO_DATA);
+				udelay(5);
+				data |= WINVIEW_PT2254_CLK;
+				btwrite(data, BT848_GPIO_DATA);
+				udelay(5);
+				data &= ~WINVIEW_PT2254_CLK;
+				btwrite(data, BT848_GPIO_DATA);
+			}
+			data |=  WINVIEW_PT2254_STROBE;
+			data &= ~WINVIEW_PT2254_DATA;
+			btwrite(data, BT848_GPIO_DATA);
+			udelay(10);                     
+			data &= ~WINVIEW_PT2254_STROBE;
+			btwrite(data, BT848_GPIO_DATA);
 
-		case BTTV_WRITEE:
-			if(!capable(CAP_SYS_ADMIN))
-				return -EPERM;
-			if(copy_from_user((void *) eedata, (void *) arg, 256))
-				return -EFAULT;
-			down(&btv->lock);
-			writeee(&(btv->i2c), eedata);
-			up(&btv->lock);
-			return 0;
+#if 0
+#warning this should be handled by tda9855.c
+		} else if (btv->audio_chip == TDA9850) {
+			unsigned char con3 = 0;
+			if (v.mode & VIDEO_SOUND_LANG1)
+				con3 = 0x80;	/* sap */
+			if (v.mode & VIDEO_SOUND_STEREO)
+				con3 = 0x40;	/* stereo */
+			I2CWrite(btv, I2C_TDA9850,
+				 TDA9850_CON3, con3, 1);
+			if (v.flags & VIDEO_AUDIO_VOLUME)
+				I2CWrite(btv, I2C_TDA9850,
+					 TDA9850_CON4,
+					 (v.volume>>12) & 15, 1);
+#endif
+		}
+		btv->audio_dev=v;
+		up(&btv->lock);
+		return 0;
+	}
 
-		case BTTV_READEE:
-			if(!capable(CAP_SYS_ADMIN))
-				return -EPERM;
-			down(&btv->lock);
-			readee(&(btv->i2c), eedata);
-			up(&btv->lock);
-			if(copy_to_user((void *) arg, (void *) eedata, 256))
-				return -EFAULT;
+	case VIDIOCSYNC:
+		if(copy_from_user((void *)&i,arg,sizeof(int)))
+			return -EFAULT;
+		switch (btv->frame_stat[i]) {
+		case GBUFFER_UNUSED:
+			return -EINVAL;
+		case GBUFFER_GRABBING:
+			while(btv->frame_stat[i]==GBUFFER_GRABBING) {
+				interruptible_sleep_on(&btv->capq);
+				if(signal_pending(current))
+					return -EINTR;
+			}
+                                /* fall */
+		case GBUFFER_DONE:
+			btv->frame_stat[i] = GBUFFER_UNUSED;
 			break;
+		}
+		return 0;
 
-                case BTTV_FIELDNR: 
-			if(copy_to_user((void *) arg, (void *) &btv->last_field, 
-                                        sizeof(btv->last_field)))
-				return -EFAULT;
-                        break;
+	case BTTV_FIELDNR: 
+		if(copy_to_user((void *) arg, (void *) &btv->last_field, 
+				sizeof(btv->last_field)))
+			return -EFAULT;
+		break;
       
-                case BTTV_PLLSET: {
-                        struct bttv_pll_info p;
-			if(!capable(CAP_SYS_ADMIN))
-                                return -EPERM;
-                        if(copy_from_user(&p , (void *) arg, sizeof(btv->pll)))
-				return -EFAULT;
-			down(&btv->lock);
-                        btv->pll.pll_ifreq = p.pll_ifreq;
-                        btv->pll.pll_ofreq = p.pll_ofreq;
-                        btv->pll.pll_crystal = p.pll_crystal;
-			up(&btv->lock);
-			break;
-                }						
-	        case VIDIOCMCAPTURE:
-		{
-                        struct video_mmap vm;
-                        int v;
-			if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm)))
-				return -EFAULT;
-                        if (btv->frame_stat[vm.frame] == GBUFFER_GRABBING)
-                                return -EBUSY;
-                        down(&btv->lock);
-		        v=vgrab(btv, &vm);
-		        up(&btv->lock);
-				return v;
-		}
+	case BTTV_PLLSET: {
+		struct bttv_pll_info p;
+		if(!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if(copy_from_user(&p , (void *) arg, sizeof(btv->pll)))
+			return -EFAULT;
+		down(&btv->lock);
+		btv->pll.pll_ifreq = p.pll_ifreq;
+		btv->pll.pll_ofreq = p.pll_ofreq;
+		btv->pll.pll_crystal = p.pll_crystal;
+		up(&btv->lock);
+
+		break;
+	}
+
+	case VIDIOCMCAPTURE:
+	{
+		struct video_mmap vm;
+		int ret;
+		if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm)))
+			return -EFAULT;
+		if (btv->frame_stat[vm.frame] == GBUFFER_GRABBING)
+			return -EBUSY;
+		down(&btv->lock);
+		ret = vgrab(btv, &vm);
+		up(&btv->lock);
+		return ret;
+	}
 		
-		case VIDIOCGMBUF:
-		{
-			struct video_mbuf vm;
-			memset(&vm, 0 , sizeof(vm));
-			vm.size=BTTV_MAX_FBUF*2;
-			vm.frames=2;
-			vm.offsets[0]=0;
-			vm.offsets[1]=BTTV_MAX_FBUF;
-			if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
-				return -EFAULT;
-			return 0;
-		}
+	case VIDIOCGMBUF:
+	{
+		struct video_mbuf vm;
+		memset(&vm, 0 , sizeof(vm));
+		vm.size=BTTV_MAX_FBUF*MAX_GBUFFERS;
+		vm.frames=MAX_GBUFFERS;
+		vm.offsets[0]=0;
+		vm.offsets[1]=BTTV_MAX_FBUF;
+		if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+			return -EFAULT;
+		return 0;
+	}
 		
-		case VIDIOCGUNIT:
-		{
-			struct video_unit vu;
-			vu.video=btv->video_dev.minor;
-			vu.vbi=btv->vbi_dev.minor;
-			if(btv->radio_dev.minor!=-1)
-				vu.radio=btv->radio_dev.minor;
-			else
-				vu.radio=VIDEO_NO_UNIT;
-			vu.audio=VIDEO_NO_UNIT;
-			if(btv->have_msp3400)
-			{
-				i2c_control_device(&(btv->i2c), I2C_DRIVERID_MSP3400,
-					MSP_GET_UNIT, &vu.audio);
-			}
-			vu.teletext=VIDEO_NO_UNIT;
-			if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu)))
-				return -EFAULT;
-			return 0;
-		}
+	case VIDIOCGUNIT:
+	{
+		struct video_unit vu;
+		vu.video=btv->video_dev.minor;
+		vu.vbi=btv->vbi_dev.minor;
+		if(btv->radio_dev.minor!=-1)
+			vu.radio=btv->radio_dev.minor;
+		else
+			vu.radio=VIDEO_NO_UNIT;
+		vu.audio=VIDEO_NO_UNIT;
+#if 0
+		AUDIO(AUDC_GET_UNIT, &vu.audio);
+#endif
+		vu.teletext=VIDEO_NO_UNIT;
+		if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu)))
+			return -EFAULT;
+		return 0;
+	}
 		
-	        case BTTV_BURST_ON:
-		{
-			tvnorms[0].scaledtwidth=1135-BURSTOFFSET-2;
-			tvnorms[0].hdelayx1=186-BURSTOFFSET;
-			return 0;
-		}
+	case BTTV_BURST_ON:
+	{
+		tvnorms[0].scaledtwidth=1135-BURSTOFFSET-2;
+		tvnorms[0].hdelayx1=186-BURSTOFFSET;
+		tvnorms[2].scaledtwidth=1135-BURSTOFFSET-2;
+		tvnorms[2].hdelayx1=186-BURSTOFFSET;
+		return 0;
+	}
 
-		case BTTV_BURST_OFF:
-		{
-			tvnorms[0].scaledtwidth=1135;
-			tvnorms[0].hdelayx1=186;
-			return 0;
-		}
+	case BTTV_BURST_OFF:
+	{
+		tvnorms[0].scaledtwidth=1135;
+		tvnorms[0].hdelayx1=186;
+		tvnorms[2].scaledtwidth=1135;
+		tvnorms[2].hdelayx1=186;
+		return 0;
+	}
 
-		case BTTV_VERSION:
-		{
-			return BTTV_VERSION_CODE;
-		}
+	case BTTV_VERSION:
+	{
+		return BTTV_VERSION_CODE;
+	}
                         
-		case BTTV_PICNR:
-		{
-			/* return picture;*/
-			return  0;
-		}
+	case BTTV_PICNR:
+	{
+		/* return picture;*/
+		return  0;
+	}
                         
-		default:
-			return -ENOIOCTLCMD;
+	default:
+		return -ENOIOCTLCMD;
 	}
 	return 0;
 }
@@ -2317,43 +2440,42 @@
  *  - remap_page_range is kind of inefficient for page by page remapping.
  *    But e.g. pte_alloc() does not work in modules ... :-(
  */
- 
+
 static int do_bttv_mmap(struct bttv *btv, const char *adr, unsigned long size)
 {
         unsigned long start=(unsigned long) adr;
-	unsigned long page,pos;
+        unsigned long page,pos;
 
-	if (size>2*BTTV_MAX_FBUF)
-	        return -EINVAL;
-	if (!btv->fbuffer)
-	{
-		if(fbuffer_alloc(btv))
-			return -EINVAL;
-	}
-	pos=(unsigned long) btv->fbuffer;
-	while (size > 0) 
-	{
-	        page = kvirt_to_pa(pos);
-		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
-		        return -EAGAIN;
-		start+=PAGE_SIZE;
-		pos+=PAGE_SIZE;
-		size-=PAGE_SIZE;    
-	}
-	return 0;
+        if (size>2*BTTV_MAX_FBUF)
+                return -EINVAL;
+        if (!btv->fbuffer) {
+                if(fbuffer_alloc(btv))
+                        return -EINVAL;
+        }
+        pos=(unsigned long) btv->fbuffer;
+        while (size > 0) {
+                page = kvirt_to_pa(pos);
+                if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+                        return -EAGAIN;
+                start+=PAGE_SIZE;
+                pos+=PAGE_SIZE;
+                size-=PAGE_SIZE;
+        }
+        return 0;
 }
 
 static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long size)
 {
-	struct bttv *btv=(struct bttv *)dev;
-	int r;
-	
-	down(&btv->lock);
-	r=do_bttv_mmap(btv, adr, size);
-	up(&btv->lock);
-	return r;
+        struct bttv *btv=(struct bttv *)dev;
+        int r;
+
+        down(&btv->lock);
+        r=do_bttv_mmap(btv, adr, size);
+        up(&btv->lock);
+        return r;
 }
 
+
 static struct video_device bttv_template=
 {
 	"UNSET",
@@ -2363,9 +2485,7 @@
 	bttv_close,
 	bttv_read,
 	bttv_write,
-#if LINUX_VERSION_CODE >= 0x020100
-	NULL,			/* poll */
-#endif
+	NULL,
 	bttv_ioctl,
 	bttv_mmap,
 	bttv_init_done,
@@ -2437,7 +2557,7 @@
 {
 	struct bttv *btv=(struct bttv *)(dev-2);
 
-	down(&btv->lock);
+        down(&btv->lock);
 	btv->vbip=VBIBUF_SIZE;
 	btv->cap|=0x0c;
 	bt848_set_risc_jmps(btv);
@@ -2451,7 +2571,7 @@
 {
 	struct bttv *btv=(struct bttv *)(dev-2);
 
-	down(&btv->lock);  
+        down(&btv->lock);
 	btv->cap&=~0x0c;
 	bt848_set_risc_jmps(btv);
 	up(&btv->lock);
@@ -2459,10 +2579,36 @@
 	MOD_DEC_USE_COUNT;  
 }
 
-
 static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
 {
-	return -EINVAL;
+	struct bttv *btv=(struct bttv *)dev;
+
+	switch (cmd) {	
+	case VIDIOCGCAP:
+	{
+		struct video_capability b;
+		strcpy(b.name,btv->vbi_dev.name);
+		b.type = ((tvcards[btv->type].tuner != -1) ? VID_TYPE_TUNER : 0) |
+			VID_TYPE_TELETEXT;
+		b.channels = 0;
+		b.audios = 0;
+		b.maxwidth = 0;
+		b.maxheight = 0;
+		b.minwidth = 0;
+		b.minheight = 0;
+		if(copy_to_user(arg,&b,sizeof(b)))
+			return -EFAULT;
+		return 0;
+	}
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
+		return bttv_ioctl((struct video_device *)btv,cmd,arg);
+	case BTTV_VBISIZE:
+		/* make alevt happy :-) */
+		return VBIBUF_SIZE;
+	default:
+		return -EINVAL;
+	}
 }
 
 static struct video_device vbi_template=
@@ -2474,9 +2620,7 @@
 	vbi_close,
 	vbi_read,
 	bttv_write,
-#if LINUX_VERSION_CODE >= 0x020100
 	vbi_poll,
-#endif
 	vbi_ioctl,
 	NULL,	/* no mmap yet */
 	bttv_init_done,
@@ -2490,17 +2634,16 @@
 {
 	struct bttv *btv = (struct bttv *)(dev-1);
 
-	down(&btv->lock);
+        down(&btv->lock);
 	if (btv->user)
 		goto busy_unlock;
 	btv->user++;
-	
-	set_freq(btv,400*16);
+
 	btv->radio = 1;
+	call_i2c_clients(btv,AUDC_SET_RADIO,&btv->tuner_type);
 	bt848_muxsel(btv,0);
-	audio(btv, AUDIO_UNMUTE);
 	up(&btv->lock);
-	
+
 	MOD_INC_USE_COUNT;
 	return 0;   
 
@@ -2512,11 +2655,10 @@
 static void radio_close(struct video_device *dev)
 {
 	struct bttv *btv=(struct bttv *)(dev-1);
-  
+
 	down(&btv->lock);
 	btv->user--;
 	btv->radio = 0;
-	/*audio(btv, AUDIO_MUTE);*/
 	up(&btv->lock);
 	MOD_DEC_USE_COUNT;  
 }
@@ -2595,9 +2737,7 @@
 	radio_close,
 	radio_read,          /* just returns -EINVAL */
 	bttv_write,          /* just returns -EINVAL */
-#if LINUX_VERSION_CODE >= 0x020100
 	NULL,                /* no poll */
-#endif
 	radio_ioctl,
 	NULL,	             /* no mmap */
 	bttv_init_done,      /* just returns 0 */
@@ -2607,7 +2747,6 @@
 };
 
 
-
 #define  TRITON_PCON	           0x50 
 #define  TRITON_BUS_CONCURRENCY   (1<<0)
 #define  TRITON_STREAMING	  (1<<1)
@@ -2623,79 +2762,69 @@
 	if (triton1)
 		triton1=BT848_INT_ETBF;
 	
-	
-	if(pci_pci_problems&PCIPCI_FAIL)
-	{
-		printk(KERN_WARNING "bttv: This configuration is known to have PCI to PCI DMA problems\n");
-		printk(KERN_WARNING "bttv: You may not be able to use overlay mode.\n");
-	}
-			
-	while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, dev))) 
+	while ((dev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, dev))) 
 	{
-		unsigned char b;
-		pci_read_config_byte(dev, 0x53, &b);
-		DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, "));
-		DEBUG(printk("bufcon=0x%02x\n",b));
-	}
+		/* Beware the SiS 85C496 my friend - rev 49 don't work with a bttv */
+		printk(KERN_WARNING "BT848 and SIS 85C496 chipset don't always work together.\n");
+	}			
+
+        while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+				      PCI_DEVICE_ID_INTEL_82441, dev))) 
+        {
+                unsigned char b;
+                pci_read_config_byte(dev, 0x53, &b);
+                DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, "));
+                DEBUG(printk("bufcon=0x%02x\n",b));
+        }
 
 	while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev))) 
 	{
-/*		unsigned char b;
-		unsigned char bo;*/
-
 		printk(KERN_INFO "bttv: Host bridge 82437FX Triton PIIX\n");
 		triton1=BT848_INT_ETBF;
 	}
 }
 
-static void init_tea6300(struct i2c_bus *bus) 
+#if 0
+#warning please use tda8425.c instead
+static void init_tda8425(struct bttv *btv) 
 {
-        I2CWrite(bus, I2C_TEA6300, TEA6300_VL, 0x35, 1); /* volume left 0dB  */
-        I2CWrite(bus, I2C_TEA6300, TEA6300_VR, 0x35, 1); /* volume right 0dB */
-        I2CWrite(bus, I2C_TEA6300, TEA6300_BA, 0x07, 1); /* bass 0dB         */
-        I2CWrite(bus, I2C_TEA6300, TEA6300_TR, 0x07, 1); /* treble 0dB       */
-        I2CWrite(bus, I2C_TEA6300, TEA6300_FA, 0x0f, 1); /* fader off        */
-        I2CWrite(bus, I2C_TEA6300, TEA6300_SW, 0x01, 1); /* mute off input A */
+        I2CWrite(btv, I2C_TDA8425, TDA8425_VL, 0xFC, 1); /* volume left 0dB  */
+        I2CWrite(btv, I2C_TDA8425, TDA8425_VR, 0xFC, 1); /* volume right 0dB */
+        I2CWrite(btv, I2C_TDA8425, TDA8425_BA, 0xF6, 1); /* bass 0dB         */
+        I2CWrite(btv, I2C_TDA8425, TDA8425_TR, 0xF6, 1); /* treble 0dB       */
+        I2CWrite(btv, I2C_TDA8425, TDA8425_S1, 0xCE, 1); /* mute off         */
 }
+#endif
 
-static void init_tea6320(struct i2c_bus *bus)
+/* can tda9855.c handle this too maybe? */
+static void init_tda9840(struct bttv *btv)
 {
-	I2CWrite(bus, I2C_TEA6300, TEA6320_V, 0x28, 1); /* master volume */
-	I2CWrite(bus, I2C_TEA6300, TEA6320_FFL, 0x28, 1); /* volume left 0dB  */
-	I2CWrite(bus, I2C_TEA6300, TEA6320_FFR, 0x28, 1); /* volume right 0dB */
-	I2CWrite(bus, I2C_TEA6300, TEA6320_FRL, 0x28, 1); /* volume rear left 0dB  */
-	I2CWrite(bus, I2C_TEA6300, TEA6320_FRR, 0x28, 1); /* volume rear right 0dB */
-	I2CWrite(bus, I2C_TEA6300, TEA6320_BA, 0x11, 1); /* bass 0dB         */
-	I2CWrite(bus, I2C_TEA6300, TEA6320_TR, 0x11, 1); /* treble 0dB       */
-	I2CWrite(bus, I2C_TEA6300, TEA6320_S, TEA6320_S_GMU, 1); /* mute off input A */
+        /* Horrible Hack */
+        I2CWrite(btv, I2C_TDA9840, TDA9840_SW, 0x2a, 1);  /* sound mode switching */
+        /* 00 - mute
+           10 - mono / averaged stereo
+           2a - stereo
+           12 - dual A
+           1a - dual AB
+           16 - dual BA
+           1e - dual B
+           7a - external */
 }
 
-static void init_tda8425(struct i2c_bus *bus) 
-{
-        I2CWrite(bus, I2C_TDA8425, TDA8425_VL, 0xFC, 1); /* volume left 0dB  */
-        I2CWrite(bus, I2C_TDA8425, TDA8425_VR, 0xFC, 1); /* volume right 0dB */
-        I2CWrite(bus, I2C_TDA8425, TDA8425_BA, 0xF6, 1); /* bass 0dB         */
-        I2CWrite(bus, I2C_TDA8425, TDA8425_TR, 0xF6, 1); /* treble 0dB       */
-        I2CWrite(bus, I2C_TDA8425, TDA8425_S1, 0xCE, 1); /* mute off         */
-}
 
-static void init_tda9840(struct i2c_bus *bus)
-{
-	I2CWrite(bus, I2C_TDA9840, TDA9840_SW, 0x2A, 1);	/* Sound mode switching */
-}
-
-static void init_tda9850(struct i2c_bus *bus)
+#if 0
+#warning this should be handled by tda9855.c
+static void init_tda9850(struct bttv *btv)
 {
-        I2CWrite(bus, I2C_TDA9850, TDA9850_CON1, 0x08, 1);  /* noise threshold st */
-	I2CWrite(bus, I2C_TDA9850, TDA9850_CON2, 0x08, 1);  /* noise threshold sap */
-	I2CWrite(bus, I2C_TDA9850, TDA9850_CON3, 0x40, 1);  /* stereo mode */
-	I2CWrite(bus, I2C_TDA9850, TDA9850_CON4, 0x07, 1);  /* 0 dB input gain?*/
-	I2CWrite(bus, I2C_TDA9850, TDA9850_ALI1, 0x10, 1);  /* wideband alignment? */
-	I2CWrite(bus, I2C_TDA9850, TDA9850_ALI2, 0x10, 1);  /* spectral alignment? */
-	I2CWrite(bus, I2C_TDA9850, TDA9850_ALI3, 0x03, 1);
+        I2CWrite(btv, I2C_TDA9850, TDA9850_CON1, 0x08, 1);  /* noise threshold st */
+	I2CWrite(btv, I2C_TDA9850, TDA9850_CON2, 0x08, 1);  /* noise threshold sap */
+	I2CWrite(btv, I2C_TDA9850, TDA9850_CON3, 0x40, 1);  /* stereo mode */
+	I2CWrite(btv, I2C_TDA9850, TDA9850_CON4, 0x07, 1);  /* 0 dB input gain?*/
+	I2CWrite(btv, I2C_TDA9850, TDA9850_ALI1, 0x10, 1);  /* wideband alignment? */
+	I2CWrite(btv, I2C_TDA9850, TDA9850_ALI2, 0x10, 1);  /* spectral alignment? */
+	I2CWrite(btv, I2C_TDA9850, TDA9850_ALI3, 0x03, 1);
 }
-
-
+#endif
 
 /* Figure out card and tuner type */
 
@@ -2707,180 +2836,119 @@
 	DEBUG(printk(KERN_DEBUG "bttv%d: GPIO: 0x%08x\n", i, btread(BT848_GPIO_DATA)));
 
 	/* Default the card to the user-selected one. */
-	btv->type=card[i];
-        btv->tuner_type=-1; /* use default tuner type */
+	if (card[i] >= 0 && card[i] < TVCARDS)
+		btv->type=card[i];
 
 	/* If we were asked to auto-detect, then do so! 
 	   Right now this will only recognize Miro, Hauppauge or STB
 	   */
 	if (btv->type == BTTV_UNKNOWN) 
 	{
-		if (I2CRead(&(btv->i2c), I2C_HAUPEE)>=0)
+		if (I2CRead(btv, I2C_HAUPEE)>=0)
 		{
 			if(btv->id>849)
 				btv->type=BTTV_HAUPPAUGE878;
 			else
 			        btv->type=BTTV_HAUPPAUGE;
 
-		} else if (I2CRead(&(btv->i2c), I2C_STBEE)>=0) {
+		} else if (I2CRead(btv, I2C_STBEE)>=0) {
 			btv->type=BTTV_STB;
+
+#if 0	/* bad idea: 0xc0 is used for the tuner on _many_ boards */
+		} else if (I2CRead(btv, I2C_VHX)>=0) {
+			btv->type=BTTV_VHX;
+#endif
+
 		} else {
-			if (I2CRead(&(btv->i2c), 0x80)>=0) /* check for msp34xx */
+			if (I2CRead(btv, 0x80)>=0) /* check for msp34xx */
 				btv->type = BTTV_MIROPRO;
 			else
-	 			btv->type=BTTV_MIRO;
+	 			btv->type = BTTV_MIRO;
 		}
 	}
 
-        /* board specific initialisations */
-        
-        switch(btv->type)
-        {
-        	case BTTV_MIRO:
-        	case BTTV_MIROPRO:
-	                /* auto detect tuner for MIRO cards */
-        	        btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7;
-        	        break;
-        	
-        	case BTTV_HAUPPAUGE:
-        	case BTTV_HAUPPAUGE878:
-	                hauppauge_msp_reset(btv);
-        	        hauppauge_eeprom(&(btv->i2c));
-                	if (btv->type == BTTV_HAUPPAUGE878) {
-				/* all bt878 hauppauge boards use this ... */
-				btv->pll.pll_ifreq=28636363;
-				btv->pll.pll_crystal=BT848_IFORM_XT0;
-			}
-        		break;
-   
-   		case BTTV_CONFERENCETV:
-			btv->tuner_type = 1;
-		   	btv->pll.pll_ifreq=28636363;
-		   	btv->pll.pll_crystal=BT848_IFORM_XT0;
-		   	break;
-
-		case BTTV_PIXVIEWPLAYTV:
-		case BTTV_AVERMEDIA98:
-		case BTTV_MODTEC_205:
-		case BTTV_MAGICTVIEW061:
-			btv->pll.pll_ifreq=28636363;
-			btv->pll.pll_crystal=BT848_IFORM_XT0;
-			break;
+	/* print which board we have found */
+	printk(KERN_INFO "bttv%d: model: ",btv->nr);
+
+	sprintf(btv->video_dev.name,"BT%d",btv->id);
+        if (btv->id==848 && btv->revision==0x12) 
+                strcat(btv->video_dev.name,"A");
+        strcat(btv->video_dev.name,"(");
+        strcat(btv->video_dev.name, tvcards[btv->type].name);
+        strcat(btv->video_dev.name,")");
+	printk("%s\n",btv->video_dev.name);
 
+        /* board specific initialisations */
+        if (btv->type == BTTV_MIRO || btv->type == BTTV_MIROPRO) {
+                /* auto detect tuner for MIRO cards */
+                btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7;
+        }
+        if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) {
+                hauppauge_msp_reset(btv);
+                hauppauge_eeprom(btv);
+        }
+	if (btv->type == BTTV_MAXI) {
+		/* PHILIPS FI1216MK2 tuner (PAL/SECAM) */
+		btv->tuner_type=TUNER_PHILIPS_SECAM;
 	}
+ 
+ 	if (btv->type == BTTV_PXC200)
+		init_PXC200(btv);
+ 	
+        if (btv->type == BTTV_CONFERENCETV)
+                btv->tuner_type = 1;
 	
-	if (btv->have_tuner && btv->tuner_type != -1) 
- 		i2c_control_device(&(btv->i2c), 
-                                   I2C_DRIVERID_TUNER,
-                                   TUNER_SET_TYPE,&btv->tuner_type);
-
-        
-        if (I2CRead(&(btv->i2c), I2C_TDA9840) >=0)
-        {
-        	btv->audio_chip = TDA9840;
-        	printk(KERN_INFO "bttv%d: audio chip: TDA9840\n", btv->nr);
-        }
-        
-        if (I2CRead(&(btv->i2c), I2C_TDA9850) >=0)
-        {
-                btv->audio_chip = TDA9850;
-                printk(KERN_INFO "bttv%d: audio chip: TDA9850\n",btv->nr);
+        if (btv->type == BTTV_HAUPPAUGE878	||
+	    btv->type == BTTV_CONFERENCETV	||
+	    btv->type == BTTV_PIXVIEWPLAYTV	||
+	    btv->type == BTTV_AVERMEDIA98) {
+                btv->pll.pll_ifreq=28636363;
+                btv->pll.pll_crystal=BT848_IFORM_XT0;
         }
 
-        if (I2CRead(&(btv->i2c), I2C_TDA8425) >=0)
-        {
-                btv->audio_chip = TDA8425;
-                printk(KERN_INFO "bttv%d: audio chip: TDA8425\n",btv->nr);
-        }
-        
-        switch(btv->audio_chip)
-        {
-                case TDA9850:
-                        init_tda9850(&(btv->i2c));
-                        break; 
-                case TDA9840:
-                        init_tda9840(&(btv->i2c));
-                        break; 
-                case TDA8425:
-                        init_tda8425(&(btv->i2c));
-                        break;
+	if (btv->tuner_type != -1) 
+		call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
+
+	/* try to detect audio/fader chips */
+	if (tvcards[btv->type].msp34xx &&
+	    I2CRead(btv, I2C_MSP3400) >=0) {
+                printk(KERN_INFO "bttv%d: audio chip: MSP34xx\n",i);
+		request_module("msp3400");
+	}
+
+	if (tvcards[btv->type].tda8425 &&
+	    I2CRead(btv, I2C_TDA8425) >=0) {
+                printk(KERN_INFO "bttv%d: audio chip: TDA8425\n",i);
+		request_module("tda8425");
         }
-        
-        if (I2CRead(&(btv->i2c), I2C_TEA6300) >=0)
-        {
-		if(btv->type==BTTV_AVEC_INTERCAP || btv->type==BTTV_CEI_RAFFLES)
-        	{
-                	printk(KERN_INFO "bttv%d: fader chip: TEA6320\n",btv->nr);
-                	btv->audio_chip = TEA6320;
-                	init_tea6320(&(btv->i2c));
-		} else {
-			printk(KERN_INFO "bttv%d: fader chip: TEA6300\n",btv->nr);
-			btv->audio_chip = TEA6300;
-			init_tea6300(&(btv->i2c));
-        	}
-        } else
-		printk(KERN_INFO "bttv%d: NO fader chip: TEA6300\n",btv->nr);
 
-	printk(KERN_INFO "bttv%d: model: ",btv->nr);
+	if (tvcards[btv->type].tda9840 &&
+	    I2CRead(btv, I2C_TDA9840) >=0) {
+		init_tda9840(btv);
+        	printk(KERN_INFO "bttv%d: audio chip: TDA9840\n", i);
+                btv->audio_chip = TDA9840;
+		/* move this to a module too? */
+		init_tda9840(btv);
+	}
 
-	sprintf(btv->video_dev.name,"BT%d",btv->id);
-	switch (btv->type) 
-	{
-                case BTTV_MIRO:
-                case BTTV_MIROPRO:
-			strcat(btv->video_dev.name,
-			       (btv->type == BTTV_MIRO) ? "(Miro)" : "(Miro pro)");
-			break;
-		case BTTV_HAUPPAUGE:
-			strcat(btv->video_dev.name,"(Hauppauge old)");
-			break;
-		case BTTV_HAUPPAUGE878:
-			strcat(btv->video_dev.name,"(Hauppauge new)");
-			break;
-		case BTTV_STB: 
-			strcat(btv->video_dev.name,"(STB)");
-			break;
-		case BTTV_INTEL: 
-			strcat(btv->video_dev.name,"(Intel)");
-			break;
-		case BTTV_DIAMOND: 
-			strcat(btv->video_dev.name,"(Diamond)");
-			break;
-		case BTTV_AVERMEDIA: 
-			strcat(btv->video_dev.name,"(AVerMedia)");
-			break;
-		case BTTV_MATRIX_VISION: 
-			strcat(btv->video_dev.name,"(MATRIX-Vision)");
-			break;
-		case BTTV_AVERMEDIA98: 
-			strcat(btv->video_dev.name,"(AVerMedia TVCapture 98)");
-			break;
-		case BTTV_VHX:
-			strcpy(btv->video_dev.name,"(Aimslab-VHX)");
- 			break;
-	        case BTTV_WINVIEW_601:
-			strcpy(btv->video_dev.name,"(Leadtek WinView 601)");
- 			break;	   
-                case BTTV_AVEC_INTERCAP:
-                        strcpy(btv->video_dev.name,"(AVEC Intercapture)");
-                        break;
-                case BTTV_CEI_RAFFLES:
-                        strcpy(btv->video_dev.name,"(CEI Raffles Card)");
-                        break;
-                case BTTV_CONFERENCETV:
-                        strcpy(btv->video_dev.name,"(Image World ConferenceTV)");
-                        break;
-                case BTTV_PHOEBE_TVMAS:
-                        strcpy(btv->video_dev.name,"(Phoebe TV Master)");
-                        break;
-		case BTTV_MODTEC_205:
-			strcpy(btv->video_dev.name,"(Modtec MM205)");
-			break;
+	if (tvcards[btv->type].tda985x &&
+	    I2CRead(btv, I2C_TDA9850) >=0) {
+                printk(KERN_INFO "bttv%d: audio chip: TDA985x\n",i);
+		request_module("tda9855");
 	}
-	printk("%s\n",btv->video_dev.name);
-	audio(btv, AUDIO_INTERN);
-}
 
+	if (tvcards[btv->type].tea63xx &&
+	    I2CRead(btv, I2C_TEA6300)) {
+		printk(KERN_INFO "bttv%d: fader chip: TEA63xx\n",i);
+		request_module("tea6300");
+	}
+
+	if (tvcards[btv->type].tuner != -1) {
+		request_module("tuner");
+	}
+
+	audio(btv, AUDIO_MUTE);
+}
 
 
 static void bt848_set_risc_jmps(struct bttv *btv)
@@ -2888,18 +2956,19 @@
 	int flags=btv->cap;
 
 	/* Sync to start of odd field */
-	btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRE);
-	btv->risc_jmp[1]=0;
+	btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC
+                                |BT848_FIFO_STATUS_VRE);
+	btv->risc_jmp[1]=cpu_to_le32(0);
 
 	/* Jump to odd vbi sub */
-	btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0x5<<20));
+	btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0xd<<20));
 	if (flags&8)
 		btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->vbi_odd));
 	else
 		btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->risc_jmp+4));
 
         /* Jump to odd sub */
-	btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0x6<<20));
+	btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0xe<<20));
 	if (flags&2)
 		btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_odd));
 	else
@@ -2907,8 +2976,9 @@
 
 
 	/* Sync to start of even field */
-	btv->risc_jmp[6]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRO);
-	btv->risc_jmp[7]=0;
+	btv->risc_jmp[6]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC
+                                |BT848_FIFO_STATUS_VRO);
+	btv->risc_jmp[7]=cpu_to_le32(0);
 
 	/* Jump to even vbi sub */
 	btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP);
@@ -2927,7 +2997,7 @@
 	btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP);
 	btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp));
 
-	/* enable capturing */
+	/* enable cpaturing and DMA */
 	btaor(flags, ~0x0f, BT848_CAP_CTL);
 	if (flags&0x0f)
 		bt848_dma(btv, 3);
@@ -2935,13 +3005,52 @@
 		bt848_dma(btv, 0);
 }
 
+static int
+init_video_dev(struct bttv *btv)
+{
+        int num = btv - bttvs;
+
+	memcpy(&btv->video_dev,&bttv_template, sizeof(bttv_template));
+	memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template));
+	memcpy(&btv->radio_dev,&radio_template,sizeof(radio_template));
+        
+	idcard(num);
+        
+	if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0)
+		return -1;
+	if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI)<0) 
+        {
+	        video_unregister_device(&btv->video_dev);
+		return -1;
+	}
+	if (radio[num])
+	{
+		if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0) 
+                {
+		        video_unregister_device(&btv->vbi_dev);
+		        video_unregister_device(&btv->video_dev);
+			return -1;
+		}
+	}
+        return 1;
+}
+
 static int init_bt848(int i)
 {
         struct bttv *btv = &bttvs[i];
 
 	btv->user=0; 
-	
-	init_MUTEX(&btv->lock);
+        init_MUTEX(&btv->lock);
+
+#if 0
+	/* dump current state of the gpio registers before changing them,
+	 * might help to make a new card work */
+	printk("bttv%d: gpio: out_enable=0x%x, data=0x%x, in=0x%x\n",
+		i,
+		btread(BT848_GPIO_OUT_EN),
+		btread(BT848_GPIO_DATA),
+		btread(BT848_GPIO_REG_INP));
+#endif
 
 	/* reset the bt848 */
 	btwrite(0, BT848_SRESET);
@@ -2964,6 +3073,7 @@
 	btv->win.bpl=1024*btv->win.bpp;
 	btv->win.swidth=1024;
 	btv->win.sheight=768;
+	btv->win.vidadr=0;
 	btv->cap=0;
 
 	btv->gmode=0;
@@ -2977,17 +3087,10 @@
 	btv->grab=0;
 	btv->lastgrab=0;
         btv->field=btv->last_field=0;
-	/* cevans - prevents panic if initialization bails due to memory
-	 * alloc failures!
-	 */
-	btv->video_dev.minor = -1;
-	btv->vbi_dev.minor = -1;
-	btv->radio_dev.minor = -1;
 
 	/* i2c */
-	memcpy(&(btv->i2c),&bttv_i2c_bus_template,sizeof(struct i2c_bus));
-	sprintf(btv->i2c.name,"bt848-%d",i);
-	btv->i2c.data = btv;
+        btv->tuner_type=-1;
+        init_bttv_i2c(btv);
 
 	if (!(btv->risc_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
 		return -1;
@@ -3017,14 +3120,14 @@
 	bt848_set_winsize(btv);
 
 /*	btwrite(0, BT848_TDEC); */
-	btwrite(0x10, BT848_COLOR_CTL);
+        btwrite(0x10, BT848_COLOR_CTL);
 	btwrite(0x00, BT848_CAP_CTL);
 	btwrite(0xac, BT848_GPIO_DMA_CTL);
 
         /* select direct input */
 	btwrite(0x00, BT848_GPIO_REG_INP);
 
-	btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_PAL_BDGHI,
+	btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_AUTO,
 		BT848_IFORM);
 
 	btwrite(0xd8, BT848_CONTRAST_LO);
@@ -3053,7 +3156,7 @@
 	btwrite(btv->triton1|
                 /*BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|
                   BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/
-                BT848_INT_VSYNC|
+                (fieldnr ? BT848_INT_VSYNC : 0)|
 		BT848_INT_SCERR|
 		BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
 		BT848_INT_FMTCHG|BT848_INT_HLOCK,
@@ -3065,30 +3168,7 @@
 	/*
 	 *	Now add the template and register the device unit.
 	 */
-
-	memcpy(&btv->video_dev,&bttv_template, sizeof(bttv_template));
-	memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template));
-	memcpy(&btv->radio_dev,&radio_template,sizeof(radio_template));
-
-	idcard(i);
-
-	if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0)
-		return -1;
-	if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI)<0) 
-        {
-	        video_unregister_device(&btv->video_dev);
-		return -1;
-	}
-	if (radio[i])
-	{
-		if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0) 
-                {
-		        video_unregister_device(&btv->vbi_dev);
-		        video_unregister_device(&btv->video_dev);
-			return -1;
-		}
-	}
-	i2c_register_bus(&btv->i2c);
+        init_video_dev(btv);
 
 	return 0;
 }
@@ -3110,7 +3190,8 @@
 		if (!astat)
 			return;
 		btwrite(astat,BT848_INT_STAT);
-		IDEBUG(printk ("bttv%d: astat %08x stat %08x\n", btv->nr, astat, stat));
+		IDEBUG(printk ("bttv%d: astat %08x\n", btv->nr, astat));
+		IDEBUG(printk ("bttv%d:  stat %08x\n", btv->nr, stat));
 
 		/* get device status bits */
 		dstat=btread(BT848_DSTATUS);
@@ -3133,7 +3214,7 @@
 		if (astat&BT848_INT_SCERR) {
 			IDEBUG(printk ("bttv%d: IRQ_SCERR\n", btv->nr));
 			bt848_dma(btv, 0);
-			bt848_dma(btv, 3);
+			bt848_dma(btv, 1);
 			wake_up_interruptible(&btv->vbiq);
 			wake_up_interruptible(&btv->capq);
 
@@ -3154,7 +3235,7 @@
 			/* captured full frame */
 			if (stat&(2<<28)) 
 			{
-				wake_up_interruptible(&btv->capq);
+				/*wake_up_interruptible(&btv->capq);*/
                                 btv->last_field=btv->field;
 			        btv->grab++;
                                 btv->frame_stat[btv->grf] = GBUFFER_DONE;
@@ -3170,14 +3251,14 @@
 					btv->risc_jmp[11]=cpu_to_le32(btv->gre);
 					bt848_set_geo(btv, btv->gwidth,
 						      btv->gheight,
-						      btv->gfmt, 0);
+						      btv->gfmt,0);
 				} else {
 					bt848_set_risc_jmps(btv);
 					btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI);
 					btand(~BT848_VSCALE_COMB, BT848_O_VSCALE_HI);
                                         bt848_set_geo(btv, btv->win.width, 
 						      btv->win.height,
-						      btv->win.color_fmt, 0);
+						      btv->win.color_fmt,0);
 				}
 				wake_up_interruptible(&btv->capq);
 				break;
@@ -3188,7 +3269,7 @@
 				btv->risc_jmp[11]=cpu_to_le32(btv->gre);
 				btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP);
 				bt848_set_geo(btv, btv->gwidth, btv->gheight,
-					      btv->gfmt, 0);
+					      btv->gfmt,0);
 			}
 		}
 		if (astat&BT848_INT_OCERR) 
@@ -3255,6 +3336,9 @@
 	int result;
 	unsigned char command;
 	struct bttv *btv;
+#if defined(__powerpc__)
+        unsigned int cmd;
+#endif
 
         btv=&bttvs[bttv_num];
         btv->dev=dev;
@@ -3278,6 +3362,7 @@
         else
                 btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA);
 
+        btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK;
         pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
         printk(KERN_INFO "bttv%d: Brooktree Bt%d (rev %d) ",
                bttv_num,btv->id, btv->revision);
@@ -3285,6 +3370,14 @@
         printk("irq: %d, ",btv->irq);
         printk("memory: 0x%lx.\n", btv->bt848_adr);
 
+#if defined(__powerpc__)
+        /* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
+        /* response on cards with no firmware is not enabled by OF */
+        pci_read_config_dword(dev, PCI_COMMAND, &cmd);
+        cmd = (cmd | PCI_COMMAND_MEMORY ); 
+        pci_write_config_dword(dev, PCI_COMMAND, cmd);
+#endif
+        
         btv->pll.pll_crystal = 0;
         btv->pll.pll_ifreq   = 0;
         btv->pll.pll_ofreq   = 0;
@@ -3306,8 +3399,12 @@
                         break;
                 }
         }
-        
-        btv->bt848_mem = ioremap(btv->bt848_adr, 0x1000);
+       
+#ifdef __sparc__
+	btv->bt848_mem=(unsigned char *)btv->bt848_adr;
+#else
+	btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000);
+#endif
         
         /* clear interrupt mask */
 	btwrite(0, BT848_INT_MASK);
@@ -3393,10 +3490,9 @@
 		btwrite(0x0, BT848_GPIO_OUT_EN);
 
     		/* unregister i2c_bus */
-		i2c_unregister_bus((&btv->i2c));
+                i2c_bit_del_bus(&btv->i2c_adap);
 
 		/* disable PCI bus-mastering */
-
 		pci_read_config_byte(btv->dev, PCI_COMMAND, &command);
 		/* Should this be &=~ ?? */
 		command&=~PCI_COMMAND_MASTER;
@@ -3436,19 +3532,15 @@
 }
 
 #ifdef MODULE
-
-EXPORT_NO_SYMBOLS;
-
 int init_module(void)
-{
 #else
 int init_bttv_cards(struct video_init *unused)
-{
 #endif
+{
 	int i;
   
 	handle_chipset();
-	if (find_bt848()<0)
+	if (find_bt848()<=0)
 		return -EIO;
 
 	/* initialize Bt848s */
@@ -3465,7 +3557,6 @@
 }
 
 
-
 #ifdef MODULE
 
 void cleanup_module(void)
@@ -3477,14 +3568,6 @@
 
 /*
  * Local variables:
- * c-indent-level: 8
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
+ * c-basic-offset: 8
  * End:
  */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)