SAA7110 & DC10+

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]



Using standard driver from RedHat kernel (2.4.9-31 and 2.4.18-0.13) my DC10+
card was unable to show correctly VCR output from VHS (the tuner output was
ok). Updating the saa7110 driver the problem disappeared.

Apparently the saa7110 driver shipped with those kernels is old, but
updated for a clean compilation, and appear to be the same from vanilla
2.4.18. I've merged a newer driver (0.8) with those patches.

Hope this helps.

Gabriele Turchi
turchi@xxxxxxxx

P.S.: I'm sorry, my english is alpha version...


--- saa7110.rhl	Wed Apr 24 12:36:52 2002
+++ saa7110.c	Wed Apr 24 12:45:08 2002
@@ -2,6 +2,10 @@
     saa7110 - Philips SAA7110(A) video decoder driver
 
     Copyright (C) 1998 Pauline Middelink <middelin@xxxxxxxxxxx>
+    
+    Copyright (C) 1999 Wolfgang Scherr <scherr@xxxxxxxxxxx>
+    Copyright (C) 2000 Serguei Miridonov <mirsev@xxxxxxxxx>
+       - some corrections for Pinnacle Systems Inc. DC10plus card.
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -18,6 +22,8 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include <linux/version.h>
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
@@ -28,7 +34,7 @@
 
 #include <linux/i2c-old.h>
 #include <linux/videodev.h>
-#include "linux/video_decoder.h"
+#include <linux/video_decoder.h>
 
 #define DEBUG(x...)			/* remove when no long debugging */
 
@@ -42,7 +48,7 @@
 struct saa7110 {
 	struct	i2c_bus	*bus;
 	int		addr;
-	unsigned char	reg[36];
+	unsigned char	reg[54];
 
 	int		norm;
 	int		input;
@@ -51,6 +57,8 @@
 	int		contrast;
 	int		hue;
 	int		sat;
+	
+	wait_queue_head_t wq;
 };
 
 /* ----------------------------------------------------------------------- */
@@ -83,7 +91,7 @@
 	while (len-- > 0) {
                 if (i2c_sendbyte(decoder->bus,*data,0)) {
                         i2c_stop(decoder->bus);
-                        UNLOCK_I2C_BUS(decoder->bus);
+			UNLOCK_I2C_BUS(decoder->bus);
                         return -EAGAIN;
                 }
 		decoder->reg[subaddr++] = *data++;
@@ -101,8 +109,8 @@
 
 	LOCK_I2C_BUS(decoder->bus);
 	i2c_start(decoder->bus);
-	i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY);
-	i2c_start(decoder->bus);
+	//i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY);
+	//i2c_start(decoder->bus);
 	i2c_sendbyte(decoder->bus, decoder->addr | 1, I2C_DELAY);
 	data = i2c_readbyte(decoder->bus, 1);
 	i2c_stop(decoder->bus);
@@ -113,19 +121,24 @@
 /* ----------------------------------------------------------------------- */
 /* SAA7110 functions							   */
 /* ----------------------------------------------------------------------- */
+
+#define FRESP_06H_COMPST 0x03       //0x13
+#define FRESP_06H_SVIDEO 0x83       //0xC0
+
+
 static
 int saa7110_selmux(struct i2c_device *device, int chan)
 {
 static	const unsigned char modes[9][8] = {
-/* mode 0 */	{ 0x00, 0xD9, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 },
-/* mode 1 */	{ 0x00, 0xD8, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 },
-/* mode 2 */	{ 0x00, 0xBA, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 },
-/* mode 3 */	{ 0x00, 0xB8, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 },
-/* mode 4 */	{ 0x00, 0x7C, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 },
-/* mode 5 */	{ 0x00, 0x78, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 },
-/* mode 6 */	{ 0x80, 0x59, 0x17, 0x42, 0xA3, 0x44, 0x75, 0x12 },
-/* mode 7 */	{ 0x80, 0x9A, 0x17, 0xB1, 0x13, 0x60, 0xB5, 0x14 },
-/* mode 8 */	{ 0x80, 0x3C, 0x27, 0xC1, 0x23, 0x44, 0x75, 0x21 } };
+/* mode 0 */	{ FRESP_06H_COMPST, 0xD9, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 },
+/* mode 1 */	{ FRESP_06H_COMPST, 0xD8, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 },
+/* mode 2 */	{ FRESP_06H_COMPST, 0xBA, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 },
+/* mode 3 */	{ FRESP_06H_COMPST, 0xB8, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 },
+/* mode 4 */	{ FRESP_06H_COMPST, 0x7C, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 },
+/* mode 5 */	{ FRESP_06H_COMPST, 0x78, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 },
+/* mode 6 */	{ FRESP_06H_SVIDEO, 0x59, 0x17, 0x42, 0xA3, 0x44, 0x75, 0x12 },
+/* mode 7 */	{ FRESP_06H_SVIDEO, 0x9A, 0x17, 0xB1, 0x13, 0x60, 0xB5, 0x14 },
+/* mode 8 */	{ FRESP_06H_SVIDEO, 0x3C, 0x27, 0xC1, 0x23, 0x44, 0x75, 0x21 } };
 	struct saa7110* decoder = device->data;
 	const unsigned char* ptr = modes[chan];
 
