patch-2.4.0-test11 linux/drivers/media/video/bttv-driver.c

Next file: linux/drivers/media/video/bttv-if.c
Previous file: linux/drivers/media/video/bttv-cards.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test10/linux/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c
@@ -44,34 +44,40 @@
 #include <linux/kmod.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
-#ifdef HACKING
-# include <linux/iobuf.h>
-#endif
 
-#include "bttv.h"
+#include "bttvp.h"
 #include "tuner.h"
 
 #define DEBUG(x)	/* Debug driver */
-#define IDEBUG(x)	/* Debug interrupt handler */
 #define MIN(a,b) (((a)>(b))?(b):(a))
 #define MAX(a,b) (((a)>(b))?(a):(b))
 
-
 static void bt848_set_risc_jmps(struct bttv *btv, int state);
 
 int bttv_num;			/* number of Bt848s in use */
 struct bttv bttvs[BTTV_MAX];
 
-
 /* insmod args */
 MODULE_PARM(triton1,"i");
 MODULE_PARM(radio,"1-4i");
+MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
 MODULE_PARM(bigendian,"i");
+MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
 MODULE_PARM(fieldnr,"i");
+MODULE_PARM_DESC(fieldnr,"count fields, default is 0 (no)");
 MODULE_PARM(bttv_verbose,"i");
+MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");
+MODULE_PARM(bttv_gpio,"i");
+MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");
 MODULE_PARM(bttv_debug,"i");
+MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
+MODULE_PARM(irq_debug,"i");
+MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
 MODULE_PARM(gbuffers,"i");
+MODULE_PARM_DESC(gbuffers,"number of capture buffers, default is 2 (64 max)");
 MODULE_PARM(gbufsize,"i");
+MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
+MODULE_PARM(combfilter,"i");
 
 MODULE_DESCRIPTION("bttv - v4l driver module for bt848/878 based cards");
 MODULE_AUTHOR("Ralph  Metzler & Marcus Metzler & Gerd Knorr");
@@ -84,10 +90,13 @@
 static int triton1=0;
 static unsigned int radio[BTTV_MAX];
 static unsigned int fieldnr = 0;
+static unsigned int irq_debug = 0;
 static unsigned int gbuffers = 2;
 static unsigned int gbufsize = BTTV_MAX_FBUF;
+static unsigned int combfilter = 0;
 unsigned int bttv_debug = 0;
 unsigned int bttv_verbose = 1;
+unsigned int bttv_gpio = 0;
 
 #define I2C_TIMING (0x7<<4)
 #define I2C_DELAY   10
@@ -133,8 +142,9 @@
                         ptep = pte_offset(pmd, adr);
                         pte = *ptep;
                         if(pte_present(pte)) {
-				ret = (unsigned long) page_address(pte_page(pte));
-                                ret |= (adr & (PAGE_SIZE - 1));
+				ret  = (unsigned long) page_address(pte_page(pte));
+				ret |= (adr & (PAGE_SIZE - 1));
+				
 			}
                 }
         }
@@ -239,9 +249,9 @@
 }
 
 
+/* init + register i2c algo-bit adapter */
 static int __devinit init_bttv_i2c(struct bttv *btv)
 {
-	/* i2c bit_adapter */
 	memcpy(&btv->i2c_adap, &bttv_i2c_adap_template, sizeof(struct i2c_adapter));
 	memcpy(&btv->i2c_algo, &bttv_i2c_algo_template, sizeof(struct i2c_algo_bit_data));
 	memcpy(&btv->i2c_client, &bttv_i2c_client_template, sizeof(struct i2c_client));
@@ -256,13 +266,25 @@
 	bttv_bit_setscl(btv,1);
 	bttv_bit_setsda(btv,1);
 
-	btv->i2c_ok = i2c_bit_add_bus(&btv->i2c_adap);
-	return btv->i2c_ok;
+	btv->i2c_rc = i2c_bit_add_bus(&btv->i2c_adap);
+	return btv->i2c_rc;
 }
 
 
 /* ----------------------------------------------------------------------- */
 
