Subject: [PATCH 6 of 6] USB stv680 bugfix
From: Greg KH <[email-masked]>
To: Marcelo Tosatti <[email-masked]>
Cc: [email-masked], [email-masked]

Hi,

Here's a patch against 2.4.18-pre4 that fixes the following bugs in the
USB stv680 driver:
	- fixed the problem with webcam crashing after two pictures
	- changed way pic is halved to improve quality
	- got rid of green line around frame
	- fixed brightness reset when changing size
	- adjusted gamma filters slightly.
It was written by Kevin Sisson.

thanks,

greg k-h

diff -Nru a/drivers/usb/stv680.c b/drivers/usb/stv680.c
--- a/drivers/usb/stv680.c	Wed Jan 16 12:10:57 2002
+++ b/drivers/usb/stv680.c	Wed Jan 16 12:10:57 2002
@@ -43,6 +43,13 @@
  * 			   Took out sharpen function, ran code through
  * 			   Lindent, and did other minor tweaks to get
  * 			   things to work properly with 2.5.1
+ *
+ * ver 0.24 Jan, 2002 (kjs) 
+ *                         Fixed the problem with webcam crashing after
+ *                         two pictures. Changed the way pic is halved to 
+ *                         improve quality. Got rid of green line around 
+ *                         frame. Fix brightness reset when changing size 
+ *                         bug. Adjusted gamma filters slightly.
  */
 
 #include <linux/config.h>
@@ -65,7 +72,8 @@
 #include "stv680.h"
 
 static int video_nr = -1;
-static int swapRGB = 0;
+static int swapRGB = 0;   /* default for auto sleect */
+static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */
 
 static unsigned int debug = 0;
 
@@ -79,7 +87,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.23"
+#define DRIVER_VERSION "v0.24"
 #define DRIVER_AUTHOR "Kevin Sisson <[email-masked]>"
 #define DRIVER_DESC "STV0680 USB Camera Driver"
 
@@ -88,8 +96,8 @@
 MODULE_LICENSE ("GPL");
 MODULE_PARM (debug, "i");
 MODULE_PARM_DESC (debug, "Debug enabled or not");
-MODULE_PARM (swapRGB, "i");
-MODULE_PARM_DESC (swapRGB, "Swap red and blue, e.g., for xawtv");
+MODULE_PARM (swapRGB_on, "i");
+MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never");
 MODULE_PARM (video_nr, "i");
 EXPORT_NO_SYMBOLS;
 
@@ -521,8 +529,15 @@
 	stv680->palette = STV_VIDEO_PALETTE;
 	stv680->depth = 24;	/* rgb24 bits */
 	swapRGB = 0;
-	PDEBUG (1, "STV(i): swapRGB is OFF");
-
+	if ((swapRGB_on == 0) && (swapRGB == 0))
+		PDEBUG (1, "STV(i): swapRGB is (auto) OFF");
+	else if ((swapRGB_on == 1) && (swapRGB == 1))
+		PDEBUG (1, "STV(i): swapRGB is (auto) ON");
+	else if (swapRGB_on == 1)
+		PDEBUG (1, "STV(i): swapRGB is (forced) ON");
+	else if (swapRGB_on == -1)
+		PDEBUG (1, "STV(i): swapRGB is (forced) OFF");
+	
 	if (stv_set_video_mode (stv680) < 0) {
 		PDEBUG (0, "STV(e): Could not set video mode in stv_init");
 		return -1;
@@ -543,6 +558,7 @@
 extern struct proc_dir_entry *video_proc_entry;
 
 #define YES_NO(x) ((x) ? "yes" : "no")
+#define ON_OFF(x) ((x) ? "(auto) on" : "(auto) off")
 
 static int stv680_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -559,7 +575,13 @@
 	out += sprintf (out, "num_frames      : %d\n", STV680_NUMFRAMES);
 
 	out += sprintf (out, "Current size    : %ix%i\n", stv680->vwidth, stv680->vheight);
-	out += sprintf (out, "swapRGB         : %s\n", YES_NO (swapRGB));
+	if (swapRGB_on == 0)
+		out += sprintf (out, "swapRGB         : %s\n", ON_OFF (swapRGB));
+	else if (swapRGB_on == 1)
+		out += sprintf (out, "swapRGB         : (forced) on\n");
+	else if (swapRGB_on == -1)
+		out += sprintf (out, "swapRGB         : (forced) off\n");
+
 	out += sprintf (out, "Palette         : %i", stv680->palette);
 
 	out += sprintf (out, "\n");
@@ -671,9 +693,7 @@
 	if (stv680->brightness != p->brightness) {
 		stv680->chgbright = 1;
 		stv680->brightness = p->brightness;
-	} else {
-		stv680->chgbright = 0;
-	}
+	} 
 
 	stv680->whiteness = p->whiteness;	/* greyscale */
 	stv680->colour = p->colour;
