diff -Naur linux-2.4.0-test12-ov511-1.29/Documentation/usb/ov511.txt linux/Documentation/usb/ov511.txt
--- linux-2.4.0-test12-ov511-1.29/Documentation/usb/ov511.txt	Thu Jan  4 03:55:50 2001
+++ linux/Documentation/usb/ov511.txt	Thu Jan  4 03:56:18 2001
@@ -8,7 +8,7 @@
 INTRODUCTION:
 
 This is a driver for the OV511, a USB-only chip used in many "webcam" devices.
-Any camera using the OV511/OV511+ and the OV7610/20/20AE CCD should work. It 
+Any camera using the OV511/OV511+ and the OV6620/OV7610/20/20AE CCD should work. It 
 supports streaming and capture of color or monochrome video via the Video4Linux
 API. Most V4L apps are compatible with it, but a few video-conferencing programs
 do not work yet. The following resolutions are supported: 640x480, 448x336,
@@ -29,14 +29,14 @@
 
 You must have first compiled USB support, support for your specific USB host
 controller (UHCI or OHCI), and Video4Linux support for your kernel (I recommend
-making them modules.)
+making them modules.) Make sure "Enforce bandwidth allocation" is NOT enabled.
 
-Next, (as root) from your appropriate modules directory (lib/modules/2.3.XX):
+Next, (as root):
 
-	insmod usb/usbcore.o
-	insmod usb/usb-uhci.o  <OR>  insmod usb/ohci-hcd.o
-	insmod misc/videodev.o
-	insmod usb/ov511.o
+	modprobe usbcore
+	modprobe usb-uhci  <OR>  modprobe usb-ohci
+	modprobe videodev
+	modprobe ov511
 
 If it is not already there (it usually is), create the video device:
 
@@ -60,21 +60,14 @@
 	
 [Using xawtv:]
 
-You must make some modifications to the source and compile it before you use it.
-(Note: this may not be applicable to versions other than 3.06)
-
-In src/Xawtv.ad, change xawtv.tv.width to 640 and xawtv.tv.height to 480. Next,
-in src/grab-v4l.c, change SYNC_TIMEOUT from 1 to 2. Then, from the main xawtv
-directory:
+From the main xawtv directory:
 
 	make clean
 	./configure
 	make
 	make install
 
-Now you should be able to run xawtv. Right click for the options dialog. If
-you get a scrambled image it is likely that you made a mistake in Xawtv.ad.
-Try setting the size to 320x240 if all else fails.
+Now you should be able to run xawtv. Right click for the options dialog. 
 
 MODULE PARAMETERS:
 
@@ -218,13 +211,11 @@
  o Snapshot mode
  o GBR422 parsing
  o 160x120
+ o OV6630 sensor support
 
 TO-DO:
  o Fix the noise / grainy image problem.
- o Get compression working. It would be a nice addition as it improves
-   frame rate quite a bit. OmniVision wouldn't tell me how the algorithm works,
-   so we can't really work on that yet. Please kindly inform OmniVision that you
-   would like them to release their specifications to the Linux community.
+ o Get compression working.
  o YUV422
  o Fix fixFrameRGBoffset(). It is not stable yet with streaming video.
  o V4L2 support (Probably not until it goes into the kernel)
@@ -238,8 +229,9 @@
  o The image should always be written properly to the mmap'ed buffer as long as
    the requested image size is at least the minimum size. This will likely
    require a rewrite of all the parsing code.
- o OV6630 and OV8600 sensor support (both are undocumented and not in use yet)
+ o OV8600 sensor support (Not used in anything yet)
  o OV518+ support
+ o cams >= 3 not working
 
 HOW TO CONTACT ME:
 
diff -Naur linux-2.4.0-test12-ov511-1.29/drivers/usb/ov511.c linux/drivers/usb/ov511.c
--- linux-2.4.0-test12-ov511-1.29/drivers/usb/ov511.c	Thu Jan  4 03:56:03 2001
+++ linux/drivers/usb/ov511.c	Thu Jan  4 04:11:02 2001
@@ -30,7 +30,7 @@
  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-static const char version[] = "1.29";