+void bttv_gpio_tracking(struct bttv *btv, char *comment)
+{
+	unsigned int outbits, data;
+	outbits = btread(BT848_GPIO_OUT_EN);
+	data    = btread(BT848_GPIO_DATA);
+	printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
+	       btv->nr,outbits,data & outbits, data & ~outbits, comment);
+}
+
+static char *audio_modes[] = { "audio: tuner", "audio: radio", "audio: extern",
+			       "audio: intern", "audio: off" };
+
 static void audio(struct bttv *btv, int mode, int no_irq_context)
 {
 	btaor(bttv_tvcards[btv->type].gpiomask, ~bttv_tvcards[btv->type].gpiomask,
@@ -295,6 +317,8 @@
 		mode = AUDIO_RADIO;
 	btaor(bttv_tvcards[btv->type].audiomux[mode],
               ~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA);
+	if (bttv_gpio)
+		bttv_gpio_tracking(btv,audio_modes[mode]);
 	if (no_irq_context)
 		bttv_call_i2c_clients(btv,AUDC_SET_INPUT,&(mode));
 }
@@ -406,14 +430,16 @@
 
 static void bt848_muxsel(struct bttv *btv, unsigned int input)
 {
+
+#if 0 /* seems no card uses this ... */
 	btaor(bttv_tvcards[btv->type].gpiomask2,~bttv_tvcards[btv->type].gpiomask2,
               BT848_GPIO_OUT_EN);
+#endif
 
 	/* This seems to get rid of some synchronization problems */
 	btand(~(3<<5), BT848_IFORM);
 	mdelay(10); 
         
-        
 	input %= bttv_tvcards[btv->type].video_inputs;
 	if (input==bttv_tvcards[btv->type].svhs) 
 	{
@@ -428,8 +454,13 @@
 	btaor((bttv_tvcards[btv->type].muxsel[input&7]&3)<<5, ~(3<<5), BT848_IFORM);
 	audio(btv, (input!=bttv_tvcards[btv->type].tuner) ? 
               AUDIO_EXTERN : AUDIO_TUNER, 1);
+
+#if 0 /* seems no card uses this ... */
 	btaor(bttv_tvcards[btv->type].muxsel[input]>>4,
 		~bttv_tvcards[btv->type].gpiomask2, BT848_GPIO_DATA);
+	if (bttv_gpio)
+		bttv_gpio_tracking(btv,"muxsel");
+#endif
 }
 
 
@@ -942,9 +973,9 @@
 				lastbit=cbit;
 				sx += dx;
 				dx = 1;
-				if (ro - btv->risc_scr_odd>RISCMEM_LEN/2 - 16)
+				if (ro - btv->risc_scr_odd>(RISCMEM_LEN>>3) - 16)
 					outofmem++;
-				if (re - btv->risc_scr_even>RISCMEM_LEN/2 - 16)
+				if (re - btv->risc_scr_even>(RISCMEM_LEN>>3) - 16)
 					outofmem++;
 			}
 			x++;
@@ -997,17 +1028,17 @@
 		((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0);
 	vscale |= inter ? (BT848_VSCALE_INT<<8) : 0;
 
-#if 0
-	/* Some people say interpolation looks bad ... */
-	vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
-	if (width < 767)
-		btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
-	else
+	if (combfilter) {
+		/* Some people say interpolation looks bad ... */
+		vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
+		if (width < 769)
+			btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
+		else
+			btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
+	} else {
+		vtc = 0;
 		btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
-#else
-	vtc = 0;
-	btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
-#endif
+	}
 
 	btwrite(vtc, BT848_E_VTC+off);
 	btwrite(hscale>>8, BT848_E_HSCALE_HI+off);
@@ -1133,131 +1164,6 @@
         bt848_set_geo(btv,1);
 }
 
-#ifdef HACKING
-/* playing with kiobufs and dma-to-userspace. 2.4.x only
-   Yes, I know: cut+paste programming is ugly.
-   will fix later, this is proof-of-concept right now. */
-static int  make_vrisctab_kiobuf(struct bttv *btv, unsigned int *ro,
-				 unsigned int *re, struct kiobuf *iobuf,
-				 unsigned short width, unsigned short height,
-				 unsigned short palette)
-{
-	unsigned long bpl;  /* bytes per line */
-	unsigned long bl;
-	unsigned long todo;
-	unsigned long pageaddr;
-	unsigned int **rp;
-	unsigned long line,inter,offset,page;
-	
-	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); 
-        *(ro++)=cpu_to_le32(0);
-	*(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
-        *(re++)=cpu_to_le32(0);
-
-	offset   = iobuf->offset;
-	page     = 0;
-	pageaddr = virt_to_bus(page_address(iobuf->maplist[page]));
-	for (line=0; line < (height<<(1^inter)); line++)
-	{
-	        if (inter) 
-		        rp= (line&1) ? &re : &ro;
-		else 
-	                rp= (line>=height) ? &ro : &re;
-
-		bl = PAGE_SIZE - offset;
-		if (bpl <= bl) {
-		        *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
-					       BT848_RISC_EOL|bpl);
-			*((*rp)++)=cpu_to_le32(pageaddr+offset);
-			offset+=bpl;
-		} else {
-		        todo = bpl;
-		        *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|bl);
-			*((*rp)++)=cpu_to_le32(pageaddr+offset);
-			todo -= bl;
-			offset = 0;
-			page++;
-			pageaddr = virt_to_bus(page_address(iobuf->maplist[page]));
-			while (todo>PAGE_SIZE)
-			{
-			        *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|PAGE_SIZE);
-				*((*rp)++)=cpu_to_le32(pageaddr);
-				page++;
-				pageaddr = virt_to_bus(page_address(iobuf->maplist[page]));
-			}
-			*((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|todo);
-			*((*rp)++)=cpu_to_le32(pageaddr);
-			offset += todo;
-		}
-	}
-	
-	*(ro++)=cpu_to_le32(BT848_RISC_JUMP);
-	*(ro++)=cpu_to_le32(btv->bus_vbi_even);
-	*(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16));
-	*(re++)=cpu_to_le32(btv->bus_vbi_odd);
-	
-	return 0;
-}
-
-static int vgrab_kiobuf(struct bttv *btv, struct bttv_just_hacking *mp,
-			struct kiobuf *iobuf)
-{
-	unsigned int *ro, *re;
-	unsigned long flags;
-	
-	if(btv->gbuf[0].stat != GBUFFER_UNUSED)
-		return -EBUSY;
-	
-	if(mp->height < 32 || mp->width < 32)
-		return -EINVAL;
-	if (mp->format >= 12 /* more is'nt yet ... PALETTEFMT_MAX */)
-		return -EINVAL;
-
-	if(-1 == palette2fmt[mp->format])
-		return -EINVAL;
-
-	/*
-	 *	Ok load up the BT848
-	 */
-	 
-	ro=btv->gbuf[0].risc;
-	re=ro+2048;
-        make_vrisctab_kiobuf(btv, ro, re, iobuf, mp->width, mp->height, mp->format);
-	
-	if (bttv_debug)
-		printk("bttv%d: cap vgrab_kiobuf: queue %d (%d:%dx%d)\n",
-		       btv->nr,0,mp->format,mp->width,mp->height);
-       	spin_lock_irqsave(&btv->s_lock, flags); 
-        btv->gbuf[0].stat    = GBUFFER_GRABBING;
-	btv->gbuf[0].fmt     = palette2fmt[mp->format];
-	btv->gbuf[0].width   = mp->width;
-	btv->gbuf[0].height  = mp->height;
-	btv->gbuf[0].ro      = virt_to_bus(ro);
-	btv->gbuf[0].re      = virt_to_bus(re);
-
-#if 1
-	if (mp->height <= tvnorms[btv->win.norm].sheight/2 &&
-	    mp->format != VIDEO_PALETTE_RAW)
-		btv->gbuf[0].ro = 0;
-#endif
-
-	if (-1 == btv->gq_grab && btv->gq_in == btv->gq_out) {
-		btv->gq_start = 1;
-		btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ);
-        }
-	btv->gqueue[btv->gq_in++] = 0;
-	btv->gq_in = btv->gq_in % MAX_GBUFFERS;
-
-	btor(3, BT848_CAP_CTL);
-	btor(3, BT848_GPIO_DMA_CTL);
-	spin_unlock_irqrestore(&btv->s_lock, flags);
-	return 0;
-}
-#endif
-
 /*
  *	Grab into virtual memory.
  */
