Merge branch 'for-next' into for-linus
[safe/jmp/linux-2.6] / drivers / media / video / gspca / ov519.c
index bfc8836..f36e11a 100644 (file)
@@ -2,14 +2,19 @@
  * OV519 driver
  *
  * Copyright (C) 2008 Jean-Francois Moine (http://moinejf.free.fr)
+ * Copyright (C) 2009 Hans de Goede <hdegoede@redhat.com>
  *
  * This module is adapted from the ov51x-jpeg package, which itself
  * was adapted from the ov511 driver.
  *
  * Original copyright for the ov511 driver is:
  *
- * Copyright (c) 1999-2004 Mark W. McClelland
+ * Copyright (c) 1999-2006 Mark W. McClelland
  * Support for OV519, OV8610 Copyright (c) 2003 Joerg Heckenbach
+ * Many improvements by Bret Wallach <bwallac1@san.rr.com>
+ * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
+ * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
+ * Changes by Claudio Matsuoka <claudio@conectiva.com>
  *
  * ov51x-jpeg original copyright is:
  *
@@ -33,6 +38,7 @@
  */
 #define MODULE_NAME "ov519"
 
+#include <linux/input.h>
 #include "gspca.h"
 
 MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
@@ -59,11 +65,15 @@ struct sd {
 #define BRIDGE_OV518PLUS       3
 #define BRIDGE_OV519           4
 #define BRIDGE_OVFX2           5
+#define BRIDGE_W9968CF         6
 #define BRIDGE_MASK            7
 
        char invert_led;
 #define BRIDGE_INVERT_LED      8
 
+       char snapshot_pressed;
+       char snapshot_needs_reset;
+
        /* Determined by sensor type */
        __u8 sif;
 
@@ -74,6 +84,10 @@ struct sd {
        __u8 vflip;
        __u8 autobrightness;
        __u8 freq;
+       __u8 quality;
+#define QUALITY_MIN 50
+#define QUALITY_MAX 70
+#define QUALITY_DEF 50
 
        __u8 stopped;           /* Streaming is temporarily paused */
 
@@ -89,12 +103,26 @@ struct sd {
 #define SEN_OV66308AF 5
 #define SEN_OV7610 6
 #define SEN_OV7620 7
-#define SEN_OV7640 8
-#define SEN_OV7670 9
-#define SEN_OV76BE 10
-#define SEN_OV8610 11
+#define SEN_OV7620AE 8
+#define SEN_OV7640 9
+#define SEN_OV7648 10
+#define SEN_OV7670 11
+#define SEN_OV76BE 12
+#define SEN_OV8610 13
+
+       u8 sensor_addr;
+       int sensor_width;
+       int sensor_height;
+       int sensor_reg_cache[256];
+
+       u8 *jpeg_hdr;
 };
 
+/* Note this is a bit of a hack, but the w9968cf driver needs the code for all
+   the ov sensors which is already present here. When we have the time we
+   really should move the sensor drivers to v4l2 sub drivers. */
+#include "w996Xcf.c"
+
 /* V4L2 controls supported by the driver */
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
@@ -117,6 +145,7 @@ static void setautobrightness(struct sd *sd);
 static void setfreq(struct sd *sd);
 
 static const struct ctrl sd_ctrls[] = {
+#define BRIGHTNESS_IDX 0
        {
            {
                .id      = V4L2_CID_BRIGHTNESS,
@@ -131,6 +160,7 @@ static const struct ctrl sd_ctrls[] = {
            .set = sd_setbrightness,
            .get = sd_getbrightness,
        },
+#define CONTRAST_IDX 1
        {
            {
                .id      = V4L2_CID_CONTRAST,
@@ -145,6 +175,7 @@ static const struct ctrl sd_ctrls[] = {
            .set = sd_setcontrast,
            .get = sd_getcontrast,
        },
+#define COLOR_IDX 2
        {
            {
                .id      = V4L2_CID_SATURATION,
@@ -389,26 +420,31 @@ static const struct v4l2_pix_format ovfx2_ov2610_mode[] = {
                .colorspace = V4L2_COLORSPACE_SRGB},
 };
 static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
-       {2080, 1544, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
-               .bytesperline = 2080,
-               .sizeimage = 2080 * 1544,
-               .colorspace = V4L2_COLORSPACE_SRGB},
-       {1600, 1200, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
-               .bytesperline = 1600,
-               .sizeimage = 1600 * 1200,
-               .colorspace = V4L2_COLORSPACE_SRGB},
-       {1024, 768, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
-               .bytesperline = 1024,
-               .sizeimage = 1024 * 768,
-               .colorspace = V4L2_COLORSPACE_SRGB},
-       {800, 600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
-               .bytesperline = 800,
-               .sizeimage = 800 * 600,
-               .colorspace = V4L2_COLORSPACE_SRGB},
        {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
                .bytesperline = 640,
                .sizeimage = 640 * 480,
-               .colorspace = V4L2_COLORSPACE_SRGB},
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1},
+       {800, 600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 800,
+               .sizeimage = 800 * 600,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1},
+       {1024, 768, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 1024,
+               .sizeimage = 1024 * 768,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1},
+       {1600, 1200, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 1600,
+               .sizeimage = 1600 * 1200,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0},
+       {2048, 1536, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 2048,
+               .sizeimage = 2048 * 1536,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0},
 };
 
 
@@ -473,6 +509,30 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
 
 #define OV511_ENDPOINT_ADDRESS  1      /* Isoc endpoint number */
 
+/*
+ * The FX2 chip does not give us a zero length read at end of frame.
+ * It does, however, give a short read at the end of a frame, if
+ * necessary, rather than run two frames together.
+ *
+ * By choosing the right bulk transfer size, we are guaranteed to always
+ * get a short read for the last read of each frame.  Frame sizes are
+ * always a composite number (width * height, or a multiple) so if we
+ * choose a prime number, we are guaranteed that the last read of a
+ * frame will be short.
+ *
+ * But it isn't that easy: the 2.6 kernel requires a multiple of 4KB,
+ * otherwise EOVERFLOW "babbling" errors occur.  I have not been able
+ * to figure out why.  [PMiller]
+ *
+ * The constant (13 * 4096) is the largest "prime enough" number less than 64KB.
+ *
+ * It isn't enough to know the number of bytes per frame, in case we
+ * have data dropouts or buffer overruns (even though the FX2 double
+ * buffers, there are some pretty strict real time constraints for
+ * isochronous transfer for larger frame sizes).
+ */
+#define OVFX2_BULK_SIZE (13 * 4096)
+
 /* I2C registers */
 #define R51x_I2C_W_SID         0x41
 #define R51x_I2C_SADDR_3       0x42
@@ -480,6 +540,7 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
 #define R51x_I2C_R_SID         0x44
 #define R51x_I2C_DATA          0x45
 #define R518_I2C_CTL           0x47    /* OV518(+) only */
+#define OVFX2_I2C_ADDR         0x00
 
 /* I2C ADDRESSES */
 #define OV7xx0_SID   0x42
@@ -579,7 +640,7 @@ struct ov_i2c_regvals {
 /* Settings for OV2610 camera chip */
 static const struct ov_i2c_regvals norm_2610[] =
 {
-       { 0x10, 0x80 }, /* reset */
+       { 0x12, 0x80 }, /* reset */
 };
 
 static const struct ov_i2c_regvals norm_3620b[] =
@@ -1436,6 +1497,7 @@ static const struct ov_i2c_regvals norm_7610[] = {
 };
 
 static const struct ov_i2c_regvals norm_7620[] = {
+       { 0x12, 0x80 },         /* reset */
        { 0x00, 0x00 },         /* gain */
        { 0x01, 0x80 },         /* blue gain */
        { 0x02, 0x80 },         /* red gain */
@@ -1800,10 +1862,28 @@ static unsigned char ov7670_abs_to_sm(unsigned char v)
 }
 
 /* Write a OV519 register */
-static int reg_w(struct sd *sd, __u16 index, __u8 value)
+static int reg_w(struct sd *sd, __u16 index, __u16 value)
 {
-       int ret;
-       int req = (sd->bridge <= BRIDGE_OV511PLUS) ? 2 : 1;
+       int ret, req = 0;
+
+       switch (sd->bridge) {
+       case BRIDGE_OV511:
+       case BRIDGE_OV511PLUS:
+               req = 2;
+               break;
+       case BRIDGE_OVFX2:
+               req = 0x0a;
+               /* fall through */
+       case BRIDGE_W9968CF:
+               ret = usb_control_msg(sd->gspca_dev.dev,
+                       usb_sndctrlpipe(sd->gspca_dev.dev, 0),
+                       req,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index, NULL, 0, 500);
+               goto leave;
+       default:
+               req = 1;
+       }
 
        sd->gspca_dev.usb_buf[0] = value;
        ret = usb_control_msg(sd->gspca_dev.dev,
@@ -1812,17 +1892,35 @@ static int reg_w(struct sd *sd, __u16 index, __u8 value)
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        0, index,
                        sd->gspca_dev.usb_buf, 1, 500);
-       if (ret < 0)
-               PDEBUG(D_ERR, "Write reg [%02x] %02x failed", index, value);
-       return ret;
+leave:
+       if (ret < 0) {
+               PDEBUG(D_ERR, "Write reg 0x%04x -> [0x%02x] failed",
+                      value, index);
+               return ret;
+       }
+
+       PDEBUG(D_USBO, "Write reg 0x%04x -> [0x%02x]", value, index);
+       return 0;
 }
 
-/* Read from a OV519 register */
+/* Read from a OV519 register, note not valid for the w9968cf!! */
 /* returns: negative is error, pos or zero is data */
 static int reg_r(struct sd *sd, __u16 index)
 {
        int ret;
-       int req = (sd->bridge <= BRIDGE_OV511PLUS) ? 3 : 1;
+       int req;
+
+       switch (sd->bridge) {
+       case BRIDGE_OV511:
+       case BRIDGE_OV511PLUS:
+               req = 3;
+               break;
+       case BRIDGE_OVFX2:
+               req = 0x0b;
+               break;
+       default:
+               req = 1;
+       }
 
        ret = usb_control_msg(sd->gspca_dev.dev,
                        usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
@@ -1830,10 +1928,12 @@ static int reg_r(struct sd *sd, __u16 index)
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        0, index, sd->gspca_dev.usb_buf, 1, 500);
 
-       if (ret >= 0)
+       if (ret >= 0) {
                ret = sd->gspca_dev.usb_buf[0];
-       else
+               PDEBUG(D_USBI, "Read reg [0x%02X] -> 0x%04X", index, ret);
+       } else
                PDEBUG(D_ERR, "Read reg [0x%02x] failed", index);
+
        return ret;
 }
 
@@ -1853,6 +1953,7 @@ static int reg_r8(struct sd *sd,
                ret = sd->gspca_dev.usb_buf[0];
        else
                PDEBUG(D_ERR, "Read reg 8 [0x%02x] failed", index);
+
        return ret;
 }
 
@@ -1890,7 +1991,7 @@ static int ov518_reg_w32(struct sd *sd, __u16 index, u32 value, int n)
 {
        int ret;
 
-       *((u32 *)sd->gspca_dev.usb_buf) = __cpu_to_le32(value);
+       *((__le32 *) sd->gspca_dev.usb_buf) = __cpu_to_le32(value);
 
        ret = usb_control_msg(sd->gspca_dev.dev,
                        usb_sndctrlpipe(sd->gspca_dev.dev, 0),
@@ -1898,9 +1999,12 @@ static int ov518_reg_w32(struct sd *sd, __u16 index, u32 value, int n)
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        0, index,
                        sd->gspca_dev.usb_buf, n, 500);
-       if (ret < 0)
+       if (ret < 0) {
                PDEBUG(D_ERR, "Write reg32 [%02x] %08x failed", index, value);
-       return ret;
+               return ret;
+       }
+
+       return 0;
 }
 
 static int ov511_i2c_w(struct sd *sd, __u8 reg, __u8 value)
@@ -1926,9 +2030,9 @@ static int ov511_i2c_w(struct sd *sd, __u8 reg, __u8 value)
                if (rc < 0)
                        return rc;
 
-               do
+               do {
                        rc = reg_r(sd, R511_I2C_CTL);
-               while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */
+               while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */
 
                if (rc < 0)
                        return rc;
@@ -1960,9 +2064,9 @@ static int ov511_i2c_r(struct sd *sd, __u8 reg)
                if (rc < 0)
                        return rc;
 
-               do
+               do {
                        rc = reg_r(sd, R511_I2C_CTL);
-               while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */
+               while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */
 
                if (rc < 0)
                        return rc;
@@ -1986,9 +2090,9 @@ static int ov511_i2c_r(struct sd *sd, __u8 reg)
                if (rc < 0)
                        return rc;
 
-               do
+               do {
                        rc = reg_r(sd, R511_I2C_CTL);
-               while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */
+               while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */
 
                if (rc < 0)
                        return rc;
@@ -2082,32 +2186,110 @@ static int ov518_i2c_r(struct sd *sd, __u8 reg)
        return value;
 }
 
+static int ovfx2_i2c_w(struct sd *sd, __u8 reg, __u8 value)
+{
+       int ret;
+
+       ret = usb_control_msg(sd->gspca_dev.dev,
+                       usb_sndctrlpipe(sd->gspca_dev.dev, 0),
+                       0x02,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       (__u16)value, (__u16)reg, NULL, 0, 500);
+
+       if (ret < 0) {
+               PDEBUG(D_ERR, "i2c 0x%02x -> [0x%02x] failed", value, reg);
+               return ret;
+       }
+
+       PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
+       return 0;
+}
+
+static int ovfx2_i2c_r(struct sd *sd, __u8 reg)
+{
+       int ret;
+
+       ret = usb_control_msg(sd->gspca_dev.dev,
+                       usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
+                       0x03,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0, (__u16)reg, sd->gspca_dev.usb_buf, 1, 500);
+
+       if (ret >= 0) {
+               ret = sd->gspca_dev.usb_buf[0];
+               PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, ret);
+       } else
+               PDEBUG(D_ERR, "i2c read [0x%02x] failed", reg);
+
+       return ret;
+}
+
 static int i2c_w(struct sd *sd, __u8 reg, __u8 value)
 {
+       int ret = -1;
+
+       if (sd->sensor_reg_cache[reg] == value)
+               return 0;
+
        switch (sd->bridge) {
        case BRIDGE_OV511:
        case BRIDGE_OV511PLUS:
-               return ov511_i2c_w(sd, reg, value);
+               ret = ov511_i2c_w(sd, reg, value);
+               break;
        case BRIDGE_OV518:
        case BRIDGE_OV518PLUS:
        case BRIDGE_OV519:
-               return ov518_i2c_w(sd, reg, value);
+               ret = ov518_i2c_w(sd, reg, value);
+               break;
+       case BRIDGE_OVFX2:
+               ret = ovfx2_i2c_w(sd, reg, value);
+               break;
+       case BRIDGE_W9968CF:
+               ret = w9968cf_i2c_w(sd, reg, value);
+               break;
+       }
+
+       if (ret >= 0) {
+               /* Up on sensor reset empty the register cache */
+               if (reg == 0x12 && (value & 0x80))
+                       memset(sd->sensor_reg_cache, -1,
+                              sizeof(sd->sensor_reg_cache));
+               else
+                       sd->sensor_reg_cache[reg] = value;
        }
-       return -1; /* Should never happen */
+
+       return ret;
 }
 
 static int i2c_r(struct sd *sd, __u8 reg)
 {
+       int ret = -1;
+
+       if (sd->sensor_reg_cache[reg] != -1)
+               return sd->sensor_reg_cache[reg];
+
        switch (sd->bridge) {
        case BRIDGE_OV511:
        case BRIDGE_OV511PLUS:
-               return ov511_i2c_r(sd, reg);
+               ret = ov511_i2c_r(sd, reg);
+               break;
        case BRIDGE_OV518:
        case BRIDGE_OV518PLUS:
        case BRIDGE_OV519:
-               return ov518_i2c_r(sd, reg);
+               ret = ov518_i2c_r(sd, reg);
+               break;
+       case BRIDGE_OVFX2:
+               ret = ovfx2_i2c_r(sd, reg);
+               break;
+       case BRIDGE_W9968CF:
+               ret = w9968cf_i2c_r(sd, reg);
+               break;
        }
-       return -1; /* Should never happen */
+
+       if (ret >= 0)
+               sd->sensor_reg_cache[reg] = ret;
+
+       return ret;
 }
 
 /* Writes bits at positions specified by mask to an I2C reg. Bits that are in
@@ -2147,6 +2329,10 @@ static inline int ov51x_stop(struct sd *sd)
                return reg_w_mask(sd, R51x_SYS_RESET, 0x3a, 0x3a);
        case BRIDGE_OV519:
                return reg_w(sd, OV519_SYS_RESET1, 0x0f);
+       case BRIDGE_OVFX2:
+               return reg_w_mask(sd, 0x0f, 0x00, 0x02);
+       case BRIDGE_W9968CF:
+               return reg_w(sd, 0x3c, 0x0a05); /* stop USB transfer */
        }
 
        return 0;
@@ -2176,6 +2362,10 @@ static inline int ov51x_restart(struct sd *sd)
                return reg_w(sd, R51x_SYS_RESET, 0x00);
        case BRIDGE_OV519:
                return reg_w(sd, OV519_SYS_RESET1, 0x00);
+       case BRIDGE_OVFX2:
+               return reg_w_mask(sd, 0x0f, 0x02, 0x02);
+       case BRIDGE_W9968CF:
+               return reg_w(sd, 0x3c, 0x8a05); /* USB FIFO enable */
        }
 
        return 0;
@@ -2229,6 +2419,14 @@ static int ov51x_set_slave_ids(struct sd *sd,
 {
        int rc;
 
+       switch (sd->bridge) {
+       case BRIDGE_OVFX2:
+               return reg_w(sd, OVFX2_I2C_ADDR, slave);
+       case BRIDGE_W9968CF:
+               sd->sensor_addr = slave;
+               return 0;
+       }
+
        rc = reg_w(sd, R51x_I2C_W_SID, slave);
        if (rc < 0)
                return rc;
@@ -2365,7 +2563,7 @@ static int ov7xx0_configure(struct sd *sd)
                /* I don't know what's different about the 76BE yet. */
                if (i2c_r(sd, 0x15) & 1) {
                        PDEBUG(D_PROBE, "Sensor is an OV7620AE");
-                       sd->sensor = SEN_OV7620;
+                       sd->sensor = SEN_OV7620AE;
                } else {
                        PDEBUG(D_PROBE, "Sensor is an OV76BE");
                        sd->sensor = SEN_OV76BE;
@@ -2399,7 +2597,7 @@ static int ov7xx0_configure(struct sd *sd)
                                break;
                        case 0x48:
                                PDEBUG(D_PROBE, "Sensor is an OV7648");
-                               sd->sensor = SEN_OV7640; /* FIXME */
+                               sd->sensor = SEN_OV7648;
                                break;
                        default:
                                PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low);
@@ -2491,6 +2689,36 @@ static void ov51x_led_control(struct sd *sd, int on)
        }
 }
 
+static void sd_reset_snapshot(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (!sd->snapshot_needs_reset)
+               return;
+
+       /* Note it is important that we clear sd->snapshot_needs_reset,
+          before actually clearing the snapshot state in the bridge
+          otherwise we might race with the pkt_scan interrupt handler */
+       sd->snapshot_needs_reset = 0;
+
+       switch (sd->bridge) {
+       case BRIDGE_OV511:
+       case BRIDGE_OV511PLUS:
+               reg_w(sd, R51x_SYS_SNAP, 0x02);
+               reg_w(sd, R51x_SYS_SNAP, 0x00);
+               break;
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               reg_w(sd, R51x_SYS_SNAP, 0x02); /* Reset */
+               reg_w(sd, R51x_SYS_SNAP, 0x01); /* Enable */
+               break;
+       case BRIDGE_OV519:
+               reg_w(sd, R51x_SYS_RESET, 0x40);
+               reg_w(sd, R51x_SYS_RESET, 0x00);
+               break;
+       }
+}
+
 static int ov51x_upload_quan_tables(struct sd *sd)
 {
        const unsigned char yQuanTable511[] = {
@@ -2762,12 +2990,29 @@ static int ov519_configure(struct sd *sd)
        return write_regvals(sd, init_519, ARRAY_SIZE(init_519));
 }
 
+static int ovfx2_configure(struct sd *sd)
+{
+       static const struct ov_regvals init_fx2[] = {
+               { 0x00, 0x60 },
+               { 0x02, 0x01 },
+               { 0x0f, 0x1d },
+               { 0xe9, 0x82 },
+               { 0xea, 0xc7 },
+               { 0xeb, 0x10 },
+               { 0xec, 0xf6 },
+       };
+
+       sd->stopped = 1;
+
+       return write_regvals(sd, init_fx2, ARRAY_SIZE(init_fx2));
+}
+
 /* this function is called at probe time */
 static int sd_config(struct gspca_dev *gspca_dev,
                        const struct usb_device_id *id)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       struct cam *cam;
+       struct cam *cam = &gspca_dev->cam;
        int ret = 0;
 
        sd->bridge = id->driver_info & BRIDGE_MASK;
@@ -2785,6 +3030,16 @@ static int sd_config(struct gspca_dev *gspca_dev,
        case BRIDGE_OV519:
                ret = ov519_configure(sd);
                break;
+       case BRIDGE_OVFX2:
+               ret = ovfx2_configure(sd);
+               cam->bulk_size = OVFX2_BULK_SIZE;
+               cam->bulk_nurbs = MAX_NURBS;
+               cam->bulk = 1;
+               break;
+       case BRIDGE_W9968CF:
+               ret = w9968cf_configure(sd);
+               cam->reverse_alts = 1;
+               break;
        }
 
        if (ret)
@@ -2825,7 +3080,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
                goto error;
        }
 
-       cam = &gspca_dev->cam;
        switch (sd->bridge) {
        case BRIDGE_OV511:
        case BRIDGE_OV511PLUS:
@@ -2871,6 +3125,16 @@ static int sd_config(struct gspca_dev *gspca_dev,
                        cam->nmodes = ARRAY_SIZE(ov519_sif_mode);
                }
                break;
+       case BRIDGE_W9968CF:
+               cam->cam_mode = w9968cf_vga_mode;
+               cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode);
+               if (sd->sif)
+                       cam->nmodes--;
+
+               /* w9968cf needs initialisation once the sensor is known */
+               if (w9968cf_init(sd) < 0)
+                       goto error;
+               break;
        }
        sd->brightness = BRIGHTNESS_DEF;
        if (sd->sensor == SEN_OV6630 || sd->sensor == SEN_OV66308AF)
@@ -2889,7 +3153,12 @@ static int sd_config(struct gspca_dev *gspca_dev,
                gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) |
                                      (1 << OV7670_FREQ_IDX);
        }
-       if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7670)
+       sd->quality = QUALITY_DEF;
+       if (sd->sensor == SEN_OV7640 ||
+           sd->sensor == SEN_OV7648)
+               gspca_dev->ctrl_dis |= (1 << AUTOBRIGHT_IDX) |
+                                      (1 << CONTRAST_IDX);
+       if (sd->sensor == SEN_OV7670)
                gspca_dev->ctrl_dis |= 1 << AUTOBRIGHT_IDX;
        /* OV8610 Frequency filter control should work but needs testing */
        if (sd->sensor == SEN_OV8610)
@@ -2943,10 +3212,12 @@ static int sd_init(struct gspca_dev *gspca_dev)
                        return -EIO;
                break;
        case SEN_OV7620:
+       case SEN_OV7620AE:
                if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620)))
                        return -EIO;
                break;
        case SEN_OV7640:
+       case SEN_OV7648:
                if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640)))
                        return -EIO;
                break;
