patch-2.3.99-pre7 linux/drivers/usb/ov511.c

Next file: linux/drivers/usb/ov511.h
Previous file: linux/drivers/usb/mousedev.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c
@@ -1,23 +1,20 @@
 /*
  * OmniVision OV511 Camera-to-USB Bridge Driver
- * Copyright (c) 1999/2000 Mark W. McClelland
+ *
+ * Copyright (c) 1999-2000 Mark W. McClelland
  * Many improvements by Bret Wallach
  * Color fixes by by Orion Sky Lawlor, olawlor@acm.org, 2/26/2000
  * Snapshot code by Kevin Moore
  * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
+ * Changes by Claudio Matsuoka, claudio@conectiva.com, 3/26/2000
  * 
- * Based on the Linux CPiA driver.
+ * Based on the Linux CPiA driver written by Peter Pregler,
+ * Scott J. Bertin and Johannes Erdfelt.
  * 
- * Released under GPL v.2 license.
- *
- * Version: 1.11
- *
  * Please see the file: linux/Documentation/usb/ov511.txt 
- * and the website at:  http://alpha.dyndns.org/ov511 
+ * and the website at:  http://alpha.dyndns.org/ov511
  * for more info.
- */
-
-/*
+ *
  * 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 the
  * Free Software Foundation; either version 2 of the License, or (at your
@@ -33,23 +30,28 @@
  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+static const char version[] = "1.13";
+
 #define __NO_VERSION__
 
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-#include <linux/videodev.h>
-#include <linux/vmalloc.h>
-#include <linux/wrapper.h>
+#include <linux/config.h>
 #include <linux/module.h>
+#include <linux/version.h>
 #include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/time.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/pagemap.h>
 #include <linux/usb.h>
 #include <asm/io.h>
+#include <asm/semaphore.h>
+#include <linux/wrapper.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
 
 #include "ov511.h"
 
@@ -59,11 +61,10 @@
 #define MAX_FRAME_SIZE (640 * 480 * 3)
 #define MAX_DATA_SIZE (MAX_FRAME_SIZE + sizeof(struct timeval))
 
-// FIXME - Should find a better way to do this.
 #define DEFAULT_WIDTH 640
 #define DEFAULT_HEIGHT 480
 
-// PARAMETER VARIABLES:
+/* PARAMETER VARIABLES: */
 static int autoadjust = 1;    /* CCD dynamically changes exposure, etc... */
 
 /* 0=no debug messages
@@ -85,24 +86,61 @@
 /* Sensor detection override (global for all attached cameras) */
 static int sensor = 0;
 
+/* Increase this if you are getting "Failed to read sensor ID..." */
+static int i2c_detect_tries = 5;
+
+/* For legal values, see the OV7610/7620 specs under register Common F,
+   upper nybble  (set to 0-F) */
+static int aperture = -1;
+
 MODULE_PARM(autoadjust, "i");
 MODULE_PARM(debug, "i");
 MODULE_PARM(fix_rgb_offset, "i");
 MODULE_PARM(snapshot, "i");
 MODULE_PARM(sensor, "i");
+MODULE_PARM(i2c_detect_tries, "i");
+MODULE_PARM(aperture, "i");
 
 MODULE_AUTHOR("Mark McClelland (and others)");
 MODULE_DESCRIPTION("OV511 USB Camera Driver");
 
 char kernel_version[] = UTS_RELEASE;
 
-/*******************************/
-/* Memory management functions */
-/*******************************/
+static struct usb_driver ov511_driver;
 
-#define MDEBUG(x)	do { } while(0)		/* Debug memory management */
+/**********************************************************************
+ * List of known OV511-based cameras
+ **********************************************************************/
+
+static struct cam_list clist[] = {
+	{   0, "generic model (no ID)" },
+	{   3, "D-Link DSB-C300" },
+	{   4, "generic OV511/OV7610" },
+	{   5, "Puretek PT-6007" },
+	{  21, "Creative Labs WebCam 3" },
+	{  36, "Koala-Cam" },
+	{  38, "Lifeview USB Life TV" },	/* No support yet! */
+	{ 100, "Lifeview RoboCam" },
+	{ 102, "AverMedia InterCam Elite" },
+	{ 112, "MediaForte MV300" },	/* or OV7110 evaluation kit */
+	{  -1, NULL }
+};
 
-static struct usb_driver ov511_driver;
+/**********************************************************************
+ *
+ * Memory management
+ *
+ * This is a shameless copy from the USB-cpia driver (linux kernel
+ * version 2.3.29 or so, I have no idea what this code actually does ;).
+ * Actually it seems to be a copy of a shameless copy of the bttv-driver.
+ * Or that is a copy of a shameless copy of ... (To the powers: is there
+ * no generic kernel-function to do this sort of stuff?)
+ *
+ * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
+ * there will be one, but apparentely not yet -jerdfelt
+ *
+ * So I copied it again for the OV511 driver -claudio
+ **********************************************************************/
 
 /* Given PGD from the address space's page table, return the kernel
  * virtual mapping of the physical memory mapped at ADR.
@@ -119,31 +157,11 @@
 			ptep = pte_offset(pmd, adr);
 			pte = *ptep;
 			if (pte_present(pte))
-				ret = page_address(pte_page(pte)) | (adr & (PAGE_SIZE-1));
+				ret = page_address(pte_page(pte)) |
+				      (adr & (PAGE_SIZE-1));
 		}
 	}
-	MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
-	return ret;
-}
-
-static inline unsigned long uvirt_to_bus(unsigned long adr)
-{
-	unsigned long kva, ret;
-
-	kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
-	ret = virt_to_bus((void *)kva);
-	MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
-	return ret;
-}
-
-static inline unsigned long kvirt_to_bus(unsigned long adr)
-{
-	unsigned long va, kva, ret;
 
-	va = VMALLOC_VMADDR(adr);
-	kva = uvirt_to_kva(pgd_offset_k(va), va);
-	ret = virt_to_bus((void *)kva);
-	MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
 	return ret;
 }
 
@@ -158,7 +176,6 @@
 	va = VMALLOC_VMADDR(adr);
 	kva = uvirt_to_kva(pgd_offset_k(va), va);
 	ret = __pa(kva);
-	MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
 	return ret;
 }
 
@@ -213,9 +230,269 @@
 	vfree(mem);
 }
 
+/**********************************************************************
+ * /proc interface
+ * Based on the CPiA driver version 0.7.4 -claudio
+ **********************************************************************/
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *ov511_proc_root = NULL;
+
+#define YES_NO(x) ((x) ? "yes" : "no")
+
+static int ov511_read_proc(char *page, char **start, off_t off,
+                          int count, int *eof, void *data)
+{
+	char *out = page;
+	int i, len;
+	struct usb_ov511 *ov511 = data;
+
+	/* IMPORTANT: This output MUST be kept under PAGE_SIZE
+	 *            or we need to get more sophisticated. */
+
+	out += sprintf (out, "custom_id       : %d\n", ov511->customid);
+	out += sprintf (out, "model           : %s\n", ov511->desc ?
+		clist[ov511->desc].description : "unknown");
+	out += sprintf (out, "streaming       : %s\n", YES_NO (ov511->streaming));
+	out += sprintf (out, "grabbing        : %s\n", YES_NO (ov511->grabbing));
+	out += sprintf (out, "compress        : %s\n", YES_NO (ov511->compress));
+	out += sprintf (out, "subcapture      : %s\n", YES_NO (ov511->sub_flag));
+	out += sprintf (out, "sub_size        : %d %d %d %d\n",
+		ov511->subx, ov511->suby, ov511->subw, ov511->subh);
+	out += sprintf (out, "num_frames      : %d\n", OV511_NUMFRAMES);
+	for (i = 0; i < OV511_NUMFRAMES; i++) {
+		out += sprintf (out, "frame           : %d\n", i);
+		out += sprintf (out, "  depth         : %d\n",
+			ov511->frame[i].depth);
+		out += sprintf (out, "  size          : %d %d\n",
+			ov511->frame[i].width, ov511->frame[i].height);
+		out += sprintf (out, "  hdr_size      : %d %d\n",
+			ov511->frame[i].hdrwidth, ov511->frame[i].hdrheight);
+		out += sprintf (out, "  format        : %d\n",
+			ov511->frame[i].format);
+		out += sprintf (out, "  segsize       : %d\n",
+			ov511->frame[i].segsize);
+#if 0
+		out += sprintf (out, "  curline       : %d\n",
+			ov511->frame[i].curline);
+		out += sprintf (out, "  segment       : %d\n",
+			ov511->frame[i].segment);
+		out += sprintf (out, "  scanlength    : %ld\n",
+			ov511->frame[i].scanlength);
+		out += sprintf (out, "  bytesread     : %ld\n",
+			ov511->frame[i].bytes_read);
+#endif
+	}
+	out += sprintf (out, "snap_enabled    : %s\n", YES_NO (ov511->snap_enabled));
+	out += sprintf (out, "bridge          : %d\n", ov511->bridge);
+	out += sprintf (out, "sensor          : %d\n", ov511->sensor);
+	out += sprintf (out, "packet_size     : %d\n", ov511->packet_size);
+	
+	len = out - page;
+	len -= off;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0) return 0;
+	} else
+		len = count;
+
+	*start = page + off;
+	return len;
+}
+
+static int ov511_write_proc(struct file *file, const char *buffer,
+                           unsigned long count, void *data)
+{
+	int retval = -EINVAL;
+
+#if 0
+	/* struct cam_data *cam = data; */
+	struct usb_ov511 new_params;
+	int size = count;
+	int find_colon;
+	unsigned long val;
+	u32 command_flags = 0;
+	u8 new_mains;
+	
+	if (down_interruptible(&cam->param_lock))
+		return -ERESTARTSYS;
+	
+	/*
+	 * Skip over leading whitespace
+	 */
+	while (count && isspace(*buffer)) {
+		--count;
+		++buffer;
+	}
+	
+	
+#define MATCH(x) \
+	({ \
+		int _len = strlen(x), _ret, _colon_found; \
+		_ret = (_len <= count && strncmp(buffer, x, _len) == 0); \
+		if (_ret) { \
+			buffer += _len; \
+			count -= _len; \
+			if (find_colon) { \
+				_colon_found = 0; \
+				while (count && (*buffer == ' ' || *buffer == '\t' || \
+				       (!_colon_found && *buffer == ':'))) { \
+					if (*buffer == ':')  \
+						_colon_found = 1; \
+					--count; \
+					++buffer; \
+				} \
+				if (!count || !_colon_found) \
+					retval = -EINVAL; \
+				find_colon = 0; \
+			} \
+		} \
+		_ret; \
+	})
+
+#define VALUE \
+	({ \
+		char *_p; \
+		unsigned long int _ret; \
+		_ret = simple_strtoul(buffer, &_p, 0); \
+		if (_p == buffer) \
+			retval = -EINVAL; \
+		else { \
+			count -= _p - buffer; \
+			buffer = _p; \
+		} \
+		_ret; \
+	})
+
+
+	retval = 0;
+	while (count && !retval) {
+		find_colon = 1;
+
+		if (MATCH("")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					/* ... = val */ ;
+				else
+					retval = -EINVAL;
+			}
+		} else {
+			DBG("No match found\n");
+			retval = -EINVAL;
+		}
+
+		if (!retval) {
+			while (count && isspace(*buffer) && *buffer != '\n') {
+				--count;
+				++buffer;
+			}
+			if (count) {
+				if (*buffer != '\n' && *buffer != ';')
+					retval = -EINVAL;
+				else {
+					--count;
+					++buffer;
+				}
+			}
+		}
+	}
+
+#undef MATCH	
+#undef FIRMWARE_VERSION
+#undef VALUE
+#undef FIND_VALUE
+#undef FIND_END
+	if (!retval) {
+		if (command_flags & COMMAND_SETCOLOURPARAMS) {
+			/* Adjust cam->vp to reflect these changes */
+			cam->vp.brightness =
+				new_params.colourParams.brightness*65535/100;
+			cam->vp.contrast =
+				new_params.colourParams.contrast*65535/100;
+			cam->vp.colour =
+				new_params.colourParams.saturation*65535/100;
+		}
+		
+		memcpy(&cam->params, &new_params, sizeof(struct cam_params));
+		cam->mainsFreq = new_mains;
+		cam->cmd_queue |= command_flags;
+		retval = size;
+	} else
+		PDEBUG(3, "error: %d\n", retval);
+	
+	up(&cam->param_lock);
+#endif
+	
+	return retval;
+}
+
+static void create_proc_ov511_cam (struct usb_ov511 *ov511)
+{
+	char name[7];
+	struct proc_dir_entry *ent;
+	
+	PDEBUG (4, "***************");
+	if (!ov511_proc_root || !ov511)
+		return;
+
+	sprintf(name, "video%d", ov511->vdev.minor);
+	PDEBUG (4, "==== name: %s", name);
+	
+	ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, ov511_proc_root);
+	if (!ent)
+		return;
+
+	ent->data = ov511;
+	ent->read_proc = ov511_read_proc;
+	ent->write_proc = ov511_write_proc;
+	ent->size = 3626;	/* FIXME */
+	ov511->proc_entry = ent;
+}
+
+static void destroy_proc_ov511_cam (struct usb_ov511 *ov511)
+{
+	char name[7];
+	
+	if (!ov511 || !ov511->proc_entry)
+		return;
+	
+	sprintf(name, "video%d", ov511->vdev.minor);
+	PDEBUG (4, "==== name: %s", name);
+#if 0
+	remove_proc_entry(name, ov511_proc_root);
+	ov511->proc_entry = NULL;
+#endif
+}
+
+static void proc_ov511_create(void)
+{
+	ov511_proc_root = create_proc_entry("ov511", S_IFDIR, 0);
+
+	if (ov511_proc_root)
+		ov511_proc_root->owner = THIS_MODULE;
+	else
+		printk("Unable to initialise /proc/ov511\n");	/***********/
+}
+
+static void proc_ov511_destroy(void)
+{
+	remove_proc_entry("ov511", 0);
+}
+#endif /* CONFIG_PROC_FS */
+
+
+/**********************************************************************
+ *
+ * Camera interface
+ *
+ **********************************************************************/
+
 static int ov511_reg_write(struct usb_device *dev,
-                           unsigned char reg,
-                           unsigned char value)
+			   unsigned char reg,
+			   unsigned char value)
 {
 	int rc;
 
@@ -233,6 +510,7 @@
 	return rc;
 }
 
