diff -Naur linux-2.4.0-test12/Documentation/usb/ov511.txt linux/Documentation/usb/ov511.txt
--- linux-2.4.0-test12/Documentation/usb/ov511.txt	Thu Dec 28 01:21:52 2000
+++ linux/Documentation/usb/ov511.txt	Thu Dec 28 02:18:37 2000
@@ -82,7 +82,7 @@
   There is currently no way to set these on a per-camera basis.
 
   NAME: autoadjust
-  TYPE: integer (boolean)
+  TYPE: integer (Boolean)
   DEFAULT: 1
   DESC: The camera normally adjusts exposure, gain, and hue automatically. This
         can be set to 0 to disable this automatic adjustment. Note that there is
@@ -102,7 +102,7 @@
           5=highly repetitive mesgs
 
   NAME: fix_rgb_offset
-  TYPE: integer (boolean)
+  TYPE: integer (Boolean)
   DEFAULT: 0
   DESC: Some people have reported that the blue component of the image is one
         or so lines higher than the red component. This is only apparent in 
@@ -111,7 +111,7 @@
         experimental and very buggy. You will likely need a fast (500 MHz) CPU.
 
   NAME: snapshot
-  TYPE: integer (boolean)
+  TYPE: integer (Boolean)
   DEFAULT: 0
   DESC: Set to 1 to enable snapshot mode. read() will block until the snapshot
         button is pressed. Note that this does not yet work with most apps,
@@ -144,7 +144,7 @@
         for if you want to play with the camera's pixel saturation.
 
   NAME: force_rgb
-  TYPE: integer (boolean)
+  TYPE: integer (Boolean)
   DEFAULT: 0
   DESC: Force image to be read in RGB instead of BGR. This option allow
         programs that expect RGB data (e.g. gqcam) to work with this driver. If
@@ -170,19 +170,39 @@
         finding the optimum setting.
 
   NAME: retry_sync
-  TYPE: boolean
+  TYPE: integer (Boolean)
   DEFAULT: 0
   DESC: Prevent apps from timing out if frame is not done in time. This is
         useful if you are having problems with Xawtv getting "stuck" on a frame
         when your system is under heavy load.
 
   NAME: sensor_gbr
-  TYPE: boolean
+  TYPE: integer (Boolean)
   DEFAULT: 0
   DESC: This makes the sensor output GBR422 instead of YUV420. This saves the
         driver the trouble of converting YUV to RGB, but it currently does not
         work very well (the colors are not quite right)
 
+  NAME: dumppix
+  TYPE: integer (0-3)
+  DEFAULT: 0
+  DESC: Dumps raw pixel data, in one of three formats. Only works with RGB24 
+	format, and is for debugging purposes only. Options are:
+	0: Disable (default)
+	1: Dump formatted YUV data. One RGB24 pixel per data byte.
+	2: Convert Y data to formatted "monochrome" RGB data
+	3: Dumps the Y channel as-is. One RGB24 pixel per data byte.
+	4: Dumps unformatted YUV data as-is.
+
+  NAME: led
+  TYPE: integer (0-2)
+  DEFAULT: 1 (Always on)
+  DESC: Controls whether the LED (the little light) on the front of the camera
+	is always off (0), always on (1), or only on when driver is open (2).
+	This is only supported with the OV511+ chipset, and even then only on
+	some cameras (ones that actually have the LED wired to the control pin,
+	and not just hardwired to be on all the time).
+
 WORKING FEATURES:
  o Color streaming/capture at 640x480, 448x336, 384x288, 352x288, and 320x240
  o RGB24, RGB565, YUV420, YUV422, YUYV, and YUV422P color
@@ -190,16 +210,16 @@
  o Setting/getting of saturation, contrast, brightness, and hue (only some of
    them work the OV7620 and OV7620AE)
  o /proc status reporting
+ o OV6620 sensor support
 
 EXPERIMENTAL FEATURES:
  o fix_rgb_offset: Sometimes works, but other times causes errors with xawtv and
    corrupted frames. If you have a very fast CPU, you can try it.
- o Snapshot mode (only works with some read() based apps; see below for more)
- o OV6620 sensor support
+ o Snapshot mode
  o GBR422 parsing
  o 160x120
 