@@ -1393,6 +1299,39 @@
 	tvnorms[2].hdelayx1     = 186  - (on?BURSTOFFSET  :0);
 }
 
+/*
+ * called from irq handler on fatal errors.  Takes the grabber chip
+ * offline, flag it needs a reinitialization (which can't be done
+ * from irq context) and wake up all sleeping proccesses.  They would
+ * block forever else.  We also need someone who actually does the
+ * reinitialization from process context...
+ */
+static void bt848_offline(struct bttv *btv)
+{
+	int i;
+	spin_lock(&btv->s_lock);
+
+	/* cancel all outstanding grab requests */
+	btv->gq_in = 0;
+	btv->gq_out = 0;
+	btv->gq_grab = -1;
+	for (i = 0; i < gbuffers; i++)
+		if (btv->gbuf[i].stat == GBUFFER_GRABBING)
+			btv->gbuf[i].stat = GBUFFER_ERROR;
+
+	/* disable screen overlay and DMA */
+	btv->risc_cap_odd  = 0;
+	btv->risc_cap_even = 0;
+	bt848_set_risc_jmps(btv,0);
+
+	/* flag the chip needs a restart */
+	btv->needs_restart = 1;
+	spin_unlock(&btv->s_lock);
+
+	wake_up_interruptible(&btv->vbiq);
+	wake_up_interruptible(&btv->capq);
+}
+
 static void bt848_restart(struct bttv *btv)
 {
  	unsigned long irq_flags;
@@ -1427,6 +1366,8 @@
         int i,ret;
 
 	ret = -EBUSY;
+	if (bttv_debug)
+		printk("bttv%d: open called\n",btv->nr);
 
 	MOD_INC_USE_COUNT;
 	down(&btv->lock);
@@ -1724,6 +1665,7 @@
 			btv->scr_on = 0;
 			bt848_set_risc_jmps(btv,-1);
 			spin_unlock_irqrestore(&btv->s_lock, irq_flags);
+			up(&btv->lock);
 			return -EINVAL;
 		}
 		if (btv->win.bpp < 4) 