@@ -3020,7 +3291,9 @@ static int ov511_mode_init_regs(struct sd *sd)
        /* Note once the FIXME's in mode_init_ov_sensor_regs() are fixed
           for more sensors we need to do this for them too */
        case SEN_OV7620:
+       case SEN_OV7620AE:
        case SEN_OV7640:
+       case SEN_OV7648:
        case SEN_OV76BE:
                if (sd->gspca_dev.width == 320)
                        interlaced = 1;
@@ -3151,7 +3424,7 @@ static int ov518_mode_init_regs(struct sd *sd)
 
        if (sd->bridge == BRIDGE_OV518PLUS) {
                switch (sd->sensor) {
-               case SEN_OV7620:
+               case SEN_OV7620AE:
                        if (sd->gspca_dev.width == 320) {
                                reg_w(sd, 0x20, 0x00);
                                reg_w(sd, 0x21, 0x19);
@@ -3160,6 +3433,10 @@ static int ov518_mode_init_regs(struct sd *sd)
                                reg_w(sd, 0x21, 0x1f);
                        }
                        break;
+               case SEN_OV7620:
+                       reg_w(sd, 0x20, 0x00);
+                       reg_w(sd, 0x21, 0x19);
+                       break;
                default:
                        reg_w(sd, 0x21, 0x19);
                }
@@ -3262,7 +3539,8 @@ static int ov519_mode_init_regs(struct sd *sd)
                if (write_regvals(sd, mode_init_519,
                                  ARRAY_SIZE(mode_init_519)))
                        return -EIO;
-               if (sd->sensor == SEN_OV7640) {
+               if (sd->sensor == SEN_OV7640 ||
+                   sd->sensor == SEN_OV7648) {
                        /* Select 8-bit input mode */
                        reg_w_mask(sd, OV519_R20_DFR, 0x10, 0x10);
                }
@@ -3277,6 +3555,9 @@ static int ov519_mode_init_regs(struct sd *sd)
        if (sd->sensor == SEN_OV7670 &&
            sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv)
                reg_w(sd, OV519_R12_X_OFFSETL, 0x04);
+       else if (sd->sensor == SEN_OV7648 &&
+           sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv)
+               reg_w(sd, OV519_R12_X_OFFSETL, 0x01);
        else
                reg_w(sd, OV519_R12_X_OFFSETL, 0x00);
        reg_w(sd, OV519_R13_X_OFFSETH,  0x00);
@@ -3294,6 +3575,7 @@ static int ov519_mode_init_regs(struct sd *sd)
        sd->clockdiv = 0;
        switch (sd->sensor) {
        case SEN_OV7640:
+       case SEN_OV7648:
                switch (sd->frame_rate) {
                default:
 /*             case 30: */
@@ -3367,7 +3649,8 @@ static int ov519_mode_init_regs(struct sd *sd)
 static int mode_init_ov_sensor_regs(struct sd *sd)
 {
        struct gspca_dev *gspca_dev;
-       int qvga;
+       int qvga, xstart, xend, ystart, yend;
+       __u8 v;
 
        gspca_dev = &sd->gspca_dev;
        qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 1;
@@ -3383,14 +3666,12 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
                i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0);
                i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);
                return 0;
-       case SEN_OV3610: {
-               int xstart, xend, ystart, yend;
-
+       case SEN_OV3610:
                if (qvga) {
                        xstart = (1040 - gspca_dev->width) / 2 + (0x1f << 4);
-                       ystart = (772 - gspca_dev->height) / 2;
+                       ystart = (776 - gspca_dev->height) / 2;
                } else {
-                       xstart = (2080 - gspca_dev->width) / 2 + (0x10 << 4);
+                       xstart = (2076 - gspca_dev->width) / 2 + (0x10 << 4);
                        ystart = (1544 - gspca_dev->height) / 2;
                }
                xend = xstart + gspca_dev->width;
@@ -3409,15 +3690,22 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
                i2c_w(sd, 0x19, ystart >> 3);
                i2c_w(sd, 0x1a, yend >> 3);
                return 0;
-       }
        case SEN_OV8610:
                /* For OV8610 qvga means qsvga */
                i2c_w_mask(sd, OV7610_REG_COM_C, qvga ? (1 << 5) : 0, 1 << 5);
+               i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
+               i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
+               i2c_w_mask(sd, 0x2d, 0x00, 0x40); /* from windrv 090403 */
+               i2c_w_mask(sd, 0x28, 0x20, 0x20); /* progressive mode on */
                break;
        case SEN_OV7610:
                i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+               i2c_w(sd, 0x35, qvga?0x1e:0x9e);
+               i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
+               i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
                break;
        case SEN_OV7620:
+       case SEN_OV7620AE:
        case SEN_OV76BE:
                i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
                i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
@@ -3426,15 +3714,23 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
                i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40);
                i2c_w_mask(sd, 0x67, qvga ? 0xb0 : 0x90, 0xf0);
                i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);
+               i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
+               i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
+               if (sd->sensor == SEN_OV76BE)
+                       i2c_w(sd, 0x35, qvga ? 0x1e : 0x9e);
                break;
        case SEN_OV7640:
+       case SEN_OV7648:
                i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
                i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
-/*             i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a); */
-/*             i2c_w(sd, 0x25, qvga ? 0x30 : 0x60); */
-/*             i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); */
-/*             i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0); */
-/*             i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); */
+               /* Setting this undocumented bit in qvga mode removes a very
+                  annoying vertical shaking of the image */
+               i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40);
+               /* Unknown */
+               i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0);
+               /* Allow higher automatic gain (to allow higher framerates) */
+               i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);
+               i2c_w_mask(sd, 0x12, 0x04, 0x04); /* AWB: 1 */
                break;
        case SEN_OV7670:
                /* set COM7_FMT_VGA or COM7_FMT_QVGA
@@ -3443,55 +3739,56 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
                i2c_w_mask(sd, OV7670_REG_COM7,
                         qvga ? OV7670_COM7_FMT_QVGA : OV7670_COM7_FMT_VGA,
                         OV7670_COM7_FMT_MASK);
+               i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
+               i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_AWB,
+                               OV7670_COM8_AWB);
+               if (qvga) {             /* QVGA from ov7670.c by
+                                        * Jonathan Corbet */
+                       xstart = 164;
+                       xend = 28;
+                       ystart = 14;
+                       yend = 494;
+               } else {                /* VGA */
+                       xstart = 158;
+                       xend = 14;
+                       ystart = 10;
+                       yend = 490;
+               }
+               /* OV7670 hardware window registers are split across
+                * multiple locations */
+               i2c_w(sd, OV7670_REG_HSTART, xstart >> 3);
+               i2c_w(sd, OV7670_REG_HSTOP, xend >> 3);
+               v = i2c_r(sd, OV7670_REG_HREF);
+               v = (v & 0xc0) | ((xend & 0x7) << 3) | (xstart & 0x07);
+               msleep(10);     /* need to sleep between read and write to
+                                * same reg! */
+               i2c_w(sd, OV7670_REG_HREF, v);
+
+               i2c_w(sd, OV7670_REG_VSTART, ystart >> 2);
+               i2c_w(sd, OV7670_REG_VSTOP, yend >> 2);
+               v = i2c_r(sd, OV7670_REG_VREF);
+               v = (v & 0xc0) | ((yend & 0x3) << 2) | (ystart & 0x03);
+               msleep(10);     /* need to sleep between read and write to
+                                * same reg! */
+               i2c_w(sd, OV7670_REG_VREF, v);
                break;
        case SEN_OV6620:
