Hi!

I'm sending you a patch for the ov511 driver for inclusion in the
latest 2.3.99-preX kernel.

Mark McClelland <[EMAIL PROTECTED]>        ov511-1.14-pre9-2.diff
        - Update of the ov511 driver to v 1.14

-- 
Vojtech Pavlik
SuSE Labs
This is against 2.3.99-pre9-2.

NEW:
 o 352x288 mode
 o force_rgb parameter for apps that expect RGB instead of BGR

CHANGES:
- Added palette_list for converting palette type to string (for proc fs)
- Moved proc entry from /proc/ov511 to /proc/video/ov511
- Added proc file fields for data format, brightness, color, contrast,
  data buffer, framebuffer
- Removed proc write functionality
- Added mode_list for simpler mode initialization
- Added 352x288 mode
- Broke subcapture :)
- Added module parameter to force RGB rather than BGR to satisfy broken
apps
- Modified code to use OV511_NUMFRAMES where appropriate
- Removed need for most of gotos in ov511_open()
- Reformatted regval structs (no reg changes)
- ov511.h: added descriptions for 7610 regs
- ov511.h: added brightness, colour, contrast, hue, and whiteness fields
to 
  usb_ov511
- ov511.h: added palette_list and mode_list struct definitions
- ov511.h: OV511_ENDPOINT_ADDRESS changed to 1, was incorrectly 0x81
- Documentation/usb/ov511.txt: Updated

Mark McClelland
[EMAIL PROTECTED]
diff -Naur linux-2.3.99-pre9-2-orig/CREDITS linux/CREDITS
--- linux-2.3.99-pre9-2-orig/CREDITS    Thu May 18 09:03:03 2000
+++ linux/CREDITS       Thu May 18 10:40:05 2000
@@ -1613,12 +1613,30 @@
 D: XF86_8514
 D: cfdisk (curses based disk partitioning program)
 
+N: Claudio S. Matsuoka
+E: [EMAIL PROTECTED]
+E: [EMAIL PROTECTED]
+W: http://helllabs.org/~claudio
+D: OV511 driver hacks
+S: Conectiva S.A.
+S: R. Tocantins 89
+S: 80050-430  Curitiba PR
+S: Brazil
+
 N: Heinz Mauelshagen
 E: [EMAIL PROTECTED]
 D: Logical Volume Manager
 S: Bartningstr. 12
 S: 64289 Darmstadt
 S: Germany 
+
+N: Mark W. McClelland
+E: [EMAIL PROTECTED]
+E: [EMAIL PROTECTED]
+W: http://alpha.dyndns.org/ov511/
+D: OV511 driver
+S: (address available on request)
+S: USA
 
 N: Mike McLagan
 E: [EMAIL PROTECTED]
diff -Naur linux-2.3.99-pre9-2-orig/Documentation/usb/ov511.txt 
linux/Documentation/usb/ov511.txt
--- linux-2.3.99-pre9-2-orig/Documentation/usb/ov511.txt        Thu May 11 13:45:35 
2000
+++ linux/Documentation/usb/ov511.txt   Thu May 18 10:40:22 2000
@@ -6,11 +6,8 @@
 Homepage: http://alpha.dyndns.org/ov511
 
 NEW IN THIS VERSION:
- o Improvements to sensor detection code
- o Added "i2c_detect_tries" and "aperture" parameters
- o proc filesystem status support
- o read() fixed partially
- o code cleanups and minor fixes
+ o 352x288 mode
+ o force_rgb parameter for apps that expect RGB instead of BGR
 
 INTRODUCTION:
 
@@ -139,7 +136,7 @@
         or so lines higher than the red component. This is only apparent in 
         images with white objects on black backgrounds at 640x480. Setting this
         to 1 will realign the color planes correctly. NOTE: This is still
-        experimental and very buggy.
+        experimental and very buggy. You will likely need a fast (500 Mhz) CPU.
 
   NAME: snapshot
   TYPE: integer (boolean)
@@ -148,8 +145,41 @@
         button is pressed. Note that this does not yet work with most apps,
         including xawtv and vidcat. NOTE: See the section "TODO" for more info.
 