@@ -1747,20 +1689,26 @@
 		 *	Do any clips.
 		 */
 		if(vw.clipcount<0) {
-			if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL)
+			if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) {
+				up(&btv->lock);
 				return -ENOMEM;
+			}
 			if(copy_from_user(vcp, vw.clips,
 					  VIDEO_CLIPMAP_SIZE)) {
+				up(&btv->lock);
 				vfree(vcp);
 				return -EFAULT;
 			}
 		} else if (vw.clipcount) {
 			if((vcp=vmalloc(sizeof(struct video_clip)*
-					(vw.clipcount))) == NULL)
+					(vw.clipcount))) == NULL) {
+				up(&btv->lock);
 				return -ENOMEM;
+			}
 			if(copy_from_user(vcp,vw.clips,
 					  sizeof(struct video_clip)*
 					  vw.clipcount)) {
+				up(&btv->lock);
 				vfree(vcp);
 				return -EFAULT;
 			}
@@ -1898,21 +1846,9 @@
 		v.mode = VIDEO_SOUND_MONO;
 		bttv_call_i2c_clients(btv,cmd,&v);
 
-		if (btv->type == BTTV_TERRATV) {
-			v.mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-				VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-		}
-#ifndef HAVE_TVAUDIO
-		else if (btv->audio_chip == TDA9840) {
-			/* begin of Horrible Hack <grin@tolna.net> */
-			v.flags|=VIDEO_AUDIO_VOLUME;
-			v.mode  = VIDEO_SOUND_MONO;
-			v.mode |= VIDEO_SOUND_STEREO;
-			v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2;
-			v.volume = 32768;       /* fixme */
-			v.step = 4096;
-		}
-#endif
+		/* card specific hooks */
+		if (bttv_tvcards[btv->type].audio_hook)
+			bttv_tvcards[btv->type].audio_hook(btv,&v,0);
 
 		if(copy_to_user(arg,&v,sizeof(v)))
 			return -EFAULT;
@@ -1938,17 +1874,9 @@
 
 		bttv_call_i2c_clients(btv,cmd,&v);
 		
-		if (btv->type == BTTV_TERRATV) {
-			unsigned int con = 0;
-			btor(0x180000, BT848_GPIO_OUT_EN);
-			if (v.mode & VIDEO_SOUND_LANG2)
-				con = 0x080000;
-			if (v.mode & VIDEO_SOUND_STEREO)
-				con = 0x180000;
-			btaor(con, ~0x180000, BT848_GPIO_DATA);
-
-		} else if (btv->type == BTTV_WINVIEW_601)
-			winview_setvol(btv,&v);
+		/* card specific hooks */
+		if (bttv_tvcards[btv->type].audio_hook)
+			bttv_tvcards[btv->type].audio_hook(btv,&v,0);
 
 		btv->audio_dev=v;
 		up(&btv->lock);
@@ -2082,90 +2010,12 @@
 		return  0;
 	}
 
