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

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

diff -u --recursive --new-file v2.3.49/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
@@ -3,7 +3,7 @@
 
     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>
+    (c) 1999,2000 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
@@ -20,6 +20,8 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include <linux/config.h>
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
@@ -40,27 +42,28 @@
 #include <linux/types.h>
 #include <linux/wrapper.h>
 #include <linux/interrupt.h>
-#include <linux/version.h>
 #include <linux/kmod.h>
 #include <linux/vmalloc.h>
 
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <linux/videodev.h>
-
+#ifdef LOCK_I2C_BUS
+# error INSTALL ERROR
+# error gcc uses the old, obsolete i2c.h include file.  Please install the \
+	new i2c stack.  Please install it by patching the kernel, otherwise \
+	gcc will not find the new header files.
+#endif
 
 #include "bttv.h"
 #include "tuner.h"
 
 #define DEBUG(x) 		/* Debug driver */
-#define IDEBUG(x) 		/* Debug interrupt handler */
+#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 void bt848_set_risc_jmps(struct bttv *btv, int state);
 
 static int bttv_num;			/* number of Bt848s in use */
 static struct bttv bttvs[BTTV_MAX];
@@ -74,7 +77,20 @@
 MODULE_PARM(pll,"1-4i");
 MODULE_PARM(bigendian,"i");
 MODULE_PARM(fieldnr,"i");
+MODULE_PARM(verbose,"i");
+MODULE_PARM(debug,"i");
 MODULE_PARM(autoload,"i");
+MODULE_PARM(gbuffers,"i");
+MODULE_PARM(gbufsize,"i");
+
+EXPORT_SYMBOL(bttv_get_id);
+EXPORT_SYMBOL(bttv_gpio_enable);
+EXPORT_SYMBOL(bttv_read_gpio);
+EXPORT_SYMBOL(bttv_write_gpio);
+EXPORT_SYMBOL(bttv_get_gpio_queue);
+
+MODULE_DESCRIPTION("bttv - v4l driver module for bt848/878 based cards");
+MODULE_AUTHOR("Ralph  Metzler & Marcus Metzler & Gerd Knorr");
 
 #if defined(__sparc__) || defined(__powerpc__)
 static unsigned int bigendian=1;
@@ -87,7 +103,15 @@
 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 unsigned int verbose = 1;
+static unsigned int debug = 0;
+static unsigned int gbuffers = 2;
+static unsigned int gbufsize = BTTV_MAX_FBUF;
+#ifdef MODULE
 static unsigned int autoload = 1;
+#else
+static unsigned int autoload = 0;
+#endif
 
 
 #define I2C_TIMING (0x7<<4)
@@ -100,6 +124,101 @@
 #define BURSTOFFSET 76
 
 
+/* ----------------------------------------------------------------------- */
+/* Exported functions - for other modules which want to access the         */
+/*                      gpio ports (IR for example)                        */
+/*                      see bttv.h for comments                            */
+
+int bttv_get_id(unsigned int card)
+{
+	if (card >= bttv_num) {
+		return -1;
+	}
+		
+	return bttvs[card].type;
+}
+
+int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data)
+{
+	struct bttv *btv;
+
+	if (card >= bttv_num) {
+		return -EINVAL;
+	}
+	
+	btv = &bttvs[card];
+	down(&btv->lock);
+	btaor(data, ~mask, BT848_GPIO_OUT_EN);
+	up(&btv->lock);
+
+	return 0;
+}
+
+int bttv_read_gpio(unsigned int card, unsigned long *data)
+{
+	struct bttv *btv;
+	
+	if (card >= bttv_num) {
+		return -EINVAL;
+	}
+
+	btv = &bttvs[card];
+
+	if(btv->shutdown) {
+		return -ENODEV;
+	}
+
+	down(&btv->lock);
+
+/* prior setting BT848_GPIO_REG_INP is (probably) not needed 
+   because we set direct input on init */
+
+	*data = btread(BT848_GPIO_DATA);
+
+	up(&btv->lock);
+
+	return 0;
+}
+
+int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data)
+{
+	struct bttv *btv;
+	
+	if (card >= bttv_num) {
+		return -EINVAL;
+	}
+
+	btv = &bttvs[card];
+
+	down(&btv->lock);
+
+/* prior setting BT848_GPIO_REG_INP is (probably) not needed 
+   because direct input is set on init */
+
+	btaor(data & mask, ~mask, BT848_GPIO_DATA);
+
+	up(&btv->lock);
+
+	return 0;
+}
+
+WAIT_QUEUE* bttv_get_gpio_queue(unsigned int card)
+{
+	struct bttv *btv;
+
+	if (card >= bttv_num) {
+		return NULL;
+	}
+
+	btv = &bttvs[card];
+
+	if (bttvs[card].shutdown) {
+		return NULL;
+	}
+
+	return &btv->gpioq;
+}
+
 /*******************************/
 /* Memory management functions */
 /*******************************/
@@ -176,11 +295,11 @@
         return ret;
 }
 
-static void * rvmalloc(unsigned long size)
+static void * rvmalloc(signed long size)
 {
 	void * mem;
 	unsigned long adr, page;
-        
+
 	mem=vmalloc(size);
 	if (mem) 
 	{
@@ -197,7 +316,7 @@
 	return mem;
 }
 
-static void rvfree(void * mem, unsigned long size)
+static void rvfree(void * mem, signed long size)
 {
         unsigned long adr, page;
         
@@ -227,7 +346,7 @@
 static int fbuffer_alloc(struct bttv *btv)
 {
 	if(!btv->fbuffer)
-		btv->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS*BTTV_MAX_FBUF);
+		btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize);
 	else
 		printk(KERN_ERR "bttv%d: Double alloc of fbuffer!\n",
 			btv->nr);
@@ -320,7 +439,8 @@
 	}
 	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);
+        if (verbose)
+		printk("bttv%d: i2c attach [%s]\n",btv->nr,client->name);
         return 0;
 }
 
@@ -328,8 +448,9 @@
 {
         struct bttv *btv = (struct bttv*)client->adapter->data;
 	int i;
-        
-        printk("bttv%d: i2c detach [%s]\n",btv->nr,client->name);
+
+        if (verbose)
+		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) {
@@ -395,19 +516,20 @@
 {
         unsigned char buffer = 0;
 
-	if (NULL != probe_for)
+	if (verbose && NULL != probe_for)
 		printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ",
 		       btv->nr,probe_for,addr);
         btv->i2c_client.addr = addr >> 1;
         if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) {
-		if (NULL != probe_for)
-			printk("not found\n");
-		else
+		if (NULL != probe_for) {
+			if (verbose)
+				printk("not found\n");
+		} else
 			printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n",
 			       btv->nr,addr);
                 return -1;
 	}
-	if (NULL != probe_for)
+	if (verbose && NULL != probe_for)
 		printk("found\n");
         return buffer;
 }
@@ -481,31 +603,70 @@
         { TUNER_PHILIPS_PAL,   "Philips FM1216" },
         { TUNER_ABSENT,        "Philips FM1216MF" },
         { TUNER_PHILIPS_NTSC,  "Philips FM1236" },
+        { TUNER_PHILIPS_PAL_I, "Philips FM1246" },
+        { TUNER_ABSENT,        "Philips FM1256" },
+        { TUNER_TEMIC_4036FY5_NTSC,  "Temic 4036FY5" },
+        { TUNER_ABSENT,        "Samsung TCPN9082D" },
+        { TUNER_ABSENT,        "Samsung TCPM9092P" },
+        { TUNER_TEMIC_PAL,     "Temic 4006FH5" },
+        { TUNER_ABSENT,        "Samsung TCPN9085D" },
+        { TUNER_ABSENT,        "Samsung TCPB9085P" },
+        { TUNER_ABSENT,        "Samsung TCPL9091P" },
+        { TUNER_ABSENT,        "Temic 4039FR5" },
+        { TUNER_ABSENT,        "Philips FQ1216 ME" },
+        { TUNER_TEMIC_PAL_I,   "Temic 4066FY5" },
+        { TUNER_ABSENT,        "Philips TD1536" },
+        { TUNER_ABSENT,        "Philips TD1536D" },
+        { TUNER_ABSENT,        "Philips FMR1236" },
+        { TUNER_ABSENT,        "Philips FI1256MP" },
+        { TUNER_ABSENT,        "Samsung TCPQ9091P" },
+        { TUNER_ABSENT,        "Temic 4006FN5" },
+        { TUNER_ABSENT,        "Temic 4009FR5" },
+        { TUNER_ABSENT,        "Temic 4046FM5" },
 };
 
 static void
 hauppauge_eeprom(struct bttv *btv)
 {
-        readee(btv, eeprom_data, 0xa0);
         if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) 
         {
                 btv->tuner_type = hauppauge_tuner[eeprom_data[9]].id;
-                printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr,
-                       hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type);
+		if (verbose)
+			printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr,
+			       hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type);
         }
 }
 
 static void
