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

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

diff -u --recursive --new-file v2.1.117/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
@@ -65,18 +65,12 @@
 #define DEBUG(x)		/* Debug driver */	
 #define IDEBUG(x) 		/* Debug interrupt handler */
 
-static unsigned int remap=0;    /* remap Bt848 */
-static unsigned int vidmem=0;   /* manually set video mem address */
-static int triton1=0;
-static int radio=0;
-
-static unsigned int card=0;
-
-MODULE_PARM(remap,"i");
 MODULE_PARM(vidmem,"i");
 MODULE_PARM(triton1,"i");
-MODULE_PARM(radio,"i");
-MODULE_PARM(card,"i");
+MODULE_PARM(remap,"1-4i");
+MODULE_PARM(radio,"1-4i");
+MODULE_PARM(card,"1-4i");
+MODULE_PARM(pll,"1-4i");
 
 static int find_vga(void);
 static void bt848_set_risc_jmps(struct bttv *btv);
@@ -84,12 +78,19 @@
 /* Anybody who uses more than four? */
 #define BTTV_MAX 4
 
+static unsigned int vidmem=0;   /* manually set video mem address */
+static int triton1=0;
+
+static unsigned int remap[BTTV_MAX];    /* remap Bt848 */
+static unsigned int radio[BTTV_MAX];
+static unsigned int card[BTTV_MAX] = { 0, 0, 
+                                       0, 0 };
+static unsigned int pll[BTTV_MAX] = { 0, 0, 0, 0 };
+
 static int bttv_num;			/* number of Bt848s in use */
 static struct bttv bttvs[BTTV_MAX];
 
 #define I2C_TIMING (0x7<<4)
-#define I2C_COMMAND (I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA)
-
 #define I2C_DELAY   10
 #define I2C_SET(CTRL,DATA) \
     { btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); }
@@ -128,10 +129,6 @@
 
 static inline unsigned long uvirt_to_bus(unsigned long adr) 
 {
-	/*  printk("adr: 0x%8x, ",adr);
-	printk("phys: 0x%8x, ",(uvirt_to_phys(adr)));
-	printk("bus: 0x%8x\n",virt_to_bus(phys_to_virt(uvirt_to_phys(adr))));
-	*/
 	return virt_to_bus(phys_to_virt(uvirt_to_phys(adr)));
 }
 
@@ -199,7 +196,8 @@
 	if(!btv->fbuffer)
 		btv->fbuffer=(unsigned char *) rvmalloc(2*BTTV_MAX_FBUF);
 	else
-		printk(KERN_ERR "bttv: Double alloc of fbuffer!\n");
+		printk(KERN_ERR "bttv%d: Double alloc of fbuffer!\n",
+			btv->nr);
 	if(!btv->fbuffer)
 		return -ENOBUFS;
 	return 0;
@@ -236,7 +234,7 @@
 	/* clear status bit ; BT848_INT_RACK is ro */
 	btwrite(BT848_INT_I2CDONE, BT848_INT_STAT);
   
-	btwrite(((addr & 0xff) << 24) | I2C_COMMAND, BT848_I2C);
+	btwrite(((addr & 0xff) << 24) | btv->i2c_command, BT848_I2C);
   
 	/*
 	 * Timeout for I2CRead is 1 second (this should be enough, really!)
@@ -251,7 +249,8 @@
   
 	if (!i) 
 	{
-		printk(KERN_DEBUG "bttv: I2CRead timeout\n");
+		printk(KERN_DEBUG "bttv%d: I2CRead timeout\n",
+			btv->nr);
 		return -1;
 	}
 	if (!(stat & BT848_INT_RACK))
@@ -274,7 +273,7 @@
 	/* clear status bit; BT848_INT_RACK is ro */
 	btwrite(BT848_INT_I2CDONE, BT848_INT_STAT);
   
-	data=((addr & 0xff) << 24) | ((b1 & 0xff) << 16) | I2C_COMMAND;
+	data=((addr & 0xff) << 24) | ((b1 & 0xff) << 16) | btv->i2c_command;
 	if (both)
 	{
 		data|=((b2 & 0xff) << 8);
@@ -293,7 +292,8 @@
   
 	if (!i) 
 	{
-		printk(KERN_DEBUG "bttv: I2CWrite timeout\n");
+		printk(KERN_DEBUG "bttv%d: I2CWrite timeout\n",
+			btv->nr);
 		return -1;
 	}
 	if (!(stat & BT848_INT_RACK))
@@ -356,9 +356,10 @@
 			if (btv->tuner_type != -1) 
 			{
 				tunertype=btv->tuner_type;
-				i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER,
-					TUNER_SET_TYPE,&tunertype);
-			}
+ 				i2c_control_device(&(btv->i2c), 
+                                                   I2C_DRIVERID_TUNER,
+                                                   TUNER_SET_TYPE,&tunertype);
+ 			}
 			break;
 	}
 }
@@ -406,6 +407,7 @@
         u32 gpiomask;
         u32 muxsel[8];
         u32 audiomux[6]; /* Tuner, Radio, internal, external, mute, stereo */
+        u32 gpiomask2; /* GPIO MUX mask */
 };
 
 static struct tvcard tvcards[] = 
@@ -423,12 +425,14 @@
 	/* Diamond DTV2000 */
         { 3, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3}},
 	/* AVerMedia TVPhone */
-        { 3, 0, 2,15, { 2, 3, 1, 1}, {12, 0,11,11, 0}},
+        { 3, 0, 3,15, { 2, 3, 1, 1}, {12, 0,11,11, 0}},
         /* Matrix Vision MV-Delta */
-        { 5,-1, 4, 0, { 2, 3, 1, 0, 0}},
+        { 5,-1, 3, 0, { 2, 3, 1, 0, 0}},
         /* Fly Video II */
         { 3, 0, 2, 0xc00, { 2, 3, 1, 1}, 
         {0, 0xc00, 0x800, 0x400, 0xc00, 0}},
+        /* TurboTV */
+        { 3, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0}},
 };
 #define TVCARDS (sizeof(tvcards)/sizeof(tvcard))
 
@@ -503,12 +507,46 @@
 
 /* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC*/
 