+               i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+               i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
+               i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
+               break;
        case SEN_OV6630:
        case SEN_OV66308AF:
                i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+               i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
                break;
        default:
                return -EINVAL;
        }
 
-       /******** Palette-specific regs ********/
-
-       /* The OV518 needs special treatment. Although both the OV518
-        * and the OV6630 support a 16-bit video bus, only the 8 bit Y
-        * bus is actually used. The UV bus is tied to ground.
-        * Therefore, the OV6630 needs to be in 8-bit multiplexed
-        * output mode */
-
-       /* OV7640 is 8-bit only */
-
-       if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV66308AF &&
-                                       sd->sensor != SEN_OV7640)
-               i2c_w_mask(sd, 0x13, 0x00, 0x20);
-
        /******** Clock programming ********/
        i2c_w(sd, 0x11, sd->clockdiv);
 
-       /******** Special Features ********/
-/* no evidence this is possible with OV7670, either */
-       /* Test Pattern */
-       if (sd->sensor != SEN_OV7640 && sd->sensor != SEN_OV7670)
-               i2c_w_mask(sd, 0x12, 0x00, 0x02);
-
-       /* Enable auto white balance */
-       if (sd->sensor == SEN_OV7670)
-               i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_AWB,
-                               OV7670_COM8_AWB);
-       else
-               i2c_w_mask(sd, 0x12, 0x04, 0x04);
-
-       /* This will go away as soon as ov51x_mode_init_sensor_regs() */
-       /* is fully tested. */
-       /* 7620/6620/6630? don't have register 0x35, so play it safe */
-       if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) {
-               if (!qvga)
-                       i2c_w(sd, 0x35, 0x9e);
-               else
-                       i2c_w(sd, 0x35, 0x1e);
-       }
        return 0;
 }
 