-hauppauge_msp_reset(struct bttv *btv)
+hauppauge_boot_msp34xx(struct bttv *btv)
 {
-        /* Reset the MSP on some Hauppauge cards */
+	int i;
+
+        /* reset/enable the MSP on some Hauppauge cards */
         /* Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)! */
-        /* Can this hurt cards without one? What about Miros with MSP? */
         btaor(32, ~32, BT848_GPIO_OUT_EN);
         btaor(0, ~32, BT848_GPIO_DATA);
         udelay(2500);
         btaor(32, ~32, BT848_GPIO_DATA);
-        /* btaor(0, ~32, BT848_GPIO_OUT_EN); */
+
+	if (verbose)
+		printk("bttv%d: Hauppauge msp34xx: reset line init\n",btv->nr);
+
+	/* look if the msp3400 driver is already registered */
+	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+		if (btv->i2c_clients[i] != NULL &&
+		    btv->i2c_clients[i]->driver->id == I2C_DRIVERID_MSP3400) {
+			return;
+		}
+	}
+
+	/* if not: look for the chip ... */
+	if (I2CRead(btv, I2C_MSP3400, "MSP34xx")) {
+		/* ... if found re-register to trigger a i2c bus rescan, */
+		/*     this time with the msp34xx chip activated */
+		i2c_bit_del_bus(&btv->i2c_adap);
+		i2c_bit_add_bus(&btv->i2c_adap);
+	}
 }
 
 
@@ -528,7 +689,15 @@
 	/* GPIO inputs are pulled up, so no need to drive 
 	 * reset pin any longer */
 	btwrite(0,BT848_GPIO_OUT_EN);
-	
+
+	/*  we could/should try and reset/control the AD pots? but
+	    right now  we simply  turned off the crushing.  Without
+	    this the AGC drifts drifts
+	    remember the EN is reverse logic -->
+	    setting BT848_ADC_AGC_EN disable the AGC
+	    tboult@eecs.lehigh.edu
+	*/
+	btwrite(BT848_ADC_RESERVED|BT848_ADC_AGC_EN, BT848_ADC);
 	
 	/*	Initialise MAX517 DAC */
 	printk(KERN_INFO "Setting DAC reference voltage level ...\n");
@@ -555,19 +724,34 @@
 	int id;
 	char *name;
 } vendors[] = {
-	{ 0x0070, "Hauppauge" },
-	{ 0x144f, "Askey" },
+	{ 0x0001, "ATI Technologies Inc" },
+	{ 0x10b4, "STB Systems Inc" },
+	{ 0x13eb, "Hauppauge Computer Works Inc" },
+	{ 0x1461, "Avermedia" },
+	{ 0x1850, "Chronos" },
+	{ 0x1852, "Typhoon" },
+	{ 0x3000, "Askey" },
+	{ 0x3002, "Askey" },
+	{ 0x6606, "Leadtek" },
 	{ -1, NULL }
 };
 
 static struct CARD {
-	int id;
 	int vid;
+	int id;
 	int cardnr;
 	char *name;
 } cards[] = {
-	{ 0x13eb, 0x0070, BTTV_HAUPPAUGE878,  "WinTV Theater" },
-	{ 0x3002, 0x144f, BTTV_MAGICTVIEW061, "Magic TView"   },
+	{ 0x0001, 0x1002, BTTV_HAUPPAUGE878,  "TV Wonder" },
+	{ 0x10b4, 0x2636, BTTV_HAUPPAUGE878,  "???" },
+	{ 0x13eb, 0x0070, BTTV_HAUPPAUGE878,  "WinTV" },
+	{ 0x1461, 0x0002, BTTV_AVERMEDIA98,   "TVCapture 98" },
+	{ 0x1850, 0x1851, BTTV_CHRONOS_VS2,   "Video Shuttle II" },
+	{ 0x1852, 0x1852, BTTV_TYPHOON_TVIEW, "TView TV/FM Tuner" },
+	{ 0x3000, 0x14ff, BTTV_MAGICTVIEW061, "TView 99"  },
+	{ 0x3002, 0x144f, BTTV_MAGICTVIEW061, "Magic TView"  },
+	{ 0x3002, 0x14ff, BTTV_PHOEBE_TVMAS,  "TV Master"  },
+	{ 0x6606, 0x217d, BTTV_WINFAST2000,   "WinFast TV 2000" },
 	{ -1, -1, -1, NULL }
 };
 
@@ -594,7 +778,7 @@
 static struct tvcard tvcards[] = 
 {
 	/* 0x00 */
-        { "unknown",
+        { " *** UNKNOWN *** ",
           3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0,
 	  1,1,1,1,0 },
         { "MIRO PCTV",
@@ -614,7 +798,7 @@
           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,
+          3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 4,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,
@@ -713,16 +897,32 @@
 	{ "Terratec TerraTValue",
           3, 1, 0, 2, 0xf00, { 2, 3, 1, 1}, { 0x500, 0, 0x300, 0x900, 0x900},0,
 	  1,1,1,1,0 },
+	{ "Leadtek WinFast 2000",
+	  3, 1, 0, 2, 0xfff000, { 2, 3, 1, 1,0},
+	  { 0x621000,0x620100,0x621100,0x620000,0xE210000,0x620000},0,
+	  1,1,1,1,1 },
+	{ "Chronos Video Shuttle II",
+	  3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0, 0x1000, 0x1000, 0x0800},0,
+	  1,1,1,1,0 },
+
+	{ "Typhoon TView TV/FM Tuner",
+	  3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0x800, 0, 0, 0x1800, 0 },0,
+	  1,1,1,1,0 },
+	{ "PixelView PlayTV pro",                                                               
+          3, 1, 0, 2, 0xff, { 2, 3, 1, 1 },                                                     
+          { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 }, 0 }
 };
 #define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard))
 
 static void
-dump_eeprom(struct bttv *btv, int addr)
+dump_eeprom(struct bttv *btv,int addr)
 {
-	int i,id1,id2,n1,n2;
+	int i;
 
+	if (verbose < 2)
+		return;
+	/* for debugging: dump eeprom to syslog */
 	printk(KERN_DEBUG "bttv%d: dump eeprom @ 0x%02x\n",btv->nr,addr);
-        readee(btv, eeprom_data,addr);
 	for (i = 0; i < 256;) {
 		printk(KERN_DEBUG "  %02x:",i);
 		do {
@@ -730,35 +930,47 @@
 		} while (i % 16);
 		printk("\n");
 	}
-	id1 = (eeprom_data[252] << 8) | (eeprom_data[253]);
-	id2 = (eeprom_data[254] << 8) | (eeprom_data[255]);
-	if (id1 != 0 && id1 != 0xffff &&
-	    id2 != 0 && id2 != 0xffff) {
-		n1 = -1;
-		n2 = -1;
-		for (i = 0; vendors[i].id != -1; i++)
-			if (vendors[i].id == id2)
-				n2 = i;
-		for (i = 0; cards[i].id != -1; i++)
-			if (cards[i].id  == id1 &&
-			    cards[i].vid == id2)
-				n1 = i;
-		if (n1 != -1 && n2 != -1) {
-			printk(KERN_INFO "  id: %s (0x%04x), vendor: %s (0x%04x)\n",
-			       cards[n1].name,id1,vendors[n2].name,id2);
-			printk(KERN_INFO "  => card=%d (%s)\n",
-			       cards[n1].cardnr,tvcards[cards[n1].cardnr].name);
-#if 1
-			/* not yet, but that's the plan for autodetect... */
-			btv->type = cards[n1].cardnr;
-#endif
-		} else {
-			printk(KERN_INFO "  id: %s (0x%04x), vendor: %s (0x%04x)\n",
-			       (n1 != -1) ? cards[n1].name   : "unknown", id1,
-			       (n2 != -1) ? vendors[n2].name : "unknown", id2);
-			printk(KERN_INFO "  please mail card type, id + vendor to ");
-			printk(" kraxel@goldbach.in-berlin.de\n");
-		}
+}
+
+static int
+idcard_eeprom(struct bttv *btv)
+{
+	int i,id1,id2,n1,n2;
+
+	id1 = (eeprom_data[254] << 8) | (eeprom_data[255]);
+	id2 = (eeprom_data[252] << 8) | (eeprom_data[253]);
+	if (id1 == 0 || id1 == 0xffff ||
+	    id2 == 0 || id2 == 0xffff)
+		return -1;
+
+	/* look for the card */
+	n1 = -1; n2 = -1;
+	for (i = 0; vendors[i].id != -1; i++)
+		if (vendors[i].id == id2)
+			n2 = i;
+	for (i = 0; cards[i].id != -1; i++)
+		if (cards[i].id  == id1 &&
+		    cards[i].vid == id2)
+			n1 = i;
+
+	if (n1 != -1 && n2 != -1) {
+		/* found it */
+		printk(KERN_INFO "bttv%d: id: %s (0x%04x), vendor: %s (0x%04x)\n",
+		       btv->nr,cards[n1].name,id1,vendors[n2].name,id2);
+		if (verbose)
+			printk(KERN_INFO "bttv%d:   => card=%d (%s)\n",
+			       btv->nr,cards[n1].cardnr,
+			       tvcards[cards[n1].cardnr].name);
+		return cards[n1].cardnr;
+	} else {
+		/* 404 */
+		printk(KERN_INFO "bttv%d: id: %s (0x%04x), vendor: %s (0x%04x)\n",
+		       btv->nr, "unknown", id1,
+		       (n2 != -1) ? vendors[n2].name : "unknown", id2);
+		printk(KERN_INFO "please mail id + vendor, board name and "
+		       "the correct card= insmod option to "
+		       "kraxel@goldbach.in-berlin.de\n");
+		return -1;
 	}
 }
 
@@ -810,21 +1022,6 @@
 }
 
 