+
 /* returns: negative is error, pos or zero is data */
 static int ov511_reg_read(struct usb_device *dev, unsigned char reg)
 {
@@ -247,24 +525,25 @@
                                
 	PDEBUG(5, "reg read: 0x%02X:0x%02X", reg, buffer[0]);
 	
-	if(rc < 0) {
+	if (rc < 0) {
 		err("ov511_reg_read: error %d", rc);
 		return rc;
-	}
-	else
+	} else {
 		return buffer[0];	
+	}
 }
 
+
 static int ov511_i2c_write(struct usb_device *dev,
-                           unsigned char reg,
-                           unsigned char value)
+			   unsigned char reg,
+			   unsigned char value)
 {
 	int rc, retries;
 
 	PDEBUG(5, "i2c write: 0x%02X:0x%02X", reg, value);
 
 	/* Three byte write cycle */
-	for(retries = OV511_I2C_RETRIES;;) {
+	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Select camera register */
 		rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg);
 		if (rc < 0) goto error;
@@ -278,10 +557,10 @@
 		if (rc < 0) goto error;
 
 		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
-		while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
+		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
 		if (rc < 0) goto error;
 
-		if((rc&2) == 0) /* Ack? */
+		if ((rc&2) == 0) /* Ack? */
 			break;
 #if 0
 		/* I2C abort */	
@@ -301,13 +580,14 @@
 	return rc;
 }
 
+
 /* returns: negative is error, pos or zero is data */
 static int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
 {
 	int rc, value, retries;
 
 	/* Two byte write cycle */
-	for(retries = OV511_I2C_RETRIES;;) {
+	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Select camera register */
 		rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg);
 		if (rc < 0) goto error;
@@ -317,10 +597,10 @@
 		if (rc < 0) goto error;
 
 		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
-		while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
+		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
 		if (rc < 0) goto error;
 
-		if((rc&2) == 0) /* Ack? */
+		if ((rc&2) == 0) /* Ack? */
 			break;
 
 		/* I2C abort */	
@@ -334,16 +614,16 @@
 	}
 
 	/* Two byte read cycle */
-	for(retries = OV511_I2C_RETRIES;;) {
+	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Initiate 2-byte read cycle */
 		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
 		if (rc < 0) goto error;
 
 		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
-		while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
+		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
 		if (rc < 0) goto error;
 
-		if((rc&2) == 0) /* Ack? */
+		if ((rc&2) == 0) /* Ack? */
 			break;
 
 		/* I2C abort */	
@@ -363,7 +643,8 @@
 		
 	/* This is needed to make ov511_i2c_write() work */
 	rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
-	if (rc < 0) goto error;
+	if (rc < 0)
+		goto error;
 	
 	return value;
 
@@ -372,12 +653,13 @@
 	return rc;
 }
 
+
 static int ov511_write_regvals(struct usb_device *dev,
 			       struct ov511_regvals * pRegvals)
 {
 	int rc;
 
-	while(pRegvals->bus != OV511_DONE_BUS) {
+	while (pRegvals->bus != OV511_DONE_BUS) {
 		if (pRegvals->bus == OV511_REG_BUS) {
 			if ((rc = ov511_reg_write(dev, pRegvals->reg,
 			                           pRegvals->val)) < 0)
@@ -400,6 +682,7 @@
 	return rc;
 }
 
+
 #if 0
 static void ov511_dump_i2c_range( struct usb_device *dev, int reg1, int regn)
 {
@@ -411,12 +694,14 @@
 	}
 }
 
+
 static void ov511_dump_i2c_regs( struct usb_device *dev)
 {
 	PDEBUG(3, "I2C REGS");
 	ov511_dump_i2c_range(dev, 0x00, 0x38);
 }
 
+
 static void ov511_dump_reg_range( struct usb_device *dev, int reg1, int regn)
 {
 	int i;
@@ -427,6 +712,7 @@
 	}
 }
 
+
 static void ov511_dump_regs( struct usb_device *dev)
 {
 	PDEBUG(1, "CAMERA INTERFACE REGS");
@@ -451,6 +737,7 @@
 }
 #endif
 
+
 static int ov511_reset(struct usb_device *dev, unsigned char reset_type)
 {
 	int rc;
@@ -465,6 +752,7 @@
 	return rc;
 }
 
+
 /* Temporarily stops OV511 from functioning. Must do this before changing
  * registers while the camera is streaming */
 static inline int ov511_stop(struct usb_device *dev)
@@ -473,6 +761,7 @@
 	return (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x3d));
 }
 
+
 /* Restarts OV511 after ov511_stop() is called */
 static inline int ov511_restart(struct usb_device *dev)
 {
@@ -480,6 +769,7 @@
 	return (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x00));
 }
 
+
 static int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
 {
 	int alt, mult;
@@ -487,7 +777,7 @@
 	if (ov511_stop(ov511->dev) < 0)
 		return -EIO;
 
-	mult = size / 32;
+	mult = size >> 5;
 
 	if (ov511->bridge == BRG_OV511) {
 		if (size == 0) alt = OV511_ALT_SIZE_0;
@@ -502,8 +792,7 @@
 			err("Set packet size: invalid size (%d)", size);
 			return -EINVAL;
 		}
-	}
-	else if (ov511->bridge == BRG_OV511PLUS) {
+	} else if (ov511->bridge == BRG_OV511PLUS) {
 		if (size == 0) alt = OV511PLUS_ALT_SIZE_0;
 		else if (size == 33) alt = OV511PLUS_ALT_SIZE_33;
 		else if (size == 129) alt = OV511PLUS_ALT_SIZE_129;
@@ -516,16 +805,14 @@
 			err("Set packet size: invalid size (%d)", size);
 			return -EINVAL;
 		}
-	}
-	else {
+	} else {
 		err("Set packet size: Invalid bridge type");
 		return -EINVAL;
 	}
 
 	PDEBUG(3, "set packet size: %d, mult=%d, alt=%d", size, mult, alt);
 
-	if (ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE,
-	                     mult) < 0)
+	if (ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE, mult) < 0)
 		return -ENOMEM;
 	
 	if (usb_set_interface(ov511->dev, ov511->iface, alt) < 0) {
@@ -545,8 +832,9 @@
 	return 0;
 }
 
-static inline int ov7610_set_picture(struct usb_ov511 *ov511,
-                                     struct video_picture *p)
+
+static inline int
+ov7610_set_picture(struct usb_ov511 *ov511, struct video_picture *p)
 {
 	int ret;
 	struct usb_device *dev = ov511->dev;
@@ -556,10 +844,10 @@
 	if (ov511_stop(dev) < 0)
 		return -EIO;
 
-	if((ret = ov511_i2c_read(dev, OV7610_REG_COM_B)) < 0)
+	if ((ret = ov511_i2c_read(dev, OV7610_REG_COM_B)) < 0)
 		return -EIO;
 #if 0
-	if(ov511_i2c_write(dev, OV7610_REG_COM_B, ret & 0xfe) < 0)
+	if (ov511_i2c_write(dev, OV7610_REG_COM_B, ret & 0xfe) < 0)
 		return -EIO;
 #endif
 	if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV7620AE)
@@ -572,17 +860,18 @@
 
 		if(ov511_i2c_write(dev, OV7610_REG_BRT, p->brightness >> 8) < 0)
 			return -EIO;
-	}		
-	else if ((ov511->sensor == SEN_OV7620) 
+	} else if ((ov511->sensor == SEN_OV7620) 
 	         || (ov511->sensor == SEN_OV7620AE)) {
-//		cur_con = ov511_i2c_read(dev, OV7610_REG_CNT);
-//		cur_brt = ov511_i2c_read(dev, OV7610_REG_BRT);
-//	        // DEBUG_CODE
-//	        PDEBUG(1, "con=%d brt=%d", ov511_i2c_read(dev, OV7610_REG_CNT),
-//	                                   ov511_i2c_read(dev, OV7610_REG_BRT)); 
-//
-//		if(ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
-//			return -EIO;
+#if 0
+		cur_con = ov511_i2c_read(dev, OV7610_REG_CNT);
+		cur_brt = ov511_i2c_read(dev, OV7610_REG_BRT);
+	        // DEBUG_CODE
+	        PDEBUG(1, "con=%d brt=%d", ov511_i2c_read(dev, OV7610_REG_CNT),
+	         ov511_i2c_read(dev, OV7610_REG_BRT)); 
+
+		if(ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
+			return -EIO;
+#endif
 	}
 
 	if (ov511_restart(dev) < 0)
@@ -591,8 +880,9 @@
 	return 0;
 }
 
-static inline int ov7610_get_picture(struct usb_ov511 *ov511,
-                                     struct video_picture *p)
+
+static inline int
+ov7610_get_picture(struct usb_ov511 *ov511, struct video_picture *p)
 {
 	int ret;
 	struct usb_device *dev = ov511->dev;
@@ -613,7 +903,11 @@
 
 	p->hue = 0x8000;
 	p->whiteness = 105 << 8;
+#if 0
 	p->depth = 3;  /* Don't know if this is right */
+#else
+	p->depth = 24;
+#endif
 	p->palette = VIDEO_PALETTE_RGB24;
 
 	if (ov511_restart(dev) < 0)
@@ -622,15 +916,17 @@
 	return 0;
 }
 