@@ -888,7 +908,7 @@
 {
 	int x, y, i;
 	int w = stv680->cwidth;
-	int vw = stv680->cwidth, vh = stv680->cheight, vstep = 1;
+	int vw = stv680->cwidth, vh = stv680->cheight;
 	unsigned int p = 0;
 	int colour = 0, bayer = 0;
 	unsigned char *raw = buffer->data;
@@ -908,46 +928,23 @@
 		return;
 	}
 
-	if ((stv680->vwidth == 322) || (stv680->vwidth == 320)) {
+	if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) {
 		vw = 320;
 		vh = 240;
-		vstep = 1;
 	}
-	if ((stv680->vwidth == 352)) {
+	if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) {
 		vw = 352;
 		vh = 288;
-		vstep = 1;
 	}
-	if ((stv680->vwidth == 160)) {
-		vw = 160;
-		vh = 120;
-		vstep = 2;
-	}
-	if ((stv680->vwidth == 176)) {
-		vw = 176;
-		vh = 144;
-		vstep = 2;
-	}
-	memset (output, 0, 3 * vw * vh);	/* clear output matrix. Maybe not necessary. */
+
+	memset (output, 0, 3 * vw * vh);	/* clear output matrix. */
 
 	for (y = 0; y < vh; y++) {
 		for (x = 0; x < vw; x++) {
-
-			switch (vstep) {
-			case 1:
-				if (x & 1)
-					p = *(raw + y * w + (x >> 1));
-				else
-					p = *(raw + y * w + (x >> 1) + (w >> 1));
-				break;
-
-			case 2:
-				if (x & 1)
-					p = *(raw + ((y * w) << 1) + x);
-				else
-					p = *(raw + ((y * w) << 1) + x + (w >> 1));
-				break;
-			}
+			if (x & 1)
+				p = *(raw + y * w + (x >> 1));
+			else
+				p = *(raw + y * w + (x >> 1) + (w >> 1));
 
 			if (y & 1)
 				bayer = 2;
@@ -968,9 +965,10 @@
 				colour = 2;
 				break;
 			}
-			i = (y * vw + x) * 3;	/* output already zeroed out with memset */
+			i = (y * vw + x) * 3;	
 			*(output + i + colour) = (unsigned char) p;
 		}		/* for x */
+
 	}			/* for y */
 
 	/****** gamma correction plus hardcoded white balance */