-static void bt848_cap(struct bttv *btv, uint state)
-{
-	if (state) 
-	{
-		btv->cap|=3;
-		bt848_set_risc_jmps(btv);
-	}
-	else
-	{
-		btv->cap&=~3;
-		bt848_set_risc_jmps(btv);
-	}
-}
-
-
 /* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC*/
 
 /* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C 
@@ -885,9 +1082,10 @@
                 /* printk("bttv%d: PLL: no change required\n",btv->nr); */
                 return 1;
         }
-        
-        printk("bttv%d: PLL: %d => %d ... ",btv->nr,
-               btv->pll.pll_ifreq, btv->pll.pll_ofreq);
+
+        if (verbose)
+		printk("bttv%d: PLL: %d => %d ... ",btv->nr,
+		       btv->pll.pll_ifreq, btv->pll.pll_ofreq);
 
 	set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
 
@@ -907,13 +1105,15 @@
                 {
                         btwrite(0x08,BT848_TGCTRL);
                         btv->pll.pll_current = btv->pll.pll_ofreq;
-                        printk("ok\n");
+			if (verbose)
+				printk("ok\n");
                         return 1;
                 }
                 mdelay(10);
         }
         btv->pll.pll_current = 0;
-        printk("oops\n");
+	if (verbose)
+		printk("oops\n");
         return -1;
 }
 
@@ -1010,10 +1210,9 @@
 	unsigned int *po=(unsigned int *) btv->vbi_odd;
 	unsigned int *pe=(unsigned int *) btv->vbi_even;
   
-	DEBUG(printk(KERN_DEBUG "vbiodd: 0x%lx\n",(long)btv->vbi_odd));
-	DEBUG(printk(KERN_DEBUG "vbievn: 0x%lx\n",(long)btv->vbi_even));
-	DEBUG(printk(KERN_DEBUG "po: 0x%lx\n",(long)po));
-	DEBUG(printk(KERN_DEBUG "pe: 0x%lx\n",(long)pe));
+	if (debug)
+		printk("bttv%d: vbi: po=%08lx pe=%08lx\n",
+		       btv->nr,virt_to_bus(po), virt_to_bus(pe));
         
 	*(po++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(po++)=0;
 	for (i=0; i<16; i++) 
@@ -1036,11 +1235,11 @@
 	DEBUG(printk(KERN_DEBUG "pe: 0x%lx\n",(long)pe));
 }
 
-int fmtbppx2[16] = {
+static int fmtbppx2[16] = {
         8, 6, 4, 4, 4, 3, 2, 2, 4, 3, 0, 0, 0, 0, 2, 0 
 };
 
-int palette2fmt[] = {
+static int palette2fmt[] = {
        0,
        BT848_COLOR_FMT_Y8,
        BT848_COLOR_FMT_RGB8,
@@ -1082,7 +1281,7 @@
                 *(ro++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL);
                 *(ro++)=cpu_to_le32(kvirt_to_bus(vadr));
                 *(re++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL);
-                *(re++)=cpu_to_le32(kvirt_to_bus(vadr+BTTV_MAX_FBUF/2));
+                *(re++)=cpu_to_le32(kvirt_to_bus(vadr+gbufsize/2));
                 vadr+=bpl;
 	}
 	
@@ -1108,6 +1307,9 @@
 	unsigned long vadr=(unsigned long) vbuf;
 	int shift, csize;	
 
+	if (debug)
+		printk("bttv%d: prisc: ro=%08lx re=%08lx\n",
+		       btv->nr,virt_to_bus(ro), virt_to_bus(re));
 
 	switch(fmt)
 	{
@@ -1140,7 +1342,7 @@
 	}
 	cbadr=vadr+(width*height);
 	cradr=cbadr+csize;
-	inter = (height>btv->win.cropheight/2) ? 1 : 0;
+	inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0;
 	
 	*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3);
         *(ro++)=0;
@@ -1158,7 +1360,7 @@
 	        if (inter) 
 		        rp= (line&1) ? &re : &ro;
 		else 
-	                rp= (line>=height) ? &re : &ro; 
+	                rp= (line>=height) ? &ro : &re; 
 	                
 
 	        if(line&lmask)
@@ -1222,9 +1424,12 @@
                 return make_rawrisctab(btv, ro, re, vbuf);
         if (palette>=VIDEO_PALETTE_PLANAR)
                 return make_prisctab(btv, ro, re, vbuf, width, height, palette);
-        
-        
-	inter = (height>btv->win.cropheight/2) ? 1 : 0;
+
+	if (debug)
+		printk("bttv%d: vrisc: ro=%08lx re=%08lx\n",
+		       btv->nr,virt_to_bus(ro), virt_to_bus(re));
+	
+	inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0;
 	bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2;
 	
 	*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); 
@@ -1237,7 +1442,7 @@
 	        if (inter) 
 		        rp= (line&1) ? &re : &ro;
 		else 
-	                rp= (line>=height) ? &re : &ro; 
+	                rp= (line>=height) ? &ro : &re; 
 
 		bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr);
 		if (bpl<=bl)
@@ -1335,32 +1540,31 @@
 
 static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
 {
-	int i, line, x, y, bpl, width, height, inter;
+	int i, line, x, y, bpl, width, height, inter, maxw;
 	unsigned int bpp, dx, sx, **rp, *ro, *re, flags, len;
 	unsigned long adr;
-	unsigned char *clipmap, cbit, lastbit, outofmem;
+	unsigned char *clipmap, *clipline, 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;
-	}
+	/* take care: bpp != btv->win.bpp is allowed here */
+	bpp = fmtbppx2[btv->win.color_fmt&0xf]/2;
+	bpl=btv->win.bpl;
+	adr=btv->win.vidadr + btv->win.x * btv->win.bpp + btv->win.y * bpl;
 	inter=(btv->win.interlace&1)^1;
 	width=btv->win.width;
 	height=btv->win.height;
+	if (debug)
+		printk("bttv%d: make_clip: pal=%d size=%dx%d, bpl=%d bpp=%d\n",
+		       btv->nr,btv->picture.palette,width,height,bpl,bpp);
 	if(width > 1023)
 		width = 1023;		/* sanity check */
 	if(height > 625)
 		height = 625;		/* sanity check */