+  NAME: sensor
+  TYPE: integer ([0, 1, 3])
+  DEFAULT: [varies]
+  DESC: If you know that your camera sensor is not detected correctly, set this
+        parameter. This is a global option for all attached OV511 cameras. You
+        will probably never need to set this, but if you do, valid values are:
+               0 for OV7620
+               1 for OV7620AE
+               3 for OV7610
+
+  NAME: i2c_detect_tries
+  TYPE: integer (don't set it insanely high!)
+  DEFAULT: 5
+  DESC: This is the number of times the driver will try to sync and detect the
+        internal i2c bus (which connects the OV511 and sensor). If you are
+        getting intermittant detection failures ("Failed to read sensor ID...")
+        you should increase this by a modest amount. If setting it to 20 or so
+        doesn't fix things, look elsewhere for the cause of the problem.
+
+  NAME: aperture
+  TYPE: integer (0 - 15)
+  DEFAULT: [varies by sensor]
+  DESC: For legal values, see the OV7610/7620 specs under register Common F.
+        This setting affects the upper nybble of that reg (bits 4-7). This is
+        for if you want to play with the camera's pixel saturation.
+
+  NAME: force_rgb
+  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
+        your colors look VERY wrong, you may want to change this.
+
 WORKING FEATURES:
- o Color streaming/capture at 640x480 and 320x240
+ o Color streaming/capture at 640x480, 352x288, and 320x240
  o YUV420 color
  o Monochrome
  o Setting/getting of saturation, contrast and brightness (no hue yet; only
@@ -158,7 +188,7 @@
 
 EXPERIMENTAL FEATURES:
  o fix_rgb_offset: Sometimes works, but other times causes errors with xawtv and
-   corrupted frames.
+   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 read() support
 
@@ -197,6 +227,6 @@
 
 The code is based in no small part on the CPiA driver by Johannes Erdfelt,
 Randy Dunlap, and others. Big thanks to them for their pioneering work on that
-and the USB stack. Thanks to Bret Wallach for getting camera reg IO , ISOC, and
-image capture working. Thanks to Orion Sky Lawlor and Kevin Moore for their
-work as well.
+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.3.99-pre9-2-orig/MAINTAINERS linux/MAINTAINERS
--- linux-2.3.99-pre9-2-orig/MAINTAINERS        Thu May 18 09:03:03 2000
+++ linux/MAINTAINERS   Thu May 18 10:40:00 2000
@@ -1140,6 +1140,13 @@
 L:     [EMAIL PROTECTED]
 S:     Maintained
 
+USB OV511 DRIVER
+P:     Mark McClelland
+M:     [EMAIL PROTECTED]
+L:     [EMAIL PROTECTED]
+W:     http://alpha.dyndns.org/ov511/
+S:     Maintained
+
 USB PEGASUS DRIVER
 P:     Petko Manolov
 M:     [EMAIL PROTECTED]
diff -Naur linux-2.3.99-pre9-2-orig/drivers/usb/ov511.c linux/drivers/usb/ov511.c
--- linux-2.3.99-pre9-2-orig/drivers/usb/ov511.c        Thu May 11 13:45:35 2000
+++ linux/drivers/usb/ov511.c   Thu May 18 10:40:30 2000
@@ -6,7 +6,7 @@
  * Color fixes by by Orion Sky Lawlor, [EMAIL PROTECTED], 2/26/2000
  * Snapshot code by Kevin Moore
  * OV7620 fixes by Charl P. Botha <[EMAIL PROTECTED]>
- * Changes by Claudio Matsuoka, [EMAIL PROTECTED], 3/26/2000
+ * Changes by Claudio Matsuoka <[EMAIL PROTECTED]>
  * 
  * Based on the Linux CPiA driver written by Peter Pregler,
  * Scott J. Bertin and Johannes Erdfelt.
@@ -30,7 +30,7 @@
  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-static const char version[] = "1.13";
+static const char version[] = "1.14";
 
 #define __NO_VERSION__
 
@@ -64,6 +64,9 @@
 #define DEFAULT_WIDTH 640
 #define DEFAULT_HEIGHT 480
 
+#define GET_SEGSIZE(p) ((p) == VIDEO_PALETTE_RGB24 ? 384 : 256)
+#define GET_DEPTH(p) ((p) == VIDEO_PALETTE_RGB24 ? 24 : 8)
+
 /* PARAMETER VARIABLES: */
 static int autoadjust = 1;    /* CCD dynamically changes exposure, etc... */
 
@@ -90,9 +93,13 @@
 static int i2c_detect_tries = 5;
 
 /* For legal values, see the OV7610/7620 specs under register Common F,
-   upper nybble  (set to 0-F) */
+ * upper nybble  (set to 0-F) */
 static int aperture = -1;
 
+/* 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. */
+static int force_rgb = 0;
+
 MODULE_PARM(autoadjust, "i");
 MODULE_PARM(debug, "i");
 MODULE_PARM(fix_rgb_offset, "i");
@@ -100,8 +107,9 @@
 MODULE_PARM(sensor, "i");
 MODULE_PARM(i2c_detect_tries, "i");
 MODULE_PARM(aperture, "i");
+MODULE_PARM(force_rgb, "i");
 
-MODULE_AUTHOR("Mark McClelland (and others)");
+MODULE_AUTHOR("Mark McClelland <[EMAIL PROTECTED]> & Bret Wallach & Orion Sky 
+Lawlor <[EMAIL PROTECTED]> & Kevin Moore & Charl P. Botha <[EMAIL PROTECTED]> & Claudio 
+Matsuoka <[EMAIL PROTECTED]>");
 MODULE_DESCRIPTION("OV511 USB Camera Driver");
 
 char kernel_version[] = UTS_RELEASE;
@@ -126,6 +134,26 @@
        {  -1, NULL }
 };
 
+static struct palette_list plist[] = {
+       { VIDEO_PALETTE_GREY,   "GREY" },
+       { VIDEO_PALETTE_HI240,  "HI240" },
+       { VIDEO_PALETTE_RGB565, "RGB565" },
+       { VIDEO_PALETTE_RGB24,  "RGB24" },
+       { VIDEO_PALETTE_RGB32,  "RGB32" },
+       { VIDEO_PALETTE_RGB555, "RGB555" },
+       { VIDEO_PALETTE_YUV422, "YUV422" },
+       { VIDEO_PALETTE_YUYV,   "YUYV" },
+       { VIDEO_PALETTE_UYVY,   "UYVY" },
+       { VIDEO_PALETTE_YUV420, "YUV420" },
+       { VIDEO_PALETTE_YUV411, "YUV411" },
+       { VIDEO_PALETTE_RAW,    "RAW" },
+       { VIDEO_PALETTE_YUV422P,"YUV422P" },
+       { VIDEO_PALETTE_YUV411P,"YUV411P" },
+       { VIDEO_PALETTE_YUV420P,"YUV420P" },
+       { VIDEO_PALETTE_YUV410P,"YUV410P" },
+       { -1, NULL }
+};
+
 /**********************************************************************
  *
  * Memory management
@@ -236,7 +264,8 @@
  **********************************************************************/
 
 #ifdef CONFIG_PROC_FS
-static struct proc_dir_entry *ov511_proc_root = NULL;
+static struct proc_dir_entry *ov511_proc_entry = NULL;
+static struct proc_dir_entry *video_proc_entry = NULL;
 
 #define YES_NO(x) ((x) ? "yes" : "no")
 
@@ -244,7 +273,7 @@
                           int count, int *eof, void *data)
 {
        char *out = page;
-       int i, len;
+       int i, j, len;
        struct usb_ov511 *ov511 = data;
 
        /* IMPORTANT: This output MUST be kept under PAGE_SIZE
@@ -259,6 +288,10 @@
        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, "data_format     : %s\n", force_rgb ? "RGB" : "BGR");
+       out += sprintf (out, "brightness      : %d\n", ov511->brightness >> 8);
+       out += sprintf (out, "colour          : %d\n", ov511->colour >> 8);
+       out += sprintf (out, "contrast        : %d\n", ov511->contrast >> 8);
        out += sprintf (out, "num_frames      : %d\n", OV511_NUMFRAMES);
        for (i = 0; i < OV511_NUMFRAMES; i++) {
                out += sprintf (out, "frame           : %d\n", i);
@@ -266,27 +299,40 @@
                        ov511->frame[i].depth);
                out += sprintf (out, "  size          : %d %d\n",
                        ov511->frame[i].width, ov511->frame[i].height);
+#if 0
                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);
+#endif
+               out += sprintf (out, "  format        : ");
+               for (j = 0; plist[j].num >= 0; j++) {
+                       if (plist[j].num == ov511->frame[i].format) {
+                               out += sprintf (out, "%s\n", plist[j].name);
+                               break;
+                       }
+               }
+               if (plist[j].num < 0)
+                       out += sprintf (out, "unknown\n");
                out += sprintf (out, "  segsize       : %d\n",
                        ov511->frame[i].segsize);
+               out += sprintf (out, "  data_buffer   : 0x%p\n",
+                       ov511->frame[i].data);
 #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, "bridge          : %s\n",
+               ov511->bridge == BRG_OV511 ? "OV511" :
+               ov511->bridge == BRG_OV511PLUS ? "OV511+" :
+               "unknown");
+       out += sprintf (out, "sensor          : %s\n",
+               ov511->sensor == SEN_OV7610 ? "OV7610" :
+               ov511->sensor == SEN_OV7620 ? "OV7620" :
+               ov511->sensor == SEN_OV7620AE ? "OV7620AE" :
+               "unknown");
        out += sprintf (out, "packet_size     : %d\n", ov511->packet_size);
+       out += sprintf (out, "framebuffer     : 0x%p\n", ov511->fbuf);
        
        len = out - page;
        len -= off;
@@ -303,130 +349,7 @@
 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;
+       return -EINVAL;
 }
 
 static void create_proc_ov511_cam (struct usb_ov511 *ov511)
@@ -434,14 +357,15 @@
        char name[7];
        struct proc_dir_entry *ent;
        
-       PDEBUG (4, "***************");
-       if (!ov511_proc_root || !ov511)
+       PDEBUG (4, "creating /proc/video/ov511/videoX entry");
+       if (!ov511_proc_entry || !ov511)
                return;
 
        sprintf(name, "video%d", ov511->vdev.minor);
-       PDEBUG (4, "==== name: %s", name);
+       PDEBUG (4, "creating %s", name);
        
-       ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, ov511_proc_root);
+       ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, ov511_proc_entry);
+
        if (!ent)
                return;
 
@@ -460,26 +384,44 @@
                return;
        
        sprintf(name, "video%d", ov511->vdev.minor);
-       PDEBUG (4, "==== name: %s", name);
-#if 0
-       remove_proc_entry(name, ov511_proc_root);
+       PDEBUG (4, "destroying %s", name);
+       remove_proc_entry(name, ov511_proc_entry);
        ov511->proc_entry = NULL;
-#endif
 }
 
 static void proc_ov511_create(void)
 {
-       ov511_proc_root = create_proc_entry("ov511", S_IFDIR, 0);
+       struct proc_dir_entry *p = NULL;
+
+       /* No current standard here. Alan prefers /proc/video/ as it keeps
+        * /proc "less cluttered than /proc/randomcardifoundintheshed/"
+        * -claudio
+        */
+       PDEBUG (3, "creating /proc/video");
+       video_proc_entry = proc_mkdir("video", p);
+       if (!video_proc_entry) {
+               if (!p) {
+                       err("Unable to initialise /proc/video\n");
+                       return;
+               } else {        /* FIXME - this doesn't work */
+                       PDEBUG (3, "/proc/video already exists");
+                       video_proc_entry = p;
+               }
+       }
 
-       if (ov511_proc_root)
-               ov511_proc_root->owner = THIS_MODULE;
+       ov511_proc_entry = create_proc_entry("ov511", S_IFDIR, video_proc_entry);
+
+       if (ov511_proc_entry)
+               ov511_proc_entry->owner = THIS_MODULE;
        else
-               printk("Unable to initialise /proc/ov511\n");   /***********/
+               err("Unable to initialise /proc/video/ov511\n");
 }
 
 static void proc_ov511_destroy(void)
 {
-       remove_proc_entry("ov511", 0);
+       PDEBUG (3, "removing /proc/video/ov511");
+       remove_proc_entry("ov511", video_proc_entry);
+       remove_proc_entry("video", NULL);
 }
 #endif /* CONFIG_PROC_FS */
 
@@ -510,7 +452,6 @@
        return rc;
 }
 