@@ -979,6 +977,7 @@
 	   (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255. 
 	   White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and 
 	   converted to unsigned char. Values are in stv680.h  */
+
 	for (y = 0; y < vh; y++) {
 		for (x = 0; x < vw; x++) {
 			i = (y * vw + x) * 3;
@@ -1022,8 +1021,47 @@
 		}		/* for x */
 	}			/* for y  - end demosaic  */
 
+	/* fix top and bottom row, left and right side */
+	i = vw * 3;
+	memcpy (output, (output + i), i);
+	memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i);
+	for (y = 0; y < vh; y++) {
+		i = y * vw * 3;
+		memcpy ((output + i), (output + i + 3), 3);
+		memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3);
+	}
+
+	/*  process all raw data, then trim to size if necessary */
+	if ((stv680->vwidth == 160) || (stv680->vwidth == 176))  {
+		i = 0;
+		for (y = 0; y < vh; y++) {
+			if (!(y & 1)) {
+				for (x = 0; x < vw; x++) {
+					p = (y * vw + x) * 3;
+					if (!(x & 1)) {
+						*(output + i) = *(output + p);
+						*(output + i + 1) = *(output + p + 1);
+						*(output + i + 2) = *(output + p + 2);
+						i += 3;
+					}
+				}  /* for x */
+			}
+		}  /* for y */
+	}
+	/* reset to proper width */
+	if ((stv680->vwidth == 160)) {
+		vw = 160;
+		vh = 120;
+	}
+	if ((stv680->vwidth == 176)) {
+		vw = 176;
+		vh = 144;
+	}
+
 	/* output is RGB; some programs want BGR  */