-	ro=btv->risc_odd;
-	re=btv->risc_even;
+	ro=btv->risc_scr_odd;
+	re=btv->risc_scr_even;
+
+	if (debug)
+		printk("bttv%d: clip: ro=%08lx re=%08lx\n",
+		       btv->nr,virt_to_bus(ro), virt_to_bus(re));
 
 	if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) {
 		/* can't clip, don't generate any risc code */
@@ -1380,16 +1584,15 @@
 	/* clip against viewing window AND screen 
 	   so we do not have to rely on the user program
 	 */
-	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));
-	}
+	maxw = (bpl - btv->win.x * btv->win.bpp) / bpp;
+	clip_draw_rectangle(clipmap, (width > maxw) ? maxw : 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++)=cpu_to_le32(0);
@@ -1401,12 +1604,30 @@
         {
 		y = line>>inter;
 		rp= (line&1) ? &re : &ro;
-		lastbit=(clipmap[y<<7]&1);
-		for(x=dx=1,sx=0; x<=width && !outofmem; x++) {
-			cbit = (clipmap[(y<<7)+(x>>3)] & (1<<(x&7)));
-			if (x < width && !lastbit == !cbit)
+		clipline = clipmap + (y<<7); /* running pointers ... */
+		lastbit = *clipline & 1;
+		for(x=dx=0,sx=0; x<=width && !outofmem;) {
+			if (0 == (x&7)) {
+				/* check bytes not bits if we can ... */
+				if (lastbit) {
+					while (0xff==*clipline && x<width-8) {
+						x  += 8;
+						dx += 8;
+						clipline++;
+					}
+				} else {
+					while (0x00==*clipline && x<width-8) {
+						x  += 8;
+						dx += 8;
+						clipline++;
+					}
+				}
+			}
+			cbit = *clipline & (1<<(x&7));
+			if (x < width && !lastbit == !cbit) {
 				dx++;
-			else {	/* generate the dma controller code */
+			} else {
+				/* generate the dma controller code */
 				len = dx * bpp;
 				flags = ((bpp==4) ? BT848_RISC_BYTE3 : 0);
 				flags |= ((!sx) ? BT848_RISC_SOL : 0);
@@ -1420,11 +1641,14 @@
 				lastbit=cbit;
 				sx += dx;
 				dx = 1;
-				if (ro - btv->risc_odd > RISCMEM_LEN/2 - 16)
+				if (ro - btv->risc_scr_odd>RISCMEM_LEN/2 - 16)
 					outofmem++;
-				if (re - btv->risc_even > RISCMEM_LEN/2 - 16)
+				if (re - btv->risc_scr_even>RISCMEM_LEN/2 - 16)
 					outofmem++;
 			}
+			x++;
+			if (0 == (x&7))
+				clipline++;
 		}
 		if ((!inter)||(line&1))
                         adr+=bpl;
@@ -1475,29 +1699,25 @@
 }
 
 
-static void bt848_set_geo(struct bttv *btv, u16 width, u16 height,
-			  u16 fmt, int no_irq_context)
+static void bt848_set_geo(struct bttv *btv,
+			  int no_irq_context)
 {
         u16 vscale, hscale;
 	u32 xsf, sr;
-	u16 hdelay, vdelay;
-	u16 hactive, vactive;
+	u16 ewidth, eheight, owidth, oheight;
+	u16 format, bswap;
+	u16 hdelay;
+	u16 hactive;
 	u16 inter;
 	u8 crop, vtc;  
 	struct tvnorm *tvn;
 	unsigned long flags;
  	
-	if (!width || !height)
-	        return;
-
 	save_flags(flags);
 	cli();
 
 	tvn=&tvnorms[btv->win.norm];
 	
-        btv->win.cropheight=tvn->sheight;
-        btv->win.cropwidth=tvn->swidth;
-
 	btwrite(tvn->adelay, BT848_ADELAY);
 	btwrite(tvn->bdelay, BT848_BDELAY);
 	btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM);
@@ -1508,59 +1728,84 @@
 	if (no_irq_context)
 		set_pll(btv);
 
-	btwrite(fmt, BT848_COLOR_FMT);
-	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 (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;
 	/* Some people say interpolation looks bad ... */
 	/* vtc = (hactive < 193) ? 2 : ((hactive < 385) ? 1 : 0); */
      
-	btv->win.interlace = (height>btv->win.cropheight/2) ? 1 : 0;
-	inter=(btv->win.interlace&1)^1;
-	vdelay=btv->win.cropy+tvn->vdelay;
+	btv->win.interlace = (btv->win.height>tvn->sheight/2) ? 1 : 0;
 
-	xsf = (hactive*tvn->scaledtwidth)/btv->win.cropwidth;
-	hscale = ((tvn->totalwidth*4096UL)/xsf-4096);
-
-	hdelay=tvn->hdelayx1+btv->win.cropx;
-	hdelay=(hdelay*hactive)/btv->win.cropwidth;
-	hdelay&=0x3fe;
+	if (0 == btv->risc_cap_odd &&
+	    0 == btv->risc_cap_even) {
+		/* overlay only */
+		owidth  = btv->win.width;
+		oheight = btv->win.height;
+		ewidth  = btv->win.width;
+		eheight = btv->win.height;
+		format  = btv->win.color_fmt;
+		bswap   = btv->fb_color_ctl;
+	} else if (-1 != btv->gq_grab      &&
+		   0  == btv->risc_cap_odd &&
+		   !btv->win.interlace     &&
+		   btv->scr_on) {
+		/* odd field -> overlay, even field -> capture */
+		owidth  = btv->win.width;
+		oheight = btv->win.height;
+		ewidth  = btv->gbuf[btv->gq_grab].width;
+		eheight = btv->gbuf[btv->gq_grab].height;
+		format  = (btv->win.color_fmt & 0xf0) |
+			(btv->gbuf[btv->gq_grab].fmt & 0x0f);
+		bswap   = btv->fb_color_ctl & 0x0a;
+	} else {
+		/* capture only */
+		owidth  = btv->gbuf[btv->gq_grab].width;
+		oheight = btv->gbuf[btv->gq_grab].height;
+		ewidth  = btv->gbuf[btv->gq_grab].width;
+		eheight = btv->gbuf[btv->gq_grab].height;
+		format  = btv->gbuf[btv->gq_grab].fmt;
+		bswap   = 0;
+		inter   = (btv->win.height>tvn->sheight/2) ? 0 : 1;
+	}
 
-	sr=((btv->win.cropheight>>inter)*512)/height-512;
+	inter = (oheight>tvn->sheight/2) ? 0 : 1;
+
+	/* odd field */
+	hactive=owidth;
+	xsf = (hactive*tvn->scaledtwidth)/tvn->swidth;
+	hscale = ((tvn->totalwidth*4096UL)/xsf-4096);
+	hdelay =  tvn->hdelayx1;
+	hdelay =  (hdelay*hactive)/tvn->swidth;
+	hdelay &= 0x3fe;
+	sr=((tvn->sheight>>inter)*512)/oheight-512;
 	vscale=(0x10000UL-sr)&0x1fff;
-	vactive=btv->win.cropheight;
 	crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)|
-	        ((vactive>>4)&0x30)|((vdelay>>2)&0xc0);
-	vscale|= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0;
+		((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0);
+	vscale |= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0;
+	bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, tvn->sheight,
+			hdelay, tvn->vdelay, crop);
+
+	/* even field */
+	hactive=ewidth;
+	xsf = (hactive*tvn->scaledtwidth)/tvn->swidth;
+	hscale = ((tvn->totalwidth*4096UL)/xsf-4096);
+	hdelay =  tvn->hdelayx1;
+	hdelay =  (hdelay*hactive)/tvn->swidth;
+	hdelay &= 0x3fe;
+	sr=((tvn->sheight>>inter)*512)/eheight-512;
+	vscale=(0x10000UL-sr)&0x1fff;
+	crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)|
+		((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0);
+	vscale |= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0;
+	bt848_set_eogeo(btv, 0, vtc, hscale, vscale, hactive, tvn->sheight,
+			hdelay, tvn->vdelay, crop);
 
-	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);
+	btwrite(format, BT848_COLOR_FMT);
+	btwrite(bswap | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
 
 	restore_flags(flags);
 }
 
 
-int bpp2fmt[4] = {
+static int bpp2fmt[4] = {
         BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16,
         BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32 
 };
@@ -1569,14 +1814,31 @@
 {
         unsigned short format;
 
-	if (btv->win.use_yuv) {
-		/* yuv-to-offscreen */
-		format = BT848_COLOR_FMT_YUY2;
+	if (btv->picture.palette > 0 && btv->picture.palette <= VIDEO_PALETTE_YUV422) {
+		/* format set by VIDIOCSPICT */
+		format = palette2fmt[btv->picture.palette];
 	} else {
+		/* use default for the given color depth */
 		format = (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 :
 			bpp2fmt[(btv->win.bpp-1)&3];
 	}
 	btv->win.color_fmt = format;
+	if (bigendian &&
+	    format == BT848_COLOR_FMT_RGB32) {
+		btv->fb_color_ctl =
+			BT848_COLOR_CTL_WSWAP_ODD	|
+			BT848_COLOR_CTL_WSWAP_EVEN	|
+			BT848_COLOR_CTL_BSWAP_ODD	|
+			BT848_COLOR_CTL_BSWAP_EVEN;
+        } else if (bigendian &&
+		   (format == BT848_COLOR_FMT_RGB16 ||
+                    format == BT848_COLOR_FMT_RGB15)) {
+		btv->fb_color_ctl =
+			BT848_COLOR_CTL_BSWAP_ODD	|
+			BT848_COLOR_CTL_BSWAP_EVEN;
+        } else {
+		btv->fb_color_ctl = 0;
+	}
 
 	/*	RGB8 seems to be a 9x5x5 GRB color cube starting at
 	 *	color 16. Why the h... can't they even mention this in the
@@ -1590,38 +1852,8 @@
 	else
 	        btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL);
 
-        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 */
-        AUDIO(AUDC_SWITCH_MUTE,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);
-        }
+        bt848_set_geo(btv,1);
 }
-#endif
 
 
 /*
@@ -1639,30 +1871,19 @@
 		if(fbuffer_alloc(btv))
 			return -ENOBUFS;
 	}
-	if(btv->grabbing >= MAX_GBUFFERS)
-		return -ENOBUFS;
-	
-	/*
-	 *	No grabbing past the end of the buffer!
-	 */
-	 
-	if(mp->frame>(MAX_GBUFFERS-1) || mp->frame <0)
+
+	if(mp->frame >= gbuffers || mp->frame < 0)
 		return -EINVAL;
+	if(btv->gbuf[mp->frame].stat != GBUFFER_UNUSED)
+		return -EBUSY;
 		
 	if(mp->height <0 || mp->width <0)
 		return -EINVAL;
-	
-/*      This doesn´t work like this for NTSC anyway.
-        So, better check the total image size ...
-*/
-/*
-	if(mp->height>576 || mp->width>768+BURSTOFFSET)
-		return -EINVAL;
-*/
 	if (mp->format >= PALETTEFMT_MAX)
 		return -EINVAL;
+
 	if (mp->height*mp->width*fmtbppx2[palette2fmt[mp->format]&0x0f]/2
-	    > BTTV_MAX_FBUF)
+	    > gbufsize)
 		return -EINVAL;
 	if(-1 == palette2fmt[mp->format])
 		return -EINVAL;
@@ -1677,41 +1898,40 @@
 	 *	Ok load up the BT848
 	 */
 	 
-	vbuf=(unsigned int *)(btv->fbuffer+BTTV_MAX_FBUF*mp->frame);
-/*	if (!(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC))
-                return -EAGAIN;*/
-	ro=btv->grisc+(((btv->grabcount++)&1) ? 4096 :0);
+	vbuf=(unsigned int *)(btv->fbuffer+gbufsize*mp->frame);
+	ro=btv->gbuf[mp->frame].risc;
 	re=ro+2048;
         make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format);
-	/* bt848_set_risc_jmps(btv); */
+
+	if (debug)
+		printk("bttv%d: cap vgrab: queue %d\n",btv->nr,mp->frame);
         cli();
-        btv->frame_stat[mp->frame] = GBUFFER_GRABBING;
-        if (btv->grabbing) {
-		btv->gfmt_next=palette2fmt[mp->format];
-		btv->gwidth_next=mp->width;
-		btv->gheight_next=mp->height;
-		btv->gro_next=virt_to_bus(ro);
-		btv->gre_next=virt_to_bus(re);
-                btv->grf_next=mp->frame;
-        } else {
-		btv->gfmt=palette2fmt[mp->format];
-		btv->gwidth=mp->width;
-		btv->gheight=mp->height;
-		btv->gro=virt_to_bus(ro);
-		btv->gre=virt_to_bus(re);
-                btv->grf=mp->frame;
-        }
-	if (!(btv->grabbing++)) {
+        btv->gbuf[mp->frame].stat    = GBUFFER_GRABBING;
+	btv->gbuf[mp->frame].fmt     = palette2fmt[mp->format];
+	btv->gbuf[mp->frame].width   = mp->width;
+	btv->gbuf[mp->frame].height  = mp->height;
+	btv->gbuf[mp->frame].ro      = virt_to_bus(ro);
+	btv->gbuf[mp->frame].re      = virt_to_bus(re);
+
+#if 1
+	if (mp->height <= tvnorms[btv->win.norm].sheight/2 &&
+	    mp->format != VIDEO_PALETTE_RAW)
+		btv->gbuf[mp->frame].ro = 0;
+#endif
+
+	if (btv->gq_in == btv->gq_out) {
 		if(mp->format>=VIDEO_PALETTE_COMPONENT) {
 			btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI);
 			btor(BT848_VSCALE_COMB, BT848_O_VSCALE_HI);
 		}
 		btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ);
         }