+static const char version[] = "1.30";
 
 #define __NO_VERSION__
 
@@ -155,8 +155,6 @@
 MODULE_AUTHOR("Mark McClelland <mwm@i.am> & Bret Wallach & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha <cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>");
 MODULE_DESCRIPTION("OV511 USB Camera Driver");
 
-char kernel_version[] = UTS_RELEASE;
-
 static struct usb_driver ov511_driver;
 
 /* I know, I know, global variables suck. This is only a temporary hack */
@@ -186,7 +184,6 @@
 	{ idVendor: 0x05a9, idProduct: 0xA511 },  /* OV511+ */
 	{ idVendor: 0x05a9, idProduct: 0x0518 },  /* OV518+ */
 	{ idVendor: 0x0813, idProduct: 0x0002 },  /* Intel Play Me2Cam OV511+ */
-	{ idVendor: 0x041e, idProduct: 0x4003 },  /* Creative Webcam Go Plus */
 	{ }  /* Terminating entry */
 };
 
@@ -355,6 +352,7 @@
 	out += sprintf (out, "brightness      : %d\n", ov511->brightness >> 8);
 	out += sprintf (out, "colour          : %d\n", ov511->colour >> 8);
 	out += sprintf (out, "contrast        : %d\n", ov511->contrast >> 8);
+	out += sprintf (out, "hue             : %d\n", ov511->hue >> 8);
 	out += sprintf (out, "num_frames      : %d\n", OV511_NUMFRAMES);
 	for (i = 0; i < OV511_NUMFRAMES; i++) {
 		out += sprintf (out, "frame           : %d\n", i);
@@ -380,12 +378,16 @@
 	out += sprintf (out, "bridge          : %s\n",
 		ov511->bridge == BRG_OV511 ? "OV511" :
 		ov511->bridge == BRG_OV511PLUS ? "OV511+" :
+		ov511->bridge == BRG_OV518PLUS ? "OV518+" :
 		"unknown");
 	out += sprintf (out, "sensor          : %s\n",
 		ov511->sensor == SEN_OV6620 ? "OV6620" :
+		ov511->sensor == SEN_OV6630 ? "OV6630" :
 		ov511->sensor == SEN_OV7610 ? "OV7610" :
 		ov511->sensor == SEN_OV7620 ? "OV7620" :
 		ov511->sensor == SEN_OV7620AE ? "OV7620AE" :
+		ov511->sensor == SEN_OV8600 ? "OV8600" :
+		ov511->sensor == SEN_KS0127 ? "KS0127" :
 		"unknown");
 	out += sprintf (out, "packet_size     : %d\n", ov511->packet_size);
 	out += sprintf (out, "framebuffer     : 0x%p\n", ov511->fbuf);
@@ -522,6 +524,32 @@
 	}
 }
 
+/*
+ * Writes bits at positions specified by mask to a reg. Bits that are in
+ * the same position as 1's in "mask" are cleared and set to "value". Bits
+ * that are in the same position as 0's in "mask" are preserved, regardless 
+ * of their respective state in "value".
+ */
+static int ov511_reg_write_mask(struct usb_device *dev,
+				unsigned char reg,
+				unsigned char value,
+				unsigned char mask)
+{
+	int ret;
+	unsigned char oldval, newval;
+
+	ret = ov511_reg_read(dev, reg);
+	if (ret < 0)
+		return ret;
+
+	oldval = (unsigned char) ret;
+	oldval &= (~mask);		/* Clear the masked bits */
+	value &= mask;			/* Enforce mask on value */
+	newval = oldval | value;	/* Set the desired bits */
+
+	return (ov511_reg_write(dev, reg, newval));
+}
+
 static int ov511_i2c_write(struct usb_device *dev,
 			   unsigned char reg,
 			   unsigned char value)