-static int ov511_mode_init_regs(struct usb_ov511 *ov511,
-				int width, int height, int mode, int sub_flag)
+
+static int
+ov511_mode_init_regs(struct usb_ov511 *ov511,
+		     int width, int height, int mode, int sub_flag)
 {
 	int rc = 0;
 	struct usb_device *dev = ov511->dev;
-        int hwsbase = 0;
-        int hwebase = 0;
+	int hwsbase = 0;
+	int hwebase = 0;
 
-	PDEBUG(3, "ov511_mode_init_regs(ov511, w:%d, h:%d, mode:%d, sub:%d)",
+	PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
 	       width, height, mode, sub_flag);
 
 	if (ov511_stop(ov511->dev) < 0)
@@ -644,34 +940,39 @@
 			ov511_i2c_write(dev, 0x0e, 0x44);
 		}
 		ov511_i2c_write(dev, 0x13, autoadjust ? 0x21 : 0x20);
+
 		/* For snapshot */
 		ov511_reg_write(dev, 0x1e, 0x00);
 		ov511_reg_write(dev, 0x1f, 0x01);
 	} else {
 		ov511_reg_write(dev, 0x16, 0x01);
-	   	if (ov511->sensor == SEN_OV7610
+		if (ov511->sensor == SEN_OV7610
 		    || ov511->sensor == SEN_OV7620AE) {
-		   /* not valid on the OV7620 */
-		   ov511_i2c_write(dev, 0x0e, 0x04);
+			/* not valid on the OV7620 */
+			ov511_i2c_write(dev, 0x0e, 0x04);
 		}
 		ov511_i2c_write(dev, 0x13, autoadjust ? 0x01 : 0x00);
+
 		/* For snapshot */
 		ov511_reg_write(dev, 0x1e, 0x01);
 		ov511_reg_write(dev, 0x1f, 0x03);
 	}
 
 	/* The different sensor ICs handle setting up of window differently */
-        switch (ov511->sensor) {
-	 case SEN_OV7610:
-	 case SEN_OV7620AE:
-	   hwsbase = 0x38;
-	   hwebase = 0x3a; break;
-	 case SEN_OV7620:
-	   hwsbase = 0x2c;
-	   hwebase = 0x2d; break;
-	 default:
-	   hwsbase = 0;
-	   hwebase = 0; break;
+	switch (ov511->sensor) {
+	case SEN_OV7610:
+	case SEN_OV7620AE:
+		hwsbase = 0x38;
+		hwebase = 0x3a;
+		break;
+	case SEN_OV7620:
+		hwsbase = 0x2c;
+		hwebase = 0x2d;
+		break;
+	default:
+		hwsbase = 0;
+		hwebase = 0;
+		break;
 	}
 
 	if (width == 640 && height == 480) {
@@ -680,12 +981,12 @@
 			ov511_i2c_write(dev, 0x17, hwsbase+(ov511->subx>>2));
 			/* horizontal window end */
 			ov511_i2c_write(dev, 0x18,
-					hwebase+((ov511->subx+ov511->subw)>>2));
+				hwebase+((ov511->subx+ov511->subw)>>2));
 			/* vertical window start */
-		   	ov511_i2c_write(dev, 0x19, 0x5+(ov511->suby>>1));
+			ov511_i2c_write(dev, 0x19, 0x5+(ov511->suby>>1));
 			/* vertical window end */
-		    ov511_i2c_write(dev, 0x1a,
-					0x5+((ov511->suby+ov511->subh)>>1));
+			ov511_i2c_write(dev, 0x1a,
+				0x5+((ov511->suby+ov511->subh)>>1));
 			ov511_reg_write(dev, 0x12, (ov511->subw>>3)-1);
 			ov511_reg_write(dev, 0x13, (ov511->subh>>3)-1);
 			/* clock rate control */
@@ -762,255 +1063,267 @@
 	return rc;
 }
 
-	
-/*************************************************************
-
-Turn a YUV4:2:0 block into an RGB block
 
-Video4Linux seems to use the blue, green, red channel
-order convention-- rgb[0] is blue, rgb[1] is green, rgb[2] is red.
-
-Color space conversion coefficients taken from the excellent
-http://www.inforamp.net/~poynton/ColorFAQ.html
-In his terminology, this is a CCIR 601.1 YCbCr -> RGB.
-Y values are given for all 4 pixels, but the U (Pb)
-and V (Pr) are assumed constant over the 2x2 block.
+/**********************************************************************
+ *
+ * Color correction functions
+ *
+ **********************************************************************/
 
-To avoid floating point arithmetic, the color conversion
-coefficients are scaled into 16.16 fixed-point integers.
+/*
+ * Turn a YUV4:2:0 block into an RGB block
+ *
+ * Video4Linux seems to use the blue, green, red channel
+ * order convention-- rgb[0] is blue, rgb[1] is green, rgb[2] is red.
+ *
+ * Color space conversion coefficients taken from the excellent
+ * http://www.inforamp.net/~poynton/ColorFAQ.html
+ * In his terminology, this is a CCIR 601.1 YCbCr -> RGB.
+ * Y values are given for all 4 pixels, but the U (Pb)
+ * and V (Pr) are assumed constant over the 2x2 block.
+ *
+ * To avoid floating point arithmetic, the color conversion
+ * coefficients are scaled into 16.16 fixed-point integers.
+ */
 
-*************************************************************/
-// LIMIT: convert a 16.16 fixed-point value to a byte, with clipping.
+/* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */
 #define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
-static inline void ov511_move_420_block(
-	                int yTL, int yTR, int yBL, int yBR,
-					int u, int v, 
-					int rowPixels, unsigned char * rgb)
-{
-	const double brightness=1.0;//0->black; 1->full scale
-	const double saturation=1.0;//0->greyscale; 1->full color
-	const double fixScale=brightness*256*256;
-	const int rvScale=(int)(1.402*saturation*fixScale);
-	const int guScale=(int)(-0.344136*saturation*fixScale);
-	const int gvScale=(int)(-0.714136*saturation*fixScale);
-	const int buScale=(int)(1.772*saturation*fixScale);
-	const int yScale=(int)(fixScale);	
-
-	int r    =               rvScale * v;
-	int g    = guScale * u + gvScale * v;
-	int b    = buScale * u;
+
+static inline void
+ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, 
+	int rowPixels, unsigned char * rgb)
+{
+	const double brightness = 1.0; // 0->black; 1->full scale
+	const double saturation = 1.0; // 0->greyscale; 1->full color
+	const double fixScale = brightness * 256 * 256;
+	const int rvScale = (int)(1.402 * saturation * fixScale);
+	const int guScale = (int)(-0.344136 * saturation * fixScale);
+	const int gvScale = (int)(-0.714136 * saturation * fixScale);
+	const int buScale = (int)(1.772 * saturation * fixScale);
+	const int yScale = (int)(fixScale);	
+
+	int r = rvScale * v;
+	int g = guScale * u + gvScale * v;
+	int b = buScale * u;
 	yTL *= yScale; yTR *= yScale;
 	yBL *= yScale; yBR *= yScale;
 
 	//Write out top two pixels
-	rgb[0]=LIMIT(b+yTL); rgb[1]=LIMIT(g+yTL); rgb[2]=LIMIT(r+yTL);
-	rgb[3]=LIMIT(b+yTR); rgb[4]=LIMIT(g+yTR); rgb[5]=LIMIT(r+yTR);
-	rgb+=3*rowPixels;//Skip down to next line to write out bottom two pixels
-	rgb[0]=LIMIT(b+yBL); rgb[1]=LIMIT(g+yBL); rgb[2]=LIMIT(r+yBL);
-	rgb[3]=LIMIT(b+yBR); rgb[4]=LIMIT(g+yBR); rgb[5]=LIMIT(r+yBR);
-}
-
-
-/***************************************************************
+	rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL); rgb[2] = LIMIT(r+yTL);
+	rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR); rgb[5] = LIMIT(r+yTR);
 
-For a 640x480 YUV4:2:0 images, data shows up in 1200 384 byte segments.  The
-first 64 bytes of each segment are U, the next 64 are V.  The U and
-V are arranged as follows:
-
-  0  1 ...  7
-  8  9 ... 15
-       ...   
- 56 57 ... 63
-
-U and V are shipped at half resolution (1 U,V sample -> one 2x2 block).
-
-The next 256 bytes are full resolution Y data and represent 4 
-squares of 8x8 pixels as follows:
-
-  0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
-  8  9 ... 15    72  73 ...  79        200 201 ... 207
-       ...              ...                    ...
- 56 57 ... 63   120 121     127        248 249 ... 255
+	//Skip down to next line to write out bottom two pixels
+	rgb += 3 * rowPixels;
+	rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL); rgb[2] = LIMIT(r+yBL);
+	rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR); rgb[5] = LIMIT(r+yBR);
+}
 
-Note that the U and V data in one segment represents a 16 x 16 pixel
-area, but the Y data represents a 32 x 8 pixel area.
 
-If OV511_DUMPPIX is defined, _parse_data just dumps the
-incoming segments, verbatim, in order, into the frame.
-When used with vidcat -f ppm -s 640x480 this puts the data
-on the standard output and can be analyzed with the parseppm.c
-utility I wrote.  That's a much faster way for figuring out how
-this data is scrambled.
+/*
+ * For a 640x480 YUV4:2:0 images, data shows up in 1200 384 byte segments.
+ * The first 64 bytes of each segment are U, the next 64 are V.  The U and
+ * V are arranged as follows:
+ *
+ *      0  1 ...  7
+ *      8  9 ... 15
+ *           ...   
+ *     56 57 ... 63
+ *
+ * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block).
+ *
+ * The next 256 bytes are full resolution Y data and represent 4 squares
+ * of 8x8 pixels as follows:
+ *
+ *      0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
+ *      8  9 ... 15    72  73 ...  79        200 201 ... 207
+ *           ...              ...                    ...
+ *     56 57 ... 63   120 121     127        248 249 ... 255
+ *
+ * Note that the U and V data in one segment represents a 16 x 16 pixel
+ * area, but the Y data represents a 32 x 8 pixel area.
+ *
+ * If OV511_DUMPPIX is defined, _parse_data just dumps the incoming segments,
+ * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480
+ * this puts the data on the standard output and can be analyzed with the
+ * parseppm.c utility I wrote.  That's a much faster way for figuring out how
+ * this data is scrambled.
+ */
 
-****************************************************************/ 
 #define HDIV 8
 #define WDIV (256/HDIV)
 
+#undef OV511_DUMPPIX
 
-static void ov511_parse_data_rgb24(unsigned char * pIn0,
-				   unsigned char * pOut0,
-				   int iOutY,
-				   int iOutUV,
-				   int iHalf,
-				   int iWidth)
- 			    			    
+static void
+ov511_parse_data_rgb24(unsigned char * pIn0, unsigned char * pOut0,
+		       int iOutY, int iOutUV, int iHalf, int iWidth)    			    
 {
 #ifndef OV511_DUMPPIX
-    int k, l, m;
-    unsigned char * pIn;
-    unsigned char * pOut, * pOut1;
-
-    /* Just copy the Y's if in the first stripe */
-    if (!iHalf) {
-	pIn = pIn0 + 128;
-	pOut = pOut0 + iOutY;
-	for(k=0; k<4; k++) {
-	    pOut1 = pOut;
-	    for(l=0; l<8; l++) {
-	      for(m=0; m<8; m++) {
-		*pOut1 = *pIn++;
-		pOut1 += 3;
-	      }
-	      pOut1 += (iWidth - 8) * 3;
-	    }
-	    pOut += 8 * 3;
-	}
-    }
-
-    /* Use the first half of VUs to calculate value */
-    pIn = pIn0;
-    pOut = pOut0 + iOutUV;
-    for(l=0; l<4; l++) {
-	for(m=0; m<8; m++) {
-	    int y00 = *(pOut);
-	    int y01 = *(pOut+3);
-	    int y10 = *(pOut+iWidth*3);
-	    int y11 = *(pOut+iWidth*3+3);
-	    int v   = *(pIn+64) - 128;
-	    int u   = *pIn++ - 128;
-	    ov511_move_420_block(y00, y01, y10, y11, u, v, iWidth, pOut);
-	    pOut += 6;
-	}
-	pOut += (iWidth*2 - 16) * 3;
-    }
-
-    /* Just copy the other UV rows */
-    for(l=0; l<4; l++) {
-	for(m=0; m<8; m++) {
-	  *pOut++ = *(pIn + 64);
-	  *pOut = *pIn++;
-	  pOut += 5;
-	}
-	pOut += (iWidth*2 - 16) * 3;
-    }
-
-    /* Calculate values if it's the second half */
-    if (iHalf) {
-	pIn = pIn0 + 128;
-	pOut = pOut0 + iOutY;
-	for(k=0; k<4; k++) {
-	    pOut1 = pOut;
-	    for(l=0; l<4; l++) {
-	      for(m=0; m<4; m++) {
-		int y10 = *(pIn+8);
-		int y00 = *pIn++;
-		int y11 = *(pIn+8);
-		int y01 = *pIn++;
-		int v   = *pOut1 - 128;
-		int u   = *(pOut1+1) - 128;
-		ov511_move_420_block(y00, y01, y10, y11, u, v, iWidth, pOut1);
-		pOut1 += 6;
-	      }
-	      pOut1 += (iWidth*2 - 8) * 3;
-	      pIn += 8;
-	    }
-	    pOut += 8 * 3;
+	int k, l, m;
+	unsigned char * pIn;
+	unsigned char * pOut, * pOut1;
+
+	/* Just copy the Y's if in the first stripe */
+	if (!iHalf) {
+		pIn = pIn0 + 128;
+		pOut = pOut0 + iOutY;
+		for (k = 0; k < 4; k++) {
+			pOut1 = pOut;
+			for (l = 0; l < 8; l++) {
+				for (m = 0; m < 8; m++) {
+					*pOut1 = *pIn++;
+					pOut1 += 3;
+				}
+				pOut1 += (iWidth - 8) * 3;
+			}
+			pOut += 8 * 3;
+		}
+	}
+
+	/* Use the first half of VUs to calculate value */
+	pIn = pIn0;
+	pOut = pOut0 + iOutUV;
+	for (l = 0; l < 4; l++) {
+		for (m=0; m<8; m++) {
+			int y00 = *(pOut);
+			int y01 = *(pOut+3);
+			int y10 = *(pOut+iWidth*3);
+			int y11 = *(pOut+iWidth*3+3);
+			int v   = *(pIn+64) - 128;
+			int u   = *pIn++ - 128;
+			ov511_move_420_block(y00, y01, y10, y11, u, v, iWidth,
+				pOut);
+			pOut += 6;
+		}
+		pOut += (iWidth*2 - 16) * 3;
+	}
+
+	/* Just copy the other UV rows */
+	for (l = 0; l < 4; l++) {
+		for (m = 0; m < 8; m++) {
+			*pOut++ = *(pIn + 64);
+			*pOut = *pIn++;
+			pOut += 5;
+		}
+		pOut += (iWidth*2 - 16) * 3;
+	}
+
+	/* Calculate values if it's the second half */
+	if (iHalf) {
+		pIn = pIn0 + 128;
+		pOut = pOut0 + iOutY;
+		for (k = 0; k < 4; k++) {
+			pOut1 = pOut;
+			for (l=0; l<4; l++) {
+				for (m=0; m<4; m++) {
+					int y10 = *(pIn+8);
+					int y00 = *pIn++;
+					int y11 = *(pIn+8);
+					int y01 = *pIn++;
+					int v   = *pOut1 - 128;
+					int u   = *(pOut1+1) - 128;
+					ov511_move_420_block(y00, y01, y10,
+						y11, u, v, iWidth, pOut1);
+					pOut1 += 6;
+				}
+				pOut1 += (iWidth*2 - 8) * 3;
+				pIn += 8;
+			}
+			pOut += 8 * 3;
+		}
 	}
-    }
 
 #else
 	/* Just dump pix data straight out for debug */
-	int i;
-	pOut0 += iSegmentY * 384;
-	for(i=0; i<384; i++) {
-	  *pOut0++ = *pIn0++;
+	int i, j;
+
+	pOut0 += iOutY;
+	for (i = 0; i < HDIV; i++) {
+		for (j = 0; j < WDIV; j++) {
+			*pOut0++ = *pIn0++;
+			*pOut0++ = *pIn0++;
+			*pOut0++ = *pIn0++;
+		}
+		pOut0 += (iWidth - WDIV) * 3;
 	}
 #endif
 }
 
-/***************************************************************
 
-For 640x480 RAW BW images, data shows up in 1200 256 byte segments.
-The segments represent 4 squares of 8x8 pixels as
-follows:
-
-  0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
-  8  9 ... 15    72  73 ...  79        200 201 ... 207
-       ...              ...                    ...
- 56 57 ... 63   120 121     127        248 249 ... 255
-
-****************************************************************/ 
-static void ov511_parse_data_grey(unsigned char * pIn0,
-				  unsigned char * pOut0,
-				  int iOutY,
-				  int iWidth)
-			    
-{
-    int k, l, m;
-    unsigned char * pIn;
-    unsigned char * pOut, * pOut1;
-
-    pIn = pIn0;
-    pOut = pOut0 + iOutY;
-    for(k=0; k<4; k++) {
-      pOut1 = pOut;
-      for(l=0; l<8; l++) {
-	for(m=0; m<8; m++) {
-	  *pOut1++ = *pIn++;
-	}
-	pOut1 += iWidth - 8;
-      }
-      pOut += 8;
-    }
+/*
+ * For 640x480 RAW BW images, data shows up in 1200 256 byte segments.
+ * The segments represent 4 squares of 8x8 pixels as follows:
+ *
+ *      0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
+ *      8  9 ... 15    72  73 ...  79        200 201 ... 207
+ *           ...              ...                    ...
+ *     56 57 ... 63   120 121     127        248 249 ... 255
+ *
+ */ 
+static void
+ov511_parse_data_grey(unsigned char * pIn0, unsigned char * pOut0,
+		      int iOutY, int iWidth)		    
+{
+	int k, l, m;
+	unsigned char *pIn;
+	unsigned char *pOut, *pOut1;
+
+	pIn = pIn0;
+	pOut = pOut0 + iOutY;
+	for (k = 0; k < 4; k++) {
+		pOut1 = pOut;
+		for (l = 0; l < 8; l++) {
+			for (m = 0; m < 8; m++) {
+				*pOut1++ = *pIn++;
+			}
+			pOut1 += iWidth - 8;
+		}
+		pOut += 8;
+	}
 }
 
 
-/**************************************************************
+/*
  * fixFrameRGBoffset--
  * My camera seems to return the red channel about 1 pixel
  * low, and the blue channel about 1 pixel high. After YUV->RGB
  * conversion, we can correct this easily. OSL 2/24/2000.
- *************************************************************/
+ */
 static void fixFrameRGBoffset(struct ov511_frame *frame)
 {
-  int x, y;
-  int rowBytes = frame->width*3, w = frame->width;
-  unsigned char *rgb = frame->data;
-  const int shift = 1;   //Distance to shift pixels by, vertically
-
-  if (frame->width < 400) 
-	   return;     //Don't bother with little images
-
-  //Shift red channel up
-  for (y = shift; y < frame->height; y++)
-  {
-    int lp = (y-shift)*rowBytes;     //Previous line offset
-    int lc = y*rowBytes;             //Current line offset
-    for (x = 0; x < w; x++)
-      rgb[lp+x*3+2] = rgb[lc+x*3+2]; //Shift red up
-  }
-
-  //Shift blue channel down
-  for (y=frame->height-shift-1; y >= 0; y--)
-  {
-    int ln = (y+shift)*rowBytes;   //Next line offset
-    int lc = y*rowBytes;           //Current line offset
-    for (x = 0; x < w; x++)
-      rgb[ln+x*3+0] = rgb[lc+x*3+0]; //Shift blue down
-  }
+	int x, y;
+	int rowBytes = frame->width*3, w = frame->width;
+	unsigned char *rgb = frame->data;
+	const int shift = 1;  /* Distance to shift pixels by, vertically */
+
+	/* Don't bother with little images */
+	if (frame->width < 400) 
+		return;
+
+	/* Shift red channel up */
+	for (y = shift; y < frame->height; y++)	{
+		int lp = (y-shift)*rowBytes;     /* Previous line offset */
+		int lc = y*rowBytes;             /* Current line offset */
+		for (x = 0; x < w; x++)
+			rgb[lp+x*3+2] = rgb[lc+x*3+2]; /* Shift red up */
+	}
+
+	/* Shift blue channel down */
+	for (y = frame->height-shift-1; y >= 0; y--) {
+		int ln = (y + shift) * rowBytes;  /* Next line offset */
+		int lc = y * rowBytes;            /* Current line offset */
+		for (x = 0; x < w; x++)
+			rgb[ln+x*3+0] = rgb[lc+x*3+0]; /* Shift blue down */
+	}
 }
 
 
+/**********************************************************************
+ *
+ * OV511 data transfer, IRQ handler
+ *
+ **********************************************************************/
+
 static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
 {
 	unsigned char *cdata;
@@ -1175,6 +1488,7 @@
 	return totlen;
 }
 
+
 static void ov511_isoc_irq(struct urb *urb)
 {
 	int len;
@@ -1187,28 +1501,32 @@
 	if (!ov511->streaming) {
 		PDEBUG(2, "hmmm... not streaming, but got interrupt");
 		return;
+	} else {
+		PDEBUG(5, "streaming. got interrupt");
 	}
 	
 	sbuf = &ov511->sbuf[ov511->cursbuf];
 
 	/* Copy the data received into our scratch buffer */
-	if (ov511->curframe >= 0)
-	  len = ov511_move_data(ov511, urb);
-	else if (waitqueue_active(&ov511->wq))
-	  wake_up_interruptible(&ov511->wq);
-	
+	if (ov511->curframe >= 0) {
+		len = ov511_move_data(ov511, urb);
+	} else if (waitqueue_active(&ov511->wq)) {
+		wake_up_interruptible(&ov511->wq);
+	}
+
 	/* Move to the next sbuf */
 	ov511->cursbuf = (ov511->cursbuf + 1) % OV511_NUMSBUF;
 
 	return;
 }
 
+
 static int ov511_init_isoc(struct usb_ov511 *ov511)
 {
 	urb_t *urb;
 	int fx, err;
 
-	PDEBUG(4, "ov511_init_isoc");
+	PDEBUG(3, "*** Initializing capture ***");
 
 	ov511->compress = 0;
 	ov511->curframe = -1;
@@ -1235,11 +1553,11 @@
 	urb->pipe = usb_rcvisocpipe(ov511->dev, OV511_ENDPOINT_ADDRESS);
 	urb->transfer_flags = USB_ISO_ASAP;
 	urb->transfer_buffer = ov511->sbuf[0].data;
- 	urb->complete = ov511_isoc_irq;
- 	urb->number_of_packets = FRAMES_PER_DESC;
- 	urb->transfer_buffer_length = ov511->packet_size * FRAMES_PER_DESC;
- 	for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- 		urb->iso_frame_desc[fx].offset = ov511->packet_size * fx;
+	urb->complete = ov511_isoc_irq;
+	urb->number_of_packets = FRAMES_PER_DESC;
+	urb->transfer_buffer_length = ov511->packet_size * FRAMES_PER_DESC;
+	for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+		urb->iso_frame_desc[fx].offset = ov511->packet_size * fx;
 		urb->iso_frame_desc[fx].length = ov511->packet_size;
 	}
 
@@ -1254,11 +1572,11 @@
 	urb->pipe = usb_rcvisocpipe(ov511->dev, OV511_ENDPOINT_ADDRESS);
 	urb->transfer_flags = USB_ISO_ASAP;
 	urb->transfer_buffer = ov511->sbuf[1].data;
- 	urb->complete = ov511_isoc_irq;
- 	urb->number_of_packets = FRAMES_PER_DESC;
- 	urb->transfer_buffer_length = ov511->packet_size * FRAMES_PER_DESC;
- 	for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- 		urb->iso_frame_desc[fx].offset = ov511->packet_size * fx;
+	urb->complete = ov511_isoc_irq;
+	urb->number_of_packets = FRAMES_PER_DESC;
+	urb->transfer_buffer_length = ov511->packet_size * FRAMES_PER_DESC;
+	for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+		urb->iso_frame_desc[fx].offset = ov511->packet_size * fx;
 		urb->iso_frame_desc[fx].length = ov511->packet_size;
 	}
 
@@ -1280,10 +1598,11 @@
 
 static void ov511_stop_isoc(struct usb_ov511 *ov511)
 {
-	PDEBUG(4, "ov511_stop_isoc");
 	if (!ov511->streaming || !ov511->dev)
 		return;
 
+	PDEBUG (3, "*** Stopping capture ***");
+
 	ov511_set_packet_size(ov511, 0);
 
 	ov511->streaming = 0;
@@ -1303,18 +1622,19 @@
 	}
 }
 
+
 static int ov511_new_frame(struct usb_ov511 *ov511, int framenum)
 {
 	struct ov511_frame *frame;
 	int width, height;
 
-	PDEBUG(4, "ov511_new_frame");
-
+	PDEBUG(4, "ov511->curframe = %d, framenum = %d", ov511->curframe,
+		framenum);
 	if (!ov511->dev)
 		return -1;
 
 	/* If we're not grabbing a frame right now and the other frame is */
-	/*  ready to be grabbed into, then use it instead */
+	/* ready to be grabbed into, then use it instead */
 	if (ov511->curframe == -1) {
 		if (ov511->frame[(framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES].grabstate == FRAME_READY)
 			framenum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES;
@@ -1325,6 +1645,9 @@
 	width = frame->width;
 	height = frame->height;
 
+	PDEBUG (4, "framenum = %d, width = %d, height = %d", framenum, width,
+		height);
+
 	frame->grabstate = FRAME_GRABBING;
 	frame->scanstate = STATE_SCANNING;
 	frame->scanlength = 0;		/* accumulated in ov511_parse_data() */
@@ -1335,11 +1658,17 @@
 	/* Make sure it's not too big */
 	if (width > DEFAULT_WIDTH)
 		width = DEFAULT_WIDTH;
+#if 0
 	width = (width / 8) * 8;	/* Multiple of 8 */
+#endif
+	width &= ~7L;
 
 	if (height > DEFAULT_HEIGHT)
 		height = DEFAULT_HEIGHT;
+#if 0
 	height = (height / 4) * 4;	/* Multiple of 4 */
+#endif
+	width &= ~3L;
 
 //	/* We want a fresh frame every 30 we get */
 //	ov511->compress = (ov511->compress + 1) % 30;
@@ -1348,7 +1677,12 @@
 }
 
 
-/* Video 4 Linux API */
+/****************************************************************************
+ *
+ * V4L API
+ *
+ ***************************************************************************/
+
 static int ov511_open(struct video_device *dev, int flags)
 {
 	int err = -EBUSY;
@@ -1409,9 +1743,9 @@
 out_unlock:
 	up(&ov511->lock);
 	return err;
-
 }
 
+
 static void ov511_close(struct video_device *dev)
 {
 	struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
@@ -1438,16 +1772,23 @@
 	}
 }
 
+
 static int ov511_init_done(struct video_device *dev)
 {
+#ifdef CONFIG_PROC_FS
+	create_proc_ov511_cam((struct usb_ov511 *)dev);
+#endif
+
 	return 0;
 }
 
+
 static long ov511_write(struct video_device *dev, const char *buf, unsigned long count, int noblock)
 {
 	return -EINVAL;
 }
 
+
 static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
 {
 	struct usb_ov511 *ov511 = (struct usb_ov511 *)vdev;
@@ -1458,311 +1799,313 @@
 		return -EIO;	
 
 	switch (cmd) {
-		case VIDIOCGCAP:
-		{
-			struct video_capability b;
-
-			strcpy(b.name, "OV511 USB Camera");
-			b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
-			b.channels = 1;
-			b.audios = 0;
-			b.maxwidth = DEFAULT_WIDTH;
-			b.maxheight = DEFAULT_HEIGHT;
-			b.minwidth = 32;
-			b.minheight = 16;
+	case VIDIOCGCAP:
+	{
+		struct video_capability b;
+
+		strcpy(b.name, "OV511 USB Camera");
+		b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
+		b.channels = 1;
+		b.audios = 0;
+		b.maxwidth = DEFAULT_WIDTH;
+		b.maxheight = DEFAULT_HEIGHT;
+		b.minwidth = 32;
+		b.minheight = 16;
 
-			if (copy_to_user(arg, &b, sizeof(b)))
-				return -EFAULT;
+		if (copy_to_user(arg, &b, sizeof(b)))
+			return -EFAULT;
 				
-			return 0;
-		}
-		case VIDIOCGCHAN:
-		{
-			struct video_channel v;
-
-			if (copy_from_user(&v, arg, sizeof(v)))
-				return -EFAULT;
-			if (v.channel != 0)
-				return -EINVAL;
+		return 0;
+	}
+	case VIDIOCGCHAN:
+	{
+		struct video_channel v;
 
-			v.flags = 0;
-			v.tuners = 0;
-			v.type = VIDEO_TYPE_CAMERA;
-			strcpy(v.name, "Camera");
+		if (copy_from_user(&v, arg, sizeof(v)))
+			return -EFAULT;
+		if (v.channel != 0)
+			return -EINVAL;
 
-			if (copy_to_user(arg, &v, sizeof(v)))
-				return -EFAULT;
-				
-			return 0;
-		}
-		case VIDIOCSCHAN:
-		{
-			int v;
+		v.flags = 0;
+		v.tuners = 0;
+		v.type = VIDEO_TYPE_CAMERA;
+		strcpy(v.name, "Camera");
 
-			if (copy_from_user(&v, arg, sizeof(v)))
-				return -EFAULT;
+		if (copy_to_user(arg, &v, sizeof(v)))
+			return -EFAULT;
+				
+		return 0;
+	}
+	case VIDIOCSCHAN:
+	{
+		int v;
 
-			if (v != 0)
-				return -EINVAL;
+		if (copy_from_user(&v, arg, sizeof(v)))
+			return -EFAULT;
 
-			return 0;
-		}
+		if (v != 0)
+			return -EINVAL;
 
-		case VIDIOCGPICT:
-		{
-			struct video_picture p;
+		return 0;
+	}
+	case VIDIOCGPICT:
+	{
+		struct video_picture p;
 
-			if (ov7610_get_picture(ov511, &p))
-				return -EIO;
+		if (ov7610_get_picture(ov511, &p))
+			return -EIO;
 							
-			if (copy_to_user(arg, &p, sizeof(p)))
-				return -EFAULT;
+		if (copy_to_user(arg, &p, sizeof(p)))
+			return -EFAULT;
 
-			return 0;
-		}
-		case VIDIOCSPICT:
-		{
-			struct video_picture p;
+		return 0;
+	}
+	case VIDIOCSPICT:
+	{
+		struct video_picture p;
 
-			if (copy_from_user(&p, arg, sizeof(p)))
-				return -EFAULT;
+		if (copy_from_user(&p, arg, sizeof(p)))
+			return -EFAULT;
 			
-			if (ov7610_set_picture(ov511, &p))
-				return -EIO;
+		if (ov7610_set_picture(ov511, &p))
+			return -EIO;
 
-			return 0;
-		}
-		case VIDIOCGCAPTURE:
-		{
-			int vf;
-			if (copy_from_user(&vf, arg, sizeof(vf)))
-				return -EFAULT;
-			ov511->sub_flag = vf;
-			return 0;
-		}
-		case VIDIOCSCAPTURE:
-		{
-			struct video_capture vc;
-
-			if (copy_from_user(&vc, arg, sizeof(vc)))
-				return -EFAULT;
-			if (vc.flags)
-				return -EINVAL;
-			if (vc.decimation)
-				return -EINVAL;
-			vc.x /= 4;
-			vc.x *= 4;
-			vc.y /= 2;
-			vc.y *= 2;
-			vc.width /= 32;
-			vc.width *= 32;
-			if (vc.width == 0) vc.width = 32;
-			vc.height /= 16;
-			vc.height *= 16;
-			if (vc.height == 0) vc.height = 16;
-
-			ov511->subx = vc.x;
-			ov511->suby = vc.y;
-			ov511->subw = vc.width;
-			ov511->subh = vc.height;
-
-			return 0;
-		}
-		case VIDIOCSWIN:
-		{
-			struct video_window vw;
-
-			if (copy_from_user(&vw, arg, sizeof(vw)))
-				return -EFAULT;
-			if (vw.flags)
-				return -EINVAL;
-			if (vw.clipcount)
-				return -EINVAL;
-			if (vw.height != DEFAULT_HEIGHT)
-				return -EINVAL;
-			if (vw.width != DEFAULT_WIDTH)
-				return -EINVAL;
+		return 0;
+	}
+	case VIDIOCGCAPTURE:
+	{
+		int vf;
+		if (copy_from_user(&vf, arg, sizeof(vf)))
+			return -EFAULT;
+		ov511->sub_flag = vf;
+		return 0;
+	}
+	case VIDIOCSCAPTURE:
+	{
+		struct video_capture vc;
 
-			ov511->compress = 0;
+		if (copy_from_user(&vc, arg, sizeof(vc)))
+			return -EFAULT;
+		if (vc.flags)
+			return -EINVAL;
+		if (vc.decimation)
+			return -EINVAL;
+		vc.x /= 4;
+		vc.x *= 4;
+		vc.y /= 2;
+		vc.y *= 2;
+		vc.width /= 32;
+		vc.width *= 32;
+		if (vc.width == 0) vc.width = 32;
+		vc.height /= 16;
+		vc.height *= 16;
+		if (vc.height == 0) vc.height = 16;
+
+		ov511->subx = vc.x;
+		ov511->suby = vc.y;
+		ov511->subw = vc.width;
+		ov511->subh = vc.height;
 
-			return 0;
-		}
-		case VIDIOCGWIN:
-		{
-			struct video_window vw;
+		return 0;
+	}
+	case VIDIOCSWIN:
+	{
+		struct video_window vw;
 
-			vw.x = 0;
-			vw.y = 0;
-			vw.width = DEFAULT_WIDTH;
-			vw.height = DEFAULT_HEIGHT;
-			vw.chromakey = 0;
-			vw.flags = 30;
+		if (copy_from_user(&vw, arg, sizeof(vw)))
+			return -EFAULT;
+		if (vw.flags)
+			return -EINVAL;
+		if (vw.clipcount)
+			return -EINVAL;
+		if (vw.height != DEFAULT_HEIGHT)
+			return -EINVAL;
+		if (vw.width != DEFAULT_WIDTH)
+			return -EINVAL;
 
-			if (copy_to_user(arg, &vw, sizeof(vw)))
-				return -EFAULT;
+		ov511->compress = 0;
 
-			return 0;
-		}
-		case VIDIOCGMBUF:
-		{
-			struct video_mbuf vm;
+		return 0;
+	}
+	case VIDIOCGWIN:
+	{
+		struct video_window vw;
 
-			memset(&vm, 0, sizeof(vm));
-			vm.size = 2 * MAX_DATA_SIZE;
-			vm.frames = 2;
-			vm.offsets[0] = 0;
-			vm.offsets[1] = MAX_FRAME_SIZE + sizeof (struct timeval);
+		vw.x = 0;
+		vw.y = 0;
+		vw.width = DEFAULT_WIDTH;
+		vw.height = DEFAULT_HEIGHT;
+		vw.chromakey = 0;
+		vw.flags = 30;
 
-			if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
-				return -EFAULT;
+		if (copy_to_user(arg, &vw, sizeof(vw)))
+			return -EFAULT;
 
-			return 0;
-		}
-		case VIDIOCMCAPTURE:
-		{
-			struct video_mmap vm;
+		return 0;
+	}
+	case VIDIOCGMBUF:
+	{
+		struct video_mbuf vm;
 
-			if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
-				return -EFAULT;
+		memset(&vm, 0, sizeof(vm));
+		vm.size = 2 * MAX_DATA_SIZE;
+		vm.frames = 2;
+		vm.offsets[0] = 0;
+		vm.offsets[1] = MAX_FRAME_SIZE + sizeof (struct timeval);
 
-			PDEBUG(4, "MCAPTURE");
-			PDEBUG(4, "frame: %d, size: %dx%d, format: %d",
-				vm.frame, vm.width, vm.height, vm.format);
+		if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+			return -EFAULT;
 
-			if (vm.format != VIDEO_PALETTE_RGB24 &&
-			    vm.format != VIDEO_PALETTE_GREY)
-				return -EINVAL;
+		return 0;
+	}
+	case VIDIOCMCAPTURE:
+	{
+		struct video_mmap vm;
 
-			if ((vm.frame != 0) && (vm.frame != 1))
-				return -EINVAL;
+		if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
+			return -EFAULT;
+
+		PDEBUG(4, "MCAPTURE");
+		PDEBUG(4, "frame: %d, size: %dx%d, format: %d",
+			vm.frame, vm.width, vm.height, vm.format);
+
+		if (vm.format != VIDEO_PALETTE_RGB24 &&
+		    vm.format != VIDEO_PALETTE_GREY)
+			return -EINVAL;
+
+		if ((vm.frame != 0) && (vm.frame != 1))
+			return -EINVAL;
 				
-			if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING)
-				return -EBUSY;
+		if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING)
+			return -EBUSY;
 
-			/* Don't compress if the size changed */
-			if ((ov511->frame[vm.frame].width != vm.width) ||
-			    (ov511->frame[vm.frame].height != vm.height) ||
-			    (ov511->frame[vm.frame].format != vm.format) ||
-			    (ov511->frame[vm.frame].sub_flag !=
-			     ov511->sub_flag)) {
-				/* If we're collecting previous frame wait
-				   before changing modes */
-				interruptible_sleep_on(&ov511->wq);
-				if (signal_pending(current)) return -EINTR;
-				ov511_mode_init_regs(ov511,
-						     vm.width, vm.height,
-						     vm.format, ov511->sub_flag);
-			}
+		/* Don't compress if the size changed */
+		if ((ov511->frame[vm.frame].width != vm.width) ||
+		    (ov511->frame[vm.frame].height != vm.height) ||
+		    (ov511->frame[vm.frame].format != vm.format) ||
+		    (ov511->frame[vm.frame].sub_flag !=
+		     ov511->sub_flag)) {
+			/* If we're collecting previous frame wait
+			   before changing modes */
+			interruptible_sleep_on(&ov511->wq);
+			if (signal_pending(current)) return -EINTR;
+			ov511_mode_init_regs(ov511,
+					     vm.width, vm.height,
+					     vm.format, ov511->sub_flag);
+		}
+
+		ov511->frame[vm.frame].width = vm.width;
+		ov511->frame[vm.frame].height = vm.height;
+		ov511->frame[vm.frame].format = vm.format;
+		ov511->frame[vm.frame].sub_flag = ov511->sub_flag;
+		ov511->frame[vm.frame].segsize =
+		  vm.format == VIDEO_PALETTE_RGB24 ? 384 : 256;
+		ov511->frame[vm.frame].depth =
+		  vm.format == VIDEO_PALETTE_RGB24 ? 3 : 1;
+
+		/* Mark it as ready */
+		ov511->frame[vm.frame].grabstate = FRAME_READY;
+
+		return ov511_new_frame(ov511, vm.frame);
+	}
+	case VIDIOCSYNC:
+	{
+		int frame;
+
+		if (copy_from_user((void *)&frame, arg, sizeof(int)))
+			return -EFAULT;
+
+		PDEBUG(4, "syncing to frame %d, grabstate = %d", frame,
+		       ov511->frame[frame].grabstate);
 
-			ov511->frame[vm.frame].width = vm.width;
-			ov511->frame[vm.frame].height = vm.height;
-			ov511->frame[vm.frame].format = vm.format;
-			ov511->frame[vm.frame].sub_flag = ov511->sub_flag;
-			ov511->frame[vm.frame].segsize =
-			  vm.format == VIDEO_PALETTE_RGB24 ? 384 : 256;
-			ov511->frame[vm.frame].depth =
-			  vm.format == VIDEO_PALETTE_RGB24 ? 3 : 1;
-
-			/* Mark it as ready */
-			ov511->frame[vm.frame].grabstate = FRAME_READY;
-
-			return ov511_new_frame(ov511, vm.frame);
-		}
-		case VIDIOCSYNC:
-		{
-			int frame;
-
-			if (copy_from_user((void *)&frame, arg, sizeof(int)))
-				return -EFAULT;
-
-			PDEBUG(4, "syncing to frame %d, grabstate = %d", frame,
-			       ov511->frame[frame].grabstate);
-
-			switch (ov511->frame[frame].grabstate) {
-				case FRAME_UNUSED:
-					return -EINVAL;
-				case FRAME_READY:
-				case FRAME_GRABBING:
-				case FRAME_ERROR:
+		switch (ov511->frame[frame].grabstate) {
+			case FRAME_UNUSED:
+				return -EINVAL;
+			case FRAME_READY:
+			case FRAME_GRABBING:
+			case FRAME_ERROR:
 redo:
-				if (!ov511->dev)
-					return -EIO;
+			if (!ov511->dev)
+				return -EIO;
 
-				do {
+			do {
 #if 0
-					init_waitqueue_head(&ov511->frame[frame].wq);
+				init_waitqueue_head(&ov511->frame[frame].wq);
 #endif
-					interruptible_sleep_on(&ov511->frame[frame].wq);
-					if (signal_pending(current))
-						return -EINTR;
-				} while (ov511->frame[frame].grabstate == FRAME_GRABBING);
-
-				if (ov511->frame[frame].grabstate == FRAME_ERROR) {
-					int ret;
-
-					if ((ret = ov511_new_frame(ov511, frame)) < 0)
-						return ret;
-					goto redo;
-				}				
-				case FRAME_DONE:
-					ov511->frame[frame].grabstate = FRAME_UNUSED;
-					break;
-			}
+				interruptible_sleep_on(&ov511->frame[frame].wq);
+				if (signal_pending(current))
+					return -EINTR;
+			} while (ov511->frame[frame].grabstate == FRAME_GRABBING);
+
+			if (ov511->frame[frame].grabstate == FRAME_ERROR) {
+				int ret;
+
+				if ((ret = ov511_new_frame(ov511, frame)) < 0)
+					return ret;
+				goto redo;
+			}				
+			case FRAME_DONE:
+				ov511->frame[frame].grabstate = FRAME_UNUSED;
+				break;
+		}
+
+		ov511->frame[frame].grabstate = FRAME_UNUSED;
+
+		/* Reset the hardware snapshot button */
+		/* FIXME - Is this the best place for this? */
+		if ((ov511->snap_enabled) &&
+		    (ov511->frame[frame].snapshot)) {
+			ov511->frame[frame].snapshot = 0;
+			ov511_reg_write(ov511->dev, 0x52, 0x01);
+			ov511_reg_write(ov511->dev, 0x52, 0x03);
+			ov511_reg_write(ov511->dev, 0x52, 0x01);
+		}
+
+		return 0;
+	}
+	case VIDIOCGFBUF:
+	{
+		struct video_buffer vb;
 
-			ov511->frame[frame].grabstate = FRAME_UNUSED;
+		memset(&vb, 0, sizeof(vb));
+		vb.base = NULL;	/* frame buffer not supported, not used */
 
-			/* Reset the hardware snapshot button */
-			/* FIXME - Is this the best place for this? */
-			if ((ov511->snap_enabled) &&
-			    (ov511->frame[frame].snapshot)) {
-				ov511->frame[frame].snapshot = 0;
-				ov511_reg_write(ov511->dev, 0x52, 0x01);
-				ov511_reg_write(ov511->dev, 0x52, 0x03);
-				ov511_reg_write(ov511->dev, 0x52, 0x01);
-			}
+		if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
+			return -EFAULT;
 
-			return 0;
-		}
-		case VIDIOCGFBUF:
-		{
-			struct video_buffer vb;
-
-			memset(&vb, 0, sizeof(vb));
-			vb.base = NULL;	/* frame buffer not supported, not used */
-
-			if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
-				return -EFAULT;
-
- 			return 0;
- 		}
-		case VIDIOCKEY:
-			return 0; 		
-		case VIDIOCCAPTURE:
-			return -EINVAL;
-		case VIDIOCSFBUF:
-			return -EINVAL;
-		case VIDIOCGTUNER:
-		case VIDIOCSTUNER:
-			return -EINVAL;			
-		case VIDIOCGFREQ:
-		case VIDIOCSFREQ:
-			return -EINVAL;
-		case VIDIOCGAUDIO:
-		case VIDIOCSAUDIO:
-			return -EINVAL;
-		default:
-			return -ENOIOCTLCMD;
+		return 0;
 	}
+	case VIDIOCKEY:
+		return 0; 		
+	case VIDIOCCAPTURE:
+		return -EINVAL;
+	case VIDIOCSFBUF:
+		return -EINVAL;
+	case VIDIOCGTUNER:
+	case VIDIOCSTUNER:
+		return -EINVAL;			
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
+		return -EINVAL;
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+		return -EINVAL;
+	default:
+		return -ENOIOCTLCMD;
+	}	/* End switch(cmd) */
+
 	return 0;
 }
 
+
 static long ov511_read(struct video_device *dev, char *buf, unsigned long count, int noblock)
 {
 	struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
+	int i;
 	int frmx = -1;
 	volatile struct ov511_frame *frame;
 
-	PDEBUG(4, "ov511_read: %ld bytes, noblock=%d", count, noblock);
+	PDEBUG(4, "%ld bytes, noblock=%d", count, noblock);
 
 	if (!dev || !buf)
 		return -EFAULT;
@@ -1776,6 +2119,7 @@
 	else if (ov511->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
 		frmx = 1;
 
+	/* If nonblocking we return immediately */
 	if (noblock && (frmx == -1))
 		return -EAGAIN;
 
@@ -1794,19 +2138,26 @@
 
 	frame = &ov511->frame[frmx];
 
+	/* FIXME */
+	frame->segsize = frame->format == VIDEO_PALETTE_RGB24 ? 384 : 256;
+	frame->depth = frame->format == VIDEO_PALETTE_RGB24 ? 24 : 8;
+
 restart:
 	if (!ov511->dev)
 		return -EIO;
 
+	/* Wait while we're grabbing the image */
+	PDEBUG(4, "Waiting image grabbing");
 	while (frame->grabstate == FRAME_GRABBING) {
 		interruptible_sleep_on(&ov511->frame[frmx].wq);
 		if (signal_pending(current))
 			return -EINTR;
 	}
+	PDEBUG(4, "Got image, frame->grabstate = %d", frame->grabstate);
 
 	if (frame->grabstate == FRAME_ERROR) {
 		frame->bytes_read = 0;
-		err("ov511_read: errored frame %d", ov511->curframe);
+		err("** ick! ** Errored frame %d", ov511->curframe);
 		if (ov511_new_frame(ov511, frmx))
 			err("ov511_read: ov511_new_frame error");
 		goto restart;
@@ -1814,14 +2165,21 @@
 
 
 	/* Repeat until we get a snapshot frame */
+	if (!ov511->snap_enabled) {
+		PDEBUG (4, "snap disabled");
+	} else {
+		PDEBUG (4, "Waiting snapshot frame");
+	}
 	if (ov511->snap_enabled && !frame->snapshot) {
 		frame->bytes_read = 0;
 		if (ov511_new_frame(ov511, frmx))
-			err("ov511_read: ov511_new_frame error");
+			err("ov511_new_frame error");
 		goto restart;
 	}
 
 	/* Clear the snapshot */
+	if (ov511->snap_enabled)
+		PDEBUG (4, "Clear snapshot");
 	if (ov511->snap_enabled && frame->snapshot) {
 		frame->snapshot = 0;
 		ov511_reg_write(ov511->dev, 0x52, 0x01);
@@ -1829,20 +2187,24 @@
 		ov511_reg_write(ov511->dev, 0x52, 0x01);
 	}
 
-	PDEBUG(4, "ov511_read: frmx=%d, bytes_read=%ld, scanlength=%ld", frmx,
+	PDEBUG(4, "frmx=%d, bytes_read=%ld, scanlength=%ld", frmx,
 		frame->bytes_read, frame->scanlength);
 
 	/* copy bytes to user space; we allow for partials reads */
 //	if ((count + frame->bytes_read) > frame->scanlength)
 //		count = frame->scanlength - frame->bytes_read;
+
 	/* FIXME - count hardwired to be one frame... */
-	count = frame->width * frame->height * frame->depth;
+	count = frame->width * frame->height * (frame->depth >> 3);
 
-	if (copy_to_user(buf, frame->data + frame->bytes_read, count))
+	PDEBUG(4, "Copy to user space: %ld bytes", count);
+	if ((i = copy_to_user(buf, frame->data + frame->bytes_read, count))) {
+		PDEBUG(4, "Copy failed! %d bytes not copied", i);
 		return -EFAULT;
+	}
 
 	frame->bytes_read += count;
-	PDEBUG(4, "ov511_read: {copy} count used=%ld, new bytes_read=%ld",
+	PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld",
 		count, frame->bytes_read);
 
 	if (frame->bytes_read >= frame->scanlength) { /* All data has been read */
@@ -1851,13 +2213,17 @@
 		/* Mark it as available to be used again. */
 		ov511->frame[frmx].grabstate = FRAME_UNUSED;
 		if (ov511_new_frame(ov511, frmx ? 0 : 1))
-			err("ov511_read: ov511_new_frame returned error");
+			err("ov511_new_frame returned error");
 	}
 
+	PDEBUG(4, "read finished, returning %ld (sweet)", count);
+
 	return count;
 }
 
-static int ov511_mmap(struct video_device *dev, const char *adr, unsigned long size)
+
+static int ov511_mmap(struct video_device *dev, const char *adr,
+	unsigned long size)
 {
 	struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
 	unsigned long start = (unsigned long)adr;
@@ -1888,6 +2254,7 @@
 	return 0;
 }
 
+
 static struct video_device ov511_template = {
 	name:		"OV511 USB Camera",
 	type:		VID_TYPE_CAPTURE,
@@ -1901,12 +2268,81 @@
 	initialize:	ov511_init_done,
 };
 
-static int ov7610_configure(struct usb_ov511 *ov511)
+
+/****************************************************************************
+ *
+ * OV511/OV7610 configuration
+ *
+ ***************************************************************************/
+
+static int ov76xx_configure(struct usb_ov511 *ov511)
 {
 	struct usb_device *dev = ov511->dev;
-	int tries;
+	int i, success;
 	int rc;
 
+	static struct ov511_regvals aRegvalsNorm7610[] =
+	{{OV511_I2C_BUS, 0x10, 0xff},
+	 {OV511_I2C_BUS, 0x16, 0x06},
+	 {OV511_I2C_BUS, 0x28, 0x24},
+	 {OV511_I2C_BUS, 0x2b, 0xac},
+	 {OV511_I2C_BUS, 0x05, 0x00},
+	 {OV511_I2C_BUS, 0x06, 0x00},
+	 {OV511_I2C_BUS, 0x12, 0x00},
+	 {OV511_I2C_BUS, 0x38, 0x81},
+	 {OV511_I2C_BUS, 0x28, 0x24}, /* 0c */
+	 {OV511_I2C_BUS, 0x05, 0x00},
+	 {OV511_I2C_BUS, 0x0f, 0x05},
+	 {OV511_I2C_BUS, 0x15, 0x01},
+	 {OV511_I2C_BUS, 0x20, 0x1c},
+	 {OV511_I2C_BUS, 0x23, 0x2a},
+	 {OV511_I2C_BUS, 0x24, 0x10},
+	 {OV511_I2C_BUS, 0x25, 0x8a},
+	 {OV511_I2C_BUS, 0x27, 0xc2},
+	 {OV511_I2C_BUS, 0x29, 0x03}, /* 91 */
+	 {OV511_I2C_BUS, 0x2a, 0x04},
+	 {OV511_I2C_BUS, 0x2c, 0xfe},
+	 {OV511_I2C_BUS, 0x30, 0x71},
+	 {OV511_I2C_BUS, 0x31, 0x60},
+	 {OV511_I2C_BUS, 0x32, 0x26},
+	 {OV511_I2C_BUS, 0x33, 0x20},
+	 {OV511_I2C_BUS, 0x34, 0x48},
+	 {OV511_I2C_BUS, 0x12, 0x24},
+	 {OV511_I2C_BUS, 0x11, 0x01},
+	 {OV511_I2C_BUS, 0x0c, 0x24},
+	 {OV511_I2C_BUS, 0x0d, 0x24},
+	 {OV511_DONE_BUS, 0x0, 0x00},
+	};
+
+	static struct ov511_regvals aRegvalsNorm7620[] =
+	{{OV511_I2C_BUS, 0x10, 0xff},
+	 {OV511_I2C_BUS, 0x16, 0x06},
+	 {OV511_I2C_BUS, 0x28, 0x24},
+	 {OV511_I2C_BUS, 0x2b, 0xac},
+	 {OV511_I2C_BUS, 0x12, 0x00},
+	 {OV511_I2C_BUS, 0x28, 0x24},
+	 {OV511_I2C_BUS, 0x05, 0x00},
+	 {OV511_I2C_BUS, 0x0f, 0x05},
+	 {OV511_I2C_BUS, 0x15, 0x01},
+	 {OV511_I2C_BUS, 0x23, 0x00},
+	 {OV511_I2C_BUS, 0x24, 0x10},
+	 {OV511_I2C_BUS, 0x25, 0x8a},
+	 {OV511_I2C_BUS, 0x27, 0xe2},
+	 {OV511_I2C_BUS, 0x29, 0x03},
+	 {OV511_I2C_BUS, 0x2a, 0x00},
+	 {OV511_I2C_BUS, 0x2c, 0xfe},
+	 {OV511_I2C_BUS, 0x30, 0x71},
+	 {OV511_I2C_BUS, 0x31, 0x60},
+	 {OV511_I2C_BUS, 0x32, 0x26},
+	 {OV511_I2C_BUS, 0x33, 0x20},
+	 {OV511_I2C_BUS, 0x34, 0x48},
+	 {OV511_I2C_BUS, 0x12, 0x24},
+	 {OV511_I2C_BUS, 0x11, 0x01},
+	 {OV511_I2C_BUS, 0x0c, 0x24},
+	 {OV511_I2C_BUS, 0x0d, 0x24},
+	 {OV511_DONE_BUS, 0x0, 0x00},
+	};
+
 	if(ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE,
 	                        OV7610_I2C_WRITE_ID) < 0)
 		return -1;
@@ -1918,64 +2354,90 @@
 	if (ov511_reset(dev, OV511_RESET_NOREGS) < 0)
 		return -1;
 	
-	/* Reset the 7610 and wait a bit for it to initialize */ 
+	/* Reset the 76xx */ 
 	if (ov511_i2c_write(dev, 0x12, 0x80) < 0) return -1;
-	schedule_timeout (1 + 150 * HZ / 1000);
 
-	/* Dummy read to sync I2C */
-	if(ov511_i2c_read(dev, 0x00) < 0)
-		return -1;
- 
-	tries = 5;
-	while((tries > 0) &&
-	      ((ov511_i2c_read(dev, OV7610_REG_ID_HIGH) != 0x7F) ||
-	       (ov511_i2c_read(dev, OV7610_REG_ID_LOW) != 0xA2))) {
-		--tries;
+	for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
+		if ((ov511_i2c_read(dev, OV7610_REG_ID_HIGH) == 0x7F) &&
+		    (ov511_i2c_read(dev, OV7610_REG_ID_LOW) == 0xA2))
+			success = 1;
+
+		/* Dummy read to sync I2C */
+		if (ov511_i2c_read(dev, 0x00) < 0) return -1;
+		/* Wait for it to initialize */ 
+		schedule_timeout (1 + 150 * HZ / 1000);
 	}
-	
-	if (tries == 1) {
-		err("Failed to read sensor ID. You might not have an OV7610/20,");
+
+	if (success) {
+		PDEBUG(1, "I2C synced in %d attempt(s)", i);
+	} else {
+		err("Failed to read sensor ID. You might not have an OV76xx,");
 		err("or it may be not responding. Report this to");
 		err("mmcclelland@delphi.com");
 		return -1;
 	}
 
+	/* Detect sensor if user didn't use override param */
 	if (sensor == 0) {
 		rc = ov511_i2c_read(dev, OV7610_REG_COM_I);
 
 		if (rc < 0) {
 			err("Error detecting sensor type");
 			return -1;
-		}
-		else if((rc & 3) == 3) {
+		} else if((rc & 3) == 3) {
 			printk("ov511: Sensor is an OV7610\n");
 			ov511->sensor = SEN_OV7610;
-		}
-		else if((rc & 3) == 1) {
+		} else if((rc & 3) == 1) {
 			printk("ov511: Sensor is an OV7620AE\n");
 			ov511->sensor = SEN_OV7620AE;
-		}
-		else if((rc & 3) == 0) {
+		} else if((rc & 3) == 0) {
 			printk("ov511: Sensor is an OV7620\n");
 			ov511->sensor = SEN_OV7620;
-		}
-		else {
+		} else {
 			err("Unknown image sensor version: %d", rc & 3);
 			return -1;
 		}
-	}
-	else {  /* sensor != 0; user overrode detection */
+	} else {	/* sensor != 0; user overrode detection */
 		ov511->sensor = sensor;
 		printk("ov511: Sensor set to type %d\n", ov511->sensor);
 	}
 
+	if (ov511->sensor == SEN_OV7620) {
+		if (ov511_write_regvals(dev, aRegvalsNorm7620))
+			return -1;
+	} else {
+		if (ov511_write_regvals(dev, aRegvalsNorm7610))
+			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 */
+		if (ov511_i2c_write(dev, 0x26, (aperture << 4) + 2) < 0)
+			return -1;
+	} else {
+		err("Invalid setting for aperture; legal value: 0 - 15");
+		return -1;
+	}
+
+	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;
+	} 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);
+	}
+
 	return 0;
 }
 
+
 static int ov511_configure(struct usb_ov511 *ov511)
 {
 	struct usb_device *dev = ov511->dev;
-	int rc;
 
 	static struct ov511_regvals aRegvalsInit[] =
 	{{OV511_REG_BUS,  OV511_REG_SYSTEM_RESET, 0x7f},
@@ -1988,7 +2450,7 @@
 	 {OV511_DONE_BUS, 0x0, 0x00},
 	};
 
-	static struct ov511_regvals aRegvalsNorm7610[] =
+	static struct ov511_regvals aRegvalsNorm511[] =
 	{{OV511_REG_BUS, 0x20, 0x01},
 	 {OV511_REG_BUS, 0x52, 0x02},
 	 {OV511_REG_BUS, 0x52, 0x00},
@@ -2003,85 +2465,6 @@
 	 {OV511_REG_BUS, 0x77, 0x01},
 	 {OV511_REG_BUS, 0x78, 0x06},
 	 {OV511_REG_BUS, 0x79, 0x03},
-
-	 {OV511_I2C_BUS, 0x10, 0xff},
-	 {OV511_I2C_BUS, 0x16, 0x06},
-	 {OV511_I2C_BUS, 0x28, 0x24},
-	 {OV511_I2C_BUS, 0x2b, 0xac},
-	 {OV511_I2C_BUS, 0x05, 0x00},
-	 {OV511_I2C_BUS, 0x06, 0x00},
-
-	 {OV511_I2C_BUS, 0x12, 0x00},
-	 {OV511_I2C_BUS, 0x38, 0x81},
-	 {OV511_I2C_BUS, 0x28, 0x24}, /* 0c */
-	 {OV511_I2C_BUS, 0x05, 0x00},
-	 {OV511_I2C_BUS, 0x0f, 0x05},
-	 {OV511_I2C_BUS, 0x15, 0x01},
-	 {OV511_I2C_BUS, 0x20, 0x1c},
-	 {OV511_I2C_BUS, 0x23, 0x2a},
-	 {OV511_I2C_BUS, 0x24, 0x10},
-	 {OV511_I2C_BUS, 0x25, 0x8a},
-	 {OV511_I2C_BUS, 0x26, 0x90},
-	 {OV511_I2C_BUS, 0x27, 0xc2},
-	 {OV511_I2C_BUS, 0x29, 0x03}, /* 91 */
-	 {OV511_I2C_BUS, 0x2a, 0x04},
-	 {OV511_I2C_BUS, 0x2c, 0xfe},
-	 {OV511_I2C_BUS, 0x30, 0x71},
-	 {OV511_I2C_BUS, 0x31, 0x60},
-	 {OV511_I2C_BUS, 0x32, 0x26},
-	 {OV511_I2C_BUS, 0x33, 0x20},
-	 {OV511_I2C_BUS, 0x34, 0x48},
-	 {OV511_I2C_BUS, 0x12, 0x24},
-	 {OV511_I2C_BUS, 0x11, 0x01},
-	 {OV511_I2C_BUS, 0x0c, 0x24},
-	 {OV511_I2C_BUS, 0x0d, 0x24},
-	 {OV511_DONE_BUS, 0x0, 0x00},
-	};
-
-	static struct ov511_regvals aRegvalsNorm7620[] =
-	{{OV511_REG_BUS, 0x20, 0x01},
-	 {OV511_REG_BUS, 0x52, 0x02},
-	 {OV511_REG_BUS, 0x52, 0x00},
-	 {OV511_REG_BUS, 0x31, 0x1f},
-	 {OV511_REG_BUS, 0x70, 0x3f},
-	 {OV511_REG_BUS, 0x71, 0x3f},
-	 {OV511_REG_BUS, 0x72, 0x01},
-	 {OV511_REG_BUS, 0x73, 0x01},
-	 {OV511_REG_BUS, 0x74, 0x01},
-	 {OV511_REG_BUS, 0x75, 0x01},
-	 {OV511_REG_BUS, 0x76, 0x01},
-	 {OV511_REG_BUS, 0x77, 0x01},
-	 {OV511_REG_BUS, 0x78, 0x06},
-	 {OV511_REG_BUS, 0x79, 0x03},
-
-	 {OV511_I2C_BUS, 0x10, 0xff},
-	 {OV511_I2C_BUS, 0x16, 0x06},
-	 {OV511_I2C_BUS, 0x28, 0x24},
-	 {OV511_I2C_BUS, 0x2b, 0xac},
-
-	 {OV511_I2C_BUS, 0x12, 0x00},
-
-	 {OV511_I2C_BUS, 0x28, 0x24},
-	 {OV511_I2C_BUS, 0x05, 0x00},
-	 {OV511_I2C_BUS, 0x0f, 0x05},
-	 {OV511_I2C_BUS, 0x15, 0x01},
-	 {OV511_I2C_BUS, 0x23, 0x00},
-	 {OV511_I2C_BUS, 0x24, 0x10},
-	 {OV511_I2C_BUS, 0x25, 0x8a},
-	 {OV511_I2C_BUS, 0x26, 0xa2},
-	 {OV511_I2C_BUS, 0x27, 0xe2},
-	 {OV511_I2C_BUS, 0x29, 0x03},
-	 {OV511_I2C_BUS, 0x2a, 0x00},
-	 {OV511_I2C_BUS, 0x2c, 0xfe},
-	 {OV511_I2C_BUS, 0x30, 0x71},
-	 {OV511_I2C_BUS, 0x31, 0x60},
-	 {OV511_I2C_BUS, 0x32, 0x26},
-	 {OV511_I2C_BUS, 0x33, 0x20},
-	 {OV511_I2C_BUS, 0x34, 0x48},
-	 {OV511_I2C_BUS, 0x12, 0x24},
-	 {OV511_I2C_BUS, 0x11, 0x01},
-	 {OV511_I2C_BUS, 0x0c, 0x24},
-	 {OV511_I2C_BUS, 0x0d, 0x24},
 	 {OV511_DONE_BUS, 0x0, 0x00},
 	};
 
@@ -2096,54 +2479,36 @@
 		return -EBUSY;
 	}
 
-	if ((rc = ov511_write_regvals(dev, aRegvalsInit)))
-		return rc;
-
-	if(ov7610_configure(ov511) < 0) {
-		err("failed to configure OV7610");
- 		goto error;	
-	}
+	if (ov511_write_regvals(dev, aRegvalsInit)) goto error;
+	if (ov511_write_regvals(dev, aRegvalsNorm511)) goto error;
 
 	ov511_set_packet_size(ov511, 0);
 
-	/* Disable compression */
-	if (ov511_reg_write(dev, OV511_OMNICE_ENABLE, 0x00) < 0)
-		goto error;
-
 	ov511->snap_enabled = snapshot;	
 
 	/* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
 	 * (using read() instead). */
 	ov511->frame[0].width = DEFAULT_WIDTH;
 	ov511->frame[0].height = DEFAULT_HEIGHT;
+	ov511->frame[0].depth = 24;		/**************/
 	ov511->frame[0].bytes_read = 0;
+	ov511->frame[0].segment = 0;
 	ov511->frame[1].width = DEFAULT_WIDTH;
 	ov511->frame[1].height = DEFAULT_HEIGHT;
+	ov511->frame[1].depth = 24;
 	ov511->frame[1].bytes_read = 0;
+	ov511->frame[1].segment = 0;
 
 	/* Initialize to DEFAULT_WIDTH, DEFAULT_HEIGHT, YUV4:2:0 */
 
-	if (ov511->sensor == SEN_OV7620) {
-		if (ov511_write_regvals(dev, aRegvalsNorm7620)) goto error;
-	}
-	else {
-		if (ov511_write_regvals(dev, aRegvalsNorm7610)) goto error;
+	if(ov76xx_configure(ov511) < 0) {
+		err("failed to configure OV76xx");
+ 		goto error;	
 	}
 
 	if (ov511_mode_init_regs(ov511, DEFAULT_WIDTH, DEFAULT_HEIGHT,
-				       VIDEO_PALETTE_RGB24, 0) < 0) goto error;
-
-	if (autoadjust) {
-		if (ov511_i2c_write(dev, 0x13, 0x01) < 0) goto error;
-		if (ov511_i2c_write(dev, 0x2d, 
-		     ov511->sensor==SEN_OV7620?0x91:0x93) < 0) goto error;
-	}
-	else {
-		if (ov511_i2c_write(dev, 0x13, 0x00) < 0) goto error;
-		if (ov511_i2c_write(dev, 0x2d, 
-		     ov511->sensor==SEN_OV7620?0x81:0x83) < 0) goto error;
-		ov511_i2c_write(dev, 0x28, ov511_i2c_read(dev, 0x28) | 8);
-	}
+				 VIDEO_PALETTE_RGB24, 0) < 0)
+		goto error;
 
 	return 0;
 	