+	btv->gqueue[btv->gq_in++] = mp->frame;
+	btv->gq_in = btv->gq_in % MAX_GBUFFERS;
+
         sti();
 	btor(3, BT848_CAP_CTL);
 	btor(3, BT848_GPIO_DMA_CTL);
-	/* interruptible_sleep_on(&btv->capq); */
 	return 0;
 }
 
@@ -1787,16 +2007,16 @@
 	if (btv->user)
 		goto out_unlock;
 	
-	btv->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS*BTTV_MAX_FBUF);
+	btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize);
 	ret = -ENOMEM;
 	if (!btv->fbuffer)
 		goto out_unlock;
 
-        btv->grabbing = 0;
-        btv->grab = 0;
-        btv->lastgrab = 0;
-        for (i = 0; i < MAX_GBUFFERS; i++)
-                btv->frame_stat[i] = GBUFFER_UNUSED;
+        btv->gq_in = 0;
+        btv->gq_out = 0;
+	btv->gq_grab = -1;
+        for (i = 0; i < gbuffers; i++)
+                btv->gbuf[i].stat = GBUFFER_UNUSED;
 
         burst(0);
         btv->user++;
@@ -1815,8 +2035,10 @@
 
 	down(&btv->lock);
 	btv->user--;
-	btv->cap&=~3;
-	bt848_set_risc_jmps(btv);
+	btv->scr_on = 0;
+	btv->risc_cap_odd = 0;
+	btv->risc_cap_even = 0;
+	bt848_set_risc_jmps(btv,-1);
 
 	/*
 	 *	A word of warning. At this point the chip
@@ -1841,7 +2063,7 @@
 	 */
 
 	if(btv->fbuffer)
-		rvfree((void *) btv->fbuffer, MAX_GBUFFERS*BTTV_MAX_FBUF);
+		rvfree((void *) btv->fbuffer, gbuffers*gbufsize);
 	btv->fbuffer=0;
 	up(&btv->lock);
 	MOD_DEC_USE_COUNT;  
@@ -1901,7 +2123,9 @@
 static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
 {
 	struct bttv *btv=(struct bttv *)dev;
- 	int i;
+ 	int i,ret;
+
+	if (debug) printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd);
 
 	switch (cmd) {
 	case VIDIOCGCAP:
@@ -2021,17 +2245,6 @@
 	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;
@@ -2041,6 +2254,8 @@
 		struct video_picture p;
 		if(copy_from_user(&p, arg,sizeof(p)))
 			return -EFAULT;
+		if (p.palette > PALETTEFMT_MAX)
+			return -EINVAL;
 		down(&btv->lock);
 		/* We want -128 to 127 we get 0-65535 */
 		bt848_bright(btv, (p.brightness>>8)-128);
@@ -2059,7 +2274,6 @@
 	{
 		struct video_window vw;
 		struct video_clip *vcp = NULL;
-		int on;
 			
 		if(copy_from_user(&vw,arg,sizeof(vw)))
 			return -EFAULT;
@@ -2067,25 +2281,24 @@
 		if(vw.flags || vw.width < 16 || vw.height < 16) 
 		{
                         down(&btv->lock);
-			bt848_cap(btv,0);
+			btv->scr_on = 0;
+			bt848_set_risc_jmps(btv,-1);
 			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;
 
-		on=(btv->cap&3);
-			
-		bt848_cap(btv,0);
+		bt848_set_risc_jmps(btv,0);
+		
 		bt848_set_winsize(btv);
 		up(&btv->lock);
 
@@ -2115,39 +2328,7 @@
 		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;
-
-		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);
+		bt848_set_risc_jmps(btv,-1);
 		up(&btv->lock);
 		return 0;
 	}
@@ -2174,13 +2355,14 @@
 			return -EFAULT;
 		if(btv->win.vidadr == 0)
 			return -EINVAL;
-		if (0 == btv->win.use_yuv && (btv->win.width==0 || btv->win.height==0))
+		if (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);
+		if (v == 1 && btv->win.vidadr != 0)
+			btv->scr_on = 1;
+		if (v == 0)
+			btv->scr_on = 0;
+		bt848_set_risc_jmps(btv,-1);
 		up(&btv->lock);
 		return 0;
 	}