@@ -808,6 +836,19 @@
 			err("Set packet size: invalid size (%d)", size);
 			return -EINVAL;
 		}
+	} else if (ov511->bridge == BRG_OV518PLUS) {
+		if (size == 0) alt = OV518PLUS_ALT_SIZE_0;
+		else if (size == 128) alt = OV518PLUS_ALT_SIZE_128;
+		else if (size == 256) alt = OV518PLUS_ALT_SIZE_256;
+		else if (size == 384) alt = OV518PLUS_ALT_SIZE_384;
+		else if (size == 512) alt = OV518PLUS_ALT_SIZE_512;
+		else if (size == 640) alt = OV518PLUS_ALT_SIZE_640;
+		else if (size == 768) alt = OV518PLUS_ALT_SIZE_768;
+		else if (size == 896) alt = OV518PLUS_ALT_SIZE_896;
+		else {
+			err("Set packet size: invalid size (%d)", size);
+			return -EINVAL;
+		}
 	} else {
 		err("Set packet size: Invalid bridge type");
 		return -EINVAL;
@@ -958,7 +999,7 @@
 ov511_led_control(struct usb_ov511 *ov511, int enable) {
 	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
 
-	if (ov511->bridge == BRG_OV511PLUS)
+	if (ov511->bridge == BRG_OV511PLUS)  // FIXME: OV518+?
 		ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_LED_CTL, 
 			        enable ? 1 : 0);
 		
@@ -1027,7 +1068,7 @@
 		ov511_reg_write(dev, 0x16, 0x00);
 		if (ov511->sensor == SEN_OV7610
 		    || ov511->sensor == SEN_OV7620AE) {
-			/* these aren't valid on the OV6620/OV7620 */
+			/* these aren't valid on the OV6620/OV7620/6630? */
 			ov511_i2c_write(dev, 0x0e, 0x44);
 		}
 		ov511_i2c_write_mask(dev, 0x13, autoadjust ? 0x21 : 0x20, 0x21);
@@ -1039,7 +1080,7 @@
 		ov511_reg_write(dev, 0x16, 0x01);
 		if (ov511->sensor == SEN_OV7610
 		    || ov511->sensor == SEN_OV7620AE) {
-			/* not valid on the OV6620/OV7620 */
+			/* not valid on the OV6620/OV7620/6630? */
 			ov511_i2c_write(dev, 0x0e, 0x04);
 		}
 		ov511_i2c_write_mask(dev, 0x13, autoadjust ? 0x01 : 0x00, 0x21);
@@ -1058,6 +1099,7 @@
 		vwsbase = vwebase = 0x05;
 		break;
 	case SEN_OV6620:
+	case SEN_OV6630:	// FIXME: Is this right?
 		hwsbase = 0x38;
 		hwebase = 0x3a;
 		vwsbase = 0x05;
@@ -1177,7 +1219,7 @@
 		if (ov511_i2c_write_mask(dev, 0x12, autoadjust ? 0x20 : 0x00, 0x20) < 0)
 			return -1;
 
-		/* 7620/6620 don't have register 0x35, so play it safe */
+		/* 7620/6620/6630? don't have register 0x35, so play it safe */
 		if (ov511->sensor == SEN_OV7610 ||
 		    ov511->sensor == SEN_OV7620AE)
 			ov511_i2c_write(dev, 0x35, mlist[i].common_L);
@@ -1714,10 +1756,19 @@
 	int aPackNum[10];
 	struct ov511_frame *frame;
 	unsigned char *pData;
-	int iPix;
+	int iPix, data_size, pn;
 
 	PDEBUG (4, "Moving %d packets", urb->number_of_packets);
 
+	/* OV518+ has no packet numbering */
+	if (ov511->bridge == BRG_OV518PLUS) {
+		pn = 0;
+		data_size = ov511->packet_size;
+	} else {
+		pn = 1;
+		data_size = ov511->packet_size - 1;
+	}
+
 	for (i = 0; i < urb->number_of_packets; i++) {
 		int n = urb->iso_frame_desc[i].actual_length;
 		int st = urb->iso_frame_desc[i].status;
@@ -1727,7 +1778,8 @@
 
 		cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
 
-		aPackNum[i] = n ? cdata[ov511->packet_size - 1] : -1;
+		if (pn)
+			aPackNum[i] = n ? cdata[ov511->packet_size - 1] : -1;
 
 		if (!n || ov511->curframe == -1)
 			continue;
@@ -1736,7 +1788,7 @@
 			PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st);
 
 		frame = &ov511->frame[ov511->curframe];
-		
+
 		/* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
 		 * byte non-zero. The EOF packet has image width/height in the
 		 * 10th and 11th bytes. The 9th bit is given as follows:
@@ -1764,8 +1816,9 @@
 			ts = (struct timeval *)(frame->data + MAX_FRAME_SIZE);
 			do_gettimeofday (ts);
 
-		 	PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d",
-				ov511->curframe, (int)(cdata[ov511->packet_size - 1]),
+	 		PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d",
+				ov511->curframe,
+				(int)(pn ? cdata[ov511->packet_size - 1] : -1),
 				(int)(cdata[9]), (int)(cdata[10]));
 
 			if (frame->scanstate == STATE_LINES) {
@@ -1839,7 +1892,7 @@
 	 	}
 
 		/* Parse the segments */
-		while (iPix <= (ov511->packet_size - 1) - frame->segsize &&
+		while (iPix <= data_size - frame->segsize &&
 		    frame->segment < frame->width * frame->height / 256) {
 			int iSegY, iSegUV;
 			int iY, jY, iUV, jUV;
@@ -1923,7 +1976,7 @@
 
 		/* Save extra data for next time */
 		if (frame->segment < frame->width * frame->height / 256) {
-			ov511->scratchlen = (ov511->packet_size - 1) - iPix;
+			ov511->scratchlen = data_size - iPix;
 			if (ov511->scratchlen < frame->segsize)
 				memmove(ov511->scratch, pData, ov511->scratchlen);
 			else
@@ -1931,9 +1984,11 @@
 		}
 	}
 
-	PDEBUG(5, "pn: %d %d %d %d %d %d %d %d %d %d",
-	       aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4],
-	       aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]);
+	if (pn) {
+		PDEBUG(5, "pn: %d %d %d %d %d %d %d %d %d %d",
+			aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4],
+			aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]);
+	}
 
 	return totlen;
 }