@@ -3514,11 +3811,11 @@ static int set_ov_sensor_window(struct sd *sd)
        struct gspca_dev *gspca_dev;
        int qvga, crop;
        int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale;
-       int ret, hstart, hstop, vstop, vstart;
-       __u8 v;
+       int ret;
 
        /* mode setup is fully handled in mode_init_ov_sensor_regs for these */
-       if (sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610)
+       if (sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610 ||
+           sd->sensor == SEN_OV7670)
                return mode_init_ov_sensor_regs(sd);
 
        gspca_dev = &sd->gspca_dev;
@@ -3558,20 +3855,17 @@ static int set_ov_sensor_window(struct sd *sd)
                }
                break;
        case SEN_OV7620:
+       case SEN_OV7620AE:
                hwsbase = 0x2f;         /* From 7620.SET (spec is wrong) */
                hwebase = 0x2f;
                vwsbase = vwebase = 0x05;
                break;
        case SEN_OV7640:
+       case SEN_OV7648:
                hwsbase = 0x1a;
                hwebase = 0x1a;
                vwsbase = vwebase = 0x03;
                break;
-       case SEN_OV7670:
-               /*handling of OV7670 hardware sensor start and stop values
-                * is very odd, compared to the other OV sensors */
-               vwsbase = vwebase = hwebase = hwsbase = 0x00;
-               break;
        default:
                return -EINVAL;
        }
