linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch] v4l: bttv driver update
@ 2003-10-07 10:58 Gerd Knorr
  2003-10-07 20:15 ` Pavel Machek
  0 siblings, 1 reply; 6+ messages in thread
From: Gerd Knorr @ 2003-10-07 10:58 UTC (permalink / raw)
  To: Linus Torvalds, Andrew Morton, Kernel List

  Hi,

This patch updates the bttv driver.  It depends on the videobuf patch.
Changes:

  * usual tv card list updates.
  * sysfs adaptions.
  * new, experimental i2c adapter code for bt878 chips
    (not used by default yet).
  * various minor fixes.

Please apply,

  Gerd

diff -u linux-2.6.0-test6/drivers/media/video/bt848.h linux/drivers/media/video/bt848.h
--- linux-2.6.0-test6/drivers/media/video/bt848.h	2003-10-06 17:44:53.000000000 +0200
+++ linux/drivers/media/video/bt848.h	2003-10-06 17:59:00.000000000 +0200
@@ -282,13 +282,16 @@
 #define BT848_GPIO_DMA_CTL_FIFO_ENABLE (1<<0)
 
 #define BT848_I2C              0x110
+#define BT878_I2C_MODE         (1<<7)
+#define BT878_I2C_RATE         (1<<6)
+#define BT878_I2C_NOSTOP       (1<<5)
+#define BT878_I2C_NOSTART      (1<<4)
 #define BT848_I2C_DIV          (0xf<<4)
 #define BT848_I2C_SYNC         (1<<3)
 #define BT848_I2C_W3B	       (1<<2)
 #define BT848_I2C_SCL          (1<<1)
 #define BT848_I2C_SDA          (1<<0)
 
-
 #define BT848_RISC_STRT_ADD    0x114
 #define BT848_GPIO_OUT_EN      0x118
 #define BT848_GPIO_REG_INP     0x11C
diff -u linux-2.6.0-test6/drivers/media/video/btcx-risc.c linux/drivers/media/video/btcx-risc.c
--- linux-2.6.0-test6/drivers/media/video/btcx-risc.c	2003-10-06 17:44:30.000000000 +0200
+++ linux/drivers/media/video/btcx-risc.c	2003-10-06 17:48:02.000000000 +0200
@@ -44,39 +44,6 @@
 
 static int memcnt;
 
-int btcx_riscmem_alloc(struct pci_dev *pci,
-		       struct btcx_riscmem *risc,
-		       unsigned int size)
-{
-	u32 *cpu;
-	dma_addr_t dma;
-	
-	cpu = pci_alloc_consistent(pci, size, &dma);
-	if (NULL == cpu)
-		return -ENOMEM;
-	memset(cpu,0,size);
-
-#if 0
-	if (risc->cpu && risc->size < size) {
-		/* realloc (enlarge buffer) -- copy old stuff */
-		memcpy(cpu,risc->cpu,risc->size);
-		btcx_riscmem_free(pci,risc);
-	}
-#else
-	BUG_ON(NULL != risc->cpu);
-#endif
-	risc->cpu  = cpu;
-	risc->dma  = dma;
-	risc->size = size;
-
-	if (debug) {
-		memcnt++;
-		printk("btcx: riscmem alloc size=%d [%d]\n",size,memcnt);
-	}
-
-	return 0;
-}
-
 void btcx_riscmem_free(struct pci_dev *pci,
 		       struct btcx_riscmem *risc)
 {
@@ -90,6 +57,31 @@
 	}
 }
 
+int btcx_riscmem_alloc(struct pci_dev *pci,
+		       struct btcx_riscmem *risc,
+		       unsigned int size)
+{
+	u32 *cpu;
+	dma_addr_t dma;
+
+	if (NULL != risc->cpu && risc->size < size)
+		btcx_riscmem_free(pci,risc);
+	if (NULL == risc->cpu) {
+		cpu = pci_alloc_consistent(pci, size, &dma);
+		if (NULL == cpu)
+			return -ENOMEM;
+		risc->cpu  = cpu;
+		risc->dma  = dma;
+		risc->size = size;
+		if (debug) {
+			memcnt++;
+			printk("btcx: riscmem alloc size=%d [%d]\n",size,memcnt);
+		}
+	}
+	memset(risc->cpu,0,risc->size);
+	return 0;
+}
+
 /* ---------------------------------------------------------- */
 /* screen overlay helpers                                     */
 
diff -u linux-2.6.0-test6/drivers/media/video/bttv-cards.c linux/drivers/media/video/bttv-cards.c
--- linux-2.6.0-test6/drivers/media/video/bttv-cards.c	2003-10-06 17:45:22.000000000 +0200
+++ linux/drivers/media/video/bttv-cards.c	2003-10-06 17:48:02.000000000 +0200
@@ -21,10 +21,9 @@
     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-    
+
 */
 
-#include <linux/version.h>
 #include <linux/config.h>
 #include <linux/delay.h>
 #include <linux/module.h>
@@ -32,7 +31,9 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
-#include <linux/firmware.h>
+#ifdef CONFIG_FW_LOADER
+# include <linux/firmware.h>
+#endif
 
 #include <asm/io.h>
 
@@ -62,6 +63,7 @@
 static void rv605_muxsel(struct bttv *btv, unsigned int input);
 static void eagle_muxsel(struct bttv *btv, unsigned int input);
 static void xguard_muxsel(struct bttv *btv, unsigned int input);
+static void ivc120_muxsel(struct bttv *btv, unsigned int input);
 
 static int terratec_active_radio_upgrade(struct bttv *btv);
 static int tea5757_read(struct bttv *btv);
@@ -78,6 +80,7 @@
 static unsigned int card[BTTV_MAX]  = { [ 0 ... (BTTV_MAX-1) ] = UNSET};
 static unsigned int pll[BTTV_MAX]   = { [ 0 ... (BTTV_MAX-1) ] = UNSET};
 static unsigned int tuner[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET};
+static unsigned int svhs[BTTV_MAX]  = { [ 0 ... (BTTV_MAX-1) ] = UNSET};
 #ifdef MODULE
 static unsigned int autoload = 1;
 #else
@@ -216,12 +219,32 @@
 	{ 0x1466aa06, BTTV_PV150,         "Provideo PV150B-3" },
 	{ 0x1467aa07, BTTV_PV150,         "Provideo PV150B-4" },
 
-
-	{ 0xa1550000, BTTV_IVC200,        "IVC-200" },
-	{ 0xa1550001, BTTV_IVC200,        "IVC-200" },
-	{ 0xa1550002, BTTV_IVC200,        "IVC-200" },
-	{ 0xa1550003, BTTV_IVC200,        "IVC-200" },	
-
+	{ 0xa132ff00, BTTV_IVC100,        "IVC-100"  },
+	{ 0xa1550000, BTTV_IVC200,        "IVC-200"  },
+	{ 0xa1550001, BTTV_IVC200,        "IVC-200"  },
+	{ 0xa1550002, BTTV_IVC200,        "IVC-200"  },
+	{ 0xa1550003, BTTV_IVC200,        "IVC-200"  },	
+	{ 0xa1550100, BTTV_IVC200,        "IVC-200G" },
+	{ 0xa1550101, BTTV_IVC200,        "IVC-200G" },
+	{ 0xa1550102, BTTV_IVC200,        "IVC-200G" },
+	{ 0xa1550103, BTTV_IVC200,        "IVC-200G" },
+	{ 0xa182ff00, BTTV_IVC120,        "IVC-120G" },
+	{ 0xa182ff01, BTTV_IVC120,        "IVC-120G" },
+	{ 0xa182ff02, BTTV_IVC120,        "IVC-120G" },
+	{ 0xa182ff03, BTTV_IVC120,        "IVC-120G" },
+	{ 0xa182ff04, BTTV_IVC120,        "IVC-120G" },
+	{ 0xa182ff05, BTTV_IVC120,        "IVC-120G" },
+	{ 0xa182ff06, BTTV_IVC120,        "IVC-120G" },
+	{ 0xa182ff07, BTTV_IVC120,        "IVC-120G" },
+	{ 0xa182ff08, BTTV_IVC120,        "IVC-120G" },
+	{ 0xa182ff09, BTTV_IVC120,        "IVC-120G" },
+	{ 0xa182ff0a, BTTV_IVC120,        "IVC-120G" },
+	{ 0xa182ff0b, BTTV_IVC120,        "IVC-120G" },
+	{ 0xa182ff0c, BTTV_IVC120,        "IVC-120G" },
+	{ 0xa182ff0d, BTTV_IVC120,        "IVC-120G" },
+	{ 0xa182ff0e, BTTV_IVC120,        "IVC-120G" },
+	{ 0xa182ff0f, BTTV_IVC120,        "IVC-120G" },
+	
 	{ 0x41424344, BTTV_GRANDTEC,      "GrandTec Multi Capture" },
 	{ 0x01020304, BTTV_XGUARD,        "Grandtec Grand X-Guard" },
 	
@@ -1338,7 +1361,7 @@
 },{
         .name           = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
         .video_inputs   = 4,
-        .audio_inputs   = 3, 
+        .audio_inputs   = 3,
         .tuner          = 0,
         .svhs           = 2,
         .gpiomask       = 7,
@@ -1388,18 +1411,19 @@
 	.gpiomask       = 7,
 	.audiomux       = {7},
 },{
-	.name           = "GV-BCTV5/PCI",
+	.name           = "IODATA GV-BCTV5/PCI",
 	.video_inputs   = 3,
 	.audio_inputs   = 1,
 	.tuner          = 0,
 	.svhs           = 2,
-	.gpiomask       = 0x010f00,
+	.gpiomask       = 0x0f0f80,
 	.muxsel         = {2, 3, 1, 0},
-	.audiomux       = {0x10000, 0, 0x10000, 0, 0, 0},
+	.audiomux       = {0x030000, 0x010000, 0x030000, 0, 0x020000, 0},
 	.no_msp34xx     = 1,
 	.pll            = PLL_28,
 	.tuner_type     = TUNER_PHILIPS_NTSC_M,
 	.audio_hook     = gvbctv3pci_audio,
+	.has_radio      = 1,
 },{
 	.name           = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
 	.video_inputs   = 4,                  /* id-inputs-clock */
@@ -1720,16 +1744,14 @@
 
 	/* ---- card 0x68 ---------------------------------- */
 	.name           = "Nebula Electronics DigiTV",
-	.video_inputs   = 0,
-	.audio_inputs   = 0,
 	.svhs           = -1,
 	.muxsel         = { 2, 3, 1, 0},
-	.needs_tvaudio  = 0,
 	.no_msp34xx     = 1,
 	.no_tda9875     = 1,
 	.no_tda7432     = 1,
 	.pll            = PLL_28,
 	.tuner_type     = -1,
+	.no_video       = 1,
 },{
 	/* Jorge Boncompte - DTI2 <jorge@dti2.net> */
 	.name           = "ProVideo PV143",
@@ -1801,6 +1823,33 @@
 	.needs_tvaudio  = 1,
 	.pll            = PLL_28,
 	.tuner_type     = -1,
+},{
+        .name           = "IVC-100",
+        .video_inputs   = 4,
+        .audio_inputs   = 0,
+        .tuner          = -1,
+        .tuner_type     = -1,
+        .svhs           = -1,
+        .gpiomask       = 0xdf,
+        .muxsel         = { 2, 3, 1, 0 },
+        .pll            = PLL_28,
+},{
+	/* IVC-120G - Alan Garfield <alan@fromorbit.com> */
+	.name           = "IVC-120G",
+	.video_inputs   = 16,
+	.audio_inputs   = 0,    /* card has no audio */
+	.tuner          = -1,   /* card has no tuner */
+	.tuner_type     = -1,
+	.svhs           = -1,   /* card has no svhs */
+	.needs_tvaudio  = 0,
+	.no_msp34xx     = 1,
+	.no_tda9875     = 1,
+	.no_tda7432     = 1,
+	.gpiomask       = 0x00,
+	.muxsel         = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 
+			    0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 },
+	.muxsel_hook    = ivc120_muxsel,
+	.pll            = PLL_28,
 }};
 
 const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -1853,12 +1902,8 @@
 		btv->type=card[btv->nr];
 	
 	/* print which card config we are using */
-	sprintf(btv->video_dev.name,"BT%d%s(%.23s)",
-		btv->id,
-		(btv->id==848 && btv->revision==0x12) ? "A" : "",
-		bttv_tvcards[btv->type].name);
 	printk(KERN_INFO "bttv%d: using: %s [card=%d,%s]\n",btv->nr,
-	       btv->video_dev.name,btv->type,
+	       bttv_tvcards[btv->type].name, btv->type,
 	       card[btv->nr] < bttv_num_tvcards
 	       ? "insmod option" : "autodetected");
 
@@ -2107,6 +2152,27 @@
 
 /* ----------------------------------------------------------------------- */
 
+void bttv_reset_audio(struct bttv *btv)
+{
+	/*
+	 * BT878A has a audio-reset register.
+	 * 1. This register is an audio reset function but it is in
+	 *    function-0 (video capture) address space.
+	 * 2. It is enough to do this once per power-up of the card.
+	 * 3. There is a typo in the Conexant doc -- it is not at
+	 *    0x5B, but at 0x058. (B is an odd-number, obviously a typo!).
+	 * --//Shrikumar 030609
+	 */
+	if (btv->id != 878)
+		return;
+	
+	if (bttv_debug)
+		printk("bttv%d: BT878A ARESET\n",btv->nr);
+	btwrite((1<<7), 0x058);
+	udelay(10);
+	btwrite(     0, 0x058);
+}
+
 /* initialization part one -- before registering i2c bus */
 void __devinit bttv_init_card1(struct bttv *btv)
 {
@@ -2269,6 +2335,9 @@
 				      &btv->pinnacle_id);
 	if (btv->tuner_type != UNSET)
 		bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
+	btv->svhs = bttv_tvcards[btv->type].svhs;
+	if (svhs[btv->nr] != UNSET)
+		btv->svhs = svhs[btv->nr];
 
 	if (bttv_tvcards[btv->type].has_radio)
 		btv->has_radio=1;
@@ -2548,10 +2617,9 @@
 int __devinit pvr_boot(struct bttv *btv)
 {
         const struct firmware *fw_entry;
-	struct device *dev = &btv->dev->dev;
 	int rc;
 
-	rc = request_firmware(&fw_entry, "hcwamc.rbf", dev);
+	rc = request_firmware(&fw_entry, "hcwamc.rbf", &btv->dev->dev);
 	if (rc != 0) {
 		printk(KERN_WARNING "bttv%d: no altera firmware [via hotplug]\n",
 		       btv->nr);
@@ -2696,12 +2764,12 @@
 
 static void __devinit avermedia_eeprom(struct bttv *btv)
 {
-        int tuner_make,tuner_tv_fm,tuner_format,tuner=0,remote;
+        int tuner_make,tuner_tv_fm,tuner_format,tuner=0;
 
-	tuner_make   = (eeprom_data[0x41] & 0x7);
-        tuner_tv_fm  = (eeprom_data[0x41] & 0x18) >> 3;
-        tuner_format = (eeprom_data[0x42] & 0xf0) >> 4;
-	remote       = (eeprom_data[0x42] & 0x01);
+	tuner_make      = (eeprom_data[0x41] & 0x7);
+        tuner_tv_fm     = (eeprom_data[0x41] & 0x18) >> 3;
+        tuner_format    = (eeprom_data[0x42] & 0xf0) >> 4;
+	btv->has_remote = (eeprom_data[0x42] & 0x01);
 
 	if (tuner_make == 0 || tuner_make == 2)
 		if(tuner_format <=9)
@@ -2718,8 +2786,8 @@
 	} else
 		printk("Unknown type");
 	printk(" radio:%s remote control:%s\n",
-		tuner_tv_fm?"yes":"no",
-		remote?"yes":"no");
+	       tuner_tv_fm     ? "yes" : "no",
+	       btv->has_remote ? "yes" : "no");
 }
 
 /* used on Voodoo TV/FM (Voodoo 200), S0 wired to 0x10000 */
@@ -3448,6 +3516,72 @@
         btwrite(masks[input%16], BT848_GPIO_DATA);
 }
 
+/*
+ * ivc120_muxsel [Added by Alan Garfield <alan@fromorbit.com>]
+ *
+ * The IVC120G security card has 4 i2c controlled TDA8540 matrix
+ * swichers to provide 16 channels to MUX0. The TDA8540's have 
+ * 4 indepedant outputs and as such the IVC120G also has the 
+ * optional "Monitor Out" bus. This allows the card to be looking 
+ * at one input while the monitor is looking at another.
+ *
+ * Since I've couldn't be bothered figuring out how to add an
+ * independant muxsel for the monitor bus, I've just set it to 
+ * whatever the card is looking at.
+ *
+ *  OUT0 of the TDA8540's is connected to MUX0         (0x03)
+ *  OUT1 of the TDA8540's is connected to "Monitor Out"        (0x0C)
+ *
+ *  TDA8540_ALT3 IN0-3 = Channel 13 - 16       (0x03)
+ *  TDA8540_ALT4 IN0-3 = Channel 1 - 4         (0x03)
+ *  TDA8540_ALT5 IN0-3 = Channel 5 - 8         (0x03)
+ *  TDA8540_ALT6 IN0-3 = Channel 9 - 12                (0x03)
+ *
+ */
+
+/* All 7 possible sub-ids for the TDA8540 Matrix Switcher */
+#define I2C_TDA8540        0x90
+#define I2C_TDA8540_ALT1   0x92
+#define I2C_TDA8540_ALT2   0x94
+#define I2C_TDA8540_ALT3   0x96
+#define I2C_TDA8540_ALT4   0x98
+#define I2C_TDA8540_ALT5   0x9a
+#define I2C_TDA8540_ALT6   0x9c
+
+static void ivc120_muxsel(struct bttv *btv, unsigned int input)
+{
+	// Simple maths
+	int key = input % 4;    
+	int matrix = input / 4;
+	
+	dprintk("bttv%d: ivc120_muxsel: Input - %02d | TDA - %02d | In - %02d\n",
+		btv->nr, input, matrix, key);
+	
+	// Handles the input selection on the TDA8540's
+	bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x00,
+		      ((matrix == 3) ? (key | key << 2) : 0x00), 1);
+	bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x00,
+		      ((matrix == 0) ? (key | key << 2) : 0x00), 1);
+	bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x00,
+		      ((matrix == 1) ? (key | key << 2) : 0x00), 1);
+	bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x00,
+		      ((matrix == 2) ? (key | key << 2) : 0x00), 1);
+	
+	// Handles the output enables on the TDA8540's
+	bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x02,
+		      ((matrix == 3) ? 0x03 : 0x00), 1);  // 13 - 16
+	bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x02,
+		      ((matrix == 0) ? 0x03 : 0x00), 1);  // 1-4
+	bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x02,
+		      ((matrix == 1) ? 0x03 : 0x00), 1);  // 5-8 
+	bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x02,
+		      ((matrix == 2) ? 0x03 : 0x00), 1);  // 9-12
+	
+	// Selects MUX0 for input on the 878
+	btaor((0)<<5, ~(3<<5), BT848_IFORM);
+}
+
+
 /* ----------------------------------------------------------------------- */
 /* motherboard chipset specific stuff                                      */
 
@@ -3467,9 +3601,11 @@
 		latency = 0x0A;
 #endif
 
+#if 0
 	/* print which chipset we have */
 	while ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8,dev)))
 		printk(KERN_INFO "bttv: Host bridge is %s\n",pci_name(dev));
+#endif
 
 	/* print warnings about any quirks found */
 	if (triton1)
diff -u linux-2.6.0-test6/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c
--- linux-2.6.0-test6/drivers/media/video/bttv-driver.c	2003-10-06 17:45:59.000000000 +0200
+++ linux/drivers/media/video/bttv-driver.c	2003-10-06 17:48:02.000000000 +0200
@@ -61,14 +61,15 @@
 static int vbi_nr = -1;
 
 static unsigned int fdsr = 0;
-static unsigned int gpint = 1;
 
 /* options */
-static unsigned int combfilter = 0;
-static unsigned int lumafilter = 0;
-static unsigned int automute   = 1;
-static unsigned int chroma_agc = 0;
-static unsigned int adc_crush  = 1;
+static unsigned int combfilter  = 0;
+static unsigned int lumafilter  = 0;
+static unsigned int automute    = 1;
+static unsigned int chroma_agc  = 0;
+static unsigned int adc_crush   = 1;
+static unsigned int vcr_hack    = 0;
+static unsigned int irq_iswitch = 0;
 
 /* API features (turn on/off stuff for testing) */
 static unsigned int sloppy     = 0;
@@ -98,7 +99,6 @@
 MODULE_PARM(vbi_nr,"i");
 
 MODULE_PARM(fdsr,"i");
-MODULE_PARM(gpint,"i");
 
 MODULE_PARM(combfilter,"i");
 MODULE_PARM(lumafilter,"i");
@@ -108,6 +108,10 @@
 MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");
 MODULE_PARM(adc_crush,"i");
 MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
+MODULE_PARM(vcr_hack,"i");
+MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
+MODULE_PARM(irq_iswitch,"i");
+MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler");
 
 MODULE_PARM(sloppy,"i");
 MODULE_PARM(v4l2,"i");
@@ -115,7 +119,6 @@
 MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
 MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(VIDEO_MAJOR);
 
 /* kernel args */
 #ifndef MODULE
@@ -124,6 +127,17 @@
 #endif
 
 /* ----------------------------------------------------------------------- */
+/* sysfs                                                                   */
+
+static ssize_t show_card(struct class_device *cd, char *buf)
+{
+	struct video_device *vfd = to_video_device(cd);
+	struct bttv *btv = dev_get_drvdata(vfd->dev);
+	return sprintf(buf, "%d\n", btv ? btv->type : UNSET);
+}
+static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
+
+/* ----------------------------------------------------------------------- */
 /* static data                                                             */
 
 /* special timing tables from conexant... */
@@ -464,7 +478,8 @@
 #define V4L2_CID_PRIVATE_AUTOMUTE    (V4L2_CID_PRIVATE_BASE + 2)
 #define V4L2_CID_PRIVATE_LUMAFILTER  (V4L2_CID_PRIVATE_BASE + 3)
 #define V4L2_CID_PRIVATE_AGC_CRUSH   (V4L2_CID_PRIVATE_BASE + 4)
-#define V4L2_CID_PRIVATE_LASTP1      (V4L2_CID_PRIVATE_BASE + 5)
+#define V4L2_CID_PRIVATE_VCR_HACK    (V4L2_CID_PRIVATE_BASE + 5)
+#define V4L2_CID_PRIVATE_LASTP1      (V4L2_CID_PRIVATE_BASE + 6)
 
 static const struct v4l2_queryctrl no_ctl = {
 	.name  = "42",
@@ -576,6 +591,12 @@
 		.minimum       = 0,
 		.maximum       = 1,
 		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_PRIVATE_VCR_HACK,
+		.name          = "vcr hack",
+		.minimum       = 0,
+		.maximum       = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
 	}
 };
 const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
@@ -721,7 +742,7 @@
 	int table_idx = bttv_tvnorms[btv->tvnorm].sram;
 	int fsc       = bttv_tvnorms[btv->tvnorm].Fsc;
 
-	if (bttv_tvcards[btv->type].muxsel[btv->input] < 0) {
+	if (UNSET == bttv_tvcards[btv->type].muxsel[btv->input]) {
 		dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
 			btv->nr,table_idx);
 
@@ -815,13 +836,7 @@
 	if (mask2)
 		btaor(mask2,~mask2,BT848_GPIO_OUT_EN);
 
-#if 0
-	/* This seems to get rid of some synchronization problems */
-	btand(~(3<<5), BT848_IFORM);
-	schedule_timeout(HZ/10);
-#endif
-
-	if (input==bttv_tvcards[btv->type].svhs)  {
+	if (input == btv->svhs)  {
 		btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
 		btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
 	} else {
@@ -933,8 +948,21 @@
 static void
 set_input(struct bttv *btv, unsigned int input)
 {
+	unsigned long flags;
+	
 	btv->input = input;
-	video_mux(btv,input);
+	if (irq_iswitch) {
+		spin_lock_irqsave(&btv->s_lock,flags);
+		if (btv->curr.irqflags) {
+			/* active capture -> delayed input switch */
+			btv->new_input = input;
+		} else {
+			video_mux(btv,input);
+		}
+		spin_unlock_irqrestore(&btv->s_lock,flags);
+	} else {
+		video_mux(btv,input);
+	}
 	audio_mux(btv,(input == bttv_tvcards[btv->type].tuner ?
 		       AUDIO_TUNER : AUDIO_EXTERN));
 	set_tvnorm(btv,btv->tvnorm);
@@ -974,6 +1002,16 @@
 		btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
 		btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
 	}
+
+        /* interrupt */
+        btwrite(0xfffffUL, BT848_INT_STAT);
+        btwrite((btv->triton1)  |
+                BT848_INT_GPINT |
+                BT848_INT_SCERR |
+                (fdsr ? BT848_INT_FDSR : 0) |
+                BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
+                BT848_INT_FMTCHG|BT848_INT_HLOCK,
+                BT848_INT_MASK);
 }
 
 extern void bttv_reinit_bt848(struct bttv *btv)
@@ -1053,6 +1091,9 @@
 	case V4L2_CID_PRIVATE_AGC_CRUSH:
 		c->value = btv->opt_adc_crush;
 		break;
+	case V4L2_CID_PRIVATE_VCR_HACK:
+		c->value = btv->opt_vcr_hack;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -1138,6 +1179,9 @@
 		btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
 			BT848_ADC);
 		break;
+	case V4L2_CID_PRIVATE_VCR_HACK:
+		btv->opt_vcr_hack = c->value;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -1281,7 +1325,7 @@
 	/* alloc risc memory */
 	if (STATE_NEEDS_INIT == buf->vb.state) {
 		redo_dma_risc = 1;
-		if (0 != (rc = videobuf_iolock(btv->dev,&buf->vb)))
+		if (0 != (rc = videobuf_iolock(btv->dev,&buf->vb,&btv->fbuf)))
 			goto fail;
 	}
 
@@ -1429,7 +1473,7 @@
                         v->flags|=VIDEO_VC_TUNER;
                         v->type=VIDEO_TYPE_TV;
                         v->tuners=1;
-                } else if (channel == bttv_tvcards[btv->type].svhs) {
+                } else if (channel == btv->svhs) {
                         strcpy(v->name,"S-Video");
                 } else {
                         sprintf(v->name,"Composite%d",channel);
@@ -1562,7 +1606,7 @@
 			sprintf(i->name, "Television");
 			i->type  = V4L2_INPUT_TYPE_TUNER;
 			i->tuner = 0;
-		} else if (i->index==bttv_tvcards[btv->type].svhs) {
+		} else if (i->index == btv->svhs) {
 			sprintf(i->name, "S-Video");
 		} else {
                         sprintf(i->name,"Composite%d",i->index);
@@ -1766,7 +1810,7 @@
 	}
 	/* clip against screen */
 	if (NULL != btv->fbuf.base)
-		n = btcx_screen_clips(btv->fbuf.width, btv->fbuf.width,
+		n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
 				      &win->w, clips, n);
 	btcx_sort_clips(clips,n);
 
@@ -2032,6 +2076,21 @@
 	if (btv->errors)
 		bttv_reinit_bt848(btv);
 
+#ifdef VIDIOC_G_PRIORITY
+	switch (cmd) {
+        case VIDIOCSFREQ:
+        case VIDIOCSTUNER:
+        case VIDIOCSCHAN:
+	case VIDIOC_S_CTRL:
+	case VIDIOC_S_STD:
+	case VIDIOC_S_INPUT:
+	case VIDIOC_S_TUNER:
+	case VIDIOC_S_FREQUENCY:
+		retval = v4l2_prio_check(&btv->prio,&fh->prio);
+		if (0 != retval)
+			return retval;
+	};
+#endif
 	switch (cmd) {
 
 	/* ***  v4l1  *** ************************************************ */
@@ -2040,7 +2099,7 @@
                 struct video_capability *cap = arg;
 
 		memset(cap,0,sizeof(*cap));
-                strcpy(cap->name,btv->video_dev.name);
+                strcpy(cap->name,btv->video_dev->name);
 		if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
 			/* vbi */
 			cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
@@ -2147,7 +2206,13 @@
 	case VIDIOCGFBUF:
 	{
 		struct video_buffer *fbuf = arg;
-		*fbuf = btv->fbuf;
+
+		fbuf->base          = btv->fbuf.base;
+		fbuf->width         = btv->fbuf.fmt.width;
+		fbuf->height        = btv->fbuf.fmt.height;
+		fbuf->bytesperline  = btv->fbuf.fmt.bytesperline;
+		if (fh->ovfmt)
+			fbuf->depth = fh->ovfmt->depth;
 		return 0;
 	}
 	case VIDIOCSFBUF:
@@ -2200,7 +2265,13 @@
 			    fbuf->depth != 24 && fbuf->depth != 32)
 				goto fh_unlock_and_return;
 		}
-		btv->fbuf = *fbuf;
+		btv->fbuf.base             = fbuf->base;
+		btv->fbuf.fmt.width        = fbuf->width;
+		btv->fbuf.fmt.height       = fbuf->height;
+		if (fbuf->bytesperline)
+			btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
+		else
+			btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
 		up(&fh->cap.lock);
 		return 0;
 	}
@@ -2245,7 +2316,8 @@
 		unsigned int i;
 
 		down(&fh->cap.lock);
-		retval = videobuf_mmap_setup(file,&fh->cap,gbuffers,gbufsize);
+		retval = videobuf_mmap_setup(file,&fh->cap,gbuffers,gbufsize,
+					     V4L2_MEMORY_MMAP);
 		if (retval < 0)
 			goto fh_unlock_and_return;
 		memset(mbuf,0,sizeof(*mbuf));
@@ -2391,7 +2463,7 @@
 		if (0 == v4l2)
 			return -EINVAL;
                 strcpy(cap->driver,"bttv");
-                strlcpy(cap->card,btv->video_dev.name,sizeof(cap->card));
+                strlcpy(cap->card,btv->video_dev->name,sizeof(cap->card));
 		sprintf(cap->bus_info,"PCI:%s",pci_name(btv->dev));
 		cap->version = BTTV_VERSION_CODE;
 		cap->capabilities =
@@ -2474,11 +2546,7 @@
 	{
 		struct v4l2_framebuffer *fb = arg;
 
-		memset(fb,0,sizeof(*fb));
-		fb->base       = btv->fbuf.base;
-		fb->fmt.width  = btv->fbuf.width;
-		fb->fmt.height = btv->fbuf.height;
-		fb->fmt.bytesperline = btv->fbuf.bytesperline;
+		*fb = btv->fbuf;
 		fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
 		if (fh->ovfmt)
 			fb->fmt.pixelformat  = fh->ovfmt->fourcc;
@@ -2488,16 +2556,12 @@
 	{
 		struct v4l2_framebuffer *fb = arg;
 		const struct bttv_format *fmt;
-		unsigned long end;
 		
 		if(!capable(CAP_SYS_ADMIN) &&
 		   !capable(CAP_SYS_RAWIO))
 			return -EPERM;
 
 		/* check args */
-		end = (unsigned long)fb->base +
-			fb->fmt.height * fb->fmt.bytesperline;
-		
 		fmt = format_by_fourcc(fb->fmt.pixelformat);
 		if (NULL == fmt)
 			return -EINVAL;
@@ -2514,14 +2578,13 @@
 		}
 
 		/* ok, accept it */
-		btv->fbuf.base   = fb->base;
-		btv->fbuf.width  = fb->fmt.width;
-		btv->fbuf.height = fb->fmt.height;
-		btv->fbuf.depth  = fmt->depth;
+		btv->fbuf.base       = fb->base;
+		btv->fbuf.fmt.width  = fb->fmt.width;
+		btv->fbuf.fmt.height = fb->fmt.height;
 		if (0 != fb->fmt.bytesperline)
-			btv->fbuf.bytesperline = fb->fmt.bytesperline;
+			btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
 		else
-			btv->fbuf.bytesperline = btv->fbuf.width*fmt->depth/8;
+			btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
 		
 		retval = 0;
 		fh->ovfmt = fmt;
@@ -2642,6 +2705,23 @@
 		parm->parm.capture.timeperframe = s.frameperiod;
 		return 0;
 	}
+
+#ifdef VIDIOC_G_PRIORITY
+	case VIDIOC_G_PRIORITY:
+	{
+		enum v4l2_priority *p = arg;
+
+		*p = v4l2_prio_max(&btv->prio);
+		return 0;
+	}
+	case VIDIOC_S_PRIORITY:
+	{
+		enum v4l2_priority *prio = arg;
+
+		return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
+	}
+#endif
+
 	
 	case VIDIOC_ENUMSTD:
 	case VIDIOC_G_STD:
@@ -2768,12 +2848,12 @@
 	dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
 
 	for (i = 0; i < bttv_num; i++) {
-		if (bttvs[i].video_dev.minor == minor) {
+		if (bttvs[i].video_dev->minor == minor) {
 			btv = &bttvs[i];
 			type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 			break;
 		}
-		if (bttvs[i].vbi_dev.minor == minor) {
+		if (bttvs[i].vbi_dev->minor == minor) {
 			btv = &bttvs[i];
 			type = V4L2_BUF_TYPE_VBI_CAPTURE;
 			break;
@@ -2793,6 +2873,10 @@
 	*fh = btv->init;
 	fh->type = type;
 	fh->ov.setup_ok = 0;
+#ifdef VIDIOC_G_PRIORITY
+	v4l2_prio_open(&btv->prio,&fh->prio);
+#endif
+
 	videobuf_queue_init(&fh->cap, &bttv_video_qops,
 			    btv->dev, &btv->s_lock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
@@ -2840,6 +2924,9 @@
 		free_btres(btv,fh,RESOURCE_VBI);
 	}
 
+#ifdef VIDIOC_G_PRIORITY
+	v4l2_prio_close(&btv->prio,&fh->prio);
+#endif
 	file->private_data = NULL;
 	kfree(fh);
 
@@ -2897,13 +2984,12 @@
 {
 	int minor = iminor(inode);
 	struct bttv *btv = NULL;
-	u32 v = 400*16;
 	unsigned int i;
 
 	dprintk("bttv: open minor=%d\n",minor);
 
 	for (i = 0; i < bttv_num; i++) {
-		if (bttvs[i].radio_dev.minor == minor) {
+		if (bttvs[i].radio_dev->minor == minor) {
 			btv = &bttvs[i];
 			break;
 		}
@@ -2921,7 +3007,6 @@
 	file->private_data = btv;
 
 	i2c_vidiocschan(btv);
-	bttv_call_i2c_clients(btv,VIDIOCSFREQ,&v);
         bttv_call_i2c_clients(btv,AUDC_SET_RADIO,&btv->tuner_type);
 	audio_mux(btv,AUDIO_RADIO);
 
@@ -2948,7 +3033,7 @@
                 struct video_capability *cap = arg;
 
 		memset(cap,0,sizeof(*cap));
-                strcpy(cap->name,btv->radio_dev.name);
+                strcpy(cap->name,btv->radio_dev->name);
                 cap->type = VID_TYPE_TUNER;
 		cap->channels = 1;
 		cap->audios = 1;
@@ -3131,7 +3216,7 @@
 	}
 	if (wakeup->top == wakeup->bottom) {
 		if (NULL != wakeup->top && curr->top != wakeup->top) {
-			if (irq_debug)
+			if (irq_debug > 1)
 				printk("bttv%d: wakeup: both=%p\n",btv->nr,wakeup->top);
 			wakeup->top->vb.ts = ts;
 			wakeup->top->vb.field_count = btv->field_count;
@@ -3140,7 +3225,7 @@
 		}
 	} else {
 		if (NULL != wakeup->top && curr->top != wakeup->top) {
-			if (irq_debug)
+			if (irq_debug > 1)
 				printk("bttv%d: wakeup: top=%p\n",btv->nr,wakeup->top);
 			wakeup->top->vb.ts = ts;
 			wakeup->top->vb.field_count = btv->field_count;
@@ -3148,7 +3233,7 @@
 			wake_up(&wakeup->top->vb.done);
 		}
 		if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) {
-			if (irq_debug)
+			if (irq_debug > 1)
 				printk("bttv%d: wakeup: bottom=%p\n",btv->nr,wakeup->bottom);
 			wakeup->bottom->vb.ts = ts;
 			wakeup->bottom->vb.field_count = btv->field_count;
@@ -3247,6 +3332,12 @@
 	bttv_buffer_set_activate(btv, &new);
 	bttv_set_dma(btv, 0, new.irqflags);
 
+	/* switch input */
+	if (UNSET != btv->new_input) {
+		video_mux(btv,btv->new_input);
+		btv->new_input = UNSET;
+	}
+
 	/* wake up finished buffers */
 	bttv_irq_wakeup_set(btv, &old, &new, STATE_DONE);
 	spin_unlock(&btv->s_lock);
@@ -3274,7 +3365,7 @@
 		/* get device status bits */
 		dstat=btread(BT848_DSTATUS);
 
-		if (0 /*irq_debug*/) {
+		if (irq_debug) {
 			printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d "
 			       "riscs=%x, riscc=%08x, ",
 			       btv->nr, count, btv->field_count,
@@ -3295,8 +3386,13 @@
 		if (astat&BT848_INT_VSYNC) 
                         btv->field_count++;
 
-		if (astat & BT848_INT_GPINT)
+		if (astat & BT848_INT_GPINT) {
+#ifdef CONFIG_VIDEO_IR
+			if (btv->remote)
+				bttv_input_irq(btv);
+#endif
 			wake_up(&btv->gpioq);
+		}
 
                 if ((astat & BT848_INT_RISCI)  &&  (stat & (2<<28)))
 			bttv_irq_wakeup_top(btv);
@@ -3325,10 +3421,12 @@
 		}
 
 		count++;
-		if (count > 20) {
+		if (count > 4) {
 			btwrite(0, BT848_INT_MASK);
 			printk(KERN_ERR 
-			       "bttv%d: IRQ lockup, cleared int mask\n", btv->nr);
+			       "bttv%d: IRQ lockup, cleared int mask [", btv->nr);
+			bttv_print_irqbits(stat,astat);
+			printk("]\n");
 		}
 	}
 	return IRQ_RETVAL(handled);
@@ -3338,31 +3436,89 @@
 /* ----------------------------------------------------------------------- */
 /* initialitation                                                          */
 
+static struct video_device *vdev_init(struct bttv *btv,
+				      struct video_device *template,
+				      char *type)
+{
+	struct video_device *vfd;
+
+	vfd = video_device_alloc();
+	if (NULL == vfd)
+		return NULL;
+	*vfd = *template;
+	vfd->minor   = -1;
+	vfd->dev     = &btv->dev->dev;
+	vfd->release = video_device_release;
+	snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
+		 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
+		 type, bttv_tvcards[btv->type].name);
+	return vfd;
+}
+
+static void bttv_unregister_video(struct bttv *btv)
+{
+	if (btv->video_dev) {
+		if (-1 != btv->video_dev->minor)
+			video_unregister_device(btv->video_dev);
+		else
+			video_device_release(btv->video_dev);
+		btv->video_dev = NULL;
+	}
+	if (btv->vbi_dev) {
+		if (-1 != btv->vbi_dev->minor)
+			video_unregister_device(btv->vbi_dev);
+		else
+			video_device_release(btv->vbi_dev);
+		btv->vbi_dev = NULL;
+	}
+	if (btv->radio_dev) {
+		if (-1 != btv->radio_dev->minor)
+			video_unregister_device(btv->radio_dev);
+		else
+			video_device_release(btv->radio_dev);
+		btv->radio_dev = NULL;
+	}
+}
+
 /* register video4linux devices */
 static int __devinit bttv_register_video(struct bttv *btv)
 {
-        if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
-                return -1;
+	/* video */
+	btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
+        if (NULL == btv->video_dev)
+		goto err;
+	if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
+		goto err;
 	printk(KERN_INFO "bttv%d: registered device video%d\n",
-	       btv->nr,btv->video_dev.minor & 0x1f);
+	       btv->nr,btv->video_dev->minor & 0x1f);
+	video_device_create_file(btv->video_dev, &class_device_attr_card);
 
-        if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0) {
-                video_unregister_device(&btv->video_dev);
-                return -1;
-        }
+	/* vbi */
+	btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
+        if (NULL == btv->vbi_dev)
+		goto err;
+        if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
+		goto err;
 	printk(KERN_INFO "bttv%d: registered device vbi%d\n",
-	       btv->nr,btv->vbi_dev.minor & 0x1f);
+	       btv->nr,btv->vbi_dev->minor & 0x1f);
 
         if (!btv->has_radio)
 		return 0;
-	if (video_register_device(&btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0) {
-		video_unregister_device(&btv->vbi_dev);
-		video_unregister_device(&btv->video_dev);
-		return -1;
-        }
+	/* radio */
+	btv->radio_dev = vdev_init(btv, &radio_template, "radio");
+        if (NULL == btv->radio_dev)
+		goto err;
+	if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
+		goto err;
 	printk(KERN_INFO "bttv%d: registered device radio%d\n",
-	       btv->nr,btv->radio_dev.minor & 0x1f);
-        return 0;
+	       btv->nr,btv->radio_dev->minor & 0x1f);
+
+	/* all done */
+	return 0;
+
+ err:
+	bttv_unregister_video(btv);
+	return -1;
 }
 
 
@@ -3401,6 +3557,9 @@
         init_waitqueue_head(&btv->gpioq);
         INIT_LIST_HEAD(&btv->capture);
         INIT_LIST_HEAD(&btv->vcapture);
+#ifdef VIDIOC_G_PRIORITY
+	v4l2_prio_init(&btv->prio);
+#endif
 
 	init_timer(&btv->timeout);
 	btv->timeout.function = bttv_irq_timeout;
@@ -3409,19 +3568,10 @@
         btv->i2c_rc = -1;
         btv->tuner_type  = UNSET;
         btv->pinnacle_id = UNSET;
-
-	memcpy(&btv->video_dev, &bttv_video_template, sizeof(bttv_video_template));
-	memcpy(&btv->radio_dev, &radio_template,      sizeof(radio_template));
-	memcpy(&btv->vbi_dev,   &bttv_vbi_template,   sizeof(bttv_vbi_template));
-        btv->video_dev.minor = -1;
-	btv->video_dev.priv = btv;
-        btv->radio_dev.minor = -1;
-	btv->radio_dev.priv = btv;
-        btv->vbi_dev.minor = -1;
-	btv->vbi_dev.priv = btv;
+	btv->new_input   = UNSET;
 	btv->has_radio=radio[btv->nr];
 	
-	/* pci stuff (init, get irq/mmip, ... */
+	/* pci stuff (init, get irq/mmio, ... */
 	btv->dev = dev;
         btv->id  = dev->device;
 	if (pci_enable_device(dev)) {
@@ -3437,13 +3587,15 @@
 	if (!request_mem_region(pci_resource_start(dev,0),
 				pci_resource_len(dev,0),
 				btv->name)) {
+                printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
+		       btv->nr, pci_resource_start(dev,0));
 		return -EBUSY;
 	}
         pci_set_master(dev);
 	pci_set_command(dev);
 	pci_set_drvdata(dev,btv);
 	if (!pci_dma_supported(dev,0xffffffff)) {
-		printk("bttv: Oops: no 32bit PCI DMA ???\n");
+		printk("bttv%d: Oops: no 32bit PCI DMA ???\n", btv->nr);
 		result = -EIO;
 		goto fail1;
 	}
@@ -3454,13 +3606,14 @@
                bttv_num,btv->id, btv->revision, pci_name(dev));
         printk("irq: %d, latency: %d, mmio: 0x%lx\n",
 	       btv->dev->irq, lat, pci_resource_start(dev,0));
+	schedule();
 	
-#ifdef __sparc__
-	/* why no ioremap for sparc? */
-	btv->bt848_mmio=(unsigned char *)pci_resource_start(dev,0);
-#else
 	btv->bt848_mmio=ioremap(pci_resource_start(dev,0), 0x1000);
-#endif
+	if (NULL == ioremap(pci_resource_start(dev,0), 0x1000)) {
+		printk("bttv%d: ioremap() failed\n", btv->nr);
+		result = -EIO;
+		goto fail1;
+	}
 
         /* identify card */
 	bttv_idcard(btv);
@@ -3486,6 +3639,7 @@
 	btv->opt_automute   = automute;
 	btv->opt_chroma_agc = chroma_agc;
 	btv->opt_adc_crush  = adc_crush;
+	btv->opt_vcr_hack   = vcr_hack;
 	
 	/* fill struct bttv with some useful defaults */
 	btv->init.btv         = btv;
@@ -3502,7 +3656,8 @@
                 bttv_gpio_tracking(btv,"pre-init");
 
 	bttv_risc_init_main(btv);
-	init_bt848(btv);
+	if (!bttv_tvcards[btv->type].no_video)
+		init_bt848(btv);
 
 	/* gpio */
         btwrite(0x00, BT848_GPIO_REG_INP);
@@ -3510,16 +3665,6 @@
         if (bttv_gpio)
                 bttv_gpio_tracking(btv,"init");
 
-        /* interrupt */
-        btwrite(0xfffffUL, BT848_INT_STAT);
-        btwrite((btv->triton1) |
-                (gpint ? BT848_INT_GPINT : 0) |
-                BT848_INT_SCERR|
-                (fdsr ? BT848_INT_FDSR : 0) |
-                BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
-                BT848_INT_FMTCHG|BT848_INT_HLOCK,
-                BT848_INT_MASK);
-	
         /* needs to be done before i2c is registered */
         bttv_init_card1(btv);
 
@@ -3529,15 +3674,20 @@
         /* some card-specific stuff (needs working i2c) */
         bttv_init_card2(btv);
 
-        /* register video4linux */
-        bttv_register_video(btv);
+        /* register video4linux + input */
+	if (!bttv_tvcards[btv->type].no_video) {
+		bttv_register_video(btv);
+#ifdef CONFIG_VIDEO_IR
+		bttv_input_init(btv);
+#endif
 
-	bt848_bright(btv,32768);
-	bt848_contrast(btv,32768);
-	bt848_hue(btv,32768);
-	bt848_sat(btv,32768);
-	audio_mux(btv,AUDIO_MUTE);
-	set_input(btv,0);
+		bt848_bright(btv,32768);
+		bt848_contrast(btv,32768);
+		bt848_hue(btv,32768);
+		bt848_sat(btv,32768);
+		audio_mux(btv,AUDIO_MUTE);
+		set_input(btv,0);
+	}
 
 	/* everything is fine */
 	bttv_num++;
@@ -3547,6 +3697,8 @@
         free_irq(btv->dev->irq,btv);
 	
  fail1:
+	if (btv->bt848_mmio)
+		iounmap(btv->bt848_mmio);
 	release_mem_region(pci_resource_start(btv->dev,0),
 			   pci_resource_len(btv->dev,0));
 	pci_set_drvdata(dev,NULL);
@@ -3572,23 +3724,21 @@
 	btv->shutdown=1;
 	wake_up(&btv->gpioq);
 
-        /* unregister i2c_bus */
-	if (0 == btv->i2c_rc)
-		i2c_bit_del_bus(&btv->i2c_adap);
+        /* unregister i2c_bus + input */
+	fini_bttv_i2c(btv);
+#ifdef CONFIG_VIDEO_IR
+	bttv_input_fini(btv);
+#endif
 
 	/* unregister video4linux */
-        if (btv->video_dev.minor!=-1)
-                video_unregister_device(&btv->video_dev);
-        if (btv->radio_dev.minor!=-1)
-                video_unregister_device(&btv->radio_dev);
-	if (btv->vbi_dev.minor!=-1)
-                video_unregister_device(&btv->vbi_dev);
+	bttv_unregister_video(btv);
 
 	/* free allocated memory */
 	btcx_riscmem_free(btv->dev,&btv->main);
 
 	/* free ressources */
         free_irq(btv->dev->irq,btv);
+	iounmap(btv->bt848_mmio);
         release_mem_region(pci_resource_start(btv->dev,0),
                            pci_resource_len(btv->dev,0));
 
diff -u linux-2.6.0-test6/drivers/media/video/bttv-if.c linux/drivers/media/video/bttv-if.c
--- linux-2.6.0-test6/drivers/media/video/bttv-if.c	2003-10-06 17:44:44.000000000 +0200
+++ linux/drivers/media/video/bttv-if.c	2003-10-06 17:48:02.000000000 +0200
@@ -27,15 +27,23 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 
 #include "bttvp.h"
 
-static struct i2c_algo_bit_data bttv_i2c_algo_template;
-static struct i2c_adapter bttv_i2c_adap_template;
+static struct i2c_algo_bit_data bttv_i2c_algo_bit_template;
+static struct i2c_adapter bttv_i2c_adap_sw_template;
+static struct i2c_adapter bttv_i2c_adap_hw_template;
 static struct i2c_client bttv_i2c_client_template;
 
+#ifndef I2C_PEC
+static void bttv_inc_use(struct i2c_adapter *adap);
+static void bttv_dec_use(struct i2c_adapter *adap);
+#endif
+static int attach_inform(struct i2c_client *client);
+
 EXPORT_SYMBOL(bttv_get_cardinfo);
 EXPORT_SYMBOL(bttv_get_pcidev);
 EXPORT_SYMBOL(bttv_get_id);
@@ -45,6 +53,11 @@
 EXPORT_SYMBOL(bttv_get_gpio_queue);
 EXPORT_SYMBOL(bttv_i2c_call);
 
+static int i2c_debug = 0;
+static int i2c_hw = 0;
+MODULE_PARM(i2c_debug,"i");
+MODULE_PARM(i2c_hw,"i");
+
 /* ----------------------------------------------------------------------- */
 /* Exported functions - for other modules which want to access the         */
 /*                      gpio ports (IR for example)                        */
@@ -76,6 +89,7 @@
 	return bttvs[card].type;
 }
 
+
 int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data)
 {
 	struct bttv *btv;
@@ -146,7 +160,7 @@
 
 
 /* ----------------------------------------------------------------------- */
-/* I2C functions                                                           */
+/* I2C functions - bitbanging adapter (software i2c)                       */
 
 void bttv_bit_setscl(void *data, int state)
 {
@@ -190,6 +204,222 @@
 	return state;
 }
 
+static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = {
+	.setsda  = bttv_bit_setsda,
+	.setscl  = bttv_bit_setscl,
+	.getsda  = bttv_bit_getsda,
+	.getscl  = bttv_bit_getscl,
+	.udelay  = 16,
+	.mdelay  = 10,
+	.timeout = 200,
+};
+
+static struct i2c_adapter bttv_i2c_adap_sw_template = {
+#ifdef I2C_PEC
+	.owner             = THIS_MODULE,
+#else
+	.inc_use           = bttv_inc_use,
+	.dec_use           = bttv_dec_use,
+#endif
+#ifdef I2C_ADAP_CLASS_TV_ANALOG
+	.class             = I2C_ADAP_CLASS_TV_ANALOG,
+#endif
+	I2C_DEVNAME("bt848"),
+	.id                = I2C_HW_B_BT848,
+	.client_register   = attach_inform,
+};
+
+/* ----------------------------------------------------------------------- */
+/* I2C functions - hardware i2c                                            */
+
+static int algo_control(struct i2c_adapter *adapter, 
+			unsigned int cmd, unsigned long arg)
+{
+	return 0;
+}
+
+static u32 functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL;
+}
+
+static int
+bttv_i2c_wait_done(struct bttv *btv)
+{
+	u32 stat;
+	int timeout;
+
+	timeout = jiffies + HZ/100 + 1; /* 10ms */
+	for (;;) {
+		stat = btread(BT848_INT_STAT);
+		if (stat & BT848_INT_I2CDONE)
+			break;
+		if (time_after(jiffies,timeout))
+			return -EIO;
+		udelay(10);
+	}
+	btwrite(BT848_INT_I2CDONE|BT848_INT_RACK, BT848_INT_STAT);
+	return ((stat & BT848_INT_RACK) ? 1 : 0);
+}
+
+#define I2C_HW (BT878_I2C_MODE  | BT848_I2C_SYNC |\
+		BT848_I2C_SCL | BT848_I2C_SDA)
+
+static int
+bttv_i2c_sendbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
+{
+	u32 xmit;
+	int retval,cnt;
+
+	/* start, address + first byte */
+	xmit = (msg->addr << 25) | (msg->buf[0] << 16) | I2C_HW;
+	if (msg->len > 1 || !last)
+		xmit |= BT878_I2C_NOSTOP;
+	btwrite(xmit, BT848_I2C);
+	retval = bttv_i2c_wait_done(btv);
+	if (retval < 0)
+		goto err;
+	if (retval == 0)
+		goto eio;
+	if (i2c_debug) {
+		printk(" <W %02x %02x", msg->addr << 1, msg->buf[0]);
+		if (!(xmit & BT878_I2C_NOSTOP))
+			printk(" >\n");
+	}
+
+	for (cnt = 1; cnt < msg->len; cnt++ ) {
+		/* following bytes */
+		xmit = (msg->buf[cnt] << 24) | I2C_HW | BT878_I2C_NOSTART;
+		if (cnt < msg->len-1 || !last)
+			xmit |= BT878_I2C_NOSTOP;
+		btwrite(xmit, BT848_I2C);
+		retval = bttv_i2c_wait_done(btv);
+		if (retval < 0)
+			goto err;
+		if (retval == 0)
+			goto eio;
+		if (i2c_debug) {
+			printk(" %02x", msg->buf[cnt]);
+			if (!(xmit & BT878_I2C_NOSTOP))
+				printk(" >\n");
+		}
+	}
+	return msg->len;
+
+ eio:
+	retval = -EIO;
+ err:
+	if (i2c_debug)
+		printk(" ERR: %d\n",retval);
+	return retval;
+}
+
+static int
+bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
+{
+	u32 xmit;
+	u32 cnt;
+	int retval;
+
+	for(cnt = 0; cnt < msg->len; cnt++) {
+		xmit = (msg->addr << 25) | (1 << 24) | I2C_HW;
+		if (cnt < msg->len-1)
+			xmit |= BT848_I2C_W3B;
+		if (cnt < msg->len-1 || !last)
+			xmit |= BT878_I2C_NOSTOP;
+		if (cnt)
+			xmit |= BT878_I2C_NOSTART;
+		btwrite(xmit, BT848_I2C);
+		retval = bttv_i2c_wait_done(btv);
+		if (retval < 0)
+			goto err;
+		if (retval == 0)
+			goto eio;
+		msg->buf[cnt] = ((u32)btread(BT848_I2C) >> 8) & 0xff;
+		if (i2c_debug) {
+			if (!(xmit & BT878_I2C_NOSTART))
+				printk(" <R %02x", (msg->addr << 1) +1);
+			printk(" =%02x", msg->buf[cnt]);
+			if (!(xmit & BT878_I2C_NOSTOP))
+				printk(" >\n");
+		}
+	}
+	return msg->len;
+
+ eio:
+	retval = -EIO;
+ err:
+	if (i2c_debug)
+		printk(" ERR: %d\n",retval);
+       	return retval;
+}
+
+int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
+{
+	struct bttv *btv = i2c_get_adapdata(i2c_adap);
+	int retval = 0;
+	int i;
+
+	if (i2c_debug)
+		printk("bt-i2c:");
+	btwrite(BT848_INT_I2CDONE|BT848_INT_RACK, BT848_INT_STAT);
+	for (i = 0 ; i < num; i++) {
+		if (msgs[i].flags & I2C_M_RD) {
+			/* read */
+			retval = bttv_i2c_readbytes(btv, &msgs[i], i+1 == num);
+			if (retval < 0)
+				goto err;
+		} else {
+			/* write */
+			retval = bttv_i2c_sendbytes(btv, &msgs[i], i+1 == num);
+			if (retval < 0)
+				goto err;
+		}
+	}
+	return num;
+
+ err:
+	return retval;
+}
+
+static struct i2c_algorithm bttv_algo = {
+	.name          = "bt878",
+	.id            = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */,
+	.master_xfer   = bttv_i2c_xfer,
+	.algo_control  = algo_control,
+	.functionality = functionality,
+};
+
+static struct i2c_adapter bttv_i2c_adap_hw_template = {
+#ifdef I2C_PEC
+	.owner         = THIS_MODULE,
+#else
+	.inc_use       = bttv_inc_use,
+	.dec_use       = bttv_dec_use,
+#endif
+#ifdef I2C_ADAP_CLASS_TV_ANALOG
+	.class         = I2C_ADAP_CLASS_TV_ANALOG,
+#endif
+	I2C_DEVNAME("bt878"),
+	.id            = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */,
+	.algo          = &bttv_algo,
+	.client_register = attach_inform,
+};
+
+/* ----------------------------------------------------------------------- */
+/* I2C functions - common stuff                                            */
+
+#ifndef I2C_PEC
+static void bttv_inc_use(struct i2c_adapter *adap)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void bttv_dec_use(struct i2c_adapter *adap)
+{
+	MOD_DEC_USE_COUNT;
+}
+#endif
 
 static int attach_inform(struct i2c_client *client)
 {
@@ -221,24 +451,6 @@
 	bttv_call_i2c_clients(&bttvs[card], cmd, arg);
 }
 
-static struct i2c_algo_bit_data bttv_i2c_algo_template = {
-	.setsda  = bttv_bit_setsda,
-	.setscl  = bttv_bit_setscl,
-	.getsda  = bttv_bit_getsda,
-	.getscl  = bttv_bit_getscl,
-	.udelay  = 16,
-	.mdelay  = 10,
-	.timeout = 200,
-};
-
-static struct i2c_adapter bttv_i2c_adap_template = {
-	.owner             = THIS_MODULE,
-	.class             = I2C_ADAP_CLASS_TV_ANALOG,
-	I2C_DEVNAME("bt848"),
-	.id                = I2C_HW_B_BT848,
-	.client_register   = attach_inform,
-};
-
 static struct i2c_client bttv_i2c_client_template = {
 	I2C_DEVNAME("bttv internal"),
         .id       = -1,
@@ -308,28 +520,56 @@
 /* init + register i2c algo-bit adapter */
 int __devinit init_bttv_i2c(struct bttv *btv)
 {
-	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));
+	int use_hw = (btv->id == 878) && i2c_hw;
+
 	memcpy(&btv->i2c_client, &bttv_i2c_client_template,
-	       sizeof(struct i2c_client));
+	       sizeof(bttv_i2c_client_template));
+
+	if (use_hw) {
+		/* bt878 */
+		memcpy(&btv->i2c_adap, &bttv_i2c_adap_hw_template,
+		       sizeof(bttv_i2c_adap_hw_template));
+	} else {
+		/* bt848 */
+		memcpy(&btv->i2c_adap, &bttv_i2c_adap_sw_template,
+		       sizeof(bttv_i2c_adap_sw_template));
+		memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template,
+		       sizeof(bttv_i2c_algo_bit_template));
+		btv->i2c_algo.data = btv;
+		btv->i2c_adap.algo_data = &btv->i2c_algo;
+	}
 
-	sprintf(btv->i2c_adap.name, "bt848 #%d", btv->nr);
 	btv->i2c_adap.dev.parent = &btv->dev->dev;
+	snprintf(btv->i2c_adap.name, sizeof(btv->i2c_adap.name),
+		 "bt%d #%d [%s]", btv->id, btv->nr, use_hw ? "hw" : "sw");
 
-        btv->i2c_algo.data = btv;
         i2c_set_adapdata(&btv->i2c_adap, btv);
-        btv->i2c_adap.algo_data = &btv->i2c_algo;
         btv->i2c_client.adapter = &btv->i2c_adap;
 
-	bttv_bit_setscl(btv,1);
-	bttv_bit_setsda(btv,1);
-
-	btv->i2c_rc = i2c_bit_add_bus(&btv->i2c_adap);
+	if (use_hw) {
+		btv->i2c_rc = i2c_add_adapter(&btv->i2c_adap);
+	} else {
+		bttv_bit_setscl(btv,1);
+		bttv_bit_setsda(btv,1);
+		btv->i2c_rc = i2c_bit_add_bus(&btv->i2c_adap);
+	}
 	return btv->i2c_rc;
 }
 
+int __devexit fini_bttv_i2c(struct bttv *btv)
+{
+	int use_hw = (btv->id == 878) && i2c_hw;
+
+	if (0 != btv->i2c_rc)
+		return 0;
+
+	if (use_hw) {
+		return i2c_del_adapter(&btv->i2c_adap);
+	} else {
+		return i2c_bit_del_bus(&btv->i2c_adap);
+	}
+}
+
 /*
  * Local variables:
  * c-basic-offset: 8
diff -u linux-2.6.0-test6/drivers/media/video/bttv-risc.c linux/drivers/media/video/bttv-risc.c
--- linux-2.6.0-test6/drivers/media/video/bttv-risc.c	2003-10-06 17:45:22.000000000 +0200
+++ linux/drivers/media/video/bttv-risc.c	2003-10-06 17:48:02.000000000 +0200
@@ -33,6 +33,8 @@
 
 #include "bttvp.h"
 
+#define VCR_HACK_LINES 4
+
 /* ---------------------------------------------------------- */
 /* risc code generators                                       */
 
@@ -62,6 +64,9 @@
 	/* scan lines */
 	sg = sglist;
 	for (line = 0; line < lines; line++) {
+		if ((btv->opt_vcr_hack) &&
+		    (line >= (lines - VCR_HACK_LINES)))
+			continue;
 		while (offset >= sg_dma_len(sg)) {
 			offset -= sg_dma_len(sg);
 			sg++;
@@ -136,6 +141,9 @@
 	usg = sglist;
 	vsg = sglist;
 	for (line = 0; line < ylines; line++) {
+		if ((btv->opt_vcr_hack) &&
+		    (line >= (ylines - VCR_HACK_LINES)))
+			continue;
 		switch (vshift) {
 		case 0:  chroma = 1;           break;
 		case 1:  chroma = !(line & 1); break;
@@ -219,8 +227,10 @@
 	instructions  = (ov->nclips + 1) *
 		((skip_even || skip_odd) ? ov->w.height>>1 :  ov->w.height);
 	instructions += 2;
-	if ((rc = btcx_riscmem_alloc(btv->dev,risc,instructions*8)) < 0)
+	if ((rc = btcx_riscmem_alloc(btv->dev,risc,instructions*8)) < 0) {
+		kfree(skips);
 		return rc;
+	}
 
 	/* sync instruction */
 	rp = risc->cpu;
@@ -228,12 +238,18 @@
 	*(rp++) = cpu_to_le32(0);
 
 	addr  = (unsigned long)btv->fbuf.base;
-	addr += btv->fbuf.bytesperline * ov->w.top;
-	addr += ((btv->fbuf.depth+7) >> 3) * ov->w.left;
+	addr += btv->fbuf.fmt.bytesperline * ov->w.top;
+	addr += (fmt->depth >> 3)          * ov->w.left;
 
 	/* scan lines */
 	for (maxy = -1, line = 0; line < ov->w.height;
-	     line++, addr += btv->fbuf.bytesperline) {
+	     line++, addr += btv->fbuf.fmt.bytesperline) {
+		if ((btv->opt_vcr_hack) &&
+		     (line >= (ov->w.height - VCR_HACK_LINES)))
+			continue;
+ 		if ((line%2) == 0  &&  skip_even)
+ 			continue;
+ 		if ((line%2) == 1  &&  skip_odd)
 		if ((line%2) == 0  &&  skip_even)
 			continue;
 		if ((line%2) == 1  &&  skip_odd)
diff -u linux-2.6.0-test6/drivers/media/video/bttv-vbi.c linux/drivers/media/video/bttv-vbi.c
--- linux-2.6.0-test6/drivers/media/video/bttv-vbi.c	2003-10-06 17:45:46.000000000 +0200
+++ linux/drivers/media/video/bttv-vbi.c	2003-10-06 17:48:02.000000000 +0200
@@ -87,7 +87,7 @@
 		return -EINVAL;
 
 	if (STATE_NEEDS_INIT == buf->vb.state) {
-		if (0 != (rc = videobuf_iolock(btv->dev,&buf->vb)))
+		if (0 != (rc = videobuf_iolock(btv->dev, &buf->vb, NULL)))
 			goto fail;
 		if (0 != (rc = vbi_buffer_risc(btv,buf,fh->lines)))
 			goto fail;
diff -u linux-2.6.0-test6/drivers/media/video/bttv.h linux/drivers/media/video/bttv.h
--- linux-2.6.0-test6/drivers/media/video/bttv.h	2003-10-06 17:44:44.000000000 +0200
+++ linux/drivers/media/video/bttv.h	2003-10-06 17:48:02.000000000 +0200
@@ -115,6 +115,8 @@
 #define BTTV_XGUARD         0x67
 #define BTTV_NEBULA_DIGITV  0x68
 #define BTTV_PV143          0x69
+#define BTTV_IVC100         0x6e
+#define BTTV_IVC120         0x6f
 
 /* i2c address list */
 #define I2C_TSA5522        0xc2
@@ -170,6 +172,9 @@
 	unsigned int needs_tvaudio:1;
 	unsigned int msp34xx_alt:1;
 
+	/* flag: video pci function is unused */
+	unsigned int no_video;
+
 	/* other settings */
 	unsigned int pll;
 #define PLL_NONE 0
diff -u linux-2.6.0-test6/drivers/media/video/bttvp.h linux/drivers/media/video/bttvp.h
--- linux-2.6.0-test6/drivers/media/video/bttvp.h	2003-10-06 17:45:13.000000000 +0200
+++ linux/drivers/media/video/bttvp.h	2003-10-06 17:48:02.000000000 +0200
@@ -24,9 +24,8 @@
 #ifndef _BTTVP_H_
 #define _BTTVP_H_
 
-
 #include <linux/version.h>
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,11)
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,12)
 
 #include <linux/types.h>
 #include <linux/wait.h>
@@ -34,9 +33,11 @@
 #include <linux/i2c-algo-bit.h>
 #include <linux/videodev.h>
 #include <linux/pci.h>
+#include <linux/input.h>
 #include <asm/scatterlist.h>
 #include <asm/io.h>
 
+#include <linux/device.h>
 #include <media/video-buf.h>
 #include <media/audiochip.h>
 #include <media/tuner.h>
@@ -44,6 +45,9 @@
 #include "bt848.h"
 #include "bttv.h"
 #include "btcx-risc.h"
+#ifdef CONFIG_VIDEO_IR
+#include "ir-common.h"
+#endif
 
 #ifdef __KERNEL__
 
@@ -142,6 +146,9 @@
 struct bttv_fh {
 	struct bttv              *btv;
 	int resources;
+#ifdef VIDIOC_G_PRIORITY 
+	enum v4l2_priority       prio;
+#endif
 	enum v4l2_buf_type       type;
 
 	/* video capture */
@@ -211,6 +218,12 @@
 
 extern struct videobuf_queue_ops bttv_vbi_qops;
 
+/* ---------------------------------------------------------- */
+/* bttv-input.c                                               */
+
+int bttv_input_init(struct bttv *btv);
+void bttv_input_fini(struct bttv *btv);
+void bttv_input_irq(struct bttv *btv);
 
 /* ---------------------------------------------------------- */
 /* bttv-driver.c                                              */
@@ -221,6 +234,7 @@
 extern unsigned int bttv_gpio;
 extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
 extern int init_bttv_i2c(struct bttv *btv);
+extern int fini_bttv_i2c(struct bttv *btv);
 extern int pvr_boot(struct bttv *btv);
 
 extern int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg);
@@ -249,6 +263,18 @@
 	unsigned int pll_current;  /* Currently programmed ofreq */
 };
 
+#ifdef CONFIG_VIDEO_IR
+/* for gpio-connected remote control */
+struct bttv_input {
+	struct input_dev      dev;
+	struct ir_input_state ir;
+	char                  name[32];
+	char                  phys[32];
+	u32                   mask_keycode;
+	u32                   mask_keydown;
+};
+#endif
+
 struct bttv {
 	/* pci device config */
 	struct pci_dev *dev;
@@ -263,6 +289,7 @@
 	unsigned int type;     /* card type (pointer into tvcards[])  */
         unsigned int tuner_type;  /* tuner chip type */
         unsigned int pinnacle_id;
+	unsigned int svhs;
 	struct bttv_pll_info pll;
 	int triton1;
 
@@ -278,22 +305,31 @@
 	int                        i2c_state, i2c_rc;
 
 	/* video4linux (1) */
-	struct video_device video_dev;
-	struct video_device radio_dev;
-	struct video_device vbi_dev;
+	struct video_device *video_dev;
+	struct video_device *radio_dev;
+	struct video_device *vbi_dev;
+
+	/* infrared remote */
+	int has_remote;
+#ifdef CONFIG_VIDEO_IR
+	struct bttv_input *remote;
+#endif
 
 	/* locking */
 	spinlock_t s_lock;
         struct semaphore lock;
 	int resources;
         struct semaphore reslock;
-
+#ifdef VIDIOC_G_PRIORITY 
+	struct v4l2_prio_state prio;
+#endif
+	
 	/* video state */
 	unsigned int input;
 	unsigned int audio;
 	unsigned long freq;
 	int tvnorm,hue,contrast,bright,saturation;
-	struct video_buffer fbuf;
+	struct v4l2_framebuffer fbuf;
 	unsigned int field_count;
 
 	/* various options */
@@ -302,6 +338,7 @@
 	int opt_automute;
 	int opt_chroma_agc;
 	int opt_adc_crush;
+	int opt_vcr_hack;
 
 	/* radio data/state */
 	int has_radio;
@@ -329,6 +366,7 @@
 	struct list_head        capture;    /* video capture queue */
 	struct list_head        vcapture;   /* vbi capture queue   */
 	struct bttv_buffer_set  curr;       /* active buffers      */
+	int                     new_input;
 
 	unsigned long cap_ctl;
 	unsigned long dma_on;

-- 
You have a new virus in /var/mail/kraxel

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [patch] v4l: bttv driver update
  2003-10-07 10:58 [patch] v4l: bttv driver update Gerd Knorr
@ 2003-10-07 20:15 ` Pavel Machek
  2003-10-08  8:09   ` Gerd Knorr
  0 siblings, 1 reply; 6+ messages in thread
From: Pavel Machek @ 2003-10-07 20:15 UTC (permalink / raw)
  To: Gerd Knorr; +Cc: Linus Torvalds, Andrew Morton, Kernel List

Hi!

> This patch updates the bttv driver.  It depends on the videobuf patch.
> Changes:
> 
>   * usual tv card list updates.
>   * sysfs adaptions.
>   * new, experimental i2c adapter code for bt878 chips
>     (not used by default yet).
>   * various minor fixes.
> 
> Please apply,

Are those "IR remote using input layer" patches going in?
								Pavel

-- 
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [patch] v4l: bttv driver update
  2003-10-07 20:15 ` Pavel Machek