-TODO:
+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,
@@ -213,12 +233,13 @@
  o Driver/camera state save/restore for when USB supports suspend/resume
  o Unstable on SMP systems
  o OV7620/OV6620 experience frame corruption with moving objects
- o OV6620 is too dark
  o 176x144 support
  o Driver sometimes hangs upon close() with OHCI
  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 OV518+ support
 
 HOW TO CONTACT ME:
 
@@ -232,3 +253,4 @@
 and the USB stack. Thanks to Bret Wallach for getting camera reg IO, ISOC, and
 image capture working. Thanks to Orion Sky Lawlor, Kevin Moore, and Claudio
 Matsuoka for their work as well.
+
diff -Naur linux-2.4.0-test12/drivers/usb/ov511.c linux/drivers/usb/ov511.c
--- linux-2.4.0-test12/drivers/usb/ov511.c	Thu Dec 28 01:21:39 2000
+++ linux/drivers/usb/ov511.c	Thu Dec 28 02:19:40 2000
@@ -30,7 +30,7 @@
  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-static const char version[] = "1.28";
+static const char version[] = "1.29";
 
 #define __NO_VERSION__
 
@@ -115,6 +115,10 @@
 /* Dump raw pixel data, in one of 3 formats. See ov511_dumppix() for details. */
 static int dumppix = 0;
 
+/* LED policy. Only works on some OV511+ cameras. 0=off, 1=on (default), 2=auto
+   (on when open) */
+static int led = 1;
+
 MODULE_PARM(autoadjust, "i");
 MODULE_PARM_DESC(autoadjust, "CCD dynamically changes exposure");
 MODULE_PARM(debug, "i");
@@ -145,6 +149,8 @@
 MODULE_PARM_DESC(sensor_gbr, "Make sensor output GBR422 rather than YUV420");
 MODULE_PARM(dumppix, "i");
 MODULE_PARM_DESC(dumppix, "Dump raw pixel data, in one of 3 formats. See ov511_dumppix() for details");
+MODULE_PARM(led, "i");
+MODULE_PARM_DESC(led, "Sets LED policy. Only works on some OV511+ cameras. 0=off, 1=on (default), 2=auto (on when open)");
 
 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");
@@ -154,7 +160,7 @@
 static struct usb_driver ov511_driver;
 
 /* I know, I know, global variables suck. This is only a temporary hack */
-int output_offset;
+static int output_offset;
 
 /**********************************************************************
  * List of known OV511-based cameras
@@ -162,6 +168,7 @@
 
 static struct cam_list clist[] = {
 	{   0, "generic model (no ID)" },
+	{   1, "Mustek WCam 3X" },
 	{   3, "D-Link DSB-C300" },
 	{   4, "generic OV511/OV7610" },
 	{   5, "Puretek PT-6007" },
@@ -177,7 +184,9 @@
 static __devinitdata struct usb_device_id device_table [] = {
 	{ idVendor: 0x05a9, idProduct: 0x0511 },  /* OV511 */
 	{ 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 */
 };
 
@@ -631,6 +640,32 @@
 	return rc;
 }
 
+/*
+ * Writes bits at positions specified by mask to an I2C 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_i2c_write_mask(struct usb_device *dev,
+				unsigned char reg,
+				unsigned char value,
+				unsigned char mask)
+{
+	int ret;
+	unsigned char oldval, newval;
+
+	ret = ov511_i2c_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_i2c_write(dev, reg, newval));
+}
+
 static int ov511_write_regvals(struct usb_device *dev,
 			       struct ov511_regvals * pRegvals)
 {
@@ -845,6 +880,19 @@
 	} else if ((ov511->sensor == SEN_OV7620) 
 	         || (ov511->sensor == SEN_OV7620AE)) {
 #if 0
+		// These are 7620 only
+
+		/* Use gamma control instead */
+		if (ov511_i2c_write(dev, 0x64, (p->contrast >> 8) | 1) < 0)
+			return -EIO;
+
+		/* These regs are undocumented. They may be backwards */
+		if (ov511_i2c_write(dev, 0x7a, 0xFF - (p->hue >> 8)) < 0)
+			return -EIO;
+
+		if (ov511_i2c_write(dev, 0x79, p->hue >> 8) < 0)
+			return -EIO;
+
 		int cur_sat, new_sat, tmp;
 
 		cur_sat = ov511_i2c_read(dev, OV7610_REG_BLUE);