@@ -3612,58 +3906,11 @@ static int set_ov_sensor_window(struct sd *sd)
        if (ret < 0)
                return ret;
 
-       if (sd->sensor == SEN_OV8610) {
-               i2c_w_mask(sd, 0x2d, 0x05, 0x40);
-                               /* old 0x95, new 0x05 from windrv 090403 */
-                                               /* bits 5-7: reserved */
-               i2c_w_mask(sd, 0x28, 0x20, 0x20);
-                                       /* bit 5: progressive mode on */
-       }
-
-       /* The below is wrong for OV7670s because their window registers
-        * only store the high bits in 0x17 to 0x1a */
+       i2c_w(sd, 0x17, hwsbase);
+       i2c_w(sd, 0x18, hwebase + (sd->sensor_width >> hwscale));
+       i2c_w(sd, 0x19, vwsbase);
+       i2c_w(sd, 0x1a, vwebase + (sd->sensor_height >> vwscale));
 
-       /* SRH Use sd->max values instead of requested win values */
-       /* SCS Since we're sticking with only the max hardware widths
-        * for a given mode */
-       /* I can hard code this for OV7670s */
-       /* Yes, these numbers do look odd, but they're tested and work! */
-       if (sd->sensor == SEN_OV7670) {
-               if (qvga) {             /* QVGA from ov7670.c by
-                                        * Jonathan Corbet */
-                       hstart = 164;
-                       hstop = 28;
-                       vstart = 14;
-                       vstop = 494;
-               } else {                /* VGA */
-                       hstart = 158;
-                       hstop = 14;
-                       vstart = 10;
-                       vstop = 490;
-               }
-               /* OV7670 hardware window registers are split across
-                * multiple locations */
-               i2c_w(sd, OV7670_REG_HSTART, hstart >> 3);
-               i2c_w(sd, OV7670_REG_HSTOP, hstop >> 3);
-               v = i2c_r(sd, OV7670_REG_HREF);
-               v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x07);
-               msleep(10);     /* need to sleep between read and write to
-                                * same reg! */
-               i2c_w(sd, OV7670_REG_HREF, v);
-
-               i2c_w(sd, OV7670_REG_VSTART, vstart >> 2);
-               i2c_w(sd, OV7670_REG_VSTOP, vstop >> 2);
-               v = i2c_r(sd, OV7670_REG_VREF);
-               v = (v & 0xc0) | ((vstop & 0x3) << 2) | (vstart & 0x03);
-               msleep(10);     /* need to sleep between read and write to
-                                * same reg! */
-               i2c_w(sd, OV7670_REG_VREF, v);
-       } else {
-               i2c_w(sd, 0x17, hwsbase);
-               i2c_w(sd, 0x18, hwebase + (sd->gspca_dev.width >> hwscale));
-               i2c_w(sd, 0x19, vwsbase);
-               i2c_w(sd, 0x1a, vwebase + (sd->gspca_dev.height >> vwscale));
-       }
        return 0;
 }
 