@@ -137,67 +150,78 @@
 	saa7110_write(decoder,0x30,ptr[5]);	/* ADCs gain control	*/
 	saa7110_write(decoder,0x31,ptr[6]);	/* Mixer Control #3	*/
 	saa7110_write(decoder,0x21,ptr[7]);	/* Analog Control #2	*/
+	decoder->input = chan;
 
 	return 0;
 }
 
+static	const unsigned char initseq[] = {
+  	   0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF2, 0x03, 0x00,
+  	      0xF8, 0xF8, 0x60, 0x60, 0x00, 0x86, 0x18, 0x90,
+  	      0x00, 0x59, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA,
+  	      0xF2, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  	      0xD9, 0x16, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F,
+  	      0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x03, 0x0C,
+  	      0x44, 0x71, 0x02, 0x8C, 0x02};
+
 static
-int determine_norm(struct i2c_device* dev)
+int determine_norm(struct i2c_device* device)
 {
-	struct	saa7110* decoder = dev->data;
+	struct	saa7110* decoder = device->data;
 	int	status;
 
 	/* mode changed, start automatic detection */
+	saa7110_write_block(decoder, initseq, sizeof(initseq));
+	saa7110_selmux(device, decoder->input);
+	sleep_on_timeout(&decoder->wq, HZ/4);
 	status = saa7110_read(decoder);
+	if (status & 0x40) {
+	    DEBUG(printk(KERN_INFO "%s: status=0x%02x (no signal)\n",device->name, status));
+	    return decoder->norm; // no change
+	}
 	if ((status & 3) == 0) {
-		saa7110_write(decoder,0x06,0x80);
+		saa7110_write(decoder,0x06,0x83);
 		if (status & 0x20) {
-			DEBUG(printk(KERN_INFO "%s: norm=bw60\n",dev->name));
-			saa7110_write(decoder,0x2E,0x81);
+			DEBUG(printk(KERN_INFO "%s: status=0x%02x (NTSC/no color)\n",device->name, status));
+			//saa7110_write(decoder,0x2E,0x81);
 			return VIDEO_MODE_NTSC;
 		}
-		DEBUG(printk(KERN_INFO "%s: norm=bw50\n",dev->name));
-		saa7110_write(decoder,0x2E,0x9A);
+		DEBUG(printk(KERN_INFO "%s: status=0x%02x (PAL/no color)\n",device->name, status));
+		//saa7110_write(decoder,0x2E,0x9A);
 		return VIDEO_MODE_PAL;
 	}
 
-	saa7110_write(decoder,0x06,0x00);
+	//saa7110_write(decoder,0x06,0x03);
 	if (status & 0x20) {	/* 60Hz */
-		DEBUG(printk(KERN_INFO "%s: norm=ntsc\n",dev->name));
-		saa7110_write(decoder,0x0D,0x06);
+		DEBUG(printk(KERN_INFO "%s: status=0x%02x (NTSC)\n",device->name, status));
+		saa7110_write(decoder,0x0D,0x86);
+		saa7110_write(decoder,0x0F,0x50);
 		saa7110_write(decoder,0x11,0x2C);
-		saa7110_write(decoder,0x2E,0x81);
+		//saa7110_write(decoder,0x2E,0x81);
 		return VIDEO_MODE_NTSC;
 	}
 
 	/* 50Hz -> PAL/SECAM */
-	saa7110_write(decoder,0x0D,0x06);
+	saa7110_write(decoder,0x0D,0x86);
+	saa7110_write(decoder,0x0F,0x10);
 	saa7110_write(decoder,0x11,0x59);
-	saa7110_write(decoder,0x2E,0x9A);
+	//saa7110_write(decoder,0x2E,0x9A);
 
-	mdelay(150);	/* pause 150 ms */
+	sleep_on_timeout(&decoder->wq, HZ/4);
 
 	status = saa7110_read(decoder);
 	if ((status & 0x03) == 0x01) {
-		DEBUG(printk(KERN_INFO "%s: norm=secam\n",dev->name));
-		saa7110_write(decoder,0x0D,0x07);
+		DEBUG(printk(KERN_INFO "%s: status=0x%02x (SECAM)\n",device->name, status));
+		saa7110_write(decoder,0x0D,0x87);
 		return VIDEO_MODE_SECAM;
 	}
-	DEBUG(printk(KERN_INFO "%s: norm=pal\n",dev->name));
+	DEBUG(printk(KERN_INFO "%s: status=0x%02x (PAL)\n",device->name, status));
 	return VIDEO_MODE_PAL;
 }
 
 static
 int saa7110_attach(struct i2c_device *device)
 {
-static	const unsigned char initseq[] = {
-	     0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF0, 0x00, 0x00,
-		0xF8, 0xF8, 0x60, 0x60, 0x00, 0x06, 0x18, 0x90,
-		0x00, 0x2C, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA,
-		0xF0, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0xD9, 0x17, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F,
-		0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x81, 0x03,
-		0x40, 0x75, 0x01, 0x8C, 0x03};
 	struct	saa7110*	decoder;
 	int			rv;
 
@@ -219,17 +243,30 @@
 	decoder->contrast = 32768;
 	decoder->hue = 32768;
 	decoder->sat = 32768;
+        
+        init_waitqueue_head(&decoder->wq);
 
 	rv = saa7110_write_block(decoder, initseq, sizeof(initseq));
 	if (rv < 0)
 		printk(KERN_ERR "%s_attach: init status %d\n", device->name, rv);
 	else {
-		saa7110_write(decoder,0x21,0x16);
+		int ver, status;
+		saa7110_write(decoder,0x21,0x10);
+		saa7110_write(decoder,0x0e,0x18);
 		saa7110_write(decoder,0x0D,0x04);
-		DEBUG(printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7110_read(decoder)));
+		ver = saa7110_read(decoder);
 		saa7110_write(decoder,0x0D,0x06);
+		//mdelay(150);
+		status = saa7110_read(decoder);
+		printk(KERN_INFO "%s_attach: SAA7110A version %x at 0x%02x, status=0x%02x\n", device->name, ver, device->addr, status);
+		saa7110_write(decoder, 0x0D, 0x86);
+		saa7110_write(decoder, 0x0F, 0x10);
+		saa7110_write(decoder, 0x11, 0x59);
+		//saa7110_write(decoder, 0x2E, 0x9A);
 	}
 