@@ -905,6 +953,18 @@
 	return 0;
 }
 
+/* Turns on or off the LED. Only has an effect with OV511+ */
+static inline void 
+ov511_led_control(struct usb_ov511 *ov511, int enable) {
+	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
+
+	if (ov511->bridge == BRG_OV511PLUS)
+		ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_LED_CTL, 
+			        enable ? 1 : 0);
+		
+	return;
+}
+
 /* Returns number of bits per pixel (regardless of where they are located; planar or
  * not), or zero for unsupported format.
  */
@@ -970,7 +1030,7 @@
 			/* these aren't valid on the OV6620/OV7620 */
 			ov511_i2c_write(dev, 0x0e, 0x44);
 		}
-		ov511_i2c_write(dev, 0x13, autoadjust ? 0x21 : 0x20);
+		ov511_i2c_write_mask(dev, 0x13, autoadjust ? 0x21 : 0x20, 0x21);
 
 		/* For snapshot */
 		ov511_reg_write(dev, 0x1e, 0x00);
@@ -982,7 +1042,7 @@
 			/* not valid on the OV6620/OV7620 */
 			ov511_i2c_write(dev, 0x0e, 0x04);
 		}
-		ov511_i2c_write(dev, 0x13, autoadjust ? 0x01 : 0x00);
+		ov511_i2c_write_mask(dev, 0x13, autoadjust ? 0x01 : 0x00, 0x21);
 
 		/* For snapshot */
 		ov511_reg_write(dev, 0x1e, 0x01);
@@ -1082,13 +1142,30 @@
                 ov511_reg_write(dev, 0x1c, mlist[i].pxdv);
                 ov511_reg_write(dev, 0x1d, mlist[i].lndv);
 
-		/* Calculate and set the clock divisor */
-		clock = ((sub_flag ? ov511->subw * ov511->subh : width * height)
+		/* The OV6620 needs special handling. This prevents the 
+		 * severe banding that normally occurs */
+		if (ov511->sensor == SEN_OV6620)
+		{
+			/* Clock down */
+			ov511_i2c_write(dev, 0x2a, 0x04);
+			ov511_i2c_write(dev, 0x11, 0x03);
+			ov511_i2c_write(dev, 0x2a, 0x84);
+			/* This next setting is critical. It seems to improve
+			 * the gain or the contrast. The "reserved" bits seem
+			 * to have some effect in this case. */
+			ov511_i2c_write(dev, 0x2d, 0x85);
+
+		}
+		else
+		{
+			/* Calculate and set the clock divisor */
+			clock = ((sub_flag ? ov511->subw * ov511->subh : width * height)
 			* (mlist[i].color ? 3 : 2) / 2) / 66000;
 #if 0
-		clock *= cams;
+			clock *= cams;
 #endif
-		ov511_i2c_write(dev, 0x11, clock);
+			ov511_i2c_write(dev, 0x11, clock);
+		}
 
 		/* We only have code to convert GBR -> RGB24 */
 		if ((mode == VIDEO_PALETTE_RGB24) && sensor_gbr)
@@ -1096,6 +1173,10 @@
 		else
 			ov511_i2c_write(dev, 0x12, mlist[i].common_A | (testpat?0x02:0x00));
 
+		/* Enable/Disable AGC */
+		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 */
 		if (ov511->sensor == SEN_OV7610 ||
 		    ov511->sensor == SEN_OV7620AE)
@@ -1418,6 +1499,16 @@
 			output_offset += 3;
 		}
 		break;
+	case 4: /* This will dump the whole unformatted data stream as-is */
+		pIn = pIn0;
+		pOut = pOut0 + output_offset;
+		for (i = 0; i < 384; i++) {
+			*pOut++ = *pIn;
+			*pOut++ = *pIn;
+			*pOut++ = *pIn++;
+			output_offset += 3;
+		}
+		break;
 	} /* End switch (dumppix) */
 }
 