@@ -3673,6 +3920,10 @@ static int sd_start(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        int ret = 0;
 
+       /* Default for most bridges, allow bridge_mode_init_regs to override */
+       sd->sensor_width = sd->gspca_dev.width;
+       sd->sensor_height = sd->gspca_dev.height;
+
        switch (sd->bridge) {
        case BRIDGE_OV511:
        case BRIDGE_OV511PLUS:
@@ -3685,6 +3936,10 @@ static int sd_start(struct gspca_dev *gspca_dev)
        case BRIDGE_OV519:
                ret = ov519_mode_init_regs(sd);
                break;
+       /* case BRIDGE_OVFX2: nothing to do */
+       case BRIDGE_W9968CF:
+               ret = w9968cf_mode_init_regs(sd);
+               break;
        }
        if (ret < 0)
                goto out;
@@ -3700,6 +3955,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
        setautobrightness(sd);
        setfreq(sd);
 
+       /* Force clear snapshot state in case the snapshot button was
+          pressed while we weren't streaming */
+       sd->snapshot_needs_reset = 1;
+       sd_reset_snapshot(gspca_dev);
+       sd->snapshot_pressed = 0;
+
        ret = ov51x_restart(sd);
        if (ret < 0)
                goto out;
@@ -3718,10 +3979,45 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        ov51x_led_control(sd, 0);
 }
 
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (sd->bridge == BRIDGE_W9968CF)
+               w9968cf_stop0(sd);
+}
+
+static void ov51x_handle_button(struct gspca_dev *gspca_dev, u8 state)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (sd->snapshot_pressed != state) {
+#ifdef CONFIG_INPUT
+               input_report_key(gspca_dev->input_dev, KEY_CAMERA, state);
+               input_sync(gspca_dev->input_dev);
+#endif
+               if (state)
+                       sd->snapshot_needs_reset = 1;
+
+               sd->snapshot_pressed = state;
+       } else {
+               /* On the ov511 / ov519 we need to reset the button state
+                  multiple times, as resetting does not work as long as the
+                  button stays pressed */
+               switch (sd->bridge) {
+               case BRIDGE_OV511:
+               case BRIDGE_OV511PLUS:
+               case BRIDGE_OV519:
+                       if (state)
+                               sd->snapshot_needs_reset = 1;
+                       break;
+               }
+       }
+}
+
 static void ov511_pkt_scan(struct gspca_dev *gspca_dev,
-                       struct gspca_frame *frame,      /* target */
-                       __u8 *in,                       /* isoc packet */
-                       int len)                        /* iso packet length */
+                       u8 *in,                 /* isoc packet */
+                       int len)                /* iso packet length */
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
@@ -3740,6 +4036,7 @@ static void ov511_pkt_scan(struct gspca_dev *gspca_dev,
         */
        if (!(in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) &&
            (in[8] & 0x08)) {
+               ov51x_handle_button(gspca_dev, (in[8] >> 2) & 1);
                if (in[8] & 0x80) {
                        /* Frame end */
                        if ((in[9] + 1) * 8 != gspca_dev->width ||
@@ -3752,11 +4049,11 @@ static void ov511_pkt_scan(struct gspca_dev *gspca_dev,
                                return;
                        }
                        /* Add 11 byte footer to frame, might be usefull */
-                       gspca_frame_add(gspca_dev, LAST_PACKET, frame, in, 11);
+                       gspca_frame_add(gspca_dev, LAST_PACKET, in, 11);
                        return;
                } else {
                        /* Frame start */
-                       gspca_frame_add(gspca_dev, FIRST_PACKET, frame, in, 0);
+                       gspca_frame_add(gspca_dev, FIRST_PACKET, in, 0);
                        sd->packet_nr = 0;
                }
        }
@@ -3765,12 +4062,11 @@ static void ov511_pkt_scan(struct gspca_dev *gspca_dev,
        len--;
 
        /* intermediate packet */
-       gspca_frame_add(gspca_dev, INTER_PACKET, frame, in, len);
+       gspca_frame_add(gspca_dev, INTER_PACKET, in, len);
 }
 
 static void ov518_pkt_scan(struct gspca_dev *gspca_dev,
-                       struct gspca_frame *frame,      /* target */
-                       __u8 *data,                     /* isoc packet */
+                       u8 *data,                       /* isoc packet */
                        int len)                        /* iso packet length */
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -3778,8 +4074,9 @@ static void ov518_pkt_scan(struct gspca_dev *gspca_dev,
        /* A false positive here is likely, until OVT gives me
         * the definitive SOF/EOF format */
        if ((!(data[0] | data[1] | data[2] | data[3] | data[5])) && data[6]) {
-               frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0);
-               gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, 0);
+               ov51x_handle_button(gspca_dev, (data[6] >> 1) & 1);
+               gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+               gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
                sd->packet_nr = 0;
        }
 
@@ -3803,12 +4100,11 @@ static void ov518_pkt_scan(struct gspca_dev *gspca_dev,
        }
 
        /* intermediate packet */
-       gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+       gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 static void ov519_pkt_scan(struct gspca_dev *gspca_dev,
-                       struct gspca_frame *frame,      /* target */
-                       __u8 *data,                     /* isoc packet */
+                       u8 *data,                       /* isoc packet */
                        int len)                        /* iso packet length */
 {
        /* Header of ov519 is 16 bytes:
@@ -3826,33 +4122,48 @@ static void ov519_pkt_scan(struct gspca_dev *gspca_dev,
        if (data[0] == 0xff && data[1] == 0xff && data[2] == 0xff) {
                switch (data[3]) {
                case 0x50:              /* start of frame */
+                       /* Don't check the button state here, as the state
+                          usually (always ?) changes at EOF and checking it
+                          here leads to unnecessary snapshot state resets. */
 #define HDRSZ 16
                        data += HDRSZ;
                        len -= HDRSZ;
 #undef HDRSZ
                        if (data[0] == 0xff || data[1] == 0xd8)
-                               gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                               gspca_frame_add(gspca_dev, FIRST_PACKET,
                                                data, len);
                        else
                                gspca_dev->last_packet_type = DISCARD_PACKET;
                        return;
                case 0x51:              /* end of frame */
+                       ov51x_handle_button(gspca_dev, data[11] & 1);
                        if (data[9] != 0)
                                gspca_dev->last_packet_type = DISCARD_PACKET;
-                       gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-                                       data, 0);
+                       gspca_frame_add(gspca_dev, LAST_PACKET,
+                                       NULL, 0);
                        return;
                }
        }
 
        /* intermediate packet */