@@ -2158,11 +2523,18 @@
 	return -EBUSY;	
 }
 
+
+/****************************************************************************
+ *
+ *  USB routines
+ *
+ ***************************************************************************/
+
 static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
 {
 	struct usb_interface_descriptor *interface;
 	struct usb_ov511 *ov511;
-	int rc;
+	int i;
 
 	PDEBUG(1, "probing for device...");
 
@@ -2191,79 +2563,58 @@
 	}
 
 	memset(ov511, 0, sizeof(*ov511));
-	
+
 	ov511->dev = dev;
 	ov511->iface = interface->bInterfaceNumber;
 
-	if (dev->descriptor.idProduct == 0x0511) {
+	switch (dev->descriptor.idProduct) {
+	case 0x0511:
 		info("USB OV511 camera found");
 		ov511->bridge = BRG_OV511;
-	}
-	else if (dev->descriptor.idProduct == 0xA511) {
+		break;
+	case 0xA511:
 		info("USB OV511+ camera found");
 		ov511->bridge = BRG_OV511PLUS;
+		break;
 	}
 
-	rc = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID);
-	if (rc < 0) {
+	ov511->customid = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID);
+	if (ov511->customid < 0) {
 		err("Unable to read camera bridge registers");
 		goto error;
 	}