-#ifdef HACKING
-	/* playing with kiobufs and dma-to-userspace */
-	case BTTV_JUST_HACKING:
-	{
-		DECLARE_WAITQUEUE(wait, current);
-		struct bttv_just_hacking hack;
-		struct kiobuf *iobuf;
-		int err;
-		
-		if(copy_from_user((void *) &hack, (void *) arg, sizeof(hack)))
-			return -EFAULT;
-		printk("bttv%d: hack: userland args: %dx%d, fmt=%d, buf=%lx, len=%d\n",
-		       btv->nr,hack.width,hack.height,hack.format,
-		       hack.buf,hack.len);
-
-		/* pin down */
-		err = alloc_kiovec(1,&iobuf);
-		if (err)
-			goto hack_oops;
-		err = map_user_kiobuf(READ, iobuf, hack.buf, hack.len);
-		if (err)
-			goto hack_oops;
-		err = lock_kiovec(1,&iobuf,1);
-		if (err)
-			goto hack_oops;
-
-		/* have a look */
-		printk("bttv%d: hack: kiobuf: nr_pages=%d, offset=%d, length=%d, locked=%d\n",
-		       btv->nr,iobuf->nr_pages,iobuf->offset,iobuf->length,
-		       iobuf->locked);
-		printk("bttv%d: hack: pages (bus addr):",btv->nr);
-		for (i = 0; i < iobuf->nr_pages; i++) {
-			printk(" %lx", virt_to_bus(page_address(iobuf->maplist[i])));
-		}
-		printk("\n");
-
-		/* start capture */
-		err = -EINVAL;
-		if (hack.height * hack.width * 2 * /* fixme: *2 */
-		    fmtbppx2[palette2fmt[hack.format]&0x0f]/2 > hack.len)
-			goto hack_oops;
-		err = vgrab_kiobuf(btv,&hack,iobuf);
-		if (err)
-			goto hack_oops;
-		printk("bttv%d: hack: capture started\n",btv->nr);
-
-		/* wait */
-		add_wait_queue(&btv->capq, &wait);
-		current->state = TASK_INTERRUPTIBLE;
-		while(btv->gbuf[0].stat==GBUFFER_GRABBING) {
-			if (bttv_debug)
-				printk("bttv%d: hack: cap sync: sleep on %d\n",btv->nr,0);
-			schedule();
-#if 0
-			if(signal_pending(current)) {
-				remove_wait_queue(&btv->capq, &wait);
-				current->state = TASK_RUNNING;
-				return -EINTR;
-			}
-#endif
-		}
-		remove_wait_queue(&btv->capq, &wait);
-		current->state = TASK_RUNNING;
-		printk("bttv%d: hack: capture done\n",btv->nr);
-		
-		/* release */
-		err = 0;
-	hack_oops:
-		free_kiovec(1,&iobuf);
-		return 0;
-	}
-#endif
-
 	default:
 		return -ENOIOCTLCMD;
 	}
 	return 0;
 }
 
-static int bttv_init_done(struct video_device *dev)
-{
-	return 0;
-}
-
 /*
  *	This maps the vmalloced and reserved fbuffer to user space.
  *
@@ -2212,20 +2062,16 @@
 
 static struct video_device bttv_template=
 {
-	"UNSET",
-	VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY|VID_TYPE_TELETEXT,
-	VID_HARDWARE_BT848,
-	bttv_open,
-	bttv_close,
-	bttv_read,
-	bttv_write,
-	NULL,
-	bttv_ioctl,
-	bttv_mmap,
-	bttv_init_done,
-	NULL,
-	0,
-	-1
+	name:		"UNSET",
+	type:		VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY|VID_TYPE_TELETEXT,
+	hardware:	VID_HARDWARE_BT848,
+	open:		bttv_open,
+	close:		bttv_close,
+	read:		bttv_read,
+	write:		bttv_write,
+	ioctl:		bttv_ioctl,
+	mmap:		bttv_mmap,
+	minor:		-1,
 };
 
 
@@ -2353,7 +2199,8 @@
 	}
 	case VIDIOCGFREQ:
 	case VIDIOCSFREQ:
-		return bttv_ioctl((struct video_device *)btv,cmd,arg);
+	case BTTV_VERSION:
+		return bttv_ioctl(dev,cmd,arg);
 	case BTTV_VBISIZE:
 		/* make alevt happy :-) */
 		return VBIBUF_SIZE;