-       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-                       data, len);
+       gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+}
+
+static void ovfx2_pkt_scan(struct gspca_dev *gspca_dev,
+                       u8 *data,                       /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       /* A short read signals EOF */
+       if (len < OVFX2_BULK_SIZE) {
+               gspca_frame_add(gspca_dev, LAST_PACKET, data, len);
+               gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
+               return;
+       }
+       gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
-                       struct gspca_frame *frame,      /* target */
-                       __u8 *data,                     /* isoc packet */
+                       u8 *data,                       /* isoc packet */
                        int len)                        /* iso packet length */
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -3860,14 +4171,20 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        switch (sd->bridge) {
        case BRIDGE_OV511:
        case BRIDGE_OV511PLUS:
-               ov511_pkt_scan(gspca_dev, frame, data, len);
+               ov511_pkt_scan(gspca_dev, data, len);
                break;
        case BRIDGE_OV518:
        case BRIDGE_OV518PLUS:
-               ov518_pkt_scan(gspca_dev, frame, data, len);
+               ov518_pkt_scan(gspca_dev, data, len);
                break;
        case BRIDGE_OV519:
-               ov519_pkt_scan(gspca_dev, frame, data, len);
+               ov519_pkt_scan(gspca_dev, data, len);
+               break;
+       case BRIDGE_OVFX2:
+               ovfx2_pkt_scan(gspca_dev, data, len);
+               break;
+       case BRIDGE_W9968CF:
+               w9968cf_pkt_scan(gspca_dev, data, len);
                break;
        }
 }