-	
-	switch(ov511->customid = rc) {
-	case 0: /* This also means that no custom ID was set */
-		printk("ov511: Camera is a generic model (no ID)\n");
-		break;
-	case 3:
-		printk("ov511: Camera is a D-Link DSB-C300\n");
-		break;
-	case 4:
-		printk("ov511: Camera is a generic OV511/OV7610\n");
-		break;
-	case 5:
-		printk("ov511: Camera is a Puretek PT-6007\n");
-		break;
-	case 21:
-		printk("ov511: Camera is a Creative Labs WebCam 3\n");
-		break;
-	case 36:
-		printk("ov511: Camera is a Koala-Cam\n");
-		break;
-	case 38:
-		printk("ov511: Camera is a Lifeview USB Life TV\n");
-		printk("ov511: This device is not supported, exiting...\n");
-		goto error;
-		break;
-	case 100:
-		printk("ov511: Camera is a Lifeview RoboCam\n");
-		break;
-	case 102:
-		printk("ov511: Camera is a AverMedia InterCam Elite\n");
-		break;
-	case 112: /* The OmniVision OV7110 evaluation kit uses this too */
-		printk("ov511: Camera is a MediaForte MV300\n");
-		break;
-	default:
-		err("Specific camera type (%d) not recognized", rc);
+
+	ov511->desc = -1;
+	PDEBUG (4, "CustomID = %d", ov511->customid);
+	for (i = 0; clist[i].id >= 0; i++) {
+		if (ov511->customid == clist[i].id) {
+			printk ("Camera: %s\n", clist[i].description);
+			ov511->desc = i;
+			break;
+		}
+	}
+
+	/* Lifeview USB Life TV not supported */
+	if (clist[i].id == 38) {
+		err("This device is not supported yet.");
+		return NULL;
+	}
+
+	if (clist[i].id == -1) {
+		err("Camera type (%d) not recognized", ov511->customid);
 		err("Please contact mmcclelland@delphi.com to request");
 		err("support for your camera.");
 	}
 
-//	if (ov511->bridge == BRG_OV511PLUS) {
-//		err("Sorry, the OV511+ chip is not supported yet");
-//		goto error;
-//	}
-
 	if (!ov511_configure(ov511)) {
-		ov511->user=0;
+		ov511->user = 0;
 		init_MUTEX(&ov511->lock);	/* to 1 == available */
 		return ov511;
-	}
-	else {
+	} else {
 		err("Failed to configure camera");
 		goto error;
 	}
-    	
+
      	return ov511;
 
 error:
@@ -2272,12 +2623,12 @@
 		ov511 = NULL;
 	}
 