@@ -2364,20 +2211,16 @@
 
 static struct video_device vbi_template=
 {
-	"bttv vbi",
-	VID_TYPE_CAPTURE|VID_TYPE_TELETEXT,
-	VID_HARDWARE_BT848,
-	vbi_open,
-	vbi_close,
-	vbi_read,
-	bttv_write,
-	vbi_poll,
-	vbi_ioctl,
-	NULL,	/* no mmap yet */
-	bttv_init_done,
-	NULL,
-	0,
-	-1
+	name:		"bttv vbi",
+	type:		VID_TYPE_CAPTURE|VID_TYPE_TELETEXT,
+	hardware:	VID_HARDWARE_BT848,
+	open:		vbi_open,
+	close:		vbi_close,
+	read:		vbi_read,
+	write:		bttv_write,
+	poll:		vbi_poll,
+	ioctl:		vbi_ioctl,
+	minor:		-1,
 };
 
 
@@ -2456,6 +2299,7 @@
 		v.rangehigh=(int)(108*16);	/* eu: 87.5MHz - 108.0MHz */
 		v.flags= 0; /* XXX */
 		v.mode = 0; /* XXX */
+		bttv_call_i2c_clients(btv,cmd,&v);
 		if(copy_to_user(arg,&v,sizeof(v)))
 			return -EFAULT;
 		return 0;
@@ -2485,20 +2329,15 @@
 
 static struct video_device radio_template=
 {
-	"bttv radio",
-	VID_TYPE_TUNER,
-	VID_HARDWARE_BT848,
-	radio_open,
-	radio_close,
-	radio_read,          /* just returns -EINVAL */
-	bttv_write,          /* just returns -EINVAL */
-	NULL,                /* no poll */
-	radio_ioctl,
-	NULL,	             /* no mmap */
-	bttv_init_done,      /* just returns 0 */
-	NULL,
-	0,
-	-1
+	name:		"bttv radio",
+	type:		VID_TYPE_TUNER,
+	hardware:	VID_HARDWARE_BT848,
+	open:		radio_open,
+	close:		radio_close,
+	read:		radio_read,          /* just returns -EINVAL */
+	write:		bttv_write,          /* just returns -EINVAL */
+	ioctl:		radio_ioctl,
+	minor:		-1,
 };
 
 
@@ -2579,7 +2418,8 @@
 			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) {
+	} else if ((flags&2) &&
+		   (!btv->win.interlace || 0 == btv->risc_cap_even)) {
 		if (bttv_debug > 1)
 			printk(" eo=%08lx",virt_to_bus(btv->risc_scr_odd));
 		btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_scr_odd));
@@ -2614,7 +2454,8 @@
 			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) {
+	} else if ((flags&1) &&
+		   btv->win.interlace) {
 		if (bttv_debug > 1)
 			printk(" oo=%08lx",virt_to_bus(btv->risc_scr_even));
 		btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_scr_even));
@@ -2648,7 +2489,6 @@
 	memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template));
 	memcpy(&btv->radio_dev,&radio_template,sizeof(radio_template));
         
-	bttv_idcard(btv);
 	audio(btv, AUDIO_MUTE, 1);
         
 	if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0)
@@ -2680,12 +2520,8 @@
 
 	/* dump current state of the gpio registers before changing them,
 	 * might help to make a new card work */
-	if (bttv_verbose >= 2)
-		printk("bttv%d: gpio: out_enable=0x%x, data=0x%x, in=0x%x\n",
-		       btv->nr,
-		       btread(BT848_GPIO_OUT_EN),
-		       btread(BT848_GPIO_DATA),
-		       btread(BT848_GPIO_REG_INP));
+	if (bttv_gpio)
+		bttv_gpio_tracking(btv,"init #1");
 
 	/* reset the bt848 */
 	btwrite(0, BT848_SRESET);
@@ -2724,10 +2560,6 @@
 	btv->errors=0;
 	btv->needs_restart=0;
 