@@ -1648,14 +1739,14 @@
 		
 		/* 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 packets. The 9th bit is given as follows:
+		 * 10th and 11th bytes. The 9th bit is given as follows:
 		 *
 		 * bit 7: EOF
 		 *     6: compression enabled
 		 *     5: 422/420/400 modes
 		 *     4: 422/420/400 modes
 		 *     3: 1
-		 *     2: snapshot bottom on
+		 *     2: snapshot button on
 		 *     1: snapshot frame
 		 *     0: even/odd field
 		 */
@@ -2182,6 +2273,9 @@
 	}
 
 	ov511->user++;
+	
+	if (ov511->led_policy == LED_AUTO)
+		ov511_led_control(ov511, 1);
 
 out:
 	up(&ov511->lock);
@@ -2203,6 +2297,9 @@
 	ov511->user--;
 	ov511_stop_isoc(ov511);
 
+	if (ov511->led_policy == LED_AUTO)
+		ov511_led_control(ov511, 0);
+
 	if (ov511->dev)
 		ov511_dealloc(ov511, 0);
 
@@ -2274,6 +2371,7 @@
 		v.flags = 0;
 		v.tuners = 0;
 		v.type = VIDEO_TYPE_CAMERA;
+		v.norm = 0;
 		strcpy(v.name, "Camera");
 
 		if (copy_to_user(arg, &v, sizeof(v)))
@@ -2615,7 +2713,7 @@
 	return 0;
 }
 