@@ -2217,9 +2399,19 @@
 		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));
+
+		/* set sefault color format */
+		switch (btv->win.bpp) {
+		case  8: btv->picture.palette = VIDEO_PALETTE_HI240;  break;
+		case 15: btv->picture.palette = VIDEO_PALETTE_RGB555; break;
+		case 16: btv->picture.palette = VIDEO_PALETTE_RGB565; break;
+		case 24: btv->picture.palette = VIDEO_PALETTE_RGB24;  break;
+		case 32: btv->picture.palette = VIDEO_PALETTE_RGB32;  break;
+		}
+	
+		if (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;		
@@ -2273,19 +2465,6 @@
 			v.step = 4096;
 		}
 
-#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;
-		}
-#endif
 		if(copy_to_user(arg,&v,sizeof(v)))
 			return -EFAULT;
 		return 0;
@@ -2354,23 +2533,8 @@
 			udelay(10);                     
 			data &= ~WINVIEW_PT2254_STROBE;
 			btwrite(data, BT848_GPIO_DATA);
-
-#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;
@@ -2379,19 +2543,27 @@
 	case VIDIOCSYNC:
 		if(copy_from_user((void *)&i,arg,sizeof(int)))
 			return -EFAULT;
-		switch (btv->frame_stat[i]) {
+		if (i < 0 || i >= gbuffers)
+			return -EINVAL;
+		switch (btv->gbuf[i].stat) {
 		case GBUFFER_UNUSED:
 			return -EINVAL;
 		case GBUFFER_GRABBING:
-			while(btv->frame_stat[i]==GBUFFER_GRABBING) {
+			while(btv->gbuf[i].stat==GBUFFER_GRABBING) {
+				if (debug)
+					printk("bttv%d: cap sync: sleep on %d\n",btv->nr,i);
 				interruptible_sleep_on(&btv->capq);
 				if(signal_pending(current))
 					return -EINTR;
 			}
-                                /* fall */
+			/* fall throuth */
 		case GBUFFER_DONE:
-			btv->frame_stat[i] = GBUFFER_UNUSED;
-			break;
+		case GBUFFER_ERROR:
+			ret = (btv->gbuf[i].stat == GBUFFER_ERROR) ? -EIO : 0;
+			if (debug)
+				printk("bttv%d: cap sync: buffer %d, retval %d\n",btv->nr,i,ret);
+			btv->gbuf[i].stat = GBUFFER_UNUSED;
+			return ret;
 		}
 		return 0;
 
@@ -2422,8 +2594,6 @@
 		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);
@@ -2434,10 +2604,10 @@
 	{
 		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;
+		vm.size=gbufsize*gbuffers;
+		vm.frames=gbuffers;
+		for (i = 0; i < gbuffers; i++)
+			vm.offsets[i]=i*gbufsize;
 		if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
 			return -EFAULT;
 		return 0;
@@ -2510,7 +2680,7 @@
         unsigned long start=(unsigned long) adr;
         unsigned long page,pos;
 
-        if (size>2*BTTV_MAX_FBUF)
+        if (size>gbuffers*gbufsize)
                 return -EINVAL;
         if (!btv->fbuffer) {
                 if(fbuffer_alloc(btv))
@@ -2623,8 +2793,8 @@
 
         down(&btv->lock);
 	btv->vbip=VBIBUF_SIZE;
-	btv->cap|=0x0c;
-	bt848_set_risc_jmps(btv);
+	btv->vbi_on = 1;
+	bt848_set_risc_jmps(btv,-1);
 	up(&btv->lock);
 
 	MOD_INC_USE_COUNT;
@@ -2636,8 +2806,8 @@
 	struct bttv *btv=(struct bttv *)(dev-2);
 
         down(&btv->lock);
-	btv->cap&=~0x0c;
-	bt848_set_risc_jmps(btv);
+	btv->vbi_on = 0;
+	bt848_set_risc_jmps(btv,-1);
 	up(&btv->lock);
 
 	MOD_DEC_USE_COUNT;  
@@ -2875,26 +3045,12 @@
            7a - external */
 }
 
-
-#if 0
-#warning this should be handled by tda9855.c
-static void init_tda9850(struct bttv *btv)
-{
-        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 */
 
 static void idcard(int i)
 {
         struct bttv *btv = &bttvs[i];
+	int type,eeprom = 0;
 
 	btwrite(0, BT848_GPIO_OUT_EN);
 	DEBUG(printk(KERN_DEBUG "bttv%d: GPIO: 0x%08x\n", i, btread(BT848_GPIO_DATA)));
@@ -2903,40 +3059,36 @@
 	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_HAUPEE, "eeprom")>=0)
-		{
-			if(btv->id>849)
-				btv->type=BTTV_HAUPPAUGE878;
-			else
+	/* If we were asked to auto-detect, then do so! */
+	if (btv->type == BTTV_UNKNOWN) {
+			
+		/* many bt878 cards have a eeprom @ 0xa0 => read ID
+		   and try to identify it */
+		if (I2CRead(btv, I2C_HAUPEE, "eeprom") >= 0) {
+			eeprom = 0xa0;
+			readee(btv,eeprom_data,0xa0);
+			dump_eeprom(btv,0xa0); /* DEBUG */
+			type = idcard_eeprom(btv);
+			if (-1 != type) {
+				btv->type = type;
+			} else if (btv->id <= 849) {
+				/* for unknown bt848, assume old Hauppauge */
 			        btv->type=BTTV_HAUPPAUGE;
+			}
 
+		/* STB cards have a eeprom @ 0xae */
 		} else if (I2CRead(btv, I2C_STBEE, "eeprom")>=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, 0x80, "msp3400")>=0) /* check for msp34xx */
+#if 0
+		/* check for msp34xx */
+			if (I2CRead(btv, 0x80, "msp3400")>=0)
 				btv->type = BTTV_MIROPRO;
 			else
-	 			btv->type = BTTV_MIRO;
-		}
-	}
-
-#if 1
-	/* DEBUG: dump eeprom content if available */
-	if (I2CRead(btv, 0xa0, "eeprom")>=0) {
-		dump_eeprom(btv,0xa0);
-	}
+				btv->type = BTTV_MIRO;
 #endif
+	}
 
 	/* print which board we have found */
 	printk(KERN_INFO "bttv%d: model: ",btv->nr);
@@ -2955,8 +3107,12 @@
                 btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7;
         }
         if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) {
-                hauppauge_msp_reset(btv);
+		if (0xa0 != eeprom) {
+			eeprom = 0xa0;
+			readee(btv,eeprom_data,0xa0);
+		}
                 hauppauge_eeprom(btv);
+                hauppauge_boot_msp34xx(btv);
         }
 	if (btv->type == BTTV_MAXI) {
 		/* PHILIPS FI1216MK2 tuner (PAL/SECAM) */
@@ -2973,7 +3129,11 @@
 	    btv->type == BTTV_CONFERENCETV	||
 	    btv->type == BTTV_PIXVIEWPLAYTV	||
 	    btv->type == BTTV_AVERMEDIA98	||
-	    btv->type == BTTV_MAGICTVIEW061) {
+	    btv->type == BTTV_MAGICTVIEW061	||
+	    btv->type == BTTV_CHRONOS_VS2	||
+	    btv->type == BTTV_TYPHOON_TVIEW	||
+	    btv->type == BTTV_PXELVWPLTVPRO     ||
+	    btv->type == BTTV_WINFAST2000) {
                 btv->pll.pll_ifreq=28636363;
                 btv->pll.pll_crystal=BT848_IFORM_XT0;
         }