-	/* i2c */
-        btv->tuner_type=-1;
-        init_bttv_i2c(btv);
-
 	if (!(btv->risc_scr_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
 		return -1;
 	if (!(btv->risc_scr_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
@@ -2772,6 +2604,9 @@
 
         /* select direct input */
 	btwrite(0x00, BT848_GPIO_REG_INP);
+	btwrite(0x00, BT848_GPIO_OUT_EN);
+	if (bttv_gpio)
+		bttv_gpio_tracking(btv,"init #2");
 
 	btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_AUTO,
 		BT848_IFORM);
@@ -2814,6 +2649,17 @@
 	bt848_set_risc_jmps(btv,-1);
 	spin_unlock_irqrestore(&btv->s_lock, irq_flags);
 
+	/* needs to be done before i2c is registered */
+        if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878)
+                bttv_hauppauge_boot_msp34xx(btv);
+
+	/* register i2c */
+        btv->tuner_type=-1;
+        init_bttv_i2c(btv);
+
+	/* some card-specific stuff (needs working i2c) */
+	bttv_init_card(btv);
+
 	/*
 	 *	Now add the template and register the device unit.
 	 */
@@ -2822,11 +2668,18 @@
 	return 0;
 }
 
+/* ----------------------------------------------------------------------- */
+
+static char *irq_name[] = { "FMTCHG", "VSYNC", "HSYNC", "OFLOW", "HLOCK",
+			    "VPRES", "6", "7", "I2CDONE", "GPINT", "10",
+			    "RISCI", "FBUS", "FTRGT", "FDSR", "PPERR",
+			    "RIPERR", "PABORT", "OCERR", "SCERR" };
+
 static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
 {
 	u32 stat,astat;
 	u32 dstat;
-	int count,i;
+	int count;
 	struct bttv *btv;
 
 	btv=(struct bttv *)dev_id;
@@ -2838,33 +2691,39 @@
 		astat=stat&btread(BT848_INT_MASK);
 		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));
+		btwrite(stat,BT848_INT_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));
-			/*btv->win.norm&=
-			  (dstat&BT848_DSTATUS_NUML) ? (~1) : (~0); */
-		}
-		if (astat&BT848_INT_VPRES) 
-		{
-			IDEBUG(printk ("bttv%d: IRQ_VPRES\n", btv->nr));
+		if (irq_debug) {
+			int i;
+			printk(KERN_DEBUG "bttv%d: irq loop=%d risc=%x, bits:",
+			       btv->nr, count, stat>>28);
+			for (i = 0; i < (sizeof(irq_name)/sizeof(char*)); i++) {
+				if (stat & (1 << i))
+					printk(" %s",irq_name[i]);
+				if (astat & (1 << i))
+					printk("*");
+			}
+			if (stat & BT848_INT_HLOCK)
+				printk("   HLOC => %s", (dstat & BT848_DSTATUS_HLOC)
+				       ? "yes" : "no");
+			if (stat & BT848_INT_VPRES)
+				printk("   PRES => %s", (dstat & BT848_DSTATUS_PRES)
+				       ? "yes" : "no");
+			if (stat & BT848_INT_FMTCHG)
+				printk("   NUML => %s", (dstat & BT848_DSTATUS_PRES)
+				       ? "625" : "525");
+			printk("\n");
 		}
+
+		if (astat&BT848_INT_GPINT)
+			wake_up_interruptible(&btv->gpioq);
+
 		if (astat&BT848_INT_VSYNC) 
-		{
-			IDEBUG(printk ("bttv%d: IRQ_VSYNC\n", btv->nr));
                         btv->field++;
-		}
+
 		if (astat&(BT848_INT_SCERR|BT848_INT_OCERR)) {
 			if (bttv_verbose)
 				printk("bttv%d: irq:%s%s risc_count=%08x\n",
@@ -2884,23 +2743,7 @@
 			} else {
 				if (bttv_verbose)
 					printk("bttv%d: aiee: error loops\n",btv->nr);
-				/* cancel all outstanding grab requests */
-				spin_lock(&btv->s_lock);
-				btv->gq_in = 0;
-				btv->gq_out = 0;
-				btv->gq_grab = -1;
-				for (i = 0; i < gbuffers; i++)
-					if (btv->gbuf[i].stat == GBUFFER_GRABBING)
-						btv->gbuf[i].stat = GBUFFER_ERROR;
-				/* disable DMA */
-				btv->risc_cap_odd  = 0;
-				btv->risc_cap_even = 0;
-				bt848_set_risc_jmps(btv,0);
-				btv->needs_restart = 1;
-				spin_unlock(&btv->s_lock);
-
-				wake_up_interruptible(&btv->vbiq);
-				wake_up_interruptible(&btv->capq);
+				bt848_offline(btv);
 			}
 		}
 		if (astat&BT848_INT_RISCI) 
@@ -2968,55 +2811,20 @@
 				spin_unlock(&btv->s_lock);
 			}
 		}