-static long ov511_read(struct video_device *dev, char *buf, unsigned long count, int noblock)
+static inline long ov511_read(struct video_device *dev, char *buf, unsigned long count, int noblock)
 {
 	struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
 	int i;
@@ -2987,33 +3085,37 @@
 	int i, success, rc;
 
 	static struct ov511_regvals aRegvalsNorm6x20[] = {
-		{ OV511_I2C_BUS, 0x12, 0x80 },  /* reset */
+		{ OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
 		{ OV511_I2C_BUS, 0x11, 0x01 },
-		{ OV511_I2C_BUS, 0x03, 0xd0 },
-		{ OV511_I2C_BUS, 0x05, 0x7f },
+		{ OV511_I2C_BUS, 0x03, 0x60 },
+		{ OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
 		{ OV511_I2C_BUS, 0x07, 0xa8 },
+		/* The ratio of 0x0c and 0x0d  controls the white point */
 		{ OV511_I2C_BUS, 0x0c, 0x24 },
 		{ OV511_I2C_BUS, 0x0d, 0x24 },
-		{ OV511_I2C_BUS, 0x10, 0xff },  /* ? */
+		{ OV511_I2C_BUS, 0x12, 0x28 }, /* Enable AGC */
 		{ OV511_I2C_BUS, 0x14, 0x04 },
-		{ OV511_I2C_BUS, 0x16, 0x06 },  /* ? */
-		{ OV511_I2C_BUS, 0x19, 0x04 },
-		{ OV511_I2C_BUS, 0x1a, 0x93 },
-		{ OV511_I2C_BUS, 0x20, 0x28 },
-		{ OV511_I2C_BUS, 0x27, 0xa2 },
-		{ OV511_I2C_BUS, 0x28, 0x24 },
-		{ OV511_I2C_BUS, 0x2a, 0x04 },  /* 84? */
-		{ OV511_I2C_BUS, 0x2b, 0xac },  /* a8? */
-		{ OV511_I2C_BUS, 0x2d, 0x95 },
-		{ OV511_I2C_BUS, 0x33, 0x28 },
-		{ OV511_I2C_BUS, 0x34, 0xc7 },
+		/* 0x16: 0x06 helps frame stability with moving objects */
+		{ OV511_I2C_BUS, 0x16, 0x06 },
+//		{ OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
+		{ OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
+		{ OV511_I2C_BUS, 0x28, 0x05 }, /* Selects RGB format if RGB on */
+		{ OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
+//		{ OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
+		{ OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */
 		{ OV511_I2C_BUS, 0x38, 0x8b },
-		{ OV511_I2C_BUS, 0x3c, 0x5c },
+		{ OV511_I2C_BUS, 0x39, 0x40 },
+		
+		{ 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 */
+
 		{ OV511_I2C_BUS, 0x3d, 0x80 },
-		{ OV511_I2C_BUS, 0x3f, 0x00 },
-		{ OV511_I2C_BUS, 0x4a, 0x80 }, /* undocumented */
-		{ OV511_I2C_BUS, 0x4b, 0x80 }, /* undocumented */
-		{ OV511_I2C_BUS, 0x4d, 0xd2 },
+		/* These next two registers (0x4a, 0x4b) are undocumented. They 
+		 * control the color balance */
+		{ OV511_I2C_BUS, 0x4a, 0x80 },
+		{ OV511_I2C_BUS, 0x4b, 0x80 },
+		{ OV511_I2C_BUS, 0x4d, 0xd2 }, /* This reduces noise a bit */
 		{ OV511_I2C_BUS, 0x4e, 0xc1 },
 		{ OV511_I2C_BUS, 0x4f, 0x04 },
 		{ OV511_DONE_BUS, 0x0, 0x00 },
@@ -3058,9 +3160,16 @@
 		if (rc < 0) {
 			err("Error detecting sensor type");
 			return -1;
-		} else {
-			info("Sensor is an OV6xx0 (version %d)", rc & 3);
+		} else if((rc & 3) == 0) {
+			info("Sensor is an OV6630");
+			ov511->sensor = SEN_OV6620; /* Closest match? */
+		} 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 {	/* sensor != 0; user overrode detection */
 		ov511->sensor = sensor;
@@ -3087,13 +3196,11 @@
 
 	if (autoadjust) {
 		if (ov511_i2c_write(dev, 0x13, 0x01) < 0) return -1;
-		if (ov511_i2c_write(dev, 0x2d, 
-		     ov511->sensor==SEN_OV7620?0x91:0x93) < 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(dev, 0x2d, 
-		     ov511->sensor==SEN_OV7620?0x81:0x83) < 0) return -1;
-		ov511_i2c_write(dev, 0x28, ov511_i2c_read(dev, 0x28) | 8);
+		if (ov511_i2c_write(dev, 0x2d, 0x89) < 0) return -1;
+		if (ov511_i2c_write_mask(dev, 0x28, 0x08, 0x08) < 0) return -1;
 	}
 
 	return 0;
@@ -3121,16 +3228,16 @@
 		{ OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x02 },
 		{ OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x00 },
 		{ OV511_REG_BUS, OV511_REG_FIFO_BITMASK, 0x1f },
-		{ OV511_REG_BUS, OV511_OMNICE_PREDICTION_HORIZ_Y, 0x08 },
+		{ OV511_REG_BUS, OV511_OMNICE_PREDICTION_HORIZ_Y, 0x1f },
 		{ OV511_REG_BUS, OV511_OMNICE_PREDICTION_HORIZ_UV, 0x01 },
 		{ OV511_REG_BUS, OV511_OMNICE_PREDICTION_VERT_Y, 0x08 },
 		{ OV511_REG_BUS, OV511_OMNICE_PREDICTION_VERT_UV, 0x01 },
-		{ OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_HORIZ_Y, 0x01 },
+		{ OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_HORIZ_Y, 0xff },
 		{ OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_HORIZ_UV, 0x01 },
-		{ OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_VERT_Y, 0x01 },
+		{ OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_VERT_Y, 0xff },
 		{ OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_VERT_UV, 0x01 },
-		{ OV511_REG_BUS, OV511_OMNICE_ENABLE, 0x06 },
-		{ OV511_REG_BUS, OV511_OMNICE_LUT_ENABLE, 0x03 },
+		{ OV511_REG_BUS, OV511_OMNICE_ENABLE, 0x00 },
+		{ OV511_REG_BUS, OV511_OMNICE_LUT_ENABLE, 0x00 },
 		{ OV511_DONE_BUS, 0x0, 0x00 },
 	};
 
@@ -3147,6 +3254,10 @@
 	}
 
 	if (ov511_write_regvals(dev, aRegvalsInit)) goto error;
+
+	if (ov511->led_policy == LED_OFF || ov511->led_policy == LED_AUTO)
+		ov511_led_control(ov511, 0);
+
 	if (ov511_write_regvals(dev, aRegvalsNorm511)) goto error;
 
 	ov511_set_packet_size(ov511, 0);
@@ -3179,13 +3290,30 @@
 			goto error;
 
 		if (ov511_i2c_write(dev, 0x12, 0x80) < 0) {
-			err("Can't determine sensor slave IDs");
-			goto error;
-		}
-		
-		if(ov6xx0_configure(ov511) < 0) {
-			err("failed to configure OV6xx0");
- 			goto error;
+			/* Test for 8xx0 */
+			if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE,
+			                    OV8xx0_I2C_WRITE_ID) < 0)
+				goto error;
+
+			if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ,
+			                    OV8xx0_I2C_READ_ID) < 0)
+				goto error;
+
+			if (ov511_reset(dev, OV511_RESET_NOREGS) < 0)
+				goto error;
+
+			if (ov511_i2c_write(dev, 0x12, 0x80) < 0) {
+				err("Can't determine sensor slave IDs");
+ 				goto error;
+			} else {
+				err("Detected unsupported OV8xx0 sensor");
+				goto error;
+			}
+		} else {
+			if(ov6xx0_configure(ov511) < 0) {
+				err("failed to configure OV6xx0");
+ 				goto error;
+			}
 		}
 	} else {
 		if(ov76xx_configure(ov511) < 0) {
@@ -3272,12 +3400,24 @@
 		info("USB OV511+ camera found");
 		ov511->bridge = BRG_OV511PLUS;
 		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;
+		break;
 	case 0x0002:
 		if (dev->descriptor.idVendor != 0x0813)
 			goto error;
 		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;
@@ -3299,6 +3439,8 @@
 		}
 	}
 
+	ov511->led_policy = led;
+
 	/* Lifeview USB Life TV not supported */
 	if (clist[i].id == 38) {
 		err("This device is not supported yet.");
@@ -3307,12 +3449,13 @@
 
 	if (clist[i].id == -1) {
 		err("Camera type (%d) not recognized", ov511->customid);
-		err("Please contact mwm@i.am to request");
-		err("support for your camera.");
+		err("Please notify mwm@i.am of the name, manufacturer, model,");
+		err("and camera type number of your camera. Also include the");
+		err("complete output of the detection process.");
 	}
 
 	/* Workaround for some applications that want data in RGB
-	 * instead of BGR */
+	 * instead of BGR. */
 	if (force_rgb)
 		info("data format set to RGB");
 
diff -Naur linux-2.4.0-test12/drivers/usb/ov511.h linux/drivers/usb/ov511.h
--- linux-2.4.0-test12/drivers/usb/ov511.h	Thu Dec 28 01:21:39 2000
+++ linux/drivers/usb/ov511.h	Thu Dec 28 01:22:21 2000
@@ -185,6 +185,8 @@
 #define OV7610_I2C_READ_ID  0x43
 #define OV6xx0_I2C_WRITE_ID 0xC0
 #define OV6xx0_I2C_READ_ID  0xC1
+#define OV8xx0_I2C_WRITE_ID 0xA0
+#define OV8xx0_I2C_READ_ID  0xA1
 
 #define OV511_I2C_CLOCK_PRESCALER 0x03
 
@@ -196,8 +198,10 @@
 
 /* Bridge types */
 enum {
+	BRG_UNKNOWN,
 	BRG_OV511,
 	BRG_OV511PLUS,
+	BRG_OV518PLUS,
 };
 
 /* Sensor types */
@@ -207,6 +211,8 @@
 	SEN_OV7620,
 	SEN_OV7620AE,
 	SEN_OV6620,
+	SEN_OV6630,
+	SEN_OV8600,
 };
 
 enum {
@@ -222,6 +228,13 @@
 	BUF_PEND_DEALLOC,	/* ov511->buf_timer is set */
 };
 
+/* LED options */
+enum {
+	LED_OFF,
+	LED_ON,
+	LED_AUTO,
+};
+
 struct usb_device;
 
 struct ov511_sbuf {
@@ -298,6 +311,8 @@
 	int contrast;
 	int hue;
 	int whiteness;
+
+	int led_policy;		/* LED: off|on|auto; OV511+ only */
 
 	struct semaphore lock;
 	int user;		/* user count for exclusive use */