+/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C 
+   PLL_X = Reference pre-divider (0=1, 1=2) 
+   PLL_C = Post divider (0=6, 1=4)
+   PLL_I = Integer input 
+   PLL_F = Fractional input 
+   
+   F_input = 28.636363 MHz: 
+   PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0
+*/
+
+static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)
+{
+        unsigned char fl, fh, fi;
+        
+        /* prevent overflows */
+        fin/=4;
+        fout/=4;
+
+        fout*=12;
+        fi=fout/fin;
+
+        fout=(fout-fin*fi)*256;
+        fh=fout/fin;
+
+        fout=(fout-fin*fh)*256;
+        fl=fout/fin;
+
+        /*printk("0x%02x 0x%02x 0x%02x\n", fi, fh, fl);*/
+        btwrite(fl,BT848_PLL_F_LO);
+        btwrite(fh,BT848_PLL_F_HI);
+        btwrite(fi|BT848_PLL_X,BT848_PLL_XCI);
+}
+
 static int set_pll(struct bttv *btv)
 {
         int i;
+        unsigned long tv;
 
-	if (!btv->pll)
-	       	return 0;
+        if (!btv->pll)
+		return 0;
         if ((btread(BT848_IFORM)&BT848_IFORM_XT0))
         {
                 /* printk ("switching PLL off\n");*/
@@ -524,13 +562,24 @@
         
         /* printk ("setting PLL for PAL/SECAM\n");*/
 
+	set_pll_freq(btv, 28636363, 35468950);
+/*	
         btwrite(0x00,BT848_TGCTRL);
         btwrite(0xf9,BT848_PLL_F_LO);
         btwrite(0xdc,BT848_PLL_F_HI);
-        btwrite(0x8e,BT848_PLL_XCI);
+        btwrite(14|BT848_PLL_X,BT848_PLL_XCI);
+*/
+	/*
+	 *	Let other people run while the PLL stabilizes
+	 */
+	
+	tv=jiffies+HZ/10;	/* .1 seconds */
+	do
+	{
+		schedule();
+	}
+	while(time_before(jiffies,tv));
 
-	/* Ugh ugh ugh .. schedule ? */
-        udelay(100000);
         for (i=0; i<100; i++) 
         {
                 if ((btread(BT848_DSTATUS)&BT848_DSTATUS_PLOCK))
@@ -548,7 +597,8 @@
 
 static void bt848_muxsel(struct bttv *btv, unsigned int input)
 {
-	btwrite(tvcards[btv->type].gpiomask, BT848_GPIO_OUT_EN);
+	btaor(tvcards[btv->type].gpiomask2,~tvcards[btv->type].gpiomask2,
+        	BT848_GPIO_OUT_EN);
 
 	/* This seems to get rid of some synchronization problems */
 	btand(~(3<<5), BT848_IFORM);
@@ -569,23 +619,7 @@
 	audio(btv, (input!=tvcards[btv->type].tuner) ? 
               AUDIO_EXTERN : AUDIO_TUNER);
 	btaor(tvcards[btv->type].muxsel[input]>>4,
-              ~tvcards[btv->type].gpiomask, BT848_GPIO_DATA);
-#if 0
-	if (input==3) 
-	{
-		btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
-		btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
-	}
-	else
-	{
-		btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
-		btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
-	}
-	if (input==2)
-		input=3;
-	btaor(((input+2)&3)<<5, ~(3<<5), BT848_IFORM);
-	audio(btv, input ? AUDIO_EXTERN : AUDIO_TUNER);
-#endif
+		~tvcards[btv->type].gpiomask2, BT848_GPIO_DATA);
 }
 
 
@@ -645,27 +679,28 @@
        BT848_COLOR_FMT_RGB15,
        BT848_COLOR_FMT_YUY2,
        BT848_COLOR_FMT_BtYUV,
-       -1,
-       -1,
-       -1,
+       0,
+       0,
+       0,
        BT848_COLOR_FMT_RAW,
        BT848_COLOR_FMT_YCrCb422,
        BT848_COLOR_FMT_YCrCb411,
 };
 #define PALETTEFMT_MAX 11
 
-static int  make_rawrisctab(struct bttv *btv, unsigned int *ro,
+static int make_rawrisctab(struct bttv *btv, unsigned int *ro,
                             unsigned int *re, unsigned int *vbuf)
 {
         unsigned long line;
-	unsigned long bpl=1024;
+	unsigned long bpl=1024;		/* bytes per line */
 	unsigned long vadr=(unsigned long) vbuf;
 
 	*(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0;
 	*(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0;
   
         /* In PAL 650 blocks of 256 DWORDs are sampled, but only if VDELAY
-           is 2. We'll have to handle this inside the IRQ handler ... */
+           is 2 and without separate VBI grabbing.
+           We'll have to handle this inside the IRQ handler ... */
 
 	for (line=0; line < 640; line++)
 	{
@@ -802,6 +837,152 @@
 	*x+=dx;
 }
 
+static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
+{
+	int i,t;
+	int yy, y, x, dx;
+	struct video_clip first, *cur, *cur2, *nx, first2, *prev, *nx2;
+	int bpp, bpl, width, height, inter;
+	unsigned int **rp,*ro,*re;
+	unsigned long adr;
+	int cx,cx2,cy,cy2;
+
+	inter=(btv->win.interlace&1)^1;
+	bpp=btv->win.bpp;
+	bpl=btv->win.bpl;
+	ro=btv->risc_odd;
+	re=btv->risc_even;
+	width=btv->win.width;
+	height=btv->win.height;
+	adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl;
+
+	/* clip clipping rects against viewing window AND screen 
+	   so we do not have to rely on the user program
+	 */
+	cx=(btv->win.x<0) ? (-btv->win.x) : 0;
+	cy=(btv->win.y<0) ? (-btv->win.y) : 0;
+	cx2=(btv->win.x+width>btv->win.swidth) ? 
+	        (btv->win.swidth-btv->win.x) : width;
+	cy2=(btv->win.y+height>btv->win.sheight) ? 
+	        (btv->win.sheight-btv->win.y) : height;
+	first.next=NULL;
+	for (i=0; i<ncr; i++)
+	{
+                if ((t=cy-cr[i].y)>0)
+		{
+		        if (cr[i].height<=t)
+			        continue;
+                        cr[i].height-=t;
+			cr[i].y=cy;
+		} 
+		if ((t=cy2-cr[i].y)<cr[i].height) 
+		{
+		        if (t<=0)
+			        continue;
+			cr[i].height=t;
+		}
+                if ((t=cx-cr[i].x)>0)
+		{
+		        if (cr[i].width<=t)
+			        continue;
+                        cr[i].width-=t;
+			cr[i].x=cx;
+		} 
+		if ((t=cx2-cr[i].x)<cr[i].width) 
+		{
+		        if (t<=0)
+			        continue;
+			cr[i].width=t;
+		}
+	        cur=&first;
+		while ((nx=cur->next) && (cr[i].y > cur->next->y))
+		        cur=nx; 
+		cur->next=&(cr[i]);
+		cr[i].next=nx;
+	}
+	first2.next=NULL;
+	
+	*(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0;
+	*(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0;
+	
+	/* loop through all lines */
+	for (yy=0; yy<(height<<inter); yy++) 
+        {
+                y=yy>>inter;
+                rp= (yy&1) ? &re : &ro;
+	  
+                /* remove rects with y2 > y */
+                if ((cur=first2.next))
+                {
+                        prev=&first2;
+                        do
+                        {
+                                if (cur->y+cur->height <= y) 
+                                        prev->next=cur->next;
+                                else
+                                        prev=cur;
+                        } 
+                        while ((cur=cur->next));
+                }
+                
+                /* add rect to second (x-sorted) list if rect.y == y  */
+                if ((cur=first.next))
+                {
+                        while ((cur) && (cur->y == y))
+                        { 
+                                first.next=cur->next;
+                                cur2=&first2;
+                                while ((nx2=cur2->next) && (cur->x > cur2->next->x)) 
+                                        cur2=nx2; 
+                                cur2->next=cur;
+                                cur->next=nx2;
+                                cur=first.next;
+                        }
+                }
+                x=0;
+                if ((btv->win.y+y<=0)||(btv->win.y+y>=btv->win.sheight))
+                        write_risc_segment(rp, adr, BT848_RISC_SKIP, &x,
+                                           width, bpp, width);
+                else 
+                {
+                        dx=cx;
+                        for (cur2=first2.next; cur2; cur2=cur2->next)
+                        {
+                                if (x+dx < cur2->x)
+                                {
+                                        write_risc_segment(rp, adr, BT848_RISC_SKIP,
+                                                           &x, dx, bpp, width);
+                                        dx=cur2->x-x;
+                                        write_risc_segment(rp, adr, BT848_RISC_WRITEC,
+                                                           &x, dx, bpp, width);
+                                        dx=cur2->width;
+                                }
+                                else if (x+dx < cur2->x+cur2->width) 
+                                        dx=cur2->x+cur2->width-x; 
+                        }
+                        if (cx2<width)
+                        {
+                                write_risc_segment(rp, adr, BT848_RISC_SKIP,
+                                                   &x, dx, bpp, width);
+                                write_risc_segment(rp, adr, BT848_RISC_WRITEC,
+                                                   &x, cx2-x, bpp, width);
+                                dx=width-x;
+                        }
+                        write_risc_segment(rp, adr, BT848_RISC_SKIP,
+                                           &x, dx, bpp, width);
+                        write_risc_segment(rp, adr, BT848_RISC_WRITEC,
+                                           &x, width-x, bpp, width);
+                }
+                if ((!inter)||(yy&1))
+                        adr+=bpl;
+	}
+        
+        *(ro++)=BT848_RISC_JUMP;
+	*(ro++)=btv->bus_vbi_even;
+	*(re++)=BT848_RISC_JUMP;
+	*(re++)=btv->bus_vbi_odd;
+}
+
 
 /*
  *	Set the registers for the size we have specified. Don't bother
@@ -814,36 +995,50 @@
  
 struct tvnorm 
 {
-        u16 cropwidth, cropheight;
+        u32 Fsc;
+        u16 swidth, sheight; /* scaled standard width, height */
 	u16 totalwidth;
 	u8 adelay, bdelay, iform;
 	u32 scaledtwidth;
 	u16 hdelayx1, hactivex1;
-	u16 vdelay;
+	u16 vdelay, fporch;
 };
 
 static struct tvnorm tvnorms[] = {
 	/* PAL-BDGHI */
-        { 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
-	    944, 186, 922, 0x20},
+        /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
+        { 35468950,
+          924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+          1135, 186, 924, 0x20},
+/*
+        { 35468950, 
+          768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+	  944, 186, 922, 0x20},
+*/
 	/* NTSC */
-	{ 640, 480,  910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
-	    780, 135, 754, 0x16},
+	{ 28636363,
+          640, 480,  910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
+          780, 135, 754, 0x1a},
 	/* SECAM */
-	{ 768, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1),
-	    944, 186, 922, 0x20},
+	{ 28636363, 
+          640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
+	  780, 135, 754, 0x16},
 	/* PAL-M */
-	{ 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
-	    780, 135, 754, 0x16},
+	{ 28636363, 
+          640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
+	  780, 135, 754, 0x16},
 	/* PAL-N */
-	{ 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
-	    944, 186, 922, 0x20},
+	{ 35468950, 
+          768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
+	  944, 186, 922, 0x20},
 	/* PAL-NC */
-	{ 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
-	    944, 186, 922, 0x20},
+	{ 35468950, 
+          768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
+	  944, 186, 922, 0x20},
 	/* NTSC-Japan */
-	{ 640, 480,  910, 0x68, 0x5d, (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
-	    780, 135, 754, 0x16},
+	{ 28636363,
+          640, 480,  910, 0x68, 0x5d, (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
+	  780, 135, 754, 0x16},
 };
 #define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm))
 
@@ -891,6 +1086,10 @@
 
 	tvn=&tvnorms[btv->win.norm];
 	
+        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)
@@ -900,7 +1099,7 @@
                 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);
@@ -916,12 +1115,13 @@
      
 	btv->win.interlace = (height>btv->win.cropheight/2) ? 1 : 0;
 	inter=(btv->win.interlace&1)^1;
+	vdelay=btv->win.cropy+tvn->vdelay;
+
 	xsf = (hactive*tvn->scaledtwidth)/btv->win.cropwidth;
 	hscale = ((tvn->totalwidth*4096UL)/xsf-4096);
-	vdelay=btv->win.cropy+tvn->vdelay;
 
-	hdelay=(tvn->hdelayx1*tvn->scaledtwidth)/tvn->totalwidth;
-	hdelay=((hdelay+btv->win.cropx)*hactive)/btv->win.cropwidth;
+	hdelay=tvn->hdelayx1+btv->win.cropx;
+	hdelay=(hdelay*hactive)/btv->win.cropwidth;
 	hdelay&=0x3fe;
 
 	sr=((btv->win.cropheight>>inter)*512)/height-512;
@@ -948,22 +1148,23 @@
 {
         unsigned short format;
 
-        btv->win.color_fmt=format= (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 :
-		bpp2fmt[(btv->win.bpp-1)&3];
-                	
+        btv->win.color_fmt = format = 
+                (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 :
+                        bpp2fmt[(btv->win.bpp-1)&3];
+
 	/*	RGB8 seems to be a 9x5x5 GRB color cube starting at
 	 *	color 16. Why the h... can't they even mention this in the
 	 *	data sheet?  [AC - because it's a standard format so I guess
 	 *	it never occurred to them]
 	 *	Enable dithering in this mode.
 	 */
-#if 0	 
+
 	if (format==BT848_COLOR_FMT_RGB8)
-                btand(~0x10, BT848_CAP_CTL); 
+                btand(~BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); 
 	else
-	        btor(0x10, BT848_CAP_CTL);
-#endif
-        bt848_set_geo(btv,btv->win.width, btv->win.height, format);
+	        btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL);
+
+        bt848_set_geo(btv, btv->win.width, btv->win.height, format);
 }
 
 /*
@@ -978,7 +1179,7 @@
 	audio(btv, AUDIO_MUTE);
 	udelay(AUDIO_MUTE_DELAY);
 
-	if (btv->radio) 
+	if (radio[btv->nr]) 
 	{
 		if (btv->have_tuner)
 			i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER,
@@ -1027,7 +1228,7 @@
 		if(fbuffer_alloc(btv))
 			return -ENOBUFS;
 	}
-	if(btv->grabbing>1)
+	if(btv->grabbing >= MAX_GBUFFERS)
 		return -ENOBUFS;
 	
 	/*
@@ -1040,9 +1241,16 @@
 	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)
 		return -EINVAL;
-
+*/
+	if (mp->height*mp->width*fmtbppx2[mp->format&0x0f]/2>BTTV_MAX_FBUF)
+		return -EINVAL;
+ 
 	/*
 	 *	FIXME: Check the format of the grab here. This is probably
 	 *	also less restrictive than the normal overlay grabs. Stuff
@@ -1055,27 +1263,31 @@
 	 
 	vbuf=(unsigned int *)(btv->fbuffer+BTTV_MAX_FBUF*mp->frame);
 /*	if (!(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC))
-                return -EAGAIN; */
+                return -EAGAIN;*/
 	ro=btv->grisc+(((btv->grabcount++)&1) ? 4096 :0);
 	re=ro+2048;
 	btv->gwidth=mp->width;
 	btv->gheight=mp->height;
+
 	if (mp->format > PALETTEFMT_MAX)
 		return -EINVAL;
 	btv->gfmt=palette2fmt[mp->format];
-	if(btv->gfmt==-1)
+	if(btv->gfmt==0)
 		return -EINVAL;
 		
 	make_vrisctab(btv, ro, re, vbuf, btv->gwidth, btv->gheight, btv->gfmt);
 	/* bt848_set_risc_jmps(btv); */
 	btor(3, BT848_CAP_CTL);
 	btor(3, BT848_GPIO_DMA_CTL);
+        btv->frame_stat[mp->frame] = GBUFFER_GRABBING;
         if (btv->grabbing) {
 		btv->gro_next=virt_to_bus(ro);
 		btv->gre_next=virt_to_bus(re);
+                btv->grf_next=mp->frame;
         } else {
 		btv->gro=virt_to_bus(ro);
 		btv->gre=virt_to_bus(re);
+                btv->grf=mp->frame;
         }
 	if (!(btv->grabbing++)) 
 		btv->risc_jmp[12]=BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ;
@@ -1159,7 +1371,12 @@
 				btv->user--;
 				return -EINVAL;
 			}
-			break;
+                        btv->grabbing = 0;
+                        btv->grab = 0;
+                        btv->lastgrab = 0;
+                        for (i = 0; i < MAX_GBUFFERS; i++)
+				btv->frame_stat[i] = GBUFFER_UNUSED;
+                        break;
 		case 1:
 			break;
 	}
@@ -1227,265 +1444,6 @@
 	btaor(datahi, ~1, BT848_O_CONTROL);
 }
 
-
-/*
- *	Cliprect -> risc table.
- *
- *	FIXME: This is generating wrong code when we have some kinds of
- *	rectangle lists. If you generate overlapped rectangles then it
- *	gets a bit confused. Since we add the frame buffer clip rectangles
- *	we need to fix this. Better yet to rewrite this function.
- */
- 
-static void write_risc_data(struct bttv *btv, struct video_clip *vp, int count)
-{
-	int i;
-	u32 yy, y, x, dx, ox;
-	u32 *rmem, *rmem2;
-	struct video_clip first, *cur, *cur2, *nx, first2, *prev, *nx2;
-	u32 *rp, rpo=0, rpe=0, p, bpsl;
-	u32 *rpp;
-	u32 mask;
-	int interlace;
-	int depth;
-  
-	rmem=(u32 *)btv->risc_odd;
-	rmem2=(u32 *)btv->risc_even;
-	depth=btv->win.bpp;
-  
-	/* create y-sorted list  */
-	
-	first.next=NULL;
-	for (i=0; i<count; i++) 
-	{
-		cur=&first;
-		while ((nx=cur->next) && (vp[i].y > cur->next->y))
-			cur=nx; 
-		cur->next=&(vp[i]);
-		vp[i].next=nx;
-	}
-	first2.next=NULL;
-	
-	rmem[rpo++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1|(0xf<<20);
-	rmem[rpo++]=0;
-
-	rmem2[rpe++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1;
-	rmem2[rpe++]=0;
-
-
-	/*
-	 *	32bit depth frame buffers need extra flags setting
-	 */
-	 
-	if (depth==4)
-		mask=BT848_RISC_BYTE3;
-	else
-		mask=0;
-		
-	bpsl=btv->win.width*btv->win.bpp;
-	p=btv->win.vidadr+btv->win.x*btv->win.bpp+
-		btv->win.y*btv->win.bpl;
-
-	interlace=btv->win.interlace;
-
-	/*
-	 *	Loop through all lines 
-	 */
-	 
-	for (yy=0; yy<(btv->win.height<<(1^interlace)); yy++) 
-	{
-		y=yy>>(1^interlace);
-		
-		/*
-		 *	Even or odd frame generation. We have to 
-		 *	write the RISC instructions to the right stream.
-		 */
-		 
-		if(!(y&1))
-		{
-			rp=&rpo;
-			rpp=rmem;
-		}
-		else
-		{
-			rp=&rpe;
-			rpp=rmem2;
-		}
-		
-		
-		/*
-		 *	first2 is the header of a list of "active" rectangles. We add
-		 *	rectangles as we hit their top and remove them as they fall off
-		 *	the bottom
-		 */
-		
-		 /* remove rects with y2 > y */
-		if ((cur=first2.next)) 
-		{
-			prev=&first2;
-			do 
-			{
-				if (cur->y+cur->height < y) 
-					prev->next=cur->next;
-				else
-					prev=cur;
-			}
-			while ((cur=cur->next));
-		}
-
-		/*
-		 *	Fixme - we have to handle overlapped rectangles
-		 *	here, but the overlap might be partial
-		 */
-		 
- 		/* add rect to second (x-sorted) list if rect.y == y  */
-		if ((cur=first.next)) 
-		{
-			while ((cur) && (cur->y == y))
-			{ 
-				first.next=cur->next;
-				cur2=&first2;
-				while ((nx2=cur2->next) && (cur->x > cur2->next->x)) 
-					cur2=nx2; 
-				cur2->next=cur;
-				cur->next=nx2;
-				cur=first.next;
-			}
-		}
-		
-		
-		/*
-		 *	Begin writing the RISC script
-		 */
-    
-		dx=x=0;
-		
-		/*
-		 *	Starting at x position 0 on a new scan line
-		 *	write to location p, don't yet write the number
-		 *	of pixels for the instruction
-		 */
-		 
-		rpp[(*rp)++]=BT848_RISC_WRITE|BT848_RISC_SOL;
-		rpp[(*rp)++]=p;
-		
-		/*
-		 *	For each rectangle we have in the "active" list - sorted left to
-		 *	right..
-		 */
-		 
-		for (cur2=first2.next; cur2; cur2=cur2->next) 
-		{
-			/*
-			 *	If we are to the left of the first drawing area
-			 */
-			 
-			if (x+dx < cur2->x) 
-			{
-				/* Bytes pending ? */
-				if (dx) 
-				{
-					/* For a delta away from the start we need to write a SKIP */
-					if (x) 
-						rpp[(*rp)++]=BT848_RISC_SKIP|(dx*depth);
-					else
-					/* Rewrite the start of line WRITE to a SKIP */
-						rpp[(*rp)-2]|=BT848_RISC_BYTE_ALL|(dx*depth);
-					/* Move X to the next point (drawing start) */
-					x=x+dx;
-				}
-				/* Ok how far are we from the start of the next rectangle ? */
-				dx=cur2->x-x;
-				/* dx is now the size of data to write */
-				
-				/* If this isnt the left edge generate a "write continue" */
-				if (x) 
-					rpp[(*rp)++]=BT848_RISC_WRITEC|(dx*depth)|mask;
-				else
-					/* Fill in the byte count on the initial WRITE */
-					rpp[(*rp)-2]|=(dx*depth)|mask;
-				/* Move to the start of the rectangle */
-				x=cur2->x;
-				/* x is our left dx is byte size of hole */
-				dx=cur2->width+1;
-			}
-			else
-			/* Already in a clip zone.. set dx */
-				if (x+dx < cur2->x+cur2->width) 
-					dx=cur2->x+cur2->width-x+1;
-		}
-		/* now treat the rest of the line */
-		ox=x;
-		if (dx) 
-		{
-			/* Complete the SKIP to eat to the end of the gap */
-			if (x) 
-				rpp[(*rp)++]=BT848_RISC_SKIP|(dx*depth);
-			else
-			/* Rewrite to SKIP start to this point */
-				rpp[(*rp)-2]|=BT848_RISC_BYTE_ALL|(dx*depth);
-			x=x+dx;
-		}
-		
-		/*
-		 *	Not at the right hand edge ?
-		 */
-		 
-		if ((dx=btv->win.width-x)!=0) 
-		{
-			/* Write to edge of display */
-			if (x)
-				rpp[(*rp)++]=BT848_RISC_WRITEC|(dx*depth)|BT848_RISC_EOL|mask;
-			else
-			/* Entire frame is a write - patch first order */
-				rpp[(*rp)-2]|=(dx*depth)|BT848_RISC_EOL|mask;
-		}
-		else
-		{
-			/* End of line if needed */
-			if (ox)
-				rpp[(*rp)-1]|=BT848_RISC_EOL|mask;
-			else 
-			{
-				/* Skip the line : write a SKIP + start/end of line marks */
-				(*rp)--;
-				rpp[(*rp)-1]=BT848_RISC_SKIP|
-				        (btv->win.width*depth)|
-					  BT848_RISC_EOL|BT848_RISC_SOL;
-			}
-		}
-		/*
-		 *	Move the video render pointer on a line 
-		 */
-		if (interlace||(y&1))
-			p+=btv->win.bpl;
-	}
-	
-	/*
-	 *	Attach the interframe jumps
-	 */
-
-	rmem[rpo++]=BT848_RISC_JUMP; 
-	rmem[rpo++]=btv->bus_vbi_even;
-
-	rmem2[rpe++]=BT848_RISC_JUMP;
-	rmem2[rpe++]=btv->bus_vbi_odd;
-}
-
-/*
- *	Helper for adding clips.
- */
-
-static void new_risc_clip(struct video_window *vw, struct video_clip *vcp, int x, int y, int w, int h)
-{
-	vcp[vw->clipcount].x=x;
-	vcp[vw->clipcount].y=y;
-	vcp[vw->clipcount].width=w;
-	vcp[vw->clipcount].height=h;
-	vw->clipcount++;
-}
-
-
 /*
  *	ioctl routine
  */
@@ -1495,7 +1453,7 @@
 {
 	unsigned char eedata[256];
 	struct bttv *btv=(struct bttv *)dev;
-  	static int lastchan=0;
+ 	int i;
   	
 	switch (cmd)
 	{	
@@ -1510,8 +1468,8 @@
 				VID_TYPE_CLIPPING|
 				VID_TYPE_FRAMERAM|
 				VID_TYPE_SCALES;
-			b.channels = 4; /* tv  , input, svhs */
-			b.audios = 4; /* tv, input, svhs */
+			b.channels = tvcards[btv->type].inputs;
+			b.audios = tvcards[btv->type].inputs;
 			b.maxwidth = 768;
 			b.maxheight = 576;
 			b.minwidth = 32;
@@ -1528,26 +1486,21 @@
 			v.flags=VIDEO_VC_AUDIO;
 			v.tuners=0;
 			v.type=VIDEO_TYPE_CAMERA;
-			switch(v.channel)
-			{
-				case 0:
-					strcpy(v.name,"Television");
-					v.flags|=VIDEO_VC_TUNER;
-					v.type=VIDEO_TYPE_TV;
-					v.tuners=1;
-					break;
-				case 1:
-					strcpy(v.name,"Composite1");
-					break;
-				case 2:
-					strcpy(v.name,"Composite2");
-					break;
-				case 3:
-					strcpy(v.name,"SVHS");
-					break;
-				default:
-					return -EINVAL;
-			}
+			v.norm = btv->win.norm;
+                        if (v.channel>=tvcards[btv->type].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,"SVHS");
+                        else
+                                sprintf(v.name,"Composite%d",v.channel);
+
 			if(copy_to_user(arg,&v,sizeof(v)))
 				return -EFAULT;
 			return 0;
@@ -1557,11 +1510,19 @@
 		 */
 		case VIDIOCSCHAN:
 		{
-			int v;
-			if(copy_from_user(&v, arg, sizeof(v)))
+			struct video_channel v;
+			if(copy_from_user(&v, arg,sizeof(v)))
 				return -EFAULT;
-			bt848_muxsel(btv, v);
-			lastchan=v;
+                        
+                        if (v.channel>tvcards[btv->type].inputs)
+                                return -EINVAL;
+			bt848_muxsel(btv, v.channel);
+			if(v.norm!=VIDEO_MODE_PAL&&v.norm!=VIDEO_MODE_NTSC
+			   &&v.norm!=VIDEO_MODE_SECAM)
+				return -EOPNOTSUPP;
+			btv->win.norm = v.norm;
+			bt848_set_winsize(btv);
+			btv->channel=v.channel;
 			return 0;
 		}
 		case VIDIOCGTUNER:
@@ -1569,7 +1530,7 @@
 			struct video_tuner v;
 			if(copy_from_user(&v,arg,sizeof(v))!=0)
 				return -EFAULT;
-			if(v.tuner||lastchan)	/* Only tuner 0 */
+			if(v.tuner||btv->channel)	/* Only tuner 0 */
 				return -EINVAL;
 			strcpy(v.name, "Television");
 			v.rangelow=0;
@@ -1581,23 +1542,22 @@
 				return -EFAULT;
 			return 0;
 		}
-		/* We have but tuner 0 */
+		/* We have but one tuner */
 		case VIDIOCSTUNER:
 		{
 			struct video_tuner v;
 			if(copy_from_user(&v, arg, sizeof(v)))
 				return -EFAULT;
-			/* Only channel 0 has a tuner */
-			if(v.tuner!=0 || lastchan)
-				return -EINVAL;
+
+			/* 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;
-			/* FIXME: norm should be in video_channel struct 
-			   composite source can have different norms too
-			 */
-			btv->win.norm = v.mode;
-			bt848_set_winsize(btv);
+ 			btv->win.norm = v.mode;
+ 			bt848_set_winsize(btv);
 			return 0;
 		}
 		case VIDIOCGPICT:
@@ -1682,24 +1642,7 @@
 				return -ENOMEM;
 			if(vw.clipcount && copy_from_user(vcp,vw.clips,sizeof(struct video_clip)*vw.clipcount))
 				return -EFAULT;
-			/*
-			 *	Impose display clips
-			 */
-			if(btv->win.x<0)
-				new_risc_clip(&vw, vcp, 0, 0, -btv->win.x, btv->win.height-1);
-			if(btv->win.y<0)
-				new_risc_clip(&vw, vcp, 0, 0, btv->win.width-1,-btv->win.y);
-			if(btv->win.x+btv->win.width> btv->win.swidth)
-				new_risc_clip(&vw, vcp, btv->win.swidth-btv->win.x, 0, btv->win.width-1, btv->win.height-1);
-			if(btv->win.y+btv->win.height > btv->win.sheight)
-				new_risc_clip(&vw, vcp, 0, btv->win.sheight-btv->win.y, btv->win.width-1, btv->win.height-1);
-			/*
-			 *	Question: Do we need to walk the clip list
-			 *	and saw off any clips outside the window 
-			 *	frame or will write_risc_tab do the right
-			 *	thing ?
-			 */
-			write_risc_data(btv,vcp, vw.clipcount);
+			make_clip_tab(btv,vcp, vw.clipcount);
 			vfree(vcp);
 			if(on && btv->win.vidadr!=0)
 				bt848_cap(btv,1);
@@ -1764,7 +1707,7 @@
 	                btv->win.vidadr=(unsigned long)v.base;
 			btv->win.sheight=v.height;
 			btv->win.swidth=v.width;
-			btv->win.bpp=((v.depth+1)&0x38)/8;
+			btv->win.bpp=((v.depth+7)&0x38)/8;
 			btv->win.depth=v.depth;
 			btv->win.bpl=v.bytesperline;
 			
@@ -1832,8 +1775,8 @@
 				return -EFAULT;
 			if(v.flags&VIDEO_AUDIO_MUTE)
 				audio(btv, AUDIO_MUTE);
-			/* One audio source per tuner */
-			if(v.audio!=0)
+ 			/* One audio source per tuner */
+ 			if(v.audio!=0)
 				return -EINVAL;
 			bt848_muxsel(btv,v.audio);
 			if(!(v.flags&VIDEO_AUDIO_MUTE))
@@ -1858,12 +1801,19 @@
 		}
 
 	        case VIDIOCSYNC:
-	        	if (!btv->grabbing)
-	        		return -EAGAIN;
-		        if (btv->grab==btv->lastgrab)
-			        interruptible_sleep_on(&btv->capq);
-		        btv->lastgrab++;
-		        return 0;
+			if(copy_from_user((void *)&i,arg,sizeof(int)))
+				return -EFAULT;
+                        switch (btv->frame_stat[i]) {
+                        case GBUFFER_UNUSED:
+                                return -EINVAL;
+                        case GBUFFER_GRABBING:
+ 			        interruptible_sleep_on(&btv->capq);
+                                /* fall */
+                        case GBUFFER_DONE:
+                                btv->frame_stat[i] = GBUFFER_UNUSED;
+                                break;
+                        }
+                        return 0;
 
 		case BTTV_WRITEE:
 			if(!capable(CAP_SYS_ADMIN))
@@ -1881,11 +1831,19 @@
 				return -EFAULT;
 			break;
 
+		case BTTV_FIELDNR:
+			if(copy_to_user((void *) arg, (void *) &btv->last_field, 
+                                        sizeof(btv->last_field)))
+				return -EFAULT;
+                        break;
+
 	        case VIDIOCMCAPTURE:
 		{
                         struct video_mmap vm;
 			if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm)))
 				return -EFAULT;
+                        if (btv->frame_stat[vm.frame] == GBUFFER_GRABBING)
+                                return -EBUSY;
 		        return vgrab(btv, &vm);
 		}
 		
@@ -2127,21 +2085,34 @@
 static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
 {
         struct bttv *btv=(struct bttv *)(dev-1);
-  	static int lastchan=0;
 	switch (cmd) {	
 	case VIDIOCGCAP:
-		/* XXX */
+	{
+		struct video_capability v;
+		strcpy(v.name,btv->video_dev.name);
+		v.type = VID_TYPE_TUNER;
+		v.channels = 1;
+		v.audios = 1;
+		/* No we don't do pictures */
+		v.maxwidth = 0;
+		v.maxheight = 0;
+		v.minwidth = 0;
+		v.minheight = 0;
+		if (copy_to_user(arg, &v, sizeof(v)))
+			return -EFAULT;
+		return 0;
 		break;
+	}
 	case VIDIOCGTUNER:
 	{
 		struct video_tuner v;
 		if(copy_from_user(&v,arg,sizeof(v))!=0)
 			return -EFAULT;
-		if(v.tuner||lastchan)	/* Only tuner 0 */
+		if(v.tuner||btv->channel)	/* Only tuner 0 */
 			return -EINVAL;
 		strcpy(v.name, "Radio");
 		v.rangelow=(int)(87.5*16);
-		v.rangehigh=(int)(108.0*16);
+		v.rangehigh=(int)(108*16);
 		v.flags= 0; /* XXX */
 		v.mode = 0; /* XXX */
 		if(copy_to_user(arg,&v,sizeof(v)))
@@ -2154,7 +2125,7 @@
 		if(copy_from_user(&v, arg, sizeof(v)))
 			return -EFAULT;
 		/* Only channel 0 has a tuner */
-		if(v.tuner!=0 || lastchan)
+		if(v.tuner!=0 || btv->channel)
 			return -EINVAL;
 		/* XXX anything to do ??? */
 		return 0;
@@ -2198,6 +2169,8 @@
 };
 
 static struct vidbases vbs[] = {
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_215CT222,
+                "ATI MACH64 CT", PCI_BASE_ADDRESS_0},
 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_210888GX,
 		"ATI MACH64 Winturbo", PCI_BASE_ADDRESS_0},
  	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_215GT,
@@ -2214,8 +2187,12 @@
 	{ PCI_VENDOR_ID_MATROX, 0x051a, "Matrox Mystique", PCI_BASE_ADDRESS_1},
 	{ PCI_VENDOR_ID_N9, PCI_DEVICE_ID_N9_I128, 
 		"Number Nine Imagine 128", PCI_BASE_ADDRESS_0},
+	{ PCI_VENDOR_ID_N9, PCI_DEVICE_ID_N9_I128_2, 
+		"Number Nine Imagine 128 Series 2", PCI_BASE_ADDRESS_0},
 	{ PCI_VENDOR_ID_S3, 0, "S3", PCI_BASE_ADDRESS_0},
 	{ PCI_VENDOR_ID_TSENG, 0, "TSENG", PCI_BASE_ADDRESS_0},
+	{ PCI_VENDOR_ID_NVIDIA_SGS, PCI_DEVICE_ID_NVIDIA_SGS_RIVA128,
+                "Riva128", PCI_BASE_ADDRESS_1},
 };
 
 
@@ -2409,13 +2386,16 @@
 
 /* Figure out card and tuner type */
 
-static void idcard(struct bttv *btv)
+static void idcard(int i)
 {
+        struct bttv *btv = &bttvs[i];
+
+	int tunertype;
 	btwrite(0, BT848_GPIO_OUT_EN);
-	DEBUG(printk(KERN_DEBUG "bttv: GPIO: 0x%08x\n", btread(BT848_GPIO_DATA)));
+	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;
+	btv->type=card[i];
         btv->tuner_type=-1; /* use default tuner type */
 
 	/* If we were asked to auto-detect, then do so! 
@@ -2440,13 +2420,13 @@
         if (I2CRead(&(btv->i2c), I2C_TDA9850) >=0)
         {
         	btv->audio_chip = TDA9850;
-        	printk(KERN_INFO "bttv: audio chip: TDA9850\n");
+        	printk(KERN_INFO "bttv%d: audio chip: TDA9850\n", i);
         }
 
         if (I2CRead(&(btv->i2c), I2C_TDA8425) >=0)
         {
             btv->audio_chip = TDA8425;
-            printk("bttv: audio chip: TDA8425\n");
+            printk("bttv%d: audio chip: TDA8425\n", i);
         }
         
         switch(btv->audio_chip)
@@ -2460,11 +2440,18 @@
         }
 
 	/* How do I detect the tuner type for other cards but Miro ??? */
-	printk(KERN_INFO "bttv: model: ");
+	printk(KERN_INFO "bttv%d: model: ", btv->nr);
 	switch (btv->type) 
 	{
 		case BTTV_MIRO:
 			printk("MIRO\n");
+			if (btv->have_tuner) 
+			{
+				tunertype=((btread(BT848_GPIO_DATA)>>10)-1)&7;
+				i2c_control_device(&(btv->i2c),
+						   I2C_DRIVERID_TUNER,
+						   TUNER_SET_TYPE,&tunertype);
+			}
 			strcpy(btv->video_dev.name,"BT848(Miro)");
 			break;
 		case BTTV_HAUPPAUGE:
@@ -2558,8 +2545,18 @@
 
 	/* reset the bt848 */
 	btwrite(0, BT848_SRESET);
+	DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%08x\n",i,(unsigned int) btv->bt848_mem));
 
-	DEBUG(printk(KERN_DEBUG "bttv: bt848_mem: 0x%08x\n",(unsigned int) btv->bt848_mem));
+#ifdef RESET_MSP_HAUPPAUGE
+        /* Reset 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);
+#endif
 
 	/* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */
 
@@ -2591,6 +2588,7 @@
 	btv->grabcount=0;
 	btv->grab=0;
 	btv->lastgrab=0;
+        btv->field=btv->last_field=0;
 
 	/* i2c */
 	memcpy(&(btv->i2c),&bttv_i2c_bus_template,sizeof(struct i2c_bus));
@@ -2642,8 +2640,8 @@
 	btwrite(0xd8, BT848_CONTRAST_LO);
 	bt848_bright(btv, 0x10);
 
-	btwrite(0x60, BT848_E_VSCALE_HI);
-	btwrite(0x60, BT848_O_VSCALE_HI);
+	btwrite(0x20, BT848_E_VSCALE_HI);
+	btwrite(0x20, BT848_O_VSCALE_HI);
 	btwrite(/*BT848_ADC_SYNC_T|*/
 		BT848_ADC_RESERVED|BT848_ADC_CRUSH, BT848_ADC);
 
@@ -2662,9 +2660,10 @@
 	btwrite(0xfffffUL, BT848_INT_STAT);
         
 	/* set interrupt mask */
-	btwrite(triton1|
-/*	        BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|
-		BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/
+	btwrite(btv->triton1|
+                /*BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|
+                  BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/
+                BT848_INT_VSYNC|
 		BT848_INT_SCERR|
 		BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
 		BT848_INT_FMTCHG|BT848_INT_HLOCK,
@@ -2680,7 +2679,7 @@
 	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(btv);
+	idcard(i);
 
 	if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0)
 		return -1;
@@ -2689,7 +2688,7 @@
 	        video_unregister_device(&btv->video_dev);
 		return -1;
 	}
-	if (radio)
+	if (radio[i])
 	{
 		if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0) 
                 {
@@ -2720,28 +2719,28 @@
 		if (!astat)
 			return;
 		btwrite(astat,BT848_INT_STAT);
-		IDEBUG(printk ("bttv: astat %08x\n",astat));
-		IDEBUG(printk ("bttv:  stat %08x\n",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_FMTCHG) 
 		{
-			IDEBUG(printk ("bttv: IRQ_FMTCHG\n"));
+			IDEBUG(printk ("bttv%d: IRQ_FMTCHG\n", btv->nr));
 			/*btv->win.norm&=
 			  (dstat&BT848_DSTATUS_NUML) ? (~1) : (~0); */
 		}
 		if (astat&BT848_INT_VPRES) 
 		{
-			IDEBUG(printk ("bttv: IRQ_VPRES\n"));
+			IDEBUG(printk ("bttv%d: IRQ_VPRES\n", btv->nr));
 		}
 		if (astat&BT848_INT_VSYNC) 
 		{
-			IDEBUG(printk ("bttv: IRQ_VSYNC\n"));
+			IDEBUG(printk ("bttv%d: IRQ_VSYNC\n", btv->nr));
 		}
 		if (astat&BT848_INT_SCERR) {
-			IDEBUG(printk ("bttv: IRQ_SCERR\n"));
+			IDEBUG(printk ("bttv%d: IRQ_SCERR\n", btv->nr));
 			bt848_dma(btv, 0);
 			bt848_dma(btv, 1);
 			wake_up_interruptible(&btv->vbiq);
@@ -2750,7 +2749,7 @@
 		}
 		if (astat&BT848_INT_RISCI) 
 		{
-			IDEBUG(printk ("bttv: IRQ_RISCI\n"));
+			IDEBUG(printk ("bttv%d: IRQ_RISCI\n", btv->nr));
 
 			/* captured VBI frame */
 			if (stat&(1<<28)) 
@@ -2763,10 +2762,14 @@
 			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))
 				{
 					btv->gro = btv->gro_next;
 					btv->gre = btv->gre_next;
+					btv->grf = btv->grf_next;
                                         btv->risc_jmp[5]=btv->gro;
 					btv->risc_jmp[11]=btv->gre;
 					bt848_set_geo(btv, btv->gwidth,
@@ -2792,31 +2795,31 @@
 		}
 		if (astat&BT848_INT_OCERR) 
 		{
-			IDEBUG(printk ("bttv: IRQ_OCERR\n"));
+			IDEBUG(printk ("bttv%d: IRQ_OCERR\n", btv->nr));
 		}
 		if (astat&BT848_INT_PABORT) 
 		{
-			IDEBUG(printk ("bttv: IRQ_PABORT\n"));
+			IDEBUG(printk ("bttv%d: IRQ_PABORT\n", btv->nr));
 		}
 		if (astat&BT848_INT_RIPERR) 
 		{
-			IDEBUG(printk ("bttv: IRQ_RIPERR\n"));
+			IDEBUG(printk ("bttv%d: IRQ_RIPERR\n", btv->nr));
 		}
 		if (astat&BT848_INT_PPERR) 
 		{
-			IDEBUG(printk ("bttv: IRQ_PPERR\n"));
+			IDEBUG(printk ("bttv%d: IRQ_PPERR\n", btv->nr));
 		}
 		if (astat&BT848_INT_FDSR) 
 		{
-			IDEBUG(printk ("bttv: IRQ_FDSR\n"));
+			IDEBUG(printk ("bttv%d: IRQ_FDSR\n", btv->nr));
 		}
 		if (astat&BT848_INT_FTRGT) 
 		{
-			IDEBUG(printk ("bttv: IRQ_FTRGT\n"));
+			IDEBUG(printk ("bttv%d: IRQ_FTRGT\n", btv->nr));
 		}
 		if (astat&BT848_INT_FBUS) 
 		{
-			IDEBUG(printk ("bttv: IRQ_FBUS\n"));
+			IDEBUG(printk ("bttv%d: IRQ_FBUS\n", btv->nr));
 		}
 		if (astat&BT848_INT_HLOCK) 
 		{
@@ -2832,12 +2835,12 @@
     
 		count++;
 		if (count > 10)
-			printk (KERN_WARNING "bttv: irq loop %d\n", count);
+			printk (KERN_WARNING "bttv%d: irq loop %d\n", btv->nr, count);
 		if (count > 20) 
 		{
 			btwrite(0, BT848_INT_MASK);
 			printk(KERN_ERR 
-			       "bttv: IRQ lockup, cleared int mask\n");
+			       "bttv%d: IRQ lockup, cleared int mask\n", btv->nr);
 		}
 	}
 }
@@ -2847,120 +2850,132 @@
 /*
  *	Scan for a Bt848 card, request the irq and map the io memory 
  */
- 
-static int find_bt848(void)
+
+int configure_bt848(struct pci_dev *dev, int bttv_num)
 {
-	unsigned char command, latency;
 	int result;
+	unsigned char bus, devfn, command;
 	struct bttv *btv;
-	struct pci_dev *dev;
 
-	bttv_num=0;
+        btv=&bttvs[bttv_num];
+        btv->dev=dev;
+        btv->nr = bttv_num;
+        btv->bus=bus=dev->bus->number;
+        btv->devfn=devfn=dev->devfn;
+        btv->bt848_mem=NULL;
+        btv->vbibuf=NULL;
+        btv->risc_jmp=NULL;
+        btv->vbi_odd=NULL;
+        btv->vbi_even=NULL;
+        btv->vbiq=NULL;
+        btv->capq=NULL;
+        btv->capqo=NULL;
+        btv->capqe=NULL;
+        btv->vbip=VBIBUF_SIZE;
+
+        btv->id=dev->device;
+        btv->irq=dev->irq;
+        btv->bt848_adr=dev->base_address[0];
+        if (btv->id >= 878)
+                btv->i2c_command = 0x83;                   
+        else
+                btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA);
 
-	if (!pcibios_present()) 
-	{
-		DEBUG(printk(KERN_DEBUG "bttv: PCI-BIOS not present or not accessible!\n"));
-		return 0;
-	}
-	for (dev = pci_devices; dev != NULL; dev = dev->next) 
-	{
-		if (dev->vendor != PCI_VENDOR_ID_BROOKTREE)
-			continue;
-		if (dev->device != PCI_DEVICE_ID_BT849 &&
-			dev->device != PCI_DEVICE_ID_BT848)
-			continue;
-
-		/* Ok, Bt848 or Bt849 found! */
-		btv=&bttvs[bttv_num];
-		btv->dev=dev;
-		btv->bt848_mem=NULL;
-		btv->vbibuf=NULL;
-		btv->risc_jmp=NULL;
-		btv->vbi_odd=NULL;
-		btv->vbi_even=NULL;
-		btv->vbiq=NULL;
-		btv->capq=NULL;
-		btv->capqo=NULL;
-		btv->capqe=NULL;
-
-		btv->vbip=VBIBUF_SIZE;
+        if (remap[bttv_num])
+        {
+                if (remap[bttv_num] < 0x1000)
+                        remap[bttv_num]<<=20;
+                remap[bttv_num]&=PCI_BASE_ADDRESS_MEM_MASK;
+                printk(KERN_INFO "bttv%d: remapping to : 0x%08x.\n",
+                       bttv_num,remap[bttv_num]);
+                remap[bttv_num]|=btv->bt848_adr&(~PCI_BASE_ADDRESS_MEM_MASK);
+                pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, remap[bttv_num]);
+                pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &btv->bt848_adr);
+                btv->dev->base_address[0] = btv->bt848_adr;
+        }					
+        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);
+        printk("bus: %d, devfn: %d, ",
+               btv->bus, btv->devfn);
+        printk("irq: %d, ",btv->irq);
+        printk("memory: 0x%08x.\n", btv->bt848_adr);
+        
+        btv->pll=0;
+        if(pll[btv->nr])
+                if (!(btv->id==848 && btv->revision==0x11))
+                {
+                        printk(KERN_INFO "bttv%d: internal PLL, single crystal operation enabled\n",bttv_num);
+                        btv->pll=1;
+                }
+        
+        btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000);
+        
+	/* clear interrupt mask */
+	btwrite(0, BT848_INT_MASK);
 