@@ -3005,7 +3165,7 @@
 	if (tvcards[btv->type].tda985x &&
 	    I2CRead(btv, I2C_TDA9850, "TDA985x") >=0) {
 		if (autoload)
-			request_module("tda9855");
+			request_module("tda985x");
 	}
 
 	if (tvcards[btv->type].tea63xx /* &&
@@ -3023,9 +3183,19 @@
 }
 
 
-static void bt848_set_risc_jmps(struct bttv *btv)
+static void bt848_set_risc_jmps(struct bttv *btv, int flags)
 {
-	int flags=btv->cap;
+	if (-1 == flags) {
+		/* defaults */
+		flags = 0;
+		if (btv->scr_on)
+			flags |= 0x03;
+		if (btv->vbi_on)
+			flags |= 0x0c;
+	}
+
+	if (debug) printk("bttv%d: set_risc_jmp %08lx:",
+			  btv->nr,virt_to_bus(btv->risc_jmp));
 
 	/* Sync to start of odd field */
 	btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC
@@ -3034,17 +3204,27 @@
 
 	/* Jump to odd vbi sub */
 	btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0xd<<20));
-	if (flags&8)
+	if (flags&8) {
+		if (debug) printk(" ev=%08lx",virt_to_bus(btv->vbi_odd));
 		btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->vbi_odd));
-	else
+	} else {
+		if (debug) printk(" -----------");
 		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|(0xe<<20));
-	if (flags&2)
-		btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_odd));
-	else
+	if (0 != btv->risc_cap_odd) {
+		if (debug) printk(" e%d=%08x",btv->gq_grab,btv->risc_cap_odd);
+		flags |= 3;
+		btv->risc_jmp[5]=cpu_to_le32(btv->risc_cap_odd);
+	} else if (flags&2) {
+		if (debug) printk(" eo=%08lx",virt_to_bus(btv->risc_scr_odd));
+		btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_scr_odd));
+	} else {
+		if (debug) printk(" -----------");
 		btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_jmp+6));
+	}
 
 
 	/* Sync to start of even field */
@@ -3054,22 +3234,34 @@
 
 	/* Jump to even vbi sub */
 	btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP);
-	if (flags&4)
+	if (flags&4) {
+		if (debug) printk(" ov=%08lx",virt_to_bus(btv->vbi_even));
 		btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->vbi_even));
-	else
+	} else {
+		if (debug) printk(" -----------");
 		btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->risc_jmp+10));
+	}
 
 	/* Jump to even sub */
 	btv->risc_jmp[10]=cpu_to_le32(BT848_RISC_JUMP|(8<<20));
-	if (flags&1)
-		btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_even));
-	else
+	if (0 != btv->risc_cap_even) {
+		if (debug) printk(" o%d=%08x",btv->gq_grab,btv->risc_cap_even);
+		flags |= 3;
+		btv->risc_jmp[11]=cpu_to_le32(btv->risc_cap_even);
+	} else if (flags&1) {
+		if (debug) printk(" oo=%08lx",virt_to_bus(btv->risc_scr_even));
+		btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_scr_even));
+	} else {
+		if (debug) printk(" -----------");
 		btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_jmp+12));
+	}
 
 	btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP);
 	btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp));
 
 	/* enable cpaturing and DMA */
+	if (debug) printk(" flags=0x%x dma=%s\n",
+			  flags,(flags&0x0f) ? "on" : "off");
 	btaor(flags, ~0x0f, BT848_CAP_CTL);
 	if (flags&0x0f)
 		bt848_dma(btv, 3);
@@ -3110,24 +3302,29 @@
 static int init_bt848(int i)
 {
         struct bttv *btv = &bttvs[i];
+	int j;
 
 	btv->user=0; 
         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
+	if (verbose >= 2)
+		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));
 
 	/* reset the bt848 */
 	btwrite(0, BT848_SRESET);
 	DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%lx\n",i,(unsigned long) btv->bt848_mem));
 
+	/* not registered yet */
+	btv->video_dev.minor = -1;
+	btv->radio_dev.minor = -1;
+	btv->vbi_dev.minor = -1;
+
 	/* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */
 	btv->win.norm=0; /* change this to 1 for NTSC, 2 for SECAM */
 	btv->win.interlace=1;
@@ -3135,10 +3332,6 @@
 	btv->win.y=0;
 	btv->win.width=768; /* 640 */
 	btv->win.height=576; /* 480 */
-	btv->win.cropwidth=768; /* 640 */
-	btv->win.cropheight=576; /* 480 */
-	btv->win.cropx=0;
-	btv->win.cropy=0;
 	btv->win.bpp=2;
 	btv->win.depth=16;
 	btv->win.color_fmt=BT848_COLOR_FMT_RGB16;
@@ -3146,27 +3339,24 @@
 	btv->win.swidth=1024;
 	btv->win.sheight=768;
 	btv->win.vidadr=0;
-	btv->cap=0;
+	btv->vbi_on=0;
+	btv->scr_on=0;
 
-	btv->gmode=0;
-	btv->risc_odd=0;
-	btv->risc_even=0;
+	btv->risc_scr_odd=0;
+	btv->risc_scr_even=0;
+	btv->risc_cap_odd=0;
+	btv->risc_cap_even=0;
 	btv->risc_jmp=0;
 	btv->vbibuf=0;
-	btv->grisc=0;
-	btv->grabbing=0;
-	btv->grabcount=0;
-	btv->grab=0;
-	btv->lastgrab=0;
         btv->field=btv->last_field=0;
 
 	/* i2c */
         btv->tuner_type=-1;
         init_bttv_i2c(btv);
 
-	if (!(btv->risc_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
+	if (!(btv->risc_scr_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
 		return -1;
-	if (!(btv->risc_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
+	if (!(btv->risc_scr_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
 		return -1;
 	if (!(btv->risc_jmp =(unsigned int *) kmalloc(2048, GFP_KERNEL)))
 		return -1;
@@ -3180,9 +3370,13 @@
 	btv->vbibuf=(unsigned char *) vmalloc(VBIBUF_SIZE);
 	if (!btv->vbibuf) 
 		return -1;
-	if (!(btv->grisc=(unsigned int *) kmalloc(32768, GFP_KERNEL)))
+	if (!(btv->gbuf = kmalloc(sizeof(struct bttv_gbuf)*gbuffers,GFP_KERNEL)))
 		return -1;
-
+	for (j = 0; j < gbuffers; j++) {
+		if (!(btv->gbuf[j].risc = kmalloc(16384,GFP_KERNEL)))
+			return -1;
+	}
+	
 	memset(btv->vbibuf, 0, VBIBUF_SIZE); /* We don't want to return random
 	                                        memory to the user */
 
@@ -3194,7 +3388,14 @@
 /*	btwrite(0, BT848_TDEC); */
         btwrite(0x10, BT848_COLOR_CTL);
 	btwrite(0x00, BT848_CAP_CTL);
-	btwrite(0xac, BT848_GPIO_DMA_CTL);
+	/* set planar and packed mode trigger points and         */
+	/* set rising edge of inverted GPINTR pin as irq trigger */
+	btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
+		BT848_GPIO_DMA_CTL_PLTP1_16|
+		BT848_GPIO_DMA_CTL_PLTP23_16|
+		BT848_GPIO_DMA_CTL_GPINTC|
+		BT848_GPIO_DMA_CTL_GPINTI, 
+		BT848_GPIO_DMA_CTL);
 
         /* select direct input */
 	btwrite(0x00, BT848_GPIO_REG_INP);
@@ -3229,13 +3430,14 @@
                 /*BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|
                   BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/
                 (fieldnr ? BT848_INT_VSYNC : 0)|
+		BT848_INT_GPINT|
 		BT848_INT_SCERR|
 		BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
 		BT848_INT_FMTCHG|BT848_INT_HLOCK,
 		BT848_INT_MASK);
 
 	make_vbitab(btv);
-	bt848_set_risc_jmps(btv);
+	bt848_set_risc_jmps(btv,-1);
   
 	/*
 	 *	Now add the template and register the device unit.
@@ -3262,12 +3464,17 @@
 		if (!astat)
 			return;
 		btwrite(astat,BT848_INT_STAT);
-		IDEBUG(printk ("bttv%d: astat %08x\n", btv->nr, astat));
-		IDEBUG(printk ("bttv%d:  stat %08x\n", btv->nr, 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);
     
+		if (astat&BT848_INT_GPINT) {
+			IDEBUG(printk ("bttv%d: IRQ_GPINT\n", btv->nr));
+			wake_up_interruptible(&btv->gpioq);
+		}
+
 		if (astat&BT848_INT_FMTCHG) 
 		{
 			IDEBUG(printk ("bttv%d: IRQ_FMTCHG\n", btv->nr));
@@ -3283,13 +3490,21 @@
 			IDEBUG(printk ("bttv%d: IRQ_VSYNC\n", btv->nr));
                         btv->field++;
 		}
-		if (astat&BT848_INT_SCERR) {
-			IDEBUG(printk ("bttv%d: IRQ_SCERR\n", btv->nr));
-			bt848_dma(btv, 0);
-			bt848_dma(btv, 1);
+		if (astat&(BT848_INT_SCERR|BT848_INT_OCERR)) {
+			printk("bttv%d: irq:%s%s risc_count=%08x\n",btv->nr,
+			       (astat&BT848_INT_SCERR) ? " SCERR" : "",
+			       (astat&BT848_INT_OCERR) ? " OCERR" : "",
+			       btread(BT848_RISC_COUNT));
+			bt848_set_risc_jmps(btv,0);
+			btwrite(0, BT848_SRESET);
+			btwrite(virt_to_bus(btv->risc_jmp),
+				BT848_RISC_STRT_ADD);
+			bt848_set_geo(btv,0);
+			bt848_set_risc_jmps(btv,-1);
+#if 0
 			wake_up_interruptible(&btv->vbiq);
 			wake_up_interruptible(&btv->capq);
-
+#endif
 		}
 		if (astat&BT848_INT_RISCI) 
 		{
@@ -3307,41 +3522,48 @@
 			/* captured full frame */
 			if (stat&(2<<28)) 
 			{
-				/*wake_up_interruptible(&btv->capq);*/
                                 btv->last_field=btv->field;
-			        btv->grab++;
-                                btv->frame_stat[btv->grf] = GBUFFER_DONE;
-			        if ((--btv->grabbing))
+				if (debug)
+					printk("bttv%d: cap irq: done %d\n",btv->nr,btv->gq_grab);
+				btv->gbuf[btv->gq_grab].stat = GBUFFER_DONE;
+				btv->gq_grab = -1;
+			        if (btv->gq_in != btv->gq_out)
 				{
-					btv->gfmt = btv->gfmt_next;
-					btv->gwidth = btv->gwidth_next;
-					btv->gheight = btv->gheight_next;
-					btv->gro = btv->gro_next;
-					btv->gre = btv->gre_next;
-					btv->grf = btv->grf_next;
-                                        btv->risc_jmp[5]=cpu_to_le32(btv->gro);
-					btv->risc_jmp[11]=cpu_to_le32(btv->gre);
-					bt848_set_geo(btv, btv->gwidth,
-						      btv->gheight,
-						      btv->gfmt,0);
+					btv->gq_grab = btv->gqueue[btv->gq_out++];
+					btv->gq_out  = btv->gq_out % MAX_GBUFFERS;
+					if (debug)
+						printk("bttv%d: cap irq: capture %d\n",btv->nr,btv->gq_grab);
+                                        btv->risc_cap_odd  = btv->gbuf[btv->gq_grab].ro;
+					btv->risc_cap_even = btv->gbuf[btv->gq_grab].re;
+					bt848_set_risc_jmps(btv,-1);
+					bt848_set_geo(btv,0);
+					btwrite(BT848_COLOR_CTL_GAMMA,
+						BT848_COLOR_CTL);
 				} else {
-					bt848_set_risc_jmps(btv);
+                                        btv->risc_cap_odd  = 0;
+					btv->risc_cap_even = 0;
+					bt848_set_risc_jmps(btv,-1);
 					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);
+                                        bt848_set_geo(btv,0);
+					btwrite(btv->fb_color_ctl | BT848_COLOR_CTL_GAMMA,
+						BT848_COLOR_CTL);
 				}
 				wake_up_interruptible(&btv->capq);
 				break;
 			}
 			if (stat&(8<<28)) 
 			{
-			        btv->risc_jmp[5]=cpu_to_le32(btv->gro);
-				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->gq_grab = btv->gqueue[btv->gq_out++];
+				btv->gq_out  = btv->gq_out % MAX_GBUFFERS;
+				if (debug)
+					printk("bttv%d: cap irq: capture %d\n",btv->nr,btv->gq_grab);
+				btv->risc_cap_odd  = btv->gbuf[btv->gq_grab].ro;
+				btv->risc_cap_even = btv->gbuf[btv->gq_grab].re;
+				bt848_set_risc_jmps(btv,-1);
+				bt848_set_geo(btv,0);
+				btwrite(BT848_COLOR_CTL_GAMMA,
+					BT848_COLOR_CTL);
 			}
 		}
 		if (astat&BT848_INT_OCERR) 
@@ -3427,6 +3649,9 @@
         init_waitqueue_head(&btv->capqe);
         btv->vbip=VBIBUF_SIZE;
 
+	init_waitqueue_head(&btv->gpioq);
+	btv->shutdown=0;
+
         btv->id=dev->device;
         btv->irq=dev->irq;
         btv->bt848_adr=dev->resource[0].start;
@@ -3544,15 +3769,17 @@
 static void release_bttv(void)
 {
 	u8 command;
-	int i;
+	int i,j;
 	struct bttv *btv;
 
 	for (i=0;i<bttv_num; i++) 
 	{
 		btv=&bttvs[i];
 
-		/* turn off all capturing, DMA and IRQs */
+    		/* unregister i2c_bus */
+                i2c_bit_del_bus(&btv->i2c_adap);
 
+		/* turn off all capturing, DMA and IRQs */
 		btand(~15, BT848_GPIO_DMA_CTL);
 
 		/* first disable interrupts before unmapping the memory! */
@@ -3560,9 +3787,6 @@
 		btwrite(0xffffffffUL,BT848_INT_STAT);
 		btwrite(0x0, BT848_GPIO_OUT_EN);
 
-    		/* unregister i2c_bus */
-                i2c_bit_del_bus(&btv->i2c_adap);
-
 		/* disable PCI bus-mastering */
 		pci_read_config_byte(btv->dev, PCI_COMMAND, &command);
 		/* Should this be &=~ ?? */
@@ -3570,14 +3794,17 @@
 		pci_write_config_byte(btv->dev, PCI_COMMAND, command);
     
 		/* unmap and free memory */
-		if (btv->grisc)
-		        kfree((void *) btv->grisc);
+		for (j = 0; j < gbuffers; j++)
+			if (btv->gbuf[j].risc)
+				kfree(btv->gbuf[j].risc);
+		if (btv->gbuf)
+		        kfree((void *) btv->gbuf);
 
-		if (btv->risc_odd)
-			kfree((void *) btv->risc_odd);
+		if (btv->risc_scr_odd)
+			kfree((void *) btv->risc_scr_odd);
 			
-		if (btv->risc_even)
-			kfree((void *) btv->risc_even);
+		if (btv->risc_scr_even)
+			kfree((void *) btv->risc_scr_even);
 
 		DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%p.\n", btv->risc_jmp));
 		if (btv->risc_jmp)
@@ -3599,6 +3826,13 @@
 			video_unregister_device(&btv->vbi_dev);
 		if (radio[btv->nr] && btv->radio_dev.minor != -1)
 			video_unregister_device(&btv->radio_dev);
+
+       		/* wake up any waiting processes
+		   because shutdown flag is set, no new processes (in this queue) 
+		   are expected
+		*/
+		btv->shutdown=1;
+		wake_up(&btv->gpioq);
 	}
 }
 
@@ -3614,6 +3848,14 @@
 	       (BTTV_VERSION_CODE >> 16) & 0xff,
 	       (BTTV_VERSION_CODE >> 8) & 0xff,
 	       BTTV_VERSION_CODE & 0xff);
+	if (gbuffers < 2 || gbuffers > MAX_GBUFFERS)
+		gbuffers = 2;
+	if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
+		gbufsize = BTTV_MAX_FBUF;
+	if (verbose)
+		printk(KERN_INFO "bttv: using %d buffers with %dk (%dk total) for capture\n",
+		       gbuffers,gbufsize/1024,gbuffers*gbufsize/1024);
+
 	handle_chipset();
 	if (find_bt848()<=0)
 		return -EIO;

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