-		if (astat&BT848_INT_OCERR) 
-		{
-			IDEBUG(printk ("bttv%d: IRQ_OCERR\n", btv->nr));
-		}
-		if (astat&BT848_INT_PABORT) 
-		{
-			IDEBUG(printk ("bttv%d: IRQ_PABORT\n", btv->nr));
-		}
-		if (astat&BT848_INT_RIPERR) 
-		{
-			IDEBUG(printk ("bttv%d: IRQ_RIPERR\n", btv->nr));
-		}
-		if (astat&BT848_INT_PPERR) 
-		{
-			IDEBUG(printk ("bttv%d: IRQ_PPERR\n", btv->nr));
-		}
-		if (astat&BT848_INT_FDSR) 
-		{
-			IDEBUG(printk ("bttv%d: IRQ_FDSR\n", btv->nr));
-		}
-		if (astat&BT848_INT_FTRGT) 
-		{
-			IDEBUG(printk ("bttv%d: IRQ_FTRGT\n", btv->nr));
-		}
-		if (astat&BT848_INT_FBUS) 
-		{
-			IDEBUG(printk ("bttv%d: IRQ_FBUS\n", btv->nr));
-		}
-		if (astat&BT848_INT_HLOCK) 
-		{
+
+		if (astat&BT848_INT_HLOCK) {
 			if ((dstat&BT848_DSTATUS_HLOC) || (btv->radio))
 				audio(btv, AUDIO_ON,0);
 			else
 				audio(btv, AUDIO_OFF,0);
 		}
     
-		if (astat&BT848_INT_I2CDONE) 
-		{
-			IDEBUG(printk ("bttv%d: IRQ_I2CDONE\n", btv->nr));
-		}
 		count++;
-		if (count > 10)
-			printk (KERN_WARNING "bttv%d: irq loop %d\n",
-                                btv->nr,count);
-		if (count > 20) 
-		{
+		if (count > 20) {
 			btwrite(0, BT848_INT_MASK);
 			printk(KERN_ERR 
 			       "bttv%d: IRQ lockup, cleared int mask\n", btv->nr);
+			bt848_offline(btv);
 		}
 	}
 }
@@ -3033,8 +2841,11 @@
         int j;
         struct bttv *btv = pci_get_drvdata(pci_dev);
 
+	if (bttv_verbose)
+		printk("bttv%d: unloading\n",btv->nr);
+
         /* unregister i2c_bus */
-	if (0 == btv->i2c_ok)
+	if (0 == btv->i2c_rc)
 		i2c_bit_del_bus(&btv->i2c_adap);
 
         /* turn off all capturing, DMA and IRQs */
@@ -3044,6 +2855,8 @@
         btwrite(0, BT848_INT_MASK);
         btwrite(~0x0UL,BT848_INT_STAT);
         btwrite(0x0, BT848_GPIO_OUT_EN);
+	if (bttv_gpio)
+		bttv_gpio_tracking(btv,"cleanup");
 
         /* disable PCI bus-mastering */
         pci_read_config_byte(btv->dev, PCI_COMMAND, &command);
@@ -3084,7 +2897,7 @@
         if (radio[btv->nr] && btv->radio_dev.minor != -1)
                 video_unregister_device(&btv->radio_dev);
 
-        release_mem_region(btv->bt848_adr,
+        release_mem_region(pci_resource_start(btv->dev,0),
                            pci_resource_len(btv->dev,0));
         /* wake up any waiting processes
            because shutdown flag is set, no new processes (in this queue)
@@ -3094,7 +2907,6 @@
         wake_up(&btv->gpioq);
 
 	pci_set_drvdata(pci_dev, NULL);
-
         return;
 }
 
@@ -3102,7 +2914,7 @@
 static int __devinit bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
 {
 	int result;
-	unsigned char command;
+	unsigned char command,lat;
 	struct bttv *btv;
 #if defined(__powerpc__)
         unsigned int cmd;
@@ -3141,11 +2953,14 @@
                 btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA);
 
         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, ",dev->bus->number, dev->devfn);
-        printk("irq: %d, ",btv->irq);
-        printk("memory: 0x%lx.\n", btv->bt848_adr);
+        pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+        printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %02x:%02x.%x, ",
+               bttv_num,btv->id, btv->revision, dev->bus->number,
+	       PCI_SLOT(dev->devfn),PCI_FUNC(dev->devfn));
+        printk("irq: %d, latency: %d, memory: 0x%lx\n",
+	       btv->irq, lat, btv->bt848_adr);
+	
+	bttv_idcard(btv);
 
 #if defined(__powerpc__)
         /* on OpenFirmware machines (PowerMac at least), PCI memory cycle */

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