-		pci_read_config_word (btv->dev, PCI_DEVICE_ID,      &btv->id);
+        result = request_irq(btv->irq, bttv_irq,
+                             SA_SHIRQ | SA_INTERRUPT,"bttv",(void *)btv);
+        if (result==-EINVAL) 
+        {
+                printk(KERN_ERR "bttv%d: Bad irq number or handler\n",
+                       bttv_num);
+                return -EINVAL;
+        }
+        if (result==-EBUSY)
+        {
+                printk(KERN_ERR "bttv%d: IRQ %d busy, change your PnP config in BIOS\n",bttv_num,btv->irq);
+                return result;
+        }
+        if (result < 0) 
+                return result;
+        
+        pci_set_master(dev);
 
-		/* pci_read_config_dword(btv->dev, PCI_BASE_ADDRESS_0, &btv->bt848_adr); */
-		btv->bt848_adr = btv->dev->base_address[0];
-    
-		if (remap&&(!bttv_num))
-		{ 
-			remap<<=20;
-			remap&=PCI_BASE_ADDRESS_MEM_MASK;
-			printk(KERN_INFO "Remapping to : 0x%08x.\n", remap);
-			remap|=btv->bt848_adr&(~PCI_BASE_ADDRESS_MEM_MASK);
-			pci_write_config_dword(btv->dev, PCI_BASE_ADDRESS_0, remap);
-			pci_read_config_dword(btv->dev,  PCI_BASE_ADDRESS_0, &btv->bt848_adr);
-			btv->dev->base_address[0] = btv->bt848_adr;
-		}					
-    
-		btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK;
-		pci_read_config_byte(btv->dev, PCI_CLASS_REVISION,
-			     &btv->revision);
-		printk(KERN_INFO "bttv: Brooktree Bt%d (rev %d) ",
-			btv->id, btv->revision);
-		printk("bus: %d, devfn: %d, ",
-			btv->dev->bus->number, btv->dev->devfn);
-		printk("irq: %d, ",btv->dev->irq);
-		printk("memory: 0x%08x.\n", btv->bt848_adr);
-    
-    		btv->pll = 0;
-#ifdef USE_PLL
-                if (btv->id==849 || (btv->id==848 && btv->revision==0x12))
+        btv->triton1=triton1 ? BT848_INT_ETBF : 0;
+        if (triton1 && btv->id >= 878) 
+        {
+                btv->triton1 = 0;
+                printk("bttv: Enabling 430FX compatibilty for bt878\n");
+                pci_read_config_byte(dev, BT878_DEVCTRL, &command);
+                command|=BT878_EN_TBFX;
+                pci_write_config_byte(dev, BT878_DEVCTRL, command);
+                pci_read_config_byte(dev, BT878_DEVCTRL, &command);
+                if (!(command&BT878_EN_TBFX)) 
                 {
-                        printk(KERN_INFO "bttv: internal PLL, single crystal operation enabled.\n");
-                        btv->pll=1;
+                        printk("bttv: 430FX compatibility could not be enabled\n");
+                        return -1;
                 }
-#endif
-                
-		btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000);
+        }
+        
+        return 0;
+}
 