-	return NULL;	
+	return NULL;
 }
 
+
 static void ov511_disconnect(struct usb_device *dev, void *ptr)
 {
-
 	struct usb_ov511 *ov511 = (struct usb_ov511 *) ptr;
 
 //	video_unregister_device(&ov511->vdev);
@@ -2318,6 +2669,11 @@
 		ov511->sbuf[0].urb = NULL;
 	}
 
+#ifdef CONFIG_PROC_FS
+        PDEBUG(3, "destroying /proc/ov511/video%d", ov511->vdev.minor);
+        destroy_proc_ov511_cam(ov511);
+#endif
+
 	/* Free the memory */
 	if (!ov511->user) {
 		kfree(ov511);
@@ -2332,18 +2688,35 @@
 	{ NULL, NULL }
 };
 
+
+/****************************************************************************
+ *
+ *  Module routines
+ *
+ ***************************************************************************/
+
 static int __init usb_ov511_init(void)
 {
+#ifdef CONFIG_PROC_FS
+	PDEBUG(3, "creating /proc/ov511");
+        proc_ov511_create();
+#endif
+
 	if (usb_register(&ov511_driver) < 0)
 		return -1;
 
-	info("ov511 driver registered");
+	info("ov511 driver version %s registered", version);
 
 	return 0;
 }
 
 static void __exit usb_ov511_exit(void)
 {
+#ifdef CONFIG_PROC_FS
+	PDEBUG(3, "destroying /proc/ov511");
+        proc_ov511_destroy();
+#endif 
+
 	usb_deregister(&ov511_driver);
 	info("ov511 driver deregistered");
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)