-
 /* returns: negative is error, pos or zero is data */
 static int ov511_reg_read(struct usb_device *dev, unsigned char reg)
 {
@@ -533,7 +474,6 @@
        }
 }
 
-
 static int ov511_i2c_write(struct usb_device *dev,
                           unsigned char reg,
                           unsigned char value)
@@ -580,7 +520,6 @@
        return rc;
 }
 
-
 /* returns: negative is error, pos or zero is data */
 static int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
 {
@@ -653,7 +592,6 @@
        return rc;
 }
 
-
 static int ov511_write_regvals(struct usb_device *dev,
                               struct ov511_regvals * pRegvals)
 {
@@ -682,9 +620,8 @@
        return rc;
 }
 
-
-#if 0
-static void ov511_dump_i2c_range( struct usb_device *dev, int reg1, int regn)
+#ifdef OV511_DEBUG 
+static void ov511_dump_i2c_range(struct usb_device *dev, int reg1, int regn)
 {
        int i;
        int rc;
@@ -694,15 +631,13 @@
        }
 }
 
-
-static void ov511_dump_i2c_regs( struct usb_device *dev)
+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)
+static void ov511_dump_reg_range(struct usb_device *dev, int reg1, int regn)
 {
        int i;
        int rc;
@@ -712,8 +647,8 @@
        }
 }
 
-
-static void ov511_dump_regs( struct usb_device *dev)
+#if 0
+static void ov511_dump_regs(struct usb_device *dev)
 {
        PDEBUG(1, "CAMERA INTERFACE REGS");
        ov511_dump_reg_range(dev, 0x10, 0x1f);
@@ -736,7 +671,7 @@
 
 }
 #endif
-
+#endif
 
 static int ov511_reset(struct usb_device *dev, unsigned char reset_type)
 {
@@ -752,24 +687,21 @@
        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)
 {
-       PDEBUG(4, "ov511_stop()");
+       PDEBUG(4, "stopping");
        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)
 {
-       PDEBUG(4, "ov511_restart()");
+       PDEBUG(4, "restarting");
        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;
@@ -844,9 +776,16 @@
        if (ov511_stop(dev) < 0)
                return -EIO;
 
+       ov511->contrast = p->contrast;
+       ov511->brightness = p->brightness;
+       ov511->colour = p->colour;
+       ov511->hue = p->hue;
+       ov511->whiteness = p->whiteness;
+
        if ((ret = ov511_i2c_read(dev, OV7610_REG_COM_B)) < 0)
                return -EIO;
 #if 0
+       /* disable auto adjust mode */
        if (ov511_i2c_write(dev, OV7610_REG_COM_B, ret & 0xfe) < 0)
                return -EIO;
 #endif
@@ -880,7 +819,6 @@
        return 0;
 }
 
-
 static inline int
 ov7610_get_picture(struct usb_ov511 *ov511, struct video_picture *p)
 {
@@ -903,12 +841,10 @@
 
        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;
+
+       /* Can we get these from frame[0]? -claudio? */
+       p->depth = ov511->frame[0].depth;
+       p->palette = ov511->frame[0].format;
 
        if (ov511_restart(dev) < 0)
                return -EIO;
@@ -916,6 +852,22 @@
        return 0;
 }
 
+/* FIXME: add 176x144, 160x140 */
+static struct mode_list mlist[] = {
+       { 640, 480, VIDEO_PALETTE_GREY, 0x4f, 0x3d, 0x00, 0x00,
+         0x4f, 0x3d, 0x00, 0x00, 0x04, 0x03, 0x24, 0x04, 0x9e },
+       { 640, 480, VIDEO_PALETTE_RGB24,0x4f, 0x3d, 0x00, 0x00,
+         0x4f, 0x3d, 0x00, 0x00, 0x06, 0x03, 0x24, 0x04, 0x9e },
+       { 320, 240, VIDEO_PALETTE_GREY, 0x27, 0x1f, 0x00, 0x00,
+         0x27, 0x1f, 0x00, 0x00, 0x01, 0x03, 0x04, 0x24, 0x1e },
+       { 320, 240, VIDEO_PALETTE_RGB24,0x27, 0x1f, 0x00, 0x00,
+         0x27, 0x1f, 0x00, 0x00, 0x01, 0x03, 0x04, 0x24, 0x1e },
+       { 352, 288, VIDEO_PALETTE_GREY, 0x2b, 0x25, 0x00, 0x00,
+         0x2b, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e },
+       { 352, 288, VIDEO_PALETTE_RGB24,0x2b, 0x25, 0x00, 0x00,
+         0x2b, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e },
+       { 0, 0 }
+};
 
 static int
 ov511_mode_init_regs(struct usb_ov511 *ov511,
@@ -925,6 +877,7 @@
        struct usb_device *dev = ov511->dev;
        int hwsbase = 0;
        int hwebase = 0;
+       int i;
 
        PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
               width, height, mode, sub_flag);
@@ -975,6 +928,9 @@
                break;
        }
 
+#if 0
+       /* FIXME: subwindow support is currently broken! 
+        */
        if (width == 640 && height == 480) {
                if (sub_flag) {
                        /* horizontal window start */
@@ -1018,41 +974,51 @@
                        }
                }
 
-               ov511_reg_write(dev, 0x14, 0x00);
-               ov511_reg_write(dev, 0x15, 0x00);
+               ov511_reg_write(dev, 0x14, 0x00);       /* Pixel divisor */
+               ov511_reg_write(dev, 0x15, 0x00);       /* Line divisor */
 
                /* FIXME?? Shouldn't below be true only for YUV420? */
-               ov511_reg_write(dev, 0x18, 0x03);
+               ov511_reg_write(dev, 0x18, 0x03);       /* YUV420/422, YFIR */
 
-               ov511_i2c_write(dev, 0x12, 0x24);
-               ov511_i2c_write(dev, 0x14, 0x04);
+               ov511_i2c_write(dev, 0x12, 0x24);       /* Common A */
+               ov511_i2c_write(dev, 0x14, 0x04);       /* Common C */
 
                /* 7620 doesn't have register 0x35, so play it safe */
                if (ov511->sensor != SEN_OV7620)
                        ov511_i2c_write(dev, 0x35, 0x9e);
-       } else if (width == 320 && height == 240) {
-               ov511_reg_write(dev, 0x12, 0x27);
-               ov511_reg_write(dev, 0x13, 0x1f);
-               ov511_reg_write(dev, 0x14, 0x00);
-               ov511_reg_write(dev, 0x15, 0x00);
-               ov511_reg_write(dev, 0x18, 0x03);
+#endif
+
+       for (i = 0; mlist[i].width; i++) {
+               if (width != mlist[i].width ||
+                   height != mlist[i].height ||
+                   mode != mlist[i].mode)
+                       continue;
+
+               ov511_reg_write(dev, 0x12, mlist[i].pxcnt);
+               ov511_reg_write(dev, 0x13, mlist[i].lncnt);
+               ov511_reg_write(dev, 0x14, mlist[i].pxdv);
+               ov511_reg_write(dev, 0x15, mlist[i].lndv);
+               ov511_reg_write(dev, 0x18, mlist[i].m420);
 
                /* Snapshot additions */
-               ov511_reg_write(dev, 0x1a, 0x27);
-               ov511_reg_write(dev, 0x1b, 0x1f);
-                ov511_reg_write(dev, 0x1c, 0x00);
-                ov511_reg_write(dev, 0x1d, 0x00);
+               ov511_reg_write(dev, 0x1a, mlist[i].s_pxcnt);
+               ov511_reg_write(dev, 0x1b, mlist[i].s_lncnt);
+                ov511_reg_write(dev, 0x1c, mlist[i].s_pxdv);
+                ov511_reg_write(dev, 0x1d, mlist[i].s_lndv);
 
-               if (mode == VIDEO_PALETTE_GREY) {
-                 ov511_i2c_write(dev, 0x11, 1); /* check */
-               } else {
-                 ov511_i2c_write(dev, 0x11, 1); /* check */
-               }
+               ov511_i2c_write(dev, 0x11, mlist[i].clock); /* check */
 
-               ov511_i2c_write(dev, 0x12, 0x04);
-               ov511_i2c_write(dev, 0x14, 0x24);
-               ov511_i2c_write(dev, 0x35, 0x1e);
-       } else {
+               ov511_i2c_write(dev, 0x12, mlist[i].common_A);
+               ov511_i2c_write(dev, 0x14, mlist[i].common_C);
+
+               /* 7620 doesn't have register 0x35, so play it safe */
+               if (ov511->sensor != SEN_OV7620)
+                       ov511_i2c_write(dev, 0x35, mlist[i].common_L);
+
+               break;
+       }
+
+       if (mlist[i].width == 0) {
                err("Unknown mode (%d, %d): %d", width, height, mode);
                rc = -EINVAL;
        }
@@ -1060,10 +1026,14 @@
        if (ov511_restart(ov511->dev) < 0)
                return -EIO;
 
+#ifdef OV511_DEBUG
+       if (debug >= 5)
+               ov511_dump_i2c_regs(dev);
+#endif
+
        return rc;
 }
 
-
 /**********************************************************************
  *
  * Color correction functions
@@ -1093,32 +1063,38 @@
 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 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, g, b;
+
+       g = guScale * u + gvScale * v;
+       if (force_rgb) {
+               r = buScale * u;
+               b = rvScale * v;
+       } else {
+               r = rvScale * v;
+               b = buScale * u;
+       }
 
-       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
+       /* 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);
 
-       //Skip down to next line to write out bottom two pixels
+       /* 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);
 }
 
-
 /*
  * 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
@@ -1155,13 +1131,13 @@
 #undef OV511_DUMPPIX
 
 static void
-ov511_parse_data_rgb24(unsigned char * pIn0, unsigned char * pOut0,
+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;
+       unsigned char *pIn;
+       unsigned char *pOut, *pOut1;
 
        /* Just copy the Y's if in the first stripe */
        if (!iHalf) {
@@ -1232,7 +1208,6 @@
                        pOut += 8 * 3;
                }
        }
-
 #else
        /* Just dump pix data straight out for debug */
        int i, j;
@@ -1249,7 +1224,6 @@
 #endif
 }
 
-
 /*
  * For 640x480 RAW BW images, data shows up in 1200 256 byte segments.
  * The segments represent 4 squares of 8x8 pixels as follows:
@@ -1257,11 +1231,11 @@
  *      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
+ *     56 57 ... 63   120 121 ... 127        248 249 ... 255
  *
  */ 
 static void
-ov511_parse_data_grey(unsigned char * pIn0, unsigned char * pOut0,
+ov511_parse_data_grey(unsigned char *pIn0, unsigned char *pOut0,
                      int iOutY, int iWidth)                
 {
        int k, l, m;
@@ -1276,13 +1250,12 @@
                        for (m = 0; m < 8; m++) {
                                *pOut1++ = *pIn++;
                        }
-                       pOut1 += iWidth - 8;
+                       pOut1 += iWidth - WDIV;
                }
                pOut += 8;
        }
 }
 
-
 /*
  * fixFrameRGBoffset--
  * My camera seems to return the red channel about 1 pixel
@@ -1317,7 +1290,6 @@
        }
 }
 
-
 /**********************************************************************
  *
  * OV511 data transfer, IRQ handler
@@ -1488,7 +1460,6 @@
        return totlen;
 }
 
-
 static void ov511_isoc_irq(struct urb *urb)
 {
        int len;
@@ -1520,7 +1491,6 @@
        return;
 }
 
-
 static int ov511_init_isoc(struct usb_ov511 *ov511)
 {
        urb_t *urb;
@@ -1595,7 +1565,6 @@
        return 0;
 }
 
-
 static void ov511_stop_isoc(struct usb_ov511 *ov511)
 {
        if (!ov511->streaming || !ov511->dev)
@@ -1622,7 +1591,6 @@
        }
 }
 
-
 static int ov511_new_frame(struct usb_ov511 *ov511, int framenum)
 {
        struct ov511_frame *frame;
@@ -1658,25 +1626,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;
+
+       width &= ~7L;                   /* Multiple of 8 */
 
        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;
+       width &= ~3L;                   /* Multiple of 4 */
 
        return 0;
 }
 
-
 /****************************************************************************
  *
  * V4L API
@@ -1687,43 +1647,45 @@
 {
        int err = -EBUSY;
        struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
+       int i;
 
-       PDEBUG(4, "ov511_open");
+       PDEBUG(4, "opening");
 
        down(&ov511->lock);
-       if (ov511->user)
-               goto out_unlock;
 
-       ov511->frame[0].grabstate = FRAME_UNUSED;
-       ov511->frame[1].grabstate = FRAME_UNUSED;
+       if (ov511->user) {
+               up(&ov511->lock);
+               return -EBUSY;
+       }
 
        err = -ENOMEM;
 
        /* Allocate memory for the frame buffers */
-       ov511->fbuf = rvmalloc(2 * MAX_DATA_SIZE);
+       ov511->fbuf = rvmalloc(OV511_NUMFRAMES * MAX_DATA_SIZE);
        if (!ov511->fbuf)
-               goto open_err_ret;
+               return err;
 
-       ov511->frame[0].data = ov511->fbuf;
-       ov511->frame[1].data = ov511->fbuf + MAX_DATA_SIZE;
        ov511->sub_flag = 0;
 
-       PDEBUG(4, "frame [0] @ %p", ov511->frame[0].data);
-       PDEBUG(4, "frame [1] @ %p", ov511->frame[1].data);
-
-       ov511->sbuf[0].data = kmalloc(FRAMES_PER_DESC * MAX_FRAME_SIZE_PER_DESC, 
GFP_KERNEL);
-       if (!ov511->sbuf[0].data)
-               goto open_err_on0;
-       ov511->sbuf[1].data = kmalloc(FRAMES_PER_DESC * MAX_FRAME_SIZE_PER_DESC, 
GFP_KERNEL);
-       if (!ov511->sbuf[1].data)
-               goto open_err_on1;
-               
-       PDEBUG(4, "sbuf[0] @ %p", ov511->sbuf[0].data);
-       PDEBUG(4, "sbuf[1] @ %p", ov511->sbuf[1].data);
+       for (i = 0; i < OV511_NUMFRAMES; i++) {
+               ov511->frame[i].grabstate = FRAME_UNUSED;
+               ov511->frame[i].data = ov511->fbuf + i * MAX_DATA_SIZE;
+               PDEBUG(4, "frame [%d] @ %p", i, ov511->frame[0].data);
+
+               ov511->sbuf[i].data = kmalloc(FRAMES_PER_DESC *
+                       MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
+               if (!ov511->sbuf[i].data) {
+open_free_ret:
+                       while (--i) kfree(ov511->sbuf[i].data);
+                       rvfree(ov511->fbuf, 2 * MAX_DATA_SIZE);
+                       return err;
+               }       
+               PDEBUG(4, "sbuf[%d] @ %p", i, ov511->sbuf[i].data);
+       }
 
        err = ov511_init_isoc(ov511);
        if (err)
-               goto open_err_on2;
+               goto open_free_ret;
 
        ov511->user++;
        up(&ov511->lock);
@@ -1731,24 +1693,12 @@
        MOD_INC_USE_COUNT;
 
        return 0;
-
-open_err_on2:
-       kfree (ov511->sbuf[1].data);
-open_err_on1:
-       kfree (ov511->sbuf[0].data);
-open_err_on0:
-       rvfree(ov511->fbuf, 2 * MAX_DATA_SIZE);
-open_err_ret:
-       return err;
-out_unlock:
-       up(&ov511->lock);
-       return err;
 }
 
-
 static void ov511_close(struct video_device *dev)
 {
        struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
+       int i;
 
        PDEBUG(4, "ov511_close");
        
@@ -1759,10 +1709,9 @@
 
        ov511_stop_isoc(ov511);
 
-       rvfree(ov511->fbuf, 2 * MAX_DATA_SIZE);
-
-       kfree(ov511->sbuf[1].data);
-       kfree(ov511->sbuf[0].data);
+       rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE);
+       for (i = 0; i < OV511_NUMFRAMES; i++)
+               kfree(ov511->sbuf[i].data);
 
        up(&ov511->lock);
 
@@ -1772,7 +1721,6 @@
        }
 }
 
-
 static int ov511_init_done(struct video_device *dev)
 {
 #ifdef CONFIG_PROC_FS
@@ -1782,13 +1730,11 @@
        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;
@@ -2097,7 +2043,6 @@
        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;
@@ -2138,10 +2083,6 @@
 
        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;
@@ -2165,11 +2106,8 @@
 
 
        /* Repeat until we get a snapshot frame */
-       if (!ov511->snap_enabled) {
-               PDEBUG (4, "snap disabled");
-       } else {
+       if (ov511->snap_enabled)
                PDEBUG (4, "Waiting snapshot frame");
-       }
        if (ov511->snap_enabled && !frame->snapshot) {
                frame->bytes_read = 0;
                if (ov511_new_frame(ov511, frmx))
@@ -2178,13 +2116,11 @@
        }
 
        /* 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);
-               ov511_reg_write(ov511->dev, 0x52, 0x03);
-               ov511_reg_write(ov511->dev, 0x52, 0x01);
+               ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01);
+               ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x03);
+               ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01);
        }
 
        PDEBUG(4, "frmx=%d, bytes_read=%ld, scanlength=%ld", frmx,
@@ -2212,7 +2148,7 @@
 
                /* Mark it as available to be used again. */
                ov511->frame[frmx].grabstate = FRAME_UNUSED;
-               if (ov511_new_frame(ov511, frmx ? 0 : 1))
+               if (ov511_new_frame(ov511, !frmx))
                        err("ov511_new_frame returned error");
        }
 
@@ -2221,7 +2157,6 @@
        return count;
 }
 