-		result = request_irq(btv->dev->irq, bttv_irq,
-			SA_SHIRQ | SA_INTERRUPT,"bttv",(void *)btv);
-		if (result==-EINVAL) 
-		{
-			printk(KERN_ERR "bttv: Bad irq number or handler\n");
-			return -EINVAL;
-		}
-		if (result==-EBUSY)
-		{
-			printk(KERN_ERR "bttv: IRQ %d busy, change your PnP config in BIOS\n",btv->dev->irq);
-			return result;
-		}
-		if (result < 0) 
-			return result;
+static int find_bt848(void)
+{
+        struct pci_dev *dev = pci_devices;
+        int result=0;
 
-		/* Enable bus-mastering */
-		pci_read_config_byte(btv->dev, PCI_COMMAND, &command);
-		command|=PCI_COMMAND_MASTER;
-		pci_write_config_byte(btv->dev, PCI_COMMAND, command);
-		pci_read_config_byte(btv->dev, PCI_COMMAND, &command);
-		if (!(command&PCI_COMMAND_MASTER)) 
-		{
-			printk(KERN_ERR "bttv: PCI bus-mastering could not be enabled\n");
-			return -1;
-		}
-		pci_read_config_byte(btv->dev, PCI_LATENCY_TIMER, &latency);
-		if (!latency) 
-		{
-			latency=32;
-			pci_write_config_byte(btv->dev, PCI_LATENCY_TIMER, latency);
-		}
-		DEBUG(printk(KERN_DEBUG "bttv: latency: %02x\n", latency));
-		bttv_num++;
-	}
+        bttv_num=0;
+
+        while (dev)
+        {
+                if (dev->vendor == PCI_VENDOR_ID_BROOKTREE)
+                        if ((dev->device == PCI_DEVICE_ID_BT848)||
+                            (dev->device == PCI_DEVICE_ID_BT849)||
+                            (dev->device == PCI_DEVICE_ID_BT878)||
+                            (dev->device == PCI_DEVICE_ID_BT879))
+                                result=configure_bt848(dev,bttv_num++);
+                if (result)
+                        return result;
+                dev = dev->next;
+        }
 	if(bttv_num)
 		printk(KERN_INFO "bttv: %d Bt848 card(s) found.\n", bttv_num);
 	return bttv_num;
 }
-
+ 
 
 static void release_bttv(void)
 {
@@ -3009,7 +3024,7 @@
 			vfree((void *) btv->vbibuf);
 
 
-		free_irq(btv->dev->irq,btv);
+		free_irq(btv->irq,btv);
 		DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%08x.\n", btv->bt848_mem));
 		if (btv->bt848_mem)
 			iounmap(btv->bt848_mem);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov