V4L/DVB (11970): gspca - ov519: Add support for the ov518 bridge.
authorHans de Goede <hdegoede@redhat.com>
Sun, 7 Jun 2009 15:10:39 +0000 (12:10 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 16 Jun 2009 22:07:42 +0000 (19:07 -0300)
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/gspca/ov519.c
include/linux/videodev2.h

index 1fff37b..188866a 100644 (file)
@@ -50,6 +50,13 @@ static int i2c_detect_tries = 10;
 struct sd {
        struct gspca_dev gspca_dev;             /* !! must be the first item */
 
+       char bridge;
+#define BRIDGE_OV511           0
+#define BRIDGE_OV511PLUS       1
+#define BRIDGE_OV518           2
+#define BRIDGE_OV518PLUS       3
+#define BRIDGE_OV519           4
+
        /* Determined by sensor type */
        __u8 sif;
 
@@ -87,6 +94,9 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
+static void setbrightness(struct gspca_dev *gspca_dev);
+static void setcontrast(struct gspca_dev *gspca_dev);
+static void setcolors(struct gspca_dev *gspca_dev);
 
 static struct ctrl sd_ctrls[] = {
        {
@@ -164,7 +174,7 @@ static struct ctrl sd_ctrls[] = {
        },
 };
 
-static const struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format ov519_vga_mode[] = {
        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -176,7 +186,7 @@ static const struct v4l2_pix_format vga_mode[] = {
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 0},
 };
-static const struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format ov519_sif_mode[] = {
        {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 176,
                .sizeimage = 176 * 144 * 3 / 8 + 590,
@@ -189,6 +199,47 @@ static const struct v4l2_pix_format sif_mode[] = {
                .priv = 0},
 };
 
+static const struct v4l2_pix_format ov518_vga_mode[] = {
+       {320, 240, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 1},
+       {640, 480, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 0},
+};
+static const struct v4l2_pix_format ov518_sif_mode[] = {
+       {176, 144, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+               .bytesperline = 176,
+               .sizeimage = 40000,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 1},
+       {352, 288, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+               .bytesperline = 352,
+               .sizeimage = 352 * 288 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 0},
+};
+
+
+/* Registers common to OV511 / OV518 */
+#define R51x_SYS_RESET                 0x50
+#define R51x_SYS_INIT                  0x53
+#define R51x_SYS_SNAP                  0x52
+#define R51x_SYS_CUST_ID               0x5F
+#define R51x_COMP_LUT_BEGIN            0x80
+
+/* OV511 Camera interface register numbers */
+#define R511_SYS_LED_CTL               0x55    /* OV511+ only */
+#define        OV511_RESET_NOREGS              0x3F    /* All but OV511 & regs */
+
+/* OV518 Camera interface register numbers */
+#define R518_GPIO_OUT                  0x56    /* OV518(+) only */
+#define R518_GPIO_CTL                  0x57    /* OV518(+) only */
+
 /* OV519 Camera interface register numbers */
 #define OV519_R10_H_SIZE               0x10
 #define OV519_R11_V_SIZE               0x11
@@ -224,6 +275,8 @@ static const struct v4l2_pix_format sif_mode[] = {
 
 /* OV7610 registers */
 #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 */
 #define OV8610_REG_HUE         0x04    /* 04 reserved */
 #define OV7610_REG_CNT         0x05    /* Y contrast */
@@ -846,11 +899,12 @@ static unsigned char ov7670_abs_to_sm(unsigned char v)
 static int reg_w(struct sd *sd, __u16 index, __u8 value)
 {
        int ret;
+       int req = (sd->bridge <= BRIDGE_OV511PLUS) ? 2 : 1;
 
        sd->gspca_dev.usb_buf[0] = value;
        ret = usb_control_msg(sd->gspca_dev.dev,
                        usb_sndctrlpipe(sd->gspca_dev.dev, 0),
-                       1,                      /* REQ_IO (ov518/519) */
+                       req,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        0, index,
                        sd->gspca_dev.usb_buf, 1, 500);
@@ -864,10 +918,11 @@ static int reg_w(struct sd *sd, __u16 index, __u8 value)
 static int reg_r(struct sd *sd, __u16 index)
 {
        int ret;
+       int req = (sd->bridge <= BRIDGE_OV511PLUS) ? 3 : 1;
 
        ret = usb_control_msg(sd->gspca_dev.dev,
                        usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
-                       1,                      /* REQ_IO */
+                       req,
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        0, index, sd->gspca_dev.usb_buf, 1, 500);
 
@@ -923,6 +978,28 @@ static int reg_w_mask(struct sd *sd,
        return reg_w(sd, index, value);
 }
 
+/*
+ * Writes multiple (n) byte value to a single register. Only valid with certain
+ * registers (0x30 and 0xc4 - 0xce).
+ */
+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);
+
+       ret = usb_control_msg(sd->gspca_dev.dev,
+                       usb_sndctrlpipe(sd->gspca_dev.dev, 0),
+                       1 /* REG_IO */,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0, index,
+                       sd->gspca_dev.usb_buf, n, 500);
+       if (ret < 0)
+               PDEBUG(D_ERR, "Write reg32 [%02x] %08x failed", index, value);
+       return ret;
+}
+
+
 /*
  * The OV518 I2C I/O procedure is different, hence, this function.
  * This is normally only called from i2c_w(). Note that this function
@@ -1014,20 +1091,47 @@ static inline int ov51x_stop(struct sd *sd)
 {
        PDEBUG(D_STREAM, "stopping");
        sd->stopped = 1;
-       return reg_w(sd, OV519_SYS_RESET1, 0x0f);
+       switch (sd->bridge) {
+       case BRIDGE_OV511:
+       case BRIDGE_OV511PLUS:
+               return reg_w(sd, R51x_SYS_RESET, 0x3d);
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               return reg_w_mask(sd, R51x_SYS_RESET, 0x3a, 0x3a);
+       case BRIDGE_OV519:
+               return reg_w(sd, OV519_SYS_RESET1, 0x0f);
+       }
+
+       return 0;
 }
 
 /* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
  * actually stopped (for performance). */
 static inline int ov51x_restart(struct sd *sd)
 {
+       int rc;
+
        PDEBUG(D_STREAM, "restarting");
        if (!sd->stopped)
                return 0;
        sd->stopped = 0;
 
        /* Reinitialize the stream */
-       return reg_w(sd, OV519_SYS_RESET1, 0x00);
+       switch (sd->bridge) {
+       case BRIDGE_OV511:
+       case BRIDGE_OV511PLUS:
+               return reg_w(sd, R51x_SYS_RESET, 0x00);
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               rc = reg_w(sd, 0x2f, 0x80);
+               if (rc < 0)
+                       return rc;
+               return reg_w(sd, R51x_SYS_RESET, 0x00);
+       case BRIDGE_OV519:
+               return reg_w(sd, OV519_SYS_RESET1, 0x00);
+       }
+
+       return 0;
 }
 
 /* This does an initial reset of an OmniVision sensor and ensures that I2C
@@ -1287,16 +1391,161 @@ static int ov6xx0_configure(struct sd *sd)
 /* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */
 static void ov51x_led_control(struct sd *sd, int on)
 {
-       reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1);   /* 0 / 1 */
+       switch (sd->bridge) {
+       /* OV511 has no LED control */
+       case BRIDGE_OV511PLUS:
+               reg_w(sd, R511_SYS_LED_CTL, on ? 1 : 0);
+               break;
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               reg_w_mask(sd, R518_GPIO_OUT, on ? 0x02 : 0x00, 0x02);
+               break;
+       case BRIDGE_OV519:
+               reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1);   /* 0 / 1 */
+               break;
+       }
 }
 
-/* this function is called at probe time */
-static int sd_config(struct gspca_dev *gspca_dev,
-                       const struct usb_device_id *id)
+/* OV518 quantization tables are 8x4 (instead of 8x8) */
+static int ov518_upload_quan_tables(struct sd *sd)
+{
+       const unsigned char yQuanTable518[] = {
+               5, 4, 5, 6, 6, 7, 7, 7,
+               5, 5, 5, 5, 6, 7, 7, 7,
+               6, 6, 6, 6, 7, 7, 7, 8,
+               7, 7, 6, 7, 7, 7, 8, 8
+       };
+
+       const unsigned char uvQuanTable518[] = {
+               6, 6, 6, 7, 7, 7, 7, 7,
+               6, 6, 6, 7, 7, 7, 7, 7,
+               6, 6, 6, 7, 7, 7, 7, 8,
+               7, 7, 7, 7, 7, 7, 8, 8
+       };
+
+       const unsigned char *pYTable = yQuanTable518;
+       const unsigned char *pUVTable = uvQuanTable518;
+       unsigned char val0, val1;
+       int i, rc, reg = R51x_COMP_LUT_BEGIN;
+
+       PDEBUG(D_PROBE, "Uploading quantization tables");
+
+       for (i = 0; i < 16; i++) {
+               val0 = *pYTable++;
+               val1 = *pYTable++;
+               val0 &= 0x0f;
+               val1 &= 0x0f;
+               val0 |= val1 << 4;
+               rc = reg_w(sd, reg, val0);
+               if (rc < 0)
+                       return rc;
+
+               val0 = *pUVTable++;
+               val1 = *pUVTable++;
+               val0 &= 0x0f;
+               val1 &= 0x0f;
+               val0 |= val1 << 4;
+               rc = reg_w(sd, reg + 16, val0);
+               if (rc < 0)
+                       return rc;
+
+               reg++;
+       }
+
+       return 0;
+}
+
+/* This initializes the OV518/OV518+ and the sensor */
+static int ov518_configure(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       struct cam *cam;
+       int rc;
+
+       /* For 518 and 518+ */
+       static struct ov_regvals init_518[] = {
+               { R51x_SYS_RESET,       0x40 },
+               { R51x_SYS_INIT,        0xe1 },
+               { R51x_SYS_RESET,       0x3e },
+               { R51x_SYS_INIT,        0xe1 },
+               { R51x_SYS_RESET,       0x00 },
+               { R51x_SYS_INIT,        0xe1 },
+               { 0x46,                 0x00 },
+               { 0x5d,                 0x03 },
+       };
+
+       static struct ov_regvals norm_518[] = {
+               { R51x_SYS_SNAP,        0x02 }, /* Reset */
+               { R51x_SYS_SNAP,        0x01 }, /* Enable */
+               { 0x31,                 0x0f },
+               { 0x5d,                 0x03 },
+               { 0x24,                 0x9f },
+               { 0x25,                 0x90 },
+               { 0x20,                 0x00 },
+               { 0x51,                 0x04 },
+               { 0x71,                 0x19 },
+               { 0x2f,                 0x80 },
+       };
+
+       static struct ov_regvals norm_518_p[] = {
+               { R51x_SYS_SNAP,        0x02 }, /* Reset */
+               { R51x_SYS_SNAP,        0x01 }, /* Enable */
+               { 0x31,                 0x0f },
+               { 0x5d,                 0x03 },
+               { 0x24,                 0x9f },
+               { 0x25,                 0x90 },
+               { 0x20,                 0x60 },
+               { 0x51,                 0x02 },
+               { 0x71,                 0x19 },
+               { 0x40,                 0xff },
+               { 0x41,                 0x42 },
+               { 0x46,                 0x00 },
+               { 0x33,                 0x04 },
+               { 0x21,                 0x19 },
+               { 0x3f,                 0x10 },
+               { 0x2f,                 0x80 },
+       };
+
+       /* First 5 bits of custom ID reg are a revision ID on OV518 */
+       PDEBUG(D_PROBE, "Device revision %d",
+              0x1F & reg_r(sd, R51x_SYS_CUST_ID));
+
+       rc = write_regvals(sd, init_518, ARRAY_SIZE(init_518));
+       if (rc < 0)
+               return rc;
+
+       /* Set LED GPIO pin to output mode */
+       rc = reg_w_mask(sd, R518_GPIO_CTL, 0x00, 0x02);
+       if (rc < 0)
+               return rc;
 
+       switch (sd->bridge) {
+       case BRIDGE_OV518:
+               rc = write_regvals(sd, norm_518, ARRAY_SIZE(norm_518));
+               if (rc < 0)
+                       return rc;
+               break;
+       case BRIDGE_OV518PLUS:
+               rc = write_regvals(sd, norm_518_p, ARRAY_SIZE(norm_518_p));
+               if (rc < 0)
+                       return rc;
+               break;
+       }
+
+       rc = ov518_upload_quan_tables(sd);
+       if (rc < 0) {
+               PDEBUG(D_ERR, "Error uploading quantization tables");
+               return rc;
+       }
+
+       rc = reg_w(sd, 0x2f, 0x80);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+static int ov519_configure(struct sd *sd)
+{
        static const struct ov_regvals init_519[] = {
                { 0x5a,  0x6d }, /* EnableSystem */
                { 0x53,  0x9b },
@@ -1313,8 +1562,32 @@ static int sd_config(struct gspca_dev *gspca_dev,
                /* windows reads 0x55 at this point*/
        };
 
-       if (write_regvals(sd, init_519, ARRAY_SIZE(init_519)))
+       return write_regvals(sd, init_519, ARRAY_SIZE(init_519));
+}
+
+/* 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;
+       int ret = 0;
+
+       sd->bridge = id->driver_info;
+
+       switch (sd->bridge) {
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               ret = ov518_configure(gspca_dev);
+               break;
+       case BRIDGE_OV519:
+               ret = ov519_configure(sd);
+               break;
+       }
+
+       if (ret)
                goto error;
+
        ov51x_led_control(sd, 0);       /* turn LED off */
 
        /* Test for 76xx */
@@ -1360,12 +1633,26 @@ static int sd_config(struct gspca_dev *gspca_dev,
        }
 
        cam = &gspca_dev->cam;
-       if (!sd->sif) {
-               cam->cam_mode = vga_mode;
-               cam->nmodes = ARRAY_SIZE(vga_mode);
-       } else {
-               cam->cam_mode = sif_mode;
-               cam->nmodes = ARRAY_SIZE(sif_mode);
+       switch (sd->bridge) {
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               if (!sd->sif) {
+                       cam->cam_mode = ov518_vga_mode;
+                       cam->nmodes = ARRAY_SIZE(ov518_vga_mode);
+               } else {
+                       cam->cam_mode = ov518_sif_mode;
+                       cam->nmodes = ARRAY_SIZE(ov518_sif_mode);
+               }
+               break;
+       case BRIDGE_OV519:
+               if (!sd->sif) {
+                       cam->cam_mode = ov519_vga_mode;
+                       cam->nmodes = ARRAY_SIZE(ov519_vga_mode);
+               } else {
+                       cam->cam_mode = ov519_sif_mode;
+                       cam->nmodes = ARRAY_SIZE(ov519_sif_mode);
+               }
+               break;
        }
        sd->brightness = BRIGHTNESS_DEF;
        sd->contrast = CONTRAST_DEF;
@@ -1422,6 +1709,106 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
+/* Sets up the OV518/OV518+ with the given image parameters
+ *
+ * OV518 needs a completely different approach, until we can figure out what
+ * the individual registers do. Also, only 15 FPS is supported now.
+ *
+ * Do not put any sensor-specific code in here (including I2C I/O functions)
+ */
+static int ov518_mode_init_regs(struct sd *sd)
+{
+       int hsegs, vsegs;
+
+       /******** Set the mode ********/
+
+       reg_w(sd, 0x2b, 0);
+       reg_w(sd, 0x2c, 0);
+       reg_w(sd, 0x2d, 0);
+       reg_w(sd, 0x2e, 0);
+       reg_w(sd, 0x3b, 0);
+       reg_w(sd, 0x3c, 0);
+       reg_w(sd, 0x3d, 0);
+       reg_w(sd, 0x3e, 0);
+
+       if (sd->bridge == BRIDGE_OV518) {
+               /* Set 8-bit (YVYU) input format */
+               reg_w_mask(sd, 0x20, 0x08, 0x08);
+
+               /* Set 12-bit (4:2:0) output format */
+               reg_w_mask(sd, 0x28, 0x80, 0xf0);
+               reg_w_mask(sd, 0x38, 0x80, 0xf0);
+       } else {
+               reg_w(sd, 0x28, 0x80);
+               reg_w(sd, 0x38, 0x80);
+       }
+
+       hsegs = sd->gspca_dev.width / 16;
+       vsegs = sd->gspca_dev.height / 4;
+
+       reg_w(sd, 0x29, hsegs);
+       reg_w(sd, 0x2a, vsegs);
+
+       reg_w(sd, 0x39, hsegs);
+       reg_w(sd, 0x3a, vsegs);
+
+       /* Windows driver does this here; who knows why */
+       reg_w(sd, 0x2f, 0x80);
+
+       /******** Set the framerate (to 30 FPS) ********/
+       if (sd->bridge == BRIDGE_OV518PLUS)
+               sd->clockdiv = 1;
+       else
+               sd->clockdiv = 0;
+
+       /* Mode independent, but framerate dependent, regs */
+       reg_w(sd, 0x51, 0x04);  /* Clock divider; lower==faster */
+       reg_w(sd, 0x22, 0x18);
+       reg_w(sd, 0x23, 0xff);
+
+       if (sd->bridge == BRIDGE_OV518PLUS)
+               reg_w(sd, 0x21, 0x19);
+       else
+               reg_w(sd, 0x71, 0x17);  /* Compression-related? */
+
+       /* FIXME: Sensor-specific */
+       /* Bit 5 is what matters here. Of course, it is "reserved" */
+       i2c_w(sd, 0x54, 0x23);
+
+       reg_w(sd, 0x2f, 0x80);
+
+       if (sd->bridge == BRIDGE_OV518PLUS) {
+               reg_w(sd, 0x24, 0x94);
+               reg_w(sd, 0x25, 0x90);
+               ov518_reg_w32(sd, 0xc4,    400, 2);     /* 190h   */
+               ov518_reg_w32(sd, 0xc6,    540, 2);     /* 21ch   */
+               ov518_reg_w32(sd, 0xc7,    540, 2);     /* 21ch   */
+               ov518_reg_w32(sd, 0xc8,    108, 2);     /* 6ch    */
+               ov518_reg_w32(sd, 0xca, 131098, 3);     /* 2001ah */
+               ov518_reg_w32(sd, 0xcb,    532, 2);     /* 214h   */
+               ov518_reg_w32(sd, 0xcc,   2400, 2);     /* 960h   */
+               ov518_reg_w32(sd, 0xcd,     32, 2);     /* 20h    */
+               ov518_reg_w32(sd, 0xce,    608, 2);     /* 260h   */
+       } else {
+               reg_w(sd, 0x24, 0x9f);
+               reg_w(sd, 0x25, 0x90);
+               ov518_reg_w32(sd, 0xc4,    400, 2);     /* 190h   */
+               ov518_reg_w32(sd, 0xc6,    381, 2);     /* 17dh   */
+               ov518_reg_w32(sd, 0xc7,    381, 2);     /* 17dh   */
+               ov518_reg_w32(sd, 0xc8,    128, 2);     /* 80h    */
+               ov518_reg_w32(sd, 0xca, 183331, 3);     /* 2cc23h */
+               ov518_reg_w32(sd, 0xcb,    746, 2);     /* 2eah   */
+               ov518_reg_w32(sd, 0xcc,   1750, 2);     /* 6d6h   */
+               ov518_reg_w32(sd, 0xcd,     45, 2);     /* 2dh    */
+               ov518_reg_w32(sd, 0xce,    851, 2);     /* 353h   */
+       }
+
+       reg_w(sd, 0x2f, 0x80);
+
+       return 0;
+}
+
+
 /* Sets up the OV519 with the given image parameters
  *
  * OV519 needs a completely different approach, until we can figure out what
@@ -1740,6 +2127,11 @@ static int set_ov_sensor_window(struct sd *sd)
                hwebase = 0x3a;
                vwsbase = 0x05;
                vwebase = 0x06;
+               if (qvga) {
+                       /* HDG: this fixes U and V getting swapped */
+                       hwsbase--;
+                       vwsbase--;
+               }
                break;
        case SEN_OV7620:
                hwsbase = 0x2f;         /* From 7620.SET (spec is wrong) */
@@ -1855,15 +2247,28 @@ static int set_ov_sensor_window(struct sd *sd)
 static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int ret;
+       int ret = 0;
 
-       ret = ov519_mode_init_regs(sd);
+       switch (sd->bridge) {
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               ret = ov518_mode_init_regs(sd);
+               break;
+       case BRIDGE_OV519:
+               ret = ov519_mode_init_regs(sd);
+               break;
+       }
        if (ret < 0)
                goto out;
+
        ret = set_ov_sensor_window(sd);
        if (ret < 0)
                goto out;
 
+       setcontrast(gspca_dev);
+       setbrightness(gspca_dev);
+       setcolors(gspca_dev);
+
        ret = ov51x_restart(sd);
        if (ret < 0)
                goto out;
@@ -1882,7 +2287,30 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        ov51x_led_control(sd, 0);
 }
 
-static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+static void ov518_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       __u8 *data,                     /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       PDEBUG(D_STREAM, "ov518_pkt_scan: %d bytes", len);
+
+       if (len & 7) {
+               len--;
+               PDEBUG(D_STREAM, "packet number: %d\n", (int)data[len]);
+       }
+
+       /* 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]) {
+               gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0);
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, 0);
+       }
+
+       /* intermediate packet */
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void ov519_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
                        int len)                        /* iso packet length */
@@ -1926,6 +2354,27 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        data, len);
 }
 
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       __u8 *data,                     /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->bridge) {
+       case BRIDGE_OV511:
+       case BRIDGE_OV511PLUS:
+               break;
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               ov518_pkt_scan(gspca_dev, frame, data, len);
+               break;
+       case BRIDGE_OV519:
+               ov519_pkt_scan(gspca_dev, frame, data, len);
+               break;
+       }
+}
+
 /* -- management routines -- */
 
 static void setbrightness(struct gspca_dev *gspca_dev)
@@ -1970,6 +2419,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
                break;
        case SEN_OV6630:
                i2c_w_mask(sd, OV7610_REG_CNT, val >> 4, 0x0f);
+               break;
        case SEN_OV8610: {
                static const __u8 ctab[] = {
                        0x03, 0x09, 0x0b, 0x0f, 0x53, 0x6f, 0x35, 0x7f
@@ -2136,19 +2586,21 @@ static const struct sd_desc sd_desc = {
 
 /* -- module initialisation -- */
 static const __devinitdata struct usb_device_id device_table[] = {
-       {USB_DEVICE(0x041e, 0x4052)},
-       {USB_DEVICE(0x041e, 0x405f)},
-       {USB_DEVICE(0x041e, 0x4060)},
-       {USB_DEVICE(0x041e, 0x4061)},
-       {USB_DEVICE(0x041e, 0x4064)},
-       {USB_DEVICE(0x041e, 0x4068)},
-       {USB_DEVICE(0x045e, 0x028c)},
-       {USB_DEVICE(0x054c, 0x0154)},
-       {USB_DEVICE(0x054c, 0x0155)},
-       {USB_DEVICE(0x05a9, 0x0519)},
-       {USB_DEVICE(0x05a9, 0x0530)},
-       {USB_DEVICE(0x05a9, 0x4519)},
-       {USB_DEVICE(0x05a9, 0x8519)},
+       {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x041e, 0x4064), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x041e, 0x4068), .driver_info = BRIDGE_OV519 },
+       {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(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, 0x4519), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x05a9, 0x8519), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x05a9, 0xa518), .driver_info = BRIDGE_OV518PLUS },
        {}
 };
 
index ebb2ea6..f24ecee 100644 (file)
@@ -347,7 +347,8 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */
 #define V4L2_PIX_FMT_SQ905C   v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */
 #define V4L2_PIX_FMT_PJPG     v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */
-#define V4L2_PIX_FMT_YVYU    v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16  YVU 4:2:2     */
+#define V4L2_PIX_FMT_YVYU     v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */
+#define V4L2_PIX_FMT_OV518    v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */
 
 /*
  *     F O R M A T   E N U M E R A T I O N