@ 2003-10-08  8:09   ` Gerd Knorr
  0 siblings, 0 replies; 6+ messages in thread
From: Gerd Knorr @ 2003-10-08  8:09 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Linus Torvalds, Andrew Morton, Kernel List

> > Please apply,
> 
> Are those "IR remote using input layer" patches going in?

Not yet, probably with the next batch of updates.

  Gerd

-- 
You have a new virus in /var/mail/kraxel

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [patch] v4l: bttv driver update
@ 2004-04-05 12:20 Gerd Knorr
  0 siblings, 0 replies; 6+ messages in thread
From: Gerd Knorr @ 2004-04-05 12:20 UTC (permalink / raw)
  To: Andrew Morton, Kernel List, video4linux list

  Hi,

This patch updates the bttv driver.  Changes:

  (1) several card-specific tweaks.
  (2) make software vs. hardware i2c configurable per TV card.
  (3) reinitialize image parameters after chip reset.
  (4) make bttv quite by default on frame drops.
  (5) new insmod option: "debug_latency=1" to enable frame drop
      debug messages.

bttv is quite sensitive to irq latencies, especially when capturing
both video and vbi.  There are several reports about problems due to
this, I don't see that on my machines through.  (5) dumps a stracktrace
if the driver thinks the frame drop is is caused by high latencies as
experiment, lets see whenever that helps ...

  Gerd

diff -up linux-2.6.5/drivers/media/video/bttv-cards.c linux/drivers/media/video/bttv-cards.c
--- linux-2.6.5/drivers/media/video/bttv-cards.c	2004-04-05 10:40:46.550267112 +0200
+++ linux/drivers/media/video/bttv-cards.c	2004-04-05 10:49:58.083249103 +0200
@@ -57,6 +57,7 @@ static void avermedia_tv_stereo_audio(st
 				      int set);
 static void terratv_audio(struct bttv *btv, struct video_audio *v, int set);
 static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set);
+static void gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set);
 static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set);
 static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set);
 static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set);
@@ -68,6 +69,8 @@ static void xguard_muxsel(struct bttv *b
 static void ivc120_muxsel(struct bttv *btv, unsigned int input);
 static void gvc1100_muxsel(struct bttv *btv, unsigned int input);
 
+static void PXC200_muxsel(struct bttv *btv, unsigned int input);
+
 static int terratec_active_radio_upgrade(struct bttv *btv);
 static int tea5757_read(struct bttv *btv);
 static int tea5757_write(struct bttv *btv, int value);
@@ -118,7 +121,7 @@ MODULE_PARM(remote,"1-" __stringify(BTTV
 
 MODULE_PARM(gpiomask,"i");
 MODULE_PARM(audioall,"i");
-MODULE_PARM(audiomux,"1-5i");
+MODULE_PARM(audiomux,"1-6i");
 
 /* kernel args */
 #ifndef MODULE
@@ -169,7 +172,7 @@ static struct CARD {
  	{ 0x402010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCTV3/PCI" },
 	{ 0x405010fc, BTTV_GVBCTV4PCI,    "I-O Data Co. GV-BCTV4/PCI" },
 	{ 0x407010fc, BTTV_GVBCTV5PCI,    "I-O Data Co. GV-BCTV5/PCI" },
- 	{ 0xd01810fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCTV3/PCI" },
+ 	{ 0xd01810fc, BTTV_GVBCTV5PCI,    "I-O Data Co. GV-BCTV5/PCI" },
 
 	{ 0x001211bd, BTTV_PINNACLE,      "Pinnacle PCTV" },
 	{ 0x001c11bd, BTTV_PINNACLESAT,   "Pinnacle PCTV Sat" },
@@ -204,7 +207,8 @@ static struct CARD {
 	//{ 0x18521852, BTTV_TERRATV,     "Terratec TV+ (V1.10)"    },
 	{ 0x1134153b, BTTV_TERRATVALUE,   "Terratec TValue (LR102)" },
 	{ 0x1135153b, BTTV_TERRATVALUER,  "Terratec TValue Radio" }, // LR102
-	{ 0x5018153b, BTTV_TERRATVALUE,   "Terratec TValue" }, // ??
+	{ 0x5018153b, BTTV_TERRATVALUE,   "Terratec TValue" },       // ??
+	{ 0xff3b153b, BTTV_TERRATVALUER,  "Terratec TValue Radio" }, // ??
 
 	{ 0x400015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
 	{ 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
@@ -270,6 +274,8 @@ static struct CARD {
 	{ 0xa0fca1a0, BTTV_ZOLTRIX,       "Face to Face Tvmax" },
 	{ 0x20007063, BTTV_PC_HDTV,       "pcHDTV HD-2000 TV"},
 	{ 0x82b2aa6a, BTTV_SIMUS_GVC1100, "SIMUS GVC1100" },
+	{ 0x146caa0c, BTTV_PV951,         "ituner spectra8" },
+ 	{ 0x200a1295, BTTV_PXC200,        "ImageNation PXC200A" },
 
 	{ 0x40111554, BTTV_PV_BT878P_9B,  "Prolink Pixelview PV-BT" },
 	{ 0x17de0a01, BTTV_KWORLD,        "Mecer TV/FM/Video Tuner" },
@@ -281,6 +287,7 @@ static struct CARD {
 	{ 0x01010071, BTTV_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
 	{ 0x002611bd, BTTV_TWINHAN_DST,   "Pinnacle PCTV SAT CI" },
 	{ 0x00011822, BTTV_TWINHAN_DST,   "Twinhan VisionPlus DVB-T" },
+	{ 0xfc00270f, BTTV_TWINHAN_DST,   "ChainTech digitop DST-1000 DVB-S" },
 	
 	{ 0, -1, NULL }
 };
@@ -597,6 +604,7 @@ struct tvcard bttv_tvcards[] = {
 	.needs_tvaudio	= 1,
 	.pll		= PLL_28,
 	.tuner_type	= -1,
+	.has_remote     = 1,
 },{
 	.name           = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar",
 	.video_inputs	= 3,
@@ -688,6 +696,8 @@ struct tvcard bttv_tvcards[] = {
 	.audiomux	= { 0 },
 	.needs_tvaudio	= 1,
 	.tuner_type	= -1,
+	.muxsel_hook    = PXC200_muxsel,
+
 },{
 	.name		= "Lifeview FlyVideo 98 LR50",
 	.video_inputs	= 4,
@@ -741,9 +751,15 @@ struct tvcard bttv_tvcards[] = {
 	.audio_inputs	= 1,
 	.tuner		= 0,
 	.svhs		= 2,
-	.gpiomask	= 0xc33000,
 	.muxsel		= { 2, 3, 1, 1, 0}, // TV, CVid, SVid, CVid over SVid connector
-	.audiomux	= { 0x422000,0x1000,0x0000,0x620000,0x800000},
+#if 0
+	.gpiomask	= 0xc33000,
+	.audiomux	= { 0x422000,0x1000,0x0000,0x620000,0x800000 },
+#else
+	/* Alexander Varakin <avarakin@hotmail.com> [stereo version] */
+	.gpiomask	= 0xb33000,
+	.audiomux	= { 0x122000,0x1000,0x0000,0x620000,0x800000 },
+#endif
 	/* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
 		gpio23 -- hef4052:nEnable (0x800000)
 		gpio12 -- hef4052:A1
@@ -810,6 +826,7 @@ struct tvcard bttv_tvcards[] = {
 	.needs_tvaudio	= 1,
 	.pll		= PLL_28,
 	.tuner_type	= 1,
+	.has_remote     = 1,
 },{
 	.name		= "Pinnacle PCTV Studio/Rave",
 	.video_inputs	= 3,
@@ -819,7 +836,7 @@ struct tvcard bttv_tvcards[] = {
 	.gpiomask	= 0x03000F,
 	.muxsel		= { 2, 3, 1, 1},
 	.audiomux	= { 2, 0, 0, 0, 1},
-	.needs_tvaudio	= 1,
+	.needs_tvaudio	= 0,
 	.pll		= PLL_28,
 	.tuner_type	= -1,
 },{
@@ -968,6 +985,7 @@ struct tvcard bttv_tvcards[] = {
 	.no_msp34xx	= 1,
 	.pll		= PLL_28,
 	.tuner_type	= TUNER_PHILIPS_PAL_I,
+	.has_remote	= 1,
 	/* GPIO wiring: (different from Rev.4C !)
 		GPIO17: U4.A0 (first hef4052bt)
 		GPIO19: U4.A1
@@ -1009,7 +1027,7 @@ struct tvcard bttv_tvcards[] = {
 			   MUX2 (mask 0x30000):
 				0,2,3= from MSP34xx
 				1= FM stereo Radio from Tuner */
-	.needs_tvaudio  = 1,
+	.needs_tvaudio  = 0,
 	.pll            = PLL_28,
 	.tuner_type     = -1,
 },{
@@ -1448,11 +1466,11 @@ struct tvcard bttv_tvcards[] = {
 	.svhs           = 2,
 	.gpiomask       = 0x0f0f80,
 	.muxsel         = {2, 3, 1, 0},
-	.audiomux       = {0x030000, 0x010000, 0x030000, 0, 0x020000, 0},
+	.audiomux       = {0x030000, 0x010000, 0, 0, 0x020000, 0},
 	.no_msp34xx     = 1,
 	.pll            = PLL_28,
 	.tuner_type     = TUNER_PHILIPS_NTSC_M,
-	.audio_hook     = gvbctv3pci_audio,
+	.audio_hook     = gvbctv5pci_audio,
 	.has_radio      = 1,
 },{
 	.name           = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
@@ -1774,6 +1792,8 @@ struct tvcard bttv_tvcards[] = {
 
 	/* ---- card 0x68 ---------------------------------- */
 	.name           = "Nebula Electronics DigiTV",
+	.video_inputs   = 1,
+        .tuner          = -1,
 	.svhs           = -1,
 	.muxsel         = { 2, 3, 1, 0},
 	.no_msp34xx     = 1,
@@ -1961,6 +1981,37 @@ struct tvcard bttv_tvcards[] = {
         .no_tda9875     = 1,
         .no_tda7432     = 1,
         .needs_tvaudio  = 0,
+},{
+	/* Helmroos Harri <harri.helmroos@pp.inet.fi> */
+	.name           = "Tekram M205 PRO",
+	.video_inputs   = 3,
+	.audio_inputs   = 1,
+	.tuner          = 0,
+	.tuner_type     = TUNER_PHILIPS_PAL,
+	.svhs           = 2,
+	.needs_tvaudio  = 0,
+	.gpiomask       = 0x68,
+	.muxsel         = { 2, 3, 1},
+	.audiomux       = { 0x68, 0x68, 0x61, 0x61, 0x00 },
+	.pll            = PLL_28,
+},{
+
+	/* ---- card 0x78 ---------------------------------- */
+	/* Javier Cendan Ares <jcendan@lycos.es> */
+	/* bt878 TV + FM without subsystem ID */
+	.name           = "Conceptronic CONTVFMi",
+	.video_inputs   = 3,
+	.audio_inputs   = 1,
+	.tuner          = 0,
+	.svhs           = 2,
+	.gpiomask       = 0x008007,
+	.muxsel         = { 2, 3, 1, 1 },
+	.audiomux       = { 0, 1, 2, 2, 3 },
+	.needs_tvaudio  = 0,
+	.pll            = PLL_28,
+	.tuner_type     = TUNER_PHILIPS_PAL,
+	.has_remote     = 1,
+	.has_radio      = 1,
 }};
 
 const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -2329,6 +2380,9 @@ void __devinit bttv_init_card1(struct bt
 	case BTTV_HAUPPAUGEPVR:
 		pvr_boot(btv);
 		break;
+	case BTTV_TWINHAN_DST:
+		btv->use_i2c_hw = 1;
+		break;
 	}
 }
 
@@ -3032,7 +3086,7 @@ static void __devinit init_PXC200(struct
 	u32 val;
 	
 	/* Initialise GPIO-connevted stuff */
-	gpio_bits(0xffffff, (1<<13));
+	gpio_inout(0xffffff, (1<<13));
 	gpio_write(0);
 	udelay(3);
 	gpio_write(1<<13);
@@ -3340,6 +3394,61 @@ gvbctv3pci_audio(struct bttv *btv, struc
 	}
 }
 
+static void
+gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+	unsigned int val, con;
+
+#if BTTV_VERSION_CODE > KERNEL_VERSION(0,8,0)
+	if (btv->radio_user)
+		return;
+#else
+	if (btv->radio)
+		return;
+#endif
+
+	val = gpio_read();
+	if (set) {
+		con = 0x000;
+		if (v->mode & VIDEO_SOUND_LANG2) {
+			if (v->mode & VIDEO_SOUND_LANG1) {
+				/* LANG1 + LANG2 */
+				con = 0x100;
+			}
+			else {
+				/* LANG2 */
+				con = 0x300;
+			}
+		}
+		if (con != (val & 0x300)) {
+			gpio_bits(0x300, con);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"gvbctv5pci");
+		}
+	} else {
+		switch (val & 0x70) {
+		  case 0x10:
+			v->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+			break;
+		  case 0x30:
+			v->mode = VIDEO_SOUND_LANG2;
+			break;
+		  case 0x50:
+			v->mode = VIDEO_SOUND_LANG1;
+			break;
+		  case 0x60:
+			v->mode = VIDEO_SOUND_STEREO;
+			break;
+		  case 0x70:
+			v->mode = VIDEO_SOUND_MONO;
+			break;
+		  default:
+			v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+				  VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+		}
+	}
+}
+
 /*
  * Mario Medina Nussbaum <medisoft@alohabbs.org.mx>
  *  I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo,
@@ -3830,6 +3939,86 @@ int __devinit bttv_handle_chipset(struct
 }
 
 
+/* PXC200 muxsel helper 
+ * luke@syseng.anu.edu.au
+ * another transplant 
+ * from Alessandro Rubini (rubini@linux.it)
+ *
+ * There are 4 kinds of cards:
+ * PXC200L which is bt848 
+ * PXC200F which is bt848 with PIC controlling mux
+ * PXC200AL which is bt878 
+ * PXC200AF which is bt878 with PIC controlling mux
+ */
+#define PX_CFG_PXC200F 0x01
+#define PX_FLAG_PXC200A  0x00001000 /* a pxc200A is bt-878 based */
+#define PX_I2C_PIC       0x0f
+#define PX_PXC200A_CARDID 0x200a1295
+#define PX_I2C_CMD_CFG   0x00
+
+static void PXC200_muxsel(struct bttv *btv, unsigned int input)
+{
+        int rc;
+	long mux;
+	int bitmask;
+        unsigned char buf[2];
+
+	/* Read PIC config to determine if this is a PXC200F */
+	/* PX_I2C_CMD_CFG*/
+	buf[0]=0;
+	buf[1]=0;
+	rc=bttv_I2CWrite(btv,(PX_I2C_PIC<<1),buf[0],buf[1],1);
+	if (rc) {
+	  printk(KERN_DEBUG "bttv%d: PXC200_muxsel: pic cfg write failed:%d\n", btv->c.nr,rc);
+	  /* not PXC ? do nothing */
+	  return;
+	}
+
+	rc=bttv_I2CRead(btv,(PX_I2C_PIC<<1),0);
+	if (!(rc & PX_CFG_PXC200F)) {
+	  printk(KERN_DEBUG "bttv%d: PXC200_muxsel: not PXC200F rc:%d \n", btv->c.nr,rc);
+	  return;
+	}
+
+
+	/* The multiplexer in the 200F is handled by the GPIO port */
+	/* get correct mapping between inputs  */
+	/*  mux = bttv_tvcards[btv->type].muxsel[input] & 3; */
+	/* ** not needed!?   */
+	mux = input;
+  
+	/* make sure output pins are enabled */
+	/* bitmask=0x30f; */
+	bitmask=0x302; 
+	/* check whether we have a PXC200A */
+ 	if (btv->cardid == PX_PXC200A_CARDID)  {
+	   bitmask ^= 0x180; /* use 7 and 9, not 8 and 9 */
+	   bitmask |= 7<<4; /* the DAC */
+	}
+	btwrite(bitmask, BT848_GPIO_OUT_EN);
+
+	bitmask = btread(BT848_GPIO_DATA);
+ 	if (btv->cardid == PX_PXC200A_CARDID) 
+	  bitmask = (bitmask & ~0x280) | ((mux & 2) << 8) | ((mux & 1) << 7);
+	else /* older device */
+	  bitmask = (bitmask & ~0x300) | ((mux & 3) << 8);
+	btwrite(bitmask,BT848_GPIO_DATA);
+
+	/*
+	 * Was "to be safe, set the bt848 to input 0"
+	 * Actually, since it's ok at load time, better not messing
+	 * with these bits (on PXC200AF you need to set mux 2 here)
+	 * 
+	 * needed because bttv-driver sets mux before calling this function
+	 */
+ 	if (btv->cardid == PX_PXC200A_CARDID) 
+	  btaor(2<<5, ~BT848_IFORM_MUXSEL, BT848_IFORM);
+	else /* older device */
+	  btand(~BT848_IFORM_MUXSEL,BT848_IFORM);
+
+	printk(KERN_DEBUG "bttv%d: setting input channel to:%d\n", btv->c.nr,(int)mux);
+}
+
 /*
  * Local variables:
  * c-basic-offset: 8
diff -up linux-2.6.5/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c
--- linux-2.6.5/drivers/media/video/bttv-driver.c	2004-04-05 10:42:21.954266410 +0200
+++ linux/drivers/media/video/bttv-driver.c	2004-04-05 10:49:58.091247596 +0200
@@ -59,6 +59,7 @@ static unsigned int gbufsize = 0x208000;
 static int video_nr = -1;
 static int radio_nr = -1;
 static int vbi_nr = -1;
+static int debug_latency = 0;
 
 static unsigned int fdsr = 0;
 
@@ -98,6 +99,7 @@ MODULE_PARM_DESC(gbufsize,"size of the c
 MODULE_PARM(video_nr,"i");
 MODULE_PARM(radio_nr,"i");
 MODULE_PARM(vbi_nr,"i");
+MODULE_PARM(debug_latency,"i");
 
 MODULE_PARM(fdsr,"i");
 
@@ -795,6 +797,7 @@ static void bt848_bright(struct bttv *bt
 {
 	int value;
 
+	// printk("bttv: set bright: %d\n",bright); // DEBUG
 	btv->bright = bright;
 
 	/* We want -128 to 127 we get 0-65535 */
@@ -1048,6 +1051,11 @@ static void init_bt848(struct bttv *btv)
 	btwrite(whitecrush_upper, BT848_WC_UP);
 	btwrite(whitecrush_lower, BT848_WC_DOWN);
 
+	bt848_bright(btv,   btv->bright);
+	bt848_hue(btv,      btv->hue);
+	bt848_contrast(btv, btv->contrast);
+	bt848_sat(btv,      btv->saturation);
+
 	if (btv->opt_lumafilter) {
 		btwrite(0, BT848_E_CONTROL);
 		btwrite(0, BT848_O_CONTROL);
@@ -2170,13 +2178,13 @@ static int bttv_do_ioctl(struct inode *i
 				VID_TYPE_OVERLAY|
 				VID_TYPE_CLIPPING|
 				VID_TYPE_SCALES;
-			cap->channels  = bttv_tvcards[btv->c.type].video_inputs;
-			cap->audios    = bttv_tvcards[btv->c.type].audio_inputs;
 			cap->maxwidth  = bttv_tvnorms[btv->tvnorm].swidth;
 			cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
 			cap->minwidth  = 48;
 			cap->minheight = 32;
 		}
+		cap->channels  = bttv_tvcards[btv->c.type].video_inputs;
+		cap->audios    = bttv_tvcards[btv->c.type].audio_inputs;
                 return 0;
 	}
 
@@ -3155,10 +3163,27 @@ static struct video_device radio_templat
 /* ----------------------------------------------------------------------- */
 /* irq handler                                                             */
 
-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 char *irq_name[] = {
+	"FMTCHG",  // format change detected (525 vs. 625)
+	"VSYNC",   // vertical sync (new field)
+	"HSYNC",   // horizontal sync
+	"OFLOW",   // chroma/luma AGC overflow
+	"HLOCK",   // horizontal lock changed
+	"VPRES",   // video presence changed
+	"6", "7",
+	"I2CDONE", // hw irc operation finished
+	"GPINT",   // gpio port triggered irq
+	"10",
+	"RISCI",   // risc instruction triggered irq
+	"FBUS",    // pixel data fifo dropped data (high pci bus latencies)
+	"FTRGT",   // pixel data fifo overrun
+	"FDSR",    // fifo data stream resyncronisation
+	"PPERR",   // parity error (data transfer)
+	"RIPERR",  // parity error (read risc instructions)
+	"PABORT",  // pci abort
+	"OCERR",   // risc instruction error
+	"SCERR",   // syncronisation error
+};
 
 static void bttv_print_irqbits(u32 print, u32 mark)
 {
@@ -3188,6 +3213,28 @@ static void bttv_print_riscaddr(struct b
 	       btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
 }
 
+static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
+{
+	printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
+	       btv->c.nr,
+	       (unsigned long)btv->main.dma,
+	       (unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1],
+	       (unsigned long)btv->main.cpu[RISC_SLOT_O_FIELD+1],
+	       (unsigned long)rc);
+
+	if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
+		printk("bttv%d: Oh, there (temporarely?) is no input signal. "
+		       "Ok, then this is harmless, don't worry ;)",
+		       btv->c.nr);
+		return;
+	}
+	printk("bttv%d: Uhm. Looks like we have unusual high IRQ latencies.\n",
+	       btv->c.nr);
+	printk("bttv%d: Lets try to catch the culpit red-handed ...\n",
+	       btv->c.nr);
+	dump_stack();
+}
+
 static int
 bttv_irq_next_set(struct bttv *btv, struct bttv_buffer_set *set)
 {
@@ -3306,8 +3353,8 @@ static void bttv_irq_timeout(unsigned lo
 	unsigned long flags;
 	
 	if (bttv_verbose) {
-		printk(KERN_INFO "bttv%d: timeout: irq=%d/%d, risc=%08x, ",
-		       btv->c.nr, btv->irq_me, btv->irq_total,
+		printk(KERN_INFO "bttv%d: timeout: drop=%d irq=%d/%d, risc=%08x, ",
+		       btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total,
 		       btread(BT848_RISC_COUNT));
 		bttv_print_irqbits(btread(BT848_INT_STAT),0);
 		printk("\n");
@@ -3376,14 +3423,9 @@ bttv_irq_switch_fields(struct bttv *btv)
 	bttv_irq_next_set(btv, &new);
 	rc = btread(BT848_RISC_COUNT);
 	if (rc < btv->main.dma || rc > btv->main.dma + 0x100) {
-		if (1 /* irq_debug */)
-			printk("bttv%d: skipped frame. no signal? high irq latency? "
-			       "[main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
-			       btv->c.nr,
-			       (unsigned long)btv->main.dma,
-			       (unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1],
-			       (unsigned long)btv->main.cpu[RISC_SLOT_O_FIELD+1],
-			       (unsigned long)rc);
+		btv->framedrop++;
+		if (debug_latency)
+			bttv_irq_debug_low_latency(btv, rc);
 		spin_unlock(&btv->s_lock);
 		return;
 	}
@@ -3870,11 +3912,6 @@ static int bttv_resume(struct pci_dev *p
 	gpio_inout(0xffffff, btv->state.gpio_enable);
 	gpio_write(btv->state.gpio_data);
 
-	bt848_bright(btv,   btv->bright);
-	bt848_hue(btv,      btv->hue);
-	bt848_contrast(btv, btv->contrast);
-	bt848_sat(btv,      btv->saturation);
-
 	/* restart dma */
 	spin_lock_irqsave(&btv->s_lock,flags);
 	btv->curr = btv->state.set;
diff -up linux-2.6.5/drivers/media/video/bttv-i2c.c linux/drivers/media/video/bttv-i2c.c
--- linux-2.6.5/drivers/media/video/bttv-i2c.c	2004-04-05 10:39:01.000000000 +0200
+++ linux/drivers/media/video/bttv-i2c.c	2004-04-05 10:49:58.096246654 +0200
@@ -414,12 +414,12 @@ void __devinit bttv_readee(struct bttv *
 /* init + register i2c algo-bit adapter */
 int __devinit init_bttv_i2c(struct bttv *btv)
 {
-	int use_hw = (btv->id == 878) && i2c_hw;
-
 	memcpy(&btv->i2c_client, &bttv_i2c_client_template,
 	       sizeof(bttv_i2c_client_template));
 
-	if (use_hw) {
+	if (i2c_hw)
+		btv->use_i2c_hw = 1;
+	if (btv->use_i2c_hw) {
 		/* bt878 */
 		memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_hw_template,
 		       sizeof(bttv_i2c_adap_hw_template));
@@ -435,12 +435,13 @@ int __devinit init_bttv_i2c(struct bttv 
 
 	btv->c.i2c_adap.dev.parent = &btv->c.pci->dev;
 	snprintf(btv->c.i2c_adap.name, sizeof(btv->c.i2c_adap.name),
-		 "bt%d #%d [%s]", btv->id, btv->c.nr, use_hw ? "hw" : "sw");
+		 "bt%d #%d [%s]", btv->id, btv->c.nr,
+		 btv->use_i2c_hw ? "hw" : "sw");
 
         i2c_set_adapdata(&btv->c.i2c_adap, btv);
         btv->i2c_client.adapter = &btv->c.i2c_adap;
 
-	if (use_hw) {
+	if (btv->use_i2c_hw) {
 		btv->i2c_rc = i2c_add_adapter(&btv->c.i2c_adap);
 	} else {
 		bttv_bit_setscl(btv,1);
@@ -452,12 +453,10 @@ int __devinit init_bttv_i2c(struct bttv 
 
 int __devexit fini_bttv_i2c(struct bttv *btv)
 {
-	int use_hw = (btv->id == 878) && i2c_hw;
-
 	if (0 != btv->i2c_rc)
 		return 0;
 
-	if (use_hw) {
+	if (btv->use_i2c_hw) {
 		return i2c_del_adapter(&btv->c.i2c_adap);
 	} else {
 		return i2c_bit_del_bus(&btv->c.i2c_adap);
diff -up linux-2.6.5/drivers/media/video/bttvp.h linux/drivers/media/video/bttvp.h
--- linux-2.6.5/drivers/media/video/bttvp.h	2004-04-05 10:40:16.129007364 +0200
+++ linux/drivers/media/video/bttvp.h	2004-04-05 10:50:14.831092839 +0200
@@ -25,7 +25,7 @@
 #define _BTTVP_H_
 
 #include <linux/version.h>
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,12)
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,14)
 
 #include <linux/types.h>
 #include <linux/wait.h>
@@ -298,6 +298,7 @@ struct bttv {
 	struct bttv_pll_info pll;
 	int triton1;
 	int gpioirq;
+	int use_i2c_hw;
 
 	/* old gpio interface */
 	wait_queue_head_t gpioq;
@@ -384,9 +385,10 @@ struct bttv {
 	struct bttv_suspend_state state;
 
 	/* stats */
+	unsigned int errors;
+	unsigned int framedrop;
 	unsigned int irq_total;
 	unsigned int irq_me;
-	unsigned int errors;
 
 	unsigned int users;
 	struct bttv_fh init;

-- 
http://bigendian.bytesex.org

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [patch] v4l: bttv driver update
@ 2004-06-18  9:50 Gerd Knorr
  0 siblings, 0 replies; 6+ messages in thread
From: Gerd Knorr @ 2004-06-18  9:50 UTC (permalink / raw)
  To: Andrew Morton, Kernel List

  Hi,

This is a update of the bttv driver.  Changes:

  * some card-specific fixes + new cards.
  * separate buffer switching for video frames and vbi data,
    that should make bttv less sensitive to high irq latencies.

Please apply,

  Gerd

diff -up linux-2.6.7/drivers/media/video/bttv-cards.c linux/drivers/media/video/bttv-cards.c
--- linux-2.6.7/drivers/media/video/bttv-cards.c	2004-06-17 10:29:05.000000000 +0200
+++ linux/drivers/media/video/bttv-cards.c	2004-06-17 13:47:59.425340155 +0200
@@ -71,6 +71,9 @@ static void gvc1100_muxsel(struct bttv *
 
 static void PXC200_muxsel(struct bttv *btv, unsigned int input);
 
+static void picolo_tetra_muxsel(struct bttv *btv, unsigned int input);
+static void picolo_tetra_init(struct bttv *btv);
+
 static int terratec_active_radio_upgrade(struct bttv *btv);
 static int tea5757_read(struct bttv *btv);
 static int tea5757_write(struct bttv *btv, int value);
@@ -181,6 +184,7 @@ static struct CARD {
 	{ 0xff00bd11, BTTV_PINNACLE,      "Pinnacle PCTV [bswap]" },
 
 	{ 0x3000121a, BTTV_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
+	{ 0x263710b4, BTTV_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
 	{ 0x3060121a, BTTV_STB2,	  "3Dfx VoodooTV 100/ STB OEM" },
 	
 	{ 0x3000144f, BTTV_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
@@ -260,12 +264,15 @@ static struct CARD {
 	{ 0x41424344, BTTV_GRANDTEC,      "GrandTec Multi Capture" },
 	{ 0x01020304, BTTV_XGUARD,        "Grandtec Grand X-Guard" },
 	
-    	{ 0x010115cb, BTTV_GMV1,          "AG GMV1" },
-	{ 0x010114c7, BTTV_MODTEC_205,    "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
 	{ 0x18501851, BTTV_CHRONOS_VS2,   "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
 	{ 0x18511851, BTTV_FLYVIDEO98EZ,  "FlyVideo 98EZ (LR51)/ CyberMail AV" },
 	{ 0x18521852, BTTV_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
 	{ 0x41a0a051, BTTV_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" },
+	{ 0x18501f7f, BTTV_FLYVIDEO_98,   "Lifeview Flyvideo 98" },
+
+    	{ 0x010115cb, BTTV_GMV1,          "AG GMV1" },
+	{ 0x010114c7, BTTV_MODTEC_205,    "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
+
 	{ 0x10b42636, BTTV_HAUPPAUGE878,  "STB ???" },
 	{ 0x217d6606, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
 	{ 0xfff6f6ff, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
@@ -280,14 +287,21 @@ static struct CARD {
 	{ 0x40111554, BTTV_PV_BT878P_9B,  "Prolink Pixelview PV-BT" },
 	{ 0x17de0a01, BTTV_KWORLD,        "Mecer TV/FM/Video Tuner" },
 
+	{ 0x01051805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #1" },
+	{ 0x01061805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #2" },
+	{ 0x01071805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #3" },
+	{ 0x01081805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #4" },
+
 	// likely broken, vendor id doesn't match the other magic views ...
 	//{ 0xa0fca04f, BTTV_MAGICTVIEW063, "Guillemot Maxi TV Video 3" },
 	
 	// DVB cards (using pci function .1 for mpeg data xfer)
 	{ 0x01010071, BTTV_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
+	{ 0x07611461, BTTV_NEBULA_DIGITV, "AverMedia AverTV DVB-T" },
 	{ 0x002611bd, BTTV_TWINHAN_DST,   "Pinnacle PCTV SAT CI" },
 	{ 0x00011822, BTTV_TWINHAN_DST,   "Twinhan VisionPlus DVB-T" },
 	{ 0xfc00270f, BTTV_TWINHAN_DST,   "ChainTech digitop DST-1000 DVB-S" },
+	{ 0x07711461, BTTV_AVDVBT_771,    "AVermedia DVB-T 771" },
 	
 	{ 0, -1, NULL }
 };
@@ -835,7 +849,7 @@ struct tvcard bttv_tvcards[] = {
 	.svhs		= 2,
 	.gpiomask	= 0x03000F,
 	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 2, 0, 0, 0, 1},
+	.audiomux	= { 2, 0xd0001, 0, 0, 1},
 	.needs_tvaudio	= 0,
 	.pll		= PLL_28,
 	.tuner_type	= -1,
@@ -1646,6 +1660,7 @@ struct tvcard bttv_tvcards[] = {
 	.muxsel         = { 3, 0, 1, 2},
 	.needs_tvaudio  = 0, 
 	.pll            = PLL_28,
+	.no_gpioirq     = 1,
 },{
         .name           = "Formac ProTV II (bt878)",
         .video_inputs   = 4,
@@ -2012,6 +2027,57 @@ struct tvcard bttv_tvcards[] = {
 	.tuner_type     = TUNER_PHILIPS_PAL,
 	.has_remote     = 1,
 	.has_radio      = 1,
+},{
+	/*Eric DEBIEF <debief@telemsa.com>*/
+	/*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controled*/
+	/* adds picolo_tetra_muxsel(), picolo_tetra_init(), the folowing declaration strucure, and #define BTTV_PICOLO_TETRA_CHIP*/
+	/*0x79 in bttv.h*/
+	.name           = "Euresys Picolo Tetra",
+	.video_inputs   = 4,
+	.audio_inputs   = 0,
+	.tuner          = -1,
+	.svhs           = -1,
+	.gpiomask       = 0,
+	.gpiomask2      = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
+	.no_msp34xx     = 1,
+	.no_tda9875     = 1,
+	.no_tda7432     = 1,
+	.muxsel         = {2,2,2,2},/*878A input is always MUX0, see above.*/
+	.audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+	.pll            = PLL_28,
+	.needs_tvaudio  = 0,
+	.muxsel_hook    = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
+},{
+	/* Spirit TV Tuner from http://spiritmodems.com.au */
+	/* Stafford Goodsell <surge@goliath.homeunix.org> */
+	.name           = "Spirit TV Tuner",
+	.video_inputs   = 3,
+	.audio_inputs   = 1,
+	.tuner          = 0,
+	.svhs           = 2,
+	.gpiomask       = 0x0000000f,
+	.muxsel         = { 2, 1, 1 },
+	.audiomux       = { 0x02, 0x00, 0x00, 0x00, 0x00},
+	.tuner_type     = TUNER_TEMIC_PAL,
+	.no_msp34xx     = 1,
+	.no_tda9875     = 1,
+},{
+	/* Wolfram Joost <wojo@frokaschwei.de> */
+        .name           = "AVerMedia AVerTV DVB-T 771",
+        .video_inputs   = 2,
+        .svhs           = 1,
+        .tuner          = -1,
+        .tuner_type     = TUNER_ABSENT,
+        .muxsel         = { 3 , 3 },
+        .no_msp34xx     = 1,
+        .no_tda9875     = 1,
+        .no_tda7432     = 1,
+        .pll            = PLL_28,
+        .has_dvb        = 1,
+        .no_gpioirq     = 1,
+#if 0 /* untested */
+        .has_remote     = 1,
+#endif
 }};
 
 const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -2381,6 +2447,7 @@ void __devinit bttv_init_card1(struct bt
 		pvr_boot(btv);
 		break;
 	case BTTV_TWINHAN_DST:
+	case BTTV_AVDVBT_771:
 		btv->use_i2c_hw = 1;
 		break;
 	}
@@ -2432,6 +2499,9 @@ void __devinit bttv_init_card2(struct bt
 	case BTTV_PXC200:
 		init_PXC200(btv);
 		break;
+	case BTTV_PICOLO_TETRA_CHIP:
+		picolo_tetra_init(btv);
+		break;
 	case BTTV_VHX:
 		btv->has_radio    = 1;
 		btv->has_matchbox = 1;
@@ -2668,6 +2738,10 @@ static void modtec_eeprom(struct bttv *b
 		btv->tuner_type=TUNER_ALPS_TSBB5_PAL_I;
 		printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
                        btv->c.nr,&eeprom_data[0x1e]);
+        } else if (strncmp(&(eeprom_data[0x1e]),"Philips FM1246",14) ==0) {
+                btv->tuner_type=TUNER_PHILIPS_NTSC;
+                printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
+                       btv->c.nr,&eeprom_data[0x1e]);
 	} else {
 		printk("bttv%d: Modtec: Unknown TunerString: %s\n",
 		       btv->c.nr,&eeprom_data[0x1e]);
@@ -3786,6 +3860,21 @@ static void xguard_muxsel(struct bttv *b
 	};
 	gpio_write(masks[input%16]);
 }
+static void picolo_tetra_init(struct bttv *btv)
+{
+	/*This is the video input redirection fonctionality : I DID NOT USED IT. */
+	btwrite (0x08<<16,BT848_GPIO_DATA);/*GPIO[19] [==> 4053 B+C] set to 1 */
+	btwrite (0x04<<16,BT848_GPIO_DATA);/*GPIO[18] [==> 4053 A]  set to 1*/
+}
+static void picolo_tetra_muxsel (struct bttv* btv, unsigned int input)
+{
+
+	dprintk (KERN_DEBUG "bttv%d : picolo_tetra_muxsel =>  input = %d\n",btv->c.nr,input);
+	/*Just set the right path in the analog multiplexers : channel 1 -> 4 ==> Analog Mux ==> MUX0*/
+	/*GPIO[20]&GPIO[21] used to choose the right input*/
+	btwrite (input<<20,BT848_GPIO_DATA);
+
+}
 
 /*
  * ivc120_muxsel [Added by Alan Garfield <alan@fromorbit.com>]
@@ -3939,15 +4028,15 @@ int __devinit bttv_handle_chipset(struct
 }
 
 
-/* PXC200 muxsel helper
+/* PXC200 muxsel helper 
  * luke@syseng.anu.edu.au
- * another transplant
+ * another transplant 
  * from Alessandro Rubini (rubini@linux.it)
  *
  * There are 4 kinds of cards:
- * PXC200L which is bt848
+ * PXC200L which is bt848 
  * PXC200F which is bt848 with PIC controlling mux
- * PXC200AL which is bt878
+ * PXC200AL which is bt878 
  * PXC200AF which is bt878 with PIC controlling mux
  */
 #define PX_CFG_PXC200F 0x01
@@ -3986,10 +4075,10 @@ static void PXC200_muxsel(struct bttv *b
 	/*  mux = bttv_tvcards[btv->type].muxsel[input] & 3; */
 	/* ** not needed!?   */
 	mux = input;
-
+  
 	/* make sure output pins are enabled */
 	/* bitmask=0x30f; */
-	bitmask=0x302;
+	bitmask=0x302; 
 	/* check whether we have a PXC200A */
  	if (btv->cardid == PX_PXC200A_CARDID)  {
 	   bitmask ^= 0x180; /* use 7 and 9, not 8 and 9 */
@@ -3998,7 +4087,7 @@ static void PXC200_muxsel(struct bttv *b
 	btwrite(bitmask, BT848_GPIO_OUT_EN);
 
 	bitmask = btread(BT848_GPIO_DATA);
- 	if (btv->cardid == PX_PXC200A_CARDID)
+ 	if (btv->cardid == PX_PXC200A_CARDID) 
 	  bitmask = (bitmask & ~0x280) | ((mux & 2) << 8) | ((mux & 1) << 7);
 	else /* older device */
 	  bitmask = (bitmask & ~0x300) | ((mux & 3) << 8);
@@ -4008,10 +4097,10 @@ static void PXC200_muxsel(struct bttv *b
 	 * Was "to be safe, set the bt848 to input 0"
 	 * Actually, since it's ok at load time, better not messing
 	 * with these bits (on PXC200AF you need to set mux 2 here)
-	 *
+	 * 
 	 * needed because bttv-driver sets mux before calling this function
 	 */
- 	if (btv->cardid == PX_PXC200A_CARDID)
+ 	if (btv->cardid == PX_PXC200A_CARDID) 
 	  btaor(2<<5, ~BT848_IFORM_MUXSEL, BT848_IFORM);
 	else /* older device */
 	  btand(~BT848_IFORM_MUXSEL,BT848_IFORM);
diff -up linux-2.6.7/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c
--- linux-2.6.7/drivers/media/video/bttv-driver.c	2004-06-17 10:30:19.000000000 +0200
+++ linux/drivers/media/video/bttv-driver.c	2004-06-17 13:47:59.432338838 +0200
@@ -1334,7 +1334,8 @@ bttv_switch_overlay(struct bttv *btv, st
 	spin_lock_irqsave(&btv->s_lock,flags);
 	old = btv->screen;
 	btv->screen = new;
-	bttv_set_dma(btv, 0x03, 1);
+	btv->curr.irqflags |= 1;
+	bttv_set_dma(btv, 0x03, btv->curr.irqflags);
 	spin_unlock_irqrestore(&btv->s_lock,flags);
 	if (NULL == new)
 		free_btres(btv,fh,RESOURCE_OVERLAY);
@@ -1441,7 +1442,8 @@ buffer_queue(struct file *file, struct v
 
 	buf->vb.state = STATE_QUEUED;
 	list_add_tail(&buf->vb.queue,&fh->btv->capture);
-	bttv_set_dma(fh->btv, 0x03, 1);
+	fh->btv->curr.irqflags |= 1;
+	bttv_set_dma(fh->btv, 0x03, fh->btv->curr.irqflags);
 }
 
 static void buffer_release(struct file *file, struct videobuf_buffer *vb)
@@ -3203,8 +3205,8 @@ static void bttv_print_riscaddr(struct b
 	printk("  main: %08Lx\n",
 	       (unsigned long long)btv->main.dma);
 	printk("  vbi : o=%08Lx e=%08Lx\n",
-	       btv->curr.vbi ? (unsigned long long)btv->curr.vbi->top.dma : 0,
-	       btv->curr.vbi ? (unsigned long long)btv->curr.vbi->bottom.dma : 0);
+	       btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
+	       btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
 	printk("  cap : o=%08Lx e=%08Lx\n",
 	       btv->curr.top    ? (unsigned long long)btv->curr.top->top.dma : 0,
 	       btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
@@ -3224,7 +3226,7 @@ static void bttv_irq_debug_low_latency(s
 
 	if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
 		printk("bttv%d: Oh, there (temporarely?) is no input signal. "
-		       "Ok, then this is harmless, don't worry ;)",
+		       "Ok, then this is harmless, don't worry ;)\n",
 		       btv->c.nr);
 		return;
 	}
@@ -3236,18 +3238,12 @@ static void bttv_irq_debug_low_latency(s
 }
 
 static int
-bttv_irq_next_set(struct bttv *btv, struct bttv_buffer_set *set)
+bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set)
 {
 	struct bttv_buffer *item;
 
 	memset(set,0,sizeof(*set));
 
-	/* vbi request ? */
-	if (!list_empty(&btv->vcapture)) {
-		set->irqflags = 1;
-		set->vbi = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
-	}
-
 	/* capture request ? */
 	if (!list_empty(&btv->capture)) {
 		set->irqflags = 1;
@@ -3295,27 +3291,20 @@ bttv_irq_next_set(struct bttv *btv, stru
 		}
 	}
 
-	dprintk("bttv%d: next set: top=%p bottom=%p vbi=%p "
-		"[screen=%p,irq=%d,%d]\n",
-		btv->c.nr,set->top, set->bottom, set->vbi,
+	dprintk("bttv%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n",
+		btv->c.nr,set->top, set->bottom,
 		btv->screen,set->irqflags,set->topirq);
 	return 0;
 }
 
 static void
-bttv_irq_wakeup_set(struct bttv *btv, struct bttv_buffer_set *wakeup,
-		    struct bttv_buffer_set *curr, unsigned int state)
+bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,
+		      struct bttv_buffer_set *curr, unsigned int state)
 {
 	struct timeval ts;
 
 	do_gettimeofday(&ts);
 
-	if (NULL != wakeup->vbi) {
-		wakeup->vbi->vb.ts = ts;
-		wakeup->vbi->vb.field_count = btv->field_count;
-		wakeup->vbi->vb.state = state;
-		wake_up(&wakeup->vbi->vb.done);
-	}
 	if (wakeup->top == wakeup->bottom) {
 		if (NULL != wakeup->top && curr->top != wakeup->top) {
 			if (irq_debug > 1)
@@ -3345,10 +3334,27 @@ bttv_irq_wakeup_set(struct bttv *btv, st
 	}
 }
 
+static void
+bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup,
+		    unsigned int state)
+{
+	struct timeval ts;
+
+	if (NULL == wakeup)
+		return;
+
+	do_gettimeofday(&ts);
+	wakeup->vb.ts = ts;
+	wakeup->vb.field_count = btv->field_count;
+	wakeup->vb.state = state;
+	wake_up(&wakeup->vb.done);
+}
+
 static void bttv_irq_timeout(unsigned long data)
 {
 	struct bttv *btv = (struct bttv *)data;
 	struct bttv_buffer_set old,new;
+	struct bttv_buffer *ovbi;
 	struct bttv_buffer *item;
 	unsigned long flags;
 	
@@ -3364,13 +3370,17 @@ static void bttv_irq_timeout(unsigned lo
 	
 	/* deactivate stuff */
 	memset(&new,0,sizeof(new));
-	old = btv->curr;
+	old  = btv->curr;
+	ovbi = btv->cvbi;
 	btv->curr = new;
-	bttv_buffer_set_activate(btv, &new);
+	btv->cvbi = NULL;
+	bttv_buffer_activate_video(btv, &new);
+	bttv_buffer_activate_vbi(btv,   NULL);
 	bttv_set_dma(btv, 0, 0);
 
 	/* wake up */
-	bttv_irq_wakeup_set(btv, &old, &new, STATE_ERROR);
+	bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR);
+	bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR);
 
 	/* cancel all outstanding capture / vbi requests */
 	while (!list_empty(&btv->capture)) {
@@ -3410,8 +3420,17 @@ bttv_irq_wakeup_top(struct bttv *btv)
 	spin_unlock(&btv->s_lock);
 }
 
+static inline int is_active(struct btcx_riscmem *risc, u32 rc)
+{
+	if (rc < risc->dma)
+		return 0;
+	if (rc > risc->dma + risc->size)
+		return 0;
+	return 1;
+}
+
 static void
-bttv_irq_switch_fields(struct bttv *btv)
+bttv_irq_switch_video(struct bttv *btv)
 {
 	struct bttv_buffer_set new;
 	struct bttv_buffer_set old;
@@ -3420,9 +3439,10 @@ bttv_irq_switch_fields(struct bttv *btv)
 	spin_lock(&btv->s_lock);
 
 	/* new buffer set */
-	bttv_irq_next_set(btv, &new);
+	bttv_irq_next_video(btv, &new);
 	rc = btread(BT848_RISC_COUNT);
-	if (rc < btv->main.dma || rc > btv->main.dma + 0x100) {
+	if ((btv->curr.top    && is_active(&btv->curr.top->top,       rc)) ||
+	    (btv->curr.bottom && is_active(&btv->curr.bottom->bottom, rc))) {
 		btv->framedrop++;
 		if (debug_latency)
 			bttv_irq_debug_low_latency(btv, rc);
@@ -3433,7 +3453,7 @@ bttv_irq_switch_fields(struct bttv *btv)
 	/* switch over */
 	old = btv->curr;
 	btv->curr = new;
-	bttv_buffer_set_activate(btv, &new);
+	bttv_buffer_activate_video(btv, &new);
 	bttv_set_dma(btv, 0, new.irqflags);
 
 	/* switch input */
@@ -3443,7 +3463,39 @@ bttv_irq_switch_fields(struct bttv *btv)
 	}
 
 	/* wake up finished buffers */
-	bttv_irq_wakeup_set(btv, &old, &new, STATE_DONE);
+	bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE);
+	spin_unlock(&btv->s_lock);
+}
+
+static void
+bttv_irq_switch_vbi(struct bttv *btv)
+{
+	struct bttv_buffer *new = NULL;
+	struct bttv_buffer *old;
+	u32 rc;
+
+	spin_lock(&btv->s_lock);
+
+	if (!list_empty(&btv->vcapture))
+		new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
+	old = btv->cvbi;
+	
+	rc = btread(BT848_RISC_COUNT);
+	if (NULL != old && (is_active(&old->top,    rc) ||
+			    is_active(&old->bottom, rc))) {
+		btv->framedrop++;
+		if (debug_latency)
+			bttv_irq_debug_low_latency(btv, rc);
+		spin_unlock(&btv->s_lock);
+		return;
+	}
+	
+	/* switch */
+	btv->cvbi = new;
+	bttv_buffer_activate_vbi(btv, new);
+	bttv_set_dma(btv, 0, btv->curr.irqflags);
+	
+	bttv_irq_wakeup_vbi(btv, old, STATE_DONE);
 	spin_unlock(&btv->s_lock);
 }
 
@@ -3500,11 +3552,14 @@ static irqreturn_t bttv_irq(int irq, voi
 			wake_up(&btv->i2c_queue);
 		}
 
+                if ((astat & BT848_INT_RISCI)  &&  (stat & (4<<28)))
+			bttv_irq_switch_vbi(btv);
+
                 if ((astat & BT848_INT_RISCI)  &&  (stat & (2<<28)))
 			bttv_irq_wakeup_top(btv);
 
                 if ((astat & BT848_INT_RISCI)  &&  (stat & (1<<28)))
-			bttv_irq_switch_fields(btv);
+			bttv_irq_switch_video(btv);
 
 		if ((astat & BT848_INT_HLOCK)  &&  btv->opt_automute)
 			audio_mux(btv, -1);
@@ -3872,9 +3927,11 @@ static int bttv_suspend(struct pci_dev *
 	/* stop dma + irqs */
 	spin_lock_irqsave(&btv->s_lock,flags);
 	memset(&idle, 0, sizeof(idle));
-	btv->state.set = btv->curr;
+	btv->state.video = btv->curr;
+	btv->state.vbi   = btv->cvbi;
 	btv->curr = idle;
-	bttv_buffer_set_activate(btv, &idle);
+	bttv_buffer_activate_video(btv, &idle);
+	bttv_buffer_activate_vbi(btv, NULL);
 	bttv_set_dma(btv, 0, 0);
 	btwrite(0, BT848_INT_MASK);
 	spin_unlock_irqrestore(&btv->s_lock,flags);
@@ -3914,8 +3971,10 @@ static int bttv_resume(struct pci_dev *p
 
 	/* restart dma */
 	spin_lock_irqsave(&btv->s_lock,flags);
-	btv->curr = btv->state.set;
-	bttv_buffer_set_activate(btv, &btv->curr);
+	btv->curr = btv->state.video;
+	btv->cvbi = btv->state.vbi;
+	bttv_buffer_activate_video(btv, &btv->curr);
+	bttv_buffer_activate_vbi(btv, btv->cvbi);
 	bttv_set_dma(btv, 0, btv->curr.irqflags);
 	spin_unlock_irqrestore(&btv->s_lock,flags);
 	return 0;
diff -up linux-2.6.7/drivers/media/video/bttv-risc.c linux/drivers/media/video/bttv-risc.c
--- linux-2.6.7/drivers/media/video/bttv-risc.c	2004-06-17 10:29:10.000000000 +0200
+++ linux/drivers/media/video/bttv-risc.c	2004-06-17 13:47:59.435338273 +0200
@@ -379,7 +379,7 @@ bttv_set_dma(struct bttv *btv, int overr
 	btv->cap_ctl = 0;
 	if (NULL != btv->curr.top)      btv->cap_ctl |= 0x02;
 	if (NULL != btv->curr.bottom)   btv->cap_ctl |= 0x01;
-	if (NULL != btv->curr.vbi)      btv->cap_ctl |= 0x0c;
+	if (NULL != btv->cvbi)          btv->cap_ctl |= 0x0c;
 
 	capctl  = 0;
 	capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00;  /* capture  */
@@ -389,9 +389,9 @@ bttv_set_dma(struct bttv *btv, int overr
 	d2printk(KERN_DEBUG
 		 "bttv%d: capctl=%x irq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n",
 		 btv->c.nr,capctl,irqflags,
-		 btv->curr.vbi     ? (unsigned long long)btv->curr.vbi->top.dma        : 0,
+		 btv->cvbi         ? (unsigned long long)btv->cvbi->top.dma            : 0,
 		 btv->curr.top     ? (unsigned long long)btv->curr.top->top.dma        : 0,
-		 btv->curr.vbi     ? (unsigned long long)btv->curr.vbi->bottom.dma     : 0,
+		 btv->cvbi         ? (unsigned long long)btv->cvbi->bottom.dma         : 0,
 		 btv->curr.bottom  ? (unsigned long long)btv->curr.bottom->bottom.dma  : 0);
 	
 	cmd = BT848_RISC_JUMP;
@@ -399,6 +399,8 @@ bttv_set_dma(struct bttv *btv, int overr
 		cmd |= BT848_RISC_IRQ;
 		cmd |= (irqflags  & 0x0f) << 16;
 		cmd |= (~irqflags & 0x0f) << 20;
+	}
+	if (irqflags || btv->cvbi) {
 		mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT);
 	} else {
 		del_timer(&btv->timeout);
@@ -501,20 +503,26 @@ bttv_dma_free(struct bttv *btv, struct b
 }
 
 int
-bttv_buffer_set_activate(struct bttv *btv,
-			 struct bttv_buffer_set *set)
+bttv_buffer_activate_vbi(struct bttv *btv,
+			 struct bttv_buffer *vbi)
 {
 	/* vbi capture */
-	if (set->vbi) {
-		set->vbi->vb.state = STATE_ACTIVE;
-		list_del(&set->vbi->vb.queue);
-		bttv_risc_hook(btv, RISC_SLOT_O_VBI, &set->vbi->top,    0);
-		bttv_risc_hook(btv, RISC_SLOT_E_VBI, &set->vbi->bottom, 0);
+	if (vbi) {
+		vbi->vb.state = STATE_ACTIVE;
+		list_del(&vbi->vb.queue);
+		bttv_risc_hook(btv, RISC_SLOT_O_VBI, &vbi->top,    0);
+		bttv_risc_hook(btv, RISC_SLOT_E_VBI, &vbi->bottom, 4);
 	} else {
 		bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0);
 		bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0);
 	}
+	return 0;
+}
 
+int
+bttv_buffer_activate_video(struct bttv *btv,
+			   struct bttv_buffer_set *set)
+{
 	/* video capture */
 	if (NULL != set->top  &&  NULL != set->bottom) {
 		if (set->top == set->bottom) {
diff -up linux-2.6.7/drivers/media/video/bttv-vbi.c linux/drivers/media/video/bttv-vbi.c
--- linux-2.6.7/drivers/media/video/bttv-vbi.c	2004-06-17 10:29:53.000000000 +0200
+++ linux/drivers/media/video/bttv-vbi.c	2004-06-17 13:47:59.438337709 +0200
@@ -114,7 +114,10 @@ vbi_buffer_queue(struct file *file, stru
 	dprintk("queue %p\n",vb);
 	buf->vb.state = STATE_QUEUED;
 	list_add_tail(&buf->vb.queue,&btv->vcapture);
-	bttv_set_dma(btv,0x0c,1);
+	if (NULL == btv->cvbi) {
+		fh->btv->curr.irqflags |= 4;
+		bttv_set_dma(btv,0x0c,fh->btv->curr.irqflags);
+	}
 }
 
 static void vbi_buffer_release(struct file *file, struct videobuf_buffer *vb)
diff -up linux-2.6.7/drivers/media/video/bttv.h linux/drivers/media/video/bttv.h
--- linux-2.6.7/drivers/media/video/bttv.h	2004-06-17 10:27:56.000000000 +0200
+++ linux/drivers/media/video/bttv.h	2004-06-17 13:47:59.440337332 +0200
@@ -124,6 +124,8 @@
 #define BTTV_SIMUS_GVC1100  0x74
 #define BTTV_NGSTV_PLUS     0x75
 #define BTTV_LMLBT4         0x76
+#define BTTV_PICOLO_TETRA_CHIP 0x79
+#define BTTV_AVDVBT_771     0x7b
 
 /* i2c address list */
 #define I2C_TSA5522        0xc2
diff -up linux-2.6.7/drivers/media/video/bttvp.h linux/drivers/media/video/bttvp.h
--- linux-2.6.7/drivers/media/video/bttvp.h	2004-06-17 10:28:42.000000000 +0200
+++ linux/drivers/media/video/bttvp.h	2004-06-17 13:47:59.442336956 +0200
@@ -25,7 +25,7 @@
 #define _BTTVP_H_
 
 #include <linux/version.h>
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,14)
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,15)
 
 #include <linux/types.h>
 #include <linux/wait.h>
@@ -127,7 +127,6 @@ struct bttv_buffer {
 struct bttv_buffer_set {
 	struct bttv_buffer     *top;       /* top field buffer    */
 	struct bttv_buffer     *bottom;    /* bottom field buffer */
-	struct bttv_buffer     *vbi;       /* vbi buffer */
 	unsigned int           irqflags;
 	unsigned int           topirq;
 };
@@ -197,8 +196,10 @@ int bttv_risc_hook(struct bttv *btv, int
 
 /* capture buffer handling */
 int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf);
-int bttv_buffer_set_activate(struct bttv *btv,
-			     struct bttv_buffer_set *set);
+int bttv_buffer_activate_video(struct bttv *btv,
+			       struct bttv_buffer_set *set);
+int bttv_buffer_activate_vbi(struct bttv *btv,
+			     struct bttv_buffer *vbi);
 void bttv_dma_free(struct bttv *btv, struct bttv_buffer *buf);
 
 /* overlay handling */
@@ -279,7 +280,8 @@ struct bttv_suspend_state {
 	u32  gpio_enable;
 	u32  gpio_data;
 	int  disabled;
-	struct bttv_buffer_set set;
+	struct bttv_buffer_set video;
+	struct bttv_buffer     *vbi;
 };
 
 struct bttv {
@@ -377,6 +379,7 @@ struct bttv {
 	struct list_head        capture;    /* video capture queue */
 	struct list_head        vcapture;   /* vbi capture queue   */
 	struct bttv_buffer_set  curr;       /* active buffers      */
+	struct bttv_buffer      *cvbi;      /* active vbi buffer   */
 	int                     new_input;
 
 	unsigned long cap_ctl;

-- 
Smoking Crack Organization

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [patch] v4l: bttv driver update
@ 2005-03-08 10:44 Gerd Knorr
  0 siblings, 0 replies; 6+ messages in thread
From: Gerd Knorr @ 2005-03-08 10:44 UTC (permalink / raw)
  To: Andrew Morton, Linux Kernel Mailing List

This is a bttv driver update, changes:
  * add support for a new card.
  * add some debug code (bt878 risc disassembler).
  * drop some obsolete i2c code.

Signed-off-by: Gerd Knorr <kraxel@bytesex.org>
---
 drivers/media/video/btcx-risc.c   |   12 +-
 drivers/media/video/bttv-cards.c  |  175 +++++++++++++++++++++++++++++-
 drivers/media/video/bttv-driver.c |   93 +++++++++++++--
 drivers/media/video/bttv-gpio.c   |   17 --
 drivers/media/video/bttv-i2c.c    |   15 --
 drivers/media/video/bttv.h        |    5 
 drivers/media/video/bttvp.h       |    3 
 7 files changed, 263 insertions(+), 57 deletions(-)

Index: linux-2.6.11/drivers/media/video/bttv.h
===================================================================
--- linux-2.6.11.orig/drivers/media/video/bttv.h	2005-03-07 15:25:35.000000000 +0100
+++ linux-2.6.11/drivers/media/video/bttv.h	2005-03-07 16:23:11.000000000 +0100
@@ -1,5 +1,5 @@
 /*
- * $Id: bttv.h,v 1.15 2005/01/24 17:37:23 kraxel Exp $
+ * $Id: bttv.h,v 1.17 2005/02/22 14:06:32 kraxel Exp $
  *
  *  bttv - Bt848 frame grabber driver
  *
@@ -134,6 +134,7 @@
 #define BTTV_APAC_VIEWCOMP  0x7f
 #define BTTV_DVICO_DVBT_LITE  0x80
 #define BTTV_TIBET_CS16  0x83
+#define BTTV_KODICOM_4400R  0x84
 
 /* i2c address list */
 #define I2C_TSA5522        0xc2
@@ -302,8 +303,6 @@ struct bttv_sub_driver {
 	struct device_driver   drv;
 	char                   wanted[BUS_ID_SIZE];
 	void                   (*gpio_irq)(struct bttv_sub_device *sub);
-	void                   (*i2c_info)(struct bttv_sub_device *sub,
-					   struct i2c_client *client, int attach);
 };
 #define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
 
Index: linux-2.6.11/drivers/media/video/bttvp.h
===================================================================
--- linux-2.6.11.orig/drivers/media/video/bttvp.h	2005-03-07 15:25:35.000000000 +0100
+++ linux-2.6.11/drivers/media/video/bttvp.h	2005-03-07 16:23:03.000000000 +0100
@@ -1,5 +1,5 @@
 /*
-    $Id: bttvp.h,v 1.16 2005/01/24 17:37:23 kraxel Exp $
+    $Id: bttvp.h,v 1.17 2005/02/16 12:14:10 kraxel Exp $
 
     bttv - Bt848 frame grabber driver
 
@@ -209,7 +209,6 @@ extern struct bus_type bttv_sub_bus_type
 int bttv_sub_add_device(struct bttv_core *core, char *name);
 int bttv_sub_del_devices(struct bttv_core *core);
 void bttv_gpio_irq(struct bttv_core *core);
-void bttv_i2c_info(struct bttv_core *core, struct i2c_client *client, int attach);
 
 
 /* ---------------------------------------------------------- */
Index: linux-2.6.11/drivers/media/video/bttv-cards.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/bttv-cards.c	2005-03-07 15:25:35.000000000 +0100
+++ linux-2.6.11/drivers/media/video/bttv-cards.c	2005-03-07 16:23:11.000000000 +0100
@@ -1,5 +1,5 @@
 /*
-    $Id: bttv-cards.c,v 1.44 2005/01/31 11:35:05 kraxel Exp $
+    $Id: bttv-cards.c,v 1.47 2005/02/22 14:06:32 kraxel Exp $
 
     bttv-cards.c
 
@@ -80,6 +80,9 @@ static void picolo_tetra_init(struct btt
 static void tibetCS16_muxsel(struct bttv *btv, unsigned int input);
 static void tibetCS16_init(struct bttv *btv);
 
+static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input);
+static void kodicom4400r_init(struct bttv *btv);
+
 static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input);
 static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input);
 
@@ -101,6 +104,7 @@ static unsigned int pll[BTTV_MAX]    = {
 static unsigned int tuner[BTTV_MAX]  = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
 static unsigned int svhs[BTTV_MAX]   = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
 static unsigned int remote[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
+static struct bttv  *master[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = NULL };
 #ifdef MODULE
 static unsigned int autoload = 1;
 #else
@@ -293,7 +297,7 @@ static struct CARD {
 	{ 0x07611461, BTTV_AVDVBT_761,    "AverMedia AverTV DVB-T 761" },
 	{ 0x001c11bd, BTTV_PINNACLESAT,   "Pinnacle PCTV Sat" },
 	{ 0x002611bd, BTTV_TWINHAN_DST,   "Pinnacle PCTV SAT CI" },
-	{ 0x00011822, BTTV_TWINHAN_DST,   "Twinhan VisionPlus DVB-T" },
+	{ 0x00011822, BTTV_TWINHAN_DST,   "Twinhan VisionPlus DVB" },
 	{ 0xfc00270f, BTTV_TWINHAN_DST,   "ChainTech digitop DST-1000 DVB-S" },
 	{ 0x07711461, BTTV_AVDVBT_771,    "AVermedia AverTV DVB-T 771" },
 	{ 0xdb1018ac, BTTV_DVICO_DVBT_LITE,    "DVICO FusionHDTV DVB-T Lite" },
@@ -1922,6 +1926,7 @@ struct tvcard bttv_tvcards[] = {
 	.svhs           = 2,
 	.muxsel         = { 2, 3, 1, 0},
 	.tuner_type     = TUNER_PHILIPS_ATSC,
+	.has_dvb        = 1,
 },{
 	.name           = "Twinhan DST + clones",
 	.no_msp34xx     = 1,
@@ -2190,6 +2195,63 @@ struct tvcard bttv_tvcards[] = {
 		.no_tda7432	= 1,
 		.tuner_type     = -1,
 		.muxsel_hook    = tibetCS16_muxsel,
+},
+{
+	/* Bill Brack <wbrack@mmm.com.hk> */
+	/*
+	 * Note that, because of the card's wiring, the "master"
+	 * BT878A chip (i.e. the one which controls the analog switch
+	 * and must use this card type) is the 2nd one detected.  The
+	 * other 3 chips should use card type 0x85, whose description
+	 * follows this one.  There is a EEPROM on the card (which is
+	 * connected to the I2C of one of those other chips), but is
+	 * not currently handled.  There is also a facility for a
+	 * "monitor", which is also not currently implemented.
+	 */
+	.name		= "Kodicom 4400R (master)",
+	.video_inputs	= 16,
+	.audio_inputs	= 0,
+	.tuner		= -1,
+	.tuner_type	= -1,
+	.svhs		= -1,
+	/* GPIO bits 0-9 used for analog switch:
+	 *   00 - 03:	camera selector
+	 *   04 - 06:	channel (controller) selector
+	 *   07:	data (1->on, 0->off)
+	 *   08:	strobe
+	 *   09:	reset
+	 * bit 16 is input from sync separator for the channel
+	 */
+	.gpiomask	= 0x0003ff,
+	.no_gpioirq     = 1,
+	.muxsel		= { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+	.pll		= PLL_28,
+	.no_msp34xx	= 1,
+	.no_tda7432	= 1,
+	.no_tda9875	= 1,
+	.muxsel_hook	= kodicom4400r_muxsel,
+},
+{
+	/* Bill Brack <wbrack@mmm.com.hk> */
+	/* Note that, for reasons unknown, the "master" BT878A chip (i.e. the
+	 * one which controls the analog switch, and must use the card type)
+	 * is the 2nd one detected.  The other 3 chips should use this card
+	 * type
+	 */
+	.name		= "Kodicom 4400R (slave)",
+	.video_inputs	= 16,
+	.audio_inputs	= 0,
+	.tuner		= -1,
+	.tuner_type	= -1,
+	.svhs		= -1,
+	.gpiomask	= 0x010000,
+	.no_gpioirq     = 1,
+	.muxsel		= { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+	.pll		= PLL_28,
+	.no_msp34xx	= 1,
+	.no_tda7432	= 1,
+	.no_tda9875	= 1,
+	.muxsel_hook	= kodicom4400r_muxsel,
 }};
 
 static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -2684,6 +2746,9 @@ void __devinit bttv_init_card2(struct bt
 	case BTTV_TIBET_CS16:
 		tibetCS16_init(btv);
 		break;
+	case BTTV_KODICOM_4400R:
+		kodicom4400r_init(btv);
+		break;
 	}
 
 	/* pll configuration */
@@ -3896,6 +3961,112 @@ static void tibetCS16_init(struct bttv *
 	gpio_write(0x0f7fff);
 }
 
+/*
+ * The following routines for the Kodicom-4400r get a little mind-twisting.
+ * There is a "master" controller and three "slave" controllers, together
+ * an analog switch which connects any of 16 cameras to any of the BT87A's.
+ * The analog switch is controlled by the "master", but the detection order
+ * of the four BT878A chips is in an order which I just don't understand.
+ * The "master" is actually the second controller to be detected.  The
+ * logic on the board uses logical numbers for the 4 controlers, but
+ * those numbers are different from the detection sequence.  When working
+ * with the analog switch, we need to "map" from the detection sequence
+ * over to the board's logical controller number.  This mapping sequence
+ * is {3, 0, 2, 1}, i.e. the first controller to be detected is logical
+ * unit 3, the second (which is the master) is logical unit 0, etc.
+ * We need to maintain the status of the analog switch (which of the 16
+ * cameras is connected to which of the 4 controllers).  Rather than
+ * add to the bttv structure for this, we use the data reserved for
+ * the mbox (unused for this card type).
+ */
+
+/*
+ * First a routine to set the analog switch, which controls which camera
+ * is routed to which controller.  The switch comprises an X-address
+ * (gpio bits 0-3, representing the camera, ranging from 0-15), and a
+ * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3).
+ * A data value (gpio bit 7) of '1' enables the switch, and '0' disables
+ * the switch.  A STROBE bit (gpio bit 8) latches the data value into the
+ * specified address.  The idea is to set the address and data, then bring
+ * STROBE high, and finally bring STROBE back to low.
+ */
+static void kodicom4400r_write(struct bttv *btv,
+			       unsigned char xaddr,
+			       unsigned char yaddr,
+			       unsigned char data) {
+	unsigned int udata;
+	
+	udata = (data << 7) | ((yaddr&3) << 4) | (xaddr&0xf);
+	gpio_bits(0x1ff, udata);		/* write ADDR and DAT */
+	gpio_bits(0x1ff, udata | (1 << 8));	/* strobe high */
+	gpio_bits(0x1ff, udata);		/* strobe low */
+}
+
+/*
+ * Next the mux select.  Both the "master" and "slave" 'cards' (controllers)
+ * use this routine.  The routine finds the "master" for the card, maps
+ * the controller number from the detected position over to the logical
+ * number, writes the appropriate data to the analog switch, and housekeeps
+ * the local copy of the switch information.  The parameter 'input' is the
+ * requested camera number (0 - 15).
+ */
+static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input)
+{
+	char *sw_status;
+	int xaddr, yaddr;
+	struct bttv *mctlr;
+	static unsigned char map[4] = {3, 0, 2, 1};
+	
+	mctlr = master[btv->c.nr];
+	if (mctlr == NULL) {	/* ignore if master not yet detected */
+		return;
+	}
+	yaddr = (btv->c.nr - mctlr->c.nr + 1) & 3; /* the '&' is for safety */
+	yaddr = map[yaddr];
+	sw_status = (char *)(&mctlr->mbox_we);
+	xaddr = input & 0xf;
+	/* Check if the controller/camera pair has changed, else ignore */
+	if (sw_status[yaddr] != xaddr)
+	{
+		/* "open" the old switch, "close" the new one, save the new */
+		kodicom4400r_write(mctlr, sw_status[yaddr], yaddr, 0);
+		sw_status[yaddr] = xaddr;
+		kodicom4400r_write(mctlr, xaddr, yaddr, 1);
+	}
+}
+
+/*
+ * During initialisation, we need to reset the analog switch.  We
+ * also preset the switch to map the 4 connectors on the card to the
+ * *user's* (see above description of kodicom4400r_muxsel) channels
+ * 0 through 3
+ */
+static void kodicom4400r_init(struct bttv *btv)
+{
+	char *sw_status = (char *)(&btv->mbox_we);
+	int ix;
+
+	gpio_inout(0x0003ff, 0x0003ff);
+	gpio_write(1 << 9);	/* reset MUX */
+	gpio_write(0);
+	/* Preset camera 0 to the 4 controllers */
+	for (ix=0; ix<4; ix++) {
+		sw_status[ix] = ix;
+		kodicom4400r_write(btv, ix, ix, 1);
+	}
+	/*
+	 * Since this is the "master", we need to set up the
+	 * other three controller chips' pointers to this structure
+	 * for later use in the muxsel routine.
+	 */
+	if ((btv->c.nr<1) || (btv->c.nr>BTTV_MAX-3))
+	    return;
+	master[btv->c.nr-1] = btv;
+	master[btv->c.nr]   = btv;
+	master[btv->c.nr+1] = btv;
+	master[btv->c.nr+2] = btv;
+}
+
 // The Grandtec X-Guard framegrabber card uses two Dual 4-channel
 // video multiplexers to provide up to 16 video inputs. These
 // multiplexers are controlled by the lower 8 GPIO pins of the
Index: linux-2.6.11/drivers/media/video/bttv-gpio.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/bttv-gpio.c	2005-03-07 10:14:52.000000000 +0100
+++ linux-2.6.11/drivers/media/video/bttv-gpio.c	2005-03-07 16:23:03.000000000 +0100
@@ -1,5 +1,5 @@
 /*
-    $Id: bttv-gpio.c,v 1.6 2004/11/03 09:04:50 kraxel Exp $
+    $Id: bttv-gpio.c,v 1.7 2005/02/16 12:14:10 kraxel Exp $
 
     bttv-gpio.c  --  gpio sub drivers
 
@@ -94,6 +94,7 @@ int bttv_sub_del_devices(struct bttv_cor
 
 	list_for_each_safe(item,save,&core->subs) {
 		sub = list_entry(item,struct bttv_sub_device,list);
+		list_del(&sub->list);
 		device_unregister(&sub->dev);
 	}
 	return 0;
@@ -113,20 +114,6 @@ void bttv_gpio_irq(struct bttv_core *cor
 	}
 }
 
-void bttv_i2c_info(struct bttv_core *core, struct i2c_client *client, int attach)
-{
-	struct bttv_sub_driver *drv;
-	struct bttv_sub_device *dev;
-	struct list_head *item;
-
-	list_for_each(item,&core->subs) {
-		dev = list_entry(item,struct bttv_sub_device,list);
-		drv = to_bttv_sub_drv(dev->dev.driver);
-		if (drv && drv->i2c_info)
-			drv->i2c_info(dev,client,attach);
-	}
-}
-
 /* ----------------------------------------------------------------------- */
 /* external: sub-driver register/unregister                                */
 
Index: linux-2.6.11/drivers/media/video/bttv-i2c.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/bttv-i2c.c	2005-03-07 10:12:39.000000000 +0100
+++ linux-2.6.11/drivers/media/video/bttv-i2c.c	2005-03-07 16:23:03.000000000 +0100
@@ -1,5 +1,5 @@
 /*
-    $Id: bttv-i2c.c,v 1.17 2004/12/14 15:33:30 kraxel Exp $
+    $Id: bttv-i2c.c,v 1.18 2005/02/16 12:14:10 kraxel Exp $
 
     bttv-i2c.c  --  all the i2c code is here
 
@@ -39,7 +39,6 @@ static struct i2c_adapter bttv_i2c_adap_
 static struct i2c_client bttv_i2c_client_template;
 
 static int attach_inform(struct i2c_client *client);
-static int detach_inform(struct i2c_client *client);
 
 static int i2c_debug = 0;
 static int i2c_hw = 0;
@@ -112,7 +111,6 @@ static struct i2c_adapter bttv_i2c_adap_
 	I2C_DEVNAME("bt848"),
 	.id                = I2C_HW_B_BT848,
 	.client_register   = attach_inform,
-	.client_unregister = detach_inform,
 };
 
 /* ----------------------------------------------------------------------- */
@@ -290,7 +288,6 @@ static struct i2c_adapter bttv_i2c_adap_
 	.id            = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */,
 	.algo          = &bttv_algo,
 	.client_register = attach_inform,
-	.client_unregister = detach_inform,
 };
 
 /* ----------------------------------------------------------------------- */
@@ -305,22 +302,12 @@ static int attach_inform(struct i2c_clie
 	if (btv->pinnacle_id != UNSET)
 		bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE,
 				      &btv->pinnacle_id);
-	bttv_i2c_info(&btv->c, client, 1);
-
         if (bttv_debug)
 		printk("bttv%d: i2c attach [client=%s]\n",
 		       btv->c.nr, i2c_clientname(client));
         return 0;
 }
 
-static int detach_inform(struct i2c_client *client)
-{
-        struct bttv *btv = i2c_get_adapdata(client->adapter);
-
-	bttv_i2c_info(&btv->c, client, 0);
-	return 0;
-}
-
 void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
 {
 	if (0 != btv->i2c_rc)
Index: linux-2.6.11/drivers/media/video/btcx-risc.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/btcx-risc.c	2005-03-07 10:12:26.000000000 +0100
+++ linux-2.6.11/drivers/media/video/btcx-risc.c	2005-03-07 16:23:11.000000000 +0100
@@ -1,5 +1,5 @@
 /*
-    $Id: btcx-risc.c,v 1.5 2004/12/10 12:33:39 kraxel Exp $
+    $Id: btcx-risc.c,v 1.6 2005/02/21 13:57:59 kraxel Exp $
 
     btcx-risc.c
 
@@ -52,12 +52,13 @@ void btcx_riscmem_free(struct pci_dev *p
 {
 	if (NULL == risc->cpu)
 		return;
-	pci_free_consistent(pci, risc->size, risc->cpu, risc->dma);
-	memset(risc,0,sizeof(*risc));
 	if (debug) {
 		memcnt--;
-		printk("btcx: riscmem free [%d]\n",memcnt);
+		printk("btcx: riscmem free [%d] dma=%lx\n",
+		       memcnt, (unsigned long)risc->dma);
 	}
+	pci_free_consistent(pci, risc->size, risc->cpu, risc->dma);
+	memset(risc,0,sizeof(*risc));
 }
 
 int btcx_riscmem_alloc(struct pci_dev *pci,
@@ -78,7 +79,8 @@ int btcx_riscmem_alloc(struct pci_dev *p
 		risc->size = size;
 		if (debug) {
 			memcnt++;
-			printk("btcx: riscmem alloc size=%d [%d]\n",size,memcnt);
+			printk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n",
+			       memcnt, (unsigned long)dma, cpu, size);
 		}
 	}
 	memset(risc->cpu,0,risc->size);
Index: linux-2.6.11/drivers/media/video/bttv-driver.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/bttv-driver.c	2005-03-07 15:25:35.000000000 +0100
+++ linux-2.6.11/drivers/media/video/bttv-driver.c	2005-03-07 16:23:11.000000000 +0100
@@ -1,5 +1,5 @@
 /*
-    $Id: bttv-driver.c,v 1.36 2005/02/15 10:51:53 kraxel Exp $
+    $Id: bttv-driver.c,v 1.37 2005/02/21 13:57:59 kraxel Exp $
 
     bttv - Bt848 frame grabber driver
 
@@ -3167,6 +3167,82 @@ static struct video_device radio_templat
 };
 
 /* ----------------------------------------------------------------------- */
+/* some debug code                                                         */
+
+int bttv_risc_decode(u32 risc)
+{
+	static char *instr[16] = {
+		[ BT848_RISC_WRITE     >> 28 ] = "write",
+		[ BT848_RISC_SKIP      >> 28 ] = "skip",
+		[ BT848_RISC_WRITEC    >> 28 ] = "writec",
+		[ BT848_RISC_JUMP      >> 28 ] = "jump",
+		[ BT848_RISC_SYNC      >> 28 ] = "sync",
+		[ BT848_RISC_WRITE123  >> 28 ] = "write123",
+		[ BT848_RISC_SKIP123   >> 28 ] = "skip123",
+		[ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23",
+	};
+	static int incr[16] = {
+		[ BT848_RISC_WRITE     >> 28 ] = 2,
+		[ BT848_RISC_JUMP      >> 28 ] = 2,
+		[ BT848_RISC_SYNC      >> 28 ] = 2,
+		[ BT848_RISC_WRITE123  >> 28 ] = 5,
+		[ BT848_RISC_SKIP123   >> 28 ] = 2,
+		[ BT848_RISC_WRITE1S23 >> 28 ] = 3,
+	};
+	static char *bits[] = {
+		"be0",  "be1",  "be2",  "be3/resync",
+		"set0", "set1", "set2", "set3",
+		"clr0", "clr1", "clr2", "clr3",
+		"irq",  "res",  "eol",  "sol",
+	};
+	int i;
+
+	printk("0x%08x [ %s", risc,
+	       instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
+	for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
+		if (risc & (1 << (i + 12)))
+			printk(" %s",bits[i]);
+	printk(" count=%d ]\n", risc & 0xfff);
+	return incr[risc >> 28] ? incr[risc >> 28] : 1;
+}
+
+void bttv_risc_disasm(struct bttv *btv,
+		      struct btcx_riscmem *risc)
+{
+	unsigned int i,j,n;
+
+	printk("%s: risc disasm: %p [dma=0x%08lx]\n",
+	       btv->c.name, risc->cpu, (unsigned long)risc->dma);
+	for (i = 0; i < (risc->size >> 2); i += n) {
+		printk("%s:   0x%lx: ", btv->c.name,
+		       (unsigned long)(risc->dma + (i<<2)));
+		n = bttv_risc_decode(risc->cpu[i]);
+		for (j = 1; j < n; j++)
+			printk("%s:   0x%lx: 0x%08x [ arg #%d ]\n",
+			       btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
+			       risc->cpu[i+j], j);
+		if (0 == risc->cpu[i])
+			break;
+	}
+}
+
+static void bttv_print_riscaddr(struct bttv *btv)
+{
+	printk("  main: %08Lx\n",
+	       (unsigned long long)btv->main.dma);
+	printk("  vbi : o=%08Lx e=%08Lx\n",
+	       btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
+	       btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
+	printk("  cap : o=%08Lx e=%08Lx\n",
+	       btv->curr.top    ? (unsigned long long)btv->curr.top->top.dma : 0,
+	       btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
+	printk("  scr : o=%08Lx e=%08Lx\n",
+	       btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
+	       btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
+	bttv_risc_disasm(btv, &btv->main);
+}
+
+/* ----------------------------------------------------------------------- */
 /* irq handler                                                             */
 
 static char *irq_name[] = {
@@ -3204,21 +3280,6 @@ static void bttv_print_irqbits(u32 print
 	}
 }
 
-static void bttv_print_riscaddr(struct bttv *btv)
-{
-	printk("  main: %08Lx\n",
-	       (unsigned long long)btv->main.dma);
-	printk("  vbi : o=%08Lx e=%08Lx\n",
-	       btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
-	       btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
-	printk("  cap : o=%08Lx e=%08Lx\n",
-	       btv->curr.top    ? (unsigned long long)btv->curr.top->top.dma : 0,
-	       btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
-	printk("  scr : o=%08Lx e=%08Lx\n",
-	       btv->screen ? (unsigned long long)btv->screen->top.dma  : 0,
-	       btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
-}
-
 static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
 {
 	printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",

-- 
#define printk(args...) fprintf(stderr, ## args)

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2005-03-08 10:49 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-10-07 10:58 [patch] v4l: bttv driver update Gerd Knorr
2003-10-07 20:15 ` Pavel Machek
2003-10-08  8:09   ` Gerd Knorr
  -- strict thread matches above, loose matches on Subject: below --
2004-04-05 12:20 Gerd Knorr
2004-06-18  9:50 Gerd Knorr
2005-03-08 10:44 Gerd Knorr

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).