-
 static int ov511_mmap(struct video_device *dev, const char *adr,
        unsigned long size)
 {
@@ -2229,7 +2164,7 @@
        unsigned long start = (unsigned long)adr;
        unsigned long page, pos;
 
-       if (!ov511->dev)
+       if (ov511->dev == NULL)
                return -EIO;
 
        PDEBUG(4, "mmap: %ld (%lX) bytes", size, size);
@@ -2238,8 +2173,7 @@
                return -EINVAL;
 
        pos = (unsigned long)ov511->fbuf;
-       while (size > 0)
-       {
+       while (size > 0) {
                page = kvirt_to_pa(pos);
                if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
                        return -EAGAIN;
@@ -2254,7 +2188,6 @@
        return 0;
 }
 
-
 static struct video_device ov511_template = {
        name:           "OV511 USB Camera",
        type:           VID_TYPE_CAPTURE,
@@ -2268,7 +2201,6 @@
        initialize:     ov511_init_done,
 };
 
-
 /****************************************************************************
  *
  * OV511/OV7610 configuration
@@ -2281,68 +2213,70 @@
        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 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},
+       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 },
        };
 
+       PDEBUG (4, "starting configuration");
+
        if(ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE,
                                OV7610_I2C_WRITE_ID) < 0)
                return -1;
@@ -2385,13 +2319,13 @@
                        err("Error detecting sensor type");
                        return -1;
                } else if((rc & 3) == 3) {
-                       printk("ov511: Sensor is an OV7610\n");
+                       info("Sensor is an OV7610");
                        ov511->sensor = SEN_OV7610;
                } else if((rc & 3) == 1) {
-                       printk("ov511: Sensor is an OV7620AE\n");
+                       info("Sensor is an OV7620AE");
                        ov511->sensor = SEN_OV7620AE;
                } else if((rc & 3) == 0) {
-                       printk("ov511: Sensor is an OV7620\n");
+                       info("Sensor is an OV7620");
                        ov511->sensor = SEN_OV7620;
                } else {
                        err("Unknown image sensor version: %d", rc & 3);
@@ -2399,13 +2333,15 @@
                }
        } else {        /* sensor != 0; user overrode detection */
                ov511->sensor = sensor;
-               printk("ov511: Sensor set to type %d\n", ov511->sensor);
+               info("Sensor set to type %d", ov511->sensor);
        }
 
        if (ov511->sensor == SEN_OV7620) {
+               PDEBUG(4, "Writing 7620 registers");
                if (ov511_write_regvals(dev, aRegvalsNorm7620))
                        return -1;
        } else {
+               PDEBUG(4, "Writing 7610 registers");
                if (ov511_write_regvals(dev, aRegvalsNorm7610))
                        return -1;
        }
@@ -2438,34 +2374,35 @@
 static int ov511_configure(struct usb_ov511 *ov511)
 {
        struct usb_device *dev = ov511->dev;
+       int i;
 
-       static struct ov511_regvals aRegvalsInit[] =
-       {{OV511_REG_BUS,  OV511_REG_SYSTEM_RESET, 0x7f},
-        {OV511_REG_BUS,  OV511_REG_SYSTEM_INIT, 0x01},
-        {OV511_REG_BUS,  OV511_REG_SYSTEM_RESET, 0x7f},
-        {OV511_REG_BUS,  OV511_REG_SYSTEM_INIT, 0x01},
-        {OV511_REG_BUS,  OV511_REG_SYSTEM_RESET, 0x3f},
-        {OV511_REG_BUS,  OV511_REG_SYSTEM_INIT, 0x01},
-        {OV511_REG_BUS,  OV511_REG_SYSTEM_RESET, 0x3d},
-        {OV511_DONE_BUS, 0x0, 0x00},
+       static struct ov511_regvals aRegvalsInit[] = {
+               { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f },
+               { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 },
+               { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f },
+               { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 },
+               { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3f },
+               { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 },
+               { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3d },
+               { OV511_DONE_BUS, 0x0, 0x00},
        };
 
-       static struct ov511_regvals aRegvalsNorm511[] =
-       {{OV511_REG_BUS, 0x20, 0x01},
-        {OV511_REG_BUS, 0x52, 0x02},
-        {OV511_REG_BUS, 0x52, 0x00},
-        {OV511_REG_BUS, 0x31, 0x1f}, /* 0f */
-        {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_DONE_BUS, 0x0, 0x00},
+       static struct ov511_regvals aRegvalsNorm511[] = {
+               { OV511_REG_BUS, OV511_REG_DRAM_ENABLE_FLOW_CONTROL, 0x01 },
+               { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x02 },
+               { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x00 },
+               { OV511_REG_BUS, OV511_REG_FIFO_BITMASK, 0x1f }, /* 0f */
+               { OV511_REG_BUS, OV511_OMNICE_PREDICTION_HORIZ_Y, 0x3f },
+               { OV511_REG_BUS, OV511_OMNICE_PREDICTION_HORIZ_UV, 0x3f },
+               { OV511_REG_BUS, OV511_OMNICE_PREDICTION_VERT_Y, 0x01 },
+               { 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_UV, 0x01 },
+               { OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_VERT_Y, 0x01 },
+               { 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_DONE_BUS, 0x0, 0x00 },
        };
 
        memcpy(&ov511->vdev, &ov511_template, sizeof(ov511_template));
@@ -2488,16 +2425,15 @@
 
        /* 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;
+       for (i = 0; i < OV511_NUMFRAMES; i++) {
+               ov511->frame[i].width = DEFAULT_WIDTH;
+               ov511->frame[i].height = DEFAULT_HEIGHT;
+               ov511->frame[i].depth = 24;
+               ov511->frame[i].bytes_read = 0;
+               ov511->frame[i].segment = 0;
+               ov511->frame[i].format = VIDEO_PALETTE_RGB24;
+               ov511->frame[i].segsize = GET_SEGSIZE(ov511->frame[i].format);
+       }
 
        /* Initialize to DEFAULT_WIDTH, DEFAULT_HEIGHT, YUV4:2:0 */
 
@@ -2588,7 +2524,7 @@
        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);
+                       info("camera: %s", clist[i].description);
                        ov511->desc = i;
                        break;
                }
@@ -2606,6 +2542,11 @@
                err("support for your camera.");
        }
 
+       /* Workaround for some applications that want data in RGB
+        * instead of BGR */
+       if (force_rgb)
+               info("data format set to RGB");
+
        if (!ov511_configure(ov511)) {
                ov511->user = 0;
                init_MUTEX(&ov511->lock);       /* to 1 == available */
@@ -2670,7 +2611,6 @@
        }
 
 #ifdef CONFIG_PROC_FS
-        PDEBUG(3, "destroying /proc/ov511/video%d", ov511->vdev.minor);
         destroy_proc_ov511_cam(ov511);
 #endif
 
@@ -2712,13 +2652,12 @@
 
 static void __exit usb_ov511_exit(void)
 {
+       usb_deregister(&ov511_driver);
+       info("ov511 driver deregistered");
+
 #ifdef CONFIG_PROC_FS
-       PDEBUG(3, "destroying /proc/ov511");
         proc_ov511_destroy();
 #endif 
-
-       usb_deregister(&ov511_driver);
-       info("ov511 driver deregistered");
 }
 
 module_init(usb_ov511_init);
diff -Naur linux-2.3.99-pre9-2-orig/drivers/usb/ov511.h linux/drivers/usb/ov511.h
--- linux-2.3.99-pre9-2-orig/drivers/usb/ov511.h        Thu May 11 13:45:35 2000
+++ linux/drivers/usb/ov511.h   Thu May 18 10:40:38 2000
@@ -1,3 +1,4 @@
+
 #ifndef __LINUX_OV511_H
 #define __LINUX_OV511_H
 
@@ -9,7 +10,7 @@
 
 #ifdef OV511_DEBUG
 #  define PDEBUG(level, fmt, args...) \
-if (debug >= level) printk("ov511: [" __PRETTY_FUNCTION__ ":%d] " fmt "\n", __LINE__ 
, ## args)
+if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
 #else
 #  define PDEBUG(level, fmt, args...) do {} while(0)
 #endif
@@ -119,48 +120,55 @@
 #define OV511PLUS_ALT_SIZE_961 7
 
 /* OV7610 registers */
-#define OV7610_REG_GAIN          0x00
-#define OV7610_REG_BLUE          0x01
-#define OV7610_REG_RED           0x02
-#define OV7610_REG_SAT           0x03
-#define OV7610_REG_CNT           0x05
-#define OV7610_REG_BRT           0x06
-#define OV7610_REG_BLUE_BIAS     0x0C
-#define OV7610_REG_RED_BIAS      0x0D
-#define OV7610_REG_GAMMA_COEFF   0x0E
-#define OV7610_REG_WB_RANGE      0x0F
-#define OV7610_REG_EXP           0x10
-#define OV7610_REG_CLOCK         0x11
-#define OV7610_REG_COM_A         0x12
-#define OV7610_REG_COM_B         0x13
-#define OV7610_REG_COM_C         0x14
-#define OV7610_REG_COM_D         0x15
-#define OV7610_REG_FIELD_DIVIDE  0x16
-#define OV7610_REG_HWIN_START    0x17
-#define OV7610_REG_HWIN_END      0x18
-#define OV7610_REG_VWIN_START    0x19
-#define OV7610_REG_VWIN_END      0x1A
-#define OV7610_REG_PIXEL_SHIFT   0x1B
-#define OV7610_REG_ID_HIGH       0x1C
-#define OV7610_REG_ID_LOW        0x1D
-#define OV7610_REG_COM_E         0x20
-#define OV7610_REG_YOFFSET       0x21
-#define OV7610_REG_UOFFSET       0x22
-#define OV7610_REG_ECW           0x24
-#define OV7610_REG_ECB           0x25
-#define OV7610_REG_COM_F         0x26
-#define OV7610_REG_COM_G         0x27
-#define OV7610_REG_COM_H         0x28
-#define OV7610_REG_COM_I         0x29
-#define OV7610_REG_FRAMERATE_H   0x2A
-#define OV7610_REG_FRAMERATE_L   0x2B
-#define OV7610_REG_ALC           0x2C
-#define OV7610_REG_COM_J         0x2D
-#define OV7610_REG_VOFFSET       0x2E
-#define OV7610_REG_YGAMMA        0x33
-#define OV7610_REG_BIAS_ADJUST   0x34
-#define OV7610_REG_COM_L         0x35
-#define OV7610_REG_COM_K         0x38
+#define OV7610_REG_GAIN          0x00  /* gain setting (5:0) */
+#define OV7610_REG_BLUE          0x01  /* blue channel balance */
+#define OV7610_REG_RED           0x02  /* red channel balance */
+#define OV7610_REG_SAT           0x03  /* saturation */
+                                       /* 04 reserved */
+#define OV7610_REG_CNT           0x05  /* Y contrast */
+#define OV7610_REG_BRT           0x06  /* Y brightness */
+                                       /* 08-0b reserved */
+#define OV7610_REG_BLUE_BIAS     0x0C  /* blue channel bias (5:0) */
+#define OV7610_REG_RED_BIAS      0x0D  /* read channel bias (5:0) */
+#define OV7610_REG_GAMMA_COEFF   0x0E  /* gamma settings */
+#define OV7610_REG_WB_RANGE      0x0F  /* AEC/ALC/S-AWB settings */
+#define OV7610_REG_EXP           0x10  /* manual exposure setting */
+#define OV7610_REG_CLOCK         0x11  /* polarity/clock prescaler */
+#define OV7610_REG_COM_A         0x12  /* misc common regs */
+#define OV7610_REG_COM_B         0x13  /* misc common regs */
+#define OV7610_REG_COM_C         0x14  /* misc common regs */
+#define OV7610_REG_COM_D         0x15  /* misc common regs */
+#define OV7610_REG_FIELD_DIVIDE  0x16  /* field interval/mode settings */
+#define OV7610_REG_HWIN_START    0x17  /* horizontal window start */
+#define OV7610_REG_HWIN_END      0x18  /* horizontal window end */
+#define OV7610_REG_VWIN_START    0x19  /* vertical window start */
+#define OV7610_REG_VWIN_END      0x1A  /* vertical window end */
+#define OV7610_REG_PIXEL_SHIFT   0x1B  /* pixel shift */
+#define OV7610_REG_ID_HIGH       0x1C  /* manufacturer ID MSB */
+#define OV7610_REG_ID_LOW        0x1D  /* manufacturer ID LSB */
+                                       /* 0e-0f reserved */
+#define OV7610_REG_COM_E         0x20  /* misc common regs */
+#define OV7610_REG_YOFFSET       0x21  /* Y channel offset */
+#define OV7610_REG_UOFFSET       0x22  /* U channel offset */
+                                       /* 23 reserved */
+#define OV7610_REG_ECW           0x24  /* Exposure white level for AEC */
+#define OV7610_REG_ECB           0x25  /* Exposure black level for AEC */
+#define OV7610_REG_COM_F         0x26  /* misc settings */
+#define OV7610_REG_COM_G         0x27  /* misc settings */
+#define OV7610_REG_COM_H         0x28  /* misc settings */
+#define OV7610_REG_COM_I         0x29  /* misc settings */
+#define OV7610_REG_FRAMERATE_H   0x2A  /* frame rate MSB + misc */
+#define OV7610_REG_FRAMERATE_L   0x2B  /* frame rate LSB */
+#define OV7610_REG_ALC           0x2C  /* Auto Level Control settings */
+#define OV7610_REG_COM_J         0x2D  /* misc settings */
+#define OV7610_REG_VOFFSET       0x2E  /* V channel offset adjustment */
+#define OV7610_REG_ARRAY_BIAS   0x2F   /* Array bias -- don't change */
+                                       /* 30-32 reserved */
+#define OV7610_REG_YGAMMA        0x33  /* misc gamma settings (7:6) */
+#define OV7610_REG_BIAS_ADJUST   0x34  /* misc bias settings */
+#define OV7610_REG_COM_L         0x35  /* misc settings */
+                                       /* 36-37 reserved */
+#define OV7610_REG_COM_K         0x38  /* misc registers */
 
 
 #define STREAM_BUF_SIZE        (PAGE_SIZE * 4)
@@ -171,8 +179,7 @@
 #define FRAME_SIZE_PER_DESC    993     /* FIXME - Deprecated */
 #define MAX_FRAME_SIZE_PER_DESC        993     /* For statically allocated stuff */
 
-// FIXME - should this be 0x81 (endpoint address) or 0x01 (endpoint number)?
-#define OV511_ENDPOINT_ADDRESS 0x81    /* Address of isoc endpoint */
+#define OV511_ENDPOINT_ADDRESS 1       /* Isoc endpoint number */
 
 // CAMERA SPECIFIC
 // FIXME - these can vary between specific models
@@ -223,9 +230,9 @@
 
 struct ov511_regvals {
        enum {
-         OV511_DONE_BUS,
-         OV511_REG_BUS,
-         OV511_I2C_BUS,
+               OV511_DONE_BUS,
+               OV511_REG_BUS,
+               OV511_I2C_BUS,
        } bus;
        unsigned char reg;
        unsigned char val;
@@ -269,15 +276,16 @@
        /* Device structure */
        struct usb_device *dev;
 
-#if 0
-       unsigned char customid; /* Type of camera */
-#else
        int customid;
        int desc;
-#endif
-
        unsigned char iface;
 
+       int brightness;
+       int colour;
+       int contrast;
+       int hue;
+       int whiteness;
+
        struct semaphore lock;
        int user;               /* user count for exclusive use */
 
@@ -318,10 +326,33 @@
        struct proc_dir_entry *proc_entry;      /* /proc/ov511/videoX */
 };
 
-
 struct cam_list {
        int id;
        char *description;
+};
+
+struct palette_list {
+       int num;
+       char *name;
+};
+
+struct mode_list {
+       int width;
+       int height;
+       int mode;
+       u8 pxcnt;
+       u8 lncnt;
+       u8 pxdv;
+       u8 lndv;
+       u8 s_pxcnt;
+       u8 s_lncnt;
+       u8 s_pxdv;
+       u8 s_lndv;
+       u8 clock;
+       u8 m420;
+       u8 common_A;
+       u8 common_C;
+       u8 common_L;
 };
 
 #endif

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to