@@ -1960,9 +2015,14 @@
 		PDEBUG(4, "hmmm... not streaming, but got interrupt");
 		return;
 	}
-	
+
 	sbuf = &ov511->sbuf[ov511->cursbuf];
 
+	if (sbuf == NULL) {
+		err("null scrath buffer pointer!");
+		return;
+	}
+
 	/* Copy the data received into our scratch buffer */
 	if (ov511->curframe >= 0) {
 		len = ov511_move_data(ov511, urb);
@@ -1990,25 +2050,34 @@
 	ov511->cursbuf = 0;
 	ov511->scratchlen = 0;
 
-	if (ov511->bridge == BRG_OV511)
-		if (cams == 1)			 size = 993;
-		else if (cams == 2)		 size = 513;
-		else if (cams == 3 || cams == 4) size = 257;
+	if (ov511->bridge == BRG_OV511) {
+		if (cams == 1)				size = 993;
+		else if (cams == 2)			size = 513;
+		else if (cams == 3 || cams == 4)	size = 257;
 		else {
 			err("\"cams\" parameter too high!");
 			return -1;
 		}
-	else if (ov511->bridge == BRG_OV511PLUS)
-		if (cams == 1)                      size = 961;
-		else if (cams == 2)                 size = 513;
-		else if (cams == 3 || cams == 4) size = 257;
-		else if (cams >= 5 && cams <= 8)    size = 129;
-		else if (cams >= 9 && cams <= 31)   size = 33;
+	} else if (ov511->bridge == BRG_OV511PLUS) {
+		if (cams == 1)				size = 961;
+		else if (cams == 2)			size = 513;
+		else if (cams == 3 || cams == 4)	size = 257;
+		else if (cams >= 5 && cams <= 8)	size = 129;
+		else if (cams >= 9 && cams <= 31)	size = 33;
 		else {
 			err("\"cams\" parameter too high!");
 			return -1;
 		}
-	else {
+	} else if (ov511->bridge == BRG_OV518PLUS) {
+		if (cams == 1)				size = 896;
+		else if (cams == 2)			size = 512;
+		else if (cams == 3 || cams == 4)	size = 256;
+		else if (cams >= 5 && cams <= 8)	size = 128;
+		else {
+			err("\"cams\" parameter too high!");
+			return -1;
+		}
+	} else {
 		err("invalid bridge type");
 		return -1;
 	}
@@ -3118,6 +3187,86 @@
 		{ OV511_I2C_BUS, 0x4d, 0xd2 }, /* This reduces noise a bit */
 		{ OV511_I2C_BUS, 0x4e, 0xc1 },
 		{ OV511_I2C_BUS, 0x4f, 0x04 },
+// Do 50-53 have any effect?
+// Toggle 0x12[2] off and on here?
+		{ OV511_DONE_BUS, 0x0, 0x00 },
+	};
+
+	/* This chip is undocumented so many of these are guesses. OK=verified,
+	 * A=Added since 6620, U=unknown function (not a 6620 reg) */
+	static struct ov511_regvals aRegvalsNorm6x30[] = {
+	/*OK*/	{ OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
+	/*00?*/	{ OV511_I2C_BUS, 0x11, 0x01 },
+	/*OK*/	{ OV511_I2C_BUS, 0x03, 0x60 },
+	/*0A?*/	{ OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
+//		{ OV511_I2C_BUS, 0x07, 0xa8 }, /* Does 6630 have this? */
+		/* The ratio of 0x0c and 0x0d  controls the white point */
+	/*OK*/	{ OV511_I2C_BUS, 0x0c, 0x24 },
+	/*OK*/	{ OV511_I2C_BUS, 0x0d, 0x24 },
+	/*A*/	{ OV511_I2C_BUS, 0x0e, 0x20 },
+	/*24?*/	{ OV511_I2C_BUS, 0x12, 0x28 }, /* Enable AGC */
+	/*A*/	{ OV511_I2C_BUS, 0x13, 0x21 },
+	/*04?*/	{ OV511_I2C_BUS, 0x14, 0x80 },
+		/* 0x16: 0x06 helps frame stability with moving objects */
+	/*03?*/	{ OV511_I2C_BUS, 0x16, 0x06 },
+//	/*OK*/	{ OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
+		// 21 & 22? The suggested values look wrong. Go with default
+	/*A*/	{ OV511_I2C_BUS, 0x23, 0xc0 },
+	/*A*/	{ OV511_I2C_BUS, 0x25, 0x9a }, // Check this against default
+	/*OK*/	{ OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
+	/*04?*/	{ OV511_I2C_BUS, 0x28, 0x05 }, /* Selects RGB format if RGB on */
+	/*OK*/	{ OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
+//	/*OK*/	{ OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
+	/*U*/	{ OV511_I2C_BUS, 0x2c, 0xa0 },
+	/*A*/	{ OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620
+		// Reg 0x34: More 6620 reserved junk
+	/*d2?*/	{ OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */
+	/*U*/	{ OV511_I2C_BUS, 0x36, 0x8f }, // May not be necessary
+	/*U*/	{ OV511_I2C_BUS, 0x37, 0x80 }, // May not be necessary
+	/*8b?*/	{ OV511_I2C_BUS, 0x38, 0x83 },
+	/*40?*/	{ OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7
+		//Check these again
+		{ OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
+		{ OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
+		{ OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
+
+	/*OK*/	{ OV511_I2C_BUS, 0x3d, 0x80 },
+	/*A*/	{ OV511_I2C_BUS, 0x3f, 0x0e }, // Reserved bits on 6620. Default may be safer.
+
+	/*U*/	{ OV511_I2C_BUS, 0x40, 0x00 },
+	/*U*/	{ OV511_I2C_BUS, 0x41, 0x00 },
+	/*U*/	{ OV511_I2C_BUS, 0x42, 0x80 },
+	/*U*/	{ OV511_I2C_BUS, 0x43, 0x3f },
+	/*U*/	{ OV511_I2C_BUS, 0x44, 0x80 },
+	/*U*/	{ OV511_I2C_BUS, 0x45, 0x20 },
+	/*U*/	{ OV511_I2C_BUS, 0x46, 0x20 },
+	/*U*/	{ OV511_I2C_BUS, 0x47, 0x80 },
+	/*U*/	{ OV511_I2C_BUS, 0x48, 0x7f },
+	/*U*/	{ OV511_I2C_BUS, 0x49, 0x00 },
+
+		/* These next two registers (0x4a, 0x4b) are undocumented. They 
+		 * control the color balance */
+	/*OK?*/	{ OV511_I2C_BUS, 0x4a, 0x80 }, // Check these
+	/*OK?*/	{ OV511_I2C_BUS, 0x4b, 0x80 },
+	/*U*/	{ OV511_I2C_BUS, 0x4c, 0xd0 }, // These high registers are always suspect
+	/*d2?*/	{ OV511_I2C_BUS, 0x4d, 0x10 }, /* This reduces noise a bit */
+	/*c1?*/	{ OV511_I2C_BUS, 0x4e, 0x40 },
+	/*04?*/	{ OV511_I2C_BUS, 0x4f, 0x07 },
+
+	/*U*/	{ OV511_I2C_BUS, 0x50, 0xff }, // These are all undocumented (by 6620 docs)
+	/*U*/	{ OV511_I2C_BUS, 0x54, 0x23 },
+	/*U*/	{ OV511_I2C_BUS, 0x55, 0xff },
+	/*U*/	{ OV511_I2C_BUS, 0x56, 0x12 },
+	/*U*/	{ OV511_I2C_BUS, 0x57, 0x81 },
+	/*U*/	{ OV511_I2C_BUS, 0x58, 0x75 },
+	/*U*/	{ OV511_I2C_BUS, 0x59, 0x01 },
+	/*U*/	{ OV511_I2C_BUS, 0x5a, 0x2c },
+	/*U*/	{ OV511_I2C_BUS, 0x5b, 0x0f },
+	/*U*/	{ OV511_I2C_BUS, 0x5c, 0x10 },
+
+// Set 0x3d to 0x80 here?
+// Set 0x27 to 0xa6 here?
+// Toggle 0x12[2] off and on here?
 		{ OV511_DONE_BUS, 0x0, 0x00 },
 	};
 
@@ -3162,28 +3311,40 @@
 			return -1;
 		} else if((rc & 3) == 0) {
 			info("Sensor is an OV6630");
-			ov511->sensor = SEN_OV6620; /* Closest match? */
+			ov511->sensor = SEN_OV6630;
 		} else if((rc & 3) == 1) {
 			info("Sensor is an OV6620");
 			ov511->sensor = SEN_OV6620;
-		} else {
-			err("Sensor is an unknown OV6xx0 (version %d)", rc & 3);
-			err("Please email mwm@i.am to report this");
-			return -1;
-		}
+		} else if((rc & 3) == 2) {
+			info("Sensor is an OV6630AE");
+			ov511->sensor = SEN_OV6630;
+		} else if((rc & 3) == 3) {
+			info("Sensor is an OV6630AF");
+			ov511->sensor = SEN_OV6630;
+		} 
 	} else {	/* sensor != 0; user overrode detection */
 		ov511->sensor = sensor;
 		info("Sensor set to type %d", ov511->sensor);
 	}
 
 	/* Set sensor-specific vars */
-	ov511->maxwidth = 352;
-	ov511->maxheight = 288;
+	if (ov511->sensor == SEN_OV6620) {
+		ov511->maxwidth = 352;
+		ov511->maxheight = 288;
 
-	PDEBUG(4, "Writing 6x20 registers");
-	if (ov511_write_regvals(dev, aRegvalsNorm6x20))
-		return -1;
+		PDEBUG(4, "Writing 6x20 registers");
+		if (ov511_write_regvals(dev, aRegvalsNorm6x20))
+			return -1;
+	} else {
+		/* Oddly, 6630 series is 640x480 */
+		ov511->maxwidth = 640;
+		ov511->maxheight = 480;
 
+		PDEBUG(4, "Writing 6x30 registers");
+		if (ov511_write_regvals(dev, aRegvalsNorm6x30))
+			return -1;
+	}
+	
 	if (aperture < 0) {          /* go with the default */
 		if (ov511_i2c_write(dev, 0x26, 0xa2) < 0) return -1;
 	} else if (aperture <= 0xf) {  /* user overrode default */
@@ -3195,10 +3356,10 @@
 	}
 
 	if (autoadjust) {
-		if (ov511_i2c_write(dev, 0x13, 0x01) < 0) return -1;
+		if (ov511_i2c_write_mask(dev, 0x13, 0x01, 0x01) < 0) return -1;
 		if (ov511_i2c_write(dev, 0x2d, 0x99) < 0) return -1;
 	} else {
-		if (ov511_i2c_write(dev, 0x13, 0x00) < 0) return -1;
+		if (ov511_i2c_write_mask(dev, 0x13, 0x00, 0x01) < 0) return -1;
 		if (ov511_i2c_write(dev, 0x2d, 0x89) < 0) return -1;
 		if (ov511_i2c_write_mask(dev, 0x28, 0x08, 0x08) < 0) return -1;
 	}
@@ -3241,6 +3402,19 @@
 		{ OV511_DONE_BUS, 0x0, 0x00 },
 	};
 
+	static struct ov511_regvals aRegvalsNorm518Plus[] = {
+		{ OV511_REG_BUS, OV511_REG_DRAM_ENABLE_FLOW_CONTROL, 0x09 },
+		{ OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x02 },
+		{ OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x00 },
+		{ OV511_REG_BUS, OV511_REG_FIFO_BITMASK, 0x0f },
+		{ OV511_REG_BUS, 0x24, 0x9f },
+		{ OV511_REG_BUS, 0x25, 0x90 },
+		{ OV511_REG_BUS, OV511_REG_SYSTEM_CLOCK_DIVISOR, 0x04 }, /* ? */
+		{ OV511_REG_BUS, OV511_OMNICE_ENABLE, 0x00 },
+		{ OV511_REG_BUS, OV511_OMNICE_LUT_ENABLE, 0x00 },
+		{ OV511_DONE_BUS, 0x0, 0x00 },
+	};
+
 	memcpy(&ov511->vdev, &ov511_template, sizeof(ov511_template));
 
 	for (i = 0; i < OV511_NUMFRAMES; i++)
@@ -3258,7 +3432,13 @@
 	if (ov511->led_policy == LED_OFF || ov511->led_policy == LED_AUTO)
 		ov511_led_control(ov511, 0);
 
-	if (ov511_write_regvals(dev, aRegvalsNorm511)) goto error;
+	if (ov511->bridge == BRG_OV518PLUS) {
+		if (ov511_write_regvals(dev, aRegvalsNorm518Plus)) goto error;
+		/* The next setting may not be necessary */
+		if (ov511_reg_write_mask(dev, 0x57,0x00, 0x02) < 0) goto error;
+	} else {
+		if (ov511_write_regvals(dev, aRegvalsNorm511)) goto error;
+	}
 
 	ov511_set_packet_size(ov511, 0);
 
@@ -3342,6 +3522,13 @@
 	return 0;
 	
 error:
+	err("Config failed");
+
+	#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+	/* Safe to call even if entry doesn't exist */
+	destroy_proc_ov511_cam((struct usb_ov511 *)dev);
+	#endif
+
 	video_unregister_device(&ov511->vdev);
 	usb_driver_release_interface(&ov511_driver,
 		&dev->actconfig->interface[ov511->iface]);
@@ -3402,9 +3589,7 @@
 		break;
 	case 0x0518:
 		info("USB OV518+ camera found");
-		err("Warning: OV518+ not supported yet!");
-		ov511->bridge = BRG_OV511PLUS;	/* A safe default for now */
-//		ov511->bridge = BRG_OV518PLUS;
+		ov511->bridge = BRG_OV518PLUS;
 		break;
 	case 0x0002:
 		if (dev->descriptor.idVendor != 0x0813)
@@ -3412,12 +3597,6 @@
 		info("Intel Play Me2Cam (OV511+) found");
 		ov511->bridge = BRG_OV511PLUS;
 		break;
-	case 0x4003:
-		info("Creative WebCam Go Plus (OV518+) found");
-		err("Warning: Creative WebCam Go Plus not supported yet!");
-		ov511->bridge = BRG_OV511PLUS;	/* A safe default for now */
-//		ov511->bridge = BRG_OV518PLUS;
-		break;
 	default:
 		err("Unknown product ID");
 		goto error;
@@ -3465,7 +3644,6 @@
 		init_MUTEX(&ov511->buf_lock);
 		ov511->buf_state = BUF_NOT_ALLOCATED;
 	} else {
-		err("Failed to configure camera");
 		goto error;
 	}
 
@@ -3473,6 +3651,7 @@
      	return ov511;
 
 error:
+	err("Camera initialization failed");
 	if (ov511) {
 		kfree(ov511);
 		ov511 = NULL;
diff -Naur linux-2.4.0-test12-ov511-1.29/drivers/usb/ov511.h linux/drivers/usb/ov511.h
--- linux-2.4.0-test12-ov511-1.29/drivers/usb/ov511.h	Thu Jan  4 03:56:03 2001
+++ linux/drivers/usb/ov511.h	Thu Jan  4 04:11:03 2001
@@ -119,6 +119,16 @@
 #define OV511PLUS_ALT_SIZE_769	6
 #define OV511PLUS_ALT_SIZE_961	7
 
+/* Alternate numbers for various max packet sizes (OV518+ only) */
+#define OV518PLUS_ALT_SIZE_0	0
+#define OV518PLUS_ALT_SIZE_128	1
+#define OV518PLUS_ALT_SIZE_256	2
+#define OV518PLUS_ALT_SIZE_384	3
+#define OV518PLUS_ALT_SIZE_512	4
+#define OV518PLUS_ALT_SIZE_640	5
+#define OV518PLUS_ALT_SIZE_768	6
+#define OV518PLUS_ALT_SIZE_896	7
+
 /* OV7610 registers */
 #define OV7610_REG_GAIN          0x00	/* gain setting (5:0) */
 #define OV7610_REG_BLUE          0x01	/* blue channel balance */
@@ -179,8 +189,7 @@
 
 #define OV511_ENDPOINT_ADDRESS 1	/* Isoc endpoint number */
 
-// CAMERA SPECIFIC
-// FIXME - these can vary between specific models
+/* CAMERA SPECIFIC */
 #define OV7610_I2C_WRITE_ID 0x42
 #define OV7610_I2C_READ_ID  0x43
 #define OV6xx0_I2C_WRITE_ID 0xC0
@@ -213,6 +222,7 @@
 	SEN_OV6620,
 	SEN_OV6630,
 	SEN_OV8600,
+	SEN_KS0127,
 };
 
 enum {