@@ -3888,9 +4205,11 @@ static void setbrightness(struct gspca_dev *gspca_dev)
        case SEN_OV6630:
        case SEN_OV66308AF:
        case SEN_OV7640:
+       case SEN_OV7648:
                i2c_w(sd, OV7610_REG_BRT, val);
                break;
        case SEN_OV7620:
+       case SEN_OV7620AE:
                /* 7620 doesn't like manual changes when in auto mode */
                if (!sd->autobrightness)
                        i2c_w(sd, OV7610_REG_BRT, val);
@@ -3927,7 +4246,8 @@ static void setcontrast(struct gspca_dev *gspca_dev)
                i2c_w(sd, 0x64, ctab[val >> 5]);
                break;
            }
-       case SEN_OV7620: {
+       case SEN_OV7620:
+       case SEN_OV7620AE: {
                static const __u8 ctab[] = {
                        0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
                        0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
@@ -3937,10 +4257,6 @@ static void setcontrast(struct gspca_dev *gspca_dev)
                i2c_w(sd, 0x64, ctab[val >> 4]);
                break;
            }
-       case SEN_OV7640:
-               /* Use gain control instead. */
-               i2c_w(sd, OV7610_REG_GAIN, val >> 2);
-               break;
        case SEN_OV7670:
                /* check that this isn't just the same as ov7610 */
                i2c_w(sd, OV7670_REG_CONTRAS, val >> 1);
@@ -3964,6 +4280,7 @@ static void setcolors(struct gspca_dev *gspca_dev)
                i2c_w(sd, OV7610_REG_SAT, val);
                break;
        case SEN_OV7620:
+       case SEN_OV7620AE:
                /* Use UV gamma control instead. Bits 0 & 7 are reserved. */
 /*             rc = ov_i2c_write(sd->dev, 0x62, (val >> 9) & 0x7e);
                if (rc < 0)
@@ -3971,6 +4288,7 @@ static void setcolors(struct gspca_dev *gspca_dev)
                i2c_w(sd, OV7610_REG_SAT, val);
                break;
        case SEN_OV7640:
+       case SEN_OV7648:
                i2c_w(sd, OV7610_REG_SAT, val & 0xf0);
                break;
        case SEN_OV7670:
@@ -3983,7 +4301,8 @@ static void setcolors(struct gspca_dev *gspca_dev)
 
 static void setautobrightness(struct sd *sd)
 {
-       if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7670 ||
+       if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7648 ||
+           sd->sensor == SEN_OV7670 ||
            sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610)
                return;
 
@@ -4164,8 +4483,12 @@ static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        sd->freq = val;
-       if (gspca_dev->streaming)
+       if (gspca_dev->streaming) {
                setfreq(sd);
+               /* Ugly but necessary */
+               if (sd->bridge == BRIDGE_W9968CF)
+                       w9968cf_set_crop_window(sd);
+       }
        return 0;
 }
 
@@ -4206,6 +4529,45 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
        return -EINVAL;
 }
 
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (sd->bridge != BRIDGE_W9968CF)
+               return -EINVAL;
+
+       memset(jcomp, 0, sizeof *jcomp);
+       jcomp->quality = sd->quality;
+       jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT | V4L2_JPEG_MARKER_DQT |
+                             V4L2_JPEG_MARKER_DRI;
+       return 0;
+}
+
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (sd->bridge != BRIDGE_W9968CF)
+               return -EINVAL;
+
+       if (gspca_dev->streaming)
+               return -EBUSY;
+
+       if (jcomp->quality < QUALITY_MIN)
+               sd->quality = QUALITY_MIN;
+       else if (jcomp->quality > QUALITY_MAX)
+               sd->quality = QUALITY_MAX;
+       else
+               sd->quality = jcomp->quality;
+
+       /* Return resulting jcomp params to app */
+       sd_get_jcomp(gspca_dev, jcomp);
+
+       return 0;
+}
+
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
@@ -4215,12 +4577,20 @@ static const struct sd_desc sd_desc = {
        .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
+       .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
+       .dq_callback = sd_reset_snapshot,
        .querymenu = sd_querymenu,
+       .get_jcomp = sd_get_jcomp,
+       .set_jcomp = sd_set_jcomp,
+#ifdef CONFIG_INPUT
+       .other_input = 1,
+#endif
 };
 
 /* -- module initialisation -- */
 static const __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x041e, 0x4003), .driver_info = BRIDGE_W9968CF },
        {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 },
        {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 },
        {USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 },
@@ -4232,16 +4602,22 @@ static const __devinitdata struct usb_device_id device_table[] = {
         .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
        {USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 },
        {USB_DEVICE(0x054c, 0x0154), .driver_info = BRIDGE_OV519 },
-       {USB_DEVICE(0x054c, 0x0155), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x054c, 0x0155),
+        .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
        {USB_DEVICE(0x05a9, 0x0511), .driver_info = BRIDGE_OV511 },
        {USB_DEVICE(0x05a9, 0x0518), .driver_info = BRIDGE_OV518 },
        {USB_DEVICE(0x05a9, 0x0519), .driver_info = BRIDGE_OV519 },
        {USB_DEVICE(0x05a9, 0x0530), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x05a9, 0x2800), .driver_info = BRIDGE_OVFX2 },
        {USB_DEVICE(0x05a9, 0x4519), .driver_info = BRIDGE_OV519 },
        {USB_DEVICE(0x05a9, 0x8519), .driver_info = BRIDGE_OV519 },
        {USB_DEVICE(0x05a9, 0xa511), .driver_info = BRIDGE_OV511PLUS },
        {USB_DEVICE(0x05a9, 0xa518), .driver_info = BRIDGE_OV518PLUS },
        {USB_DEVICE(0x0813, 0x0002), .driver_info = BRIDGE_OV511PLUS },
+       {USB_DEVICE(0x0b62, 0x0059), .driver_info = BRIDGE_OVFX2 },
+       {USB_DEVICE(0x0e96, 0xc001), .driver_info = BRIDGE_OVFX2 },
+       {USB_DEVICE(0x1046, 0x9967), .driver_info = BRIDGE_W9968CF },
+       {USB_DEVICE(0x8020, 0xEF04), .driver_info = BRIDGE_OVFX2 },
        {}
 };