+        //saa7110_selmux(device,0);
+        //determine_norm(device);
 	/* setup and implicit mode 0 select has been performed */
 	return 0;
 }
@@ -263,8 +300,7 @@
 			dc->flags = VIDEO_DECODER_PAL
 				  | VIDEO_DECODER_NTSC
 				  | VIDEO_DECODER_SECAM
-				  | VIDEO_DECODER_AUTO
-				  | VIDEO_DECODER_CCIR;
+				  | VIDEO_DECODER_AUTO;
 			dc->inputs = SAA7110_MAX_INPUT;
 			dc->outputs = SAA7110_MAX_OUTPUT;
 		}
@@ -277,7 +313,8 @@
 			int res = 0;
 
 			status = i2c_read(device->bus,device->addr|1);
-			if (status & 0x40)
+			DEBUG(printk(KERN_INFO "%s: status=0x%02x norm=%d\n",device->name, status, decoder->norm));
+			if (!(status & 0x40))
 				res |= DECODER_STATUS_GOOD;
 			if (status & 0x03)
 				res |= DECODER_STATUS_COLOR;
@@ -301,26 +338,33 @@
 		v = *(int*)arg;
 		if (decoder->norm != v) {
 			decoder->norm = v;
-			saa7110_write(decoder, 0x06, 0x00);
+			//saa7110_write(decoder, 0x06, 0x03);
 			switch (v) {
 			 case VIDEO_MODE_NTSC:
-				saa7110_write(decoder, 0x0D, 0x06);
+				saa7110_write(decoder, 0x0D, 0x86);
+				saa7110_write(decoder, 0x0F, 0x50);
 				saa7110_write(decoder, 0x11, 0x2C);
-				saa7110_write(decoder, 0x30, 0x81);
-				saa7110_write(decoder, 0x2A, 0xDF);
+				//saa7110_write(decoder, 0x2E, 0x81);
+	    	    	    	DEBUG(printk(KERN_INFO "%s: switched to NTSC\n",device->name));
 				break;
 			 case VIDEO_MODE_PAL:
-				saa7110_write(decoder, 0x0D, 0x06);
+				saa7110_write(decoder, 0x0D, 0x86);
+				saa7110_write(decoder, 0x0F, 0x10);
 				saa7110_write(decoder, 0x11, 0x59);
-				saa7110_write(decoder, 0x2E, 0x9A);
+				//saa7110_write(decoder, 0x2E, 0x9A);
+	    	    	    	DEBUG(printk(KERN_INFO "%s: switched to PAL\n",device->name));
 				break;
 			 case VIDEO_MODE_SECAM:
-				saa7110_write(decoder, 0x0D, 0x07);
+				saa7110_write(decoder, 0x0D, 0x87);
+				saa7110_write(decoder, 0x0F, 0x10);
 				saa7110_write(decoder, 0x11, 0x59);
-				saa7110_write(decoder, 0x2E, 0x9A);
+				//saa7110_write(decoder, 0x2E, 0x9A);
+	    	    	    	DEBUG(printk(KERN_INFO "%s: switched to SECAM\n",device->name));
 				break;
 			 case VIDEO_MODE_AUTO:
-				*(int*)arg = determine_norm(device);
+	    	    	    	DEBUG(printk(KERN_INFO "%s: TV standard detection...\n",device->name));
+				decoder->norm = determine_norm(device);
+				*(int*)arg = decoder->norm;
 				break;
 			 default:
 				return -EPERM;
@@ -330,11 +374,13 @@
 
 	 case DECODER_SET_INPUT:
 		v = *(int*)arg;
-		if (v<0 || v>SAA7110_MAX_INPUT)
+		if (v<0 || v>SAA7110_MAX_INPUT) {
+	    	    	DEBUG(printk(KERN_INFO "%s: input=%d not available\n",device->name, v));
 			return -EINVAL;
+		}
 		if (decoder->input != v) {
-			decoder->input = v;
 			saa7110_selmux(device, v);
+	    	    	DEBUG(printk(KERN_INFO "%s: switched to input=%d\n",device->name, v));
 		}
 		break;
 
@@ -349,7 +395,8 @@
 		v = *(int*)arg;
 		if (decoder->enable != v) {
 			decoder->enable = v;
-			saa7110_write(decoder,0x0E, v ? 0x18 : 0x00);
+	                saa7110_write(decoder,0x0E, v ? 0x18 : 0x80);
+			DEBUG(printk(KERN_INFO "%s: YUV %s\n",device->name,v ? "on" : "off"));
 		}
 		break;
 
@@ -381,7 +428,7 @@
 		break;
 
 	 case DECODER_DUMP:
-		for (v=0; v<34; v+=16) {
+		for (v=0; v<0x34; v+=16) {
 			int j;
 			DEBUG(printk(KERN_INFO "%s: %03x\n",device->name,v));
 			for (j=0; j<16; j++) {
@@ -392,7 +439,7 @@
 		break;
 
 	 default:
-		DEBUG(printk(KERN_INFO "unknown saa7110_command?(%d)\n",cmd));
+		DEBUG(printk(KERN_INFO "unknown saa7110_command??(%d)\n",cmd));
 		return -EINVAL;
 	}
 	return 0;
@@ -400,12 +447,12 @@
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_saa7110 =
+struct i2c_driver i2c_driver_saa7110 =
 {
 	"saa7110",			/* name */
 
-	I2C_DRIVERID_VIDEODECODER,	/* in i2c.h */
-	I2C_SAA7110, I2C_SAA7110+1,	/* Addr range */
+	I2C_DRIVERID_VIDEODECODER,		/* in i2c.h */
+	I2C_SAA7110, I2C_SAA7110+3,	/* Addr range */
 
 	saa7110_attach,
 	saa7110_detach,
@@ -414,17 +461,17 @@
 
 EXPORT_NO_SYMBOLS;
 
-static int saa7110_init(void)
+int saa7110_init(void)
 {
 	return i2c_register_driver(&i2c_driver_saa7110);
 }
 
-static void saa7110_exit(void)
+void saa7110_exit(void)
 {
 	i2c_unregister_driver(&i2c_driver_saa7110);
 }
 
-
 module_init(saa7110_init);
 module_exit(saa7110_exit);
 MODULE_LICENSE("GPL");
+

[Index of Archives]     [Linux DVB]     [Video Disk Recorder]     [Asterisk]     [Photo]     [DCCP]     [Netdev]     [Xorg]     [Util Linux NG]     [Xfree86]     [Free Photo Albums]     [Fedora Users]     [Fedora Women]     [ALSA Users]     [ALSA Devel]     [Linux USB]

Powered by Linux