-	if (swapRGB == 1) {
+	/* swapRGB_on=0 -> program decides;  swapRGB_on=1, always swap */
+	/* swapRGB_on=-1, never swap */
+	if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) {
 		for (y = 0; y < vh; y++) {
 			for (x = 0; x < vw; x++) {
 				i = (y * vw + x) * 3;
@@ -1242,7 +1280,7 @@
 				return -EFAULT;
 			}
 			copy_from_user (&p, arg, sizeof (p));
-			PDEBUG (2, "STV(i): palette set to RGB in VIDIOSPICT");
+			PDEBUG (2, "STV(i): palette set to %i in VIDIOSPICT", p.palette);
 
 			if (stv680_set_pict (stv680, &p))
 				return -EINVAL;
@@ -1309,8 +1347,8 @@
 			if (vm.format != STV_VIDEO_PALETTE) {
 				PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)",
 					vm.format, STV_VIDEO_PALETTE);
-				if (vm.format == 3) {
-					PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is ON");
+				if ((vm.format == 3) && (swapRGB_on == 0))  {
+					PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON");
 					/* this may fix those apps (e.g., xawtv) that want BGR */
 					swapRGB = 1;
 				}
@@ -1320,8 +1358,10 @@
 				PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES");
 				return -EINVAL;
 			}
-			if (stv680->frame[vm.frame].grabstate != FRAME_UNUSED) {
-				PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate != FRAME_UNUSED");
+			if ((stv680->frame[vm.frame].grabstate == FRAME_ERROR)
+			    || (stv680->frame[vm.frame].grabstate == FRAME_GRABBING)) {
+				PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error",
+					stv680->frame[vm.frame].grabstate);
 				return -EBUSY;
 			}
 			/* Is this according to the v4l spec??? */
diff -Nru a/drivers/usb/stv680.h b/drivers/usb/stv680.h
--- a/drivers/usb/stv680.h	Wed Jan 16 12:10:58 2002
+++ b/drivers/usb/stv680.h	Wed Jan 16 12:10:58 2002
@@ -43,7 +43,7 @@
 #define USB_PENCAM_PRODUCT_ID	0x0202
 #define PENCAM_TIMEOUT          1000
 /* fmt 4 */
-#define STV_VIDEO_PALETTE    VIDEO_PALETTE_RGB24
+#define STV_VIDEO_PALETTE       VIDEO_PALETTE_RGB24
 
 static __devinitdata struct usb_device_id device_table[] = {
 	{USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
@@ -146,77 +146,78 @@
 	int nullpackets;
 };
 
-unsigned char red[256] = {
-	0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-	21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47,
-	50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77,
-	79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97,
-	98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113,
-	114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126,
-	127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
-	139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149,
-	150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159,
-	160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
-	169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177,
-	177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185,
-	186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193,
-	193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200,
-	201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207,
-	208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214,
-	214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220,
-	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
-	227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233,
-	233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
-	239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244,
-	245, 245, 246, 246
-};
+
+unsigned char red[256] = { 
+	0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
+	18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, 
+	44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, 
+	71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, 
+	88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, 
+	102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 
+	114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, 
+	125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 
+	134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 
+	143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, 
+	152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, 
+	159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, 
+	167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, 
+	173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, 
+	180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, 
+	187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, 
+	192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, 
+	198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, 
+	204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, 
+	209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 
+	215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, 
+	220, 220, 221, 221 
+}; 
 
 unsigned char green[256] = {
-	0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-	24, 24, 24, 24, 24, 24, 24, 32, 39, 45, 50, 54,
-	58, 62, 65, 69, 71, 74, 77, 79, 83, 85, 87, 90,
-	92, 93, 95, 98, 100, 101, 104, 106, 107, 109, 111, 113,
-	114, 116, 118, 119, 121, 122, 124, 126, 127, 128, 129, 132,
-	133, 134, 135, 136, 138, 140, 141, 142, 143, 145, 146, 147,
-	148, 149, 150, 152, 153, 154, 155, 156, 157, 159, 160, 161,
-	162, 163, 164, 166, 167, 168, 168, 169, 170, 171, 173, 174,
-	175, 176, 176, 177, 179, 180, 181, 182, 182, 183, 184, 186,
-	187, 187, 188, 189, 190, 191, 191, 193, 194, 195, 195, 196,
-	197, 198, 198, 200, 201, 201, 202, 203, 204, 204, 205, 207,
-	207, 208, 209, 209, 210, 211, 212, 212, 214, 215, 215, 216,
-	217, 217, 218, 218, 219, 221, 221, 222, 223, 223, 224, 225,
-	225, 226, 226, 228, 229, 229, 230, 231, 231, 232, 232, 233,
-	235, 235, 236, 236, 237, 238, 238, 239, 239, 241, 241, 242,
-	243, 243, 244, 244, 245, 245, 246, 248, 248, 249, 249, 250,
-	250, 251, 251, 252, 253, 253, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255
-};
+	0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 
+	21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, 
+	50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, 
+	79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, 
+	98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, 
+	114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 
+	127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 
+	139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 
+	150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, 
+	160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, 
+	169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 
+	177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, 
+	186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 
+	193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 
+	201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, 
+	208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 
+	214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, 
+	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+	227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 
+	233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 
+	239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, 
+	245, 245, 246, 246 
+}; 
 
 unsigned char blue[256] = {
-	0, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
-	31, 31, 31, 31, 31, 31, 31, 41, 50, 57, 63, 69,
-	74, 78, 82, 87, 90, 94, 97, 100, 105, 108, 111, 113,
-	116, 118, 121, 124, 127, 128, 131, 134, 136, 139, 140, 143,
-	145, 148, 149, 150, 153, 155, 156, 159, 161, 162, 164, 167,
-	168, 170, 171, 173, 174, 177, 179, 180, 182, 183, 185, 186,
-	187, 189, 190, 192, 193, 195, 196, 198, 199, 201, 202, 204,
-	205, 207, 208, 210, 211, 213, 213, 214, 216, 217, 219, 220,
-	222, 223, 223, 224, 226, 227, 229, 230, 230, 232, 233, 235,
-	236, 236, 238, 239, 241, 242, 242, 244, 245, 247, 247, 248,
-	250, 251, 251, 253, 254, 254, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255
-};
+	0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 
+	23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, 
+	55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, 
+	86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, 
+	107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 
+	125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, 
+	139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 
+	152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, 
+	165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 
+	176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, 
+	185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, 
+	194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, 
+	204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, 
+	212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, 
+	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+	228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, 
+	235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, 
+	243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, 
+	249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, 
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+	255, 255, 